Projet

Général

Profil

Télécharger (35,7 ko) Statistiques
| Branche: | Révision:

univnautes-tools / patches / stable / 10 / CP_multi_instance_ipfw.diff @ f0eb9c23

1
diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile
2
index 6aea26b..e137e08 100644
3
--- a/sbin/ipfw/Makefile
4
+++ b/sbin/ipfw/Makefile
5
@@ -3,7 +3,7 @@
6
 .include <bsd.own.mk>
7
 
8
 PROG=	ipfw
9
-SRCS=	ipfw2.c dummynet.c ipv6.c main.c nat.c
10
+SRCS=	ipfw2.c dummynet.c ipv6.c main.c nat.c context.c
11
 WARNS?=	2
12
 
13
 .if ${MK_PF} != "no"
14
diff --git a/sbin/ipfw/context.c b/sbin/ipfw/context.c
15
new file mode 100644
16
index 0000000..f121b2e
17
--- /dev/null
18
+++ b/sbin/ipfw/context.c
19
@@ -0,0 +1,148 @@
20
+/*
21
+ * Copyright (c) 2013 Ermal Lu?i
22
+ *
23
+ * Redistribution and use in source forms, with and without modification,
24
+ * are permitted provided that this entire comment appears intact.
25
+ *
26
+ * Redistribution in binary form may occur without any restrictions.
27
+ * Obviously, it would be nice if you gave credit where credit is due
28
+ * but requiring it would be too onerous.
29
+ *
30
+ * This software is provided ``AS IS'' without any warranties of any kind.
31
+ *
32
+ * $FreeBSD$
33
+ */
34
+
35
+#include <sys/types.h>
36
+#include <sys/socket.h>
37
+
38
+#include <net/if.h>
39
+#include <net/if_var.h>
40
+
41
+#include <netinet/in.h>
42
+#include <netinet/ip_fw.h>
43
+
44
+#include "ipfw2.h"
45
+
46
+#include <stdio.h>
47
+#include <stdlib.h>
48
+#include <unistd.h>
49
+#include <sysexits.h>
50
+#include <string.h>
51
+#include <errno.h>
52
+#include <err.h>
53
+
54
+extern int ipfw_socket;
55
+
56
+int
57
+ipfw_context_handler(int ac, char **av)
58
+{
59
+        ip_fw3_opheader *op3;
60
+	int error = 0;
61
+	uint32_t action = 0;
62
+	socklen_t len, nlen;
63
+	char *ifname;
64
+
65
+	av++;
66
+	ac--;
67
+	NEED1("bad arguments, for usage summary ``ipfw''");
68
+
69
+	if (!strncmp(*av, "list", strlen(*av))) {
70
+		action = IP_FW_CTX_GET;
71
+		av++;
72
+		ac--;
73
+		if (ac > 0)
74
+			errx(EX_DATAERR, "list: does not take any extra arguments.");
75
+
76
+	} else {
77
+		co.ctx = atoi(*av);
78
+
79
+		av++;
80
+		ac--;
81
+		NEED1("bad arguments, for usage summary ``ipfw''");
82
+
83
+		if (!strncmp(*av, "create", strlen(*av)))
84
+			action = IP_FW_CTX_ADD;
85
+		else if (!strncmp(*av, "destroy", strlen(*av)))
86
+			action = IP_FW_CTX_DEL;
87
+		else {
88
+			if (!strncmp(*av, "madd", strlen(*av)))
89
+				action = IP_FW_CTX_ADDMEMBER;
90
+			else if (!strncmp(*av, "mdel", strlen(*av)))
91
+				action = IP_FW_CTX_DELMEMBER;
92
+			else
93
+				errx(EX_DATAERR, "Wrong parameters passed");
94
+
95
+			av++;
96
+			ac--;
97
+			NEED1("bad arguments, for usage summary ``ipfw''");
98
+
99
+			ifname = *av;
100
+		}
101
+
102
+		ac--;
103
+		if (ac > 0)
104
+			errx(EX_DATAERR, "context handling: Too many arguments passed");
105
+
106
+	}
107
+
108
+        if (co.test_only)
109
+                return (0);
110
+
111
+        if (ipfw_socket < 0)
112
+                ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
113
+        if (ipfw_socket < 0)
114
+                err(EX_UNAVAILABLE, "socket");
115
+
116
+	switch (action) {
117
+	case IP_FW_CTX_ADD:
118
+	case IP_FW_CTX_DEL:
119
+	case IP_FW_CTX_SET:
120
+		len = sizeof(ip_fw3_opheader);
121
+		op3 = alloca(len);
122
+		/* Zero reserved fields */
123
+		memset(op3, 0, sizeof(ip_fw3_opheader));
124
+		op3->opcode = action;
125
+		op3->ctxid = co.ctx;
126
+		error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
127
+		break;
128
+	case IP_FW_CTX_ADDMEMBER:
129
+	case IP_FW_CTX_DELMEMBER:
130
+		len = sizeof(ip_fw3_opheader) + strlen(ifname) + 1;
131
+		op3 = alloca(len);
132
+		/* Zero reserved fields */
133
+		memset(op3, 0, sizeof(ip_fw3_opheader) + strlen(ifname) + 1);
134
+		memcpy((op3 + 1), ifname, strlen(ifname));
135
+		op3->opcode = action;
136
+		op3->ctxid = co.ctx;
137
+		error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
138
+		break;
139
+	case IP_FW_CTX_GET:
140
+		len = sizeof(ip_fw3_opheader) + 1000;
141
+		nlen = len;
142
+		do {
143
+			if (nlen > len) {
144
+				len = nlen;
145
+			}
146
+			op3 = alloca(len);
147
+			/* Zero reserved fields */
148
+			memset(op3, 0, len);
149
+			op3->opcode = action;
150
+			op3->ctxid = co.ctx;
151
+			nlen = len;
152
+			error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, &nlen);
153
+		} while (nlen > len && !error);
154
+
155
+		if (!error) {
156
+			if (nlen == 0)
157
+				printf("There are no contextes defined\n");
158
+			else
159
+				printf("Currently defined contextes and their members:\n%s\n", (char *)op3);
160
+		} else
161
+			err(EX_UNAVAILABLE, "Error returned: %s\n", strerror(error));
162
+
163
+		break;
164
+	}
165
+
166
+	return (error);
167
+}
168
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
169
index 476f5da..8364011 100644
170
--- a/sbin/ipfw/ipfw2.c
171
+++ b/sbin/ipfw/ipfw2.c
172
@@ -54,7 +54,7 @@
173
 #include <netinet/tcp.h>
174
 #include <arpa/inet.h>
175
 
176
-struct cmdline_opts co;	/* global options */
177
+struct cmdline_opts co = { 0 };	/* global options */
178
 
179
 int resvd_set_number = RESVD_SET;
180
 
181
@@ -420,6 +420,7 @@ safe_realloc(void *ptr, size_t size)
182
 int
183
 do_cmd(int optname, void *optval, uintptr_t optlen)
