123175Smckusick /* 229136Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 332787Sbostic * All rights reserved. 423175Smckusick * 532787Sbostic * Redistribution and use in source and binary forms are permitted 6*34854Sbostic * provided that the above copyright notice and this paragraph are 7*34854Sbostic * duplicated in all such forms and that any documentation, 8*34854Sbostic * advertising materials, and other materials related to such 9*34854Sbostic * distribution and use acknowledge that the software was developed 10*34854Sbostic * by the University of California, Berkeley. The name of the 11*34854Sbostic * University may not be used to endorse or promote products derived 12*34854Sbostic * from this software without specific prior written permission. 13*34854Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34854Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34854Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632787Sbostic * 17*34854Sbostic * @(#)in.c 7.9 (Berkeley) 06/29/88 1823175Smckusick */ 197159Ssam 2017058Sbloom #include "param.h" 2118377Skarels #include "ioctl.h" 2217058Sbloom #include "mbuf.h" 2317058Sbloom #include "protosw.h" 2417058Sbloom #include "socket.h" 2517058Sbloom #include "socketvar.h" 2618377Skarels #include "uio.h" 2718377Skarels #include "dir.h" 2818377Skarels #include "user.h" 2917058Sbloom #include "in_systm.h" 307166Ssam #include "../net/if.h" 317166Ssam #include "../net/route.h" 327159Ssam #include "../net/af.h" 3318377Skarels #include "in.h" 3418377Skarels #include "in_var.h" 357159Ssam 367159Ssam #ifdef INET 377159Ssam inet_hash(sin, hp) 387159Ssam register struct sockaddr_in *sin; 397159Ssam struct afhash *hp; 407159Ssam { 4118377Skarels register u_long n; 428595Sroot 4318377Skarels n = in_netof(sin->sin_addr); 4418377Skarels if (n) 4518377Skarels while ((n & 0xff) == 0) 4618377Skarels n >>= 8; 4718377Skarels hp->afh_nethash = n; 488937Sroot hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); 497159Ssam } 507159Ssam 517159Ssam inet_netmatch(sin1, sin2) 527159Ssam struct sockaddr_in *sin1, *sin2; 537159Ssam { 548595Sroot 5511566Ssam return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr)); 567159Ssam } 577159Ssam 587159Ssam /* 5918377Skarels * Formulate an Internet address from network + host. 607159Ssam */ 617159Ssam struct in_addr 6218377Skarels in_makeaddr(net, host) 6318377Skarels u_long net, host; 647159Ssam { 6518377Skarels register struct in_ifaddr *ia; 6618377Skarels register u_long mask; 677159Ssam u_long addr; 687159Ssam 6918377Skarels if (IN_CLASSA(net)) 7018377Skarels mask = IN_CLASSA_HOST; 7118377Skarels else if (IN_CLASSB(net)) 7218377Skarels mask = IN_CLASSB_HOST; 737159Ssam else 7418377Skarels mask = IN_CLASSC_HOST; 7518377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 7618377Skarels if ((ia->ia_netmask & net) == ia->ia_net) { 7718377Skarels mask = ~ia->ia_subnetmask; 7818377Skarels break; 7918377Skarels } 8018377Skarels addr = htonl(net | (host & mask)); 817159Ssam return (*(struct in_addr *)&addr); 827159Ssam } 837159Ssam 847159Ssam /* 858595Sroot * Return the network number from an internet address. 867159Ssam */ 8724805Skarels u_long 887159Ssam in_netof(in) 897159Ssam struct in_addr in; 907159Ssam { 918937Sroot register u_long i = ntohl(in.s_addr); 9218377Skarels register u_long net; 9318377Skarels register struct in_ifaddr *ia; 947159Ssam 9518377Skarels if (IN_CLASSA(i)) 9618377Skarels net = i & IN_CLASSA_NET; 9718377Skarels else if (IN_CLASSB(i)) 9818377Skarels net = i & IN_CLASSB_NET; 9931392Skarels else if (IN_CLASSC(i)) 10031392Skarels net = i & IN_CLASSC_NET; 10118377Skarels else 10231392Skarels return (0); 10316413Skarels 10416413Skarels /* 10518377Skarels * Check whether network is a subnet; 10616413Skarels * if so, return subnet number. 10716413Skarels */ 10818377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 10924805Skarels if (net == ia->ia_net) 11018377Skarels return (i & ia->ia_subnetmask); 11116413Skarels return (net); 1127159Ssam } 1137159Ssam 1147159Ssam /* 1158595Sroot * Return the host portion of an internet address. 1167159Ssam */ 11726381Skarels u_long 1187159Ssam in_lnaof(in) 1197159Ssam struct in_addr in; 1207159Ssam { 1218937Sroot register u_long i = ntohl(in.s_addr); 12218377Skarels register u_long net, host; 12318377Skarels register struct in_ifaddr *ia; 1247159Ssam 12516377Skarels if (IN_CLASSA(i)) { 12618377Skarels net = i & IN_CLASSA_NET; 12718377Skarels host = i & IN_CLASSA_HOST; 12816377Skarels } else if (IN_CLASSB(i)) { 12918377Skarels net = i & IN_CLASSB_NET; 13018377Skarels host = i & IN_CLASSB_HOST; 13131392Skarels } else if (IN_CLASSC(i)) { 13218377Skarels net = i & IN_CLASSC_NET; 13318377Skarels host = i & IN_CLASSC_HOST; 13431392Skarels } else 13531392Skarels return (i); 1367159Ssam 13716413Skarels /* 13818377Skarels * Check whether network is a subnet; 13916413Skarels * if so, use the modified interpretation of `host'. 14016413Skarels */ 14118377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 14224805Skarels if (net == ia->ia_net) 14318377Skarels return (host &~ ia->ia_subnetmask); 14416413Skarels return (host); 14516377Skarels } 14616377Skarels 14726381Skarels #ifndef SUBNETSARELOCAL 14826381Skarels #define SUBNETSARELOCAL 1 14926381Skarels #endif 15026381Skarels int subnetsarelocal = SUBNETSARELOCAL; 15116377Skarels /* 15218377Skarels * Return 1 if an internet address is for a ``local'' host 15326381Skarels * (one to which we have a connection). If subnetsarelocal 15426381Skarels * is true, this includes other subnets of the local net. 15526381Skarels * Otherwise, it includes only the directly-connected (sub)nets. 15617271Skarels */ 15717271Skarels in_localaddr(in) 15817271Skarels struct in_addr in; 15917271Skarels { 16017271Skarels register u_long i = ntohl(in.s_addr); 16118377Skarels register struct in_ifaddr *ia; 16217271Skarels 16330697Skarels if (subnetsarelocal) { 16430697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 16530697Skarels if ((i & ia->ia_netmask) == ia->ia_net) 16630697Skarels return (1); 16730697Skarels } else { 16830697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 16930697Skarels if ((i & ia->ia_subnetmask) == ia->ia_subnet) 17030697Skarels return (1); 17130697Skarels } 17218377Skarels return (0); 17318377Skarels } 17418377Skarels 17531392Skarels /* 17631392Skarels * Determine whether an IP address is in a reserved set of addresses 17731392Skarels * that may not be forwarded, or whether datagrams to that destination 17831392Skarels * may be forwarded. 17931392Skarels */ 18031392Skarels in_canforward(in) 18131392Skarels struct in_addr in; 18231392Skarels { 18331392Skarels register u_long i = ntohl(in.s_addr); 18431392Skarels register u_long net; 18531392Skarels 18631392Skarels if (IN_EXPERIMENTAL(i)) 18731392Skarels return (0); 18831392Skarels if (IN_CLASSA(i)) { 18931392Skarels net = i & IN_CLASSA_NET; 19031392Skarels if (net == 0 || net == IN_LOOPBACKNET) 19131392Skarels return (0); 19231392Skarels } 19331392Skarels return (1); 19431392Skarels } 19531392Skarels 19624805Skarels int in_interfaces; /* number of external internet interfaces */ 19724805Skarels extern struct ifnet loif; 19824805Skarels 19918377Skarels /* 20018377Skarels * Generic internet control operations (ioctl's). 20118377Skarels * Ifp is 0 if not an interface-specific ioctl. 20218377Skarels */ 20324805Skarels /* ARGSUSED */ 20418377Skarels in_control(so, cmd, data, ifp) 20518377Skarels struct socket *so; 20618377Skarels int cmd; 20718377Skarels caddr_t data; 20818377Skarels register struct ifnet *ifp; 20918377Skarels { 21018377Skarels register struct ifreq *ifr = (struct ifreq *)data; 21118377Skarels register struct in_ifaddr *ia = 0; 21218377Skarels struct ifaddr *ifa; 21318377Skarels struct mbuf *m; 21418377Skarels int error; 21518377Skarels 21618377Skarels /* 21718377Skarels * Find address for this interface, if it exists. 21818377Skarels */ 21918377Skarels if (ifp) 22018377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 22118377Skarels if (ia->ia_ifp == ifp) 22218377Skarels break; 22318377Skarels 22418377Skarels switch (cmd) { 22518377Skarels 22618377Skarels case SIOCSIFADDR: 22718377Skarels case SIOCSIFNETMASK: 22826456Skarels case SIOCSIFDSTADDR: 22918377Skarels if (!suser()) 23018377Skarels return (u.u_error); 23118377Skarels 23218377Skarels if (ifp == 0) 23318377Skarels panic("in_control"); 23418377Skarels if (ia == (struct in_ifaddr *)0) { 23518377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 23618377Skarels if (m == (struct mbuf *)NULL) 23718377Skarels return (ENOBUFS); 23818377Skarels if (ia = in_ifaddr) { 23918377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 24018377Skarels ; 24118377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 24218377Skarels } else 24318377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 24418377Skarels ia = mtod(m, struct in_ifaddr *); 24518377Skarels if (ifa = ifp->if_addrlist) { 24618377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 24718377Skarels ; 24818377Skarels ifa->ifa_next = (struct ifaddr *) ia; 24918377Skarels } else 25018377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 25118377Skarels ia->ia_ifp = ifp; 25218377Skarels IA_SIN(ia)->sin_family = AF_INET; 25324805Skarels if (ifp != &loif) 25424805Skarels in_interfaces++; 25517271Skarels } 25618377Skarels break; 25726317Skarels 25826317Skarels case SIOCSIFBRDADDR: 25926317Skarels if (!suser()) 26026317Skarels return (u.u_error); 26126317Skarels /* FALLTHROUGH */ 26226317Skarels 26326317Skarels default: 26426317Skarels if (ia == (struct in_ifaddr *)0) 26526317Skarels return (EADDRNOTAVAIL); 26626317Skarels break; 26717271Skarels } 26818377Skarels 26918377Skarels switch (cmd) { 27018377Skarels 27118377Skarels case SIOCGIFADDR: 27218377Skarels ifr->ifr_addr = ia->ia_addr; 27318377Skarels break; 27418377Skarels 27518377Skarels case SIOCGIFBRDADDR: 27618377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 27718377Skarels return (EINVAL); 27818377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 27918377Skarels break; 28018377Skarels 28118377Skarels case SIOCGIFDSTADDR: 28218377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 28318377Skarels return (EINVAL); 28418377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 28518377Skarels break; 28618377Skarels 28718377Skarels case SIOCGIFNETMASK: 28818377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 28918377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 29018377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 29118377Skarels break; 29218377Skarels 29318377Skarels case SIOCSIFDSTADDR: 29427066Skarels { 29527066Skarels struct sockaddr oldaddr; 29627066Skarels 29718377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 29818377Skarels return (EINVAL); 29927066Skarels oldaddr = ia->ia_dstaddr; 30027066Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 30118377Skarels if (ifp->if_ioctl && 30227066Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) { 30327066Skarels ia->ia_dstaddr = oldaddr; 30418377Skarels return (error); 30527066Skarels } 30627066Skarels if (ia->ia_flags & IFA_ROUTE) { 30727066Skarels rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT, 30827066Skarels RTF_HOST); 30927066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 31027066Skarels RTF_HOST|RTF_UP); 31127066Skarels } 31227066Skarels } 31318377Skarels break; 31418377Skarels 31518377Skarels case SIOCSIFBRDADDR: 31618377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 31718377Skarels return (EINVAL); 31818377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 31918377Skarels break; 32018377Skarels 32118377Skarels case SIOCSIFADDR: 32234500Skarels return (in_ifinit(ifp, ia, 32334500Skarels (struct sockaddr_in *) &ifr->ifr_addr)); 32418377Skarels 32518377Skarels case SIOCSIFNETMASK: 32618377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 32718377Skarels break; 32818377Skarels 32918377Skarels default: 33018377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 33118377Skarels return (EOPNOTSUPP); 33218377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 33318377Skarels } 33417271Skarels return (0); 33517271Skarels } 33617271Skarels 33717271Skarels /* 33818377Skarels * Initialize an interface's internet address 33918377Skarels * and routing table entry. 3407159Ssam */ 34118377Skarels in_ifinit(ifp, ia, sin) 3427159Ssam register struct ifnet *ifp; 34318377Skarels register struct in_ifaddr *ia; 34418377Skarels struct sockaddr_in *sin; 3457159Ssam { 34618377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 34727066Skarels struct sockaddr oldaddr; 34827066Skarels struct sockaddr_in netaddr; 34918377Skarels int s = splimp(), error; 3507159Ssam 35127066Skarels oldaddr = ia->ia_addr; 35226317Skarels ia->ia_addr = *(struct sockaddr *)sin; 35326317Skarels 35418377Skarels /* 35526317Skarels * Give the interface a chance to initialize 35626317Skarels * if this is its first address, 35726317Skarels * and to validate the address if necessary. 35826317Skarels */ 35926317Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 36026317Skarels splx(s); 36127066Skarels ia->ia_addr = oldaddr; 36226317Skarels return (error); 36326317Skarels } 36426317Skarels 36526317Skarels /* 36618377Skarels * Delete any previous route for an old address. 36718377Skarels */ 36827066Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 36927066Skarels netaddr.sin_family = AF_INET; 37018377Skarels if (ia->ia_flags & IFA_ROUTE) { 37127066Skarels if (ifp->if_flags & IFF_LOOPBACK) 37227066Skarels rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST); 37327066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 37427066Skarels rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT, 37527066Skarels RTF_HOST); 37627066Skarels else { 37727066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, 37827066Skarels INADDR_ANY); 37927066Skarels rtinit((struct sockaddr *)&netaddr, &oldaddr, 38025452Ssklower (int)SIOCDELRT, 0); 38127066Skarels } 38218377Skarels ia->ia_flags &= ~IFA_ROUTE; 38318377Skarels } 38418377Skarels if (IN_CLASSA(i)) 38518377Skarels ia->ia_netmask = IN_CLASSA_NET; 38618377Skarels else if (IN_CLASSB(i)) 38718377Skarels ia->ia_netmask = IN_CLASSB_NET; 38818377Skarels else 38918377Skarels ia->ia_netmask = IN_CLASSC_NET; 39018377Skarels ia->ia_net = i & ia->ia_netmask; 39118377Skarels /* 39218377Skarels * The subnet mask includes at least the standard network part, 39318377Skarels * but may already have been set to a larger value. 39418377Skarels */ 39518377Skarels ia->ia_subnetmask |= ia->ia_netmask; 39618377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 39718377Skarels if (ifp->if_flags & IFF_BROADCAST) { 39818377Skarels ia->ia_broadaddr.sa_family = AF_INET; 39918377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 40018377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 40125195Skarels ia->ia_netbroadcast.s_addr = 40225195Skarels htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask)); 40318377Skarels } 40418377Skarels /* 40518377Skarels * Add route for the network. 40618377Skarels */ 40727066Skarels if (ifp->if_flags & IFF_LOOPBACK) 40827066Skarels rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, 40927066Skarels RTF_HOST|RTF_UP); 41027066Skarels else if (ifp->if_flags & IFF_POINTOPOINT) 41127066Skarels rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT, 41227066Skarels RTF_HOST|RTF_UP); 41327066Skarels else { 41427066Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 41527066Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, 41627066Skarels (int)SIOCADDRT, RTF_UP); 41727066Skarels } 41818377Skarels ia->ia_flags |= IFA_ROUTE; 41930523Skarels splx(s); 42018642Skarels return (0); 4217159Ssam } 42218377Skarels 42318377Skarels /* 42418377Skarels * Return address info for specified internet network. 42518377Skarels */ 42618377Skarels struct in_ifaddr * 42718377Skarels in_iaonnetof(net) 42818377Skarels u_long net; 42918377Skarels { 43018377Skarels register struct in_ifaddr *ia; 43118377Skarels 43218377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 43318377Skarels if (ia->ia_subnet == net) 43418377Skarels return (ia); 43518377Skarels return ((struct in_ifaddr *)0); 43618377Skarels } 43718377Skarels 43818377Skarels /* 43930523Skarels * Return 1 if the address might be a local broadcast address. 44018377Skarels */ 44118377Skarels in_broadcast(in) 44218377Skarels struct in_addr in; 44318377Skarels { 44418377Skarels register struct in_ifaddr *ia; 44530523Skarels u_long t; 44618377Skarels 44718377Skarels /* 44818377Skarels * Look through the list of addresses for a match 44918377Skarels * with a broadcast address. 45018377Skarels */ 45118377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 45230523Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) { 45330523Skarels if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr) 45418377Skarels return (1); 45530523Skarels /* 45630523Skarels * Check for old-style (host 0) broadcast. 45730523Skarels */ 45830523Skarels if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net) 45930523Skarels return (1); 46030523Skarels } 46130523Skarels if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) 46230523Skarels return (1); 46318377Skarels return (0); 46418377Skarels } 4657159Ssam #endif 466