BSD 4_3_Reno release
[unix-history] / usr / src / sys / netinet / in_pcb.c
index 7a8c3fb..cd1ff78 100644 (file)
@@ -1,23 +1,38 @@
 /*
 /*
- * Copyright (c) 1982 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 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)in_pcb.c    6.12 (Berkeley) %G%
+ * Redistribution is only permitted until one year after the first shipment
+ * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
+ * binary forms are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement:  This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software.  Neither the name of the University nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)in_pcb.c    7.13 (Berkeley) 6/28/90
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
+#include "malloc.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "ioctl.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 "../net/if.h"
 #include "../net/route.h"
+#include "in.h"
+#include "in_systm.h"
+#include "ip.h"
 #include "in_pcb.h"
 #include "in_var.h"
 #include "protosw.h"
 #include "in_pcb.h"
 #include "in_var.h"
 #include "protosw.h"
@@ -106,7 +121,7 @@ noname:
  * then pick one.
  */
 in_pcbconnect(inp, nam)
  * then pick one.
  */
 in_pcbconnect(inp, nam)
-       struct inpcb *inp;
+       register struct inpcb *inp;
        struct mbuf *nam;
 {
        struct in_ifaddr *ia;
        struct mbuf *nam;
 {
        struct in_ifaddr *ia;
@@ -135,39 +150,52 @@ in_pcbconnect(inp, nam)
                    sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
        }
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
                    sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
        }
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
-               ia = in_iaonnetof(in_netof(sin->sin_addr));
-               if (ia == (struct in_ifaddr *)0) {
-                       register struct route *ro;
-                       struct ifnet *ifp;
+               register struct route *ro;
+               struct ifnet *ifp;
+
+               ia = (struct in_ifaddr *)0;
+               /* 
+                * If route is known or can be allocated now,
+                * our src addr is taken from the i/f, else punt.
+                */
+               ro = &inp->inp_route;
+               if (ro->ro_rt &&
+                   (satosin(&ro->ro_dst)->sin_addr.s_addr !=
+                       sin->sin_addr.s_addr || 
+                   inp->inp_socket->so_options & SO_DONTROUTE)) {
+                       RTFREE(ro->ro_rt);
+                       ro->ro_rt = (struct rtentry *)0;
+               }
+               if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
+                   (ro->ro_rt == (struct rtentry *)0 ||
+                   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);
+               }
+               /*
+                * If we found a route, use the address
+                * corresponding to the outgoing interface
+                * unless it is the loopback (in case a route
+                * 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)
+                       for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                               if (ia->ia_ifp == ifp)
+                                       break;
+               if (ia == 0) {
+                       int fport = sin->sin_port;
 
 
-                       /* 
-                        * If route is known or can be allocated now,
-                        * our src addr is taken from the i/f, else punt.
-                        */
-                       ro = &inp->inp_route;
-                       if (ro->ro_rt &&
-                           satosin(&ro->ro_dst)->sin_addr.s_addr !=
-                           sin->sin_addr.s_addr) {
-                               RTFREE(ro->ro_rt);
-                               ro->ro_rt = (struct rtentry *)0;
-                       }
-                       if ((ro->ro_rt == (struct rtentry *)0) ||
-                           (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) {
-                               /* No route yet, so try to acquire one */
-                               ro->ro_dst.sa_family = AF_INET;
-                               ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
-                                       sin->sin_addr;
-                               rtalloc(ro);
-                               if (ro->ro_rt == (struct rtentry *)0)
-                                       ifp = (struct ifnet *)0;
-                               else
-                                       ifp = ro->ro_rt->rt_ifp;
-                       }
-                       if (ifp) {
-                               for (ia = in_ifaddr; ia; ia = ia->ia_next)
-                                       if (ia->ia_ifp == ifp)
-                                               break;
-                       }
+                       sin->sin_port = 0;
+                       ia = (struct in_ifaddr *)
+                           ifa_ifwithdstaddr((struct sockaddr *)sin);
+                       sin->sin_port = fport;
+                       if (ia == 0)
+                               ia = in_iaonnetof(in_netof(sin->sin_addr));
                        if (ia == 0)
                                ia = in_ifaddr;
                        if (ia == 0)
                        if (ia == 0)
                                ia = in_ifaddr;
                        if (ia == 0)
@@ -184,7 +212,7 @@ in_pcbconnect(inp, nam)
                return (EADDRINUSE);
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
                if (inp->inp_lport == 0)
                return (EADDRINUSE);
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
                if (inp->inp_lport == 0)
-                       in_pcbbind(inp, (struct mbuf *)0);
+                       (void)in_pcbbind(inp, (struct mbuf *)0);
                inp->inp_laddr = ifaddr->sin_addr;
        }
        inp->inp_faddr = sin->sin_addr;
                inp->inp_laddr = ifaddr->sin_addr;
        }
        inp->inp_faddr = sin->sin_addr;
