diff options
Diffstat (limited to 'sys/net/if_ethersubr.c')
-rw-r--r-- | sys/net/if_ethersubr.c | 226 |
1 files changed, 192 insertions, 34 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 348d51dd148f..9d7e897c32cb 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1982, 1989 Regents of the University of California. + * Copyright (c) 1982, 1989, 1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)if_ethersubr.c 7.13 (Berkeley) 4/20/91 - * $Id: if_ethersubr.c,v 1.4 1993/11/25 01:34:02 wollman Exp $ + * $Id: if_ethersubr.c,v 1.5 1994/05/17 22:30:54 jkh Exp $ */ #include "param.h" @@ -110,22 +110,12 @@ ether_output(ifp, m0, dst, rt) idst = ((struct sockaddr_in *)dst)->sin_addr; if (!arpresolve(ac, m, &idst, edst, &usetrailers)) return (0); /* if not yet resolved */ - if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1)) + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m, 0, (int)M_COPYALL); off = m->m_pkthdr.len - m->m_len; - if (usetrailers && off > 0 && (off & 0x1ff) == 0 && - (m->m_flags & M_EXT) == 0 && - m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { - type = ETHERTYPE_TRAIL + (off>>9); - m->m_data -= 2 * sizeof (u_short); - m->m_len += 2 * sizeof (u_short); - len += 2 * sizeof (u_short); - *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); - *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); - goto gottrailertype; - } type = ETHERTYPE_IP; - goto gottype; + break; #endif #ifdef NS case AF_NS: @@ -134,9 +124,10 @@ ether_output(ifp, m0, dst, rt) (caddr_t)edst, sizeof (edst)); if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) return (looutput(ifp, m, dst, rt)); - if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1)) + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m, 0, (int)M_COPYALL); - goto gottype; + break; #endif #ifdef ISO case AF_ISO: { @@ -165,7 +156,8 @@ ether_output(ifp, m0, dst, rt) (char *)edst, &snpalen)) > 0) goto bad; /* Not Resolved */ iso_resolved: - if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) (mcopy = m_copy(m, 0, (int)M_COPYALL))) { M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); if (mcopy) { @@ -191,7 +183,8 @@ ether_output(ifp, m0, dst, rt) printf("%x ", edst[i] & 0xff); printf("\n"); ENDDEBUG - } goto gottype; + } + break; #endif ISO #ifdef RMP case AF_RMP: @@ -208,7 +201,7 @@ ether_output(ifp, m0, dst, rt) eh = (struct ether_header *)dst->sa_data; bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); type = eh->ether_type; - goto gottype; + break; default: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, @@ -217,18 +210,6 @@ ether_output(ifp, m0, dst, rt) goto bad; } -gottrailertype: - /* - * Packet to be sent as trailer: move first packet - * (control information) to end of chain. - */ - while (m->m_next) - m = m->m_next; - m->m_next = m0; - m = m0->m_next; - m0->m_next = 0; - -gottype: if (mcopy) (void) looutput(ifp, mcopy, dst, rt); /* @@ -266,7 +247,7 @@ gottype: (*ifp->if_start)(ifp); splx(s); ifp->if_obytes += len + sizeof (struct ether_header); - if (edst[0] & 1) + if (m->m_flags & M_MCAST) ifp->if_omcasts++; return (error); @@ -293,11 +274,13 @@ ether_input(ifp, eh, m) ifp->if_lastchange = time; ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); + if (eh->ether_dhost[0] & 1) { if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, sizeof(etherbroadcastaddr)) == 0) m->m_flags |= M_BCAST; - else if (eh->ether_dhost[0] & 1) + else m->m_flags |= M_MCAST; + } if (m->m_flags & (M_BCAST|M_MCAST)) ifp->if_imcasts++; @@ -421,3 +404,178 @@ ether_sprintf(ap) *--cp = 0; return (etherbuf); } + +#ifdef MULTICAST +u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; +u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; + +/* XXX */ +#undef ac +/* + * Add an Ethernet multicast address or range of addresses to the list for a + * given interface. + */ +int +ether_addmulti(ifr, ac) + struct ifreq *ifr; + register struct arpcom *ac; +{ + register struct ether_multi *enm; + struct sockaddr_in *sin; + u_char addrlo[6]; + u_char addrhi[6]; + int s = splimp(); + + switch (ifr->ifr_addr.sa_family) { + + case AF_UNSPEC: + bcopy(ifr->ifr_addr.sa_data, addrlo, 6); + bcopy(addrlo, addrhi, 6); + break; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&(ifr->ifr_addr); + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* + * An IP address of INADDR_ANY means listen to all + * of the Ethernet multicast addresses used for IP. + * (This is for the sake of IP multicast routers.) + */ + bcopy(ether_ipmulticast_min, addrlo, 6); + bcopy(ether_ipmulticast_max, addrhi, 6); + } + else { + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); + bcopy(addrlo, addrhi, 6); + } + break; +#endif + + default: + splx(s); + return (EAFNOSUPPORT); + } + + /* + * Verify that we have valid Ethernet multicast addresses. + */ + if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { + splx(s); + return (EINVAL); + } + /* + * See if the address range is already in the list. + */ + ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); + if (enm != NULL) { + /* + * Found it; just increment the reference count. + */ + ++enm->enm_refcount; + splx(s); + return (0); + } + /* + * New address or range; malloc a new multicast record + * and link it into the interface's multicast list. + */ + enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); + if (enm == NULL) { + splx(s); + return (ENOBUFS); + } + bcopy(addrlo, enm->enm_addrlo, 6); + bcopy(addrhi, enm->enm_addrhi, 6); + enm->enm_ac = ac; + enm->enm_refcount = 1; + enm->enm_next = ac->ac_multiaddrs; + ac->ac_multiaddrs = enm; + ac->ac_multicnt++; + splx(s); + /* + * Return ENETRESET to inform the driver that the list has changed + * and its reception filter should be adjusted accordingly. + */ + return (ENETRESET); +} + +/* + * Delete a multicast address record. + */ +int +ether_delmulti(ifr, ac) + struct ifreq *ifr; + register struct arpcom *ac; +{ + register struct ether_multi *enm; + register struct ether_multi **p; + struct sockaddr_in *sin; + u_char addrlo[6]; + u_char addrhi[6]; + int s = splimp(); + + switch (ifr->ifr_addr.sa_family) { + + case AF_UNSPEC: + bcopy(ifr->ifr_addr.sa_data, addrlo, 6); + bcopy(addrlo, addrhi, 6); + break; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&(ifr->ifr_addr); + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* + * An IP address of INADDR_ANY means stop listening + * to the range of Ethernet multicast addresses used + * for IP. + */ + bcopy(ether_ipmulticast_min, addrlo, 6); + bcopy(ether_ipmulticast_max, addrhi, 6); + } + else { + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); + bcopy(addrlo, addrhi, 6); + } + break; +#endif + + default: + splx(s); + return (EAFNOSUPPORT); + } + + /* + * Look up the address in our list. + */ + ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); + if (enm == NULL) { + splx(s); + return (ENXIO); + } + if (--enm->enm_refcount != 0) { + /* + * Still some claims to this record. + */ + splx(s); + return (0); + } + /* + * No remaining claims to this record; unlink and free it. + */ + for (p = &enm->enm_ac->ac_multiaddrs; + *p != enm; + p = &(*p)->enm_next) + continue; + *p = (*p)->enm_next; + free(enm, M_IFMADDR); + ac->ac_multicnt--; + splx(s); + /* + * Return ENETRESET to inform the driver that the list has changed + * and its reception filter should be adjusted accordingly. + */ + return (ENETRESET); +} +#endif |