]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/net_filter.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / osfmk / i386 / net_filter.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1993 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56
57 #include <kern/zalloc.h>
58
59 #define NET_REG_EAX 0 /* data segment register */
60 #define NET_REG_EDX 1 /* header segment register */
61 #define NET_REG_EBX 2 /* free register */
62 #define NET_REG_ESI 3 /* free register */
63 #define NET_REG_EDI 4 /* free register */
64 #define NET_REG_MAX 5 /* number of available registers */
65
66 struct net_opt {
67 filter_t val; /* value */
68 unsigned char reg; /* register associated */
69 unsigned char used; /* how many times it will be used */
70 };
71
72 boolean_t net_filter_enable = FALSE;
73
74 /*
75 * Forward declarations.
76 */
77 void net_filter_optimize(
78 struct net_opt net_o[],
79 unsigned net_len,
80 int reg[],
81 unsigned nbreg);
82
83 /*
84 * Compilation of a source network filter into i386 instructions.
85 */
86 filter_fct_t
87 net_filter_alloc(
88 filter_t *fpstart,
89 unsigned int fplen,
90 unsigned int *len)
91 {
92 filter_t *fp;
93 unsigned int op;
94 unsigned int arg;
95 unsigned char *p;
96 filter_fct_t top;
97 unsigned char *pend;
98 unsigned char *pend_old;
99 unsigned int loop;
100 unsigned int use_header;
101 unsigned int use_data;
102 unsigned int push_ecx;
103 int reg[NET_REG_MAX];
104 struct net_opt net_o[NET_MAX_FILTER];
105 int net_i;
106 unsigned net_j;
107 unsigned i;
108 unsigned push;
109 unsigned false_pad;
110 struct net_opt *pn;
111
112 /*
113 * Addresses of end_true and end_false from the end of the program.
114 */
115 #define PEND_TRUE (pend_old - (11 + push + false_pad))
116 #define PEND_FALSE (pend_old - (4 + push))
117
118 /*
119 * Don't produce anything if net_filter generation is not enabled.
120 */
121 if (!net_filter_enable) {
122 *len = 0;
123 return ((filter_fct_t)0);
124 }
125
126 /*
127 * called as (*filter)(data, data_count, header)
128 *
129 * %esp -> stack;
130 * %ecx -> arg;
131 * %eax -> data (if needed);
132 * %edx -> header (if needed);
133 */
134 loop = 0;
135 p = (unsigned char *)0;
136 pend = 0;
137 use_header = 0;
138 use_data = 0;
139 net_j = 0;
140 false_pad = sizeof(int) - 1;
141
142 /*
143 * The compiler needs 3 passes to produce the compiled net_filter:
144 * 0) compute without optimization the maximum size of the object
145 * routine (one run),
146 * 1) try to reduce the size of the object procedure (many runs),
147 * 2) produce final object code (one run).
148 */
149 for (;;) {
150 if (loop == 0)
151 pend += 14;
152
153 else if (loop == 1) {
154 if (reg[NET_REG_EBX] == -1) {
155 /* push and pop it */
156 pend++;
157 push = 1;
158 } else
159 push = 0;
160 if (reg[NET_REG_ESI] == -1) {
161 /* push and pop it */
162 pend++;
163 push++;
164 }
165 if (reg[NET_REG_EDI] == -1) {
166 /* push and pop it */
167 pend++;
168 push++;
169 }
170 if (push) {
171 /* restore %esp */
172 push += 3;
173 }
174
175 if (use_data)
176 pend += 3;
177 if (use_header)
178 pend += 3;
179 pend += 8;
180
181 } else {
182 *p++ = 0x55; /* pushl %ebp */
183 *p++ = 0x89; /* movl %esp, %ebp */
184 *p++ = 0xE5;
185 if (reg[NET_REG_EBX] == -1)
186 *p++ = 0x53; /* pushl %ebx */
187 if (reg[NET_REG_ESI] == -1)
188 *p++ = 0x56; /* pushl %esi */
189 if (reg[NET_REG_EDI] == -1)
190 *p++ = 0x57; /* pushl %edi */
191 *p++ = 0xB9; /* movl $1, %ecx */
192 *p++ = 0x01;
193 *p++ = 0x00;
194 *p++ = 0x00;
195 *p++ = 0x00;
196 if (use_data) {
197 *p++ = 0x8B; /* movl 0x8(%ebp), %eax */
198 *p++ = 0x45;
199 *p++ = 0x08;
200 }
201 if (use_header) {
202 *p++ = 0x8B; /* movl 0x10(%ebp), %edx */
203 *p++ = 0x55;
204 *p++ = 0x10;
205 }
206 }
207 push_ecx = 1;
208 net_i = -1;
209
210 fp = fpstart;
211 while (fp - fpstart < fplen)
212 {
213 arg = *fp++;
214 op = NETF_OP(arg);
215 arg = NETF_ARG(arg);
216
217 switch (arg) {
218 case NETF_NOPUSH:
219 /*
220 * arg = *sp++;
221 */
222 if (push_ecx) {
223 push_ecx = 0;
224 break;
225 }
226 if (loop < 2)
227 pend++;
228 else
229 *p++ = 0x59; /* popl %ecx */
230 break;
231
232 case NETF_PUSHZERO:
233 /*
234 * arg = 0;
235 */
236 if (loop < 2) {
237 if (push_ecx) {
238 pend++;
239 push_ecx = 0;
240 }
241 pend += 2;
242 } else {
243 if (push_ecx) {
244 *p++ = 0x51; /* pushl %ecx */
245 push_ecx = 0;
246 }
247 *p++ = 0x31; /* xorl %ecx, %ecx */
248 *p++ = 0xC9;
249 }
250 break;
251
252 case NETF_PUSHLIT:
253 /*
254 * arg = *fp++;
255 */
256 if (loop < 2) {
257 if (push_ecx) {
258 pend++;
259 push_ecx = 0;
260 }
261 pend += 5;
262 } else {
263 if (push_ecx) {
264 *p++ = 0x51; /* pushl %ecx */
265 push_ecx = 0;
266 }
267 *p++ = 0xB9; /* movl *fp, %ecx */
268 *p++ = *(unsigned char *)fp;
269 *p++ = *(((unsigned char *)fp) + 1);
270 *p++ = 0x0;
271 *p++ = 0x0;
272 }
273 fp++;
274 break;
275
276 case NETF_PUSHIND:
277 /*
278 * arg = *sp++;
279 * if (arg >= data_count)
280 * return FALSE;
281 * arg = data_word[arg];
282 */
283 if (loop < 2) {
284 if (push_ecx)
285 push_ecx = 0;
286 else
287 pend++;
288 if (loop == 0)
289 use_data = 1;
290 if (loop == 0 ||
291 PEND_FALSE - (pend + 5) >= 128)
292 pend += 14;
293 else
294 pend += 10;
295 break;
296 }
297
298 if (push_ecx)
299 push_ecx = 0;
300 else
301 *p++ = 0x59; /* popl %ecx */
302 *p++ = 0x39; /* cmpl 0xC(%ebp), %ecx */
303 *p++ = 0x4D;
304 *p++ = 0x0C;
305
306 if (PEND_FALSE - (p + 2) >= 128) {
307 *p++ = 0x0F; /* jle end_false */
308 *p++ = 0x8E;
309 *(p+0) = PEND_FALSE - (p + 4);
310 *(p+1) = (PEND_FALSE - (p + 4)) >> 8;
311 *(p+2) = (PEND_FALSE - (p + 4)) >> 16;
312 *(p+3) = (PEND_FALSE - (p + 4)) >> 24;
313 p += 4;
314
315 } else {
316 *p++ = 0x7E; /* jle end_false */
317 *p = PEND_FALSE - (p + 1);
318 p++;
319 }
320
321 *p++ = 0x0F; /* movzwl 0(%eax,%ecx,2), %ecx */
322 *p++ = 0xB7;
323 *p++ = 0x4C;
324 *p++ = 0x48;
325 *p++ = 0x00;
326 break;
327
328 case NETF_PUSHHDRIND:
329 /*
330 * arg = *sp++;
331 * if (arg >= (NET_HDW_HDR_MAX /
332 * sizeof(unsigned short))
333 * return FALSE;
334 * arg = header_word[arg];
335 */
336 if (loop < 2) {
337 if (push_ecx)
338 push_ecx = 0;
339 else
340 pend++;
341 if (loop == 0)
342 use_header = 1;
343 if (loop == 0 ||
344 PEND_FALSE - (pend + 8) >= 128)
345 pend += 17;
346 else
347 pend += 13;
348 break;
349 }
350
351 if (push_ecx)
352 push_ecx = 0;
353 else
354 *p++ = 0x59; /* popl %ecx */
355 *p++ = 0x81; /* cmpl %ecx, <value> */
356 *p++ = 0xF9;
357 *p++ = NET_HDW_HDR_MAX /
358 sizeof(unsigned short);
359 *p++ = (NET_HDW_HDR_MAX /
360 sizeof(unsigned short)) >> 8;
361 *p++ = (NET_HDW_HDR_MAX /
362 sizeof(unsigned short)) >> 16;
363 *p++ = (NET_HDW_HDR_MAX /
364 sizeof(unsigned short)) >> 24;
365
366 if (PEND_FALSE - (p + 2) >= 128) {
367 *p++ = 0x0F; /* jge end_false */
368 *p++ = 0x8D;
369 *(p+0) = PEND_FALSE - (p + 4);
370 *(p+1) = (PEND_FALSE - (p + 4)) >> 8;
371 *(p+2) = (PEND_FALSE - (p + 4)) >> 16;
372 *(p+3) = (PEND_FALSE - (p + 4)) >> 24;
373 p += 4;
374
375 } else {
376 *p++ = 0x7D; /* jge end_false */
377 *p = PEND_FALSE - (p + 1);
378 p++;
379 }
380
381 *p++ = 0x0F; /* movzwl 0(%edx,%ecx,2), %ecx */
382 *p++ = 0xB7;
383 *p++ = 0x4C;
384 *p++ = 0x4A;
385 *p++ = 0x00;
386 break;
387
388 default:
389 if (arg >= NETF_PUSHSTK) {
390 arg -= NETF_PUSHSTK;
391 /*
392 * arg = sp[arg];
393 */
394 arg <<= 2;
395 if (loop < 2) {
396 if (push_ecx) {
397 pend++;
398 push_ecx = 0;
399 }
400 pend += (arg < 128) ? 4 : 7;
401 break;
402 }
403
404 if (push_ecx) {
405 *p++ = 0x51; /* pushl %ecx */
406 push_ecx = 0;
407 }
408 *p++ = 0x8B; /* movl arg(%esp), %ecx */
409 if (arg < 128) {
410 *p++ = 0x4C;
411 *p++ = 0x24;
412 *p++ = arg;
413 } else {
414 *p++ = 0x8C;
415 *p++ = 0x24;
416 *p++ = arg;
417 *p++ = arg >> 8;
418 *p++ = arg >> 16;
419 *p++ = arg >> 24;
420 }
421
422 } else if (arg >= NETF_PUSHHDR) {
423 arg -= NETF_PUSHHDR;
424 /*
425 * arg = header_word[arg];
426 */
427 arg <<= 1;
428 if (loop < 2) {
429 if (push_ecx) {
430 pend++;
431 push_ecx = 0;
432 }
433 if (loop == 0) {
434 use_header = 1;
435 net_o[net_j++].val =
436 arg + NETF_PUSHHDR;
437 } else {
438 net_i++;
439 assert(net_i < net_j);
440 pn = &net_o[net_i];
441 assert(reg[NET_REG_EDX]
442 == -2);
443 assert(pn->used == 0 ||
444 reg[pn->reg]
445 != -2);
446 assert(pn->val == arg +
447 NETF_PUSHHDR);
448 if (pn->used > 0 &&
449 reg[pn->reg] >= 0 &&
450 net_o[reg[pn->reg]]
451 .val == pn->val) {
452 pend += 2;
453 break;
454 }
455 }
456 pend += (arg < 128) ? 5 : 8;
457 if (loop == 1 && pn->used > 1 &&
458 (reg[pn->reg] < 0 ||
459 net_o[reg[pn->reg]].val !=
460 pn->val)) {
461 reg[pn->reg] = net_i;
462 pend += 2;
463 }
464 break;
465 }
466
467 if (push_ecx) {
468 *p++ = 0x51; /* pushl %ecx */
469 push_ecx = 0;
470 }
471
472 net_i++;
473 assert(net_i < net_j);
474 pn = &net_o[net_i];
475 assert(reg[NET_REG_EDX] == -2);
476 assert(pn->used == 0 ||
477 reg[pn->reg] != -2);
478 assert(pn->val == arg + NETF_PUSHHDR);
479 if (pn->used > 0 &&
480 reg[pn->reg] >= 0 &&
481 net_o[reg[pn->reg]].val ==
482 pn->val) {
483 *p++ = 0x89;
484 switch (pn->reg) {
485 case NET_REG_EAX:
486 /* movl %eax, %ecx */
487 *p++ = 0xC1;
488 break;
489
490 case NET_REG_EBX:
491 /* movl %ebx, %ecx */
492 *p++ = 0xD9;
493 break;
494
495 case NET_REG_ESI:
496 /* movl %esi, %ecx */
497 *p++ = 0xF1;
498 break;
499
500 case NET_REG_EDI:
501 /* movl %edi, %ecx */
502 *p++ = 0xF9;
503 break;
504 }
505 break;
506 }
507
508 *p++ = 0x0F;/* movzwl arg(%edx),%ecx */
509 *p++ = 0xB7;
510 if (arg < 128) {
511 *p++ = 0x4C;
512 *p++ = 0x22;
513 *p++ = arg;
514 } else {
515 *p++ = 0x8C;
516 *p++ = 0x22;
517 *p++ = arg;
518 *p++ = arg >> 8;
519 *p++ = arg >> 16;
520 *p++ = arg >> 24;
521 }
522
523 if (pn->used > 1 &&
524 (reg[pn->reg] == -1 ||
525 net_o[reg[pn->reg]].val !=
526 pn->val)) {
527 reg[pn->reg] = net_i;
528 *p++ = 0x89;
529 assert(net_o[net_i].reg !=
530 NET_REG_EDX);
531 switch (net_o[net_i].reg) {
532 case NET_REG_EAX:
533 /* movl %ecx, %eax */
534 *p++ = 0xC8;
535 break;
536 case NET_REG_EBX:
537 /* movl %ecx, %ebx */
538 *p++ = 0xCB;
539 break;
540 case NET_REG_ESI:
541 /* movl %ecx, %esi */
542 *p++ = 0xCE;
543 break;
544 case NET_REG_EDI:
545 /* movl %ecx, %edi */
546 *p++ = 0xCF;
547 break;
548 }
549 }
550
551 } else {
552 arg -= NETF_PUSHWORD;
553 /*
554 * if (arg >= data_count)
555 * return FALSE;
556 * arg = data_word[arg];
557 */
558 if (loop < 2) {
559 if (push_ecx) {
560 pend++;
561 push_ecx = 0;
562 }
563 if (loop == 0) {
564 use_data = 1;
565 net_o[net_j++].val =
566 arg + NETF_PUSHWORD;
567 } else {
568 net_i++;
569 assert(net_i < net_j);
570 pn = &net_o[net_i];
571 assert(reg[NET_REG_EAX]
572 == -2);
573 assert(pn->used == 0 ||
574 reg[pn->reg]
575 != -2);
576 assert(pn->val == arg +
577 NETF_PUSHWORD);
578 if (pn->used > 0 &&
579 reg[pn->reg] >= 0 &&
580 net_o[reg[pn->reg]]
581 .val == pn->val) {
582 pend += 2;
583 break;
584 }
585 }
586 arg <<= 1;
587 pend += (arg < 128) ? 4 : 7;
588 if (loop == 0 ||
589 (PEND_FALSE -
590 (pend + 2)) >= 128)
591 pend += 6;
592 else
593 pend += 2;
594
595 if (arg < 128)
596 pend += 5;
597 else
598 pend += 8;
599 if (loop == 1 && pn->used > 1 &&
600 (reg[pn->reg] < 0 ||
601 net_o[reg[pn->reg]].val !=
602 pn->val)) {
603 reg[pn->reg] = net_i;
604 pend += 2;
605 }
606 break;
607 }
608
609 if (push_ecx) {
610 *p++ = 0x51; /* pushl %ecx */
611 push_ecx = 0;
612 }
613
614 net_i++;
615 assert(net_i < net_j);
616 pn = &net_o[net_i];
617 assert(reg[NET_REG_EAX] == -2);
618 assert(pn->used == 0 ||
619 reg[pn->reg] != -2);
620 assert(pn->val == arg + NETF_PUSHWORD);
621 if (pn->used > 0 &&
622 reg[pn->reg] >= 0 &&
623 net_o[reg[pn->reg]].val ==
624 pn->val) {
625 *p++ = 0x89;
626 switch (pn->reg) {
627 case NET_REG_EDX:
628 /* movl %edx, %ecx */
629 *p++ = 0xD1;
630 break;
631
632 case NET_REG_EBX:
633 /* movl %ebx, %ecx */
634 *p++ = 0xD9;
635 break;
636
637 case NET_REG_ESI:
638 /* movl %esi, %ecx */
639 *p++ = 0xF1;
640 break;
641
642 case NET_REG_EDI:
643 /* movl %edi, %ecx */
644 *p++ = 0xF9;
645 break;
646 }
647 break;
648 }
649
650 /* cmpl 0xC(%ebp), <arg> */
651 arg <<= 1;
652 if (arg < 128) {
653 *p++ = 0x83;
654 *p++ = 0x7D;
655 *p++ = 0x0C;
656 *p++ = arg;
657 } else {
658 *p++ = 0x81;
659 *p++ = 0x7D;
660 *p++ = 0x0C;
661 *p++ = arg;
662 *p++ = arg >> 8;
663 *p++ = arg >> 16;
664 *p++ = arg >> 24;
665 }
666
667 if (PEND_FALSE - (p + 2) >= 128) {
668 *p++ = 0x0F;/* jle end_false */
669 *p++ = 0x8E;
670 *(p+0) = PEND_FALSE - (p + 4);
671 *(p+1) = (PEND_FALSE - (p + 4))
672 >> 8;
673 *(p+2) = (PEND_FALSE - (p + 4))
674 >> 16;
675 *(p+3) = (PEND_FALSE - (p + 4))
676 >> 24;
677 p += 4;
678
679 } else {
680 *p++ = 0x7E;/* jle end_false */
681 *p = PEND_FALSE - (p + 1);
682 p++;
683 }
684
685 *p++ = 0x0F;/* movzwl arg(%eax),%ecx */
686 *p++ = 0xB7;
687 if (arg < 128) {
688 *p++ = 0x4C;
689 *p++ = 0x20;
690 *p++ = arg;
691 } else {
692 *p++ = 0x8C;
693 *p++ = 0x20;
694 *p++ = arg;
695 *p++ = arg >> 8;
696 *p++ = arg >> 16;
697 *p++ = arg >> 24;
698 }
699
700 if (pn->used > 1 &&
701 (reg[pn->reg] == -1 ||
702 net_o[reg[pn->reg]].val !=
703 pn->val)) {
704 reg[pn->reg] = net_i;
705 *p++ = 0x89;
706 assert(net_o[net_i].reg !=
707 NET_REG_EAX);
708 switch (net_o[net_i].reg) {
709 case NET_REG_EDX:
710 /* movl %ecx, %edx */
711 *p++ = 0xCA;
712 break;
713 case NET_REG_EBX:
714 /* movl %ecx, %ebx */
715 *p++ = 0xCB;
716 break;
717 case NET_REG_ESI:
718 /* movl %ecx, %esi */
719 *p++ = 0xCE;
720 break;
721 case NET_REG_EDI:
722 /* movl %ecx, %edi */
723 *p++ = 0xCF;
724 break;
725 }
726 }
727 }
728 break;
729 }
730
731 switch (op) {
732 case NETF_OP(NETF_NOP):
733 /*
734 * *--sp = arg;
735 */
736 push_ecx = 1;
737 break;
738
739 case NETF_OP(NETF_AND):
740 /*
741 * *sp &= arg;
742 */
743 if (loop < 2)
744 pend += 3;
745 else {
746 *p++ = 0x21; /* andl (%esp), %ecx */
747 *p++ = 0x0C;
748 *p++ = 0x24;
749 }
750 break;
751
752 case NETF_OP(NETF_OR):
753 /*
754 * *sp |= arg;
755 */
756 if (loop < 2)
757 pend += 3;
758 else {
759 *p++ = 0x09; /* orl (%esp), %ecx */
760 *p++ = 0x0C;
761 *p++ = 0x24;
762 }
763 break;
764
765 case NETF_OP(NETF_XOR):
766 /*
767 * sp ^= arg;
768 */
769 if (loop < 2)
770 pend += 3;
771 else {
772 *p++ = 0x31; /* xorl (%esp), %ecx */
773 *p++ = 0x0C;
774 *p++ = 0x24;
775 }
776 break;
777
778 case NETF_OP(NETF_EQ):
779 /*
780 * *sp = (*sp == arg);
781 */
782 if (loop < 2) {
783 pend += 14;
784 /*
785 * Pad to longword boundary (cf dissas).
786 */
787 if (i = ((pend - (unsigned char *)0) &
788 (sizeof(int) - 1)))
789 pend += (sizeof(int) - i);
790 pend += 7;
791 break;
792 }
793 *p++ = 0x39; /* cmpl (%esp), %ecx */
794 *p++ = 0x0C;
795 *p++ = 0x24;
796
797 i = ((p - (unsigned char *)top) + 11) &
798 (sizeof(int) - 1);
799 *p++ = 0x74; /* je .+9+<pad> */
800 *p++ = 0x09 + (i ? sizeof(int) - i : 0);
801 *p++ = 0xC7; /* movl $0, 0(%esp) */
802 *p++ = 0x04;
803 *p++ = 0x24;
804 *p++ = 0x00;
805 *p++ = 0x00;
806 *p++ = 0x00;
807 *p++ = 0x00;
808
809 i = ((p - (unsigned char *)top) + 2) &
810 (sizeof(int) - 1);
811 *p++ = 0xEB; /* jmp .+7+<pad> */
812 *p++ = 0x07 + (i ? sizeof(int) - i : 0);
813
814 /*
815 * Pad to longword boundary (cf dissas).
816 */
817 if (i = (p - (unsigned char *)top) &
818 (sizeof(int) - 1))
819 while (i++ < sizeof(int))
820 *p++ = 0x90; /* nop */
821 *p++ = 0xC7; /* movl $1, 0(%esp) */
822 *p++ = 0x04;
823 *p++ = 0x24;
824 *p++ = 0x01;
825 *p++ = 0x00;
826 *p++ = 0x00;
827 *p++ = 0x00;
828 break;
829
830 case NETF_OP(NETF_NEQ):
831 /*
832 * *sp = (*sp != arg);
833 */
834 if (loop < 2) {
835 pend += 14;
836 /*
837 * Pad to longword boundary (cf dissas).
838 */
839 if (i = ((pend - (unsigned char *)0) &
840 (sizeof(int) - 1)))
841 pend += (sizeof(int) - i);
842 pend += 7;
843 break;
844 }
845 *p++ = 0x39; /* cmpl (%esp), %ecx */
846 *p++ = 0x0C;
847 *p++ = 0x24;
848
849 i = ((p - (unsigned char *)top) + 11) &
850 (sizeof(int) - 1);
851 *p++ = 0x75; /* jne .+9+<pad> */
852 *p++ = 0x09 + (i ? sizeof(int) - i : 0);
853 *p++ = 0xC7; /* movl $0, 0(%esp) */
854 *p++ = 0x04;
855 *p++ = 0x24;
856 *p++ = 0x00;
857 *p++ = 0x00;
858 *p++ = 0x00;
859 *p++ = 0x00;
860
861 i = ((p - (unsigned char *)top) + 2) &
862 (sizeof(int) - 1);
863 *p++ = 0xEB; /* jmp .+7+<pad> */
864 *p++ = 0x07 + (i ? sizeof(int) - i : 0);
865
866 /*
867 * Pad to longword boundary (cf dissas).
868 */
869 if (i = (p - (unsigned char *)top) &
870 (sizeof(int) - 1))
871 while (i++ < sizeof(int))
872 *p++ = 0x90; /* nop */
873 *p++ = 0xC7; /* movl $1, 0(%esp) */
874 *p++ = 0x04;
875 *p++ = 0x24;
876 *p++ = 0x01;
877 *p++ = 0x00;
878 *p++ = 0x00;
879 *p++ = 0x00;
880 break;
881
882 case NETF_OP(NETF_LT):
883 /*
884 * *sp = (*sp < arg);
885 */
886 if (loop < 2) {
887 pend += 14;
888 /*
889 * Pad to longword boundary (cf dissas).
890 */
891 if (i = ((pend - (unsigned char *)0) &
892 (sizeof(int) - 1)))
893 pend += (sizeof(int) - i);
894 pend += 7;
895 break;
896 }
897 *p++ = 0x39; /* cmpl (%esp), %ecx */
898 *p++ = 0x0C;
899 *p++ = 0x24;
900
901 i = ((p - (unsigned char *)top) + 11) &
902 (sizeof(int) - 1);
903 *p++ = 0x7C; /* jl .+9+<pad> */
904 *p++ = 0x09 + (i ? sizeof(int) - i : 0);
905 *p++ = 0xC7; /* movl $0, 0(%esp) */
906 *p++ = 0x04;
907 *p++ = 0x24;
908 *p++ = 0x00;
909 *p++ = 0x00;
910 *p++ = 0x00;
911 *p++ = 0x00;
912
913 i = ((p - (unsigned char *)top) + 2) &
914 (sizeof(int) - 1);
915 *p++ = 0xEB; /* jmp .+7+<pad> */
916 *p++ = 0x07 + (i ? sizeof(int) - i : 0);
917
918 /*
919 * Pad to longword boundary (cf dissas).
920 */
921 if (i = (p - (unsigned char *)top) &
922 (sizeof(int) - 1))
923 while (i++ < sizeof(int))
924 *p++ = 0x90; /* nop */
925 *p++ = 0xC7; /* movl $1, 0(%esp) */
926 *p++ = 0x04;
927 *p++ = 0x24;
928 *p++ = 0x01;
929 *p++ = 0x00;
930 *p++ = 0x00;
931 *p++ = 0x00;
932 break;
933
934 case NETF_OP(NETF_LE):
935 /*
936 * *sp = (*sp <= arg);
937 */
938 if (loop < 2) {
939 pend += 14;
940 /*
941 * Pad to longword boundary (cf dissas).
942 */
943 if (i = ((pend - (unsigned char *)0) &
944 (sizeof(int) - 1)))
945 pend += (sizeof(int) - i);
946 pend += 7;
947 break;
948 }
949 *p++ = 0x39; /* cmpl (%esp), %ecx */
950 *p++ = 0x0C;
951 *p++ = 0x24;
952
953 i = ((p - (unsigned char *)top) + 11) &
954 (sizeof(int) - 1);
955 *p++ = 0x7E; /* jle .+9+<pad> */
956 *p++ = 0x09 + (i ? sizeof(int) - i : 0);
957 *p++ = 0xC7; /* movl $0, 0(%esp) */
958 *p++ = 0x04;
959 *p++ = 0x24;
960 *p++ = 0x00;
961 *p++ = 0x00;
962 *p++ = 0x00;
963 *p++ = 0x00;
964
965 i = ((p - (unsigned char *)top) + 2) &
966 (sizeof(int) - 1);
967 *p++ = 0xEB; /* jmp .+7+<pad> */
968 *p++ = 0x07 + (i ? sizeof(int) - i : 0);
969
970 /*
971 * Pad to longword boundary (cf dissas).
972 */
973 if (i = (p - (unsigned char *)top) &
974 (sizeof(int) - 1))
975 while (i++ < sizeof(int))
976 *p++ = 0x90; /* nop */
977 *p++ = 0xC7; /* movl $1, 0(%esp) */
978 *p++ = 0x04;
979 *p++ = 0x24;
980 *p++ = 0x01;
981 *p++ = 0x00;
982 *p++ = 0x00;
983 *p++ = 0x00;
984 break;
985
986 case NETF_OP(NETF_GT):
987 /*
988 * *sp = (*sp > arg);
989 */
990 if (loop < 2) {
991 pend += 14;
992 /*
993 * Pad to longword boundary (cf dissas).
994 */
995 if (i = ((pend - (unsigned char *)0) &
996 (sizeof(int) - 1)))
997 pend += (sizeof(int) - i);
998 pend += 7;
999 break;
1000 }
1001 *p++ = 0x39; /* cmpl (%esp), %ecx */
1002 *p++ = 0x0C;
1003 *p++ = 0x24;
1004
1005 i = ((p - (unsigned char *)top) + 11) &
1006 (sizeof(int) - 1);
1007 *p++ = 0x7F; /* jg .+9+<pad> */
1008 *p++ = 0x09 + (i ? sizeof(int) - i : 0);
1009 *p++ = 0xC7; /* movl $0, 0(%esp) */
1010 *p++ = 0x04;
1011 *p++ = 0x24;
1012 *p++ = 0x00;
1013 *p++ = 0x00;
1014 *p++ = 0x00;
1015 *p++ = 0x00;
1016
1017 i = ((p - (unsigned char *)top) + 2) &
1018 (sizeof(int) - 1);
1019 *p++ = 0xEB; /* jmp .+7+<pad> */
1020 *p++ = 0x07 + (i ? sizeof(int) - i : 0);
1021
1022 /*
1023 * Pad to longword boundary (cf dissas).
1024 */
1025 if (i = (p - (unsigned char *)top) &
1026 (sizeof(int) - 1))
1027 while (i++ < sizeof(int))
1028 *p++ = 0x90; /* nop */
1029 *p++ = 0xC7; /* movl $1, 0(%esp) */
1030 *p++ = 0x04;
1031 *p++ = 0x24;
1032 *p++ = 0x01;
1033 *p++ = 0x00;
1034 *p++ = 0x00;
1035 *p++ = 0x00;
1036 break;
1037
1038 case NETF_OP(NETF_GE):
1039 /*
1040 * *sp = (*sp >= arg);
1041 */
1042 if (loop < 2) {
1043 pend += 14;
1044 /*
1045 * Pad to longword boundary (cf dissas).
1046 */
1047 if (i = ((pend - (unsigned char *)0) &
1048 (sizeof(int) - 1)))
1049 pend += (sizeof(int) - i);
1050 pend += 7;
1051 break;
1052 }
1053 *p++ = 0x39; /* cmpl (%esp), %ecx */
1054 *p++ = 0x0C;
1055 *p++ = 0x24;
1056
1057 i = ((p - (unsigned char *)top) + 11) &
1058 (sizeof(int) - 1);
1059 *p++ = 0x7D; /* jge .+9+<pad> */
1060 *p++ = 0x09 + (i ? sizeof(int) - i : 0);
1061 *p++ = 0xC7; /* movl $0, 0(%esp) */
1062 *p++ = 0x04;
1063 *p++ = 0x24;
1064 *p++ = 0x00;
1065 *p++ = 0x00;
1066 *p++ = 0x00;
1067 *p++ = 0x00;
1068
1069 i = ((p - (unsigned char *)top) + 2) &
1070 (sizeof(int) - 1);
1071 *p++ = 0xEB; /* jmp .+7+<pad> */
1072 *p++ = 0x07 + (i ? sizeof(int) - i : 0);
1073
1074 /*
1075 * Pad to longword boundary (cf dissas).
1076 */
1077 if (i = (p - (unsigned char *)top) &
1078 (sizeof(int) - 1))
1079 while (i++ < sizeof(int))
1080 *p++ = 0x90; /* nop */
1081 *p++ = 0xC7; /* movl $1, 0(%esp) */
1082 *p++ = 0x04;
1083 *p++ = 0x24;
1084 *p++ = 0x01;
1085 *p++ = 0x00;
1086 *p++ = 0x00;
1087 *p++ = 0x00;
1088 break;
1089
1090 case NETF_OP(NETF_COR):
1091 /*
1092 * if (*sp++ == arg)
1093 * return (TRUE);
1094 */
1095 if (loop < 2) {
1096 if (loop == 0 ||
1097 PEND_TRUE - (pend + 5) >= 128)
1098 pend += 12;
1099 else
1100 pend += 8;
1101 break;
1102 }
1103
1104 *p++ = 0x39; /* cmpl (%esp), %ecx */
1105 *p++ = 0x0C;
1106 *p++ = 0x24;
1107
1108 if (PEND_TRUE - (p + 2) >= 128) {
1109 *p++ = 0x0F; /* je end_true */
1110 *p++ = 0x84;
1111 *(p+0) = PEND_TRUE - (p + 4);
1112 *(p+1) = (PEND_TRUE - (p + 4)) >> 8;
1113 *(p+2) = (PEND_TRUE - (p + 4)) >> 16;
1114 *(p+3) = (PEND_TRUE - (p + 4)) >> 24;
1115 p += 4;
1116
1117 } else {
1118 *p++ = 0x74; /* je end_true */
1119 *p = PEND_TRUE - (p + 1);
1120 p++;
1121 }
1122
1123 *p++ = 0x83; /* addl $4, %esp */
1124 *p++ = 0xC4;
1125 *p++ = 0x04;
1126 break;
1127
1128 case NETF_OP(NETF_CAND):
1129 /*
1130 * if (*sp++ != arg)
1131 * return (FALSE);
1132 */
1133 if (loop < 2) {
1134 if (loop == 0 ||
1135 PEND_FALSE - (pend + 5) >= 128)
1136 pend += 12;
1137 else
1138 pend += 8;
1139 break;
1140 }
1141
1142 *p++ = 0x39; /* cmpl (%esp), %ecx */
1143 *p++ = 0x0C;
1144 *p++ = 0x24;
1145
1146 if (PEND_FALSE - (p + 2) >= 128) {
1147 *p++ = 0x0F; /* jne end_false */
1148 *p++ = 0x85;
1149 *(p+0) = PEND_FALSE - (p + 4);
1150 *(p+1) = (PEND_FALSE - (p + 4)) >> 8;
1151 *(p+2) = (PEND_FALSE - (p + 4)) >> 16;
1152 *(p+3) = (PEND_FALSE - (p + 4)) >> 24;
1153 p += 4;
1154
1155 } else {
1156 *p++ = 0x75; /* jne end_false */
1157 *p = PEND_FALSE - (p + 1);
1158 p++;
1159 }
1160
1161 *p++ = 0x83; /* addl $4, %esp */
1162 *p++ = 0xC4;
1163 *p++ = 0x04;
1164 break;
1165
1166 case NETF_OP(NETF_CNOR):
1167 /*
1168 * if (*sp++ == arg)
1169 * return (FALSE);
1170 */
1171 if (loop < 2) {
1172 if (loop == 0 ||
1173 PEND_FALSE - (pend + 5) >= 128)
1174 pend += 12;
1175 else
1176 pend += 8;
1177 break;
1178 }
1179
1180 *p++ = 0x39; /* cmpl (%esp), %ecx */
1181 *p++ = 0x0C;
1182 *p++ = 0x24;
1183
1184 if (PEND_FALSE - (p + 2) >= 128) {
1185 *p++ = 0x0F; /* je end_false */
1186 *p++ = 0x84;
1187 *(p+0) = PEND_FALSE - (p + 4);
1188 *(p+1) = (PEND_FALSE - (p + 4)) >> 8;
1189 *(p+2) = (PEND_FALSE - (p + 4)) >> 16;
1190 *(p+3) = (PEND_FALSE - (p + 4)) >> 24;
1191 p += 4;
1192 } else {
1193 *p++ = 0x74; /* je end_false */
1194 *p = PEND_FALSE - (p + 1);
1195 p++;
1196 }
1197
1198 *p++ = 0x83; /* addl $4, %esp */
1199 *p++ = 0xC4;
1200 *p++ = 0x04;
1201 break;
1202
1203 case NETF_OP(NETF_CNAND):
1204 /*
1205 * if (*sp++ != arg)
1206 * return (TRUE);
1207 */
1208 if (loop < 2) {
1209 if (loop == 0 ||
1210 PEND_TRUE - (pend + 5) >= 128)
1211 pend += 12;
1212 else
1213 pend += 8;
1214 break;
1215 }
1216
1217 *p++ = 0x39; /* cmpl (%esp), %ecx */
1218 *p++ = 0x0C;
1219 *p++ = 0x24;
1220
1221 if (PEND_TRUE - (p + 2) >= 128) {
1222 *p++ = 0x0F; /* jne end_true */
1223 *p++ = 0x85;
1224 *(p+0) = PEND_TRUE - (p + 4);
1225 *(p+1) = (PEND_TRUE - (p + 4)) >> 8;
1226 *(p+2) = (PEND_TRUE - (p + 4)) >> 16;
1227 *(p+3) = (PEND_TRUE - (p + 4)) >> 24;
1228 p += 4;
1229
1230 } else {
1231 *p++ = 0x75; /* jne end_true */
1232 *p = PEND_TRUE - (p + 1);
1233 p++;
1234 }
1235
1236 *p++ = 0x83; /* addl $4, %esp */
1237 *p++ = 0xC4;
1238 *p++ = 0x04;
1239 break;
1240
1241 case NETF_OP(NETF_LSH):
1242 /*
1243 * *sp <<= arg;
1244 */
1245 if (loop < 2)
1246 pend += 3;
1247 else {
1248 *p++ = 0xD3; /* sall (%esp), %cl */
1249 *p++ = 0x24;
1250 *p++ = 0x24;
1251 }
1252 break;
1253
1254 case NETF_OP(NETF_RSH):
1255 /*
1256 * *sp >>= arg;
1257 */
1258 if (loop < 2)
1259 pend += 3;
1260 else {
1261 *p++ = 0xD3; /* sarl (%esp), %cl */
1262 *p++ = 0x3C;
1263 *p++ = 0x24;
1264 }
1265 break;
1266
1267 case NETF_OP(NETF_ADD):
1268 /*
1269 * *sp += arg;
1270 */
1271 if (loop < 2)
1272 pend += 3;
1273 else {
1274 *p++ = 0x01; /* addl (%esp), %ecx */
1275 *p++ = 0x0C;
1276 *p++ = 0x24;
1277 }
1278 break;
1279
1280 case NETF_OP(NETF_SUB):
1281 /*
1282 * *sp -= arg;
1283 */
1284 if (loop < 2)
1285 pend += 3;
1286 else {
1287 *p++ = 0x29; /* subl (%esp), %ecx */
1288 *p++ = 0x0C;
1289 *p++ = 0x24;
1290 }
1291 break;
1292 }
1293 }
1294
1295 /*
1296 * return ((*sp) ? TRUE : FALSE);
1297 */
1298 if (loop < 2) {
1299 if (push_ecx) {
1300 pend += 12;
1301 push_ecx = 0;
1302 } else
1303 pend += 13;
1304 /*
1305 * Pad to longword boundary (cf dissas).
1306 */
1307 i = (pend - (unsigned char *)0) & (sizeof(int) - 1);
1308 false_pad = i ? sizeof(int) - i : 0;
1309 pend += 4 + push + false_pad;
1310 } else {
1311 if (push_ecx) {
1312 *p++ = 0x83; /* cmpl %ecx, $0 */
1313 *p++ = 0xF9;
1314 *p++ = 0x00;
1315 push_ecx = 0;
1316 } else {
1317 *p++ = 0x83; /* cmpl (%esp), $0 */
1318 *p++ = 0x3C;
1319 *p++ = 0x24;
1320 *p++ = 0x00;
1321 }
1322
1323 i = ((p - (unsigned char *)top) + 9) &
1324 (sizeof(int) - 1);
1325 false_pad = i ? sizeof(int) - i : 0;
1326 *p++ = 0x74; /* je end_false */
1327 *p++ = 0x07 + false_pad;
1328
1329 *p++ = 0xB8; /* movl $1, %eax */
1330 *p++ = 0x01;
1331 *p++ = 0x00;
1332 *p++ = 0x00;
1333 *p++ = 0x00;
1334
1335 *p++ = 0xEB; /* jmp .+2+<pad> */
1336 *p++ = 0x02 + false_pad;
1337
1338 /*
1339 * Pad to longword boundary (cf dissas).
1340 */
1341 for (i = 0; i < false_pad; i++)
1342 *p++ = 0x90; /* nop */
1343 *p++ = 0x31; /* xorl %eax, %eax */
1344 *p++ = 0xC0;
1345 if (push) {
1346 *p++ = 0x8D; /* leal -<push>(%ebx), %esp */
1347 *p++ = 0x65;
1348 *p++ = -((push - 3) * 4);
1349 }
1350 if (reg[NET_REG_EDI] >= 0)
1351 *p++ = 0x5F; /* pop %edi */
1352 if (reg[NET_REG_ESI] >= 0)
1353 *p++ = 0x5E; /* pop %esi */
1354 if (reg[NET_REG_EBX] >= 0)
1355 *p++ = 0x5B; /* pop %ebx */
1356 *p++ = 0xC9; /* leave */
1357 *p++ = 0xC3; /* ret */
1358 }
1359
1360 /*
1361 * Prepare next loop if any.
1362 */
1363 if (loop == 2)
1364 break;
1365
1366 if (loop == 1 && pend == pend_old) {
1367 loop = 2;
1368 *len = pend - (unsigned char *)0;
1369 top = (filter_fct_t)kalloc(*len);
1370 p = (unsigned char *)top;
1371 pend_old = p + (pend - (unsigned char *)0);
1372 } else {
1373 if (loop == 0) {
1374 loop = 1;
1375 /*
1376 * Compute and optimize free registers usage.
1377 */
1378 for (i = 0; i < NET_REG_MAX; i++)
1379 reg[i] = -1;
1380 if (use_data)
1381 reg[NET_REG_EAX] = -2;
1382 if (use_header)
1383 reg[NET_REG_EDX] = -2;
1384 net_filter_optimize(net_o, net_j,
1385 reg, NET_REG_MAX);
1386 }
1387 pend_old = pend;
1388 pend = 0;
1389 }
1390 for (i = 0; i < NET_REG_MAX; i++)
1391 if (reg[i] != -2)
1392 reg[i] = -1;
1393 }
1394 return (top);
1395 }
1396
1397 void
1398 net_filter_free(
1399 filter_fct_t fp,
1400 unsigned int len)
1401 {
1402 kfree((vm_offset_t)fp, len);
1403 }
1404
1405 /*
1406 * Try to compute how to use (if needed) extra registers to store
1407 * values read more than once.
1408 *
1409 * Input : net_o is an array of used values (only .val is valid).
1410 * net_len is the length of net_o.
1411 * reg is an array of available registers (-2 ==> used register).
1412 * nbreg is the maximum number of registers.
1413 *
1414 * Output : net_o is an array of register usage.
1415 * .used == 0 ==> do not used any register.
1416 * .used >= 2 ==> how many times the .reg register
1417 * will be used.
1418 * reg is an array of used registers.
1419 * == -2 ==> unused or unavailable register.
1420 * >= 0 ==> used register.
1421 *
1422 * N.B. This procedure is completely machine-independent and should take place
1423 * in a file of the device directory.
1424 */
1425 void
1426 net_filter_optimize(
1427 struct net_opt net_o[],
1428 unsigned net_len,
1429 int reg[],
1430 unsigned nbreg)
1431 {
1432 unsigned i;
1433 unsigned j;
1434 unsigned nbnet;
1435 unsigned avail;
1436 unsigned used;
1437 unsigned first;
1438 unsigned max;
1439 unsigned last;
1440 struct net_opt *p;
1441 struct net_opt *q;
1442
1443 avail = 0;
1444 for (i = 0; i < nbreg; i++)
1445 if (reg[i] != -2)
1446 avail++;
1447 if (avail == 0)
1448 return;
1449
1450 /*
1451 * First step: set up used field.
1452 */
1453 p = &net_o[net_len];
1454 while (p != net_o) {
1455 for (q = p--; q < &net_o[net_len]; q++)
1456 if (q->val == p->val) {
1457 p->used = q->used + 1;
1458 break;
1459 }
1460 if (q == &net_o[net_len])
1461 p->used = 1;
1462 }
1463
1464 /*
1465 * Second step: choose best register and update used field.
1466 */
1467 if (net_len > 0) {
1468 if (net_o[0].used == 1)
1469 used = net_o[0].used = 0;
1470 else {
1471 net_o[0].reg = 0;
1472 used = 1;
1473 }
1474
1475 for (p = &net_o[1]; p < &net_o[net_len]; p++) {
1476 max = 0;
1477 first = avail;
1478 for (i = 0; i < avail; i++) {
1479 q = p;
1480 j = 0;
1481 while (q-- != net_o)
1482 if (q->used > 0 && q->reg == i) {
1483 if (q->used == 1)
1484 first = i;
1485 j = 1;
1486 break;
1487 }
1488 if (j == 0)
1489 continue;
1490
1491 if (q->val == p->val) {
1492 p->reg = i;
1493 break;
1494 }
1495
1496 if (p->used == 1)
1497 continue;
1498
1499 if (first == avail && used == avail) {
1500 j = 1;
1501 for (q = p+1; q->val != p->val; p++)
1502 j++;
1503 if (j > max) {
1504 max = j;
1505 last = i;
1506 }
1507 }
1508 }
1509 if (i < avail)
1510 continue;
1511
1512 if (p->used > 1) {
1513 if (first != avail)
1514 p->reg = first;
1515 else if (used < avail)
1516 p->reg = used++;
1517 else
1518 p->reg = last;
1519 } else
1520 p->used = 0;
1521 }
1522 }
1523
1524 /*
1525 * Third step: associate correct register number and keep max value.
1526 */
1527 for (p = net_o; p < &net_o[net_len]; p++) {
1528 if (p->used == 0)
1529 continue;
1530 i = first = 0;
1531 for (;;) {
1532 if (reg[i] != -2) {
1533 if (first == p->reg) {
1534 p->reg = i;
1535 break;
1536 }
1537 first++;
1538 }
1539 i++;
1540 }
1541 }
1542
1543 /*
1544 * Forth step: invalidate useless registers.
1545 */
1546 if (net_len == 0) {
1547 for (i = 0; i < nbreg; i++)
1548 if (reg[i] != -2)
1549 reg[i] = -2;
1550
1551 } else if (used < avail) {
1552 first = 0;
1553 for (i = 0; i < nbreg; i++)
1554 if (reg[i] != -2)
1555 if (first >= used)
1556 reg[i] = -2;
1557 else
1558 first++;
1559 }
1560 }