]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfw/ip_fw_table.c
Show algorithm-specific data in "table info" output.
[FreeBSD/FreeBSD.git] / sys / netpfil / ipfw / ip_fw_table.c
1 /*-
2  * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 /*
30  * Lookup table support for ipfw.
31  *
32  * This file contains handlers for all generic tables' operations:
33  * add/del/flush entries, list/dump tables etc..
34  *
35  * Table data modification is protected by both UH and runtimg lock
36  * while reading configuration/data is protected by UH lock.
37  *
38  * Lookup algorithms for all table types are located in ip_fw_table_algo.c
39  */
40
41 #include "opt_ipfw.h"
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/kernel.h>
47 #include <sys/lock.h>
48 #include <sys/rwlock.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/queue.h>
52 #include <net/if.h>     /* ip_fw.h requires IFNAMSIZ */
53
54 #include <netinet/in.h>
55 #include <netinet/ip_var.h>     /* struct ipfw_rule_ref */
56 #include <netinet/ip_fw.h>
57
58 #include <netpfil/ipfw/ip_fw_private.h>
59 #include <netpfil/ipfw/ip_fw_table.h>
60
61
62  /*
63  * Table has the following `type` concepts:
64  *
65  * `no.type` represents lookup key type (cidr, ifp, uid, etc..)
66  * `ta->atype` represents exact lookup algorithm.
67  *     For example, we can use more efficient search schemes if we plan
68  *     to use some specific table for storing host-routes only.
69  * `ftype` (at the moment )is pure userland field helping to properly
70  *     format value data e.g. "value is IPv4 nexthop" or "value is DSCP"
71  *     or "value is port".
72  *
73  */
74 struct table_config {
75         struct named_object     no;
76         uint8_t         vtype;          /* format table type */
77         uint8_t         linked;         /* 1 if already linked */
78         uint8_t         tflags;         /* type flags */
79         uint8_t         spare;
80         uint32_t        count;          /* Number of records */
81         uint32_t        limit;          /* Max number of records */
82         char            tablename[64];  /* table name */
83         struct table_algo       *ta;    /* Callbacks for given algo */
84         void            *astate;        /* algorithm state */
85         struct table_info       ti;     /* data to put to table_info */
86 };
87
88 struct tables_config {
89         struct namedobj_instance        *namehash;
90         int                             algo_count;
91         struct table_algo               *algo[256];
92         struct table_algo               *def_algo[IPFW_TABLE_MAXTYPE + 1];
93 };
94
95 static struct table_config *find_table(struct namedobj_instance *ni,
96     struct tid_info *ti);
97 static struct table_config *alloc_table_config(struct ip_fw_chain *ch,
98     struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags,
99     uint8_t vtype);
100 static void free_table_config(struct namedobj_instance *ni,
101     struct table_config *tc);
102 static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
103     char *aname, ipfw_xtable_info *i);
104 static void link_table(struct ip_fw_chain *chain, struct table_config *tc);
105 static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc);
106 static void free_table_state(void **state, void **xstate, uint8_t type);
107 static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
108     struct sockopt_data *sd);
109 static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
110     ipfw_xtable_info *i);
111 static int dump_table_tentry(void *e, void *arg);
112 static int dump_table_xentry(void *e, void *arg);
113
114 static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd);
115 static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd);
116 static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
117     struct sockopt_data *sd);
118 static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
119     struct sockopt_data *sd);
120
121 static int check_table_space(struct ip_fw_chain *ch, struct table_config *tc,
122     struct table_info *ti, uint32_t count);
123 static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
124
125 static struct table_algo *find_table_algo(struct tables_config *tableconf,
126     struct tid_info *ti, char *name);
127
128 #define CHAIN_TO_TCFG(chain)    ((struct tables_config *)(chain)->tblcfg)
129 #define CHAIN_TO_NI(chain)      (CHAIN_TO_TCFG(chain)->namehash)
130 #define KIDX_TO_TI(ch, k)       (&(((struct table_info *)(ch)->tablestate)[k]))
131
132 #define TA_BUF_SZ       128     /* On-stack buffer for add/delete state */
133
134
135 int
136 add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
137     struct tentry_info *tei, uint32_t count)
138 {
139         struct table_config *tc;
140         struct table_algo *ta;
141         struct namedobj_instance *ni;
142         uint16_t kidx;
143         int error;
144         uint32_t num;
145         ipfw_xtable_info *xi;
146         char ta_buf[TA_BUF_SZ];
147
148         IPFW_UH_WLOCK(ch);
149         ni = CHAIN_TO_NI(ch);
150
151         /*
152          * Find and reference existing table.
153          */
154         ta = NULL;
155         if ((tc = find_table(ni, ti)) != NULL) {
156                 /* check table type */
157                 if (tc->no.type != ti->type) {
158                         IPFW_UH_WUNLOCK(ch);
159                         return (EINVAL);
160                 }
161
162                 /* Try to exit early on limit hit */
163                 if (tc->limit != 0 && tc->count == tc->limit &&
164                     (tei->flags & TEI_FLAGS_UPDATE) == 0) {
165                                 IPFW_UH_WUNLOCK(ch);
166                                 return (EFBIG);
167                 }
168
169                 /* Reference and unlock */
170                 tc->no.refcnt++;
171                 ta = tc->ta;
172         }
173         IPFW_UH_WUNLOCK(ch);
174
175         if (tc == NULL) {
176                 /* Compability mode: create new table for old clients */
177                 if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
178                         return (ESRCH);
179
180                 xi = malloc(sizeof(ipfw_xtable_info), M_TEMP, M_WAITOK|M_ZERO);
181                 xi->vtype = IPFW_VTYPE_U32;
182
183                 error = create_table_internal(ch, ti, NULL, xi);
184                 free(xi, M_TEMP);
185
186                 if (error != 0)
187                         return (error);
188
189                 /* Let's try to find & reference another time */
190                 IPFW_UH_WLOCK(ch);
191                 if ((tc = find_table(ni, ti)) == NULL) {
192                         IPFW_UH_WUNLOCK(ch);
193                         return (EINVAL);
194                 }
195
196                 if (tc->no.type != ti->type) {
197                         IPFW_UH_WUNLOCK(ch);
198                         return (EINVAL);
199                 }
200
201                 /* Reference and unlock */
202                 tc->no.refcnt++;
203                 ta = tc->ta;
204
205                 IPFW_UH_WUNLOCK(ch);
206         }
207
208         /* Prepare record (allocate memory) */
209         memset(&ta_buf, 0, sizeof(ta_buf));
210         error = ta->prepare_add(ch, tei, &ta_buf);
211         if (error != 0)
212                 return (error);
213
214         IPFW_UH_WLOCK(ch);
215
216         /*
217          * Ensure we are able to add all entries without additional
218          * memory allocations. May release/reacquire UH_WLOCK.
219          */
220         kidx = tc->no.kidx;
221         error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), count);
222         if (error != 0) {
223                 IPFW_UH_WUNLOCK(ch);
224                 ta->flush_entry(ch, tei, &ta_buf);
225                 return (error);
226         }
227
228         ni = CHAIN_TO_NI(ch);
229
230         /* Drop reference we've used in first search */
231         tc->no.refcnt--;
232         
233         /* Check limit before adding */
234         if (tc->limit != 0 && tc->count == tc->limit) {
235                 if ((tei->flags & TEI_FLAGS_UPDATE) == 0) {
236                         IPFW_UH_WUNLOCK(ch);
237                         ta->flush_entry(ch, tei, &ta_buf);
238                         return (EFBIG);
239                 }
240
241                 /*
242                  * We have UPDATE flag set.
243                  * Permit updating record (if found),
244                  * but restrict adding new one since we've
245                  * already hit the limit.
246                  */
247                 tei->flags |= TEI_FLAGS_DONTADD;
248         }
249
250         /* We've got valid table in @tc. Let's add data */
251         kidx = tc->no.kidx;
252         ta = tc->ta;
253         num = 0;
254
255         IPFW_WLOCK(ch);
256         error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &num);
257         IPFW_WUNLOCK(ch);
258
259         /* Update number of records. */
260         if (error == 0) {
261                 tc->count += num;
262                 /* Permit post-add algorithm grow/rehash. */
263                 error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0);
264         }
265
266         IPFW_UH_WUNLOCK(ch);
267
268         /* Run cleaning callback anyway */
269         ta->flush_entry(ch, tei, &ta_buf);
270
271         return (error);
272 }
273
274 int
275 del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
276     struct tentry_info *tei, uint32_t count)
277 {
278         struct table_config *tc;
279         struct table_algo *ta;
280         struct namedobj_instance *ni;
281         uint16_t kidx;
282         int error;
283         uint32_t num;
284         char ta_buf[TA_BUF_SZ];
285
286         IPFW_UH_WLOCK(ch);
287         ni = CHAIN_TO_NI(ch);
288         if ((tc = find_table(ni, ti)) == NULL) {
289                 IPFW_UH_WUNLOCK(ch);
290                 return (ESRCH);
291         }
292
293         if (tc->no.type != ti->type) {
294                 IPFW_UH_WUNLOCK(ch);
295                 return (EINVAL);
296         }
297
298         ta = tc->ta;
299
300         /*
301          * Give a chance for algorithm to shrink.
302          * May release/reacquire UH_WLOCK.
303          */
304         kidx = tc->no.kidx;
305         error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0);
306         if (error != 0) {
307                 IPFW_UH_WUNLOCK(ch);
308                 ta->flush_entry(ch, tei, &ta_buf);
309                 return (error);
310         }
311
312         /*
313          * We assume ta_buf size is enough for storing
314          * prepare_del() key, so we're running under UH_WLOCK here.
315          */
316         memset(&ta_buf, 0, sizeof(ta_buf));
317         if ((error = ta->prepare_del(ch, tei, &ta_buf)) != 0) {
318                 IPFW_UH_WUNLOCK(ch);
319                 return (error);
320         }
321
322         kidx = tc->no.kidx;
323         num = 0;
324
325         IPFW_WLOCK(ch);
326         error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &num);
327         IPFW_WUNLOCK(ch);
328
329         if (error == 0) {
330                 tc->count -= num;
331                 /* Run post-del hook to permit shrinking */
332                 error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0);
333         }
334
335         IPFW_UH_WUNLOCK(ch);
336
337         ta->flush_entry(ch, tei, &ta_buf);
338
339         return (error);
340 }
341
342 /*
343  * Ensure that table @tc has enough space to add @count entries without
344  * need for reallocation.
345  *
346  * Callbacks order:
347  * 0) has_space() (UH_WLOCK) - checks if @count items can be added w/o resize.
348  *
349  * 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags.
350  * 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage
351  * 3) modify (UH_WLOCK + WLOCK) - switch pointers
352  * 4) flush_modify (UH_WLOCK) - free state, if needed
353  *
354  * Returns 0 on success.
355  */
356 static int
357 check_table_space(struct ip_fw_chain *ch, struct table_config *tc,
358     struct table_info *ti, uint32_t count)
359 {
360         struct table_algo *ta;
361         uint64_t pflags;
362         char ta_buf[TA_BUF_SZ];
363         int error;
364
365         IPFW_UH_WLOCK_ASSERT(ch);
366
367         error = 0;
368         ta = tc->ta;
369         /* Acquire reference not to loose @tc between locks/unlocks */
370         tc->no.refcnt++;
371
372         /*
373          * TODO: think about avoiding race between large add/large delete
374          * operation on algorithm which implements shrinking along with
375          * growing.
376          */
377         while (true) {
378                 pflags = 0;
379                 if (ta->has_space(tc->astate, ti, count, &pflags) != 0) {
380                         tc->no.refcnt--;
381                         return (0);
382                 }
383
384                 /* We have to shrink/grow table */
385                 IPFW_UH_WUNLOCK(ch);
386                 memset(&ta_buf, 0, sizeof(ta_buf));
387                 
388                 if ((error = ta->prepare_mod(ta_buf, &pflags)) != 0) {
389                         IPFW_UH_WLOCK(ch);
390                         break;
391                 }
392
393                 IPFW_UH_WLOCK(ch);
394
395                 /* Check if we still need to alter table */
396                 ti = KIDX_TO_TI(ch, tc->no.kidx);
397                 if (ta->has_space(tc->astate, ti, count, &pflags) != 0) {
398
399                         /*
400                          * Other threads has already performed resize.
401                          * Flush our state and return/
402                          */
403                         ta->flush_mod(ta_buf);
404                         break;
405                 }
406         
407                 error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags);
408                 if (error == 0) {
409                         /* Do actual modification */
410                         IPFW_WLOCK(ch);
411                         ta->modify(tc->astate, ti, ta_buf, pflags);
412                         IPFW_WUNLOCK(ch);
413                 }
414
415                 /* Anyway, flush data and retry */
416                 ta->flush_mod(ta_buf);
417         }
418
419         tc->no.refcnt--;
420         return (error);
421 }
422
423
424
425 int
426 ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
427     struct sockopt_data *sd)
428 {
429         int error;
430
431         switch (op3->version) {
432         case 0:
433                 error = ipfw_manage_table_ent_v0(ch, op3, sd);
434                 break;
435         case 1:
436                 error = ipfw_manage_table_ent_v1(ch, op3, sd);
437                 break;
438         default:
439                 error = ENOTSUP;
440         }
441
442         return (error);
443 }
444
445 /*
446  * Adds or deletes record in table.
447  * Data layout (v0):
448  * Request: [ ip_fw3_opheader ipfw_table_xentry ]
449  *
450  * Returns 0 on success
451  */
452 static int
453 ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
454     struct sockopt_data *sd)
455 {
456         ipfw_table_xentry *xent;
457         struct tentry_info tei;
458         struct tid_info ti;
459         int error, hdrlen, read;
460
461         hdrlen = offsetof(ipfw_table_xentry, k);
462
463         /* Check minimum header size */
464         if (sd->valsize < (sizeof(*op3) + hdrlen))
465                 return (EINVAL);
466
467         read = sizeof(ip_fw3_opheader);
468
469         /* Check if xentry len field is valid */
470         xent = (ipfw_table_xentry *)(op3 + 1);
471         if (xent->len < hdrlen || xent->len + read > sd->valsize)
472                 return (EINVAL);
473         
474         memset(&tei, 0, sizeof(tei));
475         tei.paddr = &xent->k;
476         tei.masklen = xent->masklen;
477         tei.value = xent->value;
478         /* Old requests compability */
479         tei.flags = TEI_FLAGS_COMPAT;
480         if (xent->type == IPFW_TABLE_CIDR) {
481                 if (xent->len - hdrlen == sizeof(in_addr_t))
482                         tei.subtype = AF_INET;
483                 else
484                         tei.subtype = AF_INET6;
485         }
486
487         memset(&ti, 0, sizeof(ti));
488         ti.uidx = xent->tbl;
489         ti.type = xent->type;
490
491         error = (op3->opcode == IP_FW_TABLE_XADD) ?
492             add_table_entry(ch, &ti, &tei, 1) :
493             del_table_entry(ch, &ti, &tei, 1);
494
495         return (error);
496 }
497
498 /*
499  * Adds or deletes record in table.
500  * Data layout (v1)(current):
501  * Request: [ ipfw_obj_header
502  *   ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ]
503  * ]
504  *
505  * Returns 0 on success
506  */
507 static int
508 ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
509     struct sockopt_data *sd)
510 {
511         ipfw_obj_tentry *tent;
512         ipfw_obj_ctlv *ctlv;
513         ipfw_obj_header *oh;
514         struct tentry_info tei;
515         struct tid_info ti;
516         int error, read;
517
518         /* Check minimum header size */
519         if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv)))
520                 return (EINVAL);
521
522         /* Check if passed data is too long */
523         if (sd->valsize != sd->kavail)
524                 return (EINVAL);
525
526         oh = (ipfw_obj_header *)sd->kbuf;
527
528         /* Basic length checks for TLVs */
529         if (oh->ntlv.head.length != sizeof(oh->ntlv))
530                 return (EINVAL);
531
532         read = sizeof(*oh);
533
534         ctlv = (ipfw_obj_ctlv *)(oh + 1);
535         if (ctlv->head.length + read != sd->valsize)
536                 return (EINVAL);
537
538         /*
539          * TODO: permit adding multiple entries for given table
540          * at once
541          */
542         if (ctlv->count != 1)
543                 return (EOPNOTSUPP);
544
545         read += sizeof(*ctlv);
546
547         /* Assume tentry may grow to support larger keys */
548         tent = (ipfw_obj_tentry *)(ctlv + 1);
549         if (tent->head.length < sizeof(*tent) ||
550             tent->head.length + read > sd->valsize)
551                 return (EINVAL);
552
553         /* Convert data into kernel request objects */
554         memset(&tei, 0, sizeof(tei));
555         tei.paddr = &tent->k;
556         tei.subtype = tent->subtype;
557         tei.masklen = tent->masklen;
558         if (tent->head.flags & IPFW_TF_UPDATE)
559                 tei.flags |= TEI_FLAGS_UPDATE;
560         tei.value = tent->value;
561
562         objheader_to_ti(oh, &ti);
563         ti.type = oh->ntlv.type;
564         ti.uidx = tent->idx;
565
566         error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
567             add_table_entry(ch, &ti, &tei, 1) :
568             del_table_entry(ch, &ti, &tei, 1);
569
570         return (error);
571 }
572
573 /*
574  * Looks up an entry in given table.
575  * Data layout (v0)(current):
576  * Request: [ ipfw_obj_header ipfw_obj_tentry ]
577  * Reply: [ ipfw_obj_header ipfw_obj_tentry ]
578  *
579  * Returns 0 on success
580  */
581 int
582 ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
583     struct sockopt_data *sd)
584 {
585         ipfw_obj_tentry *tent;
586         ipfw_obj_header *oh;
587         struct tid_info ti;
588         struct table_config *tc;
589         struct table_algo *ta;
590         struct table_info *kti;
591         struct namedobj_instance *ni;
592         int error;
593         size_t sz;
594
595         /* Check minimum header size */
596         sz = sizeof(*oh) + sizeof(*tent);
597         if (sd->valsize != sz)
598                 return (EINVAL);
599
600         oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
601         tent = (ipfw_obj_tentry *)(oh + 1);
602
603         /* Basic length checks for TLVs */
604         if (oh->ntlv.head.length != sizeof(oh->ntlv))
605                 return (EINVAL);
606
607         objheader_to_ti(oh, &ti);
608         ti.type = oh->ntlv.type;
609         ti.uidx = tent->idx;
610
611         IPFW_UH_RLOCK(ch);
612         ni = CHAIN_TO_NI(ch);
613
614         /*
615          * Find existing table and check its type .
616          */
617         ta = NULL;
618         if ((tc = find_table(ni, &ti)) == NULL) {
619                 IPFW_UH_RUNLOCK(ch);
620                 return (ESRCH);
621         }
622
623         /* check table type */
624         if (tc->no.type != ti.type) {
625                 IPFW_UH_RUNLOCK(ch);
626                 return (EINVAL);
627         }
628
629         kti = KIDX_TO_TI(ch, tc->no.kidx);
630         ta = tc->ta;
631
632         if (ta->find_tentry == NULL)
633                 return (ENOTSUP);
634
635         error = ta->find_tentry(tc->astate, kti, tent);
636
637         IPFW_UH_RUNLOCK(ch);
638
639         return (error);
640 }
641
642 int
643 ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
644     struct sockopt_data *sd)
645 {
646         int error;
647         struct _ipfw_obj_header *oh;
648         struct tid_info ti;
649
650         if (sd->valsize != sizeof(*oh))
651                 return (EINVAL);
652
653         oh = (struct _ipfw_obj_header *)op3;
654         objheader_to_ti(oh, &ti);
655
656         if (op3->opcode == IP_FW_TABLE_XDESTROY)
657                 error = destroy_table(ch, &ti);
658         else if (op3->opcode == IP_FW_TABLE_XFLUSH)
659                 error = flush_table(ch, &ti);
660         else
661                 return (ENOTSUP);
662
663         return (error);
664 }
665
666 /*
667  * Flushes all entries in given table.
668  * Data layout (v0)(current):
669  * Request: [ ip_fw3_opheader ]
670  *
671  * Returns 0 on success
672  */
673 int
674 flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
675 {
676         struct namedobj_instance *ni;
677         struct table_config *tc;
678         struct table_algo *ta;
679         struct table_info ti_old, ti_new, *tablestate;
680         void *astate_old, *astate_new;
681         char algostate[64], *pstate;
682         int error;
683         uint16_t kidx;
684         uint8_t tflags;
685
686         /*
687          * Stage 1: save table algoritm.
688          * Reference found table to ensure it won't disappear.
689          */
690         IPFW_UH_WLOCK(ch);
691         ni = CHAIN_TO_NI(ch);
692         if ((tc = find_table(ni, ti)) == NULL) {
693                 IPFW_UH_WUNLOCK(ch);
694                 return (ESRCH);
695         }
696         ta = tc->ta;
697         tc->no.refcnt++;
698         /* Save statup algo parameters */
699         if (ta->print_config != NULL) {
700                 ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx),
701                     algostate, sizeof(algostate));
702                 pstate = algostate;
703         } else
704                 pstate = NULL;
705         tflags = tc->tflags;
706         IPFW_UH_WUNLOCK(ch);
707
708         /*
709          * Stage 2: allocate new table instance using same algo.
710          */
711         memset(&ti_new, 0, sizeof(struct table_info));
712         if ((error = ta->init(ch, &astate_new, &ti_new, pstate, tflags)) != 0) {
713                 IPFW_UH_WLOCK(ch);
714                 tc->no.refcnt--;
715                 IPFW_UH_WUNLOCK(ch);
716                 return (error);
717         }
718
719         /*
720          * Stage 3: swap old state pointers with newly-allocated ones.
721          * Decrease refcount.
722          */
723         IPFW_UH_WLOCK(ch);
724
725         ni = CHAIN_TO_NI(ch);
726         kidx = tc->no.kidx;
727         tablestate = (struct table_info *)ch->tablestate;
728
729         IPFW_WLOCK(ch);
730         ti_old = tablestate[kidx];
731         tablestate[kidx] = ti_new;
732         IPFW_WUNLOCK(ch);
733
734         astate_old = tc->astate;
735         tc->astate = astate_new;
736         tc->ti = ti_new;
737         tc->count = 0;
738         tc->no.refcnt--;
739
740         IPFW_UH_WUNLOCK(ch);
741
742         /*
743          * Stage 4: perform real flush.
744          */
745         ta->destroy(astate_old, &ti_old);
746
747         return (0);
748 }
749
750 /*
751  * Destroys table specified by @ti.
752  * Data layout (v0)(current):
753  * Request: [ ip_fw3_opheader ]
754  *
755  * Returns 0 on success
756  */
757 static int
758 destroy_table(struct ip_fw_chain *ch, struct tid_info *ti)
759 {
760         struct namedobj_instance *ni;
761         struct table_config *tc;
762
763         IPFW_UH_WLOCK(ch);
764
765         ni = CHAIN_TO_NI(ch);
766         if ((tc = find_table(ni, ti)) == NULL) {
767                 IPFW_UH_WUNLOCK(ch);
768                 return (ESRCH);
769         }
770
771         /* Do not permit destroying referenced tables */
772         if (tc->no.refcnt > 0) {
773                 IPFW_UH_WUNLOCK(ch);
774                 return (EBUSY);
775         }
776
777         IPFW_WLOCK(ch);
778         unlink_table(ch, tc);
779         IPFW_WUNLOCK(ch);
780
781         /* Free obj index */
782         if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0)
783                 printf("Error unlinking kidx %d from table %s\n",
784                     tc->no.kidx, tc->tablename);
785
786         IPFW_UH_WUNLOCK(ch);
787
788         free_table_config(ni, tc);
789
790         return (0);
791 }
792
793 static void
794 destroy_table_locked(struct namedobj_instance *ni, struct named_object *no,
795     void *arg)
796 {
797
798         unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no);
799         if (ipfw_objhash_free_idx(ni, no->kidx) != 0)
800                 printf("Error unlinking kidx %d from table %s\n",
801                     no->kidx, no->name);
802         free_table_config(ni, (struct table_config *)no);
803 }
804
805 void
806 ipfw_destroy_tables(struct ip_fw_chain *ch)
807 {
808
809         /* Remove all tables from working set */
810         IPFW_UH_WLOCK(ch);
811         IPFW_WLOCK(ch);
812         ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch);
813         IPFW_WUNLOCK(ch);
814         IPFW_UH_WUNLOCK(ch);
815
816         /* Free pointers itself */
817         free(ch->tablestate, M_IPFW);
818
819         ipfw_table_algo_destroy(ch);
820
821         ipfw_objhash_destroy(CHAIN_TO_NI(ch));
822         free(CHAIN_TO_TCFG(ch), M_IPFW);
823 }
824
825 int
826 ipfw_init_tables(struct ip_fw_chain *ch)
827 {
828         struct tables_config *tcfg;
829
830         /* Allocate pointers */
831         ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info),
832             M_IPFW, M_WAITOK | M_ZERO);
833
834         tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO);
835         tcfg->namehash = ipfw_objhash_create(V_fw_tables_max);
836         ch->tblcfg = tcfg;
837
838         ipfw_table_algo_init(ch);
839
840         return (0);
841 }
842
843 int
844 ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
845 {
846         unsigned int ntables_old, tbl;
847         struct namedobj_instance *ni;
848         void *new_idx, *old_tablestate, *tablestate;
849         struct table_info *ti;
850         struct table_config *tc;
851         int i, new_blocks;
852
853         /* Check new value for validity */
854         if (ntables > IPFW_TABLES_MAX)
855                 ntables = IPFW_TABLES_MAX;
856
857         /* Allocate new pointers */
858         tablestate = malloc(ntables * sizeof(struct table_info),
859             M_IPFW, M_WAITOK | M_ZERO);
860
861         ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks);
862
863         IPFW_UH_WLOCK(ch);
864
865         tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;
866         ni = CHAIN_TO_NI(ch);
867
868         /* Temporary restrict decreasing max_tables */
869         if (ntables < V_fw_tables_max) {
870
871                 /*
872                  * FIXME: Check if we really can shrink
873                  */
874                 IPFW_UH_WUNLOCK(ch);
875                 return (EINVAL);
876         }
877
878         /* Copy table info/indices */
879         memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl);
880         ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks);
881
882         IPFW_WLOCK(ch);
883
884         /* Change pointers */
885         old_tablestate = ch->tablestate;
886         ch->tablestate = tablestate;
887         ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks);
888
889         ntables_old = V_fw_tables_max;
890         V_fw_tables_max = ntables;
891
892         IPFW_WUNLOCK(ch);
893
894         /* Notify all consumers that their @ti pointer has changed */
895         ti = (struct table_info *)ch->tablestate;
896         for (i = 0; i < tbl; i++, ti++) {
897                 if (ti->lookup == NULL)
898                         continue;
899                 tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, i);
900                 if (tc == NULL || tc->ta->change_ti == NULL)
901                         continue;
902
903                 tc->ta->change_ti(tc->astate, ti);
904         }
905
906         IPFW_UH_WUNLOCK(ch);
907
908         /* Free old pointers */
909         free(old_tablestate, M_IPFW);
910         ipfw_objhash_bitmap_free(new_idx, new_blocks);
911
912         return (0);
913 }
914
915 int
916 ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
917     uint32_t *val)
918 {
919         struct table_info *ti;
920
921         ti = &(((struct table_info *)ch->tablestate)[tbl]);
922
923         return (ti->lookup(ti, &addr, sizeof(in_addr_t), val));
924 }
925
926 int
927 ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
928     void *paddr, uint32_t *val)
929 {
930         struct table_info *ti;
931
932         ti = &(((struct table_info *)ch->tablestate)[tbl]);
933
934         return (ti->lookup(ti, paddr, plen, val));
935 }
936
937 /*
938  * Info/List/dump support for tables.
939  *
940  */
941
942 /*
943  * High-level 'get' cmds sysctl handlers
944  */
945
946 /*
947  * Get buffer size needed to list info for all tables.
948  * Data layout (v0)(current):
949  * Request: [ empty ], size = sizeof(ipfw_obj_lheader)
950  * Reply: [ ipfw_obj_lheader ]
951  *
952  * Returns 0 on success
953  */
954 int
955 ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd)
956 {
957         struct _ipfw_obj_lheader *olh;
958
959         olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
960         if (olh == NULL)
961                 return (EINVAL);
962
963         olh->size = sizeof(*olh); /* Make export_table store needed size */
964
965         IPFW_UH_RLOCK(ch);
966         export_tables(ch, olh, sd);
967         IPFW_UH_RUNLOCK(ch);
968
969         return (0);
970 }
971
972 /*
973  * Lists all tables currently available in kernel.
974  * Data layout (v0)(current):
975  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
976  * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ]
977  *
978  * Returns 0 on success
979  */
980 int
981 ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd)
982 {
983         struct _ipfw_obj_lheader *olh;
984         int error;
985
986         olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
987         if (olh == NULL)
988                 return (EINVAL);
989         if (sd->valsize < olh->size)
990                 return (EINVAL);
991
992         IPFW_UH_RLOCK(ch);
993         error = export_tables(ch, olh, sd);
994         IPFW_UH_RUNLOCK(ch);
995
996         return (error);
997 }
998
999 /*
1000  * Store table info to buffer provided by @sd.
1001  * Data layout (v0)(current):
1002  * Request: [ ipfw_obj_header ipfw_xtable_info(empty)]
1003  * Reply: [ ipfw_obj_header ipfw_xtable_info ]
1004  *
1005  * Returns 0 on success.
1006  */
1007 int
1008 ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd)
1009 {
1010         struct _ipfw_obj_header *oh;
1011         struct table_config *tc;
1012         struct tid_info ti;
1013         size_t sz;
1014
1015         sz = sizeof(*oh) + sizeof(ipfw_xtable_info);
1016         oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
1017         if (oh == NULL)
1018                 return (EINVAL);
1019
1020         objheader_to_ti(oh, &ti);
1021
1022         IPFW_UH_RLOCK(ch);
1023         if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
1024                 IPFW_UH_RUNLOCK(ch);
1025                 return (ESRCH);
1026         }
1027
1028         export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1));
1029         IPFW_UH_RUNLOCK(ch);
1030
1031         return (0);
1032 }
1033
1034 struct dump_args {
1035         struct table_info *ti;
1036         struct table_config *tc;
1037         struct sockopt_data *sd;
1038         uint32_t cnt;
1039         uint16_t uidx;
1040         int error;
1041         ipfw_table_entry *ent;
1042         uint32_t size;
1043         ipfw_obj_tentry tent;
1044 };
1045
1046 int
1047 ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1048     struct sockopt_data *sd)
1049 {
1050         int error;
1051
1052         switch (op3->version) {
1053         case 0:
1054                 error = ipfw_dump_table_v0(ch, sd);
1055                 break;
1056         case 1:
1057                 error = ipfw_dump_table_v1(ch, sd);
1058                 break;
1059         default:
1060                 error = ENOTSUP;
1061         }
1062
1063         return (error);
1064 }
1065
1066 /*
1067  * Dumps all table data
1068  * Data layout (v1)(current):
1069  * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
1070  * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
1071  *
1072  * Returns 0 on success
1073  */
1074 static int
1075 ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd)
1076 {
1077         struct _ipfw_obj_header *oh;
1078         ipfw_xtable_info *i;
1079         struct tid_info ti;
1080         struct table_config *tc;
1081         struct table_algo *ta;
1082         struct dump_args da;
1083         uint32_t sz;
1084
1085         sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
1086         oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
1087         if (oh == NULL)
1088                 return (EINVAL);
1089
1090         i = (ipfw_xtable_info *)(oh + 1);
1091         objheader_to_ti(oh, &ti);
1092
1093         IPFW_UH_RLOCK(ch);
1094         if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
1095                 IPFW_UH_RUNLOCK(ch);
1096                 return (ESRCH);
1097         }
1098         export_table_info(ch, tc, i);
1099         sz = tc->count;
1100
1101         if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) {
1102
1103                 /*
1104                  * Submitted buffer size is not enough.
1105                  * WE've already filled in @i structure with
1106                  * relevant table info including size, so we
1107                  * can return. Buffer will be flushed automatically.
1108                  */
1109                 IPFW_UH_RUNLOCK(ch);
1110                 return (ENOMEM);
1111         }
1112
1113         /*
1114          * Do the actual dump in eXtended format
1115          */
1116         memset(&da, 0, sizeof(da));
1117         da.ti = KIDX_TO_TI(ch, tc->no.kidx);
1118         da.tc = tc;
1119         da.sd = sd;
1120
1121         ta = tc->ta;
1122
1123         ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
1124         IPFW_UH_RUNLOCK(ch);
1125
1126         return (da.error);
1127 }
1128
1129 /*
1130  * Dumps all table data
1131  * Data layout (version 0)(legacy):
1132  * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
1133  * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
1134  *
1135  * Returns 0 on success
1136  */
1137 static int
1138 ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd)
1139 {
1140         ipfw_xtable *xtbl;
1141         struct tid_info ti;
1142         struct table_config *tc;
1143         struct table_algo *ta;
1144         struct dump_args da;
1145         size_t sz;
1146
1147         xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
1148         if (xtbl == NULL)
1149                 return (EINVAL);
1150
1151         memset(&ti, 0, sizeof(ti));
1152         ti.uidx = xtbl->tbl;
1153         
1154         IPFW_UH_RLOCK(ch);
1155         if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
1156                 IPFW_UH_RUNLOCK(ch);
1157                 return (0);
1158         }
1159         sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
1160
1161         xtbl->cnt = tc->count;
1162         xtbl->size = sz;
1163         xtbl->type = tc->no.type;
1164         xtbl->tbl = ti.uidx;
1165
1166         if (sd->valsize < sz) {
1167
1168                 /*
1169                  * Submitted buffer size is not enough.
1170                  * WE've already filled in @i structure with
1171                  * relevant table info including size, so we
1172                  * can return. Buffer will be flushed automatically.
1173                  */
1174                 IPFW_UH_RUNLOCK(ch);
1175                 return (ENOMEM);
1176         }
1177
1178         /* Do the actual dump in eXtended format */
1179         memset(&da, 0, sizeof(da));
1180         da.ti = KIDX_TO_TI(ch, tc->no.kidx);
1181         da.tc = tc;
1182         da.sd = sd;
1183
1184         ta = tc->ta;
1185
1186         ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
1187         IPFW_UH_RUNLOCK(ch);
1188
1189         return (0);
1190 }
1191
1192 /*
1193  * Creates new table.
1194  * Data layout (v0)(current):
1195  * Request: [ ipfw_obj_header ipfw_xtable_info ]
1196  *
1197  * Returns 0 on success
1198  */
1199 int
1200 ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1201     struct sockopt_data *sd)
1202 {
1203         struct _ipfw_obj_header *oh;
1204         ipfw_xtable_info *i;
1205         char *tname, *aname;
1206         struct tid_info ti;
1207         struct namedobj_instance *ni;
1208         struct table_config *tc;
1209
1210         if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
1211                 return (EINVAL);
1212
1213         oh = (struct _ipfw_obj_header *)sd->kbuf;
1214         i = (ipfw_xtable_info *)(oh + 1);
1215
1216         /*
1217          * Verify user-supplied strings.
1218          * Check for null-terminated/zero-length strings/
1219          */
1220         tname = oh->ntlv.name;
1221         aname = i->algoname;
1222         if (ipfw_check_table_name(tname) != 0 ||
1223             strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname))
1224                 return (EINVAL);
1225
1226         if (aname[0] == '\0') {
1227                 /* Use default algorithm */
1228                 aname = NULL;
1229         }
1230
1231         objheader_to_ti(oh, &ti);
1232         ti.type = i->type;
1233
1234         ni = CHAIN_TO_NI(ch);
1235
1236         IPFW_UH_RLOCK(ch);
1237         if ((tc = find_table(ni, &ti)) != NULL) {
1238                 IPFW_UH_RUNLOCK(ch);
1239                 return (EEXIST);
1240         }
1241         IPFW_UH_RUNLOCK(ch);
1242
1243         return (create_table_internal(ch, &ti, aname, i));
1244 }
1245
1246 /*
1247  * Creates new table based on @ti and @aname.
1248  *
1249  * Relies on table name checking inside find_name_tlv()
1250  * Assume @aname to be checked and valid.
1251  *
1252  * Returns 0 on success.
1253  */
1254 static int
1255 create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
1256     char *aname, ipfw_xtable_info *i)
1257 {
1258         struct namedobj_instance *ni;
1259         struct table_config *tc;
1260         struct table_algo *ta;
1261         uint16_t kidx;
1262
1263         ni = CHAIN_TO_NI(ch);
1264
1265         ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname);
1266         if (ta == NULL)
1267                 return (ENOTSUP);
1268
1269         tc = alloc_table_config(ch, ti, ta, aname, i->tflags, i->vtype);
1270         if (tc == NULL)
1271                 return (ENOMEM);
1272
1273         tc->limit = i->limit;
1274
1275         IPFW_UH_WLOCK(ch);
1276
1277         /* Check if table has been already created */
1278         if (find_table(ni, ti) != NULL) {
1279                 IPFW_UH_WUNLOCK(ch);
1280                 free_table_config(ni, tc);
1281                 return (EEXIST);
1282         }
1283
1284         if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
1285                 IPFW_UH_WUNLOCK(ch);
1286                 printf("Unable to allocate table index."
1287                     " Consider increasing net.inet.ip.fw.tables_max");
1288                 free_table_config(ni, tc);
1289                 return (EBUSY);
1290         }
1291
1292         tc->no.kidx = kidx;
1293
1294         IPFW_WLOCK(ch);
1295         link_table(ch, tc);
1296         IPFW_WUNLOCK(ch);
1297
1298         IPFW_UH_WUNLOCK(ch);
1299
1300         return (0);
1301 }
1302
1303 void
1304 objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
1305 {
1306
1307         memset(ti, 0, sizeof(struct tid_info));
1308         ti->set = oh->ntlv.set;
1309         ti->uidx = oh->idx;
1310         ti->tlvs = &oh->ntlv;
1311         ti->tlen = oh->ntlv.head.length;
1312 }
1313
1314 int
1315 ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
1316     struct sockopt_data *sd)
1317 {
1318         struct namedobj_instance *ni;
1319         struct named_object *no;
1320         ipfw_obj_ntlv *ntlv;
1321
1322         ni = CHAIN_TO_NI(ch);
1323
1324         no = ipfw_objhash_lookup_kidx(ni, kidx);
1325         KASSERT(no != NULL, ("invalid table kidx passed"));
1326
1327         ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
1328         if (ntlv == NULL)
1329                 return (ENOMEM);
1330
1331         ntlv->head.type = IPFW_TLV_TBL_NAME;
1332         ntlv->head.length = sizeof(*ntlv);
1333         ntlv->idx = no->kidx;
1334         strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
1335
1336         return (0);
1337 }
1338
1339 static void
1340 export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
1341     ipfw_xtable_info *i)
1342 {
1343         struct table_info *ti;
1344         struct table_algo *ta;
1345         
1346         i->type = tc->no.type;
1347         i->tflags = tc->tflags;
1348         i->vtype = tc->vtype;
1349         i->set = tc->no.set;
1350         i->kidx = tc->no.kidx;
1351         i->refcnt = tc->no.refcnt;
1352         i->count = tc->count;
1353         i->limit = tc->limit;
1354         i->size = tc->count * sizeof(ipfw_obj_tentry);
1355         i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
1356         strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
1357         ti = KIDX_TO_TI(ch, tc->no.kidx);
1358         ta = tc->ta;
1359         if (ta->print_config != NULL) {
1360                 /* Use algo function to print table config to string */
1361                 ta->print_config(tc->astate, ti, i->algoname,
1362                     sizeof(i->algoname));
1363         } else
1364                 strlcpy(i->algoname, ta->name, sizeof(i->algoname));
1365         /* Dump algo-specific data, if possible */
1366         if (ta->dump_tinfo != NULL) {
1367                 ta->dump_tinfo(tc->astate, ti, &i->ta_info);
1368                 i->ta_info.flags |= IPFW_TATFLAGS_DATA;
1369         }
1370 }
1371
1372 struct dump_table_args {
1373         struct ip_fw_chain *ch;
1374         struct sockopt_data *sd;
1375 };
1376
1377 static void
1378 export_table_internal(struct namedobj_instance *ni, struct named_object *no,
1379     void *arg)
1380 {
1381         ipfw_xtable_info *i;
1382         struct dump_table_args *dta;
1383
1384         dta = (struct dump_table_args *)arg;
1385
1386         i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i));
1387         KASSERT(i != 0, ("previously checked buffer is not enough"));
1388
1389         export_table_info(dta->ch, (struct table_config *)no, i);
1390 }
1391
1392 /*
1393  * Export all tables as ipfw_xtable_info structures to
1394  * storage provided by @sd.
1395  * Returns 0 on success.
1396  */
1397 static int
1398 export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
1399     struct sockopt_data *sd)
1400 {
1401         uint32_t size;
1402         uint32_t count;
1403         struct dump_table_args dta;
1404
1405         count = ipfw_objhash_count(CHAIN_TO_NI(ch));
1406         size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader);
1407
1408         /* Fill in header regadless of buffer size */
1409         olh->count = count;
1410         olh->objsize = sizeof(ipfw_xtable_info);
1411
1412         if (size > olh->size) {
1413                 olh->size = size;
1414                 return (ENOMEM);
1415         }
1416
1417         olh->size = size;
1418
1419         dta.ch = ch;
1420         dta.sd = sd;
1421
1422         ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta);
1423
1424         return (0);
1425 }
1426
1427 /*
1428  * Legacy IP_FW_TABLE_GETSIZE handler
1429  */
1430 int
1431 ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
1432 {
1433         struct table_config *tc;
1434
1435         if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
1436                 return (ESRCH);
1437         *cnt = tc->count;
1438         return (0);
1439 }
1440
1441
1442 /*
1443  * Legacy IP_FW_TABLE_XGETSIZE handler
1444  */
1445 int
1446 ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
1447 {
1448         struct table_config *tc;
1449
1450         if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
1451                 *cnt = 0;
1452                 return (0); /* 'table all list' requires success */
1453         }
1454         *cnt = tc->count * sizeof(ipfw_table_xentry);
1455         if (tc->count > 0)
1456                 *cnt += sizeof(ipfw_xtable);
1457         return (0);
1458 }
1459
1460 static int
1461 dump_table_entry(void *e, void *arg)
1462 {
1463         struct dump_args *da;
1464         struct table_config *tc;
1465         struct table_algo *ta;
1466         ipfw_table_entry *ent;
1467         int error;
1468
1469         da = (struct dump_args *)arg;
1470
1471         tc = da->tc;
1472         ta = tc->ta;
1473
1474         /* Out of memory, returning */
1475         if (da->cnt == da->size)
1476                 return (1);
1477         ent = da->ent++;
1478         ent->tbl = da->uidx;
1479         da->cnt++;
1480
1481         error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
1482         if (error != 0)
1483                 return (error);
1484
1485         ent->addr = da->tent.k.addr.s_addr;
1486         ent->masklen = da->tent.masklen;
1487         ent->value = da->tent.value;
1488
1489         return (0);
1490 }
1491
1492 /*
1493  * Dumps table in pre-8.1 legacy format.
1494  */
1495 int
1496 ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
1497     ipfw_table *tbl)
1498 {
1499         struct table_config *tc;
1500         struct table_algo *ta;
1501         struct dump_args da;
1502
1503         tbl->cnt = 0;
1504
1505         if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
1506                 return (0);     /* XXX: We should return ESRCH */
1507
1508         ta = tc->ta;
1509
1510         /* This dump format supports IPv4 only */
1511         if (tc->no.type != IPFW_TABLE_CIDR)
1512                 return (0);
1513
1514         memset(&da, 0, sizeof(da));
1515         da.ti = KIDX_TO_TI(ch, tc->no.kidx);
1516         da.tc = tc;
1517         da.ent = &tbl->ent[0];
1518         da.size = tbl->size;
1519
1520         tbl->cnt = 0;
1521         ta->foreach(tc->astate, da.ti, dump_table_entry, &da);
1522         tbl->cnt = da.cnt;
1523
1524         return (0);
1525 }
1526
1527 /*
1528  * Dumps table entry in eXtended format (v1)(current).
1529  */
1530 static int
1531 dump_table_tentry(void *e, void *arg)
1532 {
1533         struct dump_args *da;
1534         struct table_config *tc;
1535         struct table_algo *ta;
1536         ipfw_obj_tentry *tent;
1537
1538         da = (struct dump_args *)arg;
1539
1540         tc = da->tc;
1541         ta = tc->ta;
1542
1543         tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent));
1544         /* Out of memory, returning */
1545         if (tent == NULL) {
1546                 da->error = ENOMEM;
1547                 return (1);
1548         }
1549         tent->head.length = sizeof(ipfw_obj_tentry);
1550         tent->idx = da->uidx;
1551
1552         return (ta->dump_tentry(tc->astate, da->ti, e, tent));
1553 }
1554
1555 /*
1556  * Dumps table entry in eXtended format (v0).
1557  */
1558 static int
1559 dump_table_xentry(void *e, void *arg)
1560 {
1561         struct dump_args *da;
1562         struct table_config *tc;
1563         struct table_algo *ta;
1564         ipfw_table_xentry *xent;
1565         ipfw_obj_tentry *tent;
1566         int error;
1567
1568         da = (struct dump_args *)arg;
1569
1570         tc = da->tc;
1571         ta = tc->ta;
1572
1573         xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent));
1574         /* Out of memory, returning */
1575         if (xent == NULL)
1576                 return (1);
1577         xent->len = sizeof(ipfw_table_xentry);
1578         xent->tbl = da->uidx;
1579
1580         memset(&da->tent, 0, sizeof(da->tent));
1581         tent = &da->tent;
1582         error = ta->dump_tentry(tc->astate, da->ti, e, tent);
1583         if (error != 0)
1584                 return (error);
1585
1586         /* Convert current format to previous one */
1587         xent->masklen = tent->masklen;
1588         xent->value = tent->value;
1589         /* Apply some hacks */
1590         if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) {
1591                 xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
1592                 xent->flags = IPFW_TCF_INET;
1593         } else
1594                 memcpy(&xent->k, &tent->k, sizeof(xent->k));
1595
1596         return (0);
1597 }
1598
1599 /*
1600  * Table algorithms
1601  */ 
1602
1603 /*
1604  * Finds algoritm by index, table type or supplied name
1605  */
1606 static struct table_algo *
1607 find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name)
1608 {
1609         int i, l;
1610         struct table_algo *ta;
1611
1612         if (ti->type > IPFW_TABLE_MAXTYPE)
1613                 return (NULL);
1614
1615         /* Search by index */
1616         if (ti->atype != 0) {
1617                 if (ti->atype > tcfg->algo_count)
1618                         return (NULL);
1619                 return (tcfg->algo[ti->atype]);
1620         }
1621
1622         /* Search by name if supplied */
1623         if (name != NULL) {
1624                 /* TODO: better search */
1625                 for (i = 1; i <= tcfg->algo_count; i++) {
1626                         ta = tcfg->algo[i];
1627
1628                         /*
1629                          * One can supply additional algorithm
1630                          * parameters so we compare only the first word
1631                          * of supplied name:
1632                          * 'hash_cidr hsize=32'
1633                          * '^^^^^^^^^'
1634                          *
1635                          */
1636                         l = strlen(ta->name);
1637                         if (strncmp(name, ta->name, l) == 0) {
1638                                 if (name[l] == '\0' || name[l] == ' ')
1639                                         return (ta);
1640                         }
1641                 }
1642
1643                 return (NULL);
1644         }
1645
1646         /* Return default algorithm for given type if set */
1647         return (tcfg->def_algo[ti->type]);
1648 }
1649
1650 /*
1651  * Register new table algo @ta.
1652  * Stores algo id iside @idx.<F2>
1653  *
1654  * Returns 0 on success.
1655  */
1656 int
1657 ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size,
1658     int *idx)
1659 {
1660         struct tables_config *tcfg;
1661         struct table_algo *ta_new;
1662         size_t sz;
1663
1664         if (size > sizeof(struct table_algo))
1665                 return (EINVAL);
1666
1667         /* Check for the required on-stack size for add/del */
1668         sz = roundup2(ta->ta_buf_size, sizeof(void *));
1669         if (sz > TA_BUF_SZ)
1670                 return (EINVAL);
1671
1672         KASSERT(ta->type >= IPFW_TABLE_MAXTYPE,("Increase IPFW_TABLE_MAXTYPE"));
1673
1674         ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO);
1675         memcpy(ta_new, ta, size);
1676
1677         tcfg = CHAIN_TO_TCFG(ch);
1678
1679         KASSERT(tcfg->algo_count < 255, ("Increase algo array size"));
1680
1681         tcfg->algo[++tcfg->algo_count] = ta_new;
1682         ta_new->idx = tcfg->algo_count;
1683
1684         /* Set algorithm as default one for given type */
1685         if ((ta_new->flags & TA_FLAG_DEFAULT) != 0 &&
1686             tcfg->def_algo[ta_new->type] == NULL)
1687                 tcfg->def_algo[ta_new->type] = ta_new;
1688
1689         *idx = ta_new->idx;
1690         
1691         return (0);
1692 }
1693
1694 /*
1695  * Unregisters table algo using @idx as id.
1696  */
1697 void
1698 ipfw_del_table_algo(struct ip_fw_chain *ch, int idx)
1699 {
1700         struct tables_config *tcfg;
1701         struct table_algo *ta;
1702
1703         tcfg = CHAIN_TO_TCFG(ch);
1704
1705         KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of range 1..%d",
1706             idx, tcfg->algo_count));
1707
1708         ta = tcfg->algo[idx];
1709         KASSERT(ta != NULL, ("algo idx %d is NULL", idx));
1710
1711         if (tcfg->def_algo[ta->type] == ta)
1712                 tcfg->def_algo[ta->type] = NULL;
1713
1714         free(ta, M_IPFW);
1715 }
1716
1717 /*
1718  * Lists all table algorithms currently available.
1719  * Data layout (v0)(current):
1720  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
1721  * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ]
1722  *
1723  * Returns 0 on success
1724  */
1725 int
1726 ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd)
1727 {
1728         struct _ipfw_obj_lheader *olh;
1729         struct tables_config *tcfg;
1730         ipfw_ta_info *i;
1731         struct table_algo *ta;
1732         uint32_t count, n, size;
1733
1734         olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
1735         if (olh == NULL)
1736                 return (EINVAL);
1737         if (sd->valsize < olh->size)
1738                 return (EINVAL);
1739
1740         IPFW_UH_RLOCK(ch);
1741         tcfg = CHAIN_TO_TCFG(ch);
1742         count = tcfg->algo_count;
1743         size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader);
1744
1745         /* Fill in header regadless of buffer size */
1746         olh->count = count;
1747         olh->objsize = sizeof(ipfw_ta_info);
1748
1749         if (size > olh->size) {
1750                 olh->size = size;
1751                 IPFW_UH_RUNLOCK(ch);
1752                 return (ENOMEM);
1753         }
1754         olh->size = size;
1755
1756         for (n = 1; n <= count; n++) {
1757                 i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i));
1758                 KASSERT(i != 0, ("previously checked buffer is not enough"));
1759                 ta = tcfg->algo[n];
1760                 strlcpy(i->algoname, ta->name, sizeof(i->algoname));
1761                 i->type = ta->type;
1762                 i->refcnt = ta->refcnt;
1763         }
1764
1765         IPFW_UH_RUNLOCK(ch);
1766
1767         return (0);
1768 }
1769
1770
1771 /*
1772  * Tables rewriting code 
1773  *
1774  */
1775
1776 /*
1777  * Determine table number and lookup type for @cmd.
1778  * Fill @tbl and @type with appropriate values.
1779  * Returns 0 for relevant opcodes, 1 otherwise.
1780  */
1781 static int
1782 classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
1783 {
1784         ipfw_insn_if *cmdif;
1785         int skip;
1786         uint16_t v;
1787
1788         skip = 1;
1789
1790         switch (cmd->opcode) {
1791         case O_IP_SRC_LOOKUP:
1792         case O_IP_DST_LOOKUP:
1793                 /* Basic IPv4/IPv6 or u32 lookups */
1794                 *puidx = cmd->arg1;
1795                 /* Assume CIDR by default */
1796                 *ptype = IPFW_TABLE_CIDR;
1797                 skip = 0;
1798                 
1799                 if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) {
1800                         /*
1801                          * generic lookup. The key must be
1802                          * in 32bit big-endian format.
1803                          */
1804                         v = ((ipfw_insn_u32 *)cmd)->d[1];
1805                         switch (v) {
1806                         case 0:
1807                         case 1:
1808                                 /* IPv4 src/dst */
1809                                 break;
1810                         case 2:
1811                         case 3:
1812                                 /* src/dst port */
1813                                 *ptype = IPFW_TABLE_NUMBER;
1814                                 break;
1815                         case 4:
1816                                 /* uid/gid */
1817                                 *ptype = IPFW_TABLE_NUMBER;
1818                                 break;
1819                         case 5:
1820                                 /* jid */
1821                                 *ptype = IPFW_TABLE_NUMBER;
1822                                 break;
1823                         case 6:
1824                                 /* dscp */
1825                                 *ptype = IPFW_TABLE_NUMBER;
1826                                 break;
1827                         }
1828                 }
1829                 break;
1830         case O_XMIT:
1831         case O_RECV:
1832         case O_VIA:
1833                 /* Interface table, possibly */
1834                 cmdif = (ipfw_insn_if *)cmd;
1835                 if (cmdif->name[0] != '\1')
1836                         break;
1837
1838                 *ptype = IPFW_TABLE_INTERFACE;
1839                 *puidx = cmdif->p.glob;
1840                 skip = 0;
1841                 break;
1842         case O_IP_FLOW_LOOKUP:
1843                 *puidx = cmd->arg1;
1844                 *ptype = IPFW_TABLE_FLOW;
1845                 skip = 0;
1846                 break;
1847         }
1848
1849         return (skip);
1850 }
1851
1852 /*
1853  * Sets new table value for given opcode.
1854  * Assume the same opcodes as classify_table_opcode()
1855  */
1856 static void
1857 update_table_opcode(ipfw_insn *cmd, uint16_t idx)
1858 {
1859         ipfw_insn_if *cmdif;
1860
1861         switch (cmd->opcode) {
1862         case O_IP_SRC_LOOKUP:
1863         case O_IP_DST_LOOKUP:
1864                 /* Basic IPv4/IPv6 or u32 lookups */
1865                 cmd->arg1 = idx;
1866                 break;
1867         case O_XMIT:
1868         case O_RECV:
1869         case O_VIA:
1870                 /* Interface table, possibly */
1871                 cmdif = (ipfw_insn_if *)cmd;
1872                 cmdif->p.glob = idx;
1873                 break;
1874         case O_IP_FLOW_LOOKUP:
1875                 cmd->arg1 = idx;
1876                 break;
1877         }
1878 }
1879
1880 /*
1881  * Checks table name for validity.
1882  * Enforce basic length checks, the rest
1883  * should be done in userland.
1884  *
1885  * Returns 0 if name is considered valid.
1886  */
1887 int
1888 ipfw_check_table_name(char *name)
1889 {
1890         int nsize;
1891         ipfw_obj_ntlv *ntlv = NULL;
1892
1893         nsize = sizeof(ntlv->name);
1894
1895         if (strnlen(name, nsize) == nsize)
1896                 return (EINVAL);
1897
1898         if (name[0] == '\0')
1899                 return (EINVAL);
1900
1901         /*
1902          * TODO: do some more complicated checks
1903          */
1904
1905         return (0);
1906 }
1907
1908 /*
1909  * Find tablename TLV by @uid.
1910  * Check @tlvs for valid data inside.
1911  *
1912  * Returns pointer to found TLV or NULL.
1913  */
1914 static ipfw_obj_ntlv *
1915 find_name_tlv(void *tlvs, int len, uint16_t uidx)
1916 {
1917         ipfw_obj_ntlv *ntlv;
1918         uintptr_t pa, pe;
1919         int l;
1920
1921         pa = (uintptr_t)tlvs;
1922         pe = pa + len;
1923         l = 0;
1924         for (; pa < pe; pa += l) {
1925                 ntlv = (ipfw_obj_ntlv *)pa;
1926                 l = ntlv->head.length;
1927
1928                 if (l != sizeof(*ntlv))
1929                         return (NULL);
1930
1931                 if (ntlv->head.type != IPFW_TLV_TBL_NAME)
1932                         continue;
1933
1934                 if (ntlv->idx != uidx)
1935                         continue;
1936
1937                 if (ipfw_check_table_name(ntlv->name) != 0)
1938                         return (NULL);
1939                 
1940                 return (ntlv);
1941         }
1942
1943         return (NULL);
1944 }
1945
1946 /*
1947  * Finds table config based on either legacy index
1948  * or name in ntlv.
1949  * Note @ti structure contains unchecked data from userland.
1950  *
1951  * Returns pointer to table_config or NULL.
1952  */
1953 static struct table_config *
1954 find_table(struct namedobj_instance *ni, struct tid_info *ti)
1955 {
1956         char *name, bname[16];
1957         struct named_object *no;
1958         ipfw_obj_ntlv *ntlv;
1959         uint32_t set;
1960
1961         if (ti->tlvs != NULL) {
1962                 ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
1963                 if (ntlv == NULL)
1964                         return (NULL);
1965                 name = ntlv->name;
1966                 set = ntlv->set;
1967         } else {
1968                 snprintf(bname, sizeof(bname), "%d", ti->uidx);
1969                 name = bname;
1970                 set = 0;
1971         }
1972
1973         no = ipfw_objhash_lookup_name(ni, set, name);
1974
1975         return ((struct table_config *)no);
1976 }
1977
1978 static struct table_config *
1979 alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti,
1980     struct table_algo *ta, char *aname, uint8_t tflags, uint8_t vtype)
1981 {
1982         char *name, bname[16];
1983         struct table_config *tc;
1984         int error;
1985         ipfw_obj_ntlv *ntlv;
1986         uint32_t set;
1987
1988         if (ti->tlvs != NULL) {
1989                 ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
1990                 if (ntlv == NULL)
1991                         return (NULL);
1992                 name = ntlv->name;
1993                 set = ntlv->set;
1994         } else {
1995                 snprintf(bname, sizeof(bname), "%d", ti->uidx);
1996                 name = bname;
1997                 set = 0;
1998         }
1999
2000         tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO);
2001         tc->no.name = tc->tablename;
2002         tc->no.type = ti->type;
2003         tc->no.set = set;
2004         tc->tflags = tflags;
2005         tc->ta = ta;
2006         strlcpy(tc->tablename, name, sizeof(tc->tablename));
2007         /* Set default value type to u32 for compability reasons */
2008         if (vtype == 0)
2009                 tc->vtype = IPFW_VTYPE_U32;
2010         else
2011                 tc->vtype = vtype;
2012
2013         if (ti->tlvs == NULL) {
2014                 tc->no.compat = 1;
2015                 tc->no.uidx = ti->uidx;
2016         }
2017
2018         /* Preallocate data structures for new tables */
2019         error = ta->init(ch, &tc->astate, &tc->ti, aname, tflags);
2020         if (error != 0) {
2021                 free(tc, M_IPFW);
2022                 return (NULL);
2023         }
2024         
2025         return (tc);
2026 }
2027
2028 static void
2029 free_table_config(struct namedobj_instance *ni, struct table_config *tc)
2030 {
2031
2032         if (tc->linked == 0)
2033                 tc->ta->destroy(tc->astate, &tc->ti);
2034
2035         free(tc, M_IPFW);
2036 }
2037
2038 /*
2039  * Links @tc to @chain table named instance.
2040  * Sets appropriate type/states in @chain table info.
2041  */
2042 static void
2043 link_table(struct ip_fw_chain *ch, struct table_config *tc)
2044 {
2045         struct namedobj_instance *ni;
2046         struct table_info *ti;
2047         uint16_t kidx;
2048
2049         IPFW_UH_WLOCK_ASSERT(ch);
2050         IPFW_WLOCK_ASSERT(ch);
2051
2052         ni = CHAIN_TO_NI(ch);
2053         kidx = tc->no.kidx;
2054
2055         ipfw_objhash_add(ni, &tc->no);
2056
2057         ti = KIDX_TO_TI(ch, kidx);
2058         *ti = tc->ti;
2059
2060         /* Notify algo on real @ti address */
2061         if (tc->ta->change_ti != NULL)
2062                 tc->ta->change_ti(tc->astate, ti);
2063
2064         tc->linked = 1;
2065         tc->ta->refcnt++;
2066 }
2067
2068 /*
2069  * Unlinks @tc from @chain table named instance.
2070  * Zeroes states in @chain and stores them in @tc.
2071  */
2072 static void
2073 unlink_table(struct ip_fw_chain *ch, struct table_config *tc)
2074 {
2075         struct namedobj_instance *ni;
2076         struct table_info *ti;
2077         uint16_t kidx;
2078
2079         IPFW_UH_WLOCK_ASSERT(ch);
2080         IPFW_WLOCK_ASSERT(ch);
2081
2082         ni = CHAIN_TO_NI(ch);
2083         kidx = tc->no.kidx;
2084
2085         /* Clear state. @ti copy is already saved inside @tc */
2086         ipfw_objhash_del(ni, &tc->no);
2087         ti = KIDX_TO_TI(ch, kidx);
2088         memset(ti, 0, sizeof(struct table_info));
2089         tc->linked = 0;
2090         tc->ta->refcnt--;
2091
2092         /* Notify algo on real @ti address */
2093         if (tc->ta->change_ti != NULL)
2094                 tc->ta->change_ti(tc->astate, NULL);
2095 }
2096
2097 /*
2098  * Finds named object by @uidx number.
2099  * Refs found object, allocate new index for non-existing object.
2100  * Fills in @oib with userland/kernel indexes.
2101  * First free oidx pointer is saved back in @oib.
2102  *
2103  * Returns 0 on success.
2104  */
2105 static int
2106 bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule,
2107     struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
2108 {
2109         struct table_config *tc;
2110         struct namedobj_instance *ni;
2111         struct named_object *no;
2112         int error, l, cmdlen;
2113         ipfw_insn *cmd;
2114         struct obj_idx *pidx, *p;
2115
2116         pidx = *oib;
2117         l = rule->cmd_len;
2118         cmd = rule->cmd;
2119         cmdlen = 0;
2120         error = 0;
2121
2122         IPFW_UH_WLOCK(ch);
2123         ni = CHAIN_TO_NI(ch);
2124
2125         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2126                 cmdlen = F_LEN(cmd);
2127
2128                 if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
2129                         continue;
2130
2131                 pidx->uidx = ti->uidx;
2132                 pidx->type = ti->type;
2133
2134                 if ((tc = find_table(ni, ti)) != NULL) {
2135                         if (tc->no.type != ti->type) {
2136                                 /* Incompatible types */
2137                                 error = EINVAL;
2138                                 break;
2139                         }
2140
2141                         /* Reference found table and save kidx */
2142                         tc->no.refcnt++;
2143                         pidx->kidx = tc->no.kidx;
2144                         pidx++;
2145                         continue;
2146                 }
2147
2148                 /* Table not found. Allocate new index and save for later */
2149                 if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) {
2150                         printf("Unable to allocate table %s index in set %u."
2151                             " Consider increasing net.inet.ip.fw.tables_max",
2152                             "", ti->set);
2153                         error = EBUSY;
2154                         break;
2155                 }
2156
2157                 ci->new_tables++;
2158                 pidx->new = 1;
2159                 pidx++;
2160         }
2161
2162         if (error != 0) {
2163                 /* Unref everything we have already done */
2164                 for (p = *oib; p < pidx; p++) {
2165                         if (p->new != 0) {
2166                                 ipfw_objhash_free_idx(ni, p->kidx);
2167                                 continue;
2168                         }
2169
2170                         /* Find & unref by existing idx */
2171                         no = ipfw_objhash_lookup_kidx(ni, p->kidx);
2172                         KASSERT(no != NULL, ("Ref'd table %d disappeared",
2173                             p->kidx));
2174
2175                         no->refcnt--;
2176                 }
2177         }
2178         IPFW_UH_WUNLOCK(ch);
2179
2180         *oib = pidx;
2181
2182         return (error);
2183 }
2184
2185 /*
2186  * Compatibility function for old ipfw(8) binaries.
2187  * Rewrites table kernel indices with userland ones.
2188  * Works for \d+ talbes only (e.g. for tables, converted
2189  * from old numbered system calls).
2190  *
2191  * Returns 0 on success.
2192  * Raises error on any other tables.
2193  */
2194 int
2195 ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule)
2196 {
2197         int cmdlen, error, l;
2198         ipfw_insn *cmd;
2199         uint16_t kidx, uidx;
2200         uint8_t type;
2201         struct named_object *no;
2202         struct namedobj_instance *ni;
2203
2204         ni = CHAIN_TO_NI(chain);
2205         error = 0;
2206
2207         l = rule->cmd_len;
2208         cmd = rule->cmd;
2209         cmdlen = 0;
2210         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2211                 cmdlen = F_LEN(cmd);
2212
2213                 if (classify_table_opcode(cmd, &kidx, &type) != 0)
2214                         continue;
2215
2216                 if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL)
2217                         return (1);
2218
2219                 uidx = no->uidx;
2220                 if (no->compat == 0) {
2221
2222                         /*
2223                          * We are called via legacy opcode.
2224                          * Save error and show table as fake number
2225                          * not to make ipfw(8) hang.
2226                          */
2227                         uidx = 65535;
2228                         error = 2;
2229                 }
2230
2231                 update_table_opcode(cmd, uidx);
2232         }
2233
2234         return (error);
2235 }
2236
2237 /*
2238  * Sets every table kidx in @bmask which is used in rule @rule.
2239  * 
2240  * Returns number of newly-referenced tables.
2241  */
2242 int
2243 ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
2244     uint32_t *bmask)
2245 {
2246         int cmdlen, l, count;
2247         ipfw_insn *cmd;
2248         uint16_t kidx;
2249         uint8_t type;
2250
2251         l = rule->cmd_len;
2252         cmd = rule->cmd;
2253         cmdlen = 0;
2254         count = 0;
2255         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2256                 cmdlen = F_LEN(cmd);
2257
2258                 if (classify_table_opcode(cmd, &kidx, &type) != 0)
2259                         continue;
2260
2261                 if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
2262                         count++;
2263
2264                 bmask[kidx / 32] |= 1 << (kidx % 32);
2265         }
2266
2267         return (count);
2268 }
2269
2270
2271
2272 /*
2273  * Checks is opcode is referencing table of appropriate type.
2274  * Adds reference count for found table if true.
2275  * Rewrites user-supplied opcode values with kernel ones.
2276  *
2277  * Returns 0 on success and appropriate error code otherwise.
2278  */
2279 int
2280 ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
2281     struct rule_check_info *ci)
2282 {
2283         int cmdlen, error, ftype, l;
2284         ipfw_insn *cmd;
2285         uint16_t uidx;
2286         uint8_t type;
2287         struct table_config *tc;
2288         struct table_algo *ta;
2289         struct namedobj_instance *ni;
2290         struct named_object *no, *no_n, *no_tmp;
2291         struct obj_idx *p, *pidx_first, *pidx_last;
2292         struct namedobjects_head nh;
2293         struct tid_info ti;
2294
2295         ni = CHAIN_TO_NI(chain);
2296
2297         /* Prepare queue to store configs */
2298         TAILQ_INIT(&nh);
2299
2300         /*
2301          * Prepare an array for storing opcode indices.
2302          * Use stack allocation by default.
2303          */
2304         if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
2305                 /* Stack */
2306                 pidx_first = ci->obuf;
2307         } else
2308                 pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx),
2309                     M_IPFW, M_WAITOK | M_ZERO);
2310
2311         pidx_last = pidx_first;
2312         error = 0;
2313
2314         type = 0;
2315         ftype = 0;
2316
2317         memset(&ti, 0, sizeof(ti));
2318
2319         /*
2320          * Use default set for looking up tables (old way) or
2321          * use set rule is assigned to (new way).
2322          */
2323         ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0;
2324         if (ci->ctlv != NULL) {
2325                 ti.tlvs = (void *)(ci->ctlv + 1);
2326                 ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
2327         }
2328
2329         /*
2330          * Stage 1: reference existing tables, determine number
2331          * of tables we need to allocate and allocate indexes for each.
2332          */
2333         error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti);
2334
2335         if (error != 0) {
2336                 if (pidx_first != ci->obuf)
2337                         free(pidx_first, M_IPFW);
2338
2339                 return (error);
2340         }
2341
2342         /*
2343          * Stage 2: allocate table configs for every non-existent table
2344          */
2345
2346         if (ci->new_tables > 0) {
2347                 for (p = pidx_first; p < pidx_last; p++) {
2348                         if (p->new == 0)
2349                                 continue;
2350
2351                         ti.uidx = p->uidx;
2352                         ti.type = p->type;
2353                         ti.atype = 0;
2354
2355                         ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL);
2356                         if (ta == NULL) {
2357                                 error = ENOTSUP;
2358                                 goto free;
2359                         }
2360                         tc = alloc_table_config(chain, &ti, ta, NULL, 0,
2361                             IPFW_VTYPE_U32);
2362
2363                         if (tc == NULL) {
2364                                 error = ENOMEM;
2365                                 goto free;
2366                         }
2367
2368                         tc->no.kidx = p->kidx;
2369                         tc->no.refcnt = 1;
2370
2371                         /* Add to list */
2372                         TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next);
2373                 }
2374
2375                 /*
2376                  * Stage 2.1: Check if we're going to create 2 tables
2377                  * with the same name, but different table types.
2378                  */
2379                 TAILQ_FOREACH(no, &nh, nn_next) {
2380                         TAILQ_FOREACH(no_tmp, &nh, nn_next) {
2381                                 if (ipfw_objhash_same_name(ni, no, no_tmp) == 0)
2382                                         continue;
2383                                 if (no->type != no_tmp->type) {
2384                                         error = EINVAL;
2385                                         goto free;
2386                                 }
2387                         }
2388                 }
2389         }
2390
2391         IPFW_UH_WLOCK(chain);
2392
2393         if (ci->new_tables > 0) {
2394                 /*
2395                  * Stage 3: link & reference new table configs
2396                  */
2397
2398
2399                 /*
2400                  * Step 3.1: Check if some tables we need to create have been
2401                  * already created with different table type.
2402                  */
2403
2404                 error = 0;
2405                 TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
2406                         no_n = ipfw_objhash_lookup_name(ni, no->set, no->name);
2407                         if (no_n == NULL)
2408                                 continue;
2409
2410                         if (no_n->type != no->type) {
2411                                 error = EINVAL;
2412                                 break;
2413                         }
2414
2415                 }
2416
2417                 if (error != 0) {
2418                         /*
2419                          * Someone has allocated table with different table type.
2420                          * We have to rollback everything.
2421                          */
2422                         IPFW_UH_WUNLOCK(chain);
2423                         goto free;
2424                 }
2425
2426                 /*
2427                  * Attach new tables.
2428                  * We need to set table pointers for each new table,
2429                  * so we have to acquire main WLOCK.
2430                  */
2431                 IPFW_WLOCK(chain);
2432                 TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
2433                         no_n = ipfw_objhash_lookup_name(ni, no->set, no->name);
2434
2435                         if (no_n == NULL) {
2436                                 /* New table. Attach to runtime hash */
2437                                 TAILQ_REMOVE(&nh, no, nn_next);
2438                                 link_table(chain, (struct table_config *)no);
2439                                 continue;
2440                         }
2441
2442                         /*
2443                          * Newly-allocated table with the same type.
2444                          * Reference it and update out @pidx array
2445                          * rewrite info.
2446                          */
2447                         no_n->refcnt++;
2448                         /* Keep oib array in sync: update kidx */
2449                         for (p = pidx_first; p < pidx_last; p++) {
2450                                 if (p->kidx != no->kidx)
2451                                         continue;
2452                                 /* Update kidx */
2453                                 p->kidx = no_n->kidx;
2454                                 break;
2455                         }
2456                 }
2457                 IPFW_WUNLOCK(chain);
2458         }
2459
2460         /* Perform rule rewrite */
2461         l = ci->krule->cmd_len;
2462         cmd = ci->krule->cmd;
2463         cmdlen = 0;
2464         p = pidx_first;
2465         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2466                 cmdlen = F_LEN(cmd);
2467
2468                 if (classify_table_opcode(cmd, &uidx, &type) != 0)
2469                         continue;
2470                 update_table_opcode(cmd, p->kidx);
2471                 p++;
2472         }
2473
2474         IPFW_UH_WUNLOCK(chain);
2475
2476         error = 0;
2477
2478         /*
2479          * Stage 4: free resources
2480          */
2481 free:
2482         if (!TAILQ_EMPTY(&nh)) {
2483                 /* Free indexes first */
2484                 IPFW_UH_WLOCK(chain);
2485                 TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) {
2486                         ipfw_objhash_free_idx(ni, no->kidx);
2487                 }
2488                 IPFW_UH_WUNLOCK(chain);
2489                 /* Free configs */
2490                 TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp)
2491                         free_table_config(ni, tc);
2492         }
2493
2494         if (pidx_first != ci->obuf)
2495                 free(pidx_first, M_IPFW);
2496
2497         return (error);
2498 }
2499
2500 /*
2501  * Remove references from every table used in @rule.
2502  */
2503 void
2504 ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule)
2505 {
2506         int cmdlen, l;
2507         ipfw_insn *cmd;
2508         struct namedobj_instance *ni;
2509         struct named_object *no;
2510         uint16_t kidx;
2511         uint8_t type;
2512
2513         ni = CHAIN_TO_NI(chain);
2514
2515         l = rule->cmd_len;
2516         cmd = rule->cmd;
2517         cmdlen = 0;
2518         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2519                 cmdlen = F_LEN(cmd);
2520
2521                 if (classify_table_opcode(cmd, &kidx, &type) != 0)
2522                         continue;
2523
2524                 no = ipfw_objhash_lookup_kidx(ni, kidx); 
2525
2526                 KASSERT(no != NULL, ("table id %d not found", kidx));
2527                 KASSERT(no->type == type, ("wrong type %d (%d) for table id %d",
2528                     no->type, type, kidx));
2529                 KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
2530                     kidx, no->refcnt));
2531
2532                 no->refcnt--;
2533         }
2534 }
2535
2536
2537 /*
2538  * Removes table bindings for every rule in rule chain @head.
2539  */
2540 void
2541 ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head)
2542 {
2543         struct ip_fw *rule;
2544
2545         while ((rule = head) != NULL) {
2546                 head = head->x_next;
2547                 ipfw_unbind_table_rule(chain, rule);
2548         }
2549 }
2550
2551
2552 /* end of file */