184
 {
185
+	ip_fw3_opheader op3;
186
 	int i;
187
 
188
 	if (co.test_only)
189
@@ -430,6 +431,15 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
190
 	if (ipfw_socket < 0)
191
 		err(EX_UNAVAILABLE, "socket");
192
 
193
+	if (optname != IP_FW3 && optname != IP_DUMMYNET3 && optname != -IP_DUMMYNET3) {
194
+		memset(&op3, 0, sizeof op3);
195
+		op3.ctxid = co.ctx;
196
+		op3.opcode = IP_FW_CTX_SET;
197
+		i = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, &op3, sizeof(op3));
198
+		if (i)
199
+			errx(EX_OSERR, "setsockopt: choosing context");
200
+	}
201
+
202
 	if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
203
 	    optname == IP_FW_ADD || optname == IP_FW3 ||
204
 	    optname == IP_FW_NAT_GET_CONFIG ||
205
@@ -475,6 +485,7 @@ do_setcmd3(int optname, void *optval, socklen_t optlen)
206
 	memset(op3, 0, sizeof(ip_fw3_opheader));
207
 	memcpy(op3 + 1, optval, optlen);
208
 	op3->opcode = optname;
209
+	op3->ctxid = co.ctx;
210
 
211
 	return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
212
 }
213
@@ -4435,6 +4446,7 @@ table_list(uint16_t num, int need_header)
214
 	a = (uint32_t *)(op3 + 1);
215
 	*a = num;
216
 	op3->opcode = IP_FW_TABLE_XGETSIZE;
217
+	op3->ctxid = co.ctx;
218
 	if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0)
219
 		err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)");
220
 
221
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
222
index 9abe6ee..013b0ec 100644
223
--- a/sbin/ipfw/ipfw2.h
224
+++ b/sbin/ipfw/ipfw2.h
225
@@ -54,6 +54,7 @@ struct cmdline_opts {
226
 	int	use_set;	/* work with specified set number */
227
 		/* 0 means all sets, otherwise apply to set use_set - 1 */
228
 
229
+	u_int	ctx;
230
 };
231
 
232
 extern struct cmdline_opts co;
233
@@ -280,6 +281,9 @@ void dummynet_list(int ac, char *av[], int show_counters);
234
 void dummynet_flush(void);
235
 int ipfw_delete_pipe(int pipe_or_queue, int n);
236
 
237
+/* Contextes */
238
+int ipfw_context_handler(int, char **);
239
+
240
 /* ipv6.c */
241
 void print_unreach6_code(uint16_t code);
242
 void print_ip6(struct _ipfw_insn_ip6 *cmd, char const *s);
243
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
244
index 82a299b..ab75a1b 100644
245
--- a/sbin/ipfw/main.c
246
+++ b/sbin/ipfw/main.c
247
@@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav)
248
 	save_av = av;
249
 
250
 	optind = optreset = 1;	/* restart getopt() */
251
-	while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1)
252
+	while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtvx:")) != -1)
253
 		switch (ch) {
254
 		case 'a':
255
 			do_acct = 1;
256
@@ -335,6 +335,12 @@ ipfw_main(int oldac, char **oldav)
257
 			co.verbose = 1;
258
 			break;
259
 
260
+		case 'x':
261
+			co.ctx = atoi(optarg);
262
+			if (co.ctx == 0)
263
+				errx(EX_USAGE, "Context 0 is invalid");
264
+			break;
265
+
266
 		default:
267
 			free(save_av);
268
 			return 1;
269
@@ -362,7 +368,9 @@ ipfw_main(int oldac, char **oldav)
270
 	co.do_nat = 0;
271
 	co.do_pipe = 0;
272
 	co.use_set = 0;
273
-	if (!strncmp(*av, "nat", strlen(*av)))
274
+	if (!strncmp(*av, "zone", strlen(*av)))
275
+		return (ipfw_context_handler(ac, av));
276
+	else if (!strncmp(*av, "nat", strlen(*av)))
277
  		co.do_nat = 1;
278
  	else if (!strncmp(*av, "pipe", strlen(*av)))
279
 		co.do_pipe = 1;
280
@@ -389,6 +397,9 @@ ipfw_main(int oldac, char **oldav)
281
 	}
282
 	NEED1("missing command");
283
 
284
+	if (!co.ctx && !co.do_pipe)
285
+		err(11, "Context is mandatory");
286
+
287
 	/*
288
 	 * For pipes, queues and nats we normally say 'nat|pipe NN config'
289
 	 * but the code is easier to parse as 'nat|pipe config NN'
290
@@ -458,7 +469,7 @@ ipfw_readfile(int ac, char *av[])
291
 	FILE	*f = NULL;
292
 	pid_t	preproc = 0;
293
 
294
-	while ((c = getopt(ac, av, "cfNnp:qS")) != -1) {
295
+	while ((c = getopt(ac, av, "cfNnp:qSx:")) != -1) {
296
 		switch(c) {
297
 		case 'c':
298
 			co.do_compact = 1;
299
@@ -509,6 +520,12 @@ ipfw_readfile(int ac, char *av[])
300
 			co.show_sets = 1;
301
 			break;
302
 
303
+		case 'x':
304
+			co.ctx = atoi(optarg);
305
+			if (co.ctx == 0)
306
+				errx(EX_USAGE, "Context 0 is invalid");
307
+			break;
308
+
309
 		default:
310
 			errx(EX_USAGE, "bad arguments, for usage"
311
 			     " summary ``ipfw''");
312
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
313
index 7b64bf5..40b397d 100644
314
--- a/sys/netinet/ip_fw.h
315
+++ b/sys/netinet/ip_fw.h
316
@@ -65,7 +65,8 @@
317
 /* IP_FW3 header/opcodes */
318
 typedef struct _ip_fw3_opheader {
319
 	uint16_t opcode;	/* Operation opcode */
320
-	uint16_t reserved[3];	/* Align to 64-bit boundary */
321
+	uint16_t ctxid;
322
+	uint16_t reserved[2];	/* Align to 64-bit boundary */
323
 } ip_fw3_opheader;
324
 
325
 
326
@@ -76,6 +77,12 @@ typedef struct _ip_fw3_opheader {
327
 #define	IP_FW_TABLE_XLIST	89	/* list table contents */
328
 #define	IP_FW_TABLE_XLISTENTRY	90	/* list one table entry contents */
329
 #define	IP_FW_TABLE_XZEROENTRY	91	/* zero one table entry stats */
330
+#define	IP_FW_CTX_GET		92	
331
+#define	IP_FW_CTX_ADD		93	
332
+#define	IP_FW_CTX_DEL		94	
333
+#define	IP_FW_CTX_SET		95	
334
+#define	IP_FW_CTX_ADDMEMBER	96	
335
+#define	IP_FW_CTX_DELMEMBER	97	
336
 
337
 /*
338
  * The kernel representation of ipfw rules is made of a list of
339
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
340
index aa5a94d..1913a26 100644
341
--- a/sys/netpfil/ipfw/ip_fw2.c
342
+++ b/sys/netpfil/ipfw/ip_fw2.c
343
@@ -140,8 +140,7 @@ VNET_DEFINE(int, fw_verbose);
344
 VNET_DEFINE(u_int64_t, norule_counter);
345
 VNET_DEFINE(int, verbose_limit);
346
 
347
-/* layer3_chain contains the list of rules for layer 3 */
348
-VNET_DEFINE(struct ip_fw_chain, layer3_chain);
349
+VNET_DEFINE(struct ip_fw_contextes, ip_fw_contexts);
350
 
351
 VNET_DEFINE(int, ipfw_nat_ready) = 0;
352
 
353
@@ -182,9 +181,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
354
     "Make the default rule accept all packets.");
