123175Smckusick /* 223175Smckusick * Copyright (c) 1982 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*26381Skarels * @(#)in.c 6.13 (Berkeley) 02/23/86 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 */ 104*26381Skarels 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 133*26381Skarels #ifndef SUBNETSARELOCAL 134*26381Skarels #define SUBNETSARELOCAL 1 135*26381Skarels #endif 136*26381Skarels int subnetsarelocal = SUBNETSARELOCAL; 13716377Skarels /* 13818377Skarels * Return 1 if an internet address is for a ``local'' host 139*26381Skarels * (one to which we have a connection). If subnetsarelocal 140*26381Skarels * is true, this includes other subnets of the local net. 141*26381Skarels * 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); 14717271Skarels register u_long net; 14818377Skarels register struct in_ifaddr *ia; 14917271Skarels 15017271Skarels if (IN_CLASSA(i)) 15118377Skarels net = i & IN_CLASSA_NET; 15217271Skarels else if (IN_CLASSB(i)) 15318377Skarels net = i & IN_CLASSB_NET; 15417271Skarels else 15518377Skarels net = i & IN_CLASSC_NET; 15617271Skarels 15718377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 158*26381Skarels if (net == subnetsarelocal ? ia->ia_net : ia->ia_subnet) 15918377Skarels return (1); 16018377Skarels return (0); 16118377Skarels } 16218377Skarels 16324805Skarels int in_interfaces; /* number of external internet interfaces */ 16424805Skarels extern struct ifnet loif; 16524805Skarels 16618377Skarels /* 16718377Skarels * Generic internet control operations (ioctl's). 16818377Skarels * Ifp is 0 if not an interface-specific ioctl. 16918377Skarels */ 17024805Skarels /* ARGSUSED */ 17118377Skarels in_control(so, cmd, data, ifp) 17218377Skarels struct socket *so; 17318377Skarels int cmd; 17418377Skarels caddr_t data; 17518377Skarels register struct ifnet *ifp; 17618377Skarels { 17718377Skarels register struct ifreq *ifr = (struct ifreq *)data; 17818377Skarels register struct in_ifaddr *ia = 0; 17925195Skarels u_long tmp; 18018377Skarels struct ifaddr *ifa; 18118377Skarels struct mbuf *m; 18218377Skarels int error; 18318377Skarels 18418377Skarels /* 18518377Skarels * Find address for this interface, if it exists. 18618377Skarels */ 18718377Skarels if (ifp) 18818377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 18918377Skarels if (ia->ia_ifp == ifp) 19018377Skarels break; 19118377Skarels 19218377Skarels switch (cmd) { 19318377Skarels 19418377Skarels case SIOCSIFADDR: 19518377Skarels case SIOCSIFNETMASK: 19618377Skarels if (!suser()) 19718377Skarels return (u.u_error); 19818377Skarels 19918377Skarels if (ifp == 0) 20018377Skarels panic("in_control"); 20118377Skarels if (ia == (struct in_ifaddr *)0) { 20218377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 20318377Skarels if (m == (struct mbuf *)NULL) 20418377Skarels return (ENOBUFS); 20518377Skarels if (ia = in_ifaddr) { 20618377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 20718377Skarels ; 20818377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 20918377Skarels } else 21018377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 21118377Skarels ia = mtod(m, struct in_ifaddr *); 21218377Skarels if (ifa = ifp->if_addrlist) { 21318377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 21418377Skarels ; 21518377Skarels ifa->ifa_next = (struct ifaddr *) ia; 21618377Skarels } else 21718377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 21818377Skarels ia->ia_ifp = ifp; 21918377Skarels IA_SIN(ia)->sin_family = AF_INET; 22024805Skarels if (ifp != &loif) 22124805Skarels in_interfaces++; 22217271Skarels } 22318377Skarels break; 22426317Skarels 22526317Skarels case SIOCSIFBRDADDR: 22626317Skarels case SIOCSIFDSTADDR: 22726317Skarels if (!suser()) 22826317Skarels return (u.u_error); 22926317Skarels /* FALLTHROUGH */ 23026317Skarels 23126317Skarels default: 23226317Skarels if (ia == (struct in_ifaddr *)0) 23326317Skarels return (EADDRNOTAVAIL); 23426317Skarels break; 23517271Skarels } 23618377Skarels 23718377Skarels switch (cmd) { 23818377Skarels 23918377Skarels case SIOCGIFADDR: 24018377Skarels ifr->ifr_addr = ia->ia_addr; 24118377Skarels break; 24218377Skarels 24318377Skarels case SIOCGIFBRDADDR: 24418377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 24518377Skarels return (EINVAL); 24618377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 24718377Skarels break; 24818377Skarels 24918377Skarels case SIOCGIFDSTADDR: 25018377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 25118377Skarels return (EINVAL); 25218377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 25318377Skarels break; 25418377Skarels 25518377Skarels case SIOCGIFNETMASK: 25618377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 25718377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 25818377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 25918377Skarels break; 26018377Skarels 26118377Skarels case SIOCSIFDSTADDR: 26218377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 26318377Skarels return (EINVAL); 26418377Skarels if (ifp->if_ioctl && 26524805Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) 26618377Skarels return (error); 26718377Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 26818377Skarels break; 26918377Skarels 27018377Skarels case SIOCSIFBRDADDR: 27118377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 27218377Skarels return (EINVAL); 27318377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 27425195Skarels tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); 27525195Skarels if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) 27625195Skarels tmp |= ~ia->ia_netmask; 27725195Skarels else if ((tmp &~ ia->ia_subnetmask) == 0) 27825195Skarels tmp &= ia->ia_netmask; 27925195Skarels ia->ia_netbroadcast.s_addr = htonl(tmp); 28018377Skarels break; 28118377Skarels 28218377Skarels case SIOCSIFADDR: 28318377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 28418377Skarels 28518377Skarels case SIOCSIFNETMASK: 28618377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 28718377Skarels break; 28818377Skarels 28918377Skarels default: 29018377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 29118377Skarels return (EOPNOTSUPP); 29218377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 29318377Skarels } 29417271Skarels return (0); 29517271Skarels } 29617271Skarels 29717271Skarels /* 29818377Skarels * Initialize an interface's internet address 29918377Skarels * and routing table entry. 3007159Ssam */ 30118377Skarels in_ifinit(ifp, ia, sin) 3027159Ssam register struct ifnet *ifp; 30318377Skarels register struct in_ifaddr *ia; 30418377Skarels struct sockaddr_in *sin; 3057159Ssam { 30618377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 30726317Skarels struct sockaddr_in tmpaddr; 30818377Skarels int s = splimp(), error; 3097159Ssam 31026317Skarels tmpaddr = *(struct sockaddr_in *)&ia->ia_addr; 31126317Skarels ia->ia_addr = *(struct sockaddr *)sin; 31226317Skarels 31318377Skarels /* 31426317Skarels * Give the interface a chance to initialize 31526317Skarels * if this is its first address, 31626317Skarels * and to validate the address if necessary. 31726317Skarels */ 31826317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 31926317Skarels splx(s); 32026317Skarels ia->ia_addr = *(struct sockaddr *)&tmpaddr; 32126317Skarels return (error); 32226317Skarels } 32326317Skarels 32426317Skarels bzero((caddr_t)&tmpaddr, sizeof (tmpaddr)); 32526317Skarels tmpaddr.sin_family = AF_INET; 32626317Skarels /* 32718377Skarels * Delete any previous route for an old address. 32818377Skarels */ 32918377Skarels if (ia->ia_flags & IFA_ROUTE) { 33018377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 33126317Skarels tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 33226317Skarels rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr, 33325452Ssklower (int)SIOCDELRT, 0); 33418377Skarels } else 33525452Ssklower rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 33625452Ssklower (int)SIOCDELRT, RTF_HOST); 33718377Skarels ia->ia_flags &= ~IFA_ROUTE; 33818377Skarels } 33918377Skarels if (IN_CLASSA(i)) 34018377Skarels ia->ia_netmask = IN_CLASSA_NET; 34118377Skarels else if (IN_CLASSB(i)) 34218377Skarels ia->ia_netmask = IN_CLASSB_NET; 34318377Skarels else 34418377Skarels ia->ia_netmask = IN_CLASSC_NET; 34518377Skarels ia->ia_net = i & ia->ia_netmask; 34618377Skarels /* 34718377Skarels * The subnet mask includes at least the standard network part, 34818377Skarels * but may already have been set to a larger value. 34918377Skarels */ 35018377Skarels ia->ia_subnetmask |= ia->ia_netmask; 35118377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 35218377Skarels if (ifp->if_flags & IFF_BROADCAST) { 35318377Skarels ia->ia_broadaddr.sa_family = AF_INET; 35418377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 35518377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 35625195Skarels ia->ia_netbroadcast.s_addr = 35725195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 35818377Skarels } 35918377Skarels splx(s); 36018377Skarels /* 36118377Skarels * Add route for the network. 36218377Skarels */ 36318377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 36426317Skarels tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 36526317Skarels rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr, 36625452Ssklower (int)SIOCADDRT, RTF_UP); 36718377Skarels } else 36818377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 36925452Ssklower (int)SIOCADDRT, RTF_HOST|RTF_UP); 37018377Skarels ia->ia_flags |= IFA_ROUTE; 37118642Skarels return (0); 3727159Ssam } 37318377Skarels 37418377Skarels /* 37518377Skarels * Return address info for specified internet network. 37618377Skarels */ 37718377Skarels struct in_ifaddr * 37818377Skarels in_iaonnetof(net) 37918377Skarels u_long net; 38018377Skarels { 38118377Skarels register struct in_ifaddr *ia; 38218377Skarels 38318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 38418377Skarels if (ia->ia_subnet == net) 38518377Skarels return (ia); 38618377Skarels return ((struct in_ifaddr *)0); 38718377Skarels } 38818377Skarels 38918377Skarels /* 39018377Skarels * Return 1 if the address is a local broadcast address. 39118377Skarels */ 39218377Skarels in_broadcast(in) 39318377Skarels struct in_addr in; 39418377Skarels { 39518377Skarels register struct in_ifaddr *ia; 39618377Skarels 39718377Skarels /* 39818377Skarels * Look through the list of addresses for a match 39918377Skarels * with a broadcast address. 40018377Skarels */ 40118377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 40218377Skarels if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == 40318377Skarels in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) 40418377Skarels return (1); 40518377Skarels return (0); 40618377Skarels } 4077159Ssam #endif 408