multicast changes from lbl
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Tue, 7 Jul 1992 06:08:33 +0000 (22:08 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Tue, 7 Jul 1992 06:08:33 +0000 (22:08 -0800)
SCCS-vsn: sys/netinet/in_var.h 7.7
SCCS-vsn: sys/netinet/in_pcb.c 7.19
SCCS-vsn: sys/netinet/if_ether.h 7.8
SCCS-vsn: sys/netinet/ip_output.c 7.25
SCCS-vsn: sys/netinet/in.c 7.25
SCCS-vsn: sys/netinet/in_proto.c 7.6
SCCS-vsn: sys/netinet/in_pcb.h 7.7
SCCS-vsn: sys/netinet/ip_icmp.c 7.16
SCCS-vsn: sys/netinet/ip_var.h 7.8
SCCS-vsn: sys/netinet/udp_usrreq.c 7.24
SCCS-vsn: sys/netinet/ip_input.c 7.22
SCCS-vsn: sys/netinet/raw_ip.c 7.9
SCCS-vsn: sys/netinet/if_ether.c 7.24
SCCS-vsn: sys/netinet/in.h 7.12

14 files changed:
usr/src/sys/netinet/if_ether.c
usr/src/sys/netinet/if_ether.h
usr/src/sys/netinet/in.c
usr/src/sys/netinet/in.h
usr/src/sys/netinet/in_pcb.c
usr/src/sys/netinet/in_pcb.h
usr/src/sys/netinet/in_proto.c
usr/src/sys/netinet/in_var.h
usr/src/sys/netinet/ip_icmp.c
usr/src/sys/netinet/ip_input.c
usr/src/sys/netinet/ip_output.c
usr/src/sys/netinet/ip_var.h
usr/src/sys/netinet/raw_ip.c
usr/src/sys/netinet/udp_usrreq.c

index aaf8e8d..ac13ab3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_ether.c  7.23 (Berkeley) %G%
+ *     @(#)if_ether.c  7.24 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 int    arpt_prune = (5*60*1);  /* walk list every 5 minutes */
 int    arpt_keep = (20*60);    /* once resolved, good for 20 more minutes */
 int    arpt_down = 20;         /* once declared down, don't send for 20 secs */
 int    arpt_prune = (5*60*1);  /* walk list every 5 minutes */
 int    arpt_keep = (20*60);    /* once resolved, good for 20 more minutes */
 int    arpt_down = 20;         /* once declared down, don't send for 20 secs */
-#define RTF_USETRAILERS        RTF_PROTO1
-#define rt_expire rt_rmx.rmx_expire
+#define        rt_expire rt_rmx.rmx_expire
 
 
-extern struct ifnet loif;
-extern struct timeval time;
-struct llinfo_arp *arplookup(), llinfo_arp = {&llinfo_arp, &llinfo_arp};
-struct ifqueue arpintrq = {0, 0, 0, 50};
+static void arprequest __P((struct arpcom *, u_long *, u_long *, u_char *));
+static void arptfree __P((struct llinfo_arp *));
+static struct llinfo_arp *arplookup __P((u_long, int, int));
+static void arpcatchme __P(());
+
+extern struct ifnet loif;
+extern struct timeval time;
+struct llinfo_arp llinfo_arp = {&llinfo_arp, &llinfo_arp};
+struct ifqueue arpintrq = {0, 0, 0, 50};
 int    arp_inuse, arp_allocated, arp_intimer;
 int    arp_maxtries = 5;
 int    useloopback = 1;        /* use loopback interface for local traffic */
 int    arp_inuse, arp_allocated, arp_intimer;
 int    arp_maxtries = 5;
 int    useloopback = 1;        /* use loopback interface for local traffic */
@@ -64,6 +68,7 @@ int   arpinit_done = 0;
 /*
  * Timeout routine.  Age arp_tab entries periodically.
  */
 /*
  * Timeout routine.  Age arp_tab entries periodically.
  */
+void
 arptimer()
 {
        int s = splnet();
 arptimer()
 {
        int s = splnet();
@@ -80,8 +85,9 @@ arptimer()
 }
 
 /*
 }
 
 /*
- * Parallel to llc_rtrequest. 
+ * Parallel to llc_rtrequest.
  */
  */
+void
 arp_rtrequest(req, rt, sa)
        int req;
        register struct rtentry *rt;
 arp_rtrequest(req, rt, sa)
        int req;
        register struct rtentry *rt;
@@ -98,11 +104,16 @@ arp_rtrequest(req, rt, sa)
        if (rt->rt_flags & RTF_GATEWAY)
                return;
        switch (req) {
        if (rt->rt_flags & RTF_GATEWAY)
                return;
        switch (req) {
+
        case RTM_ADD:
        case RTM_ADD:
-       case RTM_RESOLVE:
+               /*
+                * XXX: If this is a manually added route to interface
+                * such as older version of routed or gated might provide,
+                * restore cloning bit.
+                */
                if ((rt->rt_flags & RTF_HOST) == 0 &&
                    SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
                if ((rt->rt_flags & RTF_HOST) == 0 &&
                    SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
-                       rt->rt_flags |= RTF_CLONING; /* Route to IF? XXX*/
+                       rt->rt_flags |= RTF_CLONING;
                if (rt->rt_flags & RTF_CLONING) {
                        /*
                         * Case 1: This route should come from a route to iface.
                if (rt->rt_flags & RTF_CLONING) {
                        /*
                         * Case 1: This route should come from a route to iface.
@@ -114,6 +125,14 @@ arp_rtrequest(req, rt, sa)
                        rt->rt_expire = time.tv_sec;
                        break;
                }
                        rt->rt_expire = time.tv_sec;
                        break;
                }
+               /* Announce a new entry if requested. */
+               if (rt->rt_flags & RTF_ANNOUNCE)
+                       arprequest((struct arpcom *)rt->rt_ifp,
+                           &SIN(rt_key(rt))->sin_addr.s_addr,
+                           &SIN(rt_key(rt))->sin_addr.s_addr,
+                           (u_char *)LLADDR(SDL(gate)));
+               /*FALLTHROUGH*/
+       case RTM_RESOLVE:
                if (gate->sa_family != AF_LINK ||
                    gate->sa_len < sizeof(null_sdl)) {
                        log(LOG_DEBUG, "arp_rtrequest: bad gateway value");
                if (gate->sa_family != AF_LINK ||
                    gate->sa_len < sizeof(null_sdl)) {
                        log(LOG_DEBUG, "arp_rtrequest: bad gateway value");
@@ -155,7 +174,7 @@ arp_rtrequest(req, rt, sa)
                                LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
                        if (useloopback)
                                rt->rt_ifp = &loif;
                                LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
                        if (useloopback)
                                rt->rt_ifp = &loif;
-                               
+
                }
                break;
 
                }
                break;
 
@@ -178,7 +197,22 @@ arp_rtrequest(req, rt, sa)
 void
 arpwhohas(ac, addr)
        register struct arpcom *ac;
 void
 arpwhohas(ac, addr)
        register struct arpcom *ac;
-       struct in_addr *addr;
+       register struct in_addr *addr;
+{
+       arprequest(ac, &ac->ac_ipaddr.s_addr, &addr->s_addr, ac->ac_enaddr);
+}
+
+/*
+ * Broadcast an ARP request. Caller specifies:
+ *     - arp header source ip address
+ *     - arp header target ip address
+ *     - arp header source ethernet address
+ */
+static void
+arprequest(ac, sip, tip, enaddr)
+       register struct arpcom *ac;
+       register u_long *sip, *tip;
+       register u_char *enaddr;
 {
        register struct mbuf *m;
        register struct ether_header *eh;
 {
        register struct mbuf *m;
        register struct ether_header *eh;
@@ -201,11 +235,9 @@ arpwhohas(ac, addr)
        ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
        ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
        ea->arp_op = htons(ARPOP_REQUEST);
        ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
        ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
        ea->arp_op = htons(ARPOP_REQUEST);
-       bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
-          sizeof(ea->arp_sha));
-       bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
-          sizeof(ea->arp_spa));
-       bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
+       bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
+       bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
+       bcopy((caddr_t)tip, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
        sa.sa_family = AF_UNSPEC;
        sa.sa_len = sizeof(sa);
        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
        sa.sa_family = AF_UNSPEC;
        sa.sa_len = sizeof(sa);
        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
@@ -214,7 +246,7 @@ arpwhohas(ac, addr)
 int    useloopback = 1;        /* use loopback interface for local traffic */
 
 /*
 int    useloopback = 1;        /* use loopback interface for local traffic */
 
 /*
- * Resolve an IP address into an ethernet address.  If success, 
+ * Resolve an IP address into an ethernet address.  If success,
  * desten is filled in.  If there is no entry in arptab,
  * set one up and broadcast a request for the IP address.
  * Hold onto this mbuf and resend it once the address
  * desten is filled in.  If there is no entry in arptab,
  * set one up and broadcast a request for the IP address.
  * Hold onto this mbuf and resend it once the address
@@ -223,28 +255,32 @@ int       useloopback = 1;        /* use loopback interface for local traffic */
  * normally; a 0 return indicates that the packet has been
  * taken over here, either now or for later transmission.
  */
  * normally; a 0 return indicates that the packet has been
  * taken over here, either now or for later transmission.
  */
-arpresolve(ac, rt, m, dst, desten, usetrailers)
+int
+arpresolve(ac, rt, m, dst, desten)
        register struct arpcom *ac;
        register struct rtentry *rt;
        struct mbuf *m;
        register struct sockaddr *dst;
        register u_char *desten;
        register struct arpcom *ac;
        register struct rtentry *rt;
        struct mbuf *m;
        register struct sockaddr *dst;
        register u_char *desten;
-       int *usetrailers;
 {
        register struct llinfo_arp *la;
 {
        register struct llinfo_arp *la;
-       register struct in_ifaddr *ia;
        struct sockaddr_dl *sdl;
 
        struct sockaddr_dl *sdl;
 
-       *usetrailers = 0;
        if (m->m_flags & M_BCAST) {     /* broadcast */
                bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
                    sizeof(etherbroadcastaddr));
                return (1);
        }
        if (m->m_flags & M_BCAST) {     /* broadcast */
                bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
                    sizeof(etherbroadcastaddr));
                return (1);
        }
+#ifdef MULTICAST
+       if (m->m_flags & M_MCAST) {     /* multicast */
+               ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
+               return(1);
+       }
+#endif
        if (rt)
                la = (struct llinfo_arp *)rt->rt_llinfo;
        else {
        if (rt)
                la = (struct llinfo_arp *)rt->rt_llinfo;
        else {
-               if (la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0)) 
+               if (la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0))
                        rt = la->la_rt;
        }
        if (la == 0 || rt == 0) {
                        rt = la->la_rt;
        }
        if (la == 0 || rt == 0) {
@@ -260,7 +296,6 @@ arpresolve(ac, rt, m, dst, desten, usetrailers)
        if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
            sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
                bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
        if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
            sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
                bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
-               *usetrailers = rt->rt_flags & RTF_USETRAILERS;
                return 1;
        }
        /*
                return 1;
        }
        /*
@@ -292,6 +327,7 @@ arpresolve(ac, rt, m, dst, desten, usetrailers)
  * Common length and type checks are done here,
  * then the protocol-specific routine is called.
  */
  * Common length and type checks are done here,
  * then the protocol-specific routine is called.
  */
+void
 arpintr()
 {
        register struct mbuf *m;
 arpintr()
 {
        register struct mbuf *m;
@@ -326,14 +362,14 @@ arpintr()
  * Algorithm is that given in RFC 826.
  * In addition, a sanity check is performed on the sender
  * protocol address, to catch impersonators.
  * Algorithm is that given in RFC 826.
  * In addition, a sanity check is performed on the sender
  * protocol address, to catch impersonators.
- * We also handle negotiations for use of trailer protocol:
- * ARP replies for protocol type ETHERTYPE_TRAIL are sent
- * along with IP replies if we want trailers sent to us,
- * and also send them in response to IP replies.
- * This allows either end to announce the desire to receive
+ * We no longer handle negotiations for use of trailer protocol:
+ * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
+ * along with IP replies if we wanted trailers sent to us,
+ * and also sent them in response to IP replies.
+ * This allowed either end to announce the desire to receive
  * trailer packets.
  * trailer packets.
- * We reply to requests for ETHERTYPE_TRAIL protocol as well,
- * but don't normally send requests.
+ * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
+ * but formerly didn't normally send requests.
  */
 void
 in_arpinput(m)
  */
 void
 in_arpinput(m)
@@ -349,10 +385,9 @@ in_arpinput(m)
        struct sockaddr_dl *sdl;
        struct sockaddr sa;
        struct in_addr isaddr, itaddr, myaddr;
        struct sockaddr_dl *sdl;
        struct sockaddr sa;
        struct in_addr isaddr, itaddr, myaddr;
-       int proto, op, completed = 0, sendtrailers;
+       int op;
 
        ea = mtod(m, struct ether_arp *);
 
        ea = mtod(m, struct ether_arp *);
-       proto = ntohs(ea->arp_pro);
        op = ntohs(ea->arp_op);
        bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
        bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
        op = ntohs(ea->arp_op);
        bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
        bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
@@ -381,9 +416,7 @@ in_arpinput(m)
                   "duplicate IP address %x!! sent from ethernet address: %s\n",
                   ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
                itaddr = myaddr;
                   "duplicate IP address %x!! sent from ethernet address: %s\n",
                   ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
                itaddr = myaddr;
-               if (op == ARPOP_REQUEST)
-                       goto reply;
-               goto out;
+               goto reply;
        }
        s = splimp();
        la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
        }
        s = splimp();
        la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
@@ -392,7 +425,6 @@ in_arpinput(m)
                    bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen))
                        log(LOG_INFO, "arp info overwritten for %x by %s\n",
                            isaddr.s_addr, ether_sprintf(ea->arp_sha));
                    bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen))
                        log(LOG_INFO, "arp info overwritten for %x by %s\n",
                            isaddr.s_addr, ether_sprintf(ea->arp_sha));
-               completed = 1; 
                bcopy((caddr_t)ea->arp_sha, LLADDR(sdl),
                            sdl->sdl_alen = sizeof(ea->arp_sha));
                if (rt->rt_expire)
                bcopy((caddr_t)ea->arp_sha, LLADDR(sdl),
                            sdl->sdl_alen = sizeof(ea->arp_sha));
                if (rt->rt_expire)
@@ -406,29 +438,10 @@ in_arpinput(m)
                }
        }
 reply:
                }
        }
 reply:
