1/*-
2 * Copyright (c) 2014 Yandex LLC
3 * Copyright (c) 2014 Alexander V. Chernikov
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28/*
29 * Lookup table algorithms.
30 *
31 */
32
33#include "opt_ipfw.h"
34#include "opt_inet.h"
35#ifndef INET
36#error IPFIREWALL requires INET.
37#endif /* INET */
38#include "opt_inet6.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/malloc.h>
43#include <sys/kernel.h>
44#include <sys/lock.h>
45#include <sys/rwlock.h>
46#include <sys/rmlock.h>
47#include <sys/socket.h>
48#include <sys/queue.h>
49#include <net/ethernet.h>
50#include <net/if.h>	/* ip_fw.h requires IFNAMSIZ */
51#include <net/radix.h>
52#include <net/route.h>
53#include <net/route/nhop.h>
54#include <net/route/route_ctl.h>
55
56#include <netinet/in.h>
57#include <netinet/in_fib.h>
58#include <netinet/ip_var.h>	/* struct ipfw_rule_ref */
59#include <netinet/ip_fw.h>
60#include <netinet6/in6_fib.h>
61
62#include <netpfil/ipfw/ip_fw_private.h>
63#include <netpfil/ipfw/ip_fw_table.h>
64
65/*
66 * IPFW table lookup algorithms.
67 *
68 * What is needed to add another table algo?
69 *
70 * Algo init:
71 * * struct table_algo has to be filled with:
72 *   name: "type:algoname" format, e.g. "addr:radix". Currently
73 *     there are the following types: "addr", "iface", "number" and "flow".
74 *   type: one of IPFW_TABLE_* types
75 *   flags: one or more TA_FLAGS_*
76 *   ta_buf_size: size of structure used to store add/del item state.
77 *     Needs to be less than TA_BUF_SZ.
78 *   callbacks: see below for description.
79 * * ipfw_add_table_algo / ipfw_del_table_algo has to be called
80 *
81 * Callbacks description:
82 *
83 * -init: request to initialize new table instance.
84 * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state,
85 *     struct table_info *ti, char *data, uint8_t tflags);
86 * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
87 *
88 *  Allocate all structures needed for normal operations.
89 *  * Caller may want to parse @data for some algo-specific
90 *    options provided by userland.
91 *  * Caller may want to save configuration state pointer to @ta_state
92 *  * Caller needs to save desired runtime structure pointer(s)
93 *    inside @ti fields. Note that it is not correct to save
94 *    @ti pointer at this moment. Use -change_ti hook for that.
95 *  * Caller has to fill in ti->lookup to appropriate function
96 *    pointer.
97 *
98 *
99 *
100 * -destroy: request to destroy table instance.
101 * typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
102 * MANDATORY, unlocked. (M_WAITOK).
103 *
104 * Frees all table entries and all tables structures allocated by -init.
105 *
106 *
107 *
108 * -prepare_add: request to allocate state for adding new entry.
109 * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei,
110 *     void *ta_buf);
111 * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
112 *
113 * Allocates state and fills it in with all necessary data (EXCEPT value)
114 * from @tei to minimize operations needed to be done under WLOCK.
115 * "value" field has to be copied to new entry in @add callback.
116 * Buffer ta_buf of size ta->ta_buf_sz may be used to store
117 * allocated state.
118 *
119 *
120 *
121 * -prepare_del: request to set state for deleting existing entry.
122 * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
123 *     void *ta_buf);
124 * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success.
125 *
126 * Buffer ta_buf of size ta->ta_buf_sz may be used to store
127 * allocated state. Caller should use on-stack ta_buf allocation
128 * instead of doing malloc().
129 *
130 *
131 *
132 * -add: request to insert new entry into runtime/config structures.
133 *  typedef int (ta_add)(void *ta_state, struct table_info *ti,
134 *     struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
135 * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
136 *
137 * Insert new entry using previously-allocated state in @ta_buf.
138 * * @tei may have the following flags:
139 *   TEI_FLAGS_UPDATE: request to add or update entry.
140 *   TEI_FLAGS_DONTADD: request to update (but not add) entry.
141 * * Caller is required to do the following:
142 *   copy real entry value from @tei
143 *   entry added: return 0, set 1 to @pnum
144 *   entry updated: return 0, store 0 to @pnum, store old value in @tei,
145 *     add TEI_FLAGS_UPDATED flag to @tei.
146 *   entry exists: return EEXIST
147 *   entry not found: return ENOENT
148 *   other error: return non-zero error code.
149 *
150 *
151 *
152 * -del: request to delete existing entry from runtime/config structures.
153 *  typedef int (ta_del)(void *ta_state, struct table_info *ti,
154 *     struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
155 *  MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
156 *
157 *  Delete entry using previously set up in @ta_buf.
158 * * Caller is required to do the following:
159 *   entry deleted: return 0, set 1 to @pnum, store old value in @tei.
160 *   entry not found: return ENOENT
161 *   other error: return non-zero error code.
162 *
163 *
164 *
165 * -flush_entry: flush entry state created by -prepare_add / -del / others
166 *  typedef void (ta_flush_entry)(struct ip_fw_chain *ch,
167 *      struct tentry_info *tei, void *ta_buf);
168 *  MANDATORY, may be locked. (M_NOWAIT).
169 *
170 *  Delete state allocated by:
171 *  -prepare_add (-add returned EEXIST|UPDATED)
172 *  -prepare_del (if any)
173 *  -del
174 *  * Caller is required to handle empty @ta_buf correctly.
175 *
176 *
177 * -find_tentry: finds entry specified by key @tei
178 *  typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
179 *      ipfw_obj_tentry *tent);
180 *  OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success.
181 *
182 *  Finds entry specified by given key.
183 *  * Caller is required to do the following:
184 *    entry found: returns 0, export entry to @tent
185 *    entry not found: returns ENOENT
186 *
187 *
188 * -need_modify: checks if @ti has enough space to hold another @count items.
189 *  typedef int (ta_need_modify)(void *ta_state, struct table_info *ti,
190 *      uint32_t count, uint64_t *pflags);
191 *  OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has.
192 *
193 *  Checks if given table has enough space to add @count items without
194 *  resize. Caller may use @pflags to store desired modification data.
195 *
196 *
197 *
198 * -prepare_mod: allocate structures for table modification.
199 *  typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
200 * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success.
201 *
202 * Allocate all needed state for table modification. Caller
203 * should use `struct mod_item` to store new state in @ta_buf.
204 * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf.
205 *
206 *
207 *
208 * -fill_mod: copy some data to new state/
209 *  typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
210 *      void *ta_buf, uint64_t *pflags);
211 * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success.
212 *
213 * Copy as much data as we can to minimize changes under WLOCK.
214 * For example, array can be merged inside this callback.
215 *
216 *
217 *
218 * -modify: perform final modification.
219 *  typedef void (ta_modify)(void *ta_state, struct table_info *ti,
220 *      void *ta_buf, uint64_t pflags);
221 * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT).
222 *
223 * Performs all changes necessary to switch to new structures.
224 * * Caller should save old pointers to @ta_buf storage.
225 *
226 *
227 *
228 * -flush_mod: flush table modification state.
229 *  typedef void (ta_flush_mod)(void *ta_buf);
230 * OPTIONAL(need_modify), unlocked. (M_WAITOK).
231 *
232 * Performs flush for the following:
233 *   - prepare_mod (modification was not necessary)
234 *   - modify (for the old state)
235 *
236 *
237 *
238 * -change_gi: monitor table info pointer changes
239 * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti);
240 * OPTIONAL, locked (UH). (M_NOWAIT).
241 *
242 * Called on @ti pointer changed. Called immediately after -init
243 * to set initial state.
244 *
245 *
246 *
247 * -foreach: calls @f for each table entry
248 *  typedef void ta_foreach(void *ta_state, struct table_info *ti,
249 *      ta_foreach_f *f, void *arg);
250 * MANDATORY, locked(UH). (M_NOWAIT).
251 *
252 * Runs callback with specified argument for each table entry,
253 * Typically used for dumping table entries.
254 *
255 *
256 *
257 * -dump_tentry: dump table entry in current @tentry format.
258 *  typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
259 *      ipfw_obj_tentry *tent);
260 * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success.
261 *
262 * Dumps entry @e to @tent.
263 *
264 *
265 * -print_config: prints custom algorithm options into buffer.
266 *  typedef void (ta_print_config)(void *ta_state, struct table_info *ti,
267 *      char *buf, size_t bufsize);
268 * OPTIONAL. locked(UH). (M_NOWAIT).
269 *
270 * Prints custom algorithm options in the format suitable to pass
271 * back to -init callback.
272 *
273 *
274 *
275 * -dump_tinfo: dumps algo-specific info.
276 *  typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
277 *      ipfw_ta_tinfo *tinfo);
278 * OPTIONAL. locked(UH). (M_NOWAIT).
279 *
280 * Dumps options like items size/hash size, etc.
281 */
282
283MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
284
285/*
286 * Utility structures/functions common to more than one algo
287 */
288
289struct mod_item {
290	void	*main_ptr;
291	size_t	size;
292	void	*main_ptr6;
293	size_t	size6;
294};
295
296static int badd(const void *key, void *item, void *base, size_t nmemb,
297    size_t size, int (*compar) (const void *, const void *));
298static int bdel(const void *key, void *base, size_t nmemb, size_t size,
299    int (*compar) (const void *, const void *));
300
301/*
302 * ADDR implementation using radix
303 *
304 */
305
306/*
307 * The radix code expects addr and mask to be array of bytes,
308 * with the first byte being the length of the array. rn_inithead
309 * is called with the offset in bits of the lookup key within the
310 * array. If we use a sockaddr_in as the underlying type,
311 * sin_len is conveniently located at offset 0, sin_addr is at
312 * offset 4 and normally aligned.
313 * But for portability, let's avoid assumption and make the code explicit
314 */
315#define KEY_LEN(v)	*((uint8_t *)&(v))
316/*
317 * Do not require radix to compare more than actual IPv4/IPv6/MAC address
318 */
319#define KEY_LEN_INET	(offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
320#define KEY_LEN_INET6	(offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
321#define KEY_LEN_MAC	(offsetof(struct sa_mac, mac_addr) + ETHER_ADDR_LEN)
322
323#define OFF_LEN_INET	(8 * offsetof(struct sockaddr_in, sin_addr))
324#define OFF_LEN_INET6	(8 * offsetof(struct sa_in6, sin6_addr))
325#define OFF_LEN_MAC	(8 * offsetof(struct sa_mac, mac_addr))
326
327struct addr_radix_entry {
328	struct radix_node	rn[2];
329	struct sockaddr_in	addr;
330	uint32_t		value;
331	uint8_t			masklen;
332};
333
334struct sa_in6 {
335	uint8_t			sin6_len;
336	uint8_t			sin6_family;
337	uint8_t			pad[2];
338	struct in6_addr		sin6_addr;
339};
340
341struct addr_radix_xentry {
342	struct radix_node	rn[2];
343	struct sa_in6		addr6;
344	uint32_t		value;
345	uint8_t			masklen;
346};
347
348struct addr_radix_cfg {
349	struct radix_node_head	*head4;
350	struct radix_node_head	*head6;
351	size_t			count4;
352	size_t			count6;
353};
354
355struct sa_mac {
356	uint8_t			mac_len;
357	struct ether_addr	mac_addr;
358};
359
360struct ta_buf_radix
361{
362	void *ent_ptr;
363	struct sockaddr	*addr_ptr;
364	struct sockaddr	*mask_ptr;
365	union {
366		struct {
367			struct sockaddr_in sa;
368			struct sockaddr_in ma;
369		} a4;
370		struct {
371			struct sa_in6 sa;
372			struct sa_in6 ma;
373		} a6;
374		struct {
375			struct sa_mac sa;
376			struct sa_mac ma;
377		} mac;
378	} addr;
379};
380
381static int ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
382    uint32_t *val);
383static int ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state,
384    struct table_info *ti, char *data, uint8_t tflags);
385static int flush_radix_entry(struct radix_node *rn, void *arg);
386static void ta_destroy_addr_radix(void *ta_state, struct table_info *ti);
387static void ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti,
388    ipfw_ta_tinfo *tinfo);
389static int ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti,
390    void *e, ipfw_obj_tentry *tent);
391static int ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
392    ipfw_obj_tentry *tent);
393static void ta_foreach_addr_radix(void *ta_state, struct table_info *ti,
394    ta_foreach_f *f, void *arg);
395static void tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
396    struct sockaddr *ma, int *set_mask);
397static int ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
398    void *ta_buf);
399static int ta_add_addr_radix(void *ta_state, struct table_info *ti,
400    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
401static int ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
402    void *ta_buf);
403static int ta_del_addr_radix(void *ta_state, struct table_info *ti,
404    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
405static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
406    void *ta_buf);
407static int ta_need_modify_radix(void *ta_state, struct table_info *ti,
408    uint32_t count, uint64_t *pflags);
409
410static int
411ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
412    uint32_t *val)
413{
414	struct radix_node_head *rnh;
415
416	if (keylen == sizeof(in_addr_t)) {
417		struct addr_radix_entry *ent;
418		struct sockaddr_in sa;
419		KEY_LEN(sa) = KEY_LEN_INET;
420		sa.sin_addr.s_addr = *((in_addr_t *)key);
421		rnh = (struct radix_node_head *)ti->state;
422		ent = (struct addr_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
423		if (ent != NULL) {
424			*val = ent->value;
425			return (1);
426		}
427	} else if (keylen == sizeof(struct in6_addr)) {
428		struct addr_radix_xentry *xent;
429		struct sa_in6 sa6;
430		KEY_LEN(sa6) = KEY_LEN_INET6;
431		memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
432		rnh = (struct radix_node_head *)ti->xstate;
433		xent = (struct addr_radix_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
434		if (xent != NULL) {
435			*val = xent->value;
436			return (1);
437		}
438	}
439
440	return (0);
441}
442
443/*
444 * New table
445 */
446static int
447ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
448    char *data, uint8_t tflags)
449{
450	struct addr_radix_cfg *cfg;
451
452	if (!rn_inithead(&ti->state, OFF_LEN_INET))
453		return (ENOMEM);
454	if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
455		rn_detachhead(&ti->state);
456		return (ENOMEM);
457	}
458
459	cfg = malloc(sizeof(struct addr_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
460
461	*ta_state = cfg;
462	ti->lookup = ta_lookup_addr_radix;
463
464	return (0);
465}
466
467static int
468flush_radix_entry(struct radix_node *rn, void *arg)
469{
470	struct radix_node_head * const rnh = arg;
471	struct addr_radix_entry *ent;
472
473	ent = (struct addr_radix_entry *)
474	    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh);
475	if (ent != NULL)
476		free(ent, M_IPFW_TBL);
477	return (0);
478}
479
480static void
481ta_destroy_addr_radix(void *ta_state, struct table_info *ti)
482{
483	struct addr_radix_cfg *cfg;
484	struct radix_node_head *rnh;
485
486	cfg = (struct addr_radix_cfg *)ta_state;
487
488	rnh = (struct radix_node_head *)(ti->state);
489	rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
490	rn_detachhead(&ti->state);
491
492	rnh = (struct radix_node_head *)(ti->xstate);
493	rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
494	rn_detachhead(&ti->xstate);
495
496	free(cfg, M_IPFW);
497}
498
499/*
500 * Provide algo-specific table info
501 */
502static void
503ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
504{
505	struct addr_radix_cfg *cfg;
506
507	cfg = (struct addr_radix_cfg *)ta_state;
508
509	tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
510	tinfo->taclass4 = IPFW_TACLASS_RADIX;
511	tinfo->count4 = cfg->count4;
512	tinfo->itemsize4 = sizeof(struct addr_radix_entry);
513	tinfo->taclass6 = IPFW_TACLASS_RADIX;
514	tinfo->count6 = cfg->count6;
515	tinfo->itemsize6 = sizeof(struct addr_radix_xentry);
516}
517
518static int
519ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, void *e,
520    ipfw_obj_tentry *tent)
521{
522	struct addr_radix_entry *n;
523#ifdef INET6
524	struct addr_radix_xentry *xn;
525#endif
526
527	n = (struct addr_radix_entry *)e;
528
529	/* Guess IPv4/IPv6 radix by sockaddr family */
530	if (n->addr.sin_family == AF_INET) {
531		tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
532		tent->masklen = n->masklen;
533		tent->subtype = AF_INET;
534		tent->v.kidx = n->value;
535#ifdef INET6
536	} else {
537		xn = (struct addr_radix_xentry *)e;
538		memcpy(&tent->k.addr6, &xn->addr6.sin6_addr,
539		    sizeof(struct in6_addr));
540		tent->masklen = xn->masklen;
541		tent->subtype = AF_INET6;
542		tent->v.kidx = xn->value;
543#endif
544	}
545
546	return (0);
547}
548
549static int
550ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
551    ipfw_obj_tentry *tent)
552{
553	struct radix_node_head *rnh;
554	void *e;
555
556	e = NULL;
557	if (tent->subtype == AF_INET) {
558		struct sockaddr_in sa;
559		KEY_LEN(sa) = KEY_LEN_INET;
560		sa.sin_addr.s_addr = tent->k.addr.s_addr;
561		rnh = (struct radix_node_head *)ti->state;
562		e = rnh->rnh_matchaddr(&sa, &rnh->rh);
563	} else if (tent->subtype == AF_INET6) {
564		struct sa_in6 sa6;
565		KEY_LEN(sa6) = KEY_LEN_INET6;
566		memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
567		rnh = (struct radix_node_head *)ti->xstate;
568		e = rnh->rnh_matchaddr(&sa6, &rnh->rh);
569	}
570
571	if (e != NULL) {
572		ta_dump_addr_radix_tentry(ta_state, ti, e, tent);
573		return (0);
574	}
575
576	return (ENOENT);
577}
578
579static void
580ta_foreach_addr_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
581    void *arg)
582{
583	struct radix_node_head *rnh;
584
585	rnh = (struct radix_node_head *)(ti->state);
586	rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
587
588	rnh = (struct radix_node_head *)(ti->xstate);
589	rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
590}
591
592#ifdef INET6
593static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask);
594
595static inline void
596ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
597{
598	uint32_t *cp;
599
600	for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
601		*cp++ = 0xFFFFFFFF;
602	if (mask > 0)
603		*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
604}
605#endif
606
607static void
608tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
609    struct sockaddr *ma, int *set_mask)
610{
611	int mlen;
612#ifdef INET
613	struct sockaddr_in *addr, *mask;
614#endif
615#ifdef INET6
616	struct sa_in6 *addr6, *mask6;
617#endif
618	in_addr_t a4;
619
620	mlen = tei->masklen;
621
622	if (tei->subtype == AF_INET) {
623#ifdef INET
624		addr = (struct sockaddr_in *)sa;
625		mask = (struct sockaddr_in *)ma;
626		/* Set 'total' structure length */
627		KEY_LEN(*addr) = KEY_LEN_INET;
628		KEY_LEN(*mask) = KEY_LEN_INET;
629		addr->sin_family = AF_INET;
630		mask->sin_addr.s_addr =
631		    htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
632		a4 = *((in_addr_t *)tei->paddr);
633		addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
634		if (mlen != 32)
635			*set_mask = 1;
636		else
637			*set_mask = 0;
638#endif
639#ifdef INET6
640	} else if (tei->subtype == AF_INET6) {
641		/* IPv6 case */
642		addr6 = (struct sa_in6 *)sa;
643		mask6 = (struct sa_in6 *)ma;
644		/* Set 'total' structure length */
645		KEY_LEN(*addr6) = KEY_LEN_INET6;
646		KEY_LEN(*mask6) = KEY_LEN_INET6;
647		addr6->sin6_family = AF_INET6;
648		ipv6_writemask(&mask6->sin6_addr, mlen);
649		memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
650		APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
651		if (mlen != 128)
652			*set_mask = 1;
653		else
654			*set_mask = 0;
655#endif
656	}
657}
658
659static int
660ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
661    void *ta_buf)
662{
663	struct ta_buf_radix *tb;
664	struct addr_radix_entry *ent;
665#ifdef INET6
666	struct addr_radix_xentry *xent;
667#endif
668	struct sockaddr *addr, *mask;
669	int mlen, set_mask;
670
671	tb = (struct ta_buf_radix *)ta_buf;
672
673	mlen = tei->masklen;
674	set_mask = 0;
675
676	if (tei->subtype == AF_INET) {
677#ifdef INET
678		if (mlen > 32)
679			return (EINVAL);
680		ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
681		ent->masklen = mlen;
682
683		addr = (struct sockaddr *)&ent->addr;
684		mask = (struct sockaddr *)&tb->addr.a4.ma;
685		tb->ent_ptr = ent;
686#endif
687#ifdef INET6
688	} else if (tei->subtype == AF_INET6) {
689		/* IPv6 case */
690		if (mlen > 128)
691			return (EINVAL);
692		xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
693		xent->masklen = mlen;
694
695		addr = (struct sockaddr *)&xent->addr6;
696		mask = (struct sockaddr *)&tb->addr.a6.ma;
697		tb->ent_ptr = xent;
698#endif
699	} else {
700		/* Unknown CIDR type */
701		return (EINVAL);
702	}
703
704	tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
705	/* Set pointers */
706	tb->addr_ptr = addr;
707	if (set_mask != 0)
708		tb->mask_ptr = mask;
709
710	return (0);
711}
712
713static int
714ta_add_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
715    void *ta_buf, uint32_t *pnum)
716{
717	struct addr_radix_cfg *cfg;
718	struct radix_node_head *rnh;
719	struct radix_node *rn;
720	struct ta_buf_radix *tb;
721	uint32_t *old_value, value;
722
723	cfg = (struct addr_radix_cfg *)ta_state;
724	tb = (struct ta_buf_radix *)ta_buf;
725
726	/* Save current entry value from @tei */
727	if (tei->subtype == AF_INET) {
728		rnh = ti->state;
729		((struct addr_radix_entry *)tb->ent_ptr)->value = tei->value;
730	} else {
731		rnh = ti->xstate;
732		((struct addr_radix_xentry *)tb->ent_ptr)->value = tei->value;
733	}
734
735	/* Search for an entry first */
736	rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
737	if (rn != NULL) {
738		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
739			return (EEXIST);
740		/* Record already exists. Update value if we're asked to */
741		if (tei->subtype == AF_INET)
742			old_value = &((struct addr_radix_entry *)rn)->value;
743		else
744			old_value = &((struct addr_radix_xentry *)rn)->value;
745
746		value = *old_value;
747		*old_value = tei->value;
748		tei->value = value;
749
750		/* Indicate that update has happened instead of addition */
751		tei->flags |= TEI_FLAGS_UPDATED;
752		*pnum = 0;
753
754		return (0);
755	}
756
757	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
758		return (EFBIG);
759
760	rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr);
761	if (rn == NULL) {
762		/* Unknown error */
763		return (EINVAL);
764	}
765
766	if (tei->subtype == AF_INET)
767		cfg->count4++;
768	else
769		cfg->count6++;
770	tb->ent_ptr = NULL;
771	*pnum = 1;
772
773	return (0);
774}
775
776static int
777ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
778    void *ta_buf)
779{
780	struct ta_buf_radix *tb;
781	struct sockaddr *addr, *mask;
782	int mlen, set_mask;
783
784	tb = (struct ta_buf_radix *)ta_buf;
785
786	mlen = tei->masklen;
787	set_mask = 0;
788
789	if (tei->subtype == AF_INET) {
790		if (mlen > 32)
791			return (EINVAL);
792
793		addr = (struct sockaddr *)&tb->addr.a4.sa;
794		mask = (struct sockaddr *)&tb->addr.a4.ma;
795#ifdef INET6
796	} else if (tei->subtype == AF_INET6) {
797		if (mlen > 128)
798			return (EINVAL);
799
800		addr = (struct sockaddr *)&tb->addr.a6.sa;
801		mask = (struct sockaddr *)&tb->addr.a6.ma;
802#endif
803	} else
804		return (EINVAL);
805
806	tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
807	tb->addr_ptr = addr;
808	if (set_mask != 0)
809		tb->mask_ptr = mask;
810
811	return (0);
812}
813
814static int
815ta_del_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
816    void *ta_buf, uint32_t *pnum)
817{
818	struct addr_radix_cfg *cfg;
819	struct radix_node_head *rnh;
820	struct radix_node *rn;
821	struct ta_buf_radix *tb;
822
823	cfg = (struct addr_radix_cfg *)ta_state;
824	tb = (struct ta_buf_radix *)ta_buf;
825
826	if (tei->subtype == AF_INET)
827		rnh = ti->state;
828	else
829		rnh = ti->xstate;
830
831	rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
832
833	if (rn == NULL)
834		return (ENOENT);
835
836	/* Save entry value to @tei */
837	if (tei->subtype == AF_INET)
838		tei->value = ((struct addr_radix_entry *)rn)->value;
839	else
840		tei->value = ((struct addr_radix_xentry *)rn)->value;
841
842	tb->ent_ptr = rn;
843
844	if (tei->subtype == AF_INET)
845		cfg->count4--;
846	else
847		cfg->count6--;
848	*pnum = 1;
849
850	return (0);
851}
852
853static void
854ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
855    void *ta_buf)
856{
857	struct ta_buf_radix *tb;
858
859	tb = (struct ta_buf_radix *)ta_buf;
860
861	if (tb->ent_ptr != NULL)
862		free(tb->ent_ptr, M_IPFW_TBL);
863}
864
865static int
866ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count,
867    uint64_t *pflags)
868{
869
870	/*
871	 * radix does not require additional memory allocations
872	 * other than nodes itself. Adding new masks to the tree do
873	 * but we don't have any API to call (and we don't known which
874	 * sizes do we need).
875	 */
876	return (0);
877}
878
879struct table_algo addr_radix = {
880	.name		= "addr:radix",
881	.type		= IPFW_TABLE_ADDR,
882	.flags		= TA_FLAG_DEFAULT,
883	.ta_buf_size	= sizeof(struct ta_buf_radix),
884	.init		= ta_init_addr_radix,
885	.destroy	= ta_destroy_addr_radix,
886	.prepare_add	= ta_prepare_add_addr_radix,
887	.prepare_del	= ta_prepare_del_addr_radix,
888	.add		= ta_add_addr_radix,
889	.del		= ta_del_addr_radix,
890	.flush_entry	= ta_flush_radix_entry,
891	.foreach	= ta_foreach_addr_radix,
892	.dump_tentry	= ta_dump_addr_radix_tentry,
893	.find_tentry	= ta_find_addr_radix_tentry,
894	.dump_tinfo	= ta_dump_addr_radix_tinfo,
895	.need_modify	= ta_need_modify_radix,
896};
897
898/*
899 * addr:hash cmds
900 *
901 *
902 * ti->data:
903 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
904 * [        8][        8[          8][         8]
905 *
906 * inv.mask4: 32 - mask
907 * inv.mask6:
908 * 1) _slow lookup: mask
909 * 2) _aligned: (128 - mask) / 8
910 * 3) _64: 8
911 *
912 *
913 * pflags:
914 * [v4=1/v6=0][hsize]
915 * [       32][   32]
916 */
917
918struct chashentry;
919
920SLIST_HEAD(chashbhead, chashentry);
921
922struct chash_cfg {
923	struct chashbhead *head4;
924	struct chashbhead *head6;
925	size_t	size4;
926	size_t	size6;
927	size_t	items4;
928	size_t	items6;
929	uint8_t	mask4;
930	uint8_t	mask6;
931};
932
933struct chashentry {
934	SLIST_ENTRY(chashentry)	next;
935	uint32_t	value;
936	uint32_t	type;
937	union {
938		uint32_t	a4;	/* Host format */
939		struct in6_addr	a6;	/* Network format */
940	} a;
941};
942
943struct ta_buf_chash
944{
945	void *ent_ptr;
946	struct chashentry ent;
947};
948
949#ifdef INET
950static __inline uint32_t hash_ip(uint32_t addr, int hsize);
951#endif
952#ifdef INET6
953static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize);
954static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize);
955static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key,
956    int mask, int hsize);
957static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask,
958    int hsize);
959#endif
960static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
961    uint32_t *val);
962static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
963    uint32_t keylen, uint32_t *val);
964static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
965    uint32_t *val);
966static int chash_parse_opts(struct chash_cfg *cfg, char *data);
967static void ta_print_chash_config(void *ta_state, struct table_info *ti,
968    char *buf, size_t bufsize);
969static int ta_log2(uint32_t v);
970static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state,
971    struct table_info *ti, char *data, uint8_t tflags);
972static void ta_destroy_chash(void *ta_state, struct table_info *ti);
973static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti,
974    ipfw_ta_tinfo *tinfo);
975static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti,
976    void *e, ipfw_obj_tentry *tent);
977static uint32_t hash_ent(struct chashentry *ent, int af, int mlen,
978    uint32_t size);
979static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent);
980static int ta_find_chash_tentry(void *ta_state, struct table_info *ti,
981    ipfw_obj_tentry *tent);
982static void ta_foreach_chash(void *ta_state, struct table_info *ti,
983    ta_foreach_f *f, void *arg);
984static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
985    void *ta_buf);
986static int ta_add_chash(void *ta_state, struct table_info *ti,
987    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
988static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
989    void *ta_buf);
990static int ta_del_chash(void *ta_state, struct table_info *ti,
991    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
992static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
993    void *ta_buf);
994static int ta_need_modify_chash(void *ta_state, struct table_info *ti,
995    uint32_t count, uint64_t *pflags);
996static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags);
997static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
998    uint64_t *pflags);
999static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1000    uint64_t pflags);
1001static void ta_flush_mod_chash(void *ta_buf);
1002
1003#ifdef INET
1004static __inline uint32_t
1005hash_ip(uint32_t addr, int hsize)
1006{
1007
1008	return (addr % (hsize - 1));
1009}
1010#endif
1011
1012#ifdef INET6
1013static __inline uint32_t
1014hash_ip6(struct in6_addr *addr6, int hsize)
1015{
1016	uint32_t i;
1017
1018	i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
1019	    addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
1020
1021	return (i % (hsize - 1));
1022}
1023
1024static __inline uint16_t
1025hash_ip64(struct in6_addr *addr6, int hsize)
1026{
1027	uint32_t i;
1028
1029	i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
1030
1031	return (i % (hsize - 1));
1032}
1033
1034static __inline uint32_t
1035hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
1036{
1037	struct in6_addr mask6;
1038
1039	ipv6_writemask(&mask6, mask);
1040	memcpy(addr6, key, sizeof(struct in6_addr));
1041	APPLY_MASK(addr6, &mask6);
1042	return (hash_ip6(addr6, hsize));
1043}
1044
1045static __inline uint32_t
1046hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
1047{
1048	uint64_t *paddr;
1049
1050	paddr = (uint64_t *)addr6;
1051	*paddr = 0;
1052	*(paddr + 1) = 0;
1053	memcpy(addr6, key, mask);
1054	return (hash_ip6(addr6, hsize));
1055}
1056#endif
1057
1058static int
1059ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
1060    uint32_t *val)
1061{
1062	struct chashbhead *head;
1063	struct chashentry *ent;
1064	uint16_t hash, hsize;
1065	uint8_t imask;
1066
1067	if (keylen == sizeof(in_addr_t)) {
1068#ifdef INET
1069		head = (struct chashbhead *)ti->state;
1070		imask = ti->data >> 24;
1071		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1072		uint32_t a;
1073		a = ntohl(*((in_addr_t *)key));
1074		a = a >> imask;
1075		hash = hash_ip(a, hsize);
1076		SLIST_FOREACH(ent, &head[hash], next) {
1077			if (ent->a.a4 == a) {
1078				*val = ent->value;
1079				return (1);
1080			}
1081		}
1082#endif
1083	} else {
1084#ifdef INET6
1085		/* IPv6: worst scenario: non-round mask */
1086		struct in6_addr addr6;
1087		head = (struct chashbhead *)ti->xstate;
1088		imask = (ti->data & 0xFF0000) >> 16;
1089		hsize = 1 << (ti->data & 0xFF);
1090		hash = hash_ip6_slow(&addr6, key, imask, hsize);
1091		SLIST_FOREACH(ent, &head[hash], next) {
1092			if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
1093				*val = ent->value;
1094				return (1);
1095			}
1096		}
1097#endif
1098	}
1099
1100	return (0);
1101}
1102
1103static int
1104ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
1105    uint32_t *val)
1106{
1107	struct chashbhead *head;
1108	struct chashentry *ent;
1109	uint16_t hash, hsize;
1110	uint8_t imask;
1111
1112	if (keylen == sizeof(in_addr_t)) {
1113#ifdef INET
1114		head = (struct chashbhead *)ti->state;
1115		imask = ti->data >> 24;
1116		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1117		uint32_t a;
1118		a = ntohl(*((in_addr_t *)key));
1119		a = a >> imask;
1120		hash = hash_ip(a, hsize);
1121		SLIST_FOREACH(ent, &head[hash], next) {
1122			if (ent->a.a4 == a) {
1123				*val = ent->value;
1124				return (1);
1125			}
1126		}
1127#endif
1128	} else {
1129#ifdef INET6
1130		/* IPv6: aligned to 8bit mask */
1131		struct in6_addr addr6;
1132		uint64_t *paddr, *ptmp;
1133		head = (struct chashbhead *)ti->xstate;
1134		imask = (ti->data & 0xFF0000) >> 16;
1135		hsize = 1 << (ti->data & 0xFF);
1136
1137		hash = hash_ip6_al(&addr6, key, imask, hsize);
1138		paddr = (uint64_t *)&addr6;
1139		SLIST_FOREACH(ent, &head[hash], next) {
1140			ptmp = (uint64_t *)&ent->a.a6;
1141			if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
1142				*val = ent->value;
1143				return (1);
1144			}
1145		}
1146#endif
1147	}
1148
1149	return (0);
1150}
1151
1152static int
1153ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
1154    uint32_t *val)
1155{
1156	struct chashbhead *head;
1157	struct chashentry *ent;
1158	uint16_t hash, hsize;
1159	uint8_t imask;
1160
1161	if (keylen == sizeof(in_addr_t)) {
1162#ifdef INET
1163		head = (struct chashbhead *)ti->state;
1164		imask = ti->data >> 24;
1165		hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1166		uint32_t a;
1167		a = ntohl(*((in_addr_t *)key));
1168		a = a >> imask;
1169		hash = hash_ip(a, hsize);
1170		SLIST_FOREACH(ent, &head[hash], next) {
1171			if (ent->a.a4 == a) {
1172				*val = ent->value;
1173				return (1);
1174			}
1175		}
1176#endif
1177	} else {
1178#ifdef INET6
1179		/* IPv6: /64 */
1180		uint64_t a6, *paddr;
1181		head = (struct chashbhead *)ti->xstate;
1182		paddr = (uint64_t *)key;
1183		hsize = 1 << (ti->data & 0xFF);
1184		a6 = *paddr;
1185		hash = hash_ip64((struct in6_addr *)key, hsize);
1186		SLIST_FOREACH(ent, &head[hash], next) {
1187			paddr = (uint64_t *)&ent->a.a6;
1188			if (a6 == *paddr) {
1189				*val = ent->value;
1190				return (1);
1191			}
1192		}
1193#endif
1194	}
1195
1196	return (0);
1197}
1198
1199static int
1200chash_parse_opts(struct chash_cfg *cfg, char *data)
1201{
1202	char *pdel, *pend, *s;
1203	int mask4, mask6;
1204
1205	mask4 = cfg->mask4;
1206	mask6 = cfg->mask6;
1207
1208	if (data == NULL)
1209		return (0);
1210	if ((pdel = strchr(data, ' ')) == NULL)
1211		return (0);
1212	while (*pdel == ' ')
1213		pdel++;
1214	if (strncmp(pdel, "masks=", 6) != 0)
1215		return (EINVAL);
1216	if ((s = strchr(pdel, ' ')) != NULL)
1217		*s++ = '\0';
1218
1219	pdel += 6;
1220	/* Need /XX[,/YY] */
1221	if (*pdel++ != '/')
1222		return (EINVAL);
1223	mask4 = strtol(pdel, &pend, 10);
1224	if (*pend == ',') {
1225		/* ,/YY */
1226		pdel = pend + 1;
1227		if (*pdel++ != '/')
1228			return (EINVAL);
1229		mask6 = strtol(pdel, &pend, 10);
1230		if (*pend != '\0')
1231			return (EINVAL);
1232	} else if (*pend != '\0')
1233		return (EINVAL);
1234
1235	if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
1236		return (EINVAL);
1237
1238	cfg->mask4 = mask4;
1239	cfg->mask6 = mask6;
1240
1241	return (0);
1242}
1243
1244static void
1245ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
1246    size_t bufsize)
1247{
1248	struct chash_cfg *cfg;
1249
1250	cfg = (struct chash_cfg *)ta_state;
1251
1252	if (cfg->mask4 != 32 || cfg->mask6 != 128)
1253		snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash",
1254		    cfg->mask4, cfg->mask6);
1255	else
1256		snprintf(buf, bufsize, "%s", "addr:hash");
1257}
1258
1259static int
1260ta_log2(uint32_t v)
1261{
1262	uint32_t r;
1263
1264	r = 0;
1265	while (v >>= 1)
1266		r++;
1267
1268	return (r);
1269}
1270
1271/*
1272 * New table.
1273 * We assume 'data' to be either NULL or the following format:
1274 * 'addr:hash [masks=/32[,/128]]'
1275 */
1276static int
1277ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1278    char *data, uint8_t tflags)
1279{
1280	int error, i;
1281	uint32_t hsize;
1282	struct chash_cfg *cfg;
1283
1284	cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
1285
1286	cfg->mask4 = 32;
1287	cfg->mask6 = 128;
1288
1289	if ((error = chash_parse_opts(cfg, data)) != 0) {
1290		free(cfg, M_IPFW);
1291		return (error);
1292	}
1293
1294	cfg->size4 = 128;
1295	cfg->size6 = 128;
1296
1297	cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW,
1298	    M_WAITOK | M_ZERO);
1299	cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW,
1300	    M_WAITOK | M_ZERO);
1301	for (i = 0; i < cfg->size4; i++)
1302		SLIST_INIT(&cfg->head4[i]);
1303	for (i = 0; i < cfg->size6; i++)
1304		SLIST_INIT(&cfg->head6[i]);
1305
1306	*ta_state = cfg;
1307	ti->state = cfg->head4;
1308	ti->xstate = cfg->head6;
1309
1310	/* Store data depending on v6 mask length */
1311	hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1312	if (cfg->mask6 == 64) {
1313		ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16|
1314		    hsize;
1315		ti->lookup = ta_lookup_chash_64;
1316	} else if ((cfg->mask6  % 8) == 0) {
1317		ti->data = (32 - cfg->mask4) << 24 |
1318		    cfg->mask6 << 13 | hsize;
1319		ti->lookup = ta_lookup_chash_aligned;
1320	} else {
1321		/* don't do that! */
1322		ti->data = (32 - cfg->mask4) << 24 |
1323		    cfg->mask6 << 16 | hsize;
1324		ti->lookup = ta_lookup_chash_slow;
1325	}
1326
1327	return (0);
1328}
1329
1330static void
1331ta_destroy_chash(void *ta_state, struct table_info *ti)
1332{
1333	struct chash_cfg *cfg;
1334	struct chashentry *ent, *ent_next;
1335	int i;
1336
1337	cfg = (struct chash_cfg *)ta_state;
1338
1339	for (i = 0; i < cfg->size4; i++)
1340		SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1341			free(ent, M_IPFW_TBL);
1342
1343	for (i = 0; i < cfg->size6; i++)
1344		SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1345			free(ent, M_IPFW_TBL);
1346
1347	free(cfg->head4, M_IPFW);
1348	free(cfg->head6, M_IPFW);
1349
1350	free(cfg, M_IPFW);
1351}
1352
1353static void
1354ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
1355{
1356	struct chash_cfg *cfg;
1357
1358	cfg = (struct chash_cfg *)ta_state;
1359
1360	tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
1361	tinfo->taclass4 = IPFW_TACLASS_HASH;
1362	tinfo->size4 = cfg->size4;
1363	tinfo->count4 = cfg->items4;
1364	tinfo->itemsize4 = sizeof(struct chashentry);
1365	tinfo->taclass6 = IPFW_TACLASS_HASH;
1366	tinfo->size6 = cfg->size6;
1367	tinfo->count6 = cfg->items6;
1368	tinfo->itemsize6 = sizeof(struct chashentry);
1369}
1370
1371static int
1372ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
1373    ipfw_obj_tentry *tent)
1374{
1375	struct chash_cfg *cfg;
1376	struct chashentry *ent;
1377
1378	cfg = (struct chash_cfg *)ta_state;
1379	ent = (struct chashentry *)e;
1380
1381	if (ent->type == AF_INET) {
1382		tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4));
1383		tent->masklen = cfg->mask4;
1384		tent->subtype = AF_INET;
1385		tent->v.kidx = ent->value;
1386#ifdef INET6
1387	} else {
1388		memcpy(&tent->k.addr6, &ent->a.a6, sizeof(struct in6_addr));
1389		tent->masklen = cfg->mask6;
1390		tent->subtype = AF_INET6;
1391		tent->v.kidx = ent->value;
1392#endif
1393	}
1394
1395	return (0);
1396}
1397
1398static uint32_t
1399hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
1400{
1401	uint32_t hash;
1402
1403	hash = 0;
1404
1405	if (af == AF_INET) {
1406#ifdef INET
1407		hash = hash_ip(ent->a.a4, size);
1408#endif
1409	} else {
1410#ifdef INET6
1411		if (mlen == 64)
1412			hash = hash_ip64(&ent->a.a6, size);
1413		else
1414			hash = hash_ip6(&ent->a.a6, size);
1415#endif
1416	}
1417
1418	return (hash);
1419}
1420
1421static int
1422tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
1423{
1424	int mlen;
1425#ifdef INET6
1426	struct in6_addr mask6;
1427#endif
1428
1429	mlen = tei->masklen;
1430
1431	if (tei->subtype == AF_INET) {
1432#ifdef INET
1433		if (mlen > 32)
1434			return (EINVAL);
1435		ent->type = AF_INET;
1436
1437		/* Calculate masked address */
1438		ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1439#endif
1440#ifdef INET6
1441	} else if (tei->subtype == AF_INET6) {
1442		/* IPv6 case */
1443		if (mlen > 128)
1444			return (EINVAL);
1445		ent->type = AF_INET6;
1446
1447		ipv6_writemask(&mask6, mlen);
1448		memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1449		APPLY_MASK(&ent->a.a6, &mask6);
1450#endif
1451	} else {
1452		/* Unknown CIDR type */
1453		return (EINVAL);
1454	}
1455
1456	return (0);
1457}
1458
1459static int
1460ta_find_chash_tentry(void *ta_state, struct table_info *ti,
1461    ipfw_obj_tentry *tent)
1462{
1463	struct chash_cfg *cfg;
1464	struct chashbhead *head;
1465	struct chashentry ent, *tmp;
1466	struct tentry_info tei;
1467	int error;
1468	uint32_t hash;
1469
1470	cfg = (struct chash_cfg *)ta_state;
1471
1472	memset(&ent, 0, sizeof(ent));
1473	memset(&tei, 0, sizeof(tei));
1474
1475	if (tent->subtype == AF_INET) {
1476		tei.paddr = &tent->k.addr;
1477		tei.masklen = cfg->mask4;
1478		tei.subtype = AF_INET;
1479
1480		if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1481			return (error);
1482
1483		head = cfg->head4;
1484		hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
1485		/* Check for existence */
1486		SLIST_FOREACH(tmp, &head[hash], next) {
1487			if (tmp->a.a4 != ent.a.a4)
1488				continue;
1489
1490			ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1491			return (0);
1492		}
1493	} else {
1494		tei.paddr = &tent->k.addr6;
1495		tei.masklen = cfg->mask6;
1496		tei.subtype = AF_INET6;
1497
1498		if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1499			return (error);
1500
1501		head = cfg->head6;
1502		hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
1503		/* Check for existence */
1504		SLIST_FOREACH(tmp, &head[hash], next) {
1505			if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
1506				continue;
1507			ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1508			return (0);
1509		}
1510	}
1511
1512	return (ENOENT);
1513}
1514
1515static void
1516ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1517    void *arg)
1518{
1519	struct chash_cfg *cfg;
1520	struct chashentry *ent, *ent_next;
1521	int i;
1522
1523	cfg = (struct chash_cfg *)ta_state;
1524
1525	for (i = 0; i < cfg->size4; i++)
1526		SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1527			f(ent, arg);
1528
1529	for (i = 0; i < cfg->size6; i++)
1530		SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1531			f(ent, arg);
1532}
1533
1534static int
1535ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1536    void *ta_buf)
1537{
1538	struct ta_buf_chash *tb;
1539	struct chashentry *ent;
1540	int error;
1541
1542	tb = (struct ta_buf_chash *)ta_buf;
1543
1544	ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1545
1546	error = tei_to_chash_ent(tei, ent);
1547	if (error != 0) {
1548		free(ent, M_IPFW_TBL);
1549		return (error);
1550	}
1551	tb->ent_ptr = ent;
1552
1553	return (0);
1554}
1555
1556static int
1557ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1558    void *ta_buf, uint32_t *pnum)
1559{
1560	struct chash_cfg *cfg;
1561	struct chashbhead *head;
1562	struct chashentry *ent, *tmp;
1563	struct ta_buf_chash *tb;
1564	int exists;
1565	uint32_t hash, value;
1566
1567	cfg = (struct chash_cfg *)ta_state;
1568	tb = (struct ta_buf_chash *)ta_buf;
1569	ent = (struct chashentry *)tb->ent_ptr;
1570	hash = 0;
1571	exists = 0;
1572
1573	/* Read current value from @tei */
1574	ent->value = tei->value;
1575
1576	/* Read cuurrent value */
1577	if (tei->subtype == AF_INET) {
1578		if (tei->masklen != cfg->mask4)
1579			return (EINVAL);
1580		head = cfg->head4;
1581		hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1582
1583		/* Check for existence */
1584		SLIST_FOREACH(tmp, &head[hash], next) {
1585			if (tmp->a.a4 == ent->a.a4) {
1586				exists = 1;
1587				break;
1588			}
1589		}
1590	} else {
1591		if (tei->masklen != cfg->mask6)
1592			return (EINVAL);
1593		head = cfg->head6;
1594		hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1595		/* Check for existence */
1596		SLIST_FOREACH(tmp, &head[hash], next) {
1597			if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
1598				exists = 1;
1599				break;
1600			}
1601		}
1602	}
1603
1604	if (exists == 1) {
1605		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1606			return (EEXIST);
1607		/* Record already exists. Update value if we're asked to */
1608		value = tmp->value;
1609		tmp->value = tei->value;
1610		tei->value = value;
1611		/* Indicate that update has happened instead of addition */
1612		tei->flags |= TEI_FLAGS_UPDATED;
1613		*pnum = 0;
1614	} else {
1615		if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1616			return (EFBIG);
1617		SLIST_INSERT_HEAD(&head[hash], ent, next);
1618		tb->ent_ptr = NULL;
1619		*pnum = 1;
1620
1621		/* Update counters */
1622		if (tei->subtype == AF_INET)
1623			cfg->items4++;
1624		else
1625			cfg->items6++;
1626	}
1627
1628	return (0);
1629}
1630
1631static int
1632ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1633    void *ta_buf)
1634{
1635	struct ta_buf_chash *tb;
1636
1637	tb = (struct ta_buf_chash *)ta_buf;
1638
1639	return (tei_to_chash_ent(tei, &tb->ent));
1640}
1641
1642static int
1643ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1644    void *ta_buf, uint32_t *pnum)
1645{
1646	struct chash_cfg *cfg;
1647	struct chashbhead *head;
1648	struct chashentry *tmp, *tmp_next, *ent;
1649	struct ta_buf_chash *tb;
1650	uint32_t hash;
1651
1652	cfg = (struct chash_cfg *)ta_state;
1653	tb = (struct ta_buf_chash *)ta_buf;
1654	ent = &tb->ent;
1655
1656	if (tei->subtype == AF_INET) {
1657		if (tei->masklen != cfg->mask4)
1658			return (EINVAL);
1659		head = cfg->head4;
1660		hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1661
1662		SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1663			if (tmp->a.a4 != ent->a.a4)
1664				continue;
1665
1666			SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1667			cfg->items4--;
1668			tb->ent_ptr = tmp;
1669			tei->value = tmp->value;
1670			*pnum = 1;
1671			return (0);
1672		}
1673	} else {
1674		if (tei->masklen != cfg->mask6)
1675			return (EINVAL);
1676		head = cfg->head6;
1677		hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1678		SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1679			if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0)
1680				continue;
1681
1682			SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1683			cfg->items6--;
1684			tb->ent_ptr = tmp;
1685			tei->value = tmp->value;
1686			*pnum = 1;
1687			return (0);
1688		}
1689	}
1690
1691	return (ENOENT);
1692}
1693
1694static void
1695ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1696    void *ta_buf)
1697{
1698	struct ta_buf_chash *tb;
1699
1700	tb = (struct ta_buf_chash *)ta_buf;
1701
1702	if (tb->ent_ptr != NULL)
1703		free(tb->ent_ptr, M_IPFW_TBL);
1704}
1705
1706/*
1707 * Hash growing callbacks.
1708 */
1709
1710static int
1711ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count,
1712    uint64_t *pflags)
1713{
1714	struct chash_cfg *cfg;
1715	uint64_t data;
1716
1717	/*
1718	 * Since we don't know exact number of IPv4/IPv6 records in @count,
1719	 * ignore non-zero @count value at all. Check current hash sizes
1720	 * and return appropriate data.
1721	 */
1722
1723	cfg = (struct chash_cfg *)ta_state;
1724
1725	data = 0;
1726	if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
1727		data |= (cfg->size4 * 2) << 16;
1728	if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
1729		data |= cfg->size6 * 2;
1730
1731	if (data != 0) {
1732		*pflags = data;
1733		return (1);
1734	}
1735
1736	return (0);
1737}
1738
1739/*
1740 * Allocate new, larger chash.
1741 */
1742static int
1743ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
1744{
1745	struct mod_item *mi;
1746	struct chashbhead *head;
1747	int i;
1748
1749	mi = (struct mod_item *)ta_buf;
1750
1751	memset(mi, 0, sizeof(struct mod_item));
1752	mi->size = (*pflags >> 16) & 0xFFFF;
1753	mi->size6 = *pflags & 0xFFFF;
1754	if (mi->size > 0) {
1755		head = malloc(sizeof(struct chashbhead) * mi->size,
1756		    M_IPFW, M_WAITOK | M_ZERO);
1757		for (i = 0; i < mi->size; i++)
1758			SLIST_INIT(&head[i]);
1759		mi->main_ptr = head;
1760	}
1761
1762	if (mi->size6 > 0) {
1763		head = malloc(sizeof(struct chashbhead) * mi->size6,
1764		    M_IPFW, M_WAITOK | M_ZERO);
1765		for (i = 0; i < mi->size6; i++)
1766			SLIST_INIT(&head[i]);
1767		mi->main_ptr6 = head;
1768	}
1769
1770	return (0);
1771}
1772
1773/*
1774 * Copy data from old runtime array to new one.
1775 */
1776static int
1777ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1778    uint64_t *pflags)
1779{
1780
1781	/* In is not possible to do rehash if we're not holidng WLOCK. */
1782	return (0);
1783}
1784
1785/*
1786 * Switch old & new arrays.
1787 */
1788static void
1789ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1790    uint64_t pflags)
1791{
1792	struct mod_item *mi;
1793	struct chash_cfg *cfg;
1794	struct chashbhead *old_head, *new_head;
1795	struct chashentry *ent, *ent_next;
1796	int af, i, mlen;
1797	uint32_t nhash;
1798	size_t old_size, new_size;
1799
1800	mi = (struct mod_item *)ta_buf;
1801	cfg = (struct chash_cfg *)ta_state;
1802
1803	/* Check which hash we need to grow and do we still need that */
1804	if (mi->size > 0 && cfg->size4 < mi->size) {
1805		new_head = (struct chashbhead *)mi->main_ptr;
1806		new_size = mi->size;
1807		old_size = cfg->size4;
1808		old_head = ti->state;
1809		mlen = cfg->mask4;
1810		af = AF_INET;
1811
1812		for (i = 0; i < old_size; i++) {
1813			SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1814				nhash = hash_ent(ent, af, mlen, new_size);
1815				SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1816			}
1817		}
1818
1819		ti->state = new_head;
1820		cfg->head4 = new_head;
1821		cfg->size4 = mi->size;
1822		mi->main_ptr = old_head;
1823	}
1824
1825	if (mi->size6 > 0 && cfg->size6 < mi->size6) {
1826		new_head = (struct chashbhead *)mi->main_ptr6;
1827		new_size = mi->size6;
1828		old_size = cfg->size6;
1829		old_head = ti->xstate;
1830		mlen = cfg->mask6;
1831		af = AF_INET6;
1832
1833		for (i = 0; i < old_size; i++) {
1834			SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1835				nhash = hash_ent(ent, af, mlen, new_size);
1836				SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1837			}
1838		}
1839
1840		ti->xstate = new_head;
1841		cfg->head6 = new_head;
1842		cfg->size6 = mi->size6;
1843		mi->main_ptr6 = old_head;
1844	}
1845
1846	/* Update lower 32 bits with new values */
1847	ti->data &= 0xFFFFFFFF00000000;
1848	ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1849}
1850
1851/*
1852 * Free unneded array.
1853 */
1854static void
1855ta_flush_mod_chash(void *ta_buf)
1856{
1857	struct mod_item *mi;
1858
1859	mi = (struct mod_item *)ta_buf;
1860	if (mi->main_ptr != NULL)
1861		free(mi->main_ptr, M_IPFW);
1862	if (mi->main_ptr6 != NULL)
1863		free(mi->main_ptr6, M_IPFW);
1864}
1865
1866struct table_algo addr_hash = {
1867	.name		= "addr:hash",
1868	.type		= IPFW_TABLE_ADDR,
1869	.ta_buf_size	= sizeof(struct ta_buf_chash),
1870	.init		= ta_init_chash,
1871	.destroy	= ta_destroy_chash,
1872	.prepare_add	= ta_prepare_add_chash,
1873	.prepare_del	= ta_prepare_del_chash,
1874	.add		= ta_add_chash,
1875	.del		= ta_del_chash,
1876	.flush_entry	= ta_flush_chash_entry,
1877	.foreach	= ta_foreach_chash,
1878	.dump_tentry	= ta_dump_chash_tentry,
1879	.find_tentry	= ta_find_chash_tentry,
1880	.print_config	= ta_print_chash_config,
1881	.dump_tinfo	= ta_dump_chash_tinfo,
1882	.need_modify	= ta_need_modify_chash,
1883	.prepare_mod	= ta_prepare_mod_chash,
1884	.fill_mod	= ta_fill_mod_chash,
1885	.modify		= ta_modify_chash,
1886	.flush_mod	= ta_flush_mod_chash,
1887};
1888
1889/*
1890 * Iface table cmds.
1891 *
1892 * Implementation:
1893 *
1894 * Runtime part:
1895 * - sorted array of "struct ifidx" pointed by ti->state.
1896 *   Array is allocated with rounding up to IFIDX_CHUNK. Only existing
1897 *   interfaces are stored in array, however its allocated size is
1898 *   sufficient to hold all table records if needed.
1899 * - current array size is stored in ti->data
1900 *
1901 * Table data:
1902 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1903 * - All table records are stored inside namedobj instance.
1904 *
1905 */
1906
1907struct ifidx {
1908	uint16_t	kidx;
1909	uint16_t	spare;
1910	uint32_t	value;
1911};
1912#define	DEFAULT_IFIDX_SIZE	64
1913
1914struct iftable_cfg;
1915
1916struct ifentry {
1917	struct named_object	no;
1918	struct ipfw_ifc		ic;
1919	struct iftable_cfg	*icfg;
1920	uint32_t		value;
1921	int			linked;
1922};
1923
1924struct iftable_cfg {
1925	struct namedobj_instance	*ii;
1926	struct ip_fw_chain	*ch;
1927	struct table_info	*ti;
1928	void	*main_ptr;
1929	size_t	size;	/* Number of items allocated in array */
1930	size_t	count;	/* Number of all items */
1931	size_t	used;	/* Number of items _active_ now */
1932};
1933
1934struct ta_buf_ifidx
1935{
1936	struct ifentry *ife;
1937	uint32_t value;
1938};
1939
1940int compare_ifidx(const void *k, const void *v);
1941static struct ifidx * ifidx_find(struct table_info *ti, void *key);
1942static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1943    uint32_t *val);
1944static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
1945    struct table_info *ti, char *data, uint8_t tflags);
1946static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
1947static int destroy_ifidx_locked(struct namedobj_instance *ii,
1948    struct named_object *no, void *arg);
1949static void ta_destroy_ifidx(void *ta_state, struct table_info *ti);
1950static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti,
1951    ipfw_ta_tinfo *tinfo);
1952static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1953    void *ta_buf);
1954static int ta_add_ifidx(void *ta_state, struct table_info *ti,
1955    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
1956static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1957    void *ta_buf);
1958static int ta_del_ifidx(void *ta_state, struct table_info *ti,
1959    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
1960static void ta_flush_ifidx_entry(struct ip_fw_chain *ch,
1961    struct tentry_info *tei, void *ta_buf);
1962static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1963static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti,
1964    uint32_t count, uint64_t *pflags);
1965static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags);
1966static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti,
1967    void *ta_buf, uint64_t *pflags);
1968static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1969    uint64_t pflags);
1970static void ta_flush_mod_ifidx(void *ta_buf);
1971static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
1972    ipfw_obj_tentry *tent);
1973static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
1974    ipfw_obj_tentry *tent);
1975static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
1976    void *arg);
1977static void ta_foreach_ifidx(void *ta_state, struct table_info *ti,
1978    ta_foreach_f *f, void *arg);
1979
1980int
1981compare_ifidx(const void *k, const void *v)
1982{
1983	const struct ifidx *ifidx;
1984	uint16_t key;
1985
1986	key = *((const uint16_t *)k);
1987	ifidx = (const struct ifidx *)v;
1988
1989	if (key < ifidx->kidx)
1990		return (-1);
1991	else if (key > ifidx->kidx)
1992		return (1);
1993
1994	return (0);
1995}
1996
1997/*
1998 * Adds item @item with key @key into ascending-sorted array @base.
1999 * Assumes @base has enough additional storage.
2000 *
2001 * Returns 1 on success, 0 on duplicate key.
2002 */
2003static int
2004badd(const void *key, void *item, void *base, size_t nmemb,
2005    size_t size, int (*compar) (const void *, const void *))
2006{
2007	int min, max, mid, shift, res;
2008	caddr_t paddr;
2009
2010	if (nmemb == 0) {
2011		memcpy(base, item, size);
2012		return (1);
2013	}
2014
2015	/* Binary search */
2016	min = 0;
2017	max = nmemb - 1;
2018	mid = 0;
2019	while (min <= max) {
2020		mid = (min + max) / 2;
2021		res = compar(key, (const void *)((caddr_t)base + mid * size));
2022		if (res == 0)
2023			return (0);
2024
2025		if (res > 0)
2026			min = mid + 1;
2027		else
2028			max = mid - 1;
2029	}
2030
2031	/* Item not found. */
2032	res = compar(key, (const void *)((caddr_t)base + mid * size));
2033	if (res > 0)
2034		shift = mid + 1;
2035	else
2036		shift = mid;
2037
2038	paddr = (caddr_t)base + shift * size;
2039	if (nmemb > shift)
2040		memmove(paddr + size, paddr, (nmemb - shift) * size);
2041
2042	memcpy(paddr, item, size);
2043
2044	return (1);
2045}
2046
2047/*
2048 * Deletes item with key @key from ascending-sorted array @base.
2049 *
2050 * Returns 1 on success, 0 for non-existent key.
2051 */
2052static int
2053bdel(const void *key, void *base, size_t nmemb, size_t size,
2054    int (*compar) (const void *, const void *))
2055{
2056	caddr_t item;
2057	size_t sz;
2058
2059	item = (caddr_t)bsearch(key, base, nmemb, size, compar);
2060
2061	if (item == NULL)
2062		return (0);
2063
2064	sz = (caddr_t)base + nmemb * size - item;
2065
2066	if (sz > 0)
2067		memmove(item, item + size, sz);
2068
2069	return (1);
2070}
2071
2072static struct ifidx *
2073ifidx_find(struct table_info *ti, void *key)
2074{
2075	struct ifidx *ifi;
2076
2077	ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
2078	    compare_ifidx);
2079
2080	return (ifi);
2081}
2082
2083static int
2084ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
2085    uint32_t *val)
2086{
2087	struct ifidx *ifi;
2088
2089	ifi = ifidx_find(ti, key);
2090
2091	if (ifi != NULL) {
2092		*val = ifi->value;
2093		return (1);
2094	}
2095
2096	return (0);
2097}
2098
2099static int
2100ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2101    char *data, uint8_t tflags)
2102{
2103	struct iftable_cfg *icfg;
2104
2105	icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
2106
2107	icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE);
2108	icfg->size = DEFAULT_IFIDX_SIZE;
2109	icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW,
2110	    M_WAITOK | M_ZERO);
2111	icfg->ch = ch;
2112
2113	*ta_state = icfg;
2114	ti->state = icfg->main_ptr;
2115	ti->lookup = ta_lookup_ifidx;
2116
2117	return (0);
2118}
2119
2120/*
2121 * Handle tableinfo @ti pointer change (on table array resize).
2122 */
2123static void
2124ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
2125{
2126	struct iftable_cfg *icfg;
2127
2128	icfg = (struct iftable_cfg *)ta_state;
2129	icfg->ti = ti;
2130}
2131
2132static int
2133destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
2134    void *arg)
2135{
2136	struct ifentry *ife;
2137	struct ip_fw_chain *ch;
2138
2139	ch = (struct ip_fw_chain *)arg;
2140	ife = (struct ifentry *)no;
2141
2142	ipfw_iface_del_notify(ch, &ife->ic);
2143	ipfw_iface_unref(ch, &ife->ic);
2144	free(ife, M_IPFW_TBL);
2145	return (0);
2146}
2147
2148/*
2149 * Destroys table @ti
2150 */
2151static void
2152ta_destroy_ifidx(void *ta_state, struct table_info *ti)
2153{
2154	struct iftable_cfg *icfg;
2155	struct ip_fw_chain *ch;
2156
2157	icfg = (struct iftable_cfg *)ta_state;
2158	ch = icfg->ch;
2159
2160	if (icfg->main_ptr != NULL)
2161		free(icfg->main_ptr, M_IPFW);
2162
2163	IPFW_UH_WLOCK(ch);
2164	ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
2165	IPFW_UH_WUNLOCK(ch);
2166
2167	ipfw_objhash_destroy(icfg->ii);
2168
2169	free(icfg, M_IPFW);
2170}
2171
2172/*
2173 * Provide algo-specific table info
2174 */
2175static void
2176ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2177{
2178	struct iftable_cfg *cfg;
2179
2180	cfg = (struct iftable_cfg *)ta_state;
2181
2182	tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2183	tinfo->size4 = cfg->size;
2184	tinfo->count4 = cfg->used;
2185	tinfo->itemsize4 = sizeof(struct ifidx);
2186}
2187
2188/*
2189 * Prepare state to add to the table:
2190 * allocate ifentry and reference needed interface.
2191 */
2192static int
2193ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
2194    void *ta_buf)
2195{
2196	struct ta_buf_ifidx *tb;
2197	char *ifname;
2198	struct ifentry *ife;
2199
2200	tb = (struct ta_buf_ifidx *)ta_buf;
2201
2202	/* Check if string is terminated */
2203	ifname = (char *)tei->paddr;
2204	if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2205		return (EINVAL);
2206
2207	ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
2208	ife->ic.cb = if_notifier;
2209	ife->ic.cbdata = ife;
2210
2211	if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) {
2212		free(ife, M_IPFW_TBL);
2213		return (EINVAL);
2214	}
2215
2216	/* Use ipfw_iface 'ifname' field as stable storage */
2217	ife->no.name = ife->ic.iface->ifname;
2218
2219	tb->ife = ife;
2220
2221	return (0);
2222}
2223
2224static int
2225ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2226    void *ta_buf, uint32_t *pnum)
2227{
2228	struct iftable_cfg *icfg;
2229	struct ifentry *ife, *tmp;
2230	struct ta_buf_ifidx *tb;
2231	struct ipfw_iface *iif;
2232	struct ifidx *ifi;
2233	char *ifname;
2234	uint32_t value;
2235
2236	tb = (struct ta_buf_ifidx *)ta_buf;
2237	ifname = (char *)tei->paddr;
2238	icfg = (struct iftable_cfg *)ta_state;
2239	ife = tb->ife;
2240
2241	ife->icfg = icfg;
2242	ife->value = tei->value;
2243
2244	tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2245
2246	if (tmp != NULL) {
2247		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2248			return (EEXIST);
2249
2250		/* Exchange values in @tmp and @tei */
2251		value = tmp->value;
2252		tmp->value = tei->value;
2253		tei->value = value;
2254
2255		iif = tmp->ic.iface;
2256		if (iif->resolved != 0) {
2257			/* We have to update runtime value, too */
2258			ifi = ifidx_find(ti, &iif->ifindex);
2259			ifi->value = ife->value;
2260		}
2261
2262		/* Indicate that update has happened instead of addition */
2263		tei->flags |= TEI_FLAGS_UPDATED;
2264		*pnum = 0;
2265		return (0);
2266	}
2267
2268	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2269		return (EFBIG);
2270
2271	/* Link to internal list */
2272	ipfw_objhash_add(icfg->ii, &ife->no);
2273
2274	/* Link notifier (possible running its callback) */
2275	ipfw_iface_add_notify(icfg->ch, &ife->ic);
2276	icfg->count++;
2277
2278	tb->ife = NULL;
2279	*pnum = 1;
2280
2281	return (0);
2282}
2283
2284/*
2285 * Prepare to delete key from table.
2286 * Do basic interface name checks.
2287 */
2288static int
2289ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
2290    void *ta_buf)
2291{
2292	char *ifname;
2293
2294	/* Check if string is terminated */
2295	ifname = (char *)tei->paddr;
2296	if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2297		return (EINVAL);
2298
2299	return (0);
2300}
2301
2302/*
2303 * Remove key from both configuration list and
2304 * runtime array. Removed interface notification.
2305 */
2306static int
2307ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2308    void *ta_buf, uint32_t *pnum)
2309{
2310	struct iftable_cfg *icfg;
2311	struct ifentry *ife;
2312	struct ta_buf_ifidx *tb;
2313	char *ifname;
2314	uint16_t ifindex;
2315	int res __diagused;
2316
2317	tb = (struct ta_buf_ifidx *)ta_buf;
2318	ifname = (char *)tei->paddr;
2319	icfg = (struct iftable_cfg *)ta_state;
2320
2321	ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2322
2323	if (ife == NULL)
2324		return (ENOENT);
2325
2326	if (ife->linked != 0) {
2327		/* We have to remove item from runtime */
2328		ifindex = ife->ic.iface->ifindex;
2329
2330		res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2331		    sizeof(struct ifidx), compare_ifidx);
2332
2333		KASSERT(res == 1, ("index %d does not exist", ifindex));
2334		icfg->used--;
2335		ti->data = icfg->used;
2336		ife->linked = 0;
2337	}
2338
2339	/* Unlink from local list */
2340	ipfw_objhash_del(icfg->ii, &ife->no);
2341	/* Unlink notifier and deref */
2342	ipfw_iface_del_notify(icfg->ch, &ife->ic);
2343	ipfw_iface_unref(icfg->ch, &ife->ic);
2344
2345	icfg->count--;
2346	tei->value = ife->value;
2347
2348	tb->ife = ife;
2349	*pnum = 1;
2350
2351	return (0);
2352}
2353
2354/*
2355 * Flush deleted entry.
2356 * Drops interface reference and frees entry.
2357 */
2358static void
2359ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2360    void *ta_buf)
2361{
2362	struct ta_buf_ifidx *tb;
2363
2364	tb = (struct ta_buf_ifidx *)ta_buf;
2365
2366	if (tb->ife != NULL)
2367		free(tb->ife, M_IPFW_TBL);
2368}
2369
2370/*
2371 * Handle interface announce/withdrawal for particular table.
2372 * Every real runtime array modification happens here.
2373 */
2374static void
2375if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
2376{
2377	struct ifentry *ife;
2378	struct ifidx ifi;
2379	struct iftable_cfg *icfg;
2380	struct table_info *ti;
2381	int res __diagused;
2382
2383	ife = (struct ifentry *)cbdata;
2384	icfg = ife->icfg;
2385	ti = icfg->ti;
2386
2387	KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
2388
2389	if (ife->linked == 0 && ifindex != 0) {
2390		/* Interface announce */
2391		ifi.kidx = ifindex;
2392		ifi.spare = 0;
2393		ifi.value = ife->value;
2394		res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
2395		    sizeof(struct ifidx), compare_ifidx);
2396		KASSERT(res == 1, ("index %d already exists", ifindex));
2397		icfg->used++;
2398		ti->data = icfg->used;
2399		ife->linked = 1;
2400	} else if (ife->linked != 0 && ifindex == 0) {
2401		/* Interface withdrawal */
2402		ifindex = ife->ic.iface->ifindex;
2403
2404		res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2405		    sizeof(struct ifidx), compare_ifidx);
2406
2407		KASSERT(res == 1, ("index %d does not exist", ifindex));
2408		icfg->used--;
2409		ti->data = icfg->used;
2410		ife->linked = 0;
2411	}
2412}
2413
2414/*
2415 * Table growing callbacks.
2416 */
2417
2418static int
2419ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
2420    uint64_t *pflags)
2421{
2422	struct iftable_cfg *cfg;
2423	uint32_t size;
2424
2425	cfg = (struct iftable_cfg *)ta_state;
2426
2427	size = cfg->size;
2428	while (size < cfg->count + count)
2429		size *= 2;
2430
2431	if (size != cfg->size) {
2432		*pflags = size;
2433		return (1);
2434	}
2435
2436	return (0);
2437}
2438
2439/*
2440 * Allocate ned, larger runtime ifidx array.
2441 */
2442static int
2443ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
2444{
2445	struct mod_item *mi;
2446
2447	mi = (struct mod_item *)ta_buf;
2448
2449	memset(mi, 0, sizeof(struct mod_item));
2450	mi->size = *pflags;
2451	mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
2452	    M_WAITOK | M_ZERO);
2453
2454	return (0);
2455}
2456
2457/*
2458 * Copy data from old runtime array to new one.
2459 */
2460static int
2461ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2462    uint64_t *pflags)
2463{
2464	struct mod_item *mi;
2465	struct iftable_cfg *icfg;
2466
2467	mi = (struct mod_item *)ta_buf;
2468	icfg = (struct iftable_cfg *)ta_state;
2469
2470	/* Check if we still need to grow array */
2471	if (icfg->size >= mi->size) {
2472		*pflags = 0;
2473		return (0);
2474	}
2475
2476	memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
2477
2478	return (0);
2479}
2480
2481/*
2482 * Switch old & new arrays.
2483 */
2484static void
2485ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2486    uint64_t pflags)
2487{
2488	struct mod_item *mi;
2489	struct iftable_cfg *icfg;
2490	void *old_ptr;
2491
2492	mi = (struct mod_item *)ta_buf;
2493	icfg = (struct iftable_cfg *)ta_state;
2494
2495	old_ptr = icfg->main_ptr;
2496	icfg->main_ptr = mi->main_ptr;
2497	icfg->size = mi->size;
2498	ti->state = icfg->main_ptr;
2499
2500	mi->main_ptr = old_ptr;
2501}
2502
2503/*
2504 * Free unneded array.
2505 */
2506static void
2507ta_flush_mod_ifidx(void *ta_buf)
2508{
2509	struct mod_item *mi;
2510
2511	mi = (struct mod_item *)ta_buf;
2512	if (mi->main_ptr != NULL)
2513		free(mi->main_ptr, M_IPFW);
2514}
2515
2516static int
2517ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
2518    ipfw_obj_tentry *tent)
2519{
2520	struct ifentry *ife;
2521
2522	ife = (struct ifentry *)e;
2523
2524	tent->masklen = 8 * IF_NAMESIZE;
2525	memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
2526	tent->v.kidx = ife->value;
2527
2528	return (0);
2529}
2530
2531static int
2532ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
2533    ipfw_obj_tentry *tent)
2534{
2535	struct iftable_cfg *icfg;
2536	struct ifentry *ife;
2537	char *ifname;
2538
2539	icfg = (struct iftable_cfg *)ta_state;
2540	ifname = tent->k.iface;
2541
2542	if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2543		return (EINVAL);
2544
2545	ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2546
2547	if (ife != NULL) {
2548		ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
2549		return (0);
2550	}
2551
2552	return (ENOENT);
2553}
2554
2555struct wa_ifidx {
2556	ta_foreach_f	*f;
2557	void		*arg;
2558};
2559
2560static int
2561foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
2562    void *arg)
2563{
2564	struct ifentry *ife;
2565	struct wa_ifidx *wa;
2566
2567	ife = (struct ifentry *)no;
2568	wa = (struct wa_ifidx *)arg;
2569
2570	wa->f(ife, wa->arg);
2571	return (0);
2572}
2573
2574static void
2575ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2576    void *arg)
2577{
2578	struct iftable_cfg *icfg;
2579	struct wa_ifidx wa;
2580
2581	icfg = (struct iftable_cfg *)ta_state;
2582
2583	wa.f = f;
2584	wa.arg = arg;
2585
2586	ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
2587}
2588
2589struct table_algo iface_idx = {
2590	.name		= "iface:array",
2591	.type		= IPFW_TABLE_INTERFACE,
2592	.flags		= TA_FLAG_DEFAULT,
2593	.ta_buf_size	= sizeof(struct ta_buf_ifidx),
2594	.init		= ta_init_ifidx,
2595	.destroy	= ta_destroy_ifidx,
2596	.prepare_add	= ta_prepare_add_ifidx,
2597	.prepare_del	= ta_prepare_del_ifidx,
2598	.add		= ta_add_ifidx,
2599	.del		= ta_del_ifidx,
2600	.flush_entry	= ta_flush_ifidx_entry,
2601	.foreach	= ta_foreach_ifidx,
2602	.dump_tentry	= ta_dump_ifidx_tentry,
2603	.find_tentry	= ta_find_ifidx_tentry,
2604	.dump_tinfo	= ta_dump_ifidx_tinfo,
2605	.need_modify	= ta_need_modify_ifidx,
2606	.prepare_mod	= ta_prepare_mod_ifidx,
2607	.fill_mod	= ta_fill_mod_ifidx,
2608	.modify		= ta_modify_ifidx,
2609	.flush_mod	= ta_flush_mod_ifidx,
2610	.change_ti	= ta_change_ti_ifidx,
2611};
2612
2613/*
2614 * Number array cmds.
2615 *
2616 * Implementation:
2617 *
2618 * Runtime part:
2619 * - sorted array of "struct numarray" pointed by ti->state.
2620 *   Array is allocated with rounding up to NUMARRAY_CHUNK.
2621 * - current array size is stored in ti->data
2622 *
2623 */
2624
2625struct numarray {
2626	uint32_t	number;
2627	uint32_t	value;
2628};
2629
2630struct numarray_cfg {
2631	void	*main_ptr;
2632	size_t	size;	/* Number of items allocated in array */
2633	size_t	used;	/* Number of items _active_ now */
2634};
2635
2636struct ta_buf_numarray
2637{
2638	struct numarray na;
2639};
2640
2641int compare_numarray(const void *k, const void *v);
2642static struct numarray *numarray_find(struct table_info *ti, void *key);
2643static int ta_lookup_numarray(struct table_info *ti, void *key,
2644    uint32_t keylen, uint32_t *val);
2645static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
2646    struct table_info *ti, char *data, uint8_t tflags);
2647static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
2648static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti,
2649    ipfw_ta_tinfo *tinfo);
2650static int ta_prepare_add_numarray(struct ip_fw_chain *ch,
2651    struct tentry_info *tei, void *ta_buf);
2652static int ta_add_numarray(void *ta_state, struct table_info *ti,
2653    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
2654static int ta_del_numarray(void *ta_state, struct table_info *ti,
2655    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
2656static void ta_flush_numarray_entry(struct ip_fw_chain *ch,
2657    struct tentry_info *tei, void *ta_buf);
2658static int ta_need_modify_numarray(void *ta_state, struct table_info *ti,
2659    uint32_t count, uint64_t *pflags);
2660static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags);
2661static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti,
2662    void *ta_buf, uint64_t *pflags);
2663static void ta_modify_numarray(void *ta_state, struct table_info *ti,
2664    void *ta_buf, uint64_t pflags);
2665static void ta_flush_mod_numarray(void *ta_buf);
2666static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti,
2667    void *e, ipfw_obj_tentry *tent);
2668static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2669    ipfw_obj_tentry *tent);
2670static void ta_foreach_numarray(void *ta_state, struct table_info *ti,
2671    ta_foreach_f *f, void *arg);
2672
2673int
2674compare_numarray(const void *k, const void *v)
2675{
2676	const struct numarray *na;
2677	uint32_t key;
2678
2679	key = *((const uint32_t *)k);
2680	na = (const struct numarray *)v;
2681
2682	if (key < na->number)
2683		return (-1);
2684	else if (key > na->number)
2685		return (1);
2686
2687	return (0);
2688}
2689
2690static struct numarray *
2691numarray_find(struct table_info *ti, void *key)
2692{
2693	struct numarray *ri;
2694
2695	ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
2696	    compare_numarray);
2697
2698	return (ri);
2699}
2700
2701static int
2702ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
2703    uint32_t *val)
2704{
2705	struct numarray *ri;
2706
2707	ri = numarray_find(ti, key);
2708
2709	if (ri != NULL) {
2710		*val = ri->value;
2711		return (1);
2712	}
2713
2714	return (0);
2715}
2716
2717static int
2718ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2719    char *data, uint8_t tflags)
2720{
2721	struct numarray_cfg *cfg;
2722
2723	cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
2724
2725	cfg->size = 16;
2726	cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
2727	    M_WAITOK | M_ZERO);
2728
2729	*ta_state = cfg;
2730	ti->state = cfg->main_ptr;
2731	ti->lookup = ta_lookup_numarray;
2732
2733	return (0);
2734}
2735
2736/*
2737 * Destroys table @ti
2738 */
2739static void
2740ta_destroy_numarray(void *ta_state, struct table_info *ti)
2741{
2742	struct numarray_cfg *cfg;
2743
2744	cfg = (struct numarray_cfg *)ta_state;
2745
2746	if (cfg->main_ptr != NULL)
2747		free(cfg->main_ptr, M_IPFW);
2748
2749	free(cfg, M_IPFW);
2750}
2751
2752/*
2753 * Provide algo-specific table info
2754 */
2755static void
2756ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2757{
2758	struct numarray_cfg *cfg;
2759
2760	cfg = (struct numarray_cfg *)ta_state;
2761
2762	tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2763	tinfo->size4 = cfg->size;
2764	tinfo->count4 = cfg->used;
2765	tinfo->itemsize4 = sizeof(struct numarray);
2766}
2767
2768/*
2769 * Prepare for addition/deletion to an array.
2770 */
2771static int
2772ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
2773    void *ta_buf)
2774{
2775	struct ta_buf_numarray *tb;
2776
2777	tb = (struct ta_buf_numarray *)ta_buf;
2778
2779	tb->na.number = *((uint32_t *)tei->paddr);
2780
2781	return (0);
2782}
2783
2784static int
2785ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2786    void *ta_buf, uint32_t *pnum)
2787{
2788	struct numarray_cfg *cfg;
2789	struct ta_buf_numarray *tb;
2790	struct numarray *ri;
2791	int res __diagused;
2792	uint32_t value;
2793
2794	tb = (struct ta_buf_numarray *)ta_buf;
2795	cfg = (struct numarray_cfg *)ta_state;
2796
2797	/* Read current value from @tei */
2798	tb->na.value = tei->value;
2799
2800	ri = numarray_find(ti, &tb->na.number);
2801
2802	if (ri != NULL) {
2803		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2804			return (EEXIST);
2805
2806		/* Exchange values between ri and @tei */
2807		value = ri->value;
2808		ri->value = tei->value;
2809		tei->value = value;
2810		/* Indicate that update has happened instead of addition */
2811		tei->flags |= TEI_FLAGS_UPDATED;
2812		*pnum = 0;
2813		return (0);
2814	}
2815
2816	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2817		return (EFBIG);
2818
2819	res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
2820	    sizeof(struct numarray), compare_numarray);
2821
2822	KASSERT(res == 1, ("number %d already exists", tb->na.number));
2823	cfg->used++;
2824	ti->data = cfg->used;
2825	*pnum = 1;
2826
2827	return (0);
2828}
2829
2830/*
2831 * Remove key from both configuration list and
2832 * runtime array. Removed interface notification.
2833 */
2834static int
2835ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2836    void *ta_buf, uint32_t *pnum)
2837{
2838	struct numarray_cfg *cfg;
2839	struct ta_buf_numarray *tb;
2840	struct numarray *ri;
2841	int res __diagused;
2842
2843	tb = (struct ta_buf_numarray *)ta_buf;
2844	cfg = (struct numarray_cfg *)ta_state;
2845
2846	ri = numarray_find(ti, &tb->na.number);
2847	if (ri == NULL)
2848		return (ENOENT);
2849
2850	tei->value = ri->value;
2851
2852	res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
2853	    sizeof(struct numarray), compare_numarray);
2854
2855	KASSERT(res == 1, ("number %u does not exist", tb->na.number));
2856	cfg->used--;
2857	ti->data = cfg->used;
2858	*pnum = 1;
2859
2860	return (0);
2861}
2862
2863static void
2864ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2865    void *ta_buf)
2866{
2867
2868	/* We don't have any state, do nothing */
2869}
2870
2871/*
2872 * Table growing callbacks.
2873 */
2874
2875static int
2876ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count,
2877    uint64_t *pflags)
2878{
2879	struct numarray_cfg *cfg;
2880	size_t size;
2881
2882	cfg = (struct numarray_cfg *)ta_state;
2883
2884	size = cfg->size;
2885	while (size < cfg->used + count)
2886		size *= 2;
2887
2888	if (size != cfg->size) {
2889		*pflags = size;
2890		return (1);
2891	}
2892
2893	return (0);
2894}
2895
2896/*
2897 * Allocate new, larger runtime array.
2898 */
2899static int
2900ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
2901{
2902	struct mod_item *mi;
2903
2904	mi = (struct mod_item *)ta_buf;
2905
2906	memset(mi, 0, sizeof(struct mod_item));
2907	mi->size = *pflags;
2908	mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
2909	    M_WAITOK | M_ZERO);
2910
2911	return (0);
2912}
2913
2914/*
2915 * Copy data from old runtime array to new one.
2916 */
2917static int
2918ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2919    uint64_t *pflags)
2920{
2921	struct mod_item *mi;
2922	struct numarray_cfg *cfg;
2923
2924	mi = (struct mod_item *)ta_buf;
2925	cfg = (struct numarray_cfg *)ta_state;
2926
2927	/* Check if we still need to grow array */
2928	if (cfg->size >= mi->size) {
2929		*pflags = 0;
2930		return (0);
2931	}
2932
2933	memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
2934
2935	return (0);
2936}
2937
2938/*
2939 * Switch old & new arrays.
2940 */
2941static void
2942ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2943    uint64_t pflags)
2944{
2945	struct mod_item *mi;
2946	struct numarray_cfg *cfg;
2947	void *old_ptr;
2948
2949	mi = (struct mod_item *)ta_buf;
2950	cfg = (struct numarray_cfg *)ta_state;
2951
2952	old_ptr = cfg->main_ptr;
2953	cfg->main_ptr = mi->main_ptr;
2954	cfg->size = mi->size;
2955	ti->state = cfg->main_ptr;
2956
2957	mi->main_ptr = old_ptr;
2958}
2959
2960/*
2961 * Free unneded array.
2962 */
2963static void
2964ta_flush_mod_numarray(void *ta_buf)
2965{
2966	struct mod_item *mi;
2967
2968	mi = (struct mod_item *)ta_buf;
2969	if (mi->main_ptr != NULL)
2970		free(mi->main_ptr, M_IPFW);
2971}
2972
2973static int
2974ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
2975    ipfw_obj_tentry *tent)
2976{
2977	struct numarray *na;
2978
2979	na = (struct numarray *)e;
2980
2981	tent->k.key = na->number;
2982	tent->v.kidx = na->value;
2983
2984	return (0);
2985}
2986
2987static int
2988ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2989    ipfw_obj_tentry *tent)
2990{
2991	struct numarray *ri;
2992
2993	ri = numarray_find(ti, &tent->k.key);
2994
2995	if (ri != NULL) {
2996		ta_dump_numarray_tentry(ta_state, ti, ri, tent);
2997		return (0);
2998	}
2999
3000	return (ENOENT);
3001}
3002
3003static void
3004ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3005    void *arg)
3006{
3007	struct numarray_cfg *cfg;
3008	struct numarray *array;
3009	int i;
3010
3011	cfg = (struct numarray_cfg *)ta_state;
3012	array = cfg->main_ptr;
3013
3014	for (i = 0; i < cfg->used; i++)
3015		f(&array[i], arg);
3016}
3017
3018struct table_algo number_array = {
3019	.name		= "number:array",
3020	.type		= IPFW_TABLE_NUMBER,
3021	.ta_buf_size	= sizeof(struct ta_buf_numarray),
3022	.init		= ta_init_numarray,
3023	.destroy	= ta_destroy_numarray,
3024	.prepare_add	= ta_prepare_add_numarray,
3025	.prepare_del	= ta_prepare_add_numarray,
3026	.add		= ta_add_numarray,
3027	.del		= ta_del_numarray,
3028	.flush_entry	= ta_flush_numarray_entry,
3029	.foreach	= ta_foreach_numarray,
3030	.dump_tentry	= ta_dump_numarray_tentry,
3031	.find_tentry	= ta_find_numarray_tentry,
3032	.dump_tinfo	= ta_dump_numarray_tinfo,
3033	.need_modify	= ta_need_modify_numarray,
3034	.prepare_mod	= ta_prepare_mod_numarray,
3035	.fill_mod	= ta_fill_mod_numarray,
3036	.modify		= ta_modify_numarray,
3037	.flush_mod	= ta_flush_mod_numarray,
3038};
3039
3040/*
3041 * flow:hash cmds
3042 *
3043 *
3044 * ti->data:
3045 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
3046 * [        8][        8[          8][         8]
3047 *
3048 * inv.mask4: 32 - mask
3049 * inv.mask6:
3050 * 1) _slow lookup: mask
3051 * 2) _aligned: (128 - mask) / 8
3052 * 3) _64: 8
3053 *
3054 *
3055 * pflags:
3056 * [hsize4][hsize6]
3057 * [    16][    16]
3058 */
3059
3060struct fhashentry;
3061
3062SLIST_HEAD(fhashbhead, fhashentry);
3063
3064struct fhashentry {
3065	SLIST_ENTRY(fhashentry)	next;
3066	uint8_t		af;
3067	uint8_t		proto;
3068	uint16_t	spare0;
3069	uint16_t	dport;
3070	uint16_t	sport;
3071	uint32_t	value;
3072	uint32_t	spare1;
3073};
3074
3075struct fhashentry4 {
3076	struct fhashentry	e;
3077	struct in_addr		dip;
3078	struct in_addr		sip;
3079};
3080
3081struct fhashentry6 {
3082	struct fhashentry	e;
3083	struct in6_addr		dip6;
3084	struct in6_addr		sip6;
3085};
3086
3087struct fhash_cfg {
3088	struct fhashbhead	*head;
3089	size_t			size;
3090	size_t			items;
3091	struct fhashentry4	fe4;
3092	struct fhashentry6	fe6;
3093};
3094
3095struct ta_buf_fhash {
3096	void	*ent_ptr;
3097	struct fhashentry6 fe6;
3098};
3099
3100static __inline int cmp_flow_ent(struct fhashentry *a,
3101    struct fhashentry *b, size_t sz);
3102static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
3103static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
3104static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
3105static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3106    uint32_t *val);
3107static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
3108struct table_info *ti, char *data, uint8_t tflags);
3109static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
3110static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti,
3111    ipfw_ta_tinfo *tinfo);
3112static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti,
3113    void *e, ipfw_obj_tentry *tent);
3114static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent);
3115static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3116    ipfw_obj_tentry *tent);
3117static void ta_foreach_fhash(void *ta_state, struct table_info *ti,
3118    ta_foreach_f *f, void *arg);
3119static int ta_prepare_add_fhash(struct ip_fw_chain *ch,
3120    struct tentry_info *tei, void *ta_buf);
3121static int ta_add_fhash(void *ta_state, struct table_info *ti,
3122    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
3123static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3124    void *ta_buf);
3125static int ta_del_fhash(void *ta_state, struct table_info *ti,
3126    struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
3127static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3128    void *ta_buf);
3129static int ta_need_modify_fhash(void *ta_state, struct table_info *ti,
3130    uint32_t count, uint64_t *pflags);
3131static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags);
3132static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti,
3133    void *ta_buf, uint64_t *pflags);
3134static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3135    uint64_t pflags);
3136static void ta_flush_mod_fhash(void *ta_buf);
3137
3138static __inline int
3139cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
3140{
3141	uint64_t *ka, *kb;
3142
3143	ka = (uint64_t *)(&a->next + 1);
3144	kb = (uint64_t *)(&b->next + 1);
3145
3146	if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
3147		return (1);
3148
3149	return (0);
3150}
3151
3152static __inline uint32_t
3153hash_flow4(struct fhashentry4 *f, int hsize)
3154{
3155	uint32_t i;
3156
3157	i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
3158
3159	return (i % (hsize - 1));
3160}
3161
3162static __inline uint32_t
3163hash_flow6(struct fhashentry6 *f, int hsize)
3164{
3165	uint32_t i;
3166
3167	i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
3168	    (f->dip6.__u6_addr.__u6_addr32[3]) ^
3169	    (f->sip6.__u6_addr.__u6_addr32[2]) ^
3170	    (f->sip6.__u6_addr.__u6_addr32[3]) ^
3171	    (f->e.dport) ^ (f->e.sport);
3172
3173	return (i % (hsize - 1));
3174}
3175
3176static uint32_t
3177hash_flow_ent(struct fhashentry *ent, uint32_t size)
3178{
3179	uint32_t hash;
3180
3181	if (ent->af == AF_INET) {
3182		hash = hash_flow4((struct fhashentry4 *)ent, size);
3183	} else {
3184		hash = hash_flow6((struct fhashentry6 *)ent, size);
3185	}
3186
3187	return (hash);
3188}
3189
3190static int
3191ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3192    uint32_t *val)
3193{
3194	struct fhashbhead *head;
3195	struct fhashentry *ent;
3196	struct fhashentry4 *m4;
3197	struct ipfw_flow_id *id;
3198	uint32_t hsize;
3199	uint16_t hash;
3200
3201	id = (struct ipfw_flow_id *)key;
3202	head = (struct fhashbhead *)ti->state;
3203	hsize = ti->data;
3204	m4 = (struct fhashentry4 *)ti->xstate;
3205
3206	if (id->addr_type == 4) {
3207		struct fhashentry4 f;
3208
3209		/* Copy hash mask */
3210		f = *m4;
3211
3212		f.dip.s_addr &= id->dst_ip;
3213		f.sip.s_addr &= id->src_ip;
3214		f.e.dport &= id->dst_port;
3215		f.e.sport &= id->src_port;
3216		f.e.proto &= id->proto;
3217		hash = hash_flow4(&f, hsize);
3218		SLIST_FOREACH(ent, &head[hash], next) {
3219			if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
3220				*val = ent->value;
3221				return (1);
3222			}
3223		}
3224	} else if (id->addr_type == 6) {
3225		struct fhashentry6 f;
3226		uint64_t *fp, *idp;
3227
3228		/* Copy hash mask */
3229		f = *((struct fhashentry6 *)(m4 + 1));
3230
3231		/* Handle lack of __u6_addr.__u6_addr64 */
3232		fp = (uint64_t *)&f.dip6;
3233		idp = (uint64_t *)&id->dst_ip6;
3234		/* src IPv6 is stored after dst IPv6 */
3235		*fp++ &= *idp++;
3236		*fp++ &= *idp++;
3237		*fp++ &= *idp++;
3238		*fp &= *idp;
3239		f.e.dport &= id->dst_port;
3240		f.e.sport &= id->src_port;
3241		f.e.proto &= id->proto;
3242		hash = hash_flow6(&f, hsize);
3243		SLIST_FOREACH(ent, &head[hash], next) {
3244			if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
3245				*val = ent->value;
3246				return (1);
3247			}
3248		}
3249	}
3250
3251	return (0);
3252}
3253
3254/*
3255 * New table.
3256 */
3257static int
3258ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3259    char *data, uint8_t tflags)
3260{
3261	struct fhash_cfg *cfg;
3262	struct fhashentry4 *fe4;
3263	struct fhashentry6 *fe6;
3264	u_int i;
3265
3266	cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
3267
3268	cfg->size = 512;
3269
3270	cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
3271	    M_WAITOK | M_ZERO);
3272	for (i = 0; i < cfg->size; i++)
3273		SLIST_INIT(&cfg->head[i]);
3274
3275	/* Fill in fe masks based on @tflags */
3276	fe4 = &cfg->fe4;
3277	fe6 = &cfg->fe6;
3278	if (tflags & IPFW_TFFLAG_SRCIP) {
3279		memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
3280		memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
3281	}
3282	if (tflags & IPFW_TFFLAG_DSTIP) {
3283		memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
3284		memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
3285	}
3286	if (tflags & IPFW_TFFLAG_SRCPORT) {
3287		memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
3288		memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
3289	}
3290	if (tflags & IPFW_TFFLAG_DSTPORT) {
3291		memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
3292		memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
3293	}
3294	if (tflags & IPFW_TFFLAG_PROTO) {
3295		memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
3296		memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
3297	}
3298
3299	fe4->e.af = AF_INET;
3300	fe6->e.af = AF_INET6;
3301
3302	*ta_state = cfg;
3303	ti->state = cfg->head;
3304	ti->xstate = &cfg->fe4;
3305	ti->data = cfg->size;
3306	ti->lookup = ta_lookup_fhash;
3307
3308	return (0);
3309}
3310
3311static void
3312ta_destroy_fhash(void *ta_state, struct table_info *ti)
3313{
3314	struct fhash_cfg *cfg;
3315	struct fhashentry *ent, *ent_next;
3316	int i;
3317
3318	cfg = (struct fhash_cfg *)ta_state;
3319
3320	for (i = 0; i < cfg->size; i++)
3321		SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3322			free(ent, M_IPFW_TBL);
3323
3324	free(cfg->head, M_IPFW);
3325	free(cfg, M_IPFW);
3326}
3327
3328/*
3329 * Provide algo-specific table info
3330 */
3331static void
3332ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3333{
3334	struct fhash_cfg *cfg;
3335
3336	cfg = (struct fhash_cfg *)ta_state;
3337
3338	tinfo->flags = IPFW_TATFLAGS_AFITEM;
3339	tinfo->taclass4 = IPFW_TACLASS_HASH;
3340	tinfo->size4 = cfg->size;
3341	tinfo->count4 = cfg->items;
3342	tinfo->itemsize4 = sizeof(struct fhashentry4);
3343	tinfo->itemsize6 = sizeof(struct fhashentry6);
3344}
3345
3346static int
3347ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
3348    ipfw_obj_tentry *tent)
3349{
3350	struct fhashentry *ent;
3351	struct fhashentry4 *fe4;
3352#ifdef INET6
3353	struct fhashentry6 *fe6;
3354#endif
3355	struct tflow_entry *tfe;
3356
3357	ent = (struct fhashentry *)e;
3358	tfe = &tent->k.flow;
3359
3360	tfe->af = ent->af;
3361	tfe->proto = ent->proto;
3362	tfe->dport = htons(ent->dport);
3363	tfe->sport = htons(ent->sport);
3364	tent->v.kidx = ent->value;
3365	tent->subtype = ent->af;
3366
3367	if (ent->af == AF_INET) {
3368		fe4 = (struct fhashentry4 *)ent;
3369		tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
3370		tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
3371		tent->masklen = 32;
3372#ifdef INET6
3373	} else {
3374		fe6 = (struct fhashentry6 *)ent;
3375		tfe->a.a6.sip6 = fe6->sip6;
3376		tfe->a.a6.dip6 = fe6->dip6;
3377		tent->masklen = 128;
3378#endif
3379	}
3380
3381	return (0);
3382}
3383
3384static int
3385tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
3386{
3387#ifdef INET
3388	struct fhashentry4 *fe4;
3389#endif
3390#ifdef INET6
3391	struct fhashentry6 *fe6;
3392#endif
3393	struct tflow_entry *tfe;
3394
3395	tfe = (struct tflow_entry *)tei->paddr;
3396
3397	ent->af = tei->subtype;
3398	ent->proto = tfe->proto;
3399	ent->dport = ntohs(tfe->dport);
3400	ent->sport = ntohs(tfe->sport);
3401
3402	if (tei->subtype == AF_INET) {
3403#ifdef INET
3404		fe4 = (struct fhashentry4 *)ent;
3405		fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
3406		fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
3407#endif
3408#ifdef INET6
3409	} else if (tei->subtype == AF_INET6) {
3410		fe6 = (struct fhashentry6 *)ent;
3411		fe6->sip6 = tfe->a.a6.sip6;
3412		fe6->dip6 = tfe->a.a6.dip6;
3413#endif
3414	} else {
3415		/* Unknown CIDR type */
3416		return (EINVAL);
3417	}
3418
3419	return (0);
3420}
3421
3422static int
3423ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3424    ipfw_obj_tentry *tent)
3425{
3426	struct fhash_cfg *cfg;
3427	struct fhashbhead *head;
3428	struct fhashentry *ent, *tmp;
3429	struct fhashentry6 fe6;
3430	struct tentry_info tei;
3431	int error;
3432	uint32_t hash;
3433	size_t sz;
3434
3435	cfg = (struct fhash_cfg *)ta_state;
3436
3437	ent = &fe6.e;
3438
3439	memset(&fe6, 0, sizeof(fe6));
3440	memset(&tei, 0, sizeof(tei));
3441
3442	tei.paddr = &tent->k.flow;
3443	tei.subtype = tent->subtype;
3444
3445	if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
3446		return (error);
3447
3448	head = cfg->head;
3449	hash = hash_flow_ent(ent, cfg->size);
3450
3451	if (tei.subtype == AF_INET)
3452		sz = 2 * sizeof(struct in_addr);
3453	else
3454		sz = 2 * sizeof(struct in6_addr);
3455
3456	/* Check for existence */
3457	SLIST_FOREACH(tmp, &head[hash], next) {
3458		if (cmp_flow_ent(tmp, ent, sz) != 0) {
3459			ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
3460			return (0);
3461		}
3462	}
3463
3464	return (ENOENT);
3465}
3466
3467static void
3468ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3469    void *arg)
3470{
3471	struct fhash_cfg *cfg;
3472	struct fhashentry *ent, *ent_next;
3473	int i;
3474
3475	cfg = (struct fhash_cfg *)ta_state;
3476
3477	for (i = 0; i < cfg->size; i++)
3478		SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3479			f(ent, arg);
3480}
3481
3482static int
3483ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3484    void *ta_buf)
3485{
3486	struct ta_buf_fhash *tb;
3487	struct fhashentry *ent;
3488	size_t sz;
3489	int error;
3490
3491	tb = (struct ta_buf_fhash *)ta_buf;
3492
3493	if (tei->subtype == AF_INET)
3494		sz = sizeof(struct fhashentry4);
3495	else if (tei->subtype == AF_INET6)
3496		sz = sizeof(struct fhashentry6);
3497	else
3498		return (EINVAL);
3499
3500	ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
3501
3502	error = tei_to_fhash_ent(tei, ent);
3503	if (error != 0) {
3504		free(ent, M_IPFW_TBL);
3505		return (error);
3506	}
3507	tb->ent_ptr = ent;
3508
3509	return (0);
3510}
3511
3512static int
3513ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3514    void *ta_buf, uint32_t *pnum)
3515{
3516	struct fhash_cfg *cfg;
3517	struct fhashbhead *head;
3518	struct fhashentry *ent, *tmp;
3519	struct ta_buf_fhash *tb;
3520	int exists;
3521	uint32_t hash, value;
3522	size_t sz;
3523
3524	cfg = (struct fhash_cfg *)ta_state;
3525	tb = (struct ta_buf_fhash *)ta_buf;
3526	ent = (struct fhashentry *)tb->ent_ptr;
3527	exists = 0;
3528
3529	/* Read current value from @tei */
3530	ent->value = tei->value;
3531
3532	head = cfg->head;
3533	hash = hash_flow_ent(ent, cfg->size);
3534
3535	if (tei->subtype == AF_INET)
3536		sz = 2 * sizeof(struct in_addr);
3537	else
3538		sz = 2 * sizeof(struct in6_addr);
3539
3540	/* Check for existence */
3541	SLIST_FOREACH(tmp, &head[hash], next) {
3542		if (cmp_flow_ent(tmp, ent, sz) != 0) {
3543			exists = 1;
3544			break;
3545		}
3546	}
3547
3548	if (exists == 1) {
3549		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
3550			return (EEXIST);
3551		/* Record already exists. Update value if we're asked to */
3552		/* Exchange values between tmp and @tei */
3553		value = tmp->value;
3554		tmp->value = tei->value;
3555		tei->value = value;
3556		/* Indicate that update has happened instead of addition */
3557		tei->flags |= TEI_FLAGS_UPDATED;
3558		*pnum = 0;
3559	} else {
3560		if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
3561			return (EFBIG);
3562
3563		SLIST_INSERT_HEAD(&head[hash], ent, next);
3564		tb->ent_ptr = NULL;
3565		*pnum = 1;
3566
3567		/* Update counters and check if we need to grow hash */
3568		cfg->items++;
3569	}
3570
3571	return (0);
3572}
3573
3574static int
3575ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3576    void *ta_buf)
3577{
3578	struct ta_buf_fhash *tb;
3579
3580	tb = (struct ta_buf_fhash *)ta_buf;
3581
3582	return (tei_to_fhash_ent(tei, &tb->fe6.e));
3583}
3584
3585static int
3586ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3587    void *ta_buf, uint32_t *pnum)
3588{
3589	struct fhash_cfg *cfg;
3590	struct fhashbhead *head;
3591	struct fhashentry *ent, *tmp;
3592	struct ta_buf_fhash *tb;
3593	uint32_t hash;
3594	size_t sz;
3595
3596	cfg = (struct fhash_cfg *)ta_state;
3597	tb = (struct ta_buf_fhash *)ta_buf;
3598	ent = &tb->fe6.e;
3599
3600	head = cfg->head;
3601	hash = hash_flow_ent(ent, cfg->size);
3602
3603	if (tei->subtype == AF_INET)
3604		sz = 2 * sizeof(struct in_addr);
3605	else
3606		sz = 2 * sizeof(struct in6_addr);
3607
3608	/* Check for existence */
3609	SLIST_FOREACH(tmp, &head[hash], next) {
3610		if (cmp_flow_ent(tmp, ent, sz) == 0)
3611			continue;
3612
3613		SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
3614		tei->value = tmp->value;
3615		*pnum = 1;
3616		cfg->items--;
3617		tb->ent_ptr = tmp;
3618		return (0);
3619	}
3620
3621	return (ENOENT);
3622}
3623
3624static void
3625ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3626    void *ta_buf)
3627{
3628	struct ta_buf_fhash *tb;
3629
3630	tb = (struct ta_buf_fhash *)ta_buf;
3631
3632	if (tb->ent_ptr != NULL)
3633		free(tb->ent_ptr, M_IPFW_TBL);
3634}
3635
3636/*
3637 * Hash growing callbacks.
3638 */
3639
3640static int
3641ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count,
3642    uint64_t *pflags)
3643{
3644	struct fhash_cfg *cfg;
3645
3646	cfg = (struct fhash_cfg *)ta_state;
3647
3648	if (cfg->items > cfg->size && cfg->size < 65536) {
3649		*pflags = cfg->size * 2;
3650		return (1);
3651	}
3652
3653	return (0);
3654}
3655
3656/*
3657 * Allocate new, larger fhash.
3658 */
3659static int
3660ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
3661{
3662	struct mod_item *mi;
3663	struct fhashbhead *head;
3664	u_int i;
3665
3666	mi = (struct mod_item *)ta_buf;
3667
3668	memset(mi, 0, sizeof(struct mod_item));
3669	mi->size = *pflags;
3670	head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
3671	    M_WAITOK | M_ZERO);
3672	for (i = 0; i < mi->size; i++)
3673		SLIST_INIT(&head[i]);
3674
3675	mi->main_ptr = head;
3676
3677	return (0);
3678}
3679
3680/*
3681 * Copy data from old runtime array to new one.
3682 */
3683static int
3684ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3685    uint64_t *pflags)
3686{
3687
3688	/* In is not possible to do rehash if we're not holidng WLOCK. */
3689	return (0);
3690}
3691
3692/*
3693 * Switch old & new arrays.
3694 */
3695static void
3696ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3697    uint64_t pflags)
3698{
3699	struct mod_item *mi;
3700	struct fhash_cfg *cfg;
3701	struct fhashbhead *old_head, *new_head;
3702	struct fhashentry *ent, *ent_next;
3703	int i;
3704	uint32_t nhash;
3705	size_t old_size;
3706
3707	mi = (struct mod_item *)ta_buf;
3708	cfg = (struct fhash_cfg *)ta_state;
3709
3710	old_size = cfg->size;
3711	old_head = ti->state;
3712
3713	new_head = (struct fhashbhead *)mi->main_ptr;
3714	for (i = 0; i < old_size; i++) {
3715		SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
3716			nhash = hash_flow_ent(ent, mi->size);
3717			SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
3718		}
3719	}
3720
3721	ti->state = new_head;
3722	ti->data = mi->size;
3723	cfg->head = new_head;
3724	cfg->size = mi->size;
3725
3726	mi->main_ptr = old_head;
3727}
3728
3729/*
3730 * Free unneded array.
3731 */
3732static void
3733ta_flush_mod_fhash(void *ta_buf)
3734{
3735	struct mod_item *mi;
3736
3737	mi = (struct mod_item *)ta_buf;
3738	if (mi->main_ptr != NULL)
3739		free(mi->main_ptr, M_IPFW);
3740}
3741
3742struct table_algo flow_hash = {
3743	.name		= "flow:hash",
3744	.type		= IPFW_TABLE_FLOW,
3745	.flags		= TA_FLAG_DEFAULT,
3746	.ta_buf_size	= sizeof(struct ta_buf_fhash),
3747	.init		= ta_init_fhash,
3748	.destroy	= ta_destroy_fhash,
3749	.prepare_add	= ta_prepare_add_fhash,
3750	.prepare_del	= ta_prepare_del_fhash,
3751	.add		= ta_add_fhash,
3752	.del		= ta_del_fhash,
3753	.flush_entry	= ta_flush_fhash_entry,
3754	.foreach	= ta_foreach_fhash,
3755	.dump_tentry	= ta_dump_fhash_tentry,
3756	.find_tentry	= ta_find_fhash_tentry,
3757	.dump_tinfo	= ta_dump_fhash_tinfo,
3758	.need_modify	= ta_need_modify_fhash,
3759	.prepare_mod	= ta_prepare_mod_fhash,
3760	.fill_mod	= ta_fill_mod_fhash,
3761	.modify		= ta_modify_fhash,
3762	.flush_mod	= ta_flush_mod_fhash,
3763};
3764
3765/*
3766 * Kernel fibs bindings.
3767 *
3768 * Implementation:
3769 *
3770 * Runtime part:
3771 * - fully relies on route API
3772 * - fib number is stored in ti->data
3773 *
3774 */
3775
3776static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3777    uint32_t *val);
3778static int kfib_parse_opts(int *pfib, char *data);
3779static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
3780    char *buf, size_t bufsize);
3781static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state,
3782    struct table_info *ti, char *data, uint8_t tflags);
3783static void ta_destroy_kfib(void *ta_state, struct table_info *ti);
3784static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti,
3785    ipfw_ta_tinfo *tinfo);
3786static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
3787    ipfw_obj_tentry *tent);
3788static int ta_dump_kfib_tentry_int(int familt, const struct rtentry *rt,
3789    ipfw_obj_tentry *tent);
3790static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3791    ipfw_obj_tentry *tent);
3792static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
3793    ta_foreach_f *f, void *arg);
3794
3795static int
3796ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3797    uint32_t *val)
3798{
3799#ifdef INET
3800	struct in_addr in;
3801#endif
3802	int error;
3803
3804	error = ENOENT;
3805#ifdef INET
3806	if (keylen == 4) {
3807		in.s_addr = *(in_addr_t *)key;
3808		NET_EPOCH_ASSERT();
3809		error = fib4_lookup(ti->data, in, 0, NHR_NONE, 0) != NULL;
3810	}
3811#endif
3812#ifdef INET6
3813	if (keylen == 6)
3814		error = fib6_lookup(ti->data, (struct in6_addr *)key,
3815		    0, NHR_NONE, 0) != NULL;
3816#endif
3817
3818	if (error != 0)
3819		return (0);
3820
3821	*val = 0;
3822
3823	return (1);
3824}
3825
3826/* Parse 'fib=%d' */
3827static int
3828kfib_parse_opts(int *pfib, char *data)
3829{
3830	char *pdel, *pend, *s;
3831	int fibnum;
3832
3833	if (data == NULL)
3834		return (0);
3835	if ((pdel = strchr(data, ' ')) == NULL)
3836		return (0);
3837	while (*pdel == ' ')
3838		pdel++;
3839	if (strncmp(pdel, "fib=", 4) != 0)
3840		return (EINVAL);
3841	if ((s = strchr(pdel, ' ')) != NULL)
3842		*s++ = '\0';
3843
3844	pdel += 4;
3845	/* Need \d+ */
3846	fibnum = strtol(pdel, &pend, 10);
3847	if (*pend != '\0')
3848		return (EINVAL);
3849
3850	*pfib = fibnum;
3851
3852	return (0);
3853}
3854
3855static void
3856ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf,
3857    size_t bufsize)
3858{
3859
3860	if (ti->data != 0)
3861		snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data);
3862	else
3863		snprintf(buf, bufsize, "%s", "addr:kfib");
3864}
3865
3866static int
3867ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3868    char *data, uint8_t tflags)
3869{
3870	int error, fibnum;
3871
3872	fibnum = 0;
3873	if ((error = kfib_parse_opts(&fibnum, data)) != 0)
3874		return (error);
3875
3876	if (fibnum >= rt_numfibs)
3877		return (E2BIG);
3878
3879	ti->data = fibnum;
3880	ti->lookup = ta_lookup_kfib;
3881
3882	return (0);
3883}
3884
3885/*
3886 * Destroys table @ti
3887 */
3888static void
3889ta_destroy_kfib(void *ta_state, struct table_info *ti)
3890{
3891
3892}
3893
3894/*
3895 * Provide algo-specific table info
3896 */
3897static void
3898ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3899{
3900
3901	tinfo->flags = IPFW_TATFLAGS_AFDATA;
3902	tinfo->taclass4 = IPFW_TACLASS_RADIX;
3903	tinfo->count4 = 0;
3904	tinfo->itemsize4 = 128; /* table is readonly, value does not matter */
3905	tinfo->taclass6 = IPFW_TACLASS_RADIX;
3906	tinfo->count6 = 0;
3907	tinfo->itemsize6 = 128;
3908}
3909
3910static int
3911ta_dump_kfib_tentry_int(int family, const struct rtentry *rt,
3912    ipfw_obj_tentry *tent)
3913{
3914	uint32_t scopeid;
3915	int plen;
3916
3917#ifdef INET
3918	if (family == AF_INET) {
3919		rt_get_inet_prefix_plen(rt, &tent->k.addr, &plen, &scopeid);
3920		tent->masklen = plen;
3921		tent->subtype = AF_INET;
3922		tent->v.kidx = 0;
3923	}
3924#endif
3925#ifdef INET6
3926	if (family == AF_INET6) {
3927		rt_get_inet6_prefix_plen(rt, &tent->k.addr6, &plen, &scopeid);
3928		tent->masklen = plen;
3929		tent->subtype = AF_INET6;
3930		tent->v.kidx = 0;
3931	}
3932#endif
3933	return (0);
3934}
3935
3936static int
3937ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3938    ipfw_obj_tentry *tent)
3939{
3940	struct rtentry *rt = NULL;
3941	struct route_nhop_data rnd;
3942	struct epoch_tracker et;
3943	int error;
3944
3945	NET_EPOCH_ENTER(et);
3946
3947	switch (tent->subtype) {
3948#ifdef INET
3949	case AF_INET:
3950		rt = fib4_lookup_rt(ti->data, tent->k.addr, 0, 0, &rnd);
3951		break;
3952#endif
3953#ifdef INET6
3954	case AF_INET6:
3955		rt = fib6_lookup_rt(ti->data, &tent->k.addr6, 0, 0, &rnd);
3956		break;
3957#endif
3958	}
3959	if (rt != NULL)
3960		error = ta_dump_kfib_tentry_int(tent->subtype, rt, tent);
3961	else
3962		error = ENOENT;
3963	NET_EPOCH_EXIT(et);
3964
3965	return (error);
3966}
3967
3968struct kfib_dump_arg {
3969	struct rtentry *rt;
3970	int		family;
3971	ta_foreach_f	*f;
3972	void		*arg;
3973};
3974
3975static int
3976ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
3977    ipfw_obj_tentry *tent)
3978{
3979	struct kfib_dump_arg *karg = (struct kfib_dump_arg *)e;
3980
3981	return (ta_dump_kfib_tentry_int(karg->family, karg->rt, tent));
3982}
3983
3984static int
3985walk_wrapper_f(struct rtentry *rt, void *arg)
3986{
3987	struct kfib_dump_arg *karg = (struct kfib_dump_arg *)arg;
3988
3989	karg->rt = rt;
3990	return (karg->f(karg, karg->arg));
3991}
3992
3993static void
3994ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3995    void *arg)
3996{
3997	struct kfib_dump_arg karg = { .f = f, .arg = arg };
3998
3999	karg.family = AF_INET;
4000	rib_walk(ti->data, AF_INET, false, walk_wrapper_f, &karg);
4001	karg.family = AF_INET6;
4002	rib_walk(ti->data, AF_INET6, false, walk_wrapper_f, &karg);
4003}
4004
4005struct table_algo addr_kfib = {
4006	.name		= "addr:kfib",
4007	.type		= IPFW_TABLE_ADDR,
4008	.flags		= TA_FLAG_READONLY,
4009	.ta_buf_size	= 0,
4010	.init		= ta_init_kfib,
4011	.destroy	= ta_destroy_kfib,
4012	.foreach	= ta_foreach_kfib,
4013	.dump_tentry	= ta_dump_kfib_tentry,
4014	.find_tentry	= ta_find_kfib_tentry,
4015	.dump_tinfo	= ta_dump_kfib_tinfo,
4016	.print_config	= ta_print_kfib_config,
4017};
4018
4019struct mac_radix_entry {
4020	struct radix_node	rn[2];
4021	uint32_t		value;
4022	uint8_t			masklen;
4023	struct sa_mac		sa;
4024};
4025
4026struct mac_radix_cfg {
4027	struct radix_node_head	*head;
4028	size_t			count;
4029};
4030
4031static int
4032ta_lookup_mac_radix(struct table_info *ti, void *key, uint32_t keylen,
4033    uint32_t *val)
4034{
4035	struct radix_node_head *rnh;
4036
4037	if (keylen == ETHER_ADDR_LEN) {
4038		struct mac_radix_entry *ent;
4039		struct sa_mac sa;
4040		KEY_LEN(sa) = KEY_LEN_MAC;
4041		memcpy(sa.mac_addr.octet, key, ETHER_ADDR_LEN);
4042		rnh = (struct radix_node_head *)ti->state;
4043		ent = (struct mac_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
4044		if (ent != NULL) {
4045			*val = ent->value;
4046			return (1);
4047		}
4048	}
4049	return (0);
4050}
4051
4052static int
4053ta_init_mac_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
4054    char *data, uint8_t tflags)
4055{
4056	struct mac_radix_cfg *cfg;
4057
4058	if (!rn_inithead(&ti->state, OFF_LEN_MAC))
4059		return (ENOMEM);
4060
4061	cfg = malloc(sizeof(struct mac_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
4062
4063	*ta_state = cfg;
4064	ti->lookup = ta_lookup_mac_radix;
4065
4066	return (0);
4067}
4068
4069static void
4070ta_destroy_mac_radix(void *ta_state, struct table_info *ti)
4071{
4072	struct mac_radix_cfg *cfg;
4073	struct radix_node_head *rnh;
4074
4075	cfg = (struct mac_radix_cfg *)ta_state;
4076
4077	rnh = (struct radix_node_head *)(ti->state);
4078	rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
4079	rn_detachhead(&ti->state);
4080
4081	free(cfg, M_IPFW);
4082}
4083
4084static void
4085tei_to_sockaddr_ent_mac(struct tentry_info *tei, struct sockaddr *sa,
4086    struct sockaddr *ma, int *set_mask)
4087{
4088	int mlen, i;
4089	struct sa_mac *addr, *mask;
4090	u_char *cp;
4091
4092	mlen = tei->masklen;
4093	addr = (struct sa_mac *)sa;
4094	mask = (struct sa_mac *)ma;
4095	/* Set 'total' structure length */
4096	KEY_LEN(*addr) = KEY_LEN_MAC;
4097	KEY_LEN(*mask) = KEY_LEN_MAC;
4098
4099	for (i = mlen, cp = mask->mac_addr.octet; i >= 8; i -= 8)
4100		*cp++ = 0xFF;
4101	if (i > 0)
4102		*cp = ~((1 << (8 - i)) - 1);
4103
4104	addr->mac_addr = *((struct ether_addr *)tei->paddr);
4105	for (i = 0; i < ETHER_ADDR_LEN; ++i)
4106		addr->mac_addr.octet[i] &= mask->mac_addr.octet[i];
4107
4108	if (mlen != 8 * ETHER_ADDR_LEN)
4109		*set_mask = 1;
4110	else
4111		*set_mask = 0;
4112}
4113
4114static int
4115ta_prepare_add_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
4116    void *ta_buf)
4117{
4118	struct ta_buf_radix *tb;
4119	struct mac_radix_entry *ent;
4120	struct sockaddr *addr, *mask;
4121	int mlen, set_mask;
4122
4123	tb = (struct ta_buf_radix *)ta_buf;
4124
4125	mlen = tei->masklen;
4126	set_mask = 0;
4127
4128	if (tei->subtype == AF_LINK) {
4129		if (mlen > 8 * ETHER_ADDR_LEN)
4130			return (EINVAL);
4131		ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
4132		ent->masklen = mlen;
4133
4134		addr = (struct sockaddr *)&ent->sa;
4135		mask = (struct sockaddr *)&tb->addr.mac.ma;
4136		tb->ent_ptr = ent;
4137	} else {
4138		/* Unknown CIDR type */
4139		return (EINVAL);
4140	}
4141
4142	tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
4143	/* Set pointers */
4144	tb->addr_ptr = addr;
4145	if (set_mask != 0)
4146		tb->mask_ptr = mask;
4147
4148	return (0);
4149}
4150
4151static int
4152ta_add_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
4153    void *ta_buf, uint32_t *pnum)
4154{
4155	struct mac_radix_cfg *cfg;
4156	struct radix_node_head *rnh;
4157	struct radix_node *rn;
4158	struct ta_buf_radix *tb;
4159	uint32_t *old_value, value;
4160
4161	cfg = (struct mac_radix_cfg *)ta_state;
4162	tb = (struct ta_buf_radix *)ta_buf;
4163
4164	/* Save current entry value from @tei */
4165	rnh = ti->state;
4166	((struct mac_radix_entry *)tb->ent_ptr)->value = tei->value;
4167
4168	/* Search for an entry first */
4169	rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
4170	if (rn != NULL) {
4171		if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
4172			return (EEXIST);
4173		/* Record already exists. Update value if we're asked to */
4174		old_value = &((struct mac_radix_entry *)rn)->value;
4175
4176		value = *old_value;
4177		*old_value = tei->value;
4178		tei->value = value;
4179
4180		/* Indicate that update has happened instead of addition */
4181		tei->flags |= TEI_FLAGS_UPDATED;
4182		*pnum = 0;
4183
4184		return (0);
4185	}
4186
4187	if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
4188		return (EFBIG);
4189
4190	rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh, tb->ent_ptr);
4191	if (rn == NULL) {
4192		/* Unknown error */
4193		return (EINVAL);
4194	}
4195
4196	cfg->count++;
4197	tb->ent_ptr = NULL;
4198	*pnum = 1;
4199
4200	return (0);
4201}
4202
4203static int
4204ta_prepare_del_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
4205    void *ta_buf)
4206{
4207	struct ta_buf_radix *tb;
4208	struct sockaddr *addr, *mask;
4209	int mlen, set_mask;
4210
4211	tb = (struct ta_buf_radix *)ta_buf;
4212
4213	mlen = tei->masklen;
4214	set_mask = 0;
4215
4216	if (tei->subtype == AF_LINK) {
4217		if (mlen > 8 * ETHER_ADDR_LEN)
4218			return (EINVAL);
4219
4220		addr = (struct sockaddr *)&tb->addr.mac.sa;
4221		mask = (struct sockaddr *)&tb->addr.mac.ma;
4222	} else
4223		return (EINVAL);
4224
4225	tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
4226	tb->addr_ptr = addr;
4227	if (set_mask != 0)
4228		tb->mask_ptr = mask;
4229
4230	return (0);
4231}
4232
4233static int
4234ta_del_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
4235    void *ta_buf, uint32_t *pnum)
4236{
4237	struct mac_radix_cfg *cfg;
4238	struct radix_node_head *rnh;
4239	struct radix_node *rn;
4240	struct ta_buf_radix *tb;
4241
4242	cfg = (struct mac_radix_cfg *)ta_state;
4243	tb = (struct ta_buf_radix *)ta_buf;
4244	rnh = ti->state;
4245
4246	rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
4247
4248	if (rn == NULL)
4249		return (ENOENT);
4250
4251	/* Save entry value to @tei */
4252	tei->value = ((struct mac_radix_entry *)rn)->value;
4253
4254	tb->ent_ptr = rn;
4255	cfg->count--;
4256	*pnum = 1;
4257
4258	return (0);
4259}
4260
4261static void
4262ta_foreach_mac_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
4263    void *arg)
4264{
4265	struct radix_node_head *rnh;
4266
4267	rnh = (struct radix_node_head *)(ti->state);
4268	rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
4269}
4270
4271static void
4272ta_dump_mac_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
4273{
4274	struct mac_radix_cfg *cfg;
4275
4276	cfg = (struct mac_radix_cfg *)ta_state;
4277
4278	tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
4279	tinfo->taclass4 = IPFW_TACLASS_RADIX;
4280	tinfo->count4 = cfg->count;
4281	tinfo->itemsize4 = sizeof(struct mac_radix_entry);
4282}
4283
4284static int
4285ta_dump_mac_radix_tentry(void *ta_state, struct table_info *ti, void *e,
4286    ipfw_obj_tentry *tent)
4287{
4288	struct mac_radix_entry *n = (struct mac_radix_entry *)e;
4289
4290	memcpy(tent->k.mac, n->sa.mac_addr.octet, ETHER_ADDR_LEN);
4291	tent->masklen = n->masklen;
4292	tent->subtype = AF_LINK;
4293	tent->v.kidx = n->value;
4294
4295	return (0);
4296}
4297
4298static int
4299ta_find_mac_radix_tentry(void *ta_state, struct table_info *ti,
4300    ipfw_obj_tentry *tent)
4301{
4302	struct radix_node_head *rnh;
4303	void *e;
4304
4305	e = NULL;
4306	if (tent->subtype == AF_LINK) {
4307		struct sa_mac sa;
4308		KEY_LEN(sa) = KEY_LEN_MAC;
4309		memcpy(tent->k.mac, sa.mac_addr.octet, ETHER_ADDR_LEN);
4310		rnh = (struct radix_node_head *)ti->state;
4311		e = rnh->rnh_matchaddr(&sa, &rnh->rh);
4312	}
4313
4314	if (e != NULL) {
4315		ta_dump_mac_radix_tentry(ta_state, ti, e, tent);
4316		return (0);
4317	}
4318
4319	return (ENOENT);
4320}
4321
4322struct table_algo mac_radix = {
4323	.name		= "mac:radix",
4324	.type		= IPFW_TABLE_MAC,
4325	.flags		= TA_FLAG_DEFAULT,
4326	.ta_buf_size	= sizeof(struct ta_buf_radix),
4327	.init		= ta_init_mac_radix,
4328	.destroy	= ta_destroy_mac_radix,
4329	.prepare_add	= ta_prepare_add_mac_radix,
4330	.prepare_del	= ta_prepare_del_mac_radix,
4331	.add		= ta_add_mac_radix,
4332	.del		= ta_del_mac_radix,
4333	.flush_entry	= ta_flush_radix_entry,
4334	.foreach	= ta_foreach_mac_radix,
4335	.dump_tentry	= ta_dump_mac_radix_tentry,
4336	.find_tentry	= ta_find_mac_radix_tentry,
4337	.dump_tinfo	= ta_dump_mac_radix_tinfo,
4338	.need_modify	= ta_need_modify_radix,
4339};
4340
4341void
4342ipfw_table_algo_init(struct ip_fw_chain *ch)
4343{
4344	size_t sz;
4345
4346	/*
4347	 * Register all algorithms presented here.
4348	 */
4349	sz = sizeof(struct table_algo);
4350	ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx);
4351	ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx);
4352	ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
4353	ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
4354	ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
4355	ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
4356	ipfw_add_table_algo(ch, &mac_radix, sz, &mac_radix.idx);
4357}
4358
4359void
4360ipfw_table_algo_destroy(struct ip_fw_chain *ch)
4361{
4362
4363	ipfw_del_table_algo(ch, addr_radix.idx);
4364	ipfw_del_table_algo(ch, addr_hash.idx);
4365	ipfw_del_table_algo(ch, iface_idx.idx);
4366	ipfw_del_table_algo(ch, number_array.idx);
4367	ipfw_del_table_algo(ch, flow_hash.idx);
4368	ipfw_del_table_algo(ch, addr_kfib.idx);
4369	ipfw_del_table_algo(ch, mac_radix.idx);
4370}
4371