make kernel includes standard
[unix-history] / usr / src / sys / netinet / in_pcb.c
index c3b5a53..2c3dc3d 100644 (file)
@@ -1,26 +1,34 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)in_pcb.c    7.5 (Berkeley) %G%
+ * %sccs.include.redist.c%
+ *
+ *     @(#)in_pcb.c    7.23 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "mbuf.h"
-#include "socket.h"
-#include "socketvar.h"
-#include "ioctl.h"
-#include "in.h"
-#include "in_systm.h"
-#include "../net/if.h"
-#include "../net/route.h"
-#include "in_pcb.h"
-#include "in_var.h"
-#include "protosw.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+
+#ifdef MULTICAST
+#include <netinet/ip_var.h>
+#endif
 
 struct in_addr zeroin_addr;
 
 
 struct in_addr zeroin_addr;
 
@@ -31,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);
@@ -70,19 +78,22 @@ in_pcbbind(inp, nam)
        }
        lport = sin->sin_port;
        if (lport) {
        }
        lport = sin->sin_port;
        if (lport) {
+               struct inpcb *t;
                u_short aport = ntohs(lport);
                int wild = 0;
 
                /* GROSS */
                u_short aport = ntohs(lport);
                int wild = 0;
 
                /* GROSS */
-               if (aport < IPPORT_RESERVED && u.u_uid != 0)
+               if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
                        return (EACCES);
                /* even GROSSER, but this is the Internet */
                if ((so->so_options & SO_REUSEADDR) == 0 &&
                    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
                     (so->so_options & SO_ACCEPTCONN) == 0))
                        wild = INPLOOKUP_WILDCARD;
                        return (EACCES);
                /* even GROSSER, but this is the Internet */
                if ((so->so_options & SO_REUSEADDR) == 0 &&
                    ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
                     (so->so_options & SO_ACCEPTCONN) == 0))
                        wild = INPLOOKUP_WILDCARD;
-               if (in_pcblookup(head,
-                   zeroin_addr, 0, sin->sin_addr, lport, wild))
+               t = in_pcblookup(head, zeroin_addr, 0,
+                               sin->sin_addr, lport, wild);
+               if (t && !((so->so_options & t->inp_socket->so_options) &
+                   SO_REUSEPORT))
                        return (EADDRINUSE);
        }
        inp->inp_laddr = sin->sin_addr;
                        return (EADDRINUSE);
        }
        inp->inp_laddr = sin->sin_addr;
@@ -156,6 +167,7 @@ in_pcbconnect(inp, nam)
                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
                        /* No route yet, so try to acquire one */
                        ro->ro_dst.sa_family = AF_INET;
                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
                        /* No route yet, so try to acquire one */
                        ro->ro_dst.sa_family = AF_INET;
+                       ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
                        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
                                sin->sin_addr;
                        rtalloc(ro);
                        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
                                sin->sin_addr;
                        rtalloc(ro);
@@ -167,7 +179,8 @@ in_pcbconnect(inp, nam)
                 * to our address on another net goes to loopback).
                 */
                if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
                 * to our address on another net goes to loopback).
                 */
                if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
-                   (ifp->if_flags & IFF_LOOPBACK) == 0)
+                   (ifp->if_flags & IFF_LOOPBACK) == 0 &&
+                   (ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa) == 0)
                        for (ia = in_ifaddr; ia; ia = ia->ia_next)
                                if (ia->ia_ifp == ifp)
                                        break;
                        for (ia = in_ifaddr; ia; ia = ia->ia_next)
                                if (ia->ia_ifp == ifp)
                                        break;
@@ -185,6 +198,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,
@@ -225,8 +259,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)
@@ -239,6 +276,7 @@ in_setsockaddr(inp, nam)
        sin = mtod(nam, struct sockaddr_in *);
        bzero((caddr_t)sin, sizeof (*sin));
        sin->sin_family = AF_INET;
        sin = mtod(nam, struct sockaddr_in *);
        bzero((caddr_t)sin, sizeof (*sin));
        sin->sin_family = AF_INET;
+       sin->sin_len = sizeof(*sin);
        sin->sin_port = inp->inp_lport;
        sin->sin_addr = inp->inp_laddr;
 }
        sin->sin_port = inp->inp_lport;
        sin->sin_addr = inp->inp_laddr;
 }
@@ -253,37 +291,70 @@ in_setpeeraddr(inp, nam)
        sin = mtod(nam, struct sockaddr_in *);
        bzero((caddr_t)sin, sizeof (*sin));
        sin->sin_family = AF_INET;
        sin = mtod(nam, struct sockaddr_in *);
        bzero((caddr_t)sin, sizeof (*sin));
        sin->sin_family = AF_INET;
