Fold in the changes to support IP multicasting, from Jim Lowe et al.
authorJordan K. Hubbard <jkh@FreeBSD.org>
Tue, 17 May 1994 22:31:21 +0000 (22:31 +0000)
committerJordan K. Hubbard <jkh@FreeBSD.org>
Tue, 17 May 1994 22:31:21 +0000 (22:31 +0000)
25 files changed:
sys/conf/files
sys/i386/conf/LINT
sys/i386/conf/files.i386
sys/i386/isa/if_ed.c
sys/net/if.h
sys/net/if_ethersubr.c
sys/net/if_loop.c
sys/net/if_sl.c
sys/net/raw_cb.h
sys/netinet/if_ether.c
sys/netinet/if_ether.h
sys/netinet/in.c
sys/netinet/in.h
sys/netinet/in_pcb.c
sys/netinet/in_pcb.h
sys/netinet/in_proto.c
sys/netinet/in_var.h
sys/netinet/ip_icmp.c
sys/netinet/ip_input.c
sys/netinet/ip_output.c
sys/netinet/ip_var.h
sys/netinet/raw_ip.c
sys/netinet/udp_usrreq.c
sys/sys/ioctl.h
sys/sys/malloc.h

index 4af7d3e..3e89a82 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: files,v 1.20 1994/01/25 11:16:01 rgrimes Exp $
+# $Id: files,v 1.21 1994/03/15 01:57:49 wollman Exp $
 #
 ddb/db_access.c                optional ddb
 ddb/db_aout.c          optional ddb
 #
 ddb/db_access.c                optional ddb
 ddb/db_aout.c          optional ddb
@@ -133,6 +133,8 @@ netinet/tcp_subr.c  optional inet
 netinet/tcp_timer.c    optional inet
 netinet/tcp_usrreq.c   optional inet
 netinet/udp_usrreq.c   optional inet
 netinet/tcp_timer.c    optional inet
 netinet/tcp_usrreq.c   optional inet
 netinet/udp_usrreq.c   optional inet
+netinet/igmp.c         optional multicast
+netinet/ip_mroute.c    optional inet multicast mrouting
 netiso/clnp_debug.c    optional iso
 netiso/clnp_er.c       optional iso
 netiso/clnp_frag.c     optional iso
 netiso/clnp_debug.c    optional iso
 netiso/clnp_er.c       optional iso
 netiso/clnp_frag.c     optional iso
index d974546..48c2d45 100644 (file)
@@ -4,7 +4,7 @@
 #
 #      This kernel is NOT MEANT to be runnable!
 #
 #
 #      This kernel is NOT MEANT to be runnable!
 #
-#      $Id: LINT,v 1.67 1994/05/17 14:15:11 jkh Exp $
+#      $Id: LINT,v 1.68 1994/05/17 14:18:13 jkh Exp $
 #
 
 machine                "i386"
 #
 
 machine                "i386"
@@ -65,6 +65,9 @@ options               USER_LDT                #allow user-level control of i386 ldt
 # See /sys/i386/doc/sound.doc for information about EXCLUDE options for
 #  the sound drivers.
 
 # See /sys/i386/doc/sound.doc for information about EXCLUDE options for
 #  the sound drivers.
 
+options                MULTICAST               # Multicast code
+options                MROUTING                # Multicast routing
+
 #
 # options that are in sys/conf/files
 #
 #
 # options that are in sys/conf/files
 #
index e5b1e0d..1f9adda 100644 (file)
@@ -1,7 +1,7 @@
 # This file tells config what files go into building a kernel,
 # files marked standard are always included.
 #
 # This file tells config what files go into building a kernel,
 # files marked standard are always included.
 #
-#      $Id: files.i386,v 1.35 1994/05/12 01:01:39 jkh Exp $
+#      $Id: files.i386,v 1.36 1994/05/14 10:45:57 csgr Exp $
 #
 i386/i386/autoconf.c           standard                device-driver
 i386/i386/cons.c               standard
 #
 i386/i386/autoconf.c           standard                device-driver
 i386/i386/cons.c               standard
@@ -17,6 +17,7 @@ i386/i386/pmap.c              standard
 i386/i386/sys_machdep.c                standard
 i386/i386/trap.c               standard
 i386/i386/vm_machdep.c         standard
 i386/i386/sys_machdep.c                standard
 i386/i386/trap.c               standard
 i386/i386/vm_machdep.c         standard
+i386/i386/random.s             optional        multicast
 i386/isa/aha1542.c             optional        aha     device-driver
 i386/isa/aha1742.c             optional        ahb     device-driver
 i386/isa/bt742a.c              optional        bt      device-driver
 i386/isa/aha1542.c             optional        aha     device-driver
 i386/isa/aha1742.c             optional        ahb     device-driver
 i386/isa/bt742a.c              optional        bt      device-driver
index 84047e2..a2efde8 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 /*
  */
 
 /*
- * $Id: if_ed.c,v 1.36 1994/04/10 20:06:26 davidg Exp $
+ * $Id: if_ed.c,v 1.37 1994/04/13 10:15:34 davidg Exp $
  */
 
 #include "ed.h"
  */
 
 #include "ed.h"
@@ -115,6 +115,9 @@ int ed_probe(struct isa_device *);
 void   ed_start(struct ifnet *);
 void   ed_reset(int, int);
 void   ed_watchdog(int);
 void   ed_start(struct ifnet *);
 void   ed_reset(int, int);
 void   ed_watchdog(int);
+#ifdef MULTICAST
+void   ds_getmcaf();
+#endif
 
 static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
 static void ed_stop(int);
 
 static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
 static void ed_stop(int);
@@ -1032,6 +1035,9 @@ ed_attach(isa_dev)
                    (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
        else
                ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
                    (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
        else
                ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+#ifdef MULTICAST
+       ifp->if_flags |= IFF_MULTICAST;
+#endif
 
        /*
         * Attach the interface
 
        /*
         * Attach the interface
@@ -1210,11 +1216,17 @@ ed_init(unit)
         */
        outb(sc->nic_addr + ED_P0_RBCR0, 0);
        outb(sc->nic_addr + ED_P0_RBCR1, 0);
         */
        outb(sc->nic_addr + ED_P0_RBCR0, 0);
        outb(sc->nic_addr + ED_P0_RBCR1, 0);
-
+#ifndef MULTICAST
        /*
         * Enable reception of broadcast packets
         */
        outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
        /*
         * Enable reception of broadcast packets
         */
        outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+#else
+       /*
+        * Tell RCR to do nothing for now.
+        */
+       outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
+#endif
 
        /*
         * Place NIC in internal loopback mode
 
        /*
         * Place NIC in internal loopback mode
@@ -1265,6 +1277,7 @@ ed_init(unit)
        for (i = 0; i < ETHER_ADDR_LEN; ++i)
                outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
 
        for (i = 0; i < ETHER_ADDR_LEN; ++i)
                outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
 
+#ifndef MULTICAST
 #if NBPFILTER > 0
        /*
         * Initialize multicast address hashing registers to accept
 #if NBPFILTER > 0
        /*
         * Initialize multicast address hashing registers to accept
@@ -1273,6 +1286,24 @@ ed_init(unit)
        for (i = 0; i < 8; ++i)
                outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
 #endif
        for (i = 0; i < 8; ++i)
                outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
 #endif
+#else
+       /* set up multicast addresses and filter modes */
+       if (sc != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) {
+               u_long mcaf[2];
+
+               if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
+                       mcaf[0] = 0xffffffff;
+                       mcaf[1] = 0xffffffff;
+               } else
+                       ds_getmcaf(sc, mcaf);
+  
+               /*
+                * Set multicast filter on chip.
+                */
+               for (i = 0; i < 8; i++)
+                       outb(sc->nic_addr + ED_P1_MAR0 + i, ((u_char *)mcaf)[i]);
+       }
+#endif
 
        /*
         * Set Current Page pointer to next_packet (initialized above)
 
        /*
         * Set Current Page pointer to next_packet (initialized above)
@@ -1288,6 +1319,12 @@ ed_init(unit)
        } else {
                outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
        }
        } else {
                outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
        }
+#ifdef MULTICAST
+       /*
+        * Clear all interrupts
+        */
+       outb(sc->nic_addr + ED_P0_ISR, 0xff);
+#endif
        /*
         * Take interface out of loopback
         */
        /*
         * Take interface out of loopback
         */
@@ -1304,6 +1341,23 @@ ed_init(unit)
                        outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
                }
        }
                        outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
                }
        }
+#ifdef MULTICAST
+       i = ED_RCR_AB;
+       if (sc != 0) {
+               if ((ifp->if_flags & IFF_PROMISC) != 0) {
+                       /*
+                        * Set promiscuous mode.
+                        * Also reconfigure the multicast filter.
+                        */
+                       int j;
+                       i |=ED_RCR_PRO|ED_RCR_AM|ED_RCR_AR|ED_RCR_SEP;
+                       for (j = 0; j < 8; j++)
+                               outb(sc->nic_addr + ED_P1_MAR0 + j, 0xff);
+               }
+               i |= ED_RCR_AM;
+       }
+       outb(sc->nic_addr + ED_P0_RCR, i);
+#endif
 
        /*
         * Set 'running' flag, and clear output active flag.
 
        /*
         * Set 'running' flag, and clear output active flag.
@@ -2003,6 +2057,7 @@ ed_ioctl(ifp, command, data)
                            ((ifp->if_flags & IFF_RUNNING) == 0))
                                ed_init(ifp->if_unit);
                }
                            ((ifp->if_flags & IFF_RUNNING) == 0))
                                ed_init(ifp->if_unit);
                }
+#ifndef MULTICAST
 #if NBPFILTER > 0
                if (ifp->if_flags & IFF_PROMISC) {
                        /*
 #if NBPFILTER > 0
                if (ifp->if_flags & IFF_PROMISC) {
                        /*
@@ -2035,9 +2090,28 @@ ed_ioctl(ifp, command, data)
                                outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
                        }
                }
                                outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
                        }
                }
-
+#else
                break;
                break;
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               /*
+                * Update out multicast list.
+                */
+               error = (command == SIOCADDMULTI) ?
+                       ether_addmulti((struct ifreq *)data, &sc->arpcom):
+                       ether_delmulti((struct ifreq *)data, &sc->arpcom);
 
 
+               if (error == ENETRESET) {
+                       /*
+                        * Multicast list has changed; set the hardware filter
+                        * accordingly.
+                        */
+                       ed_stop(ifp->if_unit); /* XXX for ds_setmcaf? */
+                       ed_init(ifp->if_unit);
+                       error = 0;
+               }
+               break;
+#endif
        default:
                error = EINVAL;
        }
        default:
                error = EINVAL;
        }
@@ -2485,4 +2559,62 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
        }
        return (m);
 }
        }
        return (m);
 }
+#ifdef MULTICAST
+/*
+ * Compute crc for ethernet address
+ */
+u_long
+ds_crc(ep)
+      u_char *ep;
+{
+#define POLYNOMIAL 0x04c11db6
+      register u_long crc = 0xffffffffL;
+      register int carry, i, j;
+      register u_char b;
+      
+      for (i = 6; --i >= 0; ) {
+              b = *ep++;
+              for (j = 8; --j >= 0; ) {
+                      carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+                      crc <<= 1;
+                      b >>= 1;
+                      if (carry)
+                              crc = ((crc ^ POLYNOMIAL) | carry);
+              }
+      }
+      return crc;
+#undef POLYNOMIAL
+}
+
+/*
+ * Compute the multicast address filter from the
+ * list of multicast addresses we need to listen to.
+ */
+void
+ds_getmcaf(sc, mcaf)
+      struct ed_softc *sc;
+      u_long *mcaf;
+{
+      register u_int index;
+      register u_char *af = (u_char*)mcaf;
+      register struct ether_multi *enm;
+      register struct ether_multistep step;
+      
+      mcaf[0] = 0;
+      mcaf[1] = 0;
+      
+      ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+      while (enm != NULL) {
+              if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+                      mcaf[0] = 0xffffffff;
+                      mcaf[1] = 0xffffffff;
+                      return;
+              }
+              index = ds_crc(enm->enm_addrlo, 6) >> 26;
+              af[index >> 3] |= 1 << (index & 7);
+              
+              ETHER_NEXT_MULTI(step, enm);
+      }
+}
+#endif
 #endif
 #endif
