iwm: Fix S:N reporting in ifconfig(8)
[dragonfly.git] / sys / net / pf / pf_if.c
CommitLineData
ed1f0be2 1/* $OpenBSD: pf_if.c,v 1.54 2008/06/14 16:55:28 mk Exp $ */
02742ec6
JS
2
3/*
70224baa
JL
4 * Copyright 2005 Henning Brauer <henning@openbsd.org>
5 * Copyright 2005 Ryan McBride <mcbride@openbsd.org>
02742ec6
JS
6 * Copyright (c) 2001 Daniel Hartmeier
7 * Copyright (c) 2003 Cedric Berger
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 *
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
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "opt_inet.h"
36#include "opt_inet6.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/eventhandler.h>
43#include <sys/filio.h>
9a74b592 44#include <sys/msgport2.h>
02742ec6
JS
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <sys/kernel.h>
cc6e5672 48#include <sys/thread2.h>
02742ec6 49#include <sys/time.h>
c686757e 50#include <sys/lock.h>
02742ec6
JS
51
52#include <net/if.h>
c686757e 53#include <net/if_var.h>
02742ec6 54#include <net/if_types.h>
9a74b592
SZ
55#include <net/netisr2.h>
56#include <net/netmsg2.h>
e4fc90e8 57#include <net/route.h>
02742ec6
JS
58
59#include <netinet/in.h>
60#include <netinet/in_var.h>
61#include <netinet/in_systm.h>
62#include <netinet/ip.h>
63#include <netinet/ip_var.h>
64
65#include <net/pf/pfvar.h>
66
67#ifdef INET6
68#include <netinet/ip6.h>
69#endif /* INET6 */
70
c686757e
AL
71struct pfi_kif *pfi_all = NULL;
72struct pfi_ifhead pfi_ifs;
73static long pfi_update = 1;
74static struct pfr_addr *pfi_buffer;
75static int pfi_buffer_cnt;
76static int pfi_buffer_max;
77
78static eventhandler_tag pfi_attach_cookie;
79static eventhandler_tag pfi_detach_cookie;
80static eventhandler_tag pfi_attach_group_cookie;
81static eventhandler_tag pfi_detach_group_cookie;
82static eventhandler_tag pfi_change_group_cookie;
83static eventhandler_tag pfi_ifaddr_event_cookie;
84
85static void pfi_kif_update(struct pfi_kif *);
2949c680 86static void pfi_dynaddr_update(struct pfi_dynaddr *);
c686757e 87static void pfi_table_update(struct pfr_ktable *, struct pfi_kif *,
02742ec6 88 int, int);
c686757e
AL
89static void pfi_instance_add(struct ifnet *, int, int);
90static void pfi_address_add(struct sockaddr *, int, int);
91static int pfi_if_compare(struct pfi_kif *, struct pfi_kif *);
92static int pfi_skip_if(const char *, struct pfi_kif *);
93static int pfi_unmask(void *);
94
95static void pfi_attach_ifnet_event(void * __unused, struct ifnet *);
96static void pfi_detach_ifnet_event(void * __unused, struct ifnet *);
97static void pfi_attach_group_event(void * __unused, struct ifg_group *);
98static void pfi_detach_group_event(void * __unused, struct ifg_group *);
99static void pfi_change_group_event(void * __unused, char *);
100static void pfi_ifaddr_event(void * __unused, struct ifnet *,
101 enum ifaddr_event __unused, struct ifaddr * __unused);
102
103static RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
104static RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare);
02742ec6 105
02742ec6 106#define PFI_BUFFER_MAX 0x10000
c686757e 107static MALLOC_DEFINE(M_PFI, "pf_if", "pf interface");
1186cbc0 108
02742ec6
JS
109
110void
111pfi_initialize(void)
112{
c686757e
AL
113 struct ifnet *ifp;
114 struct ifg_group *ifg;
02742ec6 115
c686757e
AL
116 pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_attach_event,
117 pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
118 pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_detach_event,
119 pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
120 pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event,
121 pfi_attach_group_event, NULL, EVENTHANDLER_PRI_ANY);
122 pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event,
123 pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY);
124 pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event,
125 pfi_change_group_event, NULL, EVENTHANDLER_PRI_ANY);
126 pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
127 pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY);
02742ec6 128
02742ec6 129 pfi_buffer_max = 64;
77652cad 130 pfi_buffer = kmalloc(pfi_buffer_max * sizeof(*pfi_buffer),
c686757e 131 M_PFI, M_WAITOK);
70224baa
JL
132
133 if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
c686757e
AL
134 panic("%s: pfi_kif_get(IFG_ALL) failed", __func__);
135
136 ifgroup_lockmgr(LK_SHARED);
137 TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
138 pfi_attach_ifgroup(ifg);
139 ifgroup_lockmgr(LK_RELEASE);
02742ec6 140
b4051e25
SZ
141 /* XXX ALMOST MPSAFE */
142 ifnet_lock();
c686757e
AL
143 TAILQ_FOREACH(ifp, &ifnetlist, if_link)
144 pfi_attach_ifnet(ifp);
b4051e25 145 ifnet_unlock();
02742ec6
JS
146}
147
148void
149pfi_cleanup(void)
150{
c686757e 151 struct pfi_kif *kif;
02742ec6 152
c686757e
AL
153 while ((kif = RB_MIN(pfi_ifhead, &pfi_ifs))) {
154 RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
155 if (kif->pfik_group)
156 kif->pfik_group->ifg_pf_kif = NULL;
157 if (kif->pfik_ifp)
158 kif->pfik_ifp->if_pf_kif = NULL;
159 kfree(kif, M_PFI);
02742ec6 160 }
c686757e 161 kfree(pfi_buffer, M_PFI);
02742ec6 162 pfi_buffer = NULL;
70224baa 163 pfi_all = NULL;
5bd4422e 164
c686757e
AL
165 EVENTHANDLER_DEREGISTER(ifnet_attach_event, pfi_attach_cookie);
166 EVENTHANDLER_DEREGISTER(ifnet_detach_event, pfi_detach_cookie);
167 EVENTHANDLER_DEREGISTER(group_attach_event, pfi_attach_group_cookie);
168 EVENTHANDLER_DEREGISTER(group_detach_event, pfi_detach_group_cookie);
169 EVENTHANDLER_DEREGISTER(group_change_event, pfi_change_group_cookie);
170 EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie);
02742ec6
JS
171}
172
c686757e
AL
173struct pfi_kif *
174pfi_kif_find(const char *kif_name)
02742ec6 175{
c686757e 176 struct pfi_kif_cmp s;
02742ec6 177
c686757e
AL
178 bzero(&s, sizeof(s));
179 strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name));
02742ec6 180
c686757e 181 return (RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s));
02742ec6
JS
182}
183
70224baa
JL
184struct pfi_kif *
185pfi_kif_get(const char *kif_name)
186{
c686757e 187 struct pfi_kif *kif;
70224baa 188
c686757e 189 if ((kif = pfi_kif_find(kif_name)))
70224baa
JL
190 return (kif);
191
c686757e
AL
192 /*
193 * Create a new one
194 */
195 kif = kmalloc(sizeof(*kif), M_PFI, M_WAITOK | M_ZERO);
70224baa
JL
196 strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name));
197 kif->pfik_tzero = time_second;
198 TAILQ_INIT(&kif->pfik_dynaddrs);
199
200 RB_INSERT(pfi_ifhead, &pfi_ifs, kif);
201 return (kif);
202}
203
204void
205pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what)
206{
207 switch (what) {
208 case PFI_KIF_REF_RULE:
209 kif->pfik_rules++;
210 break;
211 case PFI_KIF_REF_STATE:
315a7da3 212 kif->pfik_states++;
70224baa
JL
213 break;
214 default:
c686757e 215 panic("%s: unknown type", __func__);
70224baa
JL
216 }
217}
218
02742ec6 219void
70224baa 220pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what)
02742ec6 221{
70224baa
JL
222 if (kif == NULL)
223 return;
224
225 switch (what) {
226 case PFI_KIF_REF_NONE:
227 break;
228 case PFI_KIF_REF_RULE:
229 if (kif->pfik_rules <= 0) {
c686757e 230 kprintf("%s: rules refcount <= 0\n", __func__);
70224baa
JL
231 return;
232 }
233 kif->pfik_rules--;
234 break;
235 case PFI_KIF_REF_STATE:
236 if (kif->pfik_states <= 0) {
c686757e 237 kprintf("%s: state refcount <= 0\n", __func__);
70224baa
JL
238 return;
239 }
315a7da3 240 kif->pfik_states--;
70224baa
JL
241 break;
242 default:
c686757e 243 panic("%s: unknown type", __func__);
70224baa
JL
244 }
245
246 if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all)
247 return;
248
249 if (kif->pfik_rules || kif->pfik_states)
250 return;
251
252 RB_REMOVE(pfi_ifhead, &pfi_ifs, kif);
c686757e 253 kfree(kif, M_PFI);
70224baa
JL
254}
255
256int
257pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif)
258{
259 struct ifg_list *p;
260
261 if (rule_kif == NULL || rule_kif == packet_kif)
262 return (1);
263
c686757e
AL
264 if (rule_kif->pfik_group != NULL) {
265 ifgroup_lockmgr(LK_SHARED);
266 TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) {
267 if (p->ifgl_group == rule_kif->pfik_group) {
268 ifgroup_lockmgr(LK_RELEASE);
70224baa 269 return (1);
c686757e
AL
270 }
271 }
272 ifgroup_lockmgr(LK_RELEASE);
273 }
70224baa
JL
274
275 return (0);
02742ec6
JS
276}
277
278void
279pfi_attach_ifnet(struct ifnet *ifp)
280{
c686757e
AL
281 struct pfi_kif *kif;
282
283 if (ifp->if_dunit == IF_DUNIT_NONE)
284 return;
02742ec6 285
cc6e5672 286 crit_enter();
02742ec6 287 pfi_update++;
70224baa 288 if ((kif = pfi_kif_get(ifp->if_xname)) == NULL)
c686757e 289 panic("%s: pfi_kif_get failed", __func__);
70224baa 290 kif->pfik_ifp = ifp;
c686757e 291 ifp->if_pf_kif = kif;
70224baa 292 pfi_kif_update(kif);
cc6e5672 293 crit_exit();
02742ec6
JS
294}
295
296void
297pfi_detach_ifnet(struct ifnet *ifp)
298{
c686757e 299 struct pfi_kif *kif;
02742ec6 300
70224baa
JL
301 if ((kif = (struct pfi_kif *)ifp->if_pf_kif) == NULL)
302 return;
ed1f0be2 303
cc6e5672 304 crit_enter();
02742ec6 305 pfi_update++;
70224baa 306 pfi_kif_update(kif);
70224baa
JL
307 kif->pfik_ifp = NULL;
308 ifp->if_pf_kif = NULL;
309 pfi_kif_unref(kif, PFI_KIF_REF_NONE);
cc6e5672 310 crit_exit();
02742ec6
JS
311}
312
70224baa
JL
313void
314pfi_attach_ifgroup(struct ifg_group *ifg)
02742ec6 315{
c686757e 316 struct pfi_kif *kif;
02742ec6 317
cc6e5672 318 crit_enter();
70224baa
JL
319 pfi_update++;
320 if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL)
c686757e 321 panic("%s: pfi_kif_get failed", __func__);
70224baa 322 kif->pfik_group = ifg;
c686757e 323 ifg->ifg_pf_kif = kif;
70224baa 324 crit_exit();
02742ec6
JS
325}
326
327void
70224baa 328pfi_detach_ifgroup(struct ifg_group *ifg)
02742ec6 329{
c686757e 330 struct pfi_kif *kif;
70224baa
JL
331
332 if ((kif = (struct pfi_kif *)ifg->ifg_pf_kif) == NULL)
02742ec6 333 return;
70224baa
JL
334
335 crit_enter();
336 pfi_update++;
70224baa
JL
337 kif->pfik_group = NULL;
338 ifg->ifg_pf_kif = NULL;
339 pfi_kif_unref(kif, PFI_KIF_REF_NONE);
340 crit_exit();
02742ec6
JS
341}
342
343void
70224baa 344pfi_group_change(const char *group)
02742ec6 345{
c686757e 346 struct pfi_kif *kif;
70224baa
JL
347
348 crit_enter();
349 pfi_update++;
350 if ((kif = pfi_kif_get(group)) == NULL)
c686757e 351 panic("%s: pfi_kif_get failed", __func__);
70224baa 352 pfi_kif_update(kif);
70224baa 353 crit_exit();
02742ec6
JS
354}
355
70224baa
JL
356int
357pfi_match_addr(struct pfi_dynaddr *dyn, struct pf_addr *a, sa_family_t af)
02742ec6 358{
70224baa
JL
359 switch (af) {
360#ifdef INET
361 case AF_INET:
362 switch (dyn->pfid_acnt4) {
363 case 0:
364 return (0);
365 case 1:
366 return (PF_MATCHA(0, &dyn->pfid_addr4,
367 &dyn->pfid_mask4, a, AF_INET));
368 default:
369 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET));
370 }
371 break;
372#endif /* INET */
373#ifdef INET6
374 case AF_INET6:
375 switch (dyn->pfid_acnt6) {
376 case 0:
377 return (0);
378 case 1:
379 return (PF_MATCHA(0, &dyn->pfid_addr6,
380 &dyn->pfid_mask6, a, AF_INET6));
381 default:
382 return (pfr_match_addr(dyn->pfid_kt, a, AF_INET6));
383 }
384 break;
385#endif /* INET6 */
386 default:
387 return (0);
02742ec6 388 }
02742ec6
JS
389}
390
391int
392pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
393{
394 struct pfi_dynaddr *dyn;
395 char tblname[PF_TABLE_NAME_SIZE];
396 struct pf_ruleset *ruleset = NULL;
cc6e5672 397 int rv = 0;
02742ec6
JS
398
399 if (aw->type != PF_ADDR_DYNIFTL)
400 return (0);
c686757e
AL
401 if ((dyn = kmalloc(sizeof(struct pfi_dynaddr), M_PFI,
402 M_WAITOK | M_NULLOK | M_ZERO)) == NULL) {
02742ec6 403 return (1);
c686757e 404 }
02742ec6 405
cc6e5672 406 crit_enter();
c686757e 407 if (strcmp(aw->v.ifname, "self") == 0)
70224baa
JL
408 dyn->pfid_kif = pfi_kif_get(IFG_ALL);
409 else
410 dyn->pfid_kif = pfi_kif_get(aw->v.ifname);
411 if (dyn->pfid_kif == NULL) {
412 rv = 1;
413 goto _bad;
414 }
415 pfi_kif_ref(dyn->pfid_kif, PFI_KIF_REF_RULE);
02742ec6
JS
416
417 dyn->pfid_net = pfi_unmask(&aw->v.a.mask);
418 if (af == AF_INET && dyn->pfid_net == 32)
419 dyn->pfid_net = 128;
420 strlcpy(tblname, aw->v.ifname, sizeof(tblname));
421 if (aw->iflags & PFI_AFLAG_NETWORK)
422 strlcat(tblname, ":network", sizeof(tblname));
423 if (aw->iflags & PFI_AFLAG_BROADCAST)
424 strlcat(tblname, ":broadcast", sizeof(tblname));
425 if (aw->iflags & PFI_AFLAG_PEER)
426 strlcat(tblname, ":peer", sizeof(tblname));
427 if (aw->iflags & PFI_AFLAG_NOALIAS)
428 strlcat(tblname, ":0", sizeof(tblname));
429 if (dyn->pfid_net != 128)
f8c7a42d 430 ksnprintf(tblname + strlen(tblname),
02742ec6 431 sizeof(tblname) - strlen(tblname), "/%d", dyn->pfid_net);
70224baa
JL
432 if ((ruleset = pf_find_or_create_ruleset(PF_RESERVED_ANCHOR)) == NULL) {
433 rv = 1;
434 goto _bad;
435 }
02742ec6 436
70224baa
JL
437 if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) {
438 rv = 1;
439 goto _bad;
440 }
02742ec6
JS
441
442 dyn->pfid_kt->pfrkt_flags |= PFR_TFLAG_ACTIVE;
443 dyn->pfid_iflags = aw->iflags;
444 dyn->pfid_af = af;
02742ec6 445
70224baa 446 TAILQ_INSERT_TAIL(&dyn->pfid_kif->pfik_dynaddrs, dyn, entry);
02742ec6 447 aw->p.dyn = dyn;
70224baa 448 pfi_kif_update(dyn->pfid_kif);
cc6e5672 449 crit_exit();
02742ec6
JS
450 return (0);
451
452_bad:
453 if (dyn->pfid_kt != NULL)
454 pfr_detach_table(dyn->pfid_kt);
455 if (ruleset != NULL)
456 pf_remove_if_empty_ruleset(ruleset);
457 if (dyn->pfid_kif != NULL)
70224baa 458 pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE);
c686757e 459 kfree(dyn, M_PFI);
cc6e5672 460 crit_exit();
02742ec6
JS
461 return (rv);
462}
463
c686757e 464static void
70224baa 465pfi_kif_update(struct pfi_kif *kif)
02742ec6 466{
70224baa
JL
467 struct ifg_list *ifgl;
468 struct pfi_dynaddr *p;
02742ec6 469
70224baa
JL
470 /* update all dynaddr */
471 TAILQ_FOREACH(p, &kif->pfik_dynaddrs, entry)
472 pfi_dynaddr_update(p);
473
c686757e
AL
474 /* and for all groups that the kif belongs to */
475 if (kif->pfik_ifp != NULL) {
476 ifgroup_lockmgr(LK_SHARED);
477 TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) {
70224baa
JL
478 pfi_kif_update((struct pfi_kif *)
479 ifgl->ifgl_group->ifg_pf_kif);
c686757e
AL
480 }
481 ifgroup_lockmgr(LK_RELEASE);
482 }
70224baa
JL
483}
484
c686757e 485static void
70224baa
JL
486pfi_dynaddr_update(struct pfi_dynaddr *dyn)
487{
488 struct pfi_kif *kif;
489 struct pfr_ktable *kt;
490
491 if (dyn == NULL || dyn->pfid_kif == NULL || dyn->pfid_kt == NULL)
c686757e 492 panic("%s: bad argument", __func__);
70224baa
JL
493
494 kif = dyn->pfid_kif;
495 kt = dyn->pfid_kt;
496
02742ec6
JS
497 if (kt->pfrkt_larg != pfi_update) {
498 /* this table needs to be brought up-to-date */
499 pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags);
500 kt->pfrkt_larg = pfi_update;
501 }
502 pfr_dynaddr_update(kt, dyn);
503}
504
c686757e 505static void
02742ec6
JS
506pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags)
507{
508 int e, size2 = 0;
70224baa 509 struct ifg_member *ifgm;
02742ec6 510
02742ec6 511 pfi_buffer_cnt = 0;
70224baa 512
c686757e 513 if (kif->pfik_ifp != NULL) {
02742ec6 514 pfi_instance_add(kif->pfik_ifp, net, flags);
c686757e
AL
515 } else if (kif->pfik_group != NULL) {
516 ifgroup_lockmgr(LK_SHARED);
70224baa
JL
517 TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next)
518 pfi_instance_add(ifgm->ifgm_ifp, net, flags);
c686757e
AL
519 ifgroup_lockmgr(LK_RELEASE);
520 }
70224baa 521
c686757e
AL
522 if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt,
523 &size2, NULL, NULL, NULL, 0,
524 PFR_TFLAG_ALLMASK))) {
525 kprintf("%s: cannot set %d new addresses into table %s: %d\n",
526 __func__, pfi_buffer_cnt, kt->pfrkt_name, e);
527 }
02742ec6
JS
528}
529
c686757e 530
9a74b592
SZ
531struct netmsg_pfiadd {
532 struct netmsg_base base;
533 struct ifnet *ifp;
534 int net;
535 int flags;
536};
537
538static void
539pfi_instance_add_dispatch(netmsg_t nmsg)
02742ec6 540{
9a74b592 541 struct netmsg_pfiadd *msg = (struct netmsg_pfiadd *)nmsg;
b2632176 542 struct ifaddr_container *ifac;
c686757e
AL
543 int got4 = 0, got6 = 0;
544 int net2, af;
9a74b592
SZ
545 struct ifnet *ifp = msg->ifp;
546 int net = msg->net, flags = msg->flags;
02742ec6
JS
547
548 if (ifp == NULL)
9a74b592
SZ
549 goto done;
550 /*
551 * The ifaddr processing in the following loop will block,
552 * however, this function is called in netisr0, in which
553 * ifaddr list changes happen, so we don't care about the
554 * blockness of the ifaddr processing here.
555 */
b2632176
SZ
556 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
557 struct ifaddr *ia = ifac->ifa;
558
02742ec6
JS
559 if (ia->ifa_addr == NULL)
560 continue;
561 af = ia->ifa_addr->sa_family;
562 if (af != AF_INET && af != AF_INET6)
563 continue;
564 /*
565 * XXX: For point-to-point interfaces, (ifname:0) and IPv4,
566 * jump over address without a proper route to work
567 * around a problem with ppp not fully removing the
568 * address used during IPCP.
569 */
570 if ((ifp->if_flags & IFF_POINTOPOINT) &&
571 !(ia->ifa_flags & IFA_ROUTE) &&
572 (flags & PFI_AFLAG_NOALIAS) && (af == AF_INET))
573 continue;
574 if ((flags & PFI_AFLAG_BROADCAST) && af == AF_INET6)
575 continue;
576 if ((flags & PFI_AFLAG_BROADCAST) &&
577 !(ifp->if_flags & IFF_BROADCAST))
578 continue;
579 if ((flags & PFI_AFLAG_PEER) &&
580 !(ifp->if_flags & IFF_POINTOPOINT))
581 continue;
6aa338e1
AL
582 if ((flags & (PFI_AFLAG_NETWORK | PFI_AFLAG_NOALIAS)) &&
583 af == AF_INET6 &&
02742ec6
JS
584 IN6_IS_ADDR_LINKLOCAL(
585 &((struct sockaddr_in6 *)ia->ifa_addr)->sin6_addr))
586 continue;
587 if (flags & PFI_AFLAG_NOALIAS) {
588 if (af == AF_INET && got4)
589 continue;
590 if (af == AF_INET6 && got6)
591 continue;
592 }
593 if (af == AF_INET)
594 got4 = 1;
70224baa 595 else if (af == AF_INET6)
02742ec6
JS
596 got6 = 1;
597 net2 = net;
598 if (net2 == 128 && (flags & PFI_AFLAG_NETWORK)) {
70224baa 599 if (af == AF_INET)
02742ec6
JS
600 net2 = pfi_unmask(&((struct sockaddr_in *)
601 ia->ifa_netmask)->sin_addr);
70224baa 602 else if (af == AF_INET6)
02742ec6
JS
603 net2 = pfi_unmask(&((struct sockaddr_in6 *)
604 ia->ifa_netmask)->sin6_addr);
02742ec6
JS
605 }
606 if (af == AF_INET && net2 > 32)
607 net2 = 32;
608 if (flags & PFI_AFLAG_BROADCAST)
609 pfi_address_add(ia->ifa_broadaddr, af, net2);
610 else if (flags & PFI_AFLAG_PEER)
611 pfi_address_add(ia->ifa_dstaddr, af, net2);
612 else
613 pfi_address_add(ia->ifa_addr, af, net2);
614 }
9a74b592 615done:
5204e13c 616 netisr_replymsg(&nmsg->base, 0);
9a74b592
SZ
617}
618
c686757e 619static void
9a74b592
SZ
620pfi_instance_add(struct ifnet *ifp, int net, int flags)
621{
622 struct netmsg_pfiadd msg;
623
9a74b592
SZ
624 netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0,
625 pfi_instance_add_dispatch);
626 msg.ifp = ifp;
627 msg.net = net;
628 msg.flags = flags;
5204e13c 629 netisr_domsg(&msg.base, 0);
02742ec6
JS
630}
631
c686757e 632static void
02742ec6
JS
633pfi_address_add(struct sockaddr *sa, int af, int net)
634{
635 struct pfr_addr *p;
636 int i;
637
638 if (pfi_buffer_cnt >= pfi_buffer_max) {
639 int new_max = pfi_buffer_max * 2;
640
641 if (new_max > PFI_BUFFER_MAX) {
c686757e 642 kprintf("%s: address buffer full (%d/%d)\n", __func__,
02742ec6
JS
643 pfi_buffer_cnt, PFI_BUFFER_MAX);
644 return;
645 }
c686757e 646 p = kmalloc(new_max * sizeof(*pfi_buffer), M_PFI, M_WAITOK);
02742ec6
JS
647 memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer));
648 /* no need to zero buffer */
c686757e 649 kfree(pfi_buffer, M_PFI);
02742ec6
JS
650 pfi_buffer = p;
651 pfi_buffer_max = new_max;
652 }
653 if (af == AF_INET && net > 32)
654 net = 128;
655 p = pfi_buffer + pfi_buffer_cnt++;
656 bzero(p, sizeof(*p));
657 p->pfra_af = af;
658 p->pfra_net = net;
659 if (af == AF_INET)
660 p->pfra_ip4addr = ((struct sockaddr_in *)sa)->sin_addr;
70224baa 661 else if (af == AF_INET6) {
02742ec6 662 p->pfra_ip6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
70224baa 663 if (IN6_IS_SCOPE_EMBED(&p->pfra_ip6addr))
02742ec6
JS
664 p->pfra_ip6addr.s6_addr16[1] = 0;
665 }
666 /* mask network address bits */
667 if (net < 128)
668 ((caddr_t)p)[p->pfra_net/8] &= ~(0xFF >> (p->pfra_net%8));
669 for (i = (p->pfra_net+7)/8; i < sizeof(p->pfra_u); i++)
670 ((caddr_t)p)[i] = 0;
671}
672
673void
674pfi_dynaddr_remove(struct pf_addr_wrap *aw)
675{
02742ec6
JS
676 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
677 aw->p.dyn->pfid_kif == NULL || aw->p.dyn->pfid_kt == NULL)
678 return;
679
cc6e5672 680 crit_enter();
70224baa
JL
681 TAILQ_REMOVE(&aw->p.dyn->pfid_kif->pfik_dynaddrs, aw->p.dyn, entry);
682 pfi_kif_unref(aw->p.dyn->pfid_kif, PFI_KIF_REF_RULE);
02742ec6
JS
683 aw->p.dyn->pfid_kif = NULL;
684 pfr_detach_table(aw->p.dyn->pfid_kt);
685 aw->p.dyn->pfid_kt = NULL;
c686757e 686 kfree(aw->p.dyn, M_PFI);
02742ec6 687 aw->p.dyn = NULL;
cc6e5672 688 crit_exit();
02742ec6
JS
689}
690
691void
692pfi_dynaddr_copyout(struct pf_addr_wrap *aw)
693{
694 if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL ||
695 aw->p.dyn->pfid_kif == NULL)
696 return;
697 aw->p.dyncnt = aw->p.dyn->pfid_acnt4 + aw->p.dyn->pfid_acnt6;
698}
699
c686757e 700static int
02742ec6
JS
701pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q)
702{
703 return (strncmp(p->pfik_name, q->pfik_name, IFNAMSIZ));
704}
705
02742ec6 706void
ed1f0be2 707pfi_update_status(const char *name, struct pf_status *pfs)
02742ec6 708{
70224baa 709 struct pfi_kif *p;
c686757e 710 struct pfi_kif_cmp key;
ed1f0be2
JL
711 struct ifg_member p_member, *ifgm;
712 TAILQ_HEAD(, ifg_member) ifg_members;
70224baa 713 int i, j, k;
02742ec6 714
c686757e 715 strlcpy(key.pfik_name, name, sizeof(key.pfik_name));
cc6e5672 716 crit_enter();
70224baa 717 p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key);
02742ec6 718 if (p == NULL) {
cc6e5672 719 crit_exit();
02742ec6
JS
720 return;
721 }
ed1f0be2
JL
722 if (p->pfik_group != NULL) {
723 bcopy(&p->pfik_group->ifg_members, &ifg_members,
724 sizeof(ifg_members));
725 } else {
726 /* build a temporary list for p only */
727 bzero(&p_member, sizeof(p_member));
728 p_member.ifgm_ifp = p->pfik_ifp;
729 TAILQ_INIT(&ifg_members);
730 TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next);
731 }
732 if (pfs) {
733 bzero(pfs->pcounters, sizeof(pfs->pcounters));
734 bzero(pfs->bcounters, sizeof(pfs->bcounters));
735 }
c686757e 736 ifgroup_lockmgr(LK_SHARED);
ed1f0be2 737 TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) {
c686757e
AL
738 if (ifgm->ifgm_ifp == NULL ||
739 ifgm->ifgm_ifp->if_pf_kif == NULL)
ed1f0be2
JL
740 continue;
741 p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif;
02742ec6 742
ed1f0be2
JL
743 /* just clear statistics */
744 if (pfs == NULL) {
745 bzero(p->pfik_packets, sizeof(p->pfik_packets));
746 bzero(p->pfik_bytes, sizeof(p->pfik_bytes));
747 p->pfik_tzero = time_second;
02742ec6 748 continue;
ed1f0be2
JL
749 }
750 for (i = 0; i < 2; i++)
751 for (j = 0; j < 2; j++)
752 for (k = 0; k < 2; k++) {
753 pfs->pcounters[i][j][k] +=
754 p->pfik_packets[i][j][k];
755 pfs->bcounters[i][j] +=
756 p->pfik_bytes[i][j][k];
757 }
02742ec6 758 }
c686757e 759 ifgroup_lockmgr(LK_RELEASE);
cc6e5672 760 crit_exit();
02742ec6
JS
761}
762
763int
70224baa 764pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size)
02742ec6 765{
70224baa 766 struct pfi_kif *p, *nextp;
cc6e5672 767 int n = 0;
02742ec6 768
cc6e5672 769 crit_enter();
70224baa
JL
770 for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) {
771 nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
772 if (pfi_skip_if(name, p))
02742ec6
JS
773 continue;
774 if (*size > n++) {
775 if (!p->pfik_tzero)
70224baa
JL
776 p->pfik_tzero = time_second;
777 pfi_kif_ref(p, PFI_KIF_REF_RULE);
02742ec6 778 if (copyout(p, buf++, sizeof(*buf))) {
70224baa 779 pfi_kif_unref(p, PFI_KIF_REF_RULE);
cc6e5672 780 crit_exit();
02742ec6
JS
781 return (EFAULT);
782 }
70224baa
JL
783 nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p);
784 pfi_kif_unref(p, PFI_KIF_REF_RULE);
02742ec6
JS
785 }
786 }
cc6e5672 787 crit_exit();
02742ec6
JS
788 *size = n;
789 return (0);
790}
791
c686757e 792static int
70224baa 793pfi_skip_if(const char *filter, struct pfi_kif *p)
02742ec6 794{
1f464430
AL
795 struct ifg_list *ifg;
796 int n;
02742ec6 797
02742ec6
JS
798 if (filter == NULL || !*filter)
799 return (0);
c686757e 800 if (strcmp(p->pfik_name, filter) == 0)
02742ec6
JS
801 return (0); /* exact match */
802 n = strlen(filter);
803 if (n < 1 || n >= IFNAMSIZ)
804 return (1); /* sanity check */
805 if (filter[n-1] >= '0' && filter[n-1] <= '9')
1f464430
AL
806 return (1); /* group names may not end in a digit */
807 if (p->pfik_ifp != NULL) {
808 ifgroup_lockmgr(LK_SHARED);
809 TAILQ_FOREACH(ifg, &p->pfik_ifp->if_groups, ifgl_next) {
810 if (strcmp(ifg->ifgl_group->ifg_group, filter) == 0) {
811 ifgroup_lockmgr(LK_RELEASE);
812 return (0); /* iface is in group "filter" */
813 }
814 }
815 ifgroup_lockmgr(LK_RELEASE);
816 }
817 return (1);
02742ec6
JS
818}
819
70224baa
JL
820int
821pfi_set_flags(const char *name, int flags)
822{
823 struct pfi_kif *p;
824
825 crit_enter();
826 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
827 if (pfi_skip_if(name, p))
828 continue;
829 p->pfik_flags |= flags;
830 }
831 crit_exit();
832 return (0);
833}
834
835int
836pfi_clear_flags(const char *name, int flags)
837{
838 struct pfi_kif *p;
839
840 crit_enter();
841 RB_FOREACH(p, pfi_ifhead, &pfi_ifs) {
842 if (pfi_skip_if(name, p))
843 continue;
844 p->pfik_flags &= ~flags;
845 }
846 crit_exit();
847 return (0);
848}
849
02742ec6 850/* from pf_print_state.c */
c686757e 851static int
02742ec6
JS
852pfi_unmask(void *addr)
853{
854 struct pf_addr *m = addr;
855 int i = 31, j = 0, b = 0;
856 u_int32_t tmp;
857
858 while (j < 4 && m->addr32[j] == 0xffffffff) {
859 b += 32;
860 j++;
861 }
862 if (j < 4) {
863 tmp = ntohl(m->addr32[j]);
864 for (i = 31; tmp & (1 << i); --i)
865 b++;
866 }
867 return (b);
868}
869
c686757e
AL
870
871/*
872 * eventhandler events
873 */
874
875static void
876pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
877{
878 pfi_attach_ifnet(ifp);
879}
880
881static void
882pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp)
883{
884 pfi_detach_ifnet(ifp);
885}
886
887static void
888pfi_attach_group_event(void *arg __unused, struct ifg_group *ifg)
889{
890 pfi_attach_ifgroup(ifg);
891}
892
893static void
894pfi_detach_group_event(void *arg __unused, struct ifg_group *ifg)
895{
896 pfi_detach_ifgroup(ifg);
897}
898
899static void
900pfi_change_group_event(void *arg __unused, char *gname)
901{
902 pfi_group_change(gname);
903}
904
905static void
906pfi_ifaddr_event(void *arg __unused, struct ifnet *ifp,
907 enum ifaddr_event event __unused,
908 struct ifaddr *ifa __unused)
909{
910 if (ifp && ifp->if_pf_kif) {
911 crit_enter();
912 pfi_update++;
913 pfi_kif_update(ifp->if_pf_kif);
914 crit_exit();
915 }
916}