new stats; change keepalives to use rcv_nxt instead of rcv_nxt-1
[unix-history] / usr / src / sys / netinet / in.c
index 536d54e..b6e6f07 100644 (file)
@@ -1,9 +1,9 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
+ * 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.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)in.c        6.8 (Berkeley) %G%
+ *     @(#)in.c        7.3 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -73,6 +73,7 @@ in_makeaddr(net, host)
 /*
  * Return the network number from an internet address.
  */
 /*
  * Return the network number from an internet address.
  */
+u_long
 in_netof(in)
        struct in_addr in;
 {
 in_netof(in)
        struct in_addr in;
 {
@@ -92,7 +93,7 @@ in_netof(in)
         * if so, return subnet number.
         */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
         * if so, return subnet number.
         */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
-               if ((ia->ia_netmask & net) == ia->ia_net)
+               if (net == ia->ia_net)
                        return (i & ia->ia_subnetmask);
        return (net);
 }
                        return (i & ia->ia_subnetmask);
        return (net);
 }
@@ -100,6 +101,7 @@ in_netof(in)
 /*
  * Return the host portion of an internet address.
  */
 /*
  * Return the host portion of an internet address.
  */
+u_long
 in_lnaof(in)
        struct in_addr in;
 {
 in_lnaof(in)
        struct in_addr in;
 {
@@ -123,14 +125,20 @@ in_lnaof(in)
         * if so, use the modified interpretation of `host'.
         */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
         * if so, use the modified interpretation of `host'.
         */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
-               if ((ia->ia_netmask & net) == ia->ia_net)
+               if (net == ia->ia_net)
                        return (host &~ ia->ia_subnetmask);
        return (host);
 }
 
                        return (host &~ ia->ia_subnetmask);
        return (host);
 }
 
+#ifndef SUBNETSARELOCAL
+#define        SUBNETSARELOCAL 1
+#endif
+int subnetsarelocal = SUBNETSARELOCAL;
 /*
  * Return 1 if an internet address is for a ``local'' host
 /*
  * Return 1 if an internet address is for a ``local'' host
- * (one to which we have a connection).
+ * (one to which we have a connection).  If subnetsarelocal
+ * is true, this includes other subnets of the local net.
+ * Otherwise, it includes only the directly-connected (sub)nets.
  */
 in_localaddr(in)
        struct in_addr in;
  */
 in_localaddr(in)
        struct in_addr in;
@@ -147,15 +155,19 @@ in_localaddr(in)
                net = i & IN_CLASSC_NET;
 
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
                net = i & IN_CLASSC_NET;
 
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
-               if ((ia->ia_netmask & net) == ia->ia_net)
+               if (net == (subnetsarelocal ? ia->ia_net : ia->ia_subnet))
                        return (1);
        return (0);
 }
 
                        return (1);
        return (0);
 }
 
+int    in_interfaces;          /* number of external internet interfaces */
+extern struct ifnet loif;
+
 /*
  * Generic internet control operations (ioctl's).
  * Ifp is 0 if not an interface-specific ioctl.
  */
 /*
  * Generic internet control operations (ioctl's).
  * Ifp is 0 if not an interface-specific ioctl.
  */
+/* ARGSUSED */
 in_control(so, cmd, data, ifp)
        struct socket *so;
        int cmd;
 in_control(so, cmd, data, ifp)
        struct socket *so;
        int cmd;
