npf_ifaddr.c revision 1.4 1 /*-
2 * Copyright (c) 2014 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Mindaugas Rasiukevicius.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * 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 the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * NPF network interface handling module.
32 */
33
34 #ifdef _KERNEL
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: npf_ifaddr.c,v 1.4 2018/09/29 14:41:36 rmind Exp $");
37
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/kmem.h>
41
42 #include <net/if.h>
43 #include <netinet/in.h>
44 #include <netinet6/in6_var.h>
45 #endif
46
47 #include "npf_impl.h"
48
49 static npf_table_t *
50 lookup_ifnet_table(npf_t *npf, ifnet_t *ifp)
51 {
52 const npf_ifops_t *ifops = npf->ifops;
53 char tname[NPF_TABLE_MAXNAMELEN];
54 npf_tableset_t *ts;
55 const char *ifname;
56 npf_table_t *t;
57 u_int tid;
58
59 /* Get the interface name and prefix it. */
60 ifname = ifops->getname(ifp);
61 snprintf(tname, sizeof(tname), ".ifnet-%s", ifname);
62
63 KERNEL_LOCK(1, NULL);
64 npf_config_enter(npf);
65 ts = npf_config_tableset(npf);
66
67 /*
68 * Check whether this interface is of any interest to us.
69 */
70 t = npf_tableset_getbyname(ts, tname);
71 if (!t) {
72 goto out;
73 }
74 tid = npf_table_getid(t);
75
76 /* Create a new NPF table for the interface. */
77 t = npf_table_create(tname, tid, NPF_TABLE_HASH, NULL, 16);
78 if (!t) {
79 goto out;
80 }
81 return t;
82 out:
83 npf_config_exit(npf);
84 KERNEL_UNLOCK_ONE(NULL);
85 return NULL;
86 }
87
88 static void
89 replace_ifnet_table(npf_t *npf, npf_table_t *newt)
90 {
91 npf_tableset_t *ts = npf_config_tableset(npf);
92 npf_table_t *oldt;
93
94 KERNEL_UNLOCK_ONE(NULL);
95
96 /*
97 * Finally, swap the tables and issue a sync barrier.
98 */
99 oldt = npf_tableset_swap(ts, newt);
100 npf_config_sync(npf);
101 npf_config_exit(npf);
102
103 /* At this point, it is safe to destroy the old table. */
104 npf_table_destroy(oldt);
105 }
106
107 void
108 npf_ifaddr_sync(npf_t *npf, ifnet_t *ifp)
109 {
110 npf_table_t *t;
111 struct ifaddr *ifa;
112
113 /*
114 * First, check whether this interface is of any interest to us.
115 *
116 * => Acquires npf-config-lock and kernel-lock on success.
117 */
118 t = lookup_ifnet_table(npf, ifp);
119 if (!t)
120 return;
121
122 /*
123 * Populate the table with the interface addresses.
124 * Note: currently, this list is protected by the kernel-lock.
125 */
126 IFADDR_FOREACH(ifa, ifp) {
127 struct sockaddr *sa = ifa->ifa_addr;
128 const void *p = NULL;
129 int alen = 0;
130
131 if (sa->sa_family == AF_INET) {
132 const struct sockaddr_in *sin4 = satosin(sa);
133 alen = sizeof(struct in_addr);
134 p = &sin4->sin_addr;
135 }
136 if (sa->sa_family == AF_INET6) {
137 const struct sockaddr_in6 *sin6 = satosin6(sa);
138 alen = sizeof(struct in6_addr);
139 p = &sin6->sin6_addr;
140 }
141 if (alen) {
142 npf_addr_t addr;
143 memcpy(&addr, p, alen);
144 npf_table_insert(t, alen, &addr, NPF_NO_NETMASK);
145 }
146 }
147
148 /* Publish the new table. */
149 replace_ifnet_table(npf, t);
150 }
151
152 void
153 npf_ifaddr_flush(npf_t *npf, ifnet_t *ifp)
154 {
155 npf_table_t *t;
156
157 /*
158 * Flush: just load an empty table.
159 */
160 t = lookup_ifnet_table(npf, ifp);
161 if (!t) {
162 return;
163 }
164 replace_ifnet_table(npf, t);
165 }
166
167 void
168 npf_ifaddr_syncall(npf_t *npf)
169 {
170 ifnet_t *ifp;
171
172 KERNEL_LOCK(1, NULL);
173 IFNET_GLOBAL_LOCK();
174 IFNET_WRITER_FOREACH(ifp) {
175 npf_ifaddr_sync(npf, ifp);
176 }
177 IFNET_GLOBAL_UNLOCK();
178 KERNEL_UNLOCK_ONE(NULL);
179 }
180