xref: /xnu-8020.140.41/bsd/net/if_6lowpan.c (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
1 /*
2  * Copyright (c) 2017-2021 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  * Copyright 1998 Massachusetts Institute of Technology
30  *
31  * Permission to use, copy, modify, and distribute this software and
32  * its documentation for any purpose and without fee is hereby
33  * granted, provided that both the above copyright notice and this
34  * permission notice appear in all copies, that both the above
35  * copyright notice and this permission notice appear in all
36  * supporting documentation, and that the name of M.I.T. not be used
37  * in advertising or publicity pertaining to distribution of the
38  * software without specific, written prior permission.  M.I.T. makes
39  * no representations about the suitability of this software for any
40  * purpose.  It is provided "as is" without express or implied
41  * warranty.
42  *
43  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
44  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
45  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
46  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
47  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
50  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
51  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
53  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  *
56  */
57 /*
58  * if_6lowpan.c - pseudo-device driver for IEEE 802.15.4 .
59  */
60 #include <sys/param.h>
61 #include <sys/kernel.h>
62 #include <sys/malloc.h>
63 #include <sys/mbuf.h>
64 #include <sys/queue.h>
65 #include <sys/socket.h>
66 #include <sys/sockio.h>
67 #include <sys/sysctl.h>
68 #include <sys/systm.h>
69 #include <sys/kern_event.h>
70 #include <sys/mcache.h>
71 
72 #include <net/bpf.h>
73 #include <net/ethernet.h>
74 #include <net/if.h>
75 #include <net/if_arp.h>
76 #include <net/if_dl.h>
77 #include <net/if_ether.h>
78 #include <net/if_types.h>
79 #include <net/if_6lowpan_var.h>
80 #include <net/frame802154.h>
81 #include <net/sixxlowpan.h>
82 #include <libkern/OSAtomic.h>
83 
84 #include <net/dlil.h>
85 
86 #include <net/kpi_interface.h>
87 #include <net/kpi_protocol.h>
88 
89 #include <kern/locks.h>
90 
91 #ifdef INET
92 #include <netinet/in.h>
93 #include <netinet/if_ether.h>
94 #endif
95 
96 #include <net/if_media.h>
97 #include <net/multicast_list.h>
98 #include <net/ether_if_module.h>
99 
100 #define SIXLOWPANNAME   "6lowpan"
101 
102 struct ifnet *p_6lowpan_ifnet = NULL;
103 
104 extern errno_t nd6_lookup_ipv6(ifnet_t interface,
105     const struct sockaddr_in6 *ip6_dest, struct sockaddr_dl *ll_dest,
106     size_t ll_dest_len, route_t hint, mbuf_t packet);
107 
108 
109 typedef int (bpf_callback_func)(struct ifnet *, struct mbuf *);
110 typedef int (if_set_bpf_tap_func)(struct ifnet *ifp, int mode, bpf_callback_func * func);
111 
112 static LCK_GRP_DECLARE(sixlowpan_lck_grp, "if_6lowpan");
113 static LCK_MTX_DECLARE(sixlowpan_lck_mtx, &sixlowpan_lck_grp);
114 
115 static __inline__ void
sixlowpan_assert_lock_held(void)116 sixlowpan_assert_lock_held(void)
117 {
118 	LCK_MTX_ASSERT(&sixlowpan_lck_mtx, LCK_MTX_ASSERT_OWNED);
119 }
120 
121 #ifdef __UNUSED__
122 static __inline__ void
sixlowpan_assert_lock_not_held(void)123 sixlowpan_assert_lock_not_held(void)
124 {
125 	LCK_MTX_ASSERT(&sixlowpan_lck_mtx, LCK_MTX_ASSERT_NOTOWNED);
126 }
127 #endif
128 
129 static __inline__ void
sixlowpan_lock(void)130 sixlowpan_lock(void)
131 {
132 	lck_mtx_lock(&sixlowpan_lck_mtx);
133 }
134 
135 static __inline__ void
sixlowpan_unlock(void)136 sixlowpan_unlock(void)
137 {
138 	lck_mtx_unlock(&sixlowpan_lck_mtx);
139 }
140 
141 struct if6lpan;
142 LIST_HEAD(if6lpan_list, if6lpan);
143 
144 typedef LIST_ENTRY(if6lpan)
145 if6lpan_entry;
146 
147 #define IF6LPAN_SIGNATURE       0x6666face
148 struct if6lpan {
149 	if6lpan_entry           if6lpan_list;
150 	char                    if6lpan_name[IFNAMSIZ]; /* our unique id */
151 	char                    if6lpan_addr[IEEE802154_ADDR_LEN]; /* our LL address */
152 	struct ifnet *          if6lpan_ifp;    /* our interface */
153 	struct ifnet *          if6lpan_pifp;   /* parent interface */
154 #define IF6LPANF_DETACHING      0x1             /* interface is detaching */
155 #define IF6LPANF_READY          0x2             /* interface is ready */
156 	u_int32_t               if6lpan_flags;
157 	bpf_packet_func         if6lpan_bpf_input;
158 	bpf_packet_func         if6lpan_bpf_output;
159 	int32_t                 if6lpan_retain_count;
160 	u_int32_t               if6lpan_signature;      /* IF6LPAN_SIGNATURE */
161 	u_int8_t                if6lpan_ieee802154_seq;
162 };
163 
164 typedef struct if6lpan * if6lpan_ref;
165 
166 static __inline__ int
if6lpan_flags_ready(if6lpan_ref ifl)167 if6lpan_flags_ready(if6lpan_ref ifl)
168 {
169 	return (ifl->if6lpan_flags & IF6LPANF_READY) != 0;
170 }
171 
172 static __inline__ void
if6lpan_flags_set_ready(if6lpan_ref ifl)173 if6lpan_flags_set_ready(if6lpan_ref ifl)
174 {
175 	ifl->if6lpan_flags |= IF6LPANF_READY;
176 	return;
177 }
178 
179 static __inline__ void
if6lpan_set_addr(if6lpan_ref ifl,caddr_t ether_addr)180 if6lpan_set_addr(if6lpan_ref ifl, caddr_t ether_addr)
181 {
182 	ifl->if6lpan_addr[0] = 0x66;
183 	ifl->if6lpan_addr[1] = 0x66;
184 	bcopy(ether_addr, &ifl->if6lpan_addr[2], ETHER_ADDR_LEN);
185 	return;
186 }
187 
188 #ifdef __UNUSED__
189 static __inline__ u_int8_t*
if6lpan_get_addr(if6lpan_ref ifl)190 if6lpan_get_addr(if6lpan_ref ifl)
191 {
192 	return ifl->ifl6lpan_addr;
193 }
194 #endif
195 
196 static __inline__ int
if6lpan_flags_detaching(if6lpan_ref ifl)197 if6lpan_flags_detaching(if6lpan_ref ifl)
198 {
199 	return (ifl->if6lpan_flags & IF6LPANF_DETACHING) != 0;
200 }
201 
202 static __inline__ void
if6lpan_flags_set_detaching(if6lpan_ref ifl)203 if6lpan_flags_set_detaching(if6lpan_ref ifl)
204 {
205 	ifl->if6lpan_flags |= IF6LPANF_DETACHING;
206 	return;
207 }
208 
209 static  int sixlowpan_clone_create(struct if_clone *, u_int32_t, void *);
210 static  int sixlowpan_clone_destroy(struct ifnet *);
211 static  int sixlowpan_input(ifnet_t ifp, protocol_family_t protocol,
212     mbuf_t m, char *frame_header);
213 static  int sixlowpan_output(struct ifnet *ifp, struct mbuf *m);
214 static  int sixlowpan_ioctl(ifnet_t ifp, u_long cmd, void *addr);
215 static  int sixlowpan_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode,
216     bpf_packet_func func);
217 static  int sixlowpan_attach_protocol(struct ifnet *ifp);
218 static  int sixlowpan_detach_protocol(struct ifnet *ifp);
219 static  int sixlowpan_unconfig(if6lpan_ref ifl);
220 static  int sixlowpan_config(struct ifnet *ifp, struct ifnet *p);
221 static  void sixlowpan_if_free(struct ifnet *ifp);
222 static  int sixlowpan_remove(if6lpan_ref ifl);
223 static  int sixlowpan_framer_extended(struct ifnet *ifp, struct mbuf **m,
224     const struct sockaddr *ndest, const char *edst,
225     const char *ether_type, u_int32_t *prepend_len, u_int32_t *postpend_len);
226 
227 #define SIXLOWPAN_MAXUNIT       IF_MAXUNIT
228 #define SIXLOWPAN_ZONE_MAX_ELEM MIN(IFNETS_MAX, SIXLOWPAN_MAXUNIT)
229 
230 static struct if_clone sixlowpan_cloner = IF_CLONE_INITIALIZER(SIXLOWPANNAME,
231     sixlowpan_clone_create,
232     sixlowpan_clone_destroy,
233     0,
234     SIXLOWPAN_MAXUNIT,
235     SIXLOWPAN_ZONE_MAX_ELEM,
236     sizeof(struct if6lpan));
237 
238 /**
239 ** if6lpan_ref routines
240 **/
241 static void
if6lpan_retain(if6lpan_ref ifl)242 if6lpan_retain(if6lpan_ref ifl)
243 {
244 	if (ifl->if6lpan_signature != IF6LPAN_SIGNATURE) {
245 		panic("if6lpan_retain: bad signature");
246 	}
247 	if (ifl->if6lpan_retain_count == 0) {
248 		panic("if6lpan_retain: retain count is 0");
249 	}
250 	OSIncrementAtomic(&ifl->if6lpan_retain_count);
251 }
252 
253 static void
if6lpan_release(if6lpan_ref ifl)254 if6lpan_release(if6lpan_ref ifl)
255 {
256 	u_int32_t old_retain_count;
257 
258 	if (ifl->if6lpan_signature != IF6LPAN_SIGNATURE) {
259 		panic("if6lpan_release: bad signature");
260 	}
261 	old_retain_count = OSDecrementAtomic(&ifl->if6lpan_retain_count);
262 	switch (old_retain_count) {
263 	case 0:
264 		panic("if6lpan_release: retain count is 0");
265 		break;
266 	case 1:
267 		ifl->if6lpan_signature = 0;
268 		if_clone_softc_deallocate(&sixlowpan_cloner, ifl);
269 		break;
270 	default:
271 		break;
272 	}
273 	return;
274 }
275 
276 static if6lpan_ref
ifnet_get_if6lpan(struct ifnet * ifp)277 ifnet_get_if6lpan(struct ifnet * ifp)
278 {
279 	if6lpan_ref             ifl;
280 
281 	ifl = (if6lpan_ref)ifnet_softc(ifp);
282 	return ifl;
283 }
284 
285 static if6lpan_ref
ifnet_get_if6lpan_retained(struct ifnet * ifp)286 ifnet_get_if6lpan_retained(struct ifnet * ifp)
287 {
288 	if6lpan_ref             ifl;
289 
290 	ifl = ifnet_get_if6lpan(ifp);
291 	if (ifl == NULL) {
292 		return NULL;
293 	}
294 	if (if6lpan_flags_detaching(ifl)) {
295 		return NULL;
296 	}
297 	if6lpan_retain(ifl);
298 	return ifl;
299 }
300 
301 static int
sixlowpan_clone_attach(void)302 sixlowpan_clone_attach(void)
303 {
304 	int error;
305 
306 	error = if_clone_attach(&sixlowpan_cloner);
307 	if (error != 0) {
308 		return error;
309 	}
310 	return 0;
311 }
312 
313 static int
sixlowpan_demux(__unused ifnet_t ifp,__unused mbuf_t m,__unused char * frame_header,protocol_family_t * protocol_family)314 sixlowpan_demux(
315 	__unused ifnet_t ifp,
316 	__unused mbuf_t m,
317 	__unused char *frame_header,
318 	protocol_family_t *protocol_family)
319 {
320 	*protocol_family = PF_INET6;
321 	return 0;
322 }
323 
324 static errno_t
sixlowpan_add_proto(__unused ifnet_t interface,protocol_family_t protocol,__unused const struct ifnet_demux_desc * demux_array,__unused u_int32_t demux_count)325 sixlowpan_add_proto(__unused ifnet_t interface, protocol_family_t protocol,
326     __unused const struct ifnet_demux_desc *demux_array,
327     __unused u_int32_t demux_count)
328 {
329 	if (protocol == PF_INET6) {
330 		return 0;
331 	}
332 	return ENOPROTOOPT;
333 }
334 
335 static errno_t
sixlowpan_del_proto(__unused ifnet_t interface,__unused protocol_family_t protocol)336 sixlowpan_del_proto(__unused ifnet_t interface, __unused protocol_family_t protocol)
337 {
338 	return 0;
339 }
340 
341 static int
sixlowpan_clone_create(struct if_clone * ifc,u_int32_t unit,__unused void * params)342 sixlowpan_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params)
343 {
344 	int                             error;
345 	if6lpan_ref                     ifl;
346 	ifnet_t                         ifp;
347 	struct ifnet_init_eparams       if_epraram;
348 
349 	ifl = if_clone_softc_allocate(&sixlowpan_cloner);
350 	if (ifl == NULL) {
351 		return ENOBUFS;
352 	}
353 	ifl->if6lpan_retain_count = 1;
354 	ifl->if6lpan_signature = IF6LPAN_SIGNATURE;
355 
356 	/* use the interface name as the unique id for ifp recycle */
357 	if ((unsigned int)
358 	    snprintf(ifl->if6lpan_name, sizeof(ifl->if6lpan_name), "%s%d",
359 	    ifc->ifc_name, unit) >= sizeof(ifl->if6lpan_name)) {
360 		if6lpan_release(ifl);
361 		return EINVAL;
362 	}
363 
364 	bzero(&if_epraram, sizeof(if_epraram));
365 	if_epraram.ver = IFNET_INIT_CURRENT_VERSION;
366 	if_epraram.len = sizeof(if_epraram);
367 	if_epraram.flags = IFNET_INIT_LEGACY;
368 	if_epraram.uniqueid = ifl->if6lpan_name;
369 	if_epraram.uniqueid_len = (uint32_t)strlen(ifl->if6lpan_name);
370 	if_epraram.name = ifc->ifc_name;
371 	if_epraram.unit = unit;
372 	if_epraram.family = IFNET_FAMILY_6LOWPAN;
373 	if_epraram.type = IFT_6LOWPAN;
374 	if_epraram.output = sixlowpan_output;
375 	if_epraram.demux = sixlowpan_demux;
376 	if_epraram.add_proto = sixlowpan_add_proto;
377 	if_epraram.del_proto = sixlowpan_del_proto;
378 	if_epraram.framer_extended = sixlowpan_framer_extended;
379 	if_epraram.softc = ifl;
380 	if_epraram.ioctl = sixlowpan_ioctl;
381 	if_epraram.set_bpf_tap = sixlowpan_set_bpf_tap;
382 	if_epraram.detach = sixlowpan_if_free;
383 	error = ifnet_allocate_extended(&if_epraram, &ifp);
384 
385 	if (error) {
386 		if6lpan_release(ifl);
387 		return error;
388 	}
389 
390 	ifnet_set_offload(ifp, 0);
391 	ifnet_set_addrlen(ifp, IEEE802154_ADDR_LEN);
392 	ifnet_set_baudrate(ifp, 0);
393 	// TODO: ifnet_set_hdrlen(ifp, IEEE802154_ENCAP_LEN);
394 
395 	error = ifnet_attach(ifp, NULL);
396 	if (error) {
397 		ifnet_release(ifp);
398 		if6lpan_release(ifl);
399 		return error;
400 	}
401 	ifl->if6lpan_ifp = ifp;
402 
403 	p_6lowpan_ifnet = ifp;
404 	/* TODO:  attach as IEEE 802.15.4 with no FCS */
405 	bpfattach(ifp, DLT_IEEE802_15_4_NOFCS, IEEE802154_ENCAP_LEN);
406 	return 0;
407 }
408 
409 static int
sixlowpan_remove(if6lpan_ref ifl)410 sixlowpan_remove(if6lpan_ref ifl)
411 {
412 	sixlowpan_assert_lock_held();
413 	if (if6lpan_flags_detaching(ifl)) {
414 		return 0;
415 	}
416 	if6lpan_flags_set_detaching(ifl);
417 	sixlowpan_unconfig(ifl);
418 	return 1;
419 }
420 
421 
422 static int
sixlowpan_clone_destroy(struct ifnet * ifp)423 sixlowpan_clone_destroy(struct ifnet *ifp)
424 {
425 	if6lpan_ref ifl;
426 
427 	sixlowpan_lock();
428 	ifl = ifnet_get_if6lpan_retained(ifp);
429 	if (ifl == NULL) {
430 		sixlowpan_unlock();
431 		return 0;
432 	}
433 	if (sixlowpan_remove(ifl) == 0) {
434 		sixlowpan_unlock();
435 		if6lpan_release(ifl);
436 		return 0;
437 	}
438 	sixlowpan_unlock();
439 	if6lpan_release(ifl);
440 	ifnet_detach(ifp);
441 	p_6lowpan_ifnet = NULL;
442 	return 0;
443 }
444 
445 static int
sixlowpan_set_bpf_tap(ifnet_t ifp,bpf_tap_mode mode,bpf_packet_func func)446 sixlowpan_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, bpf_packet_func func)
447 {
448 	if6lpan_ref     ifl;
449 
450 	sixlowpan_lock();
451 	ifl = ifnet_get_if6lpan_retained(ifp);
452 	if (ifl == NULL) {
453 		sixlowpan_unlock();
454 		return ENODEV;
455 	}
456 	switch (mode) {
457 	case BPF_TAP_DISABLE:
458 		ifl->if6lpan_bpf_input = ifl->if6lpan_bpf_output = NULL;
459 		break;
460 
461 	case BPF_TAP_INPUT:
462 		ifl->if6lpan_bpf_input = func;
463 		break;
464 
465 	case BPF_TAP_OUTPUT:
466 		ifl->if6lpan_bpf_output = func;
467 		break;
468 
469 	case BPF_TAP_INPUT_OUTPUT:
470 		ifl->if6lpan_bpf_input = ifl->if6lpan_bpf_output = func;
471 		break;
472 	default:
473 		break;
474 	}
475 	sixlowpan_unlock();
476 	if6lpan_release(ifl);
477 	return 0;
478 }
479 
480 /*
481  * 6lowpan output routine.
482  * Header compression on the protocol payload
483  * Frame the compressed payload in 802.15.4 Data Frame
484  * Encapsulate the 802.15.4 frame in an Ethernet frame.
485  */
486 static int
sixlowpan_output(struct ifnet * ifp,struct mbuf * m)487 sixlowpan_output(struct ifnet * ifp, struct mbuf * m)
488 {
489 	struct ifnet            *p_intf = NULL;
490 	if6lpan_ref             ifl = NULL;
491 	struct flowadv          adv = { .code = FADV_SUCCESS };
492 	int                     err = 0;
493 	char                    link_layer_dest[ETHER_ADDR_LEN];
494 	bpf_packet_func         bpf_func;
495 
496 	u_int16_t ethertype = htons(ETHERTYPE_IEEE802154);
497 	memset(link_layer_dest, 0xff, ETHER_ADDR_LEN);
498 
499 	if (m == 0) {
500 		return 0;
501 	}
502 	if ((m->m_flags & M_PKTHDR) == 0) {
503 		m_freem_list(m);
504 		return 0;
505 	}
506 
507 	sixlowpan_lock();
508 	ifl = ifnet_get_if6lpan_retained(ifp);
509 
510 	if (ifl == NULL || if6lpan_flags_ready(ifl) == 0) {
511 		goto unlock_done;
512 	}
513 
514 	/* XXX parent interface equivalent? */
515 	p_intf = ifl->if6lpan_pifp;
516 	bpf_func = ifl->if6lpan_bpf_output;
517 
518 	sixlowpan_unlock();
519 	if6lpan_release(ifl);
520 
521 	(void)ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
522 
523 	/*
524 	 * We added a 2 byte length before the 802.15.4 data frame
525 	 * We can play just with the length of the first mbuf in the
526 	 * chain because bpf_tap_imp() disregards the packet length
527 	 * of the mbuf packet header.
528 	 */
529 	if (bpf_func && (mbuf_setdata(m, m->m_data + 2, m->m_len - 2) == 0)) {
530 		bpf_func(ifp, m);
531 		mbuf_setdata(m, m->m_data - 2, m->m_len + 2);
532 	}
533 
534 	/* Append ethernet header */
535 	if ((err = ether_frameout_extended(p_intf, &m, NULL,
536 	    link_layer_dest, (const char *)&ethertype,
537 	    NULL, NULL))) {
538 		return err;
539 	}
540 
541 	err = dlil_output(p_intf, PF_802154, m, NULL, NULL, 1, &adv);
542 
543 	if (err == 0) {
544 		if (adv.code == FADV_FLOW_CONTROLLED) {
545 			err = EQFULL;
546 		} else if (adv.code == FADV_SUSPENDED) {
547 			err = EQSUSPENDED;
548 		}
549 	}
550 	return err;
551 
552 unlock_done:
553 	sixlowpan_unlock();
554 	if (ifl != NULL) {
555 		if6lpan_release(ifl);
556 	}
557 	m_freem(m);
558 	return err;
559 }
560 
561 /*
562  * 6lowpan input routine.
563  * Decapsulate the 802.15.4 Data Frame
564  * Header decompression on the payload
565  * Pass the mbuf to the IPV6 protocol stack using proto_input()
566  */
567 static int
sixlowpan_input(ifnet_t p,__unused protocol_family_t protocol,mbuf_t m,__unused char * frame_header)568 sixlowpan_input(ifnet_t p, __unused protocol_family_t protocol,
569     mbuf_t m, __unused char *frame_header)
570 {
571 	frame802154_t      ieee02154hdr;
572 	u_int8_t           *payload = NULL;
573 	if6lpan_ref        ifl = NULL;
574 	bpf_packet_func    bpf_func;
575 	mbuf_t mc, m_temp;
576 	int off, err = 0;
577 	u_int16_t len;
578 
579 	/* Allocate an mbuf cluster for the 802.15.4 frame and uncompressed payload */
580 	mc = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
581 	if (mc == NULL) {
582 		err = -1;
583 		goto err_out;
584 	}
585 
586 	memcpy(&len, mtod(m, u_int8_t *), sizeof(u_int16_t));
587 	len = ntohs(len);
588 	m_adj(m, sizeof(u_int16_t));
589 	/* Copy the compressed 802.15.4 payload from source mbuf to allocated cluster mbuf */
590 	for (m_temp = m, off = 0; m_temp != NULL; m_temp = m_temp->m_next) {
591 		if (m_temp->m_len > 0) {
592 			m_copyback(mc, off, m_temp->m_len, mtod(m_temp, void *));
593 			off += m_temp->m_len;
594 		}
595 	}
596 
597 	p = p_6lowpan_ifnet;
598 	mc->m_pkthdr.rcvif = p;
599 	if (len > mc->m_pkthdr.len || len > MCLBYTES) {
600 		err = -1;
601 		goto err_out;
602 	}
603 
604 	sixlowpan_lock();
605 	ifl = ifnet_get_if6lpan_retained(p);
606 
607 	if (ifl == NULL) {
608 		sixlowpan_unlock();
609 		err = -1;
610 		goto err_out;
611 	}
612 
613 	if (if6lpan_flags_ready(ifl) == 0) {
614 		if6lpan_release(ifl);
615 		sixlowpan_unlock();
616 		err = -1;
617 		goto err_out;
618 	}
619 
620 	bpf_func = ifl->if6lpan_bpf_input;
621 	sixlowpan_unlock();
622 	if6lpan_release(ifl);
623 
624 	if (bpf_func) {
625 		bpf_func(p, mc);
626 	}
627 
628 	/* Parse the 802.15.4 frame header */
629 	bzero(&ieee02154hdr, sizeof(ieee02154hdr));
630 	/*
631 	 * Use returned payload pointer to evaluate success
632 	 * vs failure.
633 	 */
634 	(void)frame802154_parse(mtod(mc, uint8_t *), len, &ieee02154hdr, &payload);
635 	if (payload == NULL) {
636 		err = -1;
637 		goto err_out;
638 	}
639 
640 	/* XXX Add check for your link layer address being dest */
641 	if (sixxlowpan_input(&ieee02154hdr, payload) != 0) {
642 		err = -1;
643 		goto err_out;
644 	}
645 
646 	if (mbuf_setdata(mc, payload, ieee02154hdr.payload_len)) {
647 		err = -1;
648 		goto err_out;
649 	}
650 	mbuf_pkthdr_setlen(mc, ieee02154hdr.payload_len);
651 
652 	/* Post decompression */
653 	if (proto_input(PF_INET6, mc) != 0) {
654 		ifnet_stat_increment_in(p, 0, 0, 1);
655 		err = -1;
656 		goto err_out;
657 	} else {
658 		ifnet_stat_increment_in(p, 1, mc->m_pkthdr.len, 0);
659 	}
660 
661 err_out:
662 	if (err && mc) {
663 		m_freem(mc);
664 	}
665 	if (!err) {
666 		m_freem(m);
667 	}
668 	return err;
669 }
670 
671 #define SIXLOWPAN_IFMTU 1280
672 
673 static int
sixlowpan_config(struct ifnet * ifp,struct ifnet * p)674 sixlowpan_config(struct ifnet *ifp, struct ifnet *p)
675 {
676 	if6lpan_ref ifl;
677 	u_int16_t parent_flags;
678 	sixlowpan_lock();
679 	ifl = ifnet_get_if6lpan_retained(ifp);
680 	if (ifl == NULL || ifl->if6lpan_pifp != NULL) {
681 		sixlowpan_unlock();
682 		if (ifl != NULL) {
683 			if6lpan_release(ifl);
684 		}
685 		return EBUSY;
686 	}
687 	sixlowpan_attach_protocol(p);
688 
689 	/* set our LL address derived from that of the parent */
690 	if6lpan_set_addr(ifl, IF_LLADDR(p));
691 	ifnet_set_lladdr_and_type(ifp, ifl->if6lpan_addr, IEEE802154_ADDR_LEN, IFT_6LOWPAN);
692 
693 	ifl->if6lpan_pifp = p;
694 	ifl->if6lpan_flags = 0;
695 	ifnet_set_mtu(ifp, SIXLOWPAN_IFMTU);
696 	parent_flags = ifnet_flags(p) & (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX);
697 	ifnet_set_flags(ifp, parent_flags, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX);
698 	ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
699 	ifnet_set_eflags(ifp, IFEF_NOAUTOIPV6LL, IFEF_NOAUTOIPV6LL);
700 	if6lpan_flags_set_ready(ifl);
701 	if6lpan_release(ifl);
702 	sixlowpan_unlock();
703 	return 0;
704 }
705 
706 static int
sixlowpan_unconfig(if6lpan_ref ifl)707 sixlowpan_unconfig(if6lpan_ref ifl)
708 {
709 	struct ifnet *ifp = ifl->if6lpan_ifp;
710 
711 	sixlowpan_assert_lock_held();
712 	/* Clear our MAC address. */
713 	ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_6LOWPAN);
714 	sixlowpan_detach_protocol(ifl->if6lpan_pifp);
715 	ifnet_set_mtu(ifp, 0);
716 	ifnet_set_flags(ifp, 0,
717 	    IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_RUNNING);
718 	ifnet_set_eflags(ifp, 0, IFEF_NOAUTOIPV6LL);
719 	ifl->if6lpan_flags = 0;
720 
721 	return 0;
722 }
723 
724 static int
sixlowpan_ioctl(ifnet_t ifp,u_long cmd,void * data)725 sixlowpan_ioctl(ifnet_t ifp, u_long cmd, void * data)
726 {
727 	int             error = 0;
728 	struct ifreq *  ifr = NULL;
729 	struct ifnet *  p = NULL;
730 	struct sixlowpanreq req = {};
731 	user_addr_t             user_addr = 0;
732 	if6lpan_ref             ifl = NULL;
733 
734 	if (ifnet_type(ifp) != IFT_6LOWPAN) {
735 		return EOPNOTSUPP;
736 	}
737 	ifr = (struct ifreq *)data;
738 
739 	switch (cmd) {
740 	case SIOCSIFADDR:
741 		ifnet_set_flags(ifp, IFF_UP, IFF_UP);
742 		break;
743 
744 	case SIOCSIF6LOWPAN:
745 		user_addr = proc_is64bit(current_proc()) ?
746 		    CAST_USER_ADDR_T(ifr->ifr_data64) :
747 		    CAST_USER_ADDR_T(ifr->ifr_data);
748 		error = copyin(user_addr, &req, sizeof(req));
749 		req.parent[IFNAMSIZ - 1] = '\0';
750 		if (error) {
751 			break;
752 		}
753 		if (req.parent[0] != '\0') {
754 			p = ifunit(req.parent);
755 			if (p == NULL) {
756 				error = ENXIO;
757 				break;
758 			}
759 			if (ifnet_type(p) != IFT_ETHER
760 			    && ifnet_type(p) != IFT_IEEE8023ADLAG) {
761 				error = EPROTONOSUPPORT;
762 				break;
763 			}
764 			error = sixlowpan_config(ifp, p);
765 			if (error) {
766 				break;
767 			}
768 		}
769 		break;
770 
771 	case SIOCGIF6LOWPAN:
772 		bzero(&req, sizeof req);
773 		sixlowpan_lock();
774 		ifl = (if6lpan_ref)ifnet_softc(ifp);
775 		if (ifl == NULL || if6lpan_flags_detaching(ifl)) {
776 			sixlowpan_unlock();
777 			return ifl == NULL ? EOPNOTSUPP : EBUSY;
778 		}
779 		p = ifl->if6lpan_pifp;
780 		sixlowpan_unlock();
781 		if (p != NULL) {
782 			snprintf(req.parent, sizeof(req.parent),
783 			    "%s%d", ifnet_name(p), ifnet_unit(p));
784 		}
785 		user_addr = proc_is64bit(current_proc()) ?
786 		    CAST_USER_ADDR_T(ifr->ifr_data64) :
787 		    CAST_USER_ADDR_T(ifr->ifr_data);
788 		error = copyout(&req, user_addr, sizeof(req));
789 		break;
790 
791 #ifdef  SIOCSIFMTU /* xxx */
792 	case SIOCGIFMTU:
793 		break;
794 
795 	case SIOCSIFMTU:
796 		ifnet_set_mtu(ifp, ifr->ifr_mtu);
797 		break;
798 #endif /* SIOCSIFMTU */
799 
800 	default:
801 		error = EOPNOTSUPP;
802 	}
803 	return error;
804 }
805 
806 static void
sixlowpan_if_free(struct ifnet * ifp)807 sixlowpan_if_free(struct ifnet * ifp)
808 {
809 	if6lpan_ref     ifl;
810 
811 	if (ifp == NULL) {
812 		return;
813 	}
814 	ifl = (if6lpan_ref)ifnet_softc(ifp);
815 	if (ifl == NULL) {
816 		return;
817 	}
818 	if6lpan_release(ifl);
819 	ifnet_release(ifp);
820 	return;
821 }
822 
823 static errno_t
sixlowpan_detached(ifnet_t p,__unused protocol_family_t protocol)824 sixlowpan_detached(ifnet_t p, __unused protocol_family_t protocol)
825 {
826 	if (ifnet_is_attached(p, 0) == 0) {
827 		// TODO: Find ifp from the parent p
828 		// sixlowpan_if_free(ifp);
829 	}
830 	return 0;
831 }
832 
833 /*
834  * Function: sixlowpan_attach_protocol
835  * Purpose:
836  *   Attach a DLIL protocol to the interface
837  *	 The ethernet demux actually special cases 802.15.4.
838  *	 The demux here isn't used. The demux will return PF_802154 for the
839  *	 appropriate packets and our sixlowpan_input function will be called.
840  */
841 static int
sixlowpan_attach_protocol(struct ifnet * ifp)842 sixlowpan_attach_protocol(struct ifnet *ifp)
843 {
844 	int     error;
845 	struct ifnet_attach_proto_param reg;
846 
847 	bzero(&reg, sizeof(reg));
848 	reg.input            = sixlowpan_input;
849 	reg.detached         = sixlowpan_detached;
850 	error = ifnet_attach_protocol(ifp, PF_802154, &reg);
851 	if (error) {
852 		printf("%s(%s%d) ifnet_attach_protocol failed, %d\n",
853 		    __func__, ifnet_name(ifp), ifnet_unit(ifp), error);
854 	}
855 	return error;
856 }
857 
858 /*
859  * Function: sixlowpan_detach_protocol
860  * Purpose:
861  *   Detach our DLIL protocol from an interface
862  */
863 static int
sixlowpan_detach_protocol(struct ifnet * ifp)864 sixlowpan_detach_protocol(struct ifnet *ifp)
865 {
866 	int error;
867 
868 	error = ifnet_detach_protocol(ifp, PF_802154);
869 	if (error) {
870 		printf("(%s%d) ifnet_detach_protocol failed, %d\n",
871 		    ifnet_name(ifp), ifnet_unit(ifp), error);
872 	}
873 
874 	return error;
875 }
876 
877 static errno_t
sixlowpan_proto_pre_output(ifnet_t ifp,__unused protocol_family_t protocol_family,mbuf_t * m0,const struct sockaddr * dest,void * route,char * type,char * ll_dest)878 sixlowpan_proto_pre_output(ifnet_t ifp,
879     __unused protocol_family_t protocol_family,
880     mbuf_t *m0,
881     const struct sockaddr *dest,
882     void *route,
883     char *type,
884     char *ll_dest)
885 {
886 #pragma unused(protocol_family)
887 	errno_t result = 0;
888 	struct sockaddr_dl sdl = {};
889 	struct sockaddr_in6 *dest6 =  (struct sockaddr_in6 *)(uintptr_t)(size_t)dest;
890 
891 	if (!IN6_IS_ADDR_MULTICAST(&dest6->sin6_addr)) {
892 		result = nd6_lookup_ipv6(ifp, dest6, &sdl, sizeof(sdl), route, *m0);
893 		if (result == 0) {
894 			bcopy(LLADDR(&sdl), ll_dest, sdl.sdl_alen);
895 		}
896 	} else {
897 		/* map multicast address */
898 		ll_dest[0] = (dest6->sin6_addr.s6_addr8[14] & 0x1f) | 0x80;
899 		ll_dest[1] = dest6->sin6_addr.s6_addr8[15];
900 	}
901 
902 	/*
903 	 * XXX This should be generic to the underlying hardware type
904 	 */
905 	if (result == 0) {
906 		u_int16_t ethertype = htons(ETHERTYPE_IEEE802154);
907 		bcopy(&ethertype, type, sizeof(ethertype));
908 	}
909 
910 	return result;
911 }
912 
913 static int
sixlowpan_framer_extended(struct ifnet * ifp,struct mbuf ** m,const struct sockaddr * ndest,const char * edst,const char * ether_type,u_int32_t * prepend_len,u_int32_t * postpend_len)914 sixlowpan_framer_extended(struct ifnet *ifp, struct mbuf **m,
915     const struct sockaddr *ndest, const char *edst,
916     const char *ether_type, u_int32_t *prepend_len, u_int32_t *postpend_len)
917 {
918 #pragma unused(ndest)
919 #pragma unused(ether_type)
920 	char buf[IEEE802154_ENCAP_LEN] = {0};
921 	int buflen = 0, err = 0;
922 	frame802154_t ieee02154hdr;
923 	if6lpan_ref ifl = NULL;
924 	uint8_t *payload = NULL;
925 	struct mbuf *mc = NULL;
926 	uint16_t len;
927 	struct sockaddr_in6 *dest6 =  (struct sockaddr_in6 *)(uintptr_t)(size_t)ndest;
928 
929 	/* Initialize 802.15.4 frame header */
930 	bzero(&ieee02154hdr, sizeof(ieee02154hdr));
931 	if (!IN6_IS_ADDR_MULTICAST(&dest6->sin6_addr)) {
932 		bcopy(edst, ieee02154hdr.dest_addr, sizeof(ieee02154hdr.dest_addr));
933 		ieee02154hdr.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
934 	} else {
935 		bcopy(edst, ieee02154hdr.dest_addr, 2);
936 		ieee02154hdr.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
937 	}
938 
939 	/* Allocate a contiguous buffer for IPv6 header & payload */
940 	/*
941 	 * XXX As of now either we compress or we don't compress at all
942 	 * adding another byte of dispatch to communicate that there's no
943 	 * compression.
944 	 *
945 	 * Allocate for the worst case.
946 	 */
947 	payload = (uint8_t *)kalloc_data(m_pktlen(*m) + 1, Z_WAITOK | Z_ZERO);
948 	if (payload == NULL) {
949 		err = -1;
950 		goto err_out;
951 	}
952 
953 	/* Copy the IPv6 header & payload */
954 	if (mbuf_copydata(*m, 0, m_pktlen(*m), payload)) {
955 		err = -1;
956 		goto err_out;
957 	}
958 
959 	/* Allocate an mbuf cluster for the 802.15.4 frame and compressed payload */
960 	mc = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
961 	if (mc == NULL) {
962 		err = -1;
963 		goto err_out;
964 	}
965 
966 	sixlowpan_lock();
967 	ifl = ifnet_get_if6lpan_retained(ifp);
968 	if (ifl == NULL || if6lpan_flags_ready(ifl) == 0) {
969 		if (ifl != NULL) {
970 			if6lpan_release(ifl);
971 		}
972 		sixlowpan_unlock();
973 		err = -1;
974 		goto err_out;
975 	}
976 	bcopy(ifl->if6lpan_addr, ieee02154hdr.src_addr, sizeof(ieee02154hdr.src_addr));
977 	ieee02154hdr.seq = ifl->if6lpan_ieee802154_seq++;   /**< Sequence number */
978 	if6lpan_release(ifl);
979 	sixlowpan_unlock();
980 
981 	/* Initialize frame control field */
982 	ieee02154hdr.fcf.frame_type = FRAME802154_DATAFRAME;  /**< 3 bit. Frame type field, see 802.15.4 */
983 	ieee02154hdr.fcf.security_enabled = 0;  /**< 1 bit. True if security is used in this frame */
984 	ieee02154hdr.fcf.frame_pending = 0;     /**< 1 bit. True if sender has more data to send */
985 	ieee02154hdr.fcf.ack_required = 0;      /**< 1 bit. Is an ack frame required? */
986 	ieee02154hdr.fcf.panid_compression = 0; /**< 1 bit. Is this a compressed header? */
987 	ieee02154hdr.fcf.frame_version = FRAME802154_IEEE802154_2006; /**< 2 bit. 802.15.4 frame version */
988 	ieee02154hdr.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;    /**< 2 bit. Source address mode, see 802.15.4 */
989 	ieee02154hdr.dest_pid = IEEE802154_PANID;   /**< Destination PAN ID */
990 	ieee02154hdr.src_pid = IEEE802154_PANID;    /**< Source PAN ID */
991 	ieee02154hdr.payload_len = m_pktlen(*m);    /**< Length of payload field */
992 
993 	/* Create an 802.15.4 Data header frame */
994 	buflen = frame802154_create(&ieee02154hdr, (uint8_t *)buf);
995 
996 	/* Perform inline compression of the IPv6 hdr & payload */
997 	sixxlowpan_output(&ieee02154hdr, payload);
998 
999 	/*
1000 	 * Add 2 bytes at the front of the frame indicating the total payload
1001 	 * length
1002 	 */
1003 	len = htons((uint16_t)(buflen + ieee02154hdr.payload_len));
1004 	m_copyback(mc, 0, sizeof(len), &len);
1005 	/* Copy back the 802.15.4 Data frame header into mbuf */
1006 	m_copyback(mc, sizeof(len), buflen, buf);
1007 	/* Copy back the compressed payload into mbuf */
1008 	m_copyback(mc, buflen + sizeof(len), ieee02154hdr.payload_len, payload);
1009 
1010 	if (prepend_len != NULL) {
1011 		*prepend_len = buflen;
1012 	}
1013 	if (postpend_len != NULL) {
1014 		*postpend_len = 0;
1015 	}
1016 
1017 err_out:
1018 	if (payload != NULL) {
1019 		kfree_data(payload, m_pktlen(*m) + 1);
1020 	}
1021 	m_freem(*m);
1022 	*m = mc;
1023 	return err;
1024 }
1025 
1026 
1027 static errno_t
sixlowpan_attach_inet6(struct ifnet * ifp,protocol_family_t protocol_family)1028 sixlowpan_attach_inet6(struct ifnet *ifp, protocol_family_t protocol_family)
1029 {
1030 	struct ifnet_attach_proto_param proto;
1031 	errno_t error;
1032 
1033 	bzero(&proto, sizeof(proto));
1034 	proto.pre_output = sixlowpan_proto_pre_output;
1035 
1036 	error = ifnet_attach_protocol(ifp, protocol_family, &proto);
1037 	if (error && error != EEXIST) {
1038 		printf("WARNING: %s can't attach ipv6 to %s\n", __func__,
1039 		    if_name(ifp));
1040 	}
1041 	return error;
1042 }
1043 
1044 static void
sixlowpan_detach_inet6(struct ifnet * ifp,protocol_family_t protocol_family)1045 sixlowpan_detach_inet6(struct ifnet *ifp, protocol_family_t protocol_family)
1046 {
1047 	(void) ifnet_detach_protocol(ifp, protocol_family);
1048 }
1049 
1050 __private_extern__ int
sixlowpan_family_init(void)1051 sixlowpan_family_init(void)
1052 {
1053 	int error = 0;
1054 
1055 	error = proto_register_plumber(PF_INET6, IFNET_FAMILY_6LOWPAN,
1056 	    sixlowpan_attach_inet6, sixlowpan_detach_inet6);
1057 	if (error != 0) {
1058 		printf("6lowpan: proto_register_plumber failed for AF_INET6 error=%d\n",
1059 		    error);
1060 		goto done;
1061 	}
1062 
1063 	error = sixlowpan_clone_attach();
1064 	if (error != 0) {
1065 		printf("6lowpan: proto_register_plumber failed sixlowpan_clone_attach error=%d\n",
1066 		    error);
1067 		goto done;
1068 	}
1069 
1070 
1071 done:
1072 	return error;
1073 }
1074