multicast changes from lbl
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Tue, 7 Jul 1992 06:30:22 +0000 (22:30 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Tue, 7 Jul 1992 06:30:22 +0000 (22:30 -0800)
SCCS-vsn: sys/net/if.h 7.18
SCCS-vsn: sys/net/if_ethersubr.c 7.20
SCCS-vsn: sys/net/if.c 7.20
SCCS-vsn: sys/net/if_sl.c 7.29
SCCS-vsn: sys/net/if_loop.c 7.17
SCCS-vsn: sys/hp300/dev/if_lereg.h 7.4
SCCS-vsn: sys/hp300/dev/if_le.c 7.12

usr/src/sys/hp300/dev/if_le.c
usr/src/sys/hp300/dev/if_lereg.h
usr/src/sys/net/if.c
usr/src/sys/net/if.h
usr/src/sys/net/if_ethersubr.c
usr/src/sys/net/if_loop.c
usr/src/sys/net/if_sl.c

index fc168a4..9943d77 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_le.c     7.11 (Berkeley) %G%
+ *     @(#)if_le.c     7.12 (Berkeley) %G%
  */
 
 #include "le.h"
  */
 
 #include "le.h"
@@ -15,7 +15,7 @@
 /*
  * AMD 7990 LANCE
  *
 /*
  * AMD 7990 LANCE
  *
- * This driver will generate and accept tailer encapsulated packets even
+ * This driver will accept tailer encapsulated packets even
  * though it buys us nothing.  The motivation was to avoid incompatibilities
  * with VAXen, SUNs, and others that handle and benefit from them.
  * This reasoning is dubious.
  * though it buys us nothing.  The motivation was to avoid incompatibilities
  * with VAXen, SUNs, and others that handle and benefit from them.
  * This reasoning is dubious.
 #include "netns/ns_if.h"
 #endif
 
 #include "netns/ns_if.h"
 #endif
 
-#ifdef ISO
-extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
-#endif
-
 #include "../include/cpu.h"
 #include "../hp300/isr.h"
 #include "../include/mtpr.h"
 #include "../include/cpu.h"
 #include "../hp300/isr.h"
 #include "../include/mtpr.h"
@@ -61,7 +57,6 @@ extern        char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
 #if NBPFILTER > 0
 #include "../net/bpf.h"
 #include "../net/bpfdesc.h"
 #if NBPFILTER > 0
 #include "../net/bpf.h"
 #include "../net/bpfdesc.h"
-char hprmp_multi[] = { 9, 0, 9, 0, 0, 4};
 #endif
 
 /* offsets for:           ID,   REGS,    MEM,  NVRAM */
 #endif
 
 /* offsets for:           ID,   REGS,    MEM,  NVRAM */
@@ -112,7 +107,6 @@ struct      le_softc {
        int     sc_txoff;
        int     sc_busy;
        short   sc_iflags;
        int     sc_txoff;
        int     sc_busy;
        short   sc_iflags;
-       caddr_t sc_bpf;
 } le_softc[NLE];
 
 /* access LANCE registers */
 } le_softc[NLE];
 
 /* access LANCE registers */
@@ -165,13 +159,8 @@ leattach(hd)
         * Setup for transmit/receive
         */
        ler2->ler2_mode = LE_MODE;
         * Setup for transmit/receive
         */
        ler2->ler2_mode = LE_MODE;
-#if defined(ISO) || NBPFILTER > 0
-       ler2->ler2_ladrf0 = 0xffffffff;
-       ler2->ler2_ladrf1 = 0xffffffff;
-#else
-       ler2->ler2_ladrf0 = 0;
-       ler2->ler2_ladrf1 = 0;
-#endif
+       ler2->ler2_ladrf[0] = 0;
+       ler2->ler2_ladrf[1] = 0;
        ler2->ler2_rlen = LE_RLEN;
        ler2->ler2_rdra = (int)lemem->ler2_rmd;
        ler2->ler2_tlen = LE_TLEN;
        ler2->ler2_rlen = LE_RLEN;
        ler2->ler2_rdra = (int)lemem->ler2_rmd;
        ler2->ler2_tlen = LE_TLEN;
@@ -186,14 +175,94 @@ leattach(hd)
        ifp->if_ioctl = leioctl;
        ifp->if_output = ether_output;
        ifp->if_start = lestart;
        ifp->if_ioctl = leioctl;
        ifp->if_output = ether_output;
        ifp->if_start = lestart;
+#ifdef MULTICAST
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#else
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+#endif
 #if NBPFILTER > 0
 #if NBPFILTER > 0
-       bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+       bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
 #endif
        if_attach(ifp);
        return (1);
 }
 
 #endif
        if_attach(ifp);
        return (1);
 }
 
