filter.c 17.2 KB
Newer Older
1 2 3 4 5 6
/*
 *	Filters: utility functions
 *
 *	Copyright 1998 Pavel Machek <pavel@ucw.cz>
 *
 *	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
Pavel Machek's avatar
Pavel Machek committed
9
 *
10 11
 */

12
#define LOCAL_DEBUG
13

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

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

29 30
struct f_inst *startup_func = NULL;

31 32 33 34 35 36
#define CMP_ERROR 999

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

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

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

69 70 71 72 73 74 75 76 77 78
  if ((v1.type == T_IP) && (v2.type == T_PREFIX))
    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))));

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

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

92 93 94
int
val_in_range(struct f_val v1, struct f_val v2)
{
95 96 97 98 99 100 101
  int res;

  res = val_simple_in_range(v1, v2);

  if (res != CMP_ERROR)
    return res;

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

112 113 114 115
static void
tree_print(struct f_tree *t)
{
  if (!t) {
116
    debug( "() " );
117 118
    return;
  }
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 127 128 129
}

void
val_print(struct f_val v)
{
  char buf[2048];
130
  char buf2[1024];
131 132 133 134 135 136 137
#define PRINTF(a...) bsnprintf( buf, 2040, a )
  buf[0] = 0;
  switch (v.type) {
  case T_VOID: PRINTF( "(void)" ); break;
  case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
  case T_INT: PRINTF( "%d ", v.val.i ); break;
  case T_STRING: PRINTF( "%s", v.val.s ); break;
138
  case T_IP: PRINTF( "%I", v.val.px.ip ); break;
139 140
  case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
  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;
Pavel Machek's avatar
Pavel Machek committed
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;
Pavel Machek's avatar
Pavel Machek committed
154
static struct ea_list **f_tmp_attrs;
155
static int f_flags;
156

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

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

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

176 177 178 179 180
static struct f_val
interpret(struct f_inst *what)
{
  struct symbol *sym;
  struct f_val v1, v2, res;
181
  int i,j,k;
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213

  res.type = T_VOID;
  if (!what)
    return res;

  switch(what->code) {
  case ',':
    TWOARGS;
    break;

/* Binary operators */
  case '+':
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can not operate with values of type void" );
    case T_INT: res.val.i = v1.val.i + v2.val.i; break;
    default: runtime( "Usage of unknown type" );
    }
    break;
  case '/':
    TWOARGS_C;
    switch (res.type = v1.type) {
    case T_VOID: runtime( "Can not operate with values of type void" );
    case T_INT: res.val.i = v1.val.i / v2.val.i; break;
    case T_IP: if (v2.type != T_INT)
                 runtime( "Operator / is <ip>/<int>" );
               break;
    default: runtime( "Usage of unknown type" );
    }
    break;

/* Relational operators */
214 215 216 217 218 219 220 221

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

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

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

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

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

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

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

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

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

406 407
      if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
	*f_rte = rte_cow(*f_rte);
Pavel Machek's avatar
Pavel Machek committed
408 409 410 411 412 413
	l->next = (*f_rte)->attrs->eattrs;
	(*f_rte)->attrs->eattrs = l;
      } else {
	l->next = (*f_tmp_attrs);
	(*f_tmp_attrs) = l;
      }
414 415
    }
    break;
416

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

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

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

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

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

509 510 511 512 513 514 515 516
  default:
    bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
  }
  if (what->next)
    return interpret(what->next);
  return res;
}

517
#undef ARG
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
#define ARG(x,y) \
	if (!i_same(f1->y, f2->y)) \
		return 0;

#define ONEARG ARG(v1, a1.p)
#define TWOARGS ARG(v1, a1.p) \
		ARG(v2, a2.p)

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

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

  switch(f1->code) {
  case ',': /* fall through */
  case '+':
  case '/':
546 547
  case P('!','='):
  case P('=','='):
548
  case '<':
549
  case P('<','='): TWOARGS; break;
550

Pavel Machek's avatar
Pavel Machek committed
551
  case '!': ONEARG; break;
552
  case '~': TWOARGS; break;
553
  case P('d','e'): ONEARG; break;
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

  case 's':
    ARG(v2, a2.p);
    {
      struct symbol *s1, *s2;
      s1 = f1->a1.p;
      s2 = f2->a1.p;
      if (strcmp(s1->name, s2->name))
	return 0;
      if (s1->class != s2->class)
	return 0;
    }
    break;

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

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

599
int
600
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
601 602 603
{
  struct f_inst *inst;
  struct f_val res;
604
  DBG( "Running filter `%s'...", filter->name );
605

606
  f_flags = flags;
Pavel Machek's avatar
Pavel Machek committed
607
  f_tmp_attrs = tmp_attrs;
608
  f_rte = rte;
609
  f_rte_old = *rte;
610
  f_pool = tmp_pool;
611 612 613 614
  inst = filter->root;
  res = interpret(inst);
  if (res.type != T_RETURN)
    return F_ERROR;
615
  DBG( "done (%d)\n", res.val.i );
616 617 618 619 620 621 622
  return res.val.i;
}

void
filters_postconfig(void)
{
  struct f_val res;
623
  if (startup_func) {
624
    debug( "Launching startup function...\n" );
625
    f_pool = lp_new(&root_pool, 1024);
626
    res = interpret(startup_func);
Pavel Machek's avatar
Pavel Machek committed
627
    if (res.type == F_ERROR)
628
      die( "Startup function resulted in error." );
629
    debug( "done\n" );
630
  }
631
} 
632 633 634 635

int
filter_same(struct filter *new, struct filter *old)
{
636 637 638 639 640
  if (old == new)	/* Handle FILTER_ACCEPT and FILTER_REJECT */
    return 1;
  if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
      new == FILTER_ACCEPT || new == FILTER_REJECT)
    return 0;
641
  return i_same(new->root, old->root);
642
}
643

Pavel Machek's avatar
Pavel Machek committed
644 645
/* This should end up far away from here!
 */
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
struct adata *
comlist_add(struct linpool *pool, struct adata *list, u32 val)
{
  struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4);
  res->length = list->length+4;
  * (u32 *) res->data = val;
  memcpy((char *) res->data + 4, list->data, list->length);
  return res;
}

struct adata *
comlist_contains(struct adata *list, u32 val)
{
  u32 *l = &(list->data);
  int i;
  for (i=0; i<list->length/4; i++)
    if (*l++ == val)
      return 1;
  return 0;
}

struct adata *
comlist_del(struct linpool *pool, struct adata *list, u32 val)
{
  struct adata *res;
  u32 *l, *k;
  int i;

  if (!comlist_contains(list, val))
    return list;

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

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

  return res;
}

struct adata *
690
adata_empty(struct linpool *pool)
691 692 693 694 695
{
  struct adata *res = lp_alloc(pool, sizeof(struct adata));
  res->length = 0;
  return res;
}