filter.c 17.4 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
static rta *f_rta_copy;
157

158 159 160 161 162 163 164 165 166
#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); \
167
	if (x.type & T_RETURN) \
168 169 170 171 172 173 174 175
		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" );
176

177 178 179 180 181
static struct f_val
interpret(struct f_inst *what)
{
  struct symbol *sym;
  struct f_val v1, v2, res;
182
  int i,j,k;
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 214

  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 */
215 216 217 218 219 220 221 222

#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); \
223
    break;
224

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

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

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

251
  /* Set to indirect value, a1 = variable, a2 = value */
252
  case 's':
Pavel Machek's avatar
Pavel Machek committed
253 254
    ARG(v2, a2.p);
    sym = what->a1.p;
255 256
    switch (res.type = v2.type) {
    case T_VOID: runtime( "Can not assign void values" );
257
    case T_ENUM:
258
    case T_INT: 
259 260 261
    case T_IP: 
    case T_PREFIX: 
    case T_PAIR: 
262 263
    case T_PATH:
    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 273
    }
    break;

274
  case 'c':	/* integer (or simple type) constant */
275
    res.type = what->aux;
276
    res.val.i = what->a2.i;
277
    break;
278 279 280
  case 'C':
    res = * ((struct f_val *) what->a1.p);
    break;
281 282
  case 'p':
    ONEARG;
283
    val_print(v1);
284 285 286 287 288 289
    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
290
      ARG(res,a2.p);
291 292 293 294 295
      res.val.i = 0;
    } else res.val.i = 1;
    res.type = T_BOOL;
    break;
  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

Pavel Machek's avatar
Pavel Machek committed
303
    switch (what->a2.i) {
304 305 306 307 308
    case F_QUITBIRD:
      die( "Filter asked me to die" );
    case F_ACCEPT:
      /* Should take care about turning ACCEPT into MODIFY */
    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 315 316 317 318 319
    case F_NOP:
      break;
    default:
      bug( "unknown return type: can not happen");
    }
    break;
320 321 322
  case 'a':	/* rta access */
    {
      struct rta *rta = (*f_rte)->attrs;
323
      res.type = what->aux;
324 325
      switch(res.type) {
      case T_IP:
326
	res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
327
	break;
328 329 330
      case T_ENUM:
	res.val.i = * ((char *) rta + what->a2.i);
	break;
331 332 333 334 335 336 337
      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:
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 );
Pavel Machek's avatar
Pavel Machek committed
347 348
      if (!e) 
	e = ea_find( (*f_tmp_attrs), what->a2.i );
349
      if ((!e) && (f_flags & FF_FORCE_TMPATTR))
350 351
	e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
      
352 353 354 355
      if (!e) {
	res.type = T_VOID;
	break;
      }
356
      res.type = what->aux;	/* FIXME: should check type? */
Martin Mareš's avatar
Martin Mareš committed
357
      switch (what->aux) {
358 359 360
      case T_INT:
	res.val.i = e->u.data;
	break;
361
      case T_CLIST:
362 363 364
      case T_PATH:
	res.val.ad = e->u.ptr;
	break;
Martin Mareš's avatar
Martin Mareš committed
365 366
      default:
	bug("Unknown type in e,a\n");
367 368
      }
    }
369
    break;
370
  case P('e','S'):
371 372
    ONEARG;
    if (v1.type != what->aux)
373
      runtime("Wrong type when setting dynamic attribute");
374 375 376 377 378 379 380 381

    {
      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
382 383
      l->attrs[0].flags = 0;
      l->attrs[0].type = what->aux | EAF_ORIGINATED;
Pavel Machek's avatar
Pavel Machek committed
384 385 386 387
      switch (what->aux & EAF_TYPE_MASK) {
      case EAF_TYPE_INT:
	if (v1.type != T_INT)
	  runtime( "Setting int attribute to non-int value" );
388 389
	l->attrs[0].u.data = v1.val.i;
	break;
390 391 392 393 394
      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;
395 396 397 398 399
      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
400 401 402
      case EAF_TYPE_UNDEF:
	if (v1.type != T_VOID)
	  runtime( "Setting void attribute to non-void value" );
403 404
	l->attrs[0].u.data = 0;
	break;
405
      }
Pavel Machek's avatar
Pavel Machek committed
406

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

424 425 426 427 428 429 430 431 432
  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;
433
  case P('c','p'):	/* Convert prefix to ... */
434 435 436
    ONEARG;
    if (v1.type != T_PREFIX)
      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 445 446 447 448 449
  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  */
450 451
    ONEARG;
    res = interpret(what->a2.p);
452 453 454
    if (res.type == T_RETURN)
      return res;
    res.type &= ~T_RETURN;    
455
    break;
456
  case P('S','W'):
457
    ONEARG;
Pavel Machek's avatar
Pavel Machek committed
458 459 460 461 462 463
    {
      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) {
464
	  debug( "No else statement?\n ");
Pavel Machek's avatar
Pavel Machek committed
465 466 467 468
	  break;
	}
      }	
      if (!t->data)
469
	bug( "Impossible: no code associated!" );
Pavel Machek's avatar
Pavel Machek committed
470 471
      return interpret(t->data);
    }
472
    break;
473
  case P('i','M'): /* IP.MASK(val) */
474 475 476 477 478 479 480 481 482 483
    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);
    }
484
    break;
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500

  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;

501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
  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;

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

524
#undef ARG
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
#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;
540 541
  if (!f1)
    return 1;
542 543 544 545
  if (f1->aux != f2->aux)
    return 0;
  if (f1->code != f2->code)
    return 0;
546 547
  if (f1 == f2)		/* It looks strange, but it is possible with call rewriting trickery */
    return 1;
548 549 550 551 552

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

Pavel Machek's avatar
Pavel Machek committed
558
  case '!': ONEARG; break;
559
  case '~': TWOARGS; break;
560
  case P('d','e'): ONEARG; break;
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579

  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;
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 586
  case P('e','a'): A2_SAME; break;
  case P('e','S'): ONEARG; A2_SAME; break;
587

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

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

613
  f_flags = flags;
Pavel Machek's avatar
Pavel Machek committed
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 620 621 622
  inst = filter->root;
  res = interpret(inst);
  if (res.type != T_RETURN)
    return F_ERROR;
623
  DBG( "done (%d)\n", res.val.i );
624 625 626 627 628 629 630
  return res.val.i;
}

void
filters_postconfig(void)
{
  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);
Pavel Machek's avatar
Pavel Machek committed
635
    if (res.type == F_ERROR)
636
      die( "Startup function resulted in error." );
637
    debug( "done\n" );
638
  }
639
} 
640 641 642 643

int
filter_same(struct filter *new, struct filter *old)
{
644 645 646 647 648
  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;
649
  return i_same(new->root, old->root);
650
}
651

Pavel Machek's avatar
Pavel Machek committed
652 653
/* This should end up far away from here!
 */
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 690 691 692 693 694 695 696 697
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 *
698
adata_empty(struct linpool *pool)
699 700 701 702 703
{
  struct adata *res = lp_alloc(pool, sizeof(struct adata));
  res->length = 0;
  return res;
}