355
 TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
356
 TUNABLE_INT("net.inet.ip.fw.tables_max", (int *)&default_fw_tables);
357
-SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
358
-    CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
359
-    "Number of static rules");
360
 
361
 #ifdef INET6
362
 SYSCTL_DECL(_net_inet6_ip6);
363
@@ -904,6 +900,9 @@ ipfw_chk(struct ip_fw_args *args)
364
 	 */
365
 	struct ifnet *oif = args->oif;
366
 
367
+	if (V_ip_fw_contexts.chain[oif->if_ispare[0]] == NULL)
368
+		return (IP_FW_PASS);
369
+
370
 	int f_pos = 0;		/* index of current rule in the array */
371
 	int retval = 0;
372
 
373
@@ -954,9 +953,15 @@ ipfw_chk(struct ip_fw_args *args)
374
 	 */
375
 	int dyn_dir = MATCH_UNKNOWN;
376
 	ipfw_dyn_rule *q = NULL;
377
-	struct ip_fw_chain *chain = &V_layer3_chain;
378
 	void *tblent = NULL;
379
 
380
+	/* XXX: WARNING - The chain is accessed unlocked here.
381
+	 * There is a potential race here with context handling.
382
+	 * The chain pointer will get destroyed and a NULL 
383
+	 * pointer dereference can happen!
384
+	 */
385
+	struct ip_fw_chain *chain = V_ip_fw_contexts.chain[oif->if_ispare[0]];
386
+
387
 	/*
388
 	 * We store in ulp a pointer to the upper layer protocol header.
389
 	 * In the ipv4 case this is easy to determine from the header,
390
@@ -2501,7 +2506,7 @@ do {								\
391
 				    set_match(args, f_pos, chain);
392
 				    /* Check if this is 'global' nat rule */
393
 				    if (cmd->arg1 == 0) {
394
-					    retval = ipfw_nat_ptr(args, NULL, m);
395
+					    retval = ipfw_nat_ptr(args, NULL, m, chain);
396
 					    l = 0;
397
 					    done = 1;
398
 					    break;
399
@@ -2520,7 +2525,7 @@ do {								\
400
 					if (cmd->arg1 != IP_FW_TABLEARG)
401
 					    ((ipfw_insn_nat *)cmd)->nat = t;
402
 				    }
403
-				    retval = ipfw_nat_ptr(args, t, m);
404
+				    retval = ipfw_nat_ptr(args, t, m, chain);
405
 				}
406
 				l = 0;          /* exit inner loop */
407
 				done = 1;       /* exit outer loop */
408
@@ -2629,7 +2634,9 @@ sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS)
409
 	if ((error != 0) || (req->newptr == NULL))
410
 		return (error);
411
 
412
-	return (ipfw_resize_tables(&V_layer3_chain, ntables));
413
+	for (int i = 1; i < IP_FW_MAXCTX; i++)
414
+		error += ipfw_resize_tables(V_ip_fw_contexts.chain[i], ntables);
415
+	return (error);
416
 }
417
 #endif
418
 /*
419
@@ -2707,11 +2714,6 @@ ipfw_destroy(void)
420
 static int
421
 vnet_ipfw_init(const void *unused)
422
 {
423
-	int error;
424
-	struct ip_fw *rule = NULL;
425
-	struct ip_fw_chain *chain;
426
-
427
-	chain = &V_layer3_chain;
428
 
429
 	/* First set up some values that are compile time options */
430
 	V_autoinc_step = 100;	/* bounded to 1..1000 in add_rule() */
431
@@ -2722,10 +2724,55 @@ vnet_ipfw_init(const void *unused)
432
 #ifdef IPFIREWALL_VERBOSE_LIMIT
433
 	V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
434
 #endif
435
+
436
+	for (int i = 0; i < IP_FW_MAXCTX; i++)
437
+		V_ip_fw_contexts.chain[i] = NULL;
438
+
439
+	IPFW_CTX_LOCK_INIT();
440
+
441
+	V_ip_fw_contexts.ifnet_arrival = EVENTHANDLER_REGISTER(ifnet_arrival_event,
442
+		ipfw_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
443
+
444
+	ipfw_dyn_init();
445
+
446
+	/* First set up some values that are compile time options */
447
+	V_ipfw_vnet_ready = 1;		/* Open for business */
448
+
449
+	/*
450
+	 * Hook the sockopt handler and pfil hooks for ipv4 and ipv6.
451
+	 * Even if the latter two fail we still keep the module alive
452
+	 * because the sockopt and layer2 paths are still useful.
453
+	 * ipfw[6]_hook return 0 on success, ENOENT on failure,
454
+	 * so we can ignore the exact return value and just set a flag.
455
+	 *
456
+	 * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so
457
+	 * changes in the underlying (per-vnet) variables trigger
458
+	 * immediate hook()/unhook() calls.
459
+	 * In layer2 we have the same behaviour, except that V_ether_ipfw
460
+	 * is checked on each packet because there are no pfil hooks.
461
+	 */
462
+	V_ip_fw_ctl_ptr = ipfw_ctl;
463
+	return ipfw_attach_hooks(1);
464
+}
465
+
466
+int
467
+ipfw_context_init(int index)
468
+{
469
+	struct ip_fw_chain *chain;
470
+	struct ip_fw *rule = NULL;
471
+
472
+	if (index > IP_FW_MAXCTX)
473
+		return (-1);
474
+
475
+	TAILQ_INIT(&V_ip_fw_contexts.iflist[index]);
476
+
477
+	chain = V_ip_fw_contexts.chain[index];
478
+
479
+	IPFW_LOCK_INIT(chain);
480
+
481
 #ifdef IPFIREWALL_NAT
482
 	LIST_INIT(&chain->nat);
483
 #endif
484
-
485
 	/* insert the default rule and create the initial map */
486
 	chain->n_rules = 1;
487
 	chain->static_len = sizeof(struct ip_fw);
488
@@ -2735,13 +2782,7 @@ vnet_ipfw_init(const void *unused)
489
 
490
 	/* Set initial number of tables */
491
 	V_fw_tables_max = default_fw_tables;
492
-	error = ipfw_init_tables(chain);
493
-	if (error) {
494
-		printf("ipfw2: setting up tables failed\n");
495
-		free(chain->map, M_IPFW);
496
-		free(rule, M_IPFW);
497
-		return (ENOSPC);
498
-	}
499
+	ipfw_init_tables(chain);
500
 
501
 	/* fill and insert the default rule */
502
 	rule->act_ofs = 0;
503
@@ -2753,28 +2794,13 @@ vnet_ipfw_init(const void *unused)
504
 	chain->rules = chain->default_rule = chain->map[0] = rule;
505
 	chain->id = rule->id = 1;
506
 
507
-	IPFW_LOCK_INIT(chain);
508
-	ipfw_dyn_init(chain);
509
-
510
-	/* First set up some values that are compile time options */
511
-	V_ipfw_vnet_ready = 1;		/* Open for business */
512
+        /*
513
+         * This can potentially be done on first dynamic rule
514
+         * being added to chain.
515
+         */
516
+        resize_dynamic_table(chain, V_curr_dyn_buckets);
517
 
518
-	/*
519
-	 * Hook the sockopt handler and pfil hooks for ipv4 and ipv6.
520
-	 * Even if the latter two fail we still keep the module alive
521
-	 * because the sockopt and layer2 paths are still useful.
522
-	 * ipfw[6]_hook return 0 on success, ENOENT on failure,
523
-	 * so we can ignore the exact return value and just set a flag.
524
-	 *
525
-	 * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so
526
-	 * changes in the underlying (per-vnet) variables trigger
527
-	 * immediate hook()/unhook() calls.
528
-	 * In layer2 we have the same behaviour, except that V_ether_ipfw
529
-	 * is checked on each packet because there are no pfil hooks.
530
-	 */
531
-	V_ip_fw_ctl_ptr = ipfw_ctl;
532
-	error = ipfw_attach_hooks(1);
533
-	return (error);
534
+	return (0);
535
 }
