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