Statistics
| Branch: | Revision:

iof-bird-daemon / filter / filter.c @ 74a7da48

History | View | Annotate | Download (17.4 KB)

1
/*
2
 *        Filters: utility functions
3
 *
4
 *        Copyright 1998 Pavel Machek <pavel@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 *
8
 *         Notice that pair is stored as integer: first << 16 | second
9
 *
10
 */
11

    
12
#define LOCAL_DEBUG
13

    
14
#include "nest/bird.h"
15
#include "lib/lists.h"
16
#include "lib/resource.h"
17
#include "lib/socket.h"
18
#include "lib/string.h"
19
#include "lib/unaligned.h"
20
#include "nest/route.h"
21
#include "nest/protocol.h"
22
#include "nest/iface.h"
23
#include "nest/attrs.h"
24
#include "conf/conf.h"
25
#include "filter/filter.h"
26

    
27
#define P(a,b) ((a<<8) | b)
28

    
29
struct f_inst *startup_func = NULL;
30

    
31
#define CMP_ERROR 999
32

    
33
/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
34
int
35
val_compare(struct f_val v1, struct f_val v2)
36
{
37
  if ((v1.type == T_VOID) && (v2.type == T_VOID))
38
    return 0;
39
  if (v1.type == T_VOID)        /* Hack for else */
40
    return -1;
41
  if (v2.type == T_VOID)
42
    return 1;
43

    
44
  if (v1.type != v2.type)
45
    return CMP_ERROR;
46
  switch (v1.type) {
47
  case T_ENUM:
48
  case T_INT: 
49
  case T_PAIR:
50
    if (v1.val.i == v2.val.i) return 0;
51
    if (v1.val.i < v2.val.i) return -1;
52
    return 1;
53
  case T_IP:
54
  case T_PREFIX:
55
    return ipa_compare(v1.val.px.ip, v2.val.px.ip);
56
  default:
57
    return CMP_ERROR;
58
  }
59
}
60

    
61
int 
62
val_simple_in_range(struct f_val v1, struct f_val v2)
63
{
64
  if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
65
    return as_path_match(v1.val.ad, v2.val.path_mask);
66
  if ((v1.type == T_PAIR) && (v2.type == T_CLIST))
67
    return int_set_contains(v2.val.ad, v1.val.i);
68

    
69
  if ((v1.type == T_IP) && (v2.type == T_PREFIX))
70
    return !(ipa_compare(ipa_and(v2.val.px.ip, ipa_mkmask(v2.val.px.len)), ipa_and(v1.val.px.ip, ipa_mkmask(v2.val.px.len))));
71

    
72
  if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
73
    ip_addr mask;
74
    if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
75
      return CMP_ERROR;
76
    mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
77
    if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
78
      return 0;
79

    
80
    if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
81
      return 0;
82
    if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
83
      return 0;
84
    if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
85
                                        || (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
86
      return 0;
87
    return 1;    
88
  }
89
  return CMP_ERROR;
90
}
91

    
92
int
93
val_in_range(struct f_val v1, struct f_val v2)
94
{
95
  int res;
96

    
97
  res = val_simple_in_range(v1, v2);
98

    
99
  if (res != CMP_ERROR)
100
    return res;
101

    
102
  if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
103
    struct f_tree *n;
104
    n = find_tree(v2.val.t, v1);
105
    if (!n)
106
      return 0;
107
    return !! (val_simple_in_range(v1, n->from));        /* We turn CMP_ERROR into compared ok, and that's fine */
108
  }
109
  return CMP_ERROR;
110
}
111

    
112
static void
113
tree_print(struct f_tree *t)
114
{
115
  if (!t) {
116
    debug( "() " );
117
    return;
118
  }
119
  debug( "[ " );
120
  tree_print( t->left );
121
  debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " );
122
  tree_print( t->right );
123
  debug( "] " );
124
}
125

    
126
void
127
val_print(struct f_val v)
128
{
129
  char buf[2048];
130
  char buf2[1024];
131
#define PRINTF(a...) bsnprintf( buf, 2040, a )
132
  buf[0] = 0;
133
  switch (v.type) {
134
  case T_VOID: PRINTF( "(void)" ); break;
135
  case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
136
  case T_INT: PRINTF( "%d ", v.val.i ); break;
137
  case T_STRING: PRINTF( "%s", v.val.s ); break;
138
  case T_IP: PRINTF( "%I", v.val.px.ip ); break;
139
  case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
140
  case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
141
  case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
142
  case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
143
  case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break;
144
  case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break;
145
  case T_PATH_MASK: debug( "(pathmask " ); { struct f_path_mask *p = v.val.s; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break;
146
  default: PRINTF( "[unknown type %x]", v.type );
147
#undef PRINTF
148
  }
149
  debug( buf );
150
}
151

    
152
static struct rte **f_rte, *f_rte_old;
153
static struct linpool *f_pool;
154
static struct ea_list **f_tmp_attrs;
155
static int f_flags;
156
static rta *f_rta_copy;
157

    
158
#define runtime(x) do { \
159
    log( L_ERR x ); \
160
    res.type = T_RETURN; \
161
    res.val.i = F_ERROR; \
162
    return res; \
163
  } while(0)
