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