-       switch (proto) {
-
-       case ETHERTYPE_IPTRAILERS:
-               /* partner says trailers are OK */
-               if (la)
-                       la->la_rt->rt_flags |= RTF_USETRAILERS;
-               /*
-                * Reply to request iff we want trailers.
-                */
-               if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
-                       goto out;
-               break;
-
-       case ETHERTYPE_IP:
-               /*
-                * Reply if this is an IP request,
-                * or if we want to send a trailer response.
-                * Send the latter only to the IP response
-                * that completes the current ARP entry.
-                */
-               if (op != ARPOP_REQUEST &&
-                   (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
-                       goto out;
+       if (op != ARPOP_REQUEST) {
+       out:
+               m_freem(m);
+               return;
        }
        if (itaddr.s_addr == myaddr.s_addr) {
                /* I am the target */
        }
        if (itaddr.s_addr == myaddr.s_addr) {
                /* I am the target */
@@ -436,7 +449,6 @@ reply:
                    sizeof(ea->arp_sha));
                bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    sizeof(ea->arp_sha));
                    sizeof(ea->arp_sha));
                bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    sizeof(ea->arp_sha));
-               sendtrailers = !(ac->ac_if.if_flags & IFF_NOTRAILERS);
        } else {
                la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
                if (la == NULL)
        } else {
                la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
                if (la == NULL)
@@ -446,25 +458,12 @@ reply:
                    sizeof(ea->arp_sha));
                sdl = SDL(rt->rt_gateway);
                bcopy(LLADDR(sdl), (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
                    sizeof(ea->arp_sha));
                sdl = SDL(rt->rt_gateway);
                bcopy(LLADDR(sdl), (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
-               sendtrailers = rt->rt_flags & RTF_USETRAILERS;
        }
 
        }
 
-       bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
-           sizeof(ea->arp_spa));
-       bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
-           sizeof(ea->arp_spa));
-       ea->arp_op = htons(ARPOP_REPLY); 
-       /*
-        * If incoming packet was an IP reply,
-        * we are sending a reply for type IPTRAILERS.
-        * If we are sending a reply for type IP
-        * and we want to receive trailers,
-        * send a trailer reply as well.
-        */
-       if (op == ARPOP_REPLY)
-               ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
-       else if (proto == ETHERTYPE_IP && sendtrailers)
-               mcopy = m_copy(m, 0, (int)M_COPYALL);
+       bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, sizeof(ea->arp_spa));
+       bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
+       ea->arp_op = htons(ARPOP_REPLY);
+       ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
        eh = (struct ether_header *)sa.sa_data;
        bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
            sizeof(eh->ether_dhost));
        eh = (struct ether_header *)sa.sa_data;
        bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
            sizeof(eh->ether_dhost));
