]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/ether_if_module.c
xnu-344.23.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 *
de355530
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 *
de355530
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,
de355530
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>
87
88#include <net/dlil.h>
89
90
91#if LLC && CCITT
92extern struct ifqueue pkintrq;
93#endif
94
95/* General stuff from if_ethersubr.c - may not need some of it */
96
97#include <netat/at_pat.h>
98#if NETAT
99extern struct ifqueue atalkintrq;
100#endif
101
102
103#if BRIDGE
104#include <net/bridge.h>
105#endif
106
107/* #include "vlan.h" */
108#if NVLAN > 0
109#include <net/if_vlan_var.h>
110#endif /* NVLAN > 0 */
111
112static u_long lo_dlt = 0;
1c79356b
A
113
114#define IFP2AC(IFP) ((struct arpcom *)IFP)
115
1c79356b 116struct en_desc {
7b1edb79
A
117 u_int16_t type; /* Type of protocol stored in data */
118 struct if_proto *proto; /* Protocol structure */
119 u_long data[2]; /* Protocol data */
1c79356b 120};
7b1edb79
A
121
122#define ETHER_DESC_BLK_SIZE (10)
1c79356b
A
123#define MAX_INTERFACES 50
124
125/*
126 * Statics for demux module
127 */
128
129struct ether_desc_blk_str {
7b1edb79
A
130 u_long n_max_used;
131 u_long n_count;
132 struct en_desc *block_ptr;
1c79356b
A
133};
134
135
136static struct ether_desc_blk_str ether_desc_blk[MAX_INTERFACES];
1c79356b
A
137
138
139/*
140 * Release all descriptor entries owned by this dl_tag (there may be several).
7b1edb79 141 * Setting the type to 0 releases the entry. Eventually we should compact-out
1c79356b
A
142 * the unused entries.
143 */
144static
145int ether_del_proto(struct if_proto *proto, u_long dl_tag)
146{
7b1edb79
A
147 struct en_desc* ed = ether_desc_blk[proto->ifp->family_cookie].block_ptr;
148 u_long current = 0;
1c79356b 149 int found = 0;
7b1edb79
A
150
151 for (current = ether_desc_blk[proto->ifp->family_cookie].n_max_used;
152 current > 0; current--) {
153 if (ed[current - 1].proto == proto) {
154 found = 1;
155 ed[current - 1].type = 0;
156
157 if (current == ether_desc_blk[proto->ifp->family_cookie].n_max_used) {
158 ether_desc_blk[proto->ifp->family_cookie].n_max_used--;
159 }
160 }
1c79356b 161 }
7b1edb79
A
162
163 return found;
1c79356b
A
164 }
165
166
167
7b1edb79
A
168static int
169ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
1c79356b
A
170{
171 char *current_ptr;
172 struct dlil_demux_desc *desc;
1c79356b 173 struct en_desc *ed;
7b1edb79 174 struct en_desc *last;
1c79356b
A
175 u_long *bitmask;
176 u_long *proto_id;
7b1edb79 177 u_long i;
1c79356b
A
178 short total_length;
179 u_long block_count;
180 u_long *tmp;
181
182
7b1edb79
A
183 TAILQ_FOREACH(desc, desc_head, next) {
184 switch (desc->type) {
185 /* These types are supported */
186 /* Top three are preferred */
187 case DLIL_DESC_ETYPE2:
188 if (desc->variants.native_type_length != 2)
189 return EINVAL;
190 break;
191
192 case DLIL_DESC_SAP:
193 if (desc->variants.native_type_length != 3)
194 return EINVAL;
195 break;
196
197 case DLIL_DESC_SNAP:
198 if (desc->variants.native_type_length != 5)
199 return EINVAL;
200 break;
201
202 case DLIL_DESC_802_2:
203 case DLIL_DESC_802_2_SNAP:
204 break;
205
206 case DLIL_DESC_RAW:
207 if (desc->variants.bitmask.proto_id_length == 0)
208 break;
209 /* else fall through, bitmask variant not supported */
210
211 default:
212 ether_del_proto(proto, dl_tag);
213 return EINVAL;
214 }
215
216 restart:
217 ed = ether_desc_blk[proto->ifp->family_cookie].block_ptr;
218
219 /* Find a free entry */
220 for (i = 0; i < ether_desc_blk[proto->ifp->family_cookie].n_count; i++) {
221 if (ed[i].type == 0) {
222 break;
223 }
224 }
225
226 if (i >= ether_desc_blk[proto->ifp->family_cookie].n_count) {
227 u_long new_count = ETHER_DESC_BLK_SIZE +
228 ether_desc_blk[proto->ifp->family_cookie].n_count;
229 tmp = _MALLOC((new_count * (sizeof(*ed))), M_IFADDR, M_WAITOK);
230 if (tmp == 0) {
231 /*
232 * Remove any previous descriptors set in the call.
233 */
234 ether_del_proto(proto, dl_tag);
235 return ENOMEM;
236 }
237
238 bzero(tmp, new_count * sizeof(*ed));
239 bcopy(ether_desc_blk[proto->ifp->family_cookie].block_ptr,
240 tmp, ether_desc_blk[proto->ifp->family_cookie].n_count * sizeof(*ed));
241 FREE(ether_desc_blk[proto->ifp->family_cookie].block_ptr, M_IFADDR);
242 ether_desc_blk[proto->ifp->family_cookie].n_count = new_count;
243 ether_desc_blk[proto->ifp->family_cookie].block_ptr = (struct en_desc*)tmp;
244 }
245
246 /* Bump n_max_used if appropriate */
247 if (i + 1 > ether_desc_blk[proto->ifp->family_cookie].n_max_used) {
248 ether_desc_blk[proto->ifp->family_cookie].n_max_used = i + 1;
249 }
250
251 ed[i].proto = proto;
9bccf70c 252 ed[i].data[0] = 0;
7b1edb79
A
253 ed[i].data[1] = 0;
254
255 switch (desc->type) {
256 case DLIL_DESC_RAW:
257 /* 2 byte ethernet raw protocol type is at native_type */
258 /* protocol is not in network byte order */
259 ed[i].type = DLIL_DESC_ETYPE2;
260 ed[i].data[0] = htons(*(u_int16_t*)desc->native_type);
261 break;
262
263 case DLIL_DESC_ETYPE2:
264 /* 2 byte ethernet raw protocol type is at native_type */
265 /* prtocol must be in network byte order */
266 ed[i].type = DLIL_DESC_ETYPE2;
267 ed[i].data[0] = *(u_int16_t*)desc->native_type;
268 break;
269
270 case DLIL_DESC_802_2:
271 ed[i].type = DLIL_DESC_SAP;
272 ed[i].data[0] = *(u_int32_t*)&desc->variants.desc_802_2;
273 ed[i].data[0] &= htonl(0xFFFFFF00);
274 break;
275
276 case DLIL_DESC_SAP:
277 ed[i].type = DLIL_DESC_SAP;
278 bcopy(desc->native_type, &ed[i].data[0], 3);
279 break;
280
281 case DLIL_DESC_802_2_SNAP:
282 ed[i].type = DLIL_DESC_SNAP;
283 desc->variants.desc_802_2_SNAP.protocol_type =
284 htons(desc->variants.desc_802_2_SNAP.protocol_type);
285 bcopy(&desc->variants.desc_802_2_SNAP, &ed[i].data[0], 8);
286 ed[i].data[0] &= htonl(0x000000FF);
287 desc->variants.desc_802_2_SNAP.protocol_type =
288 ntohs(desc->variants.desc_802_2_SNAP.protocol_type);
289 break;
290
291 case DLIL_DESC_SNAP: {
292 u_int8_t* pDest = ((u_int8_t*)&ed[i].data[0]) + 3;
293 ed[i].type = DLIL_DESC_SNAP;
9bccf70c 294 bcopy(desc->native_type, pDest, 5);
7b1edb79
A
295 }
296 break;
297 }
298 }
299
300 return 0;
1c79356b
A
301}
302
303
304static
305int ether_shutdown()
306{
307 return 0;
308}
309
310
1c79356b
A
311int ether_demux(ifp, m, frame_header, proto)
312 struct ifnet *ifp;
313 struct mbuf *m;
314 char *frame_header;
315 struct if_proto **proto;
316
317{
318 register struct ether_header *eh = (struct ether_header *)frame_header;
7b1edb79
A
319 u_short ether_type = eh->ether_type;
320 u_int16_t type;
321 u_int8_t *data;
322 u_long i = 0;
323 u_long max = ether_desc_blk[ifp->family_cookie].n_max_used;
324 struct en_desc *ed = ether_desc_blk[ifp->family_cookie].block_ptr;
325 u_int32_t extProto1 = 0;
326 u_int32_t extProto2 = 0;
327
1c79356b 328 if (eh->ether_dhost[0] & 1) {
7b1edb79
A
329 /* Check for broadcast */
330 if (*(u_int32_t*)eh->ether_dhost == 0xFFFFFFFF &&
331 *(u_int16_t*)(eh->ether_dhost + sizeof(u_int32_t)) == 0xFFFF)
332 m->m_flags |= M_BCAST;
333 else
334 m->m_flags |= M_MCAST;
1c79356b 335 }
7b1edb79
A
336
337 data = mtod(m, u_int8_t*);
338
339 /*
340 * Determine the packet's protocol type and stuff the protocol into
341 * longs for quick compares.
342 */
343
9bccf70c 344 if (ntohs(ether_type) <= 1500) {
7b1edb79
A
345 extProto1 = *(u_int32_t*)data;
346
347 // SAP or SNAP
348 if ((extProto1 & htonl(0xFFFFFF00)) == htonl(0xAAAA0300)) {
349 // SNAP
350 type = DLIL_DESC_SNAP;
351 extProto2 = *(u_int32_t*)(data + sizeof(u_int32_t));
352 extProto1 &= htonl(0x000000FF);
353 } else {
354 type = DLIL_DESC_SAP;
355 extProto1 &= htonl(0xFFFFFF00);
356 }
357 } else {
358 type = DLIL_DESC_ETYPE2;
359 }
360
1c79356b
A
361 /*
362 * Search through the connected protocols for a match.
363 */
7b1edb79
A
364
365 switch (type) {
366 case DLIL_DESC_ETYPE2:
367 for (i = 0; i < max; i++) {
368 if ((ed[i].type == type) && (ed[i].data[0] == ether_type)) {
369 *proto = ed[i].proto;
370 return 0;
371 }
372 }
373 break;
374
375 case DLIL_DESC_SAP:
376 for (i = 0; i < max; i++) {
377 if ((ed[i].type == type) && (ed[i].data[0] == extProto1)) {
378 *proto = ed[i].proto;
379 return 0;
380 }
381 }
382 break;
383
384 case DLIL_DESC_SNAP:
385 for (i = 0; i < max; i++) {
386 if ((ed[i].type == type) && (ed[i].data[0] == extProto1) &&
387 (ed[i].data[1] == extProto2)) {
388 *proto = ed[i].proto;
389 return 0;
390 }
391 }
392 break;
1c79356b 393 }
7b1edb79 394
1c79356b
A
395 return ENOENT;
396}
397
398
399
400/*
401 * Ethernet output routine.
402 * Encapsulate a packet of type family for the local net.
403 * Use trailer local net encapsulation if enough data in first
404 * packet leaves a multiple of 512 bytes of data in remainder.
405 * Assumes that ifp is actually pointer to arpcom structure.
406 */
407int
408ether_frameout(ifp, m, ndest, edst, ether_type)
409 register struct ifnet *ifp;
410 struct mbuf **m;
411 struct sockaddr *ndest;
412 char *edst;
413 char *ether_type;
414{
415 register struct ether_header *eh;
416 int hlen; /* link layer header lenght */
417 struct arpcom *ac = IFP2AC(ifp);
418
419
420 hlen = ETHER_HDR_LEN;
421
422 /*
423 * If a simplex interface, and the packet is being sent to our
424 * Ethernet address or a broadcast address, loopback a copy.
425 * XXX To make a simplex device behave exactly like a duplex
426 * device, we should copy in the case of sending to our own
427 * ethernet address (thus letting the original actually appear
428 * on the wire). However, we don't do that here for security
429 * reasons and compatibility with the original behavior.
430 */
431 if ((ifp->if_flags & IFF_SIMPLEX) &&
432 ((*m)->m_flags & M_LOOP)) {
433 if (lo_dlt == 0)
7b1edb79 434 dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dlt);
1c79356b
A
435
436 if (lo_dlt) {
7b1edb79
A
437 if ((*m)->m_flags & M_BCAST) {
438 struct mbuf *n = m_copy(*m, 0, (int)M_COPYALL);
439 if (n != NULL)
440 dlil_output(lo_dlt, n, 0, ndest, 0);
441 }
442 else
443 {
444 if (bcmp(edst, ac->ac_enaddr, ETHER_ADDR_LEN) == 0) {
445 dlil_output(lo_dlt, *m, 0, ndest, 0);
446 return EJUSTRETURN;
447 }
448 }
1c79356b
A
449 }
450 }
7b1edb79
A
451
452
1c79356b
A
453 /*
454 * Add local net header. If no space in first mbuf,
455 * allocate another.
456 */
457 M_PREPEND(*m, sizeof (struct ether_header), M_DONTWAIT);
458 if (*m == 0) {
459 return (EJUSTRETURN);
460 }
461
462
463 eh = mtod(*m, struct ether_header *);
464 (void)memcpy(&eh->ether_type, ether_type,
465 sizeof(eh->ether_type));
466 (void)memcpy(eh->ether_dhost, edst, 6);
467 (void)memcpy(eh->ether_shost, ac->ac_enaddr,
468 sizeof(eh->ether_shost));
469
470 return 0;
471}
472
473
474static
475int ether_add_if(struct ifnet *ifp)
476{
477 u_long i;
478
479 ifp->if_framer = ether_frameout;
480 ifp->if_demux = ether_demux;
481 ifp->if_event = 0;
482
483 for (i=0; i < MAX_INTERFACES; i++)
7b1edb79
A
484 if (ether_desc_blk[i].n_count == 0)
485 break;
1c79356b
A
486
487 if (i == MAX_INTERFACES)
7b1edb79 488 return ENOMEM;
1c79356b 489
7b1edb79
A
490 ether_desc_blk[i].block_ptr = _MALLOC(ETHER_DESC_BLK_SIZE * sizeof(struct en_desc),
491 M_IFADDR, M_WAITOK);
1c79356b 492 if (ether_desc_blk[i].block_ptr == 0)
7b1edb79 493 return ENOMEM;
1c79356b 494
7b1edb79
A
495 ether_desc_blk[i].n_count = ETHER_DESC_BLK_SIZE;
496 bzero(ether_desc_blk[i].block_ptr, ETHER_DESC_BLK_SIZE * sizeof(struct en_desc));
1c79356b
A
497
498 ifp->family_cookie = i;
499
500 return 0;
501}
502
503static
504int ether_del_if(struct ifnet *ifp)
505{
506 if ((ifp->family_cookie < MAX_INTERFACES) &&
7b1edb79
A
507 (ether_desc_blk[ifp->family_cookie].n_count))
508 {
509 FREE(ether_desc_blk[ifp->family_cookie].block_ptr, M_IFADDR);
510 ether_desc_blk[ifp->family_cookie].block_ptr = NULL;
511 ether_desc_blk[ifp->family_cookie].n_count = 0;
512 ether_desc_blk[ifp->family_cookie].n_max_used = 0;
513 return 0;
1c79356b
A
514 }
515 else
7b1edb79 516 return ENOENT;
1c79356b
A
517}
518
9bccf70c
A
519static
520int ether_init_if(struct ifnet *ifp)
521{
522 register struct ifaddr *ifa;
523 register struct sockaddr_dl *sdl;
524
525 ifa = ifnet_addrs[ifp->if_index - 1];
526 if (ifa == 0) {
527 printf("ether_ifattach: no lladdr!\n");
528 return;
529 }
530 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
531 sdl->sdl_type = IFT_ETHER;
532 sdl->sdl_alen = ifp->if_addrlen;
533 bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
534
535 return 0;
536}
1c79356b
A
537
538
539int
540ether_ifmod_ioctl(ifp, command, data)
541 struct ifnet *ifp;
542 u_long command;
543 caddr_t data;
544{
545 struct rslvmulti_req *rsreq = (struct rslvmulti_req *) data;
546 int error = 0;
547 struct sockaddr_dl *sdl;
548 struct sockaddr_in *sin;
549 u_char *e_addr;
550
551
7b1edb79
A
552 switch (command) {
553 case SIOCRSLVMULTI:
554 switch(rsreq->sa->sa_family) {
555 case AF_UNSPEC:
556 /* AppleTalk uses AF_UNSPEC for multicast registration.
557 * No mapping needed. Just check that it's a valid MC address.
558 */
559 e_addr = &rsreq->sa->sa_data[0];
560 if ((e_addr[0] & 1) != 1)
561 return EADDRNOTAVAIL;
562 *rsreq->llsa = 0;
563 return EJUSTRETURN;
564
565
566 case AF_LINK:
567 /*
568 * No mapping needed. Just check that it's a valid MC address.
569 */
570 sdl = (struct sockaddr_dl *)rsreq->sa;
571 e_addr = LLADDR(sdl);
572 if ((e_addr[0] & 1) != 1)
573 return EADDRNOTAVAIL;
574 *rsreq->llsa = 0;
575 return EJUSTRETURN;
576
577 default:
578 return EAFNOSUPPORT;
579 }
580
581 default:
582 return EOPNOTSUPP;
1c79356b
A
583 }
584}
585
586
587int ether_family_init()
588{
589 int i;
590 struct dlil_ifmod_reg_str ifmod_reg;
591
9bccf70c
A
592 /* ethernet family is built-in, called from bsd_init */
593 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
1c79356b 594
9bccf70c 595 bzero(&ifmod_reg, sizeof(ifmod_reg));
1c79356b
A
596 ifmod_reg.add_if = ether_add_if;
597 ifmod_reg.del_if = ether_del_if;
9bccf70c 598 ifmod_reg.init_if = ether_init_if;
1c79356b
A
599 ifmod_reg.add_proto = ether_add_proto;
600 ifmod_reg.del_proto = ether_del_proto;
601 ifmod_reg.ifmod_ioctl = ether_ifmod_ioctl;
602 ifmod_reg.shutdown = ether_shutdown;
603
604 if (dlil_reg_if_modules(APPLE_IF_FAM_ETHERNET, &ifmod_reg)) {
7b1edb79
A
605 printf("WARNING: ether_family_init -- Can't register if family modules\n");
606 return EIO;
1c79356b
A
607 }
608
1c79356b 609 for (i=0; i < MAX_INTERFACES; i++)
7b1edb79 610 ether_desc_blk[i].n_count = 0;
1c79356b 611
9bccf70c
A
612 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
613
1c79356b
A
614 return 0;
615}