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
= (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
);
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
;
636 if (len
> mc
->m_pkthdr
.len
) {
642 ifl
= ifnet_get_if6lpan_retained(p
);
650 if (if6lpan_flags_ready(ifl
) == 0) {
651 if6lpan_release(ifl
);
657 bpf_func
= ifl
->if6lpan_bpf_input
;
659 if6lpan_release(ifl
);
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
) {
673 /* XXX Add check for your link layer address being dest */
674 if (sixxlowpan_input(&ieee02154hdr
, payload
) != 0) {
679 if (mbuf_setdata(mc
, payload
, ieee02154hdr
.payload_len
)) {
683 mbuf_pkthdr_setlen(mc
, ieee02154hdr
.payload_len
);
685 /* Post decompression */
686 if (proto_input(PF_INET6
, mc
) != 0) {
687 ifnet_stat_increment_in(p
, 0, 0, 1);
691 ifnet_stat_increment_in(p
, 1, mc
->m_pkthdr
.len
, 0);
704 #define SIXLOWPAN_IFMTU 1280
707 sixlowpan_config(struct ifnet
*ifp
, struct ifnet
*p
)
710 u_int16_t parent_flags
;
712 ifl
= ifnet_get_if6lpan_retained(ifp
);
713 if (ifl
== NULL
|| ifl
->if6lpan_pifp
!= NULL
) {
716 if6lpan_release(ifl
);
720 sixlowpan_attach_protocol(p
);
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
);
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
);
740 sixlowpan_unconfig(if6lpan_ref ifl
)
742 struct ifnet
*ifp
= ifl
->if6lpan_ifp
;
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;
758 sixlowpan_ioctl(ifnet_t ifp
, u_long cmd
, void * data
)
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
;
767 if (ifnet_type(ifp
) != IFT_6LOWPAN
) {
770 ifr
= (struct ifreq
*)data
;
774 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
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';
786 if (req
.parent
[0] != '\0') {
787 p
= ifunit(req
.parent
);
792 if (ifnet_type(p
) != IFT_ETHER
793 && ifnet_type(p
) != IFT_IEEE8023ADLAG
) {
794 error
= EPROTONOSUPPORT
;
797 error
= sixlowpan_config(ifp
, p
);
805 bzero(&req
, sizeof req
);
807 ifl
= (if6lpan_ref
)ifnet_softc(ifp
);
808 if (ifl
== NULL
|| if6lpan_flags_detaching(ifl
)) {
810 return ifl
== NULL
? EOPNOTSUPP
: EBUSY
;
812 p
= ifl
->if6lpan_pifp
;
815 snprintf(req
.parent
, sizeof(req
.parent
),
816 "%s%d", ifnet_name(p
), ifnet_unit(p
));
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
));
824 #ifdef SIOCSIFMTU /* xxx */
829 ifnet_set_mtu(ifp
, ifr
->ifr_mtu
);
831 #endif /* SIOCSIFMTU */
840 sixlowpan_if_free(struct ifnet
* ifp
)
847 ifl
= (if6lpan_ref
)ifnet_softc(ifp
);
851 if6lpan_release(ifl
);
857 sixlowpan_detached(ifnet_t p
, __unused protocol_family_t protocol
)
859 if (ifnet_is_attached(p
, 0) == 0) {
860 // TODO: Find ifp from the parent p
861 // sixlowpan_if_free(ifp);
867 * Function: sixlowpan_attach_protocol
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.
875 sixlowpan_attach_protocol(struct ifnet
*ifp
)
878 struct ifnet_attach_proto_param reg
;
880 bzero(®
, sizeof(reg
));
881 reg
.input
= sixlowpan_input
;
882 reg
.detached
= sixlowpan_detached
;
883 error
= ifnet_attach_protocol(ifp
, PF_802154
, ®
);
885 printf("%s(%s%d) ifnet_attach_protocol failed, %d\n",
886 __func__
, ifnet_name(ifp
), ifnet_unit(ifp
), error
);
892 * Function: sixlowpan_detach_protocol
894 * Detach our DLIL protocol from an interface
897 sixlowpan_detach_protocol(struct ifnet
*ifp
)
901 error
= ifnet_detach_protocol(ifp
, PF_802154
);
903 printf("(%s%d) ifnet_detach_protocol failed, %d\n",
904 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
911 sixlowpan_proto_pre_output(ifnet_t ifp
,
912 __unused protocol_family_t protocol_family
,
914 const struct sockaddr
*dest
,
919 #pragma unused(protocol_family)
921 struct sockaddr_dl sdl
= {};
922 struct sockaddr_in6
*dest6
= (struct sockaddr_in6
*)(uintptr_t)(size_t)dest
;
924 if (!IN6_IS_ADDR_MULTICAST(&dest6
->sin6_addr
)) {
925 result
= nd6_lookup_ipv6(ifp
, dest6
, &sdl
, sizeof(sdl
), route
, *m0
);
927 bcopy(LLADDR(&sdl
), ll_dest
, sdl
.sdl_alen
);
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];
936 * XXX This should be generic to the underlying hardware type
939 u_int16_t ethertype
= htons(ETHERTYPE_IEEE802154
);
940 bcopy(ðertype
, type
, sizeof(ethertype
));
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
)
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
;
960 struct sockaddr_in6
*dest6
= (struct sockaddr_in6
*)(uintptr_t)(size_t)ndest
;
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
;
968 bcopy(edst
, ieee02154hdr
.dest_addr
, 2);
969 ieee02154hdr
.fcf
.dest_addr_mode
= FRAME802154_SHORTADDRMODE
;
972 /* Allocate a contiguous buffer for IPv6 header & payload */
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
978 * Allocate for the worst case.
980 payload
= _MALLOC(m_pktlen(*m
) + 1, M_TEMP
, M_WAITOK
| M_ZERO
);
981 if (payload
== NULL
) {
986 /* Copy the IPv6 header & payload */
987 if (mbuf_copydata(*m
, 0, m_pktlen(*m
), payload
)) {
992 /* Allocate an mbuf cluster for the 802.15.4 frame and compressed payload */
993 mc
= m_getcl(M_WAITOK
, MT_DATA
, M_PKTHDR
);
1000 ifl
= ifnet_get_if6lpan_retained(ifp
);
1001 if (ifl
== NULL
|| if6lpan_flags_ready(ifl
) == 0) {
1003 if6lpan_release(ifl
);
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
);
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 */
1026 /* Create an 802.15.4 Data header frame */
1027 buflen
= frame802154_create(&ieee02154hdr
, (uint8_t *)buf
);
1029 /* Perform inline compression of the IPv6 hdr & payload */
1030 sixxlowpan_output(&ieee02154hdr
, payload
);
1033 * Add 2 bytes at the front of the frame indicating the total payload
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
);
1043 if (prepend_len
!= NULL
) {
1044 *prepend_len
= buflen
;
1046 if (postpend_len
!= NULL
) {
1051 if (payload
!= NULL
) {
1052 _FREE(payload
, M_TEMP
);
1061 sixlowpan_attach_inet6(struct ifnet
*ifp
, protocol_family_t protocol_family
)
1063 struct ifnet_attach_proto_param proto
;
1066 bzero(&proto
, sizeof(proto
));
1067 proto
.pre_output
= sixlowpan_proto_pre_output
;
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__
,
1078 sixlowpan_detach_inet6(struct ifnet
*ifp
, protocol_family_t protocol_family
)
1080 (void) ifnet_detach_protocol(ifp
, protocol_family
);
1083 __private_extern__
int
1084 sixlowpan_family_init(void)
1088 error
= proto_register_plumber(PF_INET6
, IFNET_FAMILY_6LOWPAN
,
1089 sixlowpan_attach_inet6
, sixlowpan_detach_inet6
);
1091 printf("6lowpan: proto_register_plumber failed for AF_INET6 error=%d\n",
1096 error
= sixlowpan_clone_attach();
1098 printf("6lowpan: proto_register_plumber failed sixlowpan_clone_attach error=%d\n",