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