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