2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright 1998 Massachusetts Institute of Technology
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
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
58 * if_6lowpan.c - pseudo-device driver for IEEE 802.15.4 .
60 #include <sys/param.h>
61 #include <sys/kernel.h>
62 #include <sys/malloc.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>
73 #include <net/ethernet.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>
86 #include <net/kpi_interface.h>
87 #include <net/kpi_protocol.h>
89 #include <kern/locks.h>
92 #include <netinet/in.h>
93 #include <netinet/if_ether.h>
96 #include <net/if_media.h>
97 #include <net/multicast_list.h>
98 #include <net/ether_if_module.h>
100 #define SIXLOWPANNAME "6lowpan"
102 struct ifnet
*p_6lowpan_ifnet
= NULL
;
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
);
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
);
112 static __inline__ lck_grp_t
*
113 my_lck_grp_alloc_init(const char * grp_name
)
116 lck_grp_attr_t
* grp_attrs
;
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
);
124 static __inline__ lck_mtx_t
*
125 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
127 lck_attr_t
* lck_attrs
;
130 lck_attrs
= lck_attr_alloc_init();
131 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
132 lck_attr_free(lck_attrs
);
136 static lck_mtx_t
*sixlowpan_lck_mtx
;
138 static __inline__
void
139 sixlowpan_lock_init(void)
143 lck_grp
= my_lck_grp_alloc_init("if_6lowpan");
144 sixlowpan_lck_mtx
= my_lck_mtx_alloc_init(lck_grp
);
147 static __inline__
void
148 sixlowpan_assert_lock_held(void)
150 lck_mtx_assert(sixlowpan_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
155 static __inline__
void
156 sixlowpan_assert_lock_not_held(void)
158 lck_mtx_assert(sixlowpan_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
163 static __inline__
void
166 lck_mtx_lock(sixlowpan_lck_mtx
);
170 static __inline__
void
171 sixlowpan_unlock(void)
173 lck_mtx_unlock(sixlowpan_lck_mtx
);
178 LIST_HEAD(if6lpan_list
, if6lpan
);
180 typedef LIST_ENTRY(if6lpan
)
183 #define IF6LPAN_SIGNATURE 0x6666face
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
;
200 typedef struct if6lpan
* if6lpan_ref
;
202 static __inline__
int
203 if6lpan_flags_ready(if6lpan_ref ifl
)
205 return (ifl
->if6lpan_flags
& IF6LPANF_READY
) != 0;
208 static __inline__
void
209 if6lpan_flags_set_ready(if6lpan_ref ifl
)
211 ifl
->if6lpan_flags
|= IF6LPANF_READY
;
215 static __inline__
void
216 if6lpan_set_addr(if6lpan_ref ifl
, caddr_t ether_addr
)
218 ifl
->if6lpan_addr
[0] = 0x66;
219 ifl
->if6lpan_addr
[1] = 0x66;
220 bcopy(ether_addr
, &ifl
->if6lpan_addr
[2], ETHER_ADDR_LEN
);
225 static __inline__ u_int8_t
*
226 if6lpan_get_addr(if6lpan_ref ifl
)
228 return ifl
->ifl6lpan_addr
;
232 static __inline__
int
233 if6lpan_flags_detaching(if6lpan_ref ifl
)
235 return (ifl
->if6lpan_flags
& IF6LPANF_DETACHING
) != 0;
238 static __inline__
void
239 if6lpan_flags_set_detaching(if6lpan_ref ifl
)
241 ifl
->if6lpan_flags
|= IF6LPANF_DETACHING
;
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
);
263 #define SIXLOWPAN_MAXUNIT IF_MAXUNIT
264 #define SIXLOWPAN_ZONE_MAX_ELEM MIN(IFNETS_MAX, SIXLOWPAN_MAXUNIT)
266 static struct if_clone sixlowpan_cloner
= IF_CLONE_INITIALIZER(SIXLOWPANNAME
,
267 sixlowpan_clone_create
,
268 sixlowpan_clone_destroy
,
271 SIXLOWPAN_ZONE_MAX_ELEM
,
272 sizeof(struct if6lpan
));
275 ** if6lpan_ref routines
278 if6lpan_retain(if6lpan_ref ifl
)
280 if (ifl
->if6lpan_signature
!= IF6LPAN_SIGNATURE
) {
281 panic("if6lpan_retain: bad signature\n");
283 if (ifl
->if6lpan_retain_count
== 0) {
284 panic("if6lpan_retain: retain count is 0\n");
286 OSIncrementAtomic(&ifl
->if6lpan_retain_count
);
290 if6lpan_release(if6lpan_ref ifl
)
292 u_int32_t old_retain_count
;
294 if (ifl
->if6lpan_signature
!= IF6LPAN_SIGNATURE
) {
295 panic("if6lpan_release: bad signature\n");
297 old_retain_count
= OSDecrementAtomic(&ifl
->if6lpan_retain_count
);
298 switch (old_retain_count
) {
300 panic("if6lpan_release: retain count is 0\n");
303 ifl
->if6lpan_signature
= 0;
304 if_clone_softc_deallocate(&sixlowpan_cloner
, ifl
);
313 ifnet_get_if6lpan(struct ifnet
* ifp
)
317 ifl
= (if6lpan_ref
)ifnet_softc(ifp
);
322 ifnet_get_if6lpan_retained(struct ifnet
* ifp
)
326 ifl
= ifnet_get_if6lpan(ifp
);
330 if (if6lpan_flags_detaching(ifl
)) {
338 sixlowpan_clone_attach(void)
342 error
= if_clone_attach(&sixlowpan_cloner
);
346 sixlowpan_lock_init();
352 __unused ifnet_t ifp
,
354 __unused
char *frame_header
,
355 protocol_family_t
*protocol_family
)
357 *protocol_family
= PF_INET6
;
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
)
366 if (protocol
== PF_INET6
) {
373 sixlowpan_del_proto(__unused ifnet_t interface
, __unused protocol_family_t protocol
)
379 sixlowpan_clone_create(struct if_clone
*ifc
, u_int32_t unit
, __unused
void *params
)
384 struct ifnet_init_eparams if_epraram
;
386 ifl
= if_clone_softc_allocate(&sixlowpan_cloner
);
390 ifl
->if6lpan_retain_count
= 1;
391 ifl
->if6lpan_signature
= IF6LPAN_SIGNATURE
;
393 /* use the interface name as the unique id for ifp recycle */
395 snprintf(ifl
->if6lpan_name
, sizeof(ifl
->if6lpan_name
), "%s%d",
396 ifc
->ifc_name
, unit
) >= sizeof(ifl
->if6lpan_name
)) {
397 if6lpan_release(ifl
);
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
);
423 if6lpan_release(ifl
);
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);
432 error
= ifnet_attach(ifp
, NULL
);
435 if6lpan_release(ifl
);
438 ifl
->if6lpan_ifp
= ifp
;
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
);
447 sixlowpan_remove(if6lpan_ref ifl
)
449 sixlowpan_assert_lock_held();
450 if (if6lpan_flags_detaching(ifl
)) {
453 if6lpan_flags_set_detaching(ifl
);
454 sixlowpan_unconfig(ifl
);
460 sixlowpan_clone_destroy(struct ifnet
*ifp
)
465 ifl
= ifnet_get_if6lpan_retained(ifp
);
470 if (sixlowpan_remove(ifl
) == 0) {
472 if6lpan_release(ifl
);
476 if6lpan_release(ifl
);
478 p_6lowpan_ifnet
= NULL
;
483 sixlowpan_set_bpf_tap(ifnet_t ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
488 ifl
= ifnet_get_if6lpan_retained(ifp
);
494 case BPF_TAP_DISABLE
:
495 ifl
->if6lpan_bpf_input
= ifl
->if6lpan_bpf_output
= NULL
;
499 ifl
->if6lpan_bpf_input
= func
;
503 ifl
->if6lpan_bpf_output
= func
;
506 case BPF_TAP_INPUT_OUTPUT
:
507 ifl
->if6lpan_bpf_input
= ifl
->if6lpan_bpf_output
= func
;
513 if6lpan_release(ifl
);
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.
524 sixlowpan_output(struct ifnet
* ifp
, struct mbuf
* m
)
526 struct ifnet
*p_intf
= NULL
;
527 if6lpan_ref ifl
= NULL
;
528 struct flowadv adv
= { .code
= FADV_SUCCESS
};
530 char link_layer_dest
[ETHER_ADDR_LEN
];
531 bpf_packet_func bpf_func
;
533 u_int16_t ethertype
= htons(ETHERTYPE_IEEE802154
);
534 memset(link_layer_dest
, 0xff, ETHER_ADDR_LEN
);
539 if ((m
->m_flags
& M_PKTHDR
) == 0) {
545 ifl
= ifnet_get_if6lpan_retained(ifp
);
547 if (ifl
== NULL
|| if6lpan_flags_ready(ifl
) == 0) {
551 /* XXX parent interface equivalent? */
552 p_intf
= ifl
->if6lpan_pifp
;
553 bpf_func
= ifl
->if6lpan_bpf_output
;
556 if6lpan_release(ifl
);
558 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
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.
566 if (bpf_func
&& (mbuf_setdata(m
, m
->m_data
+ 2, m
->m_len
- 2) == 0)) {
568 mbuf_setdata(m
, m
->m_data
- 2, m
->m_len
+ 2);
571 /* Append ethernet header */
572 if ((err
= ether_frameout_extended(p_intf
, &m
, NULL
,
573 link_layer_dest
, (const char *)ðertype
,
578 err
= dlil_output(p_intf
, PF_802154
, m
, NULL
, NULL
, 1, &adv
);
581 if (adv
.code
== FADV_FLOW_CONTROLLED
) {
583 } else if (adv
.code
== FADV_SUSPENDED
) {
592 if6lpan_release(ifl
);
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()
605 sixlowpan_input(ifnet_t p
, __unused protocol_family_t protocol
,
606 mbuf_t m
, __unused
char *frame_header
)
608 frame802154_t ieee02154hdr
;
609 u_int8_t
*payload
= NULL
;
610 if6lpan_ref ifl
= NULL
;
611 bpf_packet_func bpf_func
;
616 /* Allocate an mbuf cluster for the 802.15.4 frame and uncompressed payload */
617 mc
= m_getcl(M_WAITOK
, MT_DATA
, M_PKTHDR
);
623 memcpy(&len
, mtod(m
, u_int8_t
*), sizeof(u_int16_t
));
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
;
635 mc
->m_pkthdr
.rcvif
= p
;
638 ifl
= ifnet_get_if6lpan_retained(p
);
646 if (if6lpan_flags_ready(ifl
) == 0) {
647 if6lpan_release(ifl
);
653 bpf_func
= ifl
->if6lpan_bpf_input
;
655 if6lpan_release(ifl
);
661 /* Parse the 802.15.4 frame header */
662 bzero(&ieee02154hdr
, sizeof(ieee02154hdr
));
663 frame802154_parse(mtod(mc
, uint8_t *), len
, &ieee02154hdr
, &payload
);
665 /* XXX Add check for your link layer address being dest */
666 sixxlowpan_input(&ieee02154hdr
, payload
);
668 if (mbuf_setdata(mc
, payload
, ieee02154hdr
.payload_len
)) {
672 mbuf_pkthdr_setlen(mc
, ieee02154hdr
.payload_len
);
674 /* Post decompression */
675 if (proto_input(PF_INET6
, mc
) != 0) {
676 ifnet_stat_increment_in(p
, 0, 0, 1);
680 ifnet_stat_increment_in(p
, 1, mc
->m_pkthdr
.len
, 0);
693 #define SIXLOWPAN_IFMTU 1280
696 sixlowpan_config(struct ifnet
*ifp
, struct ifnet
*p
)
699 u_int16_t parent_flags
;
701 ifl
= ifnet_get_if6lpan_retained(ifp
);
702 if (ifl
== NULL
|| ifl
->if6lpan_pifp
!= NULL
) {
705 if6lpan_release(ifl
);
709 sixlowpan_attach_protocol(p
);
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
);
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
);
729 sixlowpan_unconfig(if6lpan_ref ifl
)
731 struct ifnet
*ifp
= ifl
->if6lpan_ifp
;
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;
747 sixlowpan_ioctl(ifnet_t ifp
, u_long cmd
, void * data
)
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
;
756 if (ifnet_type(ifp
) != IFT_6LOWPAN
) {
759 ifr
= (struct ifreq
*)data
;
763 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
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';
774 if (req
.parent
[0] != '\0') {
775 p
= ifunit(req
.parent
);
780 if (ifnet_type(p
) != IFT_ETHER
781 && ifnet_type(p
) != IFT_IEEE8023ADLAG
) {
782 error
= EPROTONOSUPPORT
;
785 error
= sixlowpan_config(ifp
, p
);
793 bzero(&req
, sizeof req
);
795 ifl
= (if6lpan_ref
)ifnet_softc(ifp
);
796 if (ifl
== NULL
|| if6lpan_flags_detaching(ifl
)) {
798 return ifl
== NULL
? EOPNOTSUPP
: EBUSY
;
800 p
= ifl
->if6lpan_pifp
;
803 snprintf(req
.parent
, sizeof(req
.parent
),
804 "%s%d", ifnet_name(p
), ifnet_unit(p
));
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
));
811 #ifdef SIOCSIFMTU /* xxx */
816 ifnet_set_mtu(ifp
, ifr
->ifr_mtu
);
818 #endif /* SIOCSIFMTU */
827 sixlowpan_if_free(struct ifnet
* ifp
)
834 ifl
= (if6lpan_ref
)ifnet_softc(ifp
);
838 if6lpan_release(ifl
);
844 sixlowpan_detached(ifnet_t p
, __unused protocol_family_t protocol
)
846 if (ifnet_is_attached(p
, 0) == 0) {
847 // TODO: Find ifp from the parent p
848 // sixlowpan_if_free(ifp);
854 * Function: sixlowpan_attach_protocol
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.
862 sixlowpan_attach_protocol(struct ifnet
*ifp
)
865 struct ifnet_attach_proto_param reg
;
867 bzero(®
, sizeof(reg
));
868 reg
.input
= sixlowpan_input
;
869 reg
.detached
= sixlowpan_detached
;
870 error
= ifnet_attach_protocol(ifp
, PF_802154
, ®
);
872 printf("%s(%s%d) ifnet_attach_protocol failed, %d\n",
873 __func__
, ifnet_name(ifp
), ifnet_unit(ifp
), error
);
879 * Function: sixlowpan_detach_protocol
881 * Detach our DLIL protocol from an interface
884 sixlowpan_detach_protocol(struct ifnet
*ifp
)
888 error
= ifnet_detach_protocol(ifp
, PF_802154
);
890 printf("(%s%d) ifnet_detach_protocol failed, %d\n",
891 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
898 sixlowpan_proto_pre_output(ifnet_t ifp
,
899 __unused protocol_family_t protocol_family
,
901 const struct sockaddr
*dest
,
906 #pragma unused(protocol_family)
908 struct sockaddr_dl sdl
;
909 struct sockaddr_in6
*dest6
= (struct sockaddr_in6
*)(uintptr_t)(size_t)dest
;
911 if (!IN6_IS_ADDR_MULTICAST(&dest6
->sin6_addr
)) {
912 result
= nd6_lookup_ipv6(ifp
, dest6
, &sdl
, sizeof(sdl
), route
, *m0
);
914 bcopy(LLADDR(&sdl
), ll_dest
, sdl
.sdl_alen
);
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];
923 * XXX This should be generic to the underlying hardware type
926 u_int16_t ethertype
= htons(ETHERTYPE_IEEE802154
);
927 bcopy(ðertype
, type
, sizeof(ethertype
));
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
)
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
;
947 struct sockaddr_in6
*dest6
= (struct sockaddr_in6
*)(uintptr_t)(size_t)ndest
;
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
;
955 bcopy(edst
, ieee02154hdr
.dest_addr
, 2);
956 ieee02154hdr
.fcf
.dest_addr_mode
= FRAME802154_SHORTADDRMODE
;
959 /* Allocate a contiguous buffer for IPv6 header & payload */
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
965 * Allocate for the worst case.
967 payload
= _MALLOC(m_pktlen(*m
) + 1, M_TEMP
, M_WAITOK
| M_ZERO
);
968 if (payload
== NULL
) {
973 /* Copy the IPv6 header & payload */
974 if (mbuf_copydata(*m
, 0, m_pktlen(*m
), payload
)) {
979 /* Allocate an mbuf cluster for the 802.15.4 frame and compressed payload */
980 mc
= m_getcl(M_WAITOK
, MT_DATA
, M_PKTHDR
);
987 ifl
= ifnet_get_if6lpan_retained(ifp
);
988 if (ifl
== NULL
|| if6lpan_flags_ready(ifl
) == 0) {
990 if6lpan_release(ifl
);
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
);
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 */
1013 /* Create an 802.15.4 Data header frame */
1014 buflen
= frame802154_create(&ieee02154hdr
, (uint8_t *)buf
);
1016 /* Perform inline compression of the IPv6 hdr & payload */
1017 sixxlowpan_output(&ieee02154hdr
, payload
);
1020 * Add 2 bytes at the front of the frame indicating the total payload
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
);
1030 if (prepend_len
!= NULL
) {
1031 *prepend_len
= buflen
;
1033 if (postpend_len
!= NULL
) {
1038 if (payload
!= NULL
) {
1039 _FREE(payload
, M_TEMP
);
1048 sixlowpan_attach_inet6(struct ifnet
*ifp
, protocol_family_t protocol_family
)
1050 struct ifnet_attach_proto_param proto
;
1053 bzero(&proto
, sizeof(proto
));
1054 proto
.pre_output
= sixlowpan_proto_pre_output
;
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__
,
1065 sixlowpan_detach_inet6(struct ifnet
*ifp
, protocol_family_t protocol_family
)
1067 (void) ifnet_detach_protocol(ifp
, protocol_family
);
1071 __private_extern__
int
1072 sixlowpan_family_init(void)
1076 error
= proto_register_plumber(PF_INET6
, IFNET_FAMILY_6LOWPAN
,
1077 sixlowpan_attach_inet6
, sixlowpan_detach_inet6
);
1079 printf("6lowpan: proto_register_plumber failed for AF_INET6 error=%d\n",
1084 error
= sixlowpan_clone_attach();
1086 printf("6lowpan: proto_register_plumber failed sixlowpan_clone_attach error=%d\n",