536
 
537
 /*
538
@@ -2783,11 +2809,9 @@ vnet_ipfw_init(const void *unused)
539
 static int
540
 vnet_ipfw_uninit(const void *unused)
541
 {
542
-	struct ip_fw *reap, *rule;
543
-	struct ip_fw_chain *chain = &V_layer3_chain;
544
-	int i;
545
 
546
 	V_ipfw_vnet_ready = 0; /* tell new callers to go away */
547
+
548
 	/*
549
 	 * disconnect from ipv4, ipv6, layer2 and sockopt.
550
 	 * Then grab, release and grab again the WLOCK so we make
551
@@ -2795,14 +2819,51 @@ vnet_ipfw_uninit(const void *unused)
552
 	 */
553
 	(void)ipfw_attach_hooks(0 /* detach */);
554
 	V_ip_fw_ctl_ptr = NULL;
555
+
556
+	ipfw_dyn_uninit(0);	/* run the callout_drain */
557
+
558
+	IPFW_CTX_WLOCK();
559
+	EVENTHANDLER_DEREGISTER(ifnet_arrival_event, V_ip_fw_contexts.ifnet_arrival);
560
+	for (int i = 0; i < IP_FW_MAXCTX; i++) {
561
+		ipfw_context_uninit(i);
562
+	}
563
+	IPFW_CTX_WUNLOCK();
564
+	IPFW_CTX_LOCK_DESTROY();
565
+
566
+	ipfw_dyn_uninit(1);	/* free the remaining parts */
567
+
568
+	return (0);
569
+}
570
+
571
+int
572
+ipfw_context_uninit(int index)
573
+{
574
+	struct ip_fw_chain *chain;
575
+	struct ip_fw_ctx_iflist *ifl;
576
+	struct ip_fw *reap, *rule;
577
+	struct ifnet *ifp;
578
+	int i;
579
+
580
+	if (index > IP_FW_MAXCTX)
581
+		return (-1);
582
+
583
+	chain = V_ip_fw_contexts.chain[index];
584
+	if (chain == NULL)
585
+		return (0);
586
+
587
+	while (!TAILQ_EMPTY(&V_ip_fw_contexts.iflist[index])) {
588
+		ifl = TAILQ_FIRST(&V_ip_fw_contexts.iflist[index]);
589
+		TAILQ_REMOVE(&V_ip_fw_contexts.iflist[index], ifl, entry);
590
+		ifp = ifunit(ifl->ifname);
591
+		if (ifp != NULL)
592
+			ifp->if_ispare[0] = 0;
593
+		free(ifl, M_IPFW);
594
+	}
595
+
596
 	IPFW_UH_WLOCK(chain);
597
 	IPFW_UH_WUNLOCK(chain);
598
 	IPFW_UH_WLOCK(chain);
599
 
600
-	IPFW_WLOCK(chain);
601
-	ipfw_dyn_uninit(0);	/* run the callout_drain */
602
-	IPFW_WUNLOCK(chain);
603
-
604
 	ipfw_destroy_tables(chain);
605
 	reap = NULL;
606
 	IPFW_WLOCK(chain);
607
@@ -2818,8 +2879,10 @@ vnet_ipfw_uninit(const void *unused)
608
 	if (reap != NULL)
609
 		ipfw_reap_rules(reap);
610
 	IPFW_LOCK_DESTROY(chain);
611
-	ipfw_dyn_uninit(1);	/* free the remaining parts */
612
-	return 0;
613
+
614
+	free(chain, M_IPFW);
615
+
616
+	return (0);
617
 }
618
 
619
 /*
620
diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
621
index a166d12..694362a 100644
622
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
623
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
624
@@ -121,11 +121,9 @@ struct ipfw_dyn_bucket {
625
  */
626
 static VNET_DEFINE(struct ipfw_dyn_bucket *, ipfw_dyn_v);
627
 static VNET_DEFINE(u_int32_t, dyn_buckets_max);
628
-static VNET_DEFINE(u_int32_t, curr_dyn_buckets);
629
 static VNET_DEFINE(struct callout, ipfw_timeout);
630
 #define	V_ipfw_dyn_v			VNET(ipfw_dyn_v)
631
 #define	V_dyn_buckets_max		VNET(dyn_buckets_max)
632
-#define	V_curr_dyn_buckets		VNET(curr_dyn_buckets)
633
 #define V_ipfw_timeout                  VNET(ipfw_timeout)
634
 
635
 static VNET_DEFINE(uma_zone_t, ipfw_dyn_rule_zone);
636
@@ -181,6 +179,8 @@ static VNET_DEFINE(u_int32_t, dyn_max);		/* max # of dynamic rules */
637
 
638
 static int last_log;	/* Log ratelimiting */
639
 
640
+VNET_DEFINE(u_int32_t, curr_dyn_buckets);
641
+
642
 static void ipfw_dyn_tick(void *vnetx);
643
 static void check_dyn_rules(struct ip_fw_chain *, struct ip_fw *,
644
     int, int, int);
645
@@ -472,7 +472,7 @@ ipfw_dyn_unlock(ipfw_dyn_rule *q)
646
 	IPFW_BUCK_UNLOCK(q->bucket);
647
 }
648
 
649
-static int
650
+int
651
 resize_dynamic_table(struct ip_fw_chain *chain, int nbuckets)
