1 /*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "config.h"
10
11 #include "dfvm.h"
12
13 #include <ftypes/ftypes-int.h>
14 #include <wsutil/ws_assert.h>
15
16 dfvm_insn_t*
dfvm_insn_new(dfvm_opcode_t op)17 dfvm_insn_new(dfvm_opcode_t op)
18 {
19 dfvm_insn_t *insn;
20
21 insn = g_new(dfvm_insn_t, 1);
22 insn->op = op;
23 insn->arg1 = NULL;
24 insn->arg2 = NULL;
25 insn->arg3 = NULL;
26 insn->arg4 = NULL;
27 return insn;
28 }
29
30 static void
dfvm_value_free(dfvm_value_t * v)31 dfvm_value_free(dfvm_value_t *v)
32 {
33 switch (v->type) {
34 case FVALUE:
35 FVALUE_FREE(v->value.fvalue);
36 break;
37 case DRANGE:
38 drange_free(v->value.drange);
39 break;
40 case PCRE:
41 g_regex_unref(v->value.pcre);
42 break;
43 default:
44 /* nothing */
45 ;
46 }
47 g_free(v);
48 }
49
50 void
dfvm_insn_free(dfvm_insn_t * insn)51 dfvm_insn_free(dfvm_insn_t *insn)
52 {
53 if (insn->arg1) {
54 dfvm_value_free(insn->arg1);
55 }
56 if (insn->arg2) {
57 dfvm_value_free(insn->arg2);
58 }
59 if (insn->arg3) {
60 dfvm_value_free(insn->arg3);
61 }
62 if (insn->arg4) {
63 dfvm_value_free(insn->arg4);
64 }
65 g_free(insn);
66 }
67
68
69 dfvm_value_t*
dfvm_value_new(dfvm_value_type_t type)70 dfvm_value_new(dfvm_value_type_t type)
71 {
72 dfvm_value_t *v;
73
74 v = g_new(dfvm_value_t, 1);
75 v->type = type;
76 return v;
77 }
78
79
80 void
dfvm_dump(FILE * f,dfilter_t * df)81 dfvm_dump(FILE *f, dfilter_t *df)
82 {
83 int id, length;
84 dfvm_insn_t *insn;
85 dfvm_value_t *arg1;
86 dfvm_value_t *arg2;
87 dfvm_value_t *arg3;
88 dfvm_value_t *arg4;
89 char *value_str;
90 GSList *range_list;
91 drange_node *range_item;
92
93 /* First dump the constant initializations */
94 fprintf(f, "Constants:\n");
95 length = df->consts->len;
96 for (id = 0; id < length; id++) {
97
98 insn = (dfvm_insn_t *)g_ptr_array_index(df->consts, id);
99 arg1 = insn->arg1;
100 arg2 = insn->arg2;
101
102 switch (insn->op) {
103 case PUT_FVALUE:
104 value_str = fvalue_to_string_repr(NULL, arg1->value.fvalue,
105 FTREPR_DFILTER, BASE_NONE);
106 fprintf(f, "%05d PUT_FVALUE\t%s <%s> -> reg#%u\n",
107 id, value_str,
108 fvalue_type_name(arg1->value.fvalue),
109 arg2->value.numeric);
110 wmem_free(NULL, value_str);
111 break;
112 case PUT_PCRE:
113 fprintf(f, "%05d PUT_PCRE\t%s -> reg#%u\n",
114 id,
115 g_regex_get_pattern(arg1->value.pcre),
116 arg2->value.numeric);
117 break;
118 case CHECK_EXISTS:
119 case READ_TREE:
120 case CALL_FUNCTION:
121 case MK_RANGE:
122 case ANY_EQ:
123 case ALL_NE:
124 case ANY_NE:
125 case ANY_GT:
126 case ANY_GE:
127 case ANY_LT:
128 case ANY_LE:
129 case ANY_BITWISE_AND:
130 case ANY_CONTAINS:
131 case ANY_MATCHES:
132 case ANY_IN_RANGE:
133 case NOT:
134 case RETURN:
135 case IF_TRUE_GOTO:
136 case IF_FALSE_GOTO:
137 default:
138 ws_assert_not_reached();
139 break;
140 }
141 }
142
143 fprintf(f, "\nInstructions:\n");
144 /* Now dump the operations */
145 length = df->insns->len;
146 for (id = 0; id < length; id++) {
147
148 insn = (dfvm_insn_t *)g_ptr_array_index(df->insns, id);
149 arg1 = insn->arg1;
150 arg2 = insn->arg2;
151 arg3 = insn->arg3;
152 arg4 = insn->arg4;
153
154 switch (insn->op) {
155 case CHECK_EXISTS:
156 fprintf(f, "%05d CHECK_EXISTS\t%s\n",
157 id, arg1->value.hfinfo->abbrev);
158 break;
159
160 case READ_TREE:
161 fprintf(f, "%05d READ_TREE\t\t%s -> reg#%u\n",
162 id, arg1->value.hfinfo->abbrev,
163 arg2->value.numeric);
164 break;
165
166 case CALL_FUNCTION:
167 fprintf(f, "%05d CALL_FUNCTION\t%s (",
168 id, arg1->value.funcdef->name);
169 if (arg3) {
170 fprintf(f, "reg#%u", arg3->value.numeric);
171 }
172 if (arg4) {
173 fprintf(f, ", reg#%u", arg4->value.numeric);
174 }
175 fprintf(f, ") --> reg#%u\n", arg2->value.numeric);
176 break;
177
178 case PUT_FVALUE:
179 /* We already dumped these */
180 ws_assert_not_reached();
181 break;
182
183 case PUT_PCRE:
184 /* We already dumped these */
185 ws_assert_not_reached();
186 break;
187
188 case MK_RANGE:
189 arg3 = insn->arg3;
190 fprintf(f, "%05d MK_RANGE\t\treg#%u[",
191 id,
192 arg1->value.numeric);
193 for (range_list = arg3->value.drange->range_list;
194 range_list != NULL;
195 range_list = range_list->next) {
196 range_item = (drange_node *)range_list->data;
197 switch (range_item->ending) {
198
199 case DRANGE_NODE_END_T_UNINITIALIZED:
200 fprintf(f, "?");
201 break;
202
203 case DRANGE_NODE_END_T_LENGTH:
204 fprintf(f, "%d:%d",
205 range_item->start_offset,
206 range_item->length);
207 break;
208
209 case DRANGE_NODE_END_T_OFFSET:
210 fprintf(f, "%d-%d",
211 range_item->start_offset,
212 range_item->end_offset);
213 break;
214
215 case DRANGE_NODE_END_T_TO_THE_END:
216 fprintf(f, "%d:",
217 range_item->start_offset);
218 break;
219 }
220 if (range_list->next != NULL)
221 fprintf(f, ",");
222 }
223 fprintf(f, "] -> reg#%u\n",
224 arg2->value.numeric);
225 break;
226
227 case ANY_EQ:
228 fprintf(f, "%05d ANY_EQ\t\treg#%u == reg#%u\n",
229 id, arg1->value.numeric, arg2->value.numeric);
230 break;
231
232 case ALL_NE:
233 fprintf(f, "%05d ALL_NE\t\treg#%u == reg#%u\n",
234 id, arg1->value.numeric, arg2->value.numeric);
235 break;
236
237 case ANY_NE:
238 fprintf(f, "%05d ANY_NE\t\treg#%u == reg#%u\n",
239 id, arg1->value.numeric, arg2->value.numeric);
240 break;
241
242 case ANY_GT:
243 fprintf(f, "%05d ANY_GT\t\treg#%u == reg#%u\n",
244 id, arg1->value.numeric, arg2->value.numeric);
245 break;
246
247 case ANY_GE:
248 fprintf(f, "%05d ANY_GE\t\treg#%u == reg#%u\n",
249 id, arg1->value.numeric, arg2->value.numeric);
250 break;
251
252 case ANY_LT:
253 fprintf(f, "%05d ANY_LT\t\treg#%u == reg#%u\n",
254 id, arg1->value.numeric, arg2->value.numeric);
255 break;
256
257 case ANY_LE:
258 fprintf(f, "%05d ANY_LE\t\treg#%u == reg#%u\n",
259 id, arg1->value.numeric, arg2->value.numeric);
260 break;
261
262 case ANY_BITWISE_AND:
263 fprintf(f, "%05d ANY_BITWISE_AND\t\treg#%u == reg#%u\n",
264 id, arg1->value.numeric, arg2->value.numeric);
265 break;
266
267 case ANY_CONTAINS:
268 fprintf(f, "%05d ANY_CONTAINS\treg#%u contains reg#%u\n",
269 id, arg1->value.numeric, arg2->value.numeric);
270 break;
271
272 case ANY_MATCHES:
273 fprintf(f, "%05d ANY_MATCHES\treg#%u matches reg#%u\n",
274 id, arg1->value.numeric, arg2->value.numeric);
275 break;
276
277 case ANY_IN_RANGE:
278 fprintf(f, "%05d ANY_IN_RANGE\treg#%u in range reg#%u,reg#%u\n",
279 id, arg1->value.numeric, arg2->value.numeric,
280 arg3->value.numeric);
281 break;
282
283 case NOT:
284 fprintf(f, "%05d NOT\n", id);
285 break;
286
287 case RETURN:
288 fprintf(f, "%05d RETURN\n", id);
289 break;
290
291 case IF_TRUE_GOTO:
292 fprintf(f, "%05d IF-TRUE-GOTO\t%u\n",
293 id, arg1->value.numeric);
294 break;
295
296 case IF_FALSE_GOTO:
297 fprintf(f, "%05d IF-FALSE-GOTO\t%u\n",
298 id, arg1->value.numeric);
299 break;
300
301 default:
302 ws_assert_not_reached();
303 break;
304 }
305 }
306 }
307
308 /* Reads a field from the proto_tree and loads the fvalues into a register,
309 * if that field has not already been read. */
310 static gboolean
read_tree(dfilter_t * df,proto_tree * tree,header_field_info * hfinfo,int reg)311 read_tree(dfilter_t *df, proto_tree *tree, header_field_info *hfinfo, int reg)
312 {
313 GPtrArray *finfos;
314 field_info *finfo;
315 int i, len;
316 GList *fvalues = NULL;
317 gboolean found_something = FALSE;
318
319 /* Already loaded in this run of the dfilter? */
320 if (df->attempted_load[reg]) {
321 if (df->registers[reg]) {
322 return TRUE;
323 }
324 else {
325 return FALSE;
326 }
327 }
328
329 df->attempted_load[reg] = TRUE;
330
331 while (hfinfo) {
332 finfos = proto_get_finfo_ptr_array(tree, hfinfo->id);
333 if ((finfos == NULL) || (g_ptr_array_len(finfos) == 0)) {
334 hfinfo = hfinfo->same_name_next;
335 continue;
336 }
337 else {
338 found_something = TRUE;
339 }
340
341 len = finfos->len;
342 for (i = 0; i < len; i++) {
343 finfo = (field_info *)g_ptr_array_index(finfos, i);
344 fvalues = g_list_prepend(fvalues, &finfo->value);
345 }
346
347 hfinfo = hfinfo->same_name_next;
348 }
349
350 if (!found_something) {
351 return FALSE;
352 }
353
354 df->registers[reg] = fvalues;
355 // These values are referenced only, do not try to free it later.
356 df->owns_memory[reg] = FALSE;
357 return TRUE;
358 }
359
360
361 /* Put a constant value in a register. These will not be cleared by
362 * free_register_overhead. */
363 static gboolean
put_fvalue(dfilter_t * df,fvalue_t * fv,int reg)364 put_fvalue(dfilter_t *df, fvalue_t *fv, int reg)
365 {
366 df->registers[reg] = g_list_append(NULL, fv);
367 df->owns_memory[reg] = FALSE;
368 return TRUE;
369 }
370
371 /* Put a constant PCRE in a register. These will not be cleared by
372 * free_register_overhead. */
373 static gboolean
put_pcre(dfilter_t * df,GRegex * pcre,int reg)374 put_pcre(dfilter_t *df, GRegex *pcre, int reg)
375 {
376 df->registers[reg] = g_list_append(NULL, pcre);
377 df->owns_memory[reg] = FALSE;
378 return TRUE;
379 }
380
381 enum match_how {
382 MATCH_ANY,
383 MATCH_ALL
384 };
385
386 typedef gboolean (*DFVMMatchFunc)(const fvalue_t*, const fvalue_t*);
387
388 static gboolean
cmp_test(dfilter_t * df,enum match_how how,DFVMMatchFunc match_func,int reg1,int reg2)389 cmp_test(dfilter_t *df, enum match_how how, DFVMMatchFunc match_func, int reg1, int reg2)
390 {
391 GList *list_a, *list_b;
392 gboolean want_all = (how == MATCH_ALL);
393 gboolean want_any = (how == MATCH_ANY);
394 gboolean have_match;
395
396 list_a = df->registers[reg1];
397
398 while (list_a) {
399 list_b = df->registers[reg2];
400 while (list_b) {
401 have_match = match_func(list_a->data, list_b->data);
402 if (want_all && !have_match) {
403 return FALSE;
404 }
405 else if (want_any && have_match) {
406 return TRUE;
407 }
408 list_b = g_list_next(list_b);
409 }
410 list_a = g_list_next(list_a);
411 }
412 /* want_all || !want_any */
413 return want_all;
414 }
415
416 static inline gboolean
any_test(dfilter_t * df,DFVMMatchFunc cmp,int reg1,int reg2)417 any_test(dfilter_t *df, DFVMMatchFunc cmp, int reg1, int reg2)
418 {
419 /* cmp(A) <=> cmp(a1) OR cmp(a2) OR cmp(a3) OR ... */
420 return cmp_test(df, MATCH_ANY, cmp, reg1, reg2);
421 }
422
423 static inline gboolean
all_test(dfilter_t * df,DFVMMatchFunc cmp,int reg1,int reg2)424 all_test(dfilter_t *df, DFVMMatchFunc cmp, int reg1, int reg2)
425 {
426 /* cmp(A) <=> cmp(a1) AND cmp(a2) AND cmp(a3) AND ... */
427 return cmp_test(df, MATCH_ALL, cmp, reg1, reg2);
428 }
429
430 static inline gboolean
any_eq(dfilter_t * df,int reg1,int reg2)431 any_eq(dfilter_t *df, int reg1, int reg2)
432 {
433 /* A any_eq B <=> a1 == b1 OR a2 == b2 OR a3 == b3 OR ... */
434 return any_test(df, fvalue_eq, reg1, reg2);
435 }
436
437 static inline gboolean
any_ne(dfilter_t * df,int reg1,int reg2)438 any_ne(dfilter_t *df, int reg1, int reg2)
439 {
440 /* A any_ne B <=> a1 != b1 OR a2 != b2 OR a3 != b3 OR ... */
441 return any_test(df, fvalue_ne, reg1, reg2);
442 }
443
444 static inline gboolean
all_ne(dfilter_t * df,int reg1,int reg2)445 all_ne(dfilter_t *df, int reg1, int reg2)
446 {
447 /* A all_ne B <=> a1 != b1 AND a2 != b2 AND a3 != b3 AND ... */
448 return all_test(df, fvalue_ne, reg1, reg2);
449 }
450
451 static gboolean
any_matches(dfilter_t * df,int reg1,int reg2)452 any_matches(dfilter_t *df, int reg1, int reg2)
453 {
454 GList *list_a, *list_b;
455
456 list_a = df->registers[reg1];
457
458 while (list_a) {
459 list_b = df->registers[reg2];
460 while (list_b) {
461 if (fvalue_matches((fvalue_t *)list_a->data, (GRegex *)list_b->data)) {
462 return TRUE;
463 }
464 list_b = g_list_next(list_b);
465 }
466 list_a = g_list_next(list_a);
467 }
468 return FALSE;
469 }
470
471 static gboolean
any_in_range(dfilter_t * df,int reg1,int reg2,int reg3)472 any_in_range(dfilter_t *df, int reg1, int reg2, int reg3)
473 {
474 GList *list1, *list_low, *list_high;
475 fvalue_t *low, *high;
476
477 list1 = df->registers[reg1];
478 list_low = df->registers[reg2];
479 list_high = df->registers[reg3];
480
481 /* The first register contains the values associated with a field, the
482 * second and third arguments are expected to be a single value for the
483 * lower and upper bound respectively. These cannot be fields and thus
484 * the list length MUST be one. This should have been enforced by
485 * grammar.lemon.
486 */
487 ws_assert(list_low && !g_list_next(list_low));
488 ws_assert(list_high && !g_list_next(list_high));
489 low = (fvalue_t *)list_low->data;
490 high = (fvalue_t *)list_high->data;
491
492 while (list1) {
493 fvalue_t *value = (fvalue_t *)list1->data;
494 if (fvalue_ge(value, low) && fvalue_le(value, high)) {
495 return TRUE;
496 }
497 list1 = g_list_next(list1);
498 }
499 return FALSE;
500 }
501
502
503 static void
free_owned_register(gpointer data,gpointer user_data _U_)504 free_owned_register(gpointer data, gpointer user_data _U_)
505 {
506 fvalue_t *value = (fvalue_t *)data;
507 FVALUE_FREE(value);
508 }
509
510 /* Clear registers that were populated during evaluation (leaving constants
511 * intact). If we created the values, then these will be freed as well. */
512 static void
free_register_overhead(dfilter_t * df)513 free_register_overhead(dfilter_t* df)
514 {
515 guint i;
516
517 for (i = 0; i < df->num_registers; i++) {
518 df->attempted_load[i] = FALSE;
519 if (df->registers[i]) {
520 if (df->owns_memory[i]) {
521 g_list_foreach(df->registers[i], free_owned_register, NULL);
522 df->owns_memory[i] = FALSE;
523 }
524 g_list_free(df->registers[i]);
525 df->registers[i] = NULL;
526 }
527 }
528 }
529
530 /* Takes the list of fvalue_t's in a register, uses fvalue_slice()
531 * to make a new list of fvalue_t's (which are ranges, or byte-slices),
532 * and puts the new list into a new register. */
533 static void
mk_range(dfilter_t * df,int from_reg,int to_reg,drange_t * d_range)534 mk_range(dfilter_t *df, int from_reg, int to_reg, drange_t *d_range)
535 {
536 GList *from_list, *to_list;
537 fvalue_t *old_fv, *new_fv;
538
539 to_list = NULL;
540 from_list = df->registers[from_reg];
541
542 while (from_list) {
543 old_fv = (fvalue_t*)from_list->data;
544 new_fv = fvalue_slice(old_fv, d_range);
545 /* Assert here because semcheck.c should have
546 * already caught the cases in which a slice
547 * cannot be made. */
548 ws_assert(new_fv);
549 to_list = g_list_append(to_list, new_fv);
550
551 from_list = g_list_next(from_list);
552 }
553
554 df->registers[to_reg] = to_list;
555 df->owns_memory[to_reg] = TRUE;
556 }
557
558
559
560 gboolean
dfvm_apply(dfilter_t * df,proto_tree * tree)561 dfvm_apply(dfilter_t *df, proto_tree *tree)
562 {
563 int id, length;
564 gboolean accum = TRUE;
565 dfvm_insn_t *insn;
566 dfvm_value_t *arg1;
567 dfvm_value_t *arg2;
568 dfvm_value_t *arg3 = NULL;
569 dfvm_value_t *arg4 = NULL;
570 header_field_info *hfinfo;
571 GList *param1;
572 GList *param2;
573
574 ws_assert(tree);
575
576 length = df->insns->len;
577
578 for (id = 0; id < length; id++) {
579
580 AGAIN:
581 insn = (dfvm_insn_t *)g_ptr_array_index(df->insns, id);
582 arg1 = insn->arg1;
583 arg2 = insn->arg2;
584
585 switch (insn->op) {
586 case CHECK_EXISTS:
587 hfinfo = arg1->value.hfinfo;
588 while(hfinfo) {
589 accum = proto_check_for_protocol_or_field(tree,
590 hfinfo->id);
591 if (accum) {
592 break;
593 }
594 else {
595 hfinfo = hfinfo->same_name_next;
596 }
597 }
598 break;
599
600 case READ_TREE:
601 accum = read_tree(df, tree,
602 arg1->value.hfinfo, arg2->value.numeric);
603 break;
604
605 case CALL_FUNCTION:
606 arg3 = insn->arg3;
607 arg4 = insn->arg4;
608 param1 = NULL;
609 param2 = NULL;
610 if (arg3) {
611 param1 = df->registers[arg3->value.numeric];
612 }
613 if (arg4) {
614 param2 = df->registers[arg4->value.numeric];
615 }
616 accum = arg1->value.funcdef->function(param1, param2,
617 &df->registers[arg2->value.numeric]);
618 // functions create a new value, so own it.
619 df->owns_memory[arg2->value.numeric] = TRUE;
620 break;
621
622 case MK_RANGE:
623 arg3 = insn->arg3;
624 mk_range(df,
625 arg1->value.numeric, arg2->value.numeric,
626 arg3->value.drange);
627 break;
628
629 case ANY_EQ:
630 accum = any_eq(df, arg1->value.numeric, arg2->value.numeric);
631 break;
632
633 case ALL_NE:
634 accum = all_ne(df, arg1->value.numeric, arg2->value.numeric);
635 break;
636
637 case ANY_NE:
638 accum = any_ne(df, arg1->value.numeric, arg2->value.numeric);
639 break;
640
641 case ANY_GT:
642 accum = any_test(df, fvalue_gt,
643 arg1->value.numeric, arg2->value.numeric);
644 break;
645
646 case ANY_GE:
647 accum = any_test(df, fvalue_ge,
648 arg1->value.numeric, arg2->value.numeric);
649 break;
650
651 case ANY_LT:
652 accum = any_test(df, fvalue_lt,
653 arg1->value.numeric, arg2->value.numeric);
654 break;
655
656 case ANY_LE:
657 accum = any_test(df, fvalue_le,
658 arg1->value.numeric, arg2->value.numeric);
659 break;
660
661 case ANY_BITWISE_AND:
662 accum = any_test(df, fvalue_bitwise_and,
663 arg1->value.numeric, arg2->value.numeric);
664 break;
665
666 case ANY_CONTAINS:
667 accum = any_test(df, fvalue_contains,
668 arg1->value.numeric, arg2->value.numeric);
669 break;
670
671 case ANY_MATCHES:
672 accum = any_matches(df,
673 arg1->value.numeric, arg2->value.numeric);
674 break;
675
676 case ANY_IN_RANGE:
677 arg3 = insn->arg3;
678 accum = any_in_range(df, arg1->value.numeric,
679 arg2->value.numeric,
680 arg3->value.numeric);
681 break;
682
683 case NOT:
684 accum = !accum;
685 break;
686
687 case RETURN:
688 free_register_overhead(df);
689 return accum;
690
691 case IF_TRUE_GOTO:
692 if (accum) {
693 id = arg1->value.numeric;
694 goto AGAIN;
695 }
696 break;
697
698 case IF_FALSE_GOTO:
699 if (!accum) {
700 id = arg1->value.numeric;
701 goto AGAIN;
702 }
703 break;
704
705 case PUT_FVALUE:
706 #if 0
707 /* These were handled in the constants initialization */
708 accum = put_fvalue(df,
709 arg1->value.fvalue, arg2->value.numeric);
710 break;
711 #endif
712
713 case PUT_PCRE:
714 #if 0
715 /* These were handled in the constants initialization */
716 accum = put_pcre(df,
717 arg1->value.pcre, arg2->value.numeric);
718 break;
719 #endif
720
721 default:
722 ws_assert_not_reached();
723 break;
724 }
725 }
726
727 ws_assert_not_reached();
728 return FALSE; /* to appease the compiler */
729 }
730
731 void
dfvm_init_const(dfilter_t * df)732 dfvm_init_const(dfilter_t *df)
733 {
734 int id, length;
735 dfvm_insn_t *insn;
736 dfvm_value_t *arg1;
737 dfvm_value_t *arg2;
738
739 length = df->consts->len;
740
741 for (id = 0; id < length; id++) {
742
743 insn = (dfvm_insn_t *)g_ptr_array_index(df->consts, id);
744 arg1 = insn->arg1;
745 arg2 = insn->arg2;
746
747 switch (insn->op) {
748 case PUT_FVALUE:
749 put_fvalue(df,
750 arg1->value.fvalue, arg2->value.numeric);
751 break;
752 case PUT_PCRE:
753 put_pcre(df,
754 arg1->value.pcre, arg2->value.numeric);
755 break;
756 case CHECK_EXISTS:
757 case READ_TREE:
758 case CALL_FUNCTION:
759 case MK_RANGE:
760 case ANY_EQ:
761 case ALL_NE:
762 case ANY_NE:
763 case ANY_GT:
764 case ANY_GE:
765 case ANY_LT:
766 case ANY_LE:
767 case ANY_BITWISE_AND:
768 case ANY_CONTAINS:
769 case ANY_MATCHES:
770 case ANY_IN_RANGE:
771 case NOT:
772 case RETURN:
773 case IF_TRUE_GOTO:
774 case IF_FALSE_GOTO:
775 default:
776 ws_assert_not_reached();
777 break;
778 }
779 }
780
781 return;
782 }
783
784 /*
785 * Editor modelines - https://www.wireshark.org/tools/modelines.html
786 *
787 * Local variables:
788 * c-basic-offset: 8
789 * tab-width: 8
790 * indent-tabs-mode: t
791 * End:
792 *
793 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
794 * :indentSize=8:tabSize=8:noTabs=false:
795 */
796