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