]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
Send and receive communities.
[thirdparty/bird.git] / filter / filter.c
CommitLineData
23b1539b
PM
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.
29818140 7 *
720d911d 8 * Notice that pair is stored as integer: first << 16 | second
2f702671 9 *
23b1539b
PM
10 */
11
78c6217c 12#define LOCAL_DEBUG
6b9fa320 13
23b1539b
PM
14#include "nest/bird.h"
15#include "lib/lists.h"
16#include "lib/resource.h"
17#include "lib/socket.h"
38506f71 18#include "lib/string.h"
7f77e250 19#include "lib/unaligned.h"
23b1539b
PM
20#include "nest/route.h"
21#include "nest/protocol.h"
22#include "nest/iface.h"
23#include "conf/conf.h"
24#include "filter/filter.h"
25
2d496d20
PM
26#define P(a,b) ((a<<8) | b)
27
23b1539b
PM
28struct f_inst *startup_func = NULL;
29
38506f71
PM
30#define CMP_ERROR 999
31
32/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
33int
34val_compare(struct f_val v1, struct f_val v2)
35{
41be4444
PM
36 if ((v1.type == T_VOID) && (v2.type == T_VOID))
37 return 0;
38 if (v1.type == T_VOID) /* Hack for else */
39 return -1;
40 if (v2.type == T_VOID)
41 return 1;
42
7db7b7db
PM
43 if (v1.type != v2.type)
44 return CMP_ERROR;
38506f71 45 switch (v1.type) {
f4536657 46 case T_ENUM:
38506f71 47 case T_INT:
d3dd620b 48 case T_PAIR:
38506f71
PM
49 if (v1.val.i == v2.val.i) return 0;
50 if (v1.val.i < v2.val.i) return -1;
51 return 1;
43fc099b 52 case T_IP:
6dc7a0cb
PM
53 case T_PREFIX:
54 return ipa_compare(v1.val.px.ip, v2.val.px.ip);
3076b5ae
MM
55 default:
56 return CMP_ERROR;
38506f71
PM
57 }
58}
59
6dc7a0cb
PM
60int
61val_simple_in_range(struct f_val v1, struct f_val v2)
62{
10a53608 63 if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
2803c9dd 64 return path_match(v1.val.ad->data, v1.val.ad->length, v2.val.path_mask);
10a53608 65
6dc7a0cb
PM
66 if ((v1.type == T_IP) && (v2.type == T_PREFIX))
67 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))));
68
69 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
70 ip_addr mask;
71 if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
72 return CMP_ERROR;
73 mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
74 if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
75 return 0;
8f013d9c 76
6dc7a0cb
PM
77 if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
78 return 0;
79 if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
80 return 0;
81 if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
82 || (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
83 return 0;
84 return 1;
85 }
86 return CMP_ERROR;
87}
88
7db7b7db
PM
89int
90val_in_range(struct f_val v1, struct f_val v2)
91{
6dc7a0cb
PM
92 int res;
93
94 res = val_simple_in_range(v1, v2);
95
96 if (res != CMP_ERROR)
97 return res;
98
2f702671 99 if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
6dc7a0cb
PM
100 struct f_tree *n;
101 n = find_tree(v2.val.t, v1);
102 if (!n)
103 return 0;
104 return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
105 }
7db7b7db
PM
106 return CMP_ERROR;
107}
108
38506f71
PM
109static void
110tree_print(struct f_tree *t)
111{
112 if (!t) {
3cf4a2e2 113 debug( "() " );
38506f71
PM
114 return;
115 }
3cf4a2e2 116 debug( "[ " );
38506f71 117 tree_print( t->left );
3cf4a2e2 118 debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " );
38506f71 119 tree_print( t->right );
3cf4a2e2 120 debug( "] " );
38506f71
PM
121}
122
123void
124val_print(struct f_val v)
125{
126 char buf[2048];
127#define PRINTF(a...) bsnprintf( buf, 2040, a )
128 buf[0] = 0;
129 switch (v.type) {
130 case T_VOID: PRINTF( "(void)" ); break;
131 case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
132 case T_INT: PRINTF( "%d ", v.val.i ); break;
133 case T_STRING: PRINTF( "%s", v.val.s ); break;
6dc7a0cb 134 case T_IP: PRINTF( "%I", v.val.px.ip ); break;
720d911d
PM
135 case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
136 case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
38506f71 137 case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
346a12c2 138 case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
2803c9dd 139 case T_PATH: PRINTF( "%s", path_format(v.val.ad->data, v.val.ad->length)); break;
dcab7890 140 case T_PATH_MASK: debug( "(path " ); { struct f_path_mask *p = v.val.s; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break;
38506f71 141 default: PRINTF( "[unknown type %x]", v.type );
7f77e250 142#undef PRINTF
38506f71 143 }
3cf4a2e2 144 debug( buf );
38506f71
PM
145}
146
48f9e019 147static struct rte **f_rte, *f_rte_old;
f31156ca 148static struct linpool *f_pool;
31e79264 149static struct ea_list **f_tmp_attrs;
0a06a9b8 150static int f_flags;
36bbfc70 151
9a4037d4
PM
152#define runtime(x) do { \
153 log( L_ERR x ); \
154 res.type = T_RETURN; \
155 res.val.i = F_ERROR; \
156 return res; \
157 } while(0)
158
159#define ARG(x,y) \
160 x = interpret(what->y); \
2d496d20 161 if (x.type & T_RETURN) \
9a4037d4
PM
162 return x;
163
164#define ONEARG ARG(v1, a1.p)
165#define TWOARGS ARG(v1, a1.p) \
166 ARG(v2, a2.p)
167#define TWOARGS_C TWOARGS \
168 if (v1.type != v2.type) \
169 runtime( "Can not operate with values of incompatible types" );
7db7b7db 170
23b1539b
PM
171static struct f_val
172interpret(struct f_inst *what)
173{
174 struct symbol *sym;
175 struct f_val v1, v2, res;
38506f71 176 int i,j,k;
23b1539b
PM
177
178 res.type = T_VOID;
179 if (!what)
180 return res;
181
182 switch(what->code) {
183 case ',':
184 TWOARGS;
185 break;
186
187/* Binary operators */
188 case '+':
189 TWOARGS_C;
190 switch (res.type = v1.type) {
191 case T_VOID: runtime( "Can not operate with values of type void" );
192 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
193 default: runtime( "Usage of unknown type" );
194 }
195 break;
196 case '/':
197 TWOARGS_C;
198 switch (res.type = v1.type) {
199 case T_VOID: runtime( "Can not operate with values of type void" );
200 case T_INT: res.val.i = v1.val.i / v2.val.i; break;
201 case T_IP: if (v2.type != T_INT)
202 runtime( "Operator / is <ip>/<int>" );
203 break;
204 default: runtime( "Usage of unknown type" );
205 }
206 break;
207
208/* Relational operators */
38506f71
PM
209
210#define COMPARE(x) \
211 TWOARGS_C; \
212 res.type = T_BOOL; \
213 i = val_compare(v1, v2); \
214 if (i==CMP_ERROR) \
215 runtime( "Error in comparation" ); \
216 res.val.i = (x); \
23b1539b 217 break;
38506f71 218
2d496d20
PM
219 case P('!','='): COMPARE(i!=0);
220 case P('=','='): COMPARE(i==0);
38506f71 221 case '<': COMPARE(i==-1);
2d496d20 222 case P('<','='): COMPARE(i!=1);
38506f71 223
995e5894
PM
224 case '!':
225 ONEARG;
226 if (v1.type != T_BOOL)
227 runtime( "not applied to non-boolean" );
228 res = v1;
229 res.val.i = !res.val.i;
230 break;
231
38506f71
PM
232 case '~':
233 TWOARGS;
23b1539b 234 res.type = T_BOOL;
7db7b7db
PM
235 res.val.i = val_in_range(v1, v2);
236 if (res.val.i == CMP_ERROR)
237 runtime( "~ applied on unknown type pair" );
23b1539b 238 break;
2d496d20 239 case P('d','e'):
f4536657
PM
240 ONEARG;
241 res.type = T_BOOL;
242 res.val.i = (v1.type != T_VOID);
243 break;
23b1539b 244
d3dd620b 245 /* Set to indirect value, a1 = variable, a2 = value */
23b1539b 246 case 's':
2db3b288
PM
247 ARG(v2, a2.p);
248 sym = what->a1.p;
23b1539b
PM
249 switch (res.type = v2.type) {
250 case T_VOID: runtime( "Can not assign void values" );
f4536657 251 case T_ENUM:
23b1539b 252 case T_INT:
d3dd620b
PM
253 case T_IP:
254 case T_PREFIX:
255 case T_PAIR:
dcab7890 256 case T_PATH_MASK:
d3dd620b 257 if (sym->class != (SYM_VARIABLE | v2.type))
23b1539b 258 runtime( "Variable of bad type" );
d3dd620b 259 * (struct f_val *) sym->aux2 = v2;
23b1539b 260 break;
d3dd620b 261 default:
3076b5ae 262 bug( "Set to invalid type" );
23b1539b
PM
263 }
264 break;
265
d3dd620b 266 case 'c': /* integer (or simple type) constant */
c7b43f33 267 res.type = what->aux;
d3dd620b 268 res.val.i = what->a2.i;
23b1539b 269 break;
38506f71
PM
270 case 'C':
271 res = * ((struct f_val *) what->a1.p);
272 break;
23b1539b
PM
273 case 'p':
274 ONEARG;
38506f71 275 val_print(v1);
23b1539b
PM
276 break;
277 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
278 ONEARG;
279 if (v1.type != T_BOOL)
280 runtime( "If requires bool expression" );
281 if (v1.val.i) {
2db3b288 282 ARG(res,a2.p);
23b1539b
PM
283 res.val.i = 0;
284 } else res.val.i = 1;
285 res.type = T_BOOL;
286 break;
287 case '0':
3cf4a2e2 288 debug( "No operation\n" );
23b1539b 289 break;
2d496d20 290 case P('p',','):
23b1539b 291 ONEARG;
798df5b1 292 if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
3cf4a2e2 293 debug( "\n" );
23b1539b 294
2db3b288 295 switch (what->a2.i) {
23b1539b
PM
296 case F_QUITBIRD:
297 die( "Filter asked me to die" );
298 case F_ACCEPT:
299 /* Should take care about turning ACCEPT into MODIFY */
300 case F_ERROR:
2ad6dcdb 301 case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
23b1539b 302 res.type = T_RETURN;
2ad6dcdb 303 res.val.i = what->a2.i;
7e1f9971 304 return res; /* We have to return now, no more processing. */
d3dd620b 305 case F_NONL:
23b1539b
PM
306 case F_NOP:
307 break;
308 default:
309 bug( "unknown return type: can not happen");
310 }
311 break;
36bbfc70
PM
312 case 'a': /* rta access */
313 {
314 struct rta *rta = (*f_rte)->attrs;
c7b43f33 315 res.type = what->aux;
36bbfc70
PM
316 switch(res.type) {
317 case T_IP:
6dc7a0cb 318 res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
36bbfc70 319 break;
c7b43f33
PM
320 case T_ENUM:
321 res.val.i = * ((char *) rta + what->a2.i);
322 break;
36bbfc70
PM
323 case T_PREFIX: /* Warning: this works only for prefix of network */
324 {
325 res.val.px.ip = (*f_rte)->net->n.prefix;
326 res.val.px.len = (*f_rte)->net->n.pxlen;
327 break;
328 }
329 default:
3076b5ae 330 bug( "Invalid type for rta access (%x)", res.type );
36bbfc70
PM
331 }
332 }
333 break;
2d496d20 334 case P('e','a'): /* Access to extended attributes */
91447965 335 {
0a06a9b8 336 eattr *e = NULL;
3076b5ae 337 if (!(f_flags & FF_FORCE_TMPATTR))
0a06a9b8 338 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
31e79264
PM
339 if (!e)
340 e = ea_find( (*f_tmp_attrs), what->a2.i );
3076b5ae 341 if ((!e) && (f_flags & FF_FORCE_TMPATTR))
0a06a9b8
PM
342 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
343
91447965
PM
344 if (!e) {
345 res.type = T_VOID;
346 break;
347 }
10a53608 348 res.type = what->aux; /* FIXME: should check type? */
2803c9dd 349 switch (what->aux) {
91447965
PM
350 case T_INT:
351 res.val.i = e->u.data;
352 break;
10a53608
PM
353 case T_PATH:
354 res.val.ad = e->u.ptr;
355 break;
2803c9dd
MM
356 default:
357 bug("Unknown type in e,a\n");
91447965
PM
358 }
359 }
6dc7a0cb 360 break;
2d496d20 361 case P('e','S'):
f31156ca
PM
362 ONEARG;
363 if (v1.type != what->aux)
3076b5ae 364 runtime("Wrong type when setting dynamic attribute");
f31156ca 365
f31156ca
PM
366 {
367 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
368
369 l->next = NULL;
370 l->flags = EALF_SORTED;
371 l->count = 1;
372 l->attrs[0].id = what->a2.i;
373 l->attrs[0].flags = 0;
31e79264
PM
374 l->attrs[0].type = what->aux;
375 switch (what->aux & EAF_TYPE_MASK) {
376 case EAF_TYPE_INT:
377 if (v1.type != T_INT)
378 runtime( "Setting int attribute to non-int value" );
f31156ca
PM
379 l->attrs[0].u.data = v1.val.i;
380 break;
10a53608
PM
381 case EAF_TYPE_AS_PATH:
382 if (v1.type != T_PATH)
383 runtime( "Setting path attribute to non-path value" );
384 l->attrs[0].u.ptr = v1.val.ad;
385 break;
31e79264
PM
386 case EAF_TYPE_UNDEF:
387 if (v1.type != T_VOID)
388 runtime( "Setting void attribute to non-void value" );
48f9e019
PM
389 l->attrs[0].u.data = 0;
390 break;
f31156ca 391 }
31e79264 392
3076b5ae
MM
393 if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
394 *f_rte = rte_cow(*f_rte);
31e79264
PM
395 l->next = (*f_rte)->attrs->eattrs;
396 (*f_rte)->attrs->eattrs = l;
397 } else {
398 l->next = (*f_tmp_attrs);
399 (*f_tmp_attrs) = l;
400 }
f31156ca 401 }
f31156ca 402 break;
48f9e019 403
2d496d20 404 case P('c','p'): /* Convert prefix to ... */
36bbfc70
PM
405 ONEARG;
406 if (v1.type != T_PREFIX)
407 runtime( "Can not convert non-prefix this way" );
c7b43f33 408 res.type = what->aux;
36bbfc70
PM
409 switch(res.type) {
410 case T_INT: res.val.i = v1.val.px.len; break;
6dc7a0cb 411 case T_IP: res.val.px.ip = v1.val.px.ip; break;
3076b5ae 412 default: bug( "Unknown prefix to conversion" );
36bbfc70
PM
413 }
414 break;
2d496d20
PM
415 case 'r':
416 ONEARG;
417 res = v1;
418 res.type |= T_RETURN;
419 break;
420 case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */
6542ece9
PM
421 ONEARG;
422 res = interpret(what->a2.p);
2d496d20
PM
423 if (res.type == T_RETURN)
424 return res;
425 res.type &= ~T_RETURN;
6542ece9 426 break;
2d496d20 427 case P('S','W'):
7db7b7db 428 ONEARG;
41be4444
PM
429 {
430 struct f_tree *t = find_tree(what->a2.p, v1);
431 if (!t) {
432 v1.type = T_VOID;
433 t = find_tree(what->a2.p, v1);
434 if (!t) {
3cf4a2e2 435 debug( "No else statement?\n ");
41be4444
PM
436 break;
437 }
438 }
439 if (!t->data)
3076b5ae 440 bug( "Impossible: no code associated!" );
41be4444
PM
441 return interpret(t->data);
442 }
7db7b7db 443 break;
2d496d20 444 case P('i','M'): /* IP.MASK(val) */
f4536657
PM
445 TWOARGS;
446 if (v2.type != T_INT)
447 runtime( "Can not use this type for mask.");
448 if (v1.type != T_IP)
449 runtime( "You can mask only IP addresses." );
450 {
451 ip_addr mask = ipa_mkmask(v2.val.i);
452 res.type = T_IP;
453 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
454 }
d3dd620b 455 break;
afc54517
PM
456
457 case 'E': /* Create empty attribute */
458 res.type = what->aux;
459 res.val.ad = adata_empty(f_pool);
460 break;
461 case P('A','p'): /* Path prepend */
462 TWOARGS;
463 if (v1.type != T_PATH)
464 runtime("Can't prepend to non-path");
465 if (v2.type != T_INT)
466 runtime("Can't prepend non-integer");
467
468 res.type = T_PATH;
469 res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
470 break;
471
23b1539b
PM
472 default:
473 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
474 }
475 if (what->next)
476 return interpret(what->next);
477 return res;
478}
479
2d496d20 480#undef ARG
9a4037d4
PM
481#define ARG(x,y) \
482 if (!i_same(f1->y, f2->y)) \
483 return 0;
484
485#define ONEARG ARG(v1, a1.p)
486#define TWOARGS ARG(v1, a1.p) \
487 ARG(v2, a2.p)
488
489#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
490
491int
492i_same(struct f_inst *f1, struct f_inst *f2)
493{
9a4037d4
PM
494 if ((!!f1) != (!!f2))
495 return 0;
d4d75628
PM
496 if (!f1)
497 return 1;
9a4037d4
PM
498 if (f1->aux != f2->aux)
499 return 0;
500 if (f1->code != f2->code)
501 return 0;
d4d75628
PM
502 if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
503 return 1;
9a4037d4
PM
504
505 switch(f1->code) {
506 case ',': /* fall through */
507 case '+':
508 case '/':
2d496d20
PM
509 case P('!','='):
510 case P('=','='):
9a4037d4 511 case '<':
2d496d20 512 case P('<','='): TWOARGS; break;
9a4037d4 513
995e5894 514 case '!': ONEARG; break;
9a4037d4 515 case '~': TWOARGS; break;
2d496d20 516 case P('d','e'): ONEARG; break;
9a4037d4
PM
517
518 case 's':
519 ARG(v2, a2.p);
520 {
521 struct symbol *s1, *s2;
522 s1 = f1->a1.p;
523 s2 = f2->a1.p;
524 if (strcmp(s1->name, s2->name))
525 return 0;
526 if (s1->class != s2->class)
527 return 0;
528 }
529 break;
530
531 case 'c': A2_SAME; break;
532 case 'C':
533 if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a2.p))
534 return 0;
535 break;
536 case 'p': ONEARG; break;
537 case '?': TWOARGS; break;
afc54517 538 case '0': case 'E': break;
2d496d20 539 case P('p',','): ONEARG; A2_SAME; break;
9a4037d4 540 case 'a': A2_SAME; break;
2d496d20
PM
541 case P('e','a'): A2_SAME; break;
542 case P('e','S'): ONEARG; A2_SAME; break;
9a4037d4 543
2d496d20
PM
544 case 'r': ONEARG; break;
545 case P('c','p'): ONEARG; break;
d4d75628
PM
546 case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
547 ONEARG;
548 if (!i_same(f1->a2.p, f2->a2.p))
549 return 0;
550 f2->a2.p = f1->a2.p;
551 break;
2d496d20
PM
552 case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
553 case P('i','M'): TWOARGS; break;
afc54517 554 case P('A','p'): TWOARGS; break;
9a4037d4
PM
555 default:
556 bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
557 }
558 return i_same(f1->next, f2->next);
559}
560
23b1539b 561int
0a06a9b8 562f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
23b1539b
PM
563{
564 struct f_inst *inst;
565 struct f_val res;
6b9fa320 566 DBG( "Running filter `%s'...", filter->name );
23b1539b 567
0a06a9b8 568 f_flags = flags;
31e79264 569 f_tmp_attrs = tmp_attrs;
36bbfc70 570 f_rte = rte;
48f9e019 571 f_rte_old = *rte;
f31156ca 572 f_pool = tmp_pool;
23b1539b
PM
573 inst = filter->root;
574 res = interpret(inst);
575 if (res.type != T_RETURN)
576 return F_ERROR;
6b9fa320 577 DBG( "done (%d)\n", res.val.i );
23b1539b
PM
578 return res.val.i;
579}
580
23b1539b
PM
581void
582filters_postconfig(void)
583{
584 struct f_val res;
8ba2cc06 585 if (startup_func) {
3cf4a2e2 586 debug( "Launching startup function...\n" );
23b1539b 587 res = interpret(startup_func);
bad631e0 588 if (res.type == F_ERROR)
8ba2cc06 589 die( "Startup function resulted in error." );
3cf4a2e2 590 debug( "done\n" );
8ba2cc06 591 }
7f77e250 592 self_test();
23b1539b 593}
30a6108c
MM
594
595int
596filter_same(struct filter *new, struct filter *old)
597{
81ce667b
MM
598 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
599 return 1;
600 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
601 new == FILTER_ACCEPT || new == FILTER_REJECT)
602 return 0;
9a4037d4 603 return i_same(new->root, old->root);
30a6108c 604}
7f77e250 605
9196e9f8
PM
606/* This should end up far away from here!
607 *
608 * FIXME: It should take struct adata *, not u8 * + length; but that makes it a little more difficult to test.
609 * Or maybe both versions are usefull?
610 */
7f77e250
PM
611
612int
613path_getlen(u8 *p, int len)
614{
615 int res = 0;
616 u8 *q = p+len;
617 while (p<q) {
618 switch (*p++) {
619 case 1: len = *p++; res++; p += 2*len; break;
620 case 2: len = *p++; res+=len; p += 2*len; break;
621 default: bug("This should not be in path");
622 }
623 }
624 return res;
625}
626
627
78c6217c 628#define PRINTF(a...) { int l; bsnprintf( s, bigbuf+4090-s, a ); s += strlen(s); }
7f77e250
PM
629#define COMMA if (first) first = 0; else PRINTF( ", " );
630char *
631path_format(u8 *p, int len)
632{
633 char bigbuf[4096]; /* Keep it smaller than buf */
78c6217c 634 char *s = bigbuf;
7f77e250
PM
635 int first = 1;
636 int i;
637 u8 *q = p+len;
7f77e250
PM
638 while (p<q) {
639 switch (*p++) {
640 case 1: /* This is a set */
641 len = *p++;
642 COMMA;
78c6217c 643 PRINTF( "{" );
7f77e250
PM
644 {
645 int first = 1;
646 for (i=0; i<len; i++) {
647 COMMA;
648 PRINTF( "%d", get_u16(p));
649 p+=2;
650 }
651 }
78c6217c 652 PRINTF( "}" );
7f77e250
PM
653 break;
654
655 case 2: /* This is a sequence */
656 len = *p++;
657 for (i=0; i<len; i++) {
658 int l;
659 COMMA;
660 PRINTF( "%d", get_u16(p));
661 p+=2;
662 }
663 break;
664
665 default:
666 bug("This should not be in path");
667 }
668 }
2803c9dd 669 return strdup(bigbuf); /* FIXME: who frees this? */
7f77e250
PM
670}
671#undef PRINTF
672#undef COMMA
673
674#define PM_END -1
675#define PM_ASTERIX -2
676
dcab7890
PM
677#define MASK_PLUS do { mask = mask->next; if (mask->val == PM_END) return next == q; \
678 asterix = (mask->val == PM_ASTERIX); \
7f77e250 679 printf( "Asterix now %d\n", asterix ); \
dcab7890 680 if (asterix) { mask = mask->next; if (mask->val == PM_END) { printf( "Quick exit\n" ); return 1; } } \
7f77e250 681 } while(0)
dcab7890 682
7f77e250 683int
dcab7890 684path_match(u8 *p, int len, struct f_path_mask *mask)
7f77e250
PM
685{
686 int i;
687 int asterix = 0;
688 u8 *q = p+len;
689 u8 *next;
690
691 while (p<q) {
692 switch (*p++) {
693 case 1: /* This is a set */
694 len = *p++;
695 {
696 u8 *p_save = p;
697 next = p_save + 2*len;
698 retry:
699 p = p_save;
700 for (i=0; i<len; i++) {
dcab7890 701 if (asterix && (get_u16(p) == mask->val)) {
7f77e250
PM
702 MASK_PLUS;
703 goto retry;
704 }
dcab7890 705 if (!asterix && (get_u16(p) == mask->val)) {
7f77e250
PM
706 p = next;
707 MASK_PLUS;
708 goto okay;
709 }
710 p+=2;
711 }
712 if (!asterix)
713 return 0;
714 okay:
715 }
716 break;
717
718 case 2: /* This is a sequence */
719 len = *p++;
720 for (i=0; i<len; i++) {
721 next = p+2;
dcab7890 722 if (asterix && (get_u16(p) == mask->val))
7f77e250
PM
723 MASK_PLUS;
724 else if (!asterix) {
dcab7890 725 if (get_u16(p) != mask->val)
7f77e250
PM
726 return 0;
727 MASK_PLUS;
728 }
729 p+=2;
730 }
731 break;
732
733 default:
734 bug("This should not be in path");
735 }
736 }
737 return 0;
738}
739
740struct adata *
741comlist_add(struct linpool *pool, struct adata *list, u32 val)
742{
743 struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4);
744 res->length = list->length+4;
745 * (u32 *) res->data = val;
746 memcpy((char *) res->data + 4, list->data, list->length);
747 return res;
748}
749
750struct adata *
751comlist_contains(struct adata *list, u32 val)
752{
753 u32 *l = &(list->data);
754 int i;
755 for (i=0; i<list->length/4; i++)
756 if (*l++ == val)
757 return 1;
758 return 0;
759}
760
761struct adata *
762comlist_del(struct linpool *pool, struct adata *list, u32 val)
763{
764 struct adata *res;
765 u32 *l, *k;
766 int i;
767
768 if (!comlist_contains(list, val))
769 return list;
770
771 res = lp_alloc(pool, list->length + sizeof(struct adata) - 4);
772 res->length = list->length-4;
773
774 l = &(list->data);
775 k = &(res->data);
776 for (i=0; i<list->length/4; i++)
777 if (l[i] != val)
778 *k++ = l[i];
779
780 return res;
781}
782
783struct adata *
0a40e973 784adata_empty(struct linpool *pool)
7f77e250
PM
785{
786 struct adata *res = lp_alloc(pool, sizeof(struct adata));
787 res->length = 0;
788 return res;
789}
790
791void
792self_test(void)
793{
794 char path1[] = { 2, 5, 0, 5, 0, 4, 0, 3, 0, 2, 0, 1 };
795 char path2[] = { 2, 5, 0, 5, 0, 4, 0, 3, 0, 2, 0, 1, 1, 5, 0, 5, 0, 4, 0, 3, 0, 2, 0, 1 };
796 s32 match[] = { 5, PM_ASTERIX, 2, PM_ASTERIX, 1, 3, PM_END };
797
798 DBG( "Filters self-testing:\n" );
799 DBG( "%s\n", path_format(path1, sizeof(path1)) );
800 DBG( "%s\n", path_format(path2, sizeof(path2)) );
801 DBG( "5, 6 = %d, %d\n", path_getlen(path1, sizeof(path1)), path_getlen(path2, sizeof(path2)) );
dcab7890
PM
802// DBG( "%d\n", path_match(path1, sizeof(path1), match));
803// DBG( "%d\n", path_match(path2, sizeof(path2), match));
7f77e250
PM
804// die( "okay" );
805}