netisr: netisr_forwardmsg -> netisr_forwardmsg_all
[dragonfly.git] / sys / net / ipfw3 / ip_fw3_table.c
blob73dc7b64cb5adb1f548e4a555ae7e0811ab77b8c
1 /*
2 * Copyright (c) 2015 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/sysctl.h>
46 #include <sys/syslog.h>
47 #include <sys/ucred.h>
48 #include <sys/in_cksum.h>
49 #include <sys/lock.h>
50 #include <sys/thread2.h>
51 #include <sys/mplock2.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/ip_icmp.h>
60 #include <netinet/tcp.h>
61 #include <netinet/tcp_timer.h>
62 #include <netinet/tcp_var.h>
63 #include <netinet/tcpip.h>
64 #include <netinet/udp.h>
65 #include <netinet/udp_var.h>
66 #include <netinet/ip_divert.h>
67 #include <netinet/if_ether.h>
69 #include <net/if.h>
70 #include <net/route.h>
71 #include <net/pfil.h>
72 #include <net/netmsg2.h>
73 #include <net/ethernet.h>
75 #include <net/ipfw3/ip_fw.h>
76 #include <net/ipfw3/ip_fw3_table.h>
78 MALLOC_DEFINE(M_IPFW3_TABLE, "IPFW3_TABLE", "mem for ip_fw3 table");
80 extern struct ipfw_context *ipfw_ctx[MAXCPU];
83 * activate/create the table by setup the type and reset counts.
85 static void
86 table_create_dispatch(netmsg_t nmsg)
88 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
89 struct ipfw_ioc_table *ioc_table;
90 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
91 struct ipfw_table_context *table_ctx;
92 ioc_table = tbmsg->ioc_table;
93 int id = ioc_table->id;
95 table_ctx = ctx->table_ctx;
96 table_ctx += id;
97 table_ctx->type = ioc_table->type;
98 table_ctx->count = 0;
99 strlcpy(table_ctx->name , ioc_table->name, IPFW_TABLE_NAME_LEN);
100 if (table_ctx->type == 1) {
101 rn_inithead((void **)&table_ctx->mask, NULL, 0);
102 rn_inithead((void **)&table_ctx->node, table_ctx->mask, 32);
103 } else if (table_ctx->type == 2) {
104 rn_inithead((void **)&table_ctx->mask, NULL, 0);
105 rn_inithead((void **)&table_ctx->node, table_ctx->mask, 48);
106 } else {
107 goto done;
109 done:
110 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
114 * clean the table, especially the node
116 static void
117 table_delete_dispatch(netmsg_t nmsg)
119 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
120 struct ipfw_ioc_table *ioc_tbl;
121 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
122 struct ipfw_table_context *table_ctx;
123 struct radix_node_head *rnh;
125 ioc_tbl = tbmsg->ioc_table;
126 table_ctx = ctx->table_ctx;
127 table_ctx += ioc_tbl->id;
128 table_ctx->count = 0;
130 if (table_ctx->type == 1) {
131 rnh = table_ctx->node;
132 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh);
133 } else if (table_ctx->type == 2) {
134 rnh = table_ctx->node;
135 rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh);
137 table_ctx->type = 0;
138 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
141 static void
142 table_append_dispatch(netmsg_t nmsg)
144 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
145 struct ipfw_ioc_table *ioc_tbl;
146 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
147 struct ipfw_table_context *table_ctx;
148 struct radix_node_head *rnh;
150 uint8_t mlen;
152 ioc_tbl = tbmsg->ioc_table;
153 table_ctx = ctx->table_ctx;
154 table_ctx += ioc_tbl->id;
155 if (table_ctx->type != ioc_tbl->type)
156 goto done;
158 if (table_ctx->type == 1 ) {
159 struct table_ip_entry *ent;
161 rnh = table_ctx->node;
162 ent = kmalloc(sizeof(struct table_ip_entry),
163 M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
165 if (ent == NULL)
166 return;
167 mlen = ioc_tbl->ip_ent->masklen;
168 ent->addr.sin_len = ent->mask.sin_len = 8;
169 ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1));
170 ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr &
171 ent->mask.sin_addr.s_addr;
173 if (rnh->rnh_addaddr((char *)&ent->addr,
174 (char *)&ent->mask, rnh,
175 (void *)ent->rn) != NULL) {
176 table_ctx->count++;
178 } else if (table_ctx->type == 2 ) {
179 struct table_mac_entry *ent;
181 rnh = table_ctx->node;
182 ent = kmalloc(sizeof(struct table_mac_entry),
183 M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
184 if (ent == NULL)
185 return;
186 ent->addr.sa_len = 8;
187 strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6);
189 if (rnh->rnh_addaddr((char *)&ent->addr,
190 NULL, rnh, (void *)ent->rn) != NULL) {
191 table_ctx->count++;
195 done:
196 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
199 static void
200 table_remove_dispatch(netmsg_t nmsg)
202 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
203 struct ipfw_ioc_table *ioc_tbl;
204 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
205 struct ipfw_table_context *table_ctx;
206 struct radix_node_head *rnh;
207 struct table_entry *ent;
208 struct sockaddr_in sa, mask;
209 in_addr_t addr;
210 uint8_t mlen;
212 ioc_tbl = tbmsg->ioc_table;
213 table_ctx = ctx->table_ctx;
214 table_ctx += ioc_tbl->id;
215 if (table_ctx->type != ioc_tbl->type)
216 goto done;
218 rnh = table_ctx->node;
220 mlen = ioc_tbl->ip_ent->masklen;
221 addr = ioc_tbl->ip_ent->addr;
223 sa.sin_len = mask.sin_len = 8;
224 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
225 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
227 ent = (struct table_entry *)rnh->rnh_deladdr((char *)&sa, (char *)&mask, rnh);
228 if (ent != NULL) {
229 table_ctx->count--;
230 kfree(ent, M_IPFW3_TABLE);
232 done:
233 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
237 flush_table_ip_entry(struct radix_node *rn, void *arg)
239 struct radix_node_head *rnh = arg;
240 struct table_ip_entry *ent;
242 ent = (struct table_ip_entry *)
243 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
244 if (ent != NULL)
245 kfree(ent, M_IPFW3_TABLE);
246 return (0);
250 flush_table_mac_entry(struct radix_node *rn, void *arg)
252 struct radix_node_head *rnh = arg;
253 struct table_mac_entry *ent;
255 ent = (struct table_mac_entry *)
256 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
257 if (ent != NULL)
258 kfree(ent, M_IPFW3_TABLE);
259 return (0);
262 static void
263 table_flush_dispatch(netmsg_t nmsg)
265 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
266 struct ipfw_ioc_table *ioc_tbl;
267 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
268 struct ipfw_table_context *table_ctx;
269 struct radix_node_head *rnh;
271 ioc_tbl = tbmsg->ioc_table;
272 table_ctx = ctx->table_ctx;
273 table_ctx += ioc_tbl->id;
274 rnh = table_ctx->node;
275 table_ctx->count = 0;
277 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh);
278 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
282 * rename the table
284 static void
285 table_rename_dispatch(netmsg_t nmsg)
287 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
288 struct ipfw_ioc_table *ioc_tbl;
289 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
290 struct ipfw_table_context *table_ctx;
292 ioc_tbl = tbmsg->ioc_table;
293 table_ctx = ctx->table_ctx;
294 table_ctx += ioc_tbl->id;
295 strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN);
296 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
300 * list all the overview information about each table
303 ipfw_ctl_table_list(struct sockopt *sopt)
305 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
306 struct ipfw_table_context *table_ctx = ctx->table_ctx;
307 struct ipfw_ioc_table *ioc_table;
308 int i, error = 0, size;
310 size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table);
311 if (sopt->sopt_valsize < size) {
312 /* sopt_val is not big enough */
313 bzero(sopt->sopt_val, sopt->sopt_valsize);
314 return 0;
316 ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val;
317 for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) {
318 ioc_table->id = i;
319 ioc_table->type = table_ctx->type;
320 ioc_table->count = table_ctx->count;
321 strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
323 sopt->sopt_valsize = size;
324 return error;
328 * remove an item from the table
331 ipfw_ctl_table_remove(struct sockopt *sopt)
333 struct netmsg_table tbmsg;
334 bzero(&tbmsg,sizeof(tbmsg));
335 tbmsg.ioc_table = sopt->sopt_val;
336 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
337 0, table_remove_dispatch);
338 netisr_domsg(&tbmsg.base, 0);
339 return tbmsg.retval;
343 * flush everything inside the table
346 ipfw_ctl_table_flush(struct sockopt *sopt)
348 struct netmsg_table tbmsg;
349 bzero(&tbmsg,sizeof(tbmsg));
350 tbmsg.ioc_table = sopt->sopt_val;
351 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
352 0, table_flush_dispatch);
353 netisr_domsg(&tbmsg.base, 0);
354 return tbmsg.retval;
358 * dump the entries into the ioc_table
361 dump_table_ip_entry(struct radix_node *rn, void *arg)
363 struct table_ip_entry *ent = (struct table_ip_entry *)rn;
364 struct ipfw_ioc_table_ip_entry *ioc_ent;
365 struct ipfw_ioc_table *tbl = arg;
366 struct sockaddr_in *addr, *mask;
368 addr = &ent->addr;
369 mask = &ent->mask;
371 ioc_ent = &tbl->ip_ent[tbl->count];
372 if (in_nullhost(mask->sin_addr))
373 ioc_ent->masklen = 0;
374 else
375 ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr));
376 ioc_ent->addr = addr->sin_addr.s_addr;
377 tbl->count++;
378 return (0);
382 dump_table_mac_entry(struct radix_node *rn, void *arg)
384 struct table_mac_entry *ent = (struct table_mac_entry *)rn;
385 struct ipfw_ioc_table_mac_entry *ioc_ent;
386 struct ipfw_ioc_table *tbl = arg;
387 ioc_ent = &tbl->mac_ent[tbl->count];
388 strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6);
389 tbl->count++;
390 return (0);
394 * get and display all items in the table
397 ipfw_ctl_table_show(struct sockopt *sopt)
399 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
400 struct ipfw_table_context *table_ctx;
401 struct radix_node_head *rnh;
402 struct ipfw_ioc_table *tbl;
403 void *data;
404 int size;
406 int *id = (int *)sopt->sopt_val;
407 table_ctx = ctx->table_ctx;
408 table_ctx += *id;
409 if (table_ctx->type == 1) {
410 size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) +
411 sizeof(struct ipfw_ioc_table);
412 if (sopt->sopt_valsize < size) {
413 /* sopt_val is not big enough */
414 bzero(sopt->sopt_val, sopt->sopt_valsize);
415 return 0;
417 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
418 tbl = (struct ipfw_ioc_table *)data;
419 tbl->id = *id;
420 tbl->type = table_ctx->type;
421 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
422 rnh = table_ctx->node;
423 rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl);
424 bcopy(tbl, sopt->sopt_val, size);
425 sopt->sopt_valsize = size;
426 kfree(data, M_IPFW3_TABLE);
427 } else if (table_ctx->type == 2) {
428 size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) +
429 sizeof(struct ipfw_ioc_table);
430 if (sopt->sopt_valsize < size) {
431 /* sopt_val is not big enough */
432 bzero(sopt->sopt_val, sopt->sopt_valsize);
433 return 0;
435 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
436 tbl = (struct ipfw_ioc_table *)data;
437 tbl->id = *id;
438 tbl->type = table_ctx->type;
439 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
440 rnh = table_ctx->node;
441 rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl);
442 bcopy(tbl, sopt->sopt_val, size);
443 sopt->sopt_valsize = size;
444 kfree(data, M_IPFW3_TABLE);
446 return 0;
450 * test whether the ip is in the table
453 ipfw_ctl_table_test(struct sockopt *sopt)
455 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
456 struct ipfw_table_context *table_ctx;
457 struct radix_node_head *rnh;
458 struct ipfw_ioc_table *tbl;
460 tbl = (struct ipfw_ioc_table *)sopt->sopt_val;
461 table_ctx = ctx->table_ctx;
462 table_ctx += tbl->id;
464 if (table_ctx->type != tbl->type)
465 goto done;
467 rnh = table_ctx->node;
468 if (tbl->type == 1) {
469 struct sockaddr_in sa;
470 sa.sin_len = 8;
471 sa.sin_addr.s_addr = tbl->ip_ent->addr;
473 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
474 return 0;
475 } else if (tbl->type == 2) {
476 struct sockaddr sa;
477 sa.sa_len = 8;
478 strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6);
480 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
481 return 0;
482 } else {
483 /* XXX TODO */
485 done:
486 return 1;
490 * activate the table
493 ipfw_ctl_table_create(struct sockopt *sopt)
495 struct netmsg_table tbmsg;
496 bzero(&tbmsg,sizeof(tbmsg));
497 tbmsg.ioc_table = sopt->sopt_val;
498 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
499 0, table_create_dispatch);
500 netisr_domsg(&tbmsg.base, 0);
501 return tbmsg.retval;
505 * deactivate the table
508 ipfw_ctl_table_delete(struct sockopt *sopt)
510 struct netmsg_table tbmsg;
511 bzero(&tbmsg,sizeof(tbmsg));
512 tbmsg.ioc_table = sopt->sopt_val;
513 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
514 0, table_delete_dispatch);
515 netisr_domsg(&tbmsg.base, 0);
516 return tbmsg.retval;
520 * append an item into the table
523 ipfw_ctl_table_append(struct sockopt *sopt)
525 struct netmsg_table tbmsg;
526 bzero(&tbmsg,sizeof(tbmsg));
527 tbmsg.ioc_table = sopt->sopt_val;
528 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
529 0, table_append_dispatch);
530 netisr_domsg(&tbmsg.base, 0);
531 return tbmsg.retval;
535 * rename an table
538 ipfw_ctl_table_rename(struct sockopt *sopt)
540 struct netmsg_table tbmsg;
541 bzero(&tbmsg,sizeof(tbmsg));
542 tbmsg.ioc_table = sopt->sopt_val;
543 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
544 0, table_rename_dispatch);
545 netisr_domsg(&tbmsg.base, 0);
546 return tbmsg.retval;
550 * sockopt handler
553 ipfw_ctl_table_sockopt(struct sockopt *sopt)
555 int error = 0;
556 switch (sopt->sopt_name) {
557 case IP_FW_TABLE_CREATE:
558 error = ipfw_ctl_table_create(sopt);
559 break;
560 case IP_FW_TABLE_DELETE:
561 error = ipfw_ctl_table_delete(sopt);
562 break;
563 case IP_FW_TABLE_APPEND:
564 error = ipfw_ctl_table_append(sopt);
565 break;
566 case IP_FW_TABLE_REMOVE:
567 error = ipfw_ctl_table_remove(sopt);
568 break;
569 case IP_FW_TABLE_LIST:
570 error = ipfw_ctl_table_list(sopt);
571 break;
572 case IP_FW_TABLE_FLUSH:
573 error = ipfw_ctl_table_flush(sopt);
574 break;
575 case IP_FW_TABLE_SHOW:
576 error = ipfw_ctl_table_show(sopt);
577 break;
578 case IP_FW_TABLE_TEST:
579 error = ipfw_ctl_table_test(sopt);
580 break;
581 case IP_FW_TABLE_RENAME:
582 error = ipfw_ctl_table_rename(sopt);
583 break;
584 default:
585 kprintf("ipfw table invalid socket option %d\n",
586 sopt->sopt_name);
588 return error;
591 static void
592 table_init_ctx_dispatch(netmsg_t nmsg)
594 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
595 ctx->table_ctx = kmalloc(sizeof(struct ipfw_table_context) * IPFW_TABLES_MAX,
596 M_IPFW3_TABLE, M_WAITOK | M_ZERO);
597 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
601 * release the memory of the tables
603 void
604 table_fini(void)
606 struct ipfw_table_context *table_ctx, *tmp_table;
607 struct radix_node_head *rnh;
608 int cpu, id;
609 for (cpu = 0; cpu < ncpus; cpu++) {
610 table_ctx = ipfw_ctx[cpu]->table_ctx;
611 tmp_table = table_ctx;
612 for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) {
613 if (table_ctx->type == 1) {
614 rnh = table_ctx->node;
615 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh);
616 } else if (table_ctx->type == 2) {
617 rnh = table_ctx->node;
618 rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh);
621 kfree(tmp_table, M_IPFW3_TABLE);
626 * it will be invoked during init of ipfw3
627 * this function will prepare the tables
629 void
630 table_init_dispatch(netmsg_t nmsg)
632 int error = 0;
633 struct netmsg_base nmsg_base;
634 bzero(&nmsg_base, sizeof(nmsg_base));
635 netmsg_init(&nmsg_base, NULL, &curthread->td_msgport,
636 0, table_init_ctx_dispatch);
637 netisr_domsg(&nmsg_base, 0);
638 lwkt_replymsg(&nmsg->lmsg, error);