@@ -472,21 +471,13 @@ reply:
        sa.sa_family = AF_UNSPEC;
        sa.sa_len = sizeof(sa);
        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
        sa.sa_family = AF_UNSPEC;
        sa.sa_len = sizeof(sa);
        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
-       if (mcopy) {
-               ea = mtod(mcopy, struct ether_arp *);
-               ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
-               (*ac->ac_if.if_output)(&ac->ac_if,
-                                       mcopy, &sa, (struct rtentry *)0);
-       }
-       return;
-out:
-       m_freem(m);
        return;
 }
 
 /*
  * Free an arp entry.
  */
        return;
 }
 
 /*
  * Free an arp entry.
  */
+static void
 arptfree(la)
        register struct llinfo_arp *la;
 {
 arptfree(la)
        register struct llinfo_arp *la;
 {
@@ -504,11 +495,10 @@ arptfree(la)
        rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
                        0, (struct rtentry **)0);
 }
        rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
                        0, (struct rtentry **)0);
 }
-int arpdebug = 0;
 /*
  * Lookup or enter a new address in arptab.
  */
 /*
  * Lookup or enter a new address in arptab.
  */
-struct llinfo_arp *
+static struct llinfo_arp *
 arplookup(addr, create, proxy)
        u_long addr;
        int create, proxy;
 arplookup(addr, create, proxy)
        u_long addr;
        int create, proxy;
@@ -522,18 +512,16 @@ arplookup(addr, create, proxy)
        if (rt == 0)
                return (0);
        rt->rt_refcnt--;
        if (rt == 0)
                return (0);
        rt->rt_refcnt--;
-       if ((rt->rt_flags & RTF_GATEWAY) || !(rt->rt_flags & RTF_LLINFO) ||
-               rt->rt_gateway->sa_family != AF_LINK) {
-               arpcatchme();
-               if (arpdebug)
+       if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
+           rt->rt_gateway->sa_family != AF_LINK) {
+               if (create)
                        log(LOG_DEBUG, "arptnew failed on %x\n", ntohl(addr));
                return (0);
        }
        return ((struct llinfo_arp *)rt->rt_llinfo);
 }
 
                        log(LOG_DEBUG, "arptnew failed on %x\n", ntohl(addr));
                return (0);
        }
        return ((struct llinfo_arp *)rt->rt_llinfo);
 }
 
-arpcatchme(){}
-
+int
 arpioctl(cmd, data)
        int cmd;
        caddr_t data;
 arpioctl(cmd, data)
        int cmd;
        caddr_t data;
index aa27f34..2c7ae3a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)if_ether.h  7.7 (Berkeley) %G%
+ *     @(#)if_ether.h  7.8 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -16,9 +16,10 @@ struct       ether_header {
        u_short ether_type;
 };
 
        u_short ether_type;
 };
 
-#define        ETHERTYPE_PUP   0x0200          /* PUP protocol */
-#define        ETHERTYPE_IP    0x0800          /* IP protocol */
-#define ETHERTYPE_ARP  0x0806          /* Addr. resolution protocol */
+#define        ETHERTYPE_PUP           0x0200  /* PUP protocol */
+#define        ETHERTYPE_IP            0x0800  /* IP protocol */
+#define ETHERTYPE_ARP          0x0806  /* Addr. resolution protocol */
+#define ETHERTYPE_REVARP       0x8035  /* reverse Addr. resolution protocol */
 
 /*
  * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have
 
 /*
  * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have
@@ -31,6 +32,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 bits of the Ethernet address are statically assigned,
+ * and the low-order 23 bits 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.
  *
@@ -60,7 +80,9 @@ struct        ether_arp {
 struct arpcom {
        struct  ifnet ac_if;            /* network-visible interface */
        u_char  ac_enaddr[6];           /* ethernet hardware address */
 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  in_addr ac_ipaddr;      /* copy of ip address- XXX */
+       struct  ether_multi *ac_multiaddrs; /* list of ether multicast addrs */
+       int     ac_multicnt;            /* length of ac_multiaddrs list */      
 };
 
 /*
 };
 
 /*
@@ -72,7 +94,7 @@ struct        arptab {
        u_char  at_timer;               /* minutes since last reference */
        u_char  at_flags;               /* flags */
        struct  mbuf *at_hold;          /* last packet until resolved/timeout */
        u_char  at_timer;               /* minutes since last reference */
        u_char  at_flags;               /* flags */
        struct  mbuf *at_hold;          /* last packet until resolved/timeout */
