1*23175Smckusick /* 2*23175Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23175Smckusick * All rights reserved. The Berkeley software License Agreement 4*23175Smckusick * specifies the terms and conditions for redistribution. 5*23175Smckusick * 6*23175Smckusick * @(#)in.c 6.8 (Berkeley) 06/08/85 7*23175Smckusick */ 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 */ 767159Ssam in_netof(in) 777159Ssam struct in_addr in; 787159Ssam { 798937Sroot register u_long i = ntohl(in.s_addr); 8018377Skarels register u_long net; 8118377Skarels register struct in_ifaddr *ia; 827159Ssam 8318377Skarels if (IN_CLASSA(i)) 8418377Skarels net = i & IN_CLASSA_NET; 8518377Skarels else if (IN_CLASSB(i)) 8618377Skarels net = i & IN_CLASSB_NET; 8718377Skarels else 8818377Skarels net = i & IN_CLASSC_NET; 8916413Skarels 9016413Skarels /* 9118377Skarels * Check whether network is a subnet; 9216413Skarels * if so, return subnet number. 9316413Skarels */ 9418377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 9518377Skarels if ((ia->ia_netmask & net) == ia->ia_net) 9618377Skarels return (i & ia->ia_subnetmask); 9716413Skarels return (net); 987159Ssam } 997159Ssam 1007159Ssam /* 1018595Sroot * Return the host portion of an internet address. 1027159Ssam */ 1037159Ssam in_lnaof(in) 1047159Ssam struct in_addr in; 1057159Ssam { 1068937Sroot register u_long i = ntohl(in.s_addr); 10718377Skarels register u_long net, host; 10818377Skarels register struct in_ifaddr *ia; 1097159Ssam 11016377Skarels if (IN_CLASSA(i)) { 11118377Skarels net = i & IN_CLASSA_NET; 11218377Skarels host = i & IN_CLASSA_HOST; 11316377Skarels } else if (IN_CLASSB(i)) { 11418377Skarels net = i & IN_CLASSB_NET; 11518377Skarels host = i & IN_CLASSB_HOST; 11616377Skarels } else { 11718377Skarels net = i & IN_CLASSC_NET; 11818377Skarels host = i & IN_CLASSC_HOST; 11916377Skarels } 1207159Ssam 12116413Skarels /* 12218377Skarels * Check whether network is a subnet; 12316413Skarels * if so, use the modified interpretation of `host'. 12416413Skarels */ 12518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 12618377Skarels if ((ia->ia_netmask & net) == ia->ia_net) 12718377Skarels return (host &~ ia->ia_subnetmask); 12816413Skarels return (host); 12916377Skarels } 13016377Skarels 13116377Skarels /* 13218377Skarels * Return 1 if an internet address is for a ``local'' host 13318377Skarels * (one to which we have a connection). 13417271Skarels */ 13517271Skarels in_localaddr(in) 13617271Skarels struct in_addr in; 13717271Skarels { 13817271Skarels register u_long i = ntohl(in.s_addr); 13917271Skarels register u_long net; 14018377Skarels register struct in_ifaddr *ia; 14117271Skarels 14217271Skarels if (IN_CLASSA(i)) 14318377Skarels net = i & IN_CLASSA_NET; 14417271Skarels else if (IN_CLASSB(i)) 14518377Skarels net = i & IN_CLASSB_NET; 14617271Skarels else 14718377Skarels net = i & IN_CLASSC_NET; 14817271Skarels 14918377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 15018377Skarels if ((ia->ia_netmask & net) == ia->ia_net) 15118377Skarels return (1); 15218377Skarels return (0); 15318377Skarels } 15418377Skarels 15518377Skarels /* 15618377Skarels * Generic internet control operations (ioctl's). 15718377Skarels * Ifp is 0 if not an interface-specific ioctl. 15818377Skarels */ 15918377Skarels in_control(so, cmd, data, ifp) 16018377Skarels struct socket *so; 16118377Skarels int cmd; 16218377Skarels caddr_t data; 16318377Skarels register struct ifnet *ifp; 16418377Skarels { 16518377Skarels register struct ifreq *ifr = (struct ifreq *)data; 16618377Skarels register struct in_ifaddr *ia = 0; 16718377Skarels struct ifaddr *ifa; 16818377Skarels struct mbuf *m; 16918377Skarels int error; 17018377Skarels 17118377Skarels /* 17218377Skarels * Find address for this interface, if it exists. 17318377Skarels */ 17418377Skarels if (ifp) 17518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 17618377Skarels if (ia->ia_ifp == ifp) 17718377Skarels break; 17818377Skarels 17918377Skarels switch (cmd) { 18018377Skarels 18118377Skarels case SIOCGIFADDR: 18218377Skarels case SIOCGIFBRDADDR: 18318377Skarels case SIOCGIFDSTADDR: 18418377Skarels case SIOCGIFNETMASK: 18518377Skarels if (ia == (struct in_ifaddr *)0) 18618377Skarels return (EADDRNOTAVAIL); 18718377Skarels break; 18818377Skarels 18918377Skarels case SIOCSIFADDR: 19018377Skarels case SIOCSIFDSTADDR: 19118377Skarels case SIOCSIFBRDADDR: 19218377Skarels case SIOCSIFNETMASK: 19318377Skarels if (!suser()) 19418377Skarels return (u.u_error); 19518377Skarels 19618377Skarels if (ifp == 0) 19718377Skarels panic("in_control"); 19818377Skarels if (ia == (struct in_ifaddr *)0) { 19918377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 20018377Skarels if (m == (struct mbuf *)NULL) 20118377Skarels return (ENOBUFS); 20218377Skarels if (ia = in_ifaddr) { 20318377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 20418377Skarels ; 20518377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 20618377Skarels } else 20718377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 20818377Skarels ia = mtod(m, struct in_ifaddr *); 20918377Skarels if (ifa = ifp->if_addrlist) { 21018377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 21118377Skarels ; 21218377Skarels ifa->ifa_next = (struct ifaddr *) ia; 21318377Skarels } else 21418377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 21518377Skarels ia->ia_ifp = ifp; 21618377Skarels IA_SIN(ia)->sin_family = AF_INET; 21717271Skarels } 21818377Skarels break; 21917271Skarels } 22018377Skarels 22118377Skarels switch (cmd) { 22218377Skarels 22318377Skarels case SIOCGIFADDR: 22418377Skarels ifr->ifr_addr = ia->ia_addr; 22518377Skarels break; 22618377Skarels 22718377Skarels case SIOCGIFBRDADDR: 22818377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 22918377Skarels return (EINVAL); 23018377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 23118377Skarels break; 23218377Skarels 23318377Skarels case SIOCGIFDSTADDR: 23418377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 23518377Skarels return (EINVAL); 23618377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 23718377Skarels break; 23818377Skarels 23918377Skarels case SIOCGIFNETMASK: 24018377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 24118377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 24218377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 24318377Skarels break; 24418377Skarels 24518377Skarels case SIOCSIFDSTADDR: 24618377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 24718377Skarels return (EINVAL); 24818377Skarels if (ifp->if_ioctl && 24918377Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) 25018377Skarels return (error); 25118377Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 25218377Skarels break; 25318377Skarels 25418377Skarels case SIOCSIFBRDADDR: 25518377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 25618377Skarels return (EINVAL); 25718377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 25818377Skarels break; 25918377Skarels 26018377Skarels case SIOCSIFADDR: 26118377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 26218377Skarels break; 26318377Skarels 26418377Skarels case SIOCSIFNETMASK: 26518377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 26618377Skarels break; 26718377Skarels 26818377Skarels default: 26918377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 27018377Skarels return (EOPNOTSUPP); 27118377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 27218377Skarels } 27317271Skarels return (0); 27417271Skarels } 27517271Skarels 27617271Skarels /* 27718377Skarels * Initialize an interface's internet address 27818377Skarels * and routing table entry. 2797159Ssam */ 28018377Skarels in_ifinit(ifp, ia, sin) 2817159Ssam register struct ifnet *ifp; 28218377Skarels register struct in_ifaddr *ia; 28318377Skarels struct sockaddr_in *sin; 2847159Ssam { 28518377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 28618377Skarels struct sockaddr_in netaddr; 28718377Skarels int s = splimp(), error; 2887159Ssam 28918377Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 29018377Skarels netaddr.sin_family = AF_INET; 29118377Skarels /* 29218377Skarels * Delete any previous route for an old address. 29318377Skarels */ 29418377Skarels if (ia->ia_flags & IFA_ROUTE) { 29518377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 29618377Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 29718377Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1); 29818377Skarels } else 29918377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1); 30018377Skarels ia->ia_flags &= ~IFA_ROUTE; 30118377Skarels } 30218377Skarels ia->ia_addr = *(struct sockaddr *)sin; 30318377Skarels if (IN_CLASSA(i)) 30418377Skarels ia->ia_netmask = IN_CLASSA_NET; 30518377Skarels else if (IN_CLASSB(i)) 30618377Skarels ia->ia_netmask = IN_CLASSB_NET; 30718377Skarels else 30818377Skarels ia->ia_netmask = IN_CLASSC_NET; 30918377Skarels ia->ia_net = i & ia->ia_netmask; 31018377Skarels /* 31118377Skarels * The subnet mask includes at least the standard network part, 31218377Skarels * but may already have been set to a larger value. 31318377Skarels */ 31418377Skarels ia->ia_subnetmask |= ia->ia_netmask; 31518377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 31618377Skarels if (ifp->if_flags & IFF_BROADCAST) { 31718377Skarels ia->ia_broadaddr.sa_family = AF_INET; 31818377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 31918377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 32018377Skarels } 32118377Skarels 32218377Skarels /* 32318377Skarels * Give the interface a chance to initialize 32418377Skarels * if this is its first address, 32518377Skarels * and to validate the address if necessary. 32618377Skarels */ 32718377Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 32818377Skarels splx(s); 32918377Skarels bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr)); 33018377Skarels return (error); 33118377Skarels } 33218377Skarels splx(s); 33318377Skarels /* 33418377Skarels * Add route for the network. 33518377Skarels */ 33618377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 33718377Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 33818377Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP); 33918377Skarels } else 34018377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 34118377Skarels RTF_HOST|RTF_UP); 34218377Skarels ia->ia_flags |= IFA_ROUTE; 34318642Skarels return (0); 3447159Ssam } 34518377Skarels 34618377Skarels /* 34718377Skarels * Return address info for specified internet network. 34818377Skarels */ 34918377Skarels struct in_ifaddr * 35018377Skarels in_iaonnetof(net) 35118377Skarels u_long net; 35218377Skarels { 35318377Skarels register struct in_ifaddr *ia; 35418377Skarels 35518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 35618377Skarels if (ia->ia_subnet == net) 35718377Skarels return (ia); 35818377Skarels return ((struct in_ifaddr *)0); 35918377Skarels } 36018377Skarels 36118377Skarels /* 36218377Skarels * Return 1 if the address is a local broadcast address. 36318377Skarels */ 36418377Skarels in_broadcast(in) 36518377Skarels struct in_addr in; 36618377Skarels { 36718377Skarels register struct in_ifaddr *ia; 36818377Skarels 36918377Skarels /* 37018377Skarels * Look through the list of addresses for a match 37118377Skarels * with a broadcast address. 37218377Skarels */ 37318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 37418377Skarels if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == 37518377Skarels in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) 37618377Skarels return (1); 37718377Skarels return (0); 37818377Skarels } 3797159Ssam #endif 380