123175Smckusick /* 229136Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323175Smckusick * All rights reserved. The Berkeley software License Agreement 423175Smckusick * specifies the terms and conditions for redistribution. 523175Smckusick * 6*31392Skarels * @(#)in.c 7.5 (Berkeley) 06/04/87 723175Smckusick */ 87159Ssam 917058Sbloom #include "param.h" 1018377Skarels #include "ioctl.h" 1117058Sbloom #include "mbuf.h" 1217058Sbloom #include "protosw.h" 1317058Sbloom #include "socket.h" 1417058Sbloom #include "socketvar.h" 1518377Skarels #include "uio.h" 1618377Skarels #include "dir.h" 1718377Skarels #include "user.h" 1817058Sbloom #include "in_systm.h" 197166Ssam #include "../net/if.h" 207166Ssam #include "../net/route.h" 217159Ssam #include "../net/af.h" 2218377Skarels #include "in.h" 2318377Skarels #include "in_var.h" 247159Ssam 257159Ssam #ifdef INET 267159Ssam inet_hash(sin, hp) 277159Ssam register struct sockaddr_in *sin; 287159Ssam struct afhash *hp; 297159Ssam { 3018377Skarels register u_long n; 318595Sroot 3218377Skarels n = in_netof(sin->sin_addr); 3318377Skarels if (n) 3418377Skarels while ((n & 0xff) == 0) 3518377Skarels n >>= 8; 3618377Skarels hp->afh_nethash = n; 378937Sroot hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); 387159Ssam } 397159Ssam 407159Ssam inet_netmatch(sin1, sin2) 417159Ssam struct sockaddr_in *sin1, *sin2; 427159Ssam { 438595Sroot 4411566Ssam return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr)); 457159Ssam } 467159Ssam 477159Ssam /* 4818377Skarels * Formulate an Internet address from network + host. 497159Ssam */ 507159Ssam struct in_addr 5118377Skarels in_makeaddr(net, host) 5218377Skarels u_long net, host; 537159Ssam { 5418377Skarels register struct in_ifaddr *ia; 5518377Skarels register u_long mask; 567159Ssam u_long addr; 577159Ssam 5818377Skarels if (IN_CLASSA(net)) 5918377Skarels mask = IN_CLASSA_HOST; 6018377Skarels else if (IN_CLASSB(net)) 6118377Skarels mask = IN_CLASSB_HOST; 627159Ssam else 6318377Skarels mask = IN_CLASSC_HOST; 6418377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 6518377Skarels if ((ia->ia_netmask & net) == ia->ia_net) { 6618377Skarels mask = ~ia->ia_subnetmask; 6718377Skarels break; 6818377Skarels } 6918377Skarels addr = htonl(net | (host & mask)); 707159Ssam return (*(struct in_addr *)&addr); 717159Ssam } 727159Ssam 737159Ssam /* 748595Sroot * Return the network number from an internet address. 757159Ssam */ 7624805Skarels u_long 777159Ssam in_netof(in) 787159Ssam struct in_addr in; 797159Ssam { 808937Sroot register u_long i = ntohl(in.s_addr); 8118377Skarels register u_long net; 8218377Skarels register struct in_ifaddr *ia; 837159Ssam 8418377Skarels if (IN_CLASSA(i)) 8518377Skarels net = i & IN_CLASSA_NET; 8618377Skarels else if (IN_CLASSB(i)) 8718377Skarels net = i & IN_CLASSB_NET; 88*31392Skarels else if (IN_CLASSC(i)) 89*31392Skarels net = i & IN_CLASSC_NET; 9018377Skarels else 91*31392Skarels return (0); 9216413Skarels 9316413Skarels /* 9418377Skarels * Check whether network is a subnet; 9516413Skarels * if so, return subnet number. 9616413Skarels */ 9718377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 9824805Skarels if (net == ia->ia_net) 9918377Skarels return (i & ia->ia_subnetmask); 10016413Skarels return (net); 1017159Ssam } 1027159Ssam 1037159Ssam /* 1048595Sroot * Return the host portion of an internet address. 1057159Ssam */ 10626381Skarels u_long 1077159Ssam in_lnaof(in) 1087159Ssam struct in_addr in; 1097159Ssam { 1108937Sroot register u_long i = ntohl(in.s_addr); 11118377Skarels register u_long net, host; 11218377Skarels register struct in_ifaddr *ia; 1137159Ssam 11416377Skarels if (IN_CLASSA(i)) { 11518377Skarels net = i & IN_CLASSA_NET; 11618377Skarels host = i & IN_CLASSA_HOST; 11716377Skarels } else if (IN_CLASSB(i)) { 11818377Skarels net = i & IN_CLASSB_NET; 11918377Skarels host = i & IN_CLASSB_HOST; 120*31392Skarels } else if (IN_CLASSC(i)) { 12118377Skarels net = i & IN_CLASSC_NET; 12218377Skarels host = i & IN_CLASSC_HOST; 123*31392Skarels } else 124*31392Skarels return (i); 1257159Ssam 12616413Skarels /* 12718377Skarels * Check whether network is a subnet; 12816413Skarels * if so, use the modified interpretation of `host'. 12916413Skarels */ 13018377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 13124805Skarels if (net == ia->ia_net) 13218377Skarels return (host &~ ia->ia_subnetmask); 13316413Skarels return (host); 13416377Skarels } 13516377Skarels 13626381Skarels #ifndef SUBNETSARELOCAL 13726381Skarels #define SUBNETSARELOCAL 1 13826381Skarels #endif 13926381Skarels int subnetsarelocal = SUBNETSARELOCAL; 14016377Skarels /* 14118377Skarels * Return 1 if an internet address is for a ``local'' host 14226381Skarels * (one to which we have a connection). If subnetsarelocal 14326381Skarels * is true, this includes other subnets of the local net. 14426381Skarels * Otherwise, it includes only the directly-connected (sub)nets. 14517271Skarels */ 14617271Skarels in_localaddr(in) 14717271Skarels struct in_addr in; 14817271Skarels { 14917271Skarels register u_long i = ntohl(in.s_addr); 15018377Skarels register struct in_ifaddr *ia; 15117271Skarels 15230697Skarels if (subnetsarelocal) { 15330697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 15430697Skarels if ((i & ia->ia_netmask) == ia->ia_net) 15530697Skarels return (1); 15630697Skarels } else { 15730697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 15830697Skarels if ((i & ia->ia_subnetmask) == ia->ia_subnet) 15930697Skarels return (1); 16030697Skarels } 16118377Skarels return (0); 16218377Skarels } 16318377Skarels 164*31392Skarels /* 165*31392Skarels * Determine whether an IP address is in a reserved set of addresses 166*31392Skarels * that may not be forwarded, or whether datagrams to that destination 167*31392Skarels * may be forwarded. 168*31392Skarels */ 169*31392Skarels in_canforward(in) 170*31392Skarels struct in_addr in; 171*31392Skarels { 172*31392Skarels register u_long i = ntohl(in.s_addr); 173*31392Skarels register u_long net; 174*31392Skarels 175*31392Skarels if (IN_EXPERIMENTAL(i)) 176*31392Skarels return (0); 177*31392Skarels if (IN_CLASSA(i)) { 178*31392Skarels net = i & IN_CLASSA_NET; 179*31392Skarels if (net == 0 || net == IN_LOOPBACKNET) 180*31392Skarels return (0); 181*31392Skarels } 182*31392Skarels return (1); 183*31392Skarels } 184*31392Skarels 18524805Skarels int in_interfaces; /* number of external internet interfaces */ 18624805Skarels extern struct ifnet loif; 18724805Skarels 18818377Skarels /* 18918377Skarels * Generic internet control operations (ioctl's). 19018377Skarels * Ifp is 0 if not an interface-specific ioctl. 19118377Skarels */ 19224805Skarels /* ARGSUSED */ 19318377Skarels in_control(so, cmd, data, ifp) 19418377Skarels struct socket *so; 19518377Skarels int cmd; 19618377Skarels caddr_t data; 19718377Skarels register struct ifnet *ifp; 19818377Skarels { 19918377Skarels register struct ifreq *ifr = (struct ifreq *)data; 20018377Skarels register struct in_ifaddr *ia = 0; 20125195Skarels u_long tmp; 20218377Skarels struct ifaddr *ifa; 20318377Skarels struct mbuf *m; 20418377Skarels int error; 20518377Skarels 20618377Skarels /* 20718377Skarels * Find address for this interface, if it exists. 20818377Skarels */ 20918377Skarels if (ifp) 21018377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 21118377Skarels if (ia->ia_ifp == ifp) 21218377Skarels break; 21318377Skarels 21418377Skarels switch (cmd) { 21518377Skarels 21618377Skarels case SIOCSIFADDR: 21718377Skarels case SIOCSIFNETMASK: 21826456Skarels case SIOCSIFDSTADDR: 21918377Skarels if (!suser()) 22018377Skarels return (u.u_error); 22118377Skarels 22218377Skarels if (ifp == 0) 22318377Skarels panic("in_control"); 22418377Skarels if (ia == (struct in_ifaddr *)0) { 22518377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 22618377Skarels if (m == (struct mbuf *)NULL) 22718377Skarels return (ENOBUFS); 22818377Skarels if (ia = in_ifaddr) { 22918377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 23018377Skarels ; 23118377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 23218377Skarels } else 23318377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 23418377Skarels ia = mtod(m, struct in_ifaddr *); 23518377Skarels if (ifa = ifp->if_addrlist) { 23618377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 23718377Skarels ; 23818377Skarels ifa->ifa_next = (struct ifaddr *) ia; 23918377Skarels } else 24018377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 24118377Skarels ia->ia_ifp = ifp; 24218377Skarels IA_SIN(ia)->sin_family = AF_INET; 24324805Skarels if (ifp != &loif) 24424805Skarels in_interfaces++; 24517271Skarels } 24618377Skarels break; 24726317Skarels 24826317Skarels case SIOCSIFBRDADDR: 24926317Skarels if (!suser()) 25026317Skarels return (u.u_error); 25126317Skarels /* FALLTHROUGH */ 25226317Skarels 25326317Skarels default: 25426317Skarels if (ia == (struct in_ifaddr *)0) 25526317Skarels return (EADDRNOTAVAIL); 25626317Skarels break; 25717271Skarels } 25818377Skarels 25918377Skarels switch (cmd) { 26018377Skarels 26118377Skarels case SIOCGIFADDR: 26218377Skarels ifr->ifr_addr = ia->ia_addr; 26318377Skarels break; 26418377Skarels 26518377Skarels case SIOCGIFBRDADDR: 26618377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 26718377Skarels return (EINVAL); 26818377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 26918377Skarels break; 27018377Skarels 27118377Skarels case SIOCGIFDSTADDR: 27218377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 27318377Skarels return (EINVAL); 27418377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 27518377Skarels break; 27618377Skarels 27718377Skarels case SIOCGIFNETMASK: 27818377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 27918377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 28018377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 28118377Skarels break; 28218377Skarels 28318377Skarels case SIOCSIFDSTADDR: 28427066Skarels { 28527066Skarels struct sockaddr oldaddr; 28627066Skarels 28718377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 28818377Skarels return (EINVAL); 28927066Skarels oldaddr = ia->ia_dstaddr; 29027066Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 29118377Skarels if (ifp->if_ioctl && 29227066Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 29327066Skarels ia->ia_dstaddr = oldaddr; 29418377Skarels return (error); 29527066Skarels } 29627066Skarels if (ia->ia_flags & IFA_ROUTE) { 29727066Skarels rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT, 29827066Skarels RTF_HOST); 29927066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 30027066Skarels RTF_HOST|RTF_UP); 30127066Skarels } 30227066Skarels } 30318377Skarels break; 30418377Skarels 30518377Skarels case SIOCSIFBRDADDR: 30618377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 30718377Skarels return (EINVAL); 30818377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 30925195Skarels tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); 31025195Skarels if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) 31125195Skarels tmp |= ~ia->ia_netmask; 31225195Skarels else if ((tmp &~ ia->ia_subnetmask) == 0) 31325195Skarels tmp &= ia->ia_netmask; 31425195Skarels ia->ia_netbroadcast.s_addr = htonl(tmp); 31518377Skarels break; 31618377Skarels 31718377Skarels case SIOCSIFADDR: 31818377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 31918377Skarels 32018377Skarels case SIOCSIFNETMASK: 32118377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 32218377Skarels break; 32318377Skarels 32418377Skarels default: 32518377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 32618377Skarels return (EOPNOTSUPP); 32718377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 32818377Skarels } 32917271Skarels return (0); 33017271Skarels } 33117271Skarels 33217271Skarels /* 33318377Skarels * Initialize an interface's internet address 33418377Skarels * and routing table entry. 3357159Ssam */ 33618377Skarels in_ifinit(ifp, ia, sin) 3377159Ssam register struct ifnet *ifp; 33818377Skarels register struct in_ifaddr *ia; 33918377Skarels struct sockaddr_in *sin; 3407159Ssam { 34118377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 34227066Skarels struct sockaddr oldaddr; 34327066Skarels struct sockaddr_in netaddr; 34418377Skarels int s = splimp(), error; 3457159Ssam 34627066Skarels oldaddr = ia->ia_addr; 34726317Skarels ia->ia_addr = *(struct sockaddr *)sin; 34826317Skarels 34918377Skarels /* 35026317Skarels * Give the interface a chance to initialize 35126317Skarels * if this is its first address, 35226317Skarels * and to validate the address if necessary. 35326317Skarels */ 35426317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 35526317Skarels splx(s); 35627066Skarels ia->ia_addr = oldaddr; 35726317Skarels return (error); 35826317Skarels } 35926317Skarels 36026317Skarels /* 36118377Skarels * Delete any previous route for an old address. 36218377Skarels */ 36327066Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 36427066Skarels netaddr.sin_family = AF_INET; 36518377Skarels if (ia->ia_flags & IFA_ROUTE) { 36627066Skarels if (ifp->if_flags & IFF_LOOPBACK) 36727066Skarels rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST); 36827066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 36927066Skarels rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT, 37027066Skarels RTF_HOST); 37127066Skarels else { 37227066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, 37327066Skarels INADDR_ANY); 37427066Skarels rtinit((struct sockaddr *)&netaddr, &oldaddr, 37525452Ssklower (int)SIOCDELRT, 0); 37627066Skarels } 37718377Skarels ia->ia_flags &= ~IFA_ROUTE; 37818377Skarels } 37918377Skarels if (IN_CLASSA(i)) 38018377Skarels ia->ia_netmask = IN_CLASSA_NET; 38118377Skarels else if (IN_CLASSB(i)) 38218377Skarels ia->ia_netmask = IN_CLASSB_NET; 38318377Skarels else 38418377Skarels ia->ia_netmask = IN_CLASSC_NET; 38518377Skarels ia->ia_net = i & ia->ia_netmask; 38618377Skarels /* 38718377Skarels * The subnet mask includes at least the standard network part, 38818377Skarels * but may already have been set to a larger value. 38918377Skarels */ 39018377Skarels ia->ia_subnetmask |= ia->ia_netmask; 39118377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 39218377Skarels if (ifp->if_flags & IFF_BROADCAST) { 39318377Skarels ia->ia_broadaddr.sa_family = AF_INET; 39418377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 39518377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 39625195Skarels ia->ia_netbroadcast.s_addr = 39725195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 39818377Skarels } 39918377Skarels /* 40018377Skarels * Add route for the network. 40118377Skarels */ 40227066Skarels if (ifp->if_flags & IFF_LOOPBACK) 40327066Skarels rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, 40427066Skarels RTF_HOST|RTF_UP); 40527066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 40627066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 40727066Skarels RTF_HOST|RTF_UP); 40827066Skarels else { 40927066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 41027066Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 41127066Skarels (int)SIOCADDRT, RTF_UP); 41227066Skarels } 41318377Skarels ia->ia_flags |= IFA_ROUTE; 41430523Skarels splx(s); 41518642Skarels return (0); 4167159Ssam } 41718377Skarels 41818377Skarels /* 41918377Skarels * Return address info for specified internet network. 42018377Skarels */ 42118377Skarels struct in_ifaddr * 42218377Skarels in_iaonnetof(net) 42318377Skarels u_long net; 42418377Skarels { 42518377Skarels register struct in_ifaddr *ia; 42618377Skarels 42718377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 42818377Skarels if (ia->ia_subnet == net) 42918377Skarels return (ia); 43018377Skarels return ((struct in_ifaddr *)0); 43118377Skarels } 43218377Skarels 43318377Skarels /* 43430523Skarels * Return 1 if the address might be a local broadcast address. 43518377Skarels */ 43618377Skarels in_broadcast(in) 43718377Skarels struct in_addr in; 43818377Skarels { 43918377Skarels register struct in_ifaddr *ia; 44030523Skarels u_long t; 44118377Skarels 44218377Skarels /* 44318377Skarels * Look through the list of addresses for a match 44418377Skarels * with a broadcast address. 44518377Skarels */ 44618377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 44730523Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 44830523Skarels if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 44918377Skarels return (1); 45030523Skarels /* 45130523Skarels * Check for old-style (host 0) broadcast. 45230523Skarels */ 45330523Skarels if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net) 45430523Skarels return (1); 45530523Skarels } 45630523Skarels if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) 45730523Skarels return (1); 45818377Skarels return (0); 45918377Skarels } 4607159Ssam #endif 461