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*24805Skarels * @(#)in.c 6.9 (Berkeley) 09/16/85 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 */ 76*24805Skarels 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) 96*24805Skarels 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) 127*24805Skarels 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 134*24805Skarels * (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) 151*24805Skarels if (net == ia->ia_net) 15218377Skarels return (1); 15318377Skarels return (0); 15418377Skarels } 15518377Skarels 156*24805Skarels int in_interfaces; /* number of external internet interfaces */ 157*24805Skarels extern struct ifnet loif; 158*24805Skarels 15918377Skarels /* 16018377Skarels * Generic internet control operations (ioctl's). 16118377Skarels * Ifp is 0 if not an interface-specific ioctl. 16218377Skarels */ 163*24805Skarels /* 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; 17218377Skarels struct ifaddr *ifa; 17318377Skarels struct mbuf *m; 17418377Skarels int error; 17518377Skarels 17618377Skarels /* 17718377Skarels * Find address for this interface, if it exists. 17818377Skarels */ 17918377Skarels if (ifp) 18018377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 18118377Skarels if (ia->ia_ifp == ifp) 18218377Skarels break; 18318377Skarels 18418377Skarels switch (cmd) { 18518377Skarels 18618377Skarels case SIOCGIFADDR: 18718377Skarels case SIOCGIFBRDADDR: 18818377Skarels case SIOCGIFDSTADDR: 18918377Skarels case SIOCGIFNETMASK: 19018377Skarels if (ia == (struct in_ifaddr *)0) 19118377Skarels return (EADDRNOTAVAIL); 19218377Skarels break; 19318377Skarels 19418377Skarels case SIOCSIFADDR: 19518377Skarels case SIOCSIFDSTADDR: 19618377Skarels case SIOCSIFBRDADDR: 19718377Skarels case SIOCSIFNETMASK: 19818377Skarels if (!suser()) 19918377Skarels return (u.u_error); 20018377Skarels 20118377Skarels if (ifp == 0) 20218377Skarels panic("in_control"); 20318377Skarels if (ia == (struct in_ifaddr *)0) { 20418377Skarels m = m_getclr(M_WAIT, MT_IFADDR); 20518377Skarels if (m == (struct mbuf *)NULL) 20618377Skarels return (ENOBUFS); 20718377Skarels if (ia = in_ifaddr) { 20818377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 20918377Skarels ; 21018377Skarels ia->ia_next = mtod(m, struct in_ifaddr *); 21118377Skarels } else 21218377Skarels in_ifaddr = mtod(m, struct in_ifaddr *); 21318377Skarels ia = mtod(m, struct in_ifaddr *); 21418377Skarels if (ifa = ifp->if_addrlist) { 21518377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 21618377Skarels ; 21718377Skarels ifa->ifa_next = (struct ifaddr *) ia; 21818377Skarels } else 21918377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 22018377Skarels ia->ia_ifp = ifp; 22118377Skarels IA_SIN(ia)->sin_family = AF_INET; 222*24805Skarels if (ifp != &loif) 223*24805Skarels in_interfaces++; 22417271Skarels } 22518377Skarels break; 22617271Skarels } 22718377Skarels 22818377Skarels switch (cmd) { 22918377Skarels 23018377Skarels case SIOCGIFADDR: 23118377Skarels ifr->ifr_addr = ia->ia_addr; 23218377Skarels break; 23318377Skarels 23418377Skarels case SIOCGIFBRDADDR: 23518377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 23618377Skarels return (EINVAL); 23718377Skarels ifr->ifr_dstaddr = ia->ia_broadaddr; 23818377Skarels break; 23918377Skarels 24018377Skarels case SIOCGIFDSTADDR: 24118377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 24218377Skarels return (EINVAL); 24318377Skarels ifr->ifr_dstaddr = ia->ia_dstaddr; 24418377Skarels break; 24518377Skarels 24618377Skarels case SIOCGIFNETMASK: 24718377Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 24818377Skarels satosin(&ifr->ifr_addr)->sin_family = AF_INET; 24918377Skarels satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask); 25018377Skarels break; 25118377Skarels 25218377Skarels case SIOCSIFDSTADDR: 25318377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 25418377Skarels return (EINVAL); 25518377Skarels if (ifp->if_ioctl && 256*24805Skarels (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) 25718377Skarels return (error); 25818377Skarels ia->ia_dstaddr = ifr->ifr_dstaddr; 25918377Skarels break; 26018377Skarels 26118377Skarels case SIOCSIFBRDADDR: 26218377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 26318377Skarels return (EINVAL); 26418377Skarels ia->ia_broadaddr = ifr->ifr_broadaddr; 26518377Skarels break; 26618377Skarels 26718377Skarels case SIOCSIFADDR: 26818377Skarels return (in_ifinit(ifp, ia, &ifr->ifr_addr)); 26918377Skarels 27018377Skarels case SIOCSIFNETMASK: 27118377Skarels ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr); 27218377Skarels break; 27318377Skarels 27418377Skarels default: 27518377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 27618377Skarels return (EOPNOTSUPP); 27718377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 27818377Skarels } 27917271Skarels return (0); 28017271Skarels } 28117271Skarels 28217271Skarels /* 28318377Skarels * Initialize an interface's internet address 28418377Skarels * and routing table entry. 2857159Ssam */ 28618377Skarels in_ifinit(ifp, ia, sin) 2877159Ssam register struct ifnet *ifp; 28818377Skarels register struct in_ifaddr *ia; 28918377Skarels struct sockaddr_in *sin; 2907159Ssam { 29118377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 29218377Skarels struct sockaddr_in netaddr; 29318377Skarels int s = splimp(), error; 2947159Ssam 29518377Skarels bzero((caddr_t)&netaddr, sizeof (netaddr)); 29618377Skarels netaddr.sin_family = AF_INET; 29718377Skarels /* 29818377Skarels * Delete any previous route for an old address. 29918377Skarels */ 30018377Skarels if (ia->ia_flags & IFA_ROUTE) { 30118377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 30218377Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 30318377Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1); 30418377Skarels } else 30518377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1); 30618377Skarels ia->ia_flags &= ~IFA_ROUTE; 30718377Skarels } 30818377Skarels ia->ia_addr = *(struct sockaddr *)sin; 30918377Skarels if (IN_CLASSA(i)) 31018377Skarels ia->ia_netmask = IN_CLASSA_NET; 31118377Skarels else if (IN_CLASSB(i)) 31218377Skarels ia->ia_netmask = IN_CLASSB_NET; 31318377Skarels else 31418377Skarels ia->ia_netmask = IN_CLASSC_NET; 31518377Skarels ia->ia_net = i & ia->ia_netmask; 31618377Skarels /* 31718377Skarels * The subnet mask includes at least the standard network part, 31818377Skarels * but may already have been set to a larger value. 31918377Skarels */ 32018377Skarels ia->ia_subnetmask |= ia->ia_netmask; 32118377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 32218377Skarels if (ifp->if_flags & IFF_BROADCAST) { 32318377Skarels ia->ia_broadaddr.sa_family = AF_INET; 32418377Skarels ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr = 32518377Skarels in_makeaddr(ia->ia_subnet, INADDR_BROADCAST); 32618377Skarels } 32718377Skarels 32818377Skarels /* 32918377Skarels * Give the interface a chance to initialize 33018377Skarels * if this is its first address, 33118377Skarels * and to validate the address if necessary. 33218377Skarels */ 33318377Skarels if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) { 33418377Skarels splx(s); 33518377Skarels bzero((caddr_t)&ia->ia_addr, sizeof(ia->ia_addr)); 33618377Skarels return (error); 33718377Skarels } 33818377Skarels splx(s); 33918377Skarels /* 34018377Skarels * Add route for the network. 34118377Skarels */ 34218377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 34318377Skarels netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY); 34418377Skarels rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP); 34518377Skarels } else 34618377Skarels rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, 34718377Skarels RTF_HOST|RTF_UP); 34818377Skarels ia->ia_flags |= IFA_ROUTE; 34918642Skarels return (0); 3507159Ssam } 35118377Skarels 35218377Skarels /* 35318377Skarels * Return address info for specified internet network. 35418377Skarels */ 35518377Skarels struct in_ifaddr * 35618377Skarels in_iaonnetof(net) 35718377Skarels u_long net; 35818377Skarels { 35918377Skarels register struct in_ifaddr *ia; 36018377Skarels 36118377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 36218377Skarels if (ia->ia_subnet == net) 36318377Skarels return (ia); 36418377Skarels return ((struct in_ifaddr *)0); 36518377Skarels } 36618377Skarels 36718377Skarels /* 36818377Skarels * Return 1 if the address is a local broadcast address. 36918377Skarels */ 37018377Skarels in_broadcast(in) 37118377Skarels struct in_addr in; 37218377Skarels { 37318377Skarels register struct in_ifaddr *ia; 37418377Skarels 37518377Skarels /* 37618377Skarels * Look through the list of addresses for a match 37718377Skarels * with a broadcast address. 37818377Skarels */ 37918377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 38018377Skarels if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr == 38118377Skarels in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST)) 38218377Skarels return (1); 38318377Skarels return (0); 38418377Skarels } 3857159Ssam #endif 386