Deleted Added
full compact
ip_fw_table.c (266310) ip_fw_table.c (272840)
1/*-
2 * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
1/*-
2 * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.
3 * Copyright (c) 2014 Yandex LLC
4 * Copyright (c) 2014 Alexander V. Chernikov
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

--- 8 unchanged lines hidden (view full) ---

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>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the

--- 8 unchanged lines hidden (view full) ---

21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw_table.c 266310 2014-05-17 13:45:03Z melifaro $");
29__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw_table.c 272840 2014-10-09 19:32:35Z melifaro $");
28
29/*
30
31/*
30 * Lookup table support for ipfw
32 * Lookup table support for ipfw.
31 *
33 *
32 * Lookup tables are implemented (at the moment) using the radix
33 * tree used for routing tables. Tables store key-value entries, where
34 * keys are network prefixes (addr/masklen), and values are integers.
35 * As a degenerate case we can interpret keys as 32-bit integers
36 * (with a /32 mask).
34 * This file contains handlers for all generic tables' operations:
35 * add/del/flush entries, list/dump tables etc..
37 *
36 *
38 * The table is protected by the IPFW lock even for manipulation coming
39 * from userland, because operations are typically fast.
37 * Table data modification is protected by both UH and runtime lock
38 * while reading configuration/data is protected by UH lock.
39 *
40 * Lookup algorithms for all table types are located in ip_fw_table_algo.c
40 */
41
42#include "opt_ipfw.h"
41 */
42
43#include "opt_ipfw.h"
43#include "opt_inet.h"
44#ifndef INET
45#error IPFIREWALL requires INET.
46#endif /* INET */
47#include "opt_inet6.h"
48
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/malloc.h>
52#include <sys/kernel.h>
53#include <sys/lock.h>
54#include <sys/rwlock.h>
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/malloc.h>
48#include <sys/kernel.h>
49#include <sys/lock.h>
50#include <sys/rwlock.h>
51#include <sys/rmlock.h>
55#include <sys/socket.h>
52#include <sys/socket.h>
53#include <sys/socketvar.h>
56#include <sys/queue.h>
57#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
54#include <sys/queue.h>
55#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
58#include <net/radix.h>
59#include <net/route.h>
60#include <net/vnet.h>
61
62#include <netinet/in.h>
63#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
64#include <netinet/ip_fw.h>
65
66#include <netpfil/ipfw/ip_fw_private.h>
56
57#include <netinet/in.h>
58#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
59#include <netinet/ip_fw.h>
60
61#include <netpfil/ipfw/ip_fw_private.h>
62#include <netpfil/ipfw/ip_fw_table.h>
67
63
68#ifdef MAC
69#include <security/mac/mac_framework.h>
70#endif
64 /*
65 * Table has the following `type` concepts:
66 *
67 * `no.type` represents lookup key type (addr, ifp, uid, etc..)
68 * vmask represents bitmask of table values which are present at the moment.
69 * Special IPFW_VTYPE_LEGACY ( (uint32_t)-1 ) represents old
70 * single-value-for-all approach.
71 */
72struct table_config {
73 struct named_object no;
74 uint8_t tflags; /* type flags */
75 uint8_t locked; /* 1 if locked from changes */
76 uint8_t linked; /* 1 if already linked */
77 uint8_t ochanged; /* used by set swapping */
78 uint8_t vshared; /* 1 if using shared value array */
79 uint8_t spare[3];
80 uint32_t count; /* Number of records */
81 uint32_t limit; /* Max number of records */
82 uint32_t vmask; /* bitmask with supported values */
83 uint32_t ocount; /* used by set swapping */
84 uint64_t gencnt; /* generation count */
85 char tablename[64]; /* table name */
86 struct table_algo *ta; /* Callbacks for given algo */
87 void *astate; /* algorithm state */
88 struct table_info ti_copy; /* data to put to table_info */
89 struct namedobj_instance *vi;
90};
71
91
72static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
92static struct table_config *find_table(struct namedobj_instance *ni,
93 struct tid_info *ti);
94static struct table_config *alloc_table_config(struct ip_fw_chain *ch,
95 struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags);
96static void free_table_config(struct namedobj_instance *ni,
97 struct table_config *tc);
98static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
99 char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int ref);
100static void link_table(struct ip_fw_chain *ch, struct table_config *tc);
101static void unlink_table(struct ip_fw_chain *ch, struct table_config *tc);
102static int find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti,
103 struct tentry_info *tei, uint32_t count, int op, struct table_config **ptc);
104#define OP_ADD 1
105#define OP_DEL 0
106static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
107 struct sockopt_data *sd);
108static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
109 ipfw_xtable_info *i);
110static int dump_table_tentry(void *e, void *arg);
111static int dump_table_xentry(void *e, void *arg);
73
112
74struct table_entry {
75 struct radix_node rn[2];
76 struct sockaddr_in addr, mask;
77 u_int32_t value;
78};
113static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a,
114 struct tid_info *b);
79
115
80struct xaddr_iface {
81 uint8_t if_len; /* length of this struct */
82 uint8_t pad[7]; /* Align name */
83 char ifname[IF_NAMESIZE]; /* Interface name */
84};
116static int check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts,
117 struct table_config *tc, struct table_info *ti, uint32_t count);
118static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti);
85
119
86struct table_xentry {
87 struct radix_node rn[2];
88 union {
89#ifdef INET6
90 struct sockaddr_in6 addr6;
91#endif
92 struct xaddr_iface iface;
93 } a;
94 union {
95#ifdef INET6
96 struct sockaddr_in6 mask6;
97#endif
98 struct xaddr_iface ifmask;
99 } m;
100 u_int32_t value;
101};
120static struct table_algo *find_table_algo(struct tables_config *tableconf,
121 struct tid_info *ti, char *name);
102
122
123static void objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti);
124static void ntlv_to_ti(struct _ipfw_obj_ntlv *ntlv, struct tid_info *ti);
125static int classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype);
126
127#define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash)
128#define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k]))
129
130#define TA_BUF_SZ 128 /* On-stack buffer for add/delete state */
131
132void
133rollback_toperation_state(struct ip_fw_chain *ch, void *object)
134{
135 struct tables_config *tcfg;
136 struct op_state *os;
137
138 tcfg = CHAIN_TO_TCFG(ch);
139 TAILQ_FOREACH(os, &tcfg->state_list, next)
140 os->func(object, os);
141}
142
143void
144add_toperation_state(struct ip_fw_chain *ch, struct tableop_state *ts)
145{
146 struct tables_config *tcfg;
147
148 tcfg = CHAIN_TO_TCFG(ch);
149 TAILQ_INSERT_HEAD(&tcfg->state_list, &ts->opstate, next);
150}
151
152void
153del_toperation_state(struct ip_fw_chain *ch, struct tableop_state *ts)
154{
155 struct tables_config *tcfg;
156
157 tcfg = CHAIN_TO_TCFG(ch);
158 TAILQ_REMOVE(&tcfg->state_list, &ts->opstate, next);
159}
160
161void
162tc_ref(struct table_config *tc)
163{
164
165 tc->no.refcnt++;
166}
167
168void
169tc_unref(struct table_config *tc)
170{
171
172 tc->no.refcnt--;
173}
174
175static struct table_value *
176get_table_value(struct ip_fw_chain *ch, struct table_config *tc, uint32_t kidx)
177{
178 struct table_value *pval;
179
180 pval = (struct table_value *)ch->valuestate;
181
182 return (&pval[kidx]);
183}
184
185
103/*
186/*
104 * The radix code expects addr and mask to be array of bytes,
105 * with the first byte being the length of the array. rn_inithead
106 * is called with the offset in bits of the lookup key within the
107 * array. If we use a sockaddr_in as the underlying type,
108 * sin_len is conveniently located at offset 0, sin_addr is at
109 * offset 4 and normally aligned.
110 * But for portability, let's avoid assumption and make the code explicit
187 * Checks if we're able to insert/update entry @tei into table
188 * w.r.t @tc limits.
189 * May alter @tei to indicate insertion error / insert
190 * options.
191 *
192 * Returns 0 if operation can be performed/
111 */
193 */
112#define KEY_LEN(v) *((uint8_t *)&(v))
113#define KEY_OFS (8*offsetof(struct sockaddr_in, sin_addr))
194static int
195check_table_limit(struct table_config *tc, struct tentry_info *tei)
196{
197
198 if (tc->limit == 0 || tc->count < tc->limit)
199 return (0);
200
201 if ((tei->flags & TEI_FLAGS_UPDATE) == 0) {
202 /* Notify userland on error cause */
203 tei->flags |= TEI_FLAGS_LIMIT;
204 return (EFBIG);
205 }
206
207 /*
208 * We have UPDATE flag set.
209 * Permit updating record (if found),
210 * but restrict adding new one since we've
211 * already hit the limit.
212 */
213 tei->flags |= TEI_FLAGS_DONTADD;
214
215 return (0);
216}
217
114/*
218/*
115 * Do not require radix to compare more than actual IPv4/IPv6 address
219 * Convert algorithm callback return code into
220 * one of pre-defined states known by userland.
116 */
221 */
117#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
118#define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr))
119#define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname))
222static void
223store_tei_result(struct tentry_info *tei, int op, int error, uint32_t num)
224{
225 int flag;
120
226
121#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
122#define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr))
123#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname))
227 flag = 0;
124
228
229 switch (error) {
230 case 0:
231 if (op == OP_ADD && num != 0)
232 flag = TEI_FLAGS_ADDED;
233 if (op == OP_DEL)
234 flag = TEI_FLAGS_DELETED;
235 break;
236 case ENOENT:
237 flag = TEI_FLAGS_NOTFOUND;
238 break;
239 case EEXIST:
240 flag = TEI_FLAGS_EXISTS;
241 break;
242 default:
243 flag = TEI_FLAGS_ERROR;
244 }
125
245
126#ifdef INET6
127static inline void
128ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
246 tei->flags |= flag;
247}
248
249/*
250 * Creates and references table with default parameters.
251 * Saves table config, algo and allocated kidx info @ptc, @pta and
252 * @pkidx if non-zero.
253 * Used for table auto-creation to support old binaries.
254 *
255 * Returns 0 on success.
256 */
257static int
258create_table_compat(struct ip_fw_chain *ch, struct tid_info *ti,
259 uint16_t *pkidx)
129{
260{
130 uint32_t *cp;
261 ipfw_xtable_info xi;
262 int error;
131
263
132 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
133 *cp++ = 0xFFFFFFFF;
134 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
264 memset(&xi, 0, sizeof(xi));
265 /* Set default value mask for legacy clients */
266 xi.vmask = IPFW_VTYPE_LEGACY;
267
268 error = create_table_internal(ch, ti, NULL, &xi, pkidx, 1);
269 if (error != 0)
270 return (error);
271
272 return (0);
135}
273}
136#endif
137
274
138int
139ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
140 uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value)
275/*
276 * Find and reference existing table optionally
277 * creating new one.
278 *
279 * Saves found table config into @ptc.
280 * Note function may drop/acquire UH_WLOCK.
281 * Returns 0 if table was found/created and referenced
282 * or non-zero return code.
283 */
284static int
285find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti,
286 struct tentry_info *tei, uint32_t count, int op,
287 struct table_config **ptc)
141{
288{
142 struct radix_node_head *rnh, **rnh_ptr;
143 struct table_entry *ent;
144 struct table_xentry *xent;
145 struct radix_node *rn;
146 in_addr_t addr;
147 int offset;
148 void *ent_ptr;
149 struct sockaddr *addr_ptr, *mask_ptr;
150 char c;
289 struct namedobj_instance *ni;
290 struct table_config *tc;
291 uint16_t kidx;
292 int error;
151
293
152 if (tbl >= V_fw_tables_max)
153 return (EINVAL);
294 IPFW_UH_WLOCK_ASSERT(ch);
154
295
155 switch (type) {
156 case IPFW_TABLE_CIDR:
157 if (plen == sizeof(in_addr_t)) {
158#ifdef INET
159 /* IPv4 case */
160 if (mlen > 32)
161 return (EINVAL);
162 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
163 ent->value = value;
164 /* Set 'total' structure length */
165 KEY_LEN(ent->addr) = KEY_LEN_INET;
166 KEY_LEN(ent->mask) = KEY_LEN_INET;
167 /* Set offset of IPv4 address in bits */
168 offset = OFF_LEN_INET;
169 ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
170 addr = *((in_addr_t *)paddr);
171 ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
172 /* Set pointers */
173 rnh_ptr = &ch->tables[tbl];
174 ent_ptr = ent;
175 addr_ptr = (struct sockaddr *)&ent->addr;
176 mask_ptr = (struct sockaddr *)&ent->mask;
177#endif
178#ifdef INET6
179 } else if (plen == sizeof(struct in6_addr)) {
180 /* IPv6 case */
181 if (mlen > 128)
182 return (EINVAL);
183 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
184 xent->value = value;
185 /* Set 'total' structure length */
186 KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
187 KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
188 /* Set offset of IPv6 address in bits */
189 offset = OFF_LEN_INET6;
190 ipv6_writemask(&xent->m.mask6.sin6_addr, mlen);
191 memcpy(&xent->a.addr6.sin6_addr, paddr, sizeof(struct in6_addr));
192 APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr);
193 /* Set pointers */
194 rnh_ptr = &ch->xtables[tbl];
195 ent_ptr = xent;
196 addr_ptr = (struct sockaddr *)&xent->a.addr6;
197 mask_ptr = (struct sockaddr *)&xent->m.mask6;
198#endif
199 } else {
200 /* Unknown CIDR type */
296 ni = CHAIN_TO_NI(ch);
297 tc = NULL;
298 if ((tc = find_table(ni, ti)) != NULL) {
299 /* check table type */
300 if (tc->no.type != ti->type)
201 return (EINVAL);
301 return (EINVAL);
302
303 if (tc->locked != 0)
304 return (EACCES);
305
306 /* Try to exit early on limit hit */
307 if (op == OP_ADD && count == 1 &&
308 check_table_limit(tc, tei) != 0)
309 return (EFBIG);
310
311 /* Reference and return */
312 tc->no.refcnt++;
313 *ptc = tc;
314 return (0);
315 }
316
317 if (op == OP_DEL)
318 return (ESRCH);
319
320 /* Compability mode: create new table for old clients */
321 if ((tei->flags & TEI_FLAGS_COMPAT) == 0)
322 return (ESRCH);
323
324 IPFW_UH_WUNLOCK(ch);
325 error = create_table_compat(ch, ti, &kidx);
326 IPFW_UH_WLOCK(ch);
327
328 if (error != 0)
329 return (error);
330
331 tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx);
332 KASSERT(tc != NULL, ("create_table_compat returned bad idx %d", kidx));
333
334 /* OK, now we've got referenced table. */
335 *ptc = tc;
336 return (0);
337}
338
339/*
340 * Rolls back already @added to @tc entries using state array @ta_buf_m.
341 * Assume the following layout:
342 * 1) ADD state (ta_buf_m[0] ... t_buf_m[added - 1]) for handling update cases
343 * 2) DEL state (ta_buf_m[count[ ... t_buf_m[count + added - 1])
344 * for storing deleted state
345 */
346static void
347rollback_added_entries(struct ip_fw_chain *ch, struct table_config *tc,
348 struct table_info *tinfo, struct tentry_info *tei, caddr_t ta_buf_m,
349 uint32_t count, uint32_t added)
350{
351 struct table_algo *ta;
352 struct tentry_info *ptei;
353 caddr_t v, vv;
354 size_t ta_buf_sz;
355 int error, i;
356 uint32_t num;
357
358 IPFW_UH_WLOCK_ASSERT(ch);
359
360 ta = tc->ta;
361 ta_buf_sz = ta->ta_buf_size;
362 v = ta_buf_m;
363 vv = v + count * ta_buf_sz;
364 for (i = 0; i < added; i++, v += ta_buf_sz, vv += ta_buf_sz) {
365 ptei = &tei[i];
366 if ((ptei->flags & TEI_FLAGS_UPDATED) != 0) {
367
368 /*
369 * We have old value stored by previous
370 * call in @ptei->value. Do add once again
371 * to restore it.
372 */
373 error = ta->add(tc->astate, tinfo, ptei, v, &num);
374 KASSERT(error == 0, ("rollback UPDATE fail"));
375 KASSERT(num == 0, ("rollback UPDATE fail2"));
376 continue;
202 }
377 }
378
379 error = ta->prepare_del(ch, ptei, vv);
380 KASSERT(error == 0, ("pre-rollback INSERT failed"));
381 error = ta->del(tc->astate, tinfo, ptei, vv, &num);
382 KASSERT(error == 0, ("rollback INSERT failed"));
383 tc->count -= num;
384 }
385}
386
387/*
388 * Prepares add/del state for all @count entries in @tei.
389 * Uses either stack buffer (@ta_buf) or allocates a new one.
390 * Stores pointer to allocated buffer back to @ta_buf.
391 *
392 * Returns 0 on success.
393 */
394static int
395prepare_batch_buffer(struct ip_fw_chain *ch, struct table_algo *ta,
396 struct tentry_info *tei, uint32_t count, int op, caddr_t *ta_buf)
397{
398 caddr_t ta_buf_m, v;
399 size_t ta_buf_sz, sz;
400 struct tentry_info *ptei;
401 int error, i;
402
403 error = 0;
404 ta_buf_sz = ta->ta_buf_size;
405 if (count == 1) {
406 /* Sigle add/delete, use on-stack buffer */
407 memset(*ta_buf, 0, TA_BUF_SZ);
408 ta_buf_m = *ta_buf;
409 } else {
410
411 /*
412 * Multiple adds/deletes, allocate larger buffer
413 *
414 * Note we need 2xcount buffer for add case:
415 * we have hold both ADD state
416 * and DELETE state (this may be needed
417 * if we need to rollback all changes)
418 */
419 sz = count * ta_buf_sz;
420 ta_buf_m = malloc((op == OP_ADD) ? sz * 2 : sz, M_TEMP,
421 M_WAITOK | M_ZERO);
422 }
423
424 v = ta_buf_m;
425 for (i = 0; i < count; i++, v += ta_buf_sz) {
426 ptei = &tei[i];
427 error = (op == OP_ADD) ?
428 ta->prepare_add(ch, ptei, v) : ta->prepare_del(ch, ptei, v);
429
430 /*
431 * Some syntax error (incorrect mask, or address, or
432 * anything). Return error regardless of atomicity
433 * settings.
434 */
435 if (error != 0)
436 break;
437 }
438
439 *ta_buf = ta_buf_m;
440 return (error);
441}
442
443/*
444 * Flushes allocated state for each @count entries in @tei.
445 * Frees @ta_buf_m if differs from stack buffer @ta_buf.
446 */
447static void
448flush_batch_buffer(struct ip_fw_chain *ch, struct table_algo *ta,
449 struct tentry_info *tei, uint32_t count, int rollback,
450 caddr_t ta_buf_m, caddr_t ta_buf)
451{
452 caddr_t v;
453 struct tentry_info *ptei;
454 size_t ta_buf_sz;
455 int i;
456
457 ta_buf_sz = ta->ta_buf_size;
458
459 /* Run cleaning callback anyway */
460 v = ta_buf_m;
461 for (i = 0; i < count; i++, v += ta_buf_sz) {
462 ptei = &tei[i];
463 ta->flush_entry(ch, ptei, v);
464 if (ptei->ptv != NULL) {
465 free(ptei->ptv, M_IPFW);
466 ptei->ptv = NULL;
467 }
468 }
469
470 /* Clean up "deleted" state in case of rollback */
471 if (rollback != 0) {
472 v = ta_buf_m + count * ta_buf_sz;
473 for (i = 0; i < count; i++, v += ta_buf_sz)
474 ta->flush_entry(ch, &tei[i], v);
475 }
476
477 if (ta_buf_m != ta_buf)
478 free(ta_buf_m, M_TEMP);
479}
480
481
482static void
483rollback_add_entry(void *object, struct op_state *_state)
484{
485 struct ip_fw_chain *ch;
486 struct tableop_state *ts;
487
488 ts = (struct tableop_state *)_state;
489
490 if (ts->tc != object && ts->ch != object)
491 return;
492
493 ch = ts->ch;
494
495 IPFW_UH_WLOCK_ASSERT(ch);
496
497 /* Call specifid unlockers */
498 rollback_table_values(ts);
499
500 /* Indicate we've called */
501 ts->modified = 1;
502}
503
504/*
505 * Adds/updates one or more entries in table @ti.
506 *
507 * Function may drop/reacquire UH wlock multiple times due to
508 * items alloc, algorithm callbacks (check_space), value linkage
509 * (new values, value storage realloc), etc..
510 * Other processes like other adds (which may involve storage resize),
511 * table swaps (which changes table data and may change algo type),
512 * table modify (which may change value mask) may be executed
513 * simultaneously so we need to deal with it.
514 *
515 * The following approach was implemented:
516 * we have per-chain linked list, protected with UH lock.
517 * add_table_entry prepares special on-stack structure wthich is passed
518 * to its descendants. Users add this structure to this list before unlock.
519 * After performing needed operations and acquiring UH lock back, each user
520 * checks if structure has changed. If true, it rolls local state back and
521 * returns without error to the caller.
522 * add_table_entry() on its own checks if structure has changed and restarts
523 * its operation from the beginning (goto restart).
524 *
525 * Functions which are modifying fields of interest (currently
526 * resize_shared_value_storage() and swap_tables() )
527 * traverses given list while holding UH lock immediately before
528 * performing their operations calling function provided be list entry
529 * ( currently rollback_add_entry ) which performs rollback for all necessary
530 * state and sets appropriate values in structure indicating rollback
531 * has happened.
532 *
533 * Algo interaction:
534 * Function references @ti first to ensure table won't
535 * disappear or change its type.
536 * After that, prepare_add callback is called for each @tei entry.
537 * Next, we try to add each entry under UH+WHLOCK
538 * using add() callback.
539 * Finally, we free all state by calling flush_entry callback
540 * for each @tei.
541 *
542 * Returns 0 on success.
543 */
544int
545add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
546 struct tentry_info *tei, uint8_t flags, uint32_t count)
547{
548 struct table_config *tc;
549 struct table_algo *ta;
550 uint16_t kidx;
551 int error, first_error, i, rollback;
552 uint32_t num, numadd;
553 struct tentry_info *ptei;
554 struct tableop_state ts;
555 char ta_buf[TA_BUF_SZ];
556 caddr_t ta_buf_m, v;
557
558 memset(&ts, 0, sizeof(ts));
559 ta = NULL;
560 IPFW_UH_WLOCK(ch);
561
562 /*
563 * Find and reference existing table.
564 */
565restart:
566 if (ts.modified != 0) {
567 IPFW_UH_WUNLOCK(ch);
568 flush_batch_buffer(ch, ta, tei, count, rollback,
569 ta_buf_m, ta_buf);
570 memset(&ts, 0, sizeof(ts));
571 ta = NULL;
572 IPFW_UH_WLOCK(ch);
573 }
574
575 error = find_ref_table(ch, ti, tei, count, OP_ADD, &tc);
576 if (error != 0) {
577 IPFW_UH_WUNLOCK(ch);
578 return (error);
579 }
580 ta = tc->ta;
581
582 /* Fill in tablestate */
583 ts.ch = ch;
584 ts.opstate.func = rollback_add_entry;
585 ts.tc = tc;
586 ts.vshared = tc->vshared;
587 ts.vmask = tc->vmask;
588 ts.ta = ta;
589 ts.tei = tei;
590 ts.count = count;
591 rollback = 0;
592 add_toperation_state(ch, &ts);
593 IPFW_UH_WUNLOCK(ch);
594
595 /* Allocate memory and prepare record(s) */
596 /* Pass stack buffer by default */
597 ta_buf_m = ta_buf;
598 error = prepare_batch_buffer(ch, ta, tei, count, OP_ADD, &ta_buf_m);
599 if (error != 0)
600 goto cleanup;
601
602 IPFW_UH_WLOCK(ch);
603 /* Drop reference we've used in first search */
604 tc->no.refcnt--;
605
606 /*
607 * Check if table swap has happened.
608 * (so table algo might be changed).
609 * Restart operation to achieve consistent behavior.
610 */
611 del_toperation_state(ch, &ts);
612 if (ts.modified != 0)
613 goto restart;
614
615 /*
616 * Link all values values to shared/per-table value array.
617 *
618 * May release/reacquire UH_WLOCK.
619 */
620 error = ipfw_link_table_values(ch, &ts);
621 if (error != 0)
622 goto cleanup;
623 if (ts.modified != 0)
624 goto restart;
625
626 /*
627 * Ensure we are able to add all entries without additional
628 * memory allocations. May release/reacquire UH_WLOCK.
629 */
630 kidx = tc->no.kidx;
631 error = check_table_space(ch, &ts, tc, KIDX_TO_TI(ch, kidx), count);
632 if (error != 0)
633 goto cleanup;
634 if (ts.modified != 0)
635 goto restart;
636
637 /* We've got valid table in @tc. Let's try to add data */
638 kidx = tc->no.kidx;
639 ta = tc->ta;
640 numadd = 0;
641 first_error = 0;
642
643 IPFW_WLOCK(ch);
644
645 v = ta_buf_m;
646 for (i = 0; i < count; i++, v += ta->ta_buf_size) {
647 ptei = &tei[i];
648 num = 0;
649 /* check limit before adding */
650 if ((error = check_table_limit(tc, ptei)) == 0) {
651 error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx),
652 ptei, v, &num);
653 /* Set status flag to inform userland */
654 store_tei_result(ptei, OP_ADD, error, num);
655 }
656 if (error == 0) {
657 /* Update number of records to ease limit checking */
658 tc->count += num;
659 numadd += num;
660 continue;
661 }
662
663 if (first_error == 0)
664 first_error = error;
665
666 /*
667 * Some error have happened. Check our atomicity
668 * settings: continue if atomicity is not required,
669 * rollback changes otherwise.
670 */
671 if ((flags & IPFW_CTF_ATOMIC) == 0)
672 continue;
673
674 rollback_added_entries(ch, tc, KIDX_TO_TI(ch, kidx),
675 tei, ta_buf_m, count, i);
676
677 rollback = 1;
203 break;
678 break;
679 }
680
681 IPFW_WUNLOCK(ch);
682
683 ipfw_garbage_table_values(ch, tc, tei, count, rollback);
684
685 /* Permit post-add algorithm grow/rehash. */
686 if (numadd != 0)
687 check_table_space(ch, NULL, tc, KIDX_TO_TI(ch, kidx), 0);
688
689 /* Return first error to user, if any */
690 error = first_error;
691
692cleanup:
693 IPFW_UH_WUNLOCK(ch);
694
695 flush_batch_buffer(ch, ta, tei, count, rollback, ta_buf_m, ta_buf);
204
696
205 case IPFW_TABLE_INTERFACE:
206 /* Check if string is terminated */
207 c = ((char *)paddr)[IF_NAMESIZE - 1];
208 ((char *)paddr)[IF_NAMESIZE - 1] = '\0';
209 if (((mlen = strlen((char *)paddr)) == IF_NAMESIZE - 1) && (c != '\0'))
210 return (EINVAL);
697 return (error);
698}
211
699
212 /* Include last \0 into comparison */
213 mlen++;
700/*
701 * Deletes one or more entries in table @ti.
702 *
703 * Returns 0 on success.
704 */
705int
706del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
707 struct tentry_info *tei, uint8_t flags, uint32_t count)
708{
709 struct table_config *tc;
710 struct table_algo *ta;
711 struct tentry_info *ptei;
712 uint16_t kidx;
713 int error, first_error, i;
714 uint32_t num, numdel;
715 char ta_buf[TA_BUF_SZ];
716 caddr_t ta_buf_m, v;
214
717
215 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
216 xent->value = value;
217 /* Set 'total' structure length */
218 KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen;
219 KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen;
220 /* Set offset of interface name in bits */
221 offset = OFF_LEN_IFACE;
222 memcpy(xent->a.iface.ifname, paddr, mlen);
223 /* Assume direct match */
224 /* TODO: Add interface pattern matching */
225#if 0
226 memset(xent->m.ifmask.ifname, 0xFF, IF_NAMESIZE);
227 mask_ptr = (struct sockaddr *)&xent->m.ifmask;
228#endif
229 /* Set pointers */
230 rnh_ptr = &ch->xtables[tbl];
231 ent_ptr = xent;
232 addr_ptr = (struct sockaddr *)&xent->a.iface;
233 mask_ptr = NULL;
234 break;
718 /*
719 * Find and reference existing table.
720 */
721 IPFW_UH_WLOCK(ch);
722 error = find_ref_table(ch, ti, tei, count, OP_DEL, &tc);
723 if (error != 0) {
724 IPFW_UH_WUNLOCK(ch);
725 return (error);
726 }
727 ta = tc->ta;
728 IPFW_UH_WUNLOCK(ch);
235
729
236 default:
237 return (EINVAL);
730 /* Allocate memory and prepare record(s) */
731 /* Pass stack buffer by default */
732 ta_buf_m = ta_buf;
733 error = prepare_batch_buffer(ch, ta, tei, count, OP_DEL, &ta_buf_m);
734 if (error != 0)
735 goto cleanup;
736
737 IPFW_UH_WLOCK(ch);
738
739 /* Drop reference we've used in first search */
740 tc->no.refcnt--;
741
742 /*
743 * Check if table algo is still the same.
744 * (changed ta may be the result of table swap).
745 */
746 if (ta != tc->ta) {
747 IPFW_UH_WUNLOCK(ch);
748 error = EINVAL;
749 goto cleanup;
238 }
239
750 }
751
752 kidx = tc->no.kidx;
753 numdel = 0;
754 first_error = 0;
755
240 IPFW_WLOCK(ch);
756 IPFW_WLOCK(ch);
757 v = ta_buf_m;
758 for (i = 0; i < count; i++, v += ta->ta_buf_size) {
759 ptei = &tei[i];
760 num = 0;
761 error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), ptei, v,
762 &num);
763 /* Save state for userland */
764 store_tei_result(ptei, OP_DEL, error, num);
765 if (error != 0 && first_error == 0)
766 first_error = error;
767 tc->count -= num;
768 numdel += num;
769 }
770 IPFW_WUNLOCK(ch);
241
771
242 /* Check if tabletype is valid */
243 if ((ch->tabletype[tbl] != 0) && (ch->tabletype[tbl] != type)) {
244 IPFW_WUNLOCK(ch);
245 free(ent_ptr, M_IPFW_TBL);
246 return (EINVAL);
772 /* Unlink non-used values */
773 ipfw_garbage_table_values(ch, tc, tei, count, 0);
774
775 if (numdel != 0) {
776 /* Run post-del hook to permit shrinking */
777 check_table_space(ch, NULL, tc, KIDX_TO_TI(ch, kidx), 0);
247 }
248
778 }
779
249 /* Check if radix tree exists */
250 if ((rnh = *rnh_ptr) == NULL) {
251 IPFW_WUNLOCK(ch);
252 /* Create radix for a new table */
253 if (!rn_inithead((void **)&rnh, offset)) {
254 free(ent_ptr, M_IPFW_TBL);
255 return (ENOMEM);
780 IPFW_UH_WUNLOCK(ch);
781
782 /* Return first error to user, if any */
783 error = first_error;
784
785cleanup:
786 flush_batch_buffer(ch, ta, tei, count, 0, ta_buf_m, ta_buf);
787
788 return (error);
789}
790
791/*
792 * Ensure that table @tc has enough space to add @count entries without
793 * need for reallocation.
794 *
795 * Callbacks order:
796 * 0) need_modify() (UH_WLOCK) - checks if @count items can be added w/o resize.
797 *
798 * 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags.
799 * 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage
800 * 3) modify (UH_WLOCK + WLOCK) - switch pointers
801 * 4) flush_modify (UH_WLOCK) - free state, if needed
802 *
803 * Returns 0 on success.
804 */
805static int
806check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts,
807 struct table_config *tc, struct table_info *ti, uint32_t count)
808{
809 struct table_algo *ta;
810 uint64_t pflags;
811 char ta_buf[TA_BUF_SZ];
812 int error;
813
814 IPFW_UH_WLOCK_ASSERT(ch);
815
816 error = 0;
817 ta = tc->ta;
818 if (ta->need_modify == NULL)
819 return (0);
820
821 /* Acquire reference not to loose @tc between locks/unlocks */
822 tc->no.refcnt++;
823
824 /*
825 * TODO: think about avoiding race between large add/large delete
826 * operation on algorithm which implements shrinking along with
827 * growing.
828 */
829 while (true) {
830 pflags = 0;
831 if (ta->need_modify(tc->astate, ti, count, &pflags) == 0) {
832 error = 0;
833 break;
256 }
257
834 }
835
258 IPFW_WLOCK(ch);
259 if (*rnh_ptr != NULL) {
260 /* Tree is already attached by other thread */
261 rn_detachhead((void **)&rnh);
262 rnh = *rnh_ptr;
263 /* Check table type another time */
264 if (ch->tabletype[tbl] != type) {
265 IPFW_WUNLOCK(ch);
266 free(ent_ptr, M_IPFW_TBL);
267 return (EINVAL);
268 }
269 } else {
270 *rnh_ptr = rnh;
271 /*
272 * Set table type. It can be set already
273 * (if we have IPv6-only table) but setting
274 * it another time does not hurt
836 /* We have to shrink/grow table */
837 if (ts != NULL)
838 add_toperation_state(ch, ts);
839 IPFW_UH_WUNLOCK(ch);
840
841 memset(&ta_buf, 0, sizeof(ta_buf));
842 error = ta->prepare_mod(ta_buf, &pflags);
843
844 IPFW_UH_WLOCK(ch);
845 if (ts != NULL)
846 del_toperation_state(ch, ts);
847
848 if (error != 0)
849 break;
850
851 if (ts != NULL && ts->modified != 0) {
852
853 /*
854 * Swap operation has happened
855 * so we're currently operating on other
856 * table data. Stop doing this.
275 */
857 */
276 ch->tabletype[tbl] = type;
858 ta->flush_mod(ta_buf);
859 break;
277 }
860 }
861
862 /* Check if we still need to alter table */
863 ti = KIDX_TO_TI(ch, tc->no.kidx);
864 if (ta->need_modify(tc->astate, ti, count, &pflags) == 0) {
865 IPFW_UH_WUNLOCK(ch);
866
867 /*
868 * Other thread has already performed resize.
869 * Flush our state and return.
870 */
871 ta->flush_mod(ta_buf);
872 break;
873 }
874
875 error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags);
876 if (error == 0) {
877 /* Do actual modification */
878 IPFW_WLOCK(ch);
879 ta->modify(tc->astate, ti, ta_buf, pflags);
880 IPFW_WUNLOCK(ch);
881 }
882
883 /* Anyway, flush data and retry */
884 ta->flush_mod(ta_buf);
278 }
279
885 }
886
280 rn = rnh->rnh_addaddr(addr_ptr, mask_ptr, rnh, ent_ptr);
281 IPFW_WUNLOCK(ch);
887 tc->no.refcnt--;
888 return (error);
889}
282
890
283 if (rn == NULL) {
284 free(ent_ptr, M_IPFW_TBL);
285 return (EEXIST);
891/*
892 * Adds or deletes record in table.
893 * Data layout (v0):
894 * Request: [ ip_fw3_opheader ipfw_table_xentry ]
895 *
896 * Returns 0 on success
897 */
898static int
899manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
900 struct sockopt_data *sd)
901{
902 ipfw_table_xentry *xent;
903 struct tentry_info tei;
904 struct tid_info ti;
905 struct table_value v;
906 int error, hdrlen, read;
907
908 hdrlen = offsetof(ipfw_table_xentry, k);
909
910 /* Check minimum header size */
911 if (sd->valsize < (sizeof(*op3) + hdrlen))
912 return (EINVAL);
913
914 read = sizeof(ip_fw3_opheader);
915
916 /* Check if xentry len field is valid */
917 xent = (ipfw_table_xentry *)(op3 + 1);
918 if (xent->len < hdrlen || xent->len + read > sd->valsize)
919 return (EINVAL);
920
921 memset(&tei, 0, sizeof(tei));
922 tei.paddr = &xent->k;
923 tei.masklen = xent->masklen;
924 ipfw_import_table_value_legacy(xent->value, &v);
925 tei.pvalue = &v;
926 /* Old requests compability */
927 tei.flags = TEI_FLAGS_COMPAT;
928 if (xent->type == IPFW_TABLE_ADDR) {
929 if (xent->len - hdrlen == sizeof(in_addr_t))
930 tei.subtype = AF_INET;
931 else
932 tei.subtype = AF_INET6;
286 }
933 }
287 return (0);
934
935 memset(&ti, 0, sizeof(ti));
936 ti.uidx = xent->tbl;
937 ti.type = xent->type;
938
939 error = (op3->opcode == IP_FW_TABLE_XADD) ?
940 add_table_entry(ch, &ti, &tei, 0, 1) :
941 del_table_entry(ch, &ti, &tei, 0, 1);
942
943 return (error);
288}
289
944}
945
290int
291ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
292 uint8_t plen, uint8_t mlen, uint8_t type)
946/*
947 * Adds or deletes record in table.
948 * Data layout (v1)(current):
949 * Request: [ ipfw_obj_header
950 * ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ]
951 * ]
952 *
953 * Returns 0 on success
954 */
955static int
956manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
957 struct sockopt_data *sd)
293{
958{
294 struct radix_node_head *rnh, **rnh_ptr;
295 struct table_entry *ent;
296 in_addr_t addr;
297 struct sockaddr_in sa, mask;
298 struct sockaddr *sa_ptr, *mask_ptr;
299 char c;
959 ipfw_obj_tentry *tent, *ptent;
960 ipfw_obj_ctlv *ctlv;
961 ipfw_obj_header *oh;
962 struct tentry_info *ptei, tei, *tei_buf;
963 struct tid_info ti;
964 int error, i, kidx, read;
300
965
301 if (tbl >= V_fw_tables_max)
966 /* Check minimum header size */
967 if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv)))
302 return (EINVAL);
303
968 return (EINVAL);
969
304 switch (type) {
305 case IPFW_TABLE_CIDR:
306 if (plen == sizeof(in_addr_t)) {
307 /* Set 'total' structure length */
308 KEY_LEN(sa) = KEY_LEN_INET;
309 KEY_LEN(mask) = KEY_LEN_INET;
310 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
311 addr = *((in_addr_t *)paddr);
312 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
313 rnh_ptr = &ch->tables[tbl];
314 sa_ptr = (struct sockaddr *)&sa;
315 mask_ptr = (struct sockaddr *)&mask;
316#ifdef INET6
317 } else if (plen == sizeof(struct in6_addr)) {
318 /* IPv6 case */
319 if (mlen > 128)
320 return (EINVAL);
321 struct sockaddr_in6 sa6, mask6;
322 memset(&sa6, 0, sizeof(struct sockaddr_in6));
323 memset(&mask6, 0, sizeof(struct sockaddr_in6));
324 /* Set 'total' structure length */
325 KEY_LEN(sa6) = KEY_LEN_INET6;
326 KEY_LEN(mask6) = KEY_LEN_INET6;
327 ipv6_writemask(&mask6.sin6_addr, mlen);
328 memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr));
329 APPLY_MASK(&sa6.sin6_addr, &mask6.sin6_addr);
330 rnh_ptr = &ch->xtables[tbl];
331 sa_ptr = (struct sockaddr *)&sa6;
332 mask_ptr = (struct sockaddr *)&mask6;
333#endif
334 } else {
335 /* Unknown CIDR type */
336 return (EINVAL);
337 }
338 break;
970 /* Check if passed data is too long */
971 if (sd->valsize != sd->kavail)
972 return (EINVAL);
339
973
340 case IPFW_TABLE_INTERFACE:
341 /* Check if string is terminated */
342 c = ((char *)paddr)[IF_NAMESIZE - 1];
343 ((char *)paddr)[IF_NAMESIZE - 1] = '\0';
344 if (((mlen = strlen((char *)paddr)) == IF_NAMESIZE - 1) && (c != '\0'))
974 oh = (ipfw_obj_header *)sd->kbuf;
975
976 /* Basic length checks for TLVs */
977 if (oh->ntlv.head.length != sizeof(oh->ntlv))
978 return (EINVAL);
979
980 read = sizeof(*oh);
981
982 ctlv = (ipfw_obj_ctlv *)(oh + 1);
983 if (ctlv->head.length + read != sd->valsize)
984 return (EINVAL);
985
986 read += sizeof(*ctlv);
987 tent = (ipfw_obj_tentry *)(ctlv + 1);
988 if (ctlv->count * sizeof(*tent) + read != sd->valsize)
989 return (EINVAL);
990
991 if (ctlv->count == 0)
992 return (0);
993
994 /*
995 * Mark entire buffer as "read".
996 * This instructs sopt api write it back
997 * after function return.
998 */
999 ipfw_get_sopt_header(sd, sd->valsize);
1000
1001 /* Perform basic checks for each entry */
1002 ptent = tent;
1003 kidx = tent->idx;
1004 for (i = 0; i < ctlv->count; i++, ptent++) {
1005 if (ptent->head.length != sizeof(*ptent))
345 return (EINVAL);
1006 return (EINVAL);
1007 if (ptent->idx != kidx)
1008 return (ENOTSUP);
1009 }
346
1010
347 struct xaddr_iface ifname, ifmask;
348 memset(&ifname, 0, sizeof(ifname));
1011 /* Convert data into kernel request objects */
1012 objheader_to_ti(oh, &ti);
1013 ti.type = oh->ntlv.type;
1014 ti.uidx = kidx;
349
1015
350 /* Include last \0 into comparison */
351 mlen++;
1016 /* Use on-stack buffer for single add/del */
1017 if (ctlv->count == 1) {
1018 memset(&tei, 0, sizeof(tei));
1019 tei_buf = &tei;
1020 } else
1021 tei_buf = malloc(ctlv->count * sizeof(tei), M_TEMP,
1022 M_WAITOK | M_ZERO);
352
1023
353 /* Set 'total' structure length */
354 KEY_LEN(ifname) = KEY_LEN_IFACE + mlen;
355 KEY_LEN(ifmask) = KEY_LEN_IFACE + mlen;
356 /* Assume direct match */
357 /* FIXME: Add interface pattern matching */
358#if 0
359 memset(ifmask.ifname, 0xFF, IF_NAMESIZE);
360 mask_ptr = (struct sockaddr *)&ifmask;
361#endif
362 mask_ptr = NULL;
363 memcpy(ifname.ifname, paddr, mlen);
364 /* Set pointers */
365 rnh_ptr = &ch->xtables[tbl];
366 sa_ptr = (struct sockaddr *)&ifname;
1024 ptei = tei_buf;
1025 ptent = tent;
1026 for (i = 0; i < ctlv->count; i++, ptent++, ptei++) {
1027 ptei->paddr = &ptent->k;
1028 ptei->subtype = ptent->subtype;
1029 ptei->masklen = ptent->masklen;
1030 if (ptent->head.flags & IPFW_TF_UPDATE)
1031 ptei->flags |= TEI_FLAGS_UPDATE;
367
1032
368 break;
1033 ipfw_import_table_value_v1(&ptent->v.value);
1034 ptei->pvalue = (struct table_value *)&ptent->v.value;
1035 }
369
1036
370 default:
371 return (EINVAL);
1037 error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ?
1038 add_table_entry(ch, &ti, tei_buf, ctlv->flags, ctlv->count) :
1039 del_table_entry(ch, &ti, tei_buf, ctlv->flags, ctlv->count);
1040
1041 /* Translate result back to userland */
1042 ptei = tei_buf;
1043 ptent = tent;
1044 for (i = 0; i < ctlv->count; i++, ptent++, ptei++) {
1045 if (ptei->flags & TEI_FLAGS_ADDED)
1046 ptent->result = IPFW_TR_ADDED;
1047 else if (ptei->flags & TEI_FLAGS_DELETED)
1048 ptent->result = IPFW_TR_DELETED;
1049 else if (ptei->flags & TEI_FLAGS_UPDATED)
1050 ptent->result = IPFW_TR_UPDATED;
1051 else if (ptei->flags & TEI_FLAGS_LIMIT)
1052 ptent->result = IPFW_TR_LIMIT;
1053 else if (ptei->flags & TEI_FLAGS_ERROR)
1054 ptent->result = IPFW_TR_ERROR;
1055 else if (ptei->flags & TEI_FLAGS_NOTFOUND)
1056 ptent->result = IPFW_TR_NOTFOUND;
1057 else if (ptei->flags & TEI_FLAGS_EXISTS)
1058 ptent->result = IPFW_TR_EXISTS;
1059 ipfw_export_table_value_v1(ptei->pvalue, &ptent->v.value);
372 }
373
1060 }
1061
374 IPFW_WLOCK(ch);
375 if ((rnh = *rnh_ptr) == NULL) {
376 IPFW_WUNLOCK(ch);
1062 if (tei_buf != &tei)
1063 free(tei_buf, M_TEMP);
1064
1065 return (error);
1066}
1067
1068/*
1069 * Looks up an entry in given table.
1070 * Data layout (v0)(current):
1071 * Request: [ ipfw_obj_header ipfw_obj_tentry ]
1072 * Reply: [ ipfw_obj_header ipfw_obj_tentry ]
1073 *
1074 * Returns 0 on success
1075 */
1076static int
1077find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1078 struct sockopt_data *sd)
1079{
1080 ipfw_obj_tentry *tent;
1081 ipfw_obj_header *oh;
1082 struct tid_info ti;
1083 struct table_config *tc;
1084 struct table_algo *ta;
1085 struct table_info *kti;
1086 struct namedobj_instance *ni;
1087 int error;
1088 size_t sz;
1089
1090 /* Check minimum header size */
1091 sz = sizeof(*oh) + sizeof(*tent);
1092 if (sd->valsize != sz)
1093 return (EINVAL);
1094
1095 oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
1096 tent = (ipfw_obj_tentry *)(oh + 1);
1097
1098 /* Basic length checks for TLVs */
1099 if (oh->ntlv.head.length != sizeof(oh->ntlv))
1100 return (EINVAL);
1101
1102 objheader_to_ti(oh, &ti);
1103 ti.type = oh->ntlv.type;
1104 ti.uidx = tent->idx;
1105
1106 IPFW_UH_RLOCK(ch);
1107 ni = CHAIN_TO_NI(ch);
1108
1109 /*
1110 * Find existing table and check its type .
1111 */
1112 ta = NULL;
1113 if ((tc = find_table(ni, &ti)) == NULL) {
1114 IPFW_UH_RUNLOCK(ch);
377 return (ESRCH);
378 }
379
1115 return (ESRCH);
1116 }
1117
380 if (ch->tabletype[tbl] != type) {
381 IPFW_WUNLOCK(ch);
1118 /* check table type */
1119 if (tc->no.type != ti.type) {
1120 IPFW_UH_RUNLOCK(ch);
382 return (EINVAL);
383 }
384
1121 return (EINVAL);
1122 }
1123
385 ent = (struct table_entry *)rnh->rnh_deladdr(sa_ptr, mask_ptr, rnh);
386 IPFW_WUNLOCK(ch);
1124 kti = KIDX_TO_TI(ch, tc->no.kidx);
1125 ta = tc->ta;
387
1126
388 if (ent == NULL)
389 return (ESRCH);
1127 if (ta->find_tentry == NULL)
1128 return (ENOTSUP);
390
1129
391 free(ent, M_IPFW_TBL);
392 return (0);
1130 error = ta->find_tentry(tc->astate, kti, tent);
1131
1132 IPFW_UH_RUNLOCK(ch);
1133
1134 return (error);
393}
394
1135}
1136
1137/*
1138 * Flushes all entries or destroys given table.
1139 * Data layout (v0)(current):
1140 * Request: [ ipfw_obj_header ]
1141 *
1142 * Returns 0 on success
1143 */
395static int
1144static int
396flush_table_entry(struct radix_node *rn, void *arg)
1145flush_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1146 struct sockopt_data *sd)
397{
1147{
398 struct radix_node_head * const rnh = arg;
399 struct table_entry *ent;
1148 int error;
1149 struct _ipfw_obj_header *oh;
1150 struct tid_info ti;
400
1151
401 ent = (struct table_entry *)
402 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
403 if (ent != NULL)
404 free(ent, M_IPFW_TBL);
405 return (0);
1152 if (sd->valsize != sizeof(*oh))
1153 return (EINVAL);
1154
1155 oh = (struct _ipfw_obj_header *)op3;
1156 objheader_to_ti(oh, &ti);
1157
1158 if (op3->opcode == IP_FW_TABLE_XDESTROY)
1159 error = destroy_table(ch, &ti);
1160 else if (op3->opcode == IP_FW_TABLE_XFLUSH)
1161 error = flush_table(ch, &ti);
1162 else
1163 return (ENOTSUP);
1164
1165 return (error);
406}
407
1166}
1167
1168static void
1169restart_flush(void *object, struct op_state *_state)
1170{
1171 struct tableop_state *ts;
1172
1173 ts = (struct tableop_state *)_state;
1174
1175 if (ts->tc != object)
1176 return;
1177
1178 /* Indicate we've called */
1179 ts->modified = 1;
1180}
1181
1182/*
1183 * Flushes given table.
1184 *
1185 * Function create new table instance with the same
1186 * parameters, swaps it with old one and
1187 * flushes state without holding runtime WLOCK.
1188 *
1189 * Returns 0 on success.
1190 */
408int
1191int
409ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl)
1192flush_table(struct ip_fw_chain *ch, struct tid_info *ti)
410{
1193{
411 struct radix_node_head *rnh, *xrnh;
1194 struct namedobj_instance *ni;
1195 struct table_config *tc;
1196 struct table_algo *ta;
1197 struct table_info ti_old, ti_new, *tablestate;
1198 void *astate_old, *astate_new;
1199 char algostate[64], *pstate;
1200 struct tableop_state ts;
1201 int error;
1202 uint16_t kidx;
1203 uint8_t tflags;
412
1204
413 if (tbl >= V_fw_tables_max)
414 return (EINVAL);
1205 /*
1206 * Stage 1: save table algoritm.
1207 * Reference found table to ensure it won't disappear.
1208 */
1209 IPFW_UH_WLOCK(ch);
1210 ni = CHAIN_TO_NI(ch);
1211 if ((tc = find_table(ni, ti)) == NULL) {
1212 IPFW_UH_WUNLOCK(ch);
1213 return (ESRCH);
1214 }
1215restart:
1216 /* Set up swap handler */
1217 memset(&ts, 0, sizeof(ts));
1218 ts.opstate.func = restart_flush;
1219 ts.tc = tc;
415
1220
1221 ta = tc->ta;
1222 /* Do not flush readonly tables */
1223 if ((ta->flags & TA_FLAG_READONLY) != 0) {
1224 IPFW_UH_WUNLOCK(ch);
1225 return (EACCES);
1226 }
1227 /* Save startup algo parameters */
1228 if (ta->print_config != NULL) {
1229 ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx),
1230 algostate, sizeof(algostate));
1231 pstate = algostate;
1232 } else
1233 pstate = NULL;
1234 tflags = tc->tflags;
1235 tc->no.refcnt++;
1236 add_toperation_state(ch, &ts);
1237 IPFW_UH_WUNLOCK(ch);
1238
416 /*
1239 /*
417 * We free both (IPv4 and extended) radix trees and
418 * clear table type here to permit table to be reused
419 * for different type without module reload
1240 * Stage 2: allocate new table instance using same algo.
420 */
1241 */
1242 memset(&ti_new, 0, sizeof(struct table_info));
1243 error = ta->init(ch, &astate_new, &ti_new, pstate, tflags);
421
1244
422 IPFW_WLOCK(ch);
423 /* Set IPv4 table pointer to zero */
424 if ((rnh = ch->tables[tbl]) != NULL)
425 ch->tables[tbl] = NULL;
426 /* Set extended table pointer to zero */
427 if ((xrnh = ch->xtables[tbl]) != NULL)
428 ch->xtables[tbl] = NULL;
429 /* Zero table type */
430 ch->tabletype[tbl] = 0;
431 IPFW_WUNLOCK(ch);
1245 /*
1246 * Stage 3: swap old state pointers with newly-allocated ones.
1247 * Decrease refcount.
1248 */
1249 IPFW_UH_WLOCK(ch);
1250 tc->no.refcnt--;
1251 del_toperation_state(ch, &ts);
432
1252
433 if (rnh != NULL) {
434 rnh->rnh_walktree(rnh, flush_table_entry, rnh);
435 rn_detachhead((void **)&rnh);
1253 if (error != 0) {
1254 IPFW_UH_WUNLOCK(ch);
1255 return (error);
436 }
437
1256 }
1257
438 if (xrnh != NULL) {
439 xrnh->rnh_walktree(xrnh, flush_table_entry, xrnh);
440 rn_detachhead((void **)&xrnh);
1258 /*
1259 * Restart operation if table swap has happened:
1260 * even if algo may be the same, algo init parameters
1261 * may change. Restart operation instead of doing
1262 * complex checks.
1263 */
1264 if (ts.modified != 0) {
1265 ta->destroy(astate_new, &ti_new);
1266 goto restart;
441 }
442
1267 }
1268
1269 ni = CHAIN_TO_NI(ch);
1270 kidx = tc->no.kidx;
1271 tablestate = (struct table_info *)ch->tablestate;
1272
1273 IPFW_WLOCK(ch);
1274 ti_old = tablestate[kidx];
1275 tablestate[kidx] = ti_new;
1276 IPFW_WUNLOCK(ch);
1277
1278 astate_old = tc->astate;
1279 tc->astate = astate_new;
1280 tc->ti_copy = ti_new;
1281 tc->count = 0;
1282
1283 /* Notify algo on real @ti address */
1284 if (ta->change_ti != NULL)
1285 ta->change_ti(tc->astate, &tablestate[kidx]);
1286
1287 /*
1288 * Stage 4: unref values.
1289 */
1290 ipfw_unref_table_values(ch, tc, ta, astate_old, &ti_old);
1291 IPFW_UH_WUNLOCK(ch);
1292
1293 /*
1294 * Stage 5: perform real flush/destroy.
1295 */
1296 ta->destroy(astate_old, &ti_old);
1297
443 return (0);
444}
445
1298 return (0);
1299}
1300
446void
447ipfw_destroy_tables(struct ip_fw_chain *ch)
1301/*
1302 * Swaps two tables.
1303 * Data layout (v0)(current):
1304 * Request: [ ipfw_obj_header ipfw_obj_ntlv ]
1305 *
1306 * Returns 0 on success
1307 */
1308static int
1309swap_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1310 struct sockopt_data *sd)
448{
1311{
449 uint16_t tbl;
1312 int error;
1313 struct _ipfw_obj_header *oh;
1314 struct tid_info ti_a, ti_b;
450
1315
451 /* Flush all tables */
452 for (tbl = 0; tbl < V_fw_tables_max; tbl++)
453 ipfw_flush_table(ch, tbl);
1316 if (sd->valsize != sizeof(*oh) + sizeof(ipfw_obj_ntlv))
1317 return (EINVAL);
454
1318
455 /* Free pointers itself */
456 free(ch->tables, M_IPFW);
457 free(ch->xtables, M_IPFW);
458 free(ch->tabletype, M_IPFW);
1319 oh = (struct _ipfw_obj_header *)op3;
1320 ntlv_to_ti(&oh->ntlv, &ti_a);
1321 ntlv_to_ti((ipfw_obj_ntlv *)(oh + 1), &ti_b);
1322
1323 error = swap_tables(ch, &ti_a, &ti_b);
1324
1325 return (error);
459}
460
1326}
1327
461int
462ipfw_init_tables(struct ip_fw_chain *ch)
1328/*
1329 * Swaps two tables of the same type/valtype.
1330 *
1331 * Checks if tables are compatible and limits
1332 * permits swap, than actually perform swap.
1333 *
1334 * Each table consists of 2 different parts:
1335 * config:
1336 * @tc (with name, set, kidx) and rule bindings, which is "stable".
1337 * number of items
1338 * table algo
1339 * runtime:
1340 * runtime data @ti (ch->tablestate)
1341 * runtime cache in @tc
1342 * algo-specific data (@tc->astate)
1343 *
1344 * So we switch:
1345 * all runtime data
1346 * number of items
1347 * table algo
1348 *
1349 * After that we call @ti change handler for each table.
1350 *
1351 * Note that referencing @tc won't protect tc->ta from change.
1352 * XXX: Do we need to restrict swap between locked tables?
1353 * XXX: Do we need to exchange ftype?
1354 *
1355 * Returns 0 on success.
1356 */
1357static int
1358swap_tables(struct ip_fw_chain *ch, struct tid_info *a,
1359 struct tid_info *b)
463{
1360{
464 /* Allocate pointers */
465 ch->tables = malloc(V_fw_tables_max * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
466 ch->xtables = malloc(V_fw_tables_max * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
467 ch->tabletype = malloc(V_fw_tables_max * sizeof(uint8_t), M_IPFW, M_WAITOK | M_ZERO);
1361 struct namedobj_instance *ni;
1362 struct table_config *tc_a, *tc_b;
1363 struct table_algo *ta;
1364 struct table_info ti, *tablestate;
1365 void *astate;
1366 uint32_t count;
1367
1368 /*
1369 * Stage 1: find both tables and ensure they are of
1370 * the same type.
1371 */
1372 IPFW_UH_WLOCK(ch);
1373 ni = CHAIN_TO_NI(ch);
1374 if ((tc_a = find_table(ni, a)) == NULL) {
1375 IPFW_UH_WUNLOCK(ch);
1376 return (ESRCH);
1377 }
1378 if ((tc_b = find_table(ni, b)) == NULL) {
1379 IPFW_UH_WUNLOCK(ch);
1380 return (ESRCH);
1381 }
1382
1383 /* It is very easy to swap between the same table */
1384 if (tc_a == tc_b) {
1385 IPFW_UH_WUNLOCK(ch);
1386 return (0);
1387 }
1388
1389 /* Check type and value are the same */
1390 if (tc_a->no.type != tc_b->no.type || tc_a->tflags != tc_b->tflags) {
1391 IPFW_UH_WUNLOCK(ch);
1392 return (EINVAL);
1393 }
1394
1395 /* Check limits before swap */
1396 if ((tc_a->limit != 0 && tc_b->count > tc_a->limit) ||
1397 (tc_b->limit != 0 && tc_a->count > tc_b->limit)) {
1398 IPFW_UH_WUNLOCK(ch);
1399 return (EFBIG);
1400 }
1401
1402 /* Check if one of the tables is readonly */
1403 if (((tc_a->ta->flags | tc_b->ta->flags) & TA_FLAG_READONLY) != 0) {
1404 IPFW_UH_WUNLOCK(ch);
1405 return (EACCES);
1406 }
1407
1408 /* Notify we're going to swap */
1409 rollback_toperation_state(ch, tc_a);
1410 rollback_toperation_state(ch, tc_b);
1411
1412 /* Everything is fine, prepare to swap */
1413 tablestate = (struct table_info *)ch->tablestate;
1414 ti = tablestate[tc_a->no.kidx];
1415 ta = tc_a->ta;
1416 astate = tc_a->astate;
1417 count = tc_a->count;
1418
1419 IPFW_WLOCK(ch);
1420 /* a <- b */
1421 tablestate[tc_a->no.kidx] = tablestate[tc_b->no.kidx];
1422 tc_a->ta = tc_b->ta;
1423 tc_a->astate = tc_b->astate;
1424 tc_a->count = tc_b->count;
1425 /* b <- a */
1426 tablestate[tc_b->no.kidx] = ti;
1427 tc_b->ta = ta;
1428 tc_b->astate = astate;
1429 tc_b->count = count;
1430 IPFW_WUNLOCK(ch);
1431
1432 /* Ensure tc.ti copies are in sync */
1433 tc_a->ti_copy = tablestate[tc_a->no.kidx];
1434 tc_b->ti_copy = tablestate[tc_b->no.kidx];
1435
1436 /* Notify both tables on @ti change */
1437 if (tc_a->ta->change_ti != NULL)
1438 tc_a->ta->change_ti(tc_a->astate, &tablestate[tc_a->no.kidx]);
1439 if (tc_b->ta->change_ti != NULL)
1440 tc_b->ta->change_ti(tc_b->astate, &tablestate[tc_b->no.kidx]);
1441
1442 IPFW_UH_WUNLOCK(ch);
1443
468 return (0);
469}
470
1444 return (0);
1445}
1446
1447/*
1448 * Destroys table specified by @ti.
1449 * Data layout (v0)(current):
1450 * Request: [ ip_fw3_opheader ]
1451 *
1452 * Returns 0 on success
1453 */
1454static int
1455destroy_table(struct ip_fw_chain *ch, struct tid_info *ti)
1456{
1457 struct namedobj_instance *ni;
1458 struct table_config *tc;
1459
1460 IPFW_UH_WLOCK(ch);
1461
1462 ni = CHAIN_TO_NI(ch);
1463 if ((tc = find_table(ni, ti)) == NULL) {
1464 IPFW_UH_WUNLOCK(ch);
1465 return (ESRCH);
1466 }
1467
1468 /* Do not permit destroying referenced tables */
1469 if (tc->no.refcnt > 0) {
1470 IPFW_UH_WUNLOCK(ch);
1471 return (EBUSY);
1472 }
1473
1474 IPFW_WLOCK(ch);
1475 unlink_table(ch, tc);
1476 IPFW_WUNLOCK(ch);
1477
1478 /* Free obj index */
1479 if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0)
1480 printf("Error unlinking kidx %d from table %s\n",
1481 tc->no.kidx, tc->tablename);
1482
1483 /* Unref values used in tables while holding UH lock */
1484 ipfw_unref_table_values(ch, tc, tc->ta, tc->astate, &tc->ti_copy);
1485 IPFW_UH_WUNLOCK(ch);
1486
1487 free_table_config(ni, tc);
1488
1489 return (0);
1490}
1491
1492/*
1493 * Grow tables index.
1494 *
1495 * Returns 0 on success.
1496 */
471int
472ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
473{
1497int
1498ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
1499{
474 struct radix_node_head **tables, **xtables, *rnh;
475 struct radix_node_head **tables_old, **xtables_old;
476 uint8_t *tabletype, *tabletype_old;
477 unsigned int ntables_old, tbl;
1500 unsigned int ntables_old, tbl;
1501 struct namedobj_instance *ni;
1502 void *new_idx, *old_tablestate, *tablestate;
1503 struct table_info *ti;
1504 struct table_config *tc;
1505 int i, new_blocks;
478
479 /* Check new value for validity */
480 if (ntables > IPFW_TABLES_MAX)
481 ntables = IPFW_TABLES_MAX;
482
483 /* Allocate new pointers */
1506
1507 /* Check new value for validity */
1508 if (ntables > IPFW_TABLES_MAX)
1509 ntables = IPFW_TABLES_MAX;
1510
1511 /* Allocate new pointers */
484 tables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
485 xtables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
486 tabletype = malloc(ntables * sizeof(uint8_t), M_IPFW, M_WAITOK | M_ZERO);
1512 tablestate = malloc(ntables * sizeof(struct table_info),
1513 M_IPFW, M_WAITOK | M_ZERO);
487
1514
488 IPFW_WLOCK(ch);
1515 ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks);
489
1516
1517 IPFW_UH_WLOCK(ch);
1518
490 tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;
1519 tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;
1520 ni = CHAIN_TO_NI(ch);
491
1521
492 /* Copy old table pointers */
493 memcpy(tables, ch->tables, sizeof(void *) * tbl);
494 memcpy(xtables, ch->xtables, sizeof(void *) * tbl);
495 memcpy(tabletype, ch->tabletype, sizeof(uint8_t) * tbl);
1522 /* Temporary restrict decreasing max_tables */
1523 if (ntables < V_fw_tables_max) {
496
1524
497 /* Change pointers and number of tables */
498 tables_old = ch->tables;
499 xtables_old = ch->xtables;
500 tabletype_old = ch->tabletype;
501 ch->tables = tables;
502 ch->xtables = xtables;
503 ch->tabletype = tabletype;
1525 /*
1526 * FIXME: Check if we really can shrink
1527 */
1528 IPFW_UH_WUNLOCK(ch);
1529 return (EINVAL);
1530 }
504
1531
1532 /* Copy table info/indices */
1533 memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl);
1534 ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks);
1535
1536 IPFW_WLOCK(ch);
1537
1538 /* Change pointers */
1539 old_tablestate = ch->tablestate;
1540 ch->tablestate = tablestate;
1541 ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks);
1542
505 ntables_old = V_fw_tables_max;
506 V_fw_tables_max = ntables;
507
508 IPFW_WUNLOCK(ch);
509
1543 ntables_old = V_fw_tables_max;
1544 V_fw_tables_max = ntables;
1545
1546 IPFW_WUNLOCK(ch);
1547
510 /* Check if we need to destroy radix trees */
511 if (ntables < ntables_old) {
512 for (tbl = ntables; tbl < ntables_old; tbl++) {
513 if ((rnh = tables_old[tbl]) != NULL) {
514 rnh->rnh_walktree(rnh, flush_table_entry, rnh);
515 rn_detachhead((void **)&rnh);
516 }
1548 /* Notify all consumers that their @ti pointer has changed */
1549 ti = (struct table_info *)ch->tablestate;
1550 for (i = 0; i < tbl; i++, ti++) {
1551 if (ti->lookup == NULL)
1552 continue;
1553 tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, i);
1554 if (tc == NULL || tc->ta->change_ti == NULL)
1555 continue;
517
1556
518 if ((rnh = xtables_old[tbl]) != NULL) {
519 rnh->rnh_walktree(rnh, flush_table_entry, rnh);
520 rn_detachhead((void **)&rnh);
1557 tc->ta->change_ti(tc->astate, ti);
1558 }
1559
1560 IPFW_UH_WUNLOCK(ch);
1561
1562 /* Free old pointers */
1563 free(old_tablestate, M_IPFW);
1564 ipfw_objhash_bitmap_free(new_idx, new_blocks);
1565
1566 return (0);
1567}
1568
1569/*
1570 * Switch between "set 0" and "rule's set" table binding,
1571 * Check all ruleset bindings and permits changing
1572 * IFF each binding has both rule AND table in default set (set 0).
1573 *
1574 * Returns 0 on success.
1575 */
1576int
1577ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets)
1578{
1579 struct namedobj_instance *ni;
1580 struct named_object *no;
1581 struct ip_fw *rule;
1582 ipfw_insn *cmd;
1583 int cmdlen, i, l;
1584 uint16_t kidx;
1585 uint8_t type;
1586
1587 IPFW_UH_WLOCK(ch);
1588
1589 if (V_fw_tables_sets == sets) {
1590 IPFW_UH_WUNLOCK(ch);
1591 return (0);
1592 }
1593
1594 ni = CHAIN_TO_NI(ch);
1595
1596 /*
1597 * Scan all rules and examine tables opcodes.
1598 */
1599 for (i = 0; i < ch->n_rules; i++) {
1600 rule = ch->map[i];
1601
1602 l = rule->cmd_len;
1603 cmd = rule->cmd;
1604 cmdlen = 0;
1605 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
1606 cmdlen = F_LEN(cmd);
1607
1608 if (classify_table_opcode(cmd, &kidx, &type) != 0)
1609 continue;
1610
1611 no = ipfw_objhash_lookup_kidx(ni, kidx);
1612
1613 /* Check if both table object and rule has the set 0 */
1614 if (no->set != 0 || rule->set != 0) {
1615 IPFW_UH_WUNLOCK(ch);
1616 return (EBUSY);
521 }
1617 }
1618
522 }
523 }
1619 }
1620 }
1621 V_fw_tables_sets = sets;
524
1622
525 /* Free old pointers */
526 free(tables_old, M_IPFW);
527 free(xtables_old, M_IPFW);
528 free(tabletype_old, M_IPFW);
1623 IPFW_UH_WUNLOCK(ch);
529
530 return (0);
531}
532
1624
1625 return (0);
1626}
1627
1628/*
1629 * Lookup an IP @addr in table @tbl.
1630 * Stores found value in @val.
1631 *
1632 * Returns 1 if @addr was found.
1633 */
533int
534ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
535 uint32_t *val)
536{
1634int
1635ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
1636 uint32_t *val)
1637{
537 struct radix_node_head *rnh;
538 struct table_entry *ent;
539 struct sockaddr_in sa;
1638 struct table_info *ti;
540
1639
541 if (tbl >= V_fw_tables_max)
542 return (0);
543 if ((rnh = ch->tables[tbl]) == NULL)
544 return (0);
545 KEY_LEN(sa) = KEY_LEN_INET;
546 sa.sin_addr.s_addr = addr;
547 ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh));
548 if (ent != NULL) {
549 *val = ent->value;
550 return (1);
1640 ti = KIDX_TO_TI(ch, tbl);
1641
1642 return (ti->lookup(ti, &addr, sizeof(in_addr_t), val));
1643}
1644
1645/*
1646 * Lookup an arbtrary key @paddr of legth @plen in table @tbl.
1647 * Stores found value in @val.
1648 *
1649 * Returns 1 if key was found.
1650 */
1651int
1652ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
1653 void *paddr, uint32_t *val)
1654{
1655 struct table_info *ti;
1656
1657 ti = KIDX_TO_TI(ch, tbl);
1658
1659 return (ti->lookup(ti, paddr, plen, val));
1660}
1661
1662/*
1663 * Info/List/dump support for tables.
1664 *
1665 */
1666
1667/*
1668 * High-level 'get' cmds sysctl handlers
1669 */
1670
1671/*
1672 * Lists all tables currently available in kernel.
1673 * Data layout (v0)(current):
1674 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
1675 * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ]
1676 *
1677 * Returns 0 on success
1678 */
1679static int
1680list_tables(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1681 struct sockopt_data *sd)
1682{
1683 struct _ipfw_obj_lheader *olh;
1684 int error;
1685
1686 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
1687 if (olh == NULL)
1688 return (EINVAL);
1689 if (sd->valsize < olh->size)
1690 return (EINVAL);
1691
1692 IPFW_UH_RLOCK(ch);
1693 error = export_tables(ch, olh, sd);
1694 IPFW_UH_RUNLOCK(ch);
1695
1696 return (error);
1697}
1698
1699/*
1700 * Store table info to buffer provided by @sd.
1701 * Data layout (v0)(current):
1702 * Request: [ ipfw_obj_header ipfw_xtable_info(empty)]
1703 * Reply: [ ipfw_obj_header ipfw_xtable_info ]
1704 *
1705 * Returns 0 on success.
1706 */
1707static int
1708describe_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1709 struct sockopt_data *sd)
1710{
1711 struct _ipfw_obj_header *oh;
1712 struct table_config *tc;
1713 struct tid_info ti;
1714 size_t sz;
1715
1716 sz = sizeof(*oh) + sizeof(ipfw_xtable_info);
1717 oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
1718 if (oh == NULL)
1719 return (EINVAL);
1720
1721 objheader_to_ti(oh, &ti);
1722
1723 IPFW_UH_RLOCK(ch);
1724 if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
1725 IPFW_UH_RUNLOCK(ch);
1726 return (ESRCH);
551 }
1727 }
1728
1729 export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1));
1730 IPFW_UH_RUNLOCK(ch);
1731
552 return (0);
553}
554
1732 return (0);
1733}
1734
555int
556ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
557 uint32_t *val, int type)
1735/*
1736 * Modifies existing table.
1737 * Data layout (v0)(current):
1738 * Request: [ ipfw_obj_header ipfw_xtable_info ]
1739 *
1740 * Returns 0 on success
1741 */
1742static int
1743modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1744 struct sockopt_data *sd)
558{
1745{
559 struct radix_node_head *rnh;
560 struct table_xentry *xent;
561 struct sockaddr_in6 sa6;
562 struct xaddr_iface iface;
1746 struct _ipfw_obj_header *oh;
1747 ipfw_xtable_info *i;
1748 char *tname;
1749 struct tid_info ti;
1750 struct namedobj_instance *ni;
1751 struct table_config *tc;
563
1752
564 if (tbl >= V_fw_tables_max)
565 return (0);
566 if ((rnh = ch->xtables[tbl]) == NULL)
567 return (0);
1753 if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
1754 return (EINVAL);
568
1755
569 switch (type) {
570 case IPFW_TABLE_CIDR:
571 KEY_LEN(sa6) = KEY_LEN_INET6;
572 memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr));
573 xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
574 break;
1756 oh = (struct _ipfw_obj_header *)sd->kbuf;
1757 i = (ipfw_xtable_info *)(oh + 1);
575
1758
576 case IPFW_TABLE_INTERFACE:
577 KEY_LEN(iface) = KEY_LEN_IFACE +
578 strlcpy(iface.ifname, (char *)paddr, IF_NAMESIZE) + 1;
579 /* Assume direct match */
580 /* FIXME: Add interface pattern matching */
581 xent = (struct table_xentry *)(rnh->rnh_matchaddr(&iface, rnh));
582 break;
1759 /*
1760 * Verify user-supplied strings.
1761 * Check for null-terminated/zero-length strings/
1762 */
1763 tname = oh->ntlv.name;
1764 if (ipfw_check_table_name(tname) != 0)
1765 return (EINVAL);
583
1766
584 default:
585 return (0);
1767 objheader_to_ti(oh, &ti);
1768 ti.type = i->type;
1769
1770 IPFW_UH_WLOCK(ch);
1771 ni = CHAIN_TO_NI(ch);
1772 if ((tc = find_table(ni, &ti)) == NULL) {
1773 IPFW_UH_WUNLOCK(ch);
1774 return (ESRCH);
586 }
587
1775 }
1776
588 if (xent != NULL) {
589 *val = xent->value;
590 return (1);
1777 /* Do not support any modifications for readonly tables */
1778 if ((tc->ta->flags & TA_FLAG_READONLY) != 0) {
1779 IPFW_UH_WUNLOCK(ch);
1780 return (EACCES);
591 }
1781 }
1782
1783 if ((i->mflags & IPFW_TMFLAGS_LIMIT) != 0)
1784 tc->limit = i->limit;
1785 if ((i->mflags & IPFW_TMFLAGS_LOCK) != 0)
1786 tc->locked = ((i->flags & IPFW_TGFLAGS_LOCKED) != 0);
1787 IPFW_UH_WUNLOCK(ch);
1788
592 return (0);
593}
594
1789 return (0);
1790}
1791
1792/*
1793 * Creates new table.
1794 * Data layout (v0)(current):
1795 * Request: [ ipfw_obj_header ipfw_xtable_info ]
1796 *
1797 * Returns 0 on success
1798 */
595static int
1799static int
596count_table_entry(struct radix_node *rn, void *arg)
1800create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
1801 struct sockopt_data *sd)
597{
1802{
598 u_int32_t * const cnt = arg;
1803 struct _ipfw_obj_header *oh;
1804 ipfw_xtable_info *i;
1805 char *tname, *aname;
1806 struct tid_info ti;
1807 struct namedobj_instance *ni;
1808 struct table_config *tc;
599
1809
600 (*cnt)++;
1810 if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info))
1811 return (EINVAL);
1812
1813 oh = (struct _ipfw_obj_header *)sd->kbuf;
1814 i = (ipfw_xtable_info *)(oh + 1);
1815
1816 /*
1817 * Verify user-supplied strings.
1818 * Check for null-terminated/zero-length strings/
1819 */
1820 tname = oh->ntlv.name;
1821 aname = i->algoname;
1822 if (ipfw_check_table_name(tname) != 0 ||
1823 strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname))
1824 return (EINVAL);
1825
1826 if (aname[0] == '\0') {
1827 /* Use default algorithm */
1828 aname = NULL;
1829 }
1830
1831 objheader_to_ti(oh, &ti);
1832 ti.type = i->type;
1833
1834 ni = CHAIN_TO_NI(ch);
1835
1836 IPFW_UH_RLOCK(ch);
1837 if ((tc = find_table(ni, &ti)) != NULL) {
1838 IPFW_UH_RUNLOCK(ch);
1839 return (EEXIST);
1840 }
1841 IPFW_UH_RUNLOCK(ch);
1842
1843 return (create_table_internal(ch, &ti, aname, i, NULL, 0));
1844}
1845
1846/*
1847 * Creates new table based on @ti and @aname.
1848 *
1849 * Relies on table name checking inside find_name_tlv()
1850 * Assume @aname to be checked and valid.
1851 * Stores allocated table kidx inside @pkidx (if non-NULL).
1852 * Reference created table if @compat is non-zero.
1853 *
1854 * Returns 0 on success.
1855 */
1856static int
1857create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti,
1858 char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int compat)
1859{
1860 struct namedobj_instance *ni;
1861 struct table_config *tc, *tc_new, *tmp;
1862 struct table_algo *ta;
1863 uint16_t kidx;
1864
1865 ni = CHAIN_TO_NI(ch);
1866
1867 ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname);
1868 if (ta == NULL)
1869 return (ENOTSUP);
1870
1871 tc = alloc_table_config(ch, ti, ta, aname, i->tflags);
1872 if (tc == NULL)
1873 return (ENOMEM);
1874
1875 tc->vmask = i->vmask;
1876 tc->limit = i->limit;
1877 if (ta->flags & TA_FLAG_READONLY)
1878 tc->locked = 1;
1879 else
1880 tc->locked = (i->flags & IPFW_TGFLAGS_LOCKED) != 0;
1881
1882 IPFW_UH_WLOCK(ch);
1883
1884 /* Check if table has been already created */
1885 tc_new = find_table(ni, ti);
1886 if (tc_new != NULL) {
1887
1888 /*
1889 * Compat: do not fail if we're
1890 * requesting to create existing table
1891 * which has the same type
1892 */
1893 if (compat == 0 || tc_new->no.type != tc->no.type) {
1894 IPFW_UH_WUNLOCK(ch);
1895 free_table_config(ni, tc);
1896 return (EEXIST);
1897 }
1898
1899 /* Exchange tc and tc_new for proper refcounting & freeing */
1900 tmp = tc;
1901 tc = tc_new;
1902 tc_new = tmp;
1903 } else {
1904 /* New table */
1905 if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) {
1906 IPFW_UH_WUNLOCK(ch);
1907 printf("Unable to allocate table index."
1908 " Consider increasing net.inet.ip.fw.tables_max");
1909 free_table_config(ni, tc);
1910 return (EBUSY);
1911 }
1912 tc->no.kidx = kidx;
1913
1914 IPFW_WLOCK(ch);
1915 link_table(ch, tc);
1916 IPFW_WUNLOCK(ch);
1917 }
1918
1919 if (compat != 0)
1920 tc->no.refcnt++;
1921 if (pkidx != NULL)
1922 *pkidx = tc->no.kidx;
1923
1924 IPFW_UH_WUNLOCK(ch);
1925
1926 if (tc_new != NULL)
1927 free_table_config(ni, tc_new);
1928
601 return (0);
602}
603
1929 return (0);
1930}
1931
1932static void
1933ntlv_to_ti(ipfw_obj_ntlv *ntlv, struct tid_info *ti)
1934{
1935
1936 memset(ti, 0, sizeof(struct tid_info));
1937 ti->set = ntlv->set;
1938 ti->uidx = ntlv->idx;
1939 ti->tlvs = ntlv;
1940 ti->tlen = ntlv->head.length;
1941}
1942
1943static void
1944objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
1945{
1946
1947 ntlv_to_ti(&oh->ntlv, ti);
1948}
1949
1950/*
1951 * Exports basic table info as name TLV.
1952 * Used inside dump_static_rules() to provide info
1953 * about all tables referenced by current ruleset.
1954 *
1955 * Returns 0 on success.
1956 */
604int
1957int
605ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)
1958ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
1959 struct sockopt_data *sd)
606{
1960{
607 struct radix_node_head *rnh;
1961 struct namedobj_instance *ni;
1962 struct named_object *no;
1963 ipfw_obj_ntlv *ntlv;
608
1964
609 if (tbl >= V_fw_tables_max)
610 return (EINVAL);
611 *cnt = 0;
612 if ((rnh = ch->tables[tbl]) == NULL)
613 return (0);
614 rnh->rnh_walktree(rnh, count_table_entry, cnt);
1965 ni = CHAIN_TO_NI(ch);
1966
1967 no = ipfw_objhash_lookup_kidx(ni, kidx);
1968 KASSERT(no != NULL, ("invalid table kidx passed"));
1969
1970 ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
1971 if (ntlv == NULL)
1972 return (ENOMEM);
1973
1974 ntlv->head.type = IPFW_TLV_TBL_NAME;
1975 ntlv->head.length = sizeof(*ntlv);
1976 ntlv->idx = no->kidx;
1977 strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
1978
615 return (0);
616}
617
1979 return (0);
1980}
1981
618static int
619dump_table_entry(struct radix_node *rn, void *arg)
1982/*
1983 * Marks every table kidx used in @rule with bit in @bmask.
1984 * Used to generate bitmask of referenced tables for given ruleset.
1985 *
1986 * Returns number of newly-referenced tables.
1987 */
1988int
1989ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
1990 uint32_t *bmask)
620{
1991{
621 struct table_entry * const n = (struct table_entry *)rn;
622 ipfw_table * const tbl = arg;
1992 int cmdlen, l, count;
1993 ipfw_insn *cmd;
1994 uint16_t kidx;
1995 uint8_t type;
1996
1997 l = rule->cmd_len;
1998 cmd = rule->cmd;
1999 cmdlen = 0;
2000 count = 0;
2001 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2002 cmdlen = F_LEN(cmd);
2003
2004 if (classify_table_opcode(cmd, &kidx, &type) != 0)
2005 continue;
2006
2007 if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
2008 count++;
2009
2010 bmask[kidx / 32] |= 1 << (kidx % 32);
2011 }
2012
2013 return (count);
2014}
2015
2016struct dump_args {
2017 struct ip_fw_chain *ch;
2018 struct table_info *ti;
2019 struct table_config *tc;
2020 struct sockopt_data *sd;
2021 uint32_t cnt;
2022 uint16_t uidx;
2023 int error;
2024 uint32_t size;
623 ipfw_table_entry *ent;
2025 ipfw_table_entry *ent;
2026 ta_foreach_f *f;
2027 void *farg;
2028 ipfw_obj_tentry tent;
2029};
624
2030
625 if (tbl->cnt == tbl->size)
626 return (1);
627 ent = &tbl->ent[tbl->cnt];
628 ent->tbl = tbl->tbl;
629 if (in_nullhost(n->mask.sin_addr))
630 ent->masklen = 0;
631 else
632 ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
633 ent->addr = n->addr.sin_addr.s_addr;
634 ent->value = n->value;
635 tbl->cnt++;
2031static int
2032count_ext_entries(void *e, void *arg)
2033{
2034 struct dump_args *da;
2035
2036 da = (struct dump_args *)arg;
2037 da->cnt++;
2038
636 return (0);
637}
638
2039 return (0);
2040}
2041
639int
640ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl)
2042/*
2043 * Gets number of items from table either using
2044 * internal counter or calling algo callback for
2045 * externally-managed tables.
2046 *
2047 * Returns number of records.
2048 */
2049static uint32_t
2050table_get_count(struct ip_fw_chain *ch, struct table_config *tc)
641{
2051{
642 struct radix_node_head *rnh;
2052 struct table_info *ti;
2053 struct table_algo *ta;
2054 struct dump_args da;
643
2055
644 if (tbl->tbl >= V_fw_tables_max)
2056 ti = KIDX_TO_TI(ch, tc->no.kidx);
2057 ta = tc->ta;
2058
2059 /* Use internal counter for self-managed tables */
2060 if ((ta->flags & TA_FLAG_READONLY) == 0)
2061 return (tc->count);
2062
2063 /* Use callback to quickly get number of items */
2064 if ((ta->flags & TA_FLAG_EXTCOUNTER) != 0)
2065 return (ta->get_count(tc->astate, ti));
2066
2067 /* Count number of iterms ourselves */
2068 memset(&da, 0, sizeof(da));
2069 ta->foreach(tc->astate, ti, count_ext_entries, &da);
2070
2071 return (da.cnt);
2072}
2073
2074/*
2075 * Exports table @tc info into standard ipfw_xtable_info format.
2076 */
2077static void
2078export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
2079 ipfw_xtable_info *i)
2080{
2081 struct table_info *ti;
2082 struct table_algo *ta;
2083
2084 i->type = tc->no.type;
2085 i->tflags = tc->tflags;
2086 i->vmask = tc->vmask;
2087 i->set = tc->no.set;
2088 i->kidx = tc->no.kidx;
2089 i->refcnt = tc->no.refcnt;
2090 i->count = table_get_count(ch, tc);
2091 i->limit = tc->limit;
2092 i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0;
2093 i->size = tc->count * sizeof(ipfw_obj_tentry);
2094 i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
2095 strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
2096 ti = KIDX_TO_TI(ch, tc->no.kidx);
2097 ta = tc->ta;
2098 if (ta->print_config != NULL) {
2099 /* Use algo function to print table config to string */
2100 ta->print_config(tc->astate, ti, i->algoname,
2101 sizeof(i->algoname));
2102 } else
2103 strlcpy(i->algoname, ta->name, sizeof(i->algoname));
2104 /* Dump algo-specific data, if possible */
2105 if (ta->dump_tinfo != NULL) {
2106 ta->dump_tinfo(tc->astate, ti, &i->ta_info);
2107 i->ta_info.flags |= IPFW_TATFLAGS_DATA;
2108 }
2109}
2110
2111struct dump_table_args {
2112 struct ip_fw_chain *ch;
2113 struct sockopt_data *sd;
2114};
2115
2116static void
2117export_table_internal(struct namedobj_instance *ni, struct named_object *no,
2118 void *arg)
2119{
2120 ipfw_xtable_info *i;
2121 struct dump_table_args *dta;
2122
2123 dta = (struct dump_table_args *)arg;
2124
2125 i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i));
2126 KASSERT(i != 0, ("previously checked buffer is not enough"));
2127
2128 export_table_info(dta->ch, (struct table_config *)no, i);
2129}
2130
2131/*
2132 * Export all tables as ipfw_xtable_info structures to
2133 * storage provided by @sd.
2134 *
2135 * If supplied buffer is too small, fills in required size
2136 * and returns ENOMEM.
2137 * Returns 0 on success.
2138 */
2139static int
2140export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh,
2141 struct sockopt_data *sd)
2142{
2143 uint32_t size;
2144 uint32_t count;
2145 struct dump_table_args dta;
2146
2147 count = ipfw_objhash_count(CHAIN_TO_NI(ch));
2148 size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader);
2149
2150 /* Fill in header regadless of buffer size */
2151 olh->count = count;
2152 olh->objsize = sizeof(ipfw_xtable_info);
2153
2154 if (size > olh->size) {
2155 olh->size = size;
2156 return (ENOMEM);
2157 }
2158
2159 olh->size = size;
2160
2161 dta.ch = ch;
2162 dta.sd = sd;
2163
2164 ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta);
2165
2166 return (0);
2167}
2168
2169/*
2170 * Dumps all table data
2171 * Data layout (v1)(current):
2172 * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size
2173 * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ]
2174 *
2175 * Returns 0 on success
2176 */
2177static int
2178dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
2179 struct sockopt_data *sd)
2180{
2181 struct _ipfw_obj_header *oh;
2182 ipfw_xtable_info *i;
2183 struct tid_info ti;
2184 struct table_config *tc;
2185 struct table_algo *ta;
2186 struct dump_args da;
2187 uint32_t sz;
2188
2189 sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
2190 oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
2191 if (oh == NULL)
645 return (EINVAL);
2192 return (EINVAL);
646 tbl->cnt = 0;
647 if ((rnh = ch->tables[tbl->tbl]) == NULL)
2193
2194 i = (ipfw_xtable_info *)(oh + 1);
2195 objheader_to_ti(oh, &ti);
2196
2197 IPFW_UH_RLOCK(ch);
2198 if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
2199 IPFW_UH_RUNLOCK(ch);
2200 return (ESRCH);
2201 }
2202 export_table_info(ch, tc, i);
2203
2204 if (sd->valsize < i->size) {
2205
2206 /*
2207 * Submitted buffer size is not enough.
2208 * WE've already filled in @i structure with
2209 * relevant table info including size, so we
2210 * can return. Buffer will be flushed automatically.
2211 */
2212 IPFW_UH_RUNLOCK(ch);
2213 return (ENOMEM);
2214 }
2215
2216 /*
2217 * Do the actual dump in eXtended format
2218 */
2219 memset(&da, 0, sizeof(da));
2220 da.ch = ch;
2221 da.ti = KIDX_TO_TI(ch, tc->no.kidx);
2222 da.tc = tc;
2223 da.sd = sd;
2224
2225 ta = tc->ta;
2226
2227 ta->foreach(tc->astate, da.ti, dump_table_tentry, &da);
2228 IPFW_UH_RUNLOCK(ch);
2229
2230 return (da.error);
2231}
2232
2233/*
2234 * Dumps all table data
2235 * Data layout (version 0)(legacy):
2236 * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE()
2237 * Reply: [ ipfw_xtable ipfw_table_xentry x N ]
2238 *
2239 * Returns 0 on success
2240 */
2241static int
2242dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
2243 struct sockopt_data *sd)
2244{
2245 ipfw_xtable *xtbl;
2246 struct tid_info ti;
2247 struct table_config *tc;
2248 struct table_algo *ta;
2249 struct dump_args da;
2250 size_t sz, count;
2251
2252 xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable));
2253 if (xtbl == NULL)
2254 return (EINVAL);
2255
2256 memset(&ti, 0, sizeof(ti));
2257 ti.uidx = xtbl->tbl;
2258
2259 IPFW_UH_RLOCK(ch);
2260 if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) {
2261 IPFW_UH_RUNLOCK(ch);
648 return (0);
2262 return (0);
649 rnh->rnh_walktree(rnh, dump_table_entry, tbl);
2263 }
2264 count = table_get_count(ch, tc);
2265 sz = count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable);
2266
2267 xtbl->cnt = count;
2268 xtbl->size = sz;
2269 xtbl->type = tc->no.type;
2270 xtbl->tbl = ti.uidx;
2271
2272 if (sd->valsize < sz) {
2273
2274 /*
2275 * Submitted buffer size is not enough.
2276 * WE've already filled in @i structure with
2277 * relevant table info including size, so we
2278 * can return. Buffer will be flushed automatically.
2279 */
2280 IPFW_UH_RUNLOCK(ch);
2281 return (ENOMEM);
2282 }
2283
2284 /* Do the actual dump in eXtended format */
2285 memset(&da, 0, sizeof(da));
2286 da.ch = ch;
2287 da.ti = KIDX_TO_TI(ch, tc->no.kidx);
2288 da.tc = tc;
2289 da.sd = sd;
2290
2291 ta = tc->ta;
2292
2293 ta->foreach(tc->astate, da.ti, dump_table_xentry, &da);
2294 IPFW_UH_RUNLOCK(ch);
2295
650 return (0);
651}
652
2296 return (0);
2297}
2298
2299/*
2300 * Legacy function to retrieve number of items in table.
2301 */
653static int
2302static int
654count_table_xentry(struct radix_node *rn, void *arg)
2303get_table_size(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
2304 struct sockopt_data *sd)
655{
2305{
656 uint32_t * const cnt = arg;
2306 uint32_t *tbl;
2307 struct tid_info ti;
2308 size_t sz;
2309 int error;
657
2310
658 (*cnt) += sizeof(ipfw_table_xentry);
2311 sz = sizeof(*op3) + sizeof(uint32_t);
2312 op3 = (ip_fw3_opheader *)ipfw_get_sopt_header(sd, sz);
2313 if (op3 == NULL)
2314 return (EINVAL);
2315
2316 tbl = (uint32_t *)(op3 + 1);
2317 memset(&ti, 0, sizeof(ti));
2318 ti.uidx = *tbl;
2319 IPFW_UH_RLOCK(ch);
2320 error = ipfw_count_xtable(ch, &ti, tbl);
2321 IPFW_UH_RUNLOCK(ch);
2322 return (error);
2323}
2324
2325/*
2326 * Legacy IP_FW_TABLE_GETSIZE handler
2327 */
2328int
2329ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
2330{
2331 struct table_config *tc;
2332
2333 if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
2334 return (ESRCH);
2335 *cnt = table_get_count(ch, tc);
659 return (0);
660}
661
2336 return (0);
2337}
2338
2339/*
2340 * Legacy IP_FW_TABLE_XGETSIZE handler
2341 */
662int
2342int
663ipfw_count_xtable(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)
2343ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt)
664{
2344{
665 struct radix_node_head *rnh;
2345 struct table_config *tc;
2346 uint32_t count;
666
2347
667 if (tbl >= V_fw_tables_max)
668 return (EINVAL);
669 *cnt = 0;
670 if ((rnh = ch->tables[tbl]) != NULL)
671 rnh->rnh_walktree(rnh, count_table_xentry, cnt);
672 if ((rnh = ch->xtables[tbl]) != NULL)
673 rnh->rnh_walktree(rnh, count_table_xentry, cnt);
674 /* Return zero if table is empty */
675 if (*cnt > 0)
676 (*cnt) += sizeof(ipfw_xtable);
2348 if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) {
2349 *cnt = 0;
2350 return (0); /* 'table all list' requires success */
2351 }
2352
2353 count = table_get_count(ch, tc);
2354 *cnt = count * sizeof(ipfw_table_xentry);
2355 if (count > 0)
2356 *cnt += sizeof(ipfw_xtable);
677 return (0);
678}
679
2357 return (0);
2358}
2359
2360static int
2361dump_table_entry(void *e, void *arg)
2362{
2363 struct dump_args *da;
2364 struct table_config *tc;
2365 struct table_algo *ta;
2366 ipfw_table_entry *ent;
2367 struct table_value *pval;
2368 int error;
680
2369
2370 da = (struct dump_args *)arg;
2371
2372 tc = da->tc;
2373 ta = tc->ta;
2374
2375 /* Out of memory, returning */
2376 if (da->cnt == da->size)
2377 return (1);
2378 ent = da->ent++;
2379 ent->tbl = da->uidx;
2380 da->cnt++;
2381
2382 error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
2383 if (error != 0)
2384 return (error);
2385
2386 ent->addr = da->tent.k.addr.s_addr;
2387 ent->masklen = da->tent.masklen;
2388 pval = get_table_value(da->ch, da->tc, da->tent.v.kidx);
2389 ent->value = ipfw_export_table_value_legacy(pval);
2390
2391 return (0);
2392}
2393
2394/*
2395 * Dumps table in pre-8.1 legacy format.
2396 */
2397int
2398ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti,
2399 ipfw_table *tbl)
2400{
2401 struct table_config *tc;
2402 struct table_algo *ta;
2403 struct dump_args da;
2404
2405 tbl->cnt = 0;
2406
2407 if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL)
2408 return (0); /* XXX: We should return ESRCH */
2409
2410 ta = tc->ta;
2411
2412 /* This dump format supports IPv4 only */
2413 if (tc->no.type != IPFW_TABLE_ADDR)
2414 return (0);
2415
2416 memset(&da, 0, sizeof(da));
2417 da.ch = ch;
2418 da.ti = KIDX_TO_TI(ch, tc->no.kidx);
2419 da.tc = tc;
2420 da.ent = &tbl->ent[0];
2421 da.size = tbl->size;
2422
2423 tbl->cnt = 0;
2424 ta->foreach(tc->astate, da.ti, dump_table_entry, &da);
2425 tbl->cnt = da.cnt;
2426
2427 return (0);
2428}
2429
2430/*
2431 * Dumps table entry in eXtended format (v1)(current).
2432 */
681static int
2433static int
682dump_table_xentry_base(struct radix_node *rn, void *arg)
2434dump_table_tentry(void *e, void *arg)
683{
2435{
684 struct table_entry * const n = (struct table_entry *)rn;
685 ipfw_xtable * const tbl = arg;
686 ipfw_table_xentry *xent;
2436 struct dump_args *da;
2437 struct table_config *tc;
2438 struct table_algo *ta;
2439 struct table_value *pval;
2440 ipfw_obj_tentry *tent;
2441 int error;
687
2442
2443 da = (struct dump_args *)arg;
2444
2445 tc = da->tc;
2446 ta = tc->ta;
2447
2448 tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent));
688 /* Out of memory, returning */
2449 /* Out of memory, returning */
689 if (tbl->cnt == tbl->size)
2450 if (tent == NULL) {
2451 da->error = ENOMEM;
690 return (1);
2452 return (1);
691 xent = &tbl->xent[tbl->cnt];
692 xent->len = sizeof(ipfw_table_xentry);
693 xent->tbl = tbl->tbl;
694 if (in_nullhost(n->mask.sin_addr))
695 xent->masklen = 0;
696 else
697 xent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
698 /* Save IPv4 address as deprecated IPv6 compatible */
699 xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
700 xent->flags = IPFW_TCF_INET;
701 xent->value = n->value;
702 tbl->cnt++;
2453 }
2454 tent->head.length = sizeof(ipfw_obj_tentry);
2455 tent->idx = da->uidx;
2456
2457 error = ta->dump_tentry(tc->astate, da->ti, e, tent);
2458 if (error != 0)
2459 return (error);
2460
2461 pval = get_table_value(da->ch, da->tc, tent->v.kidx);
2462 ipfw_export_table_value_v1(pval, &tent->v.value);
2463
703 return (0);
704}
705
2464 return (0);
2465}
2466
2467/*
2468 * Dumps table entry in eXtended format (v0).
2469 */
706static int
2470static int
707dump_table_xentry_extended(struct radix_node *rn, void *arg)
2471dump_table_xentry(void *e, void *arg)
708{
2472{
709 struct table_xentry * const n = (struct table_xentry *)rn;
710 ipfw_xtable * const tbl = arg;
2473 struct dump_args *da;
2474 struct table_config *tc;
2475 struct table_algo *ta;
711 ipfw_table_xentry *xent;
2476 ipfw_table_xentry *xent;
712#ifdef INET6
713 int i;
714 uint32_t *v;
715#endif
2477 ipfw_obj_tentry *tent;
2478 struct table_value *pval;
2479 int error;
2480
2481 da = (struct dump_args *)arg;
2482
2483 tc = da->tc;
2484 ta = tc->ta;
2485
2486 xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent));
716 /* Out of memory, returning */
2487 /* Out of memory, returning */
717 if (tbl->cnt == tbl->size)
2488 if (xent == NULL)
718 return (1);
2489 return (1);
719 xent = &tbl->xent[tbl->cnt];
720 xent->len = sizeof(ipfw_table_xentry);
2490 xent->len = sizeof(ipfw_table_xentry);
721 xent->tbl = tbl->tbl;
2491 xent->tbl = da->uidx;
722
2492
723 switch (tbl->type) {
724#ifdef INET6
725 case IPFW_TABLE_CIDR:
726 /* Count IPv6 mask */
727 v = (uint32_t *)&n->m.mask6.sin6_addr;
728 for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++)
729 xent->masklen += bitcount32(*v);
730 memcpy(&xent->k, &n->a.addr6.sin6_addr, sizeof(struct in6_addr));
731 break;
732#endif
733 case IPFW_TABLE_INTERFACE:
734 /* Assume exact mask */
735 xent->masklen = 8 * IF_NAMESIZE;
736 memcpy(&xent->k, &n->a.iface.ifname, IF_NAMESIZE);
737 break;
2493 memset(&da->tent, 0, sizeof(da->tent));
2494 tent = &da->tent;
2495 error = ta->dump_tentry(tc->astate, da->ti, e, tent);
2496 if (error != 0)
2497 return (error);
2498
2499 /* Convert current format to previous one */
2500 xent->masklen = tent->masklen;
2501 pval = get_table_value(da->ch, da->tc, da->tent.v.kidx);
2502 xent->value = ipfw_export_table_value_legacy(pval);
2503 /* Apply some hacks */
2504 if (tc->no.type == IPFW_TABLE_ADDR && tent->subtype == AF_INET) {
2505 xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr;
2506 xent->flags = IPFW_TCF_INET;
2507 } else
2508 memcpy(&xent->k, &tent->k, sizeof(xent->k));
2509
2510 return (0);
2511}
2512
2513/*
2514 * Helper function to export table algo data
2515 * to tentry format before calling user function.
2516 *
2517 * Returns 0 on success.
2518 */
2519static int
2520prepare_table_tentry(void *e, void *arg)
2521{
2522 struct dump_args *da;
2523 struct table_config *tc;
2524 struct table_algo *ta;
2525 int error;
2526
2527 da = (struct dump_args *)arg;
2528
2529 tc = da->tc;
2530 ta = tc->ta;
2531
2532 error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent);
2533 if (error != 0)
2534 return (error);
2535
2536 da->f(&da->tent, da->farg);
2537
2538 return (0);
2539}
2540
2541/*
2542 * Allow external consumers to read table entries in standard format.
2543 */
2544int
2545ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint16_t kidx,
2546 ta_foreach_f *f, void *arg)
2547{
2548 struct namedobj_instance *ni;
2549 struct table_config *tc;
2550 struct table_algo *ta;
2551 struct dump_args da;
2552
2553 ni = CHAIN_TO_NI(ch);
2554
2555 tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx);
2556 if (tc == NULL)
2557 return (ESRCH);
2558
2559 ta = tc->ta;
2560
2561 memset(&da, 0, sizeof(da));
2562 da.ch = ch;
2563 da.ti = KIDX_TO_TI(ch, tc->no.kidx);
2564 da.tc = tc;
2565 da.f = f;
2566 da.farg = arg;
2567
2568 ta->foreach(tc->astate, da.ti, prepare_table_tentry, &da);
2569
2570 return (0);
2571}
2572
2573/*
2574 * Table algorithms
2575 */
2576
2577/*
2578 * Finds algoritm by index, table type or supplied name.
2579 *
2580 * Returns pointer to algo or NULL.
2581 */
2582static struct table_algo *
2583find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name)
2584{
2585 int i, l;
2586 struct table_algo *ta;
2587
2588 if (ti->type > IPFW_TABLE_MAXTYPE)
2589 return (NULL);
2590
2591 /* Search by index */
2592 if (ti->atype != 0) {
2593 if (ti->atype > tcfg->algo_count)
2594 return (NULL);
2595 return (tcfg->algo[ti->atype]);
2596 }
2597
2598 if (name == NULL) {
2599 /* Return default algorithm for given type if set */
2600 return (tcfg->def_algo[ti->type]);
2601 }
2602
2603 /* Search by name */
2604 /* TODO: better search */
2605 for (i = 1; i <= tcfg->algo_count; i++) {
2606 ta = tcfg->algo[i];
2607
2608 /*
2609 * One can supply additional algorithm
2610 * parameters so we compare only the first word
2611 * of supplied name:
2612 * 'addr:chash hsize=32'
2613 * '^^^^^^^^^'
2614 *
2615 */
2616 l = strlen(ta->name);
2617 if (strncmp(name, ta->name, l) != 0)
2618 continue;
2619 if (name[l] != '\0' && name[l] != ' ')
2620 continue;
2621 /* Check if we're requesting proper table type */
2622 if (ti->type != 0 && ti->type != ta->type)
2623 return (NULL);
2624 return (ta);
2625 }
2626
2627 return (NULL);
2628}
2629
2630/*
2631 * Register new table algo @ta.
2632 * Stores algo id inside @idx.
2633 *
2634 * Returns 0 on success.
2635 */
2636int
2637ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size,
2638 int *idx)
2639{
2640 struct tables_config *tcfg;
2641 struct table_algo *ta_new;
2642 size_t sz;
2643
2644 if (size > sizeof(struct table_algo))
2645 return (EINVAL);
2646
2647 /* Check for the required on-stack size for add/del */
2648 sz = roundup2(ta->ta_buf_size, sizeof(void *));
2649 if (sz > TA_BUF_SZ)
2650 return (EINVAL);
2651
2652 KASSERT(ta->type <= IPFW_TABLE_MAXTYPE,("Increase IPFW_TABLE_MAXTYPE"));
2653
2654 /* Copy algorithm data to stable storage. */
2655 ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO);
2656 memcpy(ta_new, ta, size);
2657
2658 tcfg = CHAIN_TO_TCFG(ch);
2659
2660 KASSERT(tcfg->algo_count < 255, ("Increase algo array size"));
2661
2662 tcfg->algo[++tcfg->algo_count] = ta_new;
2663 ta_new->idx = tcfg->algo_count;
2664
2665 /* Set algorithm as default one for given type */
2666 if ((ta_new->flags & TA_FLAG_DEFAULT) != 0 &&
2667 tcfg->def_algo[ta_new->type] == NULL)
2668 tcfg->def_algo[ta_new->type] = ta_new;
2669
2670 *idx = ta_new->idx;
738
2671
739 default:
740 /* unknown, skip entry */
741 return (0);
2672 return (0);
2673}
2674
2675/*
2676 * Unregisters table algo using @idx as id.
2677 * XXX: It is NOT safe to call this function in any place
2678 * other than ipfw instance destroy handler.
2679 */
2680void
2681ipfw_del_table_algo(struct ip_fw_chain *ch, int idx)
2682{
2683 struct tables_config *tcfg;
2684 struct table_algo *ta;
2685
2686 tcfg = CHAIN_TO_TCFG(ch);
2687
2688 KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of range 1..%d",
2689 idx, tcfg->algo_count));
2690
2691 ta = tcfg->algo[idx];
2692 KASSERT(ta != NULL, ("algo idx %d is NULL", idx));
2693
2694 if (tcfg->def_algo[ta->type] == ta)
2695 tcfg->def_algo[ta->type] = NULL;
2696
2697 free(ta, M_IPFW);
2698}
2699
2700/*
2701 * Lists all table algorithms currently available.
2702 * Data layout (v0)(current):
2703 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
2704 * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ]
2705 *
2706 * Returns 0 on success
2707 */
2708static int
2709list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
2710 struct sockopt_data *sd)
2711{
2712 struct _ipfw_obj_lheader *olh;
2713 struct tables_config *tcfg;
2714 ipfw_ta_info *i;
2715 struct table_algo *ta;
2716 uint32_t count, n, size;
2717
2718 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
2719 if (olh == NULL)
2720 return (EINVAL);
2721 if (sd->valsize < olh->size)
2722 return (EINVAL);
2723
2724 IPFW_UH_RLOCK(ch);
2725 tcfg = CHAIN_TO_TCFG(ch);
2726 count = tcfg->algo_count;
2727 size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader);
2728
2729 /* Fill in header regadless of buffer size */
2730 olh->count = count;
2731 olh->objsize = sizeof(ipfw_ta_info);
2732
2733 if (size > olh->size) {
2734 olh->size = size;
2735 IPFW_UH_RUNLOCK(ch);
2736 return (ENOMEM);
742 }
2737 }
2738 olh->size = size;
743
2739
744 xent->value = n->value;
745 tbl->cnt++;
2740 for (n = 1; n <= count; n++) {
2741 i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i));
2742 KASSERT(i != 0, ("previously checked buffer is not enough"));
2743 ta = tcfg->algo[n];
2744 strlcpy(i->algoname, ta->name, sizeof(i->algoname));
2745 i->type = ta->type;
2746 i->refcnt = ta->refcnt;
2747 }
2748
2749 IPFW_UH_RUNLOCK(ch);
2750
746 return (0);
747}
748
2751 return (0);
2752}
2753
2754/*
2755 * Tables rewriting code
2756 */
2757
2758/*
2759 * Determine table number and lookup type for @cmd.
2760 * Fill @tbl and @type with appropriate values.
2761 * Returns 0 for relevant opcodes, 1 otherwise.
2762 */
2763static int
2764classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
2765{
2766 ipfw_insn_if *cmdif;
2767 int skip;
2768 uint16_t v;
2769
2770 skip = 1;
2771
2772 switch (cmd->opcode) {
2773 case O_IP_SRC_LOOKUP:
2774 case O_IP_DST_LOOKUP:
2775 /* Basic IPv4/IPv6 or u32 lookups */
2776 *puidx = cmd->arg1;
2777 /* Assume ADDR by default */
2778 *ptype = IPFW_TABLE_ADDR;
2779 skip = 0;
2780
2781 if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) {
2782 /*
2783 * generic lookup. The key must be
2784 * in 32bit big-endian format.
2785 */
2786 v = ((ipfw_insn_u32 *)cmd)->d[1];
2787 switch (v) {
2788 case 0:
2789 case 1:
2790 /* IPv4 src/dst */
2791 break;
2792 case 2:
2793 case 3:
2794 /* src/dst port */
2795 *ptype = IPFW_TABLE_NUMBER;
2796 break;
2797 case 4:
2798 /* uid/gid */
2799 *ptype = IPFW_TABLE_NUMBER;
2800 break;
2801 case 5:
2802 /* jid */
2803 *ptype = IPFW_TABLE_NUMBER;
2804 break;
2805 case 6:
2806 /* dscp */
2807 *ptype = IPFW_TABLE_NUMBER;
2808 break;
2809 }
2810 }
2811 break;
2812 case O_XMIT:
2813 case O_RECV:
2814 case O_VIA:
2815 /* Interface table, possibly */
2816 cmdif = (ipfw_insn_if *)cmd;
2817 if (cmdif->name[0] != '\1')
2818 break;
2819
2820 *ptype = IPFW_TABLE_INTERFACE;
2821 *puidx = cmdif->p.kidx;
2822 skip = 0;
2823 break;
2824 case O_IP_FLOW_LOOKUP:
2825 *puidx = cmd->arg1;
2826 *ptype = IPFW_TABLE_FLOW;
2827 skip = 0;
2828 break;
2829 }
2830
2831 return (skip);
2832}
2833
2834/*
2835 * Sets new table value for given opcode.
2836 * Assume the same opcodes as classify_table_opcode()
2837 */
2838static void
2839update_table_opcode(ipfw_insn *cmd, uint16_t idx)
2840{
2841 ipfw_insn_if *cmdif;
2842
2843 switch (cmd->opcode) {
2844 case O_IP_SRC_LOOKUP:
2845 case O_IP_DST_LOOKUP:
2846 /* Basic IPv4/IPv6 or u32 lookups */
2847 cmd->arg1 = idx;
2848 break;
2849 case O_XMIT:
2850 case O_RECV:
2851 case O_VIA:
2852 /* Interface table, possibly */
2853 cmdif = (ipfw_insn_if *)cmd;
2854 cmdif->p.kidx = idx;
2855 break;
2856 case O_IP_FLOW_LOOKUP:
2857 cmd->arg1 = idx;
2858 break;
2859 }
2860}
2861
2862/*
2863 * Checks table name for validity.
2864 * Enforce basic length checks, the rest
2865 * should be done in userland.
2866 *
2867 * Returns 0 if name is considered valid.
2868 */
749int
2869int
750ipfw_dump_xtable(struct ip_fw_chain *ch, ipfw_xtable *tbl)
2870ipfw_check_table_name(char *name)
751{
2871{
752 struct radix_node_head *rnh;
2872 int nsize;
2873 ipfw_obj_ntlv *ntlv = NULL;
753
2874
754 if (tbl->tbl >= V_fw_tables_max)
2875 nsize = sizeof(ntlv->name);
2876
2877 if (strnlen(name, nsize) == nsize)
755 return (EINVAL);
2878 return (EINVAL);
756 tbl->cnt = 0;
757 tbl->type = ch->tabletype[tbl->tbl];
758 if ((rnh = ch->tables[tbl->tbl]) != NULL)
759 rnh->rnh_walktree(rnh, dump_table_xentry_base, tbl);
760 if ((rnh = ch->xtables[tbl->tbl]) != NULL)
761 rnh->rnh_walktree(rnh, dump_table_xentry_extended, tbl);
2879
2880 if (name[0] == '\0')
2881 return (EINVAL);
2882
2883 /*
2884 * TODO: do some more complicated checks
2885 */
2886
762 return (0);
763}
764
2887 return (0);
2888}
2889
765/* end of file */
2890/*
2891 * Find tablename TLV by @uid.
2892 * Check @tlvs for valid data inside.
2893 *
2894 * Returns pointer to found TLV or NULL.
2895 */
2896static ipfw_obj_ntlv *
2897find_name_tlv(void *tlvs, int len, uint16_t uidx)
2898{
2899 ipfw_obj_ntlv *ntlv;
2900 uintptr_t pa, pe;
2901 int l;
2902
2903 pa = (uintptr_t)tlvs;
2904 pe = pa + len;
2905 l = 0;
2906 for (; pa < pe; pa += l) {
2907 ntlv = (ipfw_obj_ntlv *)pa;
2908 l = ntlv->head.length;
2909
2910 if (l != sizeof(*ntlv))
2911 return (NULL);
2912
2913 if (ntlv->head.type != IPFW_TLV_TBL_NAME)
2914 continue;
2915
2916 if (ntlv->idx != uidx)
2917 continue;
2918
2919 if (ipfw_check_table_name(ntlv->name) != 0)
2920 return (NULL);
2921
2922 return (ntlv);
2923 }
2924
2925 return (NULL);
2926}
2927
2928/*
2929 * Finds table config based on either legacy index
2930 * or name in ntlv.
2931 * Note @ti structure contains unchecked data from userland.
2932 *
2933 * Returns pointer to table_config or NULL.
2934 */
2935static struct table_config *
2936find_table(struct namedobj_instance *ni, struct tid_info *ti)
2937{
2938 char *name, bname[16];
2939 struct named_object *no;
2940 ipfw_obj_ntlv *ntlv;
2941 uint32_t set;
2942
2943 if (ti->tlvs != NULL) {
2944 ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
2945 if (ntlv == NULL)
2946 return (NULL);
2947 name = ntlv->name;
2948
2949 /*
2950 * Use set provided by @ti instead of @ntlv one.
2951 * This is needed due to different sets behavior
2952 * controlled by V_fw_tables_sets.
2953 */
2954 set = ti->set;
2955 } else {
2956 snprintf(bname, sizeof(bname), "%d", ti->uidx);
2957 name = bname;
2958 set = 0;
2959 }
2960
2961 no = ipfw_objhash_lookup_name(ni, set, name);
2962
2963 return ((struct table_config *)no);
2964}
2965
2966/*
2967 * Allocate new table config structure using
2968 * specified @algo and @aname.
2969 *
2970 * Returns pointer to config or NULL.
2971 */
2972static struct table_config *
2973alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti,
2974 struct table_algo *ta, char *aname, uint8_t tflags)
2975{
2976 char *name, bname[16];
2977 struct table_config *tc;
2978 int error;
2979 ipfw_obj_ntlv *ntlv;
2980 uint32_t set;
2981
2982 if (ti->tlvs != NULL) {
2983 ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx);
2984 if (ntlv == NULL)
2985 return (NULL);
2986 name = ntlv->name;
2987 set = ntlv->set;
2988 } else {
2989 snprintf(bname, sizeof(bname), "%d", ti->uidx);
2990 name = bname;
2991 set = 0;
2992 }
2993
2994 tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO);
2995 tc->no.name = tc->tablename;
2996 tc->no.type = ta->type;
2997 tc->no.set = set;
2998 tc->tflags = tflags;
2999 tc->ta = ta;
3000 strlcpy(tc->tablename, name, sizeof(tc->tablename));
3001 /* Set "shared" value type by default */
3002 tc->vshared = 1;
3003
3004 if (ti->tlvs == NULL) {
3005 tc->no.compat = 1;
3006 tc->no.uidx = ti->uidx;
3007 }
3008
3009 /* Preallocate data structures for new tables */
3010 error = ta->init(ch, &tc->astate, &tc->ti_copy, aname, tflags);
3011 if (error != 0) {
3012 free(tc, M_IPFW);
3013 return (NULL);
3014 }
3015
3016 return (tc);
3017}
3018
3019/*
3020 * Destroys table state and config.
3021 */
3022static void
3023free_table_config(struct namedobj_instance *ni, struct table_config *tc)
3024{
3025
3026 KASSERT(tc->linked == 0, ("free() on linked config"));
3027
3028 /*
3029 * We're using ta without any locking/referencing.
3030 * TODO: fix this if we're going to use unloadable algos.
3031 */
3032 tc->ta->destroy(tc->astate, &tc->ti_copy);
3033 free(tc, M_IPFW);
3034}
3035
3036/*
3037 * Links @tc to @chain table named instance.
3038 * Sets appropriate type/states in @chain table info.
3039 */
3040static void
3041link_table(struct ip_fw_chain *ch, struct table_config *tc)
3042{
3043 struct namedobj_instance *ni;
3044 struct table_info *ti;
3045 uint16_t kidx;
3046
3047 IPFW_UH_WLOCK_ASSERT(ch);
3048 IPFW_WLOCK_ASSERT(ch);
3049
3050 ni = CHAIN_TO_NI(ch);
3051 kidx = tc->no.kidx;
3052
3053 ipfw_objhash_add(ni, &tc->no);
3054
3055 ti = KIDX_TO_TI(ch, kidx);
3056 *ti = tc->ti_copy;
3057
3058 /* Notify algo on real @ti address */
3059 if (tc->ta->change_ti != NULL)
3060 tc->ta->change_ti(tc->astate, ti);
3061
3062 tc->linked = 1;
3063 tc->ta->refcnt++;
3064}
3065
3066/*
3067 * Unlinks @tc from @chain table named instance.
3068 * Zeroes states in @chain and stores them in @tc.
3069 */
3070static void
3071unlink_table(struct ip_fw_chain *ch, struct table_config *tc)
3072{
3073 struct namedobj_instance *ni;
3074 struct table_info *ti;
3075 uint16_t kidx;
3076
3077 IPFW_UH_WLOCK_ASSERT(ch);
3078 IPFW_WLOCK_ASSERT(ch);
3079
3080 ni = CHAIN_TO_NI(ch);
3081 kidx = tc->no.kidx;
3082
3083 /* Clear state. @ti copy is already saved inside @tc */
3084 ipfw_objhash_del(ni, &tc->no);
3085 ti = KIDX_TO_TI(ch, kidx);
3086 memset(ti, 0, sizeof(struct table_info));
3087 tc->linked = 0;
3088 tc->ta->refcnt--;
3089
3090 /* Notify algo on real @ti address */
3091 if (tc->ta->change_ti != NULL)
3092 tc->ta->change_ti(tc->astate, NULL);
3093}
3094
3095struct swap_table_args {
3096 int set;
3097 int new_set;
3098 int mv;
3099};
3100
3101/*
3102 * Change set for each matching table.
3103 *
3104 * Ensure we dispatch each table once by setting/checking ochange
3105 * fields.
3106 */
3107static void
3108swap_table_set(struct namedobj_instance *ni, struct named_object *no,
3109 void *arg)
3110{
3111 struct table_config *tc;
3112 struct swap_table_args *sta;
3113
3114 tc = (struct table_config *)no;
3115 sta = (struct swap_table_args *)arg;
3116
3117 if (no->set != sta->set && (no->set != sta->new_set || sta->mv != 0))
3118 return;
3119
3120 if (tc->ochanged != 0)
3121 return;
3122
3123 tc->ochanged = 1;
3124 ipfw_objhash_del(ni, no);
3125 if (no->set == sta->set)
3126 no->set = sta->new_set;
3127 else
3128 no->set = sta->set;
3129 ipfw_objhash_add(ni, no);
3130}
3131
3132/*
3133 * Cleans up ochange field for all tables.
3134 */
3135static void
3136clean_table_set_data(struct namedobj_instance *ni, struct named_object *no,
3137 void *arg)
3138{
3139 struct table_config *tc;
3140 struct swap_table_args *sta;
3141
3142 tc = (struct table_config *)no;
3143 sta = (struct swap_table_args *)arg;
3144
3145 tc->ochanged = 0;
3146}
3147
3148/*
3149 * Swaps tables within two sets.
3150 */
3151void
3152ipfw_swap_tables_sets(struct ip_fw_chain *ch, uint32_t set,
3153 uint32_t new_set, int mv)
3154{
3155 struct swap_table_args sta;
3156
3157 IPFW_UH_WLOCK_ASSERT(ch);
3158
3159 sta.set = set;
3160 sta.new_set = new_set;
3161 sta.mv = mv;
3162
3163 ipfw_objhash_foreach(CHAIN_TO_NI(ch), swap_table_set, &sta);
3164 ipfw_objhash_foreach(CHAIN_TO_NI(ch), clean_table_set_data, &sta);
3165}
3166
3167/*
3168 * Move all tables which are reference by rules in @rr to set @new_set.
3169 * Makes sure that all relevant tables are referenced ONLLY by given rules.
3170 *
3171 * Retuns 0 on success,
3172 */
3173int
3174ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt,
3175 uint32_t new_set)
3176{
3177 struct ip_fw *rule;
3178 struct table_config *tc;
3179 struct named_object *no;
3180 struct namedobj_instance *ni;
3181 int bad, i, l, cmdlen;
3182 uint16_t kidx;
3183 uint8_t type;
3184 ipfw_insn *cmd;
3185
3186 IPFW_UH_WLOCK_ASSERT(ch);
3187
3188 ni = CHAIN_TO_NI(ch);
3189
3190 /* Stage 1: count number of references by given rules */
3191 for (i = 0; i < ch->n_rules - 1; i++) {
3192 rule = ch->map[i];
3193 if (ipfw_match_range(rule, rt) == 0)
3194 continue;
3195
3196 l = rule->cmd_len;
3197 cmd = rule->cmd;
3198 cmdlen = 0;
3199 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3200 cmdlen = F_LEN(cmd);
3201 if (classify_table_opcode(cmd, &kidx, &type) != 0)
3202 continue;
3203 no = ipfw_objhash_lookup_kidx(ni, kidx);
3204 KASSERT(no != NULL,
3205 ("objhash lookup failed on index %d", kidx));
3206 tc = (struct table_config *)no;
3207 tc->ocount++;
3208 }
3209
3210 }
3211
3212 /* Stage 2: verify "ownership" */
3213 bad = 0;
3214 for (i = 0; i < ch->n_rules - 1; i++) {
3215 rule = ch->map[i];
3216 if (ipfw_match_range(rule, rt) == 0)
3217 continue;
3218
3219 l = rule->cmd_len;
3220 cmd = rule->cmd;
3221 cmdlen = 0;
3222 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3223 cmdlen = F_LEN(cmd);
3224 if (classify_table_opcode(cmd, &kidx, &type) != 0)
3225 continue;
3226 no = ipfw_objhash_lookup_kidx(ni, kidx);
3227 KASSERT(no != NULL,
3228 ("objhash lookup failed on index %d", kidx));
3229 tc = (struct table_config *)no;
3230 if (tc->no.refcnt != tc->ocount) {
3231
3232 /*
3233 * Number of references differ:
3234 * Other rule(s) are holding reference to given
3235 * table, so it is not possible to change its set.
3236 *
3237 * Note that refcnt may account
3238 * references to some going-to-be-added rules.
3239 * Since we don't know their numbers (and event
3240 * if they will be added) it is perfectly OK
3241 * to return error here.
3242 */
3243 bad = 1;
3244 break;
3245 }
3246 }
3247
3248 if (bad != 0)
3249 break;
3250 }
3251
3252 /* Stage 3: change set or cleanup */
3253 for (i = 0; i < ch->n_rules - 1; i++) {
3254 rule = ch->map[i];
3255 if (ipfw_match_range(rule, rt) == 0)
3256 continue;
3257
3258 l = rule->cmd_len;
3259 cmd = rule->cmd;
3260 cmdlen = 0;
3261 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3262 cmdlen = F_LEN(cmd);
3263 if (classify_table_opcode(cmd, &kidx, &type) != 0)
3264 continue;
3265 no = ipfw_objhash_lookup_kidx(ni, kidx);
3266 KASSERT(no != NULL,
3267 ("objhash lookup failed on index %d", kidx));
3268 tc = (struct table_config *)no;
3269
3270 tc->ocount = 0;
3271 if (bad != 0)
3272 continue;
3273
3274 /* Actually change set. */
3275 ipfw_objhash_del(ni, no);
3276 no->set = new_set;
3277 ipfw_objhash_add(ni, no);
3278 }
3279 }
3280
3281 return (bad);
3282}
3283
3284/*
3285 * Finds and bumps refcount for tables referenced by given @rule.
3286 * Auto-creates non-existing tables.
3287 * Fills in @oib array with userland/kernel indexes.
3288 * First free oidx pointer is saved back in @oib.
3289 *
3290 * Returns 0 on success.
3291 */
3292static int
3293find_ref_rule_tables(struct ip_fw_chain *ch, struct ip_fw *rule,
3294 struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti)
3295{
3296 struct table_config *tc;
3297 struct namedobj_instance *ni;
3298 struct named_object *no;
3299 int cmdlen, error, l, numnew;
3300 uint16_t kidx;
3301 ipfw_insn *cmd;
3302 struct obj_idx *pidx, *pidx_first, *p;
3303
3304 pidx_first = *oib;
3305 pidx = pidx_first;
3306 l = rule->cmd_len;
3307 cmd = rule->cmd;
3308 cmdlen = 0;
3309 error = 0;
3310 numnew = 0;
3311
3312 IPFW_UH_WLOCK(ch);
3313 ni = CHAIN_TO_NI(ch);
3314
3315 /* Increase refcount on each existing referenced table. */
3316 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3317 cmdlen = F_LEN(cmd);
3318
3319 if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0)
3320 continue;
3321
3322 pidx->uidx = ti->uidx;
3323 pidx->type = ti->type;
3324
3325 if ((tc = find_table(ni, ti)) != NULL) {
3326 if (tc->no.type != ti->type) {
3327 /* Incompatible types */
3328 error = EINVAL;
3329 break;
3330 }
3331
3332 /* Reference found table and save kidx */
3333 tc->no.refcnt++;
3334 pidx->kidx = tc->no.kidx;
3335 pidx++;
3336 continue;
3337 }
3338
3339 /*
3340 * Compability stuff for old clients:
3341 * prepare to manually create non-existing tables.
3342 */
3343 pidx++;
3344 numnew++;
3345 }
3346
3347 if (error != 0) {
3348 /* Unref everything we have already done */
3349 for (p = *oib; p < pidx; p++) {
3350 if (p->kidx == 0)
3351 continue;
3352
3353 /* Find & unref by existing idx */
3354 no = ipfw_objhash_lookup_kidx(ni, p->kidx);
3355 KASSERT(no != NULL, ("Ref'd table %d disappeared",
3356 p->kidx));
3357
3358 no->refcnt--;
3359 }
3360 }
3361
3362 IPFW_UH_WUNLOCK(ch);
3363
3364 if (numnew == 0) {
3365 *oib = pidx;
3366 return (error);
3367 }
3368
3369 /*
3370 * Compatibility stuff: do actual creation for non-existing,
3371 * but referenced tables.
3372 */
3373 for (p = pidx_first; p < pidx; p++) {
3374 if (p->kidx != 0)
3375 continue;
3376
3377 ti->uidx = p->uidx;
3378 ti->type = p->type;
3379 ti->atype = 0;
3380
3381 error = create_table_compat(ch, ti, &kidx);
3382 if (error == 0) {
3383 p->kidx = kidx;
3384 continue;
3385 }
3386
3387 /* Error. We have to drop references */
3388 IPFW_UH_WLOCK(ch);
3389 for (p = pidx_first; p < pidx; p++) {
3390 if (p->kidx == 0)
3391 continue;
3392
3393 /* Find & unref by existing idx */
3394 no = ipfw_objhash_lookup_kidx(ni, p->kidx);
3395 KASSERT(no != NULL, ("Ref'd table %d disappeared",
3396 p->kidx));
3397
3398 no->refcnt--;
3399 }
3400 IPFW_UH_WUNLOCK(ch);
3401
3402 return (error);
3403 }
3404
3405 *oib = pidx;
3406
3407 return (error);
3408}
3409
3410/*
3411 * Remove references from every table used in @rule.
3412 */
3413void
3414ipfw_unref_rule_tables(struct ip_fw_chain *chain, struct ip_fw *rule)
3415{
3416 int cmdlen, l;
3417 ipfw_insn *cmd;
3418 struct namedobj_instance *ni;
3419 struct named_object *no;
3420 uint16_t kidx;
3421 uint8_t type;
3422
3423 IPFW_UH_WLOCK_ASSERT(chain);
3424 ni = CHAIN_TO_NI(chain);
3425
3426 l = rule->cmd_len;
3427 cmd = rule->cmd;
3428 cmdlen = 0;
3429 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3430 cmdlen = F_LEN(cmd);
3431
3432 if (classify_table_opcode(cmd, &kidx, &type) != 0)
3433 continue;
3434
3435 no = ipfw_objhash_lookup_kidx(ni, kidx);
3436
3437 KASSERT(no != NULL, ("table id %d not found", kidx));
3438 KASSERT(no->type == type, ("wrong type %d (%d) for table id %d",
3439 no->type, type, kidx));
3440 KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
3441 kidx, no->refcnt));
3442
3443 no->refcnt--;
3444 }
3445}
3446
3447/*
3448 * Compatibility function for old ipfw(8) binaries.
3449 * Rewrites table kernel indices with userland ones.
3450 * Convert tables matching '/^\d+$/' to their atoi() value.
3451 * Use number 65535 for other tables.
3452 *
3453 * Returns 0 on success.
3454 */
3455int
3456ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule)
3457{
3458 int cmdlen, error, l;
3459 ipfw_insn *cmd;
3460 uint16_t kidx, uidx;
3461 uint8_t type;
3462 struct named_object *no;
3463 struct namedobj_instance *ni;
3464
3465 ni = CHAIN_TO_NI(chain);
3466 error = 0;
3467
3468 l = rule->cmd_len;
3469 cmd = rule->cmd;
3470 cmdlen = 0;
3471 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3472 cmdlen = F_LEN(cmd);
3473
3474 if (classify_table_opcode(cmd, &kidx, &type) != 0)
3475 continue;
3476
3477 if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL)
3478 return (1);
3479
3480 uidx = no->uidx;
3481 if (no->compat == 0) {
3482
3483 /*
3484 * We are called via legacy opcode.
3485 * Save error and show table as fake number
3486 * not to make ipfw(8) hang.
3487 */
3488 uidx = 65535;
3489 error = 2;
3490 }
3491
3492 update_table_opcode(cmd, uidx);
3493 }
3494
3495 return (error);
3496}
3497
3498/*
3499 * Checks is opcode is referencing table of appropriate type.
3500 * Adds reference count for found table if true.
3501 * Rewrites user-supplied opcode values with kernel ones.
3502 *
3503 * Returns 0 on success and appropriate error code otherwise.
3504 */
3505int
3506ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
3507 struct rule_check_info *ci)
3508{
3509 int cmdlen, error, l;
3510 ipfw_insn *cmd;
3511 uint16_t uidx;
3512 uint8_t type;
3513 struct namedobj_instance *ni;
3514 struct obj_idx *p, *pidx_first, *pidx_last;
3515 struct tid_info ti;
3516
3517 ni = CHAIN_TO_NI(chain);
3518
3519 /*
3520 * Prepare an array for storing opcode indices.
3521 * Use stack allocation by default.
3522 */
3523 if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
3524 /* Stack */
3525 pidx_first = ci->obuf;
3526 } else
3527 pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx),
3528 M_IPFW, M_WAITOK | M_ZERO);
3529
3530 pidx_last = pidx_first;
3531 error = 0;
3532 type = 0;
3533 memset(&ti, 0, sizeof(ti));
3534
3535 /*
3536 * Use default set for looking up tables (old way) or
3537 * use set rule is assigned to (new way).
3538 */
3539 ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0;
3540 if (ci->ctlv != NULL) {
3541 ti.tlvs = (void *)(ci->ctlv + 1);
3542 ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
3543 }
3544
3545 /* Reference all used tables */
3546 error = find_ref_rule_tables(chain, ci->krule, ci, &pidx_last, &ti);
3547 if (error != 0)
3548 goto free;
3549
3550 IPFW_UH_WLOCK(chain);
3551
3552 /* Perform rule rewrite */
3553 l = ci->krule->cmd_len;
3554 cmd = ci->krule->cmd;
3555 cmdlen = 0;
3556 p = pidx_first;
3557 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
3558 cmdlen = F_LEN(cmd);
3559 if (classify_table_opcode(cmd, &uidx, &type) != 0)
3560 continue;
3561 update_table_opcode(cmd, p->kidx);
3562 p++;
3563 }
3564
3565 IPFW_UH_WUNLOCK(chain);
3566
3567free:
3568 if (pidx_first != ci->obuf)
3569 free(pidx_first, M_IPFW);
3570
3571 return (error);
3572}
3573
3574static struct ipfw_sopt_handler scodes[] = {
3575 { IP_FW_TABLE_XCREATE, 0, HDIR_SET, create_table },
3576 { IP_FW_TABLE_XDESTROY, 0, HDIR_SET, flush_table_v0 },
3577 { IP_FW_TABLE_XFLUSH, 0, HDIR_SET, flush_table_v0 },
3578 { IP_FW_TABLE_XMODIFY, 0, HDIR_BOTH, modify_table },
3579 { IP_FW_TABLE_XINFO, 0, HDIR_GET, describe_table },
3580 { IP_FW_TABLES_XLIST, 0, HDIR_GET, list_tables },
3581 { IP_FW_TABLE_XLIST, 0, HDIR_GET, dump_table_v0 },
3582 { IP_FW_TABLE_XLIST, 1, HDIR_GET, dump_table_v1 },
3583 { IP_FW_TABLE_XADD, 0, HDIR_BOTH, manage_table_ent_v0 },
3584 { IP_FW_TABLE_XADD, 1, HDIR_BOTH, manage_table_ent_v1 },
3585 { IP_FW_TABLE_XDEL, 0, HDIR_BOTH, manage_table_ent_v0 },
3586 { IP_FW_TABLE_XDEL, 1, HDIR_BOTH, manage_table_ent_v1 },
3587 { IP_FW_TABLE_XFIND, 0, HDIR_GET, find_table_entry },
3588 { IP_FW_TABLE_XSWAP, 0, HDIR_SET, swap_table },
3589 { IP_FW_TABLES_ALIST, 0, HDIR_GET, list_table_algo },
3590 { IP_FW_TABLE_XGETSIZE, 0, HDIR_GET, get_table_size },
3591};
3592
3593static void
3594destroy_table_locked(struct namedobj_instance *ni, struct named_object *no,
3595 void *arg)
3596{
3597
3598 unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no);
3599 if (ipfw_objhash_free_idx(ni, no->kidx) != 0)
3600 printf("Error unlinking kidx %d from table %s\n",
3601 no->kidx, no->name);
3602 free_table_config(ni, (struct table_config *)no);
3603}
3604
3605/*
3606 * Shuts tables module down.
3607 */
3608void
3609ipfw_destroy_tables(struct ip_fw_chain *ch, int last)
3610{
3611
3612 IPFW_DEL_SOPT_HANDLER(last, scodes);
3613
3614 /* Remove all tables from working set */
3615 IPFW_UH_WLOCK(ch);
3616 IPFW_WLOCK(ch);
3617 ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch);
3618 IPFW_WUNLOCK(ch);
3619 IPFW_UH_WUNLOCK(ch);
3620
3621 /* Free pointers itself */
3622 free(ch->tablestate, M_IPFW);
3623
3624 ipfw_table_value_destroy(ch, last);
3625 ipfw_table_algo_destroy(ch);
3626
3627 ipfw_objhash_destroy(CHAIN_TO_NI(ch));
3628 free(CHAIN_TO_TCFG(ch), M_IPFW);
3629}
3630
3631/*
3632 * Starts tables module.
3633 */
3634int
3635ipfw_init_tables(struct ip_fw_chain *ch, int first)
3636{
3637 struct tables_config *tcfg;
3638
3639 /* Allocate pointers */
3640 ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info),
3641 M_IPFW, M_WAITOK | M_ZERO);
3642
3643 tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO);
3644 tcfg->namehash = ipfw_objhash_create(V_fw_tables_max);
3645 ch->tblcfg = tcfg;
3646
3647 ipfw_table_value_init(ch, first);
3648 ipfw_table_algo_init(ch);
3649
3650 IPFW_ADD_SOPT_HANDLER(first, scodes);
3651 return (0);
3652}
3653
3654
3655