index 4dbcc42..b1e55d2 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)if.h  7.11 (Berkeley) 3/19/91
  * SUCH DAMAGE.
  *
  *     from: @(#)if.h  7.11 (Berkeley) 3/19/91
- *     $Id: if.h,v 1.10 1993/11/25 01:33:59 wollman Exp $
+ *     $Id: if.h,v 1.11 1993/12/19 00:52:02 wollman Exp $
  */
 
 #ifndef _NET_IF_H_
  */
 
 #ifndef _NET_IF_H_
@@ -81,7 +81,7 @@ struct ifnet {
        char    *if_name;               /* name, e.g. ``en'' or ``lo'' */
        short   if_unit;                /* sub-unit for lower level driver */
        u_short if_mtu;                 /* maximum transmission unit */
        char    *if_name;               /* name, e.g. ``en'' or ``lo'' */
        short   if_unit;                /* sub-unit for lower level driver */
        u_short if_mtu;                 /* maximum transmission unit */
-       short   if_flags;               /* up/down, broadcast, etc. */
+       u_int   if_flags;               /* up/down, broadcast, etc. */
        short   if_timer;               /* time 'til if_watchdog called */
        int     if_metric;              /* routing metric (external only) */
        struct  ifaddr *if_addrlist;    /* linked list of addresses per if */
        short   if_timer;               /* time 'til if_watchdog called */
        int     if_metric;              /* routing metric (external only) */
        struct  ifaddr *if_addrlist;    /* linked list of addresses per if */
@@ -143,12 +143,18 @@ struct ifnet {
 #define        IFF_LLC2        0x4000          /* IEEE 802.2 LLC class 2 */
 #define IFF_ALTPHYS    0x8000  /* alternative physical connection */
 #define IFF_MULTICAST  0x10000 /* i'face supports multicast */
 #define        IFF_LLC2        0x4000          /* IEEE 802.2 LLC class 2 */
 #define IFF_ALTPHYS    0x8000  /* alternative physical connection */
 #define IFF_MULTICAST  0x10000 /* i'face supports multicast */
+#ifdef notdef
 #define IFF_VIRTUAL    0x20000 /* i'face is really a VIF */
 
 /* flags set internally only: */
 #define        IFF_CANTCHANGE \
        (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|IFF_SIMPLEX\
         |IFF_MULTICAST|IFF_VIRTUAL)
 #define IFF_VIRTUAL    0x20000 /* i'face is really a VIF */
 
 /* flags set internally only: */
 #define        IFF_CANTCHANGE \
        (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|IFF_SIMPLEX\
         |IFF_MULTICAST|IFF_VIRTUAL)
+#else
+#define        IFF_CANTCHANGE \
+       (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|IFF_SIMPLEX\
+        |IFF_MULTICAST)
+#endif
 
 /*
  * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
 
 /*
  * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
@@ -222,7 +228,7 @@ struct      ifreq {
                struct  sockaddr ifru_addr;
                struct  sockaddr ifru_dstaddr;
                struct  sockaddr ifru_broadaddr;
                struct  sockaddr ifru_addr;
                struct  sockaddr ifru_dstaddr;
                struct  sockaddr ifru_broadaddr;
-               short   ifru_flags;
+               u_int   ifru_flags;
                int     ifru_metric;
                caddr_t ifru_data;
        } ifr_ifru;
                int     ifru_metric;
                caddr_t ifru_data;
        } ifr_ifru;
index 6913c6f..de4a85f 100644 (file)
@@ -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
  * 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
  * SUCH DAMAGE.
  *
  *     from: @(#)if_ethersubr.c        7.13 (Berkeley) 4/20/91
- *     $Id: if_ethersubr.c,v 1.3 1993/10/16 17:43:16 rgrimes Exp $
+ *     $Id: if_ethersubr.c,v 1.4 1993/11/25 01:34:02 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #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 */
                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;
                        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:
@@ -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));
                    (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: {
@@ -165,7 +156,8 @@ ether_output(ifp, m0, dst, rt)
                                        (char *)edst, &snpalen)) > 0)
                        goto bad; /* Not Resolved */
        iso_resolved:
                                        (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) {
                    (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
                                printf("%x ", edst[i] & 0xff);
                        printf("\n");
                ENDDEBUG
-               } goto gottype;
+               }
+               break;
 #endif ISO
 #ifdef RMP
        case AF_RMP:
 #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;
                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,
@@ -217,18 +210,6 @@ ether_output(ifp, m0, dst, rt)
                goto bad;
        }
 
                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);
        /*
        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);
                (*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);
 
@@ -293,11 +274,13 @@ ether_input(ifp, eh, m)
 
        ifp->if_lastchange = time;
        ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
 
        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;
        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;
                m->m_flags |= M_MCAST;
+       }
        if (m->m_flags & (M_BCAST|M_MCAST))
                ifp->if_imcasts++;
 
        if (m->m_flags & (M_BCAST|M_MCAST))
                ifp->if_imcasts++;
 
@@ -421,3 +404,178 @@ ether_sprintf(ap)
        *--cp = 0;
        return (etherbuf);
 }
        *--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
index fee81ac..037d99f 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)if_loop.c     7.13 (Berkeley) 4/26/91
  * SUCH DAMAGE.
  *
  *     from: @(#)if_loop.c     7.13 (Berkeley) 4/26/91
- *     $Id: if_loop.c,v 1.5 1993/11/25 01:34:03 wollman Exp $
+ *     $Id: if_loop.c,v 1.6 1993/12/20 19:31:29 wollman Exp $
  */
 
 /*
  */
 
 /*
@@ -95,7 +95,11 @@ loattach(void)
 
        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_ioctl = loioctl;
        ifp->if_output = looutput;
        ifp->if_type = IFT_LOOP;
@@ -216,6 +220,9 @@ loioctl(ifp, cmd, data)
        caddr_t data;
 {
        register struct ifaddr *ifa;
        caddr_t data;
 {
        register struct ifaddr *ifa;
+#ifdef MULTICAST
+       register struct ifreq *ifr;
+#endif
        int error = 0;
 
        switch (cmd) {
        int error = 0;
 
        switch (cmd) {
@@ -230,6 +237,27 @@ 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 1422945..a6ff4c2 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)if_sl.c       7.22 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)if_sl.c       7.22 (Berkeley) 4/20/91
- *     $Id: if_sl.c,v 1.8 1994/03/02 20:28:55 guido Exp $
+ *     $Id: if_sl.c,v 1.10 1994/03/22 01:16:06 ache Exp $
  */
 
 /*
  */
 
 /*
@@ -65,7 +65,7 @@
  * interrupts and network activity; thus, splimp must be >= spltty.
  */
 
  * interrupts and network activity; thus, splimp must be >= spltty.
  */
 
-/* $Id: if_sl.c,v 1.8 1994/03/02 20:28:55 guido Exp $ */
+/* $Id: if_sl.c,v 1.10 1994/03/22 01:16:06 ache Exp $ */
 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
 
 #include "sl.h"
 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
 
 #include "sl.h"
@@ -869,6 +869,9 @@ slioctl(ifp, cmd, data)
        caddr_t data;
 {
        register struct ifaddr *ifa = (struct ifaddr *)data;
        caddr_t data;
 {
        register struct ifaddr *ifa = (struct ifaddr *)data;
+#ifdef MULTICAST
+       register struct ifreq *ifr;
+#endif
        int s = splimp(), error = 0;
 
        switch (cmd) {
        int s = splimp(), error = 0;
 
        switch (cmd) {
@@ -890,6 +893,25 @@ 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;
        }
index f63ac3a..3b4b856 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)raw_cb.h      7.6 (Berkeley) 6/28/90
  * SUCH DAMAGE.
  *
  *     from: @(#)raw_cb.h      7.6 (Berkeley) 6/28/90
- *     $Id: raw_cb.h,v 1.3 1993/11/07 17:47:05 wollman Exp $
+ *     $Id: raw_cb.h,v 1.4 1993/12/19 00:52:05 wollman Exp $
  */
 
 #ifndef _NET_RAW_CB_H_
  */
 
 #ifndef _NET_RAW_CB_H_
@@ -48,6 +48,7 @@ struct rawcb {
        struct  sockaddr *rcb_faddr;    /* destination address */
        struct  sockaddr *rcb_laddr;    /* socket's address */
        struct  sockproto rcb_proto;    /* protocol family, protocol */
        struct  sockaddr *rcb_faddr;    /* destination address */
        struct  sockaddr *rcb_laddr;    /* socket's address */
        struct  sockproto rcb_proto;    /* protocol family, protocol */
+       struct  mbuf *rcb_moptions;     /* proto specific multicast options */
 };
 
 #define        sotorawcb(so)           ((struct rawcb *)(so)->so_pcb)
 };
 
 #define        sotorawcb(so)           ((struct rawcb *)(so)->so_pcb)
index d517bc4..8c1587b 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)if_ether.c    7.13 (Berkeley) 10/31/90
  * SUCH DAMAGE.
  *
  *     from: @(#)if_ether.c    7.13 (Berkeley) 10/31/90
- *     $Id: if_ether.c,v 1.3 1993/10/16 18:25:54 rgrimes Exp $
+ *     $Id: if_ether.c,v 1.4 1993/11/25 01:34:57 wollman Exp $
  */
 
 /*
  */
 
 /*
@@ -197,6 +197,12 @@ arpresolve(ac, m, destip, desten, usetrailers)
                    sizeof(etherbroadcastaddr));
                return (1);
        }
                    sizeof(etherbroadcastaddr));
                return (1);
        }
+#ifdef MULTICAST
+       if (m->m_flags & M_MCAST) {     /* multicast */
+               ETHER_MAP_IP_MULTICAST(destip, desten);
+               return(1);
+       }
+#endif
        lna = in_lnaof(*destip);
        /* if for us, use software loopback driver if up */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
        lna = in_lnaof(*destip);
        /* if for us, use software loopback driver if up */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
index 6831175..5e8f4d1 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)if_ether.h    7.5 (Berkeley) 6/28/90
  * SUCH DAMAGE.
  *
  *     from: @(#)if_ether.h    7.5 (Berkeley) 6/28/90
- *     $Id: if_ether.h,v 1.3 1993/11/07 17:47:47 wollman Exp $
+ *     $Id: if_ether.h,v 1.4 1993/11/25 01:35:01 wollman Exp $
  */
 
 #ifndef _NETINET_IF_ETHER_H_
  */
 
 #ifndef _NETINET_IF_ETHER_H_
@@ -61,6 +61,25 @@ struct       ether_header {
 #define        ETHERMTU        1500
 #define        ETHERMIN        (60-14)
 
 #define        ETHERMTU        1500
 #define        ETHERMIN        (60-14)
 
+#ifdef KERNEL
+/*
+ * Macro to map an IP multicast address to an Ethernet multicast address.
+ * The high-order 25 bites of the Ethernet address are staticall assigned,
+ * and the low-rder 23 bites are taken from the low end of the IP address.
+ */
+#define        ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \
+       /* struct in_addr *ipaddr; */ \
+       /* u_char enaddr[6]; */ \
+{ \
+       (enaddr)[0] = 0x01; \
+       (enaddr)[1] = 0x00; \
+       (enaddr)[2] = 0x5e; \
+       (enaddr)[3] = ((u_char *)ipaddr)[1] & 0x7f; \
+       (enaddr)[4] = ((u_char *)ipaddr)[2]; \
+       (enaddr)[5] = ((u_char *)ipaddr)[3]; \
+}
+#endif
+
 /*
  * Ethernet Address Resolution Protocol.
  *
 /*
  * Ethernet Address Resolution Protocol.
  *
@@ -91,8 +110,11 @@ struct      arpcom {
        struct  ifnet ac_if;            /* network-visible interface */
        u_char  ac_enaddr[6];           /* ethernet hardware address */
        struct in_addr ac_ipaddr;       /* copy of ip address- XXX */
        struct  ifnet ac_if;            /* network-visible interface */
        u_char  ac_enaddr[6];           /* ethernet hardware address */
        struct in_addr ac_ipaddr;       /* copy of ip address- XXX */
+       struct ether_multi *ac_multiaddrs; /* list of ether m'cast addrs */
+       int     ac_multicnt;            /* length of ac_multiaddrs list */
 };
 
 };
 
