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