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