BSD 4_3_Tahoe release
[unix-history] / usr / src / sys / netinet / in_pcb.c
index 86c987b..a7211cc 100644 (file)
@@ -1,9 +1,20 @@
 /*
 /*
- * 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.9 (Berkeley) %G%
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)in_pcb.c    7.7 (Berkeley) 6/29/88
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -13,6 +24,7 @@
 #include "mbuf.h"
 #include "socket.h"
 #include "socketvar.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 "in.h"
 #include "in_systm.h"
 #include "../net/if.h"
@@ -88,7 +100,8 @@ in_pcbbind(inp, nam)
 noname:
        if (lport == 0)
                do {
 noname:
        if (lport == 0)
                do {
-                       if (head->inp_lport++ < IPPORT_RESERVED)
+                       if (head->inp_lport++ < IPPORT_RESERVED ||
+                           head->inp_lport > IPPORT_USERRESERVED)
                                head->inp_lport = IPPORT_RESERVED;
                        lport = htons(head->inp_lport);
                } while (in_pcblookup(head,
                                head->inp_lport = IPPORT_RESERVED;
                        lport = htons(head->inp_lport);
                } while (in_pcblookup(head,
@@ -104,7 +117,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;
@@ -133,40 +146,51 @@ 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 = (struct in_ifaddr *)ifa_ifwithnet((struct sockaddr *)sin);
-               if (ia == (struct in_ifaddr *)0) {
-                       register struct route *ro;
-                       struct ifnet *ifp;
+               register struct route *ro;
+               struct ifnet *ifp;
 
 
-                       /* 
-                        * 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 == 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;
-                       } else
-                               ia = (struct in_ifaddr *)0;
+               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;
+                       ((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;
+
+                       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)
@@ -183,7 +207,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;
@@ -209,7 +233,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);
@@ -220,7 +244,7 @@ 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 *);
        
        nam->m_len = sizeof (*sin);
        sin = mtod(nam, struct sockaddr_in *);
@@ -231,10 +255,10 @@ in_setsockaddr(inp, nam)
 }
 
 in_setpeeraddr(inp, nam)
 }
 
 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 *);
        
        nam->m_len = sizeof (*sin);
        sin = mtod(nam, struct sockaddr_in *);
@@ -273,12 +297,35 @@ in_pcbnotify(head, dst, errno, notify)
        splx(s);
 }
 
        splx(s);
 }
 
+/*
+ * Check for alternatives when higher level complains
+ * about service problems.  For now, invalidate cached
+ * routing information.  If the route was created dynamically
+ * (by a redirect), time to try a default gateway again.
+ */
+in_losing(inp)
+       struct inpcb *inp;
+{
+       register struct rtentry *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;
+               /*
+                * A new route can be allocated
+                * the next time output is attempted.
+                */
+       }
+}
+
 /*
  * After a routing change, flush old routing
  * and allocate a (hopefully) better one.
  */
 in_rtchange(inp)
 /*
  * After a routing change, flush old routing
  * and allocate a (hopefully) better one.
  */
 in_rtchange(inp)
-       struct inpcb *inp;
+       register struct inpcb *inp;
 {
        if (inp->inp_route.ro_rt) {
                rtfree(inp->inp_route.ro_rt);
 {
        if (inp->inp_route.ro_rt) {
                rtfree(inp->inp_route.ro_rt);