| @@ -1,497 +1,506 @@ | | | @@ -1,497 +1,506 @@ |
1 | /* $NetBSD: npf_os.c,v 1.5 2017/01/03 00:58:05 rmind Exp $ */ | | 1 | /* $NetBSD: npf_os.c,v 1.6 2017/01/27 17:25:34 ryo Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2009-2016 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2009-2016 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This material is based upon work partially supported by The | | 7 | * This material is based upon work partially supported by The |
8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. | | 8 | * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * NPF main: dynamic load/initialisation and unload routines. | | 33 | * NPF main: dynamic load/initialisation and unload routines. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #ifdef _KERNEL | | 36 | #ifdef _KERNEL |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.5 2017/01/03 00:58:05 rmind Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.6 2017/01/27 17:25:34 ryo Exp $"); |
39 | | | 39 | |
40 | #ifdef _KERNEL_OPT | | 40 | #ifdef _KERNEL_OPT |
41 | #include "pf.h" | | 41 | #include "pf.h" |
42 | #if NPF > 0 | | 42 | #if NPF > 0 |
43 | #error "NPF and PF are mutually exclusive; please select one" | | 43 | #error "NPF and PF are mutually exclusive; please select one" |
44 | #endif | | 44 | #endif |
45 | #endif | | 45 | #endif |
46 | | | 46 | |
47 | #include <sys/param.h> | | 47 | #include <sys/param.h> |
48 | #include <sys/types.h> | | 48 | #include <sys/types.h> |
49 | | | 49 | |
50 | #include <sys/conf.h> | | 50 | #include <sys/conf.h> |
51 | #include <sys/kauth.h> | | 51 | #include <sys/kauth.h> |
52 | #include <sys/kmem.h> | | 52 | #include <sys/kmem.h> |
53 | #include <sys/lwp.h> | | 53 | #include <sys/lwp.h> |
54 | #include <sys/module.h> | | 54 | #include <sys/module.h> |
55 | #include <sys/socketvar.h> | | 55 | #include <sys/socketvar.h> |
56 | #include <sys/uio.h> | | 56 | #include <sys/uio.h> |
57 | | | 57 | |
58 | #include <netinet/in.h> | | 58 | #include <netinet/in.h> |
59 | #include <netinet6/in6_var.h> | | 59 | #include <netinet6/in6_var.h> |
60 | #endif | | 60 | #endif |
61 | | | 61 | |
62 | #include "npf_impl.h" | | 62 | #include "npf_impl.h" |
63 | #include "npfkern.h" | | 63 | #include "npfkern.h" |
64 | | | 64 | |
65 | #ifdef _KERNEL | | 65 | #ifdef _KERNEL |
66 | #ifndef _MODULE | | 66 | #ifndef _MODULE |
67 | #include "opt_modular.h" | | 67 | #include "opt_modular.h" |
| | | 68 | #include "opt_net_mpsafe.h" |
68 | #endif | | 69 | #endif |
69 | #include "ioconf.h" | | 70 | #include "ioconf.h" |
70 | #endif | | 71 | #endif |
71 | | | 72 | |
72 | /* | | 73 | /* |
73 | * Module and device structures. | | 74 | * Module and device structures. |
74 | */ | | 75 | */ |
75 | #ifndef _MODULE | | 76 | #ifndef _MODULE |
76 | /* | | 77 | /* |
77 | * Modular kernels load drivers too early, and we need percpu to be inited | | 78 | * Modular kernels load drivers too early, and we need percpu to be inited |
78 | * So we make this misc; a better way would be to have early boot and late | | 79 | * So we make this misc; a better way would be to have early boot and late |
79 | * boot drivers. | | 80 | * boot drivers. |
80 | */ | | 81 | */ |
81 | MODULE(MODULE_CLASS_MISC, npf, NULL); | | 82 | MODULE(MODULE_CLASS_MISC, npf, NULL); |
82 | #else | | 83 | #else |
83 | /* This module autoloads via /dev/npf so it needs to be a driver */ | | 84 | /* This module autoloads via /dev/npf so it needs to be a driver */ |
84 | MODULE(MODULE_CLASS_DRIVER, npf, NULL); | | 85 | MODULE(MODULE_CLASS_DRIVER, npf, NULL); |
85 | #endif | | 86 | #endif |
86 | | | 87 | |
87 | static int npf_dev_open(dev_t, int, int, lwp_t *); | | 88 | static int npf_dev_open(dev_t, int, int, lwp_t *); |
88 | static int npf_dev_close(dev_t, int, int, lwp_t *); | | 89 | static int npf_dev_close(dev_t, int, int, lwp_t *); |
89 | static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); | | 90 | static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *); |
90 | static int npf_dev_poll(dev_t, int, lwp_t *); | | 91 | static int npf_dev_poll(dev_t, int, lwp_t *); |
91 | static int npf_dev_read(dev_t, struct uio *, int); | | 92 | static int npf_dev_read(dev_t, struct uio *, int); |
92 | | | 93 | |
93 | const struct cdevsw npf_cdevsw = { | | 94 | const struct cdevsw npf_cdevsw = { |
94 | .d_open = npf_dev_open, | | 95 | .d_open = npf_dev_open, |
95 | .d_close = npf_dev_close, | | 96 | .d_close = npf_dev_close, |
96 | .d_read = npf_dev_read, | | 97 | .d_read = npf_dev_read, |
97 | .d_write = nowrite, | | 98 | .d_write = nowrite, |
98 | .d_ioctl = npf_dev_ioctl, | | 99 | .d_ioctl = npf_dev_ioctl, |
99 | .d_stop = nostop, | | 100 | .d_stop = nostop, |
100 | .d_tty = notty, | | 101 | .d_tty = notty, |
101 | .d_poll = npf_dev_poll, | | 102 | .d_poll = npf_dev_poll, |
102 | .d_mmap = nommap, | | 103 | .d_mmap = nommap, |
103 | .d_kqfilter = nokqfilter, | | 104 | .d_kqfilter = nokqfilter, |
104 | .d_discard = nodiscard, | | 105 | .d_discard = nodiscard, |
105 | .d_flag = D_OTHER | D_MPSAFE | | 106 | .d_flag = D_OTHER | D_MPSAFE |
106 | }; | | 107 | }; |
107 | | | 108 | |
108 | static const char * npf_ifop_getname(ifnet_t *); | | 109 | static const char * npf_ifop_getname(ifnet_t *); |
109 | static ifnet_t * npf_ifop_lookup(const char *); | | 110 | static ifnet_t * npf_ifop_lookup(const char *); |
110 | static void npf_ifop_flush(void *); | | 111 | static void npf_ifop_flush(void *); |
111 | static void * npf_ifop_getmeta(const ifnet_t *); | | 112 | static void * npf_ifop_getmeta(const ifnet_t *); |
112 | static void npf_ifop_setmeta(ifnet_t *, void *); | | 113 | static void npf_ifop_setmeta(ifnet_t *, void *); |
113 | | | 114 | |
114 | static const unsigned nworkers = 1; | | 115 | static const unsigned nworkers = 1; |
115 | | | 116 | |
116 | static bool pfil_registered = false; | | 117 | static bool pfil_registered = false; |
117 | static pfil_head_t * npf_ph_if = NULL; | | 118 | static pfil_head_t * npf_ph_if = NULL; |
118 | static pfil_head_t * npf_ph_inet = NULL; | | 119 | static pfil_head_t * npf_ph_inet = NULL; |
119 | static pfil_head_t * npf_ph_inet6 = NULL; | | 120 | static pfil_head_t * npf_ph_inet6 = NULL; |
120 | | | 121 | |
121 | static const npf_ifops_t kern_ifops = { | | 122 | static const npf_ifops_t kern_ifops = { |
122 | .getname = npf_ifop_getname, | | 123 | .getname = npf_ifop_getname, |
123 | .lookup = npf_ifop_lookup, | | 124 | .lookup = npf_ifop_lookup, |
124 | .flush = npf_ifop_flush, | | 125 | .flush = npf_ifop_flush, |
125 | .getmeta = npf_ifop_getmeta, | | 126 | .getmeta = npf_ifop_getmeta, |
126 | .setmeta = npf_ifop_setmeta, | | 127 | .setmeta = npf_ifop_setmeta, |
127 | }; | | 128 | }; |
128 | | | 129 | |
129 | static int | | 130 | static int |
130 | npf_fini(void) | | 131 | npf_fini(void) |
131 | { | | 132 | { |
132 | npf_t *npf = npf_getkernctx(); | | 133 | npf_t *npf = npf_getkernctx(); |
133 | | | 134 | |
134 | /* At first, detach device and remove pfil hooks. */ | | 135 | /* At first, detach device and remove pfil hooks. */ |
135 | #ifdef _MODULE | | 136 | #ifdef _MODULE |
136 | devsw_detach(NULL, &npf_cdevsw); | | 137 | devsw_detach(NULL, &npf_cdevsw); |
137 | #endif | | 138 | #endif |
138 | npf_pfil_unregister(true); | | 139 | npf_pfil_unregister(true); |
139 | npf_destroy(npf); | | 140 | npf_destroy(npf); |
140 | npf_sysfini(); | | 141 | npf_sysfini(); |
141 | return 0; | | 142 | return 0; |
142 | } | | 143 | } |
143 | | | 144 | |
144 | static int | | 145 | static int |
145 | npf_init(void) | | 146 | npf_init(void) |
146 | { | | 147 | { |
147 | npf_t *npf; | | 148 | npf_t *npf; |
148 | int error = 0; | | 149 | int error = 0; |
149 | | | 150 | |
150 | error = npf_sysinit(nworkers); | | 151 | error = npf_sysinit(nworkers); |
151 | if (error) | | 152 | if (error) |
152 | return error; | | 153 | return error; |
153 | npf = npf_create(0, NULL, &kern_ifops); | | 154 | npf = npf_create(0, NULL, &kern_ifops); |
154 | npf_setkernctx(npf); | | 155 | npf_setkernctx(npf); |
155 | npf_pfil_register(true); | | 156 | npf_pfil_register(true); |
156 | | | 157 | |
157 | #ifdef _MODULE | | 158 | #ifdef _MODULE |
158 | devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; | | 159 | devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; |
159 | | | 160 | |
160 | /* Attach /dev/npf device. */ | | 161 | /* Attach /dev/npf device. */ |
161 | error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); | | 162 | error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor); |
162 | if (error) { | | 163 | if (error) { |
163 | /* It will call devsw_detach(), which is safe. */ | | 164 | /* It will call devsw_detach(), which is safe. */ |
164 | (void)npf_fini(); | | 165 | (void)npf_fini(); |
165 | } | | 166 | } |
166 | #endif | | 167 | #endif |
167 | return error; | | 168 | return error; |
168 | } | | 169 | } |
169 | | | 170 | |
170 | | | 171 | |
171 | /* | | 172 | /* |
172 | * Module interface. | | 173 | * Module interface. |
173 | */ | | 174 | */ |
174 | static int | | 175 | static int |
175 | npf_modcmd(modcmd_t cmd, void *arg) | | 176 | npf_modcmd(modcmd_t cmd, void *arg) |
176 | { | | 177 | { |
177 | switch (cmd) { | | 178 | switch (cmd) { |
178 | case MODULE_CMD_INIT: | | 179 | case MODULE_CMD_INIT: |
179 | return npf_init(); | | 180 | return npf_init(); |
180 | case MODULE_CMD_FINI: | | 181 | case MODULE_CMD_FINI: |
181 | return npf_fini(); | | 182 | return npf_fini(); |
182 | case MODULE_CMD_AUTOUNLOAD: | | 183 | case MODULE_CMD_AUTOUNLOAD: |
183 | if (npf_autounload_p()) { | | 184 | if (npf_autounload_p()) { |
184 | return EBUSY; | | 185 | return EBUSY; |
185 | } | | 186 | } |
186 | break; | | 187 | break; |
187 | default: | | 188 | default: |
188 | return ENOTTY; | | 189 | return ENOTTY; |
189 | } | | 190 | } |
190 | return 0; | | 191 | return 0; |
191 | } | | 192 | } |
192 | | | 193 | |
193 | void | | 194 | void |
194 | npfattach(int nunits) | | 195 | npfattach(int nunits) |
195 | { | | 196 | { |
196 | /* Nothing */ | | 197 | /* Nothing */ |
197 | } | | 198 | } |
198 | | | 199 | |
199 | static int | | 200 | static int |
200 | npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) | | 201 | npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) |
201 | { | | 202 | { |
202 | /* Available only for super-user. */ | | 203 | /* Available only for super-user. */ |
203 | if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, | | 204 | if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, |
204 | KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { | | 205 | KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { |
205 | return EPERM; | | 206 | return EPERM; |
206 | } | | 207 | } |
207 | return 0; | | 208 | return 0; |
208 | } | | 209 | } |
209 | | | 210 | |
210 | static int | | 211 | static int |
211 | npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) | | 212 | npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l) |
212 | { | | 213 | { |
213 | return 0; | | 214 | return 0; |
214 | } | | 215 | } |
215 | | | 216 | |
216 | static int | | 217 | static int |
217 | npf_stats_export(npf_t *npf, void *data) | | 218 | npf_stats_export(npf_t *npf, void *data) |
218 | { | | 219 | { |
219 | uint64_t *fullst, *uptr = *(uint64_t **)data; | | 220 | uint64_t *fullst, *uptr = *(uint64_t **)data; |
220 | int error; | | 221 | int error; |
221 | | | 222 | |
222 | fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); | | 223 | fullst = kmem_alloc(NPF_STATS_SIZE, KM_SLEEP); |
223 | npf_stats(npf, fullst); /* will zero the buffer */ | | 224 | npf_stats(npf, fullst); /* will zero the buffer */ |
224 | error = copyout(fullst, uptr, NPF_STATS_SIZE); | | 225 | error = copyout(fullst, uptr, NPF_STATS_SIZE); |
225 | kmem_free(fullst, NPF_STATS_SIZE); | | 226 | kmem_free(fullst, NPF_STATS_SIZE); |
226 | return error; | | 227 | return error; |
227 | } | | 228 | } |
228 | | | 229 | |
229 | static int | | 230 | static int |
230 | npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) | | 231 | npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) |
231 | { | | 232 | { |
232 | npf_t *npf = npf_getkernctx(); | | 233 | npf_t *npf = npf_getkernctx(); |
233 | int error; | | 234 | int error; |
234 | | | 235 | |
235 | /* Available only for super-user. */ | | 236 | /* Available only for super-user. */ |
236 | if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, | | 237 | if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, |
237 | KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { | | 238 | KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { |
238 | return EPERM; | | 239 | return EPERM; |
239 | } | | 240 | } |
240 | | | 241 | |
241 | switch (cmd) { | | 242 | switch (cmd) { |
242 | case IOC_NPF_TABLE: | | 243 | case IOC_NPF_TABLE: |
243 | error = npfctl_table(npf, data); | | 244 | error = npfctl_table(npf, data); |
244 | break; | | 245 | break; |
245 | case IOC_NPF_RULE: | | 246 | case IOC_NPF_RULE: |
246 | error = npfctl_rule(npf, cmd, data); | | 247 | error = npfctl_rule(npf, cmd, data); |
247 | break; | | 248 | break; |
248 | case IOC_NPF_STATS: | | 249 | case IOC_NPF_STATS: |
249 | error = npf_stats_export(npf, data); | | 250 | error = npf_stats_export(npf, data); |
250 | break; | | 251 | break; |
251 | case IOC_NPF_SAVE: | | 252 | case IOC_NPF_SAVE: |
252 | error = npfctl_save(npf, cmd, data); | | 253 | error = npfctl_save(npf, cmd, data); |
253 | break; | | 254 | break; |
254 | case IOC_NPF_SWITCH: | | 255 | case IOC_NPF_SWITCH: |
255 | error = npfctl_switch(data); | | 256 | error = npfctl_switch(data); |
256 | break; | | 257 | break; |
257 | case IOC_NPF_LOAD: | | 258 | case IOC_NPF_LOAD: |
258 | error = npfctl_load(npf, cmd, data); | | 259 | error = npfctl_load(npf, cmd, data); |
259 | break; | | 260 | break; |
260 | case IOC_NPF_CONN_LOOKUP: | | 261 | case IOC_NPF_CONN_LOOKUP: |
261 | error = npfctl_conn_lookup(npf, cmd, data); | | 262 | error = npfctl_conn_lookup(npf, cmd, data); |
262 | break; | | 263 | break; |
263 | case IOC_NPF_VERSION: | | 264 | case IOC_NPF_VERSION: |
264 | *(int *)data = NPF_VERSION; | | 265 | *(int *)data = NPF_VERSION; |
265 | error = 0; | | 266 | error = 0; |
266 | break; | | 267 | break; |
267 | default: | | 268 | default: |
268 | error = ENOTTY; | | 269 | error = ENOTTY; |
269 | break; | | 270 | break; |
270 | } | | 271 | } |
271 | return error; | | 272 | return error; |
272 | } | | 273 | } |
273 | | | 274 | |
274 | static int | | 275 | static int |
275 | npf_dev_poll(dev_t dev, int events, lwp_t *l) | | 276 | npf_dev_poll(dev_t dev, int events, lwp_t *l) |
276 | { | | 277 | { |
277 | return ENOTSUP; | | 278 | return ENOTSUP; |
278 | } | | 279 | } |
279 | | | 280 | |
280 | static int | | 281 | static int |
281 | npf_dev_read(dev_t dev, struct uio *uio, int flag) | | 282 | npf_dev_read(dev_t dev, struct uio *uio, int flag) |
282 | { | | 283 | { |
283 | return ENOTSUP; | | 284 | return ENOTSUP; |
284 | } | | 285 | } |
285 | | | 286 | |
286 | bool | | 287 | bool |
287 | npf_autounload_p(void) | | 288 | npf_autounload_p(void) |
288 | { | | 289 | { |
289 | npf_t *npf = npf_getkernctx(); | | 290 | npf_t *npf = npf_getkernctx(); |
290 | return !npf_pfil_registered_p() && npf_default_pass(npf); | | 291 | return !npf_pfil_registered_p() && npf_default_pass(npf); |
291 | } | | 292 | } |
292 | | | 293 | |
293 | /* | | 294 | /* |
294 | * Interface operations. | | 295 | * Interface operations. |
295 | */ | | 296 | */ |
296 | | | 297 | |
297 | static const char * | | 298 | static const char * |
298 | npf_ifop_getname(ifnet_t *ifp) | | 299 | npf_ifop_getname(ifnet_t *ifp) |
299 | { | | 300 | { |
300 | return ifp->if_xname; | | 301 | return ifp->if_xname; |
301 | } | | 302 | } |
302 | | | 303 | |
303 | static ifnet_t * | | 304 | static ifnet_t * |
304 | npf_ifop_lookup(const char *name) | | 305 | npf_ifop_lookup(const char *name) |
305 | { | | 306 | { |
306 | return ifunit(name); | | 307 | return ifunit(name); |
307 | } | | 308 | } |
308 | | | 309 | |
309 | static void | | 310 | static void |
310 | npf_ifop_flush(void *arg) | | 311 | npf_ifop_flush(void *arg) |
311 | { | | 312 | { |
312 | ifnet_t *ifp; | | 313 | ifnet_t *ifp; |
313 | | | 314 | |
314 | KERNEL_LOCK(1, NULL); | | 315 | KERNEL_LOCK(1, NULL); |
315 | IFNET_LOCK(); | | 316 | IFNET_LOCK(); |
316 | IFNET_WRITER_FOREACH(ifp) { | | 317 | IFNET_WRITER_FOREACH(ifp) { |
317 | ifp->if_pf_kif = arg; | | 318 | ifp->if_pf_kif = arg; |
318 | } | | 319 | } |
319 | IFNET_UNLOCK(); | | 320 | IFNET_UNLOCK(); |
320 | KERNEL_UNLOCK_ONE(NULL); | | 321 | KERNEL_UNLOCK_ONE(NULL); |
321 | } | | 322 | } |
322 | | | 323 | |
323 | static void * | | 324 | static void * |
324 | npf_ifop_getmeta(const ifnet_t *ifp) | | 325 | npf_ifop_getmeta(const ifnet_t *ifp) |
325 | { | | 326 | { |
326 | return ifp->if_pf_kif; | | 327 | return ifp->if_pf_kif; |
327 | } | | 328 | } |
328 | | | 329 | |
329 | static void | | 330 | static void |
330 | npf_ifop_setmeta(ifnet_t *ifp, void *arg) | | 331 | npf_ifop_setmeta(ifnet_t *ifp, void *arg) |
331 | { | | 332 | { |
332 | ifp->if_pf_kif = arg; | | 333 | ifp->if_pf_kif = arg; |
333 | } | | 334 | } |
334 | | | 335 | |
335 | #ifdef _KERNEL | | 336 | #ifdef _KERNEL |
336 | | | 337 | |
337 | /* | | 338 | /* |
338 | * Wrapper of the main packet handler to pass the kernel NPF context. | | 339 | * Wrapper of the main packet handler to pass the kernel NPF context. |
339 | */ | | 340 | */ |
340 | static int | | 341 | static int |
341 | npfkern_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) | | 342 | npfkern_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di) |
342 | { | | 343 | { |
343 | npf_t *npf = npf_getkernctx(); | | 344 | npf_t *npf = npf_getkernctx(); |
344 | return npf_packet_handler(npf, mp, ifp, di); | | 345 | return npf_packet_handler(npf, mp, ifp, di); |
345 | } | | 346 | } |
346 | | | 347 | |
347 | /* | | 348 | /* |
348 | * npf_ifhook: hook handling interface changes. | | 349 | * npf_ifhook: hook handling interface changes. |
349 | */ | | 350 | */ |
350 | static void | | 351 | static void |
351 | npf_ifhook(void *arg, unsigned long cmd, void *arg2) | | 352 | npf_ifhook(void *arg, unsigned long cmd, void *arg2) |
352 | { | | 353 | { |
353 | npf_t *npf = npf_getkernctx(); | | 354 | npf_t *npf = npf_getkernctx(); |
354 | ifnet_t *ifp = arg2; | | 355 | ifnet_t *ifp = arg2; |
355 | | | 356 | |
356 | switch (cmd) { | | 357 | switch (cmd) { |
357 | case PFIL_IFNET_ATTACH: | | 358 | case PFIL_IFNET_ATTACH: |
358 | npf_ifmap_attach(npf, ifp); | | 359 | npf_ifmap_attach(npf, ifp); |
359 | npf_ifaddr_sync(npf, ifp); | | 360 | npf_ifaddr_sync(npf, ifp); |
360 | break; | | 361 | break; |
361 | case PFIL_IFNET_DETACH: | | 362 | case PFIL_IFNET_DETACH: |
362 | npf_ifmap_detach(npf, ifp); | | 363 | npf_ifmap_detach(npf, ifp); |
363 | npf_ifaddr_flush(npf, ifp); | | 364 | npf_ifaddr_flush(npf, ifp); |
364 | break; | | 365 | break; |
365 | } | | 366 | } |
366 | } | | 367 | } |
367 | | | 368 | |
368 | static void | | 369 | static void |
369 | npf_ifaddrhook(void *arg, u_long cmd, void *arg2) | | 370 | npf_ifaddrhook(void *arg, u_long cmd, void *arg2) |
370 | { | | 371 | { |
371 | npf_t *npf = npf_getkernctx(); | | 372 | npf_t *npf = npf_getkernctx(); |
372 | struct ifaddr *ifa = arg2; | | 373 | struct ifaddr *ifa = arg2; |
373 | | | 374 | |
374 | switch (cmd) { | | 375 | switch (cmd) { |
375 | case SIOCSIFADDR: | | 376 | case SIOCSIFADDR: |
376 | case SIOCAIFADDR: | | 377 | case SIOCAIFADDR: |
377 | case SIOCDIFADDR: | | 378 | case SIOCDIFADDR: |
378 | #ifdef INET6 | | 379 | #ifdef INET6 |
379 | case SIOCSIFADDR_IN6: | | 380 | case SIOCSIFADDR_IN6: |
380 | case SIOCAIFADDR_IN6: | | 381 | case SIOCAIFADDR_IN6: |
381 | case SIOCDIFADDR_IN6: | | 382 | case SIOCDIFADDR_IN6: |
382 | #endif | | 383 | #endif |
383 | break; | | 384 | break; |
384 | default: | | 385 | default: |
385 | return; | | 386 | return; |
386 | } | | 387 | } |
387 | npf_ifaddr_sync(npf, ifa->ifa_ifp); | | 388 | npf_ifaddr_sync(npf, ifa->ifa_ifp); |
388 | } | | 389 | } |
389 | | | 390 | |
390 | /* | | 391 | /* |
391 | * npf_pfil_register: register pfil(9) hooks. | | 392 | * npf_pfil_register: register pfil(9) hooks. |
392 | */ | | 393 | */ |
393 | int | | 394 | int |
394 | npf_pfil_register(bool init) | | 395 | npf_pfil_register(bool init) |
395 | { | | 396 | { |
396 | npf_t *npf = npf_getkernctx(); | | 397 | npf_t *npf = npf_getkernctx(); |
397 | int error = 0; | | 398 | int error = 0; |
398 | | | 399 | |
| | | 400 | #ifndef NET_MPSAFE |
399 | mutex_enter(softnet_lock); | | 401 | mutex_enter(softnet_lock); |
400 | KERNEL_LOCK(1, NULL); | | 402 | KERNEL_LOCK(1, NULL); |
| | | 403 | #endif |
401 | | | 404 | |
402 | /* Init: interface re-config and attach/detach hook. */ | | 405 | /* Init: interface re-config and attach/detach hook. */ |
403 | if (!npf_ph_if) { | | 406 | if (!npf_ph_if) { |
404 | npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); | | 407 | npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0); |
405 | if (!npf_ph_if) { | | 408 | if (!npf_ph_if) { |
406 | error = ENOENT; | | 409 | error = ENOENT; |
407 | goto out; | | 410 | goto out; |
408 | } | | 411 | } |
409 | | | 412 | |
410 | error = pfil_add_ihook(npf_ifhook, NULL, | | 413 | error = pfil_add_ihook(npf_ifhook, NULL, |
411 | PFIL_IFNET, npf_ph_if); | | 414 | PFIL_IFNET, npf_ph_if); |
412 | KASSERT(error == 0); | | 415 | KASSERT(error == 0); |
413 | | | 416 | |
414 | error = pfil_add_ihook(npf_ifaddrhook, NULL, | | 417 | error = pfil_add_ihook(npf_ifaddrhook, NULL, |
415 | PFIL_IFADDR, npf_ph_if); | | 418 | PFIL_IFADDR, npf_ph_if); |
416 | KASSERT(error == 0); | | 419 | KASSERT(error == 0); |
417 | } | | 420 | } |
418 | if (init) { | | 421 | if (init) { |
419 | goto out; | | 422 | goto out; |
420 | } | | 423 | } |
421 | | | 424 | |
422 | /* Check if pfil hooks are not already registered. */ | | 425 | /* Check if pfil hooks are not already registered. */ |
423 | if (pfil_registered) { | | 426 | if (pfil_registered) { |
424 | error = EEXIST; | | 427 | error = EEXIST; |
425 | goto out; | | 428 | goto out; |
426 | } | | 429 | } |
427 | | | 430 | |
428 | /* Capture points of the activity in the IP layer. */ | | 431 | /* Capture points of the activity in the IP layer. */ |
429 | npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); | | 432 | npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET); |
430 | npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); | | 433 | npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, (void *)AF_INET6); |
431 | if (!npf_ph_inet && !npf_ph_inet6) { | | 434 | if (!npf_ph_inet && !npf_ph_inet6) { |
432 | error = ENOENT; | | 435 | error = ENOENT; |
433 | goto out; | | 436 | goto out; |
434 | } | | 437 | } |
435 | | | 438 | |
436 | /* Packet IN/OUT handlers for IP layer. */ | | 439 | /* Packet IN/OUT handlers for IP layer. */ |
437 | if (npf_ph_inet) { | | 440 | if (npf_ph_inet) { |
438 | error = pfil_add_hook(npfkern_packet_handler, npf, | | 441 | error = pfil_add_hook(npfkern_packet_handler, npf, |
439 | PFIL_ALL, npf_ph_inet); | | 442 | PFIL_ALL, npf_ph_inet); |
440 | KASSERT(error == 0); | | 443 | KASSERT(error == 0); |
441 | } | | 444 | } |
442 | if (npf_ph_inet6) { | | 445 | if (npf_ph_inet6) { |
443 | error = pfil_add_hook(npfkern_packet_handler, npf, | | 446 | error = pfil_add_hook(npfkern_packet_handler, npf, |
444 | PFIL_ALL, npf_ph_inet6); | | 447 | PFIL_ALL, npf_ph_inet6); |
445 | KASSERT(error == 0); | | 448 | KASSERT(error == 0); |
446 | } | | 449 | } |
447 | | | 450 | |
448 | /* | | 451 | /* |
449 | * It is necessary to re-sync all/any interface address tables, | | 452 | * It is necessary to re-sync all/any interface address tables, |
450 | * since we did not listen for any changes. | | 453 | * since we did not listen for any changes. |
451 | */ | | 454 | */ |
452 | npf_ifaddr_syncall(npf); | | 455 | npf_ifaddr_syncall(npf); |
453 | pfil_registered = true; | | 456 | pfil_registered = true; |
454 | out: | | 457 | out: |
| | | 458 | #ifndef NET_MPSAFE |
455 | KERNEL_UNLOCK_ONE(NULL); | | 459 | KERNEL_UNLOCK_ONE(NULL); |
456 | mutex_exit(softnet_lock); | | 460 | mutex_exit(softnet_lock); |
| | | 461 | #endif |
457 | | | 462 | |
458 | return error; | | 463 | return error; |
459 | } | | 464 | } |
460 | | | 465 | |
461 | /* | | 466 | /* |
462 | * npf_pfil_unregister: unregister pfil(9) hooks. | | 467 | * npf_pfil_unregister: unregister pfil(9) hooks. |
463 | */ | | 468 | */ |
464 | void | | 469 | void |
465 | npf_pfil_unregister(bool fini) | | 470 | npf_pfil_unregister(bool fini) |
466 | { | | 471 | { |
467 | npf_t *npf = npf_getkernctx(); | | 472 | npf_t *npf = npf_getkernctx(); |
468 | | | 473 | |
| | | 474 | #ifndef NET_MPSAFE |
469 | mutex_enter(softnet_lock); | | 475 | mutex_enter(softnet_lock); |
470 | KERNEL_LOCK(1, NULL); | | 476 | KERNEL_LOCK(1, NULL); |
| | | 477 | #endif |
471 | | | 478 | |
472 | if (fini && npf_ph_if) { | | 479 | if (fini && npf_ph_if) { |
473 | (void)pfil_remove_ihook(npf_ifhook, NULL, | | 480 | (void)pfil_remove_ihook(npf_ifhook, NULL, |
474 | PFIL_IFNET, npf_ph_if); | | 481 | PFIL_IFNET, npf_ph_if); |
475 | (void)pfil_remove_ihook(npf_ifaddrhook, NULL, | | 482 | (void)pfil_remove_ihook(npf_ifaddrhook, NULL, |
476 | PFIL_IFADDR, npf_ph_if); | | 483 | PFIL_IFADDR, npf_ph_if); |
477 | } | | 484 | } |
478 | if (npf_ph_inet) { | | 485 | if (npf_ph_inet) { |
479 | (void)pfil_remove_hook(npfkern_packet_handler, npf, | | 486 | (void)pfil_remove_hook(npfkern_packet_handler, npf, |
480 | PFIL_ALL, npf_ph_inet); | | 487 | PFIL_ALL, npf_ph_inet); |
481 | } | | 488 | } |
482 | if (npf_ph_inet6) { | | 489 | if (npf_ph_inet6) { |
483 | (void)pfil_remove_hook(npfkern_packet_handler, npf, | | 490 | (void)pfil_remove_hook(npfkern_packet_handler, npf, |
484 | PFIL_ALL, npf_ph_inet6); | | 491 | PFIL_ALL, npf_ph_inet6); |
485 | } | | 492 | } |
486 | pfil_registered = false; | | 493 | pfil_registered = false; |
487 | | | 494 | |
| | | 495 | #ifndef NET_MPSAFE |
488 | KERNEL_UNLOCK_ONE(NULL); | | 496 | KERNEL_UNLOCK_ONE(NULL); |
489 | mutex_exit(softnet_lock); | | 497 | mutex_exit(softnet_lock); |
| | | 498 | #endif |
490 | } | | 499 | } |
491 | | | 500 | |
492 | bool | | 501 | bool |
493 | npf_pfil_registered_p(void) | | 502 | npf_pfil_registered_p(void) |
494 | { | | 503 | { |
495 | return pfil_registered; | | 504 | return pfil_registered; |
496 | } | | 505 | } |
497 | #endif | | 506 | #endif |