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