652
 {
653
 	int i, k, nbuckets_old;
654
@@ -972,7 +972,6 @@ ipfw_dyn_send_ka(struct mbuf **mtailp, ipfw_dyn_rule *q)
655
 static void
656
 ipfw_dyn_tick(void * vnetx) 
657
 {
658
-	struct ip_fw_chain *chain;
659
 	int check_ka = 0;
660
 #ifdef VIMAGE
661
 	struct vnet *vp = vnetx;
662
@@ -980,7 +979,6 @@ ipfw_dyn_tick(void * vnetx)
663
 
664
 	CURVNET_SET(vp);
665
 
666
-	chain = &V_layer3_chain;
667
 
668
 	/* Run keepalive checks every keepalive_period iff ka is enabled */
669
 	if ((V_dyn_keepalive_last + V_dyn_keepalive_period <= time_uptime) &&
670
@@ -989,7 +987,12 @@ ipfw_dyn_tick(void * vnetx)
671
 		check_ka = 1;
672
 	}
673
 
674
-	check_dyn_rules(chain, NULL, RESVD_SET, check_ka, 1);
675
+	IPFW_CTX_RLOCK();
676
+	for (int i = 1; i < IP_FW_MAXCTX; i++) {
677
+		if (V_ip_fw_contexts.chain[i] != NULL)
678
+			check_dyn_rules(V_ip_fw_contexts.chain[i], NULL, RESVD_SET, check_ka, 1);
679
+	}
680
+	IPFW_CTX_RUNLOCK();
681
 
682
 	callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, vnetx, 0);
683
 
684
@@ -1305,7 +1308,7 @@ ipfw_expire_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule, int set)
685
 }
686
 
687
 void
688
-ipfw_dyn_init(struct ip_fw_chain *chain)
689
+ipfw_dyn_init()
690
 {
691
 
692
         V_ipfw_dyn_v = NULL;
693
@@ -1334,12 +1337,6 @@ ipfw_dyn_init(struct ip_fw_chain *chain)
694
 	uma_zone_set_max(V_ipfw_dyn_rule_zone, V_dyn_max);
695
 
696
         callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE);
697
-
698
-	/*
699
-	 * This can potentially be done on first dynamic rule
700
-	 * being added to chain.
701
-	 */
702
-	resize_dynamic_table(chain, V_curr_dyn_buckets);
703
 }
704
 
705
 void
706
diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c
707
index d4348b5..5c04a36 100644
708
--- a/sys/netpfil/ipfw/ip_fw_nat.c
709
+++ b/sys/netpfil/ipfw/ip_fw_nat.c
710
@@ -64,26 +64,33 @@ ifaddr_change(void *arg __unused, struct ifnet *ifp)
711
 
712
 	KASSERT(curvnet == ifp->if_vnet,
713
 	    ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
714
-	chain = &V_layer3_chain;
715
-	IPFW_WLOCK(chain);
716
-	/* Check every nat entry... */
717
-	LIST_FOREACH(ptr, &chain->nat, _next) {
718
-		/* ...using nic 'ifp->if_xname' as dynamic alias address. */
719
-		if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
720
+
721
+	IPFW_CTX_RLOCK();
722
+	for (int i = 1; i < IP_FW_MAXCTX; i++) {
723
+		chain = V_ip_fw_contexts.chain[i];
724
+		if (chain == NULL)
725
 			continue;
726
-		if_addr_rlock(ifp);
727
-		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
728
-			if (ifa->ifa_addr == NULL)
729
-				continue;
730
-			if (ifa->ifa_addr->sa_family != AF_INET)
731
+		IPFW_WLOCK(chain);
732
+		/* Check every nat entry... */
733
+		LIST_FOREACH(ptr, &chain->nat, _next) {
734
+			/* ...using nic 'ifp->if_xname' as dynamic alias address. */
735
+			if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
736
 				continue;
737
-			ptr->ip = ((struct sockaddr_in *)
738
-			    (ifa->ifa_addr))->sin_addr;
739
-			LibAliasSetAddress(ptr->lib, ptr->ip);
740
+			if_addr_rlock(ifp);
741
+			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
742
+				if (ifa->ifa_addr == NULL)
743
+					continue;
744
+				if (ifa->ifa_addr->sa_family != AF_INET)
745
+					continue;
746
+				ptr->ip = ((struct sockaddr_in *)
747
+				    (ifa->ifa_addr))->sin_addr;
748
+				LibAliasSetAddress(ptr->lib, ptr->ip);
749
+			}
750
+			if_addr_runlock(ifp);
751
 		}
752
-		if_addr_runlock(ifp);
753
+		IPFW_WUNLOCK(chain);
754
 	}
755
-	IPFW_WUNLOCK(chain);
756
+	IPFW_CTX_RUNLOCK();
757
 }
758
 
759
 /*
760
@@ -206,18 +213,18 @@ add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
761
 /*
762
  * ipfw_nat - perform mbuf header translation.
763
  *
764
- * Note V_layer3_chain has to be locked while calling ipfw_nat() in
765
+ * Note *chain has to be locked while calling ipfw_nat() in
766
  * 'global' operation mode (t == NULL).
767
  *
768
  */
769
 static int
770
-ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
771
+ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m,
772
+    struct ip_fw_chain *chain)
773
 {
774
 	struct mbuf *mcl;
775
 	struct ip *ip;
776
 	/* XXX - libalias duct tape */
777
 	int ldt, retval, found;
778
-	struct ip_fw_chain *chain;
779
 	char *c;
780
 
781
 	ldt = 0;
782
@@ -276,7 +283,6 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
783
 		}
784
 
785
 		found = 0;
786
-		chain = &V_layer3_chain;
787
 		IPFW_RLOCK_ASSERT(chain);
788
 		/* Check every nat entry... */
789
 		LIST_FOREACH(t, &chain->nat, _next) {
790
@@ -391,11 +397,10 @@ lookup_nat(struct nat_list *l, int nat_id)
791
 }
792
 
793
 static int
794
-ipfw_nat_cfg(struct sockopt *sopt)
795
+ipfw_nat_cfg(struct sockopt *sopt, struct ip_fw_chain *chain)
796
 {
797
 	struct cfg_nat *cfg, *ptr;
798
 	char *buf;
799
-	struct ip_fw_chain *chain = &V_layer3_chain;
800
 	size_t len;
801
 	int gencnt, error = 0;
802
 
803
@@ -468,10 +473,9 @@ out:
804
 }
805
 
806
 static int
807
-ipfw_nat_del(struct sockopt *sopt)
808
+ipfw_nat_del(struct sockopt *sopt, struct ip_fw_chain *chain)
809
 {
810
 	struct cfg_nat *ptr;
811
-	struct ip_fw_chain *chain = &V_layer3_chain;
812
 	int i;
813
 
814
 	sooptcopyin(sopt, &i, sizeof i, sizeof i);
815
@@ -492,9 +496,8 @@ ipfw_nat_del(struct sockopt *sopt)
816
 }
817
 
818
 static int
819
-ipfw_nat_get_cfg(struct sockopt *sopt)
820
+ipfw_nat_get_cfg(struct sockopt *sopt, struct ip_fw_chain *chain)
821
 {
822
-	struct ip_fw_chain *chain = &V_layer3_chain;
823
 	struct cfg_nat *n;
824
 	struct cfg_redir *r;
825
 	struct cfg_spool *s;
826
@@ -552,14 +555,11 @@ retry:
827
 }
