2022-11-25 11:39:32 +03:00
|
|
|
/* $NetBSD: in.c,v 1.247 2022/11/25 08:39:32 knakahara Exp $ */
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2002-06-09 20:33:36 +04:00
|
|
|
*
|
1999-07-01 12:12:45 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2002-06-09 20:33:36 +04:00
|
|
|
*
|
1999-07-01 12:12:45 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
1998-12-19 05:46:12 +03:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Public Access Networks Corporation ("Panix"). It was developed under
|
|
|
|
* contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1994-05-13 10:02:48 +04:00
|
|
|
* Copyright (c) 1982, 1986, 1991, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1993-03-21 12:45:37 +03:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1998-01-05 13:31:44 +03:00
|
|
|
* @(#)in.c 8.4 (Berkeley) 1/9/95
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-13 03:32:34 +03:00
|
|
|
#include <sys/cdefs.h>
|
2022-11-25 11:39:32 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.247 2022/11/25 08:39:32 knakahara Exp $");
|
2001-11-13 03:32:34 +03:00
|
|
|
|
2015-05-02 23:22:12 +03:00
|
|
|
#include "arp.h"
|
2015-08-25 01:21:26 +03:00
|
|
|
|
|
|
|
#ifdef _KERNEL_OPT
|
1998-07-05 04:51:04 +04:00
|
|
|
#include "opt_inet.h"
|
1999-06-26 10:16:47 +04:00
|
|
|
#include "opt_inet_conf.h"
|
1998-01-12 06:02:48 +03:00
|
|
|
#include "opt_mrouting.h"
|
2016-10-18 10:30:30 +03:00
|
|
|
#include "opt_net_mpsafe.h"
|
2015-08-25 01:21:26 +03:00
|
|
|
#endif
|
1998-01-12 06:02:48 +03:00
|
|
|
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/ioctl.h>
|
1994-05-13 10:02:48 +04:00
|
|
|
#include <sys/errno.h>
|
2015-05-02 17:41:32 +03:00
|
|
|
#include <sys/kernel.h>
|
1994-05-13 10:02:48 +04:00
|
|
|
#include <sys/malloc.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
2006-11-13 08:13:38 +03:00
|
|
|
#include <sys/sysctl.h>
|
1996-02-14 02:40:59 +03:00
|
|
|
#include <sys/systm.h>
|
1996-05-22 17:54:55 +04:00
|
|
|
#include <sys/proc.h>
|
2002-02-22 00:59:16 +03:00
|
|
|
#include <sys/syslog.h>
|
2006-05-15 01:19:33 +04:00
|
|
|
#include <sys/kauth.h>
|
2015-08-31 11:02:44 +03:00
|
|
|
#include <sys/kmem.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
|
First step of random number subsystem rework described in
<20111022023242.BA26F14A158@mail.netbsd.org>. This change includes
the following:
An initial cleanup and minor reorganization of the entropy pool
code in sys/dev/rnd.c and sys/dev/rndpool.c. Several bugs are
fixed. Some effort is made to accumulate entropy more quickly at
boot time.
A generic interface, "rndsink", is added, for stream generators to
request that they be re-keyed with good quality entropy from the pool
as soon as it is available.
The arc4random()/arc4randbytes() implementation in libkern is
adjusted to use the rndsink interface for rekeying, which helps
address the problem of low-quality keys at boot time.
An implementation of the FIPS 140-2 statistical tests for random
number generator quality is provided (libkern/rngtest.c). This
is based on Greg Rose's implementation from Qualcomm.
A new random stream generator, nist_ctr_drbg, is provided. It is
based on an implementation of the NIST SP800-90 CTR_DRBG by
Henric Jungheim. This generator users AES in a modified counter
mode to generate a backtracking-resistant random stream.
An abstraction layer, "cprng", is provided for in-kernel consumers
of randomness. The arc4random/arc4randbytes API is deprecated for
in-kernel use. It is replaced by "cprng_strong". The current
cprng_fast implementation wraps the existing arc4random
implementation. The current cprng_strong implementation wraps the
new CTR_DRBG implementation. Both interfaces are rekeyed from
the entropy pool automatically at intervals justifiable from best
current cryptographic practice.
In some quick tests, cprng_fast() is about the same speed as
the old arc4randbytes(), and cprng_strong() is about 20% faster
than rnd_extract_data(). Performance is expected to improve.
The AES code in src/crypto/rijndael is no longer an optional
kernel component, as it is required by cprng_strong, which is
not an optional kernel component.
The entropy pool output is subjected to the rngtest tests at
startup time; if it fails, the system will reboot. There is
approximately a 3/10000 chance of a false positive from these
tests. Entropy pool _input_ from hardware random numbers is
subjected to the rngtest tests at attach time, as well as the
FIPS continuous-output test, to detect bad or stuck hardware
RNGs; if any are detected, they are detached, but the system
continues to run.
A problem with rndctl(8) is fixed -- datastructures with
pointers in arrays are no longer passed to userspace (this
was not a security problem, but rather a major issue for
compat32). A new kernel will require a new rndctl.
The sysctl kern.arandom() and kern.urandom() nodes are hooked
up to the new generators, but the /dev/*random pseudodevices
are not, yet.
Manual pages for the new kernel interfaces are forthcoming.
2011-11-20 02:51:18 +04:00
|
|
|
#include <sys/cprng.h>
|
|
|
|
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
2013-06-30 01:06:57 +04:00
|
|
|
#include <net/pfil.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
|
2015-08-31 11:05:20 +03:00
|
|
|
#include <net/if_arp.h>
|
1997-03-15 21:09:08 +03:00
|
|
|
#include <net/if_ether.h>
|
2015-08-31 11:02:44 +03:00
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/if_llatbl.h>
|
|
|
|
#include <net/if_dl.h>
|
1997-03-15 21:09:08 +03:00
|
|
|
|
1994-05-13 10:02:48 +04:00
|
|
|
#include <netinet/in_systm.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
2003-06-15 06:49:32 +04:00
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_var.h>
|
2006-11-13 08:13:38 +03:00
|
|
|
#include <netinet/in_ifattach.h>
|
2003-06-15 06:49:32 +04:00
|
|
|
#include <netinet/in_pcb.h>
|
2015-08-31 11:02:44 +03:00
|
|
|
#include <netinet/in_selsrc.h>
|
1997-03-15 21:09:08 +03:00
|
|
|
#include <netinet/if_inarp.h>
|
1995-06-01 01:50:34 +04:00
|
|
|
#include <netinet/ip_mroute.h>
|
1996-02-14 02:40:59 +03:00
|
|
|
#include <netinet/igmp_var.h>
|
1994-01-09 04:06:02 +03:00
|
|
|
|
2006-11-13 08:13:38 +03:00
|
|
|
#ifdef IPSELSRC
|
|
|
|
#include <netinet/in_selsrc.h>
|
|
|
|
#endif
|
|
|
|
|
2014-05-23 02:01:12 +04:00
|
|
|
static u_int in_mask2len(struct in_addr *);
|
|
|
|
static int in_lifaddr_ioctl(struct socket *, u_long, void *,
|
2014-07-01 09:49:18 +04:00
|
|
|
struct ifnet *);
|
1999-07-01 12:12:45 +04:00
|
|
|
|
2016-12-06 10:01:47 +03:00
|
|
|
static void in_addrhash_insert_locked(struct in_ifaddr *);
|
|
|
|
static void in_addrhash_remove_locked(struct in_ifaddr *);
|
|
|
|
|
2014-05-23 02:01:12 +04:00
|
|
|
static int in_addprefix(struct in_ifaddr *, int);
|
2016-09-29 17:18:38 +03:00
|
|
|
static void in_scrubaddr(struct in_ifaddr *);
|
2014-05-23 02:01:12 +04:00
|
|
|
static int in_scrubprefix(struct in_ifaddr *);
|
|
|
|
static void in_sysctl_init(struct sysctllog **);
|
2001-07-22 20:18:31 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
#ifndef SUBNETSARELOCAL
|
|
|
|
#define SUBNETSARELOCAL 1
|
|
|
|
#endif
|
1999-06-26 10:16:47 +04:00
|
|
|
|
|
|
|
#ifndef HOSTZEROBROADCAST
|
2016-05-27 19:44:15 +03:00
|
|
|
#define HOSTZEROBROADCAST 0
|
1999-06-26 10:16:47 +04:00
|
|
|
#endif
|
|
|
|
|
2014-05-30 03:02:48 +04:00
|
|
|
/* Note: 61, 127, 251, 509, 1021, 2039 are good. */
|
|
|
|
#ifndef IN_MULTI_HASH_SIZE
|
|
|
|
#define IN_MULTI_HASH_SIZE 509
|
|
|
|
#endif
|
|
|
|
|
2014-05-23 02:01:12 +04:00
|
|
|
static int subnetsarelocal = SUBNETSARELOCAL;
|
|
|
|
static int hostzeroisbroadcast = HOSTZEROBROADCAST;
|
1996-09-06 09:07:43 +04:00
|
|
|
|
2000-10-08 06:05:47 +04:00
|
|
|
/*
|
2000-10-08 13:15:28 +04:00
|
|
|
* This list is used to keep track of in_multi chains which belong to
|
|
|
|
* deleted interface addresses. We use in_ifaddr so that a chain head
|
|
|
|
* won't be deallocated until all multicast address record are deleted.
|
2000-10-08 06:05:47 +04:00
|
|
|
*/
|
2014-05-30 03:02:48 +04:00
|
|
|
|
|
|
|
LIST_HEAD(in_multihashhead, in_multi); /* Type of the hash head */
|
2014-05-23 02:01:12 +04:00
|
|
|
|
|
|
|
static struct pool inmulti_pool;
|
|
|
|
static u_int in_multientries;
|
2014-05-30 03:02:48 +04:00
|
|
|
static struct in_multihashhead *in_multihashtbl;
|
|
|
|
static u_long in_multihash;
|
|
|
|
static krwlock_t in_multilock;
|
|
|
|
|
|
|
|
#define IN_MULTI_HASH(x, ifp) \
|
|
|
|
(in_multihashtbl[(u_long)((x) ^ (ifp->if_index)) % IN_MULTI_HASH_SIZE])
|
2014-05-23 02:01:12 +04:00
|
|
|
|
2016-07-06 11:42:34 +03:00
|
|
|
/* XXX DEPRECATED. Keep them to avoid breaking kvm(3) users. */
|
2014-05-23 02:01:12 +04:00
|
|
|
struct in_ifaddrhashhead * in_ifaddrhashtbl;
|
|
|
|
u_long in_ifaddrhash;
|
|
|
|
struct in_ifaddrhead in_ifaddrhead;
|
2016-08-01 06:15:30 +03:00
|
|
|
static kmutex_t in_ifaddr_lock;
|
2014-05-23 02:01:12 +04:00
|
|
|
|
2016-11-18 13:38:55 +03:00
|
|
|
pserialize_t in_ifaddrhash_psz;
|
2016-07-06 08:27:52 +03:00
|
|
|
struct pslist_head * in_ifaddrhashtbl_pslist;
|
|
|
|
u_long in_ifaddrhash_pslist;
|
2016-07-06 11:42:34 +03:00
|
|
|
struct pslist_head in_ifaddrhead_pslist;
|
2016-07-06 08:27:52 +03:00
|
|
|
|
2014-05-23 02:01:12 +04:00
|
|
|
void
|
|
|
|
in_init(void)
|
|
|
|
{
|
|
|
|
pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl",
|
|
|
|
NULL, IPL_SOFTNET);
|
|
|
|
TAILQ_INIT(&in_ifaddrhead);
|
2016-07-06 11:42:34 +03:00
|
|
|
PSLIST_INIT(&in_ifaddrhead_pslist);
|
2014-05-23 02:01:12 +04:00
|
|
|
|
|
|
|
in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true,
|
|
|
|
&in_ifaddrhash);
|
2016-08-01 06:15:30 +03:00
|
|
|
|
2016-11-18 13:38:55 +03:00
|
|
|
in_ifaddrhash_psz = pserialize_create();
|
2016-07-06 08:27:52 +03:00
|
|
|
in_ifaddrhashtbl_pslist = hashinit(IN_IFADDR_HASH_SIZE, HASH_PSLIST,
|
|
|
|
true, &in_ifaddrhash_pslist);
|
2016-08-01 06:15:30 +03:00
|
|
|
mutex_init(&in_ifaddr_lock, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
|
2014-05-23 02:01:12 +04:00
|
|
|
in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true,
|
|
|
|
&in_multihash);
|
2014-05-30 03:02:48 +04:00
|
|
|
rw_init(&in_multilock);
|
2014-05-23 02:01:12 +04:00
|
|
|
|
|
|
|
in_sysctl_init(NULL);
|
|
|
|
}
|
2000-10-08 06:05:47 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Return 1 if an internet address is for a ``local'' host
|
|
|
|
* (one to which we have a connection). If subnetsarelocal
|
|
|
|
* is true, this includes other subnets of the local net.
|
|
|
|
* Otherwise, it includes only the directly-connected (sub)nets.
|
|
|
|
*/
|
1994-01-09 04:06:02 +03:00
|
|
|
int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_localaddr(struct in_addr in)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct in_ifaddr *ia;
|
2016-08-01 06:15:30 +03:00
|
|
|
int localaddr = 0;
|
|
|
|
int s = pserialize_read_enter();
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
if (subnetsarelocal) {
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(ia) {
|
2016-08-01 06:15:30 +03:00
|
|
|
if ((in.s_addr & ia->ia_netmask) == ia->ia_net) {
|
|
|
|
localaddr = 1;
|
|
|
|
break;
|
|
|
|
}
|
2016-07-06 11:42:34 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
} else {
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(ia) {
|
2016-08-01 06:15:30 +03:00
|
|
|
if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet) {
|
|
|
|
localaddr = 1;
|
|
|
|
break;
|
|
|
|
}
|
2016-07-06 11:42:34 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
|
|
|
return localaddr;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2017-08-10 07:31:58 +03:00
|
|
|
/*
|
|
|
|
* like in_localaddr() but can specify ifp.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
in_direct(struct in_addr in, struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
int localaddr = 0;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
KASSERT(ifp != NULL);
|
|
|
|
|
|
|
|
#define ia (ifatoia(ifa))
|
|
|
|
s = pserialize_read_enter();
|
|
|
|
if (subnetsarelocal) {
|
|
|
|
IFADDR_READER_FOREACH(ifa, ifp) {
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET &&
|
|
|
|
((in.s_addr & ia->ia_netmask) == ia->ia_net)) {
|
|
|
|
localaddr = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
IFADDR_READER_FOREACH(ifa, ifp) {
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET &&
|
|
|
|
(in.s_addr & ia->ia_subnetmask) == ia->ia_subnet) {
|
|
|
|
localaddr = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
|
|
|
return localaddr;
|
|
|
|
#undef ia
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Determine whether an IP address is in a reserved set of addresses
|
|
|
|
* that may not be forwarded, or whether datagrams to that destination
|
|
|
|
* may be forwarded.
|
|
|
|
*/
|
1994-01-09 04:06:02 +03:00
|
|
|
int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_canforward(struct in_addr in)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
u_int32_t net;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1995-06-02 01:35:34 +04:00
|
|
|
if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
|
1993-03-21 12:45:37 +03:00
|
|
|
return (0);
|
1995-06-02 01:35:34 +04:00
|
|
|
if (IN_CLASSA(in.s_addr)) {
|
|
|
|
net = in.s_addr & IN_CLASSA_NET;
|
|
|
|
if (net == 0 || net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
|
1993-03-21 12:45:37 +03:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
1994-05-13 10:02:48 +04:00
|
|
|
/*
|
|
|
|
* Trim a mask in a sockaddr
|
|
|
|
*/
|
|
|
|
void
|
2005-02-03 06:49:01 +03:00
|
|
|
in_socktrim(struct sockaddr_in *ap)
|
1994-05-13 10:02:48 +04:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
char *cplim = (char *) &ap->sin_addr;
|
|
|
|
char *cp = (char *) (&ap->sin_addr + 1);
|
1994-05-13 10:02:48 +04:00
|
|
|
|
|
|
|
ap->sin_len = 0;
|
1994-11-03 17:57:35 +03:00
|
|
|
while (--cp >= cplim)
|
1994-05-13 10:02:48 +04:00
|
|
|
if (*cp) {
|
|
|
|
(ap)->sin_len = cp - (char *) (ap) + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-07-24 01:26:40 +04:00
|
|
|
/*
|
|
|
|
* Maintain the "in_maxmtu" variable, which is the largest
|
|
|
|
* mtu for non-local interfaces with AF_INET addresses assigned
|
|
|
|
* to them that are up.
|
|
|
|
*/
|
|
|
|
unsigned long in_maxmtu;
|
|
|
|
|
|
|
|
void
|
2005-02-03 06:49:01 +03:00
|
|
|
in_setmaxmtu(void)
|
1997-07-24 01:26:40 +04:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct in_ifaddr *ia;
|
|
|
|
struct ifnet *ifp;
|
1997-07-24 01:26:40 +04:00
|
|
|
unsigned long maxmtu = 0;
|
2016-08-01 06:15:30 +03:00
|
|
|
int s = pserialize_read_enter();
|
1997-07-24 01:26:40 +04:00
|
|
|
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(ia) {
|
1997-07-24 01:26:40 +04:00
|
|
|
if ((ifp = ia->ia_ifp) == 0)
|
|
|
|
continue;
|
|
|
|
if ((ifp->if_flags & (IFF_UP|IFF_LOOPBACK)) != IFF_UP)
|
|
|
|
continue;
|
|
|
|
if (ifp->if_mtu > maxmtu)
|
1998-02-13 21:21:38 +03:00
|
|
|
maxmtu = ifp->if_mtu;
|
1997-07-24 01:26:40 +04:00
|
|
|
}
|
|
|
|
if (maxmtu)
|
|
|
|
in_maxmtu = maxmtu;
|
2016-08-01 06:15:30 +03:00
|
|
|
pserialize_read_exit(s);
|
1997-07-24 01:26:40 +04:00
|
|
|
}
|
|
|
|
|
2002-11-07 10:15:19 +03:00
|
|
|
static u_int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_mask2len(struct in_addr *mask)
|
1999-07-01 12:12:45 +04:00
|
|
|
{
|
2002-11-07 10:15:19 +03:00
|
|
|
u_int x, y;
|
1999-07-01 12:12:45 +04:00
|
|
|
u_char *p;
|
|
|
|
|
|
|
|
p = (u_char *)mask;
|
|
|
|
for (x = 0; x < sizeof(*mask); x++) {
|
|
|
|
if (p[x] != 0xff)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
y = 0;
|
|
|
|
if (x < sizeof(*mask)) {
|
2008-04-10 22:09:14 +04:00
|
|
|
for (y = 0; y < NBBY; y++) {
|
1999-07-01 12:12:45 +04:00
|
|
|
if ((p[x] & (0x80 >> y)) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-04-10 22:09:14 +04:00
|
|
|
return x * NBBY + y;
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
|
2020-08-21 00:21:31 +03:00
|
|
|
void
|
2005-02-03 06:49:01 +03:00
|
|
|
in_len2mask(struct in_addr *mask, u_int len)
|
1999-07-01 12:12:45 +04:00
|
|
|
{
|
2002-11-07 10:15:19 +03:00
|
|
|
u_int i;
|
1999-07-01 12:12:45 +04:00
|
|
|
u_char *p;
|
|
|
|
|
|
|
|
p = (u_char *)mask;
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(mask, 0, sizeof(*mask));
|
2008-04-10 22:09:14 +04:00
|
|
|
for (i = 0; i < len / NBBY; i++)
|
1999-07-01 12:12:45 +04:00
|
|
|
p[i] = 0xff;
|
2008-04-10 22:09:14 +04:00
|
|
|
if (len % NBBY)
|
|
|
|
p[i] = (0xff00 >> (len % NBBY)) & 0xff;
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Generic internet control operations (ioctl's).
|
|
|
|
* Ifp is 0 if not an interface-specific ioctl.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
2016-07-28 12:03:50 +03:00
|
|
|
static int
|
|
|
|
in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct ifreq *ifr = (struct ifreq *)data;
|
2009-12-07 21:38:55 +03:00
|
|
|
struct in_ifaddr *ia = NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct in_aliasreq *ifra = (struct in_aliasreq *)data;
|
2016-09-29 18:04:17 +03:00
|
|
|
struct sockaddr_in oldaddr, *new_dstaddr;
|
1993-03-21 12:45:37 +03:00
|
|
|
int error, hostIsNew, maskIsNew;
|
2004-08-08 13:52:41 +04:00
|
|
|
int newifaddr = 0;
|
2016-06-30 04:34:53 +03:00
|
|
|
bool run_hook = false;
|
|
|
|
bool need_reinsert = false;
|
2016-08-01 06:15:30 +03:00
|
|
|
struct psref psref;
|
|
|
|
int bound;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1999-07-01 12:12:45 +04:00
|
|
|
switch (cmd) {
|
|
|
|
case SIOCALIFADDR:
|
|
|
|
case SIOCDLIFADDR:
|
|
|
|
case SIOCGLIFADDR:
|
2007-04-15 10:15:58 +04:00
|
|
|
if (ifp == NULL)
|
1999-07-01 12:12:45 +04:00
|
|
|
return EINVAL;
|
2014-07-01 09:49:18 +04:00
|
|
|
return in_lifaddr_ioctl(so, cmd, data, ifp);
|
Make ifconfig(8) set and display preference numbers for IPv6
addresses. Make the kernel support SIOC[SG]IFADDRPREF for IPv6
interface addresses.
In in6ifa_ifpforlinklocal(), consult preference numbers before
making an otherwise arbitrary choice of in6_ifaddr. Otherwise,
preference numbers are *not* consulted by the kernel, but that will
be rather easy for somebody with a little bit of free time to fix.
Please note that setting the preference number for a link-local
IPv6 address does not work right, yet, but that ought to be fixed
soon.
In support of the changes above,
1 Add a method to struct domain for "externalizing" a sockaddr, and
provide an implementation for IPv6. Expect more work in this area: it
may be more proper to say that the IPv6 implementation "internalizes"
a sockaddr. Add sockaddr_externalize().
2 Add a subroutine, sofamily(), that returns a struct socket's address
family or AF_UNSPEC.
3 Make a lot of IPv4-specific code generic, and move it from
sys/netinet/ to sys/net/ for re-use by IPv6 parts of the kernel and
ifconfig(8).
2009-09-12 02:06:29 +04:00
|
|
|
case SIOCGIFADDRPREF:
|
|
|
|
case SIOCSIFADDRPREF:
|
|
|
|
if (ifp == NULL)
|
|
|
|
return EINVAL;
|
2014-07-01 09:49:18 +04:00
|
|
|
return ifaddrpref_ioctl(so, cmd, data, ifp);
|
2020-09-11 18:22:12 +03:00
|
|
|
#if NARP > 0
|
|
|
|
case SIOCGNBRINFO:
|
|
|
|
{
|
|
|
|
struct in_nbrinfo *nbi = (struct in_nbrinfo *)data;
|
|
|
|
struct llentry *ln;
|
|
|
|
struct in_addr nb_addr = nbi->addr; /* make local for safety */
|
|
|
|
|
|
|
|
ln = arplookup(ifp, &nb_addr, NULL, 0);
|
|
|
|
if (ln == NULL)
|
|
|
|
return EINVAL;
|
|
|
|
nbi->state = ln->ln_state;
|
|
|
|
nbi->asked = ln->ln_asked;
|
|
|
|
nbi->expire = ln->ln_expire ?
|
|
|
|
time_mono_to_wall(ln->ln_expire) : 0;
|
|
|
|
LLE_RUNLOCK(ln);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
bound = curlwp_bind();
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Find address for this interface, if it exists.
|
|
|
|
*/
|
2007-04-15 10:15:58 +04:00
|
|
|
if (ifp != NULL)
|
2016-08-01 06:15:30 +03:00
|
|
|
ia = in_get_ia_from_ifp_psref(ifp, &psref);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2015-05-02 18:22:03 +03:00
|
|
|
hostIsNew = 1; /* moved here to appease gcc */
|
1993-03-21 12:45:37 +03:00
|
|
|
switch (cmd) {
|
|
|
|
case SIOCAIFADDR:
|
|
|
|
case SIOCDIFADDR:
|
1998-09-06 21:52:01 +04:00
|
|
|
case SIOCGIFALIAS:
|
2015-05-02 17:41:32 +03:00
|
|
|
case SIOCGIFAFLAG_IN:
|
2016-07-06 08:27:52 +03:00
|
|
|
if (ifra->ifra_addr.sin_family == AF_INET) {
|
2016-08-01 06:15:30 +03:00
|
|
|
int s;
|
|
|
|
|
|
|
|
if (ia != NULL)
|
|
|
|
ia4_release(ia, &psref);
|
|
|
|
s = pserialize_read_enter();
|
2016-07-06 08:27:52 +03:00
|
|
|
IN_ADDRHASH_READER_FOREACH(ia,
|
|
|
|
ifra->ifra_addr.sin_addr.s_addr) {
|
2007-04-15 10:15:58 +04:00
|
|
|
if (ia->ia_ifp == ifp &&
|
1998-02-13 21:21:38 +03:00
|
|
|
in_hosteq(ia->ia_addr.sin_addr,
|
|
|
|
ifra->ifra_addr.sin_addr))
|
1996-05-22 18:42:27 +04:00
|
|
|
break;
|
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia != NULL)
|
|
|
|
ia4_acquire(ia, &psref);
|
|
|
|
pserialize_read_exit(s);
|
2016-07-06 08:27:52 +03:00
|
|
|
}
|
2015-05-02 17:41:32 +03:00
|
|
|
if ((cmd == SIOCDIFADDR ||
|
|
|
|
cmd == SIOCGIFALIAS ||
|
|
|
|
cmd == SIOCGIFAFLAG_IN) &&
|
2016-08-01 06:15:30 +03:00
|
|
|
ia == NULL) {
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
goto out;
|
|
|
|
}
|
2005-09-28 21:56:27 +04:00
|
|
|
|
|
|
|
if (cmd == SIOCDIFADDR &&
|
|
|
|
ifra->ifra_addr.sin_family == AF_UNSPEC) {
|
|
|
|
ifra->ifra_addr.sin_family = AF_INET;
|
2000-02-25 11:51:35 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case SIOCSIFADDR:
|
2015-05-02 17:41:32 +03:00
|
|
|
if (ia == NULL || ia->ia_addr.sin_family != AF_INET)
|
|
|
|
;
|
|
|
|
else if (ifra->ifra_addr.sin_len == 0) {
|
|
|
|
ifra->ifra_addr = ia->ia_addr;
|
|
|
|
hostIsNew = 0;
|
|
|
|
} else if (in_hosteq(ia->ia_addr.sin_addr,
|
|
|
|
ifra->ifra_addr.sin_addr))
|
|
|
|
hostIsNew = 0;
|
2018-04-24 04:32:30 +03:00
|
|
|
if (ifra->ifra_addr.sin_family != AF_INET) {
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
goto out;
|
|
|
|
}
|
2015-05-02 17:41:32 +03:00
|
|
|
/* FALLTHROUGH */
|
1993-03-21 12:45:37 +03:00
|
|
|
case SIOCSIFDSTADDR:
|
2018-04-24 04:32:30 +03:00
|
|
|
if (cmd == SIOCSIFDSTADDR &&
|
|
|
|
ifreq_getaddr(cmd, ifr)->sa_family != AF_INET) {
|
2016-08-01 06:15:30 +03:00
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
goto out;
|
|
|
|
}
|
2000-02-25 11:51:35 +03:00
|
|
|
/* FALLTHROUGH */
|
2000-02-25 10:11:38 +03:00
|
|
|
case SIOCSIFNETMASK:
|
2007-04-15 10:15:58 +04:00
|
|
|
if (ifp == NULL)
|
1998-09-28 16:32:43 +04:00
|
|
|
panic("in_control");
|
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
if (cmd == SIOCGIFALIAS || cmd == SIOCGIFAFLAG_IN)
|
1998-09-28 16:32:43 +04:00
|
|
|
break;
|
|
|
|
|
2004-08-08 13:52:41 +04:00
|
|
|
if (ia == NULL &&
|
2016-08-01 06:15:30 +03:00
|
|
|
(cmd == SIOCSIFNETMASK || cmd == SIOCSIFDSTADDR)) {
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
goto out;
|
|
|
|
}
|
2004-08-08 13:52:41 +04:00
|
|
|
|
2021-09-21 17:59:14 +03:00
|
|
|
if (kauth_authorize_network(kauth_cred_get(),
|
|
|
|
KAUTH_NETWORK_INTERFACE,
|
2006-10-25 16:48:44 +04:00
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
|
2016-08-01 06:15:30 +03:00
|
|
|
NULL) != 0) {
|
|
|
|
error = EPERM;
|
|
|
|
goto out;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2009-12-07 21:38:55 +03:00
|
|
|
if (ia == NULL) {
|
2008-12-17 23:51:31 +03:00
|
|
|
ia = malloc(sizeof(*ia), M_IFADDR, M_WAITOK|M_ZERO);
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia == NULL) {
|
|
|
|
error = ENOBUFS;
|
|
|
|
goto out;
|
|
|
|
}
|
1995-06-04 08:35:29 +04:00
|
|
|
ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
|
|
|
|
ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
|
|
|
|
ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
|
2006-11-13 08:13:38 +03:00
|
|
|
#ifdef IPSELSRC
|
|
|
|
ia->ia_ifa.ifa_getifa = in_getifa;
|
|
|
|
#else /* IPSELSRC */
|
|
|
|
ia->ia_ifa.ifa_getifa = NULL;
|
|
|
|
#endif /* IPSELSRC */
|
1993-03-21 12:45:37 +03:00
|
|
|
ia->ia_sockmask.sin_len = 8;
|
2014-12-01 20:07:43 +03:00
|
|
|
ia->ia_sockmask.sin_family = AF_INET;
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ifp->if_flags & IFF_BROADCAST) {
|
|
|
|
ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
|
|
|
|
ia->ia_broadaddr.sin_family = AF_INET;
|
|
|
|
}
|
|
|
|
ia->ia_ifp = ifp;
|
First step of random number subsystem rework described in
<20111022023242.BA26F14A158@mail.netbsd.org>. This change includes
the following:
An initial cleanup and minor reorganization of the entropy pool
code in sys/dev/rnd.c and sys/dev/rndpool.c. Several bugs are
fixed. Some effort is made to accumulate entropy more quickly at
boot time.
A generic interface, "rndsink", is added, for stream generators to
request that they be re-keyed with good quality entropy from the pool
as soon as it is available.
The arc4random()/arc4randbytes() implementation in libkern is
adjusted to use the rndsink interface for rekeying, which helps
address the problem of low-quality keys at boot time.
An implementation of the FIPS 140-2 statistical tests for random
number generator quality is provided (libkern/rngtest.c). This
is based on Greg Rose's implementation from Qualcomm.
A new random stream generator, nist_ctr_drbg, is provided. It is
based on an implementation of the NIST SP800-90 CTR_DRBG by
Henric Jungheim. This generator users AES in a modified counter
mode to generate a backtracking-resistant random stream.
An abstraction layer, "cprng", is provided for in-kernel consumers
of randomness. The arc4random/arc4randbytes API is deprecated for
in-kernel use. It is replaced by "cprng_strong". The current
cprng_fast implementation wraps the existing arc4random
implementation. The current cprng_strong implementation wraps the
new CTR_DRBG implementation. Both interfaces are rekeyed from
the entropy pool automatically at intervals justifiable from best
current cryptographic practice.
In some quick tests, cprng_fast() is about the same speed as
the old arc4randbytes(), and cprng_strong() is about 20% faster
than rnd_extract_data(). Performance is expected to improve.
The AES code in src/crypto/rijndael is no longer an optional
kernel component, as it is required by cprng_strong, which is
not an optional kernel component.
The entropy pool output is subjected to the rngtest tests at
startup time; if it fails, the system will reboot. There is
approximately a 3/10000 chance of a false positive from these
tests. Entropy pool _input_ from hardware random numbers is
subjected to the rngtest tests at attach time, as well as the
FIPS continuous-output test, to detect bad or stuck hardware
RNGs; if any are detected, they are detached, but the system
continues to run.
A problem with rndctl(8) is fixed -- datastructures with
pointers in arrays are no longer passed to userspace (this
was not a security problem, but rather a major issue for
compat32). A new kernel will require a new rndctl.
The sysctl kern.arandom() and kern.urandom() nodes are hooked
up to the new generators, but the /dev/*random pseudodevices
are not, yet.
Manual pages for the new kernel interfaces are forthcoming.
2011-11-20 02:51:18 +04:00
|
|
|
ia->ia_idsalt = cprng_fast32() % 65535;
|
1995-06-12 04:46:47 +04:00
|
|
|
LIST_INIT(&ia->ia_multiaddrs);
|
2016-07-06 08:27:52 +03:00
|
|
|
IN_ADDRHASH_ENTRY_INIT(ia);
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_ENTRY_INIT(ia);
|
2016-08-01 06:15:30 +03:00
|
|
|
ifa_psref_init(&ia->ia_ifa);
|
2017-05-25 05:43:43 +03:00
|
|
|
/*
|
|
|
|
* We need a reference to make ia survive over in_ifinit
|
|
|
|
* that does ifaref and ifafree.
|
|
|
|
*/
|
|
|
|
ifaref(&ia->ia_ifa);
|
2016-06-30 04:34:53 +03:00
|
|
|
|
2004-08-08 13:52:41 +04:00
|
|
|
newifaddr = 1;
|
2002-10-22 06:28:47 +04:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFBRDADDR:
|
2021-09-21 17:59:14 +03:00
|
|
|
if (kauth_authorize_network(kauth_cred_get(),
|
|
|
|
KAUTH_NETWORK_INTERFACE,
|
2006-10-25 16:48:44 +04:00
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
|
2016-08-01 06:15:30 +03:00
|
|
|
NULL) != 0) {
|
|
|
|
error = EPERM;
|
|
|
|
goto out;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
|
|
|
case SIOCGIFADDR:
|
|
|
|
case SIOCGIFNETMASK:
|
|
|
|
case SIOCGIFDSTADDR:
|
|
|
|
case SIOCGIFBRDADDR:
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia == NULL) {
|
|
|
|
error = EADDRNOTAVAIL;
|
|
|
|
goto out;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
}
|
2004-08-08 13:52:41 +04:00
|
|
|
error = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
switch (cmd) {
|
|
|
|
|
|
|
|
case SIOCGIFADDR:
|
2007-09-01 08:32:50 +04:00
|
|
|
ifreq_setaddr(cmd, ifr, sintocsa(&ia->ia_addr));
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFBRDADDR:
|
2016-08-01 06:15:30 +03:00
|
|
|
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2007-09-01 08:32:50 +04:00
|
|
|
ifreq_setdstaddr(cmd, ifr, sintocsa(&ia->ia_broadaddr));
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFDSTADDR:
|
2016-08-01 06:15:30 +03:00
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2007-09-01 08:32:50 +04:00
|
|
|
ifreq_setdstaddr(cmd, ifr, sintocsa(&ia->ia_dstaddr));
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFNETMASK:
|
2014-12-01 20:07:43 +03:00
|
|
|
/*
|
|
|
|
* We keep the number of trailing zero bytes the sin_len field
|
|
|
|
* of ia_sockmask, so we fix this before we pass it back to
|
|
|
|
* userland.
|
|
|
|
*/
|
|
|
|
oldaddr = ia->ia_sockmask;
|
|
|
|
oldaddr.sin_len = sizeof(struct sockaddr_in);
|
|
|
|
ifreq_setaddr(cmd, ifr, (const void *)&oldaddr);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFDSTADDR:
|
2016-08-01 06:15:30 +03:00
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
oldaddr = ia->ia_dstaddr;
|
2007-09-01 08:32:50 +04:00
|
|
|
ia->ia_dstaddr = *satocsin(ifreq_getdstaddr(cmd, ifr));
|
2011-10-19 05:52:22 +04:00
|
|
|
if ((error = if_addr_init(ifp, &ia->ia_ifa, false)) != 0) {
|
1993-03-21 12:45:37 +03:00
|
|
|
ia->ia_dstaddr = oldaddr;
|
2016-08-01 06:15:30 +03:00
|
|
|
goto out;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
if (ia->ia_flags & IFA_ROUTE) {
|
1995-06-04 08:35:29 +04:00
|
|
|
ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr);
|
2007-04-15 10:15:58 +04:00
|
|
|
rtinit(&ia->ia_ifa, RTM_DELETE, RTF_HOST);
|
1995-06-04 08:35:29 +04:00
|
|
|
ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
|
2007-04-15 10:15:58 +04:00
|
|
|
rtinit(&ia->ia_ifa, RTM_ADD, RTF_HOST|RTF_UP);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFBRDADDR:
|
2016-08-01 06:15:30 +03:00
|
|
|
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2007-09-01 08:32:50 +04:00
|
|
|
ia->ia_broadaddr = *satocsin(ifreq_getbroadaddr(cmd, ifr));
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFADDR:
|
2016-06-30 04:34:53 +03:00
|
|
|
if (!newifaddr) {
|
2016-12-06 10:01:47 +03:00
|
|
|
in_addrhash_remove(ia);
|
2016-06-30 04:34:53 +03:00
|
|
|
need_reinsert = true;
|
|
|
|
}
|
2016-09-29 18:04:17 +03:00
|
|
|
error = in_ifinit(ifp, ia, satocsin(ifreq_getaddr(cmd, ifr)),
|
|
|
|
NULL, 1);
|
2016-06-30 04:34:53 +03:00
|
|
|
|
|
|
|
run_hook = true;
|
2004-08-08 13:52:41 +04:00
|
|
|
break;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
case SIOCSIFNETMASK:
|
2016-09-29 18:18:18 +03:00
|
|
|
in_scrubprefix(ia);
|
2007-09-01 08:32:50 +04:00
|
|
|
ia->ia_sockmask = *satocsin(ifreq_getaddr(cmd, ifr));
|
2004-07-07 05:39:00 +04:00
|
|
|
ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
|
2016-06-30 04:34:53 +03:00
|
|
|
if (!newifaddr) {
|
2016-12-06 10:01:47 +03:00
|
|
|
in_addrhash_remove(ia);
|
2016-06-30 04:34:53 +03:00
|
|
|
need_reinsert = true;
|
|
|
|
}
|
2016-09-29 18:04:17 +03:00
|
|
|
error = in_ifinit(ifp, ia, NULL, NULL, 0);
|
2004-08-08 13:52:41 +04:00
|
|
|
break;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
case SIOCAIFADDR:
|
|
|
|
maskIsNew = 0;
|
|
|
|
if (ifra->ifra_mask.sin_len) {
|
2016-09-29 18:18:18 +03:00
|
|
|
in_scrubprefix(ia);
|
1993-03-21 12:45:37 +03:00
|
|
|
ia->ia_sockmask = ifra->ifra_mask;
|
1995-06-02 01:35:34 +04:00
|
|
|
ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
|
1993-03-21 12:45:37 +03:00
|
|
|
maskIsNew = 1;
|
|
|
|
}
|
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) &&
|
|
|
|
(ifra->ifra_dstaddr.sin_family == AF_INET)) {
|
2016-09-29 18:04:17 +03:00
|
|
|
new_dstaddr = &ifra->ifra_dstaddr;
|
1993-03-21 12:45:37 +03:00
|
|
|
maskIsNew = 1; /* We lie; but the effect's the same */
|
2016-09-29 18:04:17 +03:00
|
|
|
} else
|
|
|
|
new_dstaddr = NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ifra->ifra_addr.sin_family == AF_INET &&
|
2000-03-12 08:01:16 +03:00
|
|
|
(hostIsNew || maskIsNew)) {
|
2016-06-30 04:34:53 +03:00
|
|
|
if (!newifaddr) {
|
2016-12-06 10:01:47 +03:00
|
|
|
in_addrhash_remove(ia);
|
2016-06-30 04:34:53 +03:00
|
|
|
need_reinsert = true;
|
|
|
|
}
|
2016-09-29 18:04:17 +03:00
|
|
|
error = in_ifinit(ifp, ia, &ifra->ifra_addr,
|
|
|
|
new_dstaddr, 0);
|
2000-03-12 08:01:16 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
if ((ifp->if_flags & IFF_BROADCAST) &&
|
|
|
|
(ifra->ifra_broadaddr.sin_family == AF_INET))
|
|
|
|
ia->ia_broadaddr = ifra->ifra_broadaddr;
|
2016-06-30 04:34:53 +03:00
|
|
|
run_hook = true;
|
2004-08-08 13:52:41 +04:00
|
|
|
break;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1998-09-06 21:52:01 +04:00
|
|
|
case SIOCGIFALIAS:
|
|
|
|
ifra->ifra_mask = ia->ia_sockmask;
|
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) &&
|
|
|
|
(ia->ia_dstaddr.sin_family == AF_INET))
|
|
|
|
ifra->ifra_dstaddr = ia->ia_dstaddr;
|
|
|
|
else if ((ifp->if_flags & IFF_BROADCAST) &&
|
|
|
|
(ia->ia_broadaddr.sin_family == AF_INET))
|
|
|
|
ifra->ifra_broadaddr = ia->ia_broadaddr;
|
|
|
|
else
|
2007-04-15 10:15:58 +04:00
|
|
|
memset(&ifra->ifra_broadaddr, 0,
|
1999-07-01 12:12:45 +04:00
|
|
|
sizeof(ifra->ifra_broadaddr));
|
2004-08-08 13:52:41 +04:00
|
|
|
break;
|
1998-09-06 21:52:01 +04:00
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
case SIOCGIFAFLAG_IN:
|
|
|
|
ifr->ifr_addrflags = ia->ia4_flags;
|
|
|
|
break;
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
case SIOCDIFADDR:
|
2016-08-01 06:15:30 +03:00
|
|
|
ia4_release(ia, &psref);
|
2017-01-03 02:00:25 +03:00
|
|
|
ifaref(&ia->ia_ifa);
|
2007-12-06 02:47:17 +03:00
|
|
|
in_purgeaddr(&ia->ia_ifa);
|
2017-01-03 02:00:25 +03:00
|
|
|
pfil_run_addrhooks(if_pfil, cmd, &ia->ia_ifa);
|
|
|
|
ifafree(&ia->ia_ifa);
|
2016-08-01 06:15:30 +03:00
|
|
|
ia = NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
1995-06-01 01:50:34 +04:00
|
|
|
#ifdef MROUTING
|
|
|
|
case SIOCGETVIFCNT:
|
|
|
|
case SIOCGETSGCNT:
|
2004-08-08 13:52:41 +04:00
|
|
|
error = mrt_ioctl(so, cmd, data);
|
|
|
|
break;
|
1995-06-01 01:50:34 +04:00
|
|
|
#endif /* MROUTING */
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
default:
|
2016-08-01 06:15:30 +03:00
|
|
|
error = ENOTTY;
|
|
|
|
goto out;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2004-08-08 13:52:41 +04:00
|
|
|
|
2016-06-30 04:34:53 +03:00
|
|
|
/*
|
|
|
|
* XXX insert regardless of error to make in_purgeaddr below work.
|
|
|
|
* Need to improve.
|
|
|
|
*/
|
|
|
|
if (newifaddr) {
|
|
|
|
ifaref(&ia->ia_ifa);
|
|
|
|
ifa_insert(ifp, &ia->ia_ifa);
|
2016-08-01 06:15:30 +03:00
|
|
|
|
|
|
|
mutex_enter(&in_ifaddr_lock);
|
|
|
|
TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list);
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_WRITER_INSERT_TAIL(ia);
|
2016-12-06 10:01:47 +03:00
|
|
|
in_addrhash_insert_locked(ia);
|
2017-05-25 05:43:43 +03:00
|
|
|
/* Release a reference that is held just after creation. */
|
|
|
|
ifafree(&ia->ia_ifa);
|
2016-08-01 06:15:30 +03:00
|
|
|
mutex_exit(&in_ifaddr_lock);
|
2016-06-30 04:34:53 +03:00
|
|
|
} else if (need_reinsert) {
|
2016-12-06 10:01:47 +03:00
|
|
|
in_addrhash_insert(ia);
|
2016-06-30 04:34:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (error == 0) {
|
|
|
|
if (run_hook)
|
2017-01-03 02:00:25 +03:00
|
|
|
pfil_run_addrhooks(if_pfil, cmd, &ia->ia_ifa);
|
2016-06-30 04:34:53 +03:00
|
|
|
} else if (newifaddr) {
|
2004-08-08 13:52:41 +04:00
|
|
|
KASSERT(ia != NULL);
|
2007-12-06 02:47:17 +03:00
|
|
|
in_purgeaddr(&ia->ia_ifa);
|
2016-08-01 06:15:30 +03:00
|
|
|
ia = NULL;
|
2004-08-08 13:52:41 +04:00
|
|
|
}
|
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
out:
|
|
|
|
if (!newifaddr && ia != NULL)
|
|
|
|
ia4_release(ia, &psref);
|
|
|
|
curlwp_bindx(bound);
|
2004-08-08 13:52:41 +04:00
|
|
|
return error;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2016-07-28 12:03:50 +03:00
|
|
|
int
|
|
|
|
in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2018-02-24 10:37:08 +03:00
|
|
|
#ifndef NET_MPSAFE
|
|
|
|
KASSERT(KERNEL_LOCKED_P());
|
|
|
|
#endif
|
2016-07-28 12:03:50 +03:00
|
|
|
error = in_control0(so, cmd, data, ifp);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-02-26 12:54:46 +03:00
|
|
|
/* Add ownaddr as loopback rtentry. */
|
|
|
|
static void
|
|
|
|
in_ifaddlocal(struct ifaddr *ifa)
|
|
|
|
{
|
2015-02-26 15:58:36 +03:00
|
|
|
struct in_ifaddr *ia;
|
|
|
|
|
|
|
|
ia = (struct in_ifaddr *)ifa;
|
2022-11-25 11:39:32 +03:00
|
|
|
if ((ia->ia_ifp->if_flags & IFF_UNNUMBERED)) {
|
|
|
|
rt_addrmsg(RTM_NEWADDR, ifa);
|
|
|
|
return;
|
|
|
|
}
|
2015-02-26 15:58:36 +03:00
|
|
|
if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY ||
|
|
|
|
(ia->ia_ifp->if_flags & IFF_POINTOPOINT &&
|
|
|
|
in_hosteq(ia->ia_dstaddr.sin_addr, ia->ia_addr.sin_addr)))
|
|
|
|
{
|
2019-04-29 14:57:22 +03:00
|
|
|
rt_addrmsg(RTM_NEWADDR, ifa);
|
2015-02-26 15:58:36 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-02-26 12:54:46 +03:00
|
|
|
|
|
|
|
rt_ifa_addlocal(ifa);
|
|
|
|
}
|
|
|
|
|
2016-06-23 09:40:48 +03:00
|
|
|
/* Remove loopback entry of ownaddr */
|
2015-02-26 12:54:46 +03:00
|
|
|
static void
|
|
|
|
in_ifremlocal(struct ifaddr *ifa)
|
|
|
|
{
|
|
|
|
struct in_ifaddr *ia, *p;
|
|
|
|
struct ifaddr *alt_ifa = NULL;
|
|
|
|
int ia_count = 0;
|
2016-08-01 06:15:30 +03:00
|
|
|
int s;
|
|
|
|
struct psref psref;
|
|
|
|
int bound = curlwp_bind();
|
2015-02-26 12:54:46 +03:00
|
|
|
|
|
|
|
ia = (struct in_ifaddr *)ifa;
|
2022-11-25 11:39:32 +03:00
|
|
|
if ((ia->ia_ifp->if_flags & IFF_UNNUMBERED)) {
|
|
|
|
rt_addrmsg(RTM_DELADDR, ifa);
|
|
|
|
goto out;
|
|
|
|
}
|
2015-02-26 12:54:46 +03:00
|
|
|
/* Delete the entry if exactly one ifaddr matches the
|
|
|
|
* address, ifa->ifa_addr. */
|
2016-08-01 06:15:30 +03:00
|
|
|
s = pserialize_read_enter();
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(p) {
|
2022-11-25 11:39:32 +03:00
|
|
|
if ((p->ia_ifp->if_flags & IFF_UNNUMBERED))
|
|
|
|
continue;
|
|
|
|
|
2015-02-26 12:54:46 +03:00
|
|
|
if (!in_hosteq(p->ia_addr.sin_addr, ia->ia_addr.sin_addr))
|
|
|
|
continue;
|
|
|
|
if (p->ia_ifp != ia->ia_ifp)
|
|
|
|
alt_ifa = &p->ia_ifa;
|
|
|
|
if (++ia_count > 1 && alt_ifa != NULL)
|
|
|
|
break;
|
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
if (alt_ifa != NULL && ia_count > 1)
|
|
|
|
ifa_acquire(alt_ifa, &psref);
|
|
|
|
pserialize_read_exit(s);
|
2015-02-26 12:54:46 +03:00
|
|
|
|
|
|
|
if (ia_count == 0)
|
2016-08-01 06:15:30 +03:00
|
|
|
goto out;
|
2015-02-26 12:54:46 +03:00
|
|
|
|
|
|
|
rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
|
2016-08-01 06:15:30 +03:00
|
|
|
if (alt_ifa != NULL && ia_count > 1)
|
|
|
|
ifa_release(alt_ifa, &psref);
|
|
|
|
out:
|
|
|
|
curlwp_bindx(bound);
|
2015-02-26 12:54:46 +03:00
|
|
|
}
|
|
|
|
|
2016-09-29 17:18:38 +03:00
|
|
|
static void
|
|
|
|
in_scrubaddr(struct in_ifaddr *ia)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* stop DAD processing */
|
|
|
|
if (ia->ia_dad_stop != NULL)
|
|
|
|
ia->ia_dad_stop(&ia->ia_ifa);
|
|
|
|
|
2016-09-29 18:18:18 +03:00
|
|
|
in_scrubprefix(ia);
|
2016-09-29 17:18:38 +03:00
|
|
|
in_ifremlocal(&ia->ia_ifa);
|
2016-09-29 18:18:18 +03:00
|
|
|
|
2017-03-02 08:31:04 +03:00
|
|
|
mutex_enter(&in_ifaddr_lock);
|
2016-09-29 17:18:38 +03:00
|
|
|
if (ia->ia_allhosts != NULL) {
|
|
|
|
in_delmulti(ia->ia_allhosts);
|
|
|
|
ia->ia_allhosts = NULL;
|
|
|
|
}
|
2017-03-02 08:31:04 +03:00
|
|
|
mutex_exit(&in_ifaddr_lock);
|
2016-09-29 17:18:38 +03:00
|
|
|
}
|
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
/*
|
|
|
|
* Depends on it isn't called in concurrent. It should be guaranteed
|
|
|
|
* by ifa->ifa_ifp's ioctl lock. The possible callers are in_control
|
|
|
|
* and if_purgeaddrs; the former is called iva ifa->ifa_ifp's ioctl
|
|
|
|
* and the latter is called via ifa->ifa_ifp's if_detach. The functions
|
|
|
|
* never be executed in concurrent.
|
|
|
|
*/
|
2000-02-02 01:52:04 +03:00
|
|
|
void
|
2007-12-06 02:47:17 +03:00
|
|
|
in_purgeaddr(struct ifaddr *ifa)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
struct in_ifaddr *ia = (void *) ifa;
|
2016-09-29 17:18:38 +03:00
|
|
|
struct ifnet *ifp = ifa->ifa_ifp;
|
2000-02-02 01:52:04 +03:00
|
|
|
|
2017-12-25 07:41:48 +03:00
|
|
|
/* KASSERT(!ifa_held(ifa)); XXX need ifa_not_held (psref_not_held) */
|
2016-08-01 06:15:30 +03:00
|
|
|
|
Make the routing table and rtcaches MP-safe
See the following descriptions for details.
Proposed on tech-kern and tech-net
Overview
--------
We protect the routing table with a rwock and protect
rtcaches with another rwlock. Each rtentry is protected
from being freed or updated via reference counting and psref.
Global rwlocks
--------------
There are two rwlocks; one for the routing table (rt_lock) and
the other for rtcaches (rtcache_lock). rtcache_lock covers
all existing rtcaches; there may have room for optimizations
(future work).
The locking order is rtcache_lock first and rt_lock is next.
rtentry references
------------------
References to an rtentry is managed with reference counting
and psref. Either of the two mechanisms is used depending on
where a rtentry is obtained. Reference counting is used when
we obtain a rtentry from the routing table directly via
rtalloc1 and rtrequest{,1} while psref is used when we obtain
a rtentry from a rtcache via rtcache_* APIs. In both cases,
a caller can sleep/block with holding an obtained rtentry.
The reasons why we use two different mechanisms are (i) only
using reference counting hurts the performance due to atomic
instructions (rtcache case) (ii) ease of implementation;
applying psref to APIs such rtaloc1 and rtrequest{,1} requires
additional works (adding a local variable and an argument).
We will finally migrate to use only psref but we can do it
when we have a lockless routing table alternative.
Reference counting for rtentry
------------------------------
rt_refcnt now doesn't count permanent references such as for
rt_timers and rtcaches, instead it is used only for temporal
references when obtaining a rtentry via rtalloc1 and rtrequest{,1}.
We can do so because destroying a rtentry always involves
removing references of rt_timers and rtcaches to the rtentry
and we don't need to track such references. This also makes
it easy to wait for readers to release references on deleting
or updating a rtentry, i.e., we can simply wait until the
reference counter is 0 or 1. (If there are permanent references
the counter can be arbitrary.)
rt_ref increments a reference counter of a rtentry and rt_unref
decrements it. rt_ref is called inside APIs (rtalloc1 and
rtrequest{,1} so users don't need to care about it while
users must call rt_unref to an obtained rtentry after using it.
rtfree is removed and we use rt_unref and rt_free instead.
rt_unref now just decrements the counter of a given rtentry
and rt_free just tries to destroy a given rtentry.
See the next section for destructions of rtentries by rt_free.
Destructions of rtentries
-------------------------
We destroy a rtentry only when we call rtrequst{,1}(RTM_DELETE);
the original implementation can destroy in any rtfree where it's
the last reference. If we use reference counting or psref, it's
easy to understand if the place that a rtentry is destroyed is
fixed.
rt_free waits for references to a given rtentry to be released
before actually destroying the rtentry. rt_free uses a condition
variable (cv_wait) (and psref_target_destroy for psref) to wait.
Unfortunately rtrequst{,1}(RTM_DELETE) can be called in softint
that we cannot use cv_wait. In that case, we have to defer the
destruction to a workqueue.
rtentry#rt_cv, rtentry#rt_psref and global variables
(see rt_free_global) are added to conduct the procedure.
Updates of rtentries
--------------------
One difficulty to use refcnt/psref instead of rwlock for rtentry
is updates of rtentries. We need an additional mechanism to
prevent readers from seeing inconsistency of a rtentry being
updated.
We introduce RTF_UPDATING flag to rtentries that are updating.
While the flag is set to a rtentry, users cannot acquire the
rtentry. By doing so, we avoid users to see inconsistent
rtentries.
There are two options when a user tries to acquire a rtentry
with the RTF_UPDATING flag; if a user runs in softint context
the user fails to acquire a rtentry (NULL is returned).
Otherwise a user waits until the update completes by waiting
on cv.
The procedure of a updater is simpler to destruction of
a rtentry. Wait on cv (and psref) and after all readers left,
proceed with the update.
Global variables (see rt_update_global) are added to conduct
the procedure.
Currently we apply the mechanism to only RTM_CHANGE in
rtsock.c. We would have to apply other codes. See
"Known issues" section.
psref for rtentry
-----------------
When we obtain a rtentry from a rtcache via rtcache_* APIs,
psref is used to reference to the rtentry.
rtcache_ref acquires a reference to a rtentry with psref
and rtcache_unref releases the reference after using it.
rtcache_ref is called inside rtcache_* APIs and users don't
need to take care of it while users must call rtcache_unref
to release the reference.
struct psref and int bound that is needed for psref is
embedded into struct route. By doing so we don't need to
add local variables and additional argument to APIs.
However this adds another constraint to psref other than
reference counting one's; holding a reference of an rtentry
via a rtcache is allowed by just one caller at the same time.
So we must not acquire a rtentry via a rtcache twice and
avoid a recursive use of a rtcache. And also a rtcache must
be arranged to be used by a LWP/softint at the same time
somehow. For IP forwarding case, we have per-CPU rtcaches
used in softint so the constraint is guaranteed. For a h
rtcache of a PCB case, the constraint is guaranteed by the
solock of each PCB. Any other cases (pf, ipf, stf and ipsec)
are currently guaranteed by only the existence of the global
locks (softnet_lock and/or KERNEL_LOCK). If we've found the
cases that we cannot guarantee the constraint, we would need
to introduce other rtcache APIs that use simple reference
counting.
psref of rtcache is created with IPL_SOFTNET and so rtcache
shouldn't used at an IPL higher than IPL_SOFTNET.
Note that rtcache_free is used to invalidate a given rtcache.
We don't need another care by my change; just keep them as
they are.
Performance impact
------------------
When NET_MPSAFE is disabled the performance drop is 3% while
when it's enabled the drop is increased to 11%. The difference
comes from that currently we don't take any global locks and
don't use psref if NET_MPSAFE is disabled.
We can optimize the performance of the case of NET_MPSAFE
on by reducing lookups of rtcache that uses psref;
currently we do two lookups but we should be able to trim
one of two. This is a future work.
Known issues
------------
There are two known issues to be solved; one is that
a caller of rtrequest(RTM_ADD) may change rtentry (see rtinit).
We need to prevent new references during the update. Or
we may be able to remove the code (perhaps, need more
investigations).
The other is rtredirect that updates a rtentry. We need
to apply our update mechanism, however it's not easy because
rtredirect is called in softint and we cannot apply our
mechanism simply. One solution is to defer rtredirect to
a workqueue but it requires some code restructuring.
2016-12-12 06:55:57 +03:00
|
|
|
ifa->ifa_flags |= IFA_DESTROYING;
|
2016-09-29 17:18:38 +03:00
|
|
|
in_scrubaddr(ia);
|
2016-08-01 06:15:30 +03:00
|
|
|
|
|
|
|
mutex_enter(&in_ifaddr_lock);
|
2016-12-06 10:01:47 +03:00
|
|
|
in_addrhash_remove_locked(ia);
|
2003-11-11 23:25:26 +03:00
|
|
|
TAILQ_REMOVE(&in_ifaddrhead, ia, ia_list);
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_WRITER_REMOVE(ia);
|
2016-08-01 06:15:30 +03:00
|
|
|
ifa_remove(ifp, &ia->ia_ifa);
|
2018-01-15 11:17:34 +03:00
|
|
|
/* Assume ifa_remove called pserialize_perform and psref_destroy */
|
2016-12-26 03:30:07 +03:00
|
|
|
mutex_exit(&in_ifaddr_lock);
|
2016-08-01 06:15:30 +03:00
|
|
|
IN_ADDRHASH_ENTRY_DESTROY(ia);
|
|
|
|
IN_ADDRLIST_ENTRY_DESTROY(ia);
|
2014-09-10 00:16:12 +04:00
|
|
|
ifafree(&ia->ia_ifa);
|
2000-02-02 01:52:04 +03:00
|
|
|
in_setmaxmtu();
|
|
|
|
}
|
|
|
|
|
2016-12-06 10:01:47 +03:00
|
|
|
static void
|
|
|
|
in_addrhash_insert_locked(struct in_ifaddr *ia)
|
|
|
|
{
|
|
|
|
|
|
|
|
KASSERT(mutex_owned(&in_ifaddr_lock));
|
|
|
|
|
|
|
|
LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia,
|
|
|
|
ia_hash);
|
|
|
|
IN_ADDRHASH_ENTRY_INIT(ia);
|
|
|
|
IN_ADDRHASH_WRITER_INSERT_HEAD(ia);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_addrhash_insert(struct in_ifaddr *ia)
|
|
|
|
{
|
|
|
|
|
|
|
|
mutex_enter(&in_ifaddr_lock);
|
|
|
|
in_addrhash_insert_locked(ia);
|
|
|
|
mutex_exit(&in_ifaddr_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_addrhash_remove_locked(struct in_ifaddr *ia)
|
|
|
|
{
|
|
|
|
|
|
|
|
KASSERT(mutex_owned(&in_ifaddr_lock));
|
|
|
|
|
|
|
|
LIST_REMOVE(ia, ia_hash);
|
|
|
|
IN_ADDRHASH_WRITER_REMOVE(ia);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_addrhash_remove(struct in_ifaddr *ia)
|
|
|
|
{
|
|
|
|
|
|
|
|
mutex_enter(&in_ifaddr_lock);
|
|
|
|
in_addrhash_remove_locked(ia);
|
|
|
|
#ifdef NET_MPSAFE
|
|
|
|
pserialize_perform(in_ifaddrhash_psz);
|
|
|
|
#endif
|
2016-12-26 03:30:07 +03:00
|
|
|
mutex_exit(&in_ifaddr_lock);
|
2016-12-06 10:01:47 +03:00
|
|
|
IN_ADDRHASH_ENTRY_DESTROY(ia);
|
|
|
|
}
|
|
|
|
|
2000-02-03 02:28:08 +03:00
|
|
|
void
|
2006-10-05 21:35:19 +04:00
|
|
|
in_purgeif(struct ifnet *ifp) /* MUST be called at splsoftnet() */
|
2000-02-03 02:28:08 +03:00
|
|
|
{
|
2017-12-15 07:03:46 +03:00
|
|
|
|
|
|
|
IFNET_LOCK(ifp);
|
2007-12-06 02:47:17 +03:00
|
|
|
if_purgeaddrs(ifp, AF_INET, in_purgeaddr);
|
2006-10-05 21:35:19 +04:00
|
|
|
igmp_purgeif(ifp); /* manipulates pools */
|
2003-06-26 07:35:00 +04:00
|
|
|
#ifdef MROUTING
|
|
|
|
ip_mrouter_detach(ifp);
|
|
|
|
#endif
|
2017-12-15 07:03:46 +03:00
|
|
|
IFNET_UNLOCK(ifp);
|
2000-02-03 02:28:08 +03:00
|
|
|
}
|
|
|
|
|
1999-07-01 12:12:45 +04:00
|
|
|
/*
|
|
|
|
* SIOC[GAD]LIFADDR.
|
|
|
|
* SIOCGLIFADDR: get first address. (???)
|
|
|
|
* SIOCGLIFADDR with IFLR_PREFIX:
|
|
|
|
* get first address that matches the specified prefix.
|
|
|
|
* SIOCALIFADDR: add the specified address.
|
|
|
|
* SIOCALIFADDR with IFLR_PREFIX:
|
|
|
|
* EINVAL since we can't deduce hostid part of the address.
|
|
|
|
* SIOCDLIFADDR: delete the specified address.
|
|
|
|
* SIOCDLIFADDR with IFLR_PREFIX:
|
|
|
|
* delete the first address that matches the specified prefix.
|
|
|
|
* return values:
|
|
|
|
* EINVAL on invalid parameters
|
|
|
|
* EADDRNOTAVAIL on prefix match failed/specified address not found
|
|
|
|
* other values may be returned from in_ioctl()
|
|
|
|
*/
|
|
|
|
static int
|
2007-03-04 08:59:00 +03:00
|
|
|
in_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
|
2014-07-01 09:49:18 +04:00
|
|
|
struct ifnet *ifp)
|
1999-07-01 12:12:45 +04:00
|
|
|
{
|
|
|
|
struct if_laddrreq *iflr = (struct if_laddrreq *)data;
|
|
|
|
struct ifaddr *ifa;
|
1999-12-12 18:57:07 +03:00
|
|
|
struct sockaddr *sa;
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
/* sanity checks */
|
2007-11-10 02:53:13 +03:00
|
|
|
if (data == NULL || ifp == NULL) {
|
1999-07-01 12:12:45 +04:00
|
|
|
panic("invalid argument to in_lifaddr_ioctl");
|
|
|
|
/*NOTRECHED*/
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCGLIFADDR:
|
|
|
|
/* address must be specified on GET with IFLR_PREFIX */
|
|
|
|
if ((iflr->flags & IFLR_PREFIX) == 0)
|
|
|
|
break;
|
|
|
|
/*FALLTHROUGH*/
|
|
|
|
case SIOCALIFADDR:
|
|
|
|
case SIOCDLIFADDR:
|
|
|
|
/* address must be specified on ADD and DELETE */
|
1999-12-12 18:57:07 +03:00
|
|
|
sa = (struct sockaddr *)&iflr->addr;
|
|
|
|
if (sa->sa_family != AF_INET)
|
1999-07-01 12:12:45 +04:00
|
|
|
return EINVAL;
|
1999-12-12 18:57:07 +03:00
|
|
|
if (sa->sa_len != sizeof(struct sockaddr_in))
|
1999-07-01 12:12:45 +04:00
|
|
|
return EINVAL;
|
|
|
|
/* XXX need improvement */
|
1999-12-12 18:57:07 +03:00
|
|
|
sa = (struct sockaddr *)&iflr->dstaddr;
|
2008-05-12 00:17:59 +04:00
|
|
|
if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
|
1999-07-01 12:12:45 +04:00
|
|
|
return EINVAL;
|
2008-05-12 00:17:59 +04:00
|
|
|
if (sa->sa_len != 0 && sa->sa_len != sizeof(struct sockaddr_in))
|
1999-07-01 12:12:45 +04:00
|
|
|
return EINVAL;
|
|
|
|
break;
|
|
|
|
default: /*shouldn't happen*/
|
|
|
|
#if 0
|
|
|
|
panic("invalid cmd to in_lifaddr_ioctl");
|
|
|
|
/*NOTREACHED*/
|
|
|
|
#else
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
#endif
|
|
|
|
}
|
2008-04-10 22:09:14 +04:00
|
|
|
if (sizeof(struct in_addr) * NBBY < iflr->prefixlen)
|
1999-07-01 12:12:45 +04:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCALIFADDR:
|
|
|
|
{
|
|
|
|
struct in_aliasreq ifra;
|
|
|
|
|
|
|
|
if (iflr->flags & IFLR_PREFIX)
|
|
|
|
return EINVAL;
|
|
|
|
|
2006-09-24 00:54:07 +04:00
|
|
|
/* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR). */
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(&ifra, 0, sizeof(ifra));
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ifra.ifra_name, iflr->iflr_name,
|
1999-07-01 12:12:45 +04:00
|
|
|
sizeof(ifra.ifra_name));
|
|
|
|
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&ifra.ifra_addr, &iflr->addr,
|
1999-12-12 18:57:07 +03:00
|
|
|
((struct sockaddr *)&iflr->addr)->sa_len);
|
1999-07-01 12:12:45 +04:00
|
|
|
|
1999-12-12 18:57:07 +03:00
|
|
|
if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&ifra.ifra_dstaddr, &iflr->dstaddr,
|
1999-12-12 18:57:07 +03:00
|
|
|
((struct sockaddr *)&iflr->dstaddr)->sa_len);
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ifra.ifra_mask.sin_family = AF_INET;
|
|
|
|
ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
|
|
|
|
in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
|
|
|
|
|
2014-07-01 09:49:18 +04:00
|
|
|
return in_control(so, SIOCAIFADDR, &ifra, ifp);
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
case SIOCGLIFADDR:
|
|
|
|
case SIOCDLIFADDR:
|
|
|
|
{
|
|
|
|
struct in_ifaddr *ia;
|
|
|
|
struct in_addr mask, candidate, match;
|
|
|
|
struct sockaddr_in *sin;
|
2016-09-01 07:27:00 +03:00
|
|
|
int cmp, s;
|
1999-07-01 12:12:45 +04:00
|
|
|
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(&mask, 0, sizeof(mask));
|
|
|
|
memset(&match, 0, sizeof(match)); /* XXX gcc */
|
1999-07-01 12:12:45 +04:00
|
|
|
if (iflr->flags & IFLR_PREFIX) {
|
|
|
|
/* lookup a prefix rather than address. */
|
|
|
|
in_len2mask(&mask, iflr->prefixlen);
|
|
|
|
|
|
|
|
sin = (struct sockaddr_in *)&iflr->addr;
|
|
|
|
match.s_addr = sin->sin_addr.s_addr;
|
|
|
|
match.s_addr &= mask.s_addr;
|
|
|
|
|
|
|
|
/* if you set extra bits, that's wrong */
|
|
|
|
if (match.s_addr != sin->sin_addr.s_addr)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
cmp = 1;
|
|
|
|
} else {
|
|
|
|
if (cmd == SIOCGLIFADDR) {
|
|
|
|
/* on getting an address, take the 1st match */
|
|
|
|
cmp = 0; /*XXX*/
|
|
|
|
} else {
|
|
|
|
/* on deleting an address, do exact match */
|
|
|
|
in_len2mask(&mask, 32);
|
|
|
|
sin = (struct sockaddr_in *)&iflr->addr;
|
|
|
|
match.s_addr = sin->sin_addr.s_addr;
|
|
|
|
|
|
|
|
cmp = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-01 07:27:00 +03:00
|
|
|
s = pserialize_read_enter();
|
2016-07-07 12:32:01 +03:00
|
|
|
IFADDR_READER_FOREACH(ifa, ifp) {
|
2004-05-30 10:37:07 +04:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
1999-07-01 12:12:45 +04:00
|
|
|
continue;
|
2007-11-10 02:53:13 +03:00
|
|
|
if (cmp == 0)
|
1999-07-01 12:12:45 +04:00
|
|
|
break;
|
2012-06-08 19:01:51 +04:00
|
|
|
candidate.s_addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
|
1999-07-01 12:12:45 +04:00
|
|
|
candidate.s_addr &= mask.s_addr;
|
|
|
|
if (candidate.s_addr == match.s_addr)
|
|
|
|
break;
|
|
|
|
}
|
2016-09-01 07:27:00 +03:00
|
|
|
if (ifa == NULL) {
|
|
|
|
pserialize_read_exit(s);
|
1999-07-01 12:12:45 +04:00
|
|
|
return EADDRNOTAVAIL;
|
2016-09-01 07:27:00 +03:00
|
|
|
}
|
1999-07-01 12:12:45 +04:00
|
|
|
ia = (struct in_ifaddr *)ifa;
|
|
|
|
|
|
|
|
if (cmd == SIOCGLIFADDR) {
|
|
|
|
/* fill in the if_laddrreq structure */
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&iflr->addr, &ia->ia_addr, ia->ia_addr.sin_len);
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&iflr->dstaddr, &ia->ia_dstaddr,
|
1999-07-01 12:12:45 +04:00
|
|
|
ia->ia_dstaddr.sin_len);
|
|
|
|
} else
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(&iflr->dstaddr, 0, sizeof(iflr->dstaddr));
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
iflr->prefixlen =
|
|
|
|
in_mask2len(&ia->ia_sockmask.sin_addr);
|
|
|
|
|
|
|
|
iflr->flags = 0; /*XXX*/
|
2016-09-01 07:27:00 +03:00
|
|
|
pserialize_read_exit(s);
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
struct in_aliasreq ifra;
|
|
|
|
|
2006-09-24 00:54:07 +04:00
|
|
|
/* fill in_aliasreq and do ioctl(SIOCDIFADDR) */
|
2009-03-18 19:00:08 +03:00
|
|
|
memset(&ifra, 0, sizeof(ifra));
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(ifra.ifra_name, iflr->iflr_name,
|
1999-07-01 12:12:45 +04:00
|
|
|
sizeof(ifra.ifra_name));
|
|
|
|
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&ifra.ifra_addr, &ia->ia_addr,
|
1999-07-01 12:12:45 +04:00
|
|
|
ia->ia_addr.sin_len);
|
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&ifra.ifra_dstaddr, &ia->ia_dstaddr,
|
1999-07-01 12:12:45 +04:00
|
|
|
ia->ia_dstaddr.sin_len);
|
|
|
|
}
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(&ifra.ifra_dstaddr, &ia->ia_sockmask,
|
1999-07-01 12:12:45 +04:00
|
|
|
ia->ia_sockmask.sin_len);
|
2016-09-01 07:27:00 +03:00
|
|
|
pserialize_read_exit(s);
|
1999-07-01 12:12:45 +04:00
|
|
|
|
2014-07-01 09:49:18 +04:00
|
|
|
return in_control(so, SIOCDIFADDR, &ifra, ifp);
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EOPNOTSUPP; /*just for safety*/
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Initialize an interface's internet address
|
|
|
|
* and routing table entry.
|
|
|
|
*/
|
1994-05-13 10:02:48 +04:00
|
|
|
int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia,
|
2016-09-29 18:04:17 +03:00
|
|
|
const struct sockaddr_in *sin, const struct sockaddr_in *dst, int scrub)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2004-07-07 05:39:00 +04:00
|
|
|
u_int32_t i;
|
2016-09-29 18:04:17 +03:00
|
|
|
struct sockaddr_in oldaddr, olddst;
|
2016-09-16 17:17:23 +03:00
|
|
|
int s, oldflags, flags = RTF_UP, error, hostIsNew;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-09-01 08:32:50 +04:00
|
|
|
if (sin == NULL)
|
2004-07-07 05:39:00 +04:00
|
|
|
sin = &ia->ia_addr;
|
2016-09-29 18:04:17 +03:00
|
|
|
if (dst == NULL)
|
|
|
|
dst = &ia->ia_dstaddr;
|
2004-07-07 05:39:00 +04:00
|
|
|
|
1996-09-09 18:51:07 +04:00
|
|
|
/*
|
|
|
|
* Set up new addresses.
|
|
|
|
*/
|
1993-03-21 12:45:37 +03:00
|
|
|
oldaddr = ia->ia_addr;
|
2016-09-29 18:04:17 +03:00
|
|
|
olddst = ia->ia_dstaddr;
|
2016-09-16 17:17:23 +03:00
|
|
|
oldflags = ia->ia4_flags;
|
1993-03-21 12:45:37 +03:00
|
|
|
ia->ia_addr = *sin;
|
2016-09-29 18:04:17 +03:00
|
|
|
ia->ia_dstaddr = *dst;
|
2016-09-16 17:17:23 +03:00
|
|
|
hostIsNew = oldaddr.sin_family != AF_INET ||
|
|
|
|
!in_hosteq(ia->ia_addr.sin_addr, oldaddr.sin_addr);
|
2016-09-29 18:04:17 +03:00
|
|
|
if (!scrub)
|
|
|
|
scrub = oldaddr.sin_family != ia->ia_dstaddr.sin_family ||
|
|
|
|
!in_hosteq(ia->ia_dstaddr.sin_addr, olddst.sin_addr);
|
1998-02-13 21:21:38 +03:00
|
|
|
|
2016-09-16 17:17:23 +03:00
|
|
|
/*
|
|
|
|
* Configure address flags.
|
2018-05-14 01:42:51 +03:00
|
|
|
* We need to do this early because they may be adjusted
|
2016-09-16 17:17:23 +03:00
|
|
|
* by if_addr_init depending on the address.
|
|
|
|
*/
|
2018-04-06 19:01:16 +03:00
|
|
|
if (ia->ia4_flags & IN_IFF_DUPLICATED) {
|
|
|
|
ia->ia4_flags &= ~IN_IFF_DUPLICATED;
|
2016-09-16 17:17:23 +03:00
|
|
|
hostIsNew = 1;
|
2018-04-06 12:20:29 +03:00
|
|
|
}
|
2018-04-06 19:01:16 +03:00
|
|
|
if (ifp->if_link_state == LINK_STATE_DOWN) {
|
|
|
|
ia->ia4_flags |= IN_IFF_DETACHED;
|
|
|
|
ia->ia4_flags &= ~IN_IFF_TENTATIVE;
|
2018-11-29 12:51:20 +03:00
|
|
|
} else if (hostIsNew && if_do_dad(ifp) && ip_dad_enabled())
|
2018-04-06 19:01:16 +03:00
|
|
|
ia->ia4_flags |= IN_IFF_TRYTENTATIVE;
|
2015-05-02 17:41:32 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Give the interface a chance to initialize
|
|
|
|
* if this is its first address,
|
|
|
|
* and to validate the address if necessary.
|
|
|
|
*/
|
2017-01-23 13:19:03 +03:00
|
|
|
s = splsoftnet();
|
2016-09-16 17:17:23 +03:00
|
|
|
error = if_addr_init(ifp, &ia->ia_ifa, true);
|
|
|
|
splx(s);
|
2017-08-04 23:17:45 +03:00
|
|
|
/* Now clear the try tentative flag, its job is done. */
|
2015-05-16 15:12:46 +03:00
|
|
|
ia->ia4_flags &= ~IN_IFF_TRYTENTATIVE;
|
2016-09-16 17:17:23 +03:00
|
|
|
if (error != 0) {
|
|
|
|
ia->ia_addr = oldaddr;
|
2016-09-29 18:04:17 +03:00
|
|
|
ia->ia_dstaddr = olddst;
|
2016-09-16 17:17:23 +03:00
|
|
|
ia->ia4_flags = oldflags;
|
|
|
|
return error;
|
|
|
|
}
|
2015-05-16 15:12:46 +03:00
|
|
|
|
Fix sending broken RTM_DELADDR message in some operations.
Here is mininum reproduction operation.
====================
# ifconfig ixg0 172.16.0.1/29
# route monitor &
# ifconfig pppoe0 172.16.0.1/32 0.0.0.1
====================
The broken RTM_DELADDR is the following.
====================
got message of size 72 on Thu Nov 17 12:50:42 2022
#13: len 72, got message of size 80 on Thu Nov 17 12:50:42 2022
RTM_DELADDR: address being removed from iface: len 80, pid 3552, metric 0, addrflags: 0
sockaddrs: 0xb4<NETMASK,IFP,IFA,BRD>
Q00.00.ff.ff.ff.ff.00.00.00.00.00.00.00.00 pppoe0 default default
====================
This problem is related to the following two commit.
(1) https://github.com/NetBSD/src/commit/b0210214689f17ec08988acd7ef8ae9cdc4c68bc
that is, sys/netinet/in.c:r1.183
(2) https://github.com/NetBSD/src/commit/61bad33c44f2f6a01a030e8aa5840c015716792a
that is, sys/netinet/in.c:r1.185
(1) adds in_scrubaddr() for old addresses to in_ifinit() without checking
IFA_ROUTE.
And then, (2) removes in_ifscrub() for POINTTOPOINT interface in in_control0.
The removed in_ifscrub() is called with checking IFA_ROUTE.
It seems these modifications about checking IFA_ROUTE logic causes this
problem, however the real reason is calling in_ifscrub() for the interface
which does not have IPv4 address. So, scrubbing old address processing
should be done only if the interface already has IPv4 address.
2022-11-17 08:02:11 +03:00
|
|
|
/*
|
|
|
|
* The interface which does not have IPv4 address is not required
|
|
|
|
* to scrub old address. So, skip scrub such cases.
|
|
|
|
*/
|
|
|
|
if (oldaddr.sin_family == AF_INET && (scrub || hostIsNew)) {
|
2016-09-16 17:17:23 +03:00
|
|
|
int newflags = ia->ia4_flags;
|
|
|
|
|
1995-06-04 08:35:29 +04:00
|
|
|
ia->ia_ifa.ifa_addr = sintosa(&oldaddr);
|
2016-09-29 18:04:17 +03:00
|
|
|
ia->ia_ifa.ifa_dstaddr = sintosa(&olddst);
|
2016-09-16 17:17:23 +03:00
|
|
|
ia->ia4_flags = oldflags;
|
2016-09-29 17:18:38 +03:00
|
|
|
if (hostIsNew)
|
|
|
|
in_scrubaddr(ia);
|
|
|
|
else if (scrub)
|
2016-09-29 18:18:18 +03:00
|
|
|
in_scrubprefix(ia);
|
1995-06-04 08:35:29 +04:00
|
|
|
ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
|
2016-09-29 18:04:17 +03:00
|
|
|
ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
|
2016-09-16 17:17:23 +03:00
|
|
|
ia->ia4_flags = newflags;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1997-07-24 01:26:40 +04:00
|
|
|
|
2004-07-07 05:39:00 +04:00
|
|
|
i = ia->ia_addr.sin_addr.s_addr;
|
2016-10-01 20:17:20 +03:00
|
|
|
if (ifp->if_flags & IFF_POINTOPOINT)
|
|
|
|
ia->ia_netmask = INADDR_BROADCAST; /* default to /32 */
|
|
|
|
else if (IN_CLASSA(i))
|
1993-03-21 12:45:37 +03:00
|
|
|
ia->ia_netmask = IN_CLASSA_NET;
|
|
|
|
else if (IN_CLASSB(i))
|
|
|
|
ia->ia_netmask = IN_CLASSB_NET;
|
|
|
|
else
|
|
|
|
ia->ia_netmask = IN_CLASSC_NET;
|
|
|
|
/*
|
1994-05-13 10:02:48 +04:00
|
|
|
* The subnet mask usually includes at least the standard network part,
|
|
|
|
* but may may be smaller in the case of supernetting.
|
|
|
|
* If it is set, we believe it.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
1994-05-13 10:02:48 +04:00
|
|
|
if (ia->ia_subnetmask == 0) {
|
|
|
|
ia->ia_subnetmask = ia->ia_netmask;
|
1995-06-02 01:35:34 +04:00
|
|
|
ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask;
|
1994-05-13 10:02:48 +04:00
|
|
|
} else
|
|
|
|
ia->ia_netmask &= ia->ia_subnetmask;
|
1997-07-24 01:26:40 +04:00
|
|
|
|
1994-05-13 10:02:48 +04:00
|
|
|
ia->ia_net = i & ia->ia_netmask;
|
1993-03-21 12:45:37 +03:00
|
|
|
ia->ia_subnet = i & ia->ia_subnetmask;
|
1994-05-13 10:02:48 +04:00
|
|
|
in_socktrim(&ia->ia_sockmask);
|
2017-03-17 20:26:20 +03:00
|
|
|
|
1997-07-24 01:26:40 +04:00
|
|
|
/* re-calculate the "in_maxmtu" value */
|
|
|
|
in_setmaxmtu();
|
2017-03-17 20:26:20 +03:00
|
|
|
|
1994-05-13 10:02:48 +04:00
|
|
|
ia->ia_ifa.ifa_metric = ifp->if_metric;
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ifp->if_flags & IFF_BROADCAST) {
|
2019-12-18 03:49:15 +03:00
|
|
|
if (ia->ia_subnetmask == IN_RFC3021_MASK) {
|
|
|
|
ia->ia_broadaddr.sin_addr.s_addr = INADDR_BROADCAST;
|
|
|
|
ia->ia_netbroadcast.s_addr = INADDR_BROADCAST;
|
|
|
|
} else {
|
|
|
|
ia->ia_broadaddr.sin_addr.s_addr =
|
|
|
|
ia->ia_subnet | ~ia->ia_subnetmask;
|
|
|
|
ia->ia_netbroadcast.s_addr =
|
|
|
|
ia->ia_net | ~ia->ia_netmask;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
} else if (ifp->if_flags & IFF_LOOPBACK) {
|
2003-06-13 11:59:57 +04:00
|
|
|
ia->ia_dstaddr = ia->ia_addr;
|
1993-03-21 12:45:37 +03:00
|
|
|
flags |= RTF_HOST;
|
|
|
|
} else if (ifp->if_flags & IFF_POINTOPOINT) {
|
2020-08-29 20:41:14 +03:00
|
|
|
if (ia->ia_dstaddr.sin_family != AF_INET)
|
|
|
|
return (0);
|
|
|
|
flags |= RTF_HOST;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2017-03-17 20:26:20 +03:00
|
|
|
|
|
|
|
/* Add the local route to the address */
|
|
|
|
in_ifaddlocal(&ia->ia_ifa);
|
|
|
|
|
|
|
|
/* Add the prefix route for the address */
|
2001-07-22 20:18:31 +04:00
|
|
|
error = in_addprefix(ia, flags);
|
2017-03-17 20:26:20 +03:00
|
|
|
|
1993-12-06 07:50:19 +03:00
|
|
|
/*
|
|
|
|
* If the interface supports multicast, join the "all hosts"
|
|
|
|
* multicast group on that interface.
|
|
|
|
*/
|
2017-03-02 08:31:04 +03:00
|
|
|
mutex_enter(&in_ifaddr_lock);
|
2000-10-08 13:15:28 +04:00
|
|
|
if ((ifp->if_flags & IFF_MULTICAST) != 0 && ia->ia_allhosts == NULL) {
|
1993-12-06 07:50:19 +03:00
|
|
|
struct in_addr addr;
|
|
|
|
|
1995-06-02 01:35:34 +04:00
|
|
|
addr.s_addr = INADDR_ALLHOSTS_GROUP;
|
2000-10-08 13:15:28 +04:00
|
|
|
ia->ia_allhosts = in_addmulti(&addr, ifp);
|
1993-12-06 07:50:19 +03:00
|
|
|
}
|
2017-03-02 08:31:04 +03:00
|
|
|
mutex_exit(&in_ifaddr_lock);
|
2015-05-02 17:41:32 +03:00
|
|
|
|
2016-09-16 17:17:23 +03:00
|
|
|
if (hostIsNew &&
|
|
|
|
ia->ia4_flags & IN_IFF_TENTATIVE &&
|
|
|
|
if_do_dad(ifp))
|
2015-05-16 15:12:46 +03:00
|
|
|
ia->ia_dad_start((struct ifaddr *)ia);
|
2015-05-02 17:41:32 +03:00
|
|
|
|
2016-09-16 17:17:23 +03:00
|
|
|
return error;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
#define rtinitflags(x) \
|
2001-07-27 06:04:08 +04:00
|
|
|
((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
|
|
|
|
? RTF_HOST : 0)
|
2001-07-22 20:18:31 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* add a route to prefix ("connected route" in cisco terminology).
|
|
|
|
* does nothing if there's some interface address with the same prefix already.
|
|
|
|
*/
|
|
|
|
static int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_addprefix(struct in_ifaddr *target, int flags)
|
2001-07-22 20:18:31 +04:00
|
|
|
{
|
|
|
|
struct in_ifaddr *ia;
|
|
|
|
struct in_addr prefix, mask, p;
|
|
|
|
int error;
|
2016-08-01 06:15:30 +03:00
|
|
|
int s;
|
2001-07-22 20:18:31 +04:00
|
|
|
|
|
|
|
if ((flags & RTF_HOST) != 0)
|
|
|
|
prefix = target->ia_dstaddr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
else {
|
2001-07-22 20:18:31 +04:00
|
|
|
prefix = target->ia_addr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
mask = target->ia_sockmask.sin_addr;
|
|
|
|
prefix.s_addr &= mask.s_addr;
|
|
|
|
}
|
2001-07-22 20:18:31 +04:00
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
s = pserialize_read_enter();
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(ia) {
|
2001-07-22 20:18:31 +04:00
|
|
|
if (rtinitflags(ia))
|
|
|
|
p = ia->ia_dstaddr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
else {
|
2001-07-22 20:18:31 +04:00
|
|
|
p = ia->ia_addr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
|
|
|
|
}
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
if (prefix.s_addr != p.s_addr)
|
|
|
|
continue;
|
|
|
|
|
2022-11-25 11:39:32 +03:00
|
|
|
if ((ia->ia_ifp->if_flags & IFF_UNNUMBERED))
|
|
|
|
continue;
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
/*
|
|
|
|
* if we got a matching prefix route inserted by other
|
2001-09-16 12:49:50 +04:00
|
|
|
* interface address, we don't need to bother
|
2006-11-13 08:13:38 +03:00
|
|
|
*
|
|
|
|
* XXX RADIX_MPATH implications here? -dyoung
|
2001-07-22 20:18:31 +04:00
|
|
|
*/
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia->ia_flags & IFA_ROUTE) {
|
|
|
|
pserialize_read_exit(s);
|
2001-07-22 20:18:31 +04:00
|
|
|
return 0;
|
2016-08-01 06:15:30 +03:00
|
|
|
}
|
2001-07-22 20:18:31 +04:00
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
pserialize_read_exit(s);
|
2001-07-22 20:18:31 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* noone seem to have prefix route. insert it.
|
|
|
|
*/
|
2022-11-25 11:39:32 +03:00
|
|
|
if (target->ia_ifa.ifa_ifp->if_flags & IFF_UNNUMBERED) {
|
2008-12-21 22:07:35 +03:00
|
|
|
error = 0;
|
2022-11-25 11:39:32 +03:00
|
|
|
} else {
|
|
|
|
error = rtinit(&target->ia_ifa, RTM_ADD, flags);
|
|
|
|
if (error == 0)
|
|
|
|
target->ia_flags |= IFA_ROUTE;
|
|
|
|
else if (error == EEXIST) {
|
|
|
|
/*
|
|
|
|
* the fact the route already exists is not an error.
|
|
|
|
*/
|
|
|
|
error = 0;
|
|
|
|
}
|
2008-12-21 22:07:35 +03:00
|
|
|
}
|
2001-07-22 20:18:31 +04:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2022-09-20 05:23:37 +03:00
|
|
|
static int
|
|
|
|
in_rt_ifa_matcher(struct rtentry *rt, void *v)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa = v;
|
|
|
|
|
|
|
|
if (rt->rt_ifa == ifa)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
/*
|
|
|
|
* remove a route to prefix ("connected route" in cisco terminology).
|
|
|
|
* re-installs the route by using another interface address, if there's one
|
|
|
|
* with the same prefix (otherwise we lose the route mistakenly).
|
|
|
|
*/
|
|
|
|
static int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_scrubprefix(struct in_ifaddr *target)
|
2001-07-22 20:18:31 +04:00
|
|
|
{
|
|
|
|
struct in_ifaddr *ia;
|
|
|
|
struct in_addr prefix, mask, p;
|
|
|
|
int error;
|
2016-08-01 06:15:30 +03:00
|
|
|
int s;
|
2001-07-22 20:18:31 +04:00
|
|
|
|
2016-09-29 17:18:38 +03:00
|
|
|
/* If we don't have IFA_ROUTE we have nothing to do */
|
2015-02-26 12:54:46 +03:00
|
|
|
if ((target->ia_flags & IFA_ROUTE) == 0)
|
2001-07-22 20:18:31 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (rtinitflags(target))
|
|
|
|
prefix = target->ia_dstaddr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
else {
|
2001-07-22 20:18:31 +04:00
|
|
|
prefix = target->ia_addr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
mask = target->ia_sockmask.sin_addr;
|
|
|
|
prefix.s_addr &= mask.s_addr;
|
|
|
|
}
|
2001-07-22 20:18:31 +04:00
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
s = pserialize_read_enter();
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(ia) {
|
2001-07-22 20:18:31 +04:00
|
|
|
if (rtinitflags(ia))
|
|
|
|
p = ia->ia_dstaddr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
else {
|
2001-07-22 20:18:31 +04:00
|
|
|
p = ia->ia_addr.sin_addr;
|
2003-06-18 10:42:34 +04:00
|
|
|
p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
|
|
|
|
}
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
if (prefix.s_addr != p.s_addr)
|
|
|
|
continue;
|
|
|
|
|
2022-11-25 11:39:32 +03:00
|
|
|
if ((ia->ia_ifp->if_flags & IFF_UNNUMBERED))
|
|
|
|
continue;
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
/*
|
|
|
|
* if we got a matching prefix route, move IFA_ROUTE to him
|
|
|
|
*/
|
|
|
|
if ((ia->ia_flags & IFA_ROUTE) == 0) {
|
2016-08-01 06:15:30 +03:00
|
|
|
struct psref psref;
|
|
|
|
int bound = curlwp_bind();
|
|
|
|
|
|
|
|
ia4_acquire(ia, &psref);
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
2007-11-10 02:53:13 +03:00
|
|
|
rtinit(&target->ia_ifa, RTM_DELETE,
|
2001-07-22 20:18:31 +04:00
|
|
|
rtinitflags(target));
|
|
|
|
target->ia_flags &= ~IFA_ROUTE;
|
|
|
|
|
2007-11-10 02:53:13 +03:00
|
|
|
error = rtinit(&ia->ia_ifa, RTM_ADD,
|
2001-07-22 20:18:31 +04:00
|
|
|
rtinitflags(ia) | RTF_UP);
|
|
|
|
if (error == 0)
|
|
|
|
ia->ia_flags |= IFA_ROUTE;
|
2016-08-01 06:15:30 +03:00
|
|
|
|
2022-09-20 05:23:37 +03:00
|
|
|
if (!ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING))
|
|
|
|
goto skip;
|
|
|
|
/*
|
|
|
|
* Replace rt_ifa of routes that have the removing address
|
|
|
|
* with the new address.
|
|
|
|
*/
|
|
|
|
rt_replace_ifa_matched_entries(AF_INET,
|
|
|
|
in_rt_ifa_matcher, &target->ia_ifa, &ia->ia_ifa);
|
|
|
|
|
|
|
|
skip:
|
2016-08-01 06:15:30 +03:00
|
|
|
ia4_release(ia, &psref);
|
|
|
|
curlwp_bindx(bound);
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
pserialize_read_exit(s);
|
2001-07-22 20:18:31 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* noone seem to have prefix route. remove it.
|
|
|
|
*/
|
2007-11-10 02:53:13 +03:00
|
|
|
rtinit(&target->ia_ifa, RTM_DELETE, rtinitflags(target));
|
2001-07-22 20:18:31 +04:00
|
|
|
target->ia_flags &= ~IFA_ROUTE;
|
2022-09-20 05:23:37 +03:00
|
|
|
|
|
|
|
if (ISSET(target->ia_ifa.ifa_flags, IFA_DESTROYING)) {
|
|
|
|
/* Remove routes that have the removing address as rt_ifa. */
|
|
|
|
rt_delete_matched_entries(AF_INET, in_rt_ifa_matcher,
|
|
|
|
&target->ia_ifa, true);
|
|
|
|
}
|
|
|
|
|
2001-07-22 20:18:31 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef rtinitflags
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Return 1 if the address might be a local broadcast address.
|
|
|
|
*/
|
1994-01-09 04:06:02 +03:00
|
|
|
int
|
2005-02-03 06:49:01 +03:00
|
|
|
in_broadcast(struct in_addr in, struct ifnet *ifp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 16:51:13 +04:00
|
|
|
struct ifaddr *ifa;
|
2016-08-01 06:15:30 +03:00
|
|
|
int s;
|
|
|
|
|
|
|
|
KASSERT(ifp != NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1994-05-13 10:02:48 +04:00
|
|
|
if (in.s_addr == INADDR_BROADCAST ||
|
1996-09-09 18:51:07 +04:00
|
|
|
in_nullhost(in))
|
1994-05-13 10:02:48 +04:00
|
|
|
return 1;
|
|
|
|
if ((ifp->if_flags & IFF_BROADCAST) == 0)
|
|
|
|
return 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Look through the list of addresses for a match
|
|
|
|
* with a broadcast address.
|
|
|
|
*/
|
1995-06-04 09:06:49 +04:00
|
|
|
#define ia (ifatoia(ifa))
|
2016-08-01 06:15:30 +03:00
|
|
|
s = pserialize_read_enter();
|
|
|
|
IFADDR_READER_FOREACH(ifa, ifp) {
|
1994-05-13 10:02:48 +04:00
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET &&
|
2002-03-30 03:40:32 +03:00
|
|
|
!in_hosteq(in, ia->ia_addr.sin_addr) &&
|
1996-09-09 18:51:07 +04:00
|
|
|
(in_hosteq(in, ia->ia_broadaddr.sin_addr) ||
|
|
|
|
in_hosteq(in, ia->ia_netbroadcast) ||
|
2002-06-09 20:33:36 +04:00
|
|
|
(hostzeroisbroadcast &&
|
1999-06-26 10:16:47 +04:00
|
|
|
/*
|
2019-12-18 03:49:15 +03:00
|
|
|
* Check for old-style (host 0) broadcast, but
|
|
|
|
* taking into account that RFC 3021 obsoletes it.
|
1999-06-26 10:16:47 +04:00
|
|
|
*/
|
2019-12-18 03:49:15 +03:00
|
|
|
ia->ia_subnetmask != IN_RFC3021_MASK &&
|
1999-06-26 10:16:47 +04:00
|
|
|
(in.s_addr == ia->ia_subnet ||
|
2016-08-01 06:15:30 +03:00
|
|
|
in.s_addr == ia->ia_net)))) {
|
|
|
|
pserialize_read_exit(s);
|
1999-06-26 10:16:47 +04:00
|
|
|
return 1;
|
2016-08-01 06:15:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pserialize_read_exit(s);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (0);
|
1994-05-13 10:02:48 +04:00
|
|
|
#undef ia
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1993-12-06 07:50:19 +03:00
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
/*
|
|
|
|
* perform DAD when interface becomes IFF_UP.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
in_if_link_up(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct in_ifaddr *ia;
|
2016-09-01 07:27:00 +03:00
|
|
|
int s, bound;
|
2015-05-02 17:41:32 +03:00
|
|
|
|
|
|
|
/* Ensure it's sane to run DAD */
|
|
|
|
if (ifp->if_link_state == LINK_STATE_DOWN)
|
|
|
|
return;
|
|
|
|
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
|
|
|
|
return;
|
|
|
|
|
2016-09-01 07:27:00 +03:00
|
|
|
bound = curlwp_bind();
|
|
|
|
s = pserialize_read_enter();
|
2016-07-07 12:32:01 +03:00
|
|
|
IFADDR_READER_FOREACH(ifa, ifp) {
|
2016-09-01 07:27:00 +03:00
|
|
|
struct psref psref;
|
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
2016-09-01 07:27:00 +03:00
|
|
|
ifa_acquire(ifa, &psref);
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
ia = (struct in_ifaddr *)ifa;
|
|
|
|
|
|
|
|
/* If detached then mark as tentative */
|
|
|
|
if (ia->ia4_flags & IN_IFF_DETACHED) {
|
|
|
|
ia->ia4_flags &= ~IN_IFF_DETACHED;
|
2018-11-29 12:54:22 +03:00
|
|
|
if (ip_dad_enabled() && if_do_dad(ifp) &&
|
|
|
|
ia->ia_dad_start != NULL)
|
2015-05-02 17:41:32 +03:00
|
|
|
ia->ia4_flags |= IN_IFF_TENTATIVE;
|
2015-05-16 15:12:46 +03:00
|
|
|
else if ((ia->ia4_flags & IN_IFF_TENTATIVE) == 0)
|
2019-04-29 14:57:22 +03:00
|
|
|
rt_addrmsg(RTM_NEWADDR, ifa);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ia->ia4_flags & IN_IFF_TENTATIVE) {
|
|
|
|
/* Clear the duplicated flag as we're starting DAD. */
|
|
|
|
ia->ia4_flags &= ~IN_IFF_DUPLICATED;
|
2015-05-16 15:12:46 +03:00
|
|
|
ia->ia_dad_start(ifa);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
2016-09-01 07:27:00 +03:00
|
|
|
|
|
|
|
s = pserialize_read_enter();
|
|
|
|
ifa_release(ifa, &psref);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
2016-09-01 07:27:00 +03:00
|
|
|
pserialize_read_exit(s);
|
|
|
|
curlwp_bindx(bound);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_if_up(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* interface may not support link state, so bring it up also */
|
|
|
|
in_if_link_up(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark all addresses as detached.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
in_if_link_down(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct in_ifaddr *ia;
|
2016-09-01 07:27:00 +03:00
|
|
|
int s, bound;
|
2015-05-02 17:41:32 +03:00
|
|
|
|
2016-09-01 07:27:00 +03:00
|
|
|
bound = curlwp_bind();
|
|
|
|
s = pserialize_read_enter();
|
2016-07-07 12:32:01 +03:00
|
|
|
IFADDR_READER_FOREACH(ifa, ifp) {
|
2016-09-01 07:27:00 +03:00
|
|
|
struct psref psref;
|
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
2016-09-01 07:27:00 +03:00
|
|
|
ifa_acquire(ifa, &psref);
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
2015-05-02 17:41:32 +03:00
|
|
|
ia = (struct in_ifaddr *)ifa;
|
|
|
|
|
|
|
|
/* Stop DAD processing */
|
2015-05-16 15:12:46 +03:00
|
|
|
if (ia->ia_dad_stop != NULL)
|
|
|
|
ia->ia_dad_stop(ifa);
|
2015-05-02 17:41:32 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark the address as detached.
|
|
|
|
*/
|
|
|
|
if (!(ia->ia4_flags & IN_IFF_DETACHED)) {
|
|
|
|
ia->ia4_flags |= IN_IFF_DETACHED;
|
|
|
|
ia->ia4_flags &=
|
|
|
|
~(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED);
|
2019-04-29 14:57:22 +03:00
|
|
|
rt_addrmsg(RTM_NEWADDR, ifa);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
2016-09-01 07:27:00 +03:00
|
|
|
|
|
|
|
s = pserialize_read_enter();
|
|
|
|
ifa_release(ifa, &psref);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
2016-09-01 07:27:00 +03:00
|
|
|
pserialize_read_exit(s);
|
|
|
|
curlwp_bindx(bound);
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_if_down(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
|
|
|
|
in_if_link_down(ifp);
|
2018-02-08 13:11:38 +03:00
|
|
|
#if NARP > 0
|
2017-06-22 12:53:24 +03:00
|
|
|
lltable_purge_entries(LLTABLE(ifp));
|
2018-02-08 13:11:38 +03:00
|
|
|
#endif
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_if_link_state_change(struct ifnet *ifp, int link_state)
|
|
|
|
{
|
|
|
|
|
2020-09-29 22:33:36 +03:00
|
|
|
/*
|
|
|
|
* Treat LINK_STATE_UNKNOWN as UP.
|
|
|
|
* LINK_STATE_UNKNOWN transitions to LINK_STATE_DOWN when
|
|
|
|
* if_link_state_change() transitions to LINK_STATE_UP.
|
|
|
|
*/
|
|
|
|
if (link_state == LINK_STATE_DOWN)
|
2015-05-02 17:41:32 +03:00
|
|
|
in_if_link_down(ifp);
|
2020-09-29 22:33:36 +03:00
|
|
|
else
|
2015-05-02 17:41:32 +03:00
|
|
|
in_if_link_up(ifp);
|
|
|
|
}
|
|
|
|
|
2014-05-30 03:02:48 +04:00
|
|
|
/*
|
|
|
|
* in_lookup_multi: look up the in_multi record for a given IP
|
|
|
|
* multicast address on a given interface. If no matching record is
|
|
|
|
* found, return NULL.
|
|
|
|
*/
|
|
|
|
struct in_multi *
|
|
|
|
in_lookup_multi(struct in_addr addr, ifnet_t *ifp)
|
|
|
|
{
|
|
|
|
struct in_multi *inm;
|
|
|
|
|
|
|
|
KASSERT(rw_lock_held(&in_multilock));
|
|
|
|
|
|
|
|
LIST_FOREACH(inm, &IN_MULTI_HASH(addr.s_addr, ifp), inm_list) {
|
|
|
|
if (in_hosteq(inm->inm_addr, addr) && inm->inm_ifp == ifp)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return inm;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* in_multi_group: check whether the address belongs to an IP multicast
|
|
|
|
* group we are joined on this interface. Returns true or false.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
in_multi_group(struct in_addr addr, ifnet_t *ifp, int flags)
|
|
|
|
{
|
|
|
|
bool ingroup;
|
|
|
|
|
|
|
|
if (__predict_true(flags & IP_IGMP_MCAST) == 0) {
|
|
|
|
rw_enter(&in_multilock, RW_READER);
|
|
|
|
ingroup = in_lookup_multi(addr, ifp) != NULL;
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
} else {
|
|
|
|
/* XXX Recursive call from ip_output(). */
|
|
|
|
KASSERT(rw_lock_held(&in_multilock));
|
|
|
|
ingroup = in_lookup_multi(addr, ifp) != NULL;
|
|
|
|
}
|
|
|
|
return ingroup;
|
|
|
|
}
|
|
|
|
|
1993-12-06 07:50:19 +03:00
|
|
|
/*
|
|
|
|
* Add an address to the list of IP multicast addresses for a given interface.
|
|
|
|
*/
|
|
|
|
struct in_multi *
|
2014-05-30 03:02:48 +04:00
|
|
|
in_addmulti(struct in_addr *ap, ifnet_t *ifp)
|
1993-12-06 07:50:19 +03:00
|
|
|
{
|
2007-09-01 08:32:50 +04:00
|
|
|
struct sockaddr_in sin;
|
2000-03-30 16:51:13 +04:00
|
|
|
struct in_multi *inm;
|
1993-12-06 07:50:19 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* See if address already in list.
|
|
|
|
*/
|
2014-05-30 03:02:48 +04:00
|
|
|
rw_enter(&in_multilock, RW_WRITER);
|
|
|
|
inm = in_lookup_multi(*ap, ifp);
|
1993-12-06 07:50:19 +03:00
|
|
|
if (inm != NULL) {
|
|
|
|
/*
|
|
|
|
* Found it; just increment the reference count.
|
|
|
|
*/
|
2014-05-30 03:02:48 +04:00
|
|
|
inm->inm_refcount++;
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
return inm;
|
1993-12-06 07:50:19 +03:00
|
|
|
}
|
2014-05-30 03:02:48 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* New address; allocate a new multicast record.
|
|
|
|
*/
|
|
|
|
inm = pool_get(&inmulti_pool, PR_NOWAIT);
|
|
|
|
if (inm == NULL) {
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
inm->inm_addr = *ap;
|
|
|
|
inm->inm_ifp = ifp;
|
|
|
|
inm->inm_refcount = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ask the network driver to update its multicast reception
|
|
|
|
* filter appropriately for the new address.
|
|
|
|
*/
|
|
|
|
sockaddr_in_init(&sin, ap, 0);
|
|
|
|
if (if_mcast_op(ifp, SIOCADDMULTI, sintosa(&sin)) != 0) {
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
pool_put(&inmulti_pool, inm);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let IGMP know that we have joined a new IP multicast group.
|
|
|
|
*/
|
|
|
|
if (igmp_joingroup(inm) != 0) {
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
pool_put(&inmulti_pool, inm);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
LIST_INSERT_HEAD(
|
|
|
|
&IN_MULTI_HASH(inm->inm_addr.s_addr, ifp),
|
|
|
|
inm, inm_list);
|
|
|
|
in_multientries++;
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
|
|
|
|
return inm;
|
1993-12-06 07:50:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete a multicast address record.
|
|
|
|
*/
|
1996-02-14 02:40:59 +03:00
|
|
|
void
|
2005-02-03 06:49:01 +03:00
|
|
|
in_delmulti(struct in_multi *inm)
|
1993-12-06 07:50:19 +03:00
|
|
|
{
|
2007-09-01 08:32:50 +04:00
|
|
|
struct sockaddr_in sin;
|
1993-12-06 07:50:19 +03:00
|
|
|
|
2014-05-30 03:02:48 +04:00
|
|
|
rw_enter(&in_multilock, RW_WRITER);
|
|
|
|
if (--inm->inm_refcount > 0) {
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
return;
|
1993-12-06 07:50:19 +03:00
|
|
|
}
|
2014-05-30 03:02:48 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No remaining claims to this record; let IGMP know that
|
|
|
|
* we are leaving the multicast group.
|
|
|
|
*/
|
|
|
|
igmp_leavegroup(inm);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Notify the network driver to update its multicast reception
|
|
|
|
* filter.
|
|
|
|
*/
|
|
|
|
sockaddr_in_init(&sin, &inm->inm_addr, 0);
|
|
|
|
if_mcast_op(inm->inm_ifp, SIOCDELMULTI, sintosa(&sin));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unlink from list.
|
|
|
|
*/
|
|
|
|
LIST_REMOVE(inm, inm_list);
|
|
|
|
in_multientries--;
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
|
|
|
|
pool_put(&inmulti_pool, inm);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* in_next_multi: step through all of the in_multi records, one at a time.
|
|
|
|
* The current position is remembered in "step", which the caller must
|
|
|
|
* provide. in_first_multi(), below, must be called to initialize "step"
|
|
|
|
* and get the first record. Both macros return a NULL "inm" when there
|
|
|
|
* are no remaining records.
|
|
|
|
*/
|
|
|
|
struct in_multi *
|
|
|
|
in_next_multi(struct in_multistep *step)
|
|
|
|
{
|
|
|
|
struct in_multi *inm;
|
|
|
|
|
|
|
|
KASSERT(rw_lock_held(&in_multilock));
|
|
|
|
|
|
|
|
while (step->i_inm == NULL && step->i_n < IN_MULTI_HASH_SIZE) {
|
|
|
|
step->i_inm = LIST_FIRST(&in_multihashtbl[++step->i_n]);
|
|
|
|
}
|
|
|
|
if ((inm = step->i_inm) != NULL) {
|
|
|
|
step->i_inm = LIST_NEXT(inm, inm_list);
|
|
|
|
}
|
|
|
|
return inm;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct in_multi *
|
|
|
|
in_first_multi(struct in_multistep *step)
|
|
|
|
{
|
|
|
|
KASSERT(rw_lock_held(&in_multilock));
|
|
|
|
|
|
|
|
step->i_n = 0;
|
|
|
|
step->i_inm = LIST_FIRST(&in_multihashtbl[0]);
|
|
|
|
return in_next_multi(step);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_multi_lock(int op)
|
|
|
|
{
|
|
|
|
rw_enter(&in_multilock, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_multi_unlock(void)
|
|
|
|
{
|
|
|
|
rw_exit(&in_multilock);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
in_multi_lock_held(void)
|
|
|
|
{
|
|
|
|
return rw_lock_held(&in_multilock);
|
1993-12-06 07:50:19 +03:00
|
|
|
}
|
2014-05-23 02:01:12 +04:00
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
struct in_ifaddr *
|
2014-05-23 02:01:12 +04:00
|
|
|
in_selectsrc(struct sockaddr_in *sin, struct route *ro,
|
2016-08-01 06:15:30 +03:00
|
|
|
int soopts, struct ip_moptions *mopts, int *errorp, struct psref *psref)
|
2014-05-23 02:01:12 +04:00
|
|
|
{
|
|
|
|
struct rtentry *rt = NULL;
|
|
|
|
struct in_ifaddr *ia = NULL;
|
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
KASSERT(ISSET(curlwp->l_pflag, LP_BOUND));
|
2014-05-23 02:01:12 +04:00
|
|
|
/*
|
|
|
|
* If route is known or can be allocated now, take the
|
|
|
|
* source address from the interface. Otherwise, punt.
|
|
|
|
*/
|
|
|
|
if ((soopts & SO_DONTROUTE) != 0)
|
|
|
|
rtcache_free(ro);
|
|
|
|
else {
|
|
|
|
union {
|
|
|
|
struct sockaddr dst;
|
|
|
|
struct sockaddr_in dst4;
|
|
|
|
} u;
|
|
|
|
|
|
|
|
sockaddr_in_init(&u.dst4, &sin->sin_addr, 0);
|
|
|
|
rt = rtcache_lookup(ro, &u.dst);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we found a route, use the address
|
|
|
|
* corresponding to the outgoing interface
|
|
|
|
* unless it is the loopback (in case a route
|
|
|
|
* to our address on another net goes to loopback).
|
|
|
|
*
|
|
|
|
* XXX Is this still true? Do we care?
|
|
|
|
*/
|
2016-08-01 06:15:30 +03:00
|
|
|
if (rt != NULL && (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) {
|
|
|
|
int s;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
/*
|
|
|
|
* Just in case. May not need to do this workaround.
|
|
|
|
* Revisit when working on rtentry MP-ification.
|
|
|
|
*/
|
|
|
|
s = pserialize_read_enter();
|
|
|
|
IFADDR_READER_FOREACH(ifa, rt->rt_ifp) {
|
|
|
|
if (ifa == rt->rt_ifa)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ifa != NULL)
|
|
|
|
ifa_acquire(ifa, psref);
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
|
|
|
ia = ifatoia(ifa);
|
|
|
|
}
|
2014-05-23 02:01:12 +04:00
|
|
|
if (ia == NULL) {
|
2022-11-04 12:03:20 +03:00
|
|
|
in_port_t fport = sin->sin_port;
|
2016-08-01 06:15:30 +03:00
|
|
|
struct ifaddr *ifa;
|
|
|
|
int s;
|
2014-05-23 02:01:12 +04:00
|
|
|
|
|
|
|
sin->sin_port = 0;
|
2016-08-01 06:15:30 +03:00
|
|
|
ifa = ifa_ifwithladdr_psref(sintosa(sin), psref);
|
2014-05-23 02:01:12 +04:00
|
|
|
sin->sin_port = fport;
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ifa == NULL) {
|
2014-05-23 02:01:12 +04:00
|
|
|
/* Find 1st non-loopback AF_INET address */
|
2016-08-01 06:15:30 +03:00
|
|
|
s = pserialize_read_enter();
|
2016-07-06 11:42:34 +03:00
|
|
|
IN_ADDRLIST_READER_FOREACH(ia) {
|
2014-05-23 02:01:12 +04:00
|
|
|
if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK))
|
|
|
|
break;
|
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia != NULL)
|
|
|
|
ia4_acquire(ia, psref);
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
} else {
|
|
|
|
/* ia is already referenced by psref */
|
|
|
|
ia = ifatoia(ifa);
|
2014-05-23 02:01:12 +04:00
|
|
|
}
|
|
|
|
if (ia == NULL) {
|
|
|
|
*errorp = EADDRNOTAVAIL;
|
2016-12-08 08:16:33 +03:00
|
|
|
goto out;
|
2014-05-23 02:01:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If the destination address is multicast and an outgoing
|
|
|
|
* interface has been set as a multicast option, use the
|
|
|
|
* address of that interface as our source address.
|
|
|
|
*/
|
|
|
|
if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) {
|
|
|
|
struct ip_moptions *imo;
|
|
|
|
|
|
|
|
imo = mopts;
|
2016-06-21 06:28:27 +03:00
|
|
|
if (imo->imo_multicast_if_index != 0) {
|
|
|
|
struct ifnet *ifp;
|
2016-08-01 06:15:30 +03:00
|
|
|
int s;
|
2016-06-21 06:28:27 +03:00
|
|
|
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia != NULL)
|
|
|
|
ia4_release(ia, psref);
|
|
|
|
s = pserialize_read_enter();
|
2016-06-21 06:28:27 +03:00
|
|
|
ifp = if_byindex(imo->imo_multicast_if_index);
|
|
|
|
if (ifp != NULL) {
|
2016-08-01 06:15:30 +03:00
|
|
|
/* XXX */
|
|
|
|
ia = in_get_ia_from_ifp_psref(ifp, psref);
|
2016-06-21 06:28:27 +03:00
|
|
|
} else
|
|
|
|
ia = NULL;
|
|
|
|
if (ia == NULL || ia->ia4_flags & IN_IFF_NOTREADY) {
|
|
|
|
pserialize_read_exit(s);
|
2016-08-01 06:15:30 +03:00
|
|
|
if (ia != NULL)
|
|
|
|
ia4_release(ia, psref);
|
2014-05-23 02:01:12 +04:00
|
|
|
*errorp = EADDRNOTAVAIL;
|
2016-12-08 08:16:33 +03:00
|
|
|
ia = NULL;
|
|
|
|
goto out;
|
2014-05-23 02:01:12 +04:00
|
|
|
}
|
2016-06-21 06:28:27 +03:00
|
|
|
pserialize_read_exit(s);
|
2014-05-23 02:01:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ia->ia_ifa.ifa_getifa != NULL) {
|
|
|
|
ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa,
|
|
|
|
sintosa(sin)));
|
2015-05-02 17:41:32 +03:00
|
|
|
if (ia == NULL) {
|
|
|
|
*errorp = EADDRNOTAVAIL;
|
2016-12-08 08:16:33 +03:00
|
|
|
goto out;
|
2015-05-02 17:41:32 +03:00
|
|
|
}
|
2016-08-01 06:15:30 +03:00
|
|
|
/* FIXME NOMPSAFE */
|
|
|
|
ia4_acquire(ia, psref);
|
2014-05-23 02:01:12 +04:00
|
|
|
}
|
|
|
|
#ifdef GETIFA_DEBUG
|
|
|
|
else
|
|
|
|
printf("%s: missing ifa_getifa\n", __func__);
|
|
|
|
#endif
|
2016-12-08 08:16:33 +03:00
|
|
|
out:
|
|
|
|
rtcache_unref(rt, ro);
|
2016-08-01 06:15:30 +03:00
|
|
|
return ia;
|
2014-05-23 02:01:12 +04:00
|
|
|
}
|
|
|
|
|
2018-01-10 13:56:30 +03:00
|
|
|
int
|
|
|
|
in_tunnel_validate(const struct ip *ip, struct in_addr src, struct in_addr dst)
|
|
|
|
{
|
|
|
|
struct in_ifaddr *ia4;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
/* check for address match */
|
|
|
|
if (src.s_addr != ip->ip_dst.s_addr ||
|
|
|
|
dst.s_addr != ip->ip_src.s_addr)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* martian filters on outer source - NOT done in ip_input! */
|
|
|
|
if (IN_MULTICAST(ip->ip_src.s_addr))
|
|
|
|
return 0;
|
|
|
|
switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
|
|
|
|
case 0:
|
|
|
|
case 127:
|
|
|
|
case 255:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* reject packets with broadcast on source */
|
|
|
|
s = pserialize_read_enter();
|
|
|
|
IN_ADDRLIST_READER_FOREACH(ia4) {
|
|
|
|
if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
|
|
|
|
continue;
|
|
|
|
if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) {
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pserialize_read_exit(s);
|
|
|
|
|
|
|
|
/* NOTE: packet may dropped by uRPF */
|
|
|
|
|
|
|
|
/* return valid bytes length */
|
|
|
|
return sizeof(src) + sizeof(dst);
|
|
|
|
}
|
|
|
|
|
2015-11-26 04:41:20 +03:00
|
|
|
#if NARP > 0
|
2015-08-31 19:46:14 +03:00
|
|
|
|
2015-08-31 11:02:44 +03:00
|
|
|
#define IN_LLTBL_DEFAULT_HSIZE 32
|
|
|
|
#define IN_LLTBL_HASH(k, h) \
|
|
|
|
(((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do actual deallocation of @lle.
|
|
|
|
* Called by LLE_FREE_LOCKED when number of references
|
|
|
|
* drops to zero.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
in_lltable_destroy_lle(struct llentry *lle)
|
|
|
|
{
|
|
|
|
|
2019-09-25 12:53:37 +03:00
|
|
|
KASSERTMSG(lle->la_numheld == 0, "la_numheld=%d", lle->la_numheld);
|
2018-03-06 10:20:41 +03:00
|
|
|
|
2015-08-31 11:02:44 +03:00
|
|
|
LLE_WUNLOCK(lle);
|
|
|
|
LLE_LOCK_DESTROY(lle);
|
2018-03-06 10:27:55 +03:00
|
|
|
llentry_pool_put(lle);
|
2015-08-31 11:02:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct llentry *
|
|
|
|
in_lltable_new(struct in_addr addr4, u_int flags)
|
|
|
|
{
|
2018-03-06 10:27:55 +03:00
|
|
|
struct llentry *lle;
|
2015-08-31 11:02:44 +03:00
|
|
|
|
2018-03-06 10:27:55 +03:00
|
|
|
lle = llentry_pool_get(PR_NOWAIT);
|
2015-08-31 11:02:44 +03:00
|
|
|
if (lle == NULL) /* NB: caller generates msg */
|
|
|
|
return NULL;
|
|
|
|
|
2018-03-06 10:27:55 +03:00
|
|
|
lle->r_l3addr.addr4 = addr4;
|
|
|
|
lle->lle_refcnt = 1;
|
|
|
|
lle->lle_free = in_lltable_destroy_lle;
|
|
|
|
LLE_LOCK_INIT(lle);
|
|
|
|
callout_init(&lle->la_timer, CALLOUT_MPSAFE);
|
|
|
|
|
|
|
|
return lle;
|
2015-08-31 11:02:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
|
|
|
|
(((ntohl((d).s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
|
|
|
|
|
|
|
|
static int
|
|
|
|
in_lltable_match_prefix(const struct sockaddr *prefix,
|
|
|
|
const struct sockaddr *mask, u_int flags, struct llentry *lle)
|
|
|
|
{
|
|
|
|
const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
|
|
|
|
const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
|
2017-06-22 12:23:10 +03:00
|
|
|
struct in_addr lle_addr;
|
|
|
|
|
|
|
|
lle_addr.s_addr = ntohl(lle->r_l3addr.addr4.s_addr);
|
2015-08-31 11:02:44 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* (flags & LLE_STATIC) means deleting all entries
|
|
|
|
* including static ARP entries.
|
|
|
|
*/
|
2017-06-22 12:23:10 +03:00
|
|
|
if (IN_ARE_MASKED_ADDR_EQUAL(lle_addr, pfx, msk) &&
|
2015-08-31 11:02:44 +03:00
|
|
|
((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_lltable_free_entry(struct lltable *llt, struct llentry *lle)
|
|
|
|
{
|
|
|
|
size_t pkts_dropped;
|
|
|
|
|
|
|
|
LLE_WLOCK_ASSERT(lle);
|
|
|
|
KASSERT(llt != NULL);
|
|
|
|
|
|
|
|
pkts_dropped = llentry_free(lle);
|
2015-08-31 11:05:20 +03:00
|
|
|
arp_stat_add(ARP_STAT_DFRDROPPED, (uint64_t)pkts_dropped);
|
2015-08-31 11:02:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-11-10 10:24:28 +03:00
|
|
|
in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr,
|
|
|
|
const struct rtentry *rt)
|
2015-08-31 11:02:44 +03:00
|
|
|
{
|
|
|
|
int error = EINVAL;
|
|
|
|
|
|
|
|
if (rt == NULL)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the gateway for an existing host route matches the target L3
|
|
|
|
* address, which is a special route inserted by some implementation
|
|
|
|
* such as MANET, and the interface is of the correct type, then
|
|
|
|
* allow for ARP to proceed.
|
|
|
|
*/
|
|
|
|
if (rt->rt_flags & RTF_GATEWAY) {
|
|
|
|
if (!(rt->rt_flags & RTF_HOST) || !rt->rt_ifp ||
|
|
|
|
rt->rt_ifp->if_type != IFT_ETHER ||
|
|
|
|
(rt->rt_ifp->if_flags & IFF_NOARP) != 0 ||
|
|
|
|
memcmp(rt->rt_gateway->sa_data, l3addr->sa_data,
|
|
|
|
sizeof(in_addr_t)) != 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure that at least the destination address is covered
|
|
|
|
* by the route. This is for handling the case where 2 or more
|
|
|
|
* interfaces have the same prefix. An incoming packet arrives
|
|
|
|
* on one interface and the corresponding outgoing packet leaves
|
|
|
|
* another interface.
|
|
|
|
*/
|
|
|
|
if (!(rt->rt_flags & RTF_HOST) && rt->rt_ifp != ifp) {
|
|
|
|
const char *sa, *mask, *addr, *lim;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
mask = (const char *)rt_mask(rt);
|
|
|
|
/*
|
|
|
|
* Just being extra cautious to avoid some custom
|
|
|
|
* code getting into trouble.
|
|
|
|
*/
|
|
|
|
if (mask == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
sa = (const char *)rt_getkey(rt);
|
|
|
|
addr = (const char *)l3addr;
|
|
|
|
len = ((const struct sockaddr_in *)l3addr)->sin_len;
|
|
|
|
lim = addr + len;
|
|
|
|
|
|
|
|
for ( ; addr < lim; sa++, mask++, addr++) {
|
|
|
|
if ((*sa ^ *addr) & *mask) {
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
|
|
|
|
inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
|
|
|
|
#endif
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
error:
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint32_t
|
|
|
|
in_lltable_hash_dst(const struct in_addr dst, uint32_t hsize)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (IN_LLTBL_HASH(dst.s_addr, hsize));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
in_lltable_hash(const struct llentry *lle, uint32_t hsize)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (in_lltable_hash_dst(lle->r_l3addr.addr4, hsize));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
|
|
|
|
{
|
|
|
|
struct sockaddr_in *sin;
|
|
|
|
|
|
|
|
sin = (struct sockaddr_in *)sa;
|
|
|
|
memset(sin, 0, sizeof(*sin));
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_len = sizeof(*sin);
|
|
|
|
sin->sin_addr = lle->r_l3addr.addr4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct llentry *
|
|
|
|
in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
|
|
|
|
{
|
|
|
|
struct llentry *lle;
|
|
|
|
struct llentries *lleh;
|
|
|
|
u_int hashidx;
|
|
|
|
|
|
|
|
hashidx = in_lltable_hash_dst(dst, llt->llt_hsize);
|
|
|
|
lleh = &llt->lle_head[hashidx];
|
|
|
|
LIST_FOREACH(lle, lleh, lle_next) {
|
|
|
|
if (lle->la_flags & LLE_DELETED)
|
|
|
|
continue;
|
|
|
|
if (lle->r_l3addr.addr4.s_addr == dst.s_addr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (lle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
in_lltable_delete(struct lltable *llt, u_int flags,
|
|
|
|
const struct sockaddr *l3addr)
|
|
|
|
{
|
|
|
|
const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
|
2015-08-31 12:21:55 +03:00
|
|
|
struct ifnet *ifp __diagused = llt->llt_ifp;
|
2015-08-31 11:02:44 +03:00
|
|
|
struct llentry *lle;
|
|
|
|
|
|
|
|
IF_AFDATA_WLOCK_ASSERT(ifp);
|
|
|
|
KASSERTMSG(l3addr->sa_family == AF_INET,
|
|
|
|
"sin_family %d", l3addr->sa_family);
|
|
|
|
|
|
|
|
lle = in_lltable_find_dst(llt, sin->sin_addr);
|
|
|
|
if (lle == NULL) {
|
2018-01-19 11:01:05 +03:00
|
|
|
#ifdef LLTABLE_DEBUG
|
2017-04-28 08:56:33 +03:00
|
|
|
char buf[64];
|
|
|
|
sockaddr_format(l3addr, buf, sizeof(buf));
|
|
|
|
log(LOG_INFO, "%s: cache for %s is not found\n",
|
|
|
|
__func__, buf);
|
2015-08-31 11:02:44 +03:00
|
|
|
#endif
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
|
2016-04-04 10:37:07 +03:00
|
|
|
LLE_WLOCK(lle);
|
2018-01-19 11:01:05 +03:00
|
|
|
#ifdef LLTABLE_DEBUG
|
2017-04-28 08:56:33 +03:00
|
|
|
{
|
|
|
|
char buf[64];
|
|
|
|
sockaddr_format(l3addr, buf, sizeof(buf));
|
|
|
|
log(LOG_INFO, "%s: cache for %s (%p) is deleted\n",
|
|
|
|
__func__, buf, lle);
|
|
|
|
}
|
2015-08-31 11:02:44 +03:00
|
|
|
#endif
|
2018-03-06 10:25:27 +03:00
|
|
|
llentry_free(lle);
|
2015-08-31 11:02:44 +03:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct llentry *
|
2017-11-10 10:24:28 +03:00
|
|
|
in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr,
|
|
|
|
const struct rtentry *rt)
|
2015-08-31 11:02:44 +03:00
|
|
|
{
|
|
|
|
const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
|
|
|
|
struct ifnet *ifp = llt->llt_ifp;
|
|
|
|
struct llentry *lle;
|
|
|
|
|
|
|
|
IF_AFDATA_WLOCK_ASSERT(ifp);
|
|
|
|
KASSERTMSG(l3addr->sa_family == AF_INET,
|
|
|
|
"sin_family %d", l3addr->sa_family);
|
|
|
|
|
|
|
|
lle = in_lltable_find_dst(llt, sin->sin_addr);
|
|
|
|
|
|
|
|
if (lle != NULL) {
|
|
|
|
LLE_WLOCK(lle);
|
|
|
|
return (lle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no existing record, we need to create new one */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A route that covers the given address must have
|
|
|
|
* been installed 1st because we are doing a resolution,
|
|
|
|
* verify this.
|
|
|
|
*/
|
|
|
|
if (!(flags & LLE_IFADDR) &&
|
2017-11-10 10:24:28 +03:00
|
|
|
in_lltable_rtcheck(ifp, flags, l3addr, rt) != 0)
|
2015-08-31 11:02:44 +03:00
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
lle = in_lltable_new(sin->sin_addr, flags);
|
|
|
|
if (lle == NULL) {
|
|
|
|
log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
lle->la_flags = flags;
|
|
|
|
if ((flags & LLE_IFADDR) == LLE_IFADDR) {
|
|
|
|
memcpy(&lle->ll_addr, CLLADDR(ifp->if_sadl), ifp->if_addrlen);
|
|
|
|
lle->la_flags |= (LLE_VALID | LLE_STATIC);
|
|
|
|
}
|
|
|
|
|
|
|
|
lltable_link_entry(llt, lle);
|
|
|
|
LLE_WLOCK(lle);
|
|
|
|
|
|
|
|
return (lle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return NULL if not found or marked for deletion.
|
|
|
|
* If found return lle read locked.
|
|
|
|
*/
|
|
|
|
static struct llentry *
|
|
|
|
in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
|
|
|
|
{
|
|
|
|
const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
|
|
|
|
struct llentry *lle;
|
|
|
|
|
|
|
|
IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
|
|
|
|
KASSERTMSG(l3addr->sa_family == AF_INET,
|
|
|
|
"sin_family %d", l3addr->sa_family);
|
|
|
|
|
|
|
|
lle = in_lltable_find_dst(llt, sin->sin_addr);
|
|
|
|
|
|
|
|
if (lle == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (flags & LLE_EXCLUSIVE)
|
|
|
|
LLE_WLOCK(lle);
|
|
|
|
else
|
|
|
|
LLE_RLOCK(lle);
|
|
|
|
|
|
|
|
return lle;
|
|
|
|
}
|
|
|
|
|
2016-04-04 10:37:07 +03:00
|
|
|
static int
|
|
|
|
in_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
|
|
|
|
struct rt_walkarg *w)
|
|
|
|
{
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
|
|
|
|
LLTABLE_LOCK_ASSERT();
|
|
|
|
|
|
|
|
/* skip deleted entries */
|
|
|
|
if (lle->la_flags & LLE_DELETED)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sockaddr_in_init(&sin, &lle->r_l3addr.addr4, 0);
|
|
|
|
|
|
|
|
return lltable_dump_entry(llt, lle, w, sintosa(&sin));
|
|
|
|
}
|
|
|
|
|
2015-11-26 04:41:20 +03:00
|
|
|
#endif /* NARP > 0 */
|
2015-08-31 19:46:14 +03:00
|
|
|
|
2016-07-14 21:18:16 +03:00
|
|
|
static int
|
|
|
|
in_multicast_sysctl(SYSCTLFN_ARGS)
|
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct in_ifaddr *ifa4;
|
|
|
|
struct in_multi *inm;
|
|
|
|
uint32_t tmp;
|
|
|
|
int error;
|
|
|
|
size_t written;
|
|
|
|
struct psref psref;
|
|
|
|
int bound;
|
|
|
|
|
|
|
|
if (namelen != 1)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
bound = curlwp_bind();
|
|
|
|
ifp = if_get_byindex(name[0], &psref);
|
|
|
|
if (ifp == NULL) {
|
|
|
|
curlwp_bindx(bound);
|
|
|
|
return ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldp == NULL) {
|
|
|
|
*oldlenp = 0;
|
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
|
|
|
ifa4 = (void *)ifa;
|
|
|
|
LIST_FOREACH(inm, &ifa4->ia_multiaddrs, inm_list) {
|
|
|
|
*oldlenp += 2 * sizeof(struct in_addr) +
|
|
|
|
sizeof(uint32_t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if_put(ifp, &psref);
|
|
|
|
curlwp_bindx(bound);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
written = 0;
|
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
|
|
|
ifa4 = (void *)ifa;
|
|
|
|
LIST_FOREACH(inm, &ifa4->ia_multiaddrs, inm_list) {
|
|
|
|
if (written + 2 * sizeof(struct in_addr) +
|
|
|
|
sizeof(uint32_t) > *oldlenp)
|
|
|
|
goto done;
|
|
|
|
error = sysctl_copyout(l, &ifa4->ia_addr.sin_addr,
|
|
|
|
oldp, sizeof(struct in_addr));
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
oldp = (char *)oldp + sizeof(struct in_addr);
|
|
|
|
written += sizeof(struct in_addr);
|
|
|
|
error = sysctl_copyout(l, &inm->inm_addr,
|
|
|
|
oldp, sizeof(struct in_addr));
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
oldp = (char *)oldp + sizeof(struct in_addr);
|
|
|
|
written += sizeof(struct in_addr);
|
|
|
|
tmp = inm->inm_refcount;
|
|
|
|
error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp));
|
|
|
|
if (error)
|
|
|
|
goto done;
|
|
|
|
oldp = (char *)oldp + sizeof(tmp);
|
|
|
|
written += sizeof(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
if_put(ifp, &psref);
|
|
|
|
curlwp_bindx(bound);
|
|
|
|
*oldlenp = written;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2014-05-23 02:01:12 +04:00
|
|
|
static void
|
|
|
|
in_sysctl_init(struct sysctllog **clog)
|
|
|
|
{
|
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "inet",
|
|
|
|
SYSCTL_DESCR("PF_INET related settings"),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, CTL_EOL);
|
2016-07-14 21:18:16 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "multicast",
|
|
|
|
SYSCTL_DESCR("Multicast information"),
|
|
|
|
in_multicast_sysctl, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, CTL_CREATE, CTL_EOL);
|
2014-05-23 02:01:12 +04:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "ip",
|
|
|
|
SYSCTL_DESCR("IPv4 related settings"),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_IP, CTL_EOL);
|
|
|
|
|
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "subnetsarelocal",
|
|
|
|
SYSCTL_DESCR("Whether logical subnets are considered "
|
|
|
|
"local"),
|
|
|
|
NULL, 0, &subnetsarelocal, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_IP,
|
|
|
|
IPCTL_SUBNETSARELOCAL, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "hostzerobroadcast",
|
|
|
|
SYSCTL_DESCR("All zeroes address is broadcast address"),
|
|
|
|
NULL, 0, &hostzeroisbroadcast, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_IP,
|
|
|
|
IPCTL_HOSTZEROBROADCAST, CTL_EOL);
|
|
|
|
}
|
2015-08-31 11:02:44 +03:00
|
|
|
|
2015-11-26 04:41:20 +03:00
|
|
|
#if NARP > 0
|
|
|
|
|
2015-08-31 11:02:44 +03:00
|
|
|
static struct lltable *
|
2022-11-19 11:00:51 +03:00
|
|
|
in_lltattach(struct ifnet *ifp, struct in_ifinfo *ii)
|
2015-08-31 11:02:44 +03:00
|
|
|
{
|
|
|
|
struct lltable *llt;
|
|
|
|
|
|
|
|
llt = lltable_allocate_htbl(IN_LLTBL_DEFAULT_HSIZE);
|
|
|
|
llt->llt_af = AF_INET;
|
|
|
|
llt->llt_ifp = ifp;
|
|
|
|
|
|
|
|
llt->llt_lookup = in_lltable_lookup;
|
|
|
|
llt->llt_create = in_lltable_create;
|
|
|
|
llt->llt_delete = in_lltable_delete;
|
|
|
|
llt->llt_dump_entry = in_lltable_dump_entry;
|
|
|
|
llt->llt_hash = in_lltable_hash;
|
|
|
|
llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;
|
|
|
|
llt->llt_free_entry = in_lltable_free_entry;
|
|
|
|
llt->llt_match_prefix = in_lltable_match_prefix;
|
2022-11-19 11:00:51 +03:00
|
|
|
#ifdef MBUFTRACE
|
|
|
|
struct mowner *mowner = &ii->ii_mowner;
|
|
|
|
mowner_init_owner(mowner, ifp->if_xname, "arp");
|
|
|
|
MOWNER_ATTACH(mowner);
|
|
|
|
llt->llt_mowner = mowner;
|
|
|
|
#endif
|
2015-08-31 11:02:44 +03:00
|
|
|
lltable_link(llt);
|
|
|
|
|
|
|
|
return (llt);
|
|
|
|
}
|
2015-11-26 04:41:20 +03:00
|
|
|
|
|
|
|
#endif /* NARP > 0 */
|
2015-08-31 11:02:44 +03:00
|
|
|
|
|
|
|
void *
|
|
|
|
in_domifattach(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct in_ifinfo *ii;
|
|
|
|
|
|
|
|
ii = kmem_zalloc(sizeof(struct in_ifinfo), KM_SLEEP);
|
|
|
|
|
2015-11-26 04:41:20 +03:00
|
|
|
#if NARP > 0
|
2022-11-19 11:00:51 +03:00
|
|
|
ii->ii_llt = in_lltattach(ifp, ii);
|
2015-08-31 19:46:14 +03:00
|
|
|
#endif
|
2015-08-31 11:02:44 +03:00
|
|
|
|
|
|
|
#ifdef IPSELSRC
|
|
|
|
ii->ii_selsrc = in_selsrc_domifattach(ifp);
|
|
|
|
KASSERT(ii->ii_selsrc != NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ii;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
in_domifdetach(struct ifnet *ifp, void *aux)
|
|
|
|
{
|
|
|
|
struct in_ifinfo *ii = aux;
|
|
|
|
|
|
|
|
#ifdef IPSELSRC
|
|
|
|
in_selsrc_domifdetach(ifp, ii->ii_selsrc);
|
|
|
|
#endif
|
2015-11-26 04:41:20 +03:00
|
|
|
#if NARP > 0
|
2015-08-31 11:02:44 +03:00
|
|
|
lltable_free(ii->ii_llt);
|
2022-11-19 11:00:51 +03:00
|
|
|
#ifdef MBUFTRACE
|
|
|
|
MOWNER_DETACH(&ii->ii_mowner);
|
|
|
|
#endif
|
2015-08-31 19:46:14 +03:00
|
|
|
#endif
|
2015-08-31 11:02:44 +03:00
|
|
|
kmem_free(ii, sizeof(struct in_ifinfo));
|
|
|
|
}
|