-};
+}; /* XXX: only used to define SIOCGARP, which is no longer supported */
 
 struct llinfo_arp {                            
        struct  llinfo_arp *la_next;
 
 struct llinfo_arp {                            
        struct  llinfo_arp *la_next;
@@ -93,19 +115,102 @@ struct sockaddr_inarp {
        u_short sin_other;
 #define SIN_PROXY 1
 };
        u_short sin_other;
 #define SIN_PROXY 1
 };
+/*
+ * IP and ethernet specific routing flags
+ */
+#define        RTF_USETRAILERS RTF_PROTO1      /* use trailers */
+#define RTF_ANNOUNCE   RTF_PROTO2      /* announce new arp entry */
 
 #ifdef KERNEL
 u_char etherbroadcastaddr[6];
 
 #ifdef KERNEL
 u_char etherbroadcastaddr[6];
+#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 llinfo_arp *arptnew __P((struct in_addr *));
 struct llinfo_arp llinfo_arp;          /* head of the llinfo queue */
 int    ether_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
                          struct rtentry *));
 int    ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *));
 char   *ether_sprintf __P((u_char *));
 struct llinfo_arp *arptnew __P((struct in_addr *));
 struct llinfo_arp llinfo_arp;          /* head of the llinfo queue */
 int    ether_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
                          struct rtentry *));
 int    ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *));
 char   *ether_sprintf __P((u_char *));
-int    arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));
+void   arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));
 struct ifqueue arpintrq;
 
 /* XXX These probably belong elsewhere */
 void   in_arpinput __P((struct mbuf *));
 void   arpwhohas __P((struct arpcom *, struct in_addr *));
 struct ifqueue arpintrq;
 
 /* XXX These probably belong elsewhere */
 void   in_arpinput __P((struct mbuf *));
 void   arpwhohas __P((struct arpcom *, struct in_addr *));
+
+#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 pointer to arpcom */
+       u_int   enm_refcount;           /* no. claims to this addr/range */
+       struct  ether_multi *enm_next;  /* ptr to next ether_multi */
+};
+
+#ifdef KERNEL
+/*
+ * 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
+#endif
 #endif
 #endif
index 115fcbe..b6e576c 100644 (file)
@@ -4,13 +4,13 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in.c        7.24 (Berkeley) %G%
+ *     @(#)in.c        7.25 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "ioctl.h"
 #include "errno.h"
  */
 
 #include "param.h"
 #include "ioctl.h"
 #include "errno.h"
-#include "mbuf.h"
+#include "malloc.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "in_systm.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "in_systm.h"
@@ -64,6 +64,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);
 
@@ -144,6 +148,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);
 
@@ -460,8 +469,8 @@ in_ifinit(ifp, ia, sin, scrub)
 {
        register u_long i = ntohl(sin->sin_addr.s_addr);
        struct sockaddr_in oldaddr;
 {
        register u_long i = ntohl(sin->sin_addr.s_addr);
        struct sockaddr_in oldaddr;
-       int s = splimp(), error, flags = RTF_UP;
-       int ether_output(), arp_rtrequest();
+       int s = splimp(), flags = RTF_UP, error, ether_output();
+       void arp_rtrequest();
 
        oldaddr = ia->ia_addr;
        ia->ia_addr = *sin;
 
        oldaddr = ia->ia_addr;
        ia->ia_addr = *sin;
@@ -529,6 +538,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);
 }
 
@@ -574,4 +595,118 @@ 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();
+int error;
+
+       /*
+        * 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) {
+                       free(inm, M_IPMADDR);
+                       splx(s);
+                       return (NULL);
+               }
+               error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr);
+               if (error != 0) {
+                       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 0066cdd..abbeee9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in.h        7.11 (Berkeley) %G%
+ *     @(#)in.h        7.12 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -17,6 +17,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               /* group mgmt 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 */
@@ -70,6 +71,9 @@ struct in_addr {
 #define        IN_CLASSC_HOST          0x000000ff
 
 #define        IN_CLASSD(i)            (((long)(i) & 0xf0000000) == 0xe0000000)
 #define        IN_CLASSC_HOST          0x000000ff
 
 #define        IN_CLASSD(i)            (((long)(i) & 0xf0000000) == 0xe0000000)
+#define        IN_CLASSD_NET           0xf0000000      /* These ones aren't really */
+#define        IN_CLASSD_NSHIFT        28              /* net and host fields, but */
+#define        IN_CLASSD_HOST          0x0fffffff      /* routing needn't know.    */
 #define        IN_MULTICAST(i)         IN_CLASSD(i)
 
 #define        IN_EXPERIMENTAL(i)      (((long)(i) & 0xe0000000) == 0xe0000000)
 #define        IN_MULTICAST(i)         IN_CLASSD(i)
 
 #define        IN_EXPERIMENTAL(i)      (((long)(i) & 0xe0000000) == 0xe0000000)
@@ -81,6 +85,10 @@ struct in_addr {
 #define        INADDR_NONE             0xffffffff              /* -1 return */
 #endif
 
 #define        INADDR_NONE             0xffffffff              /* -1 return */
 #endif
 
+#define INADDR_UNSPEC_GROUP    (u_long)0xe0000000      /* 224.0.0.0   */
+#define INADDR_ALLHOSTS_GROUP  (u_long)0xe0000001      /* 224.0.0.1   */
+#define INADDR_MAX_LOCAL_GROUP (u_long)0xe00000ff      /* 224.0.0.255 */
+
 #define        IN_LOOPBACKNET          127                     /* official! */
 
 /*
 #define        IN_LOOPBACKNET          127                     /* official! */
 
 /*
@@ -111,13 +119,32 @@ 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 */
-#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_RECVOPTS     5       /* bool; receive all IP options w/datagram */
-#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 2       /* set/get IP multicast interface */
+#define        IP_MULTICAST_TTL 3      /* set/get IP multicast timetolive */
+#define        IP_MULTICAST_LOOP 4     /* set/get IP multicast 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 */
+
+#define        IP_DEFAULT_MULTICAST_TTL 1      /* normally limit m'casts to 1 hop */
+#define        IP_DEFAULT_MULTICAST_LOOP 1     /* normally hear sends if a member */
+#define        IP_MAX_MEMBERSHIPS      20      /* per socket */
+
+/*
+ * 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
 struct in_addr in_makeaddr();
 
 #ifdef KERNEL
 struct in_addr in_makeaddr();
index 2dc2e61..5e8724c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in_pcb.c    7.18 (Berkeley) %G%
+ *     @(#)in_pcb.c    7.19 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "in_pcb.h"
 #include "in_var.h"
 
 #include "in_pcb.h"
 #include "in_var.h"
 
+#ifdef MULTICAST
+#include "ip_var.h"
+#endif
+
 struct in_addr zeroin_addr;
 
 in_pcballoc(so, head)
 struct in_addr zeroin_addr;
 
 in_pcballoc(so, head)
@@ -35,10 +39,10 @@ in_pcballoc(so, head)
        struct mbuf *m;
        register struct inpcb *inp;
 
        struct mbuf *m;
        register struct inpcb *inp;
 
-       m = m_getclr(M_DONTWAIT, MT_PCB);
-       if (m == NULL)
+       MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK);
+       if (inp == NULL)
                return (ENOBUFS);
                return (ENOBUFS);
-       inp = mtod(m, struct inpcb *);
+       bzero((caddr_t)inp, sizeof(*inp));
        inp->inp_head = head;
        inp->inp_socket = so;
        insque(inp, head);
        inp->inp_head = head;
        inp->inp_socket = so;
        insque(inp, head);
@@ -191,6 +195,27 @@ 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;
+
+                       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,
@@ -231,8 +256,11 @@ 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);
        remque(inp);
-       (void) m_free(dtom(inp));
+       FREE(inp, M_PCB);
 }
 
 in_setsockaddr(inp, nam)
 }
 
 in_setsockaddr(inp, nam)
@@ -395,7 +423,9 @@ in_pcblookup(head, faddr, fport, laddr, lport, flags)
                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
                                continue;
                } else {
                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
                                continue;
                } else {
+#ifndef MULTICAST
                        if (laddr.s_addr != INADDR_ANY)
                        if (laddr.s_addr != INADDR_ANY)
+#endif
                                wildcard++;
                }
                if (inp->inp_faddr.s_addr != INADDR_ANY) {
                                wildcard++;
                }
                if (inp->inp_faddr.s_addr != INADDR_ANY) {
index cf9b9a0..9b5cdc2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in_pcb.h    7.6 (Berkeley) %G%
+ *     @(#)in_pcb.h    7.7 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -29,6 +29,7 @@ struct inpcb {
        int     inp_flags;              /* generic IP/datagram flags */
        struct  ip inp_ip;              /* header prototype; should have more */
        struct  mbuf *inp_options;      /* IP options */
        int     inp_flags;              /* generic IP/datagram flags */
        struct  ip inp_ip;              /* header prototype; should have more */
        struct  mbuf *inp_options;      /* IP options */
+       struct  ip_moptions *inp_moptions; /* IP multicast options */
 };
 
 /* flags in inp_flags: */
 };
 
 /* flags in inp_flags: */