+
 /*
  * Internet to ethernet address resolution table.
  */
 /*
  * Internet to ethernet address resolution table.
  */
@@ -106,10 +128,84 @@ struct    arptab {
 
 #ifdef KERNEL
 extern u_char  etherbroadcastaddr[6]; /* defined in net/if_ethersubr.c */
 
 #ifdef KERNEL
 extern u_char  etherbroadcastaddr[6]; /* defined in net/if_ethersubr.c */
+#if defined(ISO) && !defined(MULTICAST)
+#define MULTICAST 1
+#endif
+#ifdef MULTICAST
+u_char ether_ipmulticast_min[6];
+u_char ether_ipmulticast_max[6];
+#endif
 struct arptab *arptnew();
 
 extern void ether_input(struct ifnet *, struct ether_header *, struct mbuf *);
 extern char *ether_sprintf(u_char *);
 
 struct arptab *arptnew();
 
 extern void ether_input(struct ifnet *, struct ether_header *, struct mbuf *);
 extern char *ether_sprintf(u_char *);
 
-#endif
+#ifdef MULTICAST
+/*    
+ * Ethernet multicast address structure.  There is one of these for each
+ * multicast address or range of multicast addresses that we are supposed
+ * to listen to on a particular interface.  They are kept in a linked list,
+ * rooted in the interface's arpcom structure.  (This really has nothing to
+ * do with ARP, or with the Internet address family, but this appears to be
+ * the minimally-disrupting place to put it.)
+ */
+struct ether_multi {
+       u_char  enm_addrlo[6];          /* low or only address of range */
+       u_char  enm_addrhi[6];          /* high or only address of range */
+       struct arpcom *enm_ac;          /* back point to arpcom */
+       u_int   enm_refcount;           /* no. claims to this addr/range */
+       struct ether_multi *enm_next;   /* ptr to next ether_multi */
+} ;
+
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the ether_multi records.
+ */
+struct ether_multistep {
+      struct ether_multi  *e_enm;
+};
+
+/*
+ * Macro for looking up the ether_multi record for a given range of Ethernet
+ * multicast addresses connected to a given arpcom structure.  If no matching
+ * record is found, "enm" returns NULL.
+ */
+#define ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm) \
+      /* u_char addrlo[6]; */ \
+      /* u_char addrhi[6]; */ \
+      /* struct arpcom *ac; */ \
+      /* struct ether_multi *enm; */ \
+{ \
+      for ((enm) = (ac)->ac_multiaddrs; \
+          (enm) != NULL && \
+          (bcmp((enm)->enm_addrlo, (addrlo), 6) != 0 || \
+           bcmp((enm)->enm_addrhi, (addrhi), 6) != 0); \
+              (enm) = (enm)->enm_next); \
+}
+
+/*
+ * Macro to step through all of the ether_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide.  ETHER_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record.  Both macros return a NULL "enm" when there
+ * are no remaining records.
+ */
+#define ETHER_NEXT_MULTI(step, enm) \
+      /* struct ether_multistep step; */  \
+      /* struct ether_multi *enm; */  \
+{ \
+      if (((enm) = (step).e_enm) != NULL) \
+              (step).e_enm = (enm)->enm_next; \
+}
+
+#define ETHER_FIRST_MULTI(step, ac, enm) \
+      /* struct ether_multistep step; */ \
+      /* struct arpcom *ac; */ \
+      /* struct ether_multi *enm; */ \
+{ \
+      (step).e_enm = (ac)->ac_multiaddrs; \
+      ETHER_NEXT_MULTI((step), (enm)); \
+}
+#endif /* _MULTICAST */
+#endif /* KERNEL */
 #endif /* _NETINET_IF_ETHER_H_ */
 #endif /* _NETINET_IF_ETHER_H_ */
index 34a662f..2254f22 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)in.c  7.17 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)in.c  7.17 (Berkeley) 4/20/91
- *     $Id: in.c,v 1.7 1993/12/19 00:52:34 wollman Exp $
+ *     $Id: in.c,v 1.8 1994/01/15 14:29:21 davidg Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -93,6 +93,10 @@ in_netof(in)
                net = i & IN_CLASSB_NET;
        else if (IN_CLASSC(i))
                net = i & IN_CLASSC_NET;
                net = i & IN_CLASSB_NET;
        else if (IN_CLASSC(i))
                net = i & IN_CLASSC_NET;
+#ifdef MULTICAST
+       else if (IN_CLASSD(i))
+               net = i & IN_CLASSD_NET;
+#endif
        else
                return (0);
 
        else
                return (0);
 
@@ -174,6 +178,11 @@ in_lnaof(in)
        } else if (IN_CLASSC(i)) {
                net = i & IN_CLASSC_NET;
                host = i & IN_CLASSC_HOST;
        } else if (IN_CLASSC(i)) {
                net = i & IN_CLASSC_NET;
                host = i & IN_CLASSC_HOST;
+#ifdef MULTICAST
+       } else if (IN_CLASSD(i)) {
+               net = i & IN_CLASSD_NET;
+               host = i & IN_CLASSD_HOST;
+#endif
        } else
                return (i);
 
        } else
                return (i);
 
@@ -557,6 +566,18 @@ in_ifinit(ifp, ia, sin, scrub)
        }
        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
                ia->ia_flags |= IFA_ROUTE;
        }
        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
                ia->ia_flags |= IFA_ROUTE;
+#ifdef MULTICAST
+       /*
+        * If the interface supports multicast, join the "all hosts"
+        * multicast group on that interface.
+        */
+       if (ifp->if_flags & IFF_MULTICAST) {
+               struct in_addr addr;
+               
+               addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
+               in_addmulti(&addr, ifp);
+       }
+#endif
        return (error);
 }
 
        return (error);
 }
 
@@ -603,4 +624,113 @@ in_broadcast(in)
                return (1);
        return (0);
 }
                return (1);
        return (0);
 }
+
+#ifdef MULTICAST
+/*
+ * Add an address to the list of IP multicast addresses for a given interface.
+ */
+struct in_multi *
+in_addmulti(ap, ifp)
+       register struct in_addr *ap;
+       register struct ifnet *ifp;
+{
+       register struct in_multi *inm;
+       struct ifreq ifr;
+       struct in_ifaddr *ia;
+       int s = splnet();
+
+       /*
+        * See if address already in list.
+        */
+       IN_LOOKUP_MULTI(*ap, ifp, inm);
+       if (inm != NULL) {
+               /*
+                * Found it; just increment the reference count.
+                */
+               ++inm->inm_refcount;
+       }
+       else {
+               /*
+                * New address; allocate a new multicast record
+                * and link it into the interface's multicast list.
+                */
+               inm = (struct in_multi *)malloc(sizeof(*inm),
+                   M_IPMADDR, M_NOWAIT);
+               if (inm == NULL) {
+                       splx(s);
+                       return (NULL);
+               }
+               inm->inm_addr = *ap;
+               inm->inm_ifp = ifp;
+               inm->inm_refcount = 1;
+               IFP_TO_IA(ifp, ia);
+               if (ia == NULL) {
+                       free(inm, M_IPMADDR);
+                       splx(s);
+                       return (NULL);
+               }
+               inm->inm_ia = ia;
+               inm->inm_next = ia->ia_multiaddrs;
+               ia->ia_multiaddrs = inm;
+               /*
+                * Ask the network driver to update its multicast reception
+                * filter appropriately for the new address.
+                */
+               ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
+               ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
+               if (ifp->if_ioctl == NULL ||
+                   (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
+                       ia->ia_multiaddrs = inm->inm_next;
+                       free(inm, M_IPMADDR);
+                       splx(s);
+                       return (NULL);
+               }
+               /*
+                * Let IGMP know that we have joined a new IP multicast group.
+                */
+               igmp_joingroup(inm);
+       }
+       splx(s);
+       return (inm);
+}
+
+/*
+ * Delete a multicast address record.
+ */
+int
+in_delmulti(inm)
+       register struct in_multi *inm;
+{
+       register struct in_multi **p;
+       struct ifreq ifr;
+       int s = splnet();
+
+       if (--inm->inm_refcount == 0) {
+               /*
+                * No remaining claims to this record; let IGMP know that
+                * we are leaving the multicast group.
+                */
+               igmp_leavegroup(inm);
+               /*
+                * Unlink from list.
+                */
+               for (p = &inm->inm_ia->ia_multiaddrs;
+                    *p != inm;
+                    p = &(*p)->inm_next)
+                        continue;
+               *p = (*p)->inm_next;
+               /*
+                * Notify the network driver to update its multicast reception
+                * filter.
+                */
+               ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
+               ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
+                                                               inm->inm_addr;
+               (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
+                                                            (caddr_t)&ifr);
+               free(inm, M_IPMADDR);
+       }
+       splx(s);
+}
+#endif
 #endif
 #endif
index 13499d8..2f3d17d 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)in.h  7.11 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)in.h  7.11 (Berkeley) 4/20/91
- *     $Id: in.h,v 1.3 1993/10/16 18:25:58 rgrimes Exp $
+ *     $Id: in.h,v 1.4 1993/12/19 00:52:35 wollman Exp $
  */
 
 #ifndef _NETINET_IN_H_
  */
 
 #ifndef _NETINET_IN_H_
@@ -47,6 +47,7 @@
  */
 #define        IPPROTO_IP              0               /* dummy for IP */
 #define        IPPROTO_ICMP            1               /* control message protocol */
  */
 #define        IPPROTO_IP              0               /* dummy for IP */
 #define        IPPROTO_ICMP            1               /* control message protocol */
+#define        IPPROTO_IGMP            2               /* ground control protocol */
 #define        IPPROTO_GGP             3               /* gateway^2 (deprecated) */
 #define        IPPROTO_TCP             6               /* tcp */
 #define        IPPROTO_EGP             8               /* exterior gateway protocol */
 #define        IPPROTO_GGP             3               /* gateway^2 (deprecated) */
 #define        IPPROTO_TCP             6               /* tcp */
 #define        IPPROTO_EGP             8               /* exterior gateway protocol */