828
 
829
 static int
830
-ipfw_nat_get_log(struct sockopt *sopt)
831
+ipfw_nat_get_log(struct sockopt *sopt, struct ip_fw_chain *chain)
832
 {
833
 	uint8_t *data;
834
 	struct cfg_nat *ptr;
835
 	int i, size;
836
-	struct ip_fw_chain *chain;
837
-
838
-	chain = &V_layer3_chain;
839
 
840
 	IPFW_RLOCK(chain);
841
 	/* one pass to count, one to copy the data */
842
@@ -604,17 +604,22 @@ vnet_ipfw_nat_uninit(const void *arg __unused)
843
 	struct cfg_nat *ptr, *ptr_temp;
844
 	struct ip_fw_chain *chain;
845
 
846
-	chain = &V_layer3_chain;
847
-	IPFW_WLOCK(chain);
848
-	LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
849
-		LIST_REMOVE(ptr, _next);
850
-		del_redir_spool_cfg(ptr, &ptr->redir_chain);
851
-		LibAliasUninit(ptr->lib);
852
-		free(ptr, M_IPFW);
853
+	IPFW_CTX_RLOCK();
854
+	for (int i = 1; i < IP_FW_MAXCTX; i++) {
855
+		chain = V_ip_fw_contexts.chain[i];
856
+		IPFW_WLOCK(chain);
857
+		LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
858
+			LIST_REMOVE(ptr, _next);
859
+			del_redir_spool_cfg(ptr, &ptr->redir_chain);
860
+			LibAliasUninit(ptr->lib);
861
+			free(ptr, M_IPFW);
862
+		}
863
+		flush_nat_ptrs(chain, -1 /* flush all */);
864
+		V_ipfw_nat_ready = 0;
865
+		IPFW_WUNLOCK(chain);
866
 	}
867
-	flush_nat_ptrs(chain, -1 /* flush all */);
868
-	V_ipfw_nat_ready = 0;
869
-	IPFW_WUNLOCK(chain);
870
+	IPFW_CTX_RUNLOCK();
871
+
872
 	return (0);
873
 }
874
 
875
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
876
index 1d8a4aa..e7a2695 100644
877
--- a/sys/netpfil/ipfw/ip_fw_private.h
878
+++ b/sys/netpfil/ipfw/ip_fw_private.h
879
@@ -171,6 +171,9 @@ enum { /* result for matching dynamic rules */
880
 	MATCH_UNKNOWN,
881
 };
882
 
883
+VNET_DECLARE(u_int32_t, curr_dyn_buckets);
884
+#define V_curr_dyn_buckets              VNET(curr_dyn_buckets)
885
+
886
 /*
887
  * The lock for dynamic rules is only used once outside the file,
888
  * and only to release the result of lookup_dyn_rule().
889
@@ -179,6 +182,7 @@ enum { /* result for matching dynamic rules */
890
 struct ip_fw_chain;
891
 void ipfw_expire_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int);
892
 void ipfw_dyn_unlock(ipfw_dyn_rule *q);
893
+int resize_dynamic_table(struct ip_fw_chain *, int);
894
 
895
 struct tcphdr;
896
 struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
897
@@ -190,7 +194,7 @@ ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,
898
 void ipfw_remove_dyn_children(struct ip_fw *rule);
899
 void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep);
900
 
901
-void ipfw_dyn_init(struct ip_fw_chain *);	/* per-vnet initialization */
902
+void ipfw_dyn_init(void);	/* per-vnet initialization */
903
 void ipfw_dyn_uninit(int);	/* per-vnet deinitialization */
904
 int ipfw_dyn_len(void);
905
 
906
@@ -201,9 +205,6 @@ VNET_DECLARE(int, fw_one_pass);
907
 VNET_DECLARE(int, fw_verbose);
908
 #define	V_fw_verbose		VNET(fw_verbose)
909
 
910
-VNET_DECLARE(struct ip_fw_chain, layer3_chain);
911
-#define	V_layer3_chain		VNET(layer3_chain)
912
-
913
 VNET_DECLARE(u_int32_t, set_disable);
914
 #define	V_set_disable		VNET(set_disable)
915
 
916
@@ -235,6 +236,33 @@ struct ip_fw_chain {
917
 	uint32_t	gencnt;		/* generation count */
918
 };
919
 
920
+struct ip_fw_ctx_iflist {
921
+	TAILQ_ENTRY(ip_fw_ctx_iflist) entry;
922
+	char ifname[IFNAMSIZ];
923
+};
924
+
925
+#define	IP_FW_MAXCTX		4096
926
+struct ip_fw_contextes {
927
+	struct ip_fw_chain	*chain[IP_FW_MAXCTX]; /* Arrays of contextes */
928
+	TAILQ_HEAD(, ip_fw_ctx_iflist) iflist[IP_FW_MAXCTX];
929
+	struct rwlock rwctx;
930
+	eventhandler_tag        ifnet_arrival;
931
+};
932
+
933
+VNET_DECLARE(struct ip_fw_contextes,	ip_fw_contexts);
934
+#define	V_ip_fw_contexts	VNET(ip_fw_contexts)
935
+
936
+#define	IPFW_CTX_LOCK_INIT()	rw_init(&V_ip_fw_contexts.rwctx, "IPFW context")
937
+#define	IPFW_CTX_LOCK_DESTROY()	rw_destroy(&V_ip_fw_contexts.rwctx)
938
+#define	IPFW_CTX_WLOCK()	rw_wlock(&V_ip_fw_contexts.rwctx)
939
+#define	IPFW_CTX_WUNLOCK()	rw_wunlock(&V_ip_fw_contexts.rwctx)
940
+#define	IPFW_CTX_RLOCK()	rw_rlock(&V_ip_fw_contexts.rwctx)
941
+#define	IPFW_CTX_RUNLOCK()	rw_runlock(&V_ip_fw_contexts.rwctx)
942
+
943
+void	ipfw_attach_ifnet_event(void *, struct ifnet *);
944
+int	ipfw_context_init(int);
945
+int	ipfw_context_uninit(int);
946
+
947
 struct sockopt;	/* used by tcp_var.h */
948
 
949
 /* Macro for working with various counters */
950
@@ -328,8 +356,9 @@ int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables);
951
 
952
 extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
953
 
954
-typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
955
-typedef int ipfw_nat_cfg_t(struct sockopt *);
956
+typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *,
957
+			struct ip_fw_chain *);
958
+typedef int ipfw_nat_cfg_t(struct sockopt *, struct ip_fw_chain *);
959
 
960
 VNET_DECLARE(int, ipfw_nat_ready);
961
 #define	V_ipfw_nat_ready	VNET(ipfw_nat_ready)
962
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
963
index 9e6b5ca..e977df2 100644
964
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
965
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
966
@@ -943,12 +943,15 @@ ipfw_ctl(struct sockopt *sopt)
967
 #define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
968
 	int error;
969
 	size_t size, len, valsize;