@@ -36,29 +37,12 @@ struct inpcb {
 #define        INP_RECVRETOPTS         0x02    /* receive IP options for reply */
 #define        INP_RECVDSTADDR         0x04    /* receive IP dst address */
 #define        INP_CONTROLOPTS         (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR)
 #define        INP_RECVRETOPTS         0x02    /* receive IP options for reply */
 #define        INP_RECVDSTADDR         0x04    /* receive IP dst address */
 #define        INP_CONTROLOPTS         (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR)
-
-#ifdef sotorawcb
-/*
- * Common structure pcb for raw internet protocol access.
- * Here are internet specific extensions to the raw control block,
- * and space is allocated to the necessary sockaddrs.
- */
-struct raw_inpcb {
-       struct  rawcb rinp_rcb; /* common control block prefix */
-       struct  mbuf *rinp_options;     /* IP options */
-       int     rinp_flags;             /* flags, e.g. raw sockopts */
-#define        RINPF_HDRINCL   0x1             /* user supplies entire IP header */
-       struct  sockaddr_in rinp_faddr; /* foreign address */
-       struct  sockaddr_in rinp_laddr; /* local address */
-       struct  route rinp_route;       /* placeholder for routing entry */
-};
-#endif
+#define        INP_HDRINCL             0x08    /* user supplies entire IP header */
 
 #define        INPLOOKUP_WILDCARD      1
 #define        INPLOOKUP_SETLOCAL      2
 
 #define        sotoinpcb(so)   ((struct inpcb *)(so)->so_pcb)
 
 #define        INPLOOKUP_WILDCARD      1
 #define        INPLOOKUP_SETLOCAL      2
 
 #define        sotoinpcb(so)   ((struct inpcb *)(so)->so_pcb)
-#define        sotorawinpcb(so)        ((struct raw_inpcb *)(so)->so_pcb)
 
 #ifdef KERNEL
 struct inpcb *in_pcblookup();
 
 #ifdef KERNEL
 struct inpcb *in_pcblookup();
index 4b778d3..10c21ca 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in_proto.c  7.5 (Berkeley) %G%
+ *     @(#)in_proto.c  7.6 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 int    ip_output(),ip_ctloutput();
 int    ip_init(),ip_slowtimo(),ip_drain();
 int    icmp_input();
 int    ip_output(),ip_ctloutput();
 int    ip_init(),ip_slowtimo(),ip_drain();
 int    icmp_input();
+#ifdef MULTICAST
+int    igmp_init(),igmp_input(),igmp_fasttimo();
+#endif
 int    udp_input(),udp_ctlinput();
 int    udp_usrreq();
 int    udp_init();
 int    tcp_input(),tcp_ctlinput();
 int    tcp_usrreq(),tcp_ctloutput();
 int    tcp_init(),tcp_fasttimo(),tcp_slowtimo(),tcp_drain();
 int    udp_input(),udp_ctlinput();
 int    udp_usrreq();
 int    udp_init();
 int    tcp_input(),tcp_ctlinput();
 int    tcp_usrreq(),tcp_ctloutput();
 int    tcp_init(),tcp_fasttimo(),tcp_slowtimo(),tcp_drain();
-int    rip_input(),rip_output(),rip_ctloutput(), rip_usrreq();
+int    rip_init(),rip_input(),rip_output(),rip_ctloutput(), rip_usrreq();
 /*
  * IMP protocol family: raw interface.
  * Using the raw interface entry to get the timer routine
 /*
  * IMP protocol family: raw interface.
  * Using the raw interface entry to get the timer routine
@@ -82,7 +85,7 @@ struct protosw inetsw[] = {
 },
 #ifdef TPIP
 { SOCK_SEQPACKET,&inetdomain,  IPPROTO_TP,     PR_CONNREQUIRED|PR_WANTRCVD,
 },
 #ifdef TPIP
 { SOCK_SEQPACKET,&inetdomain,  IPPROTO_TP,     PR_CONNREQUIRED|PR_WANTRCVD,
-  tpip_input,  0,              tpip_ctlinput,          tp_ctloutput,
+  tpip_input,  0,              tpip_ctlinput,  tp_ctloutput,
   tp_usrreq,
   tp_init,     0,              tp_slowtimo,    tp_drain,
 },
   tp_usrreq,
   tp_init,     0,              tp_slowtimo,    tp_drain,
 },
@@ -95,6 +98,13 @@ struct 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,
@@ -106,7 +116,7 @@ struct protosw inetsw[] = {
 { SOCK_RAW,    &inetdomain,    0,              PR_ATOMIC|PR_ADDR,
   rip_input,   rip_output,     0,              rip_ctloutput,
   rip_usrreq,
 { SOCK_RAW,    &inetdomain,    0,              PR_ATOMIC|PR_ADDR,
   rip_input,   rip_output,     0,              rip_ctloutput,
   rip_usrreq,
-  0,           0,              0,              0,
+  rip_init,    0,              0,              0,
 },
 };
 
 },
 };
 
index cf7374e..e088b32 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)in_var.h    7.6 (Berkeley) %G%
+ *     @(#)in_var.h    7.7 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -28,6 +28,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 {
@@ -48,3 +49,119 @@ struct      in_ifaddr *in_ifaddr;
 struct in_ifaddr *in_iaonnetof();
 struct ifqueue ipintrq;                /* ip packet input queue */
 #endif
 struct in_ifaddr *in_iaonnetof();
 struct ifqueue ipintrq;                /* ip packet input queue */
 #endif
+
+#ifdef KERNEL
+/*
+ * 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
index f5ca657..fade13a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_icmp.c   7.15 (Berkeley) %G%
+ *     @(#)ip_icmp.c   7.16 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -73,7 +73,11 @@ icmp_error(n, type, code, dest)
                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
         */
@@ -159,11 +163,11 @@ icmp_input(m, hlen)
                goto freeit;
        }
        i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
                goto freeit;
        }
        i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
