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