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*26317Skarels * @(#)in.c 6.12 (Berkeley) 02/21/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 */ 1047159Ssam in_lnaof(in) 1057159Ssam struct in_addr in; 1067159Ssam { 1078937Sroot register u_long i = ntohl(in.s_addr); 10818377Skarels register u_long net, host; 10918377Skarels register struct in_ifaddr *ia; 1107159Ssam 11116377Skarels if (IN_CLASSA(i)) { 11218377Skarels net = i & IN_CLASSA_NET; 11318377Skarels host = i & IN_CLASSA_HOST; 11416377Skarels } else if (IN_CLASSB(i)) { 11518377Skarels net = i & IN_CLASSB_NET; 11618377Skarels host = i & IN_CLASSB_HOST; 11716377Skarels } else { 11818377Skarels net = i & IN_CLASSC_NET; 11918377Skarels host = i & IN_CLASSC_HOST; 12016377Skarels } 1217159Ssam 12216413Skarels /* 12318377Skarels * Check whether network is a subnet; 12416413Skarels * if so, use the modified interpretation of `host'. 12516413Skarels */ 12618377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 12724805Skarels if (net == ia->ia_net) 12818377Skarels return (host &~ ia->ia_subnetmask); 12916413Skarels return (host); 13016377Skarels } 13116377Skarels 13216377Skarels /* 13318377Skarels * Return 1 if an internet address is for a ``local'' host 13424805Skarels * (one to which we have a connection through a local logical net). 13517271Skarels */ 13617271Skarels in_localaddr(in) 13717271Skarels struct in_addr in; 13817271Skarels { 13917271Skarels register u_long i = ntohl(in.s_addr); 14017271Skarels register u_long net; 14118377Skarels register struct in_ifaddr *ia; 14217271Skarels 14317271Skarels if (IN_CLASSA(i)) 14418377Skarels net = i & IN_CLASSA_NET; 14517271Skarels else if (IN_CLASSB(i)) 14618377Skarels net = i & IN_CLASSB_NET; 14717271Skarels else 14818377Skarels net = i & IN_CLASSC_NET; 14917271Skarels 15018377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 15124805Skarels if (net == ia->ia_net) 15218377Skarels return (1); 15318377Skarels return (0); 15418377Skarels } 15518377Skarels 15624805Skarels int in_interfaces; /* number of external internet interfaces */ 15724805Skarels extern struct ifnet loif; 15824805Skarels 15918377Skarels /* 16018377Skarels * Generic internet control operations (ioctl's). 16118377Skarels * Ifp is 0 if not an interface-specific ioctl. 16218377Skarels */ 16324805Skarels /* ARGSUSED */ 16418377Skarels in_control(so, cmd, data, ifp) 16518377Skarels struct socket *so; 16618377Skarels int cmd; 16718377Skarels caddr_t data; 16818377Skarels register struct ifnet *ifp; 16918377Skarels { 17018377Skarels register struct ifreq *ifr = (struct ifreq *)data; 17118377Skarels register struct in_ifaddr *ia = 0; 17225195Skarels u_long tmp; 17318377Skarels struct ifaddr *ifa; 17418377Skarels struct mbuf *m; 17518377Skarels int error; 17618377Skarels 17718377Skarels /* 17818377Skarels * Find address for this interface, if it exists. 17918377Skarels */ 18018377Skarels if (ifp) 18118377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 18218377Skarels if (ia->ia_ifp == ifp) 18318377Skarels break; 18418377Skarels 18518377Skarels switch (cmd) { 18618377Skarels 18718377Skarels case SIOCSIFADDR: 18818377Skarels case SIOCSIFNETMASK: 18918377Skarels if (!suser()) 19018377Skarels return (u.u_error); 19118377Skarels 19218377Skarels if (ifp == 0) 19318377Skarels panic("in_control"); 19418377Skarels if (ia == (struct in_ifaddr *)0) { 19518377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 19618377Skarels if (m == (struct mbuf *)NULL) 19718377Skarels return (ENOBUFS); 19818377Skarels if (ia = in_ifaddr) { 19918377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 20018377Skarels ; 20118377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 20218377Skarels } else 20318377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 20418377Skarels ia = mtod(m, struct in_ifaddr *); 20518377Skarels if (ifa = ifp->if_addrlist) { 20618377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 20718377Skarels ; 20818377Skarels ifa->ifa_next = (struct ifaddr *) ia; 20918377Skarels } else 21018377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 21118377Skarels ia->ia_ifp = ifp; 21218377Skarels IA_SIN(ia)->sin_family = AF_INET; 21324805Skarels if (ifp != &loif) 21424805Skarels in_interfaces++; 21517271Skarels } 21618377Skarels break; 217*26317Skarels 218*26317Skarels case SIOCSIFBRDADDR: 219*26317Skarels case SIOCSIFDSTADDR: 220*26317Skarels if (!suser()) 221*26317Skarels return (u.u_error); 222*26317Skarels /* FALLTHROUGH */ 223*26317Skarels 224*26317Skarels default: 225*26317Skarels if (ia == (struct in_ifaddr *)0) 226*26317Skarels return (EADDRNOTAVAIL); 227*26317Skarels break; 22817271Skarels } 22918377Skarels 23018377Skarels switch (cmd) { 23118377Skarels 23218377Skarels case SIOCGIFADDR: 23318377Skarels ifr->ifr_addr = ia->ia_addr; 23418377Skarels break; 23518377Skarels 23618377Skarels case SIOCGIFBRDADDR: 23718377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 23818377Skarels return (EINVAL); 23918377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 24018377Skarels break; 24118377Skarels 24218377Skarels case SIOCGIFDSTADDR: 24318377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 24418377Skarels return (EINVAL); 24518377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 24618377Skarels break; 24718377Skarels 24818377Skarels case SIOCGIFNETMASK: 24918377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 25018377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 25118377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 25218377Skarels break; 25318377Skarels 25418377Skarels case SIOCSIFDSTADDR: 25518377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 25618377Skarels return (EINVAL); 25718377Skarels if (ifp->if_ioctl && 25824805Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) 25918377Skarels return (error); 26018377Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 26118377Skarels break; 26218377Skarels 26318377Skarels case SIOCSIFBRDADDR: 26418377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 26518377Skarels return (EINVAL); 26618377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 26725195Skarels tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); 26825195Skarels if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) 26925195Skarels tmp |= ~ia->ia_netmask; 27025195Skarels else if ((tmp &~ ia->ia_subnetmask) == 0) 27125195Skarels tmp &= ia->ia_netmask; 27225195Skarels ia->ia_netbroadcast.s_addr = htonl(tmp); 27318377Skarels break; 27418377Skarels 27518377Skarels case SIOCSIFADDR: 27618377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 27718377Skarels 27818377Skarels case SIOCSIFNETMASK: 27918377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 28018377Skarels break; 28118377Skarels 28218377Skarels default: 28318377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 28418377Skarels return (EOPNOTSUPP); 28518377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 28618377Skarels } 28717271Skarels return (0); 28817271Skarels } 28917271Skarels 29017271Skarels /* 29118377Skarels * Initialize an interface's internet address 29218377Skarels * and routing table entry. 2937159Ssam */ 29418377Skarels in_ifinit(ifp, ia, sin) 2957159Ssam register struct ifnet *ifp; 29618377Skarels register struct in_ifaddr *ia; 29718377Skarels struct sockaddr_in *sin; 2987159Ssam { 29918377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 300*26317Skarels struct sockaddr_in tmpaddr; 30118377Skarels int s = splimp(), error; 3027159Ssam 303*26317Skarels tmpaddr = *(struct sockaddr_in *)&ia->ia_addr; 304*26317Skarels ia->ia_addr = *(struct sockaddr *)sin; 305*26317Skarels 30618377Skarels /* 307*26317Skarels * Give the interface a chance to initialize 308*26317Skarels * if this is its first address, 309*26317Skarels * and to validate the address if necessary. 310*26317Skarels */ 311*26317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 312*26317Skarels splx(s); 313*26317Skarels ia->ia_addr = *(struct sockaddr *)&tmpaddr; 314*26317Skarels return (error); 315*26317Skarels } 316*26317Skarels 317*26317Skarels bzero((caddr_t)&tmpaddr, sizeof (tmpaddr)); 318*26317Skarels tmpaddr.sin_family = AF_INET; 319*26317Skarels /* 32018377Skarels * Delete any previous route for an old address. 32118377Skarels */ 32218377Skarels if (ia->ia_flags & IFA_ROUTE) { 32318377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 324*26317Skarels tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 325*26317Skarels rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr, 32625452Ssklower (int)SIOCDELRT, 0); 32718377Skarels } else 32825452Ssklower rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 32925452Ssklower (int)SIOCDELRT, RTF_HOST); 33018377Skarels ia->ia_flags &= ~IFA_ROUTE; 33118377Skarels } 33218377Skarels if (IN_CLASSA(i)) 33318377Skarels ia->ia_netmask = IN_CLASSA_NET; 33418377Skarels else if (IN_CLASSB(i)) 33518377Skarels ia->ia_netmask = IN_CLASSB_NET; 33618377Skarels else 33718377Skarels ia->ia_netmask = IN_CLASSC_NET; 33818377Skarels ia->ia_net = i & ia->ia_netmask; 33918377Skarels /* 34018377Skarels * The subnet mask includes at least the standard network part, 34118377Skarels * but may already have been set to a larger value. 34218377Skarels */ 34318377Skarels ia->ia_subnetmask |= ia->ia_netmask; 34418377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 34518377Skarels if (ifp->if_flags & IFF_BROADCAST) { 34618377Skarels ia->ia_broadaddr.sa_family = AF_INET; 34718377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 34818377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 34925195Skarels ia->ia_netbroadcast.s_addr = 35025195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 35118377Skarels } 35218377Skarels splx(s); 35318377Skarels /* 35418377Skarels * Add route for the network. 35518377Skarels */ 35618377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 357*26317Skarels tmpaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 358*26317Skarels rtinit((struct sockaddr *)&tmpaddr, &ia->ia_addr, 35925452Ssklower (int)SIOCADDRT, RTF_UP); 36018377Skarels } else 36118377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 36225452Ssklower (int)SIOCADDRT, RTF_HOST|RTF_UP); 36318377Skarels ia->ia_flags |= IFA_ROUTE; 36418642Skarels return (0); 3657159Ssam } 36618377Skarels 36718377Skarels /* 36818377Skarels * Return address info for specified internet network. 36918377Skarels */ 37018377Skarels struct in_ifaddr * 37118377Skarels in_iaonnetof(net) 37218377Skarels u_long net; 37318377Skarels { 37418377Skarels register struct in_ifaddr *ia; 37518377Skarels 37618377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 37718377Skarels if (ia->ia_subnet == net) 37818377Skarels return (ia); 37918377Skarels return ((struct in_ifaddr *)0); 38018377Skarels } 38118377Skarels 38218377Skarels /* 38318377Skarels * Return 1 if the address is a local broadcast address. 38418377Skarels */ 38518377Skarels in_broadcast(in) 38618377Skarels struct in_addr in; 38718377Skarels { 38818377Skarels register struct in_ifaddr *ia; 38918377Skarels 39018377Skarels /* 39118377Skarels * Look through the list of addresses for a match 39218377Skarels * with a broadcast address. 39318377Skarels */ 39418377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 39518377Skarels if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == 39618377Skarels in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) 39718377Skarels return (1); 39818377Skarels return (0); 39918377Skarels } 4007159Ssam #endif 401