if_ethersubr.c revision 1.6 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.6 1994/02/02 01:21:36 hpeyerl 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 if (m->m_flags & M_MCAST)
271 ifp->if_omcasts++;
272 return (error);
273
274 bad:
275 if (m)
276 m_freem(m);
277 return (error);
278 }
279
280 /*
281 * Process a received Ethernet packet;
282 * the packet is in the mbuf chain m without
283 * the ether header, which is provided separately.
284 */
285 ether_input(ifp, eh, m)
286 struct ifnet *ifp;
287 register struct ether_header *eh;
288 struct mbuf *m;
289 {
290 register struct ifqueue *inq;
291 register struct llc *l;
292 u_short etype;
293 int s;
294
295 ifp->if_lastchange = time;
296 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
297 if (eh->ether_dhost[0] & 1) {
298 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
299 sizeof(etherbroadcastaddr)) == 0)
300 m->m_flags |= M_BCAST;
301 else
302 m->m_flags |= M_MCAST;
303 }
304 if (m->m_flags & (M_BCAST|M_MCAST))
305 ifp->if_imcasts++;
306
307 etype = ntohs(eh->ether_type);
308 switch (etype) {
309 #ifdef INET
310 case ETHERTYPE_IP:
311 schednetisr(NETISR_IP);
312 inq = &ipintrq;
313 break;
314
315 case ETHERTYPE_ARP:
316 arpinput((struct arpcom *)ifp, m);
317 return;
318 #endif
319 #ifdef NS
320 case ETHERTYPE_NS:
321 schednetisr(NETISR_NS);
322 inq = &nsintrq;
323 break;
324
325 #endif
326 default:
327 #ifdef ISO
328 if (etype > ETHERMTU)
329 goto dropanyway;
330 l = mtod(m, struct llc *);
331 switch (l->llc_control) {
332 case LLC_UI:
333 /* LLC_UI_P forbidden in class 1 service */
334 if ((l->llc_dsap == LLC_ISO_LSAP) &&
335 (l->llc_ssap == LLC_ISO_LSAP)) {
336 /* LSAP for ISO */
337 if (m->m_pkthdr.len > etype)
338 m_adj(m, etype - m->m_pkthdr.len);
339 m->m_data += 3; /* XXX */
340 m->m_len -= 3; /* XXX */
341 m->m_pkthdr.len -= 3; /* XXX */
342 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
343 if (m == 0)
344 return;
345 *mtod(m, struct ether_header *) = *eh;
346 IFDEBUG(D_ETHER)
347 printf("clnp packet");
348 ENDDEBUG
349 schednetisr(NETISR_ISO);
350 inq = &clnlintrq;
351 break;
352 }
353 goto dropanyway;
354
355 case LLC_XID:
356 case LLC_XID_P:
357 if(m->m_len < 6)
358 goto dropanyway;
359 l->llc_window = 0;
360 l->llc_fid = 9;
361 l->llc_class = 1;
362 l->llc_dsap = l->llc_ssap = 0;
363 /* Fall through to */
364 case LLC_TEST:
365 case LLC_TEST_P:
366 {
367 struct sockaddr sa;
368 register struct ether_header *eh2;
369 int i;
370 u_char c = l->llc_dsap;
371 l->llc_dsap = l->llc_ssap;
372 l->llc_ssap = c;
373 if (m->m_flags & (M_BCAST | M_MCAST))
374 bcopy((caddr_t)ac->ac_enaddr,
375 (caddr_t)eh->ether_dhost, 6);
376 sa.sa_family = AF_UNSPEC;
377 sa.sa_len = sizeof(sa);
378 eh2 = (struct ether_header *)sa.sa_data;
379 for (i = 0; i < 6; i++) {
380 eh2->ether_shost[i] = c = eh->ether_dhost[i];
381 eh2->ether_dhost[i] =
382 eh->ether_dhost[i] = eh->ether_shost[i];
383 eh->ether_shost[i] = c;
384 }
385 ifp->if_output(ifp, m, &sa);
386 return;
387 }
388 dropanyway:
389 default:
390 m_freem(m);
391 return;
392 }
393 #else
394 m_freem(m);
395 return;
396 #endif ISO
397 }
398
399 s = splimp();
400 if (IF_QFULL(inq)) {
401 IF_DROP(inq);
402 m_freem(m);
403 } else
404 IF_ENQUEUE(inq, m);
405 splx(s);
406 }
407
408 /*
409 * Convert Ethernet address to printable (loggable) representation.
410 */
411 static char digits[] = "0123456789abcdef";
412 char *
413 ether_sprintf(ap)
414 register u_char *ap;
415 {
416 register i;
417 static char etherbuf[18];
418 register char *cp = etherbuf;
419
420 for (i = 0; i < 6; i++) {
421 *cp++ = digits[*ap >> 4];
422 *cp++ = digits[*ap++ & 0xf];
423 *cp++ = ':';
424 }
425 *--cp = 0;
426 return (etherbuf);
427 }
428
429 u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
430 u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
431
432 /* XXX */
433 #undef ac
434 /*
435 * Add an Ethernet multicast address or range of addresses to the list for a
436 * given interface.
437 */
438 int
439 ether_addmulti(ifr, ac)
440 struct ifreq *ifr;
441 register struct arpcom *ac;
442 {
443 register struct ether_multi *enm;
444 struct sockaddr_in *sin;
445 u_char addrlo[6];
446 u_char addrhi[6];
447 int s = splimp();
448
449 switch (ifr->ifr_addr.sa_family) {
450
451 case AF_UNSPEC:
452 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
453 bcopy(addrlo, addrhi, 6);
454 break;
455
456 #ifdef INET
457 case AF_INET:
458 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
459 if (sin->sin_addr.s_addr == INADDR_ANY) {
460 /*
461 * An IP address of INADDR_ANY means listen to all
462 * of the Ethernet multicast addresses used for IP.
463 * (This is for the sake of IP multicast routers.)
464 */
465 bcopy(ether_ipmulticast_min, addrlo, 6);
466 bcopy(ether_ipmulticast_max, addrhi, 6);
467 }
468 else {
469 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
470 bcopy(addrlo, addrhi, 6);
471 }
472 break;
473 #endif
474
475 default:
476 splx(s);
477 return (EAFNOSUPPORT);
478 }
479
480 /*
481 * Verify that we have valid Ethernet multicast addresses.
482 */
483 if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
484 splx(s);
485 return (EINVAL);
486 }
487 /*
488 * See if the address range is already in the list.
489 */
490 ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
491 if (enm != NULL) {
492 /*
493 * Found it; just increment the reference count.
494 */
495 ++enm->enm_refcount;
496 splx(s);
497 return (0);
498 }
499 /*
500 * New address or range; malloc a new multicast record
501 * and link it into the interface's multicast list.
502 */
503 enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
504 if (enm == NULL) {
505 splx(s);
506 return (ENOBUFS);
507 }
508 bcopy(addrlo, enm->enm_addrlo, 6);
509 bcopy(addrhi, enm->enm_addrhi, 6);
510 enm->enm_ac = ac;
511 enm->enm_refcount = 1;
512 enm->enm_next = ac->ac_multiaddrs;
513 ac->ac_multiaddrs = enm;
514 ac->ac_multicnt++;
515 splx(s);
516 /*
517 * Return ENETRESET to inform the driver that the list has changed
518 * and its reception filter should be adjusted accordingly.
519 */
520 return (ENETRESET);
521 }
522
523 /*
524 * Delete a multicast address record.
525 */
526 int
527 ether_delmulti(ifr, ac)
528 struct ifreq *ifr;
529 register struct arpcom *ac;
530 {
531 register struct ether_multi *enm;
532 register struct ether_multi **p;
533 struct sockaddr_in *sin;
534 u_char addrlo[6];
535 u_char addrhi[6];
536 int s = splimp();
537
538 switch (ifr->ifr_addr.sa_family) {
539
540 case AF_UNSPEC:
541 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
542 bcopy(addrlo, addrhi, 6);
543 break;
544
545 #ifdef INET
546 case AF_INET:
547 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
548 if (sin->sin_addr.s_addr == INADDR_ANY) {
549 /*
550 * An IP address of INADDR_ANY means stop listening
551 * to the range of Ethernet multicast addresses used
552 * for IP.
553 */
554 bcopy(ether_ipmulticast_min, addrlo, 6);
555 bcopy(ether_ipmulticast_max, addrhi, 6);
556 }
557 else {
558 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
559 bcopy(addrlo, addrhi, 6);
560 }
561 break;
562 #endif
563
564 default:
565 splx(s);
566 return (EAFNOSUPPORT);
567 }
568
569 /*
570 * Look up the address in our list.
571 */
572 ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
573 if (enm == NULL) {
574 splx(s);
575 return (ENXIO);
576 }
577 if (--enm->enm_refcount != 0) {
578 /*
579 * Still some claims to this record.
580 */
581 splx(s);
582 return (0);
583 }
584 /*
585 * No remaining claims to this record; unlink and free it.
586 */
587 for (p = &enm->enm_ac->ac_multiaddrs;
588 *p != enm;
589 p = &(*p)->enm_next)
590 continue;
591 *p = (*p)->enm_next;
592 free(enm, M_IFMADDR);
593 ac->ac_multicnt--;
594 splx(s);
595 /*
596 * Return ENETRESET to inform the driver that the list has changed
597 * and its reception filter should be adjusted accordingly.
598 */
599 return (ENETRESET);
600 }
601