+       sin->sin_len = sizeof(*sin);
        sin->sin_port = inp->inp_fport;
        sin->sin_addr = inp->inp_faddr;
 }
 
 /*
  * Pass some notification to all connections of a protocol
        sin->sin_port = inp->inp_fport;
        sin->sin_addr = inp->inp_faddr;
 }
 
 /*
  * Pass some notification to all connections of a protocol
- * associated with address dst.  Call the protocol specific
- * routine (if any) to handle each connection.
+ * associated with address dst.  The local address and/or port numbers
+ * may be specified to limit the search.  The "usual action" will be
+ * taken, depending on the ctlinput cmd.  The caller must filter any
+ * cmds that are uninteresting (e.g., no error in the map).
+ * Call the protocol specific routine (if any) to report
+ * any errors for each matching socket.
+ *
+ * Must be called at splnet.
  */
  */
-in_pcbnotify(head, dst, errno, notify)
+in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
        struct inpcb *head;
        struct inpcb *head;
-       register struct in_addr *dst;
-       int errno, (*notify)();
+       struct sockaddr *dst;
+       u_short fport, lport;
+       struct in_addr laddr;
+       int cmd, (*notify)();
 {
        register struct inpcb *inp, *oinp;
 {
        register struct inpcb *inp, *oinp;
-       int s = splimp();
+       struct in_addr faddr;
+       int errno;
+       int in_rtchange();
+       extern u_char inetctlerrmap[];
+
+       if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
+               return;
+       faddr = ((struct sockaddr_in *)dst)->sin_addr;
+       if (faddr.s_addr == INADDR_ANY)
+               return;
 
 
+       /*
+        * Redirects go to all references to the destination,
+        * and use in_rtchange to invalidate the route cache.
+        * Dead host indications: notify all references to the destination.
+        * Otherwise, if we have knowledge of the local port and address,
+        * deliver only to that socket.
+        */
+       if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
+               fport = 0;
+               lport = 0;
+               laddr.s_addr = 0;
+               if (cmd != PRC_HOSTDEAD)
+                       notify = in_rtchange;
+       }
+       errno = inetctlerrmap[cmd];
        for (inp = head->inp_next; inp != head;) {
        for (inp = head->inp_next; inp != head;) {
-               if (inp->inp_faddr.s_addr != dst->s_addr ||
-                   inp->inp_socket == 0) {
+               if (inp->inp_faddr.s_addr != faddr.s_addr ||
+                   inp->inp_socket == 0 ||
+                   (lport && inp->inp_lport != lport) ||
+                   (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
+                   (fport && inp->inp_fport != fport)) {
                        inp = inp->inp_next;
                        continue;
                }
                        inp = inp->inp_next;
                        continue;
                }
-               if (errno) 
-                       inp->inp_socket->so_error = errno;
                oinp = inp;
                inp = inp->inp_next;
                if (notify)
                oinp = inp;
                inp = inp->inp_next;
                if (notify)
-                       (*notify)(oinp);
+                       (*notify)(oinp, errno);
        }
        }
-       splx(s);
 }
 
 /*
 }
 
 /*
@@ -296,16 +367,26 @@ in_losing(inp)
        struct inpcb *inp;
 {
        register struct rtentry *rt;
        struct inpcb *inp;
 {
        register struct rtentry *rt;
+       struct rt_addrinfo info;
 
        if ((rt = inp->inp_route.ro_rt)) {
 
        if ((rt = inp->inp_route.ro_rt)) {
-               if (rt->rt_flags & RTF_DYNAMIC)
-                       (void) rtrequest((int)SIOCDELRT, rt);
-               rtfree(rt);
                inp->inp_route.ro_rt = 0;
                inp->inp_route.ro_rt = 0;
+               bzero((caddr_t)&info, sizeof(info));
+               info.rti_info[RTAX_DST] =
+                       (struct sockaddr *)&inp->inp_route.ro_dst;
+               info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+               info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+               rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
+               if (rt->rt_flags & RTF_DYNAMIC)
+                       (void) rtrequest(RTM_DELETE, rt_key(rt),
+                               rt->rt_gateway, rt_mask(rt), rt->rt_flags, 
+                               (struct rtentry **)0);
+               else 
                /*
                 * A new route can be allocated
                 * the next time output is attempted.
                 */
                /*
                 * A new route can be allocated
                 * the next time output is attempted.
                 */
+                       rtfree(rt);
        }
 }
 
        }
 }