164

    
165
#define ARG(x,y) \
166
        x = interpret(what->y); \
167
        if (x.type & T_RETURN) \
168
                return x;
169

    
170
#define ONEARG ARG(v1, a1.p)
171
#define TWOARGS ARG(v1, a1.p) \
172
                ARG(v2, a2.p)
173
#define TWOARGS_C TWOARGS \
174
                  if (v1.type != v2.type) \
175
                    runtime( "Can not operate with values of incompatible types" );
176

    
177
static struct f_val
178
interpret(struct f_inst *what)
179
{
180
  struct symbol *sym;
181
  struct f_val v1, v2, res;
182
  int i,j,k;
183

    
184
  res.type = T_VOID;
185
  if (!what)
186
    return res;
187

    
188
  switch(what->code) {
189
  case ',':
190
    TWOARGS;
191
    break;
192

    
193
/* Binary operators */
194
  case '+':
195
    TWOARGS_C;
196
    switch (res.type = v1.type) {
197
    case T_VOID: runtime( "Can not operate with values of type void" );
198
    case T_INT: res.val.i = v1.val.i + v2.val.i; break;
199
    default: runtime( "Usage of unknown type" );
200
    }
201
    break;
202
  case '/':
203
    TWOARGS_C;
204
    switch (res.type = v1.type) {
205
    case T_VOID: runtime( "Can not operate with values of type void" );
206
    case T_INT: res.val.i = v1.val.i / v2.val.i; break;
207
    case T_IP: if (v2.type != T_INT)
208
                 runtime( "Operator / is <ip>/<int>" );
209
               break;
210
    default: runtime( "Usage of unknown type" );
211
    }
212
    break;
213

    
214
/* Relational operators */
215

    
216
#define COMPARE(x) \
217
    TWOARGS_C; \
218
    res.type = T_BOOL; \
219
    i = val_compare(v1, v2); \
220
    if (i==CMP_ERROR) \
221
      runtime( "Error in comparation" ); \
222
    res.val.i = (x); \
223
    break;
224

    
225
  case P('!','='): COMPARE(i!=0);
226
  case P('=','='): COMPARE(i==0);
227
  case '<': COMPARE(i==-1);
228
  case P('<','='): COMPARE(i!=1);
229

    
230
  case '!':
231
    ONEARG;
232
    if (v1.type != T_BOOL)
233
      runtime( "not applied to non-boolean" );
234
    res = v1;
235
    res.val.i = !res.val.i;
236
    break;
237

    
238
  case '~':
239
    TWOARGS;
240
    res.type = T_BOOL;
241
    res.val.i = val_in_range(v1, v2);
242
    if (res.val.i == CMP_ERROR)
243
      runtime( "~ applied on unknown type pair" );
244
    break;
245
  case P('d','e'):
246
    ONEARG;
247
    res.type = T_BOOL;
248
    res.val.i = (v1.type != T_VOID);
249
    break;
250

    
251
  /* Set to indirect value, a1 = variable, a2 = value */
252
  case 's':
253
    ARG(v2, a2.p);
254
    sym = what->a1.p;
255
    switch (res.type = v2.type) {
256
    case T_VOID: runtime( "Can not assign void values" );
257
    case T_ENUM:
258
    case T_INT: 
259
    case T_IP: 
260
    case T_PREFIX: 
261
    case T_PAIR: 
262
    case T_PATH:
263
    case T_CLIST:
264
    case T_PATH_MASK:
265
      if (sym->class != (SYM_VARIABLE | v2.type))
266
        runtime( "Variable of bad type" );
267
      * (struct f_val *) sym->aux2 = v2; 
268
      break;
269
    default:
270
      bug( "Set to invalid type" );
271
    }
272
    break;
273

    
274
  case 'c':        /* integer (or simple type) constant */
275
    res.type = what->aux;
276
    res.val.i = what->a2.i;
277
    break;
278
  case 'C':
279
    res = * ((struct f_val *) what->a1.p);
280
    break;
281
  case 'p':
282
    ONEARG;
283
    val_print(v1);
284
    break;
285
  case '?':        /* ? has really strange error value, so we can implement if ... else nicely :-) */
286
    ONEARG;
287
    if (v1.type != T_BOOL)
288
      runtime( "If requires bool expression" );
289
    if (v1.val.i) {
290
      ARG(res,a2.p);
291
      res.val.i = 0;
292
    } else res.val.i = 1;
293
    res.type = T_BOOL;
294
    break;
295
  case '0':
296
    debug( "No operation\n" );
297
    break;
298
  case P('p',','):
299
    ONEARG;
300
    if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
301
      debug( "\n" );
302

    
303
    switch (what->a2.i) {
304
    case F_QUITBIRD:
305
      die( "Filter asked me to die" );
306
    case F_ACCEPT:
307
      /* Should take care about turning ACCEPT into MODIFY */
308
    case F_ERROR:
309
    case F_REJECT:        /* FIXME (noncritical) Should print complete route along with reason to reject route */
310
      res.type = T_RETURN;
311
      res.val.i = what->a2.i;
312
      return res;        /* We have to return now, no more processing. */
313
    case F_NONL:
314
    case F_NOP:
315
      break;
316
    default:
317
      bug( "unknown return type: can not happen");
318
    }
319
    break;
320
  case 'a':        /* rta access */
321
    {
322
      struct rta *rta = (*f_rte)->attrs;
323
      res.type = what->aux;
324
      switch(res.type) {
325
      case T_IP:
326
        res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
327
        break;
328
      case T_ENUM:
329
        res.val.i = * ((char *) rta + what->a2.i);
330
        break;
331
      case T_PREFIX:        /* Warning: this works only for prefix of network */
332
        {
333
          res.val.px.ip = (*f_rte)->net->n.prefix;
334
          res.val.px.len = (*f_rte)->net->n.pxlen;
335
          break;
336
        }
337
      default:
338
        bug( "Invalid type for rta access (%x)", res.type );
339
      }
340
    }
341
    break;
342
  case P('e','a'):        /* Access to extended attributes */
343
    {
344
      eattr *e = NULL;
345
      if (!(f_flags & FF_FORCE_TMPATTR))
346
        e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
347
      if (!e) 
348
        e = ea_find( (*f_tmp_attrs), what->a2.i );
349
      if ((!e) && (f_flags & FF_FORCE_TMPATTR))
350
        e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
351
      
352
      if (!e) {
353
        res.type = T_VOID;
354
        break;
355
      }
356
      res.type = what->aux;        /* FIXME: should check type? */
357
      switch (what->aux) {
358
      case T_INT:
359
        res.val.i = e->u.data;
360
        break;
361
      case T_CLIST:
362
      case T_PATH:
363
        res.val.ad = e->u.ptr;
364
        break;
365
      default:
366
        bug("Unknown type in e,a\n");
367
      }
368
    }
369
    break;
370
  case P('e','S'):
371
    ONEARG;
372
    if (v1.type != what->aux)
373
      runtime("Wrong type when setting dynamic attribute");
374

    
375
    {
376
      struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
377

    
378
      l->next = NULL;
379
      l->flags = EALF_SORTED;
380
      l->count = 1;
381
      l->attrs[0].id = what->a2.i;
382
      l->attrs[0].flags = 0;
383
      l->attrs[0].type = what->aux | EAF_ORIGINATED;
384
      switch (what->aux & EAF_TYPE_MASK) {
385
      case EAF_TYPE_INT:
386
        if (v1.type != T_INT)
387
          runtime( "Setting int attribute to non-int value" );
388
        l->attrs[0].u.data = v1.val.i;
389
        break;
390
      case EAF_TYPE_AS_PATH:
391
        if (v1.type != T_PATH)
392
          runtime( "Setting path attribute to non-path value" );
393
        l->attrs[0].u.ptr = v1.val.ad;
394
        break;
395
      case EAF_TYPE_INT_SET:
396
        if (v1.type != T_CLIST)
397
          runtime( "Setting int set  attribute to non-clist value" );
398
        l->attrs[0].u.ptr = v1.val.ad;
399
        break;
400
      case EAF_TYPE_UNDEF:
401
        if (v1.type != T_VOID)
402
          runtime( "Setting void attribute to non-void value" );
403
        l->attrs[0].u.data = 0;
404
        break;
405
      }
406

    
407
      if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
408
        if (!f_rta_copy) {
409
          f_rta_copy = lp_alloc(f_pool, sizeof(rta));
410
          memcpy(f_rta_copy, (*f_rte)->attrs, sizeof(rta));
411
          f_rta_copy->aflags = 0;
412
          *f_rte = rte_cow(*f_rte);
413
          (*f_rte)->attrs = f_rta_copy;
414
        }
415
        l->next = f_rta_copy->eattrs;
416
        f_rta_copy->eattrs = l;
417
      } else {
418
        l->next = (*f_tmp_attrs);
419
        (*f_tmp_attrs) = l;
420
      }
421
    }
422
    break;
423

    
424
  case 'L':        /* Get length of */
425
    ONEARG;
426
    res.type = T_INT;
427
    switch(v1.type) {
428
    case T_PREFIX: res.val.i = v1.val.px.len; break;
429
    case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
430
    default: bug( "Length of what?" );
431
    }
432
    break;
433
  case P('c','p'):        /* Convert prefix to ... */
434
    ONEARG;
435
    if (v1.type != T_PREFIX)
436
      runtime( "Can not convert non-prefix this way" );
437
    res.type = what->aux;
438
    switch(res.type) {
439
      /*    case T_INT:        res.val.i = v1.val.px.len; break; Not needed any more */
440
    case T_IP: res.val.px.ip = v1.val.px.ip; break;
441
    default: bug( "Unknown prefix to conversion" );
442
    }
443
    break;
444
  case 'r':
445
    ONEARG;
446
    res = v1;
447
    res.type |= T_RETURN;
448
    break;
449
  case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out  */
450
    ONEARG;
451
    res = interpret(what->a2.p);
452
    if (res.type == T_RETURN)
453
      return res;
454
    res.type &= ~T_RETURN;    
455
    break;
456
  case P('S','W'):
457
    ONEARG;
458
    {
459
      struct f_tree *t = find_tree(what->a2.p, v1);
460
      if (!t) {
461
        v1.type = T_VOID;
462
        t = find_tree(what->a2.p, v1);
463
        if (!t) {
464
          debug( "No else statement?\n ");
465
          break;
466
        }
467
      }        
468
      if (!t->data)
469
        bug( "Impossible: no code associated!" );
470
      return interpret(t->data);
471
    }
472
    break;
473
  case P('i','M'): /* IP.MASK(val) */
474
    TWOARGS;
475
    if (v2.type != T_INT)
476
      runtime( "Can not use this type for mask.");
477
    if (v1.type != T_IP)
478
      runtime( "You can mask only IP addresses." );
479
    {
480
      ip_addr mask = ipa_mkmask(v2.val.i);
481
      res.type = T_IP;
482
      res.val.px.ip = ipa_and(mask, v1.val.px.ip);
483
    }
484
    break;
485

    
486
  case 'E':        /* Create empty attribute */
487
    res.type = what->aux;
488
    res.val.ad = adata_empty(f_pool);
489
    break;
490
  case P('A','p'):        /* Path prepend */
491
    TWOARGS;
492
    if (v1.type != T_PATH)
493
      runtime("Can't prepend to non-path");
494
    if (v2.type != T_INT)
495
      runtime("Can't prepend non-integer");
496

    
497
    res.type = T_PATH;
498
    res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
499
    break;
500

    
501
  case P('C','a'):        /* Community list add or delete */
502
    TWOARGS;
503
    if (v1.type != T_CLIST)
504
      runtime("Can't add/delete to non-clist");
505
    if (v2.type != T_PAIR)
506
      runtime("Can't add/delete non-pair");
507

    
508
    res.type = T_CLIST;
509
    switch (what->aux) {
510
    case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break;
511
    case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break;
512
    default: bug("unknown Ca operation");
513
    }
514
    break;
515

    
516
  default:
517
    bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
518
  }
