1*18642Skarels /* in.c 6.7 85/04/16 */ 27159Ssam 317058Sbloom #include "param.h" 418377Skarels #include "ioctl.h" 517058Sbloom #include "mbuf.h" 617058Sbloom #include "protosw.h" 717058Sbloom #include "socket.h" 817058Sbloom #include "socketvar.h" 918377Skarels #include "uio.h" 1018377Skarels #include "dir.h" 1118377Skarels #include "user.h" 1217058Sbloom #include "in_systm.h" 137166Ssam #include "../net/if.h" 147166Ssam #include "../net/route.h" 157159Ssam #include "../net/af.h" 1618377Skarels #include "in.h" 1718377Skarels #include "in_var.h" 187159Ssam 197159Ssam #ifdef INET 207159Ssam inet_hash(sin, hp) 217159Ssam register struct sockaddr_in *sin; 227159Ssam struct afhash *hp; 237159Ssam { 2418377Skarels register u_long n; 258595Sroot 2618377Skarels n = in_netof(sin->sin_addr); 2718377Skarels if (n) 2818377Skarels while ((n & 0xff) == 0) 2918377Skarels n >>= 8; 3018377Skarels hp->afh_nethash = n; 318937Sroot hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); 327159Ssam } 337159Ssam 347159Ssam inet_netmatch(sin1, sin2) 357159Ssam struct sockaddr_in *sin1, *sin2; 367159Ssam { 378595Sroot 3811566Ssam return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr)); 397159Ssam } 407159Ssam 417159Ssam /* 4218377Skarels * Formulate an Internet address from network + host. 437159Ssam */ 447159Ssam struct in_addr 4518377Skarels in_makeaddr(net, host) 4618377Skarels u_long net, host; 477159Ssam { 4818377Skarels register struct in_ifaddr *ia; 4918377Skarels register u_long mask; 507159Ssam u_long addr; 517159Ssam 5218377Skarels if (IN_CLASSA(net)) 5318377Skarels mask = IN_CLASSA_HOST; 5418377Skarels else if (IN_CLASSB(net)) 5518377Skarels mask = IN_CLASSB_HOST; 567159Ssam else 5718377Skarels mask = IN_CLASSC_HOST; 5818377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 5918377Skarels if ((ia->ia_netmask & net) == ia->ia_net) { 6018377Skarels mask = ~ia->ia_subnetmask; 6118377Skarels break; 6218377Skarels } 6318377Skarels addr = htonl(net | (host & mask)); 647159Ssam return (*(struct in_addr *)&addr); 657159Ssam } 667159Ssam 677159Ssam /* 688595Sroot * Return the network number from an internet address. 697159Ssam */ 707159Ssam in_netof(in) 717159Ssam struct in_addr in; 727159Ssam { 738937Sroot register u_long i = ntohl(in.s_addr); 7418377Skarels register u_long net; 7518377Skarels register struct in_ifaddr *ia; 767159Ssam 7718377Skarels if (IN_CLASSA(i)) 7818377Skarels net = i & IN_CLASSA_NET; 7918377Skarels else if (IN_CLASSB(i)) 8018377Skarels net = i & IN_CLASSB_NET; 8118377Skarels else 8218377Skarels net = i & IN_CLASSC_NET; 8316413Skarels 8416413Skarels /* 8518377Skarels * Check whether network is a subnet; 8616413Skarels * if so, return subnet number. 8716413Skarels */ 8818377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 8918377Skarels if ((ia->ia_netmask & net) == ia->ia_net) 9018377Skarels return (i & ia->ia_subnetmask); 9116413Skarels return (net); 927159Ssam } 937159Ssam 947159Ssam /* 958595Sroot * Return the host portion of an internet address. 967159Ssam */ 977159Ssam in_lnaof(in) 987159Ssam struct in_addr in; 997159Ssam { 1008937Sroot register u_long i = ntohl(in.s_addr); 10118377Skarels register u_long net, host; 10218377Skarels register struct in_ifaddr *ia; 1037159Ssam 10416377Skarels if (IN_CLASSA(i)) { 10518377Skarels net = i & IN_CLASSA_NET; 10618377Skarels host = i & IN_CLASSA_HOST; 10716377Skarels } else if (IN_CLASSB(i)) { 10818377Skarels net = i & IN_CLASSB_NET; 10918377Skarels host = i & IN_CLASSB_HOST; 11016377Skarels } else { 11118377Skarels net = i & IN_CLASSC_NET; 11218377Skarels host = i & IN_CLASSC_HOST; 11316377Skarels } 1147159Ssam 11516413Skarels /* 11618377Skarels * Check whether network is a subnet; 11716413Skarels * if so, use the modified interpretation of `host'. 11816413Skarels */ 11918377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 12018377Skarels if ((ia->ia_netmask & net) == ia->ia_net) 12118377Skarels return (host &~ ia->ia_subnetmask); 12216413Skarels return (host); 12316377Skarels } 12416377Skarels 12516377Skarels /* 12618377Skarels * Return 1 if an internet address is for a ``local'' host 12718377Skarels * (one to which we have a connection). 12817271Skarels */ 12917271Skarels in_localaddr(in) 13017271Skarels struct in_addr in; 13117271Skarels { 13217271Skarels register u_long i = ntohl(in.s_addr); 13317271Skarels register u_long net; 13418377Skarels register struct in_ifaddr *ia; 13517271Skarels 13617271Skarels if (IN_CLASSA(i)) 13718377Skarels net = i & IN_CLASSA_NET; 13817271Skarels else if (IN_CLASSB(i)) 13918377Skarels net = i & IN_CLASSB_NET; 14017271Skarels else 14118377Skarels net = i & IN_CLASSC_NET; 14217271Skarels 14318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 14418377Skarels if ((ia->ia_netmask & net) == ia->ia_net) 14518377Skarels return (1); 14618377Skarels return (0); 14718377Skarels } 14818377Skarels 14918377Skarels /* 15018377Skarels * Generic internet control operations (ioctl's). 15118377Skarels * Ifp is 0 if not an interface-specific ioctl. 15218377Skarels */ 15318377Skarels in_control(so, cmd, data, ifp) 15418377Skarels struct socket *so; 15518377Skarels int cmd; 15618377Skarels caddr_t data; 15718377Skarels register struct ifnet *ifp; 15818377Skarels { 15918377Skarels register struct ifreq *ifr = (struct ifreq *)data; 16018377Skarels register struct in_ifaddr *ia = 0; 16118377Skarels struct ifaddr *ifa; 16218377Skarels struct mbuf *m; 16318377Skarels int error; 16418377Skarels 16518377Skarels /* 16618377Skarels * Find address for this interface, if it exists. 16718377Skarels */ 16818377Skarels if (ifp) 16918377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 17018377Skarels if (ia->ia_ifp == ifp) 17118377Skarels break; 17218377Skarels 17318377Skarels switch (cmd) { 17418377Skarels 17518377Skarels case SIOCGIFADDR: 17618377Skarels case SIOCGIFBRDADDR: 17718377Skarels case SIOCGIFDSTADDR: 17818377Skarels case SIOCGIFNETMASK: 17918377Skarels if (ia == (struct in_ifaddr *)0) 18018377Skarels return (EADDRNOTAVAIL); 18118377Skarels break; 18218377Skarels 18318377Skarels case SIOCSIFADDR: 18418377Skarels case SIOCSIFDSTADDR: 18518377Skarels case SIOCSIFBRDADDR: 18618377Skarels case SIOCSIFNETMASK: 18718377Skarels if (!suser()) 18818377Skarels return (u.u_error); 18918377Skarels 19018377Skarels if (ifp == 0) 19118377Skarels panic("in_control"); 19218377Skarels if (ia == (struct in_ifaddr *)0) { 19318377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 19418377Skarels if (m == (struct mbuf *)NULL) 19518377Skarels return (ENOBUFS); 19618377Skarels if (ia = in_ifaddr) { 19718377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 19818377Skarels ; 19918377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 20018377Skarels } else 20118377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 20218377Skarels ia = mtod(m, struct in_ifaddr *); 20318377Skarels if (ifa = ifp->if_addrlist) { 20418377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 20518377Skarels ; 20618377Skarels ifa->ifa_next = (struct ifaddr *) ia; 20718377Skarels } else 20818377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 20918377Skarels ia->ia_ifp = ifp; 21018377Skarels IA_SIN(ia)->sin_family = AF_INET; 21117271Skarels } 21218377Skarels break; 21317271Skarels } 21418377Skarels 21518377Skarels switch (cmd) { 21618377Skarels 21718377Skarels case SIOCGIFADDR: 21818377Skarels ifr->ifr_addr = ia->ia_addr; 21918377Skarels break; 22018377Skarels 22118377Skarels case SIOCGIFBRDADDR: 22218377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 22318377Skarels return (EINVAL); 22418377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 22518377Skarels break; 22618377Skarels 22718377Skarels case SIOCGIFDSTADDR: 22818377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 22918377Skarels return (EINVAL); 23018377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 23118377Skarels break; 23218377Skarels 23318377Skarels case SIOCGIFNETMASK: 23418377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 23518377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 23618377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 23718377Skarels break; 23818377Skarels 23918377Skarels case SIOCSIFDSTADDR: 24018377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 24118377Skarels return (EINVAL); 24218377Skarels if (ifp->if_ioctl && 24318377Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) 24418377Skarels return (error); 24518377Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 24618377Skarels break; 24718377Skarels 24818377Skarels case SIOCSIFBRDADDR: 24918377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 25018377Skarels return (EINVAL); 25118377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 25218377Skarels break; 25318377Skarels 25418377Skarels case SIOCSIFADDR: 25518377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 25618377Skarels break; 25718377Skarels 25818377Skarels case SIOCSIFNETMASK: 25918377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 26018377Skarels break; 26118377Skarels 26218377Skarels default: 26318377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 26418377Skarels return (EOPNOTSUPP); 26518377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 26618377Skarels } 26717271Skarels return (0); 26817271Skarels } 26917271Skarels 27017271Skarels /* 27118377Skarels * Initialize an interface's internet address 27218377Skarels * and routing table entry. 2737159Ssam */ 27418377Skarels in_ifinit(ifp, ia, sin) 2757159Ssam register struct ifnet *ifp; 27618377Skarels register struct in_ifaddr *ia; 27718377Skarels struct sockaddr_in *sin; 2787159Ssam { 27918377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 28018377Skarels struct sockaddr_in netaddr; 28118377Skarels int s = splimp(), error; 2827159Ssam 28318377Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 28418377Skarels netaddr.sin_family = AF_INET; 28518377Skarels /* 28618377Skarels * Delete any previous route for an old address. 28718377Skarels */ 28818377Skarels if (ia->ia_flags & IFA_ROUTE) { 28918377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 29018377Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 29118377Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1); 29218377Skarels } else 29318377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1); 29418377Skarels ia->ia_flags &= ~IFA_ROUTE; 29518377Skarels } 29618377Skarels ia->ia_addr = *(struct sockaddr *)sin; 29718377Skarels if (IN_CLASSA(i)) 29818377Skarels ia->ia_netmask = IN_CLASSA_NET; 29918377Skarels else if (IN_CLASSB(i)) 30018377Skarels ia->ia_netmask = IN_CLASSB_NET; 30118377Skarels else 30218377Skarels ia->ia_netmask = IN_CLASSC_NET; 30318377Skarels ia->ia_net = i & ia->ia_netmask; 30418377Skarels /* 30518377Skarels * The subnet mask includes at least the standard network part, 30618377Skarels * but may already have been set to a larger value. 30718377Skarels */ 30818377Skarels ia->ia_subnetmask |= ia->ia_netmask; 30918377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 31018377Skarels if (ifp->if_flags & IFF_BROADCAST) { 31118377Skarels ia->ia_broadaddr.sa_family = AF_INET; 31218377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 31318377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 31418377Skarels } 31518377Skarels 31618377Skarels /* 31718377Skarels * Give the interface a chance to initialize 31818377Skarels * if this is its first address, 31918377Skarels * and to validate the address if necessary. 32018377Skarels */ 32118377Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 32218377Skarels splx(s); 32318377Skarels bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr)); 32418377Skarels return (error); 32518377Skarels } 32618377Skarels splx(s); 32718377Skarels /* 32818377Skarels * Add route for the network. 32918377Skarels */ 33018377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 33118377Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 33218377Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP); 33318377Skarels } else 33418377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 33518377Skarels RTF_HOST|RTF_UP); 33618377Skarels ia->ia_flags |= IFA_ROUTE; 337*18642Skarels return (0); 3387159Ssam } 33918377Skarels 34018377Skarels /* 34118377Skarels * Return address info for specified internet network. 34218377Skarels */ 34318377Skarels struct in_ifaddr * 34418377Skarels in_iaonnetof(net) 34518377Skarels u_long net; 34618377Skarels { 34718377Skarels register struct in_ifaddr *ia; 34818377Skarels 34918377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 35018377Skarels if (ia->ia_subnet == net) 35118377Skarels return (ia); 35218377Skarels return ((struct in_ifaddr *)0); 35318377Skarels } 35418377Skarels 35518377Skarels /* 35618377Skarels * Return 1 if the address is a local broadcast address. 35718377Skarels */ 35818377Skarels in_broadcast(in) 35918377Skarels struct in_addr in; 36018377Skarels { 36118377Skarels register struct in_ifaddr *ia; 36218377Skarels 36318377Skarels /* 36418377Skarels * Look through the list of addresses for a match 36518377Skarels * with a broadcast address. 36618377Skarels */ 36718377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 36818377Skarels if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == 36918377Skarels in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) 37018377Skarels return (1); 37118377Skarels return (0); 37218377Skarels } 3737159Ssam #endif 374