1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 332180b925SGarrett Wollman * @(#)in.c 8.4 (Berkeley) 1/9/95 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 3826f9a767SRodney W. Grimes #include <sys/systm.h> 3951a53488SBruce Evans #include <sys/sockio.h> 40df8bae1dSRodney W. Grimes #include <sys/malloc.h> 41df8bae1dSRodney W. Grimes #include <sys/socket.h> 42f6d24a78SPoul-Henning Kamp #include <sys/kernel.h> 43f6d24a78SPoul-Henning Kamp #include <sys/sysctl.h> 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes #include <net/if.h> 466a800098SYoshinobu Inoue #include <net/if_types.h> 47df8bae1dSRodney W. Grimes #include <net/route.h> 48df8bae1dSRodney W. Grimes 49df8bae1dSRodney W. Grimes #include <netinet/in.h> 50df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 51e43cc4aeSHajimu UMEMOTO #include <netinet/in_pcb.h> 52df8bae1dSRodney W. Grimes 53c70f4510SPoul-Henning Kamp #include <netinet/igmp_var.h> 54c70f4510SPoul-Henning Kamp 55a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); 5655166637SPoul-Henning Kamp 576a800098SYoshinobu Inoue static int in_mask2len __P((struct in_addr *)); 586a800098SYoshinobu Inoue static void in_len2mask __P((struct in_addr *, int)); 596a800098SYoshinobu Inoue static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 606a800098SYoshinobu Inoue struct ifnet *, struct proc *)); 616a800098SYoshinobu Inoue 620312fbe9SPoul-Henning Kamp static void in_socktrim __P((struct sockaddr_in *)); 630312fbe9SPoul-Henning Kamp static int in_ifinit __P((struct ifnet *, 640312fbe9SPoul-Henning Kamp struct in_ifaddr *, struct sockaddr_in *, int)); 65df8bae1dSRodney W. Grimes 66f8731310SGarrett Wollman static int subnetsarelocal = 0; 67f6d24a78SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, 68f6d24a78SPoul-Henning Kamp &subnetsarelocal, 0, ""); 69477180fbSGarrett Wollman 70477180fbSGarrett Wollman struct in_multihead in_multihead; /* XXX BSS initialization */ 71477180fbSGarrett Wollman 72e43cc4aeSHajimu UMEMOTO extern struct inpcbinfo ripcbinfo; 73e43cc4aeSHajimu UMEMOTO extern struct inpcbinfo udbinfo; 74e43cc4aeSHajimu UMEMOTO 75df8bae1dSRodney W. Grimes /* 76df8bae1dSRodney W. Grimes * Return 1 if an internet address is for a ``local'' host 77df8bae1dSRodney W. Grimes * (one to which we have a connection). If subnetsarelocal 78df8bae1dSRodney W. Grimes * is true, this includes other subnets of the local net. 79df8bae1dSRodney W. Grimes * Otherwise, it includes only the directly-connected (sub)nets. 80df8bae1dSRodney W. Grimes */ 8126f9a767SRodney W. Grimes int 82df8bae1dSRodney W. Grimes in_localaddr(in) 83df8bae1dSRodney W. Grimes struct in_addr in; 84df8bae1dSRodney W. Grimes { 85df8bae1dSRodney W. Grimes register u_long i = ntohl(in.s_addr); 86df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 87df8bae1dSRodney W. Grimes 88df8bae1dSRodney W. Grimes if (subnetsarelocal) { 89462b86feSPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 90df8bae1dSRodney W. Grimes if ((i & ia->ia_netmask) == ia->ia_net) 91df8bae1dSRodney W. Grimes return (1); 92df8bae1dSRodney W. Grimes } else { 9337d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 94df8bae1dSRodney W. Grimes if ((i & ia->ia_subnetmask) == ia->ia_subnet) 95df8bae1dSRodney W. Grimes return (1); 96df8bae1dSRodney W. Grimes } 97df8bae1dSRodney W. Grimes return (0); 98df8bae1dSRodney W. Grimes } 99df8bae1dSRodney W. Grimes 100df8bae1dSRodney W. Grimes /* 101df8bae1dSRodney W. Grimes * Determine whether an IP address is in a reserved set of addresses 102df8bae1dSRodney W. Grimes * that may not be forwarded, or whether datagrams to that destination 103df8bae1dSRodney W. Grimes * may be forwarded. 104df8bae1dSRodney W. Grimes */ 10526f9a767SRodney W. Grimes int 106df8bae1dSRodney W. Grimes in_canforward(in) 107df8bae1dSRodney W. Grimes struct in_addr in; 108df8bae1dSRodney W. Grimes { 109df8bae1dSRodney W. Grimes register u_long i = ntohl(in.s_addr); 110df8bae1dSRodney W. Grimes register u_long net; 111df8bae1dSRodney W. Grimes 112df8bae1dSRodney W. Grimes if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) 113df8bae1dSRodney W. Grimes return (0); 114df8bae1dSRodney W. Grimes if (IN_CLASSA(i)) { 115df8bae1dSRodney W. Grimes net = i & IN_CLASSA_NET; 116df8bae1dSRodney W. Grimes if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) 117df8bae1dSRodney W. Grimes return (0); 118df8bae1dSRodney W. Grimes } 119df8bae1dSRodney W. Grimes return (1); 120df8bae1dSRodney W. Grimes } 121df8bae1dSRodney W. Grimes 122df8bae1dSRodney W. Grimes /* 123df8bae1dSRodney W. Grimes * Trim a mask in a sockaddr 124df8bae1dSRodney W. Grimes */ 1250312fbe9SPoul-Henning Kamp static void 126df8bae1dSRodney W. Grimes in_socktrim(ap) 127df8bae1dSRodney W. Grimes struct sockaddr_in *ap; 128df8bae1dSRodney W. Grimes { 129df8bae1dSRodney W. Grimes register char *cplim = (char *) &ap->sin_addr; 130df8bae1dSRodney W. Grimes register char *cp = (char *) (&ap->sin_addr + 1); 131df8bae1dSRodney W. Grimes 132df8bae1dSRodney W. Grimes ap->sin_len = 0; 133df00058dSGarrett Wollman while (--cp >= cplim) 134df8bae1dSRodney W. Grimes if (*cp) { 135df8bae1dSRodney W. Grimes (ap)->sin_len = cp - (char *) (ap) + 1; 136df8bae1dSRodney W. Grimes break; 137df8bae1dSRodney W. Grimes } 138df8bae1dSRodney W. Grimes } 139df8bae1dSRodney W. Grimes 1406a800098SYoshinobu Inoue static int 1416a800098SYoshinobu Inoue in_mask2len(mask) 1426a800098SYoshinobu Inoue struct in_addr *mask; 1436a800098SYoshinobu Inoue { 1446a800098SYoshinobu Inoue int x, y; 1456a800098SYoshinobu Inoue u_char *p; 1466a800098SYoshinobu Inoue 1476a800098SYoshinobu Inoue p = (u_char *)mask; 1486a800098SYoshinobu Inoue for (x = 0; x < sizeof(*mask); x++) { 1496a800098SYoshinobu Inoue if (p[x] != 0xff) 1506a800098SYoshinobu Inoue break; 1516a800098SYoshinobu Inoue } 1526a800098SYoshinobu Inoue y = 0; 1536a800098SYoshinobu Inoue if (x < sizeof(*mask)) { 1546a800098SYoshinobu Inoue for (y = 0; y < 8; y++) { 1556a800098SYoshinobu Inoue if ((p[x] & (0x80 >> y)) == 0) 1566a800098SYoshinobu Inoue break; 1576a800098SYoshinobu Inoue } 1586a800098SYoshinobu Inoue } 1596a800098SYoshinobu Inoue return x * 8 + y; 1606a800098SYoshinobu Inoue } 1616a800098SYoshinobu Inoue 1626a800098SYoshinobu Inoue static void 1636a800098SYoshinobu Inoue in_len2mask(mask, len) 1646a800098SYoshinobu Inoue struct in_addr *mask; 1656a800098SYoshinobu Inoue int len; 1666a800098SYoshinobu Inoue { 1676a800098SYoshinobu Inoue int i; 1686a800098SYoshinobu Inoue u_char *p; 1696a800098SYoshinobu Inoue 1706a800098SYoshinobu Inoue p = (u_char *)mask; 1716a800098SYoshinobu Inoue bzero(mask, sizeof(*mask)); 1726a800098SYoshinobu Inoue for (i = 0; i < len / 8; i++) 1736a800098SYoshinobu Inoue p[i] = 0xff; 1746a800098SYoshinobu Inoue if (len % 8) 1756a800098SYoshinobu Inoue p[i] = (0xff00 >> (len % 8)) & 0xff; 1766a800098SYoshinobu Inoue } 1776a800098SYoshinobu Inoue 178f6d24a78SPoul-Henning Kamp static int in_interfaces; /* number of external internet interfaces */ 179df8bae1dSRodney W. Grimes 180df8bae1dSRodney W. Grimes /* 181df8bae1dSRodney W. Grimes * Generic internet control operations (ioctl's). 182df8bae1dSRodney W. Grimes * Ifp is 0 if not an interface-specific ioctl. 183df8bae1dSRodney W. Grimes */ 184df8bae1dSRodney W. Grimes /* ARGSUSED */ 18526f9a767SRodney W. Grimes int 186a29f300eSGarrett Wollman in_control(so, cmd, data, ifp, p) 187df8bae1dSRodney W. Grimes struct socket *so; 188ecbb00a2SDoug Rabson u_long cmd; 189df8bae1dSRodney W. Grimes caddr_t data; 190df8bae1dSRodney W. Grimes register struct ifnet *ifp; 191a29f300eSGarrett Wollman struct proc *p; 192df8bae1dSRodney W. Grimes { 193df8bae1dSRodney W. Grimes register struct ifreq *ifr = (struct ifreq *)data; 194ac0aa473SBill Fenner register struct in_ifaddr *ia = 0, *iap; 195df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 196df8bae1dSRodney W. Grimes struct in_ifaddr *oia; 197df8bae1dSRodney W. Grimes struct in_aliasreq *ifra = (struct in_aliasreq *)data; 198df8bae1dSRodney W. Grimes struct sockaddr_in oldaddr; 199c655b7c4SDavid Greenman int error, hostIsNew, maskIsNew, s; 200df8bae1dSRodney W. Grimes u_long i; 201df8bae1dSRodney W. Grimes 2026a800098SYoshinobu Inoue switch (cmd) { 2036a800098SYoshinobu Inoue case SIOCALIFADDR: 2046a800098SYoshinobu Inoue case SIOCDLIFADDR: 2056a800098SYoshinobu Inoue if (p && (error = suser(p)) != 0) 2066a800098SYoshinobu Inoue return error; 2076a800098SYoshinobu Inoue /*fall through*/ 2086a800098SYoshinobu Inoue case SIOCGLIFADDR: 2096a800098SYoshinobu Inoue if (!ifp) 2106a800098SYoshinobu Inoue return EINVAL; 2116a800098SYoshinobu Inoue return in_lifaddr_ioctl(so, cmd, data, ifp, p); 2126a800098SYoshinobu Inoue } 2136a800098SYoshinobu Inoue 214df8bae1dSRodney W. Grimes /* 215df8bae1dSRodney W. Grimes * Find address for this interface, if it exists. 216ac0aa473SBill Fenner * 217ac0aa473SBill Fenner * If an alias address was specified, find that one instead of 218ac0aa473SBill Fenner * the first one on the interface. 219df8bae1dSRodney W. Grimes */ 220df8bae1dSRodney W. Grimes if (ifp) 221462b86feSPoul-Henning Kamp TAILQ_FOREACH(iap, &in_ifaddrhead, ia_link) 222ac0aa473SBill Fenner if (iap->ia_ifp == ifp) { 223ac0aa473SBill Fenner if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr == 224ac0aa473SBill Fenner iap->ia_addr.sin_addr.s_addr) { 225ac0aa473SBill Fenner ia = iap; 226df8bae1dSRodney W. Grimes break; 227ac0aa473SBill Fenner } else if (ia == NULL) { 228ac0aa473SBill Fenner ia = iap; 229ac0aa473SBill Fenner if (ifr->ifr_addr.sa_family != AF_INET) 230ac0aa473SBill Fenner break; 231ac0aa473SBill Fenner } 232ac0aa473SBill Fenner } 233df8bae1dSRodney W. Grimes 234df8bae1dSRodney W. Grimes switch (cmd) { 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes case SIOCAIFADDR: 237df8bae1dSRodney W. Grimes case SIOCDIFADDR: 2386572231dSEivind Eklund if (ifp == 0) 2396572231dSEivind Eklund return (EADDRNOTAVAIL); 2401067217dSGarrett Wollman if (ifra->ifra_addr.sin_family == AF_INET) { 241fc2ffbe6SPoul-Henning Kamp for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { 242df8bae1dSRodney W. Grimes if (ia->ia_ifp == ifp && 243df8bae1dSRodney W. Grimes ia->ia_addr.sin_addr.s_addr == 244df8bae1dSRodney W. Grimes ifra->ifra_addr.sin_addr.s_addr) 245df8bae1dSRodney W. Grimes break; 246df8bae1dSRodney W. Grimes } 2471067217dSGarrett Wollman if ((ifp->if_flags & IFF_POINTOPOINT) 2481067217dSGarrett Wollman && (cmd == SIOCAIFADDR) 2491067217dSGarrett Wollman && (ifra->ifra_dstaddr.sin_addr.s_addr 2501067217dSGarrett Wollman == INADDR_ANY)) { 251357b78a9SGarrett Wollman return EDESTADDRREQ; 2521067217dSGarrett Wollman } 2531067217dSGarrett Wollman } 254df8bae1dSRodney W. Grimes if (cmd == SIOCDIFADDR && ia == 0) 255df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 256df8bae1dSRodney W. Grimes /* FALLTHROUGH */ 257df8bae1dSRodney W. Grimes case SIOCSIFADDR: 258df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 259df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 260f711d546SPoul-Henning Kamp if (p && (error = suser(p)) != 0) 261a29f300eSGarrett Wollman return error; 262df8bae1dSRodney W. Grimes 263df8bae1dSRodney W. Grimes if (ifp == 0) 2646572231dSEivind Eklund return (EADDRNOTAVAIL); 265df8bae1dSRodney W. Grimes if (ia == (struct in_ifaddr *)0) { 26659562606SGarrett Wollman ia = (struct in_ifaddr *) 2677cc0979fSDavid Malone malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO); 26859562606SGarrett Wollman if (ia == (struct in_ifaddr *)NULL) 269df8bae1dSRodney W. Grimes return (ENOBUFS); 270c655b7c4SDavid Greenman /* 271c655b7c4SDavid Greenman * Protect from ipintr() traversing address list 272c655b7c4SDavid Greenman * while we're modifying it. 273c655b7c4SDavid Greenman */ 274c655b7c4SDavid Greenman s = splnet(); 275c655b7c4SDavid Greenman 27659562606SGarrett Wollman TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link); 27759562606SGarrett Wollman ifa = &ia->ia_ifa; 27859562606SGarrett Wollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 27959562606SGarrett Wollman 28059562606SGarrett Wollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 28159562606SGarrett Wollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 28259562606SGarrett Wollman ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 283df8bae1dSRodney W. Grimes ia->ia_sockmask.sin_len = 8; 284df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_BROADCAST) { 285df8bae1dSRodney W. Grimes ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 286df8bae1dSRodney W. Grimes ia->ia_broadaddr.sin_family = AF_INET; 287df8bae1dSRodney W. Grimes } 288df8bae1dSRodney W. Grimes ia->ia_ifp = ifp; 289f5fea3ddSPaul Traina if (!(ifp->if_flags & IFF_LOOPBACK)) 290df8bae1dSRodney W. Grimes in_interfaces++; 291c655b7c4SDavid Greenman splx(s); 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes break; 294df8bae1dSRodney W. Grimes 295df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 296f711d546SPoul-Henning Kamp if (p && (error = suser(p)) != 0) 297a29f300eSGarrett Wollman return error; 298df8bae1dSRodney W. Grimes /* FALLTHROUGH */ 299df8bae1dSRodney W. Grimes 300df8bae1dSRodney W. Grimes case SIOCGIFADDR: 301df8bae1dSRodney W. Grimes case SIOCGIFNETMASK: 302df8bae1dSRodney W. Grimes case SIOCGIFDSTADDR: 303df8bae1dSRodney W. Grimes case SIOCGIFBRDADDR: 304df8bae1dSRodney W. Grimes if (ia == (struct in_ifaddr *)0) 305df8bae1dSRodney W. Grimes return (EADDRNOTAVAIL); 306df8bae1dSRodney W. Grimes break; 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes switch (cmd) { 309df8bae1dSRodney W. Grimes 310df8bae1dSRodney W. Grimes case SIOCGIFADDR: 311df8bae1dSRodney W. Grimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; 312df8bae1dSRodney W. Grimes break; 313df8bae1dSRodney W. Grimes 314df8bae1dSRodney W. Grimes case SIOCGIFBRDADDR: 315df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 316df8bae1dSRodney W. Grimes return (EINVAL); 317df8bae1dSRodney W. Grimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; 318df8bae1dSRodney W. Grimes break; 319df8bae1dSRodney W. Grimes 320df8bae1dSRodney W. Grimes case SIOCGIFDSTADDR: 321df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 322df8bae1dSRodney W. Grimes return (EINVAL); 323df8bae1dSRodney W. Grimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; 324df8bae1dSRodney W. Grimes break; 325df8bae1dSRodney W. Grimes 326df8bae1dSRodney W. Grimes case SIOCGIFNETMASK: 327df8bae1dSRodney W. Grimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; 328df8bae1dSRodney W. Grimes break; 329df8bae1dSRodney W. Grimes 330df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 331df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 332df8bae1dSRodney W. Grimes return (EINVAL); 333df8bae1dSRodney W. Grimes oldaddr = ia->ia_dstaddr; 334df8bae1dSRodney W. Grimes ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; 335df8bae1dSRodney W. Grimes if (ifp->if_ioctl && (error = (*ifp->if_ioctl) 336df8bae1dSRodney W. Grimes (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { 337df8bae1dSRodney W. Grimes ia->ia_dstaddr = oldaddr; 338df8bae1dSRodney W. Grimes return (error); 339df8bae1dSRodney W. Grimes } 340df8bae1dSRodney W. Grimes if (ia->ia_flags & IFA_ROUTE) { 341df8bae1dSRodney W. Grimes ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; 342df8bae1dSRodney W. Grimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 343df8bae1dSRodney W. Grimes ia->ia_ifa.ifa_dstaddr = 344df8bae1dSRodney W. Grimes (struct sockaddr *)&ia->ia_dstaddr; 345df8bae1dSRodney W. Grimes rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 346df8bae1dSRodney W. Grimes } 347df8bae1dSRodney W. Grimes break; 348df8bae1dSRodney W. Grimes 349df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 350df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 351df8bae1dSRodney W. Grimes return (EINVAL); 352df8bae1dSRodney W. Grimes ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; 353df8bae1dSRodney W. Grimes break; 354df8bae1dSRodney W. Grimes 355df8bae1dSRodney W. Grimes case SIOCSIFADDR: 356df8bae1dSRodney W. Grimes return (in_ifinit(ifp, ia, 357df8bae1dSRodney W. Grimes (struct sockaddr_in *) &ifr->ifr_addr, 1)); 358df8bae1dSRodney W. Grimes 359df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 360df8bae1dSRodney W. Grimes i = ifra->ifra_addr.sin_addr.s_addr; 361df8bae1dSRodney W. Grimes ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i); 362df8bae1dSRodney W. Grimes break; 363df8bae1dSRodney W. Grimes 364df8bae1dSRodney W. Grimes case SIOCAIFADDR: 365df8bae1dSRodney W. Grimes maskIsNew = 0; 366df8bae1dSRodney W. Grimes hostIsNew = 1; 367df8bae1dSRodney W. Grimes error = 0; 368df8bae1dSRodney W. Grimes if (ia->ia_addr.sin_family == AF_INET) { 369df8bae1dSRodney W. Grimes if (ifra->ifra_addr.sin_len == 0) { 370df8bae1dSRodney W. Grimes ifra->ifra_addr = ia->ia_addr; 371df8bae1dSRodney W. Grimes hostIsNew = 0; 372df8bae1dSRodney W. Grimes } else if (ifra->ifra_addr.sin_addr.s_addr == 373df8bae1dSRodney W. Grimes ia->ia_addr.sin_addr.s_addr) 374df8bae1dSRodney W. Grimes hostIsNew = 0; 375df8bae1dSRodney W. Grimes } 376df8bae1dSRodney W. Grimes if (ifra->ifra_mask.sin_len) { 377df8bae1dSRodney W. Grimes in_ifscrub(ifp, ia); 378df8bae1dSRodney W. Grimes ia->ia_sockmask = ifra->ifra_mask; 379df8bae1dSRodney W. Grimes ia->ia_subnetmask = 380df8bae1dSRodney W. Grimes ntohl(ia->ia_sockmask.sin_addr.s_addr); 381df8bae1dSRodney W. Grimes maskIsNew = 1; 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_POINTOPOINT) && 384df8bae1dSRodney W. Grimes (ifra->ifra_dstaddr.sin_family == AF_INET)) { 385df8bae1dSRodney W. Grimes in_ifscrub(ifp, ia); 386df8bae1dSRodney W. Grimes ia->ia_dstaddr = ifra->ifra_dstaddr; 387df8bae1dSRodney W. Grimes maskIsNew = 1; /* We lie; but the effect's the same */ 388df8bae1dSRodney W. Grimes } 389df8bae1dSRodney W. Grimes if (ifra->ifra_addr.sin_family == AF_INET && 390df8bae1dSRodney W. Grimes (hostIsNew || maskIsNew)) 391df8bae1dSRodney W. Grimes error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); 392df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) && 393df8bae1dSRodney W. Grimes (ifra->ifra_broadaddr.sin_family == AF_INET)) 394df8bae1dSRodney W. Grimes ia->ia_broadaddr = ifra->ifra_broadaddr; 395df8bae1dSRodney W. Grimes return (error); 396df8bae1dSRodney W. Grimes 397df8bae1dSRodney W. Grimes case SIOCDIFADDR: 398089cdfadSRuslan Ermilov /* 399089cdfadSRuslan Ermilov * in_ifscrub kills the interface route. 400089cdfadSRuslan Ermilov */ 401df8bae1dSRodney W. Grimes in_ifscrub(ifp, ia); 402c655b7c4SDavid Greenman /* 403089cdfadSRuslan Ermilov * in_ifadown gets rid of all the rest of 404089cdfadSRuslan Ermilov * the routes. This is not quite the right 405089cdfadSRuslan Ermilov * thing to do, but at least if we are running 406089cdfadSRuslan Ermilov * a routing process they will come back. 407089cdfadSRuslan Ermilov */ 40891854268SRuslan Ermilov in_ifadown(&ia->ia_ifa, 1); 409e43cc4aeSHajimu UMEMOTO /* 410e43cc4aeSHajimu UMEMOTO * XXX horrible hack to detect that we are being called 411e43cc4aeSHajimu UMEMOTO * from if_detach() 412e43cc4aeSHajimu UMEMOTO */ 413e43cc4aeSHajimu UMEMOTO if (!ifnet_addrs[ifp->if_index - 1]) { 414e43cc4aeSHajimu UMEMOTO in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp); 415e43cc4aeSHajimu UMEMOTO in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp); 416e43cc4aeSHajimu UMEMOTO } 417089cdfadSRuslan Ermilov 418089cdfadSRuslan Ermilov /* 419c655b7c4SDavid Greenman * Protect from ipintr() traversing address list 420c655b7c4SDavid Greenman * while we're modifying it. 421c655b7c4SDavid Greenman */ 422c655b7c4SDavid Greenman s = splnet(); 423c655b7c4SDavid Greenman 42459562606SGarrett Wollman ifa = &ia->ia_ifa; 42559562606SGarrett Wollman TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 426df8bae1dSRodney W. Grimes oia = ia; 42759562606SGarrett Wollman TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link); 428ffa5b11aSGarrett Wollman IFAFREE(&oia->ia_ifa); 429c655b7c4SDavid Greenman splx(s); 430df8bae1dSRodney W. Grimes break; 431df8bae1dSRodney W. Grimes 432df8bae1dSRodney W. Grimes default: 433df8bae1dSRodney W. Grimes if (ifp == 0 || ifp->if_ioctl == 0) 434df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 435df8bae1dSRodney W. Grimes return ((*ifp->if_ioctl)(ifp, cmd, data)); 436df8bae1dSRodney W. Grimes } 437df8bae1dSRodney W. Grimes return (0); 438df8bae1dSRodney W. Grimes } 439df8bae1dSRodney W. Grimes 440df8bae1dSRodney W. Grimes /* 4416a800098SYoshinobu Inoue * SIOC[GAD]LIFADDR. 4426a800098SYoshinobu Inoue * SIOCGLIFADDR: get first address. (?!?) 4436a800098SYoshinobu Inoue * SIOCGLIFADDR with IFLR_PREFIX: 4446a800098SYoshinobu Inoue * get first address that matches the specified prefix. 4456a800098SYoshinobu Inoue * SIOCALIFADDR: add the specified address. 4466a800098SYoshinobu Inoue * SIOCALIFADDR with IFLR_PREFIX: 4476a800098SYoshinobu Inoue * EINVAL since we can't deduce hostid part of the address. 4486a800098SYoshinobu Inoue * SIOCDLIFADDR: delete the specified address. 4496a800098SYoshinobu Inoue * SIOCDLIFADDR with IFLR_PREFIX: 4506a800098SYoshinobu Inoue * delete the first address that matches the specified prefix. 4516a800098SYoshinobu Inoue * return values: 4526a800098SYoshinobu Inoue * EINVAL on invalid parameters 4536a800098SYoshinobu Inoue * EADDRNOTAVAIL on prefix match failed/specified address not found 4546a800098SYoshinobu Inoue * other values may be returned from in_ioctl() 4556a800098SYoshinobu Inoue */ 4566a800098SYoshinobu Inoue static int 4576a800098SYoshinobu Inoue in_lifaddr_ioctl(so, cmd, data, ifp, p) 4586a800098SYoshinobu Inoue struct socket *so; 4596a800098SYoshinobu Inoue u_long cmd; 4606a800098SYoshinobu Inoue caddr_t data; 4616a800098SYoshinobu Inoue struct ifnet *ifp; 4626a800098SYoshinobu Inoue struct proc *p; 4636a800098SYoshinobu Inoue { 4646a800098SYoshinobu Inoue struct if_laddrreq *iflr = (struct if_laddrreq *)data; 4656a800098SYoshinobu Inoue struct ifaddr *ifa; 4666a800098SYoshinobu Inoue 4676a800098SYoshinobu Inoue /* sanity checks */ 4686a800098SYoshinobu Inoue if (!data || !ifp) { 4696a800098SYoshinobu Inoue panic("invalid argument to in_lifaddr_ioctl"); 4706a800098SYoshinobu Inoue /*NOTRECHED*/ 4716a800098SYoshinobu Inoue } 4726a800098SYoshinobu Inoue 4736a800098SYoshinobu Inoue switch (cmd) { 4746a800098SYoshinobu Inoue case SIOCGLIFADDR: 4756a800098SYoshinobu Inoue /* address must be specified on GET with IFLR_PREFIX */ 4766a800098SYoshinobu Inoue if ((iflr->flags & IFLR_PREFIX) == 0) 4776a800098SYoshinobu Inoue break; 4786a800098SYoshinobu Inoue /*FALLTHROUGH*/ 4796a800098SYoshinobu Inoue case SIOCALIFADDR: 4806a800098SYoshinobu Inoue case SIOCDLIFADDR: 4816a800098SYoshinobu Inoue /* address must be specified on ADD and DELETE */ 4825d60ed0eSYoshinobu Inoue if (iflr->addr.ss_family != AF_INET) 4836a800098SYoshinobu Inoue return EINVAL; 4845d60ed0eSYoshinobu Inoue if (iflr->addr.ss_len != sizeof(struct sockaddr_in)) 4856a800098SYoshinobu Inoue return EINVAL; 4866a800098SYoshinobu Inoue /* XXX need improvement */ 4875d60ed0eSYoshinobu Inoue if (iflr->dstaddr.ss_family 4885d60ed0eSYoshinobu Inoue && iflr->dstaddr.ss_family != AF_INET) 4896a800098SYoshinobu Inoue return EINVAL; 4905d60ed0eSYoshinobu Inoue if (iflr->dstaddr.ss_family 4915d60ed0eSYoshinobu Inoue && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in)) 4926a800098SYoshinobu Inoue return EINVAL; 4936a800098SYoshinobu Inoue break; 4946a800098SYoshinobu Inoue default: /*shouldn't happen*/ 4956a800098SYoshinobu Inoue return EOPNOTSUPP; 4966a800098SYoshinobu Inoue } 4976a800098SYoshinobu Inoue if (sizeof(struct in_addr) * 8 < iflr->prefixlen) 4986a800098SYoshinobu Inoue return EINVAL; 4996a800098SYoshinobu Inoue 5006a800098SYoshinobu Inoue switch (cmd) { 5016a800098SYoshinobu Inoue case SIOCALIFADDR: 5026a800098SYoshinobu Inoue { 5036a800098SYoshinobu Inoue struct in_aliasreq ifra; 5046a800098SYoshinobu Inoue 5056a800098SYoshinobu Inoue if (iflr->flags & IFLR_PREFIX) 5066a800098SYoshinobu Inoue return EINVAL; 5076a800098SYoshinobu Inoue 5086a800098SYoshinobu Inoue /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 5096a800098SYoshinobu Inoue bzero(&ifra, sizeof(ifra)); 5106a800098SYoshinobu Inoue bcopy(iflr->iflr_name, ifra.ifra_name, 5116a800098SYoshinobu Inoue sizeof(ifra.ifra_name)); 5126a800098SYoshinobu Inoue 5135d60ed0eSYoshinobu Inoue bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len); 5146a800098SYoshinobu Inoue 5155d60ed0eSYoshinobu Inoue if (iflr->dstaddr.ss_family) { /*XXX*/ 5166a800098SYoshinobu Inoue bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 5175d60ed0eSYoshinobu Inoue iflr->dstaddr.ss_len); 5186a800098SYoshinobu Inoue } 5196a800098SYoshinobu Inoue 5206a800098SYoshinobu Inoue ifra.ifra_mask.sin_family = AF_INET; 5216a800098SYoshinobu Inoue ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); 5226a800098SYoshinobu Inoue in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); 5236a800098SYoshinobu Inoue 5246a800098SYoshinobu Inoue return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, p); 5256a800098SYoshinobu Inoue } 5266a800098SYoshinobu Inoue case SIOCGLIFADDR: 5276a800098SYoshinobu Inoue case SIOCDLIFADDR: 5286a800098SYoshinobu Inoue { 5296a800098SYoshinobu Inoue struct in_ifaddr *ia; 5306a800098SYoshinobu Inoue struct in_addr mask, candidate, match; 5316a800098SYoshinobu Inoue struct sockaddr_in *sin; 5326a800098SYoshinobu Inoue int cmp; 5336a800098SYoshinobu Inoue 5346a800098SYoshinobu Inoue bzero(&mask, sizeof(mask)); 5356a800098SYoshinobu Inoue if (iflr->flags & IFLR_PREFIX) { 5366a800098SYoshinobu Inoue /* lookup a prefix rather than address. */ 5376a800098SYoshinobu Inoue in_len2mask(&mask, iflr->prefixlen); 5386a800098SYoshinobu Inoue 5396a800098SYoshinobu Inoue sin = (struct sockaddr_in *)&iflr->addr; 5406a800098SYoshinobu Inoue match.s_addr = sin->sin_addr.s_addr; 5416a800098SYoshinobu Inoue match.s_addr &= mask.s_addr; 5426a800098SYoshinobu Inoue 5436a800098SYoshinobu Inoue /* if you set extra bits, that's wrong */ 5446a800098SYoshinobu Inoue if (match.s_addr != sin->sin_addr.s_addr) 5456a800098SYoshinobu Inoue return EINVAL; 5466a800098SYoshinobu Inoue 5476a800098SYoshinobu Inoue cmp = 1; 5486a800098SYoshinobu Inoue } else { 5496a800098SYoshinobu Inoue if (cmd == SIOCGLIFADDR) { 5506a800098SYoshinobu Inoue /* on getting an address, take the 1st match */ 5516a800098SYoshinobu Inoue cmp = 0; /*XXX*/ 5526a800098SYoshinobu Inoue } else { 5536a800098SYoshinobu Inoue /* on deleting an address, do exact match */ 5546a800098SYoshinobu Inoue in_len2mask(&mask, 32); 5556a800098SYoshinobu Inoue sin = (struct sockaddr_in *)&iflr->addr; 5566a800098SYoshinobu Inoue match.s_addr = sin->sin_addr.s_addr; 5576a800098SYoshinobu Inoue 5586a800098SYoshinobu Inoue cmp = 1; 5596a800098SYoshinobu Inoue } 5606a800098SYoshinobu Inoue } 5616a800098SYoshinobu Inoue 5626a800098SYoshinobu Inoue TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 5636a800098SYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 5646a800098SYoshinobu Inoue continue; 5656a800098SYoshinobu Inoue if (!cmp) 5666a800098SYoshinobu Inoue break; 5676a800098SYoshinobu Inoue candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr; 5686a800098SYoshinobu Inoue candidate.s_addr &= mask.s_addr; 5696a800098SYoshinobu Inoue if (candidate.s_addr == match.s_addr) 5706a800098SYoshinobu Inoue break; 5716a800098SYoshinobu Inoue } 5726a800098SYoshinobu Inoue if (!ifa) 5736a800098SYoshinobu Inoue return EADDRNOTAVAIL; 5746a800098SYoshinobu Inoue ia = (struct in_ifaddr *)ifa; 5756a800098SYoshinobu Inoue 5766a800098SYoshinobu Inoue if (cmd == SIOCGLIFADDR) { 5776a800098SYoshinobu Inoue /* fill in the if_laddrreq structure */ 5786a800098SYoshinobu Inoue bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); 5796a800098SYoshinobu Inoue 5806a800098SYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 5816a800098SYoshinobu Inoue bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 5826a800098SYoshinobu Inoue ia->ia_dstaddr.sin_len); 5836a800098SYoshinobu Inoue } else 5846a800098SYoshinobu Inoue bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 5856a800098SYoshinobu Inoue 5866a800098SYoshinobu Inoue iflr->prefixlen = 5876a800098SYoshinobu Inoue in_mask2len(&ia->ia_sockmask.sin_addr); 5886a800098SYoshinobu Inoue 5896a800098SYoshinobu Inoue iflr->flags = 0; /*XXX*/ 5906a800098SYoshinobu Inoue 5916a800098SYoshinobu Inoue return 0; 5926a800098SYoshinobu Inoue } else { 5936a800098SYoshinobu Inoue struct in_aliasreq ifra; 5946a800098SYoshinobu Inoue 5956a800098SYoshinobu Inoue /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 5966a800098SYoshinobu Inoue bzero(&ifra, sizeof(ifra)); 5976a800098SYoshinobu Inoue bcopy(iflr->iflr_name, ifra.ifra_name, 5986a800098SYoshinobu Inoue sizeof(ifra.ifra_name)); 5996a800098SYoshinobu Inoue 6006a800098SYoshinobu Inoue bcopy(&ia->ia_addr, &ifra.ifra_addr, 6016a800098SYoshinobu Inoue ia->ia_addr.sin_len); 6026a800098SYoshinobu Inoue if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 6036a800098SYoshinobu Inoue bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 6046a800098SYoshinobu Inoue ia->ia_dstaddr.sin_len); 6056a800098SYoshinobu Inoue } 6066a800098SYoshinobu Inoue bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, 6076a800098SYoshinobu Inoue ia->ia_sockmask.sin_len); 6086a800098SYoshinobu Inoue 6096a800098SYoshinobu Inoue return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, 6106a800098SYoshinobu Inoue ifp, p); 6116a800098SYoshinobu Inoue } 6126a800098SYoshinobu Inoue } 6136a800098SYoshinobu Inoue } 6146a800098SYoshinobu Inoue 6156a800098SYoshinobu Inoue return EOPNOTSUPP; /*just for safety*/ 6166a800098SYoshinobu Inoue } 6176a800098SYoshinobu Inoue 6186a800098SYoshinobu Inoue /* 619df8bae1dSRodney W. Grimes * Delete any existing route for an interface. 620df8bae1dSRodney W. Grimes */ 62139191c8eSGarrett Wollman void 622df8bae1dSRodney W. Grimes in_ifscrub(ifp, ia) 623df8bae1dSRodney W. Grimes register struct ifnet *ifp; 624df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 625df8bae1dSRodney W. Grimes { 626df8bae1dSRodney W. Grimes 627df8bae1dSRodney W. Grimes if ((ia->ia_flags & IFA_ROUTE) == 0) 628df8bae1dSRodney W. Grimes return; 629df8bae1dSRodney W. Grimes if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) 630df8bae1dSRodney W. Grimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 631df8bae1dSRodney W. Grimes else 632df8bae1dSRodney W. Grimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 633df8bae1dSRodney W. Grimes ia->ia_flags &= ~IFA_ROUTE; 634df8bae1dSRodney W. Grimes } 635df8bae1dSRodney W. Grimes 636df8bae1dSRodney W. Grimes /* 637df8bae1dSRodney W. Grimes * Initialize an interface's internet address 638df8bae1dSRodney W. Grimes * and routing table entry. 639df8bae1dSRodney W. Grimes */ 6400312fbe9SPoul-Henning Kamp static int 641df8bae1dSRodney W. Grimes in_ifinit(ifp, ia, sin, scrub) 642df8bae1dSRodney W. Grimes register struct ifnet *ifp; 643df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 644df8bae1dSRodney W. Grimes struct sockaddr_in *sin; 645df8bae1dSRodney W. Grimes int scrub; 646df8bae1dSRodney W. Grimes { 647df8bae1dSRodney W. Grimes register u_long i = ntohl(sin->sin_addr.s_addr); 648df8bae1dSRodney W. Grimes struct sockaddr_in oldaddr; 649f23b4c91SGarrett Wollman int s = splimp(), flags = RTF_UP, error; 650df8bae1dSRodney W. Grimes 651df8bae1dSRodney W. Grimes oldaddr = ia->ia_addr; 652df8bae1dSRodney W. Grimes ia->ia_addr = *sin; 653df8bae1dSRodney W. Grimes /* 654df8bae1dSRodney W. Grimes * Give the interface a chance to initialize 655df8bae1dSRodney W. Grimes * if this is its first address, 656df8bae1dSRodney W. Grimes * and to validate the address if necessary. 657df8bae1dSRodney W. Grimes */ 658df8bae1dSRodney W. Grimes if (ifp->if_ioctl && 659df8bae1dSRodney W. Grimes (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 660df8bae1dSRodney W. Grimes splx(s); 661df8bae1dSRodney W. Grimes ia->ia_addr = oldaddr; 662df8bae1dSRodney W. Grimes return (error); 663df8bae1dSRodney W. Grimes } 664df8bae1dSRodney W. Grimes splx(s); 665df8bae1dSRodney W. Grimes if (scrub) { 666df8bae1dSRodney W. Grimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 667df8bae1dSRodney W. Grimes in_ifscrub(ifp, ia); 668df8bae1dSRodney W. Grimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes if (IN_CLASSA(i)) 671df8bae1dSRodney W. Grimes ia->ia_netmask = IN_CLASSA_NET; 672df8bae1dSRodney W. Grimes else if (IN_CLASSB(i)) 673df8bae1dSRodney W. Grimes ia->ia_netmask = IN_CLASSB_NET; 674df8bae1dSRodney W. Grimes else 675df8bae1dSRodney W. Grimes ia->ia_netmask = IN_CLASSC_NET; 676df8bae1dSRodney W. Grimes /* 677df8bae1dSRodney W. Grimes * The subnet mask usually includes at least the standard network part, 678df8bae1dSRodney W. Grimes * but may may be smaller in the case of supernetting. 679df8bae1dSRodney W. Grimes * If it is set, we believe it. 680df8bae1dSRodney W. Grimes */ 681df8bae1dSRodney W. Grimes if (ia->ia_subnetmask == 0) { 682df8bae1dSRodney W. Grimes ia->ia_subnetmask = ia->ia_netmask; 683df8bae1dSRodney W. Grimes ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 684df8bae1dSRodney W. Grimes } else 685df8bae1dSRodney W. Grimes ia->ia_netmask &= ia->ia_subnetmask; 686df8bae1dSRodney W. Grimes ia->ia_net = i & ia->ia_netmask; 687df8bae1dSRodney W. Grimes ia->ia_subnet = i & ia->ia_subnetmask; 688df8bae1dSRodney W. Grimes in_socktrim(&ia->ia_sockmask); 689df8bae1dSRodney W. Grimes /* 690df8bae1dSRodney W. Grimes * Add route for the network. 691df8bae1dSRodney W. Grimes */ 692df8bae1dSRodney W. Grimes ia->ia_ifa.ifa_metric = ifp->if_metric; 693df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_BROADCAST) { 694df8bae1dSRodney W. Grimes ia->ia_broadaddr.sin_addr.s_addr = 695df8bae1dSRodney W. Grimes htonl(ia->ia_subnet | ~ia->ia_subnetmask); 696df8bae1dSRodney W. Grimes ia->ia_netbroadcast.s_addr = 697df8bae1dSRodney W. Grimes htonl(ia->ia_net | ~ ia->ia_netmask); 698df8bae1dSRodney W. Grimes } else if (ifp->if_flags & IFF_LOOPBACK) { 699df8bae1dSRodney W. Grimes ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; 700df8bae1dSRodney W. Grimes flags |= RTF_HOST; 701df8bae1dSRodney W. Grimes } else if (ifp->if_flags & IFF_POINTOPOINT) { 702df8bae1dSRodney W. Grimes if (ia->ia_dstaddr.sin_family != AF_INET) 703df8bae1dSRodney W. Grimes return (0); 704df8bae1dSRodney W. Grimes flags |= RTF_HOST; 705df8bae1dSRodney W. Grimes } 706df8bae1dSRodney W. Grimes if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) 707df8bae1dSRodney W. Grimes ia->ia_flags |= IFA_ROUTE; 70833841545SHajimu UMEMOTO /* XXX check if the subnet route points to the same interface */ 70933841545SHajimu UMEMOTO if (error == EEXIST) 71033841545SHajimu UMEMOTO error = 0; 711ffa5b11aSGarrett Wollman 712df8bae1dSRodney W. Grimes /* 713df8bae1dSRodney W. Grimes * If the interface supports multicast, join the "all hosts" 714df8bae1dSRodney W. Grimes * multicast group on that interface. 715df8bae1dSRodney W. Grimes */ 716df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_MULTICAST) { 717df8bae1dSRodney W. Grimes struct in_addr addr; 718df8bae1dSRodney W. Grimes 719df8bae1dSRodney W. Grimes addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 720df8bae1dSRodney W. Grimes in_addmulti(&addr, ifp); 721df8bae1dSRodney W. Grimes } 722df8bae1dSRodney W. Grimes return (error); 723df8bae1dSRodney W. Grimes } 724df8bae1dSRodney W. Grimes 725df8bae1dSRodney W. Grimes 726df8bae1dSRodney W. Grimes /* 727df8bae1dSRodney W. Grimes * Return 1 if the address might be a local broadcast address. 728df8bae1dSRodney W. Grimes */ 72926f9a767SRodney W. Grimes int 730df8bae1dSRodney W. Grimes in_broadcast(in, ifp) 731df8bae1dSRodney W. Grimes struct in_addr in; 732df8bae1dSRodney W. Grimes struct ifnet *ifp; 733df8bae1dSRodney W. Grimes { 734df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 735df8bae1dSRodney W. Grimes u_long t; 736df8bae1dSRodney W. Grimes 737df8bae1dSRodney W. Grimes if (in.s_addr == INADDR_BROADCAST || 738df8bae1dSRodney W. Grimes in.s_addr == INADDR_ANY) 739df8bae1dSRodney W. Grimes return 1; 740df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 741df8bae1dSRodney W. Grimes return 0; 742df8bae1dSRodney W. Grimes t = ntohl(in.s_addr); 743df8bae1dSRodney W. Grimes /* 744df8bae1dSRodney W. Grimes * Look through the list of addresses for a match 745df8bae1dSRodney W. Grimes * with a broadcast address. 746df8bae1dSRodney W. Grimes */ 747df8bae1dSRodney W. Grimes #define ia ((struct in_ifaddr *)ifa) 748462b86feSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 749df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family == AF_INET && 750df8bae1dSRodney W. Grimes (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 751df8bae1dSRodney W. Grimes in.s_addr == ia->ia_netbroadcast.s_addr || 752df8bae1dSRodney W. Grimes /* 753df8bae1dSRodney W. Grimes * Check for old-style (host 0) broadcast. 754df8bae1dSRodney W. Grimes */ 7558dd27fd6SGuido van Rooij t == ia->ia_subnet || t == ia->ia_net) && 7568dd27fd6SGuido van Rooij /* 7578dd27fd6SGuido van Rooij * Check for an all one subnetmask. These 7588dd27fd6SGuido van Rooij * only exist when an interface gets a secondary 7598dd27fd6SGuido van Rooij * address. 7608dd27fd6SGuido van Rooij */ 7618dd27fd6SGuido van Rooij ia->ia_subnetmask != (u_long)0xffffffff) 762df8bae1dSRodney W. Grimes return 1; 763df8bae1dSRodney W. Grimes return (0); 764df8bae1dSRodney W. Grimes #undef ia 765df8bae1dSRodney W. Grimes } 766df8bae1dSRodney W. Grimes /* 767df8bae1dSRodney W. Grimes * Add an address to the list of IP multicast addresses for a given interface. 768df8bae1dSRodney W. Grimes */ 769df8bae1dSRodney W. Grimes struct in_multi * 770df8bae1dSRodney W. Grimes in_addmulti(ap, ifp) 771df8bae1dSRodney W. Grimes register struct in_addr *ap; 772df8bae1dSRodney W. Grimes register struct ifnet *ifp; 773df8bae1dSRodney W. Grimes { 774df8bae1dSRodney W. Grimes register struct in_multi *inm; 775477180fbSGarrett Wollman int error; 776477180fbSGarrett Wollman struct sockaddr_in sin; 777477180fbSGarrett Wollman struct ifmultiaddr *ifma; 778df8bae1dSRodney W. Grimes int s = splnet(); 779df8bae1dSRodney W. Grimes 780df8bae1dSRodney W. Grimes /* 781477180fbSGarrett Wollman * Call generic routine to add membership or increment 782477180fbSGarrett Wollman * refcount. It wants addresses in the form of a sockaddr, 783477180fbSGarrett Wollman * so we build one here (being careful to zero the unused bytes). 784df8bae1dSRodney W. Grimes */ 785477180fbSGarrett Wollman bzero(&sin, sizeof sin); 786477180fbSGarrett Wollman sin.sin_family = AF_INET; 787477180fbSGarrett Wollman sin.sin_len = sizeof sin; 788477180fbSGarrett Wollman sin.sin_addr = *ap; 789477180fbSGarrett Wollman error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma); 790477180fbSGarrett Wollman if (error) { 791477180fbSGarrett Wollman splx(s); 792477180fbSGarrett Wollman return 0; 793df8bae1dSRodney W. Grimes } 794477180fbSGarrett Wollman 795df8bae1dSRodney W. Grimes /* 796477180fbSGarrett Wollman * If ifma->ifma_protospec is null, then if_addmulti() created 797477180fbSGarrett Wollman * a new record. Otherwise, we are done. 798df8bae1dSRodney W. Grimes */ 7994153a3a3SBruce Evans if (ifma->ifma_protospec != 0) { 8004153a3a3SBruce Evans splx(s); 801477180fbSGarrett Wollman return ifma->ifma_protospec; 8024153a3a3SBruce Evans } 803477180fbSGarrett Wollman 804477180fbSGarrett Wollman /* XXX - if_addmulti uses M_WAITOK. Can this really be called 805477180fbSGarrett Wollman at interrupt time? If so, need to fix if_addmulti. XXX */ 8067cc0979fSDavid Malone inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR, 8077cc0979fSDavid Malone M_NOWAIT | M_ZERO); 808df8bae1dSRodney W. Grimes if (inm == NULL) { 809df8bae1dSRodney W. Grimes splx(s); 810df8bae1dSRodney W. Grimes return (NULL); 811df8bae1dSRodney W. Grimes } 812477180fbSGarrett Wollman 813df8bae1dSRodney W. Grimes inm->inm_addr = *ap; 814df8bae1dSRodney W. Grimes inm->inm_ifp = ifp; 815477180fbSGarrett Wollman inm->inm_ifma = ifma; 816477180fbSGarrett Wollman ifma->ifma_protospec = inm; 817477180fbSGarrett Wollman LIST_INSERT_HEAD(&in_multihead, inm, inm_link); 818ffa5b11aSGarrett Wollman 819df8bae1dSRodney W. Grimes /* 820df8bae1dSRodney W. Grimes * Let IGMP know that we have joined a new IP multicast group. 821df8bae1dSRodney W. Grimes */ 822df8bae1dSRodney W. Grimes igmp_joingroup(inm); 823df8bae1dSRodney W. Grimes splx(s); 824df8bae1dSRodney W. Grimes return (inm); 825df8bae1dSRodney W. Grimes } 826df8bae1dSRodney W. Grimes 827df8bae1dSRodney W. Grimes /* 828df8bae1dSRodney W. Grimes * Delete a multicast address record. 829df8bae1dSRodney W. Grimes */ 83026f9a767SRodney W. Grimes void 831df8bae1dSRodney W. Grimes in_delmulti(inm) 832df8bae1dSRodney W. Grimes register struct in_multi *inm; 833df8bae1dSRodney W. Grimes { 834477180fbSGarrett Wollman struct ifmultiaddr *ifma = inm->inm_ifma; 83588a5354eSLuigi Rizzo struct in_multi my_inm; 836df8bae1dSRodney W. Grimes int s = splnet(); 837df8bae1dSRodney W. Grimes 83888a5354eSLuigi Rizzo my_inm.inm_ifp = NULL ; /* don't send the leave msg */ 839477180fbSGarrett Wollman if (ifma->ifma_refcount == 1) { 840df8bae1dSRodney W. Grimes /* 841df8bae1dSRodney W. Grimes * No remaining claims to this record; let IGMP know that 842df8bae1dSRodney W. Grimes * we are leaving the multicast group. 84388a5354eSLuigi Rizzo * But do it after the if_delmulti() which might reset 84488a5354eSLuigi Rizzo * the interface and nuke the packet. 845df8bae1dSRodney W. Grimes */ 84688a5354eSLuigi Rizzo my_inm = *inm ; 847477180fbSGarrett Wollman ifma->ifma_protospec = 0; 848477180fbSGarrett Wollman LIST_REMOVE(inm, inm_link); 849df8bae1dSRodney W. Grimes free(inm, M_IPMADDR); 850df8bae1dSRodney W. Grimes } 851477180fbSGarrett Wollman /* XXX - should be separate API for when we have an ifma? */ 852477180fbSGarrett Wollman if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); 85388a5354eSLuigi Rizzo if (my_inm.inm_ifp != NULL) 85488a5354eSLuigi Rizzo igmp_leavegroup(&my_inm); 855df8bae1dSRodney W. Grimes splx(s); 856df8bae1dSRodney W. Grimes } 857