@@ -100,19 +101,36 @@ struct in_addr {
 #define        IN_CLASSC_HOST          0x000000ffUL
 
 #define        IN_CLASSD(i)            (((u_long)(i) & 0xf0000000UL) == 0xe0000000UL)
 #define        IN_CLASSC_HOST          0x000000ffUL
 
 #define        IN_CLASSD(i)            (((u_long)(i) & 0xf0000000UL) == 0xe0000000UL)
+#define        IN_CLASSD_NET           0xf0000000UL    /* These ones aren't really */
+#define        IN_CLASSD_NSHIFT        28              /* net and host fields, bit */
+#define        IN_CLASSD_HOST          0x0fffffffUL    /* routing needn't know. */
 #define        IN_MULTICAST(i)         IN_CLASSD(i)
 
 #define        IN_EXPERIMENTAL(i)      (((u_long)(i) & 0xe0000000UL) == 0xe0000000UL)
 #define        IN_BADCLASS(i)          (((u_long)(i) & 0xf0000000UL) == 0xf0000000UL)
 
 #define        INADDR_ANY              0x00000000UL
 #define        IN_MULTICAST(i)         IN_CLASSD(i)
 
 #define        IN_EXPERIMENTAL(i)      (((u_long)(i) & 0xe0000000UL) == 0xe0000000UL)
 #define        IN_BADCLASS(i)          (((u_long)(i) & 0xf0000000UL) == 0xf0000000UL)
 
 #define        INADDR_ANY              0x00000000UL
+#ifndef INADDR_LOOPBACK
+#define        INADDR_LOOPBACK         0x7f000001UL
+#endif
 #define        INADDR_BROADCAST        0xffffffffUL    /* must be masked */
 #ifndef KERNEL
 #define        INADDR_NONE             0xffffffffUL            /* -1 return */
 #endif
 
 #define        INADDR_BROADCAST        0xffffffffUL    /* must be masked */
 #ifndef KERNEL
 #define        INADDR_NONE             0xffffffffUL            /* -1 return */
 #endif
 
+#define        INADDR_UNSPEC_GROUP     0xe0000000UL    /* 224.0.0.0 */
+#define        INADDR_ALLHOSTS_GROUP   0xe0000001UL    /* 244.0.0.1 */
+#define        INADDR_MAX_LOCAL_GROUP  0xe00000ffUL    /* 244.0.0.255 */
+
 #define        IN_LOOPBACKNET          127                     /* official! */
 
 #define        IN_LOOPBACKNET          127                     /* official! */
 
+/*
+ * Define a macro to stuff the loopback address into an Internet address.
+ */
+#define        IN_SET_LOOPBACK_ADDR(a) { \
+       (a)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); \
+       (a)->sin_family = AF_INET; }
+
 /*
  * Socket address, internet style.
  */
 /*
  * Socket address, internet style.
  */
@@ -141,6 +159,20 @@ struct ip_opts {
  * First word of comment is data type; bool is stored in int.
  */
 #define        IP_OPTIONS      1       /* buf/ip_opts; set/get IP per-packet options */
  * First word of comment is data type; bool is stored in int.
  */
 #define        IP_OPTIONS      1       /* buf/ip_opts; set/get IP per-packet options */
+#ifndef NO_VAT_COMPAT
+#define        IP_MULTICAST_IF 2       /* set/get IP multicast interfcae */
+#define        IP_MULTICAST_TTL 3      /* set/get IP multicast timetolive */
+#define        IP_MULTICAST_LOOP 4     /* set/get IP m'cast loopback */
+#define        IP_ADD_MEMBERSHIP 5     /* add an IP group membership */
+#define        IP_DROP_MEMBERSHIP 6    /* drop an IP group membership */
+#define        IP_HDRINCL      7       /* int; header is included with data (raw) */
+#define        IP_TOS          8       /* int; IP type of service and precedence */
+#define        IP_TTL          9       /* int; IP time to live */
+#define        IP_RECVOPTS     10      /* bool; receive all IP options w/datagram */
+#define        IP_RECVRETOPTS  11      /* bool; receive IP options for response */
+#define        IP_RECVDSTADDR  12      /* bool; receive IP dst addr w/datagram */
+#define        IP_RETOPTS      13      /* ip_opts; set/get IP per-packet options */
+#else
 #define        IP_HDRINCL      2       /* int; header is included with data (raw) */
 #define        IP_TOS          3       /* int; IP type of service and precedence */
 #define        IP_TTL          4       /* int; IP time to live */
 #define        IP_HDRINCL      2       /* int; header is included with data (raw) */
 #define        IP_TOS          3       /* int; IP type of service and precedence */
 #define        IP_TTL          4       /* int; IP time to live */
@@ -148,6 +180,24 @@ struct ip_opts {
 #define        IP_RECVRETOPTS  6       /* bool; receive IP options for response */
 #define        IP_RECVDSTADDR  7       /* bool; receive IP dst addr w/datagram */
 #define        IP_RETOPTS      8       /* ip_opts; set/get IP per-packet options */
 #define        IP_RECVRETOPTS  6       /* bool; receive IP options for response */
 #define        IP_RECVDSTADDR  7       /* bool; receive IP dst addr w/datagram */
 #define        IP_RETOPTS      8       /* ip_opts; set/get IP per-packet options */
+#define        IP_MULTICAST_IF 9       /* set/get IP multicast interfcae */
+#define        IP_MULTICAST_TTL 10     /* set/get IP multicast timetolive */
+#define        IP_MULTICAST_LOOP 11    /* set/get IP m'cast loopback */
+#define        IP_ADD_MEMBERSHIP 12    /* add an IP group membership */
+#define        IP_DROP_MEMBERSHIP 13   /* drop an IP group membership */
+#endif
+
+#define        IP_DEFAULT_MULTICAST_TTL 1      /* normally limit m'casts to 1 hop */
+#define        IP_DEFAULT_MULTICAST_LOOP 1     /* normally hear sens if a member */
+#define        IP_MAX_MEMBERSHIPS      20      /* per socket; must fit in one mbuf */
+
+/*
+ * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
+ */
+struct ip_mreq {
+       struct in_addr  imr_multiaddr;  /* IP multicast address of group */
+       struct in_addr  imr_interface;  /* local IP address of interface */
+} ;
 
 #ifdef KERNEL
 /* From in.c: */
 
 #ifdef KERNEL
 /* From in.c: */
index a38a730..8d5ef01 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)in_pcb.c      7.14 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)in_pcb.c      7.14 (Berkeley) 4/20/91
- *     $Id: in_pcb.c,v 1.4 1993/11/25 01:35:05 wollman Exp $
+ *     $Id: in_pcb.c,v 1.5 1993/12/19 00:52:37 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -51,6 +51,9 @@
 #include "ip.h"
 #include "in_pcb.h"
 #include "in_var.h"
 #include "ip.h"
 #include "in_pcb.h"
 #include "in_var.h"
+#ifdef MULTICAST
+#include "ip_var.h"
+#endif
 
 int
 in_pcballoc(so, head)
 
 int
 in_pcballoc(so, head)
@@ -70,6 +73,53 @@ in_pcballoc(so, head)
        so->so_pcb = (caddr_t)inp;
        return (0);
 }
        so->so_pcb = (caddr_t)inp;
        return (0);
 }
+/*
+ * return 1 if there's a pcb whose addresses 'confict' with the
+ * supplied addresses.  Only exact matches (address with address
+ * or wildcard with wildcard) are considered to be in conflict
+ * since in_pcblookup will resolve anything else via 'best match'.
+ */
+int
+in_pcbconflict(head, faddr, laddr, fport, lport)
+        register struct inpcb *head;
+        register u_long faddr, laddr;
+        register u_short fport, lport;
+{
+        register struct inpcb *inp = head;
+
+        while ((inp = inp->inp_next) != head)
+                if (inp->inp_lport == lport &&
+                    (fport == 0 || inp->inp_fport == fport) &&
+                    (faddr == 0 || inp->inp_faddr.s_addr == faddr) &&
+                    (laddr == 0 || inp->inp_laddr.s_addr == laddr))
+                        return (1);
+        return (0);
+}
+
+/*
+ * Chose a unique (non-conflicting) local port for the inpcb list
+ * starting at 'head'.  (A 'rover' is kept in the lport field of
+ * the list head to make N calls to this routine O(N^2) instead of
+ * O(N^3)).  The port will always be
+ *      IPPORT_RESERVED <= lport <= IPPORT_USERRESERVED
+ */
+u_short
+in_uniqueport(head, faddr, laddr, fport)
+        register struct inpcb *head;
+        register u_long faddr, laddr;
+        register u_short fport;
+{
+        register u_short lport = head->inp_lport;
+
+        do {
+                ++lport;
+                if (lport < IPPORT_RESERVED || lport > IPPORT_USERRESERVED)
+                        lport = IPPORT_RESERVED;
+        } while (in_pcbconflict(head, faddr, laddr, fport, htons(lport)));
+        head->inp_lport = lport;
+        return (htons(lport));
+}
+
        
 int
 in_pcbbind(inp, nam)
        
 int
 in_pcbbind(inp, nam)
@@ -107,6 +157,7 @@ in_pcbbind(inp, nam)
                if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
                        return (EACCES);
                /* even GROSSER, but this is the Internet */
                if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
                        return (EACCES);
                /* even GROSSER, but this is the Internet */
+#ifdef notdef
                if ((so->so_options & SO_REUSEADDR) == 0 &&
                    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
                     (so->so_options & SO_ACCEPTCONN) == 0))
                if ((so->so_options & SO_REUSEADDR) == 0 &&
                    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
                     (so->so_options & SO_ACCEPTCONN) == 0))
@@ -114,10 +165,16 @@ in_pcbbind(inp, nam)
                if (in_pcblookup(head,
                    zeroin_addr, 0, sin->sin_addr, lport, wild))
                        return (EADDRINUSE);
                if (in_pcblookup(head,
                    zeroin_addr, 0, sin->sin_addr, lport, wild))
                        return (EADDRINUSE);
+#else
+                if ((inp->inp_socket->so_options & SO_REUSEADDR) == 0 &&
+                            in_pcbconflict(head, 0, sin->sin_addr.s_addr, 0, lport))
+                                return (EADDRINUSE);
+#endif
        }
        inp->inp_laddr = sin->sin_addr;
 noname:
        if (lport == 0)
        }
        inp->inp_laddr = sin->sin_addr;
 noname:
        if (lport == 0)
+#ifdef notdef
                do {
                        if (head->inp_lport++ < IPPORT_RESERVED ||
                            head->inp_lport > IPPORT_USERRESERVED)
                do {
                        if (head->inp_lport++ < IPPORT_RESERVED ||
                            head->inp_lport > IPPORT_USERRESERVED)
@@ -125,6 +182,10 @@ noname:
                        lport = htons(head->inp_lport);
                } while (in_pcblookup(head,
                            zeroin_addr, 0, inp->inp_laddr, lport, 0));
                        lport = htons(head->inp_lport);
                } while (in_pcblookup(head,
                            zeroin_addr, 0, inp->inp_laddr, lport, 0));
+#else
+               lport = in_uniqueport(head, inp->inp_faddr.s_addr,
+                               inp->inp_laddr, inp->inp_fport);
+#endif
        inp->inp_lport = lport;
        return (0);
 }
        inp->inp_lport = lport;
        return (0);
 }
@@ -148,8 +209,13 @@ in_pcbconnect(inp, nam)
                return (EINVAL);
        if (sin->sin_family != AF_INET)
                return (EAFNOSUPPORT);
                return (EINVAL);
        if (sin->sin_family != AF_INET)
                return (EAFNOSUPPORT);