@@ -164,6 +176,7 @@ in_control(so, cmd, data, ifp)
 {
        register struct ifreq *ifr = (struct ifreq *)data;
        register struct in_ifaddr *ia = 0;
 {
        register struct ifreq *ifr = (struct ifreq *)data;
        register struct in_ifaddr *ia = 0;
+       u_long tmp;
        struct ifaddr *ifa;
        struct mbuf *m;
        int error;
        struct ifaddr *ifa;
        struct mbuf *m;
        int error;
@@ -178,18 +191,9 @@ in_control(so, cmd, data, ifp)
 
        switch (cmd) {
 
 
        switch (cmd) {
 
-       case SIOCGIFADDR:
-       case SIOCGIFBRDADDR:
-       case SIOCGIFDSTADDR:
-       case SIOCGIFNETMASK:
-               if (ia == (struct in_ifaddr *)0)
-                       return (EADDRNOTAVAIL);
-               break;
-
        case SIOCSIFADDR:
        case SIOCSIFADDR:
-       case SIOCSIFDSTADDR:
-       case SIOCSIFBRDADDR:
        case SIOCSIFNETMASK:
        case SIOCSIFNETMASK:
+       case SIOCSIFDSTADDR:
                if (!suser())
                        return (u.u_error);
 
                if (!suser())
                        return (u.u_error);
 
@@ -214,8 +218,20 @@ in_control(so, cmd, data, ifp)
                                ifp->if_addrlist = (struct ifaddr *) ia;
                        ia->ia_ifp = ifp;
                        IA_SIN(ia)->sin_family = AF_INET;
                                ifp->if_addrlist = (struct ifaddr *) ia;
                        ia->ia_ifp = ifp;
                        IA_SIN(ia)->sin_family = AF_INET;
+                       if (ifp != &loif)
+                               in_interfaces++;
                }
                break;
                }
                break;
+
+       case SIOCSIFBRDADDR:
+               if (!suser())
+                       return (u.u_error);
+               /* FALLTHROUGH */
+
+       default:
+               if (ia == (struct in_ifaddr *)0)
+                       return (EADDRNOTAVAIL);
+               break;
        }
 
        switch (cmd) {
        }
 
        switch (cmd) {
@@ -243,23 +259,41 @@ in_control(so, cmd, data, ifp)
                break;
 
        case SIOCSIFDSTADDR:
                break;
 
        case SIOCSIFDSTADDR:
+           {
+               struct sockaddr oldaddr;
+
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                        return (EINVAL);
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                        return (EINVAL);
+               oldaddr = ia->ia_dstaddr;
+               ia->ia_dstaddr = ifr->ifr_dstaddr;
                if (ifp->if_ioctl &&
                if (ifp->if_ioctl &&
-                   (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia)))
+                   (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
+                       ia->ia_dstaddr = oldaddr;
                        return (error);
                        return (error);
-               ia->ia_dstaddr = ifr->ifr_dstaddr;
+               }
+               if (ia->ia_flags & IFA_ROUTE) {
+                       rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
+                           RTF_HOST);
+                       rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
+                           RTF_HOST|RTF_UP);
+               }
+           }
                break;
 
        case SIOCSIFBRDADDR:
                if ((ifp->if_flags & IFF_BROADCAST) == 0)
                        return (EINVAL);
                ia->ia_broadaddr = ifr->ifr_broadaddr;
                break;
 
        case SIOCSIFBRDADDR:
                if ((ifp->if_flags & IFF_BROADCAST) == 0)
                        return (EINVAL);
                ia->ia_broadaddr = ifr->ifr_broadaddr;
+               tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
+               if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
+                       tmp |= ~ia->ia_netmask;
+               else if ((tmp &~ ia->ia_subnetmask) == 0)
+                       tmp &= ia->ia_netmask;
+               ia->ia_netbroadcast.s_addr = htonl(tmp);
                break;
 
        case SIOCSIFADDR:
                return (in_ifinit(ifp, ia, &ifr->ifr_addr));
                break;
 
        case SIOCSIFADDR:
                return (in_ifinit(ifp, ia, &ifr->ifr_addr));
-               break;
 
        case SIOCSIFNETMASK:
                ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
 
        case SIOCSIFNETMASK:
                ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
