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