123175Smckusick /* 229136Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*32787Sbostic * All rights reserved. 423175Smckusick * 5*32787Sbostic * Redistribution and use in source and binary forms are permitted 6*32787Sbostic * provided that this notice is preserved and that due credit is given 7*32787Sbostic * to the University of California at Berkeley. The name of the University 8*32787Sbostic * may not be used to endorse or promote products derived from this 9*32787Sbostic * software without specific prior written permission. This software 10*32787Sbostic * is provided ``as is'' without express or implied warranty. 11*32787Sbostic * 12*32787Sbostic * @(#)in.c 7.6 (Berkeley) 12/07/87 1323175Smckusick */ 147159Ssam 1517058Sbloom #include "param.h" 1618377Skarels #include "ioctl.h" 1717058Sbloom #include "mbuf.h" 1817058Sbloom #include "protosw.h" 1917058Sbloom #include "socket.h" 2017058Sbloom #include "socketvar.h" 2118377Skarels #include "uio.h" 2218377Skarels #include "dir.h" 2318377Skarels #include "user.h" 2417058Sbloom #include "in_systm.h" 257166Ssam #include "../net/if.h" 267166Ssam #include "../net/route.h" 277159Ssam #include "../net/af.h" 2818377Skarels #include "in.h" 2918377Skarels #include "in_var.h" 307159Ssam 317159Ssam #ifdef INET 327159Ssam inet_hash(sin, hp) 337159Ssam register struct sockaddr_in *sin; 347159Ssam struct afhash *hp; 357159Ssam { 3618377Skarels register u_long n; 378595Sroot 3818377Skarels n = in_netof(sin->sin_addr); 3918377Skarels if (n) 4018377Skarels while ((n & 0xff) == 0) 4118377Skarels n >>= 8; 4218377Skarels hp->afh_nethash = n; 438937Sroot hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); 447159Ssam } 457159Ssam 467159Ssam inet_netmatch(sin1, sin2) 477159Ssam struct sockaddr_in *sin1, *sin2; 487159Ssam { 498595Sroot 5011566Ssam return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr)); 517159Ssam } 527159Ssam 537159Ssam /* 5418377Skarels * Formulate an Internet address from network + host. 557159Ssam */ 567159Ssam struct in_addr 5718377Skarels in_makeaddr(net, host) 5818377Skarels u_long net, host; 597159Ssam { 6018377Skarels register struct in_ifaddr *ia; 6118377Skarels register u_long mask; 627159Ssam u_long addr; 637159Ssam 6418377Skarels if (IN_CLASSA(net)) 6518377Skarels mask = IN_CLASSA_HOST; 6618377Skarels else if (IN_CLASSB(net)) 6718377Skarels mask = IN_CLASSB_HOST; 687159Ssam else 6918377Skarels mask = IN_CLASSC_HOST; 7018377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 7118377Skarels if ((ia->ia_netmask & net) == ia->ia_net) { 7218377Skarels mask = ~ia->ia_subnetmask; 7318377Skarels break; 7418377Skarels } 7518377Skarels addr = htonl(net | (host & mask)); 767159Ssam return (*(struct in_addr *)&addr); 777159Ssam } 787159Ssam 797159Ssam /* 808595Sroot * Return the network number from an internet address. 817159Ssam */ 8224805Skarels u_long 837159Ssam in_netof(in) 847159Ssam struct in_addr in; 857159Ssam { 868937Sroot register u_long i = ntohl(in.s_addr); 8718377Skarels register u_long net; 8818377Skarels register struct in_ifaddr *ia; 897159Ssam 9018377Skarels if (IN_CLASSA(i)) 9118377Skarels net = i & IN_CLASSA_NET; 9218377Skarels else if (IN_CLASSB(i)) 9318377Skarels net = i & IN_CLASSB_NET; 9431392Skarels else if (IN_CLASSC(i)) 9531392Skarels net = i & IN_CLASSC_NET; 9618377Skarels else 9731392Skarels return (0); 9816413Skarels 9916413Skarels /* 10018377Skarels * Check whether network is a subnet; 10116413Skarels * if so, return subnet number. 10216413Skarels */ 10318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 10424805Skarels if (net == ia->ia_net) 10518377Skarels return (i & ia->ia_subnetmask); 10616413Skarels return (net); 1077159Ssam } 1087159Ssam 1097159Ssam /* 1108595Sroot * Return the host portion of an internet address. 1117159Ssam */ 11226381Skarels u_long 1137159Ssam in_lnaof(in) 1147159Ssam struct in_addr in; 1157159Ssam { 1168937Sroot register u_long i = ntohl(in.s_addr); 11718377Skarels register u_long net, host; 11818377Skarels register struct in_ifaddr *ia; 1197159Ssam 12016377Skarels if (IN_CLASSA(i)) { 12118377Skarels net = i & IN_CLASSA_NET; 12218377Skarels host = i & IN_CLASSA_HOST; 12316377Skarels } else if (IN_CLASSB(i)) { 12418377Skarels net = i & IN_CLASSB_NET; 12518377Skarels host = i & IN_CLASSB_HOST; 12631392Skarels } else if (IN_CLASSC(i)) { 12718377Skarels net = i & IN_CLASSC_NET; 12818377Skarels host = i & IN_CLASSC_HOST; 12931392Skarels } else 13031392Skarels return (i); 1317159Ssam 13216413Skarels /* 13318377Skarels * Check whether network is a subnet; 13416413Skarels * if so, use the modified interpretation of `host'. 13516413Skarels */ 13618377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 13724805Skarels if (net == ia->ia_net) 13818377Skarels return (host &~ ia->ia_subnetmask); 13916413Skarels return (host); 14016377Skarels } 14116377Skarels 14226381Skarels #ifndef SUBNETSARELOCAL 14326381Skarels #define SUBNETSARELOCAL 1 14426381Skarels #endif 14526381Skarels int subnetsarelocal = SUBNETSARELOCAL; 14616377Skarels /* 14718377Skarels * Return 1 if an internet address is for a ``local'' host 14826381Skarels * (one to which we have a connection). If subnetsarelocal 14926381Skarels * is true, this includes other subnets of the local net. 15026381Skarels * Otherwise, it includes only the directly-connected (sub)nets. 15117271Skarels */ 15217271Skarels in_localaddr(in) 15317271Skarels struct in_addr in; 15417271Skarels { 15517271Skarels register u_long i = ntohl(in.s_addr); 15618377Skarels register struct in_ifaddr *ia; 15717271Skarels 15830697Skarels if (subnetsarelocal) { 15930697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 16030697Skarels if ((i & ia->ia_netmask) == ia->ia_net) 16130697Skarels return (1); 16230697Skarels } else { 16330697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 16430697Skarels if ((i & ia->ia_subnetmask) == ia->ia_subnet) 16530697Skarels return (1); 16630697Skarels } 16718377Skarels return (0); 16818377Skarels } 16918377Skarels 17031392Skarels /* 17131392Skarels * Determine whether an IP address is in a reserved set of addresses 17231392Skarels * that may not be forwarded, or whether datagrams to that destination 17331392Skarels * may be forwarded. 17431392Skarels */ 17531392Skarels in_canforward(in) 17631392Skarels struct in_addr in; 17731392Skarels { 17831392Skarels register u_long i = ntohl(in.s_addr); 17931392Skarels register u_long net; 18031392Skarels 18131392Skarels if (IN_EXPERIMENTAL(i)) 18231392Skarels return (0); 18331392Skarels if (IN_CLASSA(i)) { 18431392Skarels net = i & IN_CLASSA_NET; 18531392Skarels if (net == 0 || net == IN_LOOPBACKNET) 18631392Skarels return (0); 18731392Skarels } 18831392Skarels return (1); 18931392Skarels } 19031392Skarels 19124805Skarels int in_interfaces; /* number of external internet interfaces */ 19224805Skarels extern struct ifnet loif; 19324805Skarels 19418377Skarels /* 19518377Skarels * Generic internet control operations (ioctl's). 19618377Skarels * Ifp is 0 if not an interface-specific ioctl. 19718377Skarels */ 19824805Skarels /* ARGSUSED */ 19918377Skarels in_control(so, cmd, data, ifp) 20018377Skarels struct socket *so; 20118377Skarels int cmd; 20218377Skarels caddr_t data; 20318377Skarels register struct ifnet *ifp; 20418377Skarels { 20518377Skarels register struct ifreq *ifr = (struct ifreq *)data; 20618377Skarels register struct in_ifaddr *ia = 0; 20725195Skarels u_long tmp; 20818377Skarels struct ifaddr *ifa; 20918377Skarels struct mbuf *m; 21018377Skarels int error; 21118377Skarels 21218377Skarels /* 21318377Skarels * Find address for this interface, if it exists. 21418377Skarels */ 21518377Skarels if (ifp) 21618377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 21718377Skarels if (ia->ia_ifp == ifp) 21818377Skarels break; 21918377Skarels 22018377Skarels switch (cmd) { 22118377Skarels 22218377Skarels case SIOCSIFADDR: 22318377Skarels case SIOCSIFNETMASK: 22426456Skarels case SIOCSIFDSTADDR: 22518377Skarels if (!suser()) 22618377Skarels return (u.u_error); 22718377Skarels 22818377Skarels if (ifp == 0) 22918377Skarels panic("in_control"); 23018377Skarels if (ia == (struct in_ifaddr *)0) { 23118377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 23218377Skarels if (m == (struct mbuf *)NULL) 23318377Skarels return (ENOBUFS); 23418377Skarels if (ia = in_ifaddr) { 23518377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 23618377Skarels ; 23718377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 23818377Skarels } else 23918377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 24018377Skarels ia = mtod(m, struct in_ifaddr *); 24118377Skarels if (ifa = ifp->if_addrlist) { 24218377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 24318377Skarels ; 24418377Skarels ifa->ifa_next = (struct ifaddr *) ia; 24518377Skarels } else 24618377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 24718377Skarels ia->ia_ifp = ifp; 24818377Skarels IA_SIN(ia)->sin_family = AF_INET; 24924805Skarels if (ifp != &loif) 25024805Skarels in_interfaces++; 25117271Skarels } 25218377Skarels break; 25326317Skarels 25426317Skarels case SIOCSIFBRDADDR: 25526317Skarels if (!suser()) 25626317Skarels return (u.u_error); 25726317Skarels /* FALLTHROUGH */ 25826317Skarels 25926317Skarels default: 26026317Skarels if (ia == (struct in_ifaddr *)0) 26126317Skarels return (EADDRNOTAVAIL); 26226317Skarels break; 26317271Skarels } 26418377Skarels 26518377Skarels switch (cmd) { 26618377Skarels 26718377Skarels case SIOCGIFADDR: 26818377Skarels ifr->ifr_addr = ia->ia_addr; 26918377Skarels break; 27018377Skarels 27118377Skarels case SIOCGIFBRDADDR: 27218377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 27318377Skarels return (EINVAL); 27418377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 27518377Skarels break; 27618377Skarels 27718377Skarels case SIOCGIFDSTADDR: 27818377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 27918377Skarels return (EINVAL); 28018377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 28118377Skarels break; 28218377Skarels 28318377Skarels case SIOCGIFNETMASK: 28418377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 28518377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 28618377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 28718377Skarels break; 28818377Skarels 28918377Skarels case SIOCSIFDSTADDR: 29027066Skarels { 29127066Skarels struct sockaddr oldaddr; 29227066Skarels 29318377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 29418377Skarels return (EINVAL); 29527066Skarels oldaddr = ia->ia_dstaddr; 29627066Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 29718377Skarels if (ifp->if_ioctl && 29827066Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 29927066Skarels ia->ia_dstaddr = oldaddr; 30018377Skarels return (error); 30127066Skarels } 30227066Skarels if (ia->ia_flags & IFA_ROUTE) { 30327066Skarels rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT, 30427066Skarels RTF_HOST); 30527066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 30627066Skarels RTF_HOST|RTF_UP); 30727066Skarels } 30827066Skarels } 30918377Skarels break; 31018377Skarels 31118377Skarels case SIOCSIFBRDADDR: 31218377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 31318377Skarels return (EINVAL); 31418377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 31525195Skarels tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); 31625195Skarels if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) 31725195Skarels tmp |= ~ia->ia_netmask; 31825195Skarels else if ((tmp &~ ia->ia_subnetmask) == 0) 31925195Skarels tmp &= ia->ia_netmask; 32025195Skarels ia->ia_netbroadcast.s_addr = htonl(tmp); 32118377Skarels break; 32218377Skarels 32318377Skarels case SIOCSIFADDR: 32418377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 32518377Skarels 32618377Skarels case SIOCSIFNETMASK: 32718377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 32818377Skarels break; 32918377Skarels 33018377Skarels default: 33118377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 33218377Skarels return (EOPNOTSUPP); 33318377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 33418377Skarels } 33517271Skarels return (0); 33617271Skarels } 33717271Skarels 33817271Skarels /* 33918377Skarels * Initialize an interface's internet address 34018377Skarels * and routing table entry. 3417159Ssam */ 34218377Skarels in_ifinit(ifp, ia, sin) 3437159Ssam register struct ifnet *ifp; 34418377Skarels register struct in_ifaddr *ia; 34518377Skarels struct sockaddr_in *sin; 3467159Ssam { 34718377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 34827066Skarels struct sockaddr oldaddr; 34927066Skarels struct sockaddr_in netaddr; 35018377Skarels int s = splimp(), error; 3517159Ssam 35227066Skarels oldaddr = ia->ia_addr; 35326317Skarels ia->ia_addr = *(struct sockaddr *)sin; 35426317Skarels 35518377Skarels /* 35626317Skarels * Give the interface a chance to initialize 35726317Skarels * if this is its first address, 35826317Skarels * and to validate the address if necessary. 35926317Skarels */ 36026317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 36126317Skarels splx(s); 36227066Skarels ia->ia_addr = oldaddr; 36326317Skarels return (error); 36426317Skarels } 36526317Skarels 36626317Skarels /* 36718377Skarels * Delete any previous route for an old address. 36818377Skarels */ 36927066Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 37027066Skarels netaddr.sin_family = AF_INET; 37118377Skarels if (ia->ia_flags & IFA_ROUTE) { 37227066Skarels if (ifp->if_flags & IFF_LOOPBACK) 37327066Skarels rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST); 37427066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 37527066Skarels rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT, 37627066Skarels RTF_HOST); 37727066Skarels else { 37827066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, 37927066Skarels INADDR_ANY); 38027066Skarels rtinit((struct sockaddr *)&netaddr, &oldaddr, 38125452Ssklower (int)SIOCDELRT, 0); 38227066Skarels } 38318377Skarels ia->ia_flags &= ~IFA_ROUTE; 38418377Skarels } 38518377Skarels if (IN_CLASSA(i)) 38618377Skarels ia->ia_netmask = IN_CLASSA_NET; 38718377Skarels else if (IN_CLASSB(i)) 38818377Skarels ia->ia_netmask = IN_CLASSB_NET; 38918377Skarels else 39018377Skarels ia->ia_netmask = IN_CLASSC_NET; 39118377Skarels ia->ia_net = i & ia->ia_netmask; 39218377Skarels /* 39318377Skarels * The subnet mask includes at least the standard network part, 39418377Skarels * but may already have been set to a larger value. 39518377Skarels */ 39618377Skarels ia->ia_subnetmask |= ia->ia_netmask; 39718377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 39818377Skarels if (ifp->if_flags & IFF_BROADCAST) { 39918377Skarels ia->ia_broadaddr.sa_family = AF_INET; 40018377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 40118377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 40225195Skarels ia->ia_netbroadcast.s_addr = 40325195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 40418377Skarels } 40518377Skarels /* 40618377Skarels * Add route for the network. 40718377Skarels */ 40827066Skarels if (ifp->if_flags & IFF_LOOPBACK) 40927066Skarels rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, 41027066Skarels RTF_HOST|RTF_UP); 41127066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 41227066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 41327066Skarels RTF_HOST|RTF_UP); 41427066Skarels else { 41527066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 41627066Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 41727066Skarels (int)SIOCADDRT, RTF_UP); 41827066Skarels } 41918377Skarels ia->ia_flags |= IFA_ROUTE; 42030523Skarels splx(s); 42118642Skarels return (0); 4227159Ssam } 42318377Skarels 42418377Skarels /* 42518377Skarels * Return address info for specified internet network. 42618377Skarels */ 42718377Skarels struct in_ifaddr * 42818377Skarels in_iaonnetof(net) 42918377Skarels u_long net; 43018377Skarels { 43118377Skarels register struct in_ifaddr *ia; 43218377Skarels 43318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 43418377Skarels if (ia->ia_subnet == net) 43518377Skarels return (ia); 43618377Skarels return ((struct in_ifaddr *)0); 43718377Skarels } 43818377Skarels 43918377Skarels /* 44030523Skarels * Return 1 if the address might be a local broadcast address. 44118377Skarels */ 44218377Skarels in_broadcast(in) 44318377Skarels struct in_addr in; 44418377Skarels { 44518377Skarels register struct in_ifaddr *ia; 44630523Skarels u_long t; 44718377Skarels 44818377Skarels /* 44918377Skarels * Look through the list of addresses for a match 45018377Skarels * with a broadcast address. 45118377Skarels */ 45218377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 45330523Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 45430523Skarels if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 45518377Skarels return (1); 45630523Skarels /* 45730523Skarels * Check for old-style (host 0) broadcast. 45830523Skarels */ 45930523Skarels if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net) 46030523Skarels return (1); 46130523Skarels } 46230523Skarels if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) 46330523Skarels return (1); 46418377Skarels return (0); 46518377Skarels } 4667159Ssam #endif 467