xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c (revision 34a0f871d192b33b865455a8812a3d34c1866315)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS	*/
27 
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/isa_defs.h>
37 
38 #include <sys/socket.h>
39 #include <sys/sockio.h>
40 #include <sys/dlpi.h>
41 #include <sys/vlan.h>
42 #include <net/if.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/in.h>
45 #include <netinet/ip.h>
46 #include <netinet/if_ether.h>
47 #include <netinet/tcp.h>
48 #include <netinet/udp.h>
49 #include <netdb.h>
50 #include <rpc/rpc.h>
51 #include <setjmp.h>
52 
53 #include <sys/pfmod.h>
54 #include "snoop.h"
55 #include "snoop_vlan.h"
56 
57 /*
58  * This module generates code for the kernel packet filter.
59  * The kernel packet filter is more efficient since it
60  * operates without context switching or moving data into
61  * the capture buffer.  On the other hand, it is limited
62  * in its filtering ability i.e. can't cope with variable
63  * length headers, can't compare the packet size, 1 and 4 octet
64  * comparisons are awkward, code space is limited to ENMAXFILTERS
65  * halfwords, etc.
66  * The parser is the same for the user-level packet filter though
67  * more limited in the variety of expressions it can generate
68  * code for.  If the pf compiler finds an expression it can't
69  * handle, it tries to set up a split filter in kernel and do the
70  * remaining filtering in userland. If that also fails, it resorts
71  * to userland filter. (See additional comment in pf_compile)
72  */
73 
74 extern struct Pf_ext_packetfilt pf;
75 static ushort_t *pfp;
76 jmp_buf env;
77 
78 int eaddr;	/* need ethernet addr */
79 
80 int opstack;	/* operand stack depth */
81 
82 #define	EQ(val)		(strcmp(token, val) == 0)
83 #define	IPV4_ONLY	0
84 #define	IPV6_ONLY	1
85 #define	IPV4_AND_IPV6	2
86 
87 /*
88  * The following constants represent the offsets in bytes from the beginning
89  * of the packet of the link and IP(v6) layer source/destination/type fields,
90  * initialized for Ethernet. Media specific code can set any unavailable
91  * link layer property's offset to -1 to indicate that the property's value
92  * is not available from the frame.
93  */
94 static int link_header_len = 14, link_type_offset = 12;
95 static int link_dest_offset = 0, link_src_offset = 6;
96 static int link_addr_len = 6;
97 
98 #define	IPV4_SRCADDR_OFFSET	(link_header_len + 12)
99 #define	IPV4_DSTADDR_OFFSET	(link_header_len + 16)
100 #define	IPV6_SRCADDR_OFFSET	(link_header_len + 8)
101 #define	IPV6_DSTADDR_OFFSET	(link_header_len + 24)
102 
103 static int inBrace = 0, inBraceOR = 0;
104 static int foundOR = 0;
105 char *tkp, *sav_tkp;
106 char *token;
107 enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
108 	ADDR_IP6 } tokentype;
109 uint_t tokenval;
110 
111 enum direction { ANY, TO, FROM };
112 enum direction dir;
113 
114 extern void next();
115 
116 static void pf_expression();
117 static void pf_check_vlan_tag(uint_t offset);
118 static void pf_clear_offset_register();
119 static void pf_emit_load_offset(uint_t offset);
120 static void pf_match_ethertype(uint_t ethertype);
121 static void pf_check_transport_protocol(uint_t transport_protocol);
122 static void pf_compare_value_mask_generic(int offset, uint_t len,
123     uint_t val, int mask, uint_t op);
124 
125 /*
126  * This pointer points to the function that last generated
127  * instructions to change the offset register.  It's used
128  * for comparisons to see if we need to issue more instructions
129  * to change the register.
130  *
131  * It's initialized to pf_clear_offset_register because the offset
132  * register in pfmod is initialized to zero, similar to the state
133  * it would be in after executing the instructions issued by
134  * pf_clear_offset_register.
135  */
136 static void *last_offset_operation = (void*)pf_clear_offset_register;
137 
138 static void
139 pf_emit(x)
140 	ushort_t x;
141 {
142 	if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1])
143 		longjmp(env, 1);
144 	*pfp++ = x;
145 }
146 
147 static void
148 pf_codeprint(code, len)
149 	ushort_t *code;
150 	int len;
151 {
152 	ushort_t *pc;
153 	ushort_t *plast = code + len;
154 	int op, action;
155 
156 	if (len > 0) {
157 		printf("Kernel Filter:\n");
158 	}
159 
160 	for (pc = code; pc < plast; pc++) {
161 		printf("\t%3d: ", pc - code);
162 
163 		op = *pc & 0xfc00;	/* high 10 bits */
164 		action = *pc & 0x3ff;	/* low   6 bits */
165 
166 		switch (action) {
167 		case ENF_PUSHLIT:
168 			printf("PUSHLIT ");
169 			break;
170 		case ENF_PUSHZERO:
171 			printf("PUSHZERO ");
172 			break;
173 #ifdef ENF_PUSHONE
174 		case ENF_PUSHONE:
175 			printf("PUSHONE ");
176 			break;
177 #endif
178 #ifdef ENF_PUSHFFFF
179 		case ENF_PUSHFFFF:
180 			printf("PUSHFFFF ");
181 			break;
182 #endif
183 #ifdef ENF_PUSHFF00
184 		case ENF_PUSHFF00:
185 			printf("PUSHFF00 ");
186 			break;
187 #endif
188 #ifdef ENF_PUSH00FF
189 		case ENF_PUSH00FF:
190 			printf("PUSH00FF ");
191 			break;
192 #endif
193 		case ENF_LOAD_OFFSET:
194 			printf("LOAD_OFFSET ");
195 			break;
196 		case ENF_BRTR:
197 			printf("BRTR ");
198 			break;
199 		case ENF_BRFL:
200 			printf("BRFL ");
201 			break;
202 		case ENF_POP:
203 			printf("POP ");
204 			break;
205 		}
206 
207 		if (action >= ENF_PUSHWORD)
208 			printf("PUSHWORD %d ", action - ENF_PUSHWORD);
209 
210 		switch (op) {
211 		case ENF_EQ:
212 			printf("EQ ");
213 			break;
214 		case ENF_LT:
215 			printf("LT ");
216 			break;
217 		case ENF_LE:
218 			printf("LE ");
219 			break;
220 		case ENF_GT:
221 			printf("GT ");
222 			break;
223 		case ENF_GE:
224 			printf("GE ");
225 			break;
226 		case ENF_AND:
227 			printf("AND ");
228 			break;
229 		case ENF_OR:
230 			printf("OR ");
231 			break;
232 		case ENF_XOR:
233 			printf("XOR ");
234 			break;
235 		case ENF_COR:
236 			printf("COR ");
237 			break;
238 		case ENF_CAND:
239 			printf("CAND ");
240 			break;
241 		case ENF_CNOR:
242 			printf("CNOR ");
243 			break;
244 		case ENF_CNAND:
245 			printf("CNAND ");
246 			break;
247 		case ENF_NEQ:
248 			printf("NEQ ");
249 			break;
250 		}
251 
252 		if (action == ENF_PUSHLIT ||
253 		    action == ENF_LOAD_OFFSET ||
254 		    action == ENF_BRTR ||
255 		    action == ENF_BRFL) {
256 			pc++;
257 			printf("\n\t%3d:   %d (0x%04x)", pc - code, *pc, *pc);
258 		}
259 
260 		printf("\n");
261 	}
262 }
263 
264 /*
265  * Emit packet filter code to check a
266  * field in the packet for a particular value.
267  * Need different code for each field size.
268  * Since the pf can only compare 16 bit quantities
269  * we have to use masking to compare byte values.
270  * Long word (32 bit) quantities have to be done
271  * as two 16 bit comparisons.
272  */
273 static void
274 pf_compare_value(int offset, uint_t len, uint_t val)
275 {
276 	/*
277 	 * If the property being filtered on is absent in the media
278 	 * packet, error out.
279 	 */
280 	if (offset == -1)
281 		pr_err("filter option unsupported on media");
282 
283 	switch (len) {
284 	case 1:
285 		pf_emit(ENF_PUSHWORD + offset / 2);
286 #if defined(_BIG_ENDIAN)
287 		if (offset % 2)
288 #else
289 		if (!(offset % 2))
290 #endif
291 		{
292 #ifdef ENF_PUSH00FF
293 			pf_emit(ENF_PUSH00FF | ENF_AND);
294 #else
295 			pf_emit(ENF_PUSHLIT | ENF_AND);
296 			pf_emit(0x00FF);
297 #endif
298 			pf_emit(ENF_PUSHLIT | ENF_EQ);
299 			pf_emit(val);
300 		} else {
301 #ifdef ENF_PUSHFF00
302 			pf_emit(ENF_PUSHFF00 | ENF_AND);
303 #else
304 			pf_emit(ENF_PUSHLIT | ENF_AND);
305 			pf_emit(0xFF00);
306 #endif
307 			pf_emit(ENF_PUSHLIT | ENF_EQ);
308 			pf_emit(val << 8);
309 		}
310 		break;
311 
312 	case 2:
313 		pf_emit(ENF_PUSHWORD + offset / 2);
314 		pf_emit(ENF_PUSHLIT | ENF_EQ);
315 		pf_emit((ushort_t)val);
316 		break;
317 
318 	case 4:
319 		pf_emit(ENF_PUSHWORD + offset / 2);
320 		pf_emit(ENF_PUSHLIT | ENF_EQ);
321 #if defined(_BIG_ENDIAN)
322 		pf_emit(val >> 16);
323 #elif defined(_LITTLE_ENDIAN)
324 		pf_emit(val & 0xffff);
325 #else
326 #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined
327 #endif
328 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
329 		pf_emit(ENF_PUSHLIT | ENF_EQ);
330 #if defined(_BIG_ENDIAN)
331 		pf_emit(val & 0xffff);
332 #else
333 		pf_emit(val >> 16);
334 #endif
335 		pf_emit(ENF_AND);
336 		break;
337 	}
338 }
339 
340 /*
341  * same as pf_compare_value, but only for emiting code to
342  * compare ipv6 addresses.
343  */
344 static void
345 pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
346 {
347 	int i;
348 
349 	for (i = 0; i < len; i += 2) {
350 		pf_emit(ENF_PUSHWORD + offset / 2 + i / 2);
351 		pf_emit(ENF_PUSHLIT | ENF_EQ);
352 		pf_emit(*(uint16_t *)&val.s6_addr[i]);
353 		if (i != 0)
354 			pf_emit(ENF_AND);
355 	}
356 }
357 
358 
359 /*
360  * Same as above except mask the field value
361  * before doing the comparison.  The comparison checks
362  * to make sure the values are equal.
363  */
364 static void
365 pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
366 {
367 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ);
368 }
369 
370 /*
371  * Same as above except the values are compared to see if they are not
372  * equal.
373  */
374 static void
375 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask)
376 {
377 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ);
378 }
379 
380 /*
381  * Similar to pf_compare_value.
382  *
383  * This is the utility function that does the actual work to compare
384  * two values using a mask.  The comparison operation is passed into
385  * the function.
386  */
387 static void
388 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask,
389     uint_t op)
390 {
391 	/*
392 	 * If the property being filtered on is absent in the media
393 	 * packet, error out.
394 	 */
395 	if (offset == -1)
396 		pr_err("filter option unsupported on media");
397 
398 	switch (len) {
399 	case 1:
400 		pf_emit(ENF_PUSHWORD + offset / 2);
401 #if defined(_BIG_ENDIAN)
402 		if (offset % 2)
403 #else
404 		if (!offset % 2)
405 #endif
406 		{
407 			pf_emit(ENF_PUSHLIT | ENF_AND);
408 			pf_emit(mask & 0x00ff);
409 			pf_emit(ENF_PUSHLIT | op);
410 			pf_emit(val);
411 		} else {
412 			pf_emit(ENF_PUSHLIT | ENF_AND);
413 			pf_emit((mask << 8) & 0xff00);
414 			pf_emit(ENF_PUSHLIT | op);
415 			pf_emit(val << 8);
416 		}
417 		break;
418 
419 	case 2:
420 		pf_emit(ENF_PUSHWORD + offset / 2);
421 		pf_emit(ENF_PUSHLIT | ENF_AND);
422 		pf_emit(htons((ushort_t)mask));
423 		pf_emit(ENF_PUSHLIT | op);
424 		pf_emit(htons((ushort_t)val));
425 		break;
426 
427 	case 4:
428 		pf_emit(ENF_PUSHWORD + offset / 2);
429 		pf_emit(ENF_PUSHLIT | ENF_AND);
430 		pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
431 		pf_emit(ENF_PUSHLIT | op);
432 		pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
433 
434 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
435 		pf_emit(ENF_PUSHLIT | ENF_AND);
436 		pf_emit(htons((ushort_t)(mask & 0xffff)));
437 		pf_emit(ENF_PUSHLIT | op);
438 		pf_emit(htons((ushort_t)(val & 0xffff)));
439 
440 		pf_emit(ENF_AND);
441 		break;
442 	}
443 }
444 
445 /*
446  * Generate pf code to match an IPv4 or IPv6 address.
447  */
448 static void
449 pf_ipaddr_match(which, hostname, inet_type)
450 	enum direction which;
451 	char *hostname;
452 	int inet_type;
453 {
454 	bool_t found_host;
455 	uint_t *addr4ptr;
456 	uint_t addr4;
457 	struct in6_addr *addr6ptr;
458 	int h_addr_index;
459 	struct hostent *hp = NULL;
460 	int error_num = 0;
461 	boolean_t first = B_TRUE;
462 	int pass = 0;
463 
464 	/*
465 	 * The addr4offset and addr6offset variables simplify the code which
466 	 * generates the address comparison filter.  With these two variables,
467 	 * duplicate code need not exist for the TO and FROM case.
468 	 * A value of -1 describes the ANY case (TO and FROM).
469 	 */
470 	int addr4offset;
471 	int addr6offset;
472 
473 	found_host = 0;
474 
475 	if (tokentype == ADDR_IP) {
476 		hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
477 		if (hp == NULL) {
478 			if (error_num == TRY_AGAIN) {
479 				pr_err("could not resolve %s (try again later)",
480 				    hostname);
481 			} else {
482 				pr_err("could not resolve %s", hostname);
483 			}
484 		}
485 		inet_type = IPV4_ONLY;
486 	} else if (tokentype == ADDR_IP6) {
487 		hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
488 		if (hp == NULL) {
489 			if (error_num == TRY_AGAIN) {
490 				pr_err("could not resolve %s (try again later)",
491 				    hostname);
492 			} else {
493 				pr_err("could not resolve %s", hostname);
494 			}
495 		}
496 		inet_type = IPV6_ONLY;
497 	} else if (tokentype == ALPHA) {
498 		/* Some hostname i.e. tokentype is ALPHA */
499 		switch (inet_type) {
500 		case IPV4_ONLY:
501 			/* Only IPv4 address is needed */
502 			hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
503 			if (hp != NULL) {
504 				found_host = 1;
505 			}
506 			break;
507 		case IPV6_ONLY:
508 			/* Only IPv6 address is needed */
509 			hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
510 			if (hp != NULL) {
511 				found_host = 1;
512 			}
513 			break;
514 		case IPV4_AND_IPV6:
515 			/* Both IPv4 and IPv6 are needed */
516 			hp = getipnodebyname(hostname, AF_INET6,
517 			    AI_ALL | AI_V4MAPPED, &error_num);
518 			if (hp != NULL) {
519 				found_host = 1;
520 			}
521 			break;
522 		default:
523 			found_host = 0;
524 		}
525 
526 		if (!found_host) {
527 			if (error_num == TRY_AGAIN) {
528 				pr_err("could not resolve %s (try again later)",
529 				    hostname);
530 			} else {
531 				pr_err("could not resolve %s", hostname);
532 			}
533 		}
534 	} else {
535 		pr_err("unknown token type: %s", hostname);
536 	}
537 
538 	switch (which) {
539 	case TO:
540 		addr4offset = IPV4_DSTADDR_OFFSET;
541 		addr6offset = IPV6_DSTADDR_OFFSET;
542 		break;
543 	case FROM:
544 		addr4offset = IPV4_SRCADDR_OFFSET;
545 		addr6offset = IPV6_SRCADDR_OFFSET;
546 		break;
547 	case ANY:
548 		addr4offset = -1;
549 		addr6offset = -1;
550 		break;
551 	}
552 
553 	if (hp != NULL && hp->h_addrtype == AF_INET) {
554 		pf_match_ethertype(ETHERTYPE_IP);
555 		pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
556 		h_addr_index = 0;
557 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
558 		while (addr4ptr != NULL) {
559 			if (addr4offset == -1) {
560 				pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
561 				    *addr4ptr);
562 				if (h_addr_index != 0)
563 					pf_emit(ENF_OR);
564 				pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
565 				    *addr4ptr);
566 				pf_emit(ENF_OR);
567 			} else {
568 				pf_compare_value(addr4offset, 4,
569 				    *addr4ptr);
570 				if (h_addr_index != 0)
571 					pf_emit(ENF_OR);
572 			}
573 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
574 		}
575 		pf_emit(ENF_AND);
576 	} else {
577 		/* first pass: IPv4 addresses */
578 		h_addr_index = 0;
579 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
580 		first = B_TRUE;
581 		while (addr6ptr != NULL) {
582 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
583 				if (first) {
584 					pf_match_ethertype(ETHERTYPE_IP);
585 					pf_check_vlan_tag(
586 					    ENCAP_ETHERTYPE_OFF/2);
587 					pass++;
588 				}
589 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
590 				    (struct in_addr *)&addr4);
591 				if (addr4offset == -1) {
592 					pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
593 					    addr4);
594 					if (!first)
595 						pf_emit(ENF_OR);
596 					pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
597 					    addr4);
598 					pf_emit(ENF_OR);
599 				} else {
600 					pf_compare_value(addr4offset, 4,
601 					    addr4);
602 					if (!first)
603 						pf_emit(ENF_OR);
604 				}
605 				if (first)
606 					first = B_FALSE;
607 			}
608 			addr6ptr = (struct in6_addr *)
609 				hp->h_addr_list[++h_addr_index];
610 		}
611 		if (!first) {
612 			pf_emit(ENF_AND);
613 		}
614 		/* second pass: IPv6 addresses */
615 		h_addr_index = 0;
616 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
617 		first = B_TRUE;
618 		while (addr6ptr != NULL) {
619 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
620 				if (first) {
621 					pf_match_ethertype(ETHERTYPE_IPV6);
622 					pf_check_vlan_tag(
623 					    ENCAP_ETHERTYPE_OFF/2);
624 					pass++;
625 				}
626 				if (addr6offset == -1) {
627 					pf_compare_value_v6(IPV6_SRCADDR_OFFSET,
628 					    16, *addr6ptr);
629 					if (!first)
630 						pf_emit(ENF_OR);
631 					pf_compare_value_v6(IPV6_DSTADDR_OFFSET,
632 					    16, *addr6ptr);
633 					pf_emit(ENF_OR);
634 				} else {
635 					pf_compare_value_v6(addr6offset, 16,
636 					    *addr6ptr);
637 					if (!first)
638 						pf_emit(ENF_OR);
639 				}
640 				if (first)
641 					first = B_FALSE;
642 			}
643 			addr6ptr = (struct in6_addr *)
644 				hp->h_addr_list[++h_addr_index];
645 		}
646 		if (!first) {
647 			pf_emit(ENF_AND);
648 		}
649 		if (pass == 2) {
650 			pf_emit(ENF_OR);
651 		}
652 	}
653 
654 	if (hp != NULL) {
655 		freehostent(hp);
656 	}
657 }
658 
659 
660 static void
661 pf_compare_address(int offset, uint_t len, uchar_t *addr)
662 {
663 	uint32_t val;
664 	uint16_t sval;
665 	boolean_t didone = B_FALSE;
666 
667 	/*
668 	 * If the property being filtered on is absent in the media
669 	 * packet, error out.
670 	 */
671 	if (offset == -1)
672 		pr_err("filter option unsupported on media");
673 
674 	while (len > 0) {
675 		if (len >= 4) {
676 			(void) memcpy(&val, addr, 4);
677 			pf_compare_value(offset, 4, val);
678 			addr += 4;
679 			offset += 4;
680 			len -= 4;
681 		} else if (len >= 2) {
682 			(void) memcpy(&sval, addr, 2);
683 			pf_compare_value(offset, 2, sval);
684 			addr += 2;
685 			offset += 2;
686 			len -= 2;
687 		} else {
688 			pf_compare_value(offset++, 1, *addr++);
689 			len--;
690 		}
691 		if (didone)
692 			pf_emit(ENF_AND);
693 		didone = B_TRUE;
694 	}
695 }
696 
697 /*
698  * Compare ethernet addresses.
699  */
700 static void
701 pf_etheraddr_match(which, hostname)
702 	enum direction which;
703 	char *hostname;
704 {
705 	struct ether_addr e, *ep = NULL;
706 
707 	if (isxdigit(*hostname))
708 		ep = ether_aton(hostname);
709 	if (ep == NULL) {
710 		if (ether_hostton(hostname, &e))
711 			if (!arp_for_ether(hostname, &e))
712 				pr_err("cannot obtain ether addr for %s",
713 					hostname);
714 		ep = &e;
715 	}
716 
717 	pf_clear_offset_register();
718 
719 	switch (which) {
720 	case TO:
721 		pf_compare_address(link_dest_offset, link_addr_len,
722 		    (uchar_t *)ep);
723 		break;
724 	case FROM:
725 		pf_compare_address(link_src_offset, link_addr_len,
726 		    (uchar_t *)ep);
727 		break;
728 	case ANY:
729 		pf_compare_address(link_dest_offset, link_addr_len,
730 		    (uchar_t *)ep);
731 		pf_compare_address(link_src_offset, link_addr_len,
732 		    (uchar_t *)ep);
733 		pf_emit(ENF_OR);
734 		break;
735 	}
736 }
737 
738 /*
739  * Emit code to compare the network part of
740  * an IP address.
741  */
742 static void
743 pf_netaddr_match(which, netname)
744 	enum direction which;
745 	char *netname;
746 {
747 	uint_t addr;
748 	uint_t mask = 0xff000000;
749 	struct netent *np;
750 
751 	if (isdigit(*netname)) {
752 		addr = inet_network(netname);
753 	} else {
754 		np = getnetbyname(netname);
755 		if (np == NULL)
756 			pr_err("net %s not known", netname);
757 		addr = np->n_net;
758 	}
759 
760 	/*
761 	 * Left justify the address and figure
762 	 * out a mask based on the supplied address.
763 	 * Set the mask according to the number of zero
764 	 * low-order bytes.
765 	 * Note: this works only for whole octet masks.
766 	 */
767 	if (addr) {
768 		while ((addr & ~mask) != 0) {
769 			mask |= (mask >> 8);
770 		}
771 	}
772 
773 	pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
774 
775 	switch (which) {
776 	case TO:
777 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
778 		break;
779 	case FROM:
780 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
781 		break;
782 	case ANY:
783 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
784 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
785 		pf_emit(ENF_OR);
786 		break;
787 	}
788 }
789 
790 /*
791  * A helper function to keep the code to emit instructions
792  * to change the offset register in one place.
793  *
794  * INPUTS: offset - An value representing an offset in 16-bit
795  *                  words.
796  * OUTPUTS:  If there is enough room in the storage for the
797  *           packet filtering program, instructions to load
798  *           a constant to the offset register.  Otherwise,
799  *           nothing.
800  */
801 static void
802 pf_emit_load_offset(uint_t offset)
803 {
804 	pf_emit(ENF_LOAD_OFFSET | ENF_NOP);
805 	pf_emit(offset);
806 }
807 
808 /*
809  * Clear pfmod's offset register.
810  *
811  * INPUTS:  none
812  * OUTPUTS:  Instructions to clear the offset register if
813  *           there is enough space remaining in the packet
814  *           filtering program structure's storage, and
815  *           the last thing done to the offset register was
816  *           not clearing the offset register.  Otherwise,
817  *           nothing.
818  */
819 static void
820 pf_clear_offset_register()
821 {
822 	if (last_offset_operation != (void*)pf_clear_offset_register) {
823 		pf_emit_load_offset(0);
824 		last_offset_operation = (void*)pf_clear_offset_register;
825 	}
826 }
827 
828 /*
829  * This function will issue opcodes to check if a packet
830  * is VLAN tagged, and if so, update the offset register
831  * with the appropriate offset.
832  *
833  * Note that if the packet is not VLAN tagged, then the offset
834  * register will be cleared.
835  *
836  * If the interface type is not an ethernet type, then this
837  * function returns without doing anything.
838  *
839  * If the last attempt to change the offset register occured because
840  * of a call to this function that was called with the same offset,
841  * then we don't issue packet filtering instructions.
842  *
843  * INPUTS:  offset - an offset in 16 bit words.  The function
844  *                   will set the offset register to this
845  *                   value if the packet is VLAN tagged.
846  * OUTPUTS:  If the conditions are met, packet filtering instructions.
847  */
848 static void
849 pf_check_vlan_tag(uint_t offset)
850 {
851 	static uint_t last_offset = 0;
852 
853 	if ((interface->mac_type == DL_ETHER ||
854 	    interface->mac_type == DL_CSMACD) &&
855 	    (last_offset_operation != (void*)pf_check_vlan_tag ||
856 	    last_offset != offset)) {
857 		/*
858 		 * First thing is to clear the offset register.
859 		 * We don't know what state it is in, and if it
860 		 * is not zero, then we have no idea what we load
861 		 * when we execute ENF_PUSHWORD.
862 		 */
863 		pf_clear_offset_register();
864 
865 		/*
866 		 * Check the ethertype.
867 		 */
868 		pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_VLAN));
869 
870 		/*
871 		 * And if it's not VLAN, don't load offset to the offset
872 		 * register.
873 		 */
874 		pf_emit(ENF_BRFL | ENF_NOP);
875 		pf_emit(3);
876 
877 		/*
878 		 * Otherwise, load offset to the offset register.
879 		 */
880 		pf_emit_load_offset(offset);
881 
882 		/*
883 		 * Now get rid of the results of the comparison,
884 		 * we don't want the results of the comparison to affect
885 		 * other logic in the packet filtering program.
886 		 */
887 		pf_emit(ENF_POP | ENF_NOP);
888 
889 		/*
890 		 * Set the last operation at the end, or any time
891 		 * after the call to pf_clear_offset because
892 		 * pf_clear_offset uses it.
893 		 */
894 		last_offset_operation = (void*)pf_check_vlan_tag;
895 		last_offset = offset;
896 	}
897 }
898 
899 /*
900  * Utility function used to emit packet filtering code
901  * to match an ethertype.
902  *
903  * INPUTS:  ethertype - The ethertype we want to check for.
904  *                      Don't call htons on the ethertype before
905  *                      calling this function.
906  * OUTPUTS:  If there is sufficient storage available, packet
907  *           filtering code to check an ethertype.  Otherwise,
908  *           nothing.
909  */
910 static void
911 pf_match_ethertype(uint_t ethertype)
912 {
913 	/*
914 	 * If the user wants to filter on ethertype VLAN,
915 	 * then clear the offset register so that the offset
916 	 * for ENF_PUSHWORD points to the right place in the
917 	 * packet.
918 	 *
919 	 * Otherwise, call pf_check_vlan_tag to set the offset
920 	 * register such that the contents of the offset register
921 	 * plus the argument for ENF_PUSHWORD point to the right
922 	 * part of the packet, whether or not the packet is VLAN
923 	 * tagged.  We call pf_check_vlan_tag with an offset of
924 	 * two words because if the packet is VLAN tagged, we have
925 	 * to move past the ethertype in the ethernet header, and
926 	 * past the lower two octets of the VLAN header to get to
927 	 * the ethertype in the VLAN header.
928 	 */
929 	if (ethertype == ETHERTYPE_VLAN)
930 		pf_clear_offset_register();
931 	else
932 		pf_check_vlan_tag(2);
933 
934 	pf_compare_value(link_type_offset, 2, htons(ethertype));
935 }
936 
937 typedef struct {
938 	int	transport_protocol;
939 	int	network_protocol;
940 	/*
941 	 * offset is the offset in bytes from the beginning
942 	 * of the network protocol header to where the transport
943 	 * protocol type is.
944 	 */
945 	int	offset;
946 } transport_protocol_table_t;
947 
948 static transport_protocol_table_t mapping_table[] = {
949 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
950 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
951 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
952 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
953 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
954 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
955 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
956 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
957 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
958 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
959 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
960 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
961 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
962 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
963 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
964 	{-1, 0, 0}	/* must be the final entry */
965 };
966 
967 /*
968  * This function uses the table above to generate a
969  * piece of a packet filtering program to check a transport
970  * protocol type.
971  *
972  * INPUTS:  tranport_protocol - the transport protocol we're
973  *                              interested in.
974  * OUTPUTS:  If there is sufficient storage, then packet filtering
975  *           code to check a transport protocol type.  Otherwise,
976  *           nothing.
977  */
978 static void
979 pf_check_transport_protocol(uint_t transport_protocol)
980 {
981 	int i = 0;
982 	uint_t number_of_matches = 0;
983 
984 	for (i = 0; mapping_table[i].transport_protocol != -1; i++) {
985 		if (transport_protocol ==
986 		    (uint_t)mapping_table[i].transport_protocol) {
987 			number_of_matches++;
988 			pf_match_ethertype(mapping_table[i].network_protocol);
989 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
990 			pf_compare_value(
991 				mapping_table[i].offset + link_header_len, 1,
992 				transport_protocol);
993 			pf_emit(ENF_AND);
994 			if (number_of_matches > 1) {
995 				/*
996 				 * Since we have two or more matches, in
997 				 * order to have a correct and complete
998 				 * program we need to OR the result of
999 				 * each block of comparisons together.
1000 				 */
1001 				pf_emit(ENF_OR);
1002 			}
1003 		}
1004 	}
1005 }
1006 
1007 static void
1008 pf_primary()
1009 {
1010 	for (;;) {
1011 		if (tokentype == FIELD)
1012 			break;
1013 
1014 		if (EQ("ip")) {
1015 			pf_match_ethertype(ETHERTYPE_IP);
1016 			opstack++;
1017 			next();
1018 			break;
1019 		}
1020 
1021 		if (EQ("ip6")) {
1022 			pf_match_ethertype(ETHERTYPE_IPV6);
1023 			opstack++;
1024 			next();
1025 			break;
1026 		}
1027 
1028 		if (EQ("pppoe")) {
1029 			pf_match_ethertype(ETHERTYPE_PPPOED);
1030 			pf_match_ethertype(ETHERTYPE_PPPOES);
1031 			pf_emit(ENF_OR);
1032 			opstack++;
1033 			next();
1034 			break;
1035 		}
1036 
1037 		if (EQ("pppoed")) {
1038 			pf_match_ethertype(ETHERTYPE_PPPOED);
1039 			opstack++;
1040 			next();
1041 			break;
1042 		}
1043 
1044 		if (EQ("pppoes")) {
1045 			pf_match_ethertype(ETHERTYPE_PPPOES);
1046 			opstack++;
1047 			next();
1048 			break;
1049 		}
1050 
1051 		if (EQ("arp")) {
1052 			pf_match_ethertype(ETHERTYPE_ARP);
1053 			opstack++;
1054 			next();
1055 			break;
1056 		}
1057 
1058 		if (EQ("vlan")) {
1059 			pf_match_ethertype(ETHERTYPE_VLAN);
1060 			pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2,
1061 			    0, VLAN_ID_MASK);
1062 			pf_emit(ENF_AND);
1063 			opstack++;
1064 			next();
1065 			break;
1066 		}
1067 
1068 		if (EQ("vlan-id")) {
1069 			next();
1070 			if (tokentype != NUMBER)
1071 				pr_err("VLAN ID expected");
1072 			pf_match_ethertype(ETHERTYPE_VLAN);
1073 			pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
1074 			    VLAN_ID_MASK);
1075 			pf_emit(ENF_AND);
1076 			opstack++;
1077 			next();
1078 			break;
1079 		}
1080 
1081 		if (EQ("rarp")) {
1082 			pf_match_ethertype(ETHERTYPE_REVARP);
1083 			opstack++;
1084 			next();
1085 			break;
1086 		}
1087 
1088 		if (EQ("tcp")) {
1089 			pf_check_transport_protocol(IPPROTO_TCP);
1090 			opstack++;
1091 			next();
1092 			break;
1093 		}
1094 
1095 		if (EQ("udp")) {
1096 			pf_check_transport_protocol(IPPROTO_UDP);
1097 			opstack++;
1098 			next();
1099 			break;
1100 		}
1101 
1102 		if (EQ("ospf")) {
1103 			pf_check_transport_protocol(IPPROTO_OSPF);
1104 			opstack++;
1105 			next();
1106 			break;
1107 		}
1108 
1109 
1110 		if (EQ("sctp")) {
1111 			pf_check_transport_protocol(IPPROTO_SCTP);
1112 			opstack++;
1113 			next();
1114 			break;
1115 		}
1116 
1117 		if (EQ("icmp")) {
1118 			pf_check_transport_protocol(IPPROTO_ICMP);
1119 			opstack++;
1120 			next();
1121 			break;
1122 		}
1123 
1124 		if (EQ("icmp6")) {
1125 			pf_check_transport_protocol(IPPROTO_ICMPV6);
1126 			opstack++;
1127 			next();
1128 			break;
1129 		}
1130 
1131 		if (EQ("ip-in-ip")) {
1132 			pf_check_transport_protocol(IPPROTO_ENCAP);
1133 			opstack++;
1134 			next();
1135 			break;
1136 		}
1137 
1138 		if (EQ("esp")) {
1139 			pf_check_transport_protocol(IPPROTO_ESP);
1140 			opstack++;
1141 			next();
1142 			break;
1143 		}
1144 
1145 		if (EQ("ah")) {
1146 			pf_check_transport_protocol(IPPROTO_AH);
1147 			opstack++;
1148 			next();
1149 			break;
1150 		}
1151 
1152 		if (EQ("(")) {
1153 			inBrace++;
1154 			next();
1155 			pf_expression();
1156 			if (EQ(")")) {
1157 				if (inBrace)
1158 					inBraceOR--;
1159 				inBrace--;
1160 				next();
1161 			}
1162 			break;
1163 		}
1164 
1165 		if (EQ("to") || EQ("dst")) {
1166 			dir = TO;
1167 			next();
1168 			continue;
1169 		}
1170 
1171 		if (EQ("from") || EQ("src")) {
1172 			dir = FROM;
1173 			next();
1174 			continue;
1175 		}
1176 
1177 		if (EQ("ether")) {
1178 			eaddr = 1;
1179 			next();
1180 			continue;
1181 		}
1182 
1183 		if (EQ("inet")) {
1184 			next();
1185 			if (EQ("host"))
1186 				next();
1187 			if (tokentype != ALPHA && tokentype != ADDR_IP)
1188 				pr_err("host/IPv4 addr expected after inet");
1189 			pf_ipaddr_match(dir, token, IPV4_ONLY);
1190 			opstack++;
1191 			next();
1192 			break;
1193 		}
1194 
1195 		if (EQ("inet6")) {
1196 			next();
1197 			if (EQ("host"))
1198 				next();
1199 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
1200 				pr_err("host/IPv6 addr expected after inet6");
1201 			pf_ipaddr_match(dir, token, IPV6_ONLY);
1202 			opstack++;
1203 			next();
1204 			break;
1205 		}
1206 
1207 		if (EQ("proto")) {
1208 			next();
1209 			if (tokentype != NUMBER)
1210 				pr_err("IP proto type expected");
1211 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1212 			pf_compare_value(
1213 			    IPV4_TYPE_HEADER_OFFSET + link_header_len, 1,
1214 			    tokenval);
1215 			opstack++;
1216 			next();
1217 			break;
1218 		}
1219 
1220 		if (EQ("broadcast")) {
1221 			pf_clear_offset_register();
1222 			pf_compare_value(link_dest_offset, 4, 0xffffffff);
1223 			opstack++;
1224 			next();
1225 			break;
1226 		}
1227 
1228 		if (EQ("multicast")) {
1229 			pf_clear_offset_register();
1230 			pf_compare_value_mask(link_dest_offset, 1, 0x01, 0x01);
1231 			opstack++;
1232 			next();
1233 			break;
1234 		}
1235 
1236 		if (EQ("ethertype")) {
1237 			next();
1238 			if (tokentype != NUMBER)
1239 				pr_err("ether type expected");
1240 			pf_match_ethertype(tokenval);
1241 			opstack++;
1242 			next();
1243 			break;
1244 		}
1245 
1246 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
1247 			if (EQ("dstnet"))
1248 				dir = TO;
1249 			else if (EQ("srcnet"))
1250 				dir = FROM;
1251 			next();
1252 			pf_netaddr_match(dir, token);
1253 			dir = ANY;
1254 			opstack++;
1255 			next();
1256 			break;
1257 		}
1258 
1259 		/*
1260 		 * Give up on anything that's obviously
1261 		 * not a primary.
1262 		 */
1263 		if (EQ("and") || EQ("or") ||
1264 		    EQ("not") || EQ("decnet") || EQ("apple") ||
1265 		    EQ("length") || EQ("less") || EQ("greater") ||
1266 		    EQ("port") || EQ("srcport") || EQ("dstport") ||
1267 		    EQ("rpc") || EQ("gateway") || EQ("nofrag") ||
1268 		    EQ("bootp") || EQ("dhcp") || EQ("dhcp6") ||
1269 		    EQ("slp") || EQ("ldap")) {
1270 			break;
1271 		}
1272 
1273 		if (EQ("host") || EQ("between") ||
1274 		    tokentype == ALPHA || /* assume its a hostname */
1275 		    tokentype == ADDR_IP ||
1276 		    tokentype == ADDR_IP6 ||
1277 		    tokentype == ADDR_ETHER) {
1278 			if (EQ("host") || EQ("between"))
1279 				next();
1280 			if (eaddr || tokentype == ADDR_ETHER) {
1281 				pf_etheraddr_match(dir, token);
1282 			} else if (tokentype == ALPHA) {
1283 				pf_ipaddr_match(dir, token, IPV4_AND_IPV6);
1284 			} else if (tokentype == ADDR_IP) {
1285 				pf_ipaddr_match(dir, token, IPV4_ONLY);
1286 			} else {
1287 				pf_ipaddr_match(dir, token, IPV6_ONLY);
1288 			}
1289 			dir = ANY;
1290 			eaddr = 0;
1291 			opstack++;
1292 			next();
1293 			break;
1294 		}
1295 
1296 		break;	/* unknown token */
1297 	}
1298 }
1299 
1300 static void
1301 pf_alternation()
1302 {
1303 	int s = opstack;
1304 
1305 	pf_primary();
1306 	for (;;) {
1307 		if (EQ("and"))
1308 			next();
1309 		pf_primary();
1310 		if (opstack != s + 2)
1311 			break;
1312 		pf_emit(ENF_AND);
1313 		opstack--;
1314 	}
1315 }
1316 
1317 static void
1318 pf_expression()
1319 {
1320 	pf_alternation();
1321 	while (EQ("or") || EQ(",")) {
1322 		if (inBrace)
1323 			inBraceOR++;
1324 		else
1325 			foundOR++;
1326 		next();
1327 		pf_alternation();
1328 		pf_emit(ENF_OR);
1329 		opstack--;
1330 	}
1331 }
1332 
1333 /*
1334  * Attempt to compile the expression
1335  * in the string "e".  If we can generate
1336  * pf code for it then return 1 - otherwise
1337  * return 0 and leave it up to the user-level
1338  * filter.
1339  */
1340 int
1341 pf_compile(e, print)
1342 	char *e;
1343 	int print;
1344 {
1345 	char *argstr;
1346 	char *sav_str, *ptr, *sav_ptr;
1347 	int inBr = 0, aheadOR = 0;
1348 
1349 	argstr = strdup(e);
1350 	sav_str = e;
1351 	tkp = argstr;
1352 	dir = ANY;
1353 
1354 	pfp = &pf.Pf_Filter[0];
1355 	if (setjmp(env)) {
1356 		return (0);
1357 	}
1358 
1359 	/*
1360 	 * Set media specific packet offsets that this code uses.
1361 	 */
1362 	if (interface->mac_type == DL_IB) {
1363 		link_header_len = 4;
1364 		link_type_offset = 0;
1365 		link_dest_offset = link_src_offset = -1;
1366 		link_addr_len = 20;
1367 	}
1368 
1369 	next();
1370 	pf_expression();
1371 
1372 	if (tokentype != EOL) {
1373 		/*
1374 		 * The idea here is to do as much filtering as possible in
1375 		 * the kernel. So even if we find a token we don't understand,
1376 		 * we try to see if we can still set up a portion of the filter
1377 		 * in the kernel and use the userland filter to filter the
1378 		 * remaining stuff. Obviously, if our filter expression is of
1379 		 * type A AND B, we can filter A in kernel and then apply B
1380 		 * to the packets that got through. The same is not true for
1381 		 * a filter of type A OR B. We can't apply A first and then B
1382 		 * on the packets filtered through A.
1383 		 *
1384 		 * (We need to keep track of the fact when we find an OR,
1385 		 * and the fact that we are inside brackets when we find OR.
1386 		 * The variable 'foundOR' tells us if there was an OR behind,
1387 		 * 'inBraceOR' tells us if we found an OR before we could find
1388 		 * the end brace i.e. ')', and variable 'aheadOR' checks if
1389 		 * there is an OR in the expression ahead. if either of these
1390 		 * cases become true, we can't split the filtering)
1391 		 */
1392 
1393 		if (foundOR || inBraceOR) {
1394 			/* FORGET IN KERNEL FILTERING */
1395 			return (0);
1396 		} else {
1397 
1398 			/* CHECK IF NO OR AHEAD */
1399 			sav_ptr = (char *)((uintptr_t)sav_str +
1400 						(uintptr_t)sav_tkp -
1401 						(uintptr_t)argstr);
1402 			ptr = sav_ptr;
1403 			while (*ptr != '\0') {
1404 				switch (*ptr) {
1405 				case '(':
1406 					inBr++;
1407 					break;
1408 				case ')':
1409 					inBr--;
1410 					break;
1411 				case 'o':
1412 				case 'O':
1413 					if ((*(ptr + 1) == 'R' ||
1414 						*(ptr + 1) == 'r') && !inBr)
1415 						aheadOR = 1;
1416 					break;
1417 				case ',':
1418 					if (!inBr)
1419 						aheadOR = 1;
1420 					break;
1421 				}
1422 				ptr++;
1423 			}
1424 			if (!aheadOR) {
1425 				/* NO OR AHEAD, SPLIT UP THE FILTERING */
1426 				pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1427 				pf.Pf_Priority = 5;
1428 				if (print) {
1429 					pf_codeprint(&pf.Pf_Filter[0],
1430 							pf.Pf_FilterLen);
1431 				}
1432 				compile(sav_ptr, print);
1433 				return (2);
1434 			} else
1435 				return (0);
1436 		}
1437 	}
1438 
1439 	pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1440 	pf.Pf_Priority = 5;	/* unimportant, so long as > 2 */
1441 	if (print) {
1442 		pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen);
1443 	}
1444 	return (1);
1445 }
1446