123175Smckusick /* 229136Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 332787Sbostic * All rights reserved. 423175Smckusick * 532787Sbostic * Redistribution and use in source and binary forms are permitted 632787Sbostic * provided that this notice is preserved and that due credit is given 732787Sbostic * to the University of California at Berkeley. The name of the University 832787Sbostic * may not be used to endorse or promote products derived from this 932787Sbostic * software without specific prior written permission. This software 1032787Sbostic * is provided ``as is'' without express or implied warranty. 1132787Sbostic * 12*34500Skarels * @(#)in.c 7.8 (Berkeley) 05/26/88 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; 20718377Skarels struct ifaddr *ifa; 20818377Skarels struct mbuf *m; 20918377Skarels int error; 21018377Skarels 21118377Skarels /* 21218377Skarels * Find address for this interface, if it exists. 21318377Skarels */ 21418377Skarels if (ifp) 21518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 21618377Skarels if (ia->ia_ifp == ifp) 21718377Skarels break; 21818377Skarels 21918377Skarels switch (cmd) { 22018377Skarels 22118377Skarels case SIOCSIFADDR: 22218377Skarels case SIOCSIFNETMASK: 22326456Skarels case SIOCSIFDSTADDR: 22418377Skarels if (!suser()) 22518377Skarels return (u.u_error); 22618377Skarels 22718377Skarels if (ifp == 0) 22818377Skarels panic("in_control"); 22918377Skarels if (ia == (struct in_ifaddr *)0) { 23018377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 23118377Skarels if (m == (struct mbuf *)NULL) 23218377Skarels return (ENOBUFS); 23318377Skarels if (ia = in_ifaddr) { 23418377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 23518377Skarels ; 23618377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 23718377Skarels } else 23818377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 23918377Skarels ia = mtod(m, struct in_ifaddr *); 24018377Skarels if (ifa = ifp->if_addrlist) { 24118377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 24218377Skarels ; 24318377Skarels ifa->ifa_next = (struct ifaddr *) ia; 24418377Skarels } else 24518377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 24618377Skarels ia->ia_ifp = ifp; 24718377Skarels IA_SIN(ia)->sin_family = AF_INET; 24824805Skarels if (ifp != &loif) 24924805Skarels in_interfaces++; 25017271Skarels } 25118377Skarels break; 25226317Skarels 25326317Skarels case SIOCSIFBRDADDR: 25426317Skarels if (!suser()) 25526317Skarels return (u.u_error); 25626317Skarels /* FALLTHROUGH */ 25726317Skarels 25826317Skarels default: 25926317Skarels if (ia == (struct in_ifaddr *)0) 26026317Skarels return (EADDRNOTAVAIL); 26126317Skarels break; 26217271Skarels } 26318377Skarels 26418377Skarels switch (cmd) { 26518377Skarels 26618377Skarels case SIOCGIFADDR: 26718377Skarels ifr->ifr_addr = ia->ia_addr; 26818377Skarels break; 26918377Skarels 27018377Skarels case SIOCGIFBRDADDR: 27118377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 27218377Skarels return (EINVAL); 27318377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 27418377Skarels break; 27518377Skarels 27618377Skarels case SIOCGIFDSTADDR: 27718377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 27818377Skarels return (EINVAL); 27918377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 28018377Skarels break; 28118377Skarels 28218377Skarels case SIOCGIFNETMASK: 28318377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 28418377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 28518377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 28618377Skarels break; 28718377Skarels 28818377Skarels case SIOCSIFDSTADDR: 28927066Skarels { 29027066Skarels struct sockaddr oldaddr; 29127066Skarels 29218377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 29318377Skarels return (EINVAL); 29427066Skarels oldaddr = ia->ia_dstaddr; 29527066Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 29618377Skarels if (ifp->if_ioctl && 29727066Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 29827066Skarels ia->ia_dstaddr = oldaddr; 29918377Skarels return (error); 30027066Skarels } 30127066Skarels if (ia->ia_flags & IFA_ROUTE) { 30227066Skarels rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT, 30327066Skarels RTF_HOST); 30427066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 30527066Skarels RTF_HOST|RTF_UP); 30627066Skarels } 30727066Skarels } 30818377Skarels break; 30918377Skarels 31018377Skarels case SIOCSIFBRDADDR: 31118377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 31218377Skarels return (EINVAL); 31318377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 31418377Skarels break; 31518377Skarels 31618377Skarels case SIOCSIFADDR: 317*34500Skarels return (in_ifinit(ifp, ia, 318*34500Skarels (struct sockaddr_in *) &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