xref: /csrg-svn/sys/net/if_ethersubr.c (revision 55900)
135379Skfall /*
239187Ssklower  * Copyright (c) 1982, 1989 Regents of the University of California.
335379Skfall  * All rights reserved.
435379Skfall  *
544464Sbostic  * %sccs.include.redist.c%
635379Skfall  *
7*55900Ssklower  *	@(#)if_ethersubr.c	7.21 (Berkeley) 08/14/92
835379Skfall  */
935379Skfall 
1035379Skfall #include "param.h"
1135379Skfall #include "systm.h"
1248455Skarels #include "kernel.h"
1335379Skfall #include "malloc.h"
1435379Skfall #include "mbuf.h"
1535379Skfall #include "protosw.h"
1635379Skfall #include "socket.h"
1735379Skfall #include "ioctl.h"
1835379Skfall #include "errno.h"
1935379Skfall #include "syslog.h"
2052270Storek #include "machine/cpu.h"
2135379Skfall 
2235379Skfall #include "if.h"
2335379Skfall #include "netisr.h"
2435379Skfall #include "route.h"
2535795Skarels #include "if_llc.h"
2640790Ssklower #include "if_dl.h"
2752567Ssklower #include "if_types.h"
2835379Skfall 
2935379Skfall #ifdef INET
3035379Skfall #include "../netinet/in.h"
3135379Skfall #include "../netinet/in_var.h"
3245930Sbostic #endif
3335379Skfall #include "../netinet/if_ether.h"
3435379Skfall 
3535379Skfall #ifdef NS
3635379Skfall #include "../netns/ns.h"
3735379Skfall #include "../netns/ns_if.h"
3835379Skfall #endif
3935379Skfall 
4037472Ssklower #ifdef ISO
4137472Ssklower #include "../netiso/argo_debug.h"
4237472Ssklower #include "../netiso/iso.h"
4337472Ssklower #include "../netiso/iso_var.h"
4443073Ssklower #include "../netiso/iso_snpac.h"
4537472Ssklower #endif
4637472Ssklower 
4735379Skfall u_char	etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
4835795Skarels extern	struct ifnet loif;
4950133Ssklower #define senderr(e) { error = (e); goto bad;}
5035379Skfall 
5135379Skfall /*
5235379Skfall  * Ethernet output routine.
5335379Skfall  * Encapsulate a packet of type family for the local net.
5435379Skfall  * Use trailer local net encapsulation if enough data in first
5535379Skfall  * packet leaves a multiple of 512 bytes of data in remainder.
5635379Skfall  * Assumes that ifp is actually pointer to arpcom structure.
5735379Skfall  */
5850133Ssklower ether_output(ifp, m0, dst, rt0)
5935379Skfall 	register struct ifnet *ifp;
6035379Skfall 	struct mbuf *m0;
6135379Skfall 	struct sockaddr *dst;
6250133Ssklower 	struct rtentry *rt0;
6335379Skfall {
6435795Skarels 	short type;
6535795Skarels 	int s, error = 0;
6635379Skfall  	u_char edst[6];
6735379Skfall 	register struct mbuf *m = m0;
6850133Ssklower 	register struct rtentry *rt;
6935795Skarels 	struct mbuf *mcopy = (struct mbuf *)0;
7035379Skfall 	register struct ether_header *eh;
7154718Ssklower 	int off, len = m->m_pkthdr.len;
7254718Ssklower 	struct arpcom *ac = (struct arpcom *)ifp;
7335379Skfall 
7450133Ssklower 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
7550133Ssklower 		senderr(ENETDOWN);
7650133Ssklower 	ifp->if_lastchange = time;
7750133Ssklower 	if (rt = rt0) {
7850133Ssklower 		if ((rt->rt_flags & RTF_UP) == 0) {
7950133Ssklower 			if (rt0 = rt = rtalloc1(dst, 1))
8050133Ssklower 				rt->rt_refcnt--;
8150133Ssklower 			else
8253060Ssklower 				senderr(EHOSTUNREACH);
8350133Ssklower 		}
8450133Ssklower 		if (rt->rt_flags & RTF_GATEWAY) {
8550133Ssklower 			if (rt->rt_gwroute == 0)
8650133Ssklower 				goto lookup;
8750133Ssklower 			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
8850133Ssklower 				rtfree(rt); rt = rt0;
8950133Ssklower 			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
9050133Ssklower 				if ((rt = rt->rt_gwroute) == 0)
9153060Ssklower 					senderr(EHOSTUNREACH);
9250133Ssklower 			}
9350133Ssklower 		}
9450133Ssklower 		if (rt->rt_flags & RTF_REJECT)
9550133Ssklower 			if (rt->rt_rmx.rmx_expire == 0 ||
9650133Ssklower 			    time.tv_sec < rt->rt_rmx.rmx_expire)
9753060Ssklower 				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
9835379Skfall 	}
9935379Skfall 	switch (dst->sa_family) {
10035379Skfall 
10135379Skfall #ifdef INET
10235379Skfall 	case AF_INET:
10350133Ssklower 		if (!arpresolve(ac, rt, m, (struct sockaddr_in *)dst,
10454718Ssklower 				edst))
10535379Skfall 			return (0);	/* if not yet resolved */
10654718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
10754718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
10841546Smckusick 			mcopy = m_copy(m, 0, (int)M_COPYALL);
10935379Skfall 		off = m->m_pkthdr.len - m->m_len;
11035379Skfall 		type = ETHERTYPE_IP;
11154718Ssklower 		break;
11235379Skfall #endif
11335379Skfall #ifdef NS
11435379Skfall 	case AF_NS:
11535379Skfall 		type = ETHERTYPE_NS;
11639187Ssklower  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
11739187Ssklower 		    (caddr_t)edst, sizeof (edst));
11835795Skarels 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
11945632Ssklower 			return (looutput(ifp, m, dst, rt));
12054718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
12154718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
12241546Smckusick 			mcopy = m_copy(m, 0, (int)M_COPYALL);
12354718Ssklower 		break;
12435379Skfall #endif
12535795Skarels #ifdef	ISO
12635795Skarels 	case AF_ISO: {
12743073Ssklower 		int	snpalen;
12837472Ssklower 		struct	llc *l;
12950133Ssklower 		register struct sockaddr_dl *sdl;
13037472Ssklower 
13150133Ssklower 		if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
13250133Ssklower 		    sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
13350133Ssklower 			bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
13450133Ssklower 		} else if (error =
13550133Ssklower 			    iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
13650133Ssklower 					    (char *)edst, &snpalen))
13743073Ssklower 			goto bad; /* Not Resolved */
13854718Ssklower 		/* If broadcasting on a simplex interface, loopback a copy */
13954718Ssklower 		if (*edst & 1)
14054718Ssklower 			m->m_flags |= (M_BCAST|M_MCAST);
14154718Ssklower 		if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
14245632Ssklower 		    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
14345632Ssklower 			M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
14445632Ssklower 			if (mcopy) {
14545632Ssklower 				eh = mtod(mcopy, struct ether_header *);
14645632Ssklower 				bcopy((caddr_t)edst,
14745632Ssklower 				      (caddr_t)eh->ether_dhost, sizeof (edst));
14845632Ssklower 				bcopy((caddr_t)ac->ac_enaddr,
14945632Ssklower 				      (caddr_t)eh->ether_shost, sizeof (edst));
15045632Ssklower 			}
15145632Ssklower 		}
15235795Skarels 		M_PREPEND(m, 3, M_DONTWAIT);
15337472Ssklower 		if (m == NULL)
15443073Ssklower 			return (0);
15535795Skarels 		type = m->m_pkthdr.len;
15635795Skarels 		l = mtod(m, struct llc *);
15735795Skarels 		l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
15835795Skarels 		l->llc_control = LLC_UI;
15939187Ssklower 		len += 3;
16035795Skarels 		IFDEBUG(D_ETHER)
16135795Skarels 			int i;
16235795Skarels 			printf("unoutput: sending pkt to: ");
16335795Skarels 			for (i=0; i<6; i++)
16435795Skarels 				printf("%x ", edst[i] & 0xff);
16535795Skarels 			printf("\n");
16635795Skarels 		ENDDEBUG
16754718Ssklower 		} break;
16835795Skarels #endif	ISO
16941546Smckusick 
17035379Skfall 	case AF_UNSPEC:
17135379Skfall 		eh = (struct ether_header *)dst->sa_data;
17235379Skfall  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
17335379Skfall 		type = eh->ether_type;
17454718Ssklower 		break;
17535379Skfall 
17635379Skfall 	default:
17735379Skfall 		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
17835379Skfall 			dst->sa_family);
17950133Ssklower 		senderr(EAFNOSUPPORT);
18035379Skfall 	}
18135379Skfall 
18235379Skfall 
18345632Ssklower 	if (mcopy)
18445632Ssklower 		(void) looutput(ifp, mcopy, dst, rt);
18535379Skfall 	/*
18635379Skfall 	 * Add local net header.  If no space in first mbuf,
18735379Skfall 	 * allocate another.
18835379Skfall 	 */
18935379Skfall 	M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
19050133Ssklower 	if (m == 0)
19150133Ssklower 		senderr(ENOBUFS);
19235379Skfall 	eh = mtod(m, struct ether_header *);
19335795Skarels 	type = htons((u_short)type);
19435795Skarels 	bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
19535795Skarels 		sizeof(eh->ether_type));
19635379Skfall  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
19735379Skfall  	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
19835379Skfall 	    sizeof(eh->ether_shost));
19945632Ssklower 	s = splimp();
20035379Skfall 	/*
20135379Skfall 	 * Queue message on interface, and start output if interface
20235379Skfall 	 * not yet active.
20335379Skfall 	 */
20435379Skfall 	if (IF_QFULL(&ifp->if_snd)) {
20535379Skfall 		IF_DROP(&ifp->if_snd);
20635379Skfall 		splx(s);
20750133Ssklower 		senderr(ENOBUFS);
20835379Skfall 	}
20935379Skfall 	IF_ENQUEUE(&ifp->if_snd, m);
21035379Skfall 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
21138845Sroot 		(*ifp->if_start)(ifp);
21235379Skfall 	splx(s);
21339187Ssklower 	ifp->if_obytes += len + sizeof (struct ether_header);
21454718Ssklower 	if (m->m_flags & M_MCAST)
21539187Ssklower 		ifp->if_omcasts++;
21635795Skarels 	return (error);
21735379Skfall 
21835379Skfall bad:
21935795Skarels 	if (m)
22035795Skarels 		m_freem(m);
22135379Skfall 	return (error);
22235379Skfall }
22335379Skfall 
22435379Skfall /*
22538845Sroot  * Process a received Ethernet packet;
22638845Sroot  * the packet is in the mbuf chain m without
22738845Sroot  * the ether header, which is provided separately.
22835379Skfall  */
22937472Ssklower ether_input(ifp, eh, m)
23035379Skfall 	struct ifnet *ifp;
23135379Skfall 	register struct ether_header *eh;
23235379Skfall 	struct mbuf *m;
23335379Skfall {
23435379Skfall 	register struct ifqueue *inq;
23535795Skarels 	register struct llc *l;
23635379Skfall 	int s;
23735379Skfall 
23853696Ssklower 	if ((ifp->if_flags & IFF_UP) == 0) {
23953696Ssklower 		m_freem(m);
24053696Ssklower 		return;
24153696Ssklower 	}
24239187Ssklower 	ifp->if_lastchange = time;
24339187Ssklower 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
24435795Skarels 	if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
24535379Skfall 	    sizeof(etherbroadcastaddr)) == 0)
24635379Skfall 		m->m_flags |= M_BCAST;
24735795Skarels 	else if (eh->ether_dhost[0] & 1)
24835795Skarels 		m->m_flags |= M_MCAST;
24939187Ssklower 	if (m->m_flags & (M_BCAST|M_MCAST))
25039187Ssklower 		ifp->if_imcasts++;
25135379Skfall 
25235379Skfall 	switch (eh->ether_type) {
25335379Skfall #ifdef INET
25435379Skfall 	case ETHERTYPE_IP:
25535379Skfall 		schednetisr(NETISR_IP);
25635379Skfall 		inq = &ipintrq;
25735379Skfall 		break;
25835379Skfall 
25935379Skfall 	case ETHERTYPE_ARP:
26050133Ssklower 		schednetisr(NETISR_ARP);
26150133Ssklower 		inq = &arpintrq;
26250133Ssklower 		break;
26335379Skfall #endif
26435379Skfall #ifdef NS
26535379Skfall 	case ETHERTYPE_NS:
26635379Skfall 		schednetisr(NETISR_NS);
26735379Skfall 		inq = &nsintrq;
26835379Skfall 		break;
26935379Skfall 
27035379Skfall #endif
27135379Skfall 	default:
27238845Sroot #ifdef	ISO
27337472Ssklower 		if (eh->ether_type > ETHERMTU)
27435795Skarels 			goto dropanyway;
27535795Skarels 		l = mtod(m, struct llc *);
27635795Skarels 		switch (l->llc_control) {
27735795Skarels 		case LLC_UI:
27835795Skarels 		/* LLC_UI_P forbidden in class 1 service */
27935795Skarels 		    if ((l->llc_dsap == LLC_ISO_LSAP) &&
28035795Skarels 			(l->llc_ssap == LLC_ISO_LSAP)) {
28135795Skarels 				/* LSAP for ISO */
28245632Ssklower 			if (m->m_pkthdr.len > eh->ether_type)
28345632Ssklower 				m_adj(m, eh->ether_type - m->m_pkthdr.len);
28438845Sroot 			m->m_data += 3;		/* XXX */
28538845Sroot 			m->m_len -= 3;		/* XXX */
28638845Sroot 			m->m_pkthdr.len -= 3;	/* XXX */
28737472Ssklower 			M_PREPEND(m, sizeof *eh, M_DONTWAIT);
28837472Ssklower 			if (m == 0)
28937472Ssklower 				return;
29037472Ssklower 			*mtod(m, struct ether_header *) = *eh;
29137472Ssklower 			IFDEBUG(D_ETHER)
29237472Ssklower 			    printf("clnp packet");
29337472Ssklower 			ENDDEBUG
29437472Ssklower 			schednetisr(NETISR_ISO);
29535795Skarels 			inq = &clnlintrq;
29638845Sroot 			break;
29735795Skarels 		    }
29838845Sroot 		    goto dropanyway;
29938845Sroot 
30035795Skarels 		case LLC_XID:
30135795Skarels 		case LLC_XID_P:
30235795Skarels 		    if(m->m_len < 6)
30335795Skarels 			goto dropanyway;
30435795Skarels 		    l->llc_window = 0;
30535795Skarels 		    l->llc_fid = 9;
30635795Skarels 		    l->llc_class = 1;
30735795Skarels 		    l->llc_dsap = l->llc_ssap = 0;
30835795Skarels 		    /* Fall through to */
30935795Skarels 		case LLC_TEST:
31035795Skarels 		case LLC_TEST_P:
31135795Skarels 		{
31235795Skarels 		    struct sockaddr sa;
31335795Skarels 		    register struct ether_header *eh2;
31435795Skarels 		    int i;
31535795Skarels 		    u_char c = l->llc_dsap;
31635795Skarels 		    l->llc_dsap = l->llc_ssap;
31735795Skarels 		    l->llc_ssap = c;
31837472Ssklower 		    if (m->m_flags & (M_BCAST | M_MCAST))
319*55900Ssklower 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
32037472Ssklower 			      (caddr_t)eh->ether_dhost, 6);
32135795Skarels 		    sa.sa_family = AF_UNSPEC;
32237472Ssklower 		    sa.sa_len = sizeof(sa);
32335795Skarels 		    eh2 = (struct ether_header *)sa.sa_data;
32435795Skarels 		    for (i = 0; i < 6; i++) {
32535795Skarels 			eh2->ether_shost[i] = c = eh->ether_dhost[i];
32635795Skarels 			eh2->ether_dhost[i] =
32735795Skarels 				eh->ether_dhost[i] = eh->ether_shost[i];
32835795Skarels 			eh->ether_shost[i] = c;
32935795Skarels 		    }
33052448Ssklower 		    ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
33135795Skarels 		    return;
33235795Skarels 		}
33335795Skarels 		dropanyway:
33435795Skarels 		default:
33535795Skarels 		    m_freem(m);
33635795Skarels 		    return;
33735795Skarels 	    }
33838845Sroot #else
33938845Sroot 	    m_freem(m);
34038845Sroot 	    return;
34138845Sroot #endif	ISO
34235379Skfall 	}
34335379Skfall 
34435379Skfall 	s = splimp();
34535379Skfall 	if (IF_QFULL(inq)) {
34635379Skfall 		IF_DROP(inq);
34735379Skfall 		m_freem(m);
34835379Skfall 	} else
34935379Skfall 		IF_ENQUEUE(inq, m);
35035379Skfall 	splx(s);
35135379Skfall }
35235379Skfall 
35335379Skfall /*
35435379Skfall  * Convert Ethernet address to printable (loggable) representation.
35535379Skfall  */
35637472Ssklower static char digits[] = "0123456789abcdef";
35735379Skfall char *
35835379Skfall ether_sprintf(ap)
35935379Skfall 	register u_char *ap;
36035379Skfall {
36135379Skfall 	register i;
36235379Skfall 	static char etherbuf[18];
36335379Skfall 	register char *cp = etherbuf;
36435379Skfall 
36535379Skfall 	for (i = 0; i < 6; i++) {
36635379Skfall 		*cp++ = digits[*ap >> 4];
36735379Skfall 		*cp++ = digits[*ap++ & 0xf];
36835379Skfall 		*cp++ = ':';
36935379Skfall 	}
37035379Skfall 	*--cp = 0;
37135379Skfall 	return (etherbuf);
37235379Skfall }
37352567Ssklower 
37452567Ssklower /*
37552567Ssklower  * Perform common duties while attaching to interface list
37652567Ssklower  */
37752567Ssklower ether_ifattach(ifp)
37852567Ssklower 	register struct ifnet *ifp;
37952567Ssklower {
38052567Ssklower 	register struct ifaddr *ifa;
38152567Ssklower 	register struct sockaddr_dl *sdl;
38252567Ssklower 
38352567Ssklower 	ifp->if_type = IFT_ETHER;
38452567Ssklower 	ifp->if_addrlen = 6;
38552567Ssklower 	ifp->if_hdrlen = 14;
38652567Ssklower 	ifp->if_mtu = ETHERMTU;
38752567Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
38852567Ssklower 		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
38952567Ssklower 		    sdl->sdl_family == AF_LINK) {
39052567Ssklower 			sdl->sdl_type = IFT_ETHER;
39152567Ssklower 			sdl->sdl_alen = ifp->if_addrlen;
39252567Ssklower 			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
39352567Ssklower 			      LLADDR(sdl), ifp->if_addrlen);
39452567Ssklower 			break;
39552567Ssklower 		}
39652567Ssklower }
39754718Ssklower 
39854718Ssklower #ifdef MULTICAST
39954718Ssklower u_char	ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
40054718Ssklower u_char	ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
40154718Ssklower /*
40254718Ssklower  * Add an Ethernet multicast address or range of addresses to the list for a
40354718Ssklower  * given interface.
40454718Ssklower  */
40554718Ssklower int
40654718Ssklower ether_addmulti(ifr, ac)
40754718Ssklower 	struct ifreq *ifr;
40854718Ssklower 	register struct arpcom *ac;
40954718Ssklower {
41054718Ssklower 	register struct ether_multi *enm;
41154718Ssklower 	struct sockaddr_in *sin;
41254718Ssklower 	u_char addrlo[6];
41354718Ssklower 	u_char addrhi[6];
41454718Ssklower 	int s = splimp();
41554718Ssklower 
41654718Ssklower 	switch (ifr->ifr_addr.sa_family) {
41754718Ssklower 
41854718Ssklower 	case AF_UNSPEC:
41954718Ssklower 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
42054718Ssklower 		bcopy(addrlo, addrhi, 6);
42154718Ssklower 		break;
42254718Ssklower 
42354718Ssklower #ifdef INET
42454718Ssklower 	case AF_INET:
42554718Ssklower 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
42654718Ssklower 		if (sin->sin_addr.s_addr == INADDR_ANY) {
42754718Ssklower 			/*
42854718Ssklower 			 * An IP address of INADDR_ANY means listen to all
42954718Ssklower 			 * of the Ethernet multicast addresses used for IP.
43054718Ssklower 			 * (This is for the sake of IP multicast routers.)
43154718Ssklower 			 */
43254718Ssklower 			bcopy(ether_ipmulticast_min, addrlo, 6);
43354718Ssklower 			bcopy(ether_ipmulticast_max, addrhi, 6);
43454718Ssklower 		}
43554718Ssklower 		else {
43654718Ssklower 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
43754718Ssklower 			bcopy(addrlo, addrhi, 6);
43854718Ssklower 		}
43954718Ssklower 		break;
44054718Ssklower #endif
44154718Ssklower 
44254718Ssklower 	default:
44354718Ssklower 		splx(s);
44454718Ssklower 		return (EAFNOSUPPORT);
44554718Ssklower 	}
44654718Ssklower 
44754718Ssklower 	/*
44854718Ssklower 	 * Verify that we have valid Ethernet multicast addresses.
44954718Ssklower 	 */
45054718Ssklower 	if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
45154718Ssklower 		splx(s);
45254718Ssklower 		return (EINVAL);
45354718Ssklower 	}
45454718Ssklower 	/*
45554718Ssklower 	 * See if the address range is already in the list.
45654718Ssklower 	 */
45754718Ssklower 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
45854718Ssklower 	if (enm != NULL) {
45954718Ssklower 		/*
46054718Ssklower 		 * Found it; just increment the reference count.
46154718Ssklower 		 */
46254718Ssklower 		++enm->enm_refcount;
46354718Ssklower 		splx(s);
46454718Ssklower 		return (0);
46554718Ssklower 	}
46654718Ssklower 	/*
46754718Ssklower 	 * New address or range; malloc a new multicast record
46854718Ssklower 	 * and link it into the interface's multicast list.
46954718Ssklower 	 */
47054718Ssklower 	enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
47154718Ssklower 	if (enm == NULL) {
47254718Ssklower 		splx(s);
47354718Ssklower 		return (ENOBUFS);
47454718Ssklower 	}
47554718Ssklower 	bcopy(addrlo, enm->enm_addrlo, 6);
47654718Ssklower 	bcopy(addrhi, enm->enm_addrhi, 6);
47754718Ssklower 	enm->enm_ac = ac;
47854718Ssklower 	enm->enm_refcount = 1;
47954718Ssklower 	enm->enm_next = ac->ac_multiaddrs;
48054718Ssklower 	ac->ac_multiaddrs = enm;
48154718Ssklower 	ac->ac_multicnt++;
48254718Ssklower 	splx(s);
48354718Ssklower 	/*
48454718Ssklower 	 * Return ENETRESET to inform the driver that the list has changed
48554718Ssklower 	 * and its reception filter should be adjusted accordingly.
48654718Ssklower 	 */
48754718Ssklower 	return (ENETRESET);
48854718Ssklower }
48954718Ssklower 
49054718Ssklower /*
49154718Ssklower  * Delete a multicast address record.
49254718Ssklower  */
49354718Ssklower int
49454718Ssklower ether_delmulti(ifr, ac)
49554718Ssklower 	struct ifreq *ifr;
49654718Ssklower 	register struct arpcom *ac;
49754718Ssklower {
49854718Ssklower 	register struct ether_multi *enm;
49954718Ssklower 	register struct ether_multi **p;
50054718Ssklower 	struct sockaddr_in *sin;
50154718Ssklower 	u_char addrlo[6];
50254718Ssklower 	u_char addrhi[6];
50354718Ssklower 	int s = splimp();
50454718Ssklower 
50554718Ssklower 	switch (ifr->ifr_addr.sa_family) {
50654718Ssklower 
50754718Ssklower 	case AF_UNSPEC:
50854718Ssklower 		bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
50954718Ssklower 		bcopy(addrlo, addrhi, 6);
51054718Ssklower 		break;
51154718Ssklower 
51254718Ssklower #ifdef INET
51354718Ssklower 	case AF_INET:
51454718Ssklower 		sin = (struct sockaddr_in *)&(ifr->ifr_addr);
51554718Ssklower 		if (sin->sin_addr.s_addr == INADDR_ANY) {
51654718Ssklower 			/*
51754718Ssklower 			 * An IP address of INADDR_ANY means stop listening
51854718Ssklower 			 * to the range of Ethernet multicast addresses used
51954718Ssklower 			 * for IP.
52054718Ssklower 			 */
52154718Ssklower 			bcopy(ether_ipmulticast_min, addrlo, 6);
52254718Ssklower 			bcopy(ether_ipmulticast_max, addrhi, 6);
52354718Ssklower 		}
52454718Ssklower 		else {
52554718Ssklower 			ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
52654718Ssklower 			bcopy(addrlo, addrhi, 6);
52754718Ssklower 		}
52854718Ssklower 		break;
52954718Ssklower #endif
53054718Ssklower 
53154718Ssklower 	default:
53254718Ssklower 		splx(s);
53354718Ssklower 		return (EAFNOSUPPORT);
53454718Ssklower 	}
53554718Ssklower 
53654718Ssklower 	/*
53754718Ssklower 	 * Look up the address in our list.
53854718Ssklower 	 */
53954718Ssklower 	ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
54054718Ssklower 	if (enm == NULL) {
54154718Ssklower 		splx(s);
54254718Ssklower 		return (ENXIO);
54354718Ssklower 	}
54454718Ssklower 	if (--enm->enm_refcount != 0) {
54554718Ssklower 		/*
54654718Ssklower 		 * Still some claims to this record.
54754718Ssklower 		 */
54854718Ssklower 		splx(s);
54954718Ssklower 		return (0);
55054718Ssklower 	}
55154718Ssklower 	/*
55254718Ssklower 	 * No remaining claims to this record; unlink and free it.
55354718Ssklower 	 */
55454718Ssklower 	for (p = &enm->enm_ac->ac_multiaddrs;
55554718Ssklower 	     *p != enm;
55654718Ssklower 	     p = &(*p)->enm_next)
55754718Ssklower 		continue;
55854718Ssklower 	*p = (*p)->enm_next;
55954718Ssklower 	free(enm, M_IFMADDR);
56054718Ssklower 	ac->ac_multicnt--;
56154718Ssklower 	splx(s);
56254718Ssklower 	/*
56354718Ssklower 	 * Return ENETRESET to inform the driver that the list has changed
56454718Ssklower 	 * and its reception filter should be adjusted accordingly.
56554718Ssklower 	 */
56654718Ssklower 	return (ENETRESET);
56754718Ssklower }
56854718Ssklower #endif
569