]>
Commit | Line | Data |
---|---|---|
cb323159 A |
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; | |
f427ee49 | 406 | if_epraram.uniqueid_len = (uint32_t)strlen(ifl->if6lpan_name); |
cb323159 A |
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 *)ðertype, | |
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; | |
f427ee49 A |
636 | if (len > mc->m_pkthdr.len) { |
637 | err = -1; | |
638 | goto err_out; | |
639 | } | |
cb323159 A |
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); | |
f427ee49 A |
668 | if (payload == NULL) { |
669 | err = -1; | |
670 | goto err_out; | |
671 | } | |
cb323159 A |
672 | |
673 | /* XXX Add check for your link layer address being dest */ | |
f427ee49 A |
674 | if (sixxlowpan_input(&ieee02154hdr, payload) != 0) { |
675 | err = -1; | |
676 | goto err_out; | |
677 | } | |
cb323159 A |
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: | |
f427ee49 A |
778 | user_addr = proc_is64bit(current_proc()) ? |
779 | CAST_USER_ADDR_T(ifr->ifr_data64) : | |
780 | CAST_USER_ADDR_T(ifr->ifr_data); | |
cb323159 A |
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 | } | |
f427ee49 A |
818 | user_addr = proc_is64bit(current_proc()) ? |
819 | CAST_USER_ADDR_T(ifr->ifr_data64) : | |
820 | CAST_USER_ADDR_T(ifr->ifr_data); | |
cb323159 A |
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(®, sizeof(reg)); | |
881 | reg.input = sixlowpan_input; | |
882 | reg.detached = sixlowpan_detached; | |
883 | error = ifnet_attach_protocol(ifp, PF_802154, ®); | |
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; | |
2a1bd2d3 | 921 | struct sockaddr_dl sdl = {}; |
cb323159 A |
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(ðertype, 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; | |
f427ee49 | 957 | uint8_t *payload = NULL; |
cb323159 | 958 | struct mbuf *mc = NULL; |
f427ee49 | 959 | uint16_t len; |
cb323159 A |
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 | */ | |
f427ee49 | 1036 | len = htons((uint16_t)(buflen + ieee02154hdr.payload_len)); |
cb323159 A |
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 | ||
cb323159 A |
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 | } |