if_ethersubr.c revision 1.5 1 /*
2 * Copyright (c) 1982, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)if_ethersubr.c 7.13 (Berkeley) 4/20/91
34 * $Id: if_ethersubr.c,v 1.5 1994/01/23 23:41:14 deraadt Exp $
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <sys/errno.h>
46 #include <sys/syslog.h>
47
48 #include <net/if.h>
49 #include <net/netisr.h>
50 #include <net/route.h>
51 #include <net/if_llc.h>
52 #include <net/if_dl.h>
53
54 #ifdef INET
55 #include <netinet/in.h>
56 #include <netinet/in_var.h>
57 #endif
58 #include <netinet/if_ether.h>
59
60 #ifdef NS
61 #include <netns/ns.h>
62 #include <netns/ns_if.h>
63 #endif
64
65 #ifdef ISO
66 #include <netiso/argo_debug.h>
67 #include <netiso/iso.h>
68 #include <netiso/iso_var.h>
69 #include <netiso/iso_snpac.h>
70 #endif
71
72 #include <machine/cpu.h>
73
74 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
75 extern struct ifnet loif;
76
77 /*
78 * Ethernet output routine.
79 * Encapsulate a packet of type family for the local net.
80 * Use trailer local net encapsulation if enough data in first
81 * packet leaves a multiple of 512 bytes of data in remainder.
82 * Assumes that ifp is actually pointer to arpcom structure.
83 */
84 ether_output(ifp, m0, dst, rt)
85 register struct ifnet *ifp;
86 struct mbuf *m0;
87 struct sockaddr *dst;
88 struct rtentry *rt;
89 {
90 u_short type;
91 int s, error = 0;
92 u_char edst[6];
93 struct in_addr idst;
94 register struct mbuf *m = m0;
95 struct mbuf *mcopy = (struct mbuf *)0;
96 register struct ether_header *eh;
97 int usetrailers, off, len = m->m_pkthdr.len;
98 #define ac ((struct arpcom *)ifp)
99
100 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
101 error = ENETDOWN;
102 goto bad;
103 }
104 ifp->if_lastchange = time;
105 switch (dst->sa_family) {
106
107 #ifdef INET
108 case AF_INET:
109 idst = ((struct sockaddr_in *)dst)->sin_addr;
110 if (!arpresolve(ac, m, &idst, edst, &usetrailers))
111 return (0); /* if not yet resolved */
112 /* If broadcasting on a simplex interface, loopback a copy */
113 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
114 mcopy = m_copy(m, 0, (int)M_COPYALL);
115 off = m->m_pkthdr.len - m->m_len;
116 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
117 (m->m_flags & M_EXT) == 0 &&
118 m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
119 type = ETHERTYPE_TRAIL + (off>>9);
120 m->m_data -= 2 * sizeof (u_short);
121 m->m_len += 2 * sizeof (u_short);
122 len += 2 * sizeof (u_short);
123 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
124 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
125 goto gottrailertype;
126 }
127 type = ETHERTYPE_IP;
128 goto gottype;
129 #endif
130 #ifdef NS
131 case AF_NS:
132 type = ETHERTYPE_NS;
133 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
134 (caddr_t)edst, sizeof (edst));
135 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
136 return (looutput(ifp, m, dst, rt));
137 /* If broadcasting on a simplex interface, loopback a copy */
138 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
139 mcopy = m_copy(m, 0, (int)M_COPYALL);
140 goto gottype;
141 #endif
142 #ifdef ISO
143 case AF_ISO: {
144 int snpalen;
145 struct llc *l;
146
147 iso_again:
148 if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
149 if (rt->rt_flags & RTF_GATEWAY) {
150 if (rt->rt_llinfo) {
151 rt = (struct rtentry *)rt->rt_llinfo;
152 goto iso_again;
153 }
154 } else {
155 register struct sockaddr_dl *sdl =
156 (struct sockaddr_dl *)rt->rt_gateway;
157 if (sdl && sdl->sdl_family == AF_LINK
158 && sdl->sdl_alen > 0) {
159 bcopy(LLADDR(sdl), (char *)edst,
160 sizeof(edst));
161 goto iso_resolved;
162 }
163 }
164 }
165 if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
166 (char *)edst, &snpalen)) > 0)
167 goto bad; /* Not Resolved */
168 iso_resolved:
169 /* If broadcasting on a simplex interface, loopback a copy */
170 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
171 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
172 M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
173 if (mcopy) {
174 eh = mtod(mcopy, struct ether_header *);
175 bcopy((caddr_t)edst,
176 (caddr_t)eh->ether_dhost, sizeof (edst));
177 bcopy((caddr_t)ac->ac_enaddr,
178 (caddr_t)eh->ether_shost, sizeof (edst));
179 }
180 }
181 M_PREPEND(m, 3, M_DONTWAIT);
182 if (m == NULL)
183 return (0);
184 type = m->m_pkthdr.len;
185 l = mtod(m, struct llc *);
186 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
187 l->llc_control = LLC_UI;
188 len += 3;
189 IFDEBUG(D_ETHER)
190 int i;
191 printf("unoutput: sending pkt to: ");
192 for (i=0; i<6; i++)
193 printf("%x ", edst[i] & 0xff);
194 printf("\n");
195 ENDDEBUG
196 }
197 goto gottype;
198 #endif ISO
199 #ifdef RMP
200 case AF_RMP:
201 /*
202 * This is IEEE 802.3 -- the Ethernet `type' field is
203 * really a `length' field.
204 */
205 type = m->m_len;
206 bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
207 break;
208 #endif
209
210 case AF_UNSPEC:
211 eh = (struct ether_header *)dst->sa_data;
212 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
213 /* AF_UNSPEC doesn't swap the byte order of the ether_type */
214 type = ntohs(eh->ether_type);
215 goto gottype;
216
217 default:
218 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
219 dst->sa_family);
220 error = EAFNOSUPPORT;
221 goto bad;
222 }
223
224 gottrailertype:
225 /*
226 * Packet to be sent as trailer: move first packet
227 * (control information) to end of chain.
228 */
229 while (m->m_next)
230 m = m->m_next;
231 m->m_next = m0;
232 m = m0->m_next;
233 m0->m_next = 0;
234
235 gottype:
236 if (mcopy)
237 (void) looutput(ifp, mcopy, dst, rt);
238 /*
239 * Add local net header. If no space in first mbuf,
240 * allocate another.
241 */
242 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
243 if (m == 0) {
244 error = ENOBUFS;
245 goto bad;
246 }
247 eh = mtod(m, struct ether_header *);
248 type = htons((u_short)type);
249 bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
250 sizeof(eh->ether_type));
251 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
252 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
253 sizeof(eh->ether_shost));
254 s = splimp();
255 /*
256 * Queue message on interface, and start output if interface
257 * not yet active.
258 */
259 if (IF_QFULL(&ifp->if_snd)) {
260 IF_DROP(&ifp->if_snd);
261 splx(s);
262 error = ENOBUFS;
263 goto bad;
264 }
265 IF_ENQUEUE(&ifp->if_snd, m);
266 if ((ifp->if_flags & IFF_OACTIVE) == 0)
267 (*ifp->if_start)(ifp);
268 splx(s);
269 ifp->if_obytes += len + sizeof (struct ether_header);
270 #ifdef MULTICAST
271 if (m->m_flags & M_MCAST)
272 #else
273 if (edst[0] & 1)
274 #endif
275 ifp->if_omcasts++;
276 return (error);
277
278 bad:
279 if (m)
280 m_freem(m);
281 return (error);
282 }
283
284 /*
285 * Process a received Ethernet packet;
286 * the packet is in the mbuf chain m without
287 * the ether header, which is provided separately.
288 */
289 ether_input(ifp, eh, m)
290 struct ifnet *ifp;
291 register struct ether_header *eh;
292 struct mbuf *m;
293 {
294 register struct ifqueue *inq;
295 register struct llc *l;
296 u_short etype;
297 int s;
298
299 ifp->if_lastchange = time;
300 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
301 #ifdef MULTICAST
302 if (eh->ether_dhost[0] & 1) {
303 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
304 sizeof(etherbroadcastaddr)) == 0)
305 m->m_flags |= M_BCAST;
306 else
307 m->m_flags |= M_MCAST;
308 }
309 #else
310 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
311 sizeof(etherbroadcastaddr)) == 0)
312 m->m_flags |= M_BCAST;
313 else if (eh->ether_dhost[0] & 1)
314 m->m_flags |= M_MCAST;
315 #endif
316 if (m->m_flags & (M_BCAST|M_MCAST))
317 ifp->if_imcasts++;
318
319 etype = ntohs(eh->ether_type);
320 switch (etype) {
321 #ifdef INET
322 case ETHERTYPE_IP:
323 schednetisr(NETISR_IP);
324 inq = &ipintrq;
325 break;
326
327 case ETHERTYPE_ARP:
328 arpinput((struct arpcom *)ifp, m);
329 return;
330 #endif
331 #ifdef NS
332 case ETHERTYPE_NS:
333 schednetisr(NETISR_NS);
334 inq = &nsintrq;
335 break;
336
337 #endif
338 default:
339 #ifdef ISO
340 if (etype > ETHERMTU)
341 goto dropanyway;
342 l = mtod(m, struct llc *);
343 switch (l->llc_control) {
344 case LLC_UI:
345 /* LLC_UI_P forbidden in class 1 service */
346 if ((l->llc_dsap == LLC_ISO_LSAP) &&
347 (l->llc_ssap == LLC_ISO_LSAP)) {
348 /* LSAP for ISO */
349 if (m->m_pkthdr.len > etype)
350 m_adj(m, etype - m->m_pkthdr.len);
351 m->m_data += 3; /* XXX */
352 m->m_len -= 3; /* XXX */
353 m->m_pkthdr.len -= 3; /* XXX */
354 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
355 if (m == 0)
356 return;
357 *mtod(m, struct ether_header *) = *eh;
358 IFDEBUG(D_ETHER)
359 printf("clnp packet");
360 ENDDEBUG
361 schednetisr(NETISR_ISO);
362 inq = &clnlintrq;
363 break;
364 }
365 goto dropanyway;
366
367 case LLC_XID:
368 case LLC_XID_P:
369 if(m->m_len < 6)
370 goto dropanyway;
371 l->llc_window = 0;
372 l->llc_fid = 9;
373 l->llc_class = 1;
374 l->llc_dsap = l->llc_ssap = 0;
375 /* Fall through to */
376 case LLC_TEST:
377 case LLC_TEST_P:
378 {
379 struct sockaddr sa;
380 register struct ether_header *eh2;
381 int i;
382 u_char c = l->llc_dsap;
383 l->llc_dsap = l->llc_ssap;
384 l->llc_ssap = c;
385 if (m->m_flags & (M_BCAST | M_MCAST))
386 bcopy((caddr_t)ac->ac_enaddr,
387 (caddr_t)eh->ether_dhost, 6);
388 sa.sa_family = AF_UNSPEC;
389 sa.sa_len = sizeof(sa);
390 eh2 = (struct ether_header *)sa.sa_data;
391 for (i = 0; i < 6; i++) {
392 eh2->ether_shost[i] = c = eh->ether_dhost[i];
393 eh2->ether_dhost[i] =
394 eh->ether_dhost[i] = eh->ether_shost[i];
395 eh->ether_shost[i] = c;
396 }
397 ifp->if_output(ifp, m, &sa);
398 return;
399 }
400 dropanyway:
401 default:
402 m_freem(m);
403 return;
404 }
405 #else
406 m_freem(m);
407 return;
408 #endif ISO
409 }
410
411 s = splimp();
412 if (IF_QFULL(inq)) {
413 IF_DROP(inq);
414 m_freem(m);
415 } else
416 IF_ENQUEUE(inq, m);
417 splx(s);
418 }
419
420 /*
421 * Convert Ethernet address to printable (loggable) representation.
422 */
423 static char digits[] = "0123456789abcdef";
424 char *
425 ether_sprintf(ap)
426 register u_char *ap;
427 {
428 register i;
429 static char etherbuf[18];
430 register char *cp = etherbuf;
431
432 for (i = 0; i < 6; i++) {
433 *cp++ = digits[*ap >> 4];
434 *cp++ = digits[*ap++ & 0xf];
435 *cp++ = ':';
436 }
437 *--cp = 0;
438 return (etherbuf);
439 }
440
441 #ifdef MULTICAST
442 u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
443 u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
444
445 /* XXX */
446 #undef ac
447 /*
448 * Add an Ethernet multicast address or range of addresses to the list for a
449 * given interface.
450 */
451 int
452 ether_addmulti(ifr, ac)
453 struct ifreq *ifr;
454 register struct arpcom *ac;
455 {
456 register struct ether_multi *enm;
457 struct sockaddr_in *sin;
458 u_char addrlo[6];
459 u_char addrhi[6];
460 int s = splimp();
461
462 switch (ifr->ifr_addr.sa_family) {
463
464 case AF_UNSPEC:
465 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
466 bcopy(addrlo, addrhi, 6);
467 break;
468
469 #ifdef INET
470 case AF_INET:
471 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
472 if (sin->sin_addr.s_addr == INADDR_ANY) {
473 /*
474 * An IP address of INADDR_ANY means listen to all
475 * of the Ethernet multicast addresses used for IP.
476 * (This is for the sake of IP multicast routers.)
477 */
478 bcopy(ether_ipmulticast_min, addrlo, 6);
479 bcopy(ether_ipmulticast_max, addrhi, 6);
480 }
481 else {
482 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
483 bcopy(addrlo, addrhi, 6);
484 }
485 break;
486 #endif
487
488 default:
489 splx(s);
490 return (EAFNOSUPPORT);
491 }
492
493 /*
494 * Verify that we have valid Ethernet multicast addresses.
495 */
496 if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
497 splx(s);
498 return (EINVAL);
499 }
500 /*
501 * See if the address range is already in the list.
502 */
503 ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
504 if (enm != NULL) {
505 /*
506 * Found it; just increment the reference count.
507 */
508 ++enm->enm_refcount;
509 splx(s);
510 return (0);
511 }
512 /*
513 * New address or range; malloc a new multicast record
514 * and link it into the interface's multicast list.
515 */
516 enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
517 if (enm == NULL) {
518 splx(s);
519 return (ENOBUFS);
520 }
521 bcopy(addrlo, enm->enm_addrlo, 6);
522 bcopy(addrhi, enm->enm_addrhi, 6);
523 enm->enm_ac = ac;
524 enm->enm_refcount = 1;
525 enm->enm_next = ac->ac_multiaddrs;
526 ac->ac_multiaddrs = enm;
527 ac->ac_multicnt++;
528 splx(s);
529 /*
530 * Return ENETRESET to inform the driver that the list has changed
531 * and its reception filter should be adjusted accordingly.
532 */
533 return (ENETRESET);
534 }
535
536 /*
537 * Delete a multicast address record.
538 */
539 int
540 ether_delmulti(ifr, ac)
541 struct ifreq *ifr;
542 register struct arpcom *ac;
543 {
544 register struct ether_multi *enm;
545 register struct ether_multi **p;
546 struct sockaddr_in *sin;
547 u_char addrlo[6];
548 u_char addrhi[6];
549 int s = splimp();
550
551 switch (ifr->ifr_addr.sa_family) {
552
553 case AF_UNSPEC:
554 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
555 bcopy(addrlo, addrhi, 6);
556 break;
557
558 #ifdef INET
559 case AF_INET:
560 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
561 if (sin->sin_addr.s_addr == INADDR_ANY) {
562 /*
563 * An IP address of INADDR_ANY means stop listening
564 * to the range of Ethernet multicast addresses used
565 * for IP.
566 */
567 bcopy(ether_ipmulticast_min, addrlo, 6);
568 bcopy(ether_ipmulticast_max, addrhi, 6);
569 }
570 else {
571 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
572 bcopy(addrlo, addrhi, 6);
573 }
574 break;
575 #endif
576
577 default:
578 splx(s);
579 return (EAFNOSUPPORT);
580 }
581
582 /*
583 * Look up the address in our list.
584 */
585 ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
586 if (enm == NULL) {
587 splx(s);
588 return (ENXIO);
589 }
590 if (--enm->enm_refcount != 0) {
591 /*
592 * Still some claims to this record.
593 */
594 splx(s);
595 return (0);
596 }
597 /*
598 * No remaining claims to this record; unlink and free it.
599 */
600 for (p = &enm->enm_ac->ac_multiaddrs;
601 *p != enm;
602 p = &(*p)->enm_next)
603 continue;
604 *p = (*p)->enm_next;
605 free(enm, M_IFMADDR);
606 ac->ac_multicnt--;
607 splx(s);
608 /*
609 * Return ENETRESET to inform the driver that the list has changed
610 * and its reception filter should be adjusted accordingly.
611 */
612 return (ENETRESET);
613 }
614 #endif
615