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*30697Skarels * @(#)in.c 7.4 (Berkeley) 03/30/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; 8818377Skarels else 8918377Skarels net = i & IN_CLASSC_NET; 9016413Skarels 9116413Skarels /* 9218377Skarels * Check whether network is a subnet; 9316413Skarels * if so, return subnet number. 9416413Skarels */ 9518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 9624805Skarels if (net == ia->ia_net) 9718377Skarels return (i & ia->ia_subnetmask); 9816413Skarels return (net); 997159Ssam } 1007159Ssam 1017159Ssam /* 1028595Sroot * Return the host portion of an internet address. 1037159Ssam */ 10426381Skarels u_long 1057159Ssam in_lnaof(in) 1067159Ssam struct in_addr in; 1077159Ssam { 1088937Sroot register u_long i = ntohl(in.s_addr); 10918377Skarels register u_long net, host; 11018377Skarels register struct in_ifaddr *ia; 1117159Ssam 11216377Skarels if (IN_CLASSA(i)) { 11318377Skarels net = i & IN_CLASSA_NET; 11418377Skarels host = i & IN_CLASSA_HOST; 11516377Skarels } else if (IN_CLASSB(i)) { 11618377Skarels net = i & IN_CLASSB_NET; 11718377Skarels host = i & IN_CLASSB_HOST; 11816377Skarels } else { 11918377Skarels net = i & IN_CLASSC_NET; 12018377Skarels host = i & IN_CLASSC_HOST; 12116377Skarels } 1227159Ssam 12316413Skarels /* 12418377Skarels * Check whether network is a subnet; 12516413Skarels * if so, use the modified interpretation of `host'. 12616413Skarels */ 12718377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 12824805Skarels if (net == ia->ia_net) 12918377Skarels return (host &~ ia->ia_subnetmask); 13016413Skarels return (host); 13116377Skarels } 13216377Skarels 13326381Skarels #ifndef SUBNETSARELOCAL 13426381Skarels #define SUBNETSARELOCAL 1 13526381Skarels #endif 13626381Skarels int subnetsarelocal = SUBNETSARELOCAL; 13716377Skarels /* 13818377Skarels * Return 1 if an internet address is for a ``local'' host 13926381Skarels * (one to which we have a connection). If subnetsarelocal 14026381Skarels * is true, this includes other subnets of the local net. 14126381Skarels * Otherwise, it includes only the directly-connected (sub)nets. 14217271Skarels */ 14317271Skarels in_localaddr(in) 14417271Skarels struct in_addr in; 14517271Skarels { 14617271Skarels register u_long i = ntohl(in.s_addr); 14718377Skarels register struct in_ifaddr *ia; 14817271Skarels 149*30697Skarels if (subnetsarelocal) { 150*30697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 151*30697Skarels if ((i & ia->ia_netmask) == ia->ia_net) 152*30697Skarels return (1); 153*30697Skarels } else { 154*30697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 155*30697Skarels if ((i & ia->ia_subnetmask) == ia->ia_subnet) 156*30697Skarels return (1); 157*30697Skarels } 15818377Skarels return (0); 15918377Skarels } 16018377Skarels 16124805Skarels int in_interfaces; /* number of external internet interfaces */ 16224805Skarels extern struct ifnet loif; 16324805Skarels 16418377Skarels /* 16518377Skarels * Generic internet control operations (ioctl's). 16618377Skarels * Ifp is 0 if not an interface-specific ioctl. 16718377Skarels */ 16824805Skarels /* ARGSUSED */ 16918377Skarels in_control(so, cmd, data, ifp) 17018377Skarels struct socket *so; 17118377Skarels int cmd; 17218377Skarels caddr_t data; 17318377Skarels register struct ifnet *ifp; 17418377Skarels { 17518377Skarels register struct ifreq *ifr = (struct ifreq *)data; 17618377Skarels register struct in_ifaddr *ia = 0; 17725195Skarels u_long tmp; 17818377Skarels struct ifaddr *ifa; 17918377Skarels struct mbuf *m; 18018377Skarels int error; 18118377Skarels 18218377Skarels /* 18318377Skarels * Find address for this interface, if it exists. 18418377Skarels */ 18518377Skarels if (ifp) 18618377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 18718377Skarels if (ia->ia_ifp == ifp) 18818377Skarels break; 18918377Skarels 19018377Skarels switch (cmd) { 19118377Skarels 19218377Skarels case SIOCSIFADDR: 19318377Skarels case SIOCSIFNETMASK: 19426456Skarels case SIOCSIFDSTADDR: 19518377Skarels if (!suser()) 19618377Skarels return (u.u_error); 19718377Skarels 19818377Skarels if (ifp == 0) 19918377Skarels panic("in_control"); 20018377Skarels if (ia == (struct in_ifaddr *)0) { 20118377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 20218377Skarels if (m == (struct mbuf *)NULL) 20318377Skarels return (ENOBUFS); 20418377Skarels if (ia = in_ifaddr) { 20518377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 20618377Skarels ; 20718377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 20818377Skarels } else 20918377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 21018377Skarels ia = mtod(m, struct in_ifaddr *); 21118377Skarels if (ifa = ifp->if_addrlist) { 21218377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 21318377Skarels ; 21418377Skarels ifa->ifa_next = (struct ifaddr *) ia; 21518377Skarels } else 21618377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 21718377Skarels ia->ia_ifp = ifp; 21818377Skarels IA_SIN(ia)->sin_family = AF_INET; 21924805Skarels if (ifp != &loif) 22024805Skarels in_interfaces++; 22117271Skarels } 22218377Skarels break; 22326317Skarels 22426317Skarels case SIOCSIFBRDADDR: 22526317Skarels if (!suser()) 22626317Skarels return (u.u_error); 22726317Skarels /* FALLTHROUGH */ 22826317Skarels 22926317Skarels default: 23026317Skarels if (ia == (struct in_ifaddr *)0) 23126317Skarels return (EADDRNOTAVAIL); 23226317Skarels break; 23317271Skarels } 23418377Skarels 23518377Skarels switch (cmd) { 23618377Skarels 23718377Skarels case SIOCGIFADDR: 23818377Skarels ifr->ifr_addr = ia->ia_addr; 23918377Skarels break; 24018377Skarels 24118377Skarels case SIOCGIFBRDADDR: 24218377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 24318377Skarels return (EINVAL); 24418377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 24518377Skarels break; 24618377Skarels 24718377Skarels case SIOCGIFDSTADDR: 24818377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 24918377Skarels return (EINVAL); 25018377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 25118377Skarels break; 25218377Skarels 25318377Skarels case SIOCGIFNETMASK: 25418377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 25518377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 25618377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 25718377Skarels break; 25818377Skarels 25918377Skarels case SIOCSIFDSTADDR: 26027066Skarels { 26127066Skarels struct sockaddr oldaddr; 26227066Skarels 26318377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 26418377Skarels return (EINVAL); 26527066Skarels oldaddr = ia->ia_dstaddr; 26627066Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 26718377Skarels if (ifp->if_ioctl && 26827066Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 26927066Skarels ia->ia_dstaddr = oldaddr; 27018377Skarels return (error); 27127066Skarels } 27227066Skarels if (ia->ia_flags & IFA_ROUTE) { 27327066Skarels rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT, 27427066Skarels RTF_HOST); 27527066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 27627066Skarels RTF_HOST|RTF_UP); 27727066Skarels } 27827066Skarels } 27918377Skarels break; 28018377Skarels 28118377Skarels case SIOCSIFBRDADDR: 28218377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 28318377Skarels return (EINVAL); 28418377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 28525195Skarels tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); 28625195Skarels if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) 28725195Skarels tmp |= ~ia->ia_netmask; 28825195Skarels else if ((tmp &~ ia->ia_subnetmask) == 0) 28925195Skarels tmp &= ia->ia_netmask; 29025195Skarels ia->ia_netbroadcast.s_addr = htonl(tmp); 29118377Skarels break; 29218377Skarels 29318377Skarels case SIOCSIFADDR: 29418377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 29518377Skarels 29618377Skarels case SIOCSIFNETMASK: 29718377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 29818377Skarels break; 29918377Skarels 30018377Skarels default: 30118377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 30218377Skarels return (EOPNOTSUPP); 30318377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 30418377Skarels } 30517271Skarels return (0); 30617271Skarels } 30717271Skarels 30817271Skarels /* 30918377Skarels * Initialize an interface's internet address 31018377Skarels * and routing table entry. 3117159Ssam */ 31218377Skarels in_ifinit(ifp, ia, sin) 3137159Ssam register struct ifnet *ifp; 31418377Skarels register struct in_ifaddr *ia; 31518377Skarels struct sockaddr_in *sin; 3167159Ssam { 31718377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 31827066Skarels struct sockaddr oldaddr; 31927066Skarels struct sockaddr_in netaddr; 32018377Skarels int s = splimp(), error; 3217159Ssam 32227066Skarels oldaddr = ia->ia_addr; 32326317Skarels ia->ia_addr = *(struct sockaddr *)sin; 32426317Skarels 32518377Skarels /* 32626317Skarels * Give the interface a chance to initialize 32726317Skarels * if this is its first address, 32826317Skarels * and to validate the address if necessary. 32926317Skarels */ 33026317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 33126317Skarels splx(s); 33227066Skarels ia->ia_addr = oldaddr; 33326317Skarels return (error); 33426317Skarels } 33526317Skarels 33626317Skarels /* 33718377Skarels * Delete any previous route for an old address. 33818377Skarels */ 33927066Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 34027066Skarels netaddr.sin_family = AF_INET; 34118377Skarels if (ia->ia_flags & IFA_ROUTE) { 34227066Skarels if (ifp->if_flags & IFF_LOOPBACK) 34327066Skarels rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST); 34427066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 34527066Skarels rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT, 34627066Skarels RTF_HOST); 34727066Skarels else { 34827066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, 34927066Skarels INADDR_ANY); 35027066Skarels rtinit((struct sockaddr *)&netaddr, &oldaddr, 35125452Ssklower (int)SIOCDELRT, 0); 35227066Skarels } 35318377Skarels ia->ia_flags &= ~IFA_ROUTE; 35418377Skarels } 35518377Skarels if (IN_CLASSA(i)) 35618377Skarels ia->ia_netmask = IN_CLASSA_NET; 35718377Skarels else if (IN_CLASSB(i)) 35818377Skarels ia->ia_netmask = IN_CLASSB_NET; 35918377Skarels else 36018377Skarels ia->ia_netmask = IN_CLASSC_NET; 36118377Skarels ia->ia_net = i & ia->ia_netmask; 36218377Skarels /* 36318377Skarels * The subnet mask includes at least the standard network part, 36418377Skarels * but may already have been set to a larger value. 36518377Skarels */ 36618377Skarels ia->ia_subnetmask |= ia->ia_netmask; 36718377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 36818377Skarels if (ifp->if_flags & IFF_BROADCAST) { 36918377Skarels ia->ia_broadaddr.sa_family = AF_INET; 37018377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 37118377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 37225195Skarels ia->ia_netbroadcast.s_addr = 37325195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 37418377Skarels } 37518377Skarels /* 37618377Skarels * Add route for the network. 37718377Skarels */ 37827066Skarels if (ifp->if_flags & IFF_LOOPBACK) 37927066Skarels rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, 38027066Skarels RTF_HOST|RTF_UP); 38127066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 38227066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 38327066Skarels RTF_HOST|RTF_UP); 38427066Skarels else { 38527066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 38627066Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 38727066Skarels (int)SIOCADDRT, RTF_UP); 38827066Skarels } 38918377Skarels ia->ia_flags |= IFA_ROUTE; 39030523Skarels splx(s); 39118642Skarels return (0); 3927159Ssam } 39318377Skarels 39418377Skarels /* 39518377Skarels * Return address info for specified internet network. 39618377Skarels */ 39718377Skarels struct in_ifaddr * 39818377Skarels in_iaonnetof(net) 39918377Skarels u_long net; 40018377Skarels { 40118377Skarels register struct in_ifaddr *ia; 40218377Skarels 40318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 40418377Skarels if (ia->ia_subnet == net) 40518377Skarels return (ia); 40618377Skarels return ((struct in_ifaddr *)0); 40718377Skarels } 40818377Skarels 40918377Skarels /* 41030523Skarels * Return 1 if the address might be a local broadcast address. 41118377Skarels */ 41218377Skarels in_broadcast(in) 41318377Skarels struct in_addr in; 41418377Skarels { 41518377Skarels register struct in_ifaddr *ia; 41630523Skarels u_long t; 41718377Skarels 41818377Skarels /* 41918377Skarels * Look through the list of addresses for a match 42018377Skarels * with a broadcast address. 42118377Skarels */ 42218377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 42330523Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 42430523Skarels if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 42518377Skarels return (1); 42630523Skarels /* 42730523Skarels * Check for old-style (host 0) broadcast. 42830523Skarels */ 42930523Skarels if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net) 43030523Skarels return (1); 43130523Skarels } 43230523Skarels if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) 43330523Skarels return (1); 43418377Skarels return (0); 43518377Skarels } 4367159Ssam #endif 437