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 *)ðertype,
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(®, sizeof(reg));
848 reg.input = sixlowpan_input;
849 reg.detached = sixlowpan_detached;
850 error = ifnet_attach_protocol(ifp, PF_802154, ®);
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(ðertype, 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