+#ifdef MULTICAST
+       if (sin->sin_port == 0 && !IN_MULTICAST(sin->sin_addr.s_addr))
+               return(EADDRNOTAVAIL);
+#else
        if (sin->sin_port == 0)
                return (EADDRNOTAVAIL);
        if (sin->sin_port == 0)
                return (EADDRNOTAVAIL);
+#endif
        if (in_ifaddr) {
                /*
                 * If the destination address is INADDR_ANY,
        if (in_ifaddr) {
                /*
                 * If the destination address is INADDR_ANY,
@@ -217,6 +283,28 @@ in_pcbconnect(inp, nam)
                        if (ia == 0)
                                return (EADDRNOTAVAIL);
                }
                        if (ia == 0)
                                return (EADDRNOTAVAIL);
                }
+#ifdef MULTICAST
+               /*
+                * If the destination address is multicast and an outgoing
+                * interface has been set as a multicast option, use the
+                * address of that interface as our source address.
+                */
+               if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
+                   inp->inp_moptions != NULL) {
+                       struct ip_moptions *imo;
+                       struct ifnet *ifp;
+                       
+                       imo = inp->inp_moptions;
+                       if (imo->imo_multicast_ifp != NULL) {
+                               ifp = imo->imo_multicast_ifp;
+                               for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                                       if (ia->ia_ifp == ifp)
+                                               break;
+                               if (ia == 0)
+                                       return (EADDRNOTAVAIL);
+                       }
+               }
+#endif
                ifaddr = (struct sockaddr_in *)&ia->ia_addr;
        }
        if (in_pcblookup(inp->inp_head,
                ifaddr = (struct sockaddr_in *)&ia->ia_addr;
        }
        if (in_pcblookup(inp->inp_head,
@@ -269,6 +357,9 @@ in_pcbdetach(inp)
                (void)m_free(inp->inp_options);
        if (inp->inp_route.ro_rt)
                rtfree(inp->inp_route.ro_rt);
                (void)m_free(inp->inp_options);
        if (inp->inp_route.ro_rt)
                rtfree(inp->inp_route.ro_rt);
+#ifdef MULTICAST
+       ip_freemoptions(inp->inp_moptions);
+#endif
        remque(inp);
        (void) m_free(dtom(inp));
 }
        remque(inp);
        (void) m_free(dtom(inp));
 }
index 826ce4c..cdde8da 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ *     Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)in_pcb.h      7.6 (Berkeley) 6/28/90
  * SUCH DAMAGE.
  *
  *     from: @(#)in_pcb.h      7.6 (Berkeley) 6/28/90
- *     $Id: in_pcb.h,v 1.4 1993/11/18 00:08:16 wollman Exp $
+ *     $Id: in_pcb.h,v 1.5 1993/11/25 01:35:06 wollman Exp $
  */
 
 #ifndef _NETINET_IN_PCB_H_
  */
 
 #ifndef _NETINET_IN_PCB_H_
@@ -67,6 +67,7 @@ struct inpcb {
                                /* function to call when MTU may have
                                 * changed */
 #endif /* MTUDISC */
                                /* function to call when MTU may have
                                 * changed */
 #endif /* MTUDISC */
+       struct  ip_moptions *inp_moptions; /* IP multicast options */
 };
 
 /* flags in inp_flags: */
 };
 
 /* flags in inp_flags: */
index 296b4ae..1f0eac8 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)in_proto.c    7.5 (Berkeley) 6/28/90
  * SUCH DAMAGE.
  *
  *     from: @(#)in_proto.c    7.5 (Berkeley) 6/28/90
- *     $Id: in_proto.c,v 1.2 1993/10/16 18:26:04 rgrimes Exp $
+ *     $Id: in_proto.c,v 1.3 1993/12/19 00:52:38 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -55,6 +55,9 @@
 #include "udp.h"
 #include "udp_var.h"           /* UDP prototypes */
 
 #include "udp.h"
 #include "udp_var.h"           /* UDP prototypes */
 
+#include "igmp.h"
+#include "igmp_var.h"          /* IGMP prototypes */
+
 #include "tcp.h"
 #include "tcp_fsm.h"
 #include "tcp_seq.h"
 #include "tcp.h"
 #include "tcp_fsm.h"
 #include "tcp_seq.h"
@@ -160,6 +163,13 @@ struct in_protosw inetsw[] = {
   eonprotoinit,        0,              0,              0,
 },
 #endif
   eonprotoinit,        0,              0,              0,
 },
 #endif
+#ifdef MULTICAST
+{ SOCK_RAW,    &inetdomain,    IPPROTO_IGMP,   PR_ATOMIC|PR_ADDR,
+  igmp_input,  rip_output,     0,              rip_ctloutput,
+  rip_usrreq,
+  igmp_init,   igmp_fasttimo,  0,              0,
+},
+#endif
 #ifdef NSIP
 { SOCK_RAW,    &inetdomain,    IPPROTO_IDP,    PR_ATOMIC|PR_ADDR,
   idpip_input, rip_output,     nsip_ctlinput,  0,
 #ifdef NSIP
 { SOCK_RAW,    &inetdomain,    IPPROTO_IDP,    PR_ATOMIC|PR_ADDR,
   idpip_input, rip_output,     nsip_ctlinput,  0,
index fae077b..0fde2ae 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)in_var.h      7.6 (Berkeley) 6/28/90
  * SUCH DAMAGE.
  *
  *     from: @(#)in_var.h      7.6 (Berkeley) 6/28/90
- *     $Id: in_var.h,v 1.5 1993/12/19 00:52:40 wollman Exp $
+ *     $Id: in_var.h,v 1.6 1993/12/19 21:43:26 wollman Exp $
  */
 
 #ifndef _NETINET_IN_VAR_H_
  */
 
 #ifndef _NETINET_IN_VAR_H_
@@ -58,6 +58,7 @@ struct in_ifaddr {
        struct  sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
 #define        ia_broadaddr    ia_dstaddr
        struct  sockaddr_in ia_sockmask; /* reserve space for general netmask */
        struct  sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
 #define        ia_broadaddr    ia_dstaddr
        struct  sockaddr_in ia_sockmask; /* reserve space for general netmask */
+       struct  in_multi *ia_multiaddrs; /* list of multicast addresses */
 };
 
 struct in_aliasreq {
 };
 
 struct in_aliasreq {
@@ -144,5 +145,119 @@ extern int        in_routemtu(struct route *);
 extern void    in_mtureduce(struct in_addr, unsigned);
 extern void    in_mtutimer(caddr_t, int);
 #endif /* MTUDISC */
 extern void    in_mtureduce(struct in_addr, unsigned);
 extern void    in_mtutimer(caddr_t, int);
 #endif /* MTUDISC */
+
+/*
+ * Macro for finding the interface (ifnet structure) corresponding to one
+ * of our IP addresses.
+ */
+#define INADDR_TO_IFP(addr, ifp) \
+       /* struct in_addr addr; */ \
+       /* struct ifnet *ifp; */ \
+{ \
+       register struct in_ifaddr *ia; \
+\
+       for (ia = in_ifaddr; \
+           ia != NULL && IA_SIN(ia)->sin_addr.s_addr != (addr).s_addr; \
+           ia = ia->ia_next) \
+                continue; \
+       (ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \
+}
+
+/*
+ * Macro for finding the internet address structure (in_ifaddr) corresponding
+ * to a given interface (ifnet structure).
+ */
+#define IFP_TO_IA(ifp, ia) \
+       /* struct ifnet *ifp; */ \
+       /* struct in_ifaddr *ia; */ \
+{ \
+       for ((ia) = in_ifaddr; \
+           (ia) != NULL && (ia)->ia_ifp != (ifp); \
+           (ia) = (ia)->ia_next) \
+               continue; \
+}
+#endif
+
+/*
+ * Internet multicast address structure.  There is one of these for each IP
+ * multicast group to which this host belongs on a given network interface.
+ * They are kept in a linked list, rooted in the interface's in_ifaddr
+ * structure.
+ */
+struct in_multi {
+       struct  in_addr inm_addr;       /* IP multicast address */
+       struct  ifnet *inm_ifp;         /* back pointer to ifnet */
+       struct  in_ifaddr *inm_ia;      /* back pointer to in_ifaddr */
+       u_int   inm_refcount;           /* no. membership claims by sockets */
+       u_int   inm_timer;              /* IGMP membership report timer */
+       struct  in_multi *inm_next;     /* ptr to next multicast address */
+};
+
+#ifdef KERNEL
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the in_multi records.
+ */
+struct in_multistep {
+       struct in_ifaddr *i_ia;
+       struct in_multi *i_inm;
+};
+
+/*
+ * Macro for looking up the in_multi record for a given IP multicast address
+ * on a given interface.  If no matching record is found, "inm" returns NULL.
+ */
+#define IN_LOOKUP_MULTI(addr, ifp, inm) \
+       /* struct in_addr addr; */ \
+       /* struct ifnet *ifp; */ \
+       /* struct in_multi *inm; */ \
+{ \
+       register struct in_ifaddr *ia; \
+\
+       IFP_TO_IA((ifp), ia); \
+       if (ia == NULL) \
+               (inm) = NULL; \
+       else \
+               for ((inm) = ia->ia_multiaddrs; \
+                   (inm) != NULL && (inm)->inm_addr.s_addr != (addr).s_addr; \
+                    (inm) = inm->inm_next) \
+                        continue; \
+}
+
+/*
+ * Macro to step through all of the in_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide.  IN_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record.  Both macros return a NULL "inm" when there
+ * are no remaining records.
+ */
+#define IN_NEXT_MULTI(step, inm) \
+       /* struct in_multistep  step; */ \
+       /* struct in_multi *inm; */ \
+{ \
+       if (((inm) = (step).i_inm) != NULL) \
+               (step).i_inm = (inm)->inm_next; \
+       else \
+               while ((step).i_ia != NULL) { \
+                       (inm) = (step).i_ia->ia_multiaddrs; \
+                       (step).i_ia = (step).i_ia->ia_next; \
+                       if ((inm) != NULL) { \
+                               (step).i_inm = (inm)->inm_next; \
+                               break; \
+                       } \
+               } \
+}
+
+#define IN_FIRST_MULTI(step, inm) \
+       /* struct in_multistep step; */ \
+       /* struct in_multi *inm; */ \
+{ \
+       (step).i_ia = in_ifaddr; \
+       (step).i_inm = NULL; \
+       IN_NEXT_MULTI((step), (inm)); \
+}
+
+struct in_multi *in_addmulti __P((struct in_addr *, struct ifnet *));
+int    in_delmulti __P((struct in_multi *));
 #endif /* KERNEL */
 #endif /* _NETINET_IN_VAR_H_ */
 #endif /* KERNEL */
 #endif /* _NETINET_IN_VAR_H_ */
index 496fb92..1085bb7 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_icmp.c     7.15 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_icmp.c     7.15 (Berkeley) 4/20/91
- *     $Id: ip_icmp.c,v 1.5 1993/11/25 01:35:07 wollman Exp $
+ *     $Id: ip_icmp.c,v 1.6 1993/12/19 00:52:42 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -156,6 +156,11 @@ icmp_error(n, type, code, dest, mtu)
                icmpstat.icps_oldicmp++;
                goto freeit;
        }
                icmpstat.icps_oldicmp++;
                goto freeit;
        }
+#ifdef MULTICAST
+       /* Don't send error in response to a multicast or broadcast packet */
+       if(n->m_flags & (M_MCAST | M_BCAST))
+               goto freeit;
+#endif
 
        /*
         * First, formulate icmp message
 
        /*
         * First, formulate icmp message
index 7535e34..8d4765d 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *     Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_input.c    7.19 (Berkeley) 5/25/91
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_input.c    7.19 (Berkeley) 5/25/91
- *     $Id: ip_input.c,v 1.7 1993/12/19 00:52:43 wollman Exp $
+ *     $Id: ip_input.c,v 1.8 1994/01/04 17:47:13 ache Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -240,6 +240,53 @@ next:
                                goto ours;
                }
        }
                                goto ours;
                }
        }
+#ifdef MULTICAST
+       if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+               struct in_multi *inm;
+#ifdef MROUTING
+               extern struct socket *ip_mrouter;
+
+               if (ip_mrouter) {
+                       /*
+                        * If we are acting as a multicast router, all
+                        * incoming multicast packets are passed to the
+                        * kernel-level multicast forwarding function.
+                        * The packet is returned (relatively) intact; if
+                        * ip_mforward() returns a non-zero value, the packet
+                        * must be discarded, else it may be accepted below.
+                        *
+                        * (The IP ident field is put in the same byte order
+                        * as expected when ip_mforward() is called from
+                        * ip_output().)
+                        */
+                       ip->ip_id = htons(ip->ip_id);
+                       if (ip_mforward(ip, m->m_pkthdr.rcvif, m) != 0) {
+                               m_freem(m);
+                               goto next;
+                       }
+                       ip->ip_id = ntohs(ip->ip_id);
+
+                       /*
+                        * The process-level routing demon needs to receive
+                        * all multicast IGMP packets, whether or not this
+                        * host belongs to their destination groups.
+                        */
+                       if (ip->ip_p == IPPROTO_IGMP)
+                               goto ours;
+               }
+#endif
+               /*
+                * See if we belong to the destination multicast group on the
+                * arrival interface.
+                */
+               IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
+               if (inm == NULL) {
+                       m_freem(m);
+                       goto next;
+               }
+               goto ours;
+       }
+#endif
        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
                goto ours;
        if (ip->ip_dst.s_addr == INADDR_ANY)
        if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
                goto ours;
        if (ip->ip_dst.s_addr == INADDR_ANY)