970
+	struct ifnet *ifp;
971
 	struct ip_fw *buf, *rule;
972
-	struct ip_fw_chain *chain;
973
+	static struct ip_fw_chain *chain;
974
+	struct ip_fw_ctx_iflist *tmpifl, *tmpifl2 = NULL;
975
+	ip_fw3_opheader *op3 = NULL;
976
 	u_int32_t rulenum[2];
977
 	uint32_t opt;
978
 	char xbuf[128];
979
-	ip_fw3_opheader *op3 = NULL;
980
+	char *ifname;
981
 
982
 	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
983
 	if (error)
984
@@ -965,7 +968,6 @@ ipfw_ctl(struct sockopt *sopt)
985
 			return (error);
986
 	}
987
 
988
-	chain = &V_layer3_chain;
989
 	error = 0;
990
 
991
 	/* Save original valsize before it is altered via sooptcopyin() */
992
@@ -980,9 +982,236 @@ ipfw_ctl(struct sockopt *sopt)
993
 			return (error);
994
 		op3 = (ip_fw3_opheader *)xbuf;
995
 		opt = op3->opcode;
996
+
997
+		if (op3->ctxid > IP_FW_MAXCTX)
998
+			return (EINVAL);
999
+
1000
+		if (opt != IP_FW_CTX_GET) {
1001
+			if (opt != IP_FW_CTX_ADD) {
1002
+				if (op3->ctxid == 0)
1003
+					return (ENOENT);
1004
+			} 
1005
+
1006
+			chain = V_ip_fw_contexts.chain[op3->ctxid];
1007
+		}
1008
+	}
1009
+
1010
+	/* Verification needed to avoid problems */
1011
+	switch (opt) {
1012
+	case IP_FW_CTX_GET:
1013
+	case IP_FW_CTX_ADD:
1014
+	case IP_FW_CTX_DEL:
1015
+		break;
1016
+	default:
1017
+		if (chain == NULL)
1018
+			return (EINVAL);
1019
+		/* NOTREACHED */
1020
 	}
1021
 
1022
 	switch (opt) {
1023
+	case IP_FW_CTX_ADD:
1024
+		IPFW_CTX_WLOCK();
1025
+		if (V_ip_fw_contexts.chain[op3->ctxid] != NULL) {
1026
+			IPFW_CTX_WUNLOCK();
1027
+			return (EEXIST);
1028
+		}
1029
+
1030
+		chain = malloc(sizeof(struct ip_fw_chain), M_IPFW, M_WAITOK | M_ZERO);
1031
+		TAILQ_INIT(&V_ip_fw_contexts.iflist[op3->ctxid]);
1032
+		V_ip_fw_contexts.chain[op3->ctxid] = chain;
1033
+		ipfw_context_init(op3->ctxid); /* XXX: error checking */
1034
+		IPFW_CTX_WUNLOCK();
1035
+		break;
1036
+
1037
+	case IP_FW_CTX_DEL:
1038
+		IPFW_CTX_WLOCK();
1039
+		if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) {
1040
+			IPFW_CTX_WUNLOCK();
1041
+			return (ENOENT);
1042
+		}
1043
+
1044
+		ipfw_context_uninit(op3->ctxid);
1045
+		V_ip_fw_contexts.chain[op3->ctxid] = NULL;
1046
+		IPFW_CTX_WUNLOCK();
1047
+		break;
1048
+
1049
+	case IP_FW_CTX_GET:
1050
+		{
1051
+			int i, n, len = 0, want;
1052
+			char *bufout, *tmpbuf;
1053
+
1054
+			sopt->sopt_valsize = valsize;
1055
+
1056
+			IPFW_CTX_RLOCK();
1057
+			for (i = 1; i < IP_FW_MAXCTX; i++) {
1058
+				if (op3->ctxid > 0 && op3->ctxid != i)
1059
+					continue;
1060
+				if (op3->ctxid > 0 && op3->ctxid < i)
1061
+					break;
1062
+
1063
+				if (V_ip_fw_contexts.chain[i] == NULL)
1064
+					continue;
1065
+
1066
+				/* Calculate number of bytes for the integer */
1067
+				n = i;
1068
+				while (n > 0) {
1069
+					n /= 10;
1070
+					len++;
1071
+				}
1072
+				TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
1073
+					len += strlen(tmpifl->ifname) + 1;
1074
+				}
1075
+				len += 3; // newline, :, space
1076
+			}
1077
+			IPFW_CTX_RUNLOCK();
1078
+
1079
+			if (len > sopt->sopt_valsize) {
1080
+				sopt->sopt_valsize = len;
1081
+				break;
1082
+			}
1083
+
1084
+			bufout = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
1085
+			if (bufout == NULL)
1086
+				break;
1087
+			
1088
+			/* Record our size for later checks */
1089
+			want = len;
1090
+			len = 0;
1091
+			IPFW_CTX_RLOCK();
1092
+			/* Recalculate length to detect if smth changed */
1093
+			for (i = 1; i < IP_FW_MAXCTX; i++) {
1094
+				if (op3->ctxid > 0 && op3->ctxid != i)
1095
+					continue;
1096
+				if (op3->ctxid > 0 && op3->ctxid < i)
1097
+					break;
1098
+
1099
+				if (V_ip_fw_contexts.chain[i] == NULL)
1100
+					continue;
1101
+
1102
+				/* Calculate number of bytes for the integer */
1103
+				n = i;
1104
+				while (n > 0) {
1105
+					n /= 10;
1106
+					len++;
1107
+				}
1108
+				TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
1109
+					len += strlen(tmpifl->ifname) + 1;
1110
+				}
1111
+				len += 3; // newline, :, space
1112
+			}
1113
+
1114
+			if (want >= len) {
1115
+				tmpbuf = bufout;
1116
+				for (i = 1; i < IP_FW_MAXCTX; i++) {
1117
+					if (op3->ctxid > 0 && op3->ctxid != i)
1118
+						continue;
1119
+					if (op3->ctxid > 0 && op3->ctxid < i)
1120
+						break;
1121
+
1122
+					if (V_ip_fw_contexts.chain[i] == NULL)
1123
+						continue;
1124
+
1125
+					sprintf(tmpbuf, "%d: ", i);
1126
+					tmpbuf += strlen(tmpbuf);
1127
+					TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
1128
+						sprintf(tmpbuf, "%s,", tmpifl->ifname);
1129
+						tmpbuf += strlen(tmpifl->ifname) + 1;
1130
+					}
1131
+					sprintf(tmpbuf, "\n");
1132
+					tmpbuf++;
1133
+				}
1134
+			}
1135
+			IPFW_CTX_RUNLOCK();
1136
+
1137
+			if (want >= len)
1138
+				error = sooptcopyout(sopt, bufout, len);
1139
+			else
1140
+				len = 0;
1141
+			free(bufout, M_TEMP);
1142
+		}
1143
+		break;
1144
+
1145
+	case IP_FW_CTX_SET:
1146
+		/* XXX: Maybe not use this option at all? */
1147
+		IPFW_CTX_RLOCK();
1148
+		if (V_ip_fw_contexts.chain[op3->ctxid] == NULL)
1149
+			error = ENOENT;
1150
+		else
1151
+			chain = V_ip_fw_contexts.chain[op3->ctxid];
1152
+		IPFW_CTX_RUNLOCK();
1153
+		break;
1154
+
1155
+	case IP_FW_CTX_ADDMEMBER:
1156
+		{
1157
+			int i;
1158
+
1159
+			ifname = (char *)(op3 + 1);
1160
+			ifp = ifunit(ifname);
1161
+			if (ifp == NULL)
1162
+				return (ENOENT);
1163
+
1164
+			tmpifl = malloc(sizeof(*tmpifl), M_IPFW, M_WAITOK | M_ZERO);
1165
+
1166
+			IPFW_CTX_WLOCK();
1167
+			if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) {
1168
+				IPFW_CTX_WUNLOCK();
1169
+				free(tmpifl, M_IPFW);
1170
+				return (ENOENT);
1171
+			}
1172
+
1173
+			for (i = 1; i < IP_FW_MAXCTX; i++) {
1174
+				if (V_ip_fw_contexts.chain[i] == NULL)
1175
+					continue;
1176
+
1177
+				TAILQ_FOREACH(tmpifl2, &V_ip_fw_contexts.iflist[i], entry) {
1178
+					if (strlen(tmpifl2->ifname) != strlen(ifname))
1179
+						continue;
1180
+					if (!strcmp(tmpifl2->ifname, ifname))
1181
+						goto ctxifacefound;
1182
+				}
1183
+			}
1184
+ctxifacefound:
1185
+			if (tmpifl2 != NULL) {
1186
+				IPFW_CTX_WUNLOCK();
1187
+				free(tmpifl, M_IPFW);
1188
+				return (EEXIST);
1189
+			}
1190
+
1191
+			strlcpy(tmpifl->ifname, ifname, IFNAMSIZ);
1192
+			TAILQ_INSERT_HEAD(&V_ip_fw_contexts.iflist[op3->ctxid], tmpifl, entry);
1193
+			ifp->if_ispare[0] = op3->ctxid;
1194
+			IPFW_CTX_WUNLOCK();
1195
+		}
1196
+		break;
1197
+
1198
+	case IP_FW_CTX_DELMEMBER:
1199
+		IPFW_CTX_WLOCK();
1200
+		if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) {
1201
+			IPFW_CTX_WUNLOCK();
1202
+			return (ENOENT);
1203
+		}
1204
+
1205
+		ifname = (char *)(op3 + 1);
1206
+		TAILQ_FOREACH(tmpifl2, &V_ip_fw_contexts.iflist[op3->ctxid], entry) {
1207
+			if (strlen(tmpifl2->ifname) != strlen(ifname))
1208
+				continue;
1209
+			if (!strcmp(tmpifl2->ifname, ifname)) 
1210
+				break;
1211
+		}
1212
+		if (tmpifl2 == NULL) {
1213
+			IPFW_CTX_WUNLOCK();
1214
+			return (ENOENT);
1215
+		}
1216
+
1217
+		TAILQ_REMOVE(&V_ip_fw_contexts.iflist[op3->ctxid], tmpifl2, entry);
1218
+		IPFW_CTX_WUNLOCK();
1219
+		free(tmpifl2, M_IPFW);
1220
+
1221
+		ifp = ifunit(ifname);
1222
+		if (ifp != NULL)
1223
+			ifp->if_ispare[0] = 0;
1224
+		break;
1225
+
1226
 	case IP_FW_GET:
1227
 		/*
1228
 		 * pass up a copy of the current rules. Static rules
1229
@@ -1321,7 +1550,7 @@ ipfw_ctl(struct sockopt *sopt)
1230
 	/*--- NAT operations are protected by the IPFW_LOCK ---*/
1231
 	case IP_FW_NAT_CFG:
1232
 		if (IPFW_NAT_LOADED)
1233
-			error = ipfw_nat_cfg_ptr(sopt);
1234
+			error = ipfw_nat_cfg_ptr(sopt, chain);
1235
 		else {
1236
 			printf("IP_FW_NAT_CFG: %s\n",
1237
 			    "ipfw_nat not present, please load it");
1238
@@ -1331,7 +1560,7 @@ ipfw_ctl(struct sockopt *sopt)
1239
 
1240
 	case IP_FW_NAT_DEL:
1241
 		if (IPFW_NAT_LOADED)
1242
-			error = ipfw_nat_del_ptr(sopt);
1243
+			error = ipfw_nat_del_ptr(sopt, chain);
1244
 		else {
1245
 			printf("IP_FW_NAT_DEL: %s\n",
1246
 			    "ipfw_nat not present, please load it");
1247
@@ -1341,7 +1570,7 @@ ipfw_ctl(struct sockopt *sopt)
1248
 
1249
 	case IP_FW_NAT_GET_CONFIG:
1250
 		if (IPFW_NAT_LOADED)
1251
-			error = ipfw_nat_get_cfg_ptr(sopt);
1252
+			error = ipfw_nat_get_cfg_ptr(sopt, chain);
1253
 		else {
1254
 			printf("IP_FW_NAT_GET_CFG: %s\n",
1255
 			    "ipfw_nat not present, please load it");
1256
@@ -1351,7 +1580,7 @@ ipfw_ctl(struct sockopt *sopt)
1257
 
1258
 	case IP_FW_NAT_GET_LOG:
1259
 		if (IPFW_NAT_LOADED)
1260
-			error = ipfw_nat_get_log_ptr(sopt);
1261
+			error = ipfw_nat_get_log_ptr(sopt, chain);
1262
 		else {
1263
 			printf("IP_FW_NAT_GET_LOG: %s\n",
1264
 			    "ipfw_nat not present, please load it");
1265
@@ -1368,6 +1597,33 @@ ipfw_ctl(struct sockopt *sopt)
1266
 #undef RULE_MAXSIZE
1267
 }
1268
 
1269
+void
1270
+ipfw_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
1271
+{
1272
+	struct ip_fw_ctx_iflist *tmpifl;
1273
+
1274
+	CURVNET_SET(ifp->if_vnet);
1275
+
1276
+	IPFW_CTX_RLOCK();
1277
+	for (int i = 1; i < IP_FW_MAXCTX; i++) {
1278
+		if (V_ip_fw_contexts.chain[i] == NULL)
1279
+			continue;
1280
+		TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
1281
+			if (strlen(tmpifl->ifname) != strlen(ifp->if_xname))
1282
+				continue;
1283
+			if (!strcmp(tmpifl->ifname, ifp->if_xname)) {
1284
+				printf("Restoring context for interface %s to %d\n", ifp->if_xname, i);
1285
+				ifp->if_ispare[0] = i;
1286
+				goto ifctxdone;
1287
+				break;
1288
+			}
1289
+		}
1290
+	}
1291
+ifctxdone:
1292
+	IPFW_CTX_RUNLOCK();
1293
+
1294
+	CURVNET_RESTORE();
1295
+}
1296
 
1297
 #define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
1298
 
(1-1/67)