-       if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
+       if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
                icmpstat.icps_tooshort++;
                return;
        }
                icmpstat.icps_tooshort++;
                return;
        }
-       ip = mtod(m, struct ip *);
+       ip = mtod(m, struct ip *);
        m->m_len -= hlen;
        m->m_data += hlen;
        icp = mtod(m, struct icmp *);
        m->m_len -= hlen;
        m->m_data += hlen;
        icp = mtod(m, struct icmp *);
@@ -259,6 +263,7 @@ icmp_input(m, hlen)
 
        case ICMP_MASKREQ:
                if (icmplen < ICMP_MASKLEN ||
 
        case ICMP_MASKREQ:
                if (icmplen < ICMP_MASKLEN ||
+                   m->m_flags & M_BCAST ||     /* Don't reply to broadcasts */
                    (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
                        break;
                icp->icmp_type = ICMP_MASKREPLY;
                    (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
                        break;
                icp->icmp_type = ICMP_MASKREPLY;
@@ -331,10 +336,7 @@ reflect:
        }
 
 raw:
        }
 
 raw:
-       icmpsrc.sin_addr = ip->ip_src;
-       icmpdst.sin_addr = ip->ip_dst;
-       (void) raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
-           (struct sockaddr *)&icmpdst);
+       rip_input(m);
        return;
 
 freeit:
        return;
 
 freeit:
index 973da9b..f312d17 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_input.c  7.21 (Berkeley) %G%
+ *     @(#)ip_input.c  7.22 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -246,6 +246,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(m, m->m_pkthdr.rcvif) != 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 5fb6567..bd0c88b 100644 (file)
@@ -29,7 +29,9 @@
 #include "machine/mtpr.h"
 #endif
 
 #include "machine/mtpr.h"
 #endif
 
-struct mbuf *ip_insertoptions();
+struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
+static 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
@@ -37,11 +39,19 @@ struct mbuf *ip_insertoptions();
  * The mbuf chain containing the packet will be freed.
  * The mbuf opt, if present, will not be freed.
  */
  * The mbuf chain containing the packet will be freed.
  * The mbuf opt, if present, will not be freed.
  */
-ip_output(m0, opt, ro, flags)
+int
+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;
@@ -123,6 +133,95 @@ 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 (imo != NULL) {
+                       ip->ip_ttl = imo->imo_multicast_ttl;
+                       if (imo->imo_multicast_ifp != NULL)
+                               ifp = imo->imo_multicast_ifp;
+               } else
+                       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(m, ifp) != 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
@@ -153,6 +252,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.
         */
@@ -307,6 +409,7 @@ ip_insertoptions(m, opt, phlen)
  * Copy options from ip to jp,
  * omitting those not copied during fragmentation.
  */
  * Copy options from ip to jp,
  * omitting those not copied during fragmentation.
  */
+int
 ip_optcopy(ip, jp)
        struct ip *ip, *jp;
 {
 ip_optcopy(ip, jp)
        struct ip *ip, *jp;
 {
@@ -340,6 +443,7 @@ ip_optcopy(ip, jp)
 /*
  * IP socket option processing.
  */
 /*
  * IP socket option processing.
  */
+int
 ip_ctloutput(op, so, level, optname, mp)
        int op;
        struct socket *so;
 ip_ctloutput(op, so, level, optname, mp)
        int op;
        struct socket *so;
@@ -405,6 +509,16 @@ 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
+
                freeit:
                default:
                        error = EINVAL;
                freeit:
                default:
                        error = EINVAL;
@@ -461,6 +575,16 @@ 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;
@@ -475,6 +599,7 @@ ip_ctloutput(op, so, level, optname, mp)
  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  * with destination address if source routed.
  */
  * Store in mbuf with pointer in pcbopt, adding pseudo-option
  * with destination address if source routed.
  */
+int
 #ifdef notyet
 ip_pcbopts(optname, pcbopt, m)
        int optname;
 #ifdef notyet
 ip_pcbopts(optname, pcbopt, m)
        int optname;
@@ -575,3 +700,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.
+ */
+static 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);
+       }
+}
+#endif
index 41b8217..642d5a4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)ip_var.h    7.7 (Berkeley) %G%
+ *     @(#)ip_var.h    7.8 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -73,6 +73,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 */
index 2ddadd9..4e53b57 100644 (file)
 #include "protosw.h"
 #include "socketvar.h"
 #include "errno.h"
 #include "protosw.h"
 #include "socketvar.h"
 #include "errno.h"
+#include "systm.h"
 
 #include "../net/if.h"
 #include "../net/route.h"
 
 #include "../net/if.h"
 #include "../net/route.h"
-#include "../net/raw_cb.h"
 
 #include "in.h"
 #include "in_systm.h"
 #include "ip.h"
 #include "ip_var.h"
 
 #include "in.h"
 #include "in_systm.h"
 #include "ip.h"
 #include "ip_var.h"
+#include "ip_mroute.h"
 #include "in_pcb.h"
 
 #include "in_pcb.h"
 
+struct inpcb rawinpcb;
+
+/*
+ * Nominal space allocated to a raw ip socket.
+ */
+#define        RIPSNDQ         8192
+#define        RIPRCVQ         8192
+
 /*
  * Raw interface to IP protocol.
  */
 
 /*
  * Raw interface to IP protocol.
  */
 
-struct sockaddr_in ripdst = { sizeof(ripdst), AF_INET };
+/*
+ * Initialize raw connection block q.
+ */
+rip_init()
+{
+
+       rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb;
+}
+
 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
-struct sockproto ripproto = { PF_INET };
 /*
  * Setup generic address and protocol structures
  * for raw_input routine, then pass them along with
 /*
  * Setup generic address and protocol structures
  * for raw_input routine, then pass them along with
@@ -41,12 +57,40 @@ rip_input(m)
        struct mbuf *m;
 {
        register struct ip *ip = mtod(m, struct ip *);
        struct mbuf *m;
 {
        register struct ip *ip = mtod(m, struct ip *);
+       register struct inpcb *inp;
+       struct socket *last = 0;
 
 
-       ripproto.sp_protocol = ip->ip_p;
-       ripdst.sin_addr = ip->ip_dst;
        ripsrc.sin_addr = ip->ip_src;
        ripsrc.sin_addr = ip->ip_src;
-       if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
-         (struct sockaddr *)&ripdst) == 0) {
+       for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) {
+               if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
+                       continue;
+               if (inp->inp_laddr.s_addr &&
+                   inp->inp_laddr.s_addr == ip->ip_dst.s_addr)
+                       continue;
+               if (inp->inp_faddr.s_addr &&
+                   inp->inp_faddr.s_addr == ip->ip_src.s_addr)
+                       continue;
+               if (last) {
+                       struct mbuf *n;
+                       if (n = m_copy(m, 0, (int)M_COPYALL)) {
+                               if (sbappendaddr(&last->so_rcv, &ripsrc,
+                                   n, (struct mbuf *)0) == 0)
+                                       /* should notify about lost packet */
+                                       m_freem(n);
+                               else
+                                       sorwakeup(last);
+                       }
+               }
+               last = inp->inp_socket;
+       }
+       if (last) {
+               if (sbappendaddr(&last->so_rcv, &ripsrc,
+                   m, (struct mbuf *)0) == 0)
+                       m_freem(m);
+               else
+                       sorwakeup(last);
+       } else {
+               m_freem(m);
                ipstat.ips_noproto++;
                ipstat.ips_delivered--;
        }
                ipstat.ips_noproto++;
                ipstat.ips_delivered--;
        }