@@ -283,23 +317,43 @@ in_ifinit(ifp, ia, sin)
        struct sockaddr_in *sin;
 {
        register u_long i = ntohl(sin->sin_addr.s_addr);
        struct sockaddr_in *sin;
 {
        register u_long i = ntohl(sin->sin_addr.s_addr);
+       struct sockaddr oldaddr;
        struct sockaddr_in netaddr;
        int s = splimp(), error;
 
        struct sockaddr_in netaddr;
        int s = splimp(), error;
 
-       bzero((caddr_t)&netaddr, sizeof (netaddr));
-       netaddr.sin_family = AF_INET;
+       oldaddr = ia->ia_addr;
+       ia->ia_addr = *(struct sockaddr *)sin;
+
+       /*
+        * Give the interface a chance to initialize
+        * if this is its first address,
+        * and to validate the address if necessary.
+        */
+       if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+               splx(s);
+               ia->ia_addr = oldaddr;
+               return (error);
+       }
+
        /*
         * Delete any previous route for an old address.
         */
        /*
         * Delete any previous route for an old address.
         */
+       bzero((caddr_t)&netaddr, sizeof (netaddr));
+       netaddr.sin_family = AF_INET;
        if (ia->ia_flags & IFA_ROUTE) {
        if (ia->ia_flags & IFA_ROUTE) {
-               if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
-                   netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
-                   rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1);
-               } else
-                   rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1);
+               if (ifp->if_flags & IFF_LOOPBACK)
+                       rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
+               else if (ifp->if_flags & IFF_POINTOPOINT)
+                       rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
+                           RTF_HOST);
+               else {
+                       netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
+                           INADDR_ANY);
+                       rtinit((struct sockaddr *)&netaddr, &oldaddr, 
+                           (int)SIOCDELRT, 0);
+               }
                ia->ia_flags &= ~IFA_ROUTE;
        }
                ia->ia_flags &= ~IFA_ROUTE;
        }
-       ia->ia_addr = *(struct sockaddr *)sin;
        if (IN_CLASSA(i))
                ia->ia_netmask = IN_CLASSA_NET;
        else if (IN_CLASSB(i))
        if (IN_CLASSA(i))
                ia->ia_netmask = IN_CLASSA_NET;
        else if (IN_CLASSB(i))
@@ -317,29 +371,25 @@ in_ifinit(ifp, ia, sin)
                ia->ia_broadaddr.sa_family = AF_INET;
                ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
                        in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
                ia->ia_broadaddr.sa_family = AF_INET;
                ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
                        in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
+               ia->ia_netbroadcast.s_addr =
+                   htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
        }
        }
-
-       /*
-        * Give the interface a chance to initialize
-        * if this is its first address,
-        * and to validate the address if necessary.
-        */
-       if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
-               splx(s);
-               bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr));
-               return (error);
-       }
-       splx(s);
        /*
         * Add route for the network.
         */
        /*
         * Add route for the network.
         */
-       if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+       if (ifp->if_flags & IFF_LOOPBACK)
+               rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
+                   RTF_HOST|RTF_UP);
+       else if (ifp->if_flags & IFF_POINTOPOINT)
+               rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
+                   RTF_HOST|RTF_UP);
+       else {
                netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
                netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
-               rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP);
-       } else
-               rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
-                       RTF_HOST|RTF_UP);
+               rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
+                   (int)SIOCADDRT, RTF_UP);
+       }
        ia->ia_flags |= IFA_ROUTE;
        ia->ia_flags |= IFA_ROUTE;
+       splx(s);
        return (0);
 }
 
        return (0);
 }
 
@@ -359,21 +409,30 @@ in_iaonnetof(net)
 }
 
 /*
 }
 
 /*
- * Return 1 if the address is a local broadcast address.
+ * Return 1 if the address might be a local broadcast address.
  */
 in_broadcast(in)
        struct in_addr in;
 {
        register struct in_ifaddr *ia;
  */
 in_broadcast(in)
        struct in_addr in;
 {
        register struct in_ifaddr *ia;
+       u_long t;
 
        /*
         * Look through the list of addresses for a match
         * with a broadcast address.
         */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
 
        /*
         * Look through the list of addresses for a match
         * with a broadcast address.
         */
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
-           if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr ==
-               in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST))
+           if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
+               if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
                     return (1);
                     return (1);
+               /*
+                * Check for old-style (host 0) broadcast.
+                */
+               if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
+                   return (1);
+       }
+       if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
+               return (1);
        return (0);
 }
 #endif
        return (0);
 }
 #endif