1c398230bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1991, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 681d96ce8SMax Laier * Copyright (C) 2001 WIDE Project. All rights reserved. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 10df8bae1dSRodney W. Grimes * are met: 11df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 17df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 18df8bae1dSRodney W. Grimes * without specific prior written permission. 19df8bae1dSRodney W. Grimes * 20df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30df8bae1dSRodney W. Grimes * SUCH DAMAGE. 31df8bae1dSRodney W. Grimes * 322180b925SGarrett Wollman * @(#)in.c 8.4 (Berkeley) 1/9/95 33df8bae1dSRodney W. Grimes */ 34df8bae1dSRodney W. Grimes 354b421e2dSMike Silbersack #include <sys/cdefs.h> 364b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 374b421e2dSMike Silbersack 38eb8dcdeaSGleb Smirnoff #include "opt_inet.h" 39eb8dcdeaSGleb Smirnoff 402f35e7d9SMike Karels #define IN_HISTORICAL_NETS /* include class masks */ 412f35e7d9SMike Karels 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43c3322cb9SGleb Smirnoff #include <sys/eventhandler.h> 4426f9a767SRodney W. Grimes #include <sys/systm.h> 4551a53488SBruce Evans #include <sys/sockio.h> 46df8bae1dSRodney W. Grimes #include <sys/malloc.h> 47acd3428bSRobert Watson #include <sys/priv.h> 48df8bae1dSRodney W. Grimes #include <sys/socket.h> 495ce0eb7fSBjoern A. Zeeb #include <sys/jail.h> 50f6d24a78SPoul-Henning Kamp #include <sys/kernel.h> 51cc0a3c8cSAndrey V. Elsukov #include <sys/lock.h> 525ce0eb7fSBjoern A. Zeeb #include <sys/proc.h> 53f6d24a78SPoul-Henning Kamp #include <sys/sysctl.h> 54ebc90701SQing Li #include <sys/syslog.h> 55f7a39160SGleb Smirnoff #include <sys/sx.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes #include <net/if.h> 58df813b7eSQing Li #include <net/if_var.h> 59e162ea60SGeorge V. Neville-Neil #include <net/if_arp.h> 60ebc90701SQing Li #include <net/if_dl.h> 616e6b3f7cSQing Li #include <net/if_llatbl.h> 626a800098SYoshinobu Inoue #include <net/if_types.h> 63df8bae1dSRodney W. Grimes #include <net/route.h> 6481728a53SAlexander V. Chernikov #include <net/route/nhop.h> 6581728a53SAlexander V. Chernikov #include <net/route/route_ctl.h> 66ebc90701SQing Li #include <net/vnet.h> 67df8bae1dSRodney W. Grimes 6808b68b0eSGleb Smirnoff #include <netinet/if_ether.h> 69df8bae1dSRodney W. Grimes #include <netinet/in.h> 70936f4a42SAlexander V. Chernikov #include <netinet/in_fib.h> 71df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 72e43cc4aeSHajimu UMEMOTO #include <netinet/in_pcb.h> 7371498f30SBruce M Simpson #include <netinet/ip_var.h> 7408b68b0eSGleb Smirnoff #include <netinet/ip_carp.h> 75d10910e6SBruce M Simpson #include <netinet/igmp_var.h> 76eddfbb76SRobert Watson #include <netinet/udp.h> 77eddfbb76SRobert Watson #include <netinet/udp_var.h> 7855166637SPoul-Henning Kamp 79f375bf0eSAlexander V. Chernikov static int in_aifaddr_ioctl(u_long, caddr_t, struct ifnet *, struct ucred *); 80f375bf0eSAlexander V. Chernikov static int in_difaddr_ioctl(u_long, caddr_t, struct ifnet *, struct ucred *); 81f375bf0eSAlexander V. Chernikov static int in_gifaddr_ioctl(u_long, caddr_t, struct ifnet *, struct ucred *); 826a800098SYoshinobu Inoue 834d77a549SAlfred Perlstein static void in_socktrim(struct sockaddr_in *); 84ec002feeSBruce M Simpson static void in_purgemaddrs(struct ifnet *); 85df8bae1dSRodney W. Grimes 86130aebbaSAlexander V. Chernikov static bool ia_need_loopback_route(const struct in_ifaddr *); 87130aebbaSAlexander V. Chernikov 885f901c92SAndrew Turner VNET_DEFINE_STATIC(int, nosameprefix); 8908b68b0eSGleb Smirnoff #define V_nosameprefix VNET(nosameprefix) 906df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, OID_AUTO, no_same_prefix, CTLFLAG_VNET | CTLFLAG_RW, 9108b68b0eSGleb Smirnoff &VNET_NAME(nosameprefix), 0, 921ae95409SGleb Smirnoff "Refuse to create same prefixes on different interfaces"); 93477180fbSGarrett Wollman 94fd076593SMike Karels VNET_DEFINE_STATIC(bool, broadcast_lowest); 95fd076593SMike Karels #define V_broadcast_lowest VNET(broadcast_lowest) 96fd076593SMike Karels SYSCTL_BOOL(_net_inet_ip, OID_AUTO, broadcast_lowest, CTLFLAG_VNET | CTLFLAG_RW, 97fd076593SMike Karels &VNET_NAME(broadcast_lowest), 0, 98fd076593SMike Karels "Treat lowest address on a subnet (host 0) as broadcast"); 99fd076593SMike Karels 100efe58855SMike Karels VNET_DEFINE(bool, ip_allow_net240) = false; 101efe58855SMike Karels #define V_ip_allow_net240 VNET(ip_allow_net240) 102efe58855SMike Karels SYSCTL_BOOL(_net_inet_ip, OID_AUTO, allow_net240, 103efe58855SMike Karels CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip_allow_net240), 0, 104efe58855SMike Karels "Allow use of Experimental addresses, aka Class E (240/4)"); 105efe58855SMike Karels /* see https://datatracker.ietf.org/doc/draft-schoen-intarea-unicast-240 */ 106efe58855SMike Karels 107efe58855SMike Karels VNET_DEFINE(bool, ip_allow_net0) = false; 108efe58855SMike Karels SYSCTL_BOOL(_net_inet_ip, OID_AUTO, allow_net0, 109efe58855SMike Karels CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip_allow_net0), 0, 110efe58855SMike Karels "Allow use of addresses in network 0/8"); 111efe58855SMike Karels /* see https://datatracker.ietf.org/doc/draft-schoen-intarea-unicast-0 */ 112efe58855SMike Karels 113efe58855SMike Karels VNET_DEFINE(uint32_t, in_loopback_mask) = IN_LOOPBACK_MASK_DFLT; 114efe58855SMike Karels #define V_in_loopback_mask VNET(in_loopback_mask) 115efe58855SMike Karels static int sysctl_loopback_prefixlen(SYSCTL_HANDLER_ARGS); 116efe58855SMike Karels SYSCTL_PROC(_net_inet_ip, OID_AUTO, loopback_prefixlen, 117efe58855SMike Karels CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW, 118efe58855SMike Karels NULL, 0, sysctl_loopback_prefixlen, "I", 119efe58855SMike Karels "Prefix length of address space reserved for loopback"); 120efe58855SMike Karels /* see https://datatracker.ietf.org/doc/draft-schoen-intarea-unicast-127 */ 121efe58855SMike Karels 12282cea7e6SBjoern A. Zeeb VNET_DECLARE(struct inpcbinfo, ripcbinfo); 12382cea7e6SBjoern A. Zeeb #define V_ripcbinfo VNET(ripcbinfo) 12482cea7e6SBjoern A. Zeeb 125f7a39160SGleb Smirnoff static struct sx in_control_sx; 126f7a39160SGleb Smirnoff SX_SYSINIT(in_control_sx, &in_control_sx, "in_control"); 127f7a39160SGleb Smirnoff 128df8bae1dSRodney W. Grimes /* 129df8bae1dSRodney W. Grimes * Return 1 if an internet address is for a ``local'' host 130b365d954SGleb Smirnoff * (one to which we have a connection). 131df8bae1dSRodney W. Grimes */ 13226f9a767SRodney W. Grimes int 133f2565d68SRobert Watson in_localaddr(struct in_addr in) 134df8bae1dSRodney W. Grimes { 1353e85b721SEd Maste u_long i = ntohl(in.s_addr); 1363e85b721SEd Maste struct in_ifaddr *ia; 137df8bae1dSRodney W. Grimes 1382144431cSGleb Smirnoff NET_EPOCH_ASSERT(); 1392144431cSGleb Smirnoff 140d7c5a620SMatt Macy CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 1412144431cSGleb Smirnoff if ((i & ia->ia_subnetmask) == ia->ia_subnet) 1422d9cfabaSRobert Watson return (1); 1432d9cfabaSRobert Watson } 1442144431cSGleb Smirnoff 145df8bae1dSRodney W. Grimes return (0); 146df8bae1dSRodney W. Grimes } 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 1492eccc90bSAndre Oppermann * Return 1 if an internet address is for the local host and configured 1502eccc90bSAndre Oppermann * on one of its interfaces. 1512eccc90bSAndre Oppermann */ 152c8ee75f2SGleb Smirnoff bool 153f2565d68SRobert Watson in_localip(struct in_addr in) 1542eccc90bSAndre Oppermann { 1552eccc90bSAndre Oppermann struct in_ifaddr *ia; 1562eccc90bSAndre Oppermann 157c8ee75f2SGleb Smirnoff NET_EPOCH_ASSERT(); 158c8ee75f2SGleb Smirnoff 159c8ee75f2SGleb Smirnoff CK_LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) 160c8ee75f2SGleb Smirnoff if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr) 161c8ee75f2SGleb Smirnoff return (true); 162c8ee75f2SGleb Smirnoff 163c8ee75f2SGleb Smirnoff return (false); 1642eccc90bSAndre Oppermann } 1652eccc90bSAndre Oppermann 1662eccc90bSAndre Oppermann /* 1679c89392fSGleb Smirnoff * Like in_localip(), but FIB-aware. 1689c89392fSGleb Smirnoff */ 1699c89392fSGleb Smirnoff bool 1709c89392fSGleb Smirnoff in_localip_fib(struct in_addr in, uint16_t fib) 1719c89392fSGleb Smirnoff { 1729c89392fSGleb Smirnoff struct in_ifaddr *ia; 1739c89392fSGleb Smirnoff 1749c89392fSGleb Smirnoff NET_EPOCH_ASSERT(); 1759c89392fSGleb Smirnoff 1769c89392fSGleb Smirnoff CK_LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) 1779c89392fSGleb Smirnoff if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr && 1789c89392fSGleb Smirnoff ia->ia_ifa.ifa_ifp->if_fib == fib) 1799c89392fSGleb Smirnoff return (true); 1809c89392fSGleb Smirnoff 1819c89392fSGleb Smirnoff return (false); 1829c89392fSGleb Smirnoff } 1839c89392fSGleb Smirnoff 1849c89392fSGleb Smirnoff /* 18528ebe80cSGleb Smirnoff * Return 1 if an internet address is configured on an interface. 18628ebe80cSGleb Smirnoff */ 18728ebe80cSGleb Smirnoff int 18828ebe80cSGleb Smirnoff in_ifhasaddr(struct ifnet *ifp, struct in_addr in) 18928ebe80cSGleb Smirnoff { 19028ebe80cSGleb Smirnoff struct ifaddr *ifa; 19128ebe80cSGleb Smirnoff struct in_ifaddr *ia; 19228ebe80cSGleb Smirnoff 193b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 194b8a6e03fSGleb Smirnoff 195d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 19628ebe80cSGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_INET) 19728ebe80cSGleb Smirnoff continue; 19828ebe80cSGleb Smirnoff ia = (struct in_ifaddr *)ifa; 199b8a6e03fSGleb Smirnoff if (ia->ia_addr.sin_addr.s_addr == in.s_addr) 20028ebe80cSGleb Smirnoff return (1); 20128ebe80cSGleb Smirnoff } 20228ebe80cSGleb Smirnoff 20328ebe80cSGleb Smirnoff return (0); 20428ebe80cSGleb Smirnoff } 20528ebe80cSGleb Smirnoff 20628ebe80cSGleb Smirnoff /* 207f7a39160SGleb Smirnoff * Return a reference to the interface address which is different to 208f7a39160SGleb Smirnoff * the supplied one but with same IP address value. 209f7a39160SGleb Smirnoff */ 210f7a39160SGleb Smirnoff static struct in_ifaddr * 2119fdbf7eeSAlexander V. Chernikov in_localip_more(struct in_ifaddr *original_ia) 212f7a39160SGleb Smirnoff { 213c8ee75f2SGleb Smirnoff struct epoch_tracker et; 2149fdbf7eeSAlexander V. Chernikov in_addr_t original_addr = IA_SIN(original_ia)->sin_addr.s_addr; 2159fdbf7eeSAlexander V. Chernikov uint32_t original_fib = original_ia->ia_ifa.ifa_ifp->if_fib; 2169fdbf7eeSAlexander V. Chernikov struct in_ifaddr *ia; 217f7a39160SGleb Smirnoff 218c8ee75f2SGleb Smirnoff NET_EPOCH_ENTER(et); 219c8ee75f2SGleb Smirnoff CK_LIST_FOREACH(ia, INADDR_HASH(original_addr), ia_hash) { 2209fdbf7eeSAlexander V. Chernikov in_addr_t addr = IA_SIN(ia)->sin_addr.s_addr; 2219fdbf7eeSAlexander V. Chernikov uint32_t fib = ia->ia_ifa.ifa_ifp->if_fib; 2229fdbf7eeSAlexander V. Chernikov if (!V_rt_add_addr_allfibs && (original_fib != fib)) 2239fdbf7eeSAlexander V. Chernikov continue; 2249fdbf7eeSAlexander V. Chernikov if ((original_ia != ia) && (original_addr == addr)) { 2259fdbf7eeSAlexander V. Chernikov ifa_ref(&ia->ia_ifa); 226c8ee75f2SGleb Smirnoff NET_EPOCH_EXIT(et); 2279fdbf7eeSAlexander V. Chernikov return (ia); 228f7a39160SGleb Smirnoff } 229f7a39160SGleb Smirnoff } 230c8ee75f2SGleb Smirnoff NET_EPOCH_EXIT(et); 231f7a39160SGleb Smirnoff 232f7a39160SGleb Smirnoff return (NULL); 233f7a39160SGleb Smirnoff } 234f7a39160SGleb Smirnoff 235f7a39160SGleb Smirnoff /* 2364b631fc8SAlexander V. Chernikov * Tries to find first IPv4 address in the provided fib. 2374b631fc8SAlexander V. Chernikov * Prefers non-loopback addresses and return loopback IFF 2384b631fc8SAlexander V. Chernikov * @loopback_ok is set. 2394b631fc8SAlexander V. Chernikov * 2404b631fc8SAlexander V. Chernikov * Returns ifa or NULL. 2414b631fc8SAlexander V. Chernikov */ 2424b631fc8SAlexander V. Chernikov struct in_ifaddr * 2434b631fc8SAlexander V. Chernikov in_findlocal(uint32_t fibnum, bool loopback_ok) 2444b631fc8SAlexander V. Chernikov { 2454b631fc8SAlexander V. Chernikov struct in_ifaddr *ia = NULL, *ia_lo = NULL; 2464b631fc8SAlexander V. Chernikov 2474b631fc8SAlexander V. Chernikov NET_EPOCH_ASSERT(); 2484b631fc8SAlexander V. Chernikov 2494b631fc8SAlexander V. Chernikov CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 2504b631fc8SAlexander V. Chernikov uint32_t ia_fib = ia->ia_ifa.ifa_ifp->if_fib; 2514b631fc8SAlexander V. Chernikov if (!V_rt_add_addr_allfibs && (fibnum != ia_fib)) 2524b631fc8SAlexander V. Chernikov continue; 2534b631fc8SAlexander V. Chernikov 2544b631fc8SAlexander V. Chernikov if (!IN_LOOPBACK(ntohl(IA_SIN(ia)->sin_addr.s_addr))) 2554b631fc8SAlexander V. Chernikov break; 2564b631fc8SAlexander V. Chernikov if (loopback_ok) 2574b631fc8SAlexander V. Chernikov ia_lo = ia; 2584b631fc8SAlexander V. Chernikov } 2594b631fc8SAlexander V. Chernikov 2604b631fc8SAlexander V. Chernikov if (ia == NULL) 2614b631fc8SAlexander V. Chernikov ia = ia_lo; 2624b631fc8SAlexander V. Chernikov 2634b631fc8SAlexander V. Chernikov return (ia); 2644b631fc8SAlexander V. Chernikov } 2654b631fc8SAlexander V. Chernikov 2664b631fc8SAlexander V. Chernikov /* 267df8bae1dSRodney W. Grimes * Determine whether an IP address is in a reserved set of addresses 268df8bae1dSRodney W. Grimes * that may not be forwarded, or whether datagrams to that destination 269df8bae1dSRodney W. Grimes * may be forwarded. 270df8bae1dSRodney W. Grimes */ 27126f9a767SRodney W. Grimes int 272f2565d68SRobert Watson in_canforward(struct in_addr in) 273df8bae1dSRodney W. Grimes { 2743e85b721SEd Maste u_long i = ntohl(in.s_addr); 275df8bae1dSRodney W. Grimes 276efe58855SMike Karels if (IN_MULTICAST(i) || IN_LINKLOCAL(i) || IN_LOOPBACK(i)) 277efe58855SMike Karels return (0); 278efe58855SMike Karels if (IN_EXPERIMENTAL(i) && !V_ip_allow_net240) 279efe58855SMike Karels return (0); 280efe58855SMike Karels if (IN_ZERONET(i) && !V_ip_allow_net0) 281df8bae1dSRodney W. Grimes return (0); 282df8bae1dSRodney W. Grimes return (1); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes 285df8bae1dSRodney W. Grimes /* 286efe58855SMike Karels * Sysctl to manage prefix of reserved loopback network; translate 287efe58855SMike Karels * to/from mask. The mask is always contiguous high-order 1 bits 288efe58855SMike Karels * followed by all 0 bits. 289efe58855SMike Karels */ 290efe58855SMike Karels static int 291efe58855SMike Karels sysctl_loopback_prefixlen(SYSCTL_HANDLER_ARGS) 292efe58855SMike Karels { 293efe58855SMike Karels int error, preflen; 294efe58855SMike Karels 295efe58855SMike Karels /* ffs is 1-based; compensate. */ 296efe58855SMike Karels preflen = 33 - ffs(V_in_loopback_mask); 297efe58855SMike Karels error = sysctl_handle_int(oidp, &preflen, 0, req); 298efe58855SMike Karels if (error || !req->newptr) 299efe58855SMike Karels return (error); 300fb8ef16bSMike Karels if (preflen < 8 || preflen > 31) 301efe58855SMike Karels return (EINVAL); 302efe58855SMike Karels V_in_loopback_mask = 0xffffffff << (32 - preflen); 303efe58855SMike Karels return (0); 304efe58855SMike Karels } 305efe58855SMike Karels 306efe58855SMike Karels /* 307df8bae1dSRodney W. Grimes * Trim a mask in a sockaddr 308df8bae1dSRodney W. Grimes */ 3090312fbe9SPoul-Henning Kamp static void 310f2565d68SRobert Watson in_socktrim(struct sockaddr_in *ap) 311df8bae1dSRodney W. Grimes { 3123e85b721SEd Maste char *cplim = (char *) &ap->sin_addr; 3133e85b721SEd Maste char *cp = (char *) (&ap->sin_addr + 1); 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes ap->sin_len = 0; 316df00058dSGarrett Wollman while (--cp >= cplim) 317df8bae1dSRodney W. Grimes if (*cp) { 318df8bae1dSRodney W. Grimes (ap)->sin_len = cp - (char *) (ap) + 1; 319df8bae1dSRodney W. Grimes break; 320df8bae1dSRodney W. Grimes } 321df8bae1dSRodney W. Grimes } 322df8bae1dSRodney W. Grimes 323df8bae1dSRodney W. Grimes /* 324df8bae1dSRodney W. Grimes * Generic internet control operations (ioctl's). 325df8bae1dSRodney W. Grimes */ 32626f9a767SRodney W. Grimes int 327f277746eSGleb Smirnoff in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp, 328f2565d68SRobert Watson struct thread *td) 329df8bae1dSRodney W. Grimes { 330f7a39160SGleb Smirnoff struct ifreq *ifr = (struct ifreq *)data; 331f7a39160SGleb Smirnoff struct sockaddr_in *addr = (struct sockaddr_in *)&ifr->ifr_addr; 332a68cc388SGleb Smirnoff struct epoch_tracker et; 333821b5cafSGleb Smirnoff struct ifaddr *ifa; 334f7a39160SGleb Smirnoff struct in_ifaddr *ia; 335f7a39160SGleb Smirnoff int error; 336f7a39160SGleb Smirnoff 337f7a39160SGleb Smirnoff if (ifp == NULL) 338f7a39160SGleb Smirnoff return (EADDRNOTAVAIL); 33971212473SGleb Smirnoff 340f375bf0eSAlexander V. Chernikov struct ucred *cred = (td != NULL) ? td->td_ucred : NULL; 341f375bf0eSAlexander V. Chernikov 34271212473SGleb Smirnoff /* 343f7a39160SGleb Smirnoff * Filter out 4 ioctls we implement directly. Forward the rest 344f7a39160SGleb Smirnoff * to specific functions and ifp->if_ioctl(). 345bbb3fb61SRobert Watson */ 3466a800098SYoshinobu Inoue switch (cmd) { 347bbb3fb61SRobert Watson case SIOCGIFADDR: 348bbb3fb61SRobert Watson case SIOCGIFBRDADDR: 349bbb3fb61SRobert Watson case SIOCGIFDSTADDR: 350bbb3fb61SRobert Watson case SIOCGIFNETMASK: 351f7a39160SGleb Smirnoff break; 3526952c3e1SAndrey V. Elsukov case SIOCGIFALIAS: 3536952c3e1SAndrey V. Elsukov sx_xlock(&in_control_sx); 354f375bf0eSAlexander V. Chernikov error = in_gifaddr_ioctl(cmd, data, ifp, cred); 3556952c3e1SAndrey V. Elsukov sx_xunlock(&in_control_sx); 3566952c3e1SAndrey V. Elsukov return (error); 3576d00fd9cSGleb Smirnoff case SIOCDIFADDR: 358f7a39160SGleb Smirnoff sx_xlock(&in_control_sx); 359f375bf0eSAlexander V. Chernikov error = in_difaddr_ioctl(cmd, data, ifp, cred); 360f7a39160SGleb Smirnoff sx_xunlock(&in_control_sx); 361f7a39160SGleb Smirnoff return (error); 36277b89ad8SGleb Smirnoff case OSIOCAIFADDR: /* 9.x compat */ 3636d00fd9cSGleb Smirnoff case SIOCAIFADDR: 364f7a39160SGleb Smirnoff sx_xlock(&in_control_sx); 365f375bf0eSAlexander V. Chernikov error = in_aifaddr_ioctl(cmd, data, ifp, cred); 366f7a39160SGleb Smirnoff sx_xunlock(&in_control_sx); 367f7a39160SGleb Smirnoff return (error); 368bbb3fb61SRobert Watson case SIOCSIFADDR: 369bbb3fb61SRobert Watson case SIOCSIFBRDADDR: 370bbb3fb61SRobert Watson case SIOCSIFDSTADDR: 371bbb3fb61SRobert Watson case SIOCSIFNETMASK: 37256cf9dc1SGleb Smirnoff /* We no longer support that old commands. */ 3736d00fd9cSGleb Smirnoff return (EINVAL); 374bbb3fb61SRobert Watson default: 375f7a39160SGleb Smirnoff if (ifp->if_ioctl == NULL) 376bbb3fb61SRobert Watson return (EOPNOTSUPP); 377bbb3fb61SRobert Watson return ((*ifp->if_ioctl)(ifp, cmd, data)); 3786a800098SYoshinobu Inoue } 3796a800098SYoshinobu Inoue 380821b5cafSGleb Smirnoff if (addr->sin_addr.s_addr != INADDR_ANY && 381f375bf0eSAlexander V. Chernikov prison_check_ip4(cred, &addr->sin_addr) != 0) 382821b5cafSGleb Smirnoff return (EADDRNOTAVAIL); 383821b5cafSGleb Smirnoff 384cf7b18f1SRobert Watson /* 385a7f77a39SXin LI * Find address for this interface, if it exists. If an 386a7f77a39SXin LI * address was specified, find that one instead of the 387a7f77a39SXin LI * first one on the interface, if possible. 388df8bae1dSRodney W. Grimes */ 389a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 390d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 3919706c950SGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_INET) 3929706c950SGleb Smirnoff continue; 393821b5cafSGleb Smirnoff ia = (struct in_ifaddr *)ifa; 394821b5cafSGleb Smirnoff if (ia->ia_addr.sin_addr.s_addr == addr->sin_addr.s_addr) 395df8bae1dSRodney W. Grimes break; 396ca925d9cSJonathan Lemon } 397a7f77a39SXin LI if (ifa == NULL) 398d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 399a7f77a39SXin LI if (ifa->ifa_addr->sa_family == AF_INET) { 400a7f77a39SXin LI ia = (struct in_ifaddr *)ifa; 401f375bf0eSAlexander V. Chernikov if (prison_check_ip4(cred, 402a7f77a39SXin LI &ia->ia_addr.sin_addr) == 0) 403a7f77a39SXin LI break; 404a7f77a39SXin LI } 405f7a39160SGleb Smirnoff 406821b5cafSGleb Smirnoff if (ifa == NULL) { 407a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 408f7a39160SGleb Smirnoff return (EADDRNOTAVAIL); 409ac0aa473SBill Fenner } 410df8bae1dSRodney W. Grimes 411588885f2SRobert Watson error = 0; 412df8bae1dSRodney W. Grimes switch (cmd) { 413f7a39160SGleb Smirnoff case SIOCGIFADDR: 414f7a39160SGleb Smirnoff *addr = ia->ia_addr; 415f7a39160SGleb Smirnoff break; 4168c0fec80SRobert Watson 417f7a39160SGleb Smirnoff case SIOCGIFBRDADDR: 418f7a39160SGleb Smirnoff if ((ifp->if_flags & IFF_BROADCAST) == 0) { 419f7a39160SGleb Smirnoff error = EINVAL; 420df8bae1dSRodney W. Grimes break; 421df8bae1dSRodney W. Grimes } 422f7a39160SGleb Smirnoff *addr = ia->ia_broadaddr; 423f7a39160SGleb Smirnoff break; 424f7a39160SGleb Smirnoff 425f7a39160SGleb Smirnoff case SIOCGIFDSTADDR: 426f7a39160SGleb Smirnoff if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 427f7a39160SGleb Smirnoff error = EINVAL; 428f7a39160SGleb Smirnoff break; 429f7a39160SGleb Smirnoff } 430f7a39160SGleb Smirnoff *addr = ia->ia_dstaddr; 431f7a39160SGleb Smirnoff break; 432f7a39160SGleb Smirnoff 433f7a39160SGleb Smirnoff case SIOCGIFNETMASK: 434f7a39160SGleb Smirnoff *addr = ia->ia_sockmask; 435f7a39160SGleb Smirnoff break; 436f7a39160SGleb Smirnoff } 437f7a39160SGleb Smirnoff 438a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 439f7a39160SGleb Smirnoff 440f7a39160SGleb Smirnoff return (error); 4411067217dSGarrett Wollman } 442f7a39160SGleb Smirnoff 443f7a39160SGleb Smirnoff static int 444f375bf0eSAlexander V. Chernikov in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct ucred *cred) 445f7a39160SGleb Smirnoff { 446f7a39160SGleb Smirnoff const struct in_aliasreq *ifra = (struct in_aliasreq *)data; 447f7a39160SGleb Smirnoff const struct sockaddr_in *addr = &ifra->ifra_addr; 448f7a39160SGleb Smirnoff const struct sockaddr_in *broadaddr = &ifra->ifra_broadaddr; 449f7a39160SGleb Smirnoff const struct sockaddr_in *mask = &ifra->ifra_mask; 450f7a39160SGleb Smirnoff const struct sockaddr_in *dstaddr = &ifra->ifra_dstaddr; 45177b89ad8SGleb Smirnoff const int vhid = (cmd == SIOCAIFADDR) ? ifra->ifra_vhid : 0; 452a68cc388SGleb Smirnoff struct epoch_tracker et; 453f7a39160SGleb Smirnoff struct ifaddr *ifa; 454f7a39160SGleb Smirnoff struct in_ifaddr *ia; 455f7a39160SGleb Smirnoff bool iaIsFirst; 456f7a39160SGleb Smirnoff int error = 0; 457f7a39160SGleb Smirnoff 458f375bf0eSAlexander V. Chernikov error = priv_check_cred(cred, PRIV_NET_ADDIFADDR); 459f7a39160SGleb Smirnoff if (error) 460f7a39160SGleb Smirnoff return (error); 461f7a39160SGleb Smirnoff 462f7a39160SGleb Smirnoff /* 463f7a39160SGleb Smirnoff * ifra_addr must be present and be of INET family. 464f7a39160SGleb Smirnoff * ifra_broadaddr/ifra_dstaddr and ifra_mask are optional. 465f7a39160SGleb Smirnoff */ 466f7a39160SGleb Smirnoff if (addr->sin_len != sizeof(struct sockaddr_in) || 467f7a39160SGleb Smirnoff addr->sin_family != AF_INET) 468f7a39160SGleb Smirnoff return (EINVAL); 469f7a39160SGleb Smirnoff if (broadaddr->sin_len != 0 && 470f7a39160SGleb Smirnoff (broadaddr->sin_len != sizeof(struct sockaddr_in) || 471f7a39160SGleb Smirnoff broadaddr->sin_family != AF_INET)) 472f7a39160SGleb Smirnoff return (EINVAL); 473f7a39160SGleb Smirnoff if (mask->sin_len != 0 && 474f7a39160SGleb Smirnoff (mask->sin_len != sizeof(struct sockaddr_in) || 475f7a39160SGleb Smirnoff mask->sin_family != AF_INET)) 476f7a39160SGleb Smirnoff return (EINVAL); 477f7a39160SGleb Smirnoff if ((ifp->if_flags & IFF_POINTOPOINT) && 478f7a39160SGleb Smirnoff (dstaddr->sin_len != sizeof(struct sockaddr_in) || 479f7a39160SGleb Smirnoff dstaddr->sin_addr.s_addr == INADDR_ANY)) 480f7a39160SGleb Smirnoff return (EDESTADDRREQ); 481620cf65cSArtem Khramov if (vhid != 0 && carp_attach_p == NULL) 482f7a39160SGleb Smirnoff return (EPROTONOSUPPORT); 483f7a39160SGleb Smirnoff 484f7a39160SGleb Smirnoff /* 485f7a39160SGleb Smirnoff * See whether address already exist. 486f7a39160SGleb Smirnoff */ 487f7a39160SGleb Smirnoff iaIsFirst = true; 488f7a39160SGleb Smirnoff ia = NULL; 489a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 490d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 4919706c950SGleb Smirnoff struct in_ifaddr *it; 492f7a39160SGleb Smirnoff 4939706c950SGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_INET) 494f7a39160SGleb Smirnoff continue; 495f7a39160SGleb Smirnoff 4969706c950SGleb Smirnoff it = (struct in_ifaddr *)ifa; 497f7a39160SGleb Smirnoff if (it->ia_addr.sin_addr.s_addr == addr->sin_addr.s_addr && 498f375bf0eSAlexander V. Chernikov prison_check_ip4(cred, &addr->sin_addr) == 0) 499f7a39160SGleb Smirnoff ia = it; 5003f740d43SAndrey V. Elsukov else 5013f740d43SAndrey V. Elsukov iaIsFirst = false; 5021067217dSGarrett Wollman } 503a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 504f7a39160SGleb Smirnoff 505f7a39160SGleb Smirnoff if (ia != NULL) 506f375bf0eSAlexander V. Chernikov (void )in_difaddr_ioctl(cmd, data, ifp, cred); 507f7a39160SGleb Smirnoff 50846758960SGleb Smirnoff ifa = ifa_alloc(sizeof(struct in_ifaddr), M_WAITOK); 50946758960SGleb Smirnoff ia = (struct in_ifaddr *)ifa; 51059562606SGarrett Wollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 51159562606SGarrett Wollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 51259562606SGarrett Wollman ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 5132d9db0bcSEric van Gyzen callout_init_rw(&ia->ia_garp_timer, &ifp->if_addr_lock, 5142d9db0bcSEric van Gyzen CALLOUT_RETURNUNLOCKED); 51519fc74fbSJeffrey Hsu 516f7a39160SGleb Smirnoff ia->ia_ifp = ifp; 517f7a39160SGleb Smirnoff ia->ia_addr = *addr; 518f7a39160SGleb Smirnoff if (mask->sin_len != 0) { 519f7a39160SGleb Smirnoff ia->ia_sockmask = *mask; 520f7a39160SGleb Smirnoff ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr); 521f7a39160SGleb Smirnoff } else { 5222f35e7d9SMike Karels in_addr_t i = ntohl(addr->sin_addr.s_addr); 5232f35e7d9SMike Karels 524f7a39160SGleb Smirnoff /* 5252f35e7d9SMike Karels * If netmask isn't supplied, use historical default. 52620d59403SMike Karels * This is deprecated for interfaces other than loopback 52720d59403SMike Karels * or point-to-point; warn in other cases. In the future 52820d59403SMike Karels * we should return an error rather than warning. 529f7a39160SGleb Smirnoff */ 53020d59403SMike Karels if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) 53120d59403SMike Karels printf("%s: set address: WARNING: network mask " 5322f35e7d9SMike Karels "should be specified; using historical default\n", 53320d59403SMike Karels ifp->if_xname); 5342f35e7d9SMike Karels if (IN_CLASSA(i)) 5352f35e7d9SMike Karels ia->ia_subnetmask = IN_CLASSA_NET; 5362f35e7d9SMike Karels else if (IN_CLASSB(i)) 5372f35e7d9SMike Karels ia->ia_subnetmask = IN_CLASSB_NET; 5382f35e7d9SMike Karels else 5392f35e7d9SMike Karels ia->ia_subnetmask = IN_CLASSC_NET; 540f7a39160SGleb Smirnoff ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 541f7a39160SGleb Smirnoff } 542f7a39160SGleb Smirnoff ia->ia_subnet = ntohl(addr->sin_addr.s_addr) & ia->ia_subnetmask; 543f7a39160SGleb Smirnoff in_socktrim(&ia->ia_sockmask); 544f7a39160SGleb Smirnoff 545df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_BROADCAST) { 546f7a39160SGleb Smirnoff if (broadaddr->sin_len != 0) { 547f7a39160SGleb Smirnoff ia->ia_broadaddr = *broadaddr; 548f7a39160SGleb Smirnoff } else if (ia->ia_subnetmask == IN_RFC3021_MASK) { 549f7a39160SGleb Smirnoff ia->ia_broadaddr.sin_addr.s_addr = INADDR_BROADCAST; 550f7a39160SGleb Smirnoff ia->ia_broadaddr.sin_len = sizeof(struct sockaddr_in); 551f7a39160SGleb Smirnoff ia->ia_broadaddr.sin_family = AF_INET; 552f7a39160SGleb Smirnoff } else { 553f7a39160SGleb Smirnoff ia->ia_broadaddr.sin_addr.s_addr = 554f7a39160SGleb Smirnoff htonl(ia->ia_subnet | ~ia->ia_subnetmask); 555f7a39160SGleb Smirnoff ia->ia_broadaddr.sin_len = sizeof(struct sockaddr_in); 556df8bae1dSRodney W. Grimes ia->ia_broadaddr.sin_family = AF_INET; 557df8bae1dSRodney W. Grimes } 558f7a39160SGleb Smirnoff } 559f7a39160SGleb Smirnoff 560f7a39160SGleb Smirnoff if (ifp->if_flags & IFF_POINTOPOINT) 561f7a39160SGleb Smirnoff ia->ia_dstaddr = *dstaddr; 562f7a39160SGleb Smirnoff 5635af464bbSSteven Hartland if (vhid != 0) { 5645af464bbSSteven Hartland error = (*carp_attach_p)(&ia->ia_ifa, vhid); 5655af464bbSSteven Hartland if (error) 5665af464bbSSteven Hartland return (error); 5675af464bbSSteven Hartland } 5685af464bbSSteven Hartland 569a49b317cSAlexander V. Chernikov /* if_addrhead is already referenced by ifa_alloc() */ 570137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 571d7c5a620SMatt Macy CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 572137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 573f7a39160SGleb Smirnoff 5748c0fec80SRobert Watson ifa_ref(ifa); /* in_ifaddrhead */ 575c8ee75f2SGleb Smirnoff sx_assert(&in_control_sx, SA_XLOCKED); 576d7c5a620SMatt Macy CK_STAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); 577c8ee75f2SGleb Smirnoff CK_LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, 578c8ee75f2SGleb Smirnoff ia_hash); 579df8bae1dSRodney W. Grimes 580f7a39160SGleb Smirnoff /* 581f7a39160SGleb Smirnoff * Give the interface a chance to initialize 582f7a39160SGleb Smirnoff * if this is its first address, 583f7a39160SGleb Smirnoff * and to validate the address if necessary. 584f7a39160SGleb Smirnoff */ 585d34165f7SSteven Hartland if (ifp->if_ioctl != NULL) { 586f7a39160SGleb Smirnoff error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 587f7a39160SGleb Smirnoff if (error) 5885af464bbSSteven Hartland goto fail1; 589d34165f7SSteven Hartland } 590f7a39160SGleb Smirnoff 591f7a39160SGleb Smirnoff /* 592f7a39160SGleb Smirnoff * Add route for the network. 593f7a39160SGleb Smirnoff */ 594f7a39160SGleb Smirnoff if (vhid == 0) { 595130aebbaSAlexander V. Chernikov error = in_addprefix(ia); 596f7a39160SGleb Smirnoff if (error) 5975af464bbSSteven Hartland goto fail1; 598df8bae1dSRodney W. Grimes } 599df8bae1dSRodney W. Grimes 600588885f2SRobert Watson /* 601f7a39160SGleb Smirnoff * Add a loopback route to self. 602588885f2SRobert Watson */ 603130aebbaSAlexander V. Chernikov if (vhid == 0 && ia_need_loopback_route(ia)) { 604f7a39160SGleb Smirnoff struct in_ifaddr *eia; 605df8bae1dSRodney W. Grimes 606f7a39160SGleb Smirnoff eia = in_localip_more(ia); 607f7a39160SGleb Smirnoff 608f7a39160SGleb Smirnoff if (eia == NULL) { 609f7a39160SGleb Smirnoff error = ifa_add_loopback_route((struct ifaddr *)ia, 610f7a39160SGleb Smirnoff (struct sockaddr *)&ia->ia_addr); 611f7a39160SGleb Smirnoff if (error) 6125af464bbSSteven Hartland goto fail2; 613f7a39160SGleb Smirnoff } else 614f7a39160SGleb Smirnoff ifa_free(&eia->ia_ifa); 615588885f2SRobert Watson } 616df8bae1dSRodney W. Grimes 617f7a39160SGleb Smirnoff if (iaIsFirst && (ifp->if_flags & IFF_MULTICAST)) { 618f7a39160SGleb Smirnoff struct in_addr allhosts_addr; 619f7a39160SGleb Smirnoff struct in_ifinfo *ii; 620df8bae1dSRodney W. Grimes 621c75aa354SBruce M Simpson ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]); 622f7a39160SGleb Smirnoff allhosts_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 623df8bae1dSRodney W. Grimes 624f7a39160SGleb Smirnoff error = in_joingroup(ifp, &allhosts_addr, NULL, 625f7a39160SGleb Smirnoff &ii->ii_allhosts); 626f7a39160SGleb Smirnoff } 627f7a39160SGleb Smirnoff 62864d63b1eSAndrey V. Elsukov /* 62964d63b1eSAndrey V. Elsukov * Note: we don't need extra reference for ifa, since we called 63064d63b1eSAndrey V. Elsukov * with sx lock held, and ifaddr can not be deleted in concurrent 63164d63b1eSAndrey V. Elsukov * thread. 63264d63b1eSAndrey V. Elsukov */ 63364d63b1eSAndrey V. Elsukov EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, ifa, IFADDR_EVENT_ADD); 634f7a39160SGleb Smirnoff 635f7a39160SGleb Smirnoff return (error); 636f7a39160SGleb Smirnoff 6375af464bbSSteven Hartland fail2: 638f7a39160SGleb Smirnoff if (vhid == 0) 639f7a39160SGleb Smirnoff (void )in_scrubprefix(ia, LLE_STATIC); 640f7a39160SGleb Smirnoff 6415af464bbSSteven Hartland fail1: 642f7a39160SGleb Smirnoff if (ia->ia_ifa.ifa_carp) 643338e227aSLuiz Otavio O Souza (*carp_detach_p)(&ia->ia_ifa, false); 644f7a39160SGleb Smirnoff 645f7a39160SGleb Smirnoff IF_ADDR_WLOCK(ifp); 646d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); 647f7a39160SGleb Smirnoff IF_ADDR_WUNLOCK(ifp); 648a49b317cSAlexander V. Chernikov ifa_free(&ia->ia_ifa); /* if_addrhead */ 649f7a39160SGleb Smirnoff 650c8ee75f2SGleb Smirnoff sx_assert(&in_control_sx, SA_XLOCKED); 651d7c5a620SMatt Macy CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link); 652c8ee75f2SGleb Smirnoff CK_LIST_REMOVE(ia, ia_hash); 653a49b317cSAlexander V. Chernikov ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ 654f7a39160SGleb Smirnoff 655f7a39160SGleb Smirnoff return (error); 656f7a39160SGleb Smirnoff } 657f7a39160SGleb Smirnoff 658f7a39160SGleb Smirnoff static int 659f375bf0eSAlexander V. Chernikov in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct ucred *cred) 660f7a39160SGleb Smirnoff { 661f7a39160SGleb Smirnoff const struct ifreq *ifr = (struct ifreq *)data; 6626224cd89SNathan Whitehorn const struct sockaddr_in *addr = (const struct sockaddr_in *) 6636224cd89SNathan Whitehorn &ifr->ifr_addr; 664f7a39160SGleb Smirnoff struct ifaddr *ifa; 665f7a39160SGleb Smirnoff struct in_ifaddr *ia; 666f7a39160SGleb Smirnoff bool deleteAny, iaIsLast; 667f7a39160SGleb Smirnoff int error; 668f7a39160SGleb Smirnoff 669f375bf0eSAlexander V. Chernikov if (cred != NULL) { 670f375bf0eSAlexander V. Chernikov error = priv_check_cred(cred, PRIV_NET_DELIFADDR); 671f7a39160SGleb Smirnoff if (error) 672f7a39160SGleb Smirnoff return (error); 673f7a39160SGleb Smirnoff } 674f7a39160SGleb Smirnoff 675f7a39160SGleb Smirnoff if (addr->sin_len != sizeof(struct sockaddr_in) || 676f7a39160SGleb Smirnoff addr->sin_family != AF_INET) 677f7a39160SGleb Smirnoff deleteAny = true; 678f7a39160SGleb Smirnoff else 679f7a39160SGleb Smirnoff deleteAny = false; 680f7a39160SGleb Smirnoff 681f7a39160SGleb Smirnoff iaIsLast = true; 682f7a39160SGleb Smirnoff ia = NULL; 683f7a39160SGleb Smirnoff IF_ADDR_WLOCK(ifp); 684d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 6859706c950SGleb Smirnoff struct in_ifaddr *it; 686f7a39160SGleb Smirnoff 6879706c950SGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_INET) 688f7a39160SGleb Smirnoff continue; 689f7a39160SGleb Smirnoff 6909706c950SGleb Smirnoff it = (struct in_ifaddr *)ifa; 691f375bf0eSAlexander V. Chernikov if (deleteAny && ia == NULL && (cred == NULL || 692f375bf0eSAlexander V. Chernikov prison_check_ip4(cred, &it->ia_addr.sin_addr) == 0)) 693f7a39160SGleb Smirnoff ia = it; 694f7a39160SGleb Smirnoff 695f7a39160SGleb Smirnoff if (it->ia_addr.sin_addr.s_addr == addr->sin_addr.s_addr && 696f375bf0eSAlexander V. Chernikov (cred == NULL || prison_check_ip4(cred, 697f7a39160SGleb Smirnoff &addr->sin_addr) == 0)) 698f7a39160SGleb Smirnoff ia = it; 699f7a39160SGleb Smirnoff 700f7a39160SGleb Smirnoff if (it != ia) 701f7a39160SGleb Smirnoff iaIsLast = false; 702f7a39160SGleb Smirnoff } 703f7a39160SGleb Smirnoff 704f7a39160SGleb Smirnoff if (ia == NULL) { 705f7a39160SGleb Smirnoff IF_ADDR_WUNLOCK(ifp); 706f7a39160SGleb Smirnoff return (EADDRNOTAVAIL); 707f7a39160SGleb Smirnoff } 708f7a39160SGleb Smirnoff 709d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); 710f7a39160SGleb Smirnoff IF_ADDR_WUNLOCK(ifp); 711f7a39160SGleb Smirnoff ifa_free(&ia->ia_ifa); /* if_addrhead */ 712f7a39160SGleb Smirnoff 713c8ee75f2SGleb Smirnoff sx_assert(&in_control_sx, SA_XLOCKED); 714d7c5a620SMatt Macy CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link); 715c8ee75f2SGleb Smirnoff CK_LIST_REMOVE(ia, ia_hash); 716f7a39160SGleb Smirnoff 717089cdfadSRuslan Ermilov /* 718237bf7f7SGleb Smirnoff * in_scrubprefix() kills the interface route. 719089cdfadSRuslan Ermilov */ 720237bf7f7SGleb Smirnoff in_scrubprefix(ia, LLE_STATIC); 721588885f2SRobert Watson 722c655b7c4SDavid Greenman /* 723089cdfadSRuslan Ermilov * in_ifadown gets rid of all the rest of 724089cdfadSRuslan Ermilov * the routes. This is not quite the right 725089cdfadSRuslan Ermilov * thing to do, but at least if we are running 726089cdfadSRuslan Ermilov * a routing process they will come back. 727089cdfadSRuslan Ermilov */ 72891854268SRuslan Ermilov in_ifadown(&ia->ia_ifa, 1); 7290f02fdacSBrian Somers 73008b68b0eSGleb Smirnoff if (ia->ia_ifa.ifa_carp) 73159b2022fSLuiz Otavio O Souza (*carp_detach_p)(&ia->ia_ifa, cmd == SIOCAIFADDR); 73208b68b0eSGleb Smirnoff 733f7e083afSBruce M Simpson /* 734f7e083afSBruce M Simpson * If this is the last IPv4 address configured on this 735f7e083afSBruce M Simpson * interface, leave the all-hosts group. 736d10910e6SBruce M Simpson * No state-change report need be transmitted. 737f7e083afSBruce M Simpson */ 738f7a39160SGleb Smirnoff if (iaIsLast && (ifp->if_flags & IFF_MULTICAST)) { 739f7a39160SGleb Smirnoff struct in_ifinfo *ii; 740f7a39160SGleb Smirnoff 741c75aa354SBruce M Simpson ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]); 742d10910e6SBruce M Simpson if (ii->ii_allhosts) { 743f3e1324bSStephen Hurd (void)in_leavegroup(ii->ii_allhosts, NULL); 744d10910e6SBruce M Simpson ii->ii_allhosts = NULL; 745d10910e6SBruce M Simpson } 746f7a39160SGleb Smirnoff } 7476d00fd9cSGleb Smirnoff 7482d9db0bcSEric van Gyzen IF_ADDR_WLOCK(ifp); 7492d9db0bcSEric van Gyzen if (callout_stop(&ia->ia_garp_timer) == 1) { 7502d9db0bcSEric van Gyzen ifa_free(&ia->ia_ifa); 7512d9db0bcSEric van Gyzen } 7522d9db0bcSEric van Gyzen IF_ADDR_WUNLOCK(ifp); 7532d9db0bcSEric van Gyzen 75464d63b1eSAndrey V. Elsukov EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa, 75564d63b1eSAndrey V. Elsukov IFADDR_EVENT_DEL); 756a49b317cSAlexander V. Chernikov ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ 757f7a39160SGleb Smirnoff 758f7a39160SGleb Smirnoff return (0); 759df8bae1dSRodney W. Grimes } 760df8bae1dSRodney W. Grimes 7616952c3e1SAndrey V. Elsukov static int 762f375bf0eSAlexander V. Chernikov in_gifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct ucred *cred) 7636952c3e1SAndrey V. Elsukov { 7646952c3e1SAndrey V. Elsukov struct in_aliasreq *ifra = (struct in_aliasreq *)data; 7656952c3e1SAndrey V. Elsukov const struct sockaddr_in *addr = &ifra->ifra_addr; 7666952c3e1SAndrey V. Elsukov struct epoch_tracker et; 7676952c3e1SAndrey V. Elsukov struct ifaddr *ifa; 7686952c3e1SAndrey V. Elsukov struct in_ifaddr *ia; 7696952c3e1SAndrey V. Elsukov 7706952c3e1SAndrey V. Elsukov /* 7716952c3e1SAndrey V. Elsukov * ifra_addr must be present and be of INET family. 7726952c3e1SAndrey V. Elsukov */ 7736952c3e1SAndrey V. Elsukov if (addr->sin_len != sizeof(struct sockaddr_in) || 7746952c3e1SAndrey V. Elsukov addr->sin_family != AF_INET) 7756952c3e1SAndrey V. Elsukov return (EINVAL); 7766952c3e1SAndrey V. Elsukov 7776952c3e1SAndrey V. Elsukov /* 7786952c3e1SAndrey V. Elsukov * See whether address exist. 7796952c3e1SAndrey V. Elsukov */ 7806952c3e1SAndrey V. Elsukov ia = NULL; 7816952c3e1SAndrey V. Elsukov NET_EPOCH_ENTER(et); 7826952c3e1SAndrey V. Elsukov CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 7836952c3e1SAndrey V. Elsukov struct in_ifaddr *it; 7846952c3e1SAndrey V. Elsukov 7856952c3e1SAndrey V. Elsukov if (ifa->ifa_addr->sa_family != AF_INET) 7866952c3e1SAndrey V. Elsukov continue; 7876952c3e1SAndrey V. Elsukov 7886952c3e1SAndrey V. Elsukov it = (struct in_ifaddr *)ifa; 7896952c3e1SAndrey V. Elsukov if (it->ia_addr.sin_addr.s_addr == addr->sin_addr.s_addr && 790f375bf0eSAlexander V. Chernikov prison_check_ip4(cred, &addr->sin_addr) == 0) { 7916952c3e1SAndrey V. Elsukov ia = it; 7926952c3e1SAndrey V. Elsukov break; 7936952c3e1SAndrey V. Elsukov } 7946952c3e1SAndrey V. Elsukov } 7956952c3e1SAndrey V. Elsukov if (ia == NULL) { 7966952c3e1SAndrey V. Elsukov NET_EPOCH_EXIT(et); 7976952c3e1SAndrey V. Elsukov return (EADDRNOTAVAIL); 7986952c3e1SAndrey V. Elsukov } 7996952c3e1SAndrey V. Elsukov 8006952c3e1SAndrey V. Elsukov ifra->ifra_mask = ia->ia_sockmask; 8016952c3e1SAndrey V. Elsukov if ((ifp->if_flags & IFF_POINTOPOINT) && 8026952c3e1SAndrey V. Elsukov ia->ia_dstaddr.sin_family == AF_INET) 8036952c3e1SAndrey V. Elsukov ifra->ifra_dstaddr = ia->ia_dstaddr; 8046952c3e1SAndrey V. Elsukov else if ((ifp->if_flags & IFF_BROADCAST) && 8056952c3e1SAndrey V. Elsukov ia->ia_broadaddr.sin_family == AF_INET) 8066952c3e1SAndrey V. Elsukov ifra->ifra_broadaddr = ia->ia_broadaddr; 8076952c3e1SAndrey V. Elsukov else 8086952c3e1SAndrey V. Elsukov memset(&ifra->ifra_broadaddr, 0, 8096952c3e1SAndrey V. Elsukov sizeof(ifra->ifra_broadaddr)); 8106952c3e1SAndrey V. Elsukov 8116952c3e1SAndrey V. Elsukov NET_EPOCH_EXIT(et); 8126952c3e1SAndrey V. Elsukov return (0); 8136952c3e1SAndrey V. Elsukov } 8146952c3e1SAndrey V. Elsukov 81581728a53SAlexander V. Chernikov static int 81681728a53SAlexander V. Chernikov in_match_ifaddr(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 81781728a53SAlexander V. Chernikov { 81881728a53SAlexander V. Chernikov 81981728a53SAlexander V. Chernikov if (nh->nh_ifa == (struct ifaddr *)arg) 82081728a53SAlexander V. Chernikov return (1); 82181728a53SAlexander V. Chernikov 82281728a53SAlexander V. Chernikov return (0); 82381728a53SAlexander V. Chernikov } 82481728a53SAlexander V. Chernikov 82581728a53SAlexander V. Chernikov static int 8267b3440fcSAlexander V. Chernikov in_handle_prefix_route(uint32_t fibnum, int cmd, 8277b3440fcSAlexander V. Chernikov struct sockaddr_in *dst, struct sockaddr_in *netmask, struct ifaddr *ifa, 8287b3440fcSAlexander V. Chernikov struct ifnet *ifp) 82981728a53SAlexander V. Chernikov { 83081728a53SAlexander V. Chernikov 83181728a53SAlexander V. Chernikov NET_EPOCH_ASSERT(); 83281728a53SAlexander V. Chernikov 8337b3440fcSAlexander V. Chernikov /* Prepare gateway */ 8347b3440fcSAlexander V. Chernikov struct sockaddr_dl_short sdl = { 8357b3440fcSAlexander V. Chernikov .sdl_family = AF_LINK, 8367b3440fcSAlexander V. Chernikov .sdl_len = sizeof(struct sockaddr_dl_short), 8377b3440fcSAlexander V. Chernikov .sdl_type = ifa->ifa_ifp->if_type, 8387b3440fcSAlexander V. Chernikov .sdl_index = ifa->ifa_ifp->if_index, 8397b3440fcSAlexander V. Chernikov }; 84081728a53SAlexander V. Chernikov 8417b3440fcSAlexander V. Chernikov struct rt_addrinfo info = { 8427b3440fcSAlexander V. Chernikov .rti_ifa = ifa, 8437b3440fcSAlexander V. Chernikov .rti_ifp = ifp, 8447b3440fcSAlexander V. Chernikov .rti_flags = RTF_PINNED | ((netmask != NULL) ? 0 : RTF_HOST), 8457b3440fcSAlexander V. Chernikov .rti_info = { 8467b3440fcSAlexander V. Chernikov [RTAX_DST] = (struct sockaddr *)dst, 8477b3440fcSAlexander V. Chernikov [RTAX_NETMASK] = (struct sockaddr *)netmask, 8487b3440fcSAlexander V. Chernikov [RTAX_GATEWAY] = (struct sockaddr *)&sdl, 8497b3440fcSAlexander V. Chernikov }, 8507b3440fcSAlexander V. Chernikov /* Ensure we delete the prefix IFF prefix ifa matches */ 8517b3440fcSAlexander V. Chernikov .rti_filter = in_match_ifaddr, 8527b3440fcSAlexander V. Chernikov .rti_filterdata = ifa, 8537b3440fcSAlexander V. Chernikov }; 8547b3440fcSAlexander V. Chernikov 8557b3440fcSAlexander V. Chernikov return (rib_handle_ifaddr_info(fibnum, cmd, &info)); 85681728a53SAlexander V. Chernikov } 85781728a53SAlexander V. Chernikov 85881728a53SAlexander V. Chernikov /* 859130aebbaSAlexander V. Chernikov * Routing table interaction with interface addresses. 860130aebbaSAlexander V. Chernikov * 861130aebbaSAlexander V. Chernikov * In general, two types of routes needs to be installed: 862130aebbaSAlexander V. Chernikov * a) "interface" or "prefix" route, telling user that the addresses 863130aebbaSAlexander V. Chernikov * behind the ifa prefix are reached directly. 864130aebbaSAlexander V. Chernikov * b) "loopback" route installed for the ifa address, telling user that 865130aebbaSAlexander V. Chernikov * the address belongs to local system. 866130aebbaSAlexander V. Chernikov * 867130aebbaSAlexander V. Chernikov * Handling for (a) and (b) differs in multi-fib aspects, hence they 868130aebbaSAlexander V. Chernikov * are implemented in different functions below. 869130aebbaSAlexander V. Chernikov * 870130aebbaSAlexander V. Chernikov * The cases above may intersect - /32 interface aliases results in 871130aebbaSAlexander V. Chernikov * the same prefix produced by (a) and (b). This blurs the definition 872130aebbaSAlexander V. Chernikov * of the "loopback" route and complicate interactions. The interaction 873130aebbaSAlexander V. Chernikov * table is defined below. The case numbers are used in the multiple 874130aebbaSAlexander V. Chernikov * functions below to refer to the particular test case. 875130aebbaSAlexander V. Chernikov * 87681728a53SAlexander V. Chernikov * There can be multiple options: 877130aebbaSAlexander V. Chernikov * 1) Adding address with prefix on non-p2p/non-loopback interface. 878130aebbaSAlexander V. Chernikov * Example: 192.0.2.1/24. Action: 879130aebbaSAlexander V. Chernikov * * add "prefix" route towards 192.0.2.0/24 via @ia interface, 880130aebbaSAlexander V. Chernikov * using @ia as an address source. 881130aebbaSAlexander V. Chernikov * * add "loopback" route towards 192.0.2.1 via V_loif, saving 882130aebbaSAlexander V. Chernikov * @ia ifp in the gateway and using @ia as an address source. 883130aebbaSAlexander V. Chernikov * 884130aebbaSAlexander V. Chernikov * 2) Adding address with /32 mask to non-p2p/non-loopback interface. 885130aebbaSAlexander V. Chernikov * Example: 192.0.2.2/32. Action: 886130aebbaSAlexander V. Chernikov * * add "prefix" host route via V_loif, using @ia as an address source. 887130aebbaSAlexander V. Chernikov * 88881728a53SAlexander V. Chernikov * 3) Adding address with or without prefix to p2p interface. 889130aebbaSAlexander V. Chernikov * Example: 10.0.0.1/24->10.0.0.2. Action: 890130aebbaSAlexander V. Chernikov * * add "prefix" host route towards 10.0.0.2 via this interface, using @ia 891130aebbaSAlexander V. Chernikov * as an address source. Note: no sense in installing full /24 as the interface 892130aebbaSAlexander V. Chernikov * is point-to-point. 893130aebbaSAlexander V. Chernikov * * add "loopback" route towards 10.0.9.1 via V_loif, saving 894130aebbaSAlexander V. Chernikov * @ia ifp in the gateway and using @ia as an address source. 895130aebbaSAlexander V. Chernikov * 89681728a53SAlexander V. Chernikov * 4) Adding address with or without prefix to loopback interface. 897130aebbaSAlexander V. Chernikov * Example: 192.0.2.1/24. Action: 898130aebbaSAlexander V. Chernikov * * add "prefix" host route via @ia interface, using @ia as an address source. 899130aebbaSAlexander V. Chernikov * Note: Skip installing /24 prefix as it would introduce TTL loop 900130aebbaSAlexander V. Chernikov * for the traffic destined to these addresses. 901130aebbaSAlexander V. Chernikov */ 902130aebbaSAlexander V. Chernikov 903130aebbaSAlexander V. Chernikov /* 904130aebbaSAlexander V. Chernikov * Checks if @ia needs to install loopback route to @ia address via 905130aebbaSAlexander V. Chernikov * ifa_maintain_loopback_route(). 906130aebbaSAlexander V. Chernikov * 907130aebbaSAlexander V. Chernikov * Return true on success. 908130aebbaSAlexander V. Chernikov */ 909130aebbaSAlexander V. Chernikov static bool 910130aebbaSAlexander V. Chernikov ia_need_loopback_route(const struct in_ifaddr *ia) 911130aebbaSAlexander V. Chernikov { 912130aebbaSAlexander V. Chernikov struct ifnet *ifp = ia->ia_ifp; 913130aebbaSAlexander V. Chernikov 914130aebbaSAlexander V. Chernikov /* Case 4: Skip loopback interfaces */ 915130aebbaSAlexander V. Chernikov if ((ifp->if_flags & IFF_LOOPBACK) || 916130aebbaSAlexander V. Chernikov (ia->ia_addr.sin_addr.s_addr == INADDR_ANY)) 917130aebbaSAlexander V. Chernikov return (false); 918130aebbaSAlexander V. Chernikov 919130aebbaSAlexander V. Chernikov /* Clash avoidance: Skip p2p interfaces with both addresses are equal */ 920130aebbaSAlexander V. Chernikov if ((ifp->if_flags & IFF_POINTOPOINT) && 921130aebbaSAlexander V. Chernikov ia->ia_dstaddr.sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) 922130aebbaSAlexander V. Chernikov return (false); 923130aebbaSAlexander V. Chernikov 924130aebbaSAlexander V. Chernikov /* Case 2: skip /32 prefixes */ 925130aebbaSAlexander V. Chernikov if (!(ifp->if_flags & IFF_POINTOPOINT) && 926130aebbaSAlexander V. Chernikov (ia->ia_sockmask.sin_addr.s_addr == INADDR_BROADCAST)) 927130aebbaSAlexander V. Chernikov return (false); 928130aebbaSAlexander V. Chernikov 929130aebbaSAlexander V. Chernikov return (true); 930130aebbaSAlexander V. Chernikov } 931130aebbaSAlexander V. Chernikov 932130aebbaSAlexander V. Chernikov /* 933130aebbaSAlexander V. Chernikov * Calculate "prefix" route corresponding to @ia. 934130aebbaSAlexander V. Chernikov */ 935130aebbaSAlexander V. Chernikov static void 936130aebbaSAlexander V. Chernikov ia_getrtprefix(const struct in_ifaddr *ia, struct in_addr *prefix, struct in_addr *mask) 937130aebbaSAlexander V. Chernikov { 938130aebbaSAlexander V. Chernikov 939130aebbaSAlexander V. Chernikov if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) { 940130aebbaSAlexander V. Chernikov /* Case 3: return host route for dstaddr */ 941130aebbaSAlexander V. Chernikov *prefix = ia->ia_dstaddr.sin_addr; 942130aebbaSAlexander V. Chernikov mask->s_addr = INADDR_BROADCAST; 943130aebbaSAlexander V. Chernikov } else if (ia->ia_ifp->if_flags & IFF_LOOPBACK) { 944130aebbaSAlexander V. Chernikov /* Case 4: return host route for ifaddr */ 945130aebbaSAlexander V. Chernikov *prefix = ia->ia_addr.sin_addr; 946130aebbaSAlexander V. Chernikov mask->s_addr = INADDR_BROADCAST; 947130aebbaSAlexander V. Chernikov } else { 948130aebbaSAlexander V. Chernikov /* Cases 1,2: return actual ia prefix */ 949130aebbaSAlexander V. Chernikov *prefix = ia->ia_addr.sin_addr; 950130aebbaSAlexander V. Chernikov *mask = ia->ia_sockmask.sin_addr; 951130aebbaSAlexander V. Chernikov prefix->s_addr &= mask->s_addr; 952130aebbaSAlexander V. Chernikov } 953130aebbaSAlexander V. Chernikov } 954130aebbaSAlexander V. Chernikov 955130aebbaSAlexander V. Chernikov /* 956130aebbaSAlexander V. Chernikov * Adds or delete interface "prefix" route corresponding to @ifa. 957130aebbaSAlexander V. Chernikov * Returns 0 on success or errno. 95881728a53SAlexander V. Chernikov */ 959b8103ca7SGleb Smirnoff static int 96081728a53SAlexander V. Chernikov in_handle_ifaddr_route(int cmd, struct in_ifaddr *ia) 96181728a53SAlexander V. Chernikov { 96281728a53SAlexander V. Chernikov struct ifaddr *ifa = &ia->ia_ifa; 96381728a53SAlexander V. Chernikov struct in_addr daddr, maddr; 9647b3440fcSAlexander V. Chernikov struct sockaddr_in *pmask; 96581728a53SAlexander V. Chernikov struct epoch_tracker et; 96681728a53SAlexander V. Chernikov int error; 96781728a53SAlexander V. Chernikov 968130aebbaSAlexander V. Chernikov ia_getrtprefix(ia, &daddr, &maddr); 96981728a53SAlexander V. Chernikov 9707b3440fcSAlexander V. Chernikov struct sockaddr_in mask = { 9717b3440fcSAlexander V. Chernikov .sin_family = AF_INET, 9727b3440fcSAlexander V. Chernikov .sin_len = sizeof(struct sockaddr_in), 9737b3440fcSAlexander V. Chernikov .sin_addr = maddr, 9747b3440fcSAlexander V. Chernikov }; 9757b3440fcSAlexander V. Chernikov 9767b3440fcSAlexander V. Chernikov pmask = (maddr.s_addr != INADDR_BROADCAST) ? &mask : NULL; 97781728a53SAlexander V. Chernikov 97881728a53SAlexander V. Chernikov struct sockaddr_in dst = { 97981728a53SAlexander V. Chernikov .sin_family = AF_INET, 98081728a53SAlexander V. Chernikov .sin_len = sizeof(struct sockaddr_in), 98181728a53SAlexander V. Chernikov .sin_addr.s_addr = daddr.s_addr & maddr.s_addr, 98281728a53SAlexander V. Chernikov }; 98381728a53SAlexander V. Chernikov 984130aebbaSAlexander V. Chernikov struct ifnet *ifp = ia->ia_ifp; 985130aebbaSAlexander V. Chernikov 986130aebbaSAlexander V. Chernikov if ((maddr.s_addr == INADDR_BROADCAST) && 987130aebbaSAlexander V. Chernikov (!(ia->ia_ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)))) { 988130aebbaSAlexander V. Chernikov /* Case 2: host route on broadcast interface */ 989130aebbaSAlexander V. Chernikov ifp = V_loif; 990130aebbaSAlexander V. Chernikov } 991130aebbaSAlexander V. Chernikov 99281728a53SAlexander V. Chernikov uint32_t fibnum = ifa->ifa_ifp->if_fib; 99381728a53SAlexander V. Chernikov NET_EPOCH_ENTER(et); 9947b3440fcSAlexander V. Chernikov error = in_handle_prefix_route(fibnum, cmd, &dst, pmask, ifa, ifp); 99581728a53SAlexander V. Chernikov NET_EPOCH_EXIT(et); 99681728a53SAlexander V. Chernikov 99781728a53SAlexander V. Chernikov return (error); 99881728a53SAlexander V. Chernikov } 99981728a53SAlexander V. Chernikov 1000ccbb9c35SQing Li /* 1001d68cf57bSAlexander V. Chernikov * Check if we have a route for the given prefix already. 100248321abeSMax Laier */ 1003d68cf57bSAlexander V. Chernikov static bool 1004130aebbaSAlexander V. Chernikov in_hasrtprefix(struct in_ifaddr *target) 100548321abeSMax Laier { 10062144431cSGleb Smirnoff struct epoch_tracker et; 100748321abeSMax Laier struct in_ifaddr *ia; 1008bfb26eecSGleb Smirnoff struct in_addr prefix, mask, p, m; 1009d68cf57bSAlexander V. Chernikov bool result = false; 101048321abeSMax Laier 1011130aebbaSAlexander V. Chernikov ia_getrtprefix(target, &prefix, &mask); 101248321abeSMax Laier 10130cfee0c2SAlan Somers /* Look for an existing address with the same prefix, mask, and fib */ 10142144431cSGleb Smirnoff NET_EPOCH_ENTER(et); 1015d7c5a620SMatt Macy CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 1016130aebbaSAlexander V. Chernikov ia_getrtprefix(ia, &p, &m); 1017bfb26eecSGleb Smirnoff 1018bfb26eecSGleb Smirnoff if (prefix.s_addr != p.s_addr || 1019bfb26eecSGleb Smirnoff mask.s_addr != m.s_addr) 1020bfb26eecSGleb Smirnoff continue; 1021130aebbaSAlexander V. Chernikov 10220cfee0c2SAlan Somers if (target->ia_ifp->if_fib != ia->ia_ifp->if_fib) 10230cfee0c2SAlan Somers continue; 102448321abeSMax Laier 102548321abeSMax Laier /* 102648321abeSMax Laier * If we got a matching prefix route inserted by other 102748321abeSMax Laier * interface address, we are done here. 102848321abeSMax Laier */ 10291ae95409SGleb Smirnoff if (ia->ia_flags & IFA_ROUTE) { 1030d68cf57bSAlexander V. Chernikov result = true; 1031d68cf57bSAlexander V. Chernikov break; 1032d68cf57bSAlexander V. Chernikov } 1033d68cf57bSAlexander V. Chernikov } 10342144431cSGleb Smirnoff NET_EPOCH_EXIT(et); 10350cfee0c2SAlan Somers 1036d68cf57bSAlexander V. Chernikov return (result); 1037d68cf57bSAlexander V. Chernikov } 1038d68cf57bSAlexander V. Chernikov 1039d68cf57bSAlexander V. Chernikov int 1040130aebbaSAlexander V. Chernikov in_addprefix(struct in_ifaddr *target) 1041d68cf57bSAlexander V. Chernikov { 1042d68cf57bSAlexander V. Chernikov int error; 1043d68cf57bSAlexander V. Chernikov 1044130aebbaSAlexander V. Chernikov if (in_hasrtprefix(target)) { 1045d68cf57bSAlexander V. Chernikov if (V_nosameprefix) 1046d68cf57bSAlexander V. Chernikov return (EEXIST); 1047d68cf57bSAlexander V. Chernikov else { 1048d68cf57bSAlexander V. Chernikov rt_addrmsg(RTM_ADD, &target->ia_ifa, 1049d68cf57bSAlexander V. Chernikov target->ia_ifp->if_fib); 10501ae95409SGleb Smirnoff return (0); 10511ae95409SGleb Smirnoff } 105248321abeSMax Laier } 105348321abeSMax Laier 105448321abeSMax Laier /* 105548321abeSMax Laier * No-one seem to have this prefix route, so we try to insert it. 105648321abeSMax Laier */ 105781728a53SAlexander V. Chernikov rt_addrmsg(RTM_ADD, &target->ia_ifa, target->ia_ifp->if_fib); 105881728a53SAlexander V. Chernikov error = in_handle_ifaddr_route(RTM_ADD, target); 105948321abeSMax Laier if (!error) 106048321abeSMax Laier target->ia_flags |= IFA_ROUTE; 1061460473a0SBjoern A. Zeeb return (error); 106248321abeSMax Laier } 106348321abeSMax Laier 106448321abeSMax Laier /* 10653e7a2321SAlexander V. Chernikov * Removes either all lle entries for given @ia, or lle 10663e7a2321SAlexander V. Chernikov * corresponding to @ia address. 10673e7a2321SAlexander V. Chernikov */ 10683e7a2321SAlexander V. Chernikov static void 10693e7a2321SAlexander V. Chernikov in_scrubprefixlle(struct in_ifaddr *ia, int all, u_int flags) 10703e7a2321SAlexander V. Chernikov { 10713e7a2321SAlexander V. Chernikov struct sockaddr_in addr, mask; 10723e7a2321SAlexander V. Chernikov struct sockaddr *saddr, *smask; 10733e7a2321SAlexander V. Chernikov struct ifnet *ifp; 10743e7a2321SAlexander V. Chernikov 10753e7a2321SAlexander V. Chernikov saddr = (struct sockaddr *)&addr; 10763e7a2321SAlexander V. Chernikov bzero(&addr, sizeof(addr)); 10773e7a2321SAlexander V. Chernikov addr.sin_len = sizeof(addr); 10783e7a2321SAlexander V. Chernikov addr.sin_family = AF_INET; 10793e7a2321SAlexander V. Chernikov smask = (struct sockaddr *)&mask; 10803e7a2321SAlexander V. Chernikov bzero(&mask, sizeof(mask)); 10813e7a2321SAlexander V. Chernikov mask.sin_len = sizeof(mask); 10823e7a2321SAlexander V. Chernikov mask.sin_family = AF_INET; 10833e7a2321SAlexander V. Chernikov mask.sin_addr.s_addr = ia->ia_subnetmask; 10843e7a2321SAlexander V. Chernikov ifp = ia->ia_ifp; 10853e7a2321SAlexander V. Chernikov 108626a60575SAlexander V. Chernikov if (all) { 108726a60575SAlexander V. Chernikov /* 108826a60575SAlexander V. Chernikov * Remove all L2 entries matching given prefix. 108926a60575SAlexander V. Chernikov * Convert address to host representation to avoid 109026a60575SAlexander V. Chernikov * doing this on every callback. ia_subnetmask is already 109126a60575SAlexander V. Chernikov * stored in host representation. 109226a60575SAlexander V. Chernikov */ 109326a60575SAlexander V. Chernikov addr.sin_addr.s_addr = ntohl(ia->ia_addr.sin_addr.s_addr); 10943e7a2321SAlexander V. Chernikov lltable_prefix_free(AF_INET, saddr, smask, flags); 109526a60575SAlexander V. Chernikov } else { 109626a60575SAlexander V. Chernikov /* Remove interface address only */ 109726a60575SAlexander V. Chernikov addr.sin_addr.s_addr = ia->ia_addr.sin_addr.s_addr; 10983e7a2321SAlexander V. Chernikov lltable_delete_addr(LLTABLE(ifp), LLE_IFADDR, saddr); 10993e7a2321SAlexander V. Chernikov } 110026a60575SAlexander V. Chernikov } 11013e7a2321SAlexander V. Chernikov 11023e7a2321SAlexander V. Chernikov /* 110348321abeSMax Laier * If there is no other address in the system that can serve a route to the 110448321abeSMax Laier * same prefix, remove the route. Hand over the route to the new address 110548321abeSMax Laier * otherwise. 110648321abeSMax Laier */ 110708b68b0eSGleb Smirnoff int 11085b84dc78SQing Li in_scrubprefix(struct in_ifaddr *target, u_int flags) 110948321abeSMax Laier { 11102144431cSGleb Smirnoff struct epoch_tracker et; 111148321abeSMax Laier struct in_ifaddr *ia; 111255174c34SGleb Smirnoff struct in_addr prefix, mask, p, m; 11137278b62aSAlan Somers int error = 0; 111448321abeSMax Laier 1115df813b7eSQing Li /* 1116df813b7eSQing Li * Remove the loopback route to the interface address. 1117df813b7eSQing Li */ 1118130aebbaSAlexander V. Chernikov if (ia_need_loopback_route(target) && (flags & LLE_STATIC)) { 1119f7a39160SGleb Smirnoff struct in_ifaddr *eia; 1120c7ab6602SQing Li 1121f7a39160SGleb Smirnoff eia = in_localip_more(target); 1122f7a39160SGleb Smirnoff 1123f7a39160SGleb Smirnoff if (eia != NULL) { 1124f7a39160SGleb Smirnoff error = ifa_switch_loopback_route((struct ifaddr *)eia, 112559c180c3SAlexander V. Chernikov (struct sockaddr *)&target->ia_addr); 1126f7a39160SGleb Smirnoff ifa_free(&eia->ia_ifa); 1127f7a39160SGleb Smirnoff } else { 11289bb7d0f4SQing Li error = ifa_del_loopback_route((struct ifaddr *)target, 11299bb7d0f4SQing Li (struct sockaddr *)&target->ia_addr); 11305b84dc78SQing Li } 1131ebc90701SQing Li } 1132ebc90701SQing Li 1133130aebbaSAlexander V. Chernikov ia_getrtprefix(target, &prefix, &mask); 113448321abeSMax Laier 1135ccbb9c35SQing Li if ((target->ia_flags & IFA_ROUTE) == 0) { 1136d68cf57bSAlexander V. Chernikov rt_addrmsg(RTM_DELETE, &target->ia_ifa, target->ia_ifp->if_fib); 113726a60575SAlexander V. Chernikov 113826a60575SAlexander V. Chernikov /* 113926a60575SAlexander V. Chernikov * Removing address from !IFF_UP interface or 114026a60575SAlexander V. Chernikov * prefix which exists on other interface (along with route). 114126a60575SAlexander V. Chernikov * No entries should exist here except target addr. 114226a60575SAlexander V. Chernikov * Given that, delete this entry only. 114326a60575SAlexander V. Chernikov */ 114426a60575SAlexander V. Chernikov in_scrubprefixlle(target, 0, flags); 1145ccbb9c35SQing Li return (0); 1146ccbb9c35SQing Li } 1147ccbb9c35SQing Li 11482144431cSGleb Smirnoff NET_EPOCH_ENTER(et); 1149d7c5a620SMatt Macy CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 1150130aebbaSAlexander V. Chernikov ia_getrtprefix(ia, &p, &m); 115155174c34SGleb Smirnoff 115255174c34SGleb Smirnoff if (prefix.s_addr != p.s_addr || 115355174c34SGleb Smirnoff mask.s_addr != m.s_addr) 115455174c34SGleb Smirnoff continue; 115548321abeSMax Laier 115655174c34SGleb Smirnoff if ((ia->ia_ifp->if_flags & IFF_UP) == 0) 115748321abeSMax Laier continue; 115848321abeSMax Laier 115948321abeSMax Laier /* 116048321abeSMax Laier * If we got a matching prefix address, move IFA_ROUTE and 116148321abeSMax Laier * the route itself to it. Make sure that routing daemons 116248321abeSMax Laier * get a heads-up. 116348321abeSMax Laier */ 116408b68b0eSGleb Smirnoff if ((ia->ia_flags & IFA_ROUTE) == 0) { 116579d51435SSergey Kandaurov ifa_ref(&ia->ia_ifa); 11662144431cSGleb Smirnoff NET_EPOCH_EXIT(et); 116781728a53SAlexander V. Chernikov error = in_handle_ifaddr_route(RTM_DELETE, target); 116892322284SQing Li if (error == 0) 116948321abeSMax Laier target->ia_flags &= ~IFA_ROUTE; 117092322284SQing Li else 117192322284SQing Li log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n", 117292322284SQing Li error); 11733e7a2321SAlexander V. Chernikov /* Scrub all entries IFF interface is different */ 11743e7a2321SAlexander V. Chernikov in_scrubprefixlle(target, target->ia_ifp != ia->ia_ifp, 11753e7a2321SAlexander V. Chernikov flags); 117681728a53SAlexander V. Chernikov error = in_handle_ifaddr_route(RTM_ADD, ia); 117748321abeSMax Laier if (error == 0) 117848321abeSMax Laier ia->ia_flags |= IFA_ROUTE; 117992322284SQing Li else 118092322284SQing Li log(LOG_INFO, "in_scrubprefix: err=%d, new prefix add failed\n", 118192322284SQing Li error); 118279d51435SSergey Kandaurov ifa_free(&ia->ia_ifa); 1183460473a0SBjoern A. Zeeb return (error); 118448321abeSMax Laier } 118548321abeSMax Laier } 11862144431cSGleb Smirnoff NET_EPOCH_EXIT(et); 118748321abeSMax Laier 118848321abeSMax Laier /* 1189c9d763bfSQing Li * remove all L2 entries on the given prefix 1190c9d763bfSQing Li */ 11913e7a2321SAlexander V. Chernikov in_scrubprefixlle(target, 1, flags); 1192c9d763bfSQing Li 1193c9d763bfSQing Li /* 119448321abeSMax Laier * As no-one seem to have this prefix, we can remove the route. 119548321abeSMax Laier */ 119681728a53SAlexander V. Chernikov rt_addrmsg(RTM_DELETE, &target->ia_ifa, target->ia_ifp->if_fib); 119781728a53SAlexander V. Chernikov error = in_handle_ifaddr_route(RTM_DELETE, target); 119892322284SQing Li if (error == 0) 119948321abeSMax Laier target->ia_flags &= ~IFA_ROUTE; 120092322284SQing Li else 120192322284SQing Li log(LOG_INFO, "in_scrubprefix: err=%d, prefix delete failed\n", error); 120292322284SQing Li return (error); 120348321abeSMax Laier } 120448321abeSMax Laier 120589856f7eSBjoern A. Zeeb void 120689856f7eSBjoern A. Zeeb in_ifscrub_all(void) 120789856f7eSBjoern A. Zeeb { 120889856f7eSBjoern A. Zeeb struct ifnet *ifp; 120989856f7eSBjoern A. Zeeb struct ifaddr *ifa, *nifa; 121089856f7eSBjoern A. Zeeb struct ifaliasreq ifr; 121189856f7eSBjoern A. Zeeb 121289856f7eSBjoern A. Zeeb IFNET_RLOCK(); 12134f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 121489856f7eSBjoern A. Zeeb /* Cannot lock here - lock recursion. */ 1215a68cc388SGleb Smirnoff /* NET_EPOCH_ENTER(et); */ 1216d7c5a620SMatt Macy CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { 121789856f7eSBjoern A. Zeeb if (ifa->ifa_addr->sa_family != AF_INET) 121889856f7eSBjoern A. Zeeb continue; 121989856f7eSBjoern A. Zeeb 122089856f7eSBjoern A. Zeeb /* 122189856f7eSBjoern A. Zeeb * This is ugly but the only way for legacy IP to 122289856f7eSBjoern A. Zeeb * cleanly remove addresses and everything attached. 122389856f7eSBjoern A. Zeeb */ 122489856f7eSBjoern A. Zeeb bzero(&ifr, sizeof(ifr)); 122589856f7eSBjoern A. Zeeb ifr.ifra_addr = *ifa->ifa_addr; 122689856f7eSBjoern A. Zeeb if (ifa->ifa_dstaddr) 122789856f7eSBjoern A. Zeeb ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 122889856f7eSBjoern A. Zeeb (void)in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, 122989856f7eSBjoern A. Zeeb ifp, NULL); 123089856f7eSBjoern A. Zeeb } 1231a68cc388SGleb Smirnoff /* NET_EPOCH_EXIT(et); */ 123289856f7eSBjoern A. Zeeb in_purgemaddrs(ifp); 123389856f7eSBjoern A. Zeeb igmp_domifdetach(ifp); 123489856f7eSBjoern A. Zeeb } 123589856f7eSBjoern A. Zeeb IFNET_RUNLOCK(); 123689856f7eSBjoern A. Zeeb } 123789856f7eSBjoern A. Zeeb 123890cc51a1SRyan Stone int 123990cc51a1SRyan Stone in_ifaddr_broadcast(struct in_addr in, struct in_ifaddr *ia) 124090cc51a1SRyan Stone { 124190cc51a1SRyan Stone 124290cc51a1SRyan Stone return ((in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 124390cc51a1SRyan Stone /* 1244fd076593SMike Karels * Optionally check for old-style (host 0) broadcast, but 124590cc51a1SRyan Stone * taking into account that RFC 3021 obsoletes it. 124690cc51a1SRyan Stone */ 1247fd076593SMike Karels (V_broadcast_lowest && ia->ia_subnetmask != IN_RFC3021_MASK && 124890cc51a1SRyan Stone ntohl(in.s_addr) == ia->ia_subnet)) && 124990cc51a1SRyan Stone /* 125090cc51a1SRyan Stone * Check for an all one subnetmask. These 125190cc51a1SRyan Stone * only exist when an interface gets a secondary 125290cc51a1SRyan Stone * address. 125390cc51a1SRyan Stone */ 125490cc51a1SRyan Stone ia->ia_subnetmask != (u_long)0xffffffff); 125590cc51a1SRyan Stone } 125690cc51a1SRyan Stone 1257df8bae1dSRodney W. Grimes /* 1258df8bae1dSRodney W. Grimes * Return 1 if the address might be a local broadcast address. 1259df8bae1dSRodney W. Grimes */ 126026f9a767SRodney W. Grimes int 1261f2565d68SRobert Watson in_broadcast(struct in_addr in, struct ifnet *ifp) 1262df8bae1dSRodney W. Grimes { 12633e85b721SEd Maste struct ifaddr *ifa; 126411f2a7cdSRyan Stone int found; 1265df8bae1dSRodney W. Grimes 1266b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 1267b8a6e03fSGleb Smirnoff 1268df8bae1dSRodney W. Grimes if (in.s_addr == INADDR_BROADCAST || 1269df8bae1dSRodney W. Grimes in.s_addr == INADDR_ANY) 1270460473a0SBjoern A. Zeeb return (1); 1271df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 1272460473a0SBjoern A. Zeeb return (0); 127311f2a7cdSRyan Stone found = 0; 1274df8bae1dSRodney W. Grimes /* 1275df8bae1dSRodney W. Grimes * Look through the list of addresses for a match 1276df8bae1dSRodney W. Grimes * with a broadcast address. 1277df8bae1dSRodney W. Grimes */ 1278d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1279df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family == AF_INET && 128011f2a7cdSRyan Stone in_ifaddr_broadcast(in, (struct in_ifaddr *)ifa)) { 128111f2a7cdSRyan Stone found = 1; 128211f2a7cdSRyan Stone break; 128311f2a7cdSRyan Stone } 128411f2a7cdSRyan Stone return (found); 1285df8bae1dSRodney W. Grimes } 1286ec002feeSBruce M Simpson 1287df8bae1dSRodney W. Grimes /* 1288b1c53bc9SRobert Watson * On interface removal, clean up IPv4 data structures hung off of the ifnet. 1289b1c53bc9SRobert Watson */ 1290b1c53bc9SRobert Watson void 1291f2565d68SRobert Watson in_ifdetach(struct ifnet *ifp) 1292b1c53bc9SRobert Watson { 1293f3e1324bSStephen Hurd IN_MULTI_LOCK(); 1294603724d3SBjoern A. Zeeb in_pcbpurgeif0(&V_ripcbinfo, ifp); 1295603724d3SBjoern A. Zeeb in_pcbpurgeif0(&V_udbinfo, ifp); 1296e06e816fSKevin Lo in_pcbpurgeif0(&V_ulitecbinfo, ifp); 1297ec002feeSBruce M Simpson in_purgemaddrs(ifp); 1298f3e1324bSStephen Hurd IN_MULTI_UNLOCK(); 12993689652cSHans Petter Selasky 13003689652cSHans Petter Selasky /* 13013689652cSHans Petter Selasky * Make sure all multicast deletions invoking if_ioctl() are 13023689652cSHans Petter Selasky * completed before returning. Else we risk accessing a freed 13033689652cSHans Petter Selasky * ifnet structure pointer. 13043689652cSHans Petter Selasky */ 13053689652cSHans Petter Selasky inm_release_wait(NULL); 1306b1c53bc9SRobert Watson } 13076e6b3f7cSQing Li 1308b8103ca7SGleb Smirnoff static void 1309b8103ca7SGleb Smirnoff in_ifnet_event(void *arg __unused, struct ifnet *ifp, int event) 1310b8103ca7SGleb Smirnoff { 1311b8103ca7SGleb Smirnoff struct epoch_tracker et; 1312b8103ca7SGleb Smirnoff struct ifaddr *ifa; 1313b8103ca7SGleb Smirnoff struct in_ifaddr *ia; 1314b8103ca7SGleb Smirnoff int error; 1315b8103ca7SGleb Smirnoff 1316b8103ca7SGleb Smirnoff NET_EPOCH_ENTER(et); 1317b8103ca7SGleb Smirnoff switch (event) { 1318b8103ca7SGleb Smirnoff case IFNET_EVENT_DOWN: 1319b8103ca7SGleb Smirnoff CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1320b8103ca7SGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_INET) 1321b8103ca7SGleb Smirnoff continue; 1322b8103ca7SGleb Smirnoff ia = (struct in_ifaddr *)ifa; 1323b8103ca7SGleb Smirnoff if ((ia->ia_flags & IFA_ROUTE) == 0) 1324b8103ca7SGleb Smirnoff continue; 1325b8103ca7SGleb Smirnoff ifa_ref(ifa); 1326b8103ca7SGleb Smirnoff /* 1327b8103ca7SGleb Smirnoff * in_scrubprefix() kills the interface route. 1328b8103ca7SGleb Smirnoff */ 1329b8103ca7SGleb Smirnoff in_scrubprefix(ia, 0); 1330b8103ca7SGleb Smirnoff /* 1331b8103ca7SGleb Smirnoff * in_ifadown gets rid of all the rest of the 1332b8103ca7SGleb Smirnoff * routes. This is not quite the right thing 1333b8103ca7SGleb Smirnoff * to do, but at least if we are running a 1334b8103ca7SGleb Smirnoff * routing process they will come back. 1335b8103ca7SGleb Smirnoff */ 1336b8103ca7SGleb Smirnoff in_ifadown(ifa, 0); 1337b8103ca7SGleb Smirnoff ifa_free(ifa); 1338b8103ca7SGleb Smirnoff } 1339b8103ca7SGleb Smirnoff break; 1340b8103ca7SGleb Smirnoff 1341b8103ca7SGleb Smirnoff case IFNET_EVENT_UP: 1342b8103ca7SGleb Smirnoff CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1343b8103ca7SGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_INET) 1344b8103ca7SGleb Smirnoff continue; 1345b8103ca7SGleb Smirnoff ia = (struct in_ifaddr *)ifa; 1346b8103ca7SGleb Smirnoff if (ia->ia_flags & IFA_ROUTE) 1347b8103ca7SGleb Smirnoff continue; 1348b8103ca7SGleb Smirnoff ifa_ref(ifa); 1349b8103ca7SGleb Smirnoff error = ifa_del_loopback_route(ifa, ifa->ifa_addr); 1350b8103ca7SGleb Smirnoff rt_addrmsg(RTM_ADD, ifa, ifa->ifa_ifp->if_fib); 1351b8103ca7SGleb Smirnoff error = in_handle_ifaddr_route(RTM_ADD, ia); 1352b8103ca7SGleb Smirnoff if (error == 0) 1353b8103ca7SGleb Smirnoff ia->ia_flags |= IFA_ROUTE; 1354b8103ca7SGleb Smirnoff error = ifa_add_loopback_route(ifa, ifa->ifa_addr); 1355b8103ca7SGleb Smirnoff ifa_free(ifa); 1356b8103ca7SGleb Smirnoff } 1357b8103ca7SGleb Smirnoff break; 1358b8103ca7SGleb Smirnoff } 1359b8103ca7SGleb Smirnoff NET_EPOCH_EXIT(et); 1360b8103ca7SGleb Smirnoff } 1361b8103ca7SGleb Smirnoff EVENTHANDLER_DEFINE(ifnet_event, in_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); 1362b8103ca7SGleb Smirnoff 1363d10910e6SBruce M Simpson /* 1364d10910e6SBruce M Simpson * Delete all IPv4 multicast address records, and associated link-layer 1365d10910e6SBruce M Simpson * multicast address records, associated with ifp. 1366d10910e6SBruce M Simpson * XXX It looks like domifdetach runs AFTER the link layer cleanup. 136756663a40SBruce M Simpson * XXX This should not race with ifma_protospec being set during 136856663a40SBruce M Simpson * a new allocation, if it does, we have bigger problems. 1369d10910e6SBruce M Simpson */ 1370d10910e6SBruce M Simpson static void 1371d10910e6SBruce M Simpson in_purgemaddrs(struct ifnet *ifp) 1372d10910e6SBruce M Simpson { 1373*1e9482f4SAlexander Motin struct epoch_tracker et; 1374f3e1324bSStephen Hurd struct in_multi_head purgeinms; 1375f3e1324bSStephen Hurd struct in_multi *inm; 1376*1e9482f4SAlexander Motin struct ifmultiaddr *ifma; 1377d10910e6SBruce M Simpson 1378f3e1324bSStephen Hurd SLIST_INIT(&purgeinms); 1379f3e1324bSStephen Hurd IN_MULTI_LIST_LOCK(); 1380d10910e6SBruce M Simpson 1381d10910e6SBruce M Simpson /* 1382d10910e6SBruce M Simpson * Extract list of in_multi associated with the detaching ifp 1383d10910e6SBruce M Simpson * which the PF_INET layer is about to release. 1384d10910e6SBruce M Simpson * We need to do this as IF_ADDR_LOCK() may be re-acquired 1385d10910e6SBruce M Simpson * by code further down. 1386d10910e6SBruce M Simpson */ 1387b6f6f880SMatt Macy IF_ADDR_WLOCK(ifp); 1388*1e9482f4SAlexander Motin NET_EPOCH_ENTER(et); 1389*1e9482f4SAlexander Motin CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1390*1e9482f4SAlexander Motin inm = inm_ifmultiaddr_get_inm(ifma); 1391*1e9482f4SAlexander Motin if (inm == NULL) 1392d10910e6SBruce M Simpson continue; 1393f3e1324bSStephen Hurd inm_rele_locked(&purgeinms, inm); 1394d10910e6SBruce M Simpson } 1395*1e9482f4SAlexander Motin NET_EPOCH_EXIT(et); 1396b6f6f880SMatt Macy IF_ADDR_WUNLOCK(ifp); 1397d10910e6SBruce M Simpson 1398f3e1324bSStephen Hurd inm_release_list_deferred(&purgeinms); 1399d10910e6SBruce M Simpson igmp_ifdetach(ifp); 1400f3e1324bSStephen Hurd IN_MULTI_LIST_UNLOCK(); 1401d10910e6SBruce M Simpson } 1402d10910e6SBruce M Simpson 14036e6b3f7cSQing Li struct in_llentry { 14046e6b3f7cSQing Li struct llentry base; 14056e6b3f7cSQing Li }; 14066e6b3f7cSQing Li 140711cdad98SAlexander V. Chernikov #define IN_LLTBL_DEFAULT_HSIZE 32 140811cdad98SAlexander V. Chernikov #define IN_LLTBL_HASH(k, h) \ 140911cdad98SAlexander V. Chernikov (((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1)) 141011cdad98SAlexander V. Chernikov 1411a93cda78SKip Macy /* 141211cdad98SAlexander V. Chernikov * Do actual deallocation of @lle. 14132769d062SConrad Meyer */ 14142769d062SConrad Meyer static void 14154f6c66ccSMatt Macy in_lltable_destroy_lle_unlocked(epoch_context_t ctx) 14162769d062SConrad Meyer { 14174f6c66ccSMatt Macy struct llentry *lle; 14182769d062SConrad Meyer 14194f6c66ccSMatt Macy lle = __containerof(ctx, struct llentry, lle_epoch_ctx); 14202769d062SConrad Meyer LLE_LOCK_DESTROY(lle); 14212769d062SConrad Meyer LLE_REQ_DESTROY(lle); 14222769d062SConrad Meyer free(lle, M_LLTABLE); 14232769d062SConrad Meyer } 14242769d062SConrad Meyer 14252769d062SConrad Meyer /* 142611cdad98SAlexander V. Chernikov * Called by LLE_FREE_LOCKED when number of references 142711cdad98SAlexander V. Chernikov * drops to zero. 1428a93cda78SKip Macy */ 1429a93cda78SKip Macy static void 143011cdad98SAlexander V. Chernikov in_lltable_destroy_lle(struct llentry *lle) 1431a93cda78SKip Macy { 143211cdad98SAlexander V. Chernikov 1433a93cda78SKip Macy LLE_WUNLOCK(lle); 14342a4bd982SGleb Smirnoff NET_EPOCH_CALL(in_lltable_destroy_lle_unlocked, &lle->lle_epoch_ctx); 1435a93cda78SKip Macy } 1436a93cda78SKip Macy 14376e6b3f7cSQing Li static struct llentry * 1438314294deSAlexander V. Chernikov in_lltable_new(struct in_addr addr4, u_int flags) 14396e6b3f7cSQing Li { 14406e6b3f7cSQing Li struct in_llentry *lle; 14416e6b3f7cSQing Li 144290b357f6SGleb Smirnoff lle = malloc(sizeof(struct in_llentry), M_LLTABLE, M_NOWAIT | M_ZERO); 14436e6b3f7cSQing Li if (lle == NULL) /* NB: caller generates msg */ 14446e6b3f7cSQing Li return NULL; 14456e6b3f7cSQing Li 14466e6b3f7cSQing Li /* 14476e6b3f7cSQing Li * For IPv4 this will trigger "arpresolve" to generate 14486e6b3f7cSQing Li * an ARP request. 14496e6b3f7cSQing Li */ 1450a98c06f1SGleb Smirnoff lle->base.la_expire = time_uptime; /* mark expired */ 1451314294deSAlexander V. Chernikov lle->base.r_l3addr.addr4 = addr4; 14526e6b3f7cSQing Li lle->base.lle_refcnt = 1; 145311cdad98SAlexander V. Chernikov lle->base.lle_free = in_lltable_destroy_lle; 14546e6b3f7cSQing Li LLE_LOCK_INIT(&lle->base); 1455f8aee88fSAlexander V. Chernikov LLE_REQ_INIT(&lle->base); 14560447c136SAlexander V. Chernikov callout_init(&lle->base.lle_timer, 1); 1457ea537929SGleb Smirnoff 1458ea537929SGleb Smirnoff return (&lle->base); 14596e6b3f7cSQing Li } 14606e6b3f7cSQing Li 1461c9d763bfSQing Li #define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \ 14623e7a2321SAlexander V. Chernikov ((((d).s_addr ^ (a).s_addr) & (m).s_addr)) == 0 ) 1463c9d763bfSQing Li 146411cdad98SAlexander V. Chernikov static int 14653e7a2321SAlexander V. Chernikov in_lltable_match_prefix(const struct sockaddr *saddr, 14663e7a2321SAlexander V. Chernikov const struct sockaddr *smask, u_int flags, struct llentry *lle) 1467c9d763bfSQing Li { 14683e7a2321SAlexander V. Chernikov struct in_addr addr, mask, lle_addr; 14693e7a2321SAlexander V. Chernikov 14703e7a2321SAlexander V. Chernikov addr = ((const struct sockaddr_in *)saddr)->sin_addr; 14713e7a2321SAlexander V. Chernikov mask = ((const struct sockaddr_in *)smask)->sin_addr; 14723e7a2321SAlexander V. Chernikov lle_addr.s_addr = ntohl(lle->r_l3addr.addr4.s_addr); 14733e7a2321SAlexander V. Chernikov 14743e7a2321SAlexander V. Chernikov if (IN_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0) 14753e7a2321SAlexander V. Chernikov return (0); 14763e7a2321SAlexander V. Chernikov 14773e7a2321SAlexander V. Chernikov if (lle->la_flags & LLE_IFADDR) { 14785b84dc78SQing Li /* 14793e7a2321SAlexander V. Chernikov * Delete LLE_IFADDR records IFF address & flag matches. 14803e7a2321SAlexander V. Chernikov * Note that addr is the interface address within prefix 14813e7a2321SAlexander V. Chernikov * being matched. 14823e7a2321SAlexander V. Chernikov * Note also we should handle 'ifdown' cases without removing 14833e7a2321SAlexander V. Chernikov * ifaddr macs. 14845b84dc78SQing Li */ 14853e7a2321SAlexander V. Chernikov if (addr.s_addr == lle_addr.s_addr && (flags & LLE_STATIC) != 0) 14863e7a2321SAlexander V. Chernikov return (1); 14873e7a2321SAlexander V. Chernikov return (0); 14883e7a2321SAlexander V. Chernikov } 14893e7a2321SAlexander V. Chernikov 14903e7a2321SAlexander V. Chernikov /* flags & LLE_STATIC means deleting both dynamic and static entries */ 14913e7a2321SAlexander V. Chernikov if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)) 149211cdad98SAlexander V. Chernikov return (1); 149311cdad98SAlexander V. Chernikov 149411cdad98SAlexander V. Chernikov return (0); 149511cdad98SAlexander V. Chernikov } 149611cdad98SAlexander V. Chernikov 149711cdad98SAlexander V. Chernikov static void 149811cdad98SAlexander V. Chernikov in_lltable_free_entry(struct lltable *llt, struct llentry *lle) 149911cdad98SAlexander V. Chernikov { 150011cdad98SAlexander V. Chernikov size_t pkts_dropped; 150111cdad98SAlexander V. Chernikov 150211cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 150311cdad98SAlexander V. Chernikov KASSERT(llt != NULL, ("lltable is NULL")); 150411cdad98SAlexander V. Chernikov 150511cdad98SAlexander V. Chernikov /* Unlink entry from table if not already */ 150611cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) { 1507f6960e20SMatt Macy IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 150811cdad98SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 150911cdad98SAlexander V. Chernikov } 151011cdad98SAlexander V. Chernikov 151111cdad98SAlexander V. Chernikov /* Drop hold queue */ 1512e162ea60SGeorge V. Neville-Neil pkts_dropped = llentry_free(lle); 1513e162ea60SGeorge V. Neville-Neil ARPSTAT_ADD(dropped, pkts_dropped); 1514c9d763bfSQing Li } 1515c9d763bfSQing Li 15166e6b3f7cSQing Li static int 1517c7ab6602SQing Li in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr) 15186e6b3f7cSQing Li { 1519936f4a42SAlexander V. Chernikov struct nhop_object *nh; 1520936f4a42SAlexander V. Chernikov struct in_addr addr; 15216e6b3f7cSQing Li 15226e6b3f7cSQing Li KASSERT(l3addr->sa_family == AF_INET, 15236e6b3f7cSQing Li ("sin_family %d", l3addr->sa_family)); 15246e6b3f7cSQing Li 1525936f4a42SAlexander V. Chernikov addr = ((const struct sockaddr_in *)l3addr)->sin_addr; 152613e255faSMarko Zec 1527936f4a42SAlexander V. Chernikov nh = fib4_lookup(ifp->if_fib, addr, 0, NHR_NONE, 0); 1528936f4a42SAlexander V. Chernikov if (nh == NULL) 15296cf8e330SQing Li return (EINVAL); 15306cf8e330SQing Li 153113e255faSMarko Zec /* 153213e255faSMarko Zec * If the gateway for an existing host route matches the target L3 15336cf8e330SQing Li * address, which is a special route inserted by some implementation 15346cf8e330SQing Li * such as MANET, and the interface is of the correct type, then 15356cf8e330SQing Li * allow for ARP to proceed. 153613e255faSMarko Zec */ 1537936f4a42SAlexander V. Chernikov if (nh->nh_flags & NHF_GATEWAY) { 1538936f4a42SAlexander V. Chernikov if (!(nh->nh_flags & NHF_HOST) || nh->nh_ifp->if_type != IFT_ETHER || 1539936f4a42SAlexander V. Chernikov (nh->nh_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 || 1540936f4a42SAlexander V. Chernikov memcmp(nh->gw_sa.sa_data, l3addr->sa_data, 154115d25219SQing Li sizeof(in_addr_t)) != 0) { 1542db92413eSQing Li return (EINVAL); 1543db92413eSQing Li } 154415d25219SQing Li } 1545db92413eSQing Li 1546db92413eSQing Li /* 1547db92413eSQing Li * Make sure that at least the destination address is covered 1548db92413eSQing Li * by the route. This is for handling the case where 2 or more 1549db92413eSQing Li * interfaces have the same prefix. An incoming packet arrives 1550db92413eSQing Li * on one interface and the corresponding outgoing packet leaves 1551db92413eSQing Li * another interface. 1552db92413eSQing Li */ 1553936f4a42SAlexander V. Chernikov if ((nh->nh_ifp != ifp) && (nh->nh_flags & NHF_HOST) == 0) { 1554936f4a42SAlexander V. Chernikov struct in_ifaddr *ia = (struct in_ifaddr *)ifaof_ifpforaddr(l3addr, ifp); 1555936f4a42SAlexander V. Chernikov struct in_addr dst_addr, mask_addr; 1556db92413eSQing Li 1557936f4a42SAlexander V. Chernikov if (ia == NULL) 1558936f4a42SAlexander V. Chernikov return (EINVAL); 1559936f4a42SAlexander V. Chernikov 1560b3664a14SQing Li /* 1561936f4a42SAlexander V. Chernikov * ifaof_ifpforaddr() returns _best matching_ IFA. 1562936f4a42SAlexander V. Chernikov * It is possible that ifa prefix does not cover our address. 1563936f4a42SAlexander V. Chernikov * Explicitly verify and fail if that's the case. 1564b3664a14SQing Li */ 1565936f4a42SAlexander V. Chernikov dst_addr = IA_SIN(ia)->sin_addr; 1566936f4a42SAlexander V. Chernikov mask_addr.s_addr = htonl(ia->ia_subnetmask); 1567936f4a42SAlexander V. Chernikov 1568936f4a42SAlexander V. Chernikov if (!IN_ARE_MASKED_ADDR_EQUAL(dst_addr, addr, mask_addr)) 1569b3664a14SQing Li return (EINVAL); 1570db92413eSQing Li } 1571db92413eSQing Li 157215d25219SQing Li return (0); 15736e6b3f7cSQing Li } 15746e6b3f7cSQing Li 157511cdad98SAlexander V. Chernikov static inline uint32_t 157611cdad98SAlexander V. Chernikov in_lltable_hash_dst(const struct in_addr dst, uint32_t hsize) 157711cdad98SAlexander V. Chernikov { 157811cdad98SAlexander V. Chernikov 157911cdad98SAlexander V. Chernikov return (IN_LLTBL_HASH(dst.s_addr, hsize)); 158011cdad98SAlexander V. Chernikov } 158111cdad98SAlexander V. Chernikov 158211cdad98SAlexander V. Chernikov static uint32_t 158311cdad98SAlexander V. Chernikov in_lltable_hash(const struct llentry *lle, uint32_t hsize) 158411cdad98SAlexander V. Chernikov { 158511cdad98SAlexander V. Chernikov 1586314294deSAlexander V. Chernikov return (in_lltable_hash_dst(lle->r_l3addr.addr4, hsize)); 158711cdad98SAlexander V. Chernikov } 158811cdad98SAlexander V. Chernikov 158911cdad98SAlexander V. Chernikov static void 159011cdad98SAlexander V. Chernikov in_lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 159111cdad98SAlexander V. Chernikov { 159211cdad98SAlexander V. Chernikov struct sockaddr_in *sin; 159311cdad98SAlexander V. Chernikov 159411cdad98SAlexander V. Chernikov sin = (struct sockaddr_in *)sa; 159511cdad98SAlexander V. Chernikov bzero(sin, sizeof(*sin)); 159611cdad98SAlexander V. Chernikov sin->sin_family = AF_INET; 159711cdad98SAlexander V. Chernikov sin->sin_len = sizeof(*sin); 1598314294deSAlexander V. Chernikov sin->sin_addr = lle->r_l3addr.addr4; 159911cdad98SAlexander V. Chernikov } 160011cdad98SAlexander V. Chernikov 1601b4b1367aSAlexander V. Chernikov static inline struct llentry * 1602b4b1367aSAlexander V. Chernikov in_lltable_find_dst(struct lltable *llt, struct in_addr dst) 1603b4b1367aSAlexander V. Chernikov { 1604b4b1367aSAlexander V. Chernikov struct llentry *lle; 1605b4b1367aSAlexander V. Chernikov struct llentries *lleh; 160611cdad98SAlexander V. Chernikov u_int hashidx; 1607b4b1367aSAlexander V. Chernikov 16083a749863SAlexander V. Chernikov hashidx = in_lltable_hash_dst(dst, llt->llt_hsize); 160911cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 16104f6c66ccSMatt Macy CK_LIST_FOREACH(lle, lleh, lle_next) { 1611b4b1367aSAlexander V. Chernikov if (lle->la_flags & LLE_DELETED) 1612b4b1367aSAlexander V. Chernikov continue; 1613314294deSAlexander V. Chernikov if (lle->r_l3addr.addr4.s_addr == dst.s_addr) 1614b4b1367aSAlexander V. Chernikov break; 1615b4b1367aSAlexander V. Chernikov } 1616b4b1367aSAlexander V. Chernikov 1617b4b1367aSAlexander V. Chernikov return (lle); 1618b4b1367aSAlexander V. Chernikov } 1619b4b1367aSAlexander V. Chernikov 16203e7a2321SAlexander V. Chernikov static void 16213e7a2321SAlexander V. Chernikov in_lltable_delete_entry(struct lltable *llt, struct llentry *lle) 1622b4b1367aSAlexander V. Chernikov { 1623b4b1367aSAlexander V. Chernikov 1624b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_DELETED; 1625b4b1367aSAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); 1626b4b1367aSAlexander V. Chernikov #ifdef DIAGNOSTIC 1627b4b1367aSAlexander V. Chernikov log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); 1628b4b1367aSAlexander V. Chernikov #endif 1629b4b1367aSAlexander V. Chernikov llentry_free(lle); 1630b4b1367aSAlexander V. Chernikov } 1631b4b1367aSAlexander V. Chernikov 1632b4b1367aSAlexander V. Chernikov static struct llentry * 16335a255516SAlexander V. Chernikov in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) 1634b4b1367aSAlexander V. Chernikov { 1635b4b1367aSAlexander V. Chernikov const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; 1636b4b1367aSAlexander V. Chernikov struct ifnet *ifp = llt->llt_ifp; 1637b4b1367aSAlexander V. Chernikov struct llentry *lle; 16384fb3a820SAlexander V. Chernikov char linkhdr[LLE_MAX_LINKHDR]; 16394fb3a820SAlexander V. Chernikov size_t linkhdrsize; 16404fb3a820SAlexander V. Chernikov int lladdr_off; 1641b4b1367aSAlexander V. Chernikov 1642b4b1367aSAlexander V. Chernikov KASSERT(l3addr->sa_family == AF_INET, 1643b4b1367aSAlexander V. Chernikov ("sin_family %d", l3addr->sa_family)); 1644b4b1367aSAlexander V. Chernikov 1645b4b1367aSAlexander V. Chernikov /* 1646b4b1367aSAlexander V. Chernikov * A route that covers the given address must have 1647b4b1367aSAlexander V. Chernikov * been installed 1st because we are doing a resolution, 1648b4b1367aSAlexander V. Chernikov * verify this. 1649b4b1367aSAlexander V. Chernikov */ 1650b4b1367aSAlexander V. Chernikov if (!(flags & LLE_IFADDR) && 1651b4b1367aSAlexander V. Chernikov in_lltable_rtcheck(ifp, flags, l3addr) != 0) 1652b4b1367aSAlexander V. Chernikov return (NULL); 1653b4b1367aSAlexander V. Chernikov 1654314294deSAlexander V. Chernikov lle = in_lltable_new(sin->sin_addr, flags); 1655b4b1367aSAlexander V. Chernikov if (lle == NULL) { 1656b4b1367aSAlexander V. Chernikov log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); 1657b4b1367aSAlexander V. Chernikov return (NULL); 1658b4b1367aSAlexander V. Chernikov } 1659b4b1367aSAlexander V. Chernikov lle->la_flags = flags; 1660f8aee88fSAlexander V. Chernikov if (flags & LLE_STATIC) 1661f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID; 1662b4b1367aSAlexander V. Chernikov if ((flags & LLE_IFADDR) == LLE_IFADDR) { 16634fb3a820SAlexander V. Chernikov linkhdrsize = LLE_MAX_LINKHDR; 16644fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, AF_INET, IF_LLADDR(ifp), 16652769d062SConrad Meyer linkhdr, &linkhdrsize, &lladdr_off) != 0) { 1666990a6d18SMark Johnston in_lltable_free_entry(llt, lle); 16674fb3a820SAlexander V. Chernikov return (NULL); 16682769d062SConrad Meyer } 16694fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, 16704fb3a820SAlexander V. Chernikov lladdr_off); 1671ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_STATIC; 1672f8aee88fSAlexander V. Chernikov lle->r_flags |= (RLLE_VALID | RLLE_IFADDR); 1673b4b1367aSAlexander V. Chernikov } 1674b4b1367aSAlexander V. Chernikov 1675b4b1367aSAlexander V. Chernikov return (lle); 1676b4b1367aSAlexander V. Chernikov } 1677b4b1367aSAlexander V. Chernikov 16786e6b3f7cSQing Li /* 16796e6b3f7cSQing Li * Return NULL if not found or marked for deletion. 16806e6b3f7cSQing Li * If found return lle read locked. 16816e6b3f7cSQing Li */ 16826e6b3f7cSQing Li static struct llentry * 16836e6b3f7cSQing Li in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) 16846e6b3f7cSQing Li { 16856e6b3f7cSQing Li const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; 16866e6b3f7cSQing Li struct llentry *lle; 16876e6b3f7cSQing Li 16886e4cd746SMarius Strobl IF_AFDATA_LOCK_ASSERT(llt->llt_ifp); 16896e6b3f7cSQing Li KASSERT(l3addr->sa_family == AF_INET, 16906e6b3f7cSQing Li ("sin_family %d", l3addr->sa_family)); 169149cf58e5SMark Johnston KASSERT((flags & (LLE_UNLOCKED | LLE_EXCLUSIVE)) != 169249cf58e5SMark Johnston (LLE_UNLOCKED | LLE_EXCLUSIVE), 169349cf58e5SMark Johnston ("wrong lle request flags: %#x", flags)); 1694b4b1367aSAlexander V. Chernikov 169549cf58e5SMark Johnston lle = in_lltable_find_dst(llt, sin->sin_addr); 1696b4b1367aSAlexander V. Chernikov if (lle == NULL) 16976e6b3f7cSQing Li return (NULL); 1698f8aee88fSAlexander V. Chernikov if (flags & LLE_UNLOCKED) 1699f8aee88fSAlexander V. Chernikov return (lle); 1700f8aee88fSAlexander V. Chernikov 17016e6b3f7cSQing Li if (flags & LLE_EXCLUSIVE) 17026e6b3f7cSQing Li LLE_WLOCK(lle); 17036e6b3f7cSQing Li else 17046e6b3f7cSQing Li LLE_RLOCK(lle); 1705b4b1367aSAlexander V. Chernikov 1706c06cc56eSMark Johnston /* 1707c06cc56eSMark Johnston * If the afdata lock is not held, the LLE may have been unlinked while 1708c06cc56eSMark Johnston * we were blocked on the LLE lock. Check for this case. 1709c06cc56eSMark Johnston */ 1710c06cc56eSMark Johnston if (__predict_false((lle->la_flags & LLE_LINKED) == 0)) { 1711c06cc56eSMark Johnston if (flags & LLE_EXCLUSIVE) 1712c06cc56eSMark Johnston LLE_WUNLOCK(lle); 1713c06cc56eSMark Johnston else 1714c06cc56eSMark Johnston LLE_RUNLOCK(lle); 1715c06cc56eSMark Johnston return (NULL); 1716c06cc56eSMark Johnston } 17176e6b3f7cSQing Li return (lle); 17186e6b3f7cSQing Li } 17196e6b3f7cSQing Li 17206e6b3f7cSQing Li static int 172111cdad98SAlexander V. Chernikov in_lltable_dump_entry(struct lltable *llt, struct llentry *lle, 172211cdad98SAlexander V. Chernikov struct sysctl_req *wr) 17236e6b3f7cSQing Li { 17246e6b3f7cSQing Li struct ifnet *ifp = llt->llt_ifp; 17256e6b3f7cSQing Li /* XXX stack use */ 17266e6b3f7cSQing Li struct { 17276e6b3f7cSQing Li struct rt_msghdr rtm; 17289711a168SGleb Smirnoff struct sockaddr_in sin; 17296e6b3f7cSQing Li struct sockaddr_dl sdl; 17306e6b3f7cSQing Li } arpc; 17316e6b3f7cSQing Li struct sockaddr_dl *sdl; 173211cdad98SAlexander V. Chernikov int error; 17336e6b3f7cSQing Li 173411cdad98SAlexander V. Chernikov bzero(&arpc, sizeof(arpc)); 17356e6b3f7cSQing Li /* skip deleted entries */ 173693704ac5SQing Li if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) 173711cdad98SAlexander V. Chernikov return (0); 1738813dd6aeSBjoern A. Zeeb /* Skip if jailed and not a valid IP of the prison. */ 173911cdad98SAlexander V. Chernikov lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin); 1740514ef08cSBrooks Davis if (prison_if(wr->td->td_ucred, (struct sockaddr *)&arpc.sin) != 0) 174111cdad98SAlexander V. Chernikov return (0); 17426e6b3f7cSQing Li /* 17436e6b3f7cSQing Li * produce a msg made of: 17446e6b3f7cSQing Li * struct rt_msghdr; 17459711a168SGleb Smirnoff * struct sockaddr_in; (IPv4) 17466e6b3f7cSQing Li * struct sockaddr_dl; 17476e6b3f7cSQing Li */ 17486e6b3f7cSQing Li arpc.rtm.rtm_msglen = sizeof(arpc); 1749c0e9a8a1SHartmut Brandt arpc.rtm.rtm_version = RTM_VERSION; 1750c0e9a8a1SHartmut Brandt arpc.rtm.rtm_type = RTM_GET; 1751c0e9a8a1SHartmut Brandt arpc.rtm.rtm_flags = RTF_UP; 1752c0e9a8a1SHartmut Brandt arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; 17536e6b3f7cSQing Li 17546e6b3f7cSQing Li /* publish */ 17559711a168SGleb Smirnoff if (lle->la_flags & LLE_PUB) 17566e6b3f7cSQing Li arpc.rtm.rtm_flags |= RTF_ANNOUNCE; 17576e6b3f7cSQing Li 17586e6b3f7cSQing Li sdl = &arpc.sdl; 17596e6b3f7cSQing Li sdl->sdl_family = AF_LINK; 17606e6b3f7cSQing Li sdl->sdl_len = sizeof(*sdl); 17616e6b3f7cSQing Li sdl->sdl_index = ifp->if_index; 17626e6b3f7cSQing Li sdl->sdl_type = ifp->if_type; 176393704ac5SQing Li if ((lle->la_flags & LLE_VALID) == LLE_VALID) { 176493704ac5SQing Li sdl->sdl_alen = ifp->if_addrlen; 17654fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); 176693704ac5SQing Li } else { 176793704ac5SQing Li sdl->sdl_alen = 0; 176893704ac5SQing Li bzero(LLADDR(sdl), ifp->if_addrlen); 176993704ac5SQing Li } 17706e6b3f7cSQing Li 17716e6b3f7cSQing Li arpc.rtm.rtm_rmx.rmx_expire = 17726e6b3f7cSQing Li lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; 17738eca593cSQing Li arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); 17746e6b3f7cSQing Li if (lle->la_flags & LLE_STATIC) 17756e6b3f7cSQing Li arpc.rtm.rtm_flags |= RTF_STATIC; 17764a336ef4SAlexander V. Chernikov if (lle->la_flags & LLE_IFADDR) 17774a336ef4SAlexander V. Chernikov arpc.rtm.rtm_flags |= RTF_PINNED; 17786e6b3f7cSQing Li arpc.rtm.rtm_index = ifp->if_index; 17796e6b3f7cSQing Li error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); 178011cdad98SAlexander V. Chernikov 178111cdad98SAlexander V. Chernikov return (error); 17826e6b3f7cSQing Li } 17836e6b3f7cSQing Li 178477001f9bSKUROSAWA Takahiro static void 178577001f9bSKUROSAWA Takahiro in_lltable_post_resolved(struct lltable *llt, struct llentry *lle) 178677001f9bSKUROSAWA Takahiro { 178777001f9bSKUROSAWA Takahiro struct ifnet *ifp = llt->llt_ifp; 178877001f9bSKUROSAWA Takahiro 178977001f9bSKUROSAWA Takahiro /* gratuitous ARP */ 179077001f9bSKUROSAWA Takahiro if ((lle->la_flags & LLE_PUB) != 0) 179177001f9bSKUROSAWA Takahiro arprequest(ifp, &lle->r_l3addr.addr4, &lle->r_l3addr.addr4, 179277001f9bSKUROSAWA Takahiro lle->ll_addr); 179377001f9bSKUROSAWA Takahiro } 179477001f9bSKUROSAWA Takahiro 17953a749863SAlexander V. Chernikov static struct lltable * 17963a749863SAlexander V. Chernikov in_lltattach(struct ifnet *ifp) 17976e6b3f7cSQing Li { 1798d10910e6SBruce M Simpson struct lltable *llt; 17996e6b3f7cSQing Li 18003a749863SAlexander V. Chernikov llt = lltable_allocate_htbl(IN_LLTBL_DEFAULT_HSIZE); 1801721cd2e0SAlexander V. Chernikov llt->llt_af = AF_INET; 1802721cd2e0SAlexander V. Chernikov llt->llt_ifp = ifp; 1803d10910e6SBruce M Simpson 18046e6b3f7cSQing Li llt->llt_lookup = in_lltable_lookup; 18055a255516SAlexander V. Chernikov llt->llt_alloc_entry = in_lltable_alloc; 18063e7a2321SAlexander V. Chernikov llt->llt_delete_entry = in_lltable_delete_entry; 180711cdad98SAlexander V. Chernikov llt->llt_dump_entry = in_lltable_dump_entry; 180811cdad98SAlexander V. Chernikov llt->llt_hash = in_lltable_hash; 180911cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry = in_lltable_fill_sa_entry; 181011cdad98SAlexander V. Chernikov llt->llt_free_entry = in_lltable_free_entry; 181111cdad98SAlexander V. Chernikov llt->llt_match_prefix = in_lltable_match_prefix; 1812f3a3b061SAlexander V. Chernikov llt->llt_mark_used = llentry_mark_used; 181377001f9bSKUROSAWA Takahiro llt->llt_post_resolved = in_lltable_post_resolved; 1814721cd2e0SAlexander V. Chernikov lltable_link(llt); 1815d10910e6SBruce M Simpson 18163a749863SAlexander V. Chernikov return (llt); 18173a749863SAlexander V. Chernikov } 18183a749863SAlexander V. Chernikov 1819ff3a85d3SAlexander V. Chernikov struct lltable * 1820ff3a85d3SAlexander V. Chernikov in_lltable_get(struct ifnet *ifp) 1821ff3a85d3SAlexander V. Chernikov { 1822ff3a85d3SAlexander V. Chernikov struct lltable *llt = NULL; 1823ff3a85d3SAlexander V. Chernikov 1824ff3a85d3SAlexander V. Chernikov void *afdata_ptr = ifp->if_afdata[AF_INET]; 1825ff3a85d3SAlexander V. Chernikov if (afdata_ptr != NULL) 1826ff3a85d3SAlexander V. Chernikov llt = ((struct in_ifinfo *)afdata_ptr)->ii_llt; 1827ff3a85d3SAlexander V. Chernikov return (llt); 1828ff3a85d3SAlexander V. Chernikov } 1829ff3a85d3SAlexander V. Chernikov 18303a749863SAlexander V. Chernikov void * 18313a749863SAlexander V. Chernikov in_domifattach(struct ifnet *ifp) 18323a749863SAlexander V. Chernikov { 18333a749863SAlexander V. Chernikov struct in_ifinfo *ii; 18343a749863SAlexander V. Chernikov 1835721cd2e0SAlexander V. Chernikov ii = malloc(sizeof(struct in_ifinfo), M_IFADDR, M_WAITOK|M_ZERO); 183641cb42a6SAlexander V. Chernikov 18373a749863SAlexander V. Chernikov ii->ii_llt = in_lltattach(ifp); 1838d10910e6SBruce M Simpson ii->ii_igmp = igmp_domifattach(ifp); 1839d10910e6SBruce M Simpson 184041cb42a6SAlexander V. Chernikov return (ii); 18416e6b3f7cSQing Li } 18426e6b3f7cSQing Li 18436e6b3f7cSQing Li void 1844d10910e6SBruce M Simpson in_domifdetach(struct ifnet *ifp, void *aux) 18456e6b3f7cSQing Li { 1846d10910e6SBruce M Simpson struct in_ifinfo *ii = (struct in_ifinfo *)aux; 18476e6b3f7cSQing Li 1848d10910e6SBruce M Simpson igmp_domifdetach(ifp); 1849d10910e6SBruce M Simpson lltable_free(ii->ii_llt); 1850d10910e6SBruce M Simpson free(ii, M_IFADDR); 18516e6b3f7cSQing Li } 1852