519
  if (what->next)
520
    return interpret(what->next);
521
  return res;
522
}
523

    
524
#undef ARG
525
#define ARG(x,y) \
526
        if (!i_same(f1->y, f2->y)) \
527
                return 0;
528

    
529
#define ONEARG ARG(v1, a1.p)
530
#define TWOARGS ARG(v1, a1.p) \
531
                ARG(v2, a2.p)
532

    
533
#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
534

    
535
int
536
i_same(struct f_inst *f1, struct f_inst *f2)
537
{
538
  if ((!!f1) != (!!f2))
539
    return 0;
540
  if (!f1)
541
    return 1;
542
  if (f1->aux != f2->aux)
543
    return 0;
544
  if (f1->code != f2->code)
545
    return 0;
546
  if (f1 == f2)                /* It looks strange, but it is possible with call rewriting trickery */
547
    return 1;
548

    
549
  switch(f1->code) {
550
  case ',': /* fall through */
551
  case '+':
552
  case '/':
553
  case P('!','='):
554
  case P('=','='):
555
  case '<':
556
  case P('<','='): TWOARGS; break;
557

    
558
  case '!': ONEARG; break;
559
  case '~': TWOARGS; break;
560
  case P('d','e'): ONEARG; break;
561

    
562
  case 's':
563
    ARG(v2, a2.p);
564
    {
565
      struct symbol *s1, *s2;
566
      s1 = f1->a1.p;
567
      s2 = f2->a1.p;
568
      if (strcmp(s1->name, s2->name))
569
        return 0;
570
      if (s1->class != s2->class)
571
        return 0;
572
    }
573
    break;
574

    
575
  case 'c': A2_SAME; break;
576
  case 'C': 
577
    if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a2.p))