index 7e77bff..ef08029 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ *     Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_output.c   7.23 (Berkeley) 11/12/90
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_output.c   7.23 (Berkeley) 11/12/90
- *     $Id: ip_output.c,v 1.4 1993/11/25 01:35:09 wollman Exp $
+ *     $Id: ip_output.c,v 1.5 1993/12/19 00:52:45 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -58,6 +58,7 @@
 #endif
 
 struct mbuf *ip_insertoptions();
 #endif
 
 struct mbuf *ip_insertoptions();
+void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
 
 /*
  * IP output.  The packet in mbuf chain m contains a skeletal IP
 
 /*
  * IP output.  The packet in mbuf chain m contains a skeletal IP
@@ -66,11 +67,18 @@ struct mbuf *ip_insertoptions();
  * The mbuf opt, if present, will not be freed.
  */
 int
  * The mbuf opt, if present, will not be freed.
  */
 int
-ip_output(m0, opt, ro, flags)
+ip_output(m0, opt, ro, flags
+#ifdef MULTICAST
+       , imo
+#endif
+               )
        struct mbuf *m0;
        struct mbuf *opt;
        struct route *ro;
        int flags;
        struct mbuf *m0;
        struct mbuf *opt;
        struct route *ro;
        int flags;
+#ifdef MULTICAST
+       struct ip_moptions *imo;
+#endif
 {
        register struct ip *ip, *mhip;
        register struct ifnet *ifp;
 {
        register struct ip *ip, *mhip;
        register struct ifnet *ifp;
@@ -152,6 +160,97 @@ ip_output(m0, opt, ro, flags)
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
        }
                if (ro->ro_rt->rt_flags & RTF_GATEWAY)
                        dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
        }
+#ifdef MULTICAST
+       if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+               struct in_multi *inm;
+               extern struct ifnet loif;
+               extern struct socket *ip_mrouter;
+
+               m->m_flags |= M_MCAST;
+               /*
+                * IP destination address is multicast.  Make sure "dst"
+                * still points to the address in "ro".  (It may have been
+                * changed to point to a gateway address, above.)
+                */
+               dst = (struct sockaddr_in *)&ro->ro_dst;
+               /*
+                * See if the caller provided any multicast options
+                */
+               if ((flags & IP_MULTICASTOPTS) && imo != NULL) {
+                       ip->ip_ttl = imo->imo_multicast_ttl;
+                       if (imo->imo_multicast_ifp != NULL)
+                               ifp = imo->imo_multicast_ifp;
+               } else {
+                       imo = NULL;
+                       ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
+               }
+               /*
+                * Confirm that the outgoing interface supports multicast.
+                */
+               if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+                       error = ENETUNREACH;
+                       goto bad;
+               }
+               /*
+                * If source address not specified yet, use address
+                * of outgoing interface.
+                */
+               if (ip->ip_src.s_addr == INADDR_ANY) {
+                       register struct in_ifaddr *ia;
+
+                       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                               if (ia->ia_ifp == ifp) {
+                                       ip->ip_src = IA_SIN(ia)->sin_addr;
+                                       break;
+                               }
+               }
+
+               IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
+               if (inm != NULL &&
+                  (imo == NULL || imo->imo_multicast_loop)) {
+                       /*
+                        * If we belong to the destination multicast group
+                        * on the outgoing interface, and the caller did not
+                        * forbid loopback, loop back a copy.
+                        */
+                       ip_mloopback(ifp, m, dst);
+               }
+#ifdef MROUTING
+               else if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
+                       /*
+                        * If we are acting as a multicast router, perform
+                        * multicast forwarding as if the packet had just
+                        * arrived on the interface to which we are about
+                        * to send.  The multicast forwarding function
+                        * recursively calls this function, using the
+                        * IP_FORWARDING flag to prevent infinite recursion.
+                        *
+                        * Multicasts that are looped back by ip_mloopback(),
+                        * above, will be forwarded by the ip_input() routine,
+                        * if necessary.
+                        */
+                       if (ip_mforward(ip, ifp, m) != 0) {
+                               m_freem(m);
+                               goto done;
+                       }
+               }
+#endif
+               /*
+                * Multicasts with a time-to-live of zero may be looped-
+                * back, above, but must not be transmitted on a network.
+                * Also, multicasts addressed to the loopback interface
+                * are not sent -- the above call to ip_mloopback() will
+                * loop back a copy if this host actually belongs to the
+                * destination group on the loopback interface.
+                */
+               if (ip->ip_ttl == 0 || ifp == &loif) {
+                       m_freem(m);
+                       goto done;
+               }
+
+               goto sendit;
+       }
+#endif
 #ifndef notdef
        /*
         * If source address not specified yet, use address
 #ifndef notdef
        /*
         * If source address not specified yet, use address
@@ -192,7 +291,9 @@ ip_output(m0, opt, ro, flags)
                }
                m->m_flags |= M_BCAST;
        }
                }
                m->m_flags |= M_BCAST;
        }
-
+#ifdef MULTICAST
+sendit:
+#endif
        /*
         * If small enough for interface, can just send directly.
         */
        /*
         * If small enough for interface, can just send directly.
         */
@@ -446,7 +547,15 @@ ip_ctloutput(op, so, level, optname, mp)
                        }
                        break;
 #undef OPTSET
                        }
                        break;
 #undef OPTSET
-
+#ifdef MULTICAST
+               case IP_MULTICAST_IF:
+               case IP_MULTICAST_TTL:
+               case IP_MULTICAST_LOOP:
+               case IP_ADD_MEMBERSHIP:
+               case IP_DROP_MEMBERSHIP:
+                       error = ip_setmoptions(optname, &inp->inp_moptions, m);
+                       break;
+#endif
                default:
                        error = EINVAL;
                        break;
                default:
                        error = EINVAL;
                        break;
@@ -501,7 +610,15 @@ ip_ctloutput(op, so, level, optname, mp)
                        }
                        *mtod(m, int *) = optval;
                        break;
                        }
                        *mtod(m, int *) = optval;
                        break;
-
+#ifdef MULTICAST
+               case IP_MULTICAST_IF:
+               case IP_MULTICAST_TTL:
+               case IP_MULTICAST_LOOP:
+               case IP_ADD_MEMBERSHIP:
+               case IP_DROP_MEMBERSHIP:
+                       error = ip_getmoptions(optname, inp->inp_moptions, mp);
+                       break;
+#endif
                default:
                        error = EINVAL;
                        break;
                default:
                        error = EINVAL;
                        break;
@@ -617,3 +734,339 @@ bad:
        (void)m_free(m);
        return (EINVAL);
 }
        (void)m_free(m);
        return (EINVAL);
 }