+#ifdef MULTICAST
+/*
+ * Setup the logical address filter
+ */
+void
+lesetladrf(sc)
+       register struct le_softc *sc;
+{
+       register volatile struct lereg2 *ler2 = sc->sc_r2;
+       register struct ifnet *ifp = &sc->sc_if;
+       register struct ether_multi *enm;
+       register u_char *cp;
+       register u_long crc;
+       register u_long c;
+       register int i, len;
+       struct ether_multistep step;
+
+       /*
+        * Set up multicast address filter by passing all multicast
+        * addresses through a crc generator, and then using the high
+        * order 6 bits as a index into the 64 bit logical address
+        * filter. The high order two bits select the word, while the
+        * rest of the bits select the bit within the word.
+        */
+
+       ler2->ler2_ladrf[0] = 0;
+       ler2->ler2_ladrf[1] = 0;
+       ifp->if_flags &= ~IFF_ALLMULTI;
+       ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
+       while (enm != NULL) {
+               if (bcmp((caddr_t)&enm->enm_addrlo,
+                   (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) {
+                       /*
+                        * We must listen to a range of multicast
+                        * addresses. For now, just accept all
+                        * multicasts, rather than trying to set only
+                        * those filter bits needed to match the range.
+                        * (At this time, the only use of address
+                        * ranges is for IP multicast routing, for
+                        * which the range is big enough to require all
+                        * bits set.)
+                        */
+                       ler2->ler2_ladrf[0] = 0xffffffff;
+                       ler2->ler2_ladrf[1] = 0xffffffff;
+                       ifp->if_flags |= IFF_ALLMULTI;
+                       return;
+               }
+
+               cp = (unsigned char *)&enm->enm_addrlo;
+               c = *cp;
+               crc = 0xffffffff;
+               len = 6;
+               while (len-- > 0) {
+                       c = *cp;
+                       for (i = 0; i < 8; i++) {
+                               if ((c & 0x01) ^ (crc & 0x01)) {
+                                       crc >>= 1;
+                                       crc = crc ^ 0xedb88320;
+                               }
+                               else
+                                       crc >>= 1;
+                               c >>= 1;
+                       }
+                       cp++;
+               }
+               /* Just want the 6 most significant bits. */
+               crc = crc >> 26;
+
+               /* Turn on the corresponding bit in the filter. */
+               ler2->ler2_ladrf[crc >> 5] |= 1 << (crc & 0x1f);
+
+               ETHER_NEXT_MULTI(step, enm);
+       }
+}
+#endif
+
 ledrinit(ler2, le)
        register struct lereg2 *ler2;
        register struct le_softc *le;
 ledrinit(ler2, le)
        register struct lereg2 *ler2;
        register struct le_softc *le;
@@ -219,6 +288,13 @@ ledrinit(ler2, le)
                ler2->ler2_tmd[i].tmd2 = 0;
                ler2->ler2_tmd[i].tmd3 = 0;
        }
                ler2->ler2_tmd[i].tmd2 = 0;
                ler2->ler2_tmd[i].tmd3 = 0;
        }
+       /* Setup the logical address filter */
+#ifdef MULTICAST
+       lesetladrf(le);
+#else
+       ler2->ler2_ladrf[0] = 0;
+       ler2->ler2_ladrf[1] = 0;
+#endif
 }
 
 lereset(unit)
 }
 
 lereset(unit)
@@ -323,8 +399,8 @@ lestart(ifp)
                 * If bpf is listening on this interface, let it 
                 * see the packet before we commit it to the wire.
                 */
                 * If bpf is listening on this interface, let it 
                 * see the packet before we commit it to the wire.
                 */
-               if (le->sc_bpf)
-                       bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[le->sc_tmd],
+               if (ifp->if_bpf)
+                       bpf_tap(ifp->if_bpf, le->sc_r2->ler2_tbuf[le->sc_tmd],
                                len);
 #endif
 
                                len);
 #endif
 
@@ -518,7 +594,7 @@ leread(unit, buf, len)
        register struct le_softc *le = &le_softc[unit];
        register struct ether_header *et;
        struct mbuf *m;
        register struct le_softc *le = &le_softc[unit];
        register struct ether_header *et;
        struct mbuf *m;
