xref: /csrg-svn/sys/net/if_ethersubr.c (revision 56529)
135379Skfall /*
239187Ssklower  * Copyright (c) 1982, 1989 Regents of the University of California.
335379Skfall  * All rights reserved.
435379Skfall  *
544464Sbostic  * %sccs.include.redist.c%
635379Skfall  *
7*56529Sbostic  *	@(#)if_ethersubr.c	7.22 (Berkeley) 10/11/92
835379Skfall  */
935379Skfall 
10*56529Sbostic #include <sys/param.h>
11*56529Sbostic #include <sys/systm.h>
12*56529Sbostic #include <sys/kernel.h>
13*56529Sbostic #include <sys/malloc.h>
14*56529Sbostic #include <sys/mbuf.h>
15*56529Sbostic #include <sys/protosw.h>
16*56529Sbostic #include <sys/socket.h>
17*56529Sbostic #include <sys/ioctl.h>
18*56529Sbostic #include <sys/errno.h>
19*56529Sbostic #include <sys/syslog.h>
2035379Skfall 
21*56529Sbostic #include <machine/cpu.h>
2235379Skfall 
23*56529Sbostic #include <net/if.h>
24*56529Sbostic #include <net/netisr.h>
25*56529Sbostic #include <net/route.h>
26*56529Sbostic #include <net/if_llc.h>
27*56529Sbostic #include <net/if_dl.h>
28*56529Sbostic #include <net/if_types.h>
29*56529Sbostic 
3035379Skfall #ifdef INET
31*56529Sbostic #include <netinet/in.h>
32*56529Sbostic #include <netinet/in_var.h>
3345930Sbostic #endif
34*56529Sbostic #include <netinet/if_ether.h>
3535379Skfall 
3635379Skfall #ifdef NS
37*56529Sbostic #include <netns/ns.h>
38*56529Sbostic #include <netns/ns_if.h>
3935379Skfall #endif
4035379Skfall 
4137472Ssklower #ifdef ISO
42*56529Sbostic #include <netiso/argo_debug.h>
43*56529Sbostic #include <netiso/iso.h>
44*56529Sbostic #include <netiso/iso_var.h>
45*56529Sbostic #include <netiso/iso_snpac.h>
4637472Ssklower #endif
4737472Ssklower 
4835379Skfall u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
4935795Skarels extern	struct ifnet loif;
5050133Ssklower #define senderr(e) { error = (e); goto bad;}
5135379Skfall 
5235379Skfall /*
5335379Skfall  * Ethernet output routine.
5435379Skfall  * Encapsulate a packet of type family for the local net.
5535379Skfall  * Use trailer local net encapsulation if enough data in first
5635379Skfall  * packet leaves a multiple of 512 bytes of data in remainder.
5735379Skfall  * Assumes that ifp is actually pointer to arpcom structure.
5835379Skfall  */
5950133Ssklower ether_output(ifp, m0, dst, rt0)
6035379Skfall 	register struct ifnet *ifp;
6135379Skfall 	struct mbuf *m0;
6235379Skfall 	struct sockaddr *dst;
6350133Ssklower 	struct rtentry *rt0;
6435379Skfall {
6535795Skarels 	short type;
6635795Skarels 	int s, error = 0;
6735379Skfall  	u_char edst[6];
6835379Skfall 	register struct mbuf *m = m0;
6950133Ssklower 	register struct rtentry *rt;
7035795Skarels 	struct mbuf *mcopy = (struct mbuf *)0;
7135379Skfall 	register struct ether_header *eh;
7254718Ssklower 	int off, len = m->m_pkthdr.len;
7354718Ssklower 	struct arpcom *ac = (struct arpcom *)ifp;
7435379Skfall 
7550133Ssklower 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
7650133Ssklower 		senderr(ENETDOWN);
7750133Ssklower 	ifp->if_lastchange = time;
7850133Ssklower 	if (rt = rt0) {
7950133Ssklower 		if ((rt->rt_flags & RTF_UP) == 0) {
8050133Ssklower 			if (rt0 = rt = rtalloc1(dst, 1))
8150133Ssklower 				rt->rt_refcnt--;
8250133Ssklower 			else
8353060Ssklower 				senderr(EHOSTUNREACH);
8450133Ssklower 		}
8550133Ssklower 		if (rt->rt_flags & RTF_GATEWAY) {
8650133Ssklower 			if (rt->rt_gwroute == 0)
8750133Ssklower 				goto lookup;
8850133Ssklower 			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
8950133Ssklower 				rtfree(rt); rt = rt0;
9050133Ssklower 			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
9150133Ssklower 				if ((rt = rt->rt_gwroute) == 0)
9253060Ssklower 					senderr(EHOSTUNREACH);
9350133Ssklower 			}
9450133Ssklower 		}
9550133Ssklower 		if (rt->rt_flags & RTF_REJECT)
9650133Ssklower 			if (rt->rt_rmx.rmx_expire == 0 ||
9750133Ssklower 			    time.tv_sec < rt->rt_rmx.rmx_expire)
9853060Ssklower 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
9935379Skfall 	}
10035379Skfall 	switch (dst->sa_family) {
10135379Skfall 
10235379Skfall #ifdef INET
10335379Skfall 	case AF_INET:
10450133Ssklower 		if (!arpresolve(ac, rt, m, (struct sockaddr_in *)dst,
10554718Ssklower 				edst))
10635379Skfall 			return (0);	/* if not yet resolved */
10754718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
10854718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
10941546Smckusick 			mcopy = m_copy(m, 0, (int)M_COPYALL);
11035379Skfall 		off = m->m_pkthdr.len - m->m_len;
11135379Skfall 		type = ETHERTYPE_IP;
11254718Ssklower 		break;
11335379Skfall #endif
11435379Skfall #ifdef NS
11535379Skfall 	case AF_NS:
11635379Skfall 		type = ETHERTYPE_NS;
11739187Ssklower  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
11839187Ssklower 		    (caddr_t)edst, sizeof (edst));
11935795Skarels 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
12045632Ssklower 			return (looutput(ifp, m, dst, rt));
12154718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
12254718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
12341546Smckusick 			mcopy = m_copy(m, 0, (int)M_COPYALL);
12454718Ssklower 		break;
12535379Skfall #endif
12635795Skarels #ifdef	ISO
12735795Skarels 	case AF_ISO: {
12843073Ssklower 		int	snpalen;
12937472Ssklower 		struct	llc *l;
13050133Ssklower 		register struct sockaddr_dl *sdl;
13137472Ssklower 
13250133Ssklower 		if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
13350133Ssklower 		    sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
13450133Ssklower 			bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
13550133Ssklower 		} else if (error =
13650133Ssklower 			    iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
13750133Ssklower 					    (char *)edst, &snpalen))
13843073Ssklower 			goto bad; /* Not Resolved */
13954718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
14054718Ssklower 		if (*edst & 1)
14154718Ssklower 			m->m_flags |= (M_BCAST|M_MCAST);
14254718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
14345632Ssklower 		    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
14445632Ssklower 			M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
14545632Ssklower 			if (mcopy) {
14645632Ssklower 				eh = mtod(mcopy, struct ether_header *);
14745632Ssklower 				bcopy((caddr_t)edst,
14845632Ssklower 				      (caddr_t)eh->ether_dhost, sizeof (edst));
14945632Ssklower 				bcopy((caddr_t)ac->ac_enaddr,
15045632Ssklower 				      (caddr_t)eh->ether_shost, sizeof (edst));
15145632Ssklower 			}
15245632Ssklower 		}
15335795Skarels 		M_PREPEND(m, 3, M_DONTWAIT);
15437472Ssklower 		if (m == NULL)
15543073Ssklower 			return (0);
15635795Skarels 		type = m->m_pkthdr.len;
15735795Skarels 		l = mtod(m, struct llc *);
15835795Skarels 		l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
15935795Skarels 		l->llc_control = LLC_UI;
16039187Ssklower 		len += 3;
16135795Skarels 		IFDEBUG(D_ETHER)
16235795Skarels 			int i;
16335795Skarels 			printf("unoutput: sending pkt to: ");
16435795Skarels 			for (i=0; i<6; i++)
16535795Skarels 				printf("%x ", edst[i] & 0xff);
16635795Skarels 			printf("\n");
16735795Skarels 		ENDDEBUG
16854718Ssklower 		} break;
16935795Skarels #endif	ISO
17041546Smckusick 
17135379Skfall 	case AF_UNSPEC:
17235379Skfall 		eh = (struct ether_header *)dst->sa_data;
17335379Skfall  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
17435379Skfall 		type = eh->ether_type;
17554718Ssklower 		break;
17635379Skfall 
17735379Skfall 	default:
17835379Skfall 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
17935379Skfall 			dst->sa_family);
18050133Ssklower 		senderr(EAFNOSUPPORT);
18135379Skfall 	}
18235379Skfall 
18335379Skfall 
18445632Ssklower 	if (mcopy)
18545632Ssklower 		(void) looutput(ifp, mcopy, dst, rt);
18635379Skfall 	/*
18735379Skfall 	 * Add local net header.  If no space in first mbuf,
18835379Skfall 	 * allocate another.
18935379Skfall 	 */
19035379Skfall 	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
19150133Ssklower 	if (m == 0)
19250133Ssklower 		senderr(ENOBUFS);
19335379Skfall 	eh = mtod(m, struct ether_header *);
19435795Skarels 	type = htons((u_short)type);
19535795Skarels 	bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
19635795Skarels 		sizeof(eh->ether_type));
19735379Skfall  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
19835379Skfall  	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
19935379Skfall 	    sizeof(eh->ether_shost));
20045632Ssklower 	s = splimp();
20135379Skfall 	/*
20235379Skfall 	 * Queue message on interface, and start output if interface
20335379Skfall 	 * not yet active.
20435379Skfall 	 */
20535379Skfall 	if (IF_QFULL(&ifp->if_snd)) {
20635379Skfall 		IF_DROP(&ifp->if_snd);
20735379Skfall 		splx(s);
20850133Ssklower 		senderr(ENOBUFS);
20935379Skfall 	}
21035379Skfall 	IF_ENQUEUE(&ifp->if_snd, m);
21135379Skfall 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
21238845Sroot 		(*ifp->if_start)(ifp);
21335379Skfall 	splx(s);
21439187Ssklower 	ifp->if_obytes += len + sizeof (struct ether_header);
21554718Ssklower 	if (m->m_flags & M_MCAST)
21639187Ssklower 		ifp->if_omcasts++;
21735795Skarels 	return (error);
21835379Skfall 
21935379Skfall bad:
22035795Skarels 	if (m)
22135795Skarels 		m_freem(m);
22235379Skfall 	return (error);
22335379Skfall }
22435379Skfall 
22535379Skfall /*
22638845Sroot  * Process a received Ethernet packet;
22738845Sroot  * the packet is in the mbuf chain m without
22838845Sroot  * the ether header, which is provided separately.
22935379Skfall  */
23037472Ssklower ether_input(ifp, eh, m)
23135379Skfall 	struct ifnet *ifp;
23235379Skfall 	register struct ether_header *eh;
23335379Skfall 	struct mbuf *m;
23435379Skfall {
23535379Skfall 	register struct ifqueue *inq;
23635795Skarels 	register struct llc *l;
23735379Skfall 	int s;
23835379Skfall 
23953696Ssklower 	if ((ifp->if_flags & IFF_UP) == 0) {
24053696Ssklower 		m_freem(m);
24153696Ssklower 		return;
24253696Ssklower 	}
24339187Ssklower 	ifp->if_lastchange = time;
24439187Ssklower 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
24535795Skarels 	if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
24635379Skfall 	    sizeof(etherbroadcastaddr)) == 0)
24735379Skfall 		m->m_flags |= M_BCAST;
24835795Skarels 	else if (eh->ether_dhost[0] & 1)
24935795Skarels 		m->m_flags |= M_MCAST;
25039187Ssklower 	if (m->m_flags & (M_BCAST|M_MCAST))
25139187Ssklower 		ifp->if_imcasts++;
25235379Skfall 
25335379Skfall 	switch (eh->ether_type) {
25435379Skfall #ifdef INET
25535379Skfall 	case ETHERTYPE_IP:
25635379Skfall 		schednetisr(NETISR_IP);
25735379Skfall 		inq = &ipintrq;
25835379Skfall 		break;
25935379Skfall 
26035379Skfall 	case ETHERTYPE_ARP:
26150133Ssklower 		schednetisr(NETISR_ARP);
26250133Ssklower 		inq = &arpintrq;
26350133Ssklower 		break;
26435379Skfall #endif
26535379Skfall #ifdef NS
26635379Skfall 	case ETHERTYPE_NS:
26735379Skfall 		schednetisr(NETISR_NS);
26835379Skfall 		inq = &nsintrq;
26935379Skfall 		break;
27035379Skfall 
27135379Skfall #endif
27235379Skfall 	default:
27338845Sroot #ifdef	ISO
27437472Ssklower 		if (eh->ether_type > ETHERMTU)
27535795Skarels 			goto dropanyway;
27635795Skarels 		l = mtod(m, struct llc *);
27735795Skarels 		switch (l->llc_control) {
27835795Skarels 		case LLC_UI:
27935795Skarels 		/* LLC_UI_P forbidden in class 1 service */
28035795Skarels 		    if ((l->llc_dsap == LLC_ISO_LSAP) &&
28135795Skarels 			(l->llc_ssap == LLC_ISO_LSAP)) {
28235795Skarels 				/* LSAP for ISO */
28345632Ssklower 			if (m->m_pkthdr.len > eh->ether_type)
28445632Ssklower 				m_adj(m, eh->ether_type - m->m_pkthdr.len);
28538845Sroot 			m->m_data += 3;		/* XXX */
28638845Sroot 			m->m_len -= 3;		/* XXX */
28738845Sroot 			m->m_pkthdr.len -= 3;	/* XXX */
28837472Ssklower 			M_PREPEND(m, sizeof *eh, M_DONTWAIT);
28937472Ssklower 			if (m == 0)
29037472Ssklower 				return;
29137472Ssklower 			*mtod(m, struct ether_header *) = *eh;
29237472Ssklower 			IFDEBUG(D_ETHER)
29337472Ssklower 			    printf("clnp packet");
29437472Ssklower 			ENDDEBUG
29537472Ssklower 			schednetisr(NETISR_ISO);
29635795Skarels 			inq = &clnlintrq;
29738845Sroot 			break;
29835795Skarels 		    }
29938845Sroot 		    goto dropanyway;
30038845Sroot 
30135795Skarels 		case LLC_XID:
30235795Skarels 		case LLC_XID_P:
30335795Skarels 		    if(m->m_len < 6)
30435795Skarels 			goto dropanyway;
30535795Skarels 		    l->llc_window = 0;
30635795Skarels 		    l->llc_fid = 9;
30735795Skarels 		    l->llc_class = 1;
30835795Skarels 		    l->llc_dsap = l->llc_ssap = 0;
30935795Skarels 		    /* Fall through to */
31035795Skarels 		case LLC_TEST:
31135795Skarels 		case LLC_TEST_P:
31235795Skarels 		{
31335795Skarels 		    struct sockaddr sa;
31435795Skarels 		    register struct ether_header *eh2;
31535795Skarels 		    int i;
31635795Skarels 		    u_char c = l->llc_dsap;
31735795Skarels 		    l->llc_dsap = l->llc_ssap;
31835795Skarels 		    l->llc_ssap = c;
31937472Ssklower 		    if (m->m_flags & (M_BCAST | M_MCAST))
32055900Ssklower 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
32137472Ssklower 			      (caddr_t)eh->ether_dhost, 6);
32235795Skarels 		    sa.sa_family = AF_UNSPEC;
32337472Ssklower 		    sa.sa_len = sizeof(sa);
32435795Skarels 		    eh2 = (struct ether_header *)sa.sa_data;
32535795Skarels 		    for (i = 0; i < 6; i++) {
32635795Skarels 			eh2->ether_shost[i] = c = eh->ether_dhost[i];
32735795Skarels 			eh2->ether_dhost[i] =
32835795Skarels 				eh->ether_dhost[i] = eh->ether_shost[i];
32935795Skarels 			eh->ether_shost[i] = c;
33035795Skarels 		    }
33152448Ssklower 		    ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
33235795Skarels 		    return;
33335795Skarels 		}
33435795Skarels 		dropanyway:
33535795Skarels 		default:
33635795Skarels 		    m_freem(m);
33735795Skarels 		    return;
33835795Skarels 	    }
33938845Sroot #else
34038845Sroot 	    m_freem(m);
34138845Sroot 	    return;
34238845Sroot #endif	ISO
34335379Skfall 	}
34435379Skfall 
34535379Skfall 	s = splimp();
34635379Skfall 	if (IF_QFULL(inq)) {
34735379Skfall 		IF_DROP(inq);
34835379Skfall 		m_freem(m);
34935379Skfall 	} else
35035379Skfall 		IF_ENQUEUE(inq, m);
35135379Skfall 	splx(s);
35235379Skfall }
35335379Skfall 
35435379Skfall /*
35535379Skfall  * Convert Ethernet address to printable (loggable) representation.
35635379Skfall  */
35737472Ssklower static char digits[] = "0123456789abcdef";
35835379Skfall char *
35935379Skfall ether_sprintf(ap)
36035379Skfall 	register u_char *ap;
36135379Skfall {
36235379Skfall 	register i;
36335379Skfall 	static char etherbuf[18];
36435379Skfall 	register char *cp = etherbuf;
36535379Skfall 
36635379Skfall 	for (i = 0; i < 6; i++) {
36735379Skfall 		*cp++ = digits[*ap >> 4];
36835379Skfall 		*cp++ = digits[*ap++ & 0xf];
36935379Skfall 		*cp++ = ':';
37035379Skfall 	}
37135379Skfall 	*--cp = 0;
37235379Skfall 	return (etherbuf);
37335379Skfall }
37452567Ssklower 
37552567Ssklower /*
37652567Ssklower  * Perform common duties while attaching to interface list
37752567Ssklower  */
37852567Ssklower ether_ifattach(ifp)
37952567Ssklower 	register struct ifnet *ifp;
38052567Ssklower {
38152567Ssklower 	register struct ifaddr *ifa;
38252567Ssklower 	register struct sockaddr_dl *sdl;
38352567Ssklower 
38452567Ssklower 	ifp->if_type = IFT_ETHER;
38552567Ssklower 	ifp->if_addrlen = 6;
38652567Ssklower 	ifp->if_hdrlen = 14;
38752567Ssklower 	ifp->if_mtu = ETHERMTU;
38852567Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
38952567Ssklower 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
39052567Ssklower 		    sdl->sdl_family == AF_LINK) {
39152567Ssklower 			sdl->sdl_type = IFT_ETHER;
39252567Ssklower 			sdl->sdl_alen = ifp->if_addrlen;
39352567Ssklower 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
39452567Ssklower 			      LLADDR(sdl), ifp->if_addrlen);
39552567Ssklower 			break;
39652567Ssklower 		}
39752567Ssklower }
39854718Ssklower 
39954718Ssklower #ifdef MULTICAST
40054718Ssklower u_char	ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
40154718Ssklower u_char	ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
40254718Ssklower /*
40354718Ssklower  * Add an Ethernet multicast address or range of addresses to the list for a
40454718Ssklower  * given interface.
40554718Ssklower  */
40654718Ssklower int
40754718Ssklower ether_addmulti(ifr, ac)
40854718Ssklower 	struct ifreq *ifr;
40954718Ssklower 	register struct arpcom *ac;
41054718Ssklower {
41154718Ssklower 	register struct ether_multi *enm;
41254718Ssklower 	struct sockaddr_in *sin;
41354718Ssklower 	u_char addrlo[6];
41454718Ssklower 	u_char addrhi[6];
41554718Ssklower 	int s = splimp();
41654718Ssklower 
41754718Ssklower 	switch (ifr->ifr_addr.sa_family) {
41854718Ssklower 
41954718Ssklower 	case AF_UNSPEC:
42054718Ssklower 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
42154718Ssklower 		bcopy(addrlo, addrhi, 6);
42254718Ssklower 		break;
42354718Ssklower 
42454718Ssklower #ifdef INET
42554718Ssklower 	case AF_INET:
42654718Ssklower 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
42754718Ssklower 		if (sin->sin_addr.s_addr == INADDR_ANY) {
42854718Ssklower 			/*
42954718Ssklower 			 * An IP address of INADDR_ANY means listen to all
43054718Ssklower 			 * of the Ethernet multicast addresses used for IP.
43154718Ssklower 			 * (This is for the sake of IP multicast routers.)
43254718Ssklower 			 */
43354718Ssklower 			bcopy(ether_ipmulticast_min, addrlo, 6);
43454718Ssklower 			bcopy(ether_ipmulticast_max, addrhi, 6);
43554718Ssklower 		}
43654718Ssklower 		else {
43754718Ssklower 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
43854718Ssklower 			bcopy(addrlo, addrhi, 6);
43954718Ssklower 		}
44054718Ssklower 		break;
44154718Ssklower #endif
44254718Ssklower 
44354718Ssklower 	default:
44454718Ssklower 		splx(s);
44554718Ssklower 		return (EAFNOSUPPORT);
44654718Ssklower 	}
44754718Ssklower 
44854718Ssklower 	/*
44954718Ssklower 	 * Verify that we have valid Ethernet multicast addresses.
45054718Ssklower 	 */
45154718Ssklower 	if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
45254718Ssklower 		splx(s);
45354718Ssklower 		return (EINVAL);
45454718Ssklower 	}
45554718Ssklower 	/*
45654718Ssklower 	 * See if the address range is already in the list.
45754718Ssklower 	 */
45854718Ssklower 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
45954718Ssklower 	if (enm != NULL) {
46054718Ssklower 		/*
46154718Ssklower 		 * Found it; just increment the reference count.
46254718Ssklower 		 */
46354718Ssklower 		++enm->enm_refcount;
46454718Ssklower 		splx(s);
46554718Ssklower 		return (0);
46654718Ssklower 	}
46754718Ssklower 	/*
46854718Ssklower 	 * New address or range; malloc a new multicast record
46954718Ssklower 	 * and link it into the interface's multicast list.
47054718Ssklower 	 */
47154718Ssklower 	enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
47254718Ssklower 	if (enm == NULL) {
47354718Ssklower 		splx(s);
47454718Ssklower 		return (ENOBUFS);
47554718Ssklower 	}
47654718Ssklower 	bcopy(addrlo, enm->enm_addrlo, 6);
47754718Ssklower 	bcopy(addrhi, enm->enm_addrhi, 6);
47854718Ssklower 	enm->enm_ac = ac;
47954718Ssklower 	enm->enm_refcount = 1;
48054718Ssklower 	enm->enm_next = ac->ac_multiaddrs;
48154718Ssklower 	ac->ac_multiaddrs = enm;
48254718Ssklower 	ac->ac_multicnt++;
48354718Ssklower 	splx(s);
48454718Ssklower 	/*
48554718Ssklower 	 * Return ENETRESET to inform the driver that the list has changed
48654718Ssklower 	 * and its reception filter should be adjusted accordingly.
48754718Ssklower 	 */
48854718Ssklower 	return (ENETRESET);
48954718Ssklower }
49054718Ssklower 
49154718Ssklower /*
49254718Ssklower  * Delete a multicast address record.
49354718Ssklower  */
49454718Ssklower int
49554718Ssklower ether_delmulti(ifr, ac)
49654718Ssklower 	struct ifreq *ifr;
49754718Ssklower 	register struct arpcom *ac;
49854718Ssklower {
49954718Ssklower 	register struct ether_multi *enm;
50054718Ssklower 	register struct ether_multi **p;
50154718Ssklower 	struct sockaddr_in *sin;
50254718Ssklower 	u_char addrlo[6];
50354718Ssklower 	u_char addrhi[6];
50454718Ssklower 	int s = splimp();
50554718Ssklower 
50654718Ssklower 	switch (ifr->ifr_addr.sa_family) {
50754718Ssklower 
50854718Ssklower 	case AF_UNSPEC:
50954718Ssklower 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
51054718Ssklower 		bcopy(addrlo, addrhi, 6);
51154718Ssklower 		break;
51254718Ssklower 
51354718Ssklower #ifdef INET
51454718Ssklower 	case AF_INET:
51554718Ssklower 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
51654718Ssklower 		if (sin->sin_addr.s_addr == INADDR_ANY) {
51754718Ssklower 			/*
51854718Ssklower 			 * An IP address of INADDR_ANY means stop listening
51954718Ssklower 			 * to the range of Ethernet multicast addresses used
52054718Ssklower 			 * for IP.
52154718Ssklower 			 */
52254718Ssklower 			bcopy(ether_ipmulticast_min, addrlo, 6);
52354718Ssklower 			bcopy(ether_ipmulticast_max, addrhi, 6);
52454718Ssklower 		}
52554718Ssklower 		else {
52654718Ssklower 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
52754718Ssklower 			bcopy(addrlo, addrhi, 6);
52854718Ssklower 		}
52954718Ssklower 		break;
53054718Ssklower #endif
53154718Ssklower 
53254718Ssklower 	default:
53354718Ssklower 		splx(s);
53454718Ssklower 		return (EAFNOSUPPORT);
53554718Ssklower 	}
53654718Ssklower 
53754718Ssklower 	/*
53854718Ssklower 	 * Look up the address in our list.
53954718Ssklower 	 */
54054718Ssklower 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
54154718Ssklower 	if (enm == NULL) {
54254718Ssklower 		splx(s);
54354718Ssklower 		return (ENXIO);
54454718Ssklower 	}
54554718Ssklower 	if (--enm->enm_refcount != 0) {
54654718Ssklower 		/*
54754718Ssklower 		 * Still some claims to this record.
54854718Ssklower 		 */
54954718Ssklower 		splx(s);
55054718Ssklower 		return (0);
55154718Ssklower 	}
55254718Ssklower 	/*
55354718Ssklower 	 * No remaining claims to this record; unlink and free it.
55454718Ssklower 	 */
55554718Ssklower 	for (p = &enm->enm_ac->ac_multiaddrs;
55654718Ssklower 	     *p != enm;
55754718Ssklower 	     p = &(*p)->enm_next)
55854718Ssklower 		continue;
55954718Ssklower 	*p = (*p)->enm_next;
56054718Ssklower 	free(enm, M_IFMADDR);
56154718Ssklower 	ac->ac_multicnt--;
56254718Ssklower 	splx(s);
56354718Ssklower 	/*
56454718Ssklower 	 * Return ENETRESET to inform the driver that the list has changed
56554718Ssklower 	 * and its reception filter should be adjusted accordingly.
56654718Ssklower 	 */
56754718Ssklower 	return (ENETRESET);
56854718Ssklower }
56954718Ssklower #endif
570