578
      return 0;
579
    break;
580
  case 'p': case 'L': ONEARG; break;
581
  case '?': TWOARGS; break;
582
  case '0': case 'E': break;
583
  case P('p',','): ONEARG; A2_SAME; break;
584
  case 'a': A2_SAME; break;
585
  case P('e','a'): A2_SAME; break;
586
  case P('e','S'): ONEARG; A2_SAME; break;
587

    
588
  case 'r': ONEARG; break;
589
  case P('c','p'): ONEARG; break;
590
  case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
591
             ONEARG; 
592
             if (!i_same(f1->a2.p, f2->a2.p))
593
               return 0; 
594
             f2->a2.p = f1->a2.p;
595
             break;
596
  case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
597
  case P('i','M'): TWOARGS; break;
598
  case P('A','p'): TWOARGS; break;
599
  case P('C','a'): TWOARGS; break;
600
  default:
601
    bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
602
  }
603
  return i_same(f1->next, f2->next);
604
}
605

    
606
int
607
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
608
{
609
  struct f_inst *inst;
610
  struct f_val res;
611
  DBG( "Running filter `%s'...", filter->name );
612

    
613
  f_flags = flags;
614
  f_tmp_attrs = tmp_attrs;
615
  f_rte = rte;
616
  f_rte_old = *rte;
617
  f_rta_copy = NULL;
618
  f_pool = tmp_pool;
619
  inst = filter->root;
620
  res = interpret(inst);
621
  if (res.type != T_RETURN)
622
    return F_ERROR;
623
  DBG( "done (%d)\n", res.val.i );
624
  return res.val.i;
625
}
626

    
627
void
628
filters_postconfig(void)
629
{
630
  struct f_val res;
631
  if (startup_func) {
632
    debug( "Launching startup function...\n" );
633
    f_pool = lp_new(&root_pool, 1024);
634
    res = interpret(startup_func);
635
    if (res.type == F_ERROR)
636
      die( "Startup function resulted in error." );
637
    debug( "done\n" );
638
  }
639
} 
640

    
641
int
642
filter_same(struct filter *new, struct filter *old)
643
{
644
  if (old == new)        /* Handle FILTER_ACCEPT and FILTER_REJECT */
645
    return 1;
646
  if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
647
      new == FILTER_ACCEPT || new == FILTER_REJECT)
