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