xref: /csrg-svn/sys/net/if_ethersubr.c (revision 63211)
135379Skfall /*
2*63211Sbostic  * Copyright (c) 1982, 1989, 1993
3*63211Sbostic  *	The Regents of the University of California.  All rights reserved.
435379Skfall  *
544464Sbostic  * %sccs.include.redist.c%
635379Skfall  *
7*63211Sbostic  *	@(#)if_ethersubr.c	8.1 (Berkeley) 06/10/93
835379Skfall  */
935379Skfall 
1056529Sbostic #include <sys/param.h>
1156529Sbostic #include <sys/systm.h>
1256529Sbostic #include <sys/kernel.h>
1356529Sbostic #include <sys/malloc.h>
1456529Sbostic #include <sys/mbuf.h>
1556529Sbostic #include <sys/protosw.h>
1656529Sbostic #include <sys/socket.h>
1756529Sbostic #include <sys/ioctl.h>
1856529Sbostic #include <sys/errno.h>
1956529Sbostic #include <sys/syslog.h>
2035379Skfall 
2156529Sbostic #include <machine/cpu.h>
2235379Skfall 
2356529Sbostic #include <net/if.h>
2456529Sbostic #include <net/netisr.h>
2556529Sbostic #include <net/route.h>
2656529Sbostic #include <net/if_llc.h>
2756529Sbostic #include <net/if_dl.h>
2856529Sbostic #include <net/if_types.h>
2956529Sbostic 
3035379Skfall #ifdef INET
3156529Sbostic #include <netinet/in.h>
3256529Sbostic #include <netinet/in_var.h>
3345930Sbostic #endif
3456529Sbostic #include <netinet/if_ether.h>
3535379Skfall 
3635379Skfall #ifdef NS
3756529Sbostic #include <netns/ns.h>
3856529Sbostic #include <netns/ns_if.h>
3935379Skfall #endif
4035379Skfall 
4137472Ssklower #ifdef ISO
4256529Sbostic #include <netiso/argo_debug.h>
4356529Sbostic #include <netiso/iso.h>
4456529Sbostic #include <netiso/iso_var.h>
4556529Sbostic #include <netiso/iso_snpac.h>
4637472Ssklower #endif
4737472Ssklower 
4858231Ssklower #ifdef LLC
4958231Ssklower #include <netccitt/dll.h>
5058231Ssklower #include <netccitt/llc_var.h>
5158231Ssklower #endif
5258231Ssklower 
5358231Ssklower #if defined(LLC) && defined(CCITT)
5458231Ssklower extern struct ifqueue pkintrq;
5558231Ssklower #endif
5658231Ssklower 
5735379Skfall u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5835795Skarels extern	struct ifnet loif;
5950133Ssklower #define senderr(e) { error = (e); goto bad;}
6035379Skfall 
6135379Skfall /*
6235379Skfall  * Ethernet output routine.
6335379Skfall  * Encapsulate a packet of type family for the local net.
6435379Skfall  * Use trailer local net encapsulation if enough data in first
6535379Skfall  * packet leaves a multiple of 512 bytes of data in remainder.
6635379Skfall  * Assumes that ifp is actually pointer to arpcom structure.
6735379Skfall  */
6861347Sbostic int
ether_output(ifp,m0,dst,rt0)6950133Ssklower ether_output(ifp, m0, dst, rt0)
7035379Skfall 	register struct ifnet *ifp;
7135379Skfall 	struct mbuf *m0;
7235379Skfall 	struct sockaddr *dst;
7350133Ssklower 	struct rtentry *rt0;
7435379Skfall {
7535795Skarels 	short type;
7635795Skarels 	int s, error = 0;
7735379Skfall  	u_char edst[6];
7835379Skfall 	register struct mbuf *m = m0;
7950133Ssklower 	register struct rtentry *rt;
8035795Skarels 	struct mbuf *mcopy = (struct mbuf *)0;
8135379Skfall 	register struct ether_header *eh;
8254718Ssklower 	int off, len = m->m_pkthdr.len;
8354718Ssklower 	struct arpcom *ac = (struct arpcom *)ifp;
8435379Skfall 
8550133Ssklower 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
8650133Ssklower 		senderr(ENETDOWN);
8750133Ssklower 	ifp->if_lastchange = time;
8850133Ssklower 	if (rt = rt0) {
8950133Ssklower 		if ((rt->rt_flags & RTF_UP) == 0) {
9050133Ssklower 			if (rt0 = rt = rtalloc1(dst, 1))
9150133Ssklower 				rt->rt_refcnt--;
9250133Ssklower 			else
9353060Ssklower 				senderr(EHOSTUNREACH);
9450133Ssklower 		}
9550133Ssklower 		if (rt->rt_flags & RTF_GATEWAY) {
9650133Ssklower 			if (rt->rt_gwroute == 0)
9750133Ssklower 				goto lookup;
9850133Ssklower 			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
9950133Ssklower 				rtfree(rt); rt = rt0;
10050133Ssklower 			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
10150133Ssklower 				if ((rt = rt->rt_gwroute) == 0)
10253060Ssklower 					senderr(EHOSTUNREACH);
10350133Ssklower 			}
10450133Ssklower 		}
10550133Ssklower 		if (rt->rt_flags & RTF_REJECT)
10650133Ssklower 			if (rt->rt_rmx.rmx_expire == 0 ||
10750133Ssklower 			    time.tv_sec < rt->rt_rmx.rmx_expire)
10853060Ssklower 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
10935379Skfall 	}
11035379Skfall 	switch (dst->sa_family) {
11135379Skfall 
11235379Skfall #ifdef INET
11335379Skfall 	case AF_INET:
11461347Sbostic 		if (!arpresolve(ac, rt, m, dst, edst))
11535379Skfall 			return (0);	/* if not yet resolved */
11654718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
11754718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
11841546Smckusick 			mcopy = m_copy(m, 0, (int)M_COPYALL);
11935379Skfall 		off = m->m_pkthdr.len - m->m_len;
12035379Skfall 		type = ETHERTYPE_IP;
12154718Ssklower 		break;
12235379Skfall #endif
12335379Skfall #ifdef NS
12435379Skfall 	case AF_NS:
12535379Skfall 		type = ETHERTYPE_NS;
12639187Ssklower  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
12739187Ssklower 		    (caddr_t)edst, sizeof (edst));
12835795Skarels 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
12945632Ssklower 			return (looutput(ifp, m, dst, rt));
13054718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
13154718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
13241546Smckusick 			mcopy = m_copy(m, 0, (int)M_COPYALL);
13354718Ssklower 		break;
13435379Skfall #endif
13535795Skarels #ifdef	ISO
13635795Skarels 	case AF_ISO: {
13743073Ssklower 		int	snpalen;
13837472Ssklower 		struct	llc *l;
13950133Ssklower 		register struct sockaddr_dl *sdl;
14037472Ssklower 
14150133Ssklower 		if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
14250133Ssklower 		    sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
14350133Ssklower 			bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
14450133Ssklower 		} else if (error =
14550133Ssklower 			    iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
14650133Ssklower 					    (char *)edst, &snpalen))
14743073Ssklower 			goto bad; /* Not Resolved */
14854718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
14954718Ssklower 		if (*edst & 1)
15054718Ssklower 			m->m_flags |= (M_BCAST|M_MCAST);
15154718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
15245632Ssklower 		    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
15345632Ssklower 			M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
15445632Ssklower 			if (mcopy) {
15545632Ssklower 				eh = mtod(mcopy, struct ether_header *);
15645632Ssklower 				bcopy((caddr_t)edst,
15745632Ssklower 				      (caddr_t)eh->ether_dhost, sizeof (edst));
15845632Ssklower 				bcopy((caddr_t)ac->ac_enaddr,
15945632Ssklower 				      (caddr_t)eh->ether_shost, sizeof (edst));
16045632Ssklower 			}
16145632Ssklower 		}
16235795Skarels 		M_PREPEND(m, 3, M_DONTWAIT);
16337472Ssklower 		if (m == NULL)
16443073Ssklower 			return (0);
16535795Skarels 		type = m->m_pkthdr.len;
16635795Skarels 		l = mtod(m, struct llc *);
16735795Skarels 		l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
16835795Skarels 		l->llc_control = LLC_UI;
16939187Ssklower 		len += 3;
17035795Skarels 		IFDEBUG(D_ETHER)
17135795Skarels 			int i;
17235795Skarels 			printf("unoutput: sending pkt to: ");
17335795Skarels 			for (i=0; i<6; i++)
17435795Skarels 				printf("%x ", edst[i] & 0xff);
17535795Skarels 			printf("\n");
17635795Skarels 		ENDDEBUG
17754718Ssklower 		} break;
17860346Storek #endif /* ISO */
17958231Ssklower #ifdef	LLC
18058231Ssklower /*	case AF_NSAP: */
18158231Ssklower 	case AF_CCITT: {
18258231Ssklower 		register struct sockaddr_dl *sdl =
18358231Ssklower 			(struct sockaddr_dl *) rt -> rt_gateway;
18441546Smckusick 
18558231Ssklower 		if (sdl && sdl->sdl_family == AF_LINK
18658231Ssklower 		    && sdl->sdl_alen > 0) {
18758231Ssklower 			bcopy(LLADDR(sdl), (char *)edst,
18858231Ssklower 				sizeof(edst));
18958231Ssklower 		} else goto bad; /* Not a link interface ? Funny ... */
19058231Ssklower 		if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
19158231Ssklower 		    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
19258231Ssklower 			M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
19358231Ssklower 			if (mcopy) {
19458231Ssklower 				eh = mtod(mcopy, struct ether_header *);
19558231Ssklower 				bcopy((caddr_t)edst,
19658231Ssklower 				      (caddr_t)eh->ether_dhost, sizeof (edst));
19758231Ssklower 				bcopy((caddr_t)ac->ac_enaddr,
19858231Ssklower 				      (caddr_t)eh->ether_shost, sizeof (edst));
19958231Ssklower 			}
20058231Ssklower 		}
20158231Ssklower 		type = m->m_pkthdr.len;
20258231Ssklower #ifdef LLC_DEBUG
20358231Ssklower 		{
20458231Ssklower 			int i;
20558231Ssklower 			register struct llc *l = mtod(m, struct llc *);
20658231Ssklower 
20758231Ssklower 			printf("ether_output: sending LLC2 pkt to: ");
20858231Ssklower 			for (i=0; i<6; i++)
20958231Ssklower 				printf("%x ", edst[i] & 0xff);
21058231Ssklower 			printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
21158231Ssklower 			       type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff,
21258231Ssklower 			       l->llc_control & 0xff);
21358231Ssklower 
21458231Ssklower 		}
21560346Storek #endif /* LLC_DEBUG */
21658231Ssklower 		} break;
21760346Storek #endif /* LLC */
21858231Ssklower 
21935379Skfall 	case AF_UNSPEC:
22035379Skfall 		eh = (struct ether_header *)dst->sa_data;
22135379Skfall  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
22235379Skfall 		type = eh->ether_type;
22354718Ssklower 		break;
22435379Skfall 
22535379Skfall 	default:
22635379Skfall 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
22735379Skfall 			dst->sa_family);
22850133Ssklower 		senderr(EAFNOSUPPORT);
22935379Skfall 	}
23035379Skfall 
23135379Skfall 
23245632Ssklower 	if (mcopy)
23345632Ssklower 		(void) looutput(ifp, mcopy, dst, rt);
23435379Skfall 	/*
23535379Skfall 	 * Add local net header.  If no space in first mbuf,
23635379Skfall 	 * allocate another.
23735379Skfall 	 */
23835379Skfall 	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
23950133Ssklower 	if (m == 0)
24050133Ssklower 		senderr(ENOBUFS);
24135379Skfall 	eh = mtod(m, struct ether_header *);
24235795Skarels 	type = htons((u_short)type);
24335795Skarels 	bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
24435795Skarels 		sizeof(eh->ether_type));
24535379Skfall  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
24635379Skfall  	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
24735379Skfall 	    sizeof(eh->ether_shost));
24845632Ssklower 	s = splimp();
24935379Skfall 	/*
25035379Skfall 	 * Queue message on interface, and start output if interface
25135379Skfall 	 * not yet active.
25235379Skfall 	 */
25335379Skfall 	if (IF_QFULL(&ifp->if_snd)) {
25435379Skfall 		IF_DROP(&ifp->if_snd);
25535379Skfall 		splx(s);
25650133Ssklower 		senderr(ENOBUFS);
25735379Skfall 	}
25835379Skfall 	IF_ENQUEUE(&ifp->if_snd, m);
25935379Skfall 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
26038845Sroot 		(*ifp->if_start)(ifp);
26135379Skfall 	splx(s);
26239187Ssklower 	ifp->if_obytes += len + sizeof (struct ether_header);
26354718Ssklower 	if (m->m_flags & M_MCAST)
26439187Ssklower 		ifp->if_omcasts++;
26535795Skarels 	return (error);
26635379Skfall 
26735379Skfall bad:
26835795Skarels 	if (m)
26935795Skarels 		m_freem(m);
27035379Skfall 	return (error);
27135379Skfall }
27235379Skfall 
27335379Skfall /*
27438845Sroot  * Process a received Ethernet packet;
27538845Sroot  * the packet is in the mbuf chain m without
27638845Sroot  * the ether header, which is provided separately.
27735379Skfall  */
27861347Sbostic void
ether_input(ifp,eh,m)27937472Ssklower ether_input(ifp, eh, m)
28035379Skfall 	struct ifnet *ifp;
28135379Skfall 	register struct ether_header *eh;
28235379Skfall 	struct mbuf *m;
28335379Skfall {
28435379Skfall 	register struct ifqueue *inq;
28535795Skarels 	register struct llc *l;
28658231Ssklower 	struct arpcom *ac = (struct arpcom *)ifp;
28735379Skfall 	int s;
28835379Skfall 
28953696Ssklower 	if ((ifp->if_flags & IFF_UP) == 0) {
29053696Ssklower 		m_freem(m);
29153696Ssklower 		return;
29253696Ssklower 	}
29339187Ssklower 	ifp->if_lastchange = time;
29439187Ssklower 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
29535795Skarels 	if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
29635379Skfall 	    sizeof(etherbroadcastaddr)) == 0)
29735379Skfall 		m->m_flags |= M_BCAST;
29835795Skarels 	else if (eh->ether_dhost[0] & 1)
29935795Skarels 		m->m_flags |= M_MCAST;
30039187Ssklower 	if (m->m_flags & (M_BCAST|M_MCAST))
30139187Ssklower 		ifp->if_imcasts++;
30235379Skfall 
30335379Skfall 	switch (eh->ether_type) {
30435379Skfall #ifdef INET
30535379Skfall 	case ETHERTYPE_IP:
30635379Skfall 		schednetisr(NETISR_IP);
30735379Skfall 		inq = &ipintrq;
30835379Skfall 		break;
30935379Skfall 
31035379Skfall 	case ETHERTYPE_ARP:
31150133Ssklower 		schednetisr(NETISR_ARP);
31250133Ssklower 		inq = &arpintrq;
31350133Ssklower 		break;
31435379Skfall #endif
31535379Skfall #ifdef NS
31635379Skfall 	case ETHERTYPE_NS:
31735379Skfall 		schednetisr(NETISR_NS);
31835379Skfall 		inq = &nsintrq;
31935379Skfall 		break;
32035379Skfall 
32135379Skfall #endif
32235379Skfall 	default:
32358231Ssklower #if defined (ISO) || defined (LLC)
32437472Ssklower 		if (eh->ether_type > ETHERMTU)
32535795Skarels 			goto dropanyway;
32635795Skarels 		l = mtod(m, struct llc *);
32758231Ssklower 		switch (l->llc_dsap) {
32858231Ssklower #ifdef	ISO
32958231Ssklower 		case LLC_ISO_LSAP:
33058231Ssklower 			switch (l->llc_control) {
33158231Ssklower 			case LLC_UI:
33258231Ssklower 				/* LLC_UI_P forbidden in class 1 service */
33358231Ssklower 				if ((l->llc_dsap == LLC_ISO_LSAP) &&
33458231Ssklower 				    (l->llc_ssap == LLC_ISO_LSAP)) {
33558231Ssklower 					/* LSAP for ISO */
33658231Ssklower 					if (m->m_pkthdr.len > eh->ether_type)
33758231Ssklower 						m_adj(m, eh->ether_type - m->m_pkthdr.len);
33858231Ssklower 					m->m_data += 3;		/* XXX */
33958231Ssklower 					m->m_len -= 3;		/* XXX */
34058231Ssklower 					m->m_pkthdr.len -= 3;	/* XXX */
34158231Ssklower 					M_PREPEND(m, sizeof *eh, M_DONTWAIT);
34258231Ssklower 					if (m == 0)
34358231Ssklower 						return;
34458231Ssklower 					*mtod(m, struct ether_header *) = *eh;
34558231Ssklower 					IFDEBUG(D_ETHER)
34658231Ssklower 						printf("clnp packet");
34758231Ssklower 					ENDDEBUG
34858231Ssklower 					schednetisr(NETISR_ISO);
34958231Ssklower 					inq = &clnlintrq;
35058231Ssklower 					break;
35158231Ssklower 				}
35258231Ssklower 				goto dropanyway;
35358231Ssklower 
35458231Ssklower 			case LLC_XID:
35558231Ssklower 			case LLC_XID_P:
35658231Ssklower 				if(m->m_len < 6)
35758231Ssklower 					goto dropanyway;
35858231Ssklower 				l->llc_window = 0;
35958231Ssklower 				l->llc_fid = 9;
36058231Ssklower 				l->llc_class = 1;
36158231Ssklower 				l->llc_dsap = l->llc_ssap = 0;
36258231Ssklower 				/* Fall through to */
36358231Ssklower 			case LLC_TEST:
36458231Ssklower 			case LLC_TEST_P:
36558231Ssklower 			{
36658231Ssklower 				struct sockaddr sa;
36758231Ssklower 				register struct ether_header *eh2;
36858231Ssklower 				int i;
36958231Ssklower 				u_char c = l->llc_dsap;
37058231Ssklower 
37158231Ssklower 				l->llc_dsap = l->llc_ssap;
37258231Ssklower 				l->llc_ssap = c;
37358231Ssklower 				if (m->m_flags & (M_BCAST | M_MCAST))
37458231Ssklower 					bcopy((caddr_t)ac->ac_enaddr,
37558231Ssklower 					      (caddr_t)eh->ether_dhost, 6);
37658231Ssklower 				sa.sa_family = AF_UNSPEC;
37758231Ssklower 				sa.sa_len = sizeof(sa);
37858231Ssklower 				eh2 = (struct ether_header *)sa.sa_data;
37958231Ssklower 				for (i = 0; i < 6; i++) {
38058231Ssklower 					eh2->ether_shost[i] = c = eh->ether_dhost[i];
38158231Ssklower 					eh2->ether_dhost[i] =
38258231Ssklower 						eh->ether_dhost[i] = eh->ether_shost[i];
38358231Ssklower 					eh->ether_shost[i] = c;
38458231Ssklower 				}
38558231Ssklower 				ifp->if_output(ifp, m, &sa, NULL);
38658231Ssklower 				return;
38758231Ssklower 			}
38858231Ssklower 			default:
38958231Ssklower 				m_freem(m);
39058231Ssklower 				return;
39158231Ssklower 			}
39258231Ssklower 			break;
39358231Ssklower #endif /* ISO */
39458231Ssklower #ifdef LLC
39558231Ssklower 		case LLC_X25_LSAP:
39658231Ssklower 		{
39745632Ssklower 			if (m->m_pkthdr.len > eh->ether_type)
39845632Ssklower 				m_adj(m, eh->ether_type - m->m_pkthdr.len);
39958231Ssklower 			M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
40037472Ssklower 			if (m == 0)
40137472Ssklower 				return;
40258231Ssklower 			if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP,
40358231Ssklower 					    eh->ether_dhost, LLC_X25_LSAP, 6,
40458231Ssklower 					    mtod(m, struct sdl_hdr *)))
40558231Ssklower 				panic("ETHER cons addr failure");
40658231Ssklower 			mtod(m, struct sdl_hdr *)->sdlhdr_len = eh->ether_type;
40758231Ssklower #ifdef LLC_DEBUG
40858231Ssklower 				printf("llc packet\n");
40960346Storek #endif /* LLC_DEBUG */
41058231Ssklower 			schednetisr(NETISR_CCITT);
41158231Ssklower 			inq = &llcintrq;
41238845Sroot 			break;
41335795Skarels 		}
41458231Ssklower #endif /* LLC */
41535795Skarels 		dropanyway:
41635795Skarels 		default:
41758231Ssklower 			m_freem(m);
41858231Ssklower 			return;
41958231Ssklower 		}
42058231Ssklower #else /* ISO || LLC */
42138845Sroot 	    m_freem(m);
42238845Sroot 	    return;
42358231Ssklower #endif /* ISO || LLC */
42435379Skfall 	}
42535379Skfall 
42635379Skfall 	s = splimp();
42735379Skfall 	if (IF_QFULL(inq)) {
42835379Skfall 		IF_DROP(inq);
42935379Skfall 		m_freem(m);
43035379Skfall 	} else
43135379Skfall 		IF_ENQUEUE(inq, m);
43235379Skfall 	splx(s);
43335379Skfall }
43435379Skfall 
43535379Skfall /*
43635379Skfall  * Convert Ethernet address to printable (loggable) representation.
43735379Skfall  */
43837472Ssklower static char digits[] = "0123456789abcdef";
43935379Skfall char *
ether_sprintf(ap)44035379Skfall ether_sprintf(ap)
44135379Skfall 	register u_char *ap;
44235379Skfall {
44335379Skfall 	register i;
44435379Skfall 	static char etherbuf[18];
44535379Skfall 	register char *cp = etherbuf;
44635379Skfall 
44735379Skfall 	for (i = 0; i < 6; i++) {
44835379Skfall 		*cp++ = digits[*ap >> 4];
44935379Skfall 		*cp++ = digits[*ap++ & 0xf];
45035379Skfall 		*cp++ = ':';
45135379Skfall 	}
45235379Skfall 	*--cp = 0;
45335379Skfall 	return (etherbuf);
45435379Skfall }
45552567Ssklower 
45652567Ssklower /*
45752567Ssklower  * Perform common duties while attaching to interface list
45852567Ssklower  */
45961347Sbostic void
ether_ifattach(ifp)46052567Ssklower ether_ifattach(ifp)
46152567Ssklower 	register struct ifnet *ifp;
46252567Ssklower {
46352567Ssklower 	register struct ifaddr *ifa;
46452567Ssklower 	register struct sockaddr_dl *sdl;
46552567Ssklower 
46652567Ssklower 	ifp->if_type = IFT_ETHER;
46752567Ssklower 	ifp->if_addrlen = 6;
46852567Ssklower 	ifp->if_hdrlen = 14;
46952567Ssklower 	ifp->if_mtu = ETHERMTU;
47052567Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
47152567Ssklower 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
47252567Ssklower 		    sdl->sdl_family == AF_LINK) {
47352567Ssklower 			sdl->sdl_type = IFT_ETHER;
47452567Ssklower 			sdl->sdl_alen = ifp->if_addrlen;
47552567Ssklower 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
47652567Ssklower 			      LLADDR(sdl), ifp->if_addrlen);
47752567Ssklower 			break;
47852567Ssklower 		}
47952567Ssklower }
48054718Ssklower 
48154718Ssklower u_char	ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
48254718Ssklower u_char	ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
48354718Ssklower /*
48454718Ssklower  * Add an Ethernet multicast address or range of addresses to the list for a
48554718Ssklower  * given interface.
48654718Ssklower  */
48754718Ssklower int
ether_addmulti(ifr,ac)48854718Ssklower ether_addmulti(ifr, ac)
48954718Ssklower 	struct ifreq *ifr;
49054718Ssklower 	register struct arpcom *ac;
49154718Ssklower {
49254718Ssklower 	register struct ether_multi *enm;
49354718Ssklower 	struct sockaddr_in *sin;
49454718Ssklower 	u_char addrlo[6];
49554718Ssklower 	u_char addrhi[6];
49654718Ssklower 	int s = splimp();
49754718Ssklower 
49854718Ssklower 	switch (ifr->ifr_addr.sa_family) {
49954718Ssklower 
50054718Ssklower 	case AF_UNSPEC:
50154718Ssklower 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
50254718Ssklower 		bcopy(addrlo, addrhi, 6);
50354718Ssklower 		break;
50454718Ssklower 
50554718Ssklower #ifdef INET
50654718Ssklower 	case AF_INET:
50754718Ssklower 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
50854718Ssklower 		if (sin->sin_addr.s_addr == INADDR_ANY) {
50954718Ssklower 			/*
51054718Ssklower 			 * An IP address of INADDR_ANY means listen to all
51154718Ssklower 			 * of the Ethernet multicast addresses used for IP.
51254718Ssklower 			 * (This is for the sake of IP multicast routers.)
51354718Ssklower 			 */
51454718Ssklower 			bcopy(ether_ipmulticast_min, addrlo, 6);
51554718Ssklower 			bcopy(ether_ipmulticast_max, addrhi, 6);
51654718Ssklower 		}
51754718Ssklower 		else {
51854718Ssklower 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
51954718Ssklower 			bcopy(addrlo, addrhi, 6);
52054718Ssklower 		}
52154718Ssklower 		break;
52254718Ssklower #endif
52354718Ssklower 
52454718Ssklower 	default:
52554718Ssklower 		splx(s);
52654718Ssklower 		return (EAFNOSUPPORT);
52754718Ssklower 	}
52854718Ssklower 
52954718Ssklower 	/*
53054718Ssklower 	 * Verify that we have valid Ethernet multicast addresses.
53154718Ssklower 	 */
53254718Ssklower 	if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
53354718Ssklower 		splx(s);
53454718Ssklower 		return (EINVAL);
53554718Ssklower 	}
53654718Ssklower 	/*
53754718Ssklower 	 * See if the address range is already in the list.
53854718Ssklower 	 */
53954718Ssklower 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
54054718Ssklower 	if (enm != NULL) {
54154718Ssklower 		/*
54254718Ssklower 		 * Found it; just increment the reference count.
54354718Ssklower 		 */
54454718Ssklower 		++enm->enm_refcount;
54554718Ssklower 		splx(s);
54654718Ssklower 		return (0);
54754718Ssklower 	}
54854718Ssklower 	/*
54954718Ssklower 	 * New address or range; malloc a new multicast record
55054718Ssklower 	 * and link it into the interface's multicast list.
55154718Ssklower 	 */
55254718Ssklower 	enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
55354718Ssklower 	if (enm == NULL) {
55454718Ssklower 		splx(s);
55554718Ssklower 		return (ENOBUFS);
55654718Ssklower 	}
55754718Ssklower 	bcopy(addrlo, enm->enm_addrlo, 6);
55854718Ssklower 	bcopy(addrhi, enm->enm_addrhi, 6);
55954718Ssklower 	enm->enm_ac = ac;
56054718Ssklower 	enm->enm_refcount = 1;
56154718Ssklower 	enm->enm_next = ac->ac_multiaddrs;
56254718Ssklower 	ac->ac_multiaddrs = enm;
56354718Ssklower 	ac->ac_multicnt++;
56454718Ssklower 	splx(s);
56554718Ssklower 	/*
56654718Ssklower 	 * Return ENETRESET to inform the driver that the list has changed
56754718Ssklower 	 * and its reception filter should be adjusted accordingly.
56854718Ssklower 	 */
56954718Ssklower 	return (ENETRESET);
57054718Ssklower }
57154718Ssklower 
57254718Ssklower /*
57354718Ssklower  * Delete a multicast address record.
57454718Ssklower  */
57554718Ssklower int
ether_delmulti(ifr,ac)57654718Ssklower ether_delmulti(ifr, ac)
57754718Ssklower 	struct ifreq *ifr;
57854718Ssklower 	register struct arpcom *ac;
57954718Ssklower {
58054718Ssklower 	register struct ether_multi *enm;
58154718Ssklower 	register struct ether_multi **p;
58254718Ssklower 	struct sockaddr_in *sin;
58354718Ssklower 	u_char addrlo[6];
58454718Ssklower 	u_char addrhi[6];
58554718Ssklower 	int s = splimp();
58654718Ssklower 
58754718Ssklower 	switch (ifr->ifr_addr.sa_family) {
58854718Ssklower 
58954718Ssklower 	case AF_UNSPEC:
59054718Ssklower 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
59154718Ssklower 		bcopy(addrlo, addrhi, 6);
59254718Ssklower 		break;
59354718Ssklower 
59454718Ssklower #ifdef INET
59554718Ssklower 	case AF_INET:
59654718Ssklower 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
59754718Ssklower 		if (sin->sin_addr.s_addr == INADDR_ANY) {
59854718Ssklower 			/*
59954718Ssklower 			 * An IP address of INADDR_ANY means stop listening
60054718Ssklower 			 * to the range of Ethernet multicast addresses used
60154718Ssklower 			 * for IP.
60254718Ssklower 			 */
60354718Ssklower 			bcopy(ether_ipmulticast_min, addrlo, 6);
60454718Ssklower 			bcopy(ether_ipmulticast_max, addrhi, 6);
60554718Ssklower 		}
60654718Ssklower 		else {
60754718Ssklower 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
60854718Ssklower 			bcopy(addrlo, addrhi, 6);
60954718Ssklower 		}
61054718Ssklower 		break;
61154718Ssklower #endif
61254718Ssklower 
61354718Ssklower 	default:
61454718Ssklower 		splx(s);
61554718Ssklower 		return (EAFNOSUPPORT);
61654718Ssklower 	}
61754718Ssklower 
61854718Ssklower 	/*
61954718Ssklower 	 * Look up the address in our list.
62054718Ssklower 	 */
62154718Ssklower 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
62254718Ssklower 	if (enm == NULL) {
62354718Ssklower 		splx(s);
62454718Ssklower 		return (ENXIO);
62554718Ssklower 	}
62654718Ssklower 	if (--enm->enm_refcount != 0) {
62754718Ssklower 		/*
62854718Ssklower 		 * Still some claims to this record.
62954718Ssklower 		 */
63054718Ssklower 		splx(s);
63154718Ssklower 		return (0);
63254718Ssklower 	}
63354718Ssklower 	/*
63454718Ssklower 	 * No remaining claims to this record; unlink and free it.
63554718Ssklower 	 */
63654718Ssklower 	for (p = &enm->enm_ac->ac_multiaddrs;
63754718Ssklower 	     *p != enm;
63854718Ssklower 	     p = &(*p)->enm_next)
63954718Ssklower 		continue;
64054718Ssklower 	*p = (*p)->enm_next;
64154718Ssklower 	free(enm, M_IFMADDR);
64254718Ssklower 	ac->ac_multicnt--;
64354718Ssklower 	splx(s);
64454718Ssklower 	/*
64554718Ssklower 	 * Return ENETRESET to inform the driver that the list has changed
64654718Ssklower 	 * and its reception filter should be adjusted accordingly.
64754718Ssklower 	 */
64854718Ssklower 	return (ENETRESET);
64954718Ssklower }
650