648
    return 0;
649
  return i_same(new->root, old->root);
650
}
651

    
652
/* This should end up far away from here!
653
 */
654
struct adata *
655
comlist_add(struct linpool *pool, struct adata *list, u32 val)
656
{
657
  struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4);
658
  res->length = list->length+4;
659
  * (u32 *) res->data = val;
660
  memcpy((char *) res->data + 4, list->data, list->length);
661
  return res;
662
}
663

    
664
struct adata *
665
comlist_contains(struct adata *list, u32 val)
666
{
667
  u32 *l = &(list->data);
668
  int i;
669
  for (i=0; i<list->length/4; i++)
670
    if (*l++ == val)
671
      return 1;
672
  return 0;
673
}
674

    
675
struct adata *
676
comlist_del(struct linpool *pool, struct adata *list, u32 val)
677
{
678
  struct adata *res;
679
  u32 *l, *k;
680
  int i;
681

    
682
  if (!comlist_contains(list, val))
683
    return list;
684

    
685
  res = lp_alloc(pool, list->length + sizeof(struct adata) - 4);
686
  res->length = list->length-4;
687

    
688
  l = &(list->data);
689
  k = &(res->data);
690
  for (i=0; i<list->length/4; i++)
691
    if (l[i] != val)
692
      *k++ = l[i];
693

    
694
  return res;
695
}
696

    
697
struct adata *
698
adata_empty(struct linpool *pool)
699
{
700
  struct adata *res = lp_alloc(pool, sizeof(struct adata));
701
  res->length = 0;
702
  return res;
703
}