+
+#ifdef MULTICAST
+/*
+ * Set the IP multicast options in response to user setsockopt().
+ */
+int
+ip_setmoptions(optname, imop, m)
+       int optname;
+       struct ip_moptions **imop;
+       struct mbuf *m;
+{
+       register int error = 0;
+       u_char loop;
+       register int i;
+       struct in_addr addr;
+       register struct ip_mreq *mreq;
+       register struct ifnet *ifp;
+       register struct ip_moptions *imo = *imop;
+       struct route ro;
+       register struct sockaddr_in *dst;
+
+       if (imo == NULL) {
+               /*
+                * No multicast option buffer attached to the pcb;
+                * allocate one and initialize to default values.
+                */
+               imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
+                   M_WAITOK);
+
+               if (imo == NULL)
+                       return (ENOBUFS);
+               *imop = imo;
+               imo->imo_multicast_ifp = NULL;
+               imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
+               imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
+               imo->imo_num_memberships = 0;
+       }
+
+       switch (optname) {
+
+       case IP_MULTICAST_IF:
+               /*
+                * Select the interface for outgoing multicast packets.
+                */
+               if (m == NULL || m->m_len != sizeof(struct in_addr)) {
+                       error = EINVAL;
+                       break;
+               }
+               addr = *(mtod(m, struct in_addr *));
+               /*
+                * INADDR_ANY is used to remove a previous selection.
+                * When no interface is selected, a default one is
+                * chosen every time a multicast packet is sent.
+                */
+               if (addr.s_addr == INADDR_ANY) {
+                       imo->imo_multicast_ifp = NULL;
+                       break;
+               }
+               /*
+                * The selected interface is identified by its local
+                * IP address.  Find the interface and confirm that
+                * it supports multicasting.
+                */
+               INADDR_TO_IFP(addr, ifp);
+               if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+                       error = EADDRNOTAVAIL;
+                       break;
+               }
+               imo->imo_multicast_ifp = ifp;
+               break;
+
+       case IP_MULTICAST_TTL:
+               /*
+                * Set the IP time-to-live for outgoing multicast packets.
+                */
+               if (m == NULL || m->m_len != 1) {
+                       error = EINVAL;
+                       break;
+               }
+               imo->imo_multicast_ttl = *(mtod(m, u_char *));
+               break;
+
+       case IP_MULTICAST_LOOP:
+               /*
+                * Set the loopback flag for outgoing multicast packets.
+                * Must be zero or one.
+                */
+               if (m == NULL || m->m_len != 1 ||
+                  (loop = *(mtod(m, u_char *))) > 1) {
+                       error = EINVAL;
+                       break;
+               }
+               imo->imo_multicast_loop = loop;
+               break;
+
+       case IP_ADD_MEMBERSHIP:
+               /*
+                * Add a multicast group membership.
+                * Group must be a valid IP multicast address.
+                */
+               if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
+                       error = EINVAL;
+                       break;
+               }
+               mreq = mtod(m, struct ip_mreq *);
+               if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
+                       error = EINVAL;
+                       break;
+               }
+               /*
+                * If no interface address was provided, use the interface of
+                * the route to the given multicast address.
+                */
+               if (mreq->imr_interface.s_addr == INADDR_ANY) {
+                       ro.ro_rt = NULL;
+                       dst = (struct sockaddr_in *)&ro.ro_dst;
+                       dst->sin_len = sizeof(*dst);
+                       dst->sin_family = AF_INET;
+                       dst->sin_addr = mreq->imr_multiaddr;
+                       rtalloc(&ro);
+                       if (ro.ro_rt == NULL) {
+                               error = EADDRNOTAVAIL;
+                               break;
+                       }
+                       ifp = ro.ro_rt->rt_ifp;
+                       rtfree(ro.ro_rt);
+               }
+               else {
+                       INADDR_TO_IFP(mreq->imr_interface, ifp);
+               }
+               /*
+                * See if we found an interface, and confirm that it
+                * supports multicast.
+                */
+               if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+                       error = EADDRNOTAVAIL;
+                       break;
+               }
+               /*
+                * See if the membership already exists or if all the
+                * membership slots are full.
+                */
+               for (i = 0; i < imo->imo_num_memberships; ++i) {
+                       if (imo->imo_membership[i]->inm_ifp == ifp &&
+                           imo->imo_membership[i]->inm_addr.s_addr
+                                               == mreq->imr_multiaddr.s_addr)
+                               break;
+               }
+               if (i < imo->imo_num_memberships) {
+                       error = EADDRINUSE;
+                       break;
+               }
+               if (i == IP_MAX_MEMBERSHIPS) {
+                       error = ETOOMANYREFS;
+                       break;
+               }
+               /*
+                * Everything looks good; add a new record to the multicast
+                * address list for the given interface.
+                */
+               if ((imo->imo_membership[i] =
+                   in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
+                       error = ENOBUFS;
+                       break;
+               }
+               ++imo->imo_num_memberships;
+               break;
+
+       case IP_DROP_MEMBERSHIP:
+               /*
+                * Drop a multicast group membership.
+                * Group must be a valid IP multicast address.
+                */
+               if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
+                       error = EINVAL;
+                       break;
+               }
+               mreq = mtod(m, struct ip_mreq *);
+               if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
+                       error = EINVAL;
+                       break;
+               }
+               /*
+                * If an interface address was specified, get a pointer
+                * to its ifnet structure.
+                */
+               if (mreq->imr_interface.s_addr == INADDR_ANY)
+                       ifp = NULL;
+               else {
+                       INADDR_TO_IFP(mreq->imr_interface, ifp);
+                       if (ifp == NULL) {
+                               error = EADDRNOTAVAIL;
+                               break;
+                       }
+               }
+               /*
+                * Find the membership in the membership array.
+                */
+               for (i = 0; i < imo->imo_num_memberships; ++i) {
+                       if ((ifp == NULL ||
+                            imo->imo_membership[i]->inm_ifp == ifp) &&
+                            imo->imo_membership[i]->inm_addr.s_addr ==
+                            mreq->imr_multiaddr.s_addr)
+                               break;
+               }
+               if (i == imo->imo_num_memberships) {
+                       error = EADDRNOTAVAIL;
+                       break;
+               }
+               /*
+                * Give up the multicast address record to which the
+                * membership points.
+                */
+               in_delmulti(imo->imo_membership[i]);
+               /*
+                * Remove the gap in the membership array.
+                */
+               for (++i; i < imo->imo_num_memberships; ++i)
+                       imo->imo_membership[i-1] = imo->imo_membership[i];
+               --imo->imo_num_memberships;
+               break;
+
+       default:
+               error = EOPNOTSUPP;
+               break;
+       }
+
+       /*
+        * If all options have default values, no need to keep the mbuf.
+        */
+       if (imo->imo_multicast_ifp == NULL &&
+           imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
+           imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
+           imo->imo_num_memberships == 0) {
+               free(*imop, M_IPMOPTS);
+               *imop = NULL;
+       }
+
+       return (error);
+}
+
+/*
+ * Return the IP multicast options in response to user getsockopt().
+ */
+int
+ip_getmoptions(optname, imo, mp)
+       int optname;
+       register struct ip_moptions *imo;
+       register struct mbuf **mp;
+{
+       u_char *ttl;
+       u_char *loop;
+       struct in_addr *addr;
+       struct in_ifaddr *ia;
+
+       *mp = m_get(M_WAIT, MT_SOOPTS);
+
+       switch (optname) {
+
+       case IP_MULTICAST_IF:
+               addr = mtod(*mp, struct in_addr *);
+               (*mp)->m_len = sizeof(struct in_addr);
+               if (imo == NULL || imo->imo_multicast_ifp == NULL)
+                       addr->s_addr = INADDR_ANY;
+               else {
+                       IFP_TO_IA(imo->imo_multicast_ifp, ia);
+                       addr->s_addr = (ia == NULL) ? INADDR_ANY
+                                       : IA_SIN(ia)->sin_addr.s_addr;
+               }
+               return (0);
+
+       case IP_MULTICAST_TTL:
+               ttl = mtod(*mp, u_char *);
+               (*mp)->m_len = 1;
+               *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
+                                    : imo->imo_multicast_ttl;
+               return (0);
+
+       case IP_MULTICAST_LOOP:
+               loop = mtod(*mp, u_char *);
+               (*mp)->m_len = 1;
+               *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
+                                     : imo->imo_multicast_loop;
+               return (0);
+
+       default:
+               return (EOPNOTSUPP);
+       }
+}
+
+/*
+ * Discard the IP multicast options.
+ */
+void
+ip_freemoptions(imo)
+       register struct ip_moptions *imo;
+{
+       register int i;
+
+       if (imo != NULL) {
+               for (i = 0; i < imo->imo_num_memberships; ++i)
+                       in_delmulti(imo->imo_membership[i]);
+               free(imo, M_IPMOPTS);
+       }
+}
+
+/*
+ * Routine called from ip_output() to loop back a copy of an IP multicast
+ * packet to the input queue of a specified interface.  Note that this
+ * calls the output routine of the loopback "driver", but with an interface
+ * pointer that might NOT be &loif -- easier than replicating that code here.
+ */
+void
+ip_mloopback(ifp, m, dst)
+       struct ifnet *ifp;
+       register struct mbuf *m;
+       register struct sockaddr_in *dst;
+{
+       register struct ip *ip;
+       struct mbuf *copym;
+
+       copym = m_copy(m, 0, M_COPYALL);
+       if (copym != NULL) {
+               /*
+                * We don't bother to fragment if the IP length is greater
+                * than the interface's MTU.  Can this possibly matter?
+                */
+               ip = mtod(copym, struct ip *);
+               ip->ip_len = htons((u_short)ip->ip_len);
+               ip->ip_off = htons((u_short)ip->ip_off);
+               ip->ip_sum = 0;
+               ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
+               (void) looutput(ifp, copym, (struct sockaddr *)dst, 0);
+       }
+}
+#endif
index 1fccdb3..e58c48c 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1993 Regents of the University of California.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_var.h      7.7 (Berkeley) 6/28/90
  * SUCH DAMAGE.
  *
  *     from: @(#)ip_var.h      7.7 (Berkeley) 6/28/90
- *     $Id: ip_var.h,v 1.2 1993/10/16 18:26:17 rgrimes Exp $
+ *     $Id: ip_var.h,v 1.3 1993/11/07 17:48:00 wollman Exp $
  */
 
 #ifndef _NETINET_IP_VAR_H_
  */
 
 #ifndef _NETINET_IP_VAR_H_
@@ -103,6 +103,18 @@ struct ipoption {
        char    ipopt_list[MAX_IPOPTLEN];       /* options proper */
 };
 
        char    ipopt_list[MAX_IPOPTLEN];       /* options proper */
 };
 