@@ -56,40 +100,38 @@ rip_input(m)
  * Generate IP header and pass packet to ip_output.
  * Tack on options user may have setup with control call.
  */
  * Generate IP header and pass packet to ip_output.
  * Tack on options user may have setup with control call.
  */
-#define        satosin(sa)     ((struct sockaddr_in *)(sa))
-rip_output(m, so)
+rip_output(m, so, dst)
        register struct mbuf *m;
        struct socket *so;
        register struct mbuf *m;
        struct socket *so;
+       u_long dst;
 {
        register struct ip *ip;
 {
        register struct ip *ip;
-       register struct raw_inpcb *rp = sotorawinpcb(so);
+       register struct inpcb *inp = sotoinpcb(so);
        register struct sockaddr_in *sin;
 
        /*
         * If the user handed us a complete IP packet, use it.
         * Otherwise, allocate an mbuf for a header and fill it in.
         */
        register struct sockaddr_in *sin;
 
        /*
         * If the user handed us a complete IP packet, use it.
         * Otherwise, allocate an mbuf for a header and fill it in.
         */
-       if (rp->rinp_flags & RINPF_HDRINCL)
-               ip = mtod(m, struct ip *);
-       else {
+       if ((inp->inp_flags & INP_HDRINCL) == 0) {
                M_PREPEND(m, sizeof(struct ip), M_WAIT);
                ip = mtod(m, struct ip *);
                ip->ip_tos = 0;
                ip->ip_off = 0;
                M_PREPEND(m, sizeof(struct ip), M_WAIT);
                ip = mtod(m, struct ip *);
                ip->ip_tos = 0;
                ip->ip_off = 0;
-               ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol;
+               ip->ip_p = inp->inp_ip.ip_p;
                ip->ip_len = m->m_pkthdr.len;
                ip->ip_len = m->m_pkthdr.len;
-               if (sin = satosin(rp->rinp_rcb.rcb_laddr)) {
-                       ip->ip_src = sin->sin_addr;
-               } else
-                       ip->ip_src.s_addr = 0;
-               if (sin = satosin(rp->rinp_rcb.rcb_faddr))
-                   ip->ip_dst = sin->sin_addr;
+               ip->ip_src = inp->inp_laddr;
+               ip->ip_dst.s_addr = dst;
                ip->ip_ttl = MAXTTL;
        }
        return (ip_output(m,
                ip->ip_ttl = MAXTTL;
        }
        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));
+          (inp->inp_flags & INP_HDRINCL)? (struct mbuf *)0: inp->inp_options,
+           &inp->inp_route, 
+          (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST
+#ifdef MULTICAST
+          , inp->inp_moptions
+#endif
+          ));
 }
 
 /*
 }
 
 /*
@@ -101,135 +143,214 @@ rip_ctloutput(op, so, level, optname, m)
        int level, optname;
        struct mbuf **m;
 {
        int level, optname;
        struct mbuf **m;
 {
-       int error = 0;
-       register struct raw_inpcb *rp = sotorawinpcb(so);
+       register struct inpcb *inp = sotoinpcb(so);
+       register int error;
 
        if (level != IPPROTO_IP)
 
        if (level != IPPROTO_IP)
-               error = EINVAL;
-       else switch (op) {
-
-       case PRCO_SETOPT:
-               switch (optname) {
+               return (EINVAL);
 
 
-               case IP_OPTIONS:
-                       return (ip_pcbopts(&rp->rinp_options, *m));
+       switch (optname) {
 
 
-               case IP_HDRINCL:
-                       if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) {
-                               error = EINVAL;
-                               break;
+       case IP_HDRINCL:
+               if (op == PRCO_SETOPT || op == PRCO_GETOPT) {
+                       if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
+                               return (EINVAL);
+                       if (op == PRCO_SETOPT) {
+                               if (*mtod(*m, int *))
+                                       inp->inp_flags |= INP_HDRINCL;
+                               else
+                                       inp->inp_flags &= ~INP_HDRINCL;
+                               (void)m_free(*m);
+                       } else {
+                               (*m)->m_len = sizeof (int);
+                               *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
                        }
                        }
-                       if (*mtod(*m, int *))
-                               rp->rinp_flags |= RINPF_HDRINCL;
-                       else
-                               rp->rinp_flags &= ~RINPF_HDRINCL;
-                       break;
-
-               default:
-                       error = EINVAL;
-                       break;
+                       return (0);
                }
                break;
 
                }
                break;
 
-       case PRCO_GETOPT:
-               *m = m_get(M_WAIT, MT_SOOPTS);
-               switch (optname) {
-
-               case IP_OPTIONS:
-                       if (rp->rinp_options) {
-                               (*m)->m_len = rp->rinp_options->m_len;
-                               bcopy(mtod(rp->rinp_options, caddr_t),
-                                   mtod(*m, caddr_t), (unsigned)(*m)->m_len);
-                       } else
-                               (*m)->m_len = 0;
-                       break;
-
-               case IP_HDRINCL:
-                       (*m)->m_len = sizeof (int);
-                       *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
-                       break;
-
-               default:
+       case DVMRP_INIT:
+       case DVMRP_DONE:
+       case DVMRP_ADD_VIF:
+       case DVMRP_DEL_VIF:
+       case DVMRP_ADD_LGRP:
+       case DVMRP_DEL_LGRP:
+       case DVMRP_ADD_MRT:
+       case DVMRP_DEL_MRT:
+#ifdef MROUTING
+               if (op == PRCO_SETOPT) {
+                       error = ip_mrouter_cmd(optname, so, *m);
+                       if (*m)
+                               (void)m_free(*m);
+               } else
                        error = EINVAL;
                        error = EINVAL;
-                       m_freem(*m);
-                       *m = 0;
-                       break;
-               }
-               break;
+               return (error);
+#else
+               if (op == PRCO_SETOPT && *m)
+                       (void)m_free(*m);
+               return (EOPNOTSUPP);
+#endif
        }
        }
-       if (op == PRCO_SETOPT && *m)
-               (void)m_free(*m);
-       return (error);
+       return (ip_ctloutput(op, so, level, optname, m));
 }
 
 }
 
+u_long rip_sendspace = RIPSNDQ;
+u_long rip_recvspace = RIPRCVQ;
+
 /*ARGSUSED*/
 /*ARGSUSED*/
