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