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