-       int off, resid;
+       int off, resid, flags;
 
        le->sc_if.if_ipackets++;
        et = (struct ether_header *)buf;
 
        le->sc_if.if_ipackets++;
        et = (struct ether_header *)buf;
@@ -549,32 +625,36 @@ leread(unit, buf, len)
                le->sc_if.if_ierrors++;
                return;
        }
                le->sc_if.if_ierrors++;
                return;
        }
+       flags = 0;
+       if (bcmp((caddr_t)etherbroadcastaddr,
+           (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0)
+               flags |= M_BCAST;
+       if (et->ether_dhost[0] & 1)
+               flags |= M_MCAST;
+
 #if NBPFILTER > 0
        /*
         * Check if there's a bpf filter listening on this interface.
 #if NBPFILTER > 0
        /*
         * Check if there's a bpf filter listening on this interface.
-        * If so, hand off the raw packet to bpf, which must deal with
-        * trailers in its own way.
+        * If so, hand off the raw packet to enet.
         */
         */
-       if (le->sc_bpf)
-               bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
-#endif
-#if defined(ISO) || NBPFILTER > 0
-       /*
-        * Note that the interface cannot be in promiscuous mode if
-        * there are no bpf listeners.  If we are in promiscuous
-        * mode, we have to check if this packet is really ours.
-        * However, there may be appropriate multicate addresses involved
-        */
-#define NOT_TO(p) (bcmp(et->ether_dhost, p, sizeof(et->ether_dhost)) != 0)
-       if (et->ether_dhost[0] & 1) {
-               if (NOT_TO(etherbroadcastaddr) && NOT_TO(hprmp_multi)
-#ifdef ISO
-                   && NOT_TO(all_es_snpa) && NOT_TO(all_is_snpa)
-                   && NOT_TO(all_l1is_snpa) && NOT_TO(all_l2is_snpa)
+       if (le->sc_if.if_bpf) {
+               bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header));
+
+               /*
+                * Keep the packet if it's a broadcast or has our
+                * physical ethernet address (or if we support
+                * multicast and it's one).
+                */
+               if (
+#ifdef MULTICAST
+                   (flags & (M_BCAST | M_MCAST)) == 0 &&
+#else
+                   (flags & M_BCAST) == 0 &&
 #endif
 #endif
-                    ) return;
-       } else if ((le->sc_if.if_flags & IFF_PROMISC) && NOT_TO(le->sc_addr))
-               return;
+                   bcmp(et->ether_dhost, le->sc_addr,
+                       sizeof(et->ether_dhost)) != 0)
+                       return;
+       }
 #endif
        /*
         * Pull packet off interface.  Off is nonzero if packet
 #endif
        /*
         * Pull packet off interface.  Off is nonzero if packet
@@ -583,6 +663,7 @@ leread(unit, buf, len)
         * the type and length which are at the front of any trailer data.
         */
        m = m_devget((char *)(et + 1), len, off, &le->sc_if, 0);
         * the type and length which are at the front of any trailer data.
         */
        m = m_devget((char *)(et + 1), len, off, &le->sc_if, 0);
+       m->m_flags |= flags;
        if (m == 0)
                return;
        ether_input(&le->sc_if, et, m);
        if (m == 0)
                return;
        ether_input(&le->sc_if, et, m);
@@ -689,6 +770,24 @@ leioctl(ifp, cmd, data)
                }
                break;
 
                }
                break;
 
+#ifdef MULTICAST
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               /* Update our multicast list  */
+               error = (cmd == SIOCADDMULTI) ?
+                   ether_addmulti((struct ifreq *)data, &le->sc_ac) :
+                   ether_delmulti((struct ifreq *)data, &le->sc_ac);
+
+               if (error == ENETRESET) {
+                       /*
+                        * Multicast list has changed; set the hardware
+                        * filter accordingly.
+                        */
+                       lereset(ifp->if_unit);
+                       error = 0;
+               }
+               break;
+#endif
        default:
                error = EINVAL;
        }
        default:
                error = EINVAL;
        }
index bd47c9a..2d598b2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_lereg.h  7.3 (Berkeley) %G%
+ *     @(#)if_lereg.h  7.4 (Berkeley) %G%
  */
 
 #ifdef KERNEL
  */
 
 #ifdef KERNEL
@@ -48,8 +48,7 @@ struct lereg2 {
        /* init block */
        u_short ler2_mode;              /* +0x0000 */
        u_char  ler2_padr[6];           /* +0x0002 */
        /* init block */
        u_short ler2_mode;              /* +0x0000 */
        u_char  ler2_padr[6];           /* +0x0002 */
-       u_long  ler2_ladrf0;            /* +0x0008 */
-       u_long  ler2_ladrf1;            /* +0x000C */
+       u_long  ler2_ladrf[2];          /* +0x0008 */
        u_short ler2_rdra;              /* +0x0010 */
        u_short ler2_rlen;              /* +0x0012 */
        u_short ler2_tdra;              /* +0x0014 */
        u_short ler2_rdra;              /* +0x0010 */
        u_short ler2_rlen;              /* +0x0012 */
        u_short ler2_tdra;              /* +0x0014 */
index a861058..b717a88 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if.c        7.19 (Berkeley) %G%
+ *     @(#)if.c        7.20 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -71,13 +71,13 @@ if_attach(ifp)
        struct ifnet *ifp;
 {
        unsigned socksize, ifasize;
        struct ifnet *ifp;
 {
        unsigned socksize, ifasize;
-       int namelen, unitlen, masklen;
+       int namelen, unitlen, masklen, ether_output();
        char workbuf[12], *unitname;
        register struct ifnet **p = &ifnet;
        register struct sockaddr_dl *sdl;
        register struct ifaddr *ifa;
        static int if_indexlim = 8;
        char workbuf[12], *unitname;
        register struct ifnet **p = &ifnet;
        register struct sockaddr_dl *sdl;
        register struct ifaddr *ifa;
        static int if_indexlim = 8;
-       extern link_rtrequest(), ether_output();
+       extern void link_rtrequest();
 
        while (*p)
                p = &((*p)->if_next);
 
        while (*p)
                p = &((*p)->if_next);
@@ -282,6 +282,7 @@ ifaof_ifpforaddr(addr, ifp)
  * Lookup an appropriate real ifa to point to.
  * This should be moved to /sys/net/link.c eventually.
  */
  * Lookup an appropriate real ifa to point to.
  * This should be moved to /sys/net/link.c eventually.
  */
+void
 link_rtrequest(cmd, rt, sa)
        int cmd;
        register struct rtentry *rt;
 link_rtrequest(cmd, rt, sa)
        int cmd;
        register struct rtentry *rt;
@@ -484,6 +485,16 @@ ifioctl(so, cmd, data, p)
                ifp->if_metric = ifr->ifr_metric;
                break;
 
                ifp->if_metric = ifr->ifr_metric;
                break;
 
+#ifdef MULTICAST
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               if (error = suser(p->p_ucred, &p->p_acflag))
+                       return (error);
+               if (ifp->if_ioctl)
+                       return (EOPNOTSUPP);
+               return ((*ifp->if_ioctl)(ifp, cmd, data));
+#endif
+
        default:
                if (so->so_proto == 0)
                        return (EOPNOTSUPP);
        default:
                if (so->so_proto == 0)
                        return (EOPNOTSUPP);
index 10232e1..2797928 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if.h        7.17 (Berkeley) %G%
+ *     @(#)if.h        7.18 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -61,30 +61,31 @@ struct ifnet {
        struct  ifnet *if_next;         /* all struct ifnets are chained */
        struct  ifaddr *if_addrlist;    /* linked list of addresses per if */
         int    if_pcount;              /* number of promiscuous listeners */
        struct  ifnet *if_next;         /* all struct ifnets are chained */
        struct  ifaddr *if_addrlist;    /* linked list of addresses per if */
         int    if_pcount;              /* number of promiscuous listeners */
+       caddr_t if_bpf;                 /* packet filter structure */
        u_short if_index;               /* numeric abbreviation for this if  */
        short   if_unit;                /* sub-unit for lower level driver */
        short   if_timer;               /* time 'til if_watchdog called */
        short   if_flags;               /* up/down, broadcast, etc. */
        struct  if_data {
 /* generic interface information */
        u_short if_index;               /* numeric abbreviation for this if  */
        short   if_unit;                /* sub-unit for lower level driver */
        short   if_timer;               /* time 'til if_watchdog called */
        short   if_flags;               /* up/down, broadcast, etc. */
        struct  if_data {
 /* generic interface information */
-               short   ifi_mtu;        /* maximum transmission unit */
                u_char  ifi_type;       /* ethernet, tokenring, etc */
                u_char  ifi_addrlen;    /* media address length */
                u_char  ifi_hdrlen;     /* media header length */
                u_char  ifi_type;       /* ethernet, tokenring, etc */
                u_char  ifi_addrlen;    /* media address length */
                u_char  ifi_hdrlen;     /* media header length */
-               int     ifi_metric;     /* routing metric (external only) */
-               int     ifi_baudrate;   /* linespeed */
+               u_long  ifi_mtu;        /* maximum transmission unit */
+               u_long  ifi_metric;     /* routing metric (external only) */
+               u_long  ifi_baudrate;   /* linespeed */
 /* volatile statistics */
 /* volatile statistics */
-               int     ifi_ipackets;   /* packets received on interface */
-               int     ifi_ierrors;    /* input errors on interface */
-               int     ifi_opackets;   /* packets sent on interface */
-               int     ifi_oerrors;    /* output errors on interface */
-               int     ifi_collisions; /* collisions on csma interfaces */
-               int     ifi_ibytes;     /* total number of octets received */
-               int     ifi_obytes;     /* total number of octets sent */
-               int     ifi_imcasts;    /* packets received via multicast */
-               int     ifi_omcasts;    /* packets sent via multicast */
-               int     ifi_iqdrops;    /* dropped on input, this interface */
-               int     ifi_noproto;    /* destined for unsupported protocol */
+               u_long  ifi_ipackets;   /* packets received on interface */
+               u_long  ifi_ierrors;    /* input errors on interface */
+               u_long  ifi_opackets;   /* packets sent on interface */
+               u_long  ifi_oerrors;    /* output errors on interface */
+               u_long  ifi_collisions; /* collisions on csma interfaces */
+               u_long  ifi_ibytes;     /* total number of octets received */
+               u_long  ifi_obytes;     /* total number of octets sent */
+               u_long  ifi_imcasts;    /* packets received via multicast */
+               u_long  ifi_omcasts;    /* packets sent via multicast */
+               u_long  ifi_iqdrops;    /* dropped on input, this interface */
+               u_long  ifi_noproto;    /* destined for unsupported protocol */
                struct  timeval ifi_lastchange;/* last updated */
        }       if_data;
 /* procedure handles */
                struct  timeval ifi_lastchange;/* last updated */
        }       if_data;
 /* procedure handles */
@@ -99,8 +100,8 @@ struct ifnet {
                __P((struct ifnet *));  /* (XXX not used; fake prototype) */
        int     (*if_ioctl)             /* ioctl routine */
                __P((struct ifnet *, int, caddr_t));
                __P((struct ifnet *));  /* (XXX not used; fake prototype) */
        int     (*if_ioctl)             /* ioctl routine */
                __P((struct ifnet *, int, caddr_t));
-       int     (*if_reset)             /* XXX; Unibus reset routine for vax */
-               __P((int, int));        /* new autoconfig will permit removal */
+       int     (*if_reset)     
+               __P((int));             /* new autoconfig will permit removal */
        int     (*if_watchdog)          /* timer routine */
                __P((int));
        struct  ifqueue {
        int     (*if_watchdog)          /* timer routine */
                __P((int));
        struct  ifqueue {
@@ -138,7 +139,6 @@ struct ifnet {
 #define        IFF_NOTRAILERS  0x20            /* avoid use of trailers */
 #define        IFF_RUNNING     0x40            /* resources allocated */
 #define        IFF_NOARP       0x80            /* no address resolution protocol */
 #define        IFF_NOTRAILERS  0x20            /* avoid use of trailers */
 #define        IFF_RUNNING     0x40            /* resources allocated */
 #define        IFF_NOARP       0x80            /* no address resolution protocol */
-/* next two not supported now, but reserved: */
 #define        IFF_PROMISC     0x100           /* receive all packets */
 #define        IFF_ALLMULTI    0x200           /* receive all multicast packets */
 #define        IFF_OACTIVE     0x400           /* transmission in progress */
 #define        IFF_PROMISC     0x100           /* receive all packets */
 #define        IFF_ALLMULTI    0x200           /* receive all multicast packets */
 #define        IFF_OACTIVE     0x400           /* transmission in progress */
@@ -146,10 +146,12 @@ struct ifnet {
 #define        IFF_LINK0       0x1000          /* per link layer defined bit */
 #define        IFF_LINK1       0x2000          /* per link layer defined bit */
 #define        IFF_LINK2       0x4000          /* per link layer defined bit */
 #define        IFF_LINK0       0x1000          /* per link layer defined bit */
 #define        IFF_LINK1       0x2000          /* per link layer defined bit */
 #define        IFF_LINK2       0x4000          /* per link layer defined bit */
+#define        IFF_MULTICAST   0x8000          /* supports multicast */
 
 /* flags set internally only: */
 #define        IFF_CANTCHANGE \
 
 /* flags set internally only: */
 #define        IFF_CANTCHANGE \
-       (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|IFF_SIMPLEX)
+       (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
+           IFF_SIMPLEX|IFF_MULTICAST)
 
 /*
  * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
 
 /*
  * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
@@ -201,13 +203,15 @@ struct ifaddr {
        struct  sockaddr *ifa_netmask;  /* used to determine subnet */
        struct  ifnet *ifa_ifp;         /* back-pointer to interface */
        struct  ifaddr *ifa_next;       /* next address for interface */
        struct  sockaddr *ifa_netmask;  /* used to determine subnet */
        struct  ifnet *ifa_ifp;         /* back-pointer to interface */
        struct  ifaddr *ifa_next;       /* next address for interface */
-       int     (*ifa_rtrequest)();     /* check or clean routes (+ or -)'d */
+       void    (*ifa_rtrequest)();     /* check or clean routes (+ or -)'d */
        u_short ifa_flags;              /* mostly rt_flags for cloning */
        short   ifa_refcnt;             /* extra to malloc for link info */
        int     ifa_metric;             /* cost of going out this interface */
        u_short ifa_flags;              /* mostly rt_flags for cloning */
        short   ifa_refcnt;             /* extra to malloc for link info */
        int     ifa_metric;             /* cost of going out this interface */
-/*     struct  rtentry *ifa_rt;        /* XXXX for ROUTETOIF ????? */
+#ifdef notdef
+       struct  rtentry *ifa_rt;        /* XXXX for ROUTETOIF ????? */
+#endif
 };
 };
-#define IFA_ROUTE      RTF_UP          /* route installed */
+#define        IFA_ROUTE       RTF_UP          /* route installed */
 
 /*
  * Message format for use in obtaining information about interfaces
 
 /*
  * Message format for use in obtaining information about interfaces
index d0222e1..ac6fa94 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_ethersubr.c      7.19 (Berkeley) %G%
+ *     @(#)if_ethersubr.c      7.20 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -68,8 +68,8 @@ ether_output(ifp, m0, dst, rt0)
        register struct rtentry *rt;
        struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
        register struct rtentry *rt;
        struct mbuf *mcopy = (struct mbuf *)0;
        register struct ether_header *eh;
-       int usetrailers, off, len = m->m_pkthdr.len;
-#define        ac ((struct arpcom *)ifp)
+       int off, len = m->m_pkthdr.len;
+       struct arpcom *ac = (struct arpcom *)ifp;
 
        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
                senderr(ENETDOWN);
 
        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
                senderr(ENETDOWN);
@@ -101,24 +101,14 @@ ether_output(ifp, m0, dst, rt0)
 #ifdef INET
        case AF_INET:
                if (!arpresolve(ac, rt, m, (struct sockaddr_in *)dst,
 #ifdef INET
        case AF_INET:
                if (!arpresolve(ac, rt, m, (struct sockaddr_in *)dst,
-                               edst, &usetrailers))
+                               edst))
                        return (0);     /* if not yet resolved */
                        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;
                        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;
                type = ETHERTYPE_IP;
-               goto gottype;
+               break;
 #endif
 #ifdef NS
        case AF_NS:
 #endif
 #ifdef NS
        case AF_NS:
@@ -127,9 +117,10 @@ ether_output(ifp, m0, dst, rt0)
                    (caddr_t)edst, sizeof (edst));
                if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
                        return (looutput(ifp, m, 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);
                        mcopy = m_copy(m, 0, (int)M_COPYALL);
-               goto gottype;
+               break;
 #endif
 #ifdef ISO
        case AF_ISO: {
 #endif
 #ifdef ISO
        case AF_ISO: {
@@ -144,7 +135,10 @@ ether_output(ifp, m0, dst, rt0)
                            iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
                                            (char *)edst, &snpalen))
                        goto bad; /* Not Resolved */
                            iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
                                            (char *)edst, &snpalen))
                        goto bad; /* Not Resolved */
-               if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
+               /* If broadcasting on a simplex interface, loopback a copy */
+               if (*edst & 1)
+                       m->m_flags |= (M_BCAST|M_MCAST);
+               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) {
                    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
                        M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
                        if (mcopy) {
@@ -170,24 +164,14 @@ ether_output(ifp, m0, dst, rt0)
                                printf("%x ", edst[i] & 0xff);
                        printf("\n");
                ENDDEBUG
                                printf("%x ", edst[i] & 0xff);
                        printf("\n");
                ENDDEBUG
-               } goto gottype;
+               } break;
 #endif ISO
 #endif ISO
-#ifdef RMP
-       case AF_RMP:
-               /*
-                *  This is IEEE 802.3 -- the Ethernet `type' field is
-                *  really a `length' field.
-                */
-               type = m->m_len;
-               bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
-               break;
-#endif
 
        case AF_UNSPEC:
                eh = (struct ether_header *)dst->sa_data;
                bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
                type = eh->ether_type;
 
        case AF_UNSPEC:
                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,
 
        default:
                printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
@@ -195,18 +179,7 @@ ether_output(ifp, m0, dst, rt0)
                senderr(EAFNOSUPPORT);
        }
 
                senderr(EAFNOSUPPORT);
        }
 
-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);
        /*
        if (mcopy)
                (void) looutput(ifp, mcopy, dst, rt);
        /*
@@ -238,7 +211,7 @@ gottype:
                (*ifp->if_start)(ifp);
        splx(s);
        ifp->if_obytes += len + sizeof (struct ether_header);
                (*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);
 
                ifp->if_omcasts++;
        return (error);
 
@@ -421,3 +394,175 @@ ether_ifattach(ifp)
                        break;
                }
 }
                        break;
                }
 }
+
+#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 };
+/*
+ * 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
index 895a442..aa7f607 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_loop.c   7.16 (Berkeley) %G%
+ *     @(#)if_loop.c   7.17 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 
 #include "param.h"
 #include "systm.h"
 
 #include "param.h"
 #include "systm.h"
+#include "kernel.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "errno.h"
 #include "ioctl.h"
 #include "machine/cpu.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "errno.h"
 #include "ioctl.h"
 #include "machine/cpu.h"
+#include "time.h"
 
 #include "if.h"
 #include "if_types.h"
 #include "netisr.h"
 #include "route.h"
 
 #include "if.h"
 #include "if_types.h"
 #include "netisr.h"
 #include "route.h"
+#include "bpf.h"
 
 #ifdef INET
 #include "netinet/in.h"
 
 #ifdef INET
 #include "netinet/in.h"
@@ -41,6 +44,8 @@
 #include "netiso/iso_var.h"
 #endif
 
 #include "netiso/iso_var.h"
 #endif
 
+#include "bpfilter.h"
+
 #define        LOMTU   (1024+512)
 
 struct ifnet loif;
 #define        LOMTU   (1024+512)
 
 struct ifnet loif;
@@ -52,13 +57,20 @@ loattach()
 
        ifp->if_name = "lo";
        ifp->if_mtu = LOMTU;
 
        ifp->if_name = "lo";
        ifp->if_mtu = LOMTU;
+#ifdef MULTICAST
+       ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
+#else
        ifp->if_flags = IFF_LOOPBACK;
        ifp->if_flags = IFF_LOOPBACK;
+#endif
        ifp->if_ioctl = loioctl;
        ifp->if_output = looutput;
        ifp->if_type = IFT_LOOP;
        ifp->if_hdrlen = 0;
        ifp->if_addrlen = 0;
        if_attach(ifp);
        ifp->if_ioctl = loioctl;
        ifp->if_output = looutput;
        ifp->if_type = IFT_LOOP;
        ifp->if_hdrlen = 0;
        ifp->if_addrlen = 0;
        if_attach(ifp);
+#if NBPFILTER > 0
+       bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
+#endif
 }
 
 looutput(ifp, m, dst, rt)
 }
 
 looutput(ifp, m, dst, rt)
@@ -72,6 +84,26 @@ looutput(ifp, m, dst, rt)
 
        if ((m->m_flags & M_PKTHDR) == 0)
                panic("looutput no HDR");
 
        if ((m->m_flags & M_PKTHDR) == 0)
                panic("looutput no HDR");
+       ifp->if_lastchange = time;
+#if NBPFILTER > 0
+       if (loif.if_bpf) {
+               /*
+                * We need to prepend the address family as
+                * a four byte field.  Cons up a dummy header
+                * to pacify bpf.  This is safe because bpf
+                * will only read from the mbuf (i.e., it won't
+                * try to free it or keep a pointer a to it).
+                */
+               struct mbuf m0;
+               u_int af = dst->sa_family;
+
+               m0.m_next = m;
+               m0.m_len = 4;
+               m0.m_data = (char *)&af;
+               
+               bpf_mtap(loif.if_bpf, &m0);
+       }
+#endif
        m->m_pkthdr.rcvif = ifp;
 
        if (rt && rt->rt_flags & RTF_REJECT) {
        m->m_pkthdr.rcvif = ifp;
 
        if (rt && rt->rt_flags & RTF_REJECT) {
@@ -122,6 +154,7 @@ looutput(ifp, m, dst, rt)
 }
 
 /* ARGSUSED */
 }
 
 /* ARGSUSED */
+void
 lortrequest(cmd, rt, sa)
        int cmd;
        struct rtentry *rt;
 lortrequest(cmd, rt, sa)
        int cmd;
        struct rtentry *rt;
@@ -142,7 +175,10 @@ loioctl(ifp, cmd, data)
        caddr_t data;
 {
        register struct ifaddr *ifa;
        caddr_t data;
 {
        register struct ifaddr *ifa;
-       int error = 0;
+#ifdef MULTICAST
+       register struct ifreq *ifr;
+#endif
+       register int error = 0;
 
        switch (cmd) {
 
 
        switch (cmd) {
 
@@ -156,6 +192,28 @@ loioctl(ifp, cmd, data)
                 */
                break;
 
                 */
                break;
 
+#ifdef MULTICAST
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               ifr = (struct ifreq *)data;
+               if (ifr == 0) {
+                       error = EAFNOSUPPORT;           /* XXX */
+                       break;
+               }
+               switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+               case AF_INET:
+                       break;
+#endif
+
+               default:
+                       error = EAFNOSUPPORT;
+                       break;
+               }
+               break;
+#endif
+
        default:
                error = EINVAL;
        }
        default:
                error = EINVAL;
        }
index 7b3d9e1..0787c38 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_sl.c     7.28 (Berkeley) %G%
+ *     @(#)if_sl.c     7.29 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -155,7 +155,12 @@ slattach()
                sc->sc_if.if_next = NULL;
                sc->sc_if.if_unit = i++;
                sc->sc_if.if_mtu = SLMTU;
                sc->sc_if.if_next = NULL;
                sc->sc_if.if_unit = i++;
                sc->sc_if.if_mtu = SLMTU;
+#ifdef MULTICAST
+               sc->sc_if.if_flags =
+                   IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
+#else
                sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP;
                sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP;
+#endif
                sc->sc_if.if_type = IFT_SLIP;
                sc->sc_if.if_ioctl = slioctl;
                sc->sc_if.if_output = sloutput;
                sc->sc_if.if_type = IFT_SLIP;
                sc->sc_if.if_ioctl = slioctl;
                sc->sc_if.if_output = sloutput;
@@ -661,7 +666,10 @@ slioctl(ifp, cmd, data)
        caddr_t data;
 {
        register struct ifaddr *ifa = (struct ifaddr *)data;
        caddr_t data;
 {
        register struct ifaddr *ifa = (struct ifaddr *)data;
-       int s = splimp(), error = 0;
+#ifdef MULTICAST
+       register struct ifreq *ifr;
+#endif
+       register int s = splimp(), error = 0;
 
        switch (cmd) {
 
 
        switch (cmd) {
 
@@ -677,6 +685,28 @@ slioctl(ifp, cmd, data)
                        error = EAFNOSUPPORT;
                break;
 
                        error = EAFNOSUPPORT;
                break;
 
+#ifdef MULTICAST
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               ifr = (struct ifreq *)data;
+               if (ifr == 0) {
+                       error = EAFNOSUPPORT;           /* XXX */
+                       break;
+               }
+               switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+               case AF_INET:
+                       break;
+#endif
+
+               default:
+                       error = EAFNOSUPPORT;
+                       break;
+               }
+               break;
+#endif
+
        default:
                error = EINVAL;
        }
        default:
                error = EINVAL;
        }