]>
Commit | Line | Data |
---|---|---|
316670eb | 1 | /* |
d9a64523 | 2 | * Copyright (c) 1999-2018 Apple Inc. All rights reserved. |
316670eb A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
39236c6e | 28 | |
316670eb | 29 | #include <kern/locks.h> |
d9a64523 | 30 | #include <kern/zalloc.h> |
39236c6e A |
31 | |
32 | #include <sys/types.h> | |
33 | #include <sys/kernel_types.h> | |
34 | #include <sys/kauth.h> | |
316670eb | 35 | #include <sys/socket.h> |
39236c6e A |
36 | #include <sys/socketvar.h> |
37 | #include <sys/sockio.h> | |
38 | #include <sys/sysctl.h> | |
0a7de745 | 39 | #include <sys/proc.h> |
39236c6e | 40 | |
316670eb | 41 | #include <net/if.h> |
39236c6e A |
42 | #include <net/if_var.h> |
43 | #include <net/if_types.h> | |
316670eb | 44 | #include <net/bpf.h> |
39236c6e A |
45 | #include <net/net_osdep.h> |
46 | #include <net/pktap.h> | |
316670eb | 47 | #include <net/iptap.h> |
316670eb | 48 | |
39236c6e A |
49 | #include <netinet/in_pcb.h> |
50 | #include <netinet/tcp.h> | |
51 | #include <netinet/tcp_var.h> | |
52 | #define _IP_VHL | |
53 | #include <netinet/ip.h> | |
54 | #include <netinet/ip_var.h> | |
55 | #include <netinet/udp.h> | |
56 | #include <netinet/udp_var.h> | |
316670eb | 57 | |
39236c6e A |
58 | #include <netinet/ip6.h> |
59 | #include <netinet6/in6_pcb.h> | |
316670eb | 60 | |
39236c6e | 61 | #include <netinet/kpi_ipfilter.h> |
316670eb | 62 | |
39236c6e | 63 | #include <libkern/OSAtomic.h> |
316670eb | 64 | |
39236c6e | 65 | #include <kern/debug.h> |
316670eb | 66 | |
39236c6e | 67 | #include <sys/mcache.h> |
316670eb | 68 | |
39236c6e | 69 | #include <string.h> |
316670eb | 70 | |
39236c6e | 71 | struct iptap_softc { |
0a7de745 A |
72 | LIST_ENTRY(iptap_softc) iptap_link; |
73 | uint32_t iptap_unit; | |
74 | uint32_t iptap_dlt_raw_count; | |
75 | uint32_t iptap_dlt_pkttap_count; | |
76 | struct ifnet *iptap_ifp; | |
39236c6e | 77 | }; |
316670eb | 78 | |
39236c6e | 79 | static LIST_HEAD(iptap_list, iptap_softc) iptap_list = LIST_HEAD_INITIALIZER(iptap_list); |
316670eb | 80 | |
0a7de745 A |
81 | static void iptap_lock_shared(void); |
82 | static void iptap_lock_exclusive(void); | |
83 | static void iptap_lock_done(void); | |
84 | static void iptap_alloc_lock(void); | |
316670eb | 85 | |
39236c6e | 86 | decl_lck_rw_data(static, iptap_lck_rw); |
0a7de745 | 87 | static lck_grp_t *iptap_grp; |
316670eb | 88 | |
39236c6e | 89 | errno_t iptap_if_output(ifnet_t, mbuf_t); |
0a7de745 | 90 | errno_t iptap_demux(ifnet_t, mbuf_t, char *, protocol_family_t *); |
39236c6e | 91 | errno_t iptap_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc *, |
0a7de745 | 92 | u_int32_t); |
39236c6e | 93 | errno_t iptap_del_proto(ifnet_t, protocol_family_t); |
0a7de745 | 94 | errno_t iptap_getdrvspec(ifnet_t, struct ifdrv64 *); |
39236c6e A |
95 | errno_t iptap_ioctl(ifnet_t, unsigned long, void *); |
96 | void iptap_detach(ifnet_t); | |
0a7de745 | 97 | errno_t iptap_tap_callback(ifnet_t, u_int32_t, bpf_tap_mode ); |
39236c6e A |
98 | int iptap_clone_create(struct if_clone *, u_int32_t, void *); |
99 | int iptap_clone_destroy(struct ifnet *); | |
100 | ||
101 | static int iptap_ipf_register(void); | |
102 | static int iptap_ipf_unregister(void); | |
103 | static errno_t iptap_ipf_input(void *, mbuf_t *, int, u_int8_t); | |
104 | static errno_t iptap_ipf_output(void *, mbuf_t *, ipf_pktopts_t); | |
105 | static void iptap_ipf_detach(void *); | |
106 | ||
107 | static ipfilter_t iptap_ipf4, iptap_ipf6; | |
108 | ||
0a7de745 | 109 | void iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing); |
39236c6e | 110 | |
0a7de745 A |
111 | #define IPTAP_MAXUNIT IF_MAXUNIT |
112 | #define IPTAP_ZONE_MAX_ELEM MIN(IFNETS_MAX, IPTAP_MAXUNIT) | |
d9a64523 | 113 | |
0a7de745 A |
114 | static struct if_clone iptap_cloner = |
115 | IF_CLONE_INITIALIZER(IPTAP_IFNAME, | |
116 | iptap_clone_create, | |
117 | iptap_clone_destroy, | |
118 | 0, | |
119 | IPTAP_MAXUNIT, | |
120 | IPTAP_ZONE_MAX_ELEM, | |
121 | sizeof(struct iptap_softc)); | |
39236c6e A |
122 | |
123 | SYSCTL_DECL(_net_link); | |
0a7de745 | 124 | SYSCTL_NODE(_net_link, OID_AUTO, iptap, CTLFLAG_RW | CTLFLAG_LOCKED, 0, |
39236c6e A |
125 | "iptap virtual interface"); |
126 | ||
0a7de745 A |
127 | static int iptap_total_tap_count = 0; |
128 | SYSCTL_INT(_net_link_iptap, OID_AUTO, total_tap_count, CTLFLAG_RD | CTLFLAG_LOCKED, | |
129 | &iptap_total_tap_count, 0, ""); | |
39236c6e A |
130 | |
131 | static int iptap_log = 0; | |
132 | SYSCTL_INT(_net_link_iptap, OID_AUTO, log, CTLFLAG_RW | CTLFLAG_LOCKED, | |
0a7de745 | 133 | &iptap_log, 0, ""); |
39236c6e A |
134 | |
135 | #define IPTAP_LOG(fmt, ...) \ | |
136 | do { \ | |
137 | if ((iptap_log)) \ | |
0a7de745 | 138 | printf("%s:%d " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ |
39236c6e | 139 | } while(false) |
316670eb A |
140 | |
141 | __private_extern__ void | |
39236c6e A |
142 | iptap_init(void) |
143 | { | |
144 | errno_t error; | |
0a7de745 | 145 | |
316670eb | 146 | iptap_alloc_lock(); |
0a7de745 | 147 | |
39236c6e | 148 | error = if_clone_attach(&iptap_cloner); |
0a7de745 | 149 | if (error != 0) { |
39236c6e | 150 | panic("%s: if_clone_attach() failed, error %d\n", __func__, error); |
0a7de745 | 151 | } |
39236c6e A |
152 | } |
153 | ||
154 | static void | |
155 | iptap_alloc_lock(void) | |
156 | { | |
157 | lck_grp_attr_t *grp_attr; | |
158 | lck_attr_t *attr; | |
0a7de745 | 159 | |
39236c6e A |
160 | grp_attr = lck_grp_attr_alloc_init(); |
161 | lck_grp_attr_setdefault(grp_attr); | |
162 | iptap_grp = lck_grp_alloc_init(IPTAP_IFNAME, grp_attr); | |
163 | lck_grp_attr_free(grp_attr); | |
0a7de745 | 164 | |
39236c6e A |
165 | attr = lck_attr_alloc_init(); |
166 | lck_attr_setdefault(attr); | |
0a7de745 | 167 | |
39236c6e A |
168 | lck_rw_init(&iptap_lck_rw, iptap_grp, attr); |
169 | lck_attr_free(attr); | |
316670eb A |
170 | } |
171 | ||
39236c6e A |
172 | static void |
173 | iptap_lock_shared(void) | |
174 | { | |
175 | lck_rw_lock_shared(&iptap_lck_rw); | |
316670eb A |
176 | } |
177 | ||
39236c6e A |
178 | static void |
179 | iptap_lock_exclusive(void) | |
180 | { | |
181 | lck_rw_lock_exclusive(&iptap_lck_rw); | |
316670eb A |
182 | } |
183 | ||
184 | static void | |
39236c6e | 185 | iptap_lock_done(void) |
316670eb | 186 | { |
39236c6e A |
187 | lck_rw_done(&iptap_lck_rw); |
188 | } | |
189 | ||
190 | __private_extern__ int | |
191 | iptap_clone_create(struct if_clone *ifc, u_int32_t unit, void *params) | |
192 | { | |
193 | #pragma unused(params) | |
194 | ||
195 | int error = 0; | |
196 | struct iptap_softc *iptap = NULL; | |
5ba3f43e | 197 | struct ifnet_init_eparams if_init; |
0a7de745 | 198 | |
d9a64523 | 199 | iptap = if_clone_softc_allocate(&iptap_cloner); |
39236c6e A |
200 | if (iptap == NULL) { |
201 | printf("%s: _MALLOC failed\n", __func__); | |
202 | error = ENOMEM; | |
203 | goto done; | |
204 | } | |
205 | iptap->iptap_unit = unit; | |
206 | ||
207 | /* | |
0a7de745 | 208 | * We do not use a set_bpf_tap() function as we rather rely on the more |
39236c6e A |
209 | * accurate callback passed to bpf_attach() |
210 | */ | |
5ba3f43e A |
211 | bzero(&if_init, sizeof(if_init)); |
212 | if_init.ver = IFNET_INIT_CURRENT_VERSION; | |
0a7de745 | 213 | if_init.len = sizeof(if_init); |
5ba3f43e | 214 | if_init.flags = IFNET_INIT_LEGACY; |
39236c6e A |
215 | if_init.name = ifc->ifc_name; |
216 | if_init.unit = unit; | |
217 | if_init.type = IFT_OTHER; | |
218 | if_init.family = IFNET_FAMILY_LOOPBACK; | |
219 | if_init.output = iptap_if_output; | |
220 | if_init.demux = iptap_demux; | |
221 | if_init.add_proto = iptap_add_proto; | |
222 | if_init.del_proto = iptap_del_proto; | |
223 | if_init.softc = iptap; | |
224 | if_init.ioctl = iptap_ioctl; | |
225 | if_init.detach = iptap_detach; | |
226 | ||
5ba3f43e | 227 | error = ifnet_allocate_extended(&if_init, &iptap->iptap_ifp); |
39236c6e A |
228 | if (error != 0) { |
229 | printf("%s: ifnet_allocate failed, error %d\n", __func__, error); | |
230 | goto done; | |
231 | } | |
0a7de745 | 232 | |
39236c6e | 233 | ifnet_set_flags(iptap->iptap_ifp, IFF_UP, IFF_UP); |
0a7de745 | 234 | |
39236c6e A |
235 | error = ifnet_attach(iptap->iptap_ifp, NULL); |
236 | if (error != 0) { | |
237 | printf("%s: ifnet_attach failed - error %d\n", __func__, error); | |
238 | ifnet_release(iptap->iptap_ifp); | |
239 | goto done; | |
316670eb | 240 | } |
0a7de745 A |
241 | |
242 | /* | |
39236c6e A |
243 | * Attach by default as DLT_PKTAP for packet metadata |
244 | * Provide DLT_RAW for legacy | |
245 | */ | |
0a7de745 A |
246 | bpf_attach(iptap->iptap_ifp, DLT_PKTAP, sizeof(struct pktap_header), NULL, |
247 | iptap_tap_callback); | |
39236c6e | 248 | bpf_attach(iptap->iptap_ifp, DLT_RAW, 0, NULL, |
0a7de745 A |
249 | iptap_tap_callback); |
250 | ||
39236c6e A |
251 | /* Take a reference and add to the global list */ |
252 | ifnet_reference(iptap->iptap_ifp); | |
0a7de745 | 253 | |
39236c6e | 254 | iptap_lock_exclusive(); |
0a7de745 A |
255 | |
256 | if (LIST_EMPTY(&iptap_list)) { | |
39236c6e | 257 | iptap_ipf_register(); |
0a7de745 | 258 | } |
39236c6e | 259 | LIST_INSERT_HEAD(&iptap_list, iptap, iptap_link); |
316670eb | 260 | iptap_lock_done(); |
39236c6e A |
261 | done: |
262 | if (error != 0) { | |
0a7de745 | 263 | if (iptap != NULL) { |
d9a64523 | 264 | if_clone_softc_deallocate(&iptap_cloner, iptap); |
0a7de745 | 265 | } |
39236c6e | 266 | } |
0a7de745 | 267 | return error; |
316670eb A |
268 | } |
269 | ||
39236c6e A |
270 | __private_extern__ int |
271 | iptap_clone_destroy(struct ifnet *ifp) | |
316670eb | 272 | { |
39236c6e A |
273 | int error = 0; |
274 | ||
275 | (void) ifnet_detach(ifp); | |
0a7de745 A |
276 | |
277 | return error; | |
316670eb A |
278 | } |
279 | ||
39236c6e A |
280 | /* |
281 | * This function is called whenever a DLT is set on the interface: | |
282 | * - When interface is attached to a BPF device via BIOCSETIF for the default DLT | |
283 | * - Whenever a new DLT is selected via BIOCSDLT | |
284 | * - When the interface is detached from a BPF device (direction is zero) | |
285 | */ | |
286 | __private_extern__ errno_t | |
287 | iptap_tap_callback(ifnet_t ifp, u_int32_t dlt, bpf_tap_mode direction) | |
316670eb | 288 | { |
39236c6e | 289 | struct iptap_softc *iptap; |
316670eb | 290 | |
39236c6e A |
291 | iptap = ifp->if_softc; |
292 | if (iptap == NULL) { | |
293 | printf("%s: if_softc is NULL for ifp %s\n", __func__, | |
294 | ifp->if_xname); | |
295 | goto done; | |
296 | } | |
297 | switch (dlt) { | |
0a7de745 A |
298 | case DLT_RAW: |
299 | if (direction == 0) { | |
300 | if (iptap->iptap_dlt_raw_count > 0) { | |
301 | iptap->iptap_dlt_raw_count--; | |
302 | OSAddAtomic(-1, &iptap_total_tap_count); | |
39236c6e | 303 | } |
0a7de745 A |
304 | } else { |
305 | iptap->iptap_dlt_raw_count++; | |
306 | OSAddAtomic(1, &iptap_total_tap_count); | |
307 | } | |
308 | break; | |
309 | case DLT_PKTAP: | |
310 | if (direction == 0) { | |
311 | if (iptap->iptap_dlt_pkttap_count > 0) { | |
312 | iptap->iptap_dlt_pkttap_count--; | |
313 | OSAddAtomic(-1, &iptap_total_tap_count); | |
39236c6e | 314 | } |
0a7de745 A |
315 | } else { |
316 | iptap->iptap_dlt_pkttap_count++; | |
317 | OSAddAtomic(1, &iptap_total_tap_count); | |
318 | } | |
319 | break; | |
39236c6e A |
320 | } |
321 | done: | |
0a7de745 A |
322 | /* |
323 | * Attachements count must be positive and we're in trouble | |
39236c6e A |
324 | * if we have more that 2**31 attachements |
325 | */ | |
326 | VERIFY(iptap_total_tap_count >= 0); | |
327 | ||
0a7de745 | 328 | return 0; |
316670eb A |
329 | } |
330 | ||
39236c6e A |
331 | __private_extern__ errno_t |
332 | iptap_if_output(ifnet_t ifp, mbuf_t m) | |
316670eb | 333 | { |
39236c6e A |
334 | #pragma unused(ifp) |
335 | ||
336 | mbuf_freem(m); | |
0a7de745 | 337 | return ENOTSUP; |
316670eb A |
338 | } |
339 | ||
39236c6e | 340 | __private_extern__ errno_t |
0a7de745 A |
341 | iptap_demux(ifnet_t ifp, mbuf_t m, char *header, |
342 | protocol_family_t *ppf) | |
316670eb | 343 | { |
39236c6e A |
344 | #pragma unused(ifp) |
345 | #pragma unused(m) | |
346 | #pragma unused(header) | |
347 | #pragma unused(ppf) | |
348 | ||
0a7de745 | 349 | return ENOTSUP; |
316670eb A |
350 | } |
351 | ||
39236c6e A |
352 | __private_extern__ errno_t |
353 | iptap_add_proto(ifnet_t ifp, protocol_family_t pf, | |
354 | const struct ifnet_demux_desc *dmx, u_int32_t cnt) | |
316670eb | 355 | { |
39236c6e A |
356 | #pragma unused(ifp) |
357 | #pragma unused(pf) | |
358 | #pragma unused(dmx) | |
359 | #pragma unused(cnt) | |
360 | ||
0a7de745 | 361 | return 0; |
316670eb A |
362 | } |
363 | ||
39236c6e A |
364 | __private_extern__ errno_t |
365 | iptap_del_proto(ifnet_t ifp, protocol_family_t pf) | |
316670eb | 366 | { |
39236c6e A |
367 | #pragma unused(ifp) |
368 | #pragma unused(pf) | |
369 | ||
0a7de745 | 370 | return 0; |
316670eb A |
371 | } |
372 | ||
39236c6e A |
373 | __private_extern__ errno_t |
374 | iptap_getdrvspec(ifnet_t ifp, struct ifdrv64 *ifd) | |
316670eb | 375 | { |
39236c6e A |
376 | errno_t error = 0; |
377 | struct iptap_softc *iptap; | |
378 | ||
379 | iptap = ifp->if_softc; | |
380 | if (iptap == NULL) { | |
381 | error = ENOENT; | |
382 | printf("%s: iptap NULL - error %d\n", __func__, error); | |
383 | goto done; | |
384 | } | |
385 | ||
386 | switch (ifd->ifd_cmd) { | |
387 | case PKTP_CMD_TAP_COUNT: { | |
388 | uint32_t tap_count = iptap->iptap_dlt_raw_count + iptap->iptap_dlt_pkttap_count; | |
0a7de745 | 389 | |
39236c6e | 390 | if (ifd->ifd_len < sizeof(tap_count)) { |
0a7de745 A |
391 | printf("%s: PKTP_CMD_TAP_COUNT ifd_len %llu too small - error %d\n", |
392 | __func__, ifd->ifd_len, error); | |
39236c6e A |
393 | error = EINVAL; |
394 | break; | |
395 | } | |
396 | error = copyout(&tap_count, ifd->ifd_data, sizeof(tap_count)); | |
397 | if (error) { | |
398 | printf("%s: PKTP_CMD_TAP_COUNT copyout - error %d\n", __func__, error); | |
399 | goto done; | |
400 | } | |
401 | break; | |
402 | } | |
403 | default: | |
404 | error = EINVAL; | |
405 | break; | |
406 | } | |
407 | ||
408 | done: | |
0a7de745 | 409 | return error; |
316670eb A |
410 | } |
411 | ||
39236c6e A |
412 | __private_extern__ errno_t |
413 | iptap_ioctl(ifnet_t ifp, unsigned long cmd, void *data) | |
316670eb | 414 | { |
39236c6e A |
415 | errno_t error = 0; |
416 | ||
417 | if ((cmd & IOC_IN)) { | |
418 | error = kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER); | |
419 | if (error) { | |
420 | goto done; | |
421 | } | |
422 | } | |
0a7de745 | 423 | |
39236c6e A |
424 | switch (cmd) { |
425 | case SIOCGDRVSPEC32: { | |
426 | struct ifdrv64 ifd; | |
427 | struct ifdrv32 *ifd32 = (struct ifdrv32 *)data; | |
0a7de745 | 428 | |
39236c6e A |
429 | memcpy(ifd.ifd_name, ifd32->ifd_name, sizeof(ifd.ifd_name)); |
430 | ifd.ifd_cmd = ifd32->ifd_cmd; | |
431 | ifd.ifd_len = ifd32->ifd_len; | |
432 | ifd.ifd_data = ifd32->ifd_data; | |
0a7de745 | 433 | |
39236c6e | 434 | error = iptap_getdrvspec(ifp, &ifd); |
0a7de745 | 435 | |
39236c6e | 436 | break; |
316670eb | 437 | } |
39236c6e A |
438 | case SIOCGDRVSPEC64: { |
439 | struct ifdrv64 *ifd64 = (struct ifdrv64 *)data; | |
0a7de745 | 440 | |
39236c6e A |
441 | error = iptap_getdrvspec(ifp, ifd64); |
442 | ||
443 | break; | |
444 | } | |
445 | default: | |
446 | error = ENOTSUP; | |
447 | break; | |
448 | } | |
449 | done: | |
0a7de745 | 450 | return error; |
316670eb A |
451 | } |
452 | ||
39236c6e A |
453 | __private_extern__ void |
454 | iptap_detach(ifnet_t ifp) | |
316670eb | 455 | { |
d9a64523 | 456 | struct iptap_softc *iptap = NULL; |
0a7de745 | 457 | |
316670eb | 458 | iptap_lock_exclusive(); |
39236c6e A |
459 | |
460 | iptap = ifp->if_softc; | |
461 | ifp->if_softc = NULL; | |
462 | LIST_REMOVE(iptap, iptap_link); | |
463 | ||
0a7de745 | 464 | if (LIST_EMPTY(&iptap_list)) { |
39236c6e | 465 | iptap_ipf_unregister(); |
0a7de745 | 466 | } |
39236c6e | 467 | |
316670eb | 468 | iptap_lock_done(); |
39236c6e A |
469 | |
470 | /* Drop reference as it's no more on the global list */ | |
471 | ifnet_release(ifp); | |
d9a64523 | 472 | if_clone_softc_deallocate(&iptap_cloner, iptap); |
316670eb | 473 | |
39236c6e A |
474 | /* This is for the reference taken by ifnet_attach() */ |
475 | (void) ifnet_release(ifp); | |
476 | } | |
316670eb | 477 | |
39236c6e A |
478 | static int |
479 | iptap_ipf_register(void) | |
480 | { | |
481 | struct ipf_filter iptap_ipfinit; | |
482 | int err = 0; | |
483 | ||
484 | IPTAP_LOG("\n"); | |
485 | ||
0a7de745 | 486 | bzero(&iptap_ipfinit, sizeof(iptap_ipfinit)); |
39236c6e A |
487 | iptap_ipfinit.name = IPTAP_IFNAME; |
488 | iptap_ipfinit.cookie = &iptap_ipf4; | |
489 | iptap_ipfinit.ipf_input = iptap_ipf_input; | |
490 | iptap_ipfinit.ipf_output = iptap_ipf_output; | |
491 | iptap_ipfinit.ipf_detach = iptap_ipf_detach; | |
492 | ||
493 | err = ipf_addv4(&iptap_ipfinit, &iptap_ipf4); | |
494 | if (err != 0) { | |
495 | printf("%s: ipf_addv4 for %s0 failed - %d\n", | |
496 | __func__, IPTAP_IFNAME, err); | |
497 | goto done; | |
316670eb | 498 | } |
39236c6e A |
499 | |
500 | iptap_ipfinit.cookie = &iptap_ipf6; | |
501 | err = ipf_addv6(&iptap_ipfinit, &iptap_ipf6); | |
502 | if (err != 0) { | |
503 | printf("%s: ipf_addv6 for %s0 failed - %d\n", | |
504 | __func__, IPTAP_IFNAME, err); | |
505 | (void) ipf_remove(iptap_ipf4); | |
506 | iptap_ipf4 = NULL; | |
507 | goto done; | |
316670eb | 508 | } |
39236c6e A |
509 | |
510 | done: | |
0a7de745 | 511 | return err; |
316670eb A |
512 | } |
513 | ||
39236c6e A |
514 | static int |
515 | iptap_ipf_unregister(void) | |
316670eb | 516 | { |
39236c6e A |
517 | int err = 0; |
518 | ||
519 | IPTAP_LOG("\n"); | |
520 | ||
521 | if (iptap_ipf4 != NULL) { | |
522 | err = ipf_remove(iptap_ipf4); | |
523 | if (err != 0) { | |
524 | printf("%s: ipf_remove (ipv4) for %s0 failed - %d\n", | |
525 | __func__, IPTAP_IFNAME, err); | |
526 | goto done; | |
527 | } | |
528 | iptap_ipf4 = NULL; | |
316670eb | 529 | } |
39236c6e A |
530 | |
531 | if (iptap_ipf6 != NULL) { | |
532 | err = ipf_remove(iptap_ipf6); | |
533 | if (err != 0) { | |
534 | printf("%s: ipf_remove (ipv6) for %s0 failed - %d\n", | |
535 | __func__, IPTAP_IFNAME, err); | |
536 | goto done; | |
537 | } | |
538 | iptap_ipf6 = NULL; | |
539 | } | |
540 | done: | |
0a7de745 | 541 | return err; |
316670eb A |
542 | } |
543 | ||
544 | static errno_t | |
0a7de745 | 545 | iptap_ipf_input(void *arg, mbuf_t *mp, int off, u_int8_t proto) |
316670eb | 546 | { |
39236c6e A |
547 | #pragma unused(off) |
548 | #pragma unused(proto) | |
549 | ||
0a7de745 | 550 | if (arg == (void *)&iptap_ipf4) { |
39236c6e | 551 | iptap_bpf_tap(*mp, AF_INET, 0); |
0a7de745 | 552 | } else if (arg == (void *)&iptap_ipf6) { |
39236c6e | 553 | iptap_bpf_tap(*mp, AF_INET6, 0); |
0a7de745 | 554 | } else { |
39236c6e A |
555 | IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx " |
556 | "&iptap_ipf6 0x%llx\n", __func__, __LINE__, | |
557 | (uint64_t)VM_KERNEL_ADDRPERM(arg), | |
558 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4), | |
559 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6)); | |
0a7de745 | 560 | } |
39236c6e | 561 | |
0a7de745 | 562 | return 0; |
316670eb A |
563 | } |
564 | ||
565 | static errno_t | |
39236c6e A |
566 | iptap_ipf_output(void *arg, mbuf_t *mp, ipf_pktopts_t opt) |
567 | { | |
316670eb | 568 | #pragma unused(opt) |
39236c6e | 569 | |
0a7de745 | 570 | if (arg == (void *)&iptap_ipf4) { |
39236c6e | 571 | iptap_bpf_tap(*mp, AF_INET, 1); |
0a7de745 | 572 | } else if (arg == (void *)&iptap_ipf6) { |
39236c6e | 573 | iptap_bpf_tap(*mp, AF_INET6, 1); |
0a7de745 | 574 | } else { |
39236c6e A |
575 | IPTAP_LOG("%s:%d bad cookie 0x%llx &iptap_ipf4 0x%llx " |
576 | "&iptap_ipf6 0x%llx\n", __func__, __LINE__, | |
577 | (uint64_t)VM_KERNEL_ADDRPERM(arg), | |
578 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf4), | |
579 | (uint64_t)VM_KERNEL_ADDRPERM(&iptap_ipf6)); | |
0a7de745 | 580 | } |
39236c6e | 581 | |
0a7de745 | 582 | return 0; |
316670eb A |
583 | } |
584 | ||
39236c6e A |
585 | static void |
586 | iptap_ipf_detach(void *arg) | |
316670eb | 587 | { |
39236c6e | 588 | #pragma unused(arg) |
316670eb A |
589 | } |
590 | ||
39236c6e | 591 | __private_extern__ void |
0a7de745 | 592 | iptap_bpf_tap(struct mbuf *m, u_int32_t proto, int outgoing) |
39236c6e A |
593 | { |
594 | struct iptap_softc *iptap; | |
0a7de745 A |
595 | void (*bpf_tap_func)(ifnet_t, u_int32_t, mbuf_t, void *, size_t ) = |
596 | outgoing ? bpf_tap_out : bpf_tap_in; | |
5ba3f43e A |
597 | uint16_t src_scope_id = 0; |
598 | uint16_t dst_scope_id = 0; | |
599 | ||
600 | if (proto == AF_INET6) { | |
601 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | |
602 | /* | |
603 | * Clear the embedded scope ID | |
604 | */ | |
605 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) { | |
606 | src_scope_id = ip6->ip6_src.s6_addr16[1]; | |
607 | ip6->ip6_src.s6_addr16[1] = 0; | |
608 | } | |
609 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) { | |
610 | dst_scope_id = ip6->ip6_dst.s6_addr16[1]; | |
611 | ip6->ip6_dst.s6_addr16[1] = 0; | |
612 | } | |
613 | } | |
39236c6e A |
614 | |
615 | iptap_lock_shared(); | |
316670eb | 616 | |
39236c6e | 617 | LIST_FOREACH(iptap, &iptap_list, iptap_link) { |
0a7de745 A |
618 | if (iptap->iptap_dlt_raw_count > 0) { |
619 | bpf_tap_func(iptap->iptap_ifp, DLT_RAW, m, | |
620 | NULL, 0); | |
621 | } | |
622 | if (iptap->iptap_dlt_pkttap_count > 0) { | |
623 | struct { | |
624 | struct pktap_header hdr; | |
625 | u_int32_t proto; | |
626 | } hdr_buffer; | |
627 | struct pktap_header *hdr = &hdr_buffer.hdr; | |
628 | size_t hdr_size = sizeof(hdr_buffer); | |
629 | struct ifnet *ifp = outgoing ? NULL : m->m_pkthdr.rcvif; | |
630 | ||
631 | /* Verify the structure is packed */ | |
632 | _CASSERT(sizeof(hdr_buffer) == sizeof(struct pktap_header) + sizeof(u_int32_t)); | |
633 | ||
634 | bzero(hdr, sizeof(hdr_buffer)); | |
635 | hdr->pth_length = sizeof(struct pktap_header); | |
636 | hdr->pth_type_next = PTH_TYPE_PACKET; | |
637 | hdr->pth_dlt = DLT_NULL; | |
638 | if (ifp != NULL) { | |
639 | snprintf(hdr->pth_ifname, sizeof(hdr->pth_ifname), "%s", | |
640 | ifp->if_xname); | |
39236c6e | 641 | } |
0a7de745 A |
642 | hdr_buffer.proto = proto; |
643 | hdr->pth_flags = outgoing ? PTH_FLAG_DIR_OUT : PTH_FLAG_DIR_IN; | |
644 | hdr->pth_protocol_family = proto; | |
645 | hdr->pth_frame_pre_length = 0; | |
646 | hdr->pth_frame_post_length = 0; | |
647 | hdr->pth_iftype = ifp != NULL ? ifp->if_type : 0; | |
648 | hdr->pth_ifunit = ifp != NULL ? ifp->if_unit : 0; | |
649 | ||
650 | pktap_fill_proc_info(hdr, proto, m, 0, outgoing, ifp); | |
651 | ||
652 | hdr->pth_svc = so_svc2tc(m->m_pkthdr.pkt_svc); | |
653 | ||
654 | bpf_tap_func(iptap->iptap_ifp, DLT_PKTAP, m, hdr, hdr_size); | |
655 | } | |
39236c6e | 656 | } |
0a7de745 | 657 | |
39236c6e | 658 | iptap_lock_done(); |
0a7de745 | 659 | |
5ba3f43e A |
660 | if (proto == AF_INET6) { |
661 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | |
662 | ||
663 | /* | |
664 | * Restore the embedded scope ID | |
665 | */ | |
666 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) { | |
667 | ip6->ip6_src.s6_addr16[1] = src_scope_id; | |
668 | } | |
669 | if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) { | |
670 | ip6->ip6_dst.s6_addr16[1] = dst_scope_id; | |
671 | } | |
672 | } | |
39236c6e | 673 | } |