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