xref: /original-bsd/sys/net/if_ethersubr.c (revision a043e977)
1 /*
2  * Copyright (c) 1982, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_ethersubr.c	7.22 (Berkeley) 10/11/92
8  */
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/kernel.h>
13 #include <sys/malloc.h>
14 #include <sys/mbuf.h>
15 #include <sys/protosw.h>
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
18 #include <sys/errno.h>
19 #include <sys/syslog.h>
20 
21 #include <machine/cpu.h>
22 
23 #include <net/if.h>
24 #include <net/netisr.h>
25 #include <net/route.h>
26 #include <net/if_llc.h>
27 #include <net/if_dl.h>
28 #include <net/if_types.h>
29 
30 #ifdef INET
31 #include <netinet/in.h>
32 #include <netinet/in_var.h>
33 #endif
34 #include <netinet/if_ether.h>
35 
36 #ifdef NS
37 #include <netns/ns.h>
38 #include <netns/ns_if.h>
39 #endif
40 
41 #ifdef ISO
42 #include <netiso/argo_debug.h>
43 #include <netiso/iso.h>
44 #include <netiso/iso_var.h>
45 #include <netiso/iso_snpac.h>
46 #endif
47 
48 u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
49 extern	struct ifnet loif;
50 #define senderr(e) { error = (e); goto bad;}
51 
52 /*
53  * Ethernet output routine.
54  * Encapsulate a packet of type family for the local net.
55  * Use trailer local net encapsulation if enough data in first
56  * packet leaves a multiple of 512 bytes of data in remainder.
57  * Assumes that ifp is actually pointer to arpcom structure.
58  */
59 ether_output(ifp, m0, dst, rt0)
60 	register struct ifnet *ifp;
61 	struct mbuf *m0;
62 	struct sockaddr *dst;
63 	struct rtentry *rt0;
64 {
65 	short type;
66 	int s, error = 0;
67  	u_char edst[6];
68 	register struct mbuf *m = m0;
69 	register struct rtentry *rt;
70 	struct mbuf *mcopy = (struct mbuf *)0;
71 	register struct ether_header *eh;
72 	int off, len = m->m_pkthdr.len;
73 	struct arpcom *ac = (struct arpcom *)ifp;
74 
75 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
76 		senderr(ENETDOWN);
77 	ifp->if_lastchange = time;
78 	if (rt = rt0) {
79 		if ((rt->rt_flags & RTF_UP) == 0) {
80 			if (rt0 = rt = rtalloc1(dst, 1))
81 				rt->rt_refcnt--;
82 			else
83 				senderr(EHOSTUNREACH);
84 		}
85 		if (rt->rt_flags & RTF_GATEWAY) {
86 			if (rt->rt_gwroute == 0)
87 				goto lookup;
88 			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
89 				rtfree(rt); rt = rt0;
90 			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
91 				if ((rt = rt->rt_gwroute) == 0)
92 					senderr(EHOSTUNREACH);
93 			}
94 		}
95 		if (rt->rt_flags & RTF_REJECT)
96 			if (rt->rt_rmx.rmx_expire == 0 ||
97 			    time.tv_sec < rt->rt_rmx.rmx_expire)
98 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
99 	}
100 	switch (dst->sa_family) {
101 
102 #ifdef INET
103 	case AF_INET:
104 		if (!arpresolve(ac, rt, m, (struct sockaddr_in *)dst,
105 				edst))
106 			return (0);	/* if not yet resolved */
107 		/* If broadcasting on a simplex interface, loopback a copy */
108 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
109 			mcopy = m_copy(m, 0, (int)M_COPYALL);
110 		off = m->m_pkthdr.len - m->m_len;
111 		type = ETHERTYPE_IP;
112 		break;
113 #endif
114 #ifdef NS
115 	case AF_NS:
116 		type = ETHERTYPE_NS;
117  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
118 		    (caddr_t)edst, sizeof (edst));
119 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
120 			return (looutput(ifp, m, dst, rt));
121 		/* If broadcasting on a simplex interface, loopback a copy */
122 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
123 			mcopy = m_copy(m, 0, (int)M_COPYALL);
124 		break;
125 #endif
126 #ifdef	ISO
127 	case AF_ISO: {
128 		int	snpalen;
129 		struct	llc *l;
130 		register struct sockaddr_dl *sdl;
131 
132 		if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
133 		    sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
134 			bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
135 		} else if (error =
136 			    iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
137 					    (char *)edst, &snpalen))
138 			goto bad; /* Not Resolved */
139 		/* If broadcasting on a simplex interface, loopback a copy */
140 		if (*edst & 1)
141 			m->m_flags |= (M_BCAST|M_MCAST);
142 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
143 		    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
144 			M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
145 			if (mcopy) {
146 				eh = mtod(mcopy, struct ether_header *);
147 				bcopy((caddr_t)edst,
148 				      (caddr_t)eh->ether_dhost, sizeof (edst));
149 				bcopy((caddr_t)ac->ac_enaddr,
150 				      (caddr_t)eh->ether_shost, sizeof (edst));
151 			}
152 		}
153 		M_PREPEND(m, 3, M_DONTWAIT);
154 		if (m == NULL)
155 			return (0);
156 		type = m->m_pkthdr.len;
157 		l = mtod(m, struct llc *);
158 		l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
159 		l->llc_control = LLC_UI;
160 		len += 3;
161 		IFDEBUG(D_ETHER)
162 			int i;
163 			printf("unoutput: sending pkt to: ");
164 			for (i=0; i<6; i++)
165 				printf("%x ", edst[i] & 0xff);
166 			printf("\n");
167 		ENDDEBUG
168 		} break;
169 #endif	ISO
170 
171 	case AF_UNSPEC:
172 		eh = (struct ether_header *)dst->sa_data;
173  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
174 		type = eh->ether_type;
175 		break;
176 
177 	default:
178 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
179 			dst->sa_family);
180 		senderr(EAFNOSUPPORT);
181 	}
182 
183 
184 	if (mcopy)
185 		(void) looutput(ifp, mcopy, dst, rt);
186 	/*
187 	 * Add local net header.  If no space in first mbuf,
188 	 * allocate another.
189 	 */
190 	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
191 	if (m == 0)
192 		senderr(ENOBUFS);
193 	eh = mtod(m, struct ether_header *);
194 	type = htons((u_short)type);
195 	bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
196 		sizeof(eh->ether_type));
197  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
198  	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
199 	    sizeof(eh->ether_shost));
200 	s = splimp();
201 	/*
202 	 * Queue message on interface, and start output if interface
203 	 * not yet active.
204 	 */
205 	if (IF_QFULL(&ifp->if_snd)) {
206 		IF_DROP(&ifp->if_snd);
207 		splx(s);
208 		senderr(ENOBUFS);
209 	}
210 	IF_ENQUEUE(&ifp->if_snd, m);
211 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
212 		(*ifp->if_start)(ifp);
213 	splx(s);
214 	ifp->if_obytes += len + sizeof (struct ether_header);
215 	if (m->m_flags & M_MCAST)
216 		ifp->if_omcasts++;
217 	return (error);
218 
219 bad:
220 	if (m)
221 		m_freem(m);
222 	return (error);
223 }
224 
225 /*
226  * Process a received Ethernet packet;
227  * the packet is in the mbuf chain m without
228  * the ether header, which is provided separately.
229  */
230 ether_input(ifp, eh, m)
231 	struct ifnet *ifp;
232 	register struct ether_header *eh;
233 	struct mbuf *m;
234 {
235 	register struct ifqueue *inq;
236 	register struct llc *l;
237 	int s;
238 
239 	if ((ifp->if_flags & IFF_UP) == 0) {
240 		m_freem(m);
241 		return;
242 	}
243 	ifp->if_lastchange = time;
244 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
245 	if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
246 	    sizeof(etherbroadcastaddr)) == 0)
247 		m->m_flags |= M_BCAST;
248 	else if (eh->ether_dhost[0] & 1)
249 		m->m_flags |= M_MCAST;
250 	if (m->m_flags & (M_BCAST|M_MCAST))
251 		ifp->if_imcasts++;
252 
253 	switch (eh->ether_type) {
254 #ifdef INET
255 	case ETHERTYPE_IP:
256 		schednetisr(NETISR_IP);
257 		inq = &ipintrq;
258 		break;
259 
260 	case ETHERTYPE_ARP:
261 		schednetisr(NETISR_ARP);
262 		inq = &arpintrq;
263 		break;
264 #endif
265 #ifdef NS
266 	case ETHERTYPE_NS:
267 		schednetisr(NETISR_NS);
268 		inq = &nsintrq;
269 		break;
270 
271 #endif
272 	default:
273 #ifdef	ISO
274 		if (eh->ether_type > ETHERMTU)
275 			goto dropanyway;
276 		l = mtod(m, struct llc *);
277 		switch (l->llc_control) {
278 		case LLC_UI:
279 		/* LLC_UI_P forbidden in class 1 service */
280 		    if ((l->llc_dsap == LLC_ISO_LSAP) &&
281 			(l->llc_ssap == LLC_ISO_LSAP)) {
282 				/* LSAP for ISO */
283 			if (m->m_pkthdr.len > eh->ether_type)
284 				m_adj(m, eh->ether_type - m->m_pkthdr.len);
285 			m->m_data += 3;		/* XXX */
286 			m->m_len -= 3;		/* XXX */
287 			m->m_pkthdr.len -= 3;	/* XXX */
288 			M_PREPEND(m, sizeof *eh, M_DONTWAIT);
289 			if (m == 0)
290 				return;
291 			*mtod(m, struct ether_header *) = *eh;
292 			IFDEBUG(D_ETHER)
293 			    printf("clnp packet");
294 			ENDDEBUG
295 			schednetisr(NETISR_ISO);
296 			inq = &clnlintrq;
297 			break;
298 		    }
299 		    goto dropanyway;
300 
301 		case LLC_XID:
302 		case LLC_XID_P:
303 		    if(m->m_len < 6)
304 			goto dropanyway;
305 		    l->llc_window = 0;
306 		    l->llc_fid = 9;
307 		    l->llc_class = 1;
308 		    l->llc_dsap = l->llc_ssap = 0;
309 		    /* Fall through to */
310 		case LLC_TEST:
311 		case LLC_TEST_P:
312 		{
313 		    struct sockaddr sa;
314 		    register struct ether_header *eh2;
315 		    int i;
316 		    u_char c = l->llc_dsap;
317 		    l->llc_dsap = l->llc_ssap;
318 		    l->llc_ssap = c;
319 		    if (m->m_flags & (M_BCAST | M_MCAST))
320 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
321 			      (caddr_t)eh->ether_dhost, 6);
322 		    sa.sa_family = AF_UNSPEC;
323 		    sa.sa_len = sizeof(sa);
324 		    eh2 = (struct ether_header *)sa.sa_data;
325 		    for (i = 0; i < 6; i++) {
326 			eh2->ether_shost[i] = c = eh->ether_dhost[i];
327 			eh2->ether_dhost[i] =
328 				eh->ether_dhost[i] = eh->ether_shost[i];
329 			eh->ether_shost[i] = c;
330 		    }
331 		    ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
332 		    return;
333 		}
334 		dropanyway:
335 		default:
336 		    m_freem(m);
337 		    return;
338 	    }
339 #else
340 	    m_freem(m);
341 	    return;
342 #endif	ISO
343 	}
344 
345 	s = splimp();
346 	if (IF_QFULL(inq)) {
347 		IF_DROP(inq);
348 		m_freem(m);
349 	} else
350 		IF_ENQUEUE(inq, m);
351 	splx(s);
352 }
353 
354 /*
355  * Convert Ethernet address to printable (loggable) representation.
356  */
357 static char digits[] = "0123456789abcdef";
358 char *
359 ether_sprintf(ap)
360 	register u_char *ap;
361 {
362 	register i;
363 	static char etherbuf[18];
364 	register char *cp = etherbuf;
365 
366 	for (i = 0; i < 6; i++) {
367 		*cp++ = digits[*ap >> 4];
368 		*cp++ = digits[*ap++ & 0xf];
369 		*cp++ = ':';
370 	}
371 	*--cp = 0;
372 	return (etherbuf);
373 }
374 
375 /*
376  * Perform common duties while attaching to interface list
377  */
378 ether_ifattach(ifp)
379 	register struct ifnet *ifp;
380 {
381 	register struct ifaddr *ifa;
382 	register struct sockaddr_dl *sdl;
383 
384 	ifp->if_type = IFT_ETHER;
385 	ifp->if_addrlen = 6;
386 	ifp->if_hdrlen = 14;
387 	ifp->if_mtu = ETHERMTU;
388 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
389 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
390 		    sdl->sdl_family == AF_LINK) {
391 			sdl->sdl_type = IFT_ETHER;
392 			sdl->sdl_alen = ifp->if_addrlen;
393 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
394 			      LLADDR(sdl), ifp->if_addrlen);
395 			break;
396 		}
397 }
398 
399 #ifdef MULTICAST
400 u_char	ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
401 u_char	ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
402 /*
403  * Add an Ethernet multicast address or range of addresses to the list for a
404  * given interface.
405  */
406 int
407 ether_addmulti(ifr, ac)
408 	struct ifreq *ifr;
409 	register struct arpcom *ac;
410 {
411 	register struct ether_multi *enm;
412 	struct sockaddr_in *sin;
413 	u_char addrlo[6];
414 	u_char addrhi[6];
415 	int s = splimp();
416 
417 	switch (ifr->ifr_addr.sa_family) {
418 
419 	case AF_UNSPEC:
420 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
421 		bcopy(addrlo, addrhi, 6);
422 		break;
423 
424 #ifdef INET
425 	case AF_INET:
426 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
427 		if (sin->sin_addr.s_addr == INADDR_ANY) {
428 			/*
429 			 * An IP address of INADDR_ANY means listen to all
430 			 * of the Ethernet multicast addresses used for IP.
431 			 * (This is for the sake of IP multicast routers.)
432 			 */
433 			bcopy(ether_ipmulticast_min, addrlo, 6);
434 			bcopy(ether_ipmulticast_max, addrhi, 6);
435 		}
436 		else {
437 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
438 			bcopy(addrlo, addrhi, 6);
439 		}
440 		break;
441 #endif
442 
443 	default:
444 		splx(s);
445 		return (EAFNOSUPPORT);
446 	}
447 
448 	/*
449 	 * Verify that we have valid Ethernet multicast addresses.
450 	 */
451 	if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
452 		splx(s);
453 		return (EINVAL);
454 	}
455 	/*
456 	 * See if the address range is already in the list.
457 	 */
458 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
459 	if (enm != NULL) {
460 		/*
461 		 * Found it; just increment the reference count.
462 		 */
463 		++enm->enm_refcount;
464 		splx(s);
465 		return (0);
466 	}
467 	/*
468 	 * New address or range; malloc a new multicast record
469 	 * and link it into the interface's multicast list.
470 	 */
471 	enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
472 	if (enm == NULL) {
473 		splx(s);
474 		return (ENOBUFS);
475 	}
476 	bcopy(addrlo, enm->enm_addrlo, 6);
477 	bcopy(addrhi, enm->enm_addrhi, 6);
478 	enm->enm_ac = ac;
479 	enm->enm_refcount = 1;
480 	enm->enm_next = ac->ac_multiaddrs;
481 	ac->ac_multiaddrs = enm;
482 	ac->ac_multicnt++;
483 	splx(s);
484 	/*
485 	 * Return ENETRESET to inform the driver that the list has changed
486 	 * and its reception filter should be adjusted accordingly.
487 	 */
488 	return (ENETRESET);
489 }
490 
491 /*
492  * Delete a multicast address record.
493  */
494 int
495 ether_delmulti(ifr, ac)
496 	struct ifreq *ifr;
497 	register struct arpcom *ac;
498 {
499 	register struct ether_multi *enm;
500 	register struct ether_multi **p;
501 	struct sockaddr_in *sin;
502 	u_char addrlo[6];
503 	u_char addrhi[6];
504 	int s = splimp();
505 
506 	switch (ifr->ifr_addr.sa_family) {
507 
508 	case AF_UNSPEC:
509 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
510 		bcopy(addrlo, addrhi, 6);
511 		break;
512 
513 #ifdef INET
514 	case AF_INET:
515 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
516 		if (sin->sin_addr.s_addr == INADDR_ANY) {
517 			/*
518 			 * An IP address of INADDR_ANY means stop listening
519 			 * to the range of Ethernet multicast addresses used
520 			 * for IP.
521 			 */
522 			bcopy(ether_ipmulticast_min, addrlo, 6);
523 			bcopy(ether_ipmulticast_max, addrhi, 6);
524 		}
525 		else {
526 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
527 			bcopy(addrlo, addrhi, 6);
528 		}
529 		break;
530 #endif
531 
532 	default:
533 		splx(s);
534 		return (EAFNOSUPPORT);
535 	}
536 
537 	/*
538 	 * Look up the address in our list.
539 	 */
540 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
541 	if (enm == NULL) {
542 		splx(s);
543 		return (ENXIO);
544 	}
545 	if (--enm->enm_refcount != 0) {
546 		/*
547 		 * Still some claims to this record.
548 		 */
549 		splx(s);
550 		return (0);
551 	}
552 	/*
553 	 * No remaining claims to this record; unlink and free it.
554 	 */
555 	for (p = &enm->enm_ac->ac_multiaddrs;
556 	     *p != enm;
557 	     p = &(*p)->enm_next)
558 		continue;
559 	*p = (*p)->enm_next;
560 	free(enm, M_IFMADDR);
561 	ac->ac_multicnt--;
562 	splx(s);
563 	/*
564 	 * Return ENETRESET to inform the driver that the list has changed
565 	 * and its reception filter should be adjusted accordingly.
566 	 */
567 	return (ENETRESET);
568 }
569 #endif
570