@@ -210,7 +238,7 @@ in_pcbdetach(inp)
        so->so_pcb = 0;
        sofree(so);
        if (inp->inp_options)
        so->so_pcb = 0;
        sofree(so);
        if (inp->inp_options)
-               m_free(inp->inp_options);
+               (void)m_free(inp->inp_options);
        if (inp->inp_route.ro_rt)
                rtfree(inp->inp_route.ro_rt);
        remque(inp);
        if (inp->inp_route.ro_rt)
                rtfree(inp->inp_route.ro_rt);
        remque(inp);
@@ -221,57 +249,91 @@ in_setsockaddr(inp, nam)
        register struct inpcb *inp;
        struct mbuf *nam;
 {
        register struct inpcb *inp;
        struct mbuf *nam;
 {
-       register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+       register struct sockaddr_in *sin;
        
        nam->m_len = sizeof (*sin);
        sin = mtod(nam, struct sockaddr_in *);
        bzero((caddr_t)sin, sizeof (*sin));
        sin->sin_family = AF_INET;
        
        nam->m_len = sizeof (*sin);
        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;
 }
 
 in_setpeeraddr(inp, nam)
        sin->sin_port = inp->inp_lport;
        sin->sin_addr = inp->inp_laddr;
 }
 
 in_setpeeraddr(inp, nam)
-       register struct inpcb *inp;
+       struct inpcb *inp;
        struct mbuf *nam;
 {
        struct mbuf *nam;
 {
-       register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+       register struct sockaddr_in *sin;
        
        nam->m_len = sizeof (*sin);
        sin = mtod(nam, struct sockaddr_in *);
        bzero((caddr_t)sin, sizeof (*sin));
        sin->sin_family = AF_INET;
        
        nam->m_len = sizeof (*sin);
        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);
 }
 
 /*
 }
 
 /*
@@ -286,10 +348,15 @@ in_losing(inp)
        register struct rtentry *rt;
 
        if ((rt = inp->inp_route.ro_rt)) {
        register struct rtentry *rt;
 
        if ((rt = inp->inp_route.ro_rt)) {
+               rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
+                           rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
+                           (struct sockaddr *)0, rt->rt_flags, 0);
                if (rt->rt_flags & RTF_DYNAMIC)
                if (rt->rt_flags & RTF_DYNAMIC)
-                       rtrequest(SIOCDELRT, rt);
-               rtfree(rt);
+                       (void) rtrequest(RTM_DELETE, rt_key(rt),
+                               rt->rt_gateway, rt_mask(rt), rt->rt_flags, 
+                               (struct rtentry **)0);
                inp->inp_route.ro_rt = 0;
                inp->inp_route.ro_rt = 0;
+               rtfree(rt);
                /*
                 * A new route can be allocated
                 * the next time output is attempted.
                /*
                 * A new route can be allocated
                 * the next time output is attempted.