X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/20666ad3e5f69f897fc87dcc46a82d12a0e60c3d..d360c192f460b2b2669e4ab61d385f5777bd15be:/usr/src/sys/netinet/in.c diff --git a/usr/src/sys/netinet/in.c b/usr/src/sys/netinet/in.c index 8c46237089..5085f9ee70 100644 --- a/usr/src/sys/netinet/in.c +++ b/usr/src/sys/netinet/in.c @@ -1,23 +1,39 @@ -/* in.c 6.4 84/08/29 */ +/* + * 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. + * + * @(#)in.c 7.2 (Berkeley) %G% + */ #include "param.h" +#include "ioctl.h" #include "mbuf.h" #include "protosw.h" #include "socket.h" #include "socketvar.h" -#include "in.h" +#include "uio.h" +#include "dir.h" +#include "user.h" #include "in_systm.h" #include "../net/if.h" #include "../net/route.h" #include "../net/af.h" +#include "in.h" +#include "in_var.h" #ifdef INET inet_hash(sin, hp) register struct sockaddr_in *sin; struct afhash *hp; { + register u_long n; - hp->afh_nethash = in_netof(sin->sin_addr); + n = in_netof(sin->sin_addr); + if (n) + while ((n & 0xff) == 0) + n >>= 8; + hp->afh_nethash = n; hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); } @@ -29,142 +45,385 @@ inet_netmatch(sin1, sin2) } /* - * Formulate an Internet address from network + host. Used in - * building addresses stored in the ifnet structure. + * Formulate an Internet address from network + host. */ struct in_addr -if_makeaddr(net, host) - int net, host; +in_makeaddr(net, host) + u_long net, host; { + register struct in_ifaddr *ia; + register u_long mask; u_long addr; - if (net < IN_CLASSA_MAX) - addr = (net << IN_CLASSA_NSHIFT) | host; - else if (net < IN_CLASSB_MAX) - addr = (net << IN_CLASSB_NSHIFT) | host; + if (IN_CLASSA(net)) + mask = IN_CLASSA_HOST; + else if (IN_CLASSB(net)) + mask = IN_CLASSB_HOST; else - addr = (net << IN_CLASSC_NSHIFT) | host; - addr = htonl(addr); + mask = IN_CLASSC_HOST; + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if ((ia->ia_netmask & net) == ia->ia_net) { + mask = ~ia->ia_subnetmask; + break; + } + addr = htonl(net | (host & mask)); return (*(struct in_addr *)&addr); } /* * Return the network number from an internet address. */ +u_long in_netof(in) struct in_addr in; { register u_long i = ntohl(in.s_addr); - register u_long net, subnet; - register struct ifnet *ifp; + register u_long net; + register struct in_ifaddr *ia; - if (IN_CLASSA(i)) { - net = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; - if (IN_SUBNETA(i)) { - subnet = (i & IN_CLASSA_SUBNET) >> IN_CLASSA_SUBNSHIFT; - /* Fall through and check whether a subnet */ - } else - return (net); - } else if (IN_CLASSB(i)) { - net = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; - if (IN_SUBNETB(i)) { - subnet = (i & IN_CLASSB_SUBNET) >> IN_CLASSB_SUBNSHIFT; - /* Fall through and check whether a subnet */ - } else - return (net); - } else { - return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); - } + if (IN_CLASSA(i)) + net = i & IN_CLASSA_NET; + else if (IN_CLASSB(i)) + net = i & IN_CLASSB_NET; + else + net = i & IN_CLASSC_NET; /* - * Check whether network is a subnet of a `local' network; + * Check whether network is a subnet; * if so, return subnet number. */ - for (ifp = ifnet; ifp; ifp = ifp->if_next) { - if (ifp->if_addr.sa_family != AF_INET) - continue; - if (ifp->if_flags & IFF_LOCAL) { - if (ifp->if_net == net) - return (subnet); - if ((ifp->if_net >> SUBNETSHIFT) == net) - return (subnet); - /* - * Hack for use in setting if_net initially. - */ - if (ifp->if_net == 0) { - register struct sockaddr_in *sin; - sin = (struct sockaddr_in *) &ifp->if_addr; - if (sin->sin_addr.s_addr == in.s_addr) - return (subnet); - } - } - } + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (net == ia->ia_net) + return (i & ia->ia_subnetmask); return (net); } /* * Return the host portion of an internet address. */ +u_long in_lnaof(in) struct in_addr in; { register u_long i = ntohl(in.s_addr); - register u_long net, host, subhost; - register struct ifnet *ifp; + register u_long net, host; + register struct in_ifaddr *ia; if (IN_CLASSA(i)) { - if (IN_SUBNETA(i)) { - net = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; - host = i & IN_CLASSA_HOST; - subhost = i & IN_CLASSA_SUBHOST; - /* Fall through and check whether a subnet */ - } else - return (i & IN_CLASSA_HOST); + net = i & IN_CLASSA_NET; + host = i & IN_CLASSA_HOST; } else if (IN_CLASSB(i)) { - if (IN_SUBNETB(i)) { - net = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; - host = i & IN_CLASSB_HOST; - subhost = i & IN_CLASSB_SUBHOST; - /* Fall through and check whether a subnet */ - } else - return (i & IN_CLASSB_HOST); + net = i & IN_CLASSB_NET; + host = i & IN_CLASSB_HOST; } else { - return (i & IN_CLASSC_HOST); + net = i & IN_CLASSC_NET; + host = i & IN_CLASSC_HOST; } /* - * Check whether network is a subnet of a `local' network; + * Check whether network is a subnet; * if so, use the modified interpretation of `host'. */ - for (ifp = ifnet; ifp; ifp = ifp->if_next) { - if (ifp->if_addr.sa_family != AF_INET) - continue; - if (ifp->if_flags & IFF_LOCAL) { - if (ifp->if_net == net) - return (subhost); - if ((ifp->if_net >> SUBNETSHIFT) == net) - return (subhost); + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (net == ia->ia_net) + 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 + * (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; +{ + register u_long i = ntohl(in.s_addr); + register u_long net; + register struct in_ifaddr *ia; + + if (IN_CLASSA(i)) + net = i & IN_CLASSA_NET; + else if (IN_CLASSB(i)) + net = i & IN_CLASSB_NET; + else + net = i & IN_CLASSC_NET; + + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (net == (subnetsarelocal ? ia->ia_net : ia->ia_subnet)) + 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. + */ +/* ARGSUSED */ +in_control(so, cmd, data, ifp) + struct socket *so; + int cmd; + caddr_t data; + register struct ifnet *ifp; +{ + register struct ifreq *ifr = (struct ifreq *)data; + register struct in_ifaddr *ia = 0; + u_long tmp; + struct ifaddr *ifa; + struct mbuf *m; + int error; + + /* + * Find address for this interface, if it exists. + */ + if (ifp) + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) + break; + + switch (cmd) { + + case SIOCSIFADDR: + case SIOCSIFNETMASK: + case SIOCSIFDSTADDR: + if (!suser()) + return (u.u_error); + + if (ifp == 0) + panic("in_control"); + if (ia == (struct in_ifaddr *)0) { + m = m_getclr(M_WAIT, MT_IFADDR); + if (m == (struct mbuf *)NULL) + return (ENOBUFS); + if (ia = in_ifaddr) { + for ( ; ia->ia_next; ia = ia->ia_next) + ; + ia->ia_next = mtod(m, struct in_ifaddr *); + } else + in_ifaddr = mtod(m, struct in_ifaddr *); + ia = mtod(m, struct in_ifaddr *); + if (ifa = ifp->if_addrlist) { + for ( ; ifa->ifa_next; ifa = ifa->ifa_next) + ; + ifa->ifa_next = (struct ifaddr *) ia; + } else + ifp->if_addrlist = (struct ifaddr *) ia; + ia->ia_ifp = ifp; + IA_SIN(ia)->sin_family = AF_INET; + if (ifp != &loif) + in_interfaces++; } + break; + + case SIOCSIFBRDADDR: + if (!suser()) + return (u.u_error); + /* FALLTHROUGH */ + + default: + if (ia == (struct in_ifaddr *)0) + return (EADDRNOTAVAIL); + break; } - return (host); + + switch (cmd) { + + case SIOCGIFADDR: + ifr->ifr_addr = ia->ia_addr; + break; + + case SIOCGIFBRDADDR: + if ((ifp->if_flags & IFF_BROADCAST) == 0) + return (EINVAL); + ifr->ifr_dstaddr = ia->ia_broadaddr; + break; + + case SIOCGIFDSTADDR: + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + ifr->ifr_dstaddr = ia->ia_dstaddr; + break; + + case SIOCGIFNETMASK: +#define satosin(sa) ((struct sockaddr_in *)(sa)) + satosin(&ifr->ifr_addr)->sin_family = AF_INET; + satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); + break; + + case SIOCSIFDSTADDR: + { + struct sockaddr oldaddr; + + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + oldaddr = ia->ia_dstaddr; + ia->ia_dstaddr = ifr->ifr_dstaddr; + if (ifp->if_ioctl && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { + ia->ia_dstaddr = oldaddr; + return (error); + } + 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; + 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)); + + case SIOCSIFNETMASK: + ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); + break; + + default: + if (ifp == 0 || ifp->if_ioctl == 0) + return (EOPNOTSUPP); + return ((*ifp->if_ioctl)(ifp, cmd, data)); + } + return (0); } /* - * Initialize an interface's routing - * table entry according to the network. - * INTERNET SPECIFIC. + * Initialize an interface's internet address + * and routing table entry. */ -if_rtinit(ifp, flags) +in_ifinit(ifp, ia, sin) register struct ifnet *ifp; - int flags; + register struct in_ifaddr *ia; + 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; + + 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. + */ + bzero((caddr_t)&netaddr, sizeof (netaddr)); + netaddr.sin_family = AF_INET; + if (ia->ia_flags & IFA_ROUTE) { + 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; + } + if (IN_CLASSA(i)) + ia->ia_netmask = IN_CLASSA_NET; + else if (IN_CLASSB(i)) + ia->ia_netmask = IN_CLASSB_NET; + else + ia->ia_netmask = IN_CLASSC_NET; + ia->ia_net = i & ia->ia_netmask; + /* + * The subnet mask includes at least the standard network part, + * but may already have been set to a larger value. + */ + ia->ia_subnetmask |= ia->ia_netmask; + ia->ia_subnet = i & ia->ia_subnetmask; + if (ifp->if_flags & IFF_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)); + } + splx(s); + /* + * Add route for the network. + */ + 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); + rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, + (int)SIOCADDRT, RTF_UP); + } + ia->ia_flags |= IFA_ROUTE; + return (0); +} + +/* + * Return address info for specified internet network. + */ +struct in_ifaddr * +in_iaonnetof(net) + u_long net; { - struct sockaddr_in sin; - - if (ifp->if_flags & IFF_ROUTE) - return; - bzero((caddr_t)&sin, sizeof (sin)); - sin.sin_family = AF_INET; - sin.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); - rtinit((struct sockaddr *)&sin, &ifp->if_addr, flags); + register struct in_ifaddr *ia; + + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_subnet == net) + return (ia); + return ((struct in_ifaddr *)0); +} + +/* + * Return 1 if the address is a local broadcast address. + */ +in_broadcast(in) + struct in_addr in; +{ + register struct in_ifaddr *ia; + + /* + * 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)) + return (1); + return (0); } #endif