-rip_usrreq(so, req, m, nam, rights, control)
+rip_usrreq(so, req, m, nam, control)
        register struct socket *so;
        int req;
        register struct socket *so;
        int req;
-       struct mbuf *m, *nam, *rights, *control;
+       struct mbuf *m, *nam, *control;
 {
        register int error = 0;
 {
        register int error = 0;
-       register struct raw_inpcb *rp = sotorawinpcb(so);
+       register struct inpcb *inp = sotoinpcb(so);
+#if defined(MULTICAST) && defined(MROUTING)
+       extern struct socket *ip_mrouter;
+#endif
 
        switch (req) {
 
        case PRU_ATTACH:
 
        switch (req) {
 
        case PRU_ATTACH:
-               if (rp)
+               if (inp)
                        panic("rip_attach");
                        panic("rip_attach");
-               MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK);
-               if (rp == 0)
-                       return (ENOBUFS);
-               bzero((caddr_t)rp, sizeof *rp);
-               so->so_pcb = (caddr_t)rp;
+               if ((so->so_state & SS_PRIV) == 0) {
+                       error = EACCES;
+                       break;
+               }
+               if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
+                   (error = in_pcballoc(so, &rawinpcb)))
+                       break;
+               inp = (struct inpcb *)so->so_pcb;
+               inp->inp_ip.ip_p = (int)nam;
                break;
 
                break;
 
+       case PRU_DISCONNECT:
+               if ((so->so_state & SS_ISCONNECTED) == 0) {
+                       error = ENOTCONN;
+                       break;
+               }
+               /* FALLTHROUGH */
+       case PRU_ABORT:
+               soisdisconnected(so);
+               /* FALLTHROUGH */
        case PRU_DETACH:
        case PRU_DETACH:
-               if (rp == 0)
+               if (inp == 0)
                        panic("rip_detach");
                        panic("rip_detach");
-               if (rp->rinp_options)
-                       m_freem(rp->rinp_options);
-               if (rp->rinp_route.ro_rt)
-                       RTFREE(rp->rinp_route.ro_rt);
-               if (rp->rinp_rcb.rcb_laddr)
-                       rp->rinp_rcb.rcb_laddr = 0;
+#if defined(MULTICAST) && defined(MROUTING)
+               if (so == ip_mrouter)
+                       ip_mrouter_done();
+#endif
+               in_pcbdetach(inp);
                break;
 
        case PRU_BIND:
            {
                struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
 
                break;
 
        case PRU_BIND:
            {
                struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
 
-               if (nam->m_len != sizeof(*addr))
-                       return (EINVAL);
+               if (nam->m_len != sizeof(*addr)) {
+                       error = EINVAL;
+                       break;
+               }
                if ((ifnet == 0) ||
                    ((addr->sin_family != AF_INET) &&
                     (addr->sin_family != AF_IMPLINK)) ||
                    (addr->sin_addr.s_addr &&
                if ((ifnet == 0) ||
                    ((addr->sin_family != AF_INET) &&
                     (addr->sin_family != AF_IMPLINK)) ||
                    (addr->sin_addr.s_addr &&
-                    ifa_ifwithaddr((struct sockaddr *)addr) == 0))
-                       return (EADDRNOTAVAIL);
-               rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr;
-               rp->rinp_laddr = *addr;
-               return (0);
+                    ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
+                       error = EADDRNOTAVAIL;
+                       break;
+               }
+               inp->inp_laddr = addr->sin_addr;
+               break;
            }
        case PRU_CONNECT:
            {
                struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
 
            }
        case PRU_CONNECT:
            {
                struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
 
-               if (nam->m_len != sizeof(*addr))
-                       return (EINVAL);
-               if (ifnet == 0)
-                       return (EADDRNOTAVAIL);
+               if (nam->m_len != sizeof(*addr)) {
+                       error = EINVAL;
+                       break;
+               }
+               if (ifnet == 0) {
+                       error = EADDRNOTAVAIL;
+                       break;
+               }
                if ((addr->sin_family != AF_INET) &&
                if ((addr->sin_family != AF_INET) &&
-                    (addr->sin_family != AF_IMPLINK))
-                       return (EAFNOSUPPORT);
-               rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr;
-               rp->rinp_faddr = *addr;
+                    (addr->sin_family != AF_IMPLINK)) {
+                       error = EAFNOSUPPORT;
+                       break;
+               }
+               inp->inp_faddr = addr->sin_addr;
                soisconnected(so);
                soisconnected(so);
-               return (0);
+               break;
            }
            }
-       }
-       error =  raw_usrreq(so, req, m, nam, rights, control);
 
 
-       if (error && (req == PRU_ATTACH) && so->so_pcb)
-               free(so->so_pcb, M_PCB);
+       case PRU_CONNECT2:
+               error = EOPNOTSUPP;
+               break;
+
+       /*
+        * Mark the connection as being incapable of further input.
+        */
+       case PRU_SHUTDOWN:
+               socantsendmore(so);
+               break;
+
+       /*
+        * Ship a packet out.  The appropriate raw output
+        * routine handles any massaging necessary.
+        */
+       case PRU_SEND:
+           {
+               register u_long dst;
+
+               if (so->so_state & SS_ISCONNECTED) {
+                       if (nam) {
+                               error = EISCONN;
+                               break;
+                       }
+                       dst = inp->inp_faddr.s_addr;
+               } else {
+                       if (nam == NULL) {
+                               error = ENOTCONN;
+                               break;
+                       }
+                       dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
+               }
+               error = rip_output(m, so, dst);
+               m = NULL;
+               break;
+           }
+
+       case PRU_SENSE:
+               /*
+                * stat: don't bother with a blocksize.
+                */
+               return (0);
+
+       /*
+        * Not supported.
+        */
+       case PRU_RCVOOB:
+       case PRU_RCVD:
+       case PRU_LISTEN:
+       case PRU_ACCEPT:
+       case PRU_SENDOOB:
+               error = EOPNOTSUPP;
+               break;
+
+       case PRU_SOCKADDR:
+               in_setsockaddr(inp, nam);
+               break;
+
+       case PRU_PEERADDR:
+               in_setpeeraddr(inp, nam);
+               break;
+
+       default:
+               panic("rip_usrreq");
+       }
+       if (m != NULL)
+               m_freem(m);
        return (error);
 }
        return (error);
 }
index d8c80c5..d0c648a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)udp_usrreq.c        7.23 (Berkeley) %G%
+ *     @(#)udp_usrreq.c        7.24 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -120,6 +120,93 @@ udp_input(m, iphlen)
                }
        }
 
                }
        }
 
+#ifdef MULTICAST
+       if (IN_MULTICAST(ntohl(ip->ip_src.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.
         */
@@ -137,10 +224,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;
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
                *ip = save_ip;
                ip->ip_len += iphlen;
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
@@ -327,7 +417,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
+           , inp->inp_moptions
+#endif
+           );
 
        if (addr) {
                in_pcbdisconnect(inp);
 
        if (addr) {
                in_pcbdisconnect(inp);