]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_6lowpan.c
xnu-6153.11.26.tar.gz
[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 = 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
637 sixlowpan_lock();
638 ifl = ifnet_get_if6lpan_retained(p);
639
640 if (ifl == NULL) {
641 sixlowpan_unlock();
642 err = -1;
643 goto err_out;
644 }
645
646 if (if6lpan_flags_ready(ifl) == 0) {
647 if6lpan_release(ifl);
648 sixlowpan_unlock();
649 err = -1;
650 goto err_out;
651 }
652
653 bpf_func = ifl->if6lpan_bpf_input;
654 sixlowpan_unlock();
655 if6lpan_release(ifl);
656
657 if (bpf_func) {
658 bpf_func(p, mc);
659 }
660
661 /* Parse the 802.15.4 frame header */
662 bzero(&ieee02154hdr, sizeof(ieee02154hdr));
663 frame802154_parse(mtod(mc, uint8_t *), len, &ieee02154hdr, &payload);
664
665 /* XXX Add check for your link layer address being dest */
666 sixxlowpan_input(&ieee02154hdr, payload);
667
668 if (mbuf_setdata(mc, payload, ieee02154hdr.payload_len)) {
669 err = -1;
670 goto err_out;
671 }
672 mbuf_pkthdr_setlen(mc, ieee02154hdr.payload_len);
673
674 /* Post decompression */
675 if (proto_input(PF_INET6, mc) != 0) {
676 ifnet_stat_increment_in(p, 0, 0, 1);
677 err = -1;
678 goto err_out;
679 } else {
680 ifnet_stat_increment_in(p, 1, mc->m_pkthdr.len, 0);
681 }
682
683 err_out:
684 if (err && mc) {
685 m_freem(mc);
686 }
687 if (!err) {
688 m_freem(m);
689 }
690 return err;
691 }
692
693 #define SIXLOWPAN_IFMTU 1280
694
695 static int
696 sixlowpan_config(struct ifnet *ifp, struct ifnet *p)
697 {
698 if6lpan_ref ifl;
699 u_int16_t parent_flags;
700 sixlowpan_lock();
701 ifl = ifnet_get_if6lpan_retained(ifp);
702 if (ifl == NULL || ifl->if6lpan_pifp != NULL) {
703 sixlowpan_unlock();
704 if (ifl != NULL) {
705 if6lpan_release(ifl);
706 }
707 return EBUSY;
708 }
709 sixlowpan_attach_protocol(p);
710
711 /* set our LL address derived from that of the parent */
712 if6lpan_set_addr(ifl, IF_LLADDR(p));
713 ifnet_set_lladdr_and_type(ifp, ifl->if6lpan_addr, IEEE802154_ADDR_LEN, IFT_6LOWPAN);
714
715 ifl->if6lpan_pifp = p;
716 ifl->if6lpan_flags = 0;
717 ifnet_set_mtu(ifp, SIXLOWPAN_IFMTU);
718 parent_flags = ifnet_flags(p) & (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX);
719 ifnet_set_flags(ifp, parent_flags, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX);
720 ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
721 ifnet_set_eflags(ifp, IFEF_NOAUTOIPV6LL, IFEF_NOAUTOIPV6LL);
722 if6lpan_flags_set_ready(ifl);
723 if6lpan_release(ifl);
724 sixlowpan_unlock();
725 return 0;
726 }
727
728 static int
729 sixlowpan_unconfig(if6lpan_ref ifl)
730 {
731 struct ifnet *ifp = ifl->if6lpan_ifp;
732
733 sixlowpan_assert_lock_held();
734 /* Clear our MAC address. */
735 ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_6LOWPAN);
736 sixlowpan_detach_protocol(ifl->if6lpan_pifp);
737 ifnet_set_mtu(ifp, 0);
738 ifnet_set_flags(ifp, 0,
739 IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_RUNNING);
740 ifnet_set_eflags(ifp, 0, IFEF_NOAUTOIPV6LL);
741 ifl->if6lpan_flags = 0;
742
743 return 0;
744 }
745
746 static int
747 sixlowpan_ioctl(ifnet_t ifp, u_long cmd, void * data)
748 {
749 int error = 0;
750 struct ifreq * ifr = NULL;
751 struct ifnet * p = NULL;
752 struct sixlowpanreq req = {};
753 user_addr_t user_addr = 0;
754 if6lpan_ref ifl = NULL;
755
756 if (ifnet_type(ifp) != IFT_6LOWPAN) {
757 return EOPNOTSUPP;
758 }
759 ifr = (struct ifreq *)data;
760
761 switch (cmd) {
762 case SIOCSIFADDR:
763 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
764 break;
765
766 case SIOCSIF6LOWPAN:
767 user_addr = proc_is64bit(current_proc())
768 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
769 error = copyin(user_addr, &req, sizeof(req));
770 req.parent[IFNAMSIZ - 1] = '\0';
771 if (error) {
772 break;
773 }
774 if (req.parent[0] != '\0') {
775 p = ifunit(req.parent);
776 if (p == NULL) {
777 error = ENXIO;
778 break;
779 }
780 if (ifnet_type(p) != IFT_ETHER
781 && ifnet_type(p) != IFT_IEEE8023ADLAG) {
782 error = EPROTONOSUPPORT;
783 break;
784 }
785 error = sixlowpan_config(ifp, p);
786 if (error) {
787 break;
788 }
789 }
790 break;
791
792 case SIOCGIF6LOWPAN:
793 bzero(&req, sizeof req);
794 sixlowpan_lock();
795 ifl = (if6lpan_ref)ifnet_softc(ifp);
796 if (ifl == NULL || if6lpan_flags_detaching(ifl)) {
797 sixlowpan_unlock();
798 return ifl == NULL ? EOPNOTSUPP : EBUSY;
799 }
800 p = ifl->if6lpan_pifp;
801 sixlowpan_unlock();
802 if (p != NULL) {
803 snprintf(req.parent, sizeof(req.parent),
804 "%s%d", ifnet_name(p), ifnet_unit(p));
805 }
806 user_addr = proc_is64bit(current_proc())
807 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
808 error = copyout(&req, user_addr, sizeof(req));
809 break;
810
811 #ifdef SIOCSIFMTU /* xxx */
812 case SIOCGIFMTU:
813 break;
814
815 case SIOCSIFMTU:
816 ifnet_set_mtu(ifp, ifr->ifr_mtu);
817 break;
818 #endif /* SIOCSIFMTU */
819
820 default:
821 error = EOPNOTSUPP;
822 }
823 return error;
824 }
825
826 static void
827 sixlowpan_if_free(struct ifnet * ifp)
828 {
829 if6lpan_ref ifl;
830
831 if (ifp == NULL) {
832 return;
833 }
834 ifl = (if6lpan_ref)ifnet_softc(ifp);
835 if (ifl == NULL) {
836 return;
837 }
838 if6lpan_release(ifl);
839 ifnet_release(ifp);
840 return;
841 }
842
843 static errno_t
844 sixlowpan_detached(ifnet_t p, __unused protocol_family_t protocol)
845 {
846 if (ifnet_is_attached(p, 0) == 0) {
847 // TODO: Find ifp from the parent p
848 // sixlowpan_if_free(ifp);
849 }
850 return 0;
851 }
852
853 /*
854 * Function: sixlowpan_attach_protocol
855 * Purpose:
856 * Attach a DLIL protocol to the interface
857 * The ethernet demux actually special cases 802.15.4.
858 * The demux here isn't used. The demux will return PF_802154 for the
859 * appropriate packets and our sixlowpan_input function will be called.
860 */
861 static int
862 sixlowpan_attach_protocol(struct ifnet *ifp)
863 {
864 int error;
865 struct ifnet_attach_proto_param reg;
866
867 bzero(&reg, sizeof(reg));
868 reg.input = sixlowpan_input;
869 reg.detached = sixlowpan_detached;
870 error = ifnet_attach_protocol(ifp, PF_802154, &reg);
871 if (error) {
872 printf("%s(%s%d) ifnet_attach_protocol failed, %d\n",
873 __func__, ifnet_name(ifp), ifnet_unit(ifp), error);
874 }
875 return error;
876 }
877
878 /*
879 * Function: sixlowpan_detach_protocol
880 * Purpose:
881 * Detach our DLIL protocol from an interface
882 */
883 static int
884 sixlowpan_detach_protocol(struct ifnet *ifp)
885 {
886 int error;
887
888 error = ifnet_detach_protocol(ifp, PF_802154);
889 if (error) {
890 printf("(%s%d) ifnet_detach_protocol failed, %d\n",
891 ifnet_name(ifp), ifnet_unit(ifp), error);
892 }
893
894 return error;
895 }
896
897 static errno_t
898 sixlowpan_proto_pre_output(ifnet_t ifp,
899 __unused protocol_family_t protocol_family,
900 mbuf_t *m0,
901 const struct sockaddr *dest,
902 void *route,
903 char *type,
904 char *ll_dest)
905 {
906 #pragma unused(protocol_family)
907 errno_t result = 0;
908 struct sockaddr_dl sdl;
909 struct sockaddr_in6 *dest6 = (struct sockaddr_in6 *)(uintptr_t)(size_t)dest;
910
911 if (!IN6_IS_ADDR_MULTICAST(&dest6->sin6_addr)) {
912 result = nd6_lookup_ipv6(ifp, dest6, &sdl, sizeof(sdl), route, *m0);
913 if (result == 0) {
914 bcopy(LLADDR(&sdl), ll_dest, sdl.sdl_alen);
915 }
916 } else {
917 /* map multicast address */
918 ll_dest[0] = (dest6->sin6_addr.s6_addr8[14] & 0x1f) | 0x80;
919 ll_dest[1] = dest6->sin6_addr.s6_addr8[15];
920 }
921
922 /*
923 * XXX This should be generic to the underlying hardware type
924 */
925 if (result == 0) {
926 u_int16_t ethertype = htons(ETHERTYPE_IEEE802154);
927 bcopy(&ethertype, type, sizeof(ethertype));
928 }
929
930 return result;
931 }
932
933 static int
934 sixlowpan_framer_extended(struct ifnet *ifp, struct mbuf **m,
935 const struct sockaddr *ndest, const char *edst,
936 const char *ether_type, u_int32_t *prepend_len, u_int32_t *postpend_len)
937 {
938 #pragma unused(ndest)
939 #pragma unused(ether_type)
940 char buf[IEEE802154_ENCAP_LEN] = {0};
941 int buflen = 0, err = 0;
942 frame802154_t ieee02154hdr;
943 if6lpan_ref ifl = NULL;
944 u_int8_t *payload = NULL;
945 struct mbuf *mc = NULL;
946 u_int16_t len;
947 struct sockaddr_in6 *dest6 = (struct sockaddr_in6 *)(uintptr_t)(size_t)ndest;
948
949 /* Initialize 802.15.4 frame header */
950 bzero(&ieee02154hdr, sizeof(ieee02154hdr));
951 if (!IN6_IS_ADDR_MULTICAST(&dest6->sin6_addr)) {
952 bcopy(edst, ieee02154hdr.dest_addr, sizeof(ieee02154hdr.dest_addr));
953 ieee02154hdr.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
954 } else {
955 bcopy(edst, ieee02154hdr.dest_addr, 2);
956 ieee02154hdr.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
957 }
958
959 /* Allocate a contiguous buffer for IPv6 header & payload */
960 /*
961 * XXX As of now either we compress or we don't compress at all
962 * adding another byte of dispatch to communicate that there's no
963 * compression.
964 *
965 * Allocate for the worst case.
966 */
967 payload = _MALLOC(m_pktlen(*m) + 1, M_TEMP, M_WAITOK | M_ZERO);
968 if (payload == NULL) {
969 err = -1;
970 goto err_out;
971 }
972
973 /* Copy the IPv6 header & payload */
974 if (mbuf_copydata(*m, 0, m_pktlen(*m), payload)) {
975 err = -1;
976 goto err_out;
977 }
978
979 /* Allocate an mbuf cluster for the 802.15.4 frame and compressed payload */
980 mc = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
981 if (mc == NULL) {
982 err = -1;
983 goto err_out;
984 }
985
986 sixlowpan_lock();
987 ifl = ifnet_get_if6lpan_retained(ifp);
988 if (ifl == NULL || if6lpan_flags_ready(ifl) == 0) {
989 if (ifl != NULL) {
990 if6lpan_release(ifl);
991 }
992 sixlowpan_unlock();
993 err = -1;
994 goto err_out;
995 }
996 bcopy(ifl->if6lpan_addr, ieee02154hdr.src_addr, sizeof(ieee02154hdr.src_addr));
997 ieee02154hdr.seq = ifl->if6lpan_ieee802154_seq++; /**< Sequence number */
998 if6lpan_release(ifl);
999 sixlowpan_unlock();
1000
1001 /* Initialize frame control field */
1002 ieee02154hdr.fcf.frame_type = FRAME802154_DATAFRAME; /**< 3 bit. Frame type field, see 802.15.4 */
1003 ieee02154hdr.fcf.security_enabled = 0; /**< 1 bit. True if security is used in this frame */
1004 ieee02154hdr.fcf.frame_pending = 0; /**< 1 bit. True if sender has more data to send */
1005 ieee02154hdr.fcf.ack_required = 0; /**< 1 bit. Is an ack frame required? */
1006 ieee02154hdr.fcf.panid_compression = 0; /**< 1 bit. Is this a compressed header? */
1007 ieee02154hdr.fcf.frame_version = FRAME802154_IEEE802154_2006; /**< 2 bit. 802.15.4 frame version */
1008 ieee02154hdr.fcf.src_addr_mode = FRAME802154_LONGADDRMODE; /**< 2 bit. Source address mode, see 802.15.4 */
1009 ieee02154hdr.dest_pid = IEEE802154_PANID; /**< Destination PAN ID */
1010 ieee02154hdr.src_pid = IEEE802154_PANID; /**< Source PAN ID */
1011 ieee02154hdr.payload_len = m_pktlen(*m); /**< Length of payload field */
1012
1013 /* Create an 802.15.4 Data header frame */
1014 buflen = frame802154_create(&ieee02154hdr, (uint8_t *)buf);
1015
1016 /* Perform inline compression of the IPv6 hdr & payload */
1017 sixxlowpan_output(&ieee02154hdr, payload);
1018
1019 /*
1020 * Add 2 bytes at the front of the frame indicating the total payload
1021 * length
1022 */
1023 len = htons(buflen + ieee02154hdr.payload_len);
1024 m_copyback(mc, 0, sizeof(len), &len);
1025 /* Copy back the 802.15.4 Data frame header into mbuf */
1026 m_copyback(mc, sizeof(len), buflen, buf);
1027 /* Copy back the compressed payload into mbuf */
1028 m_copyback(mc, buflen + sizeof(len), ieee02154hdr.payload_len, payload);
1029
1030 if (prepend_len != NULL) {
1031 *prepend_len = buflen;
1032 }
1033 if (postpend_len != NULL) {
1034 *postpend_len = 0;
1035 }
1036
1037 err_out:
1038 if (payload != NULL) {
1039 _FREE(payload, M_TEMP);
1040 }
1041 m_freem(*m);
1042 *m = mc;
1043 return err;
1044 }
1045
1046
1047 static errno_t
1048 sixlowpan_attach_inet6(struct ifnet *ifp, protocol_family_t protocol_family)
1049 {
1050 struct ifnet_attach_proto_param proto;
1051 errno_t error;
1052
1053 bzero(&proto, sizeof(proto));
1054 proto.pre_output = sixlowpan_proto_pre_output;
1055
1056 error = ifnet_attach_protocol(ifp, protocol_family, &proto);
1057 if (error && error != EEXIST) {
1058 printf("WARNING: %s can't attach ipv6 to %s\n", __func__,
1059 if_name(ifp));
1060 }
1061 return error;
1062 }
1063
1064 static void
1065 sixlowpan_detach_inet6(struct ifnet *ifp, protocol_family_t protocol_family)
1066 {
1067 (void) ifnet_detach_protocol(ifp, protocol_family);
1068 }
1069
1070 #if INET6
1071 __private_extern__ int
1072 sixlowpan_family_init(void)
1073 {
1074 int error = 0;
1075
1076 error = proto_register_plumber(PF_INET6, IFNET_FAMILY_6LOWPAN,
1077 sixlowpan_attach_inet6, sixlowpan_detach_inet6);
1078 if (error != 0) {
1079 printf("6lowpan: proto_register_plumber failed for AF_INET6 error=%d\n",
1080 error);
1081 goto done;
1082 }
1083
1084 error = sixlowpan_clone_attach();
1085 if (error != 0) {
1086 printf("6lowpan: proto_register_plumber failed sixlowpan_clone_attach error=%d\n",
1087 error);
1088 goto done;
1089 }
1090
1091
1092 done:
1093 return error;
1094 }
1095 #endif