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