+/*
+ * Structure attached to inpcb.ip_moptions and
+ * passed to ip_output when IP multicast options are in use.
+ */
+struct ip_moptions {
+       struct  ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */
+       u_char  imo_multicast_ttl;      /* TTL for outgoing multicasts */
+       u_char  imo_multicast_loop;     /* 1 => hear sends if a member */
+       u_short imo_num_memberships;    /* no. memberships this socket */
+       struct  in_multi *imo_membership[IP_MAX_MEMBERSHIPS];
+};
+
 struct ipstat {
        long    ips_total;              /* total packets received */
        long    ips_badsum;             /* checksum bad */
 struct ipstat {
        long    ips_total;              /* total packets received */
        long    ips_badsum;             /* checksum bad */
@@ -129,6 +141,7 @@ struct      ipstat {
 #ifdef KERNEL
 /* flags passed to ip_output as last parameter */
 #define        IP_FORWARDING           0x1             /* most of ip header exists */
 #ifdef KERNEL
 /* flags passed to ip_output as last parameter */
 #define        IP_FORWARDING           0x1             /* most of ip header exists */
+#define IP_MULTICASTOPTS       0x2             /* multicast opts present */
 #define        IP_ROUTETOIF            SO_DONTROUTE    /* bypass routing tables */
 #define        IP_ALLOWBROADCAST       SO_BROADCAST    /* can send broadcast packets */
 
 #define        IP_ROUTETOIF            SO_DONTROUTE    /* bypass routing tables */
 #define        IP_ALLOWBROADCAST       SO_BROADCAST    /* can send broadcast packets */
 
index a6a10e9..3bb4dfe 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *     Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)raw_ip.c      7.8 (Berkeley) 7/25/90
  * SUCH DAMAGE.
  *
  *     from: @(#)raw_ip.c      7.8 (Berkeley) 7/25/90
- *     $Id: raw_ip.c,v 1.3 1993/11/25 01:35:11 wollman Exp $
+ *     $Id: raw_ip.c,v 1.4 1993/12/19 00:52:46 wollman Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -118,7 +118,11 @@ rip_output(m, so)
        return (ip_output(m,
           (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
            &rp->rinp_route, 
        return (ip_output(m,
           (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
            &rp->rinp_route, 
-          (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+          (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST
+#ifdef MULTICAST
+         | IP_MULTICASTOPTS, rp->rinp_rcb.rcb_moptions
+#endif
+       ));
 }
 
 /*
 }
 
 /*
@@ -154,10 +158,27 @@ rip_ctloutput(op, so, level, optname, m)
                        else
                                rp->rinp_flags &= ~RINPF_HDRINCL;
                        break;
                        else
                                rp->rinp_flags &= ~RINPF_HDRINCL;
                        break;
-
+#ifdef MULTICAST
+               case IP_MULTICAST_IF:
+               case IP_MULTICAST_TTL:
+               case IP_MULTICAST_LOOP:
+               case IP_ADD_MEMBERSHIP:
+               case IP_DROP_MEMBERSHIP:
+                       error = ip_setmoptions(optname,
+                                              &rp->rinp_rcb.rcb_moptions, *m);
+                       break;
+               default:
+#ifdef MROUTING
+                       error = ip_mrouter_cmd(optname, so, *m);
+#else
+                       error = EINVAL;
+#endif
+                       break;
+#else
                default:
                        error = EINVAL;
                        break;
                default:
                        error = EINVAL;
                        break;
+#endif
                }
                break;
 
                }
                break;
 
@@ -178,7 +199,16 @@ rip_ctloutput(op, so, level, optname, m)
                        (*m)->m_len = sizeof (int);
                        *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
                        break;
                        (*m)->m_len = sizeof (int);
                        *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
                        break;
-
+#ifdef MULTICAST
+               case IP_MULTICAST_IF:
+               case IP_MULTICAST_TTL:
+               case IP_MULTICAST_LOOP:
+               case IP_ADD_MEMBERSHIP:
+               case IP_DROP_MEMBERSHIP:
+                       error = ip_getmoptions(optname, 
+                                              rp->rinp_rcb.rcb_moptions, m);
+                       break;
+#endif
                default:
                        error = EINVAL;
                        m_freem(*m);
                default:
                        error = EINVAL;
                        m_freem(*m);
@@ -201,7 +231,9 @@ rip_usrreq(so, req, m, nam, control)
 {
        register int error = 0;
        register struct raw_inpcb *rp = sotorawinpcb(so);
 {
        register int error = 0;
        register struct raw_inpcb *rp = sotorawinpcb(so);
-
+#if defined(MULTICAST) && defined(MROUTING)
+       extern struct socket *ip_mrouter;
+#endif
        switch (req) {
 
        case PRU_ATTACH:
        switch (req) {
 
        case PRU_ATTACH:
@@ -217,8 +249,16 @@ rip_usrreq(so, req, m, nam, control)
        case PRU_DETACH:
                if (rp == 0)
                        panic("rip_detach");
        case PRU_DETACH:
                if (rp == 0)
                        panic("rip_detach");
+#if defined(MULTICAST) && defined(MROUTING)
+               if (so == ip_mrouter)
+                       ip_mrouter_done();
+#endif
                if (rp->rinp_options)
                        m_freem(rp->rinp_options);
                if (rp->rinp_options)
                        m_freem(rp->rinp_options);
+#ifdef MULTICAST
+               if (rp->rinp_rcb.rcb_moptions)
+                       ip_freemoptions(rp->rinp_rcb.rcb_moptions);
+#endif
                if (rp->rinp_route.ro_rt)
                        RTFREE(rp->rinp_route.ro_rt);
                if (rp->rinp_rcb.rcb_laddr)
                if (rp->rinp_route.ro_rt)
                        RTFREE(rp->rinp_route.ro_rt);
                if (rp->rinp_rcb.rcb_laddr)
index 3c5c17a..1447952 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ *     Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)udp_usrreq.c  7.20 (Berkeley) 4/20/91
  * SUCH DAMAGE.
  *
  *     from: @(#)udp_usrreq.c  7.20 (Berkeley) 4/20/91
- *     $Id: udp_usrreq.c,v 1.6 1993/12/19 00:52:55 wollman Exp $
+ *     $Id: udp_usrreq.c,v 1.7 1994/02/07 19:53:25 ache Exp $
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -145,6 +145,93 @@ udp_input(m, iphlen)
                        return;
                }
        }
                        return;
                }
        }
+#ifdef MULTICAST
+       if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
+           in_broadcast(ip->ip_dst)) {
+               struct socket *last;
+               /*
+                * Deliver a multicast or broadcast datagram to *all* sockets
+                * for which the local and remote addresses and ports match
+                * those of the incoming datagram.  This allows more than
+                * one process to receive multi/broadcasts on the same port.
+                * (This really ought to be done for unicast datagrams as
+                * well, but that would cause problems with existing
+                * applications that open both address-specific sockets and
+                * a wildcard socket listening to the same port -- they would
+                * end up receiving duplicates of every unicast datagram.
+                * Those applications open the multiple sockets to overcome an
+                * inadequacy of the UDP socket interface, but for backwards
+                * compatibility we avoid the problem here rather than
+                * fixing the interface.  Maybe 4.4BSD will remedy this?)
+                */
+  
+               /*
+                * Construct sockaddr format source address.
+                */
+               udp_in.sin_port = uh->uh_sport;
+               udp_in.sin_addr = ip->ip_src;
+               m->m_len -= sizeof (struct udpiphdr);
+               m->m_data += sizeof (struct udpiphdr);
+               /*
+                * Locate pcb(s) for datagram.
+                * (Algorithm copied from raw_intr().)
+                */
+               last = NULL;
+               for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) {
+                       if (inp->inp_lport != uh->uh_dport)
+                               continue;
+                       if (inp->inp_laddr.s_addr != INADDR_ANY) {
+                               if (inp->inp_laddr.s_addr !=
+                                   ip->ip_dst.s_addr)
+                                       continue;
+                       }
+                       if (inp->inp_faddr.s_addr != INADDR_ANY) {
+                               if (inp->inp_faddr.s_addr !=
+                                   ip->ip_src.s_addr ||
+                                   inp->inp_fport != uh->uh_sport)
+                                       continue;
+                       }
+
+                       if (last != NULL) {
+                               struct mbuf *n;
+
+                               if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
+                                       if (sbappendaddr(&last->so_rcv,
+                                               (struct sockaddr *)&udp_in,
+                                               n, (struct mbuf *)0) == 0)
+                                               m_freem(n);
+                                       else
+                                               sorwakeup(last);
+                               }
+                       }
+                       last = inp->inp_socket;
+                       /*
+                        * Don't look for additional matches if this one
+                        * does not have the SO_REUSEADDR socket option set.
+                        * This heuristic avoids searching through all pcbs
+                        * in the common case of a non-shared port.  It
+                        * assumes that an application will never clear
+                        * the SO_REUSEADDR option after setting it.
+                        */
+                       if ((last->so_options & SO_REUSEADDR) == 0)
+                               break;
+               }
+
+               if (last == NULL) {
+                       /*
+                        * No matching pcb found; discard datagram.
+                        * (No need to send an ICMP Port Unreachable
+                        * for a broadcast or multicast datgram.)
+                        */
+                       goto bad;
+               }
+               if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
+                    m, (struct mbuf *)0) == 0)
+                       goto bad;
+               sorwakeup(last);
+               return;
+       }
+#endif
 
        /*
         * Locate pcb for datagram.
 
        /*
         * Locate pcb for datagram.
@@ -163,10 +250,13 @@ udp_input(m, iphlen)
        if (inp == 0) {
                /* don't send ICMP response for broadcast packet */
                udpstat.udps_noport++;
        if (inp == 0) {
                /* don't send ICMP response for broadcast packet */
                udpstat.udps_noport++;
-               if (m->m_flags & M_BCAST) {
+#ifndef MULTICAST
+               /* XXX why don't we do this with MULTICAST? */
+               if (m->m_flags & (M_BCAST | M_MCAST)) {
                        udpstat.udps_noportbcast++;
                        goto bad;
                }
                        udpstat.udps_noportbcast++;
                        goto bad;
                }
+#endif
                *ip = save_ip;
                ip->ip_len += iphlen;
                {
                *ip = save_ip;
                ip->ip_len += iphlen;
                {
@@ -355,7 +445,11 @@ udp_output(inp, m, addr, control)
        ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
        udpstat.udps_opackets++;
        error = ip_output(m, inp->inp_options, &inp->inp_route,
        ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
        udpstat.udps_opackets++;
        error = ip_output(m, inp->inp_options, &inp->inp_route,
-           inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
+           inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)
+#ifdef MULTICAST
+         | IP_MULTICASTOPTS, inp->inp_moptions
+#endif
+         );
 
        if (addr) {
                in_pcbdisconnect(inp);
 
        if (addr) {
                in_pcbdisconnect(inp);
index 6faa438..6b0188e 100644 (file)
@@ -38,7 +38,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)ioctl.h       7.19 (Berkeley) 6/26/91
  * SUCH DAMAGE.
  *
  *     from: @(#)ioctl.h       7.19 (Berkeley) 6/26/91
- *     $Id: ioctl.h,v 1.7 1994/02/24 16:09:09 phk Exp $
+ *     $Id: ioctl.h,v 1.8 1994/05/04 08:30:41 rgrimes Exp $
  */
 
 #ifndef        _IOCTL_H_
  */
 
 #ifndef        _IOCTL_H_
@@ -222,6 +222,9 @@ struct ttysize {
 #define        SIOCSIFASYNCMAP _IOW('i', 125, struct ifreq)    /* set ppp asyncmap */
 #define        SIOCGIFASYNCMAP _IOWR('i',124, struct ifreq)    /* get ppp asyncmap */
 
 #define        SIOCSIFASYNCMAP _IOW('i', 125, struct ifreq)    /* set ppp asyncmap */
 #define        SIOCGIFASYNCMAP _IOWR('i',124, struct ifreq)    /* get ppp asyncmap */
 
+#define        SIOCADDMULTI    _IOW('i', 49, struct ifreq)     /* add m'cast addr */
+#define        SIOCDELMULTI    _IOW('i', 50, struct ifreq)     /* del m'cast addr */
+
 #ifndef KERNEL
 
 #include <sys/cdefs.h>
 #ifndef KERNEL
 
 #include <sys/cdefs.h>
index 6bb03f6..5d09b6a 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     from: @(#)malloc.h      7.25 (Berkeley) 5/15/91
  * SUCH DAMAGE.
  *
  *     from: @(#)malloc.h      7.25 (Berkeley) 5/15/91
- *     $Id: malloc.h,v 1.5 1994/03/02 20:29:01 guido Exp $
+ *     $Id: malloc.h,v 1.6 1994/04/13 00:50:16 ache Exp $
  */
 
 #ifndef _MALLOC_H_
  */
 
 #ifndef _MALLOC_H_
 #define        M_LOCKF         40      /* Byte-range locking structures */
 #define        M_PROC          41      /* Proc structures */
 #define        M_SUBPROC       42      /* Proc sub-structures */
 #define        M_LOCKF         40      /* Byte-range locking structures */
 #define        M_PROC          41      /* Proc structures */
 #define        M_SUBPROC       42      /* Proc sub-structures */
-#define        M_TTYS          45      /* allocated tty structures */
+#define M_IPMOPTS      43      /* Internet multicast options */
+#define        M_IPMADDR       44      /* Internet multicast address */
+#define        M_IFMADDR       45      /* link-level multicast address */
+#define        M_MRTABLE       46      /* multicast routing tables */
+#define        M_TTYS          47      /* allocated tty structures */
 #define M_ISOFSMNT      48     /* isofs mount structures */
 #define        M_TEMP          49      /* misc temporary data buffers */
 #define        M_PCFSMNT       50      /* PCFS mount structure */
 #define M_ISOFSMNT      48     /* isofs mount structures */
 #define        M_TEMP          49      /* misc temporary data buffers */
 #define        M_PCFSMNT       50      /* PCFS mount structure */
        "file desc",    /* 39 M_FILEDESC */ \
        "lockf",        /* 40 M_LOCKF */ \
        "proc",         /* 41 M_PROC */ \
        "file desc",    /* 39 M_FILEDESC */ \
        "lockf",        /* 40 M_LOCKF */ \
        "proc",         /* 41 M_PROC */ \
-       "subproc",      /* 42 M_PROC */ \
-       0, 0, \
-       "ttys",         /* 45 M_TTYS */ \
-       0, 0, \
+       "subproc",      /* 42 M_SUBPROC */ \
+       "mcast opts",   /* 43 M_IPMOPTS */ \
+       "ip mcast",     /* 44 M_IPMADDR */ \
+       "if mcast",     /* 45 M_IFMADDR */ \
+       "mcast route",  /* 46 M_MRTABLE */ \
+       "ttys",         /* 47 M_TTYS */ \
        "isofs mount",  /* 48 M_ISOFSMNT */ \
        "temp",         /* 49 M_TEMP */ \
        "PCFS mount",   /* 50 M_PCFSMNT */ \
        "isofs mount",  /* 48 M_ISOFSMNT */ \
        "temp",         /* 49 M_TEMP */ \
        "PCFS mount",   /* 50 M_PCFSMNT */ \