]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ether_if_module.c
a5e21e645679e6c937efe11b2d8eaab7d09e4c76
[apple/xnu.git] / bsd / net / ether_if_module.c
1 /*
2 * Copyright (c) 2000 Apple Computer, 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 (c) 1982, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 */
61
62
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
67 #include <sys/malloc.h>
68 #include <sys/mbuf.h>
69 #include <sys/socket.h>
70 #include <sys/sockio.h>
71 #include <sys/sysctl.h>
72
73 #include <net/if.h>
74 #include <net/route.h>
75 #include <net/if_llc.h>
76 #include <net/if_dl.h>
77 #include <net/if_types.h>
78 #include <net/if_ether.h>
79 #include <netinet/if_ether.h>
80 #include <netinet/in.h> /* For M_LOOP */
81
82 /*
83 #if INET
84 #include <netinet/in.h>
85 #include <netinet/in_var.h>
86
87 #include <netinet/in_systm.h>
88 #include <netinet/ip.h>
89 #endif
90 */
91
92 #include <sys/socketvar.h>
93 #include <net/if_vlan_var.h>
94 #include <net/if_bond_var.h>
95
96 #include <net/dlil.h>
97
98 #if LLC && CCITT
99 extern struct ifqueue pkintrq;
100 #endif
101
102 /* General stuff from if_ethersubr.c - may not need some of it */
103
104 #include <netat/at_pat.h>
105 #if NETAT
106 extern struct ifqueue atalkintrq;
107 #endif
108
109
110 #if BRIDGE
111 #include <net/bridge.h>
112 #endif
113
114 #define memcpy(x,y,z) bcopy(y, x, z)
115
116
117 SYSCTL_DECL(_net_link);
118 SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
119
120 struct en_desc {
121 u_int16_t type; /* Type of protocol stored in data */
122 u_long protocol_family; /* Protocol family */
123 u_long data[2]; /* Protocol data */
124 };
125 /* descriptors are allocated in blocks of ETHER_DESC_BLK_SIZE */
126 #define ETHER_DESC_BLK_SIZE (10)
127
128 /*
129 * Header for the demux list, hangs off of IFP at family_cookie
130 */
131
132 struct ether_desc_blk_str {
133 u_long n_max_used;
134 u_long n_count;
135 u_long n_used;
136 struct en_desc block_ptr[1];
137 };
138 /* Size of the above struct before the array of struct en_desc */
139 #define ETHER_DESC_HEADER_SIZE ((size_t)&(((struct ether_desc_blk_str*)0)->block_ptr[0]))
140 __private_extern__ u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
141 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
142
143 int ether_add_proto_old(struct ifnet *ifp, u_long protocol_family, struct ddesc_head_str *desc_head);
144 int ether_add_if(struct ifnet *ifp);
145 int ether_del_if(struct ifnet *ifp);
146 int ether_init_if(struct ifnet *ifp);
147 int ether_family_init(void);
148
149 /*
150 * Release all descriptor entries owned by this protocol (there may be several).
151 * Setting the type to 0 releases the entry. Eventually we should compact-out
152 * the unused entries.
153 */
154 int
155 ether_del_proto(
156 ifnet_t ifp,
157 protocol_family_t protocol_family)
158 {
159 struct ether_desc_blk_str *desc_blk = (struct ether_desc_blk_str *)ifp->family_cookie;
160 u_long current = 0;
161 int found = 0;
162
163 if (desc_blk == NULL)
164 return 0;
165
166 for (current = desc_blk->n_max_used; current > 0; current--) {
167 if (desc_blk->block_ptr[current - 1].protocol_family == protocol_family) {
168 found = 1;
169 desc_blk->block_ptr[current - 1].type = 0;
170 desc_blk->n_used--;
171 }
172 }
173
174 if (desc_blk->n_used == 0) {
175 FREE(ifp->family_cookie, M_IFADDR);
176 ifp->family_cookie = 0;
177 }
178 else {
179 /* Decrement n_max_used */
180 for (; desc_blk->n_max_used > 0 && desc_blk->block_ptr[desc_blk->n_max_used - 1].type == 0; desc_blk->n_max_used--)
181 ;
182 }
183
184 return 0;
185 }
186
187
188 static int
189 ether_add_proto_internal(
190 struct ifnet *ifp,
191 protocol_family_t protocol,
192 const struct ifnet_demux_desc *demux)
193 {
194 struct en_desc *ed;
195 struct ether_desc_blk_str *desc_blk = (struct ether_desc_blk_str *)ifp->family_cookie;
196 u_int32_t i;
197
198 switch (demux->type) {
199 /* These types are supported */
200 /* Top three are preferred */
201 case DLIL_DESC_ETYPE2:
202 if (demux->datalen != 2) {
203 return EINVAL;
204 }
205 break;
206
207 case DLIL_DESC_SAP:
208 if (demux->datalen != 3) {
209 return EINVAL;
210 }
211 break;
212
213 case DLIL_DESC_SNAP:
214 if (demux->datalen != 5) {
215 return EINVAL;
216 }
217 break;
218
219 default:
220 return ENOTSUP;
221 }
222
223 // Verify a matching descriptor does not exist.
224 if (desc_blk != NULL) {
225 switch (demux->type) {
226 case DLIL_DESC_ETYPE2:
227 for (i = 0; i < desc_blk->n_max_used; i++) {
228 if (desc_blk->block_ptr[i].type == DLIL_DESC_ETYPE2 &&
229 desc_blk->block_ptr[i].data[0] ==
230 *(u_int16_t*)demux->data) {
231 return EADDRINUSE;
232 }
233 }
234 break;
235 case DLIL_DESC_SAP:
236 case DLIL_DESC_SNAP:
237 for (i = 0; i < desc_blk->n_max_used; i++) {
238 if (desc_blk->block_ptr[i].type == demux->type &&
239 bcmp(desc_blk->block_ptr[i].data, demux->data,
240 demux->datalen) == 0) {
241 return EADDRINUSE;
242 }
243 }
244 break;
245 }
246 }
247
248 // Check for case where all of the descriptor blocks are in use
249 if (desc_blk == NULL || desc_blk->n_used == desc_blk->n_count) {
250 struct ether_desc_blk_str *tmp;
251 u_long new_count = ETHER_DESC_BLK_SIZE;
252 u_long new_size;
253 u_long old_size = 0;
254
255 i = 0;
256
257 if (desc_blk) {
258 new_count += desc_blk->n_count;
259 old_size = desc_blk->n_count * sizeof(struct en_desc) + ETHER_DESC_HEADER_SIZE;
260 i = desc_blk->n_used;
261 }
262
263 new_size = new_count * sizeof(struct en_desc) + ETHER_DESC_HEADER_SIZE;
264
265 tmp = _MALLOC(new_size, M_IFADDR, M_WAITOK);
266 if (tmp == 0) {
267 /*
268 * Remove any previous descriptors set in the call.
269 */
270 return ENOMEM;
271 }
272
273 bzero(tmp + old_size, new_size - old_size);
274 if (desc_blk) {
275 bcopy(desc_blk, tmp, old_size);
276 FREE(desc_blk, M_IFADDR);
277 }
278 desc_blk = tmp;
279 ifp->family_cookie = (u_long)desc_blk;
280 desc_blk->n_count = new_count;
281 }
282 else {
283 /* Find a free entry */
284 for (i = 0; i < desc_blk->n_count; i++) {
285 if (desc_blk->block_ptr[i].type == 0) {
286 break;
287 }
288 }
289 }
290
291 /* Bump n_max_used if appropriate */
292 if (i + 1 > desc_blk->n_max_used) {
293 desc_blk->n_max_used = i + 1;
294 }
295
296 ed = &desc_blk->block_ptr[i];
297 ed->protocol_family = protocol;
298 ed->data[0] = 0;
299 ed->data[1] = 0;
300
301 switch (demux->type) {
302 case DLIL_DESC_ETYPE2:
303 /* 2 byte ethernet raw protocol type is at native_type */
304 /* prtocol must be in network byte order */
305 ed->type = DLIL_DESC_ETYPE2;
306 ed->data[0] = *(u_int16_t*)demux->data;
307 break;
308
309 case DLIL_DESC_SAP:
310 ed->type = DLIL_DESC_SAP;
311 bcopy(demux->data, &ed->data[0], 3);
312 break;
313
314 case DLIL_DESC_SNAP: {
315 u_int8_t* pDest = ((u_int8_t*)&ed->data[0]) + 3;
316 ed->type = DLIL_DESC_SNAP;
317 bcopy(demux->data, pDest, 5);
318 }
319 break;
320 }
321
322 desc_blk->n_used++;
323
324 return 0;
325 }
326
327 int
328 ether_add_proto(
329 ifnet_t ifp,
330 protocol_family_t protocol,
331 const struct ifnet_demux_desc *demux_list,
332 u_int32_t demux_count)
333 {
334 int error = 0;
335 u_int32_t i;
336
337 for (i = 0; i < demux_count; i++) {
338 error = ether_add_proto_internal(ifp, protocol, &demux_list[i]);
339 if (error) {
340 ether_del_proto(ifp, protocol);
341 break;
342 }
343 }
344
345 return error;
346 }
347
348 __private_extern__ int
349 ether_add_proto_old(
350 struct ifnet *ifp,
351 u_long protocol_family,
352 struct ddesc_head_str *desc_head)
353 {
354 struct dlil_demux_desc *desc;
355 int error = 0;
356
357 TAILQ_FOREACH(desc, desc_head, next) {
358 struct ifnet_demux_desc dmx;
359 int swapped = 0;
360
361 // Convert dlil_demux_desc to ifnet_demux_desc
362 dmx.type = desc->type;
363 dmx.datalen = desc->variants.native_type_length;
364 dmx.data = desc->native_type;
365
366 #ifdef DLIL_DESC_RAW
367 if (dmx.type == DLIL_DESC_RAW) {
368 swapped = 1;
369 dmx.type = DLIL_DESC_ETYPE2;
370 dmx.datalen = 2;
371 *(u_int16_t*)dmx.data = htons(*(u_int16_t*)dmx.data);
372 }
373 #endif
374
375 error = ether_add_proto_internal(ifp, protocol_family, &dmx);
376 if (swapped) {
377 *(u_int16_t*)dmx.data = ntohs(*(u_int16_t*)dmx.data);
378 swapped = 0;
379 }
380 if (error) {
381 ether_del_proto(ifp, protocol_family);
382 break;
383 }
384 }
385
386 return error;
387 }
388
389
390 static int
391 ether_shutdown(void)
392 {
393 return 0;
394 }
395
396
397 int
398 ether_demux(
399 ifnet_t ifp,
400 mbuf_t m,
401 char *frame_header,
402 protocol_family_t *protocol_family)
403 {
404 struct ether_header *eh = (struct ether_header *)frame_header;
405 u_short ether_type = eh->ether_type;
406 u_int16_t type;
407 u_int8_t *data;
408 u_long i = 0;
409 struct ether_desc_blk_str *desc_blk = (struct ether_desc_blk_str *)ifp->family_cookie;
410 u_long maxd = desc_blk ? desc_blk->n_max_used : 0;
411 struct en_desc *ed = desc_blk ? desc_blk->block_ptr : NULL;
412 u_int32_t extProto1 = 0;
413 u_int32_t extProto2 = 0;
414
415 if (eh->ether_dhost[0] & 1) {
416 /* Check for broadcast */
417 if (*(u_int32_t*)eh->ether_dhost == 0xFFFFFFFF &&
418 *(u_int16_t*)(eh->ether_dhost + sizeof(u_int32_t)) == 0xFFFF)
419 m->m_flags |= M_BCAST;
420 else
421 m->m_flags |= M_MCAST;
422 }
423
424 if (ifp->if_eflags & IFEF_BOND) {
425 /* if we're bonded, bond "protocol" gets all the packets */
426 *protocol_family = PF_BOND;
427 return (0);
428 }
429
430 if ((eh->ether_dhost[0] & 1) == 0) {
431 /*
432 * When the driver is put into promiscuous mode we may receive unicast
433 * frames that are not intended for our interfaces. They are marked here
434 * as being promiscuous so the caller may dispose of them after passing
435 * the packets to any interface filters.
436 */
437 #define ETHER_CMP(x, y) ( ((u_int16_t *) x)[0] != ((u_int16_t *) y)[0] || \
438 ((u_int16_t *) x)[1] != ((u_int16_t *) y)[1] || \
439 ((u_int16_t *) x)[2] != ((u_int16_t *) y)[2] )
440
441 if (ETHER_CMP(eh->ether_dhost, ifnet_lladdr(ifp))) {
442 m->m_flags |= M_PROMISC;
443 }
444 }
445
446 /* Quick check for VLAN */
447 if ((m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) != 0 ||
448 ether_type == htons(ETHERTYPE_VLAN)) {
449 *protocol_family = PF_VLAN;
450 return 0;
451 }
452
453 data = mtod(m, u_int8_t*);
454
455 /*
456 * Determine the packet's protocol type and stuff the protocol into
457 * longs for quick compares.
458 */
459
460 if (ntohs(ether_type) <= 1500) {
461 extProto1 = *(u_int32_t*)data;
462
463 // SAP or SNAP
464 if ((extProto1 & htonl(0xFFFFFF00)) == htonl(0xAAAA0300)) {
465 // SNAP
466 type = DLIL_DESC_SNAP;
467 extProto2 = *(u_int32_t*)(data + sizeof(u_int32_t));
468 extProto1 &= htonl(0x000000FF);
469 } else {
470 type = DLIL_DESC_SAP;
471 extProto1 &= htonl(0xFFFFFF00);
472 }
473 } else {
474 type = DLIL_DESC_ETYPE2;
475 }
476
477 /*
478 * Search through the connected protocols for a match.
479 */
480
481 switch (type) {
482 case DLIL_DESC_ETYPE2:
483 for (i = 0; i < maxd; i++) {
484 if ((ed[i].type == type) && (ed[i].data[0] == ether_type)) {
485 *protocol_family = ed[i].protocol_family;
486 return 0;
487 }
488 }
489 break;
490
491 case DLIL_DESC_SAP:
492 for (i = 0; i < maxd; i++) {
493 if ((ed[i].type == type) && (ed[i].data[0] == extProto1)) {
494 *protocol_family = ed[i].protocol_family;
495 return 0;
496 }
497 }
498 break;
499
500 case DLIL_DESC_SNAP:
501 for (i = 0; i < maxd; i++) {
502 if ((ed[i].type == type) && (ed[i].data[0] == extProto1) &&
503 (ed[i].data[1] == extProto2)) {
504 *protocol_family = ed[i].protocol_family;
505 return 0;
506 }
507 }
508 break;
509 }
510
511 return ENOENT;
512 }
513
514 /*
515 * Ethernet output routine.
516 * Encapsulate a packet of type family for the local net.
517 * Use trailer local net encapsulation if enough data in first
518 * packet leaves a multiple of 512 bytes of data in remainder.
519 */
520 int
521 ether_frameout(
522 struct ifnet *ifp,
523 struct mbuf **m,
524 const struct sockaddr *ndest,
525 const char *edst,
526 const char *ether_type)
527 {
528 struct ether_header *eh;
529 int hlen; /* link layer header length */
530
531 hlen = ETHER_HDR_LEN;
532
533 /*
534 * If a simplex interface, and the packet is being sent to our
535 * Ethernet address or a broadcast address, loopback a copy.
536 * XXX To make a simplex device behave exactly like a duplex
537 * device, we should copy in the case of sending to our own
538 * ethernet address (thus letting the original actually appear
539 * on the wire). However, we don't do that here for security
540 * reasons and compatibility with the original behavior.
541 */
542 if ((ifp->if_flags & IFF_SIMPLEX) &&
543 ((*m)->m_flags & M_LOOP)) {
544 if (lo_ifp) {
545 if ((*m)->m_flags & M_BCAST) {
546 struct mbuf *n = m_copy(*m, 0, (int)M_COPYALL);
547 if (n != NULL)
548 dlil_output(lo_ifp, ndest->sa_family, n, 0, ndest, 0);
549 }
550 else {
551 if (bcmp(edst, ifnet_lladdr(ifp), ETHER_ADDR_LEN) == 0) {
552 dlil_output(lo_ifp, ndest->sa_family, *m, 0, ndest, 0);
553 return EJUSTRETURN;
554 }
555 }
556 }
557 }
558
559 /*
560 * Add local net header. If no space in first mbuf,
561 * allocate another.
562 */
563 M_PREPEND(*m, sizeof (struct ether_header), M_DONTWAIT);
564 if (*m == 0) {
565 return (EJUSTRETURN);
566 }
567
568
569 eh = mtod(*m, struct ether_header *);
570 (void)memcpy(&eh->ether_type, ether_type,
571 sizeof(eh->ether_type));
572 (void)memcpy(eh->ether_dhost, edst, 6);
573 ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, ETHER_ADDR_LEN);
574
575 return 0;
576 }
577
578
579 __private_extern__ int
580 ether_add_if(struct ifnet *ifp)
581 {
582 ifp->if_framer = ether_frameout;
583 ifp->if_demux = ether_demux;
584
585 return 0;
586 }
587
588 __private_extern__ int
589 ether_del_if(struct ifnet *ifp)
590 {
591 if (ifp->family_cookie) {
592 FREE(ifp->family_cookie, M_IFADDR);
593 return 0;
594 }
595 else
596 return ENOENT;
597 }
598
599 __private_extern__ int
600 ether_init_if(struct ifnet *ifp)
601 {
602 /*
603 * Copy ethernet address out of old style arpcom. New
604 * interfaces created using the KPIs will not have an
605 * interface family. Those interfaces will have the
606 * lladdr passed in when the interface is created.
607 */
608 u_char *enaddr = ((u_char*)ifp) + sizeof(struct ifnet);
609 ifnet_set_lladdr(ifp, enaddr, 6);
610 bzero(enaddr, 6);
611
612 return 0;
613 }
614
615
616 errno_t
617 ether_check_multi(
618 ifnet_t ifp,
619 const struct sockaddr *proto_addr)
620 {
621 errno_t result = EAFNOSUPPORT;
622 const u_char *e_addr;
623
624 /*
625 * AF_SPEC and AF_LINK don't require translation. We do
626 * want to verify that they specify a valid multicast.
627 */
628 switch(proto_addr->sa_family) {
629 case AF_UNSPEC:
630 e_addr = (const u_char*)&proto_addr->sa_data[0];
631 if ((e_addr[0] & 0x01) != 0x01)
632 result = EADDRNOTAVAIL;
633 else
634 result = 0;
635 break;
636
637 case AF_LINK:
638 e_addr = CONST_LLADDR((const struct sockaddr_dl*)proto_addr);
639 if ((e_addr[0] & 0x01) != 0x01)
640 result = EADDRNOTAVAIL;
641 else
642 result = 0;
643 break;
644 }
645
646 return result;
647 }
648
649 int
650 ether_ioctl(
651 __unused ifnet_t ifp,
652 __unused u_int32_t command,
653 __unused void* data)
654 {
655 return EOPNOTSUPP;
656 }
657
658
659 extern int ether_attach_inet(struct ifnet *ifp, u_long proto_family);
660 extern int ether_detach_inet(struct ifnet *ifp, u_long proto_family);
661 extern int ether_attach_inet6(struct ifnet *ifp, u_long proto_family);
662 extern int ether_detach_inet6(struct ifnet *ifp, u_long proto_family);
663
664 extern void kprintf(const char *, ...);
665
666 int ether_family_init(void)
667 {
668 int error=0;
669 struct dlil_ifmod_reg_str ifmod_reg;
670
671 /* ethernet family is built-in, called from bsd_init */
672
673 bzero(&ifmod_reg, sizeof(ifmod_reg));
674 ifmod_reg.add_if = ether_add_if;
675 ifmod_reg.del_if = ether_del_if;
676 ifmod_reg.init_if = ether_init_if;
677 ifmod_reg.add_proto = ether_add_proto_old;
678 ifmod_reg.del_proto = ether_del_proto;
679 ifmod_reg.ifmod_ioctl = ether_ioctl;
680 ifmod_reg.shutdown = ether_shutdown;
681
682 if (dlil_reg_if_modules(APPLE_IF_FAM_ETHERNET, &ifmod_reg)) {
683 printf("WARNING: ether_family_init -- Can't register if family modules\n");
684 error = EIO;
685 goto done;
686 }
687
688 /* Register protocol registration functions */
689
690 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_ETHERNET,
691 ether_attach_inet, ether_detach_inet)) != 0) {
692 kprintf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
693 goto done;
694 }
695
696
697 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_ETHERNET,
698 ether_attach_inet6, ether_detach_inet6)) != 0) {
699 kprintf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
700 goto done;
701 }
702 vlan_family_init();
703 bond_family_init();
704
705 done:
706
707 return (error);
708 }