xref: /freebsd/sys/netpfil/ipfw/ip_fw_table_algo.c (revision 9f7d47b02590c7ed73b2d29450c4c8c52ac8c80b)
1*9f7d47b0SAlexander V. Chernikov /*-
2*9f7d47b0SAlexander V. Chernikov  * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
3*9f7d47b0SAlexander V. Chernikov  *
4*9f7d47b0SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
5*9f7d47b0SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
6*9f7d47b0SAlexander V. Chernikov  * are met:
7*9f7d47b0SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
8*9f7d47b0SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
9*9f7d47b0SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
10*9f7d47b0SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
11*9f7d47b0SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
12*9f7d47b0SAlexander V. Chernikov  *
13*9f7d47b0SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*9f7d47b0SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*9f7d47b0SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*9f7d47b0SAlexander V. Chernikov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*9f7d47b0SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*9f7d47b0SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*9f7d47b0SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*9f7d47b0SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*9f7d47b0SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*9f7d47b0SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*9f7d47b0SAlexander V. Chernikov  * SUCH DAMAGE.
24*9f7d47b0SAlexander V. Chernikov  */
25*9f7d47b0SAlexander V. Chernikov 
26*9f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h>
27*9f7d47b0SAlexander V. Chernikov __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-12 09:59:11Z melifaro $");
28*9f7d47b0SAlexander V. Chernikov 
29*9f7d47b0SAlexander V. Chernikov /*
30*9f7d47b0SAlexander V. Chernikov  * Lookup table algorithms.
31*9f7d47b0SAlexander V. Chernikov  *
32*9f7d47b0SAlexander V. Chernikov  * Lookup tables are implemented (at the moment) using the radix
33*9f7d47b0SAlexander V. Chernikov  * tree used for routing tables. Tables store key-value entries, where
34*9f7d47b0SAlexander V. Chernikov  * keys are network prefixes (addr/masklen), and values are integers.
35*9f7d47b0SAlexander V. Chernikov  * As a degenerate case we can interpret keys as 32-bit integers
36*9f7d47b0SAlexander V. Chernikov  * (with a /32 mask).
37*9f7d47b0SAlexander V. Chernikov  *
38*9f7d47b0SAlexander V. Chernikov  * The table is protected by the IPFW lock even for manipulation coming
39*9f7d47b0SAlexander V. Chernikov  * from userland, because operations are typically fast.
40*9f7d47b0SAlexander V. Chernikov  */
41*9f7d47b0SAlexander V. Chernikov 
42*9f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h"
43*9f7d47b0SAlexander V. Chernikov #include "opt_inet.h"
44*9f7d47b0SAlexander V. Chernikov #ifndef INET
45*9f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET.
46*9f7d47b0SAlexander V. Chernikov #endif /* INET */
47*9f7d47b0SAlexander V. Chernikov #include "opt_inet6.h"
48*9f7d47b0SAlexander V. Chernikov 
49*9f7d47b0SAlexander V. Chernikov #include <sys/param.h>
50*9f7d47b0SAlexander V. Chernikov #include <sys/systm.h>
51*9f7d47b0SAlexander V. Chernikov #include <sys/malloc.h>
52*9f7d47b0SAlexander V. Chernikov #include <sys/kernel.h>
53*9f7d47b0SAlexander V. Chernikov #include <sys/lock.h>
54*9f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h>
55*9f7d47b0SAlexander V. Chernikov #include <sys/socket.h>
56*9f7d47b0SAlexander V. Chernikov #include <sys/queue.h>
57*9f7d47b0SAlexander V. Chernikov #include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
58*9f7d47b0SAlexander V. Chernikov #include <net/radix.h>
59*9f7d47b0SAlexander V. Chernikov #include <net/route.h>
60*9f7d47b0SAlexander V. Chernikov #include <net/vnet.h>
61*9f7d47b0SAlexander V. Chernikov 
62*9f7d47b0SAlexander V. Chernikov #include <netinet/in.h>
63*9f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
64*9f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h>
65*9f7d47b0SAlexander V. Chernikov 
66*9f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h>
67*9f7d47b0SAlexander V. Chernikov 
68*9f7d47b0SAlexander V. Chernikov static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
69*9f7d47b0SAlexander V. Chernikov 
70*9f7d47b0SAlexander V. Chernikov /*
71*9f7d47b0SAlexander V. Chernikov  * The radix code expects addr and mask to be array of bytes,
72*9f7d47b0SAlexander V. Chernikov  * with the first byte being the length of the array. rn_inithead
73*9f7d47b0SAlexander V. Chernikov  * is called with the offset in bits of the lookup key within the
74*9f7d47b0SAlexander V. Chernikov  * array. If we use a sockaddr_in as the underlying type,
75*9f7d47b0SAlexander V. Chernikov  * sin_len is conveniently located at offset 0, sin_addr is at
76*9f7d47b0SAlexander V. Chernikov  * offset 4 and normally aligned.
77*9f7d47b0SAlexander V. Chernikov  * But for portability, let's avoid assumption and make the code explicit
78*9f7d47b0SAlexander V. Chernikov  */
79*9f7d47b0SAlexander V. Chernikov #define KEY_LEN(v)	*((uint8_t *)&(v))
80*9f7d47b0SAlexander V. Chernikov #define KEY_OFS		(8*offsetof(struct sockaddr_in, sin_addr))
81*9f7d47b0SAlexander V. Chernikov /*
82*9f7d47b0SAlexander V. Chernikov  * Do not require radix to compare more than actual IPv4/IPv6 address
83*9f7d47b0SAlexander V. Chernikov  */
84*9f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET	(offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
85*9f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET6	(offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr))
86*9f7d47b0SAlexander V. Chernikov #define KEY_LEN_IFACE	(offsetof(struct xaddr_iface, ifname))
87*9f7d47b0SAlexander V. Chernikov 
88*9f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET	(8 * offsetof(struct sockaddr_in, sin_addr))
89*9f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET6	(8 * offsetof(struct sockaddr_in6, sin6_addr))
90*9f7d47b0SAlexander V. Chernikov #define OFF_LEN_IFACE	(8 * offsetof(struct xaddr_iface, ifname))
91*9f7d47b0SAlexander V. Chernikov 
92*9f7d47b0SAlexander V. Chernikov struct table_entry {
93*9f7d47b0SAlexander V. Chernikov 	struct radix_node	rn[2];
94*9f7d47b0SAlexander V. Chernikov 	struct sockaddr_in	addr, mask;
95*9f7d47b0SAlexander V. Chernikov 	u_int32_t		value;
96*9f7d47b0SAlexander V. Chernikov };
97*9f7d47b0SAlexander V. Chernikov 
98*9f7d47b0SAlexander V. Chernikov struct xaddr_iface {
99*9f7d47b0SAlexander V. Chernikov 	uint8_t		if_len;		/* length of this struct */
100*9f7d47b0SAlexander V. Chernikov 	uint8_t		pad[7];		/* Align name */
101*9f7d47b0SAlexander V. Chernikov 	char 		ifname[IF_NAMESIZE];	/* Interface name */
102*9f7d47b0SAlexander V. Chernikov };
103*9f7d47b0SAlexander V. Chernikov 
104*9f7d47b0SAlexander V. Chernikov struct table_xentry {
105*9f7d47b0SAlexander V. Chernikov 	struct radix_node	rn[2];
106*9f7d47b0SAlexander V. Chernikov 	union {
107*9f7d47b0SAlexander V. Chernikov #ifdef INET6
108*9f7d47b0SAlexander V. Chernikov 		struct sockaddr_in6	addr6;
109*9f7d47b0SAlexander V. Chernikov #endif
110*9f7d47b0SAlexander V. Chernikov 		struct xaddr_iface	iface;
111*9f7d47b0SAlexander V. Chernikov 	} a;
112*9f7d47b0SAlexander V. Chernikov 	union {
113*9f7d47b0SAlexander V. Chernikov #ifdef INET6
114*9f7d47b0SAlexander V. Chernikov 		struct sockaddr_in6	mask6;
115*9f7d47b0SAlexander V. Chernikov #endif
116*9f7d47b0SAlexander V. Chernikov 		struct xaddr_iface	ifmask;
117*9f7d47b0SAlexander V. Chernikov 	} m;
118*9f7d47b0SAlexander V. Chernikov 	u_int32_t		value;
119*9f7d47b0SAlexander V. Chernikov };
120*9f7d47b0SAlexander V. Chernikov 
121*9f7d47b0SAlexander V. Chernikov 
122*9f7d47b0SAlexander V. Chernikov 
123*9f7d47b0SAlexander V. Chernikov 
124*9f7d47b0SAlexander V. Chernikov /*
125*9f7d47b0SAlexander V. Chernikov  * CIDR implementation using radix
126*9f7d47b0SAlexander V. Chernikov  *
127*9f7d47b0SAlexander V. Chernikov  */
128*9f7d47b0SAlexander V. Chernikov 
129*9f7d47b0SAlexander V. Chernikov static int
130*9f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
131*9f7d47b0SAlexander V. Chernikov     uint32_t *val)
132*9f7d47b0SAlexander V. Chernikov {
133*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
134*9f7d47b0SAlexander V. Chernikov 
135*9f7d47b0SAlexander V. Chernikov 	if (keylen == sizeof(in_addr_t)) {
136*9f7d47b0SAlexander V. Chernikov 		struct table_entry *ent;
137*9f7d47b0SAlexander V. Chernikov 		struct sockaddr_in sa;
138*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(sa) = KEY_LEN_INET;
139*9f7d47b0SAlexander V. Chernikov 		sa.sin_addr.s_addr = *((in_addr_t *)key);
140*9f7d47b0SAlexander V. Chernikov 		rnh = (struct radix_node_head *)ti->state;
141*9f7d47b0SAlexander V. Chernikov 		ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh));
142*9f7d47b0SAlexander V. Chernikov 		if (ent != NULL) {
143*9f7d47b0SAlexander V. Chernikov 			*val = ent->value;
144*9f7d47b0SAlexander V. Chernikov 			return (1);
145*9f7d47b0SAlexander V. Chernikov 		}
146*9f7d47b0SAlexander V. Chernikov 	} else {
147*9f7d47b0SAlexander V. Chernikov 		struct table_xentry *xent;
148*9f7d47b0SAlexander V. Chernikov 		struct sockaddr_in6 sa6;
149*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(sa6) = KEY_LEN_INET6;
150*9f7d47b0SAlexander V. Chernikov 		memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
151*9f7d47b0SAlexander V. Chernikov 		rnh = (struct radix_node_head *)ti->xstate;
152*9f7d47b0SAlexander V. Chernikov 		xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
153*9f7d47b0SAlexander V. Chernikov 		if (xent != NULL) {
154*9f7d47b0SAlexander V. Chernikov 			*val = xent->value;
155*9f7d47b0SAlexander V. Chernikov 			return (1);
156*9f7d47b0SAlexander V. Chernikov 		}
157*9f7d47b0SAlexander V. Chernikov 	}
158*9f7d47b0SAlexander V. Chernikov 
159*9f7d47b0SAlexander V. Chernikov 	return (0);
160*9f7d47b0SAlexander V. Chernikov }
161*9f7d47b0SAlexander V. Chernikov 
162*9f7d47b0SAlexander V. Chernikov /*
163*9f7d47b0SAlexander V. Chernikov  * New table
164*9f7d47b0SAlexander V. Chernikov  */
165*9f7d47b0SAlexander V. Chernikov static int
166*9f7d47b0SAlexander V. Chernikov ta_init_radix(void **ta_state, struct table_info *ti)
167*9f7d47b0SAlexander V. Chernikov {
168*9f7d47b0SAlexander V. Chernikov 
169*9f7d47b0SAlexander V. Chernikov 	if (!rn_inithead(&ti->state, OFF_LEN_INET))
170*9f7d47b0SAlexander V. Chernikov 		return (ENOMEM);
171*9f7d47b0SAlexander V. Chernikov 	if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
172*9f7d47b0SAlexander V. Chernikov 		rn_detachhead(&ti->state);
173*9f7d47b0SAlexander V. Chernikov 		return (ENOMEM);
174*9f7d47b0SAlexander V. Chernikov 	}
175*9f7d47b0SAlexander V. Chernikov 
176*9f7d47b0SAlexander V. Chernikov 	*ta_state = NULL;
177*9f7d47b0SAlexander V. Chernikov 	ti->lookup = ta_lookup_radix;
178*9f7d47b0SAlexander V. Chernikov 
179*9f7d47b0SAlexander V. Chernikov 	return (0);
180*9f7d47b0SAlexander V. Chernikov }
181*9f7d47b0SAlexander V. Chernikov 
182*9f7d47b0SAlexander V. Chernikov static int
183*9f7d47b0SAlexander V. Chernikov flush_table_entry(struct radix_node *rn, void *arg)
184*9f7d47b0SAlexander V. Chernikov {
185*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head * const rnh = arg;
186*9f7d47b0SAlexander V. Chernikov 	struct table_entry *ent;
187*9f7d47b0SAlexander V. Chernikov 
188*9f7d47b0SAlexander V. Chernikov 	ent = (struct table_entry *)
189*9f7d47b0SAlexander V. Chernikov 	    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
190*9f7d47b0SAlexander V. Chernikov 	if (ent != NULL)
191*9f7d47b0SAlexander V. Chernikov 		free(ent, M_IPFW_TBL);
192*9f7d47b0SAlexander V. Chernikov 	return (0);
193*9f7d47b0SAlexander V. Chernikov }
194*9f7d47b0SAlexander V. Chernikov 
195*9f7d47b0SAlexander V. Chernikov static void
196*9f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti)
197*9f7d47b0SAlexander V. Chernikov {
198*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
199*9f7d47b0SAlexander V. Chernikov 
200*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)(ti->state);
201*9f7d47b0SAlexander V. Chernikov 	rnh->rnh_walktree(rnh, flush_table_entry, rnh);
202*9f7d47b0SAlexander V. Chernikov 	rn_detachhead(&ti->state);
203*9f7d47b0SAlexander V. Chernikov 
204*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)(ti->xstate);
205*9f7d47b0SAlexander V. Chernikov 	rnh->rnh_walktree(rnh, flush_table_entry, rnh);
206*9f7d47b0SAlexander V. Chernikov 	rn_detachhead(&ti->xstate);
207*9f7d47b0SAlexander V. Chernikov }
208*9f7d47b0SAlexander V. Chernikov 
209*9f7d47b0SAlexander V. Chernikov static int
210*9f7d47b0SAlexander V. Chernikov ta_dump_radix_entry(void *ta_state, struct table_info *ti, void *e,
211*9f7d47b0SAlexander V. Chernikov     ipfw_table_entry *ent)
212*9f7d47b0SAlexander V. Chernikov {
213*9f7d47b0SAlexander V. Chernikov 	struct table_entry *n;
214*9f7d47b0SAlexander V. Chernikov 
215*9f7d47b0SAlexander V. Chernikov 	n = (struct table_entry *)e;
216*9f7d47b0SAlexander V. Chernikov 
217*9f7d47b0SAlexander V. Chernikov 	/* Guess IPv4/IPv6 radix by sockaddr family */
218*9f7d47b0SAlexander V. Chernikov 	if (n->addr.sin_family != AF_INET)
219*9f7d47b0SAlexander V. Chernikov 		return (0);
220*9f7d47b0SAlexander V. Chernikov 
221*9f7d47b0SAlexander V. Chernikov 	if (in_nullhost(n->mask.sin_addr))
222*9f7d47b0SAlexander V. Chernikov 		ent->masklen = 0;
223*9f7d47b0SAlexander V. Chernikov 	else
224*9f7d47b0SAlexander V. Chernikov 		ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
225*9f7d47b0SAlexander V. Chernikov 	ent->addr = n->addr.sin_addr.s_addr;
226*9f7d47b0SAlexander V. Chernikov 	ent->value = n->value;
227*9f7d47b0SAlexander V. Chernikov 
228*9f7d47b0SAlexander V. Chernikov 	return (0);
229*9f7d47b0SAlexander V. Chernikov }
230*9f7d47b0SAlexander V. Chernikov 
231*9f7d47b0SAlexander V. Chernikov static int
232*9f7d47b0SAlexander V. Chernikov ta_dump_radix_xentry(void *ta_state, struct table_info *ti, void *e,
233*9f7d47b0SAlexander V. Chernikov     ipfw_table_xentry *xent)
234*9f7d47b0SAlexander V. Chernikov {
235*9f7d47b0SAlexander V. Chernikov 	struct table_entry *n;
236*9f7d47b0SAlexander V. Chernikov 	struct table_xentry *xn;
237*9f7d47b0SAlexander V. Chernikov #ifdef INET6
238*9f7d47b0SAlexander V. Chernikov 	int i;
239*9f7d47b0SAlexander V. Chernikov 	uint32_t *v;
240*9f7d47b0SAlexander V. Chernikov #endif
241*9f7d47b0SAlexander V. Chernikov 
242*9f7d47b0SAlexander V. Chernikov 	n = (struct table_entry *)e;
243*9f7d47b0SAlexander V. Chernikov 
244*9f7d47b0SAlexander V. Chernikov 	/* Guess IPv4/IPv6 radix by sockaddr family */
245*9f7d47b0SAlexander V. Chernikov 	if (n->addr.sin_family == AF_INET) {
246*9f7d47b0SAlexander V. Chernikov 		if (in_nullhost(n->mask.sin_addr))
247*9f7d47b0SAlexander V. Chernikov 			xent->masklen = 0;
248*9f7d47b0SAlexander V. Chernikov 		else
249*9f7d47b0SAlexander V. Chernikov 			xent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr));
250*9f7d47b0SAlexander V. Chernikov 		/* Save IPv4 address as deprecated IPv6 compatible */
251*9f7d47b0SAlexander V. Chernikov 		xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
252*9f7d47b0SAlexander V. Chernikov 		xent->flags = IPFW_TCF_INET;
253*9f7d47b0SAlexander V. Chernikov 		xent->value = n->value;
254*9f7d47b0SAlexander V. Chernikov #ifdef INET6
255*9f7d47b0SAlexander V. Chernikov 	} else {
256*9f7d47b0SAlexander V. Chernikov 		xn = (struct table_xentry *)e;
257*9f7d47b0SAlexander V. Chernikov 		/* Count IPv6 mask */
258*9f7d47b0SAlexander V. Chernikov 		v = (uint32_t *)&xn->m.mask6.sin6_addr;
259*9f7d47b0SAlexander V. Chernikov 		for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++)
260*9f7d47b0SAlexander V. Chernikov 			xent->masklen += bitcount32(*v);
261*9f7d47b0SAlexander V. Chernikov 		memcpy(&xent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr));
262*9f7d47b0SAlexander V. Chernikov 		xent->value = xn->value;
263*9f7d47b0SAlexander V. Chernikov #endif
264*9f7d47b0SAlexander V. Chernikov 	}
265*9f7d47b0SAlexander V. Chernikov 
266*9f7d47b0SAlexander V. Chernikov 	return (0);
267*9f7d47b0SAlexander V. Chernikov }
268*9f7d47b0SAlexander V. Chernikov 
269*9f7d47b0SAlexander V. Chernikov static void
270*9f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
271*9f7d47b0SAlexander V. Chernikov     void *arg)
272*9f7d47b0SAlexander V. Chernikov {
273*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
274*9f7d47b0SAlexander V. Chernikov 
275*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)(ti->state);
276*9f7d47b0SAlexander V. Chernikov 	rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
277*9f7d47b0SAlexander V. Chernikov 
278*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)(ti->xstate);
279*9f7d47b0SAlexander V. Chernikov 	rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
280*9f7d47b0SAlexander V. Chernikov }
281*9f7d47b0SAlexander V. Chernikov 
282*9f7d47b0SAlexander V. Chernikov 
283*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr
284*9f7d47b0SAlexander V. Chernikov {
285*9f7d47b0SAlexander V. Chernikov 	struct sockaddr	*addr_ptr;
286*9f7d47b0SAlexander V. Chernikov 	struct sockaddr	*mask_ptr;
287*9f7d47b0SAlexander V. Chernikov 	void *ent_ptr;
288*9f7d47b0SAlexander V. Chernikov 	union {
289*9f7d47b0SAlexander V. Chernikov 		struct {
290*9f7d47b0SAlexander V. Chernikov 			struct sockaddr_in sa;
291*9f7d47b0SAlexander V. Chernikov 			struct sockaddr_in ma;
292*9f7d47b0SAlexander V. Chernikov 		} a4;
293*9f7d47b0SAlexander V. Chernikov 		struct {
294*9f7d47b0SAlexander V. Chernikov 			struct sockaddr_in6 sa;
295*9f7d47b0SAlexander V. Chernikov 			struct sockaddr_in6 ma;
296*9f7d47b0SAlexander V. Chernikov 		} a6;
297*9f7d47b0SAlexander V. Chernikov 	} addr;
298*9f7d47b0SAlexander V. Chernikov };
299*9f7d47b0SAlexander V. Chernikov 
300*9f7d47b0SAlexander V. Chernikov #ifdef INET6
301*9f7d47b0SAlexander V. Chernikov static inline void
302*9f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
303*9f7d47b0SAlexander V. Chernikov {
304*9f7d47b0SAlexander V. Chernikov 	uint32_t *cp;
305*9f7d47b0SAlexander V. Chernikov 
306*9f7d47b0SAlexander V. Chernikov 	for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
307*9f7d47b0SAlexander V. Chernikov 		*cp++ = 0xFFFFFFFF;
308*9f7d47b0SAlexander V. Chernikov 	*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
309*9f7d47b0SAlexander V. Chernikov }
310*9f7d47b0SAlexander V. Chernikov #endif
311*9f7d47b0SAlexander V. Chernikov 
312*9f7d47b0SAlexander V. Chernikov 
313*9f7d47b0SAlexander V. Chernikov static int
314*9f7d47b0SAlexander V. Chernikov ta_prepare_add_cidr(struct tentry_info *tei, void *ta_buf)
315*9f7d47b0SAlexander V. Chernikov {
316*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_cidr *tb;
317*9f7d47b0SAlexander V. Chernikov 	struct table_entry *ent;
318*9f7d47b0SAlexander V. Chernikov 	struct table_xentry *xent;
319*9f7d47b0SAlexander V. Chernikov 	in_addr_t addr;
320*9f7d47b0SAlexander V. Chernikov 	int mlen;
321*9f7d47b0SAlexander V. Chernikov 
322*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_cidr *)ta_buf;
323*9f7d47b0SAlexander V. Chernikov 	memset(tb, 0, sizeof(struct ta_buf_cidr));
324*9f7d47b0SAlexander V. Chernikov 
325*9f7d47b0SAlexander V. Chernikov 	mlen = tei->masklen;
326*9f7d47b0SAlexander V. Chernikov 
327*9f7d47b0SAlexander V. Chernikov 	if (tei->plen == sizeof(in_addr_t)) {
328*9f7d47b0SAlexander V. Chernikov #ifdef INET
329*9f7d47b0SAlexander V. Chernikov 		/* IPv4 case */
330*9f7d47b0SAlexander V. Chernikov 		if (mlen > 32)
331*9f7d47b0SAlexander V. Chernikov 			return (EINVAL);
332*9f7d47b0SAlexander V. Chernikov 		ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
333*9f7d47b0SAlexander V. Chernikov 		ent->value = tei->value;
334*9f7d47b0SAlexander V. Chernikov 		/* Set 'total' structure length */
335*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(ent->addr) = KEY_LEN_INET;
336*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(ent->mask) = KEY_LEN_INET;
337*9f7d47b0SAlexander V. Chernikov 		ent->addr.sin_family = AF_INET;
338*9f7d47b0SAlexander V. Chernikov 		ent->mask.sin_addr.s_addr =
339*9f7d47b0SAlexander V. Chernikov 		    htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
340*9f7d47b0SAlexander V. Chernikov 		addr = *((in_addr_t *)tei->paddr);
341*9f7d47b0SAlexander V. Chernikov 		ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
342*9f7d47b0SAlexander V. Chernikov 		/* Set pointers */
343*9f7d47b0SAlexander V. Chernikov 		tb->ent_ptr = ent;
344*9f7d47b0SAlexander V. Chernikov 		tb->addr_ptr = (struct sockaddr *)&ent->addr;
345*9f7d47b0SAlexander V. Chernikov 		tb->mask_ptr = (struct sockaddr *)&ent->mask;
346*9f7d47b0SAlexander V. Chernikov #endif
347*9f7d47b0SAlexander V. Chernikov #ifdef INET6
348*9f7d47b0SAlexander V. Chernikov 	} else if (tei->plen == sizeof(struct in6_addr)) {
349*9f7d47b0SAlexander V. Chernikov 		/* IPv6 case */
350*9f7d47b0SAlexander V. Chernikov 		if (mlen > 128)
351*9f7d47b0SAlexander V. Chernikov 			return (EINVAL);
352*9f7d47b0SAlexander V. Chernikov 		xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
353*9f7d47b0SAlexander V. Chernikov 		xent->value = tei->value;
354*9f7d47b0SAlexander V. Chernikov 		/* Set 'total' structure length */
355*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
356*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
357*9f7d47b0SAlexander V. Chernikov 		xent->a.addr6.sin6_family = AF_INET6;
358*9f7d47b0SAlexander V. Chernikov 		ipv6_writemask(&xent->m.mask6.sin6_addr, mlen);
359*9f7d47b0SAlexander V. Chernikov 		memcpy(&xent->a.addr6.sin6_addr, tei->paddr,
360*9f7d47b0SAlexander V. Chernikov 		    sizeof(struct in6_addr));
361*9f7d47b0SAlexander V. Chernikov 		APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr);
362*9f7d47b0SAlexander V. Chernikov 		/* Set pointers */
363*9f7d47b0SAlexander V. Chernikov 		tb->ent_ptr = xent;
364*9f7d47b0SAlexander V. Chernikov 		tb->addr_ptr = (struct sockaddr *)&xent->a.addr6;
365*9f7d47b0SAlexander V. Chernikov 		tb->mask_ptr = (struct sockaddr *)&xent->m.mask6;
366*9f7d47b0SAlexander V. Chernikov #endif
367*9f7d47b0SAlexander V. Chernikov 	} else {
368*9f7d47b0SAlexander V. Chernikov 		/* Unknown CIDR type */
369*9f7d47b0SAlexander V. Chernikov 		return (EINVAL);
370*9f7d47b0SAlexander V. Chernikov 	}
371*9f7d47b0SAlexander V. Chernikov 
372*9f7d47b0SAlexander V. Chernikov 	return (0);
373*9f7d47b0SAlexander V. Chernikov }
374*9f7d47b0SAlexander V. Chernikov 
375*9f7d47b0SAlexander V. Chernikov static int
376*9f7d47b0SAlexander V. Chernikov ta_add_cidr(void *ta_state, struct table_info *ti,
377*9f7d47b0SAlexander V. Chernikov     struct tentry_info *tei, void *ta_buf)
378*9f7d47b0SAlexander V. Chernikov {
379*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
380*9f7d47b0SAlexander V. Chernikov 	struct radix_node *rn;
381*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_cidr *tb;
382*9f7d47b0SAlexander V. Chernikov 
383*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_cidr *)ta_buf;
384*9f7d47b0SAlexander V. Chernikov 
385*9f7d47b0SAlexander V. Chernikov 	if (tei->plen == sizeof(in_addr_t))
386*9f7d47b0SAlexander V. Chernikov 		rnh = ti->state;
387*9f7d47b0SAlexander V. Chernikov 	else
388*9f7d47b0SAlexander V. Chernikov 		rnh = ti->xstate;
389*9f7d47b0SAlexander V. Chernikov 
390*9f7d47b0SAlexander V. Chernikov 	rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr);
391*9f7d47b0SAlexander V. Chernikov 
392*9f7d47b0SAlexander V. Chernikov 	if (rn == NULL)
393*9f7d47b0SAlexander V. Chernikov 		return (EEXIST);
394*9f7d47b0SAlexander V. Chernikov 
395*9f7d47b0SAlexander V. Chernikov 	return (0);
396*9f7d47b0SAlexander V. Chernikov }
397*9f7d47b0SAlexander V. Chernikov 
398*9f7d47b0SAlexander V. Chernikov static int
399*9f7d47b0SAlexander V. Chernikov ta_prepare_del_cidr(struct tentry_info *tei, void *ta_buf)
400*9f7d47b0SAlexander V. Chernikov {
401*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_cidr *tb;
402*9f7d47b0SAlexander V. Chernikov 	in_addr_t addr;
403*9f7d47b0SAlexander V. Chernikov 	int mlen;
404*9f7d47b0SAlexander V. Chernikov 
405*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_cidr *)ta_buf;
406*9f7d47b0SAlexander V. Chernikov 	memset(tb, 0, sizeof(struct ta_buf_cidr));
407*9f7d47b0SAlexander V. Chernikov 
408*9f7d47b0SAlexander V. Chernikov 	mlen = tei->masklen;
409*9f7d47b0SAlexander V. Chernikov 
410*9f7d47b0SAlexander V. Chernikov 	if (tei->plen == sizeof(in_addr_t)) {
411*9f7d47b0SAlexander V. Chernikov 		/* Set 'total' structure length */
412*9f7d47b0SAlexander V. Chernikov 		struct sockaddr_in sa, mask;
413*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(sa) = KEY_LEN_INET;
414*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(mask) = KEY_LEN_INET;
415*9f7d47b0SAlexander V. Chernikov 		mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
416*9f7d47b0SAlexander V. Chernikov 		addr = *((in_addr_t *)tei->paddr);
417*9f7d47b0SAlexander V. Chernikov 		sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
418*9f7d47b0SAlexander V. Chernikov 		tb->addr.a4.sa = sa;
419*9f7d47b0SAlexander V. Chernikov 		tb->addr.a4.ma = mask;
420*9f7d47b0SAlexander V. Chernikov 		tb->addr_ptr = (struct sockaddr *)&tb->addr.a4.sa;
421*9f7d47b0SAlexander V. Chernikov 		tb->mask_ptr = (struct sockaddr *)&tb->addr.a4.ma;
422*9f7d47b0SAlexander V. Chernikov #ifdef INET6
423*9f7d47b0SAlexander V. Chernikov 	} else if (tei->plen == sizeof(struct in6_addr)) {
424*9f7d47b0SAlexander V. Chernikov 		/* IPv6 case */
425*9f7d47b0SAlexander V. Chernikov 		if (mlen > 128)
426*9f7d47b0SAlexander V. Chernikov 			return (EINVAL);
427*9f7d47b0SAlexander V. Chernikov 		struct sockaddr_in6 sa6, mask6;
428*9f7d47b0SAlexander V. Chernikov 		memset(&sa6, 0, sizeof(struct sockaddr_in6));
429*9f7d47b0SAlexander V. Chernikov 		memset(&mask6, 0, sizeof(struct sockaddr_in6));
430*9f7d47b0SAlexander V. Chernikov 		/* Set 'total' structure length */
431*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(sa6) = KEY_LEN_INET6;
432*9f7d47b0SAlexander V. Chernikov 		KEY_LEN(mask6) = KEY_LEN_INET6;
433*9f7d47b0SAlexander V. Chernikov 		ipv6_writemask(&mask6.sin6_addr, mlen);
434*9f7d47b0SAlexander V. Chernikov 		memcpy(&sa6.sin6_addr, tei->paddr,
435*9f7d47b0SAlexander V. Chernikov 		    sizeof(struct in6_addr));
436*9f7d47b0SAlexander V. Chernikov 		APPLY_MASK(&sa6.sin6_addr, &mask6.sin6_addr);
437*9f7d47b0SAlexander V. Chernikov 		tb->addr.a6.sa = sa6;
438*9f7d47b0SAlexander V. Chernikov 		tb->addr.a6.ma = mask6;
439*9f7d47b0SAlexander V. Chernikov 		tb->addr_ptr = (struct sockaddr *)&tb->addr.a6.sa;
440*9f7d47b0SAlexander V. Chernikov 		tb->mask_ptr = (struct sockaddr *)&tb->addr.a6.ma;
441*9f7d47b0SAlexander V. Chernikov #endif
442*9f7d47b0SAlexander V. Chernikov 	} else
443*9f7d47b0SAlexander V. Chernikov 		return (EINVAL);
444*9f7d47b0SAlexander V. Chernikov 
445*9f7d47b0SAlexander V. Chernikov 	return (0);
446*9f7d47b0SAlexander V. Chernikov }
447*9f7d47b0SAlexander V. Chernikov 
448*9f7d47b0SAlexander V. Chernikov static int
449*9f7d47b0SAlexander V. Chernikov ta_del_cidr(void *ta_state, struct table_info *ti,
450*9f7d47b0SAlexander V. Chernikov     struct tentry_info *tei, void *ta_buf)
451*9f7d47b0SAlexander V. Chernikov {
452*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
453*9f7d47b0SAlexander V. Chernikov 	struct radix_node *rn;
454*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_cidr *tb;
455*9f7d47b0SAlexander V. Chernikov 
456*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_cidr *)ta_buf;
457*9f7d47b0SAlexander V. Chernikov 
458*9f7d47b0SAlexander V. Chernikov 	if (tei->plen == sizeof(in_addr_t))
459*9f7d47b0SAlexander V. Chernikov 		rnh = ti->state;
460*9f7d47b0SAlexander V. Chernikov 	else
461*9f7d47b0SAlexander V. Chernikov 		rnh = ti->xstate;
462*9f7d47b0SAlexander V. Chernikov 
463*9f7d47b0SAlexander V. Chernikov 	rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh);
464*9f7d47b0SAlexander V. Chernikov 
465*9f7d47b0SAlexander V. Chernikov 	tb->ent_ptr = rn;
466*9f7d47b0SAlexander V. Chernikov 
467*9f7d47b0SAlexander V. Chernikov 	if (rn == NULL)
468*9f7d47b0SAlexander V. Chernikov 		return (ESRCH);
469*9f7d47b0SAlexander V. Chernikov 
470*9f7d47b0SAlexander V. Chernikov 	return (0);
471*9f7d47b0SAlexander V. Chernikov }
472*9f7d47b0SAlexander V. Chernikov 
473*9f7d47b0SAlexander V. Chernikov static void
474*9f7d47b0SAlexander V. Chernikov ta_flush_cidr_entry(struct tentry_info *tei, void *ta_buf)
475*9f7d47b0SAlexander V. Chernikov {
476*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_cidr *tb;
477*9f7d47b0SAlexander V. Chernikov 
478*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_cidr *)ta_buf;
479*9f7d47b0SAlexander V. Chernikov 
480*9f7d47b0SAlexander V. Chernikov 	free(tb->ent_ptr, M_IPFW_TBL);
481*9f7d47b0SAlexander V. Chernikov }
482*9f7d47b0SAlexander V. Chernikov 
483*9f7d47b0SAlexander V. Chernikov struct table_algo radix_cidr = {
484*9f7d47b0SAlexander V. Chernikov 	.name		= "cidr",
485*9f7d47b0SAlexander V. Chernikov 	.lookup		= ta_lookup_radix,
486*9f7d47b0SAlexander V. Chernikov 	.init		= ta_init_radix,
487*9f7d47b0SAlexander V. Chernikov 	.destroy	= ta_destroy_radix,
488*9f7d47b0SAlexander V. Chernikov 	.prepare_add	= ta_prepare_add_cidr,
489*9f7d47b0SAlexander V. Chernikov 	.prepare_del	= ta_prepare_del_cidr,
490*9f7d47b0SAlexander V. Chernikov 	.add		= ta_add_cidr,
491*9f7d47b0SAlexander V. Chernikov 	.del		= ta_del_cidr,
492*9f7d47b0SAlexander V. Chernikov 	.flush_entry	= ta_flush_cidr_entry,
493*9f7d47b0SAlexander V. Chernikov 	.foreach	= ta_foreach_radix,
494*9f7d47b0SAlexander V. Chernikov 	.dump_entry	= ta_dump_radix_entry,
495*9f7d47b0SAlexander V. Chernikov 	.dump_xentry	= ta_dump_radix_xentry,
496*9f7d47b0SAlexander V. Chernikov };
497*9f7d47b0SAlexander V. Chernikov 
498*9f7d47b0SAlexander V. Chernikov 
499*9f7d47b0SAlexander V. Chernikov /*
500*9f7d47b0SAlexander V. Chernikov  * Iface table cmds
501*9f7d47b0SAlexander V. Chernikov  *
502*9f7d47b0SAlexander V. Chernikov  */
503*9f7d47b0SAlexander V. Chernikov 
504*9f7d47b0SAlexander V. Chernikov static int
505*9f7d47b0SAlexander V. Chernikov ta_lookup_iface(struct table_info *ti, void *key, uint32_t keylen,
506*9f7d47b0SAlexander V. Chernikov     uint32_t *val)
507*9f7d47b0SAlexander V. Chernikov {
508*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
509*9f7d47b0SAlexander V. Chernikov 	struct xaddr_iface iface;
510*9f7d47b0SAlexander V. Chernikov 	struct table_xentry *xent;
511*9f7d47b0SAlexander V. Chernikov 
512*9f7d47b0SAlexander V. Chernikov 	KEY_LEN(iface) = KEY_LEN_IFACE +
513*9f7d47b0SAlexander V. Chernikov 	    strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1;
514*9f7d47b0SAlexander V. Chernikov 
515*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)ti->xstate;
516*9f7d47b0SAlexander V. Chernikov 	xent = (struct table_xentry *)(rnh->rnh_matchaddr(&iface, rnh));
517*9f7d47b0SAlexander V. Chernikov 	if (xent != NULL) {
518*9f7d47b0SAlexander V. Chernikov 		*val = xent->value;
519*9f7d47b0SAlexander V. Chernikov 		return (1);
520*9f7d47b0SAlexander V. Chernikov 	}
521*9f7d47b0SAlexander V. Chernikov 
522*9f7d47b0SAlexander V. Chernikov 	return (0);
523*9f7d47b0SAlexander V. Chernikov }
524*9f7d47b0SAlexander V. Chernikov 
525*9f7d47b0SAlexander V. Chernikov static int
526*9f7d47b0SAlexander V. Chernikov flush_iface_entry(struct radix_node *rn, void *arg)
527*9f7d47b0SAlexander V. Chernikov {
528*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head * const rnh = arg;
529*9f7d47b0SAlexander V. Chernikov 	struct table_entry *ent;
530*9f7d47b0SAlexander V. Chernikov 
531*9f7d47b0SAlexander V. Chernikov 	ent = (struct table_entry *)
532*9f7d47b0SAlexander V. Chernikov 	    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
533*9f7d47b0SAlexander V. Chernikov 	if (ent != NULL)
534*9f7d47b0SAlexander V. Chernikov 		free(ent, M_IPFW_TBL);
535*9f7d47b0SAlexander V. Chernikov 	return (0);
536*9f7d47b0SAlexander V. Chernikov }
537*9f7d47b0SAlexander V. Chernikov 
538*9f7d47b0SAlexander V. Chernikov static int
539*9f7d47b0SAlexander V. Chernikov ta_init_iface(void **ta_state, struct table_info *ti)
540*9f7d47b0SAlexander V. Chernikov {
541*9f7d47b0SAlexander V. Chernikov 
542*9f7d47b0SAlexander V. Chernikov 	if (!rn_inithead(&ti->xstate, OFF_LEN_IFACE))
543*9f7d47b0SAlexander V. Chernikov 		return (ENOMEM);
544*9f7d47b0SAlexander V. Chernikov 
545*9f7d47b0SAlexander V. Chernikov 	*ta_state = NULL;
546*9f7d47b0SAlexander V. Chernikov 	ti->lookup = ta_lookup_iface;
547*9f7d47b0SAlexander V. Chernikov 
548*9f7d47b0SAlexander V. Chernikov 	return (0);
549*9f7d47b0SAlexander V. Chernikov }
550*9f7d47b0SAlexander V. Chernikov 
551*9f7d47b0SAlexander V. Chernikov 
552*9f7d47b0SAlexander V. Chernikov static void
553*9f7d47b0SAlexander V. Chernikov ta_destroy_iface(void *ta_state, struct table_info *ti)
554*9f7d47b0SAlexander V. Chernikov {
555*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
556*9f7d47b0SAlexander V. Chernikov 
557*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)(ti->xstate);
558*9f7d47b0SAlexander V. Chernikov 	rnh->rnh_walktree(rnh, flush_iface_entry, rnh);
559*9f7d47b0SAlexander V. Chernikov 	rn_detachhead(&ti->state);
560*9f7d47b0SAlexander V. Chernikov }
561*9f7d47b0SAlexander V. Chernikov 
562*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface
563*9f7d47b0SAlexander V. Chernikov {
564*9f7d47b0SAlexander V. Chernikov 	void	*addr_ptr;
565*9f7d47b0SAlexander V. Chernikov 	void	*mask_ptr;
566*9f7d47b0SAlexander V. Chernikov 	void	*ent_ptr;
567*9f7d47b0SAlexander V. Chernikov 	struct xaddr_iface	iface;
568*9f7d47b0SAlexander V. Chernikov };
569*9f7d47b0SAlexander V. Chernikov 
570*9f7d47b0SAlexander V. Chernikov static int
571*9f7d47b0SAlexander V. Chernikov ta_prepare_add_iface(struct tentry_info *tei, void *ta_buf)
572*9f7d47b0SAlexander V. Chernikov {
573*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_iface *tb;
574*9f7d47b0SAlexander V. Chernikov 	struct table_xentry *xent;
575*9f7d47b0SAlexander V. Chernikov 	int mlen;
576*9f7d47b0SAlexander V. Chernikov 	char c;
577*9f7d47b0SAlexander V. Chernikov 
578*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_iface *)ta_buf;
579*9f7d47b0SAlexander V. Chernikov 	memset(tb, 0, sizeof(struct ta_buf_cidr));
580*9f7d47b0SAlexander V. Chernikov 
581*9f7d47b0SAlexander V. Chernikov 	mlen = tei->masklen;
582*9f7d47b0SAlexander V. Chernikov 
583*9f7d47b0SAlexander V. Chernikov 	/* Check if string is terminated */
584*9f7d47b0SAlexander V. Chernikov 	c = ((char *)tei->paddr)[IF_NAMESIZE - 1];
585*9f7d47b0SAlexander V. Chernikov 	((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0';
586*9f7d47b0SAlexander V. Chernikov 	mlen = strlen((char *)tei->paddr);
587*9f7d47b0SAlexander V. Chernikov 	if ((mlen == IF_NAMESIZE - 1) && (c != '\0'))
588*9f7d47b0SAlexander V. Chernikov 		return (EINVAL);
589*9f7d47b0SAlexander V. Chernikov 
590*9f7d47b0SAlexander V. Chernikov 	/* Include last \0 into comparison */
591*9f7d47b0SAlexander V. Chernikov 	mlen++;
592*9f7d47b0SAlexander V. Chernikov 
593*9f7d47b0SAlexander V. Chernikov 	xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
594*9f7d47b0SAlexander V. Chernikov 	xent->value = tei->value;
595*9f7d47b0SAlexander V. Chernikov 	/* Set 'total' structure length */
596*9f7d47b0SAlexander V. Chernikov 	KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen;
597*9f7d47b0SAlexander V. Chernikov 	KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen;
598*9f7d47b0SAlexander V. Chernikov 	memcpy(xent->a.iface.ifname, tei->paddr, mlen);
599*9f7d47b0SAlexander V. Chernikov 	/* Set pointers */
600*9f7d47b0SAlexander V. Chernikov 	tb->ent_ptr = xent;
601*9f7d47b0SAlexander V. Chernikov 	tb->addr_ptr = (struct sockaddr *)&xent->a.iface;
602*9f7d47b0SAlexander V. Chernikov 	/* Assume direct match */
603*9f7d47b0SAlexander V. Chernikov 	tb->mask_ptr = NULL;
604*9f7d47b0SAlexander V. Chernikov 
605*9f7d47b0SAlexander V. Chernikov 	return (0);
606*9f7d47b0SAlexander V. Chernikov }
607*9f7d47b0SAlexander V. Chernikov 
608*9f7d47b0SAlexander V. Chernikov static int
609*9f7d47b0SAlexander V. Chernikov ta_add_iface(void *ta_state, struct table_info *ti,
610*9f7d47b0SAlexander V. Chernikov     struct tentry_info *tei, void *ta_buf)
611*9f7d47b0SAlexander V. Chernikov {
612*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
613*9f7d47b0SAlexander V. Chernikov 	struct radix_node *rn;
614*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_iface *tb;
615*9f7d47b0SAlexander V. Chernikov 
616*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_iface *)ta_buf;
617*9f7d47b0SAlexander V. Chernikov 
618*9f7d47b0SAlexander V. Chernikov 	rnh = ti->xstate;
619*9f7d47b0SAlexander V. Chernikov 	rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr);
620*9f7d47b0SAlexander V. Chernikov 
621*9f7d47b0SAlexander V. Chernikov 	if (rn == NULL)
622*9f7d47b0SAlexander V. Chernikov 		return (1);
623*9f7d47b0SAlexander V. Chernikov 
624*9f7d47b0SAlexander V. Chernikov 	return (0);
625*9f7d47b0SAlexander V. Chernikov }
626*9f7d47b0SAlexander V. Chernikov 
627*9f7d47b0SAlexander V. Chernikov static int
628*9f7d47b0SAlexander V. Chernikov ta_prepare_del_iface(struct tentry_info *tei, void *ta_buf)
629*9f7d47b0SAlexander V. Chernikov {
630*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_iface *tb;
631*9f7d47b0SAlexander V. Chernikov 	int mlen;
632*9f7d47b0SAlexander V. Chernikov 	char c;
633*9f7d47b0SAlexander V. Chernikov 
634*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_iface *)ta_buf;
635*9f7d47b0SAlexander V. Chernikov 	memset(tb, 0, sizeof(struct ta_buf_cidr));
636*9f7d47b0SAlexander V. Chernikov 
637*9f7d47b0SAlexander V. Chernikov 	/* Check if string is terminated */
638*9f7d47b0SAlexander V. Chernikov 	c = ((char *)tei->paddr)[IF_NAMESIZE - 1];
639*9f7d47b0SAlexander V. Chernikov 	((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0';
640*9f7d47b0SAlexander V. Chernikov 	mlen = strlen((char *)tei->paddr);
641*9f7d47b0SAlexander V. Chernikov 	if ((mlen == IF_NAMESIZE - 1) && (c != '\0'))
642*9f7d47b0SAlexander V. Chernikov 		return (EINVAL);
643*9f7d47b0SAlexander V. Chernikov 
644*9f7d47b0SAlexander V. Chernikov 	struct xaddr_iface ifname, ifmask;
645*9f7d47b0SAlexander V. Chernikov 	memset(&ifname, 0, sizeof(ifname));
646*9f7d47b0SAlexander V. Chernikov 
647*9f7d47b0SAlexander V. Chernikov 	/* Include last \0 into comparison */
648*9f7d47b0SAlexander V. Chernikov 	mlen++;
649*9f7d47b0SAlexander V. Chernikov 
650*9f7d47b0SAlexander V. Chernikov 	/* Set 'total' structure length */
651*9f7d47b0SAlexander V. Chernikov 	KEY_LEN(ifname) = KEY_LEN_IFACE + mlen;
652*9f7d47b0SAlexander V. Chernikov 	KEY_LEN(ifmask) = KEY_LEN_IFACE + mlen;
653*9f7d47b0SAlexander V. Chernikov 	/* Assume direct match */
654*9f7d47b0SAlexander V. Chernikov 	memcpy(ifname.ifname, tei->paddr, mlen);
655*9f7d47b0SAlexander V. Chernikov 	/* Set pointers */
656*9f7d47b0SAlexander V. Chernikov 	tb->iface = ifname;
657*9f7d47b0SAlexander V. Chernikov 	tb->addr_ptr = &tb->iface;
658*9f7d47b0SAlexander V. Chernikov 	tb->mask_ptr = NULL;
659*9f7d47b0SAlexander V. Chernikov 
660*9f7d47b0SAlexander V. Chernikov 	return (0);
661*9f7d47b0SAlexander V. Chernikov }
662*9f7d47b0SAlexander V. Chernikov 
663*9f7d47b0SAlexander V. Chernikov static int
664*9f7d47b0SAlexander V. Chernikov ta_del_iface(void *ta_state, struct table_info *ti,
665*9f7d47b0SAlexander V. Chernikov     struct tentry_info *tei, void *ta_buf)
666*9f7d47b0SAlexander V. Chernikov {
667*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
668*9f7d47b0SAlexander V. Chernikov 	struct radix_node *rn;
669*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_iface *tb;
670*9f7d47b0SAlexander V. Chernikov 
671*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_iface *)ta_buf;
672*9f7d47b0SAlexander V. Chernikov 
673*9f7d47b0SAlexander V. Chernikov 	rnh = ti->xstate;
674*9f7d47b0SAlexander V. Chernikov 	rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh);
675*9f7d47b0SAlexander V. Chernikov 
676*9f7d47b0SAlexander V. Chernikov 	tb->ent_ptr = rn;
677*9f7d47b0SAlexander V. Chernikov 
678*9f7d47b0SAlexander V. Chernikov 	if (rn == NULL)
679*9f7d47b0SAlexander V. Chernikov 		return (ESRCH);
680*9f7d47b0SAlexander V. Chernikov 
681*9f7d47b0SAlexander V. Chernikov 	return (0);
682*9f7d47b0SAlexander V. Chernikov }
683*9f7d47b0SAlexander V. Chernikov 
684*9f7d47b0SAlexander V. Chernikov static void
685*9f7d47b0SAlexander V. Chernikov ta_flush_iface_entry(struct tentry_info *tei, void *ta_buf)
686*9f7d47b0SAlexander V. Chernikov {
687*9f7d47b0SAlexander V. Chernikov 	struct ta_buf_iface *tb;
688*9f7d47b0SAlexander V. Chernikov 
689*9f7d47b0SAlexander V. Chernikov 	tb = (struct ta_buf_iface *)ta_buf;
690*9f7d47b0SAlexander V. Chernikov 
691*9f7d47b0SAlexander V. Chernikov 	free(tb->ent_ptr, M_IPFW_TBL);
692*9f7d47b0SAlexander V. Chernikov }
693*9f7d47b0SAlexander V. Chernikov 
694*9f7d47b0SAlexander V. Chernikov static int
695*9f7d47b0SAlexander V. Chernikov ta_dump_iface_xentry(void *ta_state, struct table_info *ti, void *e,
696*9f7d47b0SAlexander V. Chernikov     ipfw_table_xentry *xent)
697*9f7d47b0SAlexander V. Chernikov {
698*9f7d47b0SAlexander V. Chernikov 	struct table_xentry *xn;
699*9f7d47b0SAlexander V. Chernikov 
700*9f7d47b0SAlexander V. Chernikov 	xn = (struct table_xentry *)e;
701*9f7d47b0SAlexander V. Chernikov 	xent->masklen = 8 * IF_NAMESIZE;
702*9f7d47b0SAlexander V. Chernikov 	memcpy(&xent->k, &xn->a.iface.ifname, IF_NAMESIZE);
703*9f7d47b0SAlexander V. Chernikov 	xent->value = xn->value;
704*9f7d47b0SAlexander V. Chernikov 
705*9f7d47b0SAlexander V. Chernikov 	return (0);
706*9f7d47b0SAlexander V. Chernikov }
707*9f7d47b0SAlexander V. Chernikov 
708*9f7d47b0SAlexander V. Chernikov static void
709*9f7d47b0SAlexander V. Chernikov ta_foreach_iface(void *ta_state, struct table_info *ti, ta_foreach_f *f,
710*9f7d47b0SAlexander V. Chernikov     void *arg)
711*9f7d47b0SAlexander V. Chernikov {
712*9f7d47b0SAlexander V. Chernikov 	struct radix_node_head *rnh;
713*9f7d47b0SAlexander V. Chernikov 
714*9f7d47b0SAlexander V. Chernikov 	rnh = (struct radix_node_head *)(ti->xstate);
715*9f7d47b0SAlexander V. Chernikov 	rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg);
716*9f7d47b0SAlexander V. Chernikov }
717*9f7d47b0SAlexander V. Chernikov 
718*9f7d47b0SAlexander V. Chernikov struct table_algo radix_iface = {
719*9f7d47b0SAlexander V. Chernikov 	.name		= "iface",
720*9f7d47b0SAlexander V. Chernikov 	.lookup		= ta_lookup_iface,
721*9f7d47b0SAlexander V. Chernikov 	.init		= ta_init_iface,
722*9f7d47b0SAlexander V. Chernikov 	.destroy		= ta_destroy_iface,
723*9f7d47b0SAlexander V. Chernikov 	.prepare_add	= ta_prepare_add_iface,
724*9f7d47b0SAlexander V. Chernikov 	.prepare_del	= ta_prepare_del_iface,
725*9f7d47b0SAlexander V. Chernikov 	.add		= ta_add_iface,
726*9f7d47b0SAlexander V. Chernikov 	.del		= ta_del_iface,
727*9f7d47b0SAlexander V. Chernikov 	.flush_entry	= ta_flush_iface_entry,
728*9f7d47b0SAlexander V. Chernikov 	.foreach		= ta_foreach_iface,
729*9f7d47b0SAlexander V. Chernikov 	.dump_xentry	= ta_dump_iface_xentry,
730*9f7d47b0SAlexander V. Chernikov };
731*9f7d47b0SAlexander V. Chernikov 
732*9f7d47b0SAlexander V. Chernikov void
733*9f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *chain)
734*9f7d47b0SAlexander V. Chernikov {
735*9f7d47b0SAlexander V. Chernikov 	/*
736*9f7d47b0SAlexander V. Chernikov 	 * Register all algorithms presented here.
737*9f7d47b0SAlexander V. Chernikov 	 */
738*9f7d47b0SAlexander V. Chernikov 	ipfw_add_table_algo(chain, &radix_cidr);
739*9f7d47b0SAlexander V. Chernikov 	ipfw_add_table_algo(chain, &radix_iface);
740*9f7d47b0SAlexander V. Chernikov }
741*9f7d47b0SAlexander V. Chernikov 
742*9f7d47b0SAlexander V. Chernikov void
743*9f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *chain)
744*9f7d47b0SAlexander V. Chernikov {
745*9f7d47b0SAlexander V. Chernikov 	/* Do nothing */
746*9f7d47b0SAlexander V. Chernikov }
747*9f7d47b0SAlexander V. Chernikov 
748*9f7d47b0SAlexander V. Chernikov 
749