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