1145519Sdarrenr/*	$FreeBSD: stable/11/contrib/ipfilter/tools/ipfcomp.c 369245 2021-02-09 13:47:46Z git2svn $	*/
2145510Sdarrenr
3145510Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr */
8145510Sdarrenr#if !defined(lint)
9145510Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10255332Scystatic const char rcsid[] = "@(#)$Id$";
11145510Sdarrenr#endif
12145510Sdarrenr
13145510Sdarrenr#include "ipf.h"
14145510Sdarrenr
15145510Sdarrenr
16145510Sdarrenrtypedef struct {
17145510Sdarrenr	int c;
18145510Sdarrenr	int e;
19145510Sdarrenr	int n;
20145510Sdarrenr	int p;
21145510Sdarrenr	int s;
22145510Sdarrenr} mc_t;
23145510Sdarrenr
24145510Sdarrenr
25145510Sdarrenrstatic char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" };
26145510Sdarrenrstatic int count = 0;
27145510Sdarrenr
28369245Sgit2svnint intcmp(const void *, const void *);
29369245Sgit2svnstatic void indent(FILE *, int);
30369245Sgit2svnstatic void printeq(FILE *, char *, int, int, int);
31369245Sgit2svnstatic void printipeq(FILE *, char *, int, int, int);
32369245Sgit2svnstatic void addrule(FILE *, frentry_t *);
33369245Sgit2svnstatic void printhooks(FILE *, int, int, frgroup_t *);
34369245Sgit2svnstatic void emitheader(frgroup_t *, u_int, u_int);
35369245Sgit2svnstatic void emitGroup(int, int, void *, frentry_t *, char *,
36369245Sgit2svn			   u_int, u_int);
37369245Sgit2svnstatic void emittail(void);
38369245Sgit2svnstatic void printCgroup(int, frentry_t *, mc_t *, char *);
39145510Sdarrenr
40145510Sdarrenr#define	FRC_IFN	0
41145510Sdarrenr#define	FRC_V	1
42145510Sdarrenr#define	FRC_P	2
43145510Sdarrenr#define	FRC_FL	3
44145510Sdarrenr#define	FRC_TOS	4
45145510Sdarrenr#define	FRC_TTL	5
46145510Sdarrenr#define	FRC_SRC	6
47145510Sdarrenr#define	FRC_DST	7
48145510Sdarrenr#define	FRC_TCP	8
49145510Sdarrenr#define	FRC_SP	9
50145510Sdarrenr#define	FRC_DP	10
51145510Sdarrenr#define	FRC_OPT	11
52145510Sdarrenr#define	FRC_SEC	12
53145510Sdarrenr#define	FRC_ATH	13
54145510Sdarrenr#define	FRC_ICT	14
55145510Sdarrenr#define	FRC_ICC	15
56145510Sdarrenr#define	FRC_MAX	16
57145510Sdarrenr
58145510Sdarrenr
59145510Sdarrenrstatic	FILE	*cfile = NULL;
60145510Sdarrenr
61145510Sdarrenr/*
62145510Sdarrenr * This is called once per filter rule being loaded to emit data structures
63145510Sdarrenr * required.
64145510Sdarrenr */
65145510Sdarrenrvoid printc(fr)
66255332Scy	frentry_t *fr;
67145510Sdarrenr{
68145510Sdarrenr	fripf_t *ipf;
69145510Sdarrenr	u_long *ulp;
70145510Sdarrenr	char *and;
71145510Sdarrenr	FILE *fp;
72145510Sdarrenr	int i;
73145510Sdarrenr
74255332Scy	if (fr->fr_family == 6)
75145510Sdarrenr		return;
76145510Sdarrenr	if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE))
77145510Sdarrenr		return;
78145510Sdarrenr	if ((fr->fr_type == FR_T_IPF) &&
79145510Sdarrenr	    ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL)))
80145510Sdarrenr		return;
81145510Sdarrenr	ipf = fr->fr_ipf;
82145510Sdarrenr
83145510Sdarrenr	if (cfile == NULL)
84145510Sdarrenr		cfile = fopen("ip_rules.c", "w");
85145510Sdarrenr	if (cfile == NULL)
86145510Sdarrenr		return;
87145510Sdarrenr	fp = cfile;
88145510Sdarrenr	if (count == 0) {
89145510Sdarrenr		fprintf(fp, "/*\n");
90255332Scy 		fprintf(fp, "* Copyright (C) 2012 by Darren Reed.\n");
91145510Sdarrenr 		fprintf(fp, "*\n");
92145510Sdarrenr 		fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n");
93145510Sdarrenr 		fprintf(fp, "* provided that this notice is preserved and due credit is given\n");
94145510Sdarrenr 		fprintf(fp, "* to the original author and the contributors.\n");
95145510Sdarrenr 		fprintf(fp, "*/\n\n");
96145510Sdarrenr
97170268Sdarrenr		fprintf(fp, "#include <sys/param.h>\n");
98145510Sdarrenr		fprintf(fp, "#include <sys/types.h>\n");
99145510Sdarrenr		fprintf(fp, "#include <sys/time.h>\n");
100145510Sdarrenr		fprintf(fp, "#include <sys/socket.h>\n");
101170268Sdarrenr		fprintf(fp, "#if (__FreeBSD_version >= 40000)\n");
102170268Sdarrenr		fprintf(fp, "# if defined(_KERNEL)\n");
103170268Sdarrenr		fprintf(fp, "#  include <sys/libkern.h>\n");
104170268Sdarrenr		fprintf(fp, "# else\n");
105170268Sdarrenr		fprintf(fp, "#  include <sys/unistd.h>\n");
106170268Sdarrenr		fprintf(fp, "# endif\n");
107145510Sdarrenr		fprintf(fp, "#endif\n");
108170268Sdarrenr		fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n");
109170268Sdarrenr		fprintf(fp, "#else\n");
110170268Sdarrenr		fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n");
111170268Sdarrenr		fprintf(fp, "#  include <sys/systm.h>\n");
112170268Sdarrenr		fprintf(fp, "# endif\n");
113170268Sdarrenr		fprintf(fp, "#endif\n");
114145510Sdarrenr		fprintf(fp, "#include <sys/errno.h>\n");
115145510Sdarrenr		fprintf(fp, "#include <sys/param.h>\n");
116145510Sdarrenr		fprintf(fp,
117145510Sdarrenr"#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n");
118145510Sdarrenr		fprintf(fp, "# include <sys/mbuf.h>\n");
119145510Sdarrenr		fprintf(fp, "#endif\n");
120145510Sdarrenr		fprintf(fp,
121145510Sdarrenr"#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n");
122145510Sdarrenr		fprintf(fp, "# include <sys/sockio.h>\n");
123145510Sdarrenr		fprintf(fp, "#else\n");
124145510Sdarrenr		fprintf(fp, "# include <sys/ioctl.h>\n");
125145510Sdarrenr		fprintf(fp, "#endif /* FreeBSD */\n");
126145510Sdarrenr		fprintf(fp, "#include <net/if.h>\n");
127145510Sdarrenr		fprintf(fp, "#include <netinet/in.h>\n");
128145510Sdarrenr		fprintf(fp, "#include <netinet/in_systm.h>\n");
129145510Sdarrenr		fprintf(fp, "#include <netinet/ip.h>\n");
130145510Sdarrenr		fprintf(fp, "#include <netinet/tcp.h>\n");
131145510Sdarrenr		fprintf(fp, "#include \"netinet/ip_compat.h\"\n");
132145510Sdarrenr		fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n");
133145510Sdarrenr		fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n");
134145510Sdarrenr		fprintf(fp, "#ifndef _KERNEL\n");
135145510Sdarrenr		fprintf(fp, "# include <string.h>\n");
136145510Sdarrenr		fprintf(fp, "#endif /* _KERNEL */\n");
137145510Sdarrenr		fprintf(fp, "\n");
138145510Sdarrenr		fprintf(fp, "#ifdef IPFILTER_COMPILED\n");
139255332Scy		fprintf(fp, "\n");
140255332Scy		fprintf(fp, "extern ipf_main_softc_t ipfmain;\n");
141255332Scy		fprintf(fp, "\n");
142145510Sdarrenr	}
143145510Sdarrenr
144145510Sdarrenr	addrule(fp, fr);
145145510Sdarrenr	fr->fr_type |= FR_T_BUILTIN;
146145510Sdarrenr	and = "";
147145510Sdarrenr	fr->fr_ref = 1;
148145510Sdarrenr	i = sizeof(*fr);
149145510Sdarrenr	if (i & -(1 - sizeof(*ulp)))
150145510Sdarrenr		i += sizeof(u_long);
151145510Sdarrenr	for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) {
152145510Sdarrenr		fprintf(fp, "%s%#lx", and, *ulp++);
153145510Sdarrenr		and = ", ";
154145510Sdarrenr	}
155145510Sdarrenr	fprintf(fp, "\n};\n");
156145510Sdarrenr	fr->fr_type &= ~FR_T_BUILTIN;
157145510Sdarrenr
158145510Sdarrenr	count++;
159145510Sdarrenr
160145510Sdarrenr	fflush(fp);
161145510Sdarrenr}
162145510Sdarrenr
163145510Sdarrenr
164145510Sdarrenrstatic frgroup_t *groups = NULL;
165145510Sdarrenr
166145510Sdarrenr
167145510Sdarrenrstatic void addrule(fp, fr)
168255332Scy	FILE *fp;
169255332Scy	frentry_t *fr;
170145510Sdarrenr{
171145510Sdarrenr	frentry_t *f, **fpp;
172145510Sdarrenr	frgroup_t *g;
173145510Sdarrenr	u_long *ulp;
174255332Scy	char *ghead;
175255332Scy	char *gname;
176145510Sdarrenr	char *and;
177145510Sdarrenr	int i;
178145510Sdarrenr
179145510Sdarrenr	f = (frentry_t *)malloc(sizeof(*f));
180145510Sdarrenr	bcopy((char *)fr, (char *)f, sizeof(*fr));
181145510Sdarrenr	if (fr->fr_ipf) {
182145510Sdarrenr		f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf));
183145510Sdarrenr		bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf,
184145510Sdarrenr		      sizeof(*fr->fr_ipf));
185145510Sdarrenr	}
186145510Sdarrenr
187145510Sdarrenr	f->fr_next = NULL;
188255332Scy	gname = FR_NAME(fr, fr_group);
189255332Scy
190145510Sdarrenr	for (g = groups; g != NULL; g = g->fg_next)
191255332Scy		if ((strncmp(g->fg_name, gname, FR_GROUPLEN) == 0) &&
192145510Sdarrenr		    (g->fg_flags == (f->fr_flags & FR_INOUT)))
193145510Sdarrenr			break;
194145510Sdarrenr
195145510Sdarrenr	if (g == NULL) {
196145510Sdarrenr		g = (frgroup_t *)calloc(1, sizeof(*g));
197145510Sdarrenr		g->fg_next = groups;
198145510Sdarrenr		groups = g;
199145510Sdarrenr		g->fg_head = f;
200255332Scy		strncpy(g->fg_name, gname, FR_GROUPLEN);
201145510Sdarrenr		g->fg_ref = 0;
202145510Sdarrenr		g->fg_flags = f->fr_flags & FR_INOUT;
203145510Sdarrenr	}
204145510Sdarrenr
205145510Sdarrenr	for (fpp = &g->fg_start; *fpp != NULL; )
206145510Sdarrenr		fpp = &((*fpp)->fr_next);
207145510Sdarrenr	*fpp = f;
208145510Sdarrenr
209145510Sdarrenr	if (fr->fr_dsize > 0) {
210145510Sdarrenr		fprintf(fp, "\
211145510Sdarrenrstatic u_long ipf%s_rule_data_%s_%u[] = {\n",
212145510Sdarrenr			f->fr_flags & FR_INQUE ? "in" : "out",
213145510Sdarrenr			g->fg_name, g->fg_ref);
214145510Sdarrenr		and = "";
215145510Sdarrenr		i = fr->fr_dsize;
216145510Sdarrenr		ulp = fr->fr_data;
217145510Sdarrenr		for (i /= sizeof(u_long); i > 0; i--) {
218145510Sdarrenr			fprintf(fp, "%s%#lx", and, *ulp++);
219145510Sdarrenr			and = ", ";
220145510Sdarrenr		}
221145510Sdarrenr		fprintf(fp, "\n};\n");
222145510Sdarrenr	}
223145510Sdarrenr
224145510Sdarrenr	fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n",
225145510Sdarrenr		f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref);
226145510Sdarrenr
227145510Sdarrenr	g->fg_ref++;
228145510Sdarrenr
229255332Scy	if (f->fr_grhead != -1) {
230255332Scy		ghead = FR_NAME(f, fr_grhead);
231145510Sdarrenr		for (g = groups; g != NULL; g = g->fg_next)
232255332Scy			if ((strncmp(g->fg_name, ghead, FR_GROUPLEN) == 0) &&
233145510Sdarrenr			    g->fg_flags == (f->fr_flags & FR_INOUT))
234145510Sdarrenr				break;
235145510Sdarrenr		if (g == NULL) {
236145510Sdarrenr			g = (frgroup_t *)calloc(1, sizeof(*g));
237145510Sdarrenr			g->fg_next = groups;
238145510Sdarrenr			groups = g;
239145510Sdarrenr			g->fg_head = f;
240255332Scy			strncpy(g->fg_name, ghead, FR_GROUPLEN);
241145510Sdarrenr			g->fg_ref = 0;
242145510Sdarrenr			g->fg_flags = f->fr_flags & FR_INOUT;
243145510Sdarrenr		}
244145510Sdarrenr	}
245145510Sdarrenr}
246145510Sdarrenr
247145510Sdarrenr
248145510Sdarrenrint intcmp(c1, c2)
249255332Scy	const void *c1, *c2;
250145510Sdarrenr{
251145510Sdarrenr	const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2;
252145510Sdarrenr
253145510Sdarrenr	if (i1->n == i2->n) {
254145510Sdarrenr		return i1->c - i2->c;
255145510Sdarrenr	}
256145510Sdarrenr	return i2->n - i1->n;
257145510Sdarrenr}
258145510Sdarrenr
259145510Sdarrenr
260145510Sdarrenrstatic void indent(fp, in)
261255332Scy	FILE *fp;
262255332Scy	int in;
263145510Sdarrenr{
264145510Sdarrenr	for (; in; in--)
265145510Sdarrenr		fputc('\t', fp);
266145510Sdarrenr}
267145510Sdarrenr
268145510Sdarrenrstatic void printeq(fp, var, m, max, v)
269255332Scy	FILE *fp;
270255332Scy	char *var;
271255332Scy	int m, max, v;
272145510Sdarrenr{
273145510Sdarrenr	if (m == max)
274145510Sdarrenr		fprintf(fp, "%s == %#x) {\n", var, v);
275145510Sdarrenr	else
276145510Sdarrenr		fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v);
277145510Sdarrenr}
278145510Sdarrenr
279145510Sdarrenr/*
280145510Sdarrenr * Parameters: var - IP# being compared
281145510Sdarrenr *             fl - 0 for positive match, 1 for negative match
282145510Sdarrenr *             m - netmask
283145510Sdarrenr *             v - required address
284145510Sdarrenr */
285145510Sdarrenrstatic void printipeq(fp, var, fl, m, v)
286255332Scy	FILE *fp;
287255332Scy	char *var;
288255332Scy	int fl, m, v;
289145510Sdarrenr{
290145510Sdarrenr	if (m == 0xffffffff)
291145510Sdarrenr		fprintf(fp, "%s ", var);
292145510Sdarrenr	else
293145510Sdarrenr		fprintf(fp, "(%s & %#x) ", var, m);
294145510Sdarrenr	fprintf(fp, "%c", fl ? '!' : '=');
295145510Sdarrenr	fprintf(fp, "= %#x) {\n", v);
296145510Sdarrenr}
297145510Sdarrenr
298145510Sdarrenr
299145510Sdarrenrvoid emit(num, dir, v, fr)
300255332Scy	int num, dir;
301255332Scy	void *v;
302255332Scy	frentry_t *fr;
303145510Sdarrenr{
304145510Sdarrenr	u_int incnt, outcnt;
305145510Sdarrenr	frgroup_t *g;
306145510Sdarrenr	frentry_t *f;
307145510Sdarrenr
308145510Sdarrenr	for (g = groups; g != NULL; g = g->fg_next) {
309145510Sdarrenr		if (dir == 0 || dir == -1) {
310145510Sdarrenr			if ((g->fg_flags & FR_INQUE) == 0)
311145510Sdarrenr				continue;
312145510Sdarrenr			for (incnt = 0, f = g->fg_start; f != NULL;
313145510Sdarrenr			     f = f->fr_next)
314145510Sdarrenr				incnt++;
315145510Sdarrenr			emitGroup(num, dir, v, fr, g->fg_name, incnt, 0);
316145510Sdarrenr		}
317145510Sdarrenr		if (dir == 1 || dir == -1) {
318145510Sdarrenr			if ((g->fg_flags & FR_OUTQUE) == 0)
319145510Sdarrenr				continue;
320145510Sdarrenr			for (outcnt = 0, f = g->fg_start; f != NULL;
321145510Sdarrenr			     f = f->fr_next)
322145510Sdarrenr				outcnt++;
323145510Sdarrenr			emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt);
324145510Sdarrenr		}
325145510Sdarrenr	}
326145510Sdarrenr
327145510Sdarrenr	if (num == -1 && dir == -1) {
328145510Sdarrenr		for (g = groups; g != NULL; g = g->fg_next) {
329145510Sdarrenr			if ((g->fg_flags & FR_INQUE) != 0) {
330145510Sdarrenr				for (incnt = 0, f = g->fg_start; f != NULL;
331145510Sdarrenr				     f = f->fr_next)
332145510Sdarrenr					incnt++;
333145510Sdarrenr				if (incnt > 0)
334145510Sdarrenr					emitheader(g, incnt, 0);
335145510Sdarrenr			}
336145510Sdarrenr			if ((g->fg_flags & FR_OUTQUE) != 0) {
337145510Sdarrenr				for (outcnt = 0, f = g->fg_start; f != NULL;
338145510Sdarrenr				     f = f->fr_next)
339145510Sdarrenr					outcnt++;
340145510Sdarrenr				if (outcnt > 0)
341145510Sdarrenr					emitheader(g, 0, outcnt);
342145510Sdarrenr			}
343145510Sdarrenr		}
344145510Sdarrenr		emittail();
345145510Sdarrenr		fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n");
346145510Sdarrenr	}
347145510Sdarrenr
348145510Sdarrenr}
349145510Sdarrenr
350145510Sdarrenr
351145510Sdarrenrstatic void emitheader(grp, incount, outcount)
352255332Scy	frgroup_t *grp;
353255332Scy	u_int incount, outcount;
354145510Sdarrenr{
355145510Sdarrenr	static FILE *fph = NULL;
356145510Sdarrenr	frgroup_t *g;
357145510Sdarrenr
358145510Sdarrenr	if (fph == NULL) {
359145510Sdarrenr		fph = fopen("ip_rules.h", "w");
360145510Sdarrenr		if (fph == NULL)
361145510Sdarrenr			return;
362145510Sdarrenr
363369245Sgit2svn		fprintf(fph, "extern int ipfrule_add(void));\n");
364369245Sgit2svn		fprintf(fph, "extern int ipfrule_remove(void));\n");
365145510Sdarrenr	}
366145510Sdarrenr
367145510Sdarrenr	printhooks(cfile, incount, outcount, grp);
368145510Sdarrenr
369145510Sdarrenr	if (incount) {
370145510Sdarrenr		fprintf(fph, "\n\
371369245Sgit2svnextern frentry_t *ipfrule_match_in_%s(fr_info_t *, u_32_t *));\n\
372145510Sdarrenrextern frentry_t *ipf_rules_in_%s[%d];\n",
373145510Sdarrenr			grp->fg_name, grp->fg_name, incount);
374145510Sdarrenr
375145510Sdarrenr		for (g = groups; g != grp; g = g->fg_next)
376145510Sdarrenr			if ((strncmp(g->fg_name, grp->fg_name,
377145510Sdarrenr				     FR_GROUPLEN) == 0) &&
378145510Sdarrenr			    g->fg_flags == grp->fg_flags)
379145510Sdarrenr				break;
380145510Sdarrenr		if (g == grp) {
381145510Sdarrenr			fprintf(fph, "\n\
382369245Sgit2svnextern int ipfrule_add_in_%s(void));\n\
383369245Sgit2svnextern int ipfrule_remove_in_%s(void));\n", grp->fg_name, grp->fg_name);
384145510Sdarrenr		}
385145510Sdarrenr	}
386145510Sdarrenr	if (outcount) {
387145510Sdarrenr		fprintf(fph, "\n\
388369245Sgit2svnextern frentry_t *ipfrule_match_out_%s(fr_info_t *, u_32_t *));\n\
389145510Sdarrenrextern frentry_t *ipf_rules_out_%s[%d];\n",
390145510Sdarrenr			grp->fg_name, grp->fg_name, outcount);
391145510Sdarrenr
392194290Srdivacky		for (g = groups; g != grp; g = g->fg_next)
393145510Sdarrenr			if ((strncmp(g->fg_name, grp->fg_name,
394145510Sdarrenr				     FR_GROUPLEN) == 0) &&
395145510Sdarrenr			    g->fg_flags == grp->fg_flags)
396145510Sdarrenr				break;
397145510Sdarrenr		if (g == grp) {
398145510Sdarrenr			fprintf(fph, "\n\
399369245Sgit2svnextern int ipfrule_add_out_%s(void));\n\
400369245Sgit2svnextern int ipfrule_remove_out_%s(void));\n",
401145510Sdarrenr				grp->fg_name, grp->fg_name);
402145510Sdarrenr		}
403145510Sdarrenr	}
404145510Sdarrenr}
405145510Sdarrenr
406145510Sdarrenrstatic void emittail()
407145510Sdarrenr{
408145510Sdarrenr	frgroup_t *g;
409145510Sdarrenr
410145510Sdarrenr	fprintf(cfile, "\n\
411145510Sdarrenrint ipfrule_add()\n\
412145510Sdarrenr{\n\
413145510Sdarrenr	int err;\n\
414145510Sdarrenr\n");
415145510Sdarrenr	for (g = groups; g != NULL; g = g->fg_next)
416145510Sdarrenr		fprintf(cfile, "\
417145510Sdarrenr	err = ipfrule_add_%s_%s();\n\
418145510Sdarrenr	if (err != 0)\n\
419145510Sdarrenr		return err;\n",
420145510Sdarrenr			(g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
421145510Sdarrenr	fprintf(cfile, "\
422145510Sdarrenr	return 0;\n");
423145510Sdarrenr	fprintf(cfile, "}\n\
424145510Sdarrenr\n");
425145510Sdarrenr
426145510Sdarrenr	fprintf(cfile, "\n\
427145510Sdarrenrint ipfrule_remove()\n\
428145510Sdarrenr{\n\
429145510Sdarrenr	int err;\n\
430145510Sdarrenr\n");
431145510Sdarrenr	for (g = groups; g != NULL; g = g->fg_next)
432145510Sdarrenr		fprintf(cfile, "\
433145510Sdarrenr	err = ipfrule_remove_%s_%s();\n\
434145510Sdarrenr	if (err != 0)\n\
435145510Sdarrenr		return err;\n",
436145510Sdarrenr			(g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
437145510Sdarrenr	fprintf(cfile, "\
438145510Sdarrenr	return 0;\n");
439145510Sdarrenr	fprintf(cfile, "}\n");
440145510Sdarrenr}
441145510Sdarrenr
442145510Sdarrenr
443145510Sdarrenrstatic void emitGroup(num, dir, v, fr, group, incount, outcount)
444255332Scy	int num, dir;
445255332Scy	void *v;
446255332Scy	frentry_t *fr;
447255332Scy	char *group;
448255332Scy	u_int incount, outcount;
449145510Sdarrenr{
450145510Sdarrenr	static FILE *fp = NULL;
451145510Sdarrenr	static int header[2] = { 0, 0 };
452145510Sdarrenr	static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
453145510Sdarrenr	static int openfunc = 0;
454145510Sdarrenr	static mc_t *n = NULL;
455145510Sdarrenr	static int sin = 0;
456145510Sdarrenr	frentry_t *f;
457145510Sdarrenr	frgroup_t *g;
458145510Sdarrenr	fripf_t *ipf;
459145510Sdarrenr	int i, in, j;
460145510Sdarrenr	mc_t *m = v;
461145510Sdarrenr
462145510Sdarrenr	if (fp == NULL)
463145510Sdarrenr		fp = cfile;
464145510Sdarrenr	if (fp == NULL)
465145510Sdarrenr		return;
466145510Sdarrenr	if (strncmp(egroup, group, FR_GROUPLEN)) {
467145510Sdarrenr		for (sin--; sin > 0; sin--) {
468145510Sdarrenr			indent(fp, sin);
469145510Sdarrenr			fprintf(fp, "}\n");
470145510Sdarrenr		}
471145510Sdarrenr		if (openfunc == 1) {
472145510Sdarrenr			fprintf(fp, "\treturn fr;\n}\n");
473145510Sdarrenr			openfunc = 0;
474145510Sdarrenr			if (n != NULL) {
475145510Sdarrenr				free(n);
476145510Sdarrenr				n = NULL;
477145510Sdarrenr			}
478145510Sdarrenr		}
479145510Sdarrenr		sin = 0;
480145510Sdarrenr		header[0] = 0;
481145510Sdarrenr		header[1] = 0;
482145510Sdarrenr		strncpy(egroup, group, FR_GROUPLEN);
483145510Sdarrenr	} else if (openfunc == 1 && num < 0) {
484145510Sdarrenr		if (n != NULL) {
485145510Sdarrenr			free(n);
486145510Sdarrenr			n = NULL;
487145510Sdarrenr		}
488145510Sdarrenr		for (sin--; sin > 0; sin--) {
489145510Sdarrenr			indent(fp, sin);
490145510Sdarrenr			fprintf(fp, "}\n");
491145510Sdarrenr		}
492145510Sdarrenr		if (openfunc == 1) {
493145510Sdarrenr			fprintf(fp, "\treturn fr;\n}\n");
494145510Sdarrenr			openfunc = 0;
495145510Sdarrenr		}
496145510Sdarrenr	}
497145510Sdarrenr
498145510Sdarrenr	if (dir == -1)
499145510Sdarrenr		return;
500145510Sdarrenr
501145510Sdarrenr	for (g = groups; g != NULL; g = g->fg_next) {
502145510Sdarrenr		if (dir == 0 && (g->fg_flags & FR_INQUE) == 0)
503145510Sdarrenr			continue;
504145510Sdarrenr		else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0)
505145510Sdarrenr			continue;
506145510Sdarrenr		if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0)
507145510Sdarrenr			continue;
508145510Sdarrenr		break;
509145510Sdarrenr	}
510145510Sdarrenr
511145510Sdarrenr	/*
512145510Sdarrenr	 * Output the array of pointers to rules for this group.
513145510Sdarrenr	 */
514170268Sdarrenr	if (g != NULL && num == -2 && dir == 0 && header[0] == 0 &&
515170268Sdarrenr	    incount != 0) {
516145510Sdarrenr		fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {",
517145510Sdarrenr			group, incount);
518145510Sdarrenr		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
519145510Sdarrenr			if ((f->fr_flags & FR_INQUE) == 0)
520145510Sdarrenr				continue;
521145510Sdarrenr			if ((i & 1) == 0) {
522145510Sdarrenr				fprintf(fp, "\n\t");
523145510Sdarrenr			}
524255332Scy			fprintf(fp, "(frentry_t *)&in_rule_%s_%d",
525255332Scy				FR_NAME(f, fr_group), i);
526145510Sdarrenr			if (i + 1 < incount)
527145510Sdarrenr				fprintf(fp, ", ");
528145510Sdarrenr			i++;
529145510Sdarrenr		}
530145510Sdarrenr		fprintf(fp, "\n};\n");
531145510Sdarrenr	}
532145510Sdarrenr
533170268Sdarrenr	if (g != NULL && num == -2 && dir == 1 && header[0] == 0 &&
534170268Sdarrenr	    outcount != 0) {
535145510Sdarrenr		fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {",
536145510Sdarrenr			group, outcount);
537145510Sdarrenr		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
538145510Sdarrenr			if ((f->fr_flags & FR_OUTQUE) == 0)
539145510Sdarrenr				continue;
540145510Sdarrenr			if ((i & 1) == 0) {
541145510Sdarrenr				fprintf(fp, "\n\t");
542145510Sdarrenr			}
543255332Scy			fprintf(fp, "(frentry_t *)&out_rule_%s_%d",
544255332Scy				FR_NAME(f, fr_group), i);
545145510Sdarrenr			if (i + 1 < outcount)
546145510Sdarrenr				fprintf(fp, ", ");
547145510Sdarrenr			i++;
548145510Sdarrenr		}
549145510Sdarrenr		fprintf(fp, "\n};\n");
550145510Sdarrenr		fp = NULL;
551145510Sdarrenr	}
552145510Sdarrenr
553145510Sdarrenr	if (num < 0)
554145510Sdarrenr		return;
555145510Sdarrenr
556145510Sdarrenr	in = 0;
557145510Sdarrenr	ipf = fr->fr_ipf;
558145510Sdarrenr
559145510Sdarrenr	/*
560145510Sdarrenr	 * If the function header has not been printed then print it now.
561145510Sdarrenr	 */
562170268Sdarrenr	if (g != NULL && header[dir] == 0) {
563145510Sdarrenr		int pdst = 0, psrc = 0;
564145510Sdarrenr
565145510Sdarrenr		openfunc = 1;
566145510Sdarrenr		fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n",
567145510Sdarrenr			(dir == 0) ? "in" : "out", group);
568145510Sdarrenr		fprintf(fp, "fr_info_t *fin;\n");
569145510Sdarrenr		fprintf(fp, "u_32_t *passp;\n");
570145510Sdarrenr		fprintf(fp, "{\n");
571145510Sdarrenr		fprintf(fp, "\tfrentry_t *fr = NULL;\n");
572145510Sdarrenr
573145510Sdarrenr		/*
574145510Sdarrenr		 * Print out any variables that need to be declared.
575145510Sdarrenr		 */
576145510Sdarrenr		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
577145510Sdarrenr			if (incount + outcount > m[FRC_SRC].e + 1)
578145510Sdarrenr				psrc = 1;
579145510Sdarrenr			if (incount + outcount > m[FRC_DST].e + 1)
580145510Sdarrenr				pdst = 1;
581145510Sdarrenr		}
582145510Sdarrenr		if (psrc == 1)
583145510Sdarrenr			fprintf(fp, "\tu_32_t src = ntohl(%s);\n",
584145510Sdarrenr				"fin->fin_fi.fi_saddr");
585145510Sdarrenr		if (pdst == 1)
586145510Sdarrenr			fprintf(fp, "\tu_32_t dst = ntohl(%s);\n",
587145510Sdarrenr				"fin->fin_fi.fi_daddr");
588145510Sdarrenr	}
589145510Sdarrenr
590145510Sdarrenr	for (i = 0; i < FRC_MAX; i++) {
591145510Sdarrenr		switch(m[i].c)
592145510Sdarrenr		{
593145510Sdarrenr		case FRC_IFN :
594255332Scy			if (fr->fr_ifnames[0] != -1)
595145510Sdarrenr				m[i].s = 1;
596145510Sdarrenr			break;
597145510Sdarrenr		case FRC_V :
598145510Sdarrenr			if (ipf != NULL && ipf->fri_mip.fi_v != 0)
599145510Sdarrenr				m[i].s = 1;
600145510Sdarrenr			break;
601145510Sdarrenr		case FRC_FL :
602145510Sdarrenr			if (ipf != NULL && ipf->fri_mip.fi_flx != 0)
603145510Sdarrenr				m[i].s = 1;
604145510Sdarrenr			break;
605145510Sdarrenr		case FRC_P :
606145510Sdarrenr			if (ipf != NULL && ipf->fri_mip.fi_p != 0)
607145510Sdarrenr				m[i].s = 1;
608145510Sdarrenr			break;
609145510Sdarrenr		case FRC_TTL :
610145510Sdarrenr			if (ipf != NULL && ipf->fri_mip.fi_ttl != 0)
611145510Sdarrenr				m[i].s = 1;
612145510Sdarrenr			break;
613145510Sdarrenr		case FRC_TOS :
614145510Sdarrenr			if (ipf != NULL && ipf->fri_mip.fi_tos != 0)
615145510Sdarrenr				m[i].s = 1;
616145510Sdarrenr			break;
617145510Sdarrenr		case FRC_TCP :
618145510Sdarrenr			if (ipf == NULL)
619145510Sdarrenr				break;
620145510Sdarrenr			if ((ipf->fri_ip.fi_p == IPPROTO_TCP) &&
621145510Sdarrenr			    fr->fr_tcpfm != 0)
622145510Sdarrenr				m[i].s = 1;
623145510Sdarrenr			break;
624145510Sdarrenr		case FRC_SP :
625145510Sdarrenr			if (ipf == NULL)
626145510Sdarrenr				break;
627145510Sdarrenr			if (fr->fr_scmp == FR_INRANGE)
628145510Sdarrenr				m[i].s = 1;
629145510Sdarrenr			else if (fr->fr_scmp == FR_OUTRANGE)
630145510Sdarrenr				m[i].s = 1;
631145510Sdarrenr			else if (fr->fr_scmp != 0)
632145510Sdarrenr				m[i].s = 1;
633145510Sdarrenr			break;
634145510Sdarrenr		case FRC_DP :
635145510Sdarrenr			if (ipf == NULL)
636145510Sdarrenr				break;
637145510Sdarrenr			if (fr->fr_dcmp == FR_INRANGE)
638145510Sdarrenr				m[i].s = 1;
639145510Sdarrenr			else if (fr->fr_dcmp == FR_OUTRANGE)
640145510Sdarrenr				m[i].s = 1;
641145510Sdarrenr			else if (fr->fr_dcmp != 0)
642145510Sdarrenr				m[i].s = 1;
643145510Sdarrenr			break;
644145510Sdarrenr		case FRC_SRC :
645145510Sdarrenr			if (ipf == NULL)
646145510Sdarrenr				break;
647145510Sdarrenr			if (fr->fr_satype == FRI_LOOKUP) {
648145510Sdarrenr				;
649145510Sdarrenr			} else if ((fr->fr_smask != 0) ||
650145510Sdarrenr				   (fr->fr_flags & FR_NOTSRCIP) != 0)
651145510Sdarrenr				m[i].s = 1;
652145510Sdarrenr			break;
653145510Sdarrenr		case FRC_DST :
654145510Sdarrenr			if (ipf == NULL)
655145510Sdarrenr				break;
656145510Sdarrenr			if (fr->fr_datype == FRI_LOOKUP) {
657145510Sdarrenr				;
658145510Sdarrenr			} else if ((fr->fr_dmask != 0) ||
659145510Sdarrenr				   (fr->fr_flags & FR_NOTDSTIP) != 0)
660145510Sdarrenr				m[i].s = 1;
661145510Sdarrenr			break;
662145510Sdarrenr		case FRC_OPT :
663145510Sdarrenr			if (ipf == NULL)
664145510Sdarrenr				break;
665145510Sdarrenr			if (fr->fr_optmask != 0)
666145510Sdarrenr				m[i].s = 1;
667145510Sdarrenr			break;
668145510Sdarrenr		case FRC_SEC :
669145510Sdarrenr			if (ipf == NULL)
670145510Sdarrenr				break;
671145510Sdarrenr			if (fr->fr_secmask != 0)
672145510Sdarrenr				m[i].s = 1;
673145510Sdarrenr			break;
674145510Sdarrenr		case FRC_ATH :
675145510Sdarrenr			if (ipf == NULL)
676145510Sdarrenr				break;
677145510Sdarrenr			if (fr->fr_authmask != 0)
678145510Sdarrenr				m[i].s = 1;
679145510Sdarrenr			break;
680145510Sdarrenr		case FRC_ICT :
681145510Sdarrenr			if (ipf == NULL)
682145510Sdarrenr				break;
683145510Sdarrenr			if ((fr->fr_icmpm & 0xff00) != 0)
684145510Sdarrenr				m[i].s = 1;
685145510Sdarrenr			break;
686145510Sdarrenr		case FRC_ICC :
687145510Sdarrenr			if (ipf == NULL)
688145510Sdarrenr				break;
689145510Sdarrenr			if ((fr->fr_icmpm & 0xff) != 0)
690145510Sdarrenr				m[i].s = 1;
691145510Sdarrenr			break;
692145510Sdarrenr		}
693145510Sdarrenr	}
694145510Sdarrenr
695145510Sdarrenr	if (!header[dir]) {
696145510Sdarrenr		fprintf(fp, "\n");
697145510Sdarrenr		header[dir] = 1;
698145510Sdarrenr		sin = 0;
699145510Sdarrenr	}
700145510Sdarrenr
701145510Sdarrenr	qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
702145510Sdarrenr
703145510Sdarrenr	if (n) {
704145510Sdarrenr		/*
705145510Sdarrenr		 * Calculate the indentation interval upto the last common
706145510Sdarrenr		 * common comparison being made.
707145510Sdarrenr		 */
708145510Sdarrenr		for (i = 0, in = 1; i < FRC_MAX; i++) {
709145510Sdarrenr			if (n[i].c != m[i].c)
710145510Sdarrenr				break;
711145510Sdarrenr			if (n[i].s != m[i].s)
712145510Sdarrenr				break;
713145510Sdarrenr			if (n[i].s) {
714145510Sdarrenr				if (n[i].n && (n[i].n > n[i].e)) {
715145510Sdarrenr					m[i].p++;
716145510Sdarrenr					in += m[i].p;
717145510Sdarrenr					break;
718145510Sdarrenr				}
719145510Sdarrenr				if (n[i].e > 0) {
720145510Sdarrenr					in++;
721145510Sdarrenr				} else
722145510Sdarrenr					break;
723145510Sdarrenr			}
724145510Sdarrenr		}
725145510Sdarrenr		if (sin != in) {
726145510Sdarrenr			for (j = sin - 1; j >= in; j--) {
727145510Sdarrenr				indent(fp, j);
728145510Sdarrenr				fprintf(fp, "}\n");
729145510Sdarrenr			}
730145510Sdarrenr		}
731145510Sdarrenr	} else {
732145510Sdarrenr		in = 1;
733145510Sdarrenr		i = 0;
734145510Sdarrenr	}
735145510Sdarrenr
736145510Sdarrenr	/*
737145510Sdarrenr	 * print out C code that implements a filter rule.
738145510Sdarrenr	 */
739145510Sdarrenr	for (; i < FRC_MAX; i++) {
740145510Sdarrenr		switch(m[i].c)
741145510Sdarrenr		{
742145510Sdarrenr		case FRC_IFN :
743145510Sdarrenr			if (m[i].s) {
744145510Sdarrenr				indent(fp, in);
745145510Sdarrenr				fprintf(fp, "if (fin->fin_ifp == ");
746145510Sdarrenr				fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n",
747145510Sdarrenr					dir ? "out" : "in", group, num);
748145510Sdarrenr				in++;
749145510Sdarrenr			}
750145510Sdarrenr			break;
751145510Sdarrenr		case FRC_V :
752145510Sdarrenr			if (m[i].s) {
753145510Sdarrenr				indent(fp, in);
754145510Sdarrenr				fprintf(fp, "if (fin->fin_v == %d) {\n",
755145510Sdarrenr					ipf->fri_ip.fi_v);
756145510Sdarrenr				in++;
757145510Sdarrenr			}
758145510Sdarrenr			break;
759145510Sdarrenr		case FRC_FL :
760145510Sdarrenr			if (m[i].s) {
761145510Sdarrenr				indent(fp, in);
762145510Sdarrenr				fprintf(fp, "if (");
763145510Sdarrenr				printeq(fp, "fin->fin_flx",
764145510Sdarrenr				        ipf->fri_mip.fi_flx, 0xf,
765145510Sdarrenr					ipf->fri_ip.fi_flx);
766145510Sdarrenr				in++;
767145510Sdarrenr			}
768145510Sdarrenr			break;
769145510Sdarrenr		case FRC_P :
770145510Sdarrenr			if (m[i].s) {
771145510Sdarrenr				indent(fp, in);
772145510Sdarrenr				fprintf(fp, "if (fin->fin_p == %d) {\n",
773145510Sdarrenr					ipf->fri_ip.fi_p);
774145510Sdarrenr				in++;
775145510Sdarrenr			}
776145510Sdarrenr			break;
777145510Sdarrenr		case FRC_TTL :
778145510Sdarrenr			if (m[i].s) {
779145510Sdarrenr				indent(fp, in);
780145510Sdarrenr				fprintf(fp, "if (");
781145510Sdarrenr				printeq(fp, "fin->fin_ttl",
782145510Sdarrenr					ipf->fri_mip.fi_ttl, 0xff,
783145510Sdarrenr					ipf->fri_ip.fi_ttl);
784145510Sdarrenr				in++;
785145510Sdarrenr			}
786145510Sdarrenr			break;
787145510Sdarrenr		case FRC_TOS :
788145510Sdarrenr			if (m[i].s) {
789145510Sdarrenr				indent(fp, in);
790145510Sdarrenr				fprintf(fp, "if (fin->fin_tos");
791145510Sdarrenr				printeq(fp, "fin->fin_tos",
792145510Sdarrenr					ipf->fri_mip.fi_tos, 0xff,
793145510Sdarrenr					ipf->fri_ip.fi_tos);
794145510Sdarrenr				in++;
795145510Sdarrenr			}
796145510Sdarrenr			break;
797145510Sdarrenr		case FRC_TCP :
798145510Sdarrenr			if (m[i].s) {
799145510Sdarrenr				indent(fp, in);
800145510Sdarrenr				fprintf(fp, "if (");
801145510Sdarrenr				printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm,
802145510Sdarrenr					0xff, fr->fr_tcpf);
803145510Sdarrenr				in++;
804145510Sdarrenr			}
805145510Sdarrenr			break;
806145510Sdarrenr		case FRC_SP :
807145510Sdarrenr			if (!m[i].s)
808145510Sdarrenr				break;
809145510Sdarrenr			if (fr->fr_scmp == FR_INRANGE) {
810145510Sdarrenr				indent(fp, in);
811145510Sdarrenr				fprintf(fp, "if ((fin->fin_data[0] > %d) && ",
812145510Sdarrenr					fr->fr_sport);
813145510Sdarrenr				fprintf(fp, "(fin->fin_data[0] < %d)",
814145510Sdarrenr					fr->fr_stop);
815145510Sdarrenr				fprintf(fp, ") {\n");
816145510Sdarrenr				in++;
817145510Sdarrenr			} else if (fr->fr_scmp == FR_OUTRANGE) {
818145510Sdarrenr				indent(fp, in);
819145510Sdarrenr				fprintf(fp, "if ((fin->fin_data[0] < %d) || ",
820145510Sdarrenr					fr->fr_sport);
821145510Sdarrenr				fprintf(fp, "(fin->fin_data[0] > %d)",
822145510Sdarrenr					fr->fr_stop);
823145510Sdarrenr				fprintf(fp, ") {\n");
824145510Sdarrenr				in++;
825145510Sdarrenr			} else if (fr->fr_scmp) {
826145510Sdarrenr				indent(fp, in);
827145510Sdarrenr				fprintf(fp, "if (fin->fin_data[0] %s %d)",
828145510Sdarrenr					portcmp[fr->fr_scmp], fr->fr_sport);
829145510Sdarrenr				fprintf(fp, " {\n");
830145510Sdarrenr				in++;
831145510Sdarrenr			}
832145510Sdarrenr			break;
833145510Sdarrenr		case FRC_DP :
834145510Sdarrenr			if (!m[i].s)
835145510Sdarrenr				break;
836145510Sdarrenr			if (fr->fr_dcmp == FR_INRANGE) {
837145510Sdarrenr				indent(fp, in);
838145510Sdarrenr				fprintf(fp, "if ((fin->fin_data[1] > %d) && ",
839145510Sdarrenr					fr->fr_dport);
840145510Sdarrenr				fprintf(fp, "(fin->fin_data[1] < %d)",
841145510Sdarrenr					fr->fr_dtop);
842145510Sdarrenr				fprintf(fp, ") {\n");
843145510Sdarrenr				in++;
844145510Sdarrenr			} else if (fr->fr_dcmp == FR_OUTRANGE) {
845145510Sdarrenr				indent(fp, in);
846145510Sdarrenr				fprintf(fp, "if ((fin->fin_data[1] < %d) || ",
847145510Sdarrenr					fr->fr_dport);
848145510Sdarrenr				fprintf(fp, "(fin->fin_data[1] > %d)",
849145510Sdarrenr					fr->fr_dtop);
850145510Sdarrenr				fprintf(fp, ") {\n");
851145510Sdarrenr				in++;
852145510Sdarrenr			} else if (fr->fr_dcmp) {
853145510Sdarrenr				indent(fp, in);
854145510Sdarrenr				fprintf(fp, "if (fin->fin_data[1] %s %d)",
855145510Sdarrenr					portcmp[fr->fr_dcmp], fr->fr_dport);
856145510Sdarrenr				fprintf(fp, " {\n");
857145510Sdarrenr				in++;
858145510Sdarrenr			}
859145510Sdarrenr			break;
860145510Sdarrenr		case FRC_SRC :
861145510Sdarrenr			if (!m[i].s)
862145510Sdarrenr				break;
863145510Sdarrenr			if (fr->fr_satype == FRI_LOOKUP) {
864145510Sdarrenr				;
865145510Sdarrenr			} else if ((fr->fr_smask != 0) ||
866145510Sdarrenr				   (fr->fr_flags & FR_NOTSRCIP) != 0) {
867145510Sdarrenr				indent(fp, in);
868145510Sdarrenr				fprintf(fp, "if (");
869145510Sdarrenr				printipeq(fp, "src",
870145510Sdarrenr					  fr->fr_flags & FR_NOTSRCIP,
871145510Sdarrenr					  fr->fr_smask, fr->fr_saddr);
872145510Sdarrenr				in++;
873145510Sdarrenr			}
874145510Sdarrenr			break;
875145510Sdarrenr		case FRC_DST :
876145510Sdarrenr			if (!m[i].s)
877145510Sdarrenr				break;
878145510Sdarrenr			if (fr->fr_datype == FRI_LOOKUP) {
879145510Sdarrenr				;
880145510Sdarrenr			} else if ((fr->fr_dmask != 0) ||
881145510Sdarrenr				   (fr->fr_flags & FR_NOTDSTIP) != 0) {
882145510Sdarrenr				indent(fp, in);
883145510Sdarrenr				fprintf(fp, "if (");
884145510Sdarrenr				printipeq(fp, "dst",
885145510Sdarrenr					  fr->fr_flags & FR_NOTDSTIP,
886145510Sdarrenr					  fr->fr_dmask, fr->fr_daddr);
887145510Sdarrenr				in++;
888145510Sdarrenr			}
889145510Sdarrenr			break;
890145510Sdarrenr		case FRC_OPT :
891145510Sdarrenr			if (m[i].s) {
892145510Sdarrenr				indent(fp, in);
893145510Sdarrenr				fprintf(fp, "if (");
894145510Sdarrenr				printeq(fp, "fin->fin_fi.fi_optmsk",
895145510Sdarrenr					fr->fr_optmask, 0xffffffff,
896145510Sdarrenr				        fr->fr_optbits);
897145510Sdarrenr				in++;
898145510Sdarrenr			}
899145510Sdarrenr			break;
900145510Sdarrenr		case FRC_SEC :
901145510Sdarrenr			if (m[i].s) {
902145510Sdarrenr				indent(fp, in);
903145510Sdarrenr				fprintf(fp, "if (");
904145510Sdarrenr				printeq(fp, "fin->fin_fi.fi_secmsk",
905145510Sdarrenr					fr->fr_secmask, 0xffff,
906145510Sdarrenr					fr->fr_secbits);
907145510Sdarrenr				in++;
908145510Sdarrenr			}
909145510Sdarrenr			break;
910145510Sdarrenr		case FRC_ATH :
911145510Sdarrenr			if (m[i].s) {
912145510Sdarrenr				indent(fp, in);
913145510Sdarrenr				fprintf(fp, "if (");
914145510Sdarrenr				printeq(fp, "fin->fin_fi.fi_authmsk",
915145510Sdarrenr					fr->fr_authmask, 0xffff,
916145510Sdarrenr					fr->fr_authbits);
917145510Sdarrenr				in++;
918145510Sdarrenr			}
919145510Sdarrenr			break;
920145510Sdarrenr		case FRC_ICT :
921145510Sdarrenr			if (m[i].s) {
922145510Sdarrenr				indent(fp, in);
923145510Sdarrenr				fprintf(fp, "if (");
924145510Sdarrenr				printeq(fp, "fin->fin_data[0]",
925145510Sdarrenr					fr->fr_icmpm & 0xff00, 0xffff,
926145510Sdarrenr					fr->fr_icmp & 0xff00);
927145510Sdarrenr				in++;
928145510Sdarrenr			}
929145510Sdarrenr			break;
930145510Sdarrenr		case FRC_ICC :
931145510Sdarrenr			if (m[i].s) {
932145510Sdarrenr				indent(fp, in);
933145510Sdarrenr				fprintf(fp, "if (");
934145510Sdarrenr				printeq(fp, "fin->fin_data[0]",
935145510Sdarrenr					fr->fr_icmpm & 0xff, 0xffff,
936145510Sdarrenr					fr->fr_icmp & 0xff);
937145510Sdarrenr				in++;
938145510Sdarrenr			}
939145510Sdarrenr			break;
940145510Sdarrenr		}
941145510Sdarrenr
942145510Sdarrenr	}
943145510Sdarrenr
944145510Sdarrenr	indent(fp, in);
945145510Sdarrenr	if (fr->fr_flags & FR_QUICK) {
946145510Sdarrenr		fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n",
947145510Sdarrenr			fr->fr_flags & FR_INQUE ? "in" : "out",
948255332Scy			FR_NAME(fr, fr_group), num);
949145510Sdarrenr	} else {
950145510Sdarrenr		fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n",
951145510Sdarrenr			fr->fr_flags & FR_INQUE ? "in" : "out",
952255332Scy			FR_NAME(fr, fr_group), num);
953145510Sdarrenr	}
954145510Sdarrenr	if (n == NULL)
955145510Sdarrenr		n = (mc_t *)malloc(sizeof(*n) * FRC_MAX);
956145510Sdarrenr	bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX);
957145510Sdarrenr	sin = in;
958145510Sdarrenr}
959145510Sdarrenr
960145510Sdarrenr
961145510Sdarrenrvoid printC(dir)
962255332Scy	int dir;
963145510Sdarrenr{
964145510Sdarrenr	static mc_t *m = NULL;
965145510Sdarrenr	frgroup_t *g;
966145510Sdarrenr
967145510Sdarrenr	if (m == NULL)
968319175Scy		m = (mc_t *)calloc(FRC_MAX, sizeof(*m));
969145510Sdarrenr
970145510Sdarrenr	for (g = groups; g != NULL; g = g->fg_next) {
971145510Sdarrenr		if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0))
972145510Sdarrenr			printCgroup(dir, g->fg_start, m, g->fg_name);
973145510Sdarrenr		if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0))
974145510Sdarrenr			printCgroup(dir, g->fg_start, m, g->fg_name);
975145510Sdarrenr	}
976145510Sdarrenr
977145510Sdarrenr	emit(-1, dir, m, NULL);
978145510Sdarrenr}
979145510Sdarrenr
980145510Sdarrenr
981145510Sdarrenr/*
982145510Sdarrenr * Now print out code to implement all of the rules.
983145510Sdarrenr */
984145510Sdarrenrstatic void printCgroup(dir, top, m, group)
985255332Scy	int dir;
986255332Scy	frentry_t *top;
987255332Scy	mc_t *m;
988255332Scy	char *group;
989145510Sdarrenr{
990145510Sdarrenr	frentry_t *fr, *fr1;
991145510Sdarrenr	int i, n, rn;
992145510Sdarrenr	u_int count;
993145510Sdarrenr
994145510Sdarrenr	for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) {
995145510Sdarrenr		if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0))
996145510Sdarrenr			count++;
997145510Sdarrenr		else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0))
998145510Sdarrenr			count++;
999145510Sdarrenr	}
1000145510Sdarrenr
1001145510Sdarrenr	if (dir == 0)
1002145510Sdarrenr		emitGroup(-2, dir, m, fr1, group, count, 0);
1003145510Sdarrenr	else if (dir == 1)
1004145510Sdarrenr		emitGroup(-2, dir, m, fr1, group, 0, count);
1005145510Sdarrenr
1006145510Sdarrenr	/*
1007145510Sdarrenr	 * Before printing each rule, check to see how many of its fields are
1008145510Sdarrenr	 * matched by subsequent rules.
1009145510Sdarrenr	 */
1010145510Sdarrenr	for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) {
1011145510Sdarrenr		if (!dir && !(fr1->fr_flags & FR_INQUE))
1012145510Sdarrenr			continue;
1013145510Sdarrenr		if (dir && !(fr1->fr_flags & FR_OUTQUE))
1014145510Sdarrenr			continue;
1015145510Sdarrenr		n = 0xfffffff;
1016145510Sdarrenr
1017145510Sdarrenr		for (i = 0; i < FRC_MAX; i++)
1018145510Sdarrenr			m[i].e = 0;
1019145510Sdarrenr		qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
1020145510Sdarrenr
1021145510Sdarrenr		for (i = 0; i < FRC_MAX; i++) {
1022145510Sdarrenr			m[i].c = i;
1023145510Sdarrenr			m[i].e = 0;
1024145510Sdarrenr			m[i].n = 0;
1025145510Sdarrenr			m[i].s = 0;
1026145510Sdarrenr		}
1027145510Sdarrenr
1028145510Sdarrenr		for (fr = fr1->fr_next; fr; fr = fr->fr_next) {
1029145510Sdarrenr			if (!dir && !(fr->fr_flags & FR_INQUE))
1030145510Sdarrenr				continue;
1031145510Sdarrenr			if (dir && !(fr->fr_flags & FR_OUTQUE))
1032145510Sdarrenr				continue;
1033145510Sdarrenr
1034145510Sdarrenr			if ((n & 0x0001) &&
1035255332Scy			    !strcmp(fr1->fr_names + fr1->fr_ifnames[0],
1036255332Scy				    fr->fr_names + fr->fr_ifnames[0])) {
1037145510Sdarrenr				m[FRC_IFN].e++;
1038145510Sdarrenr				m[FRC_IFN].n++;
1039145510Sdarrenr			} else
1040145510Sdarrenr				n &= ~0x0001;
1041145510Sdarrenr
1042255332Scy			if ((n & 0x0002) && (fr1->fr_family == fr->fr_family)) {
1043145510Sdarrenr				m[FRC_V].e++;
1044145510Sdarrenr				m[FRC_V].n++;
1045145510Sdarrenr			} else
1046145510Sdarrenr				n &= ~0x0002;
1047145510Sdarrenr
1048145510Sdarrenr			if ((n & 0x0004) &&
1049145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1050145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1051145510Sdarrenr			    (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) &&
1052145510Sdarrenr			    (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) {
1053145510Sdarrenr				m[FRC_FL].e++;
1054145510Sdarrenr				m[FRC_FL].n++;
1055145510Sdarrenr			} else
1056145510Sdarrenr				n &= ~0x0004;
1057145510Sdarrenr
1058145510Sdarrenr			if ((n & 0x0008) &&
1059145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1060145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1061145510Sdarrenr			    (fr1->fr_proto == fr->fr_proto)) {
1062145510Sdarrenr				m[FRC_P].e++;
1063145510Sdarrenr				m[FRC_P].n++;
1064145510Sdarrenr			} else
1065145510Sdarrenr				n &= ~0x0008;
1066145510Sdarrenr
1067145510Sdarrenr			if ((n & 0x0010) &&
1068145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1069145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1070145510Sdarrenr			    (fr1->fr_ttl == fr->fr_ttl)) {
1071145510Sdarrenr				m[FRC_TTL].e++;
1072145510Sdarrenr				m[FRC_TTL].n++;
1073145510Sdarrenr			} else
1074145510Sdarrenr				n &= ~0x0010;
1075145510Sdarrenr
1076145510Sdarrenr			if ((n & 0x0020) &&
1077145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1078145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1079145510Sdarrenr			    (fr1->fr_tos == fr->fr_tos)) {
1080145510Sdarrenr				m[FRC_TOS].e++;
1081145510Sdarrenr				m[FRC_TOS].n++;
1082145510Sdarrenr			} else
1083145510Sdarrenr				n &= ~0x0020;
1084145510Sdarrenr
1085145510Sdarrenr			if ((n & 0x0040) &&
1086145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1087145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1088145510Sdarrenr			    ((fr1->fr_tcpfm == fr->fr_tcpfm) &&
1089145510Sdarrenr			    (fr1->fr_tcpf == fr->fr_tcpf))) {
1090145510Sdarrenr				m[FRC_TCP].e++;
1091145510Sdarrenr				m[FRC_TCP].n++;
1092145510Sdarrenr			} else
1093145510Sdarrenr				n &= ~0x0040;
1094145510Sdarrenr
1095145510Sdarrenr			if ((n & 0x0080) &&
1096145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1097145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1098145510Sdarrenr			    ((fr1->fr_scmp == fr->fr_scmp) &&
1099145510Sdarrenr			     (fr1->fr_stop == fr->fr_stop) &&
1100145510Sdarrenr			     (fr1->fr_sport == fr->fr_sport))) {
1101145510Sdarrenr				m[FRC_SP].e++;
1102145510Sdarrenr				m[FRC_SP].n++;
1103145510Sdarrenr			} else
1104145510Sdarrenr				n &= ~0x0080;
1105145510Sdarrenr
1106145510Sdarrenr			if ((n & 0x0100) &&
1107145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1108145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1109145510Sdarrenr			    ((fr1->fr_dcmp == fr->fr_dcmp) &&
1110145510Sdarrenr			     (fr1->fr_dtop == fr->fr_dtop) &&
1111145510Sdarrenr			     (fr1->fr_dport == fr->fr_dport))) {
1112145510Sdarrenr				m[FRC_DP].e++;
1113145510Sdarrenr				m[FRC_DP].n++;
1114145510Sdarrenr			} else
1115145510Sdarrenr				n &= ~0x0100;
1116145510Sdarrenr
1117145510Sdarrenr			if ((n & 0x0200) &&
1118145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1119145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1120145510Sdarrenr			    ((fr1->fr_satype == FRI_LOOKUP) &&
1121145510Sdarrenr			    (fr->fr_satype == FRI_LOOKUP) &&
1122145510Sdarrenr			    (fr1->fr_srcnum == fr->fr_srcnum))) {
1123145510Sdarrenr				m[FRC_SRC].e++;
1124145510Sdarrenr				m[FRC_SRC].n++;
1125145510Sdarrenr			} else if ((n & 0x0200) &&
1126145510Sdarrenr				   (fr->fr_type == fr1->fr_type) &&
1127145510Sdarrenr				   (fr->fr_type == FR_T_IPF) &&
1128145510Sdarrenr				   (((fr1->fr_flags & FR_NOTSRCIP) ==
1129145510Sdarrenr				    (fr->fr_flags & FR_NOTSRCIP)))) {
1130145510Sdarrenr					if ((fr1->fr_smask == fr->fr_smask) &&
1131145510Sdarrenr					    (fr1->fr_saddr == fr->fr_saddr))
1132145510Sdarrenr						m[FRC_SRC].e++;
1133145510Sdarrenr					else
1134145510Sdarrenr						n &= ~0x0200;
1135145510Sdarrenr					if (fr1->fr_smask &&
1136145510Sdarrenr					    (fr1->fr_saddr & fr1->fr_smask) ==
1137145510Sdarrenr					    (fr->fr_saddr & fr1->fr_smask)) {
1138145510Sdarrenr						m[FRC_SRC].n++;
1139145510Sdarrenr						n |= 0x0200;
1140145510Sdarrenr					}
1141145510Sdarrenr			} else {
1142145510Sdarrenr				n &= ~0x0200;
1143145510Sdarrenr			}
1144145510Sdarrenr
1145145510Sdarrenr			if ((n & 0x0400) &&
1146145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1147145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1148145510Sdarrenr			    ((fr1->fr_datype == FRI_LOOKUP) &&
1149145510Sdarrenr			    (fr->fr_datype == FRI_LOOKUP) &&
1150145510Sdarrenr			    (fr1->fr_dstnum == fr->fr_dstnum))) {
1151145510Sdarrenr				m[FRC_DST].e++;
1152145510Sdarrenr				m[FRC_DST].n++;
1153145510Sdarrenr			} else if ((n & 0x0400) &&
1154145510Sdarrenr				   (fr->fr_type == fr1->fr_type) &&
1155145510Sdarrenr				   (fr->fr_type == FR_T_IPF) &&
1156145510Sdarrenr				   (((fr1->fr_flags & FR_NOTDSTIP) ==
1157145510Sdarrenr				    (fr->fr_flags & FR_NOTDSTIP)))) {
1158145510Sdarrenr					if ((fr1->fr_dmask == fr->fr_dmask) &&
1159145510Sdarrenr					    (fr1->fr_daddr == fr->fr_daddr))
1160145510Sdarrenr						m[FRC_DST].e++;
1161145510Sdarrenr					else
1162145510Sdarrenr						n &= ~0x0400;
1163145510Sdarrenr					if (fr1->fr_dmask &&
1164145510Sdarrenr					    (fr1->fr_daddr & fr1->fr_dmask) ==
1165145510Sdarrenr					    (fr->fr_daddr & fr1->fr_dmask)) {
1166145510Sdarrenr						m[FRC_DST].n++;
1167145510Sdarrenr						n |= 0x0400;
1168145510Sdarrenr					}
1169145510Sdarrenr			} else {
1170145510Sdarrenr				n &= ~0x0400;
1171145510Sdarrenr			}
1172145510Sdarrenr
1173145510Sdarrenr			if ((n & 0x0800) &&
1174145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1175145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1176145510Sdarrenr			    (fr1->fr_optmask == fr->fr_optmask) &&
1177145510Sdarrenr			    (fr1->fr_optbits == fr->fr_optbits)) {
1178145510Sdarrenr				m[FRC_OPT].e++;
1179145510Sdarrenr				m[FRC_OPT].n++;
1180145510Sdarrenr			} else
1181145510Sdarrenr				n &= ~0x0800;
1182145510Sdarrenr
1183145510Sdarrenr			if ((n & 0x1000) &&
1184145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1185145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1186145510Sdarrenr			    (fr1->fr_secmask == fr->fr_secmask) &&
1187145510Sdarrenr			    (fr1->fr_secbits == fr->fr_secbits)) {
1188145510Sdarrenr				m[FRC_SEC].e++;
1189145510Sdarrenr				m[FRC_SEC].n++;
1190145510Sdarrenr			} else
1191145510Sdarrenr				n &= ~0x1000;
1192145510Sdarrenr
1193145510Sdarrenr			if ((n & 0x10000) &&
1194145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1195145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1196145510Sdarrenr			    (fr1->fr_authmask == fr->fr_authmask) &&
1197145510Sdarrenr			    (fr1->fr_authbits == fr->fr_authbits)) {
1198145510Sdarrenr				m[FRC_ATH].e++;
1199145510Sdarrenr				m[FRC_ATH].n++;
1200145510Sdarrenr			} else
1201145510Sdarrenr				n &= ~0x10000;
1202145510Sdarrenr
1203145510Sdarrenr			if ((n & 0x20000) &&
1204145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1205145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1206145510Sdarrenr			    ((fr1->fr_icmpm & 0xff00) ==
1207145510Sdarrenr			     (fr->fr_icmpm & 0xff00)) &&
1208145510Sdarrenr			    ((fr1->fr_icmp & 0xff00) ==
1209145510Sdarrenr			     (fr->fr_icmp & 0xff00))) {
1210145510Sdarrenr				m[FRC_ICT].e++;
1211145510Sdarrenr				m[FRC_ICT].n++;
1212145510Sdarrenr			} else
1213145510Sdarrenr				n &= ~0x20000;
1214145510Sdarrenr
1215145510Sdarrenr			if ((n & 0x40000) &&
1216145510Sdarrenr			    (fr->fr_type == fr1->fr_type) &&
1217145510Sdarrenr			    (fr->fr_type == FR_T_IPF) &&
1218145510Sdarrenr			    ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) &&
1219145510Sdarrenr			    ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) {
1220145510Sdarrenr				m[FRC_ICC].e++;
1221145510Sdarrenr				m[FRC_ICC].n++;
1222145510Sdarrenr			} else
1223145510Sdarrenr				n &= ~0x40000;
1224145510Sdarrenr		}
1225145510Sdarrenr		/*msort(m);*/
1226145510Sdarrenr
1227145510Sdarrenr		if (dir == 0)
1228145510Sdarrenr			emitGroup(rn, dir, m, fr1, group, count, 0);
1229145510Sdarrenr		else if (dir == 1)
1230145510Sdarrenr			emitGroup(rn, dir, m, fr1, group, 0, count);
1231145510Sdarrenr	}
1232145510Sdarrenr}
1233145510Sdarrenr
1234145510Sdarrenrstatic void printhooks(fp, in, out, grp)
1235255332Scy	FILE *fp;
1236255332Scy	int in;
1237255332Scy	int out;
1238255332Scy	frgroup_t *grp;
1239145510Sdarrenr{
1240145510Sdarrenr	frentry_t *fr;
1241145510Sdarrenr	char *group;
1242145510Sdarrenr	int dogrp, i;
1243145510Sdarrenr	char *instr;
1244145510Sdarrenr
1245145510Sdarrenr	group = grp->fg_name;
1246255332Scy	dogrp = 0;
1247145510Sdarrenr
1248145510Sdarrenr	if (in && out) {
1249145510Sdarrenr		fprintf(stderr,
1250145510Sdarrenr			"printhooks called with both in and out set\n");
1251145510Sdarrenr		exit(1);
1252145510Sdarrenr	}
1253145510Sdarrenr
1254145510Sdarrenr	if (in) {
1255145510Sdarrenr		instr = "in";
1256145510Sdarrenr	} else if (out) {
1257145510Sdarrenr		instr = "out";
1258145510Sdarrenr	} else {
1259145510Sdarrenr		instr = "???";
1260145510Sdarrenr	}
1261145510Sdarrenr	fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group);
1262145510Sdarrenr
1263145510Sdarrenr	fprintf(fp, "\
1264145510Sdarrenr\n\
1265145510Sdarrenrint ipfrule_add_%s_%s()\n", instr, group);
1266145510Sdarrenr	fprintf(fp, "\
1267145510Sdarrenr{\n\
1268145510Sdarrenr	int i, j, err = 0, max;\n\
1269145510Sdarrenr	frentry_t *fp;\n");
1270145510Sdarrenr
1271145510Sdarrenr	if (dogrp)
1272145510Sdarrenr		fprintf(fp, "\
1273145510Sdarrenr	frgroup_t *fg;\n");
1274145510Sdarrenr
1275145510Sdarrenr	fprintf(fp, "\n");
1276145510Sdarrenr
1277145510Sdarrenr	for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next)
1278145510Sdarrenr		if (fr->fr_dsize > 0) {
1279145510Sdarrenr			fprintf(fp, "\
1280145510Sdarrenr	ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n",
1281145510Sdarrenr				instr, grp->fg_name, i,
1282145510Sdarrenr				instr, grp->fg_name, i);
1283145510Sdarrenr		}
1284145510Sdarrenr	fprintf(fp, "\
1285145510Sdarrenr	max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\
1286145510Sdarrenr	for (i = 0; i < max; i++) {\n\
1287145510Sdarrenr		fp = ipf_rules_%s_%s[i];\n\
1288145510Sdarrenr		fp->fr_next = NULL;\n", instr, group, instr, group);
1289145510Sdarrenr
1290145510Sdarrenr	fprintf(fp, "\
1291145510Sdarrenr		for (j = i + 1; j < max; j++)\n\
1292255332Scy			if (strncmp(fp->fr_names + fp->fr_group,\n\
1293255332Scy				    ipf_rules_%s_%s[j]->fr_names +\n\
1294145510Sdarrenr				    ipf_rules_%s_%s[j]->fr_group,\n\
1295145510Sdarrenr				    FR_GROUPLEN) == 0) {\n\
1296255332Scy				if (ipf_rules_%s_%s[j] != NULL)\n\
1297255332Scy					ipf_rules_%s_%s[j]->fr_pnext =\n\
1298255332Scy					    &fp->fr_next;\n\
1299255332Scy				fp->fr_pnext = &ipf_rules_%s_%s[j];\n\
1300145510Sdarrenr				fp->fr_next = ipf_rules_%s_%s[j];\n\
1301145510Sdarrenr				break;\n\
1302255332Scy			}\n", instr, group, instr, group, instr, group,
1303255332Scy			      instr, group, instr, group, instr, group);
1304145510Sdarrenr	if (dogrp)
1305145510Sdarrenr		fprintf(fp, "\
1306145510Sdarrenr\n\
1307255332Scy		if (fp->fr_grhead != -1) {\n\
1308255332Scy			fg = fr_addgroup(fp->fr_names + fp->fr_grhead,\n\
1309255332Scy					 fp, FR_INQUE, IPL_LOGIPF, 0);\n\
1310145510Sdarrenr			if (fg != NULL)\n\
1311145510Sdarrenr				fp->fr_grp = &fg->fg_start;\n\
1312145510Sdarrenr		}\n");
1313145510Sdarrenr	fprintf(fp, "\
1314145510Sdarrenr	}\n\
1315145510Sdarrenr\n\
1316145510Sdarrenr	fp = &ipfrule_%s_%s;\n", instr, group);
1317145510Sdarrenr		fprintf(fp, "\
1318145510Sdarrenr	bzero((char *)fp, sizeof(*fp));\n\
1319255332Scy	fp->fr_type = FR_T_CALLFUNC_BUILTIN;\n\
1320145510Sdarrenr	fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\
1321145510Sdarrenr	fp->fr_data = (void *)ipf_rules_%s_%s[0];\n",
1322145510Sdarrenr		(in != 0) ? "IN" : "OUT", instr, group);
1323145510Sdarrenr	fprintf(fp, "\
1324145510Sdarrenr	fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n",
1325145510Sdarrenr		instr, group);
1326145510Sdarrenr
1327145510Sdarrenr	fprintf(fp, "\
1328255332Scy	fp->fr_family = AF_INET;\n\
1329145510Sdarrenr	fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\
1330255332Scy	err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,\n\
1331255332Scy			ipfmain.ipf_active, 0);\n",
1332145510Sdarrenr			instr, group);
1333145510Sdarrenr	fprintf(fp, "\treturn err;\n}\n");
1334145510Sdarrenr
1335145510Sdarrenr	fprintf(fp, "\n\n\
1336145510Sdarrenrint ipfrule_remove_%s_%s()\n", instr, group);
1337145510Sdarrenr	fprintf(fp, "\
1338145510Sdarrenr{\n\
1339145510Sdarrenr	int err = 0, i;\n\
1340145510Sdarrenr	frentry_t *fp;\n\
1341145510Sdarrenr\n\
1342145510Sdarrenr	/*\n\
1343145510Sdarrenr	 * Try to remove the %sbound rule.\n", instr);
1344145510Sdarrenr
1345145510Sdarrenr	fprintf(fp, "\
1346145510Sdarrenr	 */\n\
1347145510Sdarrenr	if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group);
1348145510Sdarrenr
1349145510Sdarrenr	fprintf(fp, "\
1350145510Sdarrenr		err = EBUSY;\n\
1351145510Sdarrenr	} else {\n");
1352145510Sdarrenr
1353145510Sdarrenr	fprintf(fp, "\
1354145510Sdarrenr		i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\
1355145510Sdarrenr		for (; i >= 0; i--) {\n\
1356145510Sdarrenr			fp = ipf_rules_%s_%s[i];\n\
1357145510Sdarrenr			if (fp->fr_ref > 1) {\n\
1358145510Sdarrenr				err = EBUSY;\n\
1359145510Sdarrenr				break;\n\
1360145510Sdarrenr			}\n\
1361145510Sdarrenr		}\n\
1362145510Sdarrenr	}\n\
1363145510Sdarrenr	if (err == 0)\n\
1364255332Scy		err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,\n\
1365255332Scy				(caddr_t)&ipfrule_%s_%s,\n\
1366255332Scy				ipfmain.ipf_active, 0);\n",
1367145510Sdarrenr		instr, group, instr, group, instr, group);
1368145510Sdarrenr	fprintf(fp, "\
1369145510Sdarrenr	if (err)\n\
1370145510Sdarrenr		return err;\n\
1371145510Sdarrenr\n\n");
1372145510Sdarrenr
1373145510Sdarrenr	fprintf(fp, "\treturn err;\n}\n");
1374145510Sdarrenr}
1375