]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ether_if_module.c
2d1a9f52a3b894a0c7061415ec9471941b9e742a
[apple/xnu.git] / bsd / net / ether_if_module.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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>
73 #include <net/ndrv.h>
74 #include <netinet/if_ether.h>
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
92 extern 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
99 extern 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
112 static u_long lo_dlt = 0;
113 static ivedonethis = 0;
114
115 #define IFP2AC(IFP) ((struct arpcom *)IFP)
116
117 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
118
119
120 #define DB_HEADER_SIZE 20
121 struct en_desc {
122 short total_len;
123 u_short ethertype;
124 u_long dl_tag;
125 struct ifnet *ifp;
126 struct if_proto *proto;
127 u_long proto_id_length;
128 u_long proto_id_data[8]; /* probably less - proto-id and bitmasks */
129 };
130
131 #define LITMUS_SIZE 16
132 #define ETHER_DESC_BLK_SIZE 50
133 #define MAX_INTERFACES 50
134
135 /*
136 * Statics for demux module
137 */
138
139 struct ether_desc_blk_str {
140 u_long n_blocks;
141 u_long *block_ptr;
142 };
143
144 struct dl_es_at_entry
145 {
146 struct ifnet *ifp;
147 u_long dl_tag;
148 int ref_count;
149 };
150
151
152 static struct ether_desc_blk_str ether_desc_blk[MAX_INTERFACES];
153 static u_long litmus_mask[LITMUS_SIZE];
154 static u_long litmus_length = 0;
155
156
157 /*
158 * Temp static for protocol registration XXX
159 */
160
161 #define MAX_EN_COUNT 30
162
163 static struct dl_es_at_entry en_at_array[MAX_EN_COUNT];
164
165 /*
166 * This could be done below in-line with heavy casting, but the pointer arithmetic is
167 * prone to error.
168 */
169
170 static
171 int desc_in_bounds(block, current_ptr, offset_length)
172 u_int block;
173 char *current_ptr;
174 u_long offset_length;
175 {
176 u_long end_of_block;
177 u_long current_ptr_tmp;
178
179 current_ptr_tmp = (u_long) current_ptr;
180 end_of_block = (u_long) ether_desc_blk[block].block_ptr;
181 end_of_block += (ETHER_DESC_BLK_SIZE * ether_desc_blk[block].n_blocks);
182 if ((current_ptr_tmp + offset_length) < end_of_block)
183 return 1;
184 else
185 return 0;
186 }
187
188
189 /*
190 * Release all descriptor entries owned by this dl_tag (there may be several).
191 * Setting the dl_tag to 0 releases the entry. Eventually we should compact-out
192 * the unused entries.
193 */
194 static
195 int ether_del_proto(struct if_proto *proto, u_long dl_tag)
196 {
197 char *current_ptr = (char *) ether_desc_blk[proto->ifp->family_cookie].block_ptr;
198 struct en_desc *ed;
199 int i;
200 int found = 0;
201
202 ed = (struct en_desc *) current_ptr;
203
204 while(ed->total_len) {
205 if (ed->dl_tag == dl_tag) {
206 found = 1;
207 ed->dl_tag = 0;
208 }
209
210 current_ptr += ed->total_len;
211 ed = (struct en_desc *) current_ptr;
212 }
213 }
214
215
216
217 static
218 int ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
219 {
220 char *current_ptr;
221 struct dlil_demux_desc *desc;
222 u_long id_length; /* IN LONGWORDS!!! */
223 struct en_desc *ed;
224 u_long *bitmask;
225 u_long *proto_id;
226 int i;
227 short total_length;
228 u_long block_count;
229 u_long *tmp;
230
231
232 TAILQ_FOREACH(desc, desc_head, next) {
233 switch (desc->type)
234 {
235 case DLIL_DESC_RAW:
236 id_length = desc->variants.bitmask.proto_id_length;
237 break;
238
239 case DLIL_DESC_802_2:
240 id_length = 1;
241 break;
242
243 case DLIL_DESC_802_2_SNAP:
244 id_length = 2;
245 break;
246
247 default:
248 return EINVAL;
249 }
250
251 restart:
252 block_count = ether_desc_blk[proto->ifp->family_cookie].n_blocks;
253 current_ptr = (char *) ether_desc_blk[proto->ifp->family_cookie].block_ptr;
254 ed = (struct en_desc *) current_ptr;
255 total_length = ((id_length << 2) * 2) + DB_HEADER_SIZE;
256
257 while ((ed->total_len) && (desc_in_bounds(proto->ifp->family_cookie,
258 current_ptr, total_length))) {
259 if ((ed->dl_tag == 0) && (total_length <= ed->total_len))
260 break;
261 else
262 current_ptr += *(short *)current_ptr;
263
264 ed = (struct en_desc *) current_ptr;
265 }
266
267 if (!desc_in_bounds(proto->ifp->family_cookie, current_ptr, total_length)) {
268
269 tmp = _MALLOC((ETHER_DESC_BLK_SIZE * (block_count + 1)),
270 M_IFADDR, M_NOWAIT);
271 if (tmp == 0) {
272 /*
273 * Remove any previous descriptors set in the call.
274 */
275 ether_del_proto(proto, dl_tag);
276 return ENOMEM;
277 }
278
279 bzero(tmp, ETHER_DESC_BLK_SIZE * (block_count + 1));
280 bcopy(ether_desc_blk[proto->ifp->family_cookie].block_ptr,
281 tmp, (ETHER_DESC_BLK_SIZE * block_count));
282 FREE(ether_desc_blk[proto->ifp->family_cookie].block_ptr, M_IFADDR);
283 ether_desc_blk[proto->ifp->family_cookie].n_blocks = block_count + 1;
284 ether_desc_blk[proto->ifp->family_cookie].block_ptr = tmp;
285 goto restart;
286 }
287
288 if (ed->total_len == 0)
289 ed->total_len = total_length;
290 ed->ethertype = *((u_short *) desc->native_type);
291
292 ed->dl_tag = dl_tag;
293 ed->proto = proto;
294 ed->proto_id_length = id_length;
295 ed->ifp = proto->ifp;
296
297 switch (desc->type)
298 {
299 case DLIL_DESC_RAW:
300 bcopy(desc->variants.bitmask.proto_id, &ed->proto_id_data[0], (id_length << 2) );
301 bcopy(desc->variants.bitmask.proto_id_mask, &ed->proto_id_data[id_length],
302 (id_length << 2));
303 break;
304
305 case DLIL_DESC_802_2:
306 ed->proto_id_data[0] = 0;
307 bcopy(&desc->variants.desc_802_2, &ed->proto_id_data[0], 3);
308 ed->proto_id_data[1] = 0xffffff00;
309 break;
310
311 case DLIL_DESC_802_2_SNAP:
312 /* XXX Add verification of fixed values here */
313
314 ed->proto_id_data[0] = 0;
315 ed->proto_id_data[1] = 0;
316 bcopy(&desc->variants.desc_802_2_SNAP, &ed->proto_id_data[0], 8);
317 ed->proto_id_data[2] = 0xffffffff;
318 ed->proto_id_data[3] = 0xffffffff;;
319 break;
320 }
321
322 if (id_length) {
323 proto_id = (u_long *) &ed->proto_id_data[0];
324 bitmask = (u_long *) &ed->proto_id_data[id_length];
325 for (i=0; i < (id_length); i++) {
326 litmus_mask[i] &= bitmask[i];
327 litmus_mask[i] &= proto_id[i];
328 }
329 if (id_length > litmus_length)
330 litmus_length = id_length;
331 }
332 }
333
334 return 0;
335 }
336
337
338 static
339 int ether_shutdown()
340 {
341 return 0;
342 }
343
344
345
346
347
348 int ether_demux(ifp, m, frame_header, proto)
349 struct ifnet *ifp;
350 struct mbuf *m;
351 char *frame_header;
352 struct if_proto **proto;
353
354 {
355 register struct ether_header *eh = (struct ether_header *)frame_header;
356 u_short ether_type;
357 char *current_ptr = (char *) ether_desc_blk[ifp->family_cookie].block_ptr;
358 struct dlil_demux_desc *desc;
359 register u_long temp;
360 u_long *data;
361 register struct if_proto *ifproto;
362 u_long i;
363 struct en_desc *ed;
364
365
366 if (eh->ether_dhost[0] & 1) {
367 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
368 sizeof(etherbroadcastaddr)) == 0)
369 m->m_flags |= M_BCAST;
370 else
371 m->m_flags |= M_MCAST;
372 }
373
374 ether_type = ntohs(eh->ether_type);
375
376 /*
377 * Search through the connected protocols for a match.
378 */
379
380
381 data = mtod(m, u_long *);
382 ed = (struct en_desc *) current_ptr;
383 while (desc_in_bounds(ifp->family_cookie, current_ptr, DB_HEADER_SIZE)) {
384 if (ed->total_len == 0)
385 break;
386
387 if ((ed->dl_tag != 0) && (ed->ifp == ifp) &&
388 ((ed->ethertype == ntohs(eh->ether_type)) || (ed->ethertype == 0))) {
389 if (ed->proto_id_length) {
390 for (i=0; i < (ed->proto_id_length); i++) {
391 temp = ntohs(data[i]) & ed->proto_id_data[ed->proto_id_length + i];
392 if ((temp ^ ed->proto_id_data[i]))
393 break;
394 }
395
396 if (i >= (ed->proto_id_length)) {
397 *proto = ed->proto;
398 return 0;
399 }
400 }
401 else {
402 *proto = ed->proto;
403 return 0;
404 }
405 }
406 current_ptr += ed->total_len;
407 ed = (struct en_desc *) current_ptr;
408 }
409
410 /*
411 kprintf("ether_demux - No match for <%x><%x><%x><%x><%x><%x><%x<%x>\n",
412 eh->ether_type,data[0], data[1], data[2], data[3], data[4],data[5],data[6]);
413 */
414
415 return ENOENT;
416 }
417
418
419
420 /*
421 * Ethernet output routine.
422 * Encapsulate a packet of type family for the local net.
423 * Use trailer local net encapsulation if enough data in first
424 * packet leaves a multiple of 512 bytes of data in remainder.
425 * Assumes that ifp is actually pointer to arpcom structure.
426 */
427 int
428 ether_frameout(ifp, m, ndest, edst, ether_type)
429 register struct ifnet *ifp;
430 struct mbuf **m;
431 struct sockaddr *ndest;
432 char *edst;
433 char *ether_type;
434 {
435 register struct ether_header *eh;
436 int hlen; /* link layer header lenght */
437 struct arpcom *ac = IFP2AC(ifp);
438
439
440 hlen = ETHER_HDR_LEN;
441
442 /*
443 * If a simplex interface, and the packet is being sent to our
444 * Ethernet address or a broadcast address, loopback a copy.
445 * XXX To make a simplex device behave exactly like a duplex
446 * device, we should copy in the case of sending to our own
447 * ethernet address (thus letting the original actually appear
448 * on the wire). However, we don't do that here for security
449 * reasons and compatibility with the original behavior.
450 */
451 if ((ifp->if_flags & IFF_SIMPLEX) &&
452 ((*m)->m_flags & M_LOOP)) {
453 if (lo_dlt == 0)
454 dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dlt);
455
456 if (lo_dlt) {
457 if ((*m)->m_flags & M_BCAST) {
458 struct mbuf *n = m_copy(*m, 0, (int)M_COPYALL);
459 dlil_output(lo_dlt, n, 0, ndest, 0);
460 }
461 else
462 {
463 if (bcmp(edst, ac->ac_enaddr, ETHER_ADDR_LEN) == 0) {
464 dlil_output(lo_dlt, *m, 0, ndest, 0);
465 return EJUSTRETURN;
466 }
467 }
468 }
469 }
470
471
472 /*
473 * Add local net header. If no space in first mbuf,
474 * allocate another.
475 */
476 M_PREPEND(*m, sizeof (struct ether_header), M_DONTWAIT);
477 if (*m == 0) {
478 return (EJUSTRETURN);
479 }
480
481
482 eh = mtod(*m, struct ether_header *);
483 (void)memcpy(&eh->ether_type, ether_type,
484 sizeof(eh->ether_type));
485 (void)memcpy(eh->ether_dhost, edst, 6);
486 (void)memcpy(eh->ether_shost, ac->ac_enaddr,
487 sizeof(eh->ether_shost));
488
489 return 0;
490 }
491
492
493 static
494 int ether_add_if(struct ifnet *ifp)
495 {
496 u_long i;
497
498 ifp->if_framer = ether_frameout;
499 ifp->if_demux = ether_demux;
500 ifp->if_event = 0;
501
502 for (i=0; i < MAX_INTERFACES; i++)
503 if (ether_desc_blk[i].n_blocks == 0)
504 break;
505
506 if (i == MAX_INTERFACES)
507 return ENOMEM;
508
509 ether_desc_blk[i].block_ptr = _MALLOC(ETHER_DESC_BLK_SIZE, M_IFADDR, M_NOWAIT);
510 if (ether_desc_blk[i].block_ptr == 0)
511 return ENOMEM;
512
513 ether_desc_blk[i].n_blocks = 1;
514 bzero(ether_desc_blk[i].block_ptr, ETHER_DESC_BLK_SIZE);
515
516 ifp->family_cookie = i;
517
518 return 0;
519 }
520
521 static
522 int ether_del_if(struct ifnet *ifp)
523 {
524 if ((ifp->family_cookie < MAX_INTERFACES) &&
525 (ether_desc_blk[ifp->family_cookie].n_blocks)) {
526 FREE(ether_desc_blk[ifp->family_cookie].block_ptr, M_IFADDR);
527 ether_desc_blk[ifp->family_cookie].n_blocks = 0;
528 return 0;
529 }
530 else
531 return ENOENT;
532 }
533
534
535
536 int
537 ether_ifmod_ioctl(ifp, command, data)
538 struct ifnet *ifp;
539 u_long command;
540 caddr_t data;
541 {
542 struct rslvmulti_req *rsreq = (struct rslvmulti_req *) data;
543 int error = 0;
544 struct sockaddr_dl *sdl;
545 struct sockaddr_in *sin;
546 u_char *e_addr;
547
548
549 switch (command)
550 {
551 case SIOCRSLVMULTI:
552 switch(rsreq->sa->sa_family)
553 {
554 case AF_UNSPEC:
555 /* AppleTalk uses AF_UNSPEC for multicast registration.
556 * No mapping needed. Just check that it's a valid MC address.
557 */
558 e_addr = &rsreq->sa->sa_data[0];
559 if ((e_addr[0] & 1) != 1)
560 return EADDRNOTAVAIL;
561 *rsreq->llsa = 0;
562 return EJUSTRETURN;
563
564
565 case AF_LINK:
566 /*
567 * No mapping needed. Just check that it's a valid MC address.
568 */
569 sdl = (struct sockaddr_dl *)rsreq->sa;
570 e_addr = LLADDR(sdl);
571 if ((e_addr[0] & 1) != 1)
572 return EADDRNOTAVAIL;
573 *rsreq->llsa = 0;
574 return EJUSTRETURN;
575
576 default:
577 return EAFNOSUPPORT;
578 }
579
580 default:
581 return EOPNOTSUPP;
582 }
583 }
584
585
586 int ether_family_init()
587 {
588 int i;
589 struct dlil_ifmod_reg_str ifmod_reg;
590
591 if (ivedonethis)
592 return 0;
593
594 ivedonethis = 1;
595
596 ifmod_reg.add_if = ether_add_if;
597 ifmod_reg.del_if = ether_del_if;
598 ifmod_reg.add_proto = ether_add_proto;
599 ifmod_reg.del_proto = ether_del_proto;
600 ifmod_reg.ifmod_ioctl = ether_ifmod_ioctl;
601 ifmod_reg.shutdown = ether_shutdown;
602
603 if (dlil_reg_if_modules(APPLE_IF_FAM_ETHERNET, &ifmod_reg)) {
604 printf("WARNING: ether_family_init -- Can't register if family modules\n");
605 return EIO;
606 }
607
608 for (i=0; i < (LITMUS_SIZE/4); i++)
609 litmus_mask[i] = 0xffffffff;
610
611 for (i=0; i < MAX_INTERFACES; i++)
612 ether_desc_blk[i].n_blocks = 0;
613
614 for (i=0; i < MAX_EN_COUNT; i++)
615 en_at_array[i].ifp = 0;
616
617 return 0;
618 }