123175Smckusick /* 229136Smckusick * Copyright (c) 1982, 1986 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*30523Skarels * @(#)in.c 7.3 (Berkeley) 02/19/87 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 */ 10426381Skarels 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 13326381Skarels #ifndef SUBNETSARELOCAL 13426381Skarels #define SUBNETSARELOCAL 1 13526381Skarels #endif 13626381Skarels int subnetsarelocal = SUBNETSARELOCAL; 13716377Skarels /* 13818377Skarels * Return 1 if an internet address is for a ``local'' host 13926381Skarels * (one to which we have a connection). If subnetsarelocal 14026381Skarels * is true, this includes other subnets of the local net. 14126381Skarels * 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) 15830140Skarels 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: 19626456Skarels case SIOCSIFDSTADDR: 19718377Skarels if (!suser()) 19818377Skarels return (u.u_error); 19918377Skarels 20018377Skarels if (ifp == 0) 20118377Skarels panic("in_control"); 20218377Skarels if (ia == (struct in_ifaddr *)0) { 20318377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 20418377Skarels if (m == (struct mbuf *)NULL) 20518377Skarels return (ENOBUFS); 20618377Skarels if (ia = in_ifaddr) { 20718377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 20818377Skarels ; 20918377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 21018377Skarels } else 21118377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 21218377Skarels ia = mtod(m, struct in_ifaddr *); 21318377Skarels if (ifa = ifp->if_addrlist) { 21418377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 21518377Skarels ; 21618377Skarels ifa->ifa_next = (struct ifaddr *) ia; 21718377Skarels } else 21818377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 21918377Skarels ia->ia_ifp = ifp; 22018377Skarels IA_SIN(ia)->sin_family = AF_INET; 22124805Skarels if (ifp != &loif) 22224805Skarels in_interfaces++; 22317271Skarels } 22418377Skarels break; 22526317Skarels 22626317Skarels case SIOCSIFBRDADDR: 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: 26227066Skarels { 26327066Skarels struct sockaddr oldaddr; 26427066Skarels 26518377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 26618377Skarels return (EINVAL); 26727066Skarels oldaddr = ia->ia_dstaddr; 26827066Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 26918377Skarels if (ifp->if_ioctl && 27027066Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 27127066Skarels ia->ia_dstaddr = oldaddr; 27218377Skarels return (error); 27327066Skarels } 27427066Skarels if (ia->ia_flags & IFA_ROUTE) { 27527066Skarels rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT, 27627066Skarels RTF_HOST); 27727066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 27827066Skarels RTF_HOST|RTF_UP); 27927066Skarels } 28027066Skarels } 28118377Skarels break; 28218377Skarels 28318377Skarels case SIOCSIFBRDADDR: 28418377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 28518377Skarels return (EINVAL); 28618377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 28725195Skarels tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr); 28825195Skarels if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask) 28925195Skarels tmp |= ~ia->ia_netmask; 29025195Skarels else if ((tmp &~ ia->ia_subnetmask) == 0) 29125195Skarels tmp &= ia->ia_netmask; 29225195Skarels ia->ia_netbroadcast.s_addr = htonl(tmp); 29318377Skarels break; 29418377Skarels 29518377Skarels case SIOCSIFADDR: 29618377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 29718377Skarels 29818377Skarels case SIOCSIFNETMASK: 29918377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 30018377Skarels break; 30118377Skarels 30218377Skarels default: 30318377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 30418377Skarels return (EOPNOTSUPP); 30518377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 30618377Skarels } 30717271Skarels return (0); 30817271Skarels } 30917271Skarels 31017271Skarels /* 31118377Skarels * Initialize an interface's internet address 31218377Skarels * and routing table entry. 3137159Ssam */ 31418377Skarels in_ifinit(ifp, ia, sin) 3157159Ssam register struct ifnet *ifp; 31618377Skarels register struct in_ifaddr *ia; 31718377Skarels struct sockaddr_in *sin; 3187159Ssam { 31918377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 32027066Skarels struct sockaddr oldaddr; 32127066Skarels struct sockaddr_in netaddr; 32218377Skarels int s = splimp(), error; 3237159Ssam 32427066Skarels oldaddr = ia->ia_addr; 32526317Skarels ia->ia_addr = *(struct sockaddr *)sin; 32626317Skarels 32718377Skarels /* 32826317Skarels * Give the interface a chance to initialize 32926317Skarels * if this is its first address, 33026317Skarels * and to validate the address if necessary. 33126317Skarels */ 33226317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 33326317Skarels splx(s); 33427066Skarels ia->ia_addr = oldaddr; 33526317Skarels return (error); 33626317Skarels } 33726317Skarels 33826317Skarels /* 33918377Skarels * Delete any previous route for an old address. 34018377Skarels */ 34127066Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 34227066Skarels netaddr.sin_family = AF_INET; 34318377Skarels if (ia->ia_flags & IFA_ROUTE) { 34427066Skarels if (ifp->if_flags & IFF_LOOPBACK) 34527066Skarels rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST); 34627066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 34727066Skarels rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT, 34827066Skarels RTF_HOST); 34927066Skarels else { 35027066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, 35127066Skarels INADDR_ANY); 35227066Skarels rtinit((struct sockaddr *)&netaddr, &oldaddr, 35325452Ssklower (int)SIOCDELRT, 0); 35427066Skarels } 35518377Skarels ia->ia_flags &= ~IFA_ROUTE; 35618377Skarels } 35718377Skarels if (IN_CLASSA(i)) 35818377Skarels ia->ia_netmask = IN_CLASSA_NET; 35918377Skarels else if (IN_CLASSB(i)) 36018377Skarels ia->ia_netmask = IN_CLASSB_NET; 36118377Skarels else 36218377Skarels ia->ia_netmask = IN_CLASSC_NET; 36318377Skarels ia->ia_net = i & ia->ia_netmask; 36418377Skarels /* 36518377Skarels * The subnet mask includes at least the standard network part, 36618377Skarels * but may already have been set to a larger value. 36718377Skarels */ 36818377Skarels ia->ia_subnetmask |= ia->ia_netmask; 36918377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 37018377Skarels if (ifp->if_flags & IFF_BROADCAST) { 37118377Skarels ia->ia_broadaddr.sa_family = AF_INET; 37218377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 37318377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 37425195Skarels ia->ia_netbroadcast.s_addr = 37525195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 37618377Skarels } 37718377Skarels /* 37818377Skarels * Add route for the network. 37918377Skarels */ 38027066Skarels if (ifp->if_flags & IFF_LOOPBACK) 38127066Skarels rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, 38227066Skarels RTF_HOST|RTF_UP); 38327066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 38427066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 38527066Skarels RTF_HOST|RTF_UP); 38627066Skarels else { 38727066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 38827066Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 38927066Skarels (int)SIOCADDRT, RTF_UP); 39027066Skarels } 39118377Skarels ia->ia_flags |= IFA_ROUTE; 392*30523Skarels splx(s); 39318642Skarels return (0); 3947159Ssam } 39518377Skarels 39618377Skarels /* 39718377Skarels * Return address info for specified internet network. 39818377Skarels */ 39918377Skarels struct in_ifaddr * 40018377Skarels in_iaonnetof(net) 40118377Skarels u_long net; 40218377Skarels { 40318377Skarels register struct in_ifaddr *ia; 40418377Skarels 40518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 40618377Skarels if (ia->ia_subnet == net) 40718377Skarels return (ia); 40818377Skarels return ((struct in_ifaddr *)0); 40918377Skarels } 41018377Skarels 41118377Skarels /* 412*30523Skarels * Return 1 if the address might be a local broadcast address. 41318377Skarels */ 41418377Skarels in_broadcast(in) 41518377Skarels struct in_addr in; 41618377Skarels { 41718377Skarels register struct in_ifaddr *ia; 418*30523Skarels u_long t; 41918377Skarels 42018377Skarels /* 42118377Skarels * Look through the list of addresses for a match 42218377Skarels * with a broadcast address. 42318377Skarels */ 42418377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 425*30523Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 426*30523Skarels if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 42718377Skarels return (1); 428*30523Skarels /* 429*30523Skarels * Check for old-style (host 0) broadcast. 430*30523Skarels */ 431*30523Skarels if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net) 432*30523Skarels return (1); 433*30523Skarels } 434*30523Skarels if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) 435*30523Skarels return (1); 43618377Skarels return (0); 43718377Skarels } 4387159Ssam #endif 439