1 /*	$FreeBSD$	*/
2 
3 /*
4  * Copyright (C) 2001-2005 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if !defined(lint)
9 static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10 static const char rcsid[] = "@(#)$Id: ipfcomp.c,v 1.24.2.7 2007/05/01 22:15:00 darrenr Exp $";
11 #endif
12 
13 #include "ipf.h"
14 
15 
16 typedef struct {
17 	int c;
18 	int e;
19 	int n;
20 	int p;
21 	int s;
22 } mc_t;
23 
24 
25 static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" };
26 static int count = 0;
27 
28 int intcmp __P((const void *, const void *));
29 static void indent __P((FILE *, int));
30 static void printeq __P((FILE *, char *, int, int, int));
31 static void printipeq __P((FILE *, char *, int, int, int));
32 static void addrule __P((FILE *, frentry_t *));
33 static void printhooks __P((FILE *, int, int, frgroup_t *));
34 static void emitheader __P((frgroup_t *, u_int, u_int));
35 static void emitGroup __P((int, int, void *, frentry_t *, char *,
36 			   u_int, u_int));
37 static void emittail __P((void));
38 static void printCgroup __P((int, frentry_t *, mc_t *, char *));
39 
40 #define	FRC_IFN	0
41 #define	FRC_V	1
42 #define	FRC_P	2
43 #define	FRC_FL	3
44 #define	FRC_TOS	4
45 #define	FRC_TTL	5
46 #define	FRC_SRC	6
47 #define	FRC_DST	7
48 #define	FRC_TCP	8
49 #define	FRC_SP	9
50 #define	FRC_DP	10
51 #define	FRC_OPT	11
52 #define	FRC_SEC	12
53 #define	FRC_ATH	13
54 #define	FRC_ICT	14
55 #define	FRC_ICC	15
56 #define	FRC_MAX	16
57 
58 
59 static	FILE	*cfile = NULL;
60 
61 /*
62  * This is called once per filter rule being loaded to emit data structures
63  * required.
64  */
65 void printc(fr)
66 frentry_t *fr;
67 {
68 	fripf_t *ipf;
69 	u_long *ulp;
70 	char *and;
71 	FILE *fp;
72 	int i;
73 
74 	if (fr->fr_v != 4)
75 		return;
76 	if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE))
77 		return;
78 	if ((fr->fr_type == FR_T_IPF) &&
79 	    ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL)))
80 		return;
81 	ipf = fr->fr_ipf;
82 
83 	if (cfile == NULL)
84 		cfile = fopen("ip_rules.c", "w");
85 	if (cfile == NULL)
86 		return;
87 	fp = cfile;
88 	if (count == 0) {
89 		fprintf(fp, "/*\n");
90  		fprintf(fp, "* Copyright (C) 1993-2000 by Darren Reed.\n");
91  		fprintf(fp, "*\n");
92  		fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n");
93  		fprintf(fp, "* provided that this notice is preserved and due credit is given\n");
94  		fprintf(fp, "* to the original author and the contributors.\n");
95  		fprintf(fp, "*/\n\n");
96 
97 		fprintf(fp, "#include <sys/param.h>\n");
98 		fprintf(fp, "#include <sys/types.h>\n");
99 		fprintf(fp, "#include <sys/time.h>\n");
100 		fprintf(fp, "#include <sys/socket.h>\n");
101 		fprintf(fp, "#if (__FreeBSD_version >= 40000)\n");
102 		fprintf(fp, "# if defined(_KERNEL)\n");
103 		fprintf(fp, "#  include <sys/libkern.h>\n");
104 		fprintf(fp, "# else\n");
105 		fprintf(fp, "#  include <sys/unistd.h>\n");
106 		fprintf(fp, "# endif\n");
107 		fprintf(fp, "#endif\n");
108 		fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n");
109 		fprintf(fp, "#else\n");
110 		fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n");
111 		fprintf(fp, "#  include <sys/systm.h>\n");
112 		fprintf(fp, "# endif\n");
113 		fprintf(fp, "#endif\n");
114 		fprintf(fp, "#include <sys/errno.h>\n");
115 		fprintf(fp, "#include <sys/param.h>\n");
116 		fprintf(fp,
117 "#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n");
118 		fprintf(fp, "# include <sys/mbuf.h>\n");
119 		fprintf(fp, "#endif\n");
120 		fprintf(fp,
121 "#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n");
122 		fprintf(fp, "# include <sys/sockio.h>\n");
123 		fprintf(fp, "#else\n");
124 		fprintf(fp, "# include <sys/ioctl.h>\n");
125 		fprintf(fp, "#endif /* FreeBSD */\n");
126 		fprintf(fp, "#include <net/if.h>\n");
127 		fprintf(fp, "#include <netinet/in.h>\n");
128 		fprintf(fp, "#include <netinet/in_systm.h>\n");
129 		fprintf(fp, "#include <netinet/ip.h>\n");
130 		fprintf(fp, "#include <netinet/tcp.h>\n");
131 		fprintf(fp, "#include \"netinet/ip_compat.h\"\n");
132 		fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n");
133 		fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n");
134 		fprintf(fp, "#ifndef _KERNEL\n");
135 		fprintf(fp, "# include <string.h>\n");
136 		fprintf(fp, "#endif /* _KERNEL */\n");
137 		fprintf(fp, "\n");
138 		fprintf(fp, "#ifdef IPFILTER_COMPILED\n");
139 	}
140 
141 	addrule(fp, fr);
142 	fr->fr_type |= FR_T_BUILTIN;
143 	and = "";
144 	fr->fr_ref = 1;
145 	i = sizeof(*fr);
146 	if (i & -(1 - sizeof(*ulp)))
147 		i += sizeof(u_long);
148 	for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) {
149 		fprintf(fp, "%s%#lx", and, *ulp++);
150 		and = ", ";
151 	}
152 	fprintf(fp, "\n};\n");
153 	fr->fr_type &= ~FR_T_BUILTIN;
154 
155 	count++;
156 
157 	fflush(fp);
158 }
159 
160 
161 static frgroup_t *groups = NULL;
162 
163 
164 static void addrule(fp, fr)
165 FILE *fp;
166 frentry_t *fr;
167 {
168 	frentry_t *f, **fpp;
169 	frgroup_t *g;
170 	u_long *ulp;
171 	char *and;
172 	int i;
173 
174 	f = (frentry_t *)malloc(sizeof(*f));
175 	bcopy((char *)fr, (char *)f, sizeof(*fr));
176 	if (fr->fr_ipf) {
177 		f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf));
178 		bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf,
179 		      sizeof(*fr->fr_ipf));
180 	}
181 
182 	f->fr_next = NULL;
183 	for (g = groups; g != NULL; g = g->fg_next)
184 		if ((strncmp(g->fg_name, f->fr_group, FR_GROUPLEN) == 0) &&
185 		    (g->fg_flags == (f->fr_flags & FR_INOUT)))
186 			break;
187 
188 	if (g == NULL) {
189 		g = (frgroup_t *)calloc(1, sizeof(*g));
190 		g->fg_next = groups;
191 		groups = g;
192 		g->fg_head = f;
193 		bcopy(f->fr_group, g->fg_name, FR_GROUPLEN);
194 		g->fg_ref = 0;
195 		g->fg_flags = f->fr_flags & FR_INOUT;
196 	}
197 
198 	for (fpp = &g->fg_start; *fpp != NULL; )
199 		fpp = &((*fpp)->fr_next);
200 	*fpp = f;
201 
202 	if (fr->fr_dsize > 0) {
203 		fprintf(fp, "\
204 static u_long ipf%s_rule_data_%s_%u[] = {\n",
205 			f->fr_flags & FR_INQUE ? "in" : "out",
206 			g->fg_name, g->fg_ref);
207 		and = "";
208 		i = fr->fr_dsize;
209 		ulp = fr->fr_data;
210 		for (i /= sizeof(u_long); i > 0; i--) {
211 			fprintf(fp, "%s%#lx", and, *ulp++);
212 			and = ", ";
213 		}
214 		fprintf(fp, "\n};\n");
215 	}
216 
217 	fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n",
218 		f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref);
219 
220 	g->fg_ref++;
221 
222 	if (f->fr_grhead != 0) {
223 		for (g = groups; g != NULL; g = g->fg_next)
224 			if ((strncmp(g->fg_name, f->fr_grhead,
225 				     FR_GROUPLEN) == 0) &&
226 			    g->fg_flags == (f->fr_flags & FR_INOUT))
227 				break;
228 		if (g == NULL) {
229 			g = (frgroup_t *)calloc(1, sizeof(*g));
230 			g->fg_next = groups;
231 			groups = g;
232 			g->fg_head = f;
233 			bcopy(f->fr_grhead, g->fg_name, FR_GROUPLEN);
234 			g->fg_ref = 0;
235 			g->fg_flags = f->fr_flags & FR_INOUT;
236 		}
237 	}
238 }
239 
240 
241 int intcmp(c1, c2)
242 const void *c1, *c2;
243 {
244 	const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2;
245 
246 	if (i1->n == i2->n) {
247 		return i1->c - i2->c;
248 	}
249 	return i2->n - i1->n;
250 }
251 
252 
253 static void indent(fp, in)
254 FILE *fp;
255 int in;
256 {
257 	for (; in; in--)
258 		fputc('\t', fp);
259 }
260 
261 static void printeq(fp, var, m, max, v)
262 FILE *fp;
263 char *var;
264 int m, max, v;
265 {
266 	if (m == max)
267 		fprintf(fp, "%s == %#x) {\n", var, v);
268 	else
269 		fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v);
270 }
271 
272 /*
273  * Parameters: var - IP# being compared
274  *             fl - 0 for positive match, 1 for negative match
275  *             m - netmask
276  *             v - required address
277  */
278 static void printipeq(fp, var, fl, m, v)
279 FILE *fp;
280 char *var;
281 int fl, m, v;
282 {
283 	if (m == 0xffffffff)
284 		fprintf(fp, "%s ", var);
285 	else
286 		fprintf(fp, "(%s & %#x) ", var, m);
287 	fprintf(fp, "%c", fl ? '!' : '=');
288 	fprintf(fp, "= %#x) {\n", v);
289 }
290 
291 
292 void emit(num, dir, v, fr)
293 int num, dir;
294 void *v;
295 frentry_t *fr;
296 {
297 	u_int incnt, outcnt;
298 	frgroup_t *g;
299 	frentry_t *f;
300 
301 	for (g = groups; g != NULL; g = g->fg_next) {
302 		if (dir == 0 || dir == -1) {
303 			if ((g->fg_flags & FR_INQUE) == 0)
304 				continue;
305 			for (incnt = 0, f = g->fg_start; f != NULL;
306 			     f = f->fr_next)
307 				incnt++;
308 			emitGroup(num, dir, v, fr, g->fg_name, incnt, 0);
309 		}
310 		if (dir == 1 || dir == -1) {
311 			if ((g->fg_flags & FR_OUTQUE) == 0)
312 				continue;
313 			for (outcnt = 0, f = g->fg_start; f != NULL;
314 			     f = f->fr_next)
315 				outcnt++;
316 			emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt);
317 		}
318 	}
319 
320 	if (num == -1 && dir == -1) {
321 		for (g = groups; g != NULL; g = g->fg_next) {
322 			if ((g->fg_flags & FR_INQUE) != 0) {
323 				for (incnt = 0, f = g->fg_start; f != NULL;
324 				     f = f->fr_next)
325 					incnt++;
326 				if (incnt > 0)
327 					emitheader(g, incnt, 0);
328 			}
329 			if ((g->fg_flags & FR_OUTQUE) != 0) {
330 				for (outcnt = 0, f = g->fg_start; f != NULL;
331 				     f = f->fr_next)
332 					outcnt++;
333 				if (outcnt > 0)
334 					emitheader(g, 0, outcnt);
335 			}
336 		}
337 		emittail();
338 		fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n");
339 	}
340 
341 }
342 
343 
344 static void emitheader(grp, incount, outcount)
345 frgroup_t *grp;
346 u_int incount, outcount;
347 {
348 	static FILE *fph = NULL;
349 	frgroup_t *g;
350 
351 	if (fph == NULL) {
352 		fph = fopen("ip_rules.h", "w");
353 		if (fph == NULL)
354 			return;
355 
356 		fprintf(fph, "extern int ipfrule_add __P((void));\n");
357 		fprintf(fph, "extern int ipfrule_remove __P((void));\n");
358 	}
359 
360 	printhooks(cfile, incount, outcount, grp);
361 
362 	if (incount) {
363 		fprintf(fph, "\n\
364 extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\
365 extern frentry_t *ipf_rules_in_%s[%d];\n",
366 			grp->fg_name, grp->fg_name, incount);
367 
368 		for (g = groups; g != grp; g = g->fg_next)
369 			if ((strncmp(g->fg_name, grp->fg_name,
370 				     FR_GROUPLEN) == 0) &&
371 			    g->fg_flags == grp->fg_flags)
372 				break;
373 		if (g == grp) {
374 			fprintf(fph, "\n\
375 extern int ipfrule_add_in_%s __P((void));\n\
376 extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name);
377 		}
378 	}
379 	if (outcount) {
380 		fprintf(fph, "\n\
381 extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\
382 extern frentry_t *ipf_rules_out_%s[%d];\n",
383 			grp->fg_name, grp->fg_name, outcount);
384 
385 		for (g = groups; g != grp; g = g->fg_next)
386 			if ((strncmp(g->fg_name, grp->fg_name,
387 				     FR_GROUPLEN) == 0) &&
388 			    g->fg_flags == grp->fg_flags)
389 				break;
390 		if (g == grp) {
391 			fprintf(fph, "\n\
392 extern int ipfrule_add_out_%s __P((void));\n\
393 extern int ipfrule_remove_out_%s __P((void));\n",
394 				grp->fg_name, grp->fg_name);
395 		}
396 	}
397 }
398 
399 static void emittail()
400 {
401 	frgroup_t *g;
402 
403 	fprintf(cfile, "\n\
404 int ipfrule_add()\n\
405 {\n\
406 	int err;\n\
407 \n");
408 	for (g = groups; g != NULL; g = g->fg_next)
409 		fprintf(cfile, "\
410 	err = ipfrule_add_%s_%s();\n\
411 	if (err != 0)\n\
412 		return err;\n",
413 			(g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
414 	fprintf(cfile, "\
415 	return 0;\n");
416 	fprintf(cfile, "}\n\
417 \n");
418 
419 	fprintf(cfile, "\n\
420 int ipfrule_remove()\n\
421 {\n\
422 	int err;\n\
423 \n");
424 	for (g = groups; g != NULL; g = g->fg_next)
425 		fprintf(cfile, "\
426 	err = ipfrule_remove_%s_%s();\n\
427 	if (err != 0)\n\
428 		return err;\n",
429 			(g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
430 	fprintf(cfile, "\
431 	return 0;\n");
432 	fprintf(cfile, "}\n");
433 }
434 
435 
436 static void emitGroup(num, dir, v, fr, group, incount, outcount)
437 int num, dir;
438 void *v;
439 frentry_t *fr;
440 char *group;
441 u_int incount, outcount;
442 {
443 	static FILE *fp = NULL;
444 	static int header[2] = { 0, 0 };
445 	static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
446 	static int openfunc = 0;
447 	static mc_t *n = NULL;
448 	static int sin = 0;
449 	frentry_t *f;
450 	frgroup_t *g;
451 	fripf_t *ipf;
452 	int i, in, j;
453 	mc_t *m = v;
454 
455 	if (fp == NULL)
456 		fp = cfile;
457 	if (fp == NULL)
458 		return;
459 	if (strncmp(egroup, group, FR_GROUPLEN)) {
460 		for (sin--; sin > 0; sin--) {
461 			indent(fp, sin);
462 			fprintf(fp, "}\n");
463 		}
464 		if (openfunc == 1) {
465 			fprintf(fp, "\treturn fr;\n}\n");
466 			openfunc = 0;
467 			if (n != NULL) {
468 				free(n);
469 				n = NULL;
470 			}
471 		}
472 		sin = 0;
473 		header[0] = 0;
474 		header[1] = 0;
475 		strncpy(egroup, group, FR_GROUPLEN);
476 	} else if (openfunc == 1 && num < 0) {
477 		if (n != NULL) {
478 			free(n);
479 			n = NULL;
480 		}
481 		for (sin--; sin > 0; sin--) {
482 			indent(fp, sin);
483 			fprintf(fp, "}\n");
484 		}
485 		if (openfunc == 1) {
486 			fprintf(fp, "\treturn fr;\n}\n");
487 			openfunc = 0;
488 		}
489 	}
490 
491 	if (dir == -1)
492 		return;
493 
494 	for (g = groups; g != NULL; g = g->fg_next) {
495 		if (dir == 0 && (g->fg_flags & FR_INQUE) == 0)
496 			continue;
497 		else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0)
498 			continue;
499 		if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0)
500 			continue;
501 		break;
502 	}
503 
504 	/*
505 	 * Output the array of pointers to rules for this group.
506 	 */
507 	if (g != NULL && num == -2 && dir == 0 && header[0] == 0 &&
508 	    incount != 0) {
509 		fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {",
510 			group, incount);
511 		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
512 			if ((f->fr_flags & FR_INQUE) == 0)
513 				continue;
514 			if ((i & 1) == 0) {
515 				fprintf(fp, "\n\t");
516 			}
517 			fprintf(fp,
518 				"(frentry_t *)&in_rule_%s_%d",
519 				f->fr_group, i);
520 			if (i + 1 < incount)
521 				fprintf(fp, ", ");
522 			i++;
523 		}
524 		fprintf(fp, "\n};\n");
525 	}
526 
527 	if (g != NULL && num == -2 && dir == 1 && header[0] == 0 &&
528 	    outcount != 0) {
529 		fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {",
530 			group, outcount);
531 		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
532 			if ((f->fr_flags & FR_OUTQUE) == 0)
533 				continue;
534 			if ((i & 1) == 0) {
535 				fprintf(fp, "\n\t");
536 			}
537 			fprintf(fp,
538 				"(frentry_t *)&out_rule_%s_%d",
539 				f->fr_group, i);
540 			if (i + 1 < outcount)
541 				fprintf(fp, ", ");
542 			i++;
543 		}
544 		fprintf(fp, "\n};\n");
545 		fp = NULL;
546 	}
547 
548 	if (num < 0)
549 		return;
550 
551 	in = 0;
552 	ipf = fr->fr_ipf;
553 
554 	/*
555 	 * If the function header has not been printed then print it now.
556 	 */
557 	if (g != NULL && header[dir] == 0) {
558 		int pdst = 0, psrc = 0;
559 
560 		openfunc = 1;
561 		fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n",
562 			(dir == 0) ? "in" : "out", group);
563 		fprintf(fp, "fr_info_t *fin;\n");
564 		fprintf(fp, "u_32_t *passp;\n");
565 		fprintf(fp, "{\n");
566 		fprintf(fp, "\tfrentry_t *fr = NULL;\n");
567 
568 		/*
569 		 * Print out any variables that need to be declared.
570 		 */
571 		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
572 			if (incount + outcount > m[FRC_SRC].e + 1)
573 				psrc = 1;
574 			if (incount + outcount > m[FRC_DST].e + 1)
575 				pdst = 1;
576 		}
577 		if (psrc == 1)
578 			fprintf(fp, "\tu_32_t src = ntohl(%s);\n",
579 				"fin->fin_fi.fi_saddr");
580 		if (pdst == 1)
581 			fprintf(fp, "\tu_32_t dst = ntohl(%s);\n",
582 				"fin->fin_fi.fi_daddr");
583 	}
584 
585 	for (i = 0; i < FRC_MAX; i++) {
586 		switch(m[i].c)
587 		{
588 		case FRC_IFN :
589 			if (*fr->fr_ifname)
590 				m[i].s = 1;
591 			break;
592 		case FRC_V :
593 			if (ipf != NULL && ipf->fri_mip.fi_v != 0)
594 				m[i].s = 1;
595 			break;
596 		case FRC_FL :
597 			if (ipf != NULL && ipf->fri_mip.fi_flx != 0)
598 				m[i].s = 1;
599 			break;
600 		case FRC_P :
601 			if (ipf != NULL && ipf->fri_mip.fi_p != 0)
602 				m[i].s = 1;
603 			break;
604 		case FRC_TTL :
605 			if (ipf != NULL && ipf->fri_mip.fi_ttl != 0)
606 				m[i].s = 1;
607 			break;
608 		case FRC_TOS :
609 			if (ipf != NULL && ipf->fri_mip.fi_tos != 0)
610 				m[i].s = 1;
611 			break;
612 		case FRC_TCP :
613 			if (ipf == NULL)
614 				break;
615 			if ((ipf->fri_ip.fi_p == IPPROTO_TCP) &&
616 			    fr->fr_tcpfm != 0)
617 				m[i].s = 1;
618 			break;
619 		case FRC_SP :
620 			if (ipf == NULL)
621 				break;
622 			if (fr->fr_scmp == FR_INRANGE)
623 				m[i].s = 1;
624 			else if (fr->fr_scmp == FR_OUTRANGE)
625 				m[i].s = 1;
626 			else if (fr->fr_scmp != 0)
627 				m[i].s = 1;
628 			break;
629 		case FRC_DP :
630 			if (ipf == NULL)
631 				break;
632 			if (fr->fr_dcmp == FR_INRANGE)
633 				m[i].s = 1;
634 			else if (fr->fr_dcmp == FR_OUTRANGE)
635 				m[i].s = 1;
636 			else if (fr->fr_dcmp != 0)
637 				m[i].s = 1;
638 			break;
639 		case FRC_SRC :
640 			if (ipf == NULL)
641 				break;
642 			if (fr->fr_satype == FRI_LOOKUP) {
643 				;
644 			} else if ((fr->fr_smask != 0) ||
645 				   (fr->fr_flags & FR_NOTSRCIP) != 0)
646 				m[i].s = 1;
647 			break;
648 		case FRC_DST :
649 			if (ipf == NULL)
650 				break;
651 			if (fr->fr_datype == FRI_LOOKUP) {
652 				;
653 			} else if ((fr->fr_dmask != 0) ||
654 				   (fr->fr_flags & FR_NOTDSTIP) != 0)
655 				m[i].s = 1;
656 			break;
657 		case FRC_OPT :
658 			if (ipf == NULL)
659 				break;
660 			if (fr->fr_optmask != 0)
661 				m[i].s = 1;
662 			break;
663 		case FRC_SEC :
664 			if (ipf == NULL)
665 				break;
666 			if (fr->fr_secmask != 0)
667 				m[i].s = 1;
668 			break;
669 		case FRC_ATH :
670 			if (ipf == NULL)
671 				break;
672 			if (fr->fr_authmask != 0)
673 				m[i].s = 1;
674 			break;
675 		case FRC_ICT :
676 			if (ipf == NULL)
677 				break;
678 			if ((fr->fr_icmpm & 0xff00) != 0)
679 				m[i].s = 1;
680 			break;
681 		case FRC_ICC :
682 			if (ipf == NULL)
683 				break;
684 			if ((fr->fr_icmpm & 0xff) != 0)
685 				m[i].s = 1;
686 			break;
687 		}
688 	}
689 
690 	if (!header[dir]) {
691 		fprintf(fp, "\n");
692 		header[dir] = 1;
693 		sin = 0;
694 	}
695 
696 	qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
697 
698 	if (n) {
699 		/*
700 		 * Calculate the indentation interval upto the last common
701 		 * common comparison being made.
702 		 */
703 		for (i = 0, in = 1; i < FRC_MAX; i++) {
704 			if (n[i].c != m[i].c)
705 				break;
706 			if (n[i].s != m[i].s)
707 				break;
708 			if (n[i].s) {
709 				if (n[i].n && (n[i].n > n[i].e)) {
710 					m[i].p++;
711 					in += m[i].p;
712 					break;
713 				}
714 				if (n[i].e > 0) {
715 					in++;
716 				} else
717 					break;
718 			}
719 		}
720 		if (sin != in) {
721 			for (j = sin - 1; j >= in; j--) {
722 				indent(fp, j);
723 				fprintf(fp, "}\n");
724 			}
725 		}
726 	} else {
727 		in = 1;
728 		i = 0;
729 	}
730 
731 	/*
732 	 * print out C code that implements a filter rule.
733 	 */
734 	for (; i < FRC_MAX; i++) {
735 		switch(m[i].c)
736 		{
737 		case FRC_IFN :
738 			if (m[i].s) {
739 				indent(fp, in);
740 				fprintf(fp, "if (fin->fin_ifp == ");
741 				fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n",
742 					dir ? "out" : "in", group, num);
743 				in++;
744 			}
745 			break;
746 		case FRC_V :
747 			if (m[i].s) {
748 				indent(fp, in);
749 				fprintf(fp, "if (fin->fin_v == %d) {\n",
750 					ipf->fri_ip.fi_v);
751 				in++;
752 			}
753 			break;
754 		case FRC_FL :
755 			if (m[i].s) {
756 				indent(fp, in);
757 				fprintf(fp, "if (");
758 				printeq(fp, "fin->fin_flx",
759 				        ipf->fri_mip.fi_flx, 0xf,
760 					ipf->fri_ip.fi_flx);
761 				in++;
762 			}
763 			break;
764 		case FRC_P :
765 			if (m[i].s) {
766 				indent(fp, in);
767 				fprintf(fp, "if (fin->fin_p == %d) {\n",
768 					ipf->fri_ip.fi_p);
769 				in++;
770 			}
771 			break;
772 		case FRC_TTL :
773 			if (m[i].s) {
774 				indent(fp, in);
775 				fprintf(fp, "if (");
776 				printeq(fp, "fin->fin_ttl",
777 					ipf->fri_mip.fi_ttl, 0xff,
778 					ipf->fri_ip.fi_ttl);
779 				in++;
780 			}
781 			break;
782 		case FRC_TOS :
783 			if (m[i].s) {
784 				indent(fp, in);
785 				fprintf(fp, "if (fin->fin_tos");
786 				printeq(fp, "fin->fin_tos",
787 					ipf->fri_mip.fi_tos, 0xff,
788 					ipf->fri_ip.fi_tos);
789 				in++;
790 			}
791 			break;
792 		case FRC_TCP :
793 			if (m[i].s) {
794 				indent(fp, in);
795 				fprintf(fp, "if (");
796 				printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm,
797 					0xff, fr->fr_tcpf);
798 				in++;
799 			}
800 			break;
801 		case FRC_SP :
802 			if (!m[i].s)
803 				break;
804 			if (fr->fr_scmp == FR_INRANGE) {
805 				indent(fp, in);
806 				fprintf(fp, "if ((fin->fin_data[0] > %d) && ",
807 					fr->fr_sport);
808 				fprintf(fp, "(fin->fin_data[0] < %d)",
809 					fr->fr_stop);
810 				fprintf(fp, ") {\n");
811 				in++;
812 			} else if (fr->fr_scmp == FR_OUTRANGE) {
813 				indent(fp, in);
814 				fprintf(fp, "if ((fin->fin_data[0] < %d) || ",
815 					fr->fr_sport);
816 				fprintf(fp, "(fin->fin_data[0] > %d)",
817 					fr->fr_stop);
818 				fprintf(fp, ") {\n");
819 				in++;
820 			} else if (fr->fr_scmp) {
821 				indent(fp, in);
822 				fprintf(fp, "if (fin->fin_data[0] %s %d)",
823 					portcmp[fr->fr_scmp], fr->fr_sport);
824 				fprintf(fp, " {\n");
825 				in++;
826 			}
827 			break;
828 		case FRC_DP :
829 			if (!m[i].s)
830 				break;
831 			if (fr->fr_dcmp == FR_INRANGE) {
832 				indent(fp, in);
833 				fprintf(fp, "if ((fin->fin_data[1] > %d) && ",
834 					fr->fr_dport);
835 				fprintf(fp, "(fin->fin_data[1] < %d)",
836 					fr->fr_dtop);
837 				fprintf(fp, ") {\n");
838 				in++;
839 			} else if (fr->fr_dcmp == FR_OUTRANGE) {
840 				indent(fp, in);
841 				fprintf(fp, "if ((fin->fin_data[1] < %d) || ",
842 					fr->fr_dport);
843 				fprintf(fp, "(fin->fin_data[1] > %d)",
844 					fr->fr_dtop);
845 				fprintf(fp, ") {\n");
846 				in++;
847 			} else if (fr->fr_dcmp) {
848 				indent(fp, in);
849 				fprintf(fp, "if (fin->fin_data[1] %s %d)",
850 					portcmp[fr->fr_dcmp], fr->fr_dport);
851 				fprintf(fp, " {\n");
852 				in++;
853 			}
854 			break;
855 		case FRC_SRC :
856 			if (!m[i].s)
857 				break;
858 			if (fr->fr_satype == FRI_LOOKUP) {
859 				;
860 			} else if ((fr->fr_smask != 0) ||
861 				   (fr->fr_flags & FR_NOTSRCIP) != 0) {
862 				indent(fp, in);
863 				fprintf(fp, "if (");
864 				printipeq(fp, "src",
865 					  fr->fr_flags & FR_NOTSRCIP,
866 					  fr->fr_smask, fr->fr_saddr);
867 				in++;
868 			}
869 			break;
870 		case FRC_DST :
871 			if (!m[i].s)
872 				break;
873 			if (fr->fr_datype == FRI_LOOKUP) {
874 				;
875 			} else if ((fr->fr_dmask != 0) ||
876 				   (fr->fr_flags & FR_NOTDSTIP) != 0) {
877 				indent(fp, in);
878 				fprintf(fp, "if (");
879 				printipeq(fp, "dst",
880 					  fr->fr_flags & FR_NOTDSTIP,
881 					  fr->fr_dmask, fr->fr_daddr);
882 				in++;
883 			}
884 			break;
885 		case FRC_OPT :
886 			if (m[i].s) {
887 				indent(fp, in);
888 				fprintf(fp, "if (");
889 				printeq(fp, "fin->fin_fi.fi_optmsk",
890 					fr->fr_optmask, 0xffffffff,
891 				        fr->fr_optbits);
892 				in++;
893 			}
894 			break;
895 		case FRC_SEC :
896 			if (m[i].s) {
897 				indent(fp, in);
898 				fprintf(fp, "if (");
899 				printeq(fp, "fin->fin_fi.fi_secmsk",
900 					fr->fr_secmask, 0xffff,
901 					fr->fr_secbits);
902 				in++;
903 			}
904 			break;
905 		case FRC_ATH :
906 			if (m[i].s) {
907 				indent(fp, in);
908 				fprintf(fp, "if (");
909 				printeq(fp, "fin->fin_fi.fi_authmsk",
910 					fr->fr_authmask, 0xffff,
911 					fr->fr_authbits);
912 				in++;
913 			}
914 			break;
915 		case FRC_ICT :
916 			if (m[i].s) {
917 				indent(fp, in);
918 				fprintf(fp, "if (");
919 				printeq(fp, "fin->fin_data[0]",
920 					fr->fr_icmpm & 0xff00, 0xffff,
921 					fr->fr_icmp & 0xff00);
922 				in++;
923 			}
924 			break;
925 		case FRC_ICC :
926 			if (m[i].s) {
927 				indent(fp, in);
928 				fprintf(fp, "if (");
929 				printeq(fp, "fin->fin_data[0]",
930 					fr->fr_icmpm & 0xff, 0xffff,
931 					fr->fr_icmp & 0xff);
932 				in++;
933 			}
934 			break;
935 		}
936 
937 	}
938 
939 	indent(fp, in);
940 	if (fr->fr_flags & FR_QUICK) {
941 		fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n",
942 			fr->fr_flags & FR_INQUE ? "in" : "out",
943 			fr->fr_group, num);
944 	} else {
945 		fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n",
946 			fr->fr_flags & FR_INQUE ? "in" : "out",
947 			fr->fr_group, num);
948 	}
949 	if (n == NULL)
950 		n = (mc_t *)malloc(sizeof(*n) * FRC_MAX);
951 	bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX);
952 	sin = in;
953 }
954 
955 
956 void printC(dir)
957 int dir;
958 {
959 	static mc_t *m = NULL;
960 	frgroup_t *g;
961 
962 	if (m == NULL)
963 		m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX);
964 
965 	for (g = groups; g != NULL; g = g->fg_next) {
966 		if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0))
967 			printCgroup(dir, g->fg_start, m, g->fg_name);
968 		if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0))
969 			printCgroup(dir, g->fg_start, m, g->fg_name);
970 	}
971 
972 	emit(-1, dir, m, NULL);
973 }
974 
975 
976 /*
977  * Now print out code to implement all of the rules.
978  */
979 static void printCgroup(dir, top, m, group)
980 int dir;
981 frentry_t *top;
982 mc_t *m;
983 char *group;
984 {
985 	frentry_t *fr, *fr1;
986 	int i, n, rn;
987 	u_int count;
988 
989 	for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) {
990 		if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0))
991 			count++;
992 		else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0))
993 			count++;
994 	}
995 
996 	if (dir == 0)
997 		emitGroup(-2, dir, m, fr1, group, count, 0);
998 	else if (dir == 1)
999 		emitGroup(-2, dir, m, fr1, group, 0, count);
1000 
1001 	/*
1002 	 * Before printing each rule, check to see how many of its fields are
1003 	 * matched by subsequent rules.
1004 	 */
1005 	for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) {
1006 		if (!dir && !(fr1->fr_flags & FR_INQUE))
1007 			continue;
1008 		if (dir && !(fr1->fr_flags & FR_OUTQUE))
1009 			continue;
1010 		n = 0xfffffff;
1011 
1012 		for (i = 0; i < FRC_MAX; i++)
1013 			m[i].e = 0;
1014 		qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
1015 
1016 		for (i = 0; i < FRC_MAX; i++) {
1017 			m[i].c = i;
1018 			m[i].e = 0;
1019 			m[i].n = 0;
1020 			m[i].s = 0;
1021 		}
1022 
1023 		for (fr = fr1->fr_next; fr; fr = fr->fr_next) {
1024 			if (!dir && !(fr->fr_flags & FR_INQUE))
1025 				continue;
1026 			if (dir && !(fr->fr_flags & FR_OUTQUE))
1027 				continue;
1028 
1029 			if ((n & 0x0001) &&
1030 			    !strcmp(fr1->fr_ifname, fr->fr_ifname)) {
1031 				m[FRC_IFN].e++;
1032 				m[FRC_IFN].n++;
1033 			} else
1034 				n &= ~0x0001;
1035 
1036 			if ((n & 0x0002) && (fr1->fr_v == fr->fr_v)) {
1037 				m[FRC_V].e++;
1038 				m[FRC_V].n++;
1039 			} else
1040 				n &= ~0x0002;
1041 
1042 			if ((n & 0x0004) &&
1043 			    (fr->fr_type == fr1->fr_type) &&
1044 			    (fr->fr_type == FR_T_IPF) &&
1045 			    (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) &&
1046 			    (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) {
1047 				m[FRC_FL].e++;
1048 				m[FRC_FL].n++;
1049 			} else
1050 				n &= ~0x0004;
1051 
1052 			if ((n & 0x0008) &&
1053 			    (fr->fr_type == fr1->fr_type) &&
1054 			    (fr->fr_type == FR_T_IPF) &&
1055 			    (fr1->fr_proto == fr->fr_proto)) {
1056 				m[FRC_P].e++;
1057 				m[FRC_P].n++;
1058 			} else
1059 				n &= ~0x0008;
1060 
1061 			if ((n & 0x0010) &&
1062 			    (fr->fr_type == fr1->fr_type) &&
1063 			    (fr->fr_type == FR_T_IPF) &&
1064 			    (fr1->fr_ttl == fr->fr_ttl)) {
1065 				m[FRC_TTL].e++;
1066 				m[FRC_TTL].n++;
1067 			} else
1068 				n &= ~0x0010;
1069 
1070 			if ((n & 0x0020) &&
1071 			    (fr->fr_type == fr1->fr_type) &&
1072 			    (fr->fr_type == FR_T_IPF) &&
1073 			    (fr1->fr_tos == fr->fr_tos)) {
1074 				m[FRC_TOS].e++;
1075 				m[FRC_TOS].n++;
1076 			} else
1077 				n &= ~0x0020;
1078 
1079 			if ((n & 0x0040) &&
1080 			    (fr->fr_type == fr1->fr_type) &&
1081 			    (fr->fr_type == FR_T_IPF) &&
1082 			    ((fr1->fr_tcpfm == fr->fr_tcpfm) &&
1083 			    (fr1->fr_tcpf == fr->fr_tcpf))) {
1084 				m[FRC_TCP].e++;
1085 				m[FRC_TCP].n++;
1086 			} else
1087 				n &= ~0x0040;
1088 
1089 			if ((n & 0x0080) &&
1090 			    (fr->fr_type == fr1->fr_type) &&
1091 			    (fr->fr_type == FR_T_IPF) &&
1092 			    ((fr1->fr_scmp == fr->fr_scmp) &&
1093 			     (fr1->fr_stop == fr->fr_stop) &&
1094 			     (fr1->fr_sport == fr->fr_sport))) {
1095 				m[FRC_SP].e++;
1096 				m[FRC_SP].n++;
1097 			} else
1098 				n &= ~0x0080;
1099 
1100 			if ((n & 0x0100) &&
1101 			    (fr->fr_type == fr1->fr_type) &&
1102 			    (fr->fr_type == FR_T_IPF) &&
1103 			    ((fr1->fr_dcmp == fr->fr_dcmp) &&
1104 			     (fr1->fr_dtop == fr->fr_dtop) &&
1105 			     (fr1->fr_dport == fr->fr_dport))) {
1106 				m[FRC_DP].e++;
1107 				m[FRC_DP].n++;
1108 			} else
1109 				n &= ~0x0100;
1110 
1111 			if ((n & 0x0200) &&
1112 			    (fr->fr_type == fr1->fr_type) &&
1113 			    (fr->fr_type == FR_T_IPF) &&
1114 			    ((fr1->fr_satype == FRI_LOOKUP) &&
1115 			    (fr->fr_satype == FRI_LOOKUP) &&
1116 			    (fr1->fr_srcnum == fr->fr_srcnum))) {
1117 				m[FRC_SRC].e++;
1118 				m[FRC_SRC].n++;
1119 			} else if ((n & 0x0200) &&
1120 				   (fr->fr_type == fr1->fr_type) &&
1121 				   (fr->fr_type == FR_T_IPF) &&
1122 				   (((fr1->fr_flags & FR_NOTSRCIP) ==
1123 				    (fr->fr_flags & FR_NOTSRCIP)))) {
1124 					if ((fr1->fr_smask == fr->fr_smask) &&
1125 					    (fr1->fr_saddr == fr->fr_saddr))
1126 						m[FRC_SRC].e++;
1127 					else
1128 						n &= ~0x0200;
1129 					if (fr1->fr_smask &&
1130 					    (fr1->fr_saddr & fr1->fr_smask) ==
1131 					    (fr->fr_saddr & fr1->fr_smask)) {
1132 						m[FRC_SRC].n++;
1133 						n |= 0x0200;
1134 					}
1135 			} else {
1136 				n &= ~0x0200;
1137 			}
1138 
1139 			if ((n & 0x0400) &&
1140 			    (fr->fr_type == fr1->fr_type) &&
1141 			    (fr->fr_type == FR_T_IPF) &&
1142 			    ((fr1->fr_datype == FRI_LOOKUP) &&
1143 			    (fr->fr_datype == FRI_LOOKUP) &&
1144 			    (fr1->fr_dstnum == fr->fr_dstnum))) {
1145 				m[FRC_DST].e++;
1146 				m[FRC_DST].n++;
1147 			} else if ((n & 0x0400) &&
1148 				   (fr->fr_type == fr1->fr_type) &&
1149 				   (fr->fr_type == FR_T_IPF) &&
1150 				   (((fr1->fr_flags & FR_NOTDSTIP) ==
1151 				    (fr->fr_flags & FR_NOTDSTIP)))) {
1152 					if ((fr1->fr_dmask == fr->fr_dmask) &&
1153 					    (fr1->fr_daddr == fr->fr_daddr))
1154 						m[FRC_DST].e++;
1155 					else
1156 						n &= ~0x0400;
1157 					if (fr1->fr_dmask &&
1158 					    (fr1->fr_daddr & fr1->fr_dmask) ==
1159 					    (fr->fr_daddr & fr1->fr_dmask)) {
1160 						m[FRC_DST].n++;
1161 						n |= 0x0400;
1162 					}
1163 			} else {
1164 				n &= ~0x0400;
1165 			}
1166 
1167 			if ((n & 0x0800) &&
1168 			    (fr->fr_type == fr1->fr_type) &&
1169 			    (fr->fr_type == FR_T_IPF) &&
1170 			    (fr1->fr_optmask == fr->fr_optmask) &&
1171 			    (fr1->fr_optbits == fr->fr_optbits)) {
1172 				m[FRC_OPT].e++;
1173 				m[FRC_OPT].n++;
1174 			} else
1175 				n &= ~0x0800;
1176 
1177 			if ((n & 0x1000) &&
1178 			    (fr->fr_type == fr1->fr_type) &&
1179 			    (fr->fr_type == FR_T_IPF) &&
1180 			    (fr1->fr_secmask == fr->fr_secmask) &&
1181 			    (fr1->fr_secbits == fr->fr_secbits)) {
1182 				m[FRC_SEC].e++;
1183 				m[FRC_SEC].n++;
1184 			} else
1185 				n &= ~0x1000;
1186 
1187 			if ((n & 0x10000) &&
1188 			    (fr->fr_type == fr1->fr_type) &&
1189 			    (fr->fr_type == FR_T_IPF) &&
1190 			    (fr1->fr_authmask == fr->fr_authmask) &&
1191 			    (fr1->fr_authbits == fr->fr_authbits)) {
1192 				m[FRC_ATH].e++;
1193 				m[FRC_ATH].n++;
1194 			} else
1195 				n &= ~0x10000;
1196 
1197 			if ((n & 0x20000) &&
1198 			    (fr->fr_type == fr1->fr_type) &&
1199 			    (fr->fr_type == FR_T_IPF) &&
1200 			    ((fr1->fr_icmpm & 0xff00) ==
1201 			     (fr->fr_icmpm & 0xff00)) &&
1202 			    ((fr1->fr_icmp & 0xff00) ==
1203 			     (fr->fr_icmp & 0xff00))) {
1204 				m[FRC_ICT].e++;
1205 				m[FRC_ICT].n++;
1206 			} else
1207 				n &= ~0x20000;
1208 
1209 			if ((n & 0x40000) &&
1210 			    (fr->fr_type == fr1->fr_type) &&
1211 			    (fr->fr_type == FR_T_IPF) &&
1212 			    ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) &&
1213 			    ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) {
1214 				m[FRC_ICC].e++;
1215 				m[FRC_ICC].n++;
1216 			} else
1217 				n &= ~0x40000;
1218 		}
1219 		/*msort(m);*/
1220 
1221 		if (dir == 0)
1222 			emitGroup(rn, dir, m, fr1, group, count, 0);
1223 		else if (dir == 1)
1224 			emitGroup(rn, dir, m, fr1, group, 0, count);
1225 	}
1226 }
1227 
1228 static void printhooks(fp, in, out, grp)
1229 FILE *fp;
1230 int in;
1231 int out;
1232 frgroup_t *grp;
1233 {
1234 	frentry_t *fr;
1235 	char *group;
1236 	int dogrp, i;
1237 	char *instr;
1238 
1239 	group = grp->fg_name;
1240 	dogrp = *group ? 1 : 0;
1241 
1242 	if (in && out) {
1243 		fprintf(stderr,
1244 			"printhooks called with both in and out set\n");
1245 		exit(1);
1246 	}
1247 
1248 	if (in) {
1249 		instr = "in";
1250 	} else if (out) {
1251 		instr = "out";
1252 	} else {
1253 		instr = "???";
1254 	}
1255 	fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group);
1256 
1257 	fprintf(fp, "\
1258 \n\
1259 int ipfrule_add_%s_%s()\n", instr, group);
1260 	fprintf(fp, "\
1261 {\n\
1262 	int i, j, err = 0, max;\n\
1263 	frentry_t *fp;\n");
1264 
1265 	if (dogrp)
1266 		fprintf(fp, "\
1267 	frgroup_t *fg;\n");
1268 
1269 	fprintf(fp, "\n");
1270 
1271 	for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next)
1272 		if (fr->fr_dsize > 0) {
1273 			fprintf(fp, "\
1274 	ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n",
1275 				instr, grp->fg_name, i,
1276 				instr, grp->fg_name, i);
1277 		}
1278 	fprintf(fp, "\
1279 	max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\
1280 	for (i = 0; i < max; i++) {\n\
1281 		fp = ipf_rules_%s_%s[i];\n\
1282 		fp->fr_next = NULL;\n", instr, group, instr, group);
1283 
1284 	fprintf(fp, "\
1285 		for (j = i + 1; j < max; j++)\n\
1286 			if (strncmp(fp->fr_group,\n\
1287 				    ipf_rules_%s_%s[j]->fr_group,\n\
1288 				    FR_GROUPLEN) == 0) {\n\
1289 				fp->fr_next = ipf_rules_%s_%s[j];\n\
1290 				break;\n\
1291 			}\n", instr, group, instr, group);
1292 	if (dogrp)
1293 		fprintf(fp, "\
1294 \n\
1295 		if (fp->fr_grhead != 0) {\n\
1296 			fg = fr_addgroup(fp->fr_grhead, fp, FR_INQUE,\n\
1297 					 IPL_LOGIPF, 0);\n\
1298 			if (fg != NULL)\n\
1299 				fp->fr_grp = &fg->fg_start;\n\
1300 		}\n");
1301 	fprintf(fp, "\
1302 	}\n\
1303 \n\
1304 	fp = &ipfrule_%s_%s;\n", instr, group);
1305 		fprintf(fp, "\
1306 	bzero((char *)fp, sizeof(*fp));\n\
1307 	fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;\n\
1308 	fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\
1309 	fp->fr_data = (void *)ipf_rules_%s_%s[0];\n",
1310 		(in != 0) ? "IN" : "OUT", instr, group);
1311 	fprintf(fp, "\
1312 	fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n",
1313 		instr, group);
1314 
1315 	fprintf(fp, "\
1316 	fp->fr_v = 4;\n\
1317 	fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\
1318 	err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);\n",
1319 			instr, group);
1320 	fprintf(fp, "\treturn err;\n}\n");
1321 
1322 	fprintf(fp, "\n\n\
1323 int ipfrule_remove_%s_%s()\n", instr, group);
1324 	fprintf(fp, "\
1325 {\n\
1326 	int err = 0, i;\n\
1327 	frentry_t *fp;\n\
1328 \n\
1329 	/*\n\
1330 	 * Try to remove the %sbound rule.\n", instr);
1331 
1332 	fprintf(fp, "\
1333 	 */\n\
1334 	if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group);
1335 
1336 	fprintf(fp, "\
1337 		err = EBUSY;\n\
1338 	} else {\n");
1339 
1340 	fprintf(fp, "\
1341 		i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\
1342 		for (; i >= 0; i--) {\n\
1343 			fp = ipf_rules_%s_%s[i];\n\
1344 			if (fp->fr_ref > 1) {\n\
1345 				err = EBUSY;\n\
1346 				break;\n\
1347 			}\n\
1348 		}\n\
1349 	}\n\
1350 	if (err == 0)\n\
1351 		err = frrequest(IPL_LOGIPF, SIOCDELFR,\n\
1352 				(caddr_t)&ipfrule_%s_%s, fr_active, 0);\n",
1353 		instr, group, instr, group, instr, group);
1354 	fprintf(fp, "\
1355 	if (err)\n\
1356 		return err;\n\
1357 \n\n");
1358 
1359 	fprintf(fp, "\treturn err;\n}\n");
1360 }
1361