2009-11-14 02:11:08 +03:00
|
|
|
/* $NetBSD: if.c,v 1.241 2009/11/13 23:11:08 joerg Exp $ */
|
2000-02-02 01:52:04 +03:00
|
|
|
|
|
|
|
/*-
|
2008-04-24 15:38:36 +04:00
|
|
|
* Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
|
2000-02-02 01:52:04 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
2004-12-05 02:03:33 +03:00
|
|
|
* by William Studenmund and Jason R. Thorpe.
|
2000-02-02 01:52:04 +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.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2005-02-27 01:45:09 +03: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.
|
2005-02-27 01:45:09 +03: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.
|
|
|
|
*/
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1994-05-13 10:01:27 +04:00
|
|
|
* Copyright (c) 1980, 1986, 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-03-01 05:20:01 +03:00
|
|
|
* @(#)if.c 8.5 (Berkeley) 1/9/95
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-13 02:49:33 +03:00
|
|
|
#include <sys/cdefs.h>
|
2009-11-14 02:11:08 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.241 2009/11/13 23:11:08 joerg Exp $");
|
2001-11-13 02:49:33 +03:00
|
|
|
|
1999-07-10 03:41:16 +04:00
|
|
|
#include "opt_inet.h"
|
|
|
|
|
1999-08-24 20:02:27 +04:00
|
|
|
#include "opt_atalk.h"
|
2003-06-23 15:00:59 +04:00
|
|
|
#include "opt_natm.h"
|
2001-04-11 01:45:39 +04:00
|
|
|
#include "opt_pfil_hooks.h"
|
1998-06-26 03:18:23 +04:00
|
|
|
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/systm.h>
|
2000-03-23 10:01:25 +03:00
|
|
|
#include <sys/callout.h>
|
1994-05-13 10:01:27 +04:00
|
|
|
#include <sys/proc.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
2000-02-06 19:43:33 +03:00
|
|
|
#include <sys/domain.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <sys/protosw.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/ioctl.h>
|
2003-11-10 23:03:29 +03:00
|
|
|
#include <sys/sysctl.h>
|
2005-06-22 10:14:51 +04:00
|
|
|
#include <sys/syslog.h>
|
2006-05-15 01:19:33 +04:00
|
|
|
#include <sys/kauth.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_dl.h>
|
2000-07-19 10:00:39 +04:00
|
|
|
#include <net/if_ether.h>
|
2003-07-06 11:54:43 +04:00
|
|
|
#include <net/if_media.h>
|
2003-10-13 12:02:02 +04:00
|
|
|
#include <net80211/ieee80211.h>
|
|
|
|
#include <net80211/ieee80211_ioctl.h>
|
1993-12-18 03:40:47 +03:00
|
|
|
#include <net/if_types.h>
|
1996-02-14 00:59:53 +03:00
|
|
|
#include <net/radix.h>
|
2000-02-02 01:52:04 +03:00
|
|
|
#include <net/route.h>
|
2001-07-29 07:28:30 +04:00
|
|
|
#include <net/netisr.h>
|
1999-08-24 20:02:27 +04:00
|
|
|
#ifdef NETATALK
|
|
|
|
#include <netatalk/at_extern.h>
|
|
|
|
#include <netatalk/at.h>
|
|
|
|
#endif
|
2004-06-22 16:50:41 +04:00
|
|
|
#include <net/pfil.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1999-07-01 12:12:45 +04:00
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet/in.h>
|
2000-10-05 01:12:40 +04:00
|
|
|
#include <netinet6/in6_var.h>
|
2002-05-30 09:06:28 +04:00
|
|
|
#include <netinet6/nd6.h>
|
1999-07-01 12:12:45 +04:00
|
|
|
#endif
|
|
|
|
|
2006-05-18 13:05:49 +04:00
|
|
|
#include "carp.h"
|
|
|
|
#if NCARP > 0
|
|
|
|
#include <netinet/ip_carp.h>
|
|
|
|
#endif
|
|
|
|
|
2007-05-30 01:32:27 +04:00
|
|
|
#include <compat/sys/sockio.h>
|
2005-09-24 19:52:03 +04:00
|
|
|
#include <compat/sys/socket.h>
|
|
|
|
|
2003-02-01 09:23:35 +03:00
|
|
|
MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
|
|
|
|
MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
int ifqmaxlen = IFQ_MAXLEN;
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_t if_slowtimo_ch;
|
2000-03-23 10:01:25 +03:00
|
|
|
|
2002-05-13 00:40:11 +04:00
|
|
|
int netisr; /* scheduling bits for network */
|
|
|
|
|
2007-06-09 07:07:21 +04:00
|
|
|
static int if_rt_walktree(struct rtentry *, void *);
|
2000-02-02 01:52:04 +03:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static struct if_clone *if_clone_lookup(const char *, int *);
|
|
|
|
static int if_clone_list(struct if_clonereq *);
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
|
|
|
|
static int if_cloners_count;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2009-08-13 04:23:31 +04:00
|
|
|
static uint64_t index_gen;
|
|
|
|
static kmutex_t index_gen_mtx;
|
|
|
|
|
2004-06-22 16:50:41 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
struct pfil_head if_pfil; /* packet filtering hook for interfaces */
|
|
|
|
#endif
|
|
|
|
|
2009-10-03 05:46:39 +04:00
|
|
|
static kauth_listener_t if_listener;
|
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static void if_detach_queues(struct ifnet *, struct ifqueue *);
|
2009-08-13 04:23:31 +04:00
|
|
|
static void sysctl_sndq_setup(struct sysctllog **, const char *,
|
|
|
|
struct ifaltq *);
|
2001-07-29 07:28:30 +04:00
|
|
|
|
2009-10-26 19:41:35 +03:00
|
|
|
#if defined(INET) || defined(INET6)
|
2009-09-16 19:23:04 +04:00
|
|
|
static void sysctl_net_ifq_setup(struct sysctllog **, int, const char *,
|
|
|
|
int, const char *, int, struct ifqueue *);
|
2009-10-26 19:41:35 +03:00
|
|
|
#endif
|
2009-09-16 19:23:04 +04:00
|
|
|
|
2009-10-03 05:46:39 +04:00
|
|
|
static int
|
|
|
|
if_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
|
|
|
|
void *arg0, void *arg1, void *arg2, void *arg3)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
enum kauth_network_req req;
|
|
|
|
|
|
|
|
result = KAUTH_RESULT_DEFER;
|
|
|
|
req = (enum kauth_network_req)arg1;
|
|
|
|
|
|
|
|
if (action != KAUTH_NETWORK_INTERFACE)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
if ((req == KAUTH_REQ_NETWORK_INTERFACE_GET) ||
|
|
|
|
(req == KAUTH_REQ_NETWORK_INTERFACE_SET))
|
|
|
|
result = KAUTH_RESULT_ALLOW;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Network interface utility routines.
|
|
|
|
*
|
|
|
|
* Routines with ifa_ifwith* names take sockaddr *'s as
|
|
|
|
* parameters.
|
|
|
|
*/
|
1993-06-27 10:01:27 +04:00
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
ifinit(void)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2009-09-16 19:23:04 +04:00
|
|
|
#ifdef INET
|
|
|
|
{extern struct ifqueue ipintrq;
|
|
|
|
sysctl_net_ifq_setup(NULL, PF_INET, "inet", IPPROTO_IP, "ip",
|
|
|
|
IPCTL_IFQ, &ipintrq);}
|
|
|
|
#endif /* INET */
|
|
|
|
#ifdef INET6
|
|
|
|
{extern struct ifqueue ip6intrq;
|
|
|
|
sysctl_net_ifq_setup(NULL, PF_INET6, "inet6", IPPROTO_IPV6, "ip6",
|
|
|
|
IPV6CTL_IFQ, &ip6intrq);}
|
|
|
|
#endif /* INET6 */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&if_slowtimo_ch, 0);
|
1993-06-27 10:01:27 +04:00
|
|
|
if_slowtimo(NULL);
|
2009-10-03 05:46:39 +04:00
|
|
|
|
|
|
|
if_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
|
|
|
|
if_listener_cb, NULL);
|
2008-06-18 13:06:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX Initialization before configure().
|
|
|
|
* XXX hack to get pfil_add_hook working in autoconf.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ifinit1(void)
|
|
|
|
{
|
|
|
|
|
2009-09-19 15:02:07 +04:00
|
|
|
mutex_init(&index_gen_mtx, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
|
2004-06-22 16:50:41 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
if_pfil.ph_type = PFIL_TYPE_IFNET;
|
|
|
|
if_pfil.ph_ifnet = NULL;
|
|
|
|
if (pfil_head_register(&if_pfil) != 0)
|
|
|
|
printf("WARNING: unable to register pfil hook\n");
|
|
|
|
#endif
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2008-06-15 20:37:21 +04:00
|
|
|
struct ifnet *
|
|
|
|
if_alloc(u_char type)
|
|
|
|
{
|
|
|
|
return malloc(sizeof(struct ifnet), M_DEVBUF, M_WAITOK|M_ZERO);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
if_initname(struct ifnet *ifp, const char *name, int unit)
|
|
|
|
{
|
|
|
|
(void)snprintf(ifp->if_xname, sizeof(ifp->if_xname),
|
|
|
|
"%s%d", name, unit);
|
|
|
|
}
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
/*
|
|
|
|
* Null routines used while an interface is going away. These routines
|
|
|
|
* just return an error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nulloutput(struct ifnet *ifp, struct mbuf *m,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
const struct sockaddr *so, struct rtentry *rt)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return ENXIO;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nullinput(struct ifnet *ifp, struct mbuf *m)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
/* Nothing. */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nullstart(struct ifnet *ifp)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
/* Nothing. */
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-03-04 08:59:00 +03:00
|
|
|
if_nullioctl(struct ifnet *ifp, u_long cmd, void *data)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return ENXIO;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nullinit(struct ifnet *ifp)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return ENXIO;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
|
2000-10-11 20:52:34 +04:00
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nullstop(struct ifnet *ifp, int disable)
|
2000-10-11 20:52:34 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
/* Nothing. */
|
|
|
|
}
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nullwatchdog(struct ifnet *ifp)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
/* Nothing. */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
if_nulldrain(struct ifnet *ifp)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
/* Nothing. */
|
|
|
|
}
|
|
|
|
|
2003-12-10 14:46:33 +03:00
|
|
|
static u_int if_index = 1;
|
2002-03-17 13:21:42 +03:00
|
|
|
struct ifnet_head ifnet;
|
2003-12-10 14:46:33 +03:00
|
|
|
size_t if_indexlim = 0;
|
1999-07-01 12:12:45 +04:00
|
|
|
struct ifaddr **ifnet_addrs = NULL;
|
|
|
|
struct ifnet **ifindex2ifnet = NULL;
|
2004-12-04 19:10:25 +03:00
|
|
|
struct ifnet *lo0ifp;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-12-21 00:08:17 +03:00
|
|
|
void
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
if_set_sadl(struct ifnet *ifp, const void *lla, u_char addrlen, bool factory)
|
2007-12-21 00:08:17 +03:00
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct sockaddr_dl *sdl;
|
|
|
|
|
|
|
|
ifp->if_addrlen = addrlen;
|
|
|
|
if_alloc_sadl(ifp);
|
|
|
|
ifa = ifp->if_dl;
|
|
|
|
sdl = satosdl(ifa->ifa_addr);
|
|
|
|
|
|
|
|
(void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lla, ifp->if_addrlen);
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
if (factory) {
|
|
|
|
ifp->if_hwdl = ifp->if_dl;
|
|
|
|
IFAREF(ifp->if_hwdl);
|
|
|
|
}
|
2008-05-12 03:48:07 +04:00
|
|
|
/* TBD routing socket */
|
2007-12-21 00:08:17 +03:00
|
|
|
}
|
|
|
|
|
2008-01-22 19:25:15 +03:00
|
|
|
struct ifaddr *
|
|
|
|
if_dl_create(const struct ifnet *ifp, const struct sockaddr_dl **sdlp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
unsigned socksize, ifasize;
|
2007-08-07 08:14:37 +04:00
|
|
|
int addrlen, namelen;
|
|
|
|
struct sockaddr_dl *mask, *sdl;
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifaddr *ifa;
|
2001-01-17 03:30:49 +03:00
|
|
|
|
|
|
|
namelen = strlen(ifp->if_xname);
|
2007-08-07 08:14:37 +04:00
|
|
|
addrlen = ifp->if_addrlen;
|
Use malloc(9) for sockaddrs instead of pool(9), and remove dom_sa_pool
and dom_sa_len members from struct domain. Pools of fixed-size
objects are too rigid for sockaddr_dls, whose size can vary over
a wide range.
Return sockaddr_dl to its "historical" size. Now that I'm using
malloc(9) instead of pool(9) to allocate sockaddr_dl, I can create
a sockaddr_dl of any size in the kernel, so expanding sockaddr_dl
is useless.
Avoid using sizeof(struct sockaddr_dl) in the kernel.
Introduce sockaddr_dl_alloc() for allocating & initializing an
arbitrary sockaddr_dl on the heap.
Add an argument, the sockaddr length, to sockaddr_alloc(),
sockaddr_copy(), and sockaddr_dl_setaddr().
Constify: LLADDR() -> CLLADDR().
Where the kernel overwrites LLADDR(), use sockaddr_dl_setaddr(),
instead. Used properly, sockaddr_dl_setaddr() will not overrun
the end of the sockaddr.
2007-08-30 06:17:34 +04:00
|
|
|
socksize = roundup(sockaddr_dl_measure(namelen, addrlen), sizeof(long));
|
2001-01-17 03:30:49 +03:00
|
|
|
ifasize = sizeof(*ifa) + 2 * socksize;
|
2007-11-01 23:37:48 +03:00
|
|
|
ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK|M_ZERO);
|
2007-08-07 08:14:37 +04:00
|
|
|
|
2001-01-17 03:30:49 +03:00
|
|
|
sdl = (struct sockaddr_dl *)(ifa + 1);
|
2007-08-07 08:14:37 +04:00
|
|
|
mask = (struct sockaddr_dl *)(socksize + (char *)sdl);
|
|
|
|
|
Use malloc(9) for sockaddrs instead of pool(9), and remove dom_sa_pool
and dom_sa_len members from struct domain. Pools of fixed-size
objects are too rigid for sockaddr_dls, whose size can vary over
a wide range.
Return sockaddr_dl to its "historical" size. Now that I'm using
malloc(9) instead of pool(9) to allocate sockaddr_dl, I can create
a sockaddr_dl of any size in the kernel, so expanding sockaddr_dl
is useless.
Avoid using sizeof(struct sockaddr_dl) in the kernel.
Introduce sockaddr_dl_alloc() for allocating & initializing an
arbitrary sockaddr_dl on the heap.
Add an argument, the sockaddr length, to sockaddr_alloc(),
sockaddr_copy(), and sockaddr_dl_setaddr().
Constify: LLADDR() -> CLLADDR().
Where the kernel overwrites LLADDR(), use sockaddr_dl_setaddr(),
instead. Used properly, sockaddr_dl_setaddr() will not overrun
the end of the sockaddr.
2007-08-30 06:17:34 +04:00
|
|
|
sockaddr_dl_init(sdl, socksize, ifp->if_index, ifp->if_type,
|
2007-08-07 08:14:37 +04:00
|
|
|
ifp->if_xname, namelen, NULL, addrlen);
|
|
|
|
mask->sdl_len = sockaddr_dl_measure(namelen, 0);
|
Use malloc(9) for sockaddrs instead of pool(9), and remove dom_sa_pool
and dom_sa_len members from struct domain. Pools of fixed-size
objects are too rigid for sockaddr_dls, whose size can vary over
a wide range.
Return sockaddr_dl to its "historical" size. Now that I'm using
malloc(9) instead of pool(9) to allocate sockaddr_dl, I can create
a sockaddr_dl of any size in the kernel, so expanding sockaddr_dl
is useless.
Avoid using sizeof(struct sockaddr_dl) in the kernel.
Introduce sockaddr_dl_alloc() for allocating & initializing an
arbitrary sockaddr_dl on the heap.
Add an argument, the sockaddr length, to sockaddr_alloc(),
sockaddr_copy(), and sockaddr_dl_setaddr().
Constify: LLADDR() -> CLLADDR().
Where the kernel overwrites LLADDR(), use sockaddr_dl_setaddr(),
instead. Used properly, sockaddr_dl_setaddr() will not overrun
the end of the sockaddr.
2007-08-30 06:17:34 +04:00
|
|
|
memset(&mask->sdl_data[0], 0xff, namelen);
|
2008-01-22 19:25:15 +03:00
|
|
|
ifa->ifa_rtrequest = link_rtrequest;
|
|
|
|
ifa->ifa_addr = (struct sockaddr *)sdl;
|
|
|
|
ifa->ifa_netmask = (struct sockaddr *)mask;
|
|
|
|
|
|
|
|
*sdlp = sdl;
|
|
|
|
|
|
|
|
return ifa;
|
|
|
|
}
|
|
|
|
|
2008-05-12 03:48:07 +04:00
|
|
|
static void
|
|
|
|
if_sadl_setrefs(struct ifnet *ifp, struct ifaddr *ifa)
|
|
|
|
{
|
|
|
|
const struct sockaddr_dl *sdl;
|
|
|
|
ifnet_addrs[ifp->if_index] = ifa;
|
|
|
|
IFAREF(ifa);
|
|
|
|
ifp->if_dl = ifa;
|
|
|
|
IFAREF(ifa);
|
|
|
|
sdl = satosdl(ifa->ifa_addr);
|
|
|
|
ifp->if_sadl = sdl;
|
|
|
|
}
|
|
|
|
|
2008-01-22 19:25:15 +03:00
|
|
|
/*
|
|
|
|
* Allocate the link level name for the specified interface. This
|
|
|
|
* is an attachment helper. It must be called after ifp->if_addrlen
|
|
|
|
* is initialized, which may not be the case when if_attach() is
|
|
|
|
* called.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
if_alloc_sadl(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
const struct sockaddr_dl *sdl;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the interface already has a link name, release it
|
|
|
|
* now. This is useful for interfaces that can change
|
|
|
|
* link types, and thus switch link names often.
|
|
|
|
*/
|
|
|
|
if (ifp->if_sadl != NULL)
|
|
|
|
if_free_sadl(ifp);
|
|
|
|
|
|
|
|
ifa = if_dl_create(ifp, &sdl);
|
2007-08-07 08:14:37 +04:00
|
|
|
|
2007-12-06 03:23:09 +03:00
|
|
|
ifa_insert(ifp, ifa);
|
2008-05-12 03:48:07 +04:00
|
|
|
if_sadl_setrefs(ifp, ifa);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
if_deactivate_sadl(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
|
|
|
|
KASSERT(ifp->if_dl != NULL);
|
|
|
|
|
|
|
|
ifa = ifp->if_dl;
|
|
|
|
|
|
|
|
ifp->if_sadl = NULL;
|
|
|
|
|
|
|
|
ifnet_addrs[ifp->if_index] = NULL;
|
|
|
|
IFAFREE(ifa);
|
|
|
|
ifp->if_dl = NULL;
|
|
|
|
IFAFREE(ifa);
|
|
|
|
}
|
|
|
|
|
2008-05-13 22:09:22 +04:00
|
|
|
void
|
2008-05-12 03:48:07 +04:00
|
|
|
if_activate_sadl(struct ifnet *ifp, struct ifaddr *ifa,
|
|
|
|
const struct sockaddr_dl *sdl)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splnet();
|
|
|
|
|
|
|
|
if_deactivate_sadl(ifp);
|
|
|
|
|
|
|
|
if_sadl_setrefs(ifp, ifa);
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp)
|
|
|
|
rtinit(ifa, RTM_LLINFO_UPD, 0);
|
2008-05-12 03:48:07 +04:00
|
|
|
splx(s);
|
2001-01-17 03:30:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the link level name for the specified interface. This is
|
|
|
|
* a detach helper. This is called from if_detach() or from
|
|
|
|
* link layer type specific detach functions.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
if_free_sadl(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
ifa = ifnet_addrs[ifp->if_index];
|
|
|
|
if (ifa == NULL) {
|
|
|
|
KASSERT(ifp->if_sadl == NULL);
|
2007-12-20 22:53:29 +03:00
|
|
|
KASSERT(ifp->if_dl == NULL);
|
2001-01-17 03:30:49 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KASSERT(ifp->if_sadl != NULL);
|
2007-12-20 22:53:29 +03:00
|
|
|
KASSERT(ifp->if_dl != NULL);
|
2001-01-17 03:30:49 +03:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2001-01-17 03:30:49 +03:00
|
|
|
rtinit(ifa, RTM_DELETE, 0);
|
2007-12-06 03:23:09 +03:00
|
|
|
ifa_remove(ifp, ifa);
|
2008-05-12 03:48:07 +04:00
|
|
|
if_deactivate_sadl(ifp);
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
if (ifp->if_hwdl == ifa) {
|
|
|
|
IFAFREE(ifa);
|
|
|
|
ifp->if_hwdl = NULL;
|
|
|
|
}
|
2001-01-17 03:30:49 +03:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attach an interface to the
|
|
|
|
* list of "active" interfaces.
|
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_attach(struct ifnet *ifp)
|
2001-01-17 03:30:49 +03:00
|
|
|
{
|
2002-02-09 08:56:34 +03:00
|
|
|
int indexlim = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2002-02-09 08:56:34 +03:00
|
|
|
if (if_indexlim == 0) {
|
1995-06-12 06:22:13 +04:00
|
|
|
TAILQ_INIT(&ifnet);
|
2002-02-09 08:56:34 +03:00
|
|
|
if_indexlim = 8;
|
|
|
|
}
|
1995-06-12 06:22:13 +04:00
|
|
|
TAILQ_INIT(&ifp->if_addrlist);
|
1995-06-12 04:46:47 +04:00
|
|
|
TAILQ_INSERT_TAIL(&ifnet, ifp, if_list);
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
if (ifp->if_ioctl == NULL)
|
|
|
|
ifp->if_ioctl = ifioctl_common;
|
|
|
|
|
2009-08-13 04:23:31 +04:00
|
|
|
mutex_enter(&index_gen_mtx);
|
|
|
|
ifp->if_index_gen = index_gen++;
|
|
|
|
mutex_exit(&index_gen_mtx);
|
|
|
|
|
2002-02-09 08:56:34 +03:00
|
|
|
ifp->if_index = if_index;
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifindex2ifnet == NULL)
|
2002-02-09 08:56:34 +03:00
|
|
|
if_index++;
|
|
|
|
else
|
2003-10-01 08:22:33 +04:00
|
|
|
while (ifp->if_index < if_indexlim &&
|
|
|
|
ifindex2ifnet[ifp->if_index] != NULL) {
|
2002-02-09 08:56:34 +03:00
|
|
|
++if_index;
|
|
|
|
if (if_index == 0)
|
|
|
|
if_index = 1;
|
|
|
|
/*
|
|
|
|
* If we hit USHRT_MAX, we skip back to 0 since
|
|
|
|
* there are a number of places where the value
|
|
|
|
* of if_index or if_index itself is compared
|
2002-06-13 09:12:12 +04:00
|
|
|
* to or stored in an unsigned short. By
|
2002-02-09 08:56:34 +03:00
|
|
|
* jumping back, we won't botch those assignments
|
|
|
|
* or comparisons.
|
|
|
|
*/
|
|
|
|
else if (if_index == USHRT_MAX) {
|
|
|
|
/*
|
|
|
|
* However, if we have to jump back to
|
|
|
|
* zero *twice* without finding an empty
|
|
|
|
* slot in ifindex2ifnet[], then there
|
|
|
|
* there are too many (>65535) interfaces.
|
|
|
|
*/
|
|
|
|
if (indexlim++)
|
|
|
|
panic("too many interfaces");
|
|
|
|
else
|
|
|
|
if_index = 1;
|
|
|
|
}
|
|
|
|
ifp->if_index = if_index;
|
|
|
|
}
|
1999-07-01 12:12:45 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We have some arrays that should be indexed by if_index.
|
|
|
|
* since if_index will grow dynamically, they should grow too.
|
|
|
|
* struct ifadd **ifnet_addrs
|
|
|
|
* struct ifnet **ifindex2ifnet
|
|
|
|
*/
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifnet_addrs == NULL || ifindex2ifnet == NULL ||
|
2000-02-02 01:52:04 +03:00
|
|
|
ifp->if_index >= if_indexlim) {
|
2003-10-01 08:22:33 +04:00
|
|
|
size_t m, n, oldlim;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *q;
|
2005-02-27 01:45:09 +03:00
|
|
|
|
2003-10-01 08:22:33 +04:00
|
|
|
oldlim = if_indexlim;
|
2000-02-02 01:52:04 +03:00
|
|
|
while (ifp->if_index >= if_indexlim)
|
1999-07-01 12:12:45 +04:00
|
|
|
if_indexlim <<= 1;
|
|
|
|
|
|
|
|
/* grow ifnet_addrs */
|
2003-10-01 08:22:33 +04:00
|
|
|
m = oldlim * sizeof(struct ifaddr *);
|
2001-01-17 03:30:49 +03:00
|
|
|
n = if_indexlim * sizeof(struct ifaddr *);
|
2008-10-25 01:46:09 +04:00
|
|
|
q = malloc(n, M_IFADDR, M_WAITOK|M_ZERO);
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifnet_addrs != NULL) {
|
|
|
|
memcpy(q, ifnet_addrs, m);
|
2008-10-25 01:46:09 +04:00
|
|
|
free(ifnet_addrs, M_IFADDR);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1999-07-01 12:12:45 +04:00
|
|
|
ifnet_addrs = (struct ifaddr **)q;
|
|
|
|
|
|
|
|
/* grow ifindex2ifnet */
|
2003-10-01 08:22:33 +04:00
|
|
|
m = oldlim * sizeof(struct ifnet *);
|
1999-07-01 12:12:45 +04:00
|
|
|
n = if_indexlim * sizeof(struct ifnet *);
|
2008-10-25 01:46:09 +04:00
|
|
|
q = malloc(n, M_IFADDR, M_WAITOK|M_ZERO);
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifindex2ifnet != NULL) {
|
2008-10-25 01:46:09 +04:00
|
|
|
memcpy(q, ifindex2ifnet, m);
|
|
|
|
free(ifindex2ifnet, M_IFADDR);
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
ifindex2ifnet = (struct ifnet **)q;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1999-07-01 12:12:45 +04:00
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
ifindex2ifnet[ifp->if_index] = ifp;
|
1999-07-01 12:12:45 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
2001-01-17 03:30:49 +03:00
|
|
|
* Link level name is allocated later by a separate call to
|
|
|
|
* if_alloc_sadl().
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2001-01-17 03:30:49 +03:00
|
|
|
|
1997-08-29 04:57:28 +04:00
|
|
|
if (ifp->if_snd.ifq_maxlen == 0)
|
2001-07-28 05:13:56 +04:00
|
|
|
ifp->if_snd.ifq_maxlen = ifqmaxlen;
|
2009-08-13 04:23:31 +04:00
|
|
|
|
|
|
|
sysctl_sndq_setup(&ifp->if_sysctl_log, ifp->if_xname, &ifp->if_snd);
|
|
|
|
|
1997-10-02 23:41:56 +04:00
|
|
|
ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */
|
2000-03-06 23:49:00 +03:00
|
|
|
|
|
|
|
ifp->if_link_state = LINK_STATE_UNKNOWN;
|
|
|
|
|
2001-06-02 20:17:06 +04:00
|
|
|
ifp->if_capenable = 0;
|
2001-09-17 21:26:59 +04:00
|
|
|
ifp->if_csum_flags_tx = 0;
|
|
|
|
ifp->if_csum_flags_rx = 0;
|
2001-06-02 20:17:06 +04:00
|
|
|
|
2001-03-03 06:29:20 +03:00
|
|
|
#ifdef ALTQ
|
|
|
|
ifp->if_snd.altq_type = 0;
|
|
|
|
ifp->if_snd.altq_disc = NULL;
|
|
|
|
ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
|
|
|
|
ifp->if_snd.altq_tbr = NULL;
|
|
|
|
ifp->if_snd.altq_ifp = ifp;
|
|
|
|
#endif
|
|
|
|
|
2001-04-11 01:45:39 +04:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
ifp->if_pfil.ph_type = PFIL_TYPE_IFNET;
|
|
|
|
ifp->if_pfil.ph_ifnet = ifp;
|
|
|
|
if (pfil_head_register(&ifp->if_pfil) != 0)
|
|
|
|
printf("%s: WARNING: unable to register pfil hook\n",
|
|
|
|
ifp->if_xname);
|
2004-07-27 16:22:59 +04:00
|
|
|
(void)pfil_run_hooks(&if_pfil,
|
|
|
|
(struct mbuf **)PFIL_IFNET_ATTACH, ifp, PFIL_IFNET);
|
2001-04-11 01:45:39 +04:00
|
|
|
#endif
|
|
|
|
|
2005-01-23 21:41:56 +03:00
|
|
|
if (!STAILQ_EMPTY(&domains))
|
2004-10-08 00:06:58 +04:00
|
|
|
if_attachdomain1(ifp);
|
|
|
|
|
2002-05-27 17:46:45 +04:00
|
|
|
/* Announce the interface. */
|
|
|
|
rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_attachdomain(void)
|
2002-05-27 17:46:45 +04:00
|
|
|
{
|
|
|
|
struct ifnet *ifp;
|
2002-06-08 15:58:50 +04:00
|
|
|
int s;
|
2002-05-27 17:46:45 +04:00
|
|
|
|
2002-06-08 15:58:50 +04:00
|
|
|
s = splnet();
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp)
|
2002-05-27 17:46:45 +04:00
|
|
|
if_attachdomain1(ifp);
|
2002-06-08 15:58:50 +04:00
|
|
|
splx(s);
|
2002-05-27 17:46:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_attachdomain1(struct ifnet *ifp)
|
2002-05-27 17:46:45 +04:00
|
|
|
{
|
|
|
|
struct domain *dp;
|
2002-06-08 15:54:24 +04:00
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splnet();
|
2002-05-27 17:46:45 +04:00
|
|
|
|
2002-05-27 06:53:49 +04:00
|
|
|
/* address family dependent data region */
|
|
|
|
memset(ifp->if_afdata, 0, sizeof(ifp->if_afdata));
|
2005-01-23 21:41:56 +03:00
|
|
|
DOMAIN_FOREACH(dp) {
|
2007-03-18 23:59:38 +03:00
|
|
|
if (dp->dom_ifattach != NULL)
|
2002-05-27 06:53:49 +04:00
|
|
|
ifp->if_afdata[dp->dom_family] =
|
|
|
|
(*dp->dom_ifattach)(ifp);
|
|
|
|
}
|
2002-06-08 15:54:24 +04:00
|
|
|
|
|
|
|
splx(s);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2000-02-02 01:52:04 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Deactivate an interface. This points all of the procedure
|
|
|
|
* handles at error stubs. May be called from interrupt context.
|
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_deactivate(struct ifnet *ifp)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2000-02-02 01:52:04 +03:00
|
|
|
|
|
|
|
ifp->if_output = if_nulloutput;
|
|
|
|
ifp->if_input = if_nullinput;
|
|
|
|
ifp->if_start = if_nullstart;
|
|
|
|
ifp->if_ioctl = if_nullioctl;
|
2000-10-11 20:52:34 +04:00
|
|
|
ifp->if_init = if_nullinit;
|
|
|
|
ifp->if_stop = if_nullstop;
|
2000-02-02 01:52:04 +03:00
|
|
|
ifp->if_watchdog = if_nullwatchdog;
|
|
|
|
ifp->if_drain = if_nulldrain;
|
|
|
|
|
|
|
|
/* No more packets may be enqueued. */
|
|
|
|
ifp->if_snd.ifq_maxlen = 0;
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2007-12-06 02:47:17 +03:00
|
|
|
void
|
2008-03-01 00:23:55 +03:00
|
|
|
if_purgeaddrs(struct ifnet *ifp, int family, void (*purgeaddr)(struct ifaddr *))
|
2007-12-06 02:47:17 +03:00
|
|
|
{
|
|
|
|
struct ifaddr *ifa, *nifa;
|
|
|
|
|
|
|
|
for (ifa = IFADDR_FIRST(ifp); ifa != NULL; ifa = nifa) {
|
|
|
|
nifa = IFADDR_NEXT(ifa);
|
|
|
|
if (ifa->ifa_addr->sa_family != family)
|
|
|
|
continue;
|
|
|
|
(*purgeaddr)(ifa);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
/*
|
|
|
|
* Detach an interface from the list of "active" interfaces,
|
|
|
|
* freeing any resources as we go along.
|
|
|
|
*
|
|
|
|
* NOTE: This routine must be called with a valid thread context,
|
|
|
|
* as it may block.
|
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_detach(struct ifnet *ifp)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
2000-02-06 19:43:33 +03:00
|
|
|
struct socket so;
|
2006-11-20 07:09:25 +03:00
|
|
|
struct ifaddr *ifa;
|
2000-02-02 01:52:04 +03:00
|
|
|
#ifdef IFAREF_DEBUG
|
|
|
|
struct ifaddr *last_ifa = NULL;
|
|
|
|
#endif
|
2000-02-06 19:43:33 +03:00
|
|
|
struct domain *dp;
|
2004-04-22 05:01:40 +04:00
|
|
|
const struct protosw *pr;
|
2000-02-06 19:43:33 +03:00
|
|
|
int s, i, family, purged;
|
2000-02-02 01:52:04 +03:00
|
|
|
|
2000-02-06 19:43:33 +03:00
|
|
|
/*
|
|
|
|
* XXX It's kind of lame that we have to have the
|
|
|
|
* XXX socket structure...
|
|
|
|
*/
|
|
|
|
memset(&so, 0, sizeof(so));
|
2000-02-02 01:52:04 +03:00
|
|
|
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2000-02-02 01:52:04 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do an if_down() to give protocols a chance to do something.
|
|
|
|
*/
|
|
|
|
if_down(ifp);
|
|
|
|
|
2001-03-03 06:29:20 +03:00
|
|
|
#ifdef ALTQ
|
|
|
|
if (ALTQ_IS_ENABLED(&ifp->if_snd))
|
|
|
|
altq_disable(&ifp->if_snd);
|
|
|
|
if (ALTQ_IS_ATTACHED(&ifp->if_snd))
|
|
|
|
altq_detach(&ifp->if_snd);
|
|
|
|
#endif
|
|
|
|
|
2009-08-13 04:23:31 +04:00
|
|
|
sysctl_teardown(&ifp->if_sysctl_log);
|
2006-05-18 13:05:49 +04:00
|
|
|
|
|
|
|
#if NCARP > 0
|
|
|
|
/* Remove the interface from any carp group it is a part of. */
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifp->if_carp != NULL && ifp->if_type != IFT_CARP)
|
2006-05-18 13:05:49 +04:00
|
|
|
carp_ifdetach(ifp);
|
|
|
|
#endif
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
/*
|
|
|
|
* Rip all the addresses off the interface. This should make
|
|
|
|
* all of the routes go away.
|
2006-11-20 07:09:25 +03:00
|
|
|
*
|
|
|
|
* pr_usrreq calls can remove an arbitrary number of ifaddrs
|
|
|
|
* from the list, including our "cursor", ifa. For safety,
|
|
|
|
* and to honor the TAILQ abstraction, I just restart the
|
|
|
|
* loop after each removal. Note that the loop will exit
|
|
|
|
* when all of the remaining ifaddrs belong to the AF_LINK
|
|
|
|
* family. I am counting on the historical fact that at
|
|
|
|
* least one pr_usrreq in each address domain removes at
|
|
|
|
* least one ifaddr.
|
2000-02-02 01:52:04 +03:00
|
|
|
*/
|
2006-11-20 07:09:25 +03:00
|
|
|
again:
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2000-02-06 19:43:33 +03:00
|
|
|
family = ifa->ifa_addr->sa_family;
|
2000-02-02 01:52:04 +03:00
|
|
|
#ifdef IFAREF_DEBUG
|
|
|
|
printf("if_detach: ifaddr %p, family %d, refcnt %d\n",
|
2000-02-06 19:43:33 +03:00
|
|
|
ifa, family, ifa->ifa_refcnt);
|
2000-02-02 01:52:04 +03:00
|
|
|
if (last_ifa != NULL && ifa == last_ifa)
|
2000-02-06 19:43:33 +03:00
|
|
|
panic("if_detach: loop detected");
|
2000-02-02 01:52:04 +03:00
|
|
|
last_ifa = ifa;
|
|
|
|
#endif
|
2006-11-20 07:09:25 +03:00
|
|
|
if (family == AF_LINK)
|
2003-05-16 20:57:09 +04:00
|
|
|
continue;
|
|
|
|
dp = pffinddomain(family);
|
2000-02-06 19:43:33 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2003-05-16 20:57:09 +04:00
|
|
|
if (dp == NULL)
|
|
|
|
panic("if_detach: no domain for AF %d",
|
|
|
|
family);
|
2000-02-06 19:43:33 +03:00
|
|
|
#endif
|
2005-07-19 16:58:24 +04:00
|
|
|
/*
|
|
|
|
* XXX These PURGEIF calls are redundant with the
|
|
|
|
* purge-all-families calls below, but are left in for
|
|
|
|
* now both to make a smaller change, and to avoid
|
|
|
|
* unplanned interactions with clearing of
|
|
|
|
* ifp->if_addrlist.
|
|
|
|
*/
|
2003-05-16 20:57:09 +04:00
|
|
|
purged = 0;
|
|
|
|
for (pr = dp->dom_protosw;
|
|
|
|
pr < dp->dom_protoswNPROTOSW; pr++) {
|
|
|
|
so.so_proto = pr;
|
|
|
|
if (pr->pr_usrreq != NULL) {
|
|
|
|
(void) (*pr->pr_usrreq)(&so,
|
|
|
|
PRU_PURGEIF, NULL, NULL,
|
2005-12-11 15:16:03 +03:00
|
|
|
(struct mbuf *) ifp, curlwp);
|
2003-05-16 20:57:09 +04:00
|
|
|
purged = 1;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
}
|
2003-05-16 20:57:09 +04:00
|
|
|
if (purged == 0) {
|
|
|
|
/*
|
|
|
|
* XXX What's really the best thing to do
|
2003-11-28 11:56:48 +03:00
|
|
|
* XXX here? --thorpej@NetBSD.org
|
2003-05-16 20:57:09 +04:00
|
|
|
*/
|
|
|
|
printf("if_detach: WARNING: AF %d not purged\n",
|
|
|
|
family);
|
2007-12-06 03:23:09 +03:00
|
|
|
ifa_remove(ifp, ifa);
|
2003-05-16 20:57:09 +04:00
|
|
|
}
|
2006-11-20 07:09:25 +03:00
|
|
|
goto again;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
|
2003-05-16 20:57:09 +04:00
|
|
|
if_free_sadl(ifp);
|
|
|
|
|
2006-12-03 22:17:41 +03:00
|
|
|
/* Walk the routing table looking for stragglers. */
|
2007-06-09 07:07:21 +04:00
|
|
|
for (i = 0; i <= AF_MAX; i++)
|
|
|
|
(void)rt_walktree(i, if_rt_walktree, ifp);
|
2000-02-02 01:52:04 +03:00
|
|
|
|
2005-01-23 21:41:56 +03:00
|
|
|
DOMAIN_FOREACH(dp) {
|
2007-03-18 23:59:38 +03:00
|
|
|
if (dp->dom_ifdetach != NULL && ifp->if_afdata[dp->dom_family])
|
2002-05-27 06:53:49 +04:00
|
|
|
(*dp->dom_ifdetach)(ifp,
|
|
|
|
ifp->if_afdata[dp->dom_family]);
|
2005-07-19 16:58:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* One would expect multicast memberships (INET and
|
|
|
|
* INET6) on UDP sockets to be purged by the PURGEIF
|
|
|
|
* calls above, but if all addresses were removed from
|
|
|
|
* the interface prior to destruction, the calls will
|
|
|
|
* not be made (e.g. ppp, for which pppd(8) generally
|
|
|
|
* removes addresses before destroying the interface).
|
|
|
|
* Because there is no invariant that multicast
|
|
|
|
* memberships only exist for interfaces with IPv4
|
|
|
|
* addresses, we must call PURGEIF regardless of
|
|
|
|
* addresses. (Protocols which might store ifnet
|
|
|
|
* pointers are marked with PR_PURGEIF.)
|
|
|
|
*/
|
2007-03-18 23:59:38 +03:00
|
|
|
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
|
2005-07-19 16:58:24 +04:00
|
|
|
so.so_proto = pr;
|
2007-03-18 23:59:38 +03:00
|
|
|
if (pr->pr_usrreq != NULL && pr->pr_flags & PR_PURGEIF)
|
|
|
|
(void)(*pr->pr_usrreq)(&so, PRU_PURGEIF, NULL,
|
|
|
|
NULL, (struct mbuf *)ifp, curlwp);
|
2005-07-19 16:58:24 +04:00
|
|
|
}
|
2002-05-27 06:53:49 +04:00
|
|
|
}
|
|
|
|
|
2007-03-18 23:05:52 +03:00
|
|
|
#ifdef PFIL_HOOKS
|
|
|
|
(void)pfil_run_hooks(&if_pfil,
|
|
|
|
(struct mbuf **)PFIL_IFNET_DETACH, ifp, PFIL_IFNET);
|
|
|
|
(void)pfil_head_unregister(&ifp->if_pfil);
|
|
|
|
#endif
|
|
|
|
|
2000-03-06 23:49:00 +03:00
|
|
|
/* Announce that the interface is gone. */
|
|
|
|
rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
|
|
|
|
|
2001-07-24 20:35:29 +04:00
|
|
|
ifindex2ifnet[ifp->if_index] = NULL;
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
TAILQ_REMOVE(&ifnet, ifp, if_list);
|
|
|
|
|
2001-07-29 07:28:30 +04:00
|
|
|
/*
|
2006-08-25 23:33:50 +04:00
|
|
|
* remove packets that came from ifp, from software interrupt queues.
|
2001-07-29 07:28:30 +04:00
|
|
|
*/
|
2006-08-25 23:33:50 +04:00
|
|
|
DOMAIN_FOREACH(dp) {
|
|
|
|
for (i = 0; i < __arraycount(dp->dom_ifqueues); i++) {
|
|
|
|
if (dp->dom_ifqueues[i] == NULL)
|
|
|
|
break;
|
|
|
|
if_detach_queues(ifp, dp->dom_ifqueues[i]);
|
|
|
|
}
|
|
|
|
}
|
2001-07-29 07:28:30 +04:00
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2001-07-29 07:28:30 +04:00
|
|
|
static void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_detach_queues(struct ifnet *ifp, struct ifqueue *q)
|
2001-07-29 07:28:30 +04:00
|
|
|
{
|
|
|
|
struct mbuf *m, *prev, *next;
|
|
|
|
|
|
|
|
prev = NULL;
|
2007-03-18 23:59:38 +03:00
|
|
|
for (m = q->ifq_head; m != NULL; m = next) {
|
2001-07-29 07:28:30 +04:00
|
|
|
next = m->m_nextpkt;
|
|
|
|
#ifdef DIAGNOSTIC
|
2001-08-02 05:42:38 +04:00
|
|
|
if ((m->m_flags & M_PKTHDR) == 0) {
|
|
|
|
prev = m;
|
2001-07-29 07:28:30 +04:00
|
|
|
continue;
|
2001-08-02 05:42:38 +04:00
|
|
|
}
|
2001-07-29 07:28:30 +04:00
|
|
|
#endif
|
2001-08-02 05:42:38 +04:00
|
|
|
if (m->m_pkthdr.rcvif != ifp) {
|
|
|
|
prev = m;
|
2001-07-29 07:28:30 +04:00
|
|
|
continue;
|
2001-08-02 05:42:38 +04:00
|
|
|
}
|
2001-07-29 07:28:30 +04:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
if (prev != NULL)
|
2001-07-29 07:28:30 +04:00
|
|
|
prev->m_nextpkt = m->m_nextpkt;
|
|
|
|
else
|
|
|
|
q->ifq_head = m->m_nextpkt;
|
|
|
|
if (q->ifq_tail == m)
|
|
|
|
q->ifq_tail = prev;
|
|
|
|
q->ifq_len--;
|
|
|
|
|
|
|
|
m->m_nextpkt = NULL;
|
|
|
|
m_freem(m);
|
|
|
|
IF_DROP(q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
/*
|
|
|
|
* Callback for a radix tree walk to delete all references to an
|
|
|
|
* ifnet.
|
|
|
|
*/
|
2005-12-12 02:05:24 +03:00
|
|
|
static int
|
2007-06-09 07:07:21 +04:00
|
|
|
if_rt_walktree(struct rtentry *rt, void *v)
|
2000-02-02 01:52:04 +03:00
|
|
|
{
|
2000-02-05 10:58:54 +03:00
|
|
|
struct ifnet *ifp = (struct ifnet *)v;
|
2000-02-02 01:52:04 +03:00
|
|
|
int error;
|
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
if (rt->rt_ifp != ifp)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Delete the entry. */
|
|
|
|
++rt->rt_refcnt;
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
error = rtrequest(RTM_DELETE, rt_getkey(rt), rt->rt_gateway,
|
2007-03-18 23:59:38 +03:00
|
|
|
rt_mask(rt), rt->rt_flags, NULL);
|
|
|
|
KASSERT((rt->rt_flags & RTF_UP) == 0);
|
|
|
|
rt->rt_ifp = NULL;
|
|
|
|
RTFREE(rt);
|
|
|
|
if (error != 0)
|
|
|
|
printf("%s: warning: unable to delete rtentry @ %p, "
|
|
|
|
"error = %d\n", ifp->if_xname, rt, error);
|
|
|
|
return 0;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
|
2000-07-02 04:20:48 +04:00
|
|
|
/*
|
|
|
|
* Create a clone network interface.
|
|
|
|
*/
|
|
|
|
int
|
2005-12-12 02:05:24 +03:00
|
|
|
if_clone_create(const char *name)
|
2000-07-02 04:20:48 +04:00
|
|
|
{
|
|
|
|
struct if_clone *ifc;
|
|
|
|
int unit;
|
|
|
|
|
|
|
|
ifc = if_clone_lookup(name, &unit);
|
|
|
|
if (ifc == NULL)
|
2007-03-18 23:59:38 +03:00
|
|
|
return EINVAL;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
|
|
|
if (ifunit(name) != NULL)
|
2007-03-18 23:59:38 +03:00
|
|
|
return EEXIST;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return (*ifc->ifc_create)(ifc, unit);
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destroy a clone network interface.
|
|
|
|
*/
|
|
|
|
int
|
2005-12-12 02:05:24 +03:00
|
|
|
if_clone_destroy(const char *name)
|
2000-07-02 04:20:48 +04:00
|
|
|
{
|
|
|
|
struct if_clone *ifc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
|
|
|
ifc = if_clone_lookup(name, NULL);
|
|
|
|
if (ifc == NULL)
|
2007-03-18 23:59:38 +03:00
|
|
|
return EINVAL;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
|
|
|
ifp = ifunit(name);
|
|
|
|
if (ifp == NULL)
|
2007-03-18 23:59:38 +03:00
|
|
|
return ENXIO;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
|
|
|
if (ifc->ifc_destroy == NULL)
|
2007-03-18 23:59:38 +03:00
|
|
|
return EOPNOTSUPP;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return (*ifc->ifc_destroy)(ifp);
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up a network interface cloner.
|
|
|
|
*/
|
2005-12-12 02:05:24 +03:00
|
|
|
static struct if_clone *
|
|
|
|
if_clone_lookup(const char *name, int *unitp)
|
2000-07-02 04:20:48 +04:00
|
|
|
{
|
|
|
|
struct if_clone *ifc;
|
|
|
|
const char *cp;
|
2003-08-14 04:13:34 +04:00
|
|
|
int unit;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2003-08-14 04:13:34 +04:00
|
|
|
/* separate interface name from unit */
|
|
|
|
for (cp = name;
|
2003-08-14 11:39:22 +04:00
|
|
|
cp - name < IFNAMSIZ && *cp && (*cp < '0' || *cp > '9');
|
2003-08-14 04:13:34 +04:00
|
|
|
cp++)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cp == name || cp - name == IFNAMSIZ || !*cp)
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL; /* No name or unit number */
|
2003-08-14 04:13:34 +04:00
|
|
|
|
|
|
|
LIST_FOREACH(ifc, &if_cloners, ifc_list) {
|
|
|
|
if (strlen(ifc->ifc_name) == cp - name &&
|
2007-03-18 23:59:38 +03:00
|
|
|
strncmp(name, ifc->ifc_name, cp - name) == 0)
|
2003-08-14 04:13:34 +04:00
|
|
|
break;
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
2003-08-14 04:13:34 +04:00
|
|
|
if (ifc == NULL)
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2003-08-14 04:13:34 +04:00
|
|
|
unit = 0;
|
2003-08-14 04:19:43 +04:00
|
|
|
while (cp - name < IFNAMSIZ && *cp) {
|
|
|
|
if (*cp < '0' || *cp > '9' || unit > INT_MAX / 10) {
|
2000-07-02 04:20:48 +04:00
|
|
|
/* Bogus unit number. */
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
2003-08-14 04:13:34 +04:00
|
|
|
unit = (unit * 10) + (*cp++ - '0');
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (unitp != NULL)
|
2003-08-14 04:13:34 +04:00
|
|
|
*unitp = unit;
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifc;
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register a network interface cloner.
|
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_clone_attach(struct if_clone *ifc)
|
2000-07-02 04:20:48 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
|
2000-07-20 22:40:26 +04:00
|
|
|
if_cloners_count++;
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unregister a network interface cloner.
|
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_clone_detach(struct if_clone *ifc)
|
2000-07-02 04:20:48 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
LIST_REMOVE(ifc, ifc_list);
|
2000-07-20 22:40:26 +04:00
|
|
|
if_cloners_count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Provide list of interface cloners to userspace.
|
|
|
|
*/
|
2005-12-12 02:05:24 +03:00
|
|
|
static int
|
|
|
|
if_clone_list(struct if_clonereq *ifcr)
|
2000-07-20 22:40:26 +04:00
|
|
|
{
|
|
|
|
char outbuf[IFNAMSIZ], *dst;
|
|
|
|
struct if_clone *ifc;
|
|
|
|
int count, error = 0;
|
|
|
|
|
|
|
|
ifcr->ifcr_total = if_cloners_count;
|
|
|
|
if ((dst = ifcr->ifcr_buffer) == NULL) {
|
|
|
|
/* Just asking how many there are. */
|
2007-03-18 23:59:38 +03:00
|
|
|
return 0;
|
2000-07-20 22:40:26 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ifcr->ifcr_count < 0)
|
2007-03-18 23:59:38 +03:00
|
|
|
return EINVAL;
|
2000-07-20 22:40:26 +04:00
|
|
|
|
|
|
|
count = (if_cloners_count < ifcr->ifcr_count) ?
|
|
|
|
if_cloners_count : ifcr->ifcr_count;
|
|
|
|
|
|
|
|
for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
|
|
|
|
ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
|
2006-10-27 19:33:11 +04:00
|
|
|
(void)strncpy(outbuf, ifc->ifc_name, sizeof(outbuf));
|
|
|
|
if (outbuf[sizeof(outbuf) - 1] != '\0')
|
|
|
|
return ENAMETOOLONG;
|
2006-10-22 22:24:02 +04:00
|
|
|
error = copyout(outbuf, dst, sizeof(outbuf));
|
2007-03-18 23:59:38 +03:00
|
|
|
if (error != 0)
|
2000-07-20 22:40:26 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return error;
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
2007-12-06 03:23:09 +03:00
|
|
|
void
|
|
|
|
ifa_insert(struct ifnet *ifp, struct ifaddr *ifa)
|
|
|
|
{
|
|
|
|
ifa->ifa_ifp = ifp;
|
2007-12-06 05:23:42 +03:00
|
|
|
TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list);
|
2007-12-06 03:23:09 +03:00
|
|
|
IFAREF(ifa);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ifa_remove(struct ifnet *ifp, struct ifaddr *ifa)
|
|
|
|
{
|
|
|
|
KASSERT(ifa->ifa_ifp == ifp);
|
|
|
|
TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
|
|
|
|
IFAFREE(ifa);
|
|
|
|
}
|
|
|
|
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
static inline int
|
|
|
|
equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
|
|
|
|
{
|
|
|
|
return sockaddr_cmp(sa1, sa2) == 0;
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Locate an interface based on a complete address.
|
|
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
|
|
struct ifaddr *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifa_ifwithaddr(const struct sockaddr *addr)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifaddr *ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifa->ifa_addr->sa_family != addr->sa_family)
|
|
|
|
continue;
|
|
|
|
if (equal(addr, ifa->ifa_addr))
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa;
|
2000-02-02 01:52:04 +03:00
|
|
|
if ((ifp->if_flags & IFF_BROADCAST) &&
|
|
|
|
ifa->ifa_broadaddr &&
|
|
|
|
/* IP6 doesn't have broadcast */
|
|
|
|
ifa->ifa_broadaddr->sa_len != 0 &&
|
|
|
|
equal(ifa->ifa_broadaddr, addr))
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1999-07-01 12:12:45 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Locate the point to point interface with a given destination address.
|
|
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
|
|
struct ifaddr *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifa_ifwithdstaddr(const struct sockaddr *addr)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifaddr *ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
|
|
|
continue;
|
2007-03-18 23:59:38 +03:00
|
|
|
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
|
|
|
|
continue;
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifa->ifa_addr->sa_family != addr->sa_family ||
|
|
|
|
ifa->ifa_dstaddr == NULL)
|
|
|
|
continue;
|
|
|
|
if (equal(addr, ifa->ifa_dstaddr))
|
|
|
|
return ifa;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find an interface on a specific network. If many, choice
|
1994-05-13 10:01:27 +04:00
|
|
|
* is most specific found.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
struct ifaddr *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifa_ifwithnet(const struct sockaddr *addr)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifaddr *ifa;
|
2004-04-21 08:17:28 +04:00
|
|
|
const struct sockaddr_dl *sdl;
|
1994-05-13 10:01:27 +04:00
|
|
|
struct ifaddr *ifa_maybe = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
u_int af = addr->sa_family;
|
2006-10-22 17:25:54 +04:00
|
|
|
const char *addr_data = addr->sa_data, *cplim;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
if (af == AF_LINK) {
|
2007-08-07 08:14:37 +04:00
|
|
|
sdl = satocsdl(addr);
|
2003-12-10 14:46:33 +03:00
|
|
|
if (sdl->sdl_index && sdl->sdl_index < if_indexlim &&
|
|
|
|
ifindex2ifnet[sdl->sdl_index] &&
|
2000-02-02 01:52:04 +03:00
|
|
|
ifindex2ifnet[sdl->sdl_index]->if_output != if_nulloutput)
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifnet_addrs[sdl->sdl_index];
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1999-08-24 20:02:27 +04:00
|
|
|
#ifdef NETATALK
|
|
|
|
if (af == AF_APPLETALK) {
|
2004-04-21 08:17:28 +04:00
|
|
|
const struct sockaddr_at *sat, *sat2;
|
2005-05-30 01:22:52 +04:00
|
|
|
sat = (const struct sockaddr_at *)addr;
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
|
|
|
continue;
|
2005-05-30 01:22:52 +04:00
|
|
|
ifa = at_ifawithnet((const struct sockaddr_at *)addr, ifp);
|
2000-04-26 17:38:13 +04:00
|
|
|
if (ifa == NULL)
|
|
|
|
continue;
|
|
|
|
sat2 = (struct sockaddr_at *)ifa->ifa_addr;
|
|
|
|
if (sat2->sat_addr.s_net == sat->sat_addr.s_net)
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa; /* exact match */
|
2000-04-26 17:38:13 +04:00
|
|
|
if (ifa_maybe == NULL) {
|
2002-07-26 18:11:34 +04:00
|
|
|
/* else keep the if with the right range */
|
2000-04-26 17:38:13 +04:00
|
|
|
ifa_maybe = ifa;
|
|
|
|
}
|
1999-08-24 20:02:27 +04:00
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa_maybe;
|
1999-08-24 20:02:27 +04:00
|
|
|
}
|
|
|
|
#endif
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
|
|
|
continue;
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2006-10-22 17:25:54 +04:00
|
|
|
const char *cp, *cp2, *cp3;
|
1994-05-13 10:01:27 +04:00
|
|
|
|
|
|
|
if (ifa->ifa_addr->sa_family != af ||
|
2007-03-18 23:59:38 +03:00
|
|
|
ifa->ifa_netmask == NULL)
|
2000-02-02 01:52:04 +03:00
|
|
|
next: continue;
|
1994-05-13 10:01:27 +04:00
|
|
|
cp = addr_data;
|
|
|
|
cp2 = ifa->ifa_addr->sa_data;
|
|
|
|
cp3 = ifa->ifa_netmask->sa_data;
|
2006-10-22 17:25:54 +04:00
|
|
|
cplim = (const char *)ifa->ifa_netmask +
|
2000-02-02 01:52:04 +03:00
|
|
|
ifa->ifa_netmask->sa_len;
|
|
|
|
while (cp3 < cplim) {
|
|
|
|
if ((*cp++ ^ *cp2++) & *cp3++) {
|
|
|
|
/* want to continue for() loop */
|
1996-03-12 16:07:52 +03:00
|
|
|
goto next;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifa_maybe == NULL ||
|
2007-03-04 08:59:00 +03:00
|
|
|
rn_refines((void *)ifa->ifa_netmask,
|
|
|
|
(void *)ifa_maybe->ifa_netmask))
|
1994-05-13 10:01:27 +04:00
|
|
|
ifa_maybe = ifa;
|
|
|
|
}
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa_maybe;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2000-02-02 01:52:04 +03:00
|
|
|
|
1996-02-27 02:16:42 +03:00
|
|
|
/*
|
|
|
|
* Find the interface of the addresss.
|
|
|
|
*/
|
|
|
|
struct ifaddr *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifa_ifwithladdr(const struct sockaddr *addr)
|
1996-02-27 02:16:42 +03:00
|
|
|
{
|
|
|
|
struct ifaddr *ia;
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
if ((ia = ifa_ifwithaddr(addr)) || (ia = ifa_ifwithdstaddr(addr)) ||
|
|
|
|
(ia = ifa_ifwithnet(addr)))
|
2007-03-18 23:59:38 +03:00
|
|
|
return ia;
|
|
|
|
return NULL;
|
1996-02-27 02:16:42 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find an interface using a specific address family
|
|
|
|
*/
|
|
|
|
struct ifaddr *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifa_ifwithaf(int af)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifaddr *ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
|
|
|
continue;
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
1995-06-12 04:46:47 +04:00
|
|
|
if (ifa->ifa_addr->sa_family == af)
|
2006-11-20 07:09:25 +03:00
|
|
|
return ifa;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
|
|
|
}
|
2006-11-20 07:09:25 +03:00
|
|
|
return NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find an interface address specific to an interface best matching
|
|
|
|
* a given address.
|
|
|
|
*/
|
|
|
|
struct ifaddr *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifaddr *ifa;
|
2004-04-21 08:17:28 +04:00
|
|
|
const char *cp, *cp2, *cp3;
|
|
|
|
const char *cplim;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct ifaddr *ifa_maybe = 0;
|
|
|
|
u_int af = addr->sa_family;
|
|
|
|
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
2000-02-02 01:52:04 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
if (af >= AF_MAX)
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
2000-02-02 01:52:04 +03:00
|
|
|
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ifa->ifa_addr->sa_family != af)
|
|
|
|
continue;
|
|
|
|
ifa_maybe = ifa;
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifa->ifa_netmask == NULL) {
|
1993-03-21 12:45:37 +03:00
|
|
|
if (equal(addr, ifa->ifa_addr) ||
|
2000-02-02 01:52:04 +03:00
|
|
|
(ifa->ifa_dstaddr &&
|
|
|
|
equal(addr, ifa->ifa_dstaddr)))
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
cp = addr->sa_data;
|
|
|
|
cp2 = ifa->ifa_addr->sa_data;
|
|
|
|
cp3 = ifa->ifa_netmask->sa_data;
|
|
|
|
cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
|
2000-02-02 01:52:04 +03:00
|
|
|
for (; cp3 < cplim; cp3++) {
|
1993-03-21 12:45:37 +03:00
|
|
|
if ((*cp++ ^ *cp2++) & *cp3)
|
|
|
|
break;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
if (cp3 == cplim)
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifa_maybe;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1993-12-18 07:46:25 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Default action when installing a route with a Link Level gateway.
|
|
|
|
* Lookup an appropriate real ifa to point to.
|
|
|
|
* This should be moved to /sys/net/link.c eventually.
|
|
|
|
*/
|
1994-05-13 10:01:27 +04:00
|
|
|
void
|
2008-10-24 21:07:33 +04:00
|
|
|
link_rtrequest(int cmd, struct rtentry *rt, const struct rt_addrinfo *info)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifaddr *ifa;
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
const struct sockaddr *dst;
|
1994-05-13 10:01:27 +04:00
|
|
|
struct ifnet *ifp;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2008-05-14 00:40:33 +04:00
|
|
|
if (cmd != RTM_ADD || (ifa = rt->rt_ifa) == NULL ||
|
|
|
|
(ifp = ifa->ifa_ifp) == NULL || (dst = rt_getkey(rt)) == NULL)
|
1993-03-21 12:45:37 +03:00
|
|
|
return;
|
1996-02-14 00:59:53 +03:00
|
|
|
if ((ifa = ifaof_ifpforaddr(dst, ifp)) != NULL) {
|
2006-11-13 08:13:38 +03:00
|
|
|
rt_replace_ifa(rt, ifa);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
|
2001-01-17 07:05:41 +03:00
|
|
|
ifa->ifa_rtrequest(cmd, rt, info);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-22 10:14:51 +04:00
|
|
|
/*
|
|
|
|
* Handle a change in the interface link state.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
if_link_state_change(struct ifnet *ifp, int link_state)
|
|
|
|
{
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifp->if_link_state == link_state)
|
|
|
|
return;
|
|
|
|
ifp->if_link_state = link_state;
|
2005-06-22 10:14:51 +04:00
|
|
|
/* Notify that the link state has changed. */
|
2007-03-18 23:59:38 +03:00
|
|
|
rt_ifmsg(ifp);
|
2006-05-18 13:05:49 +04:00
|
|
|
#if NCARP > 0
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifp->if_carp)
|
|
|
|
carp_carpdev_state(ifp);
|
2006-05-18 13:05:49 +04:00
|
|
|
#endif
|
2005-06-22 10:14:51 +04:00
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Mark an interface down and notify protocols of
|
|
|
|
* the transition.
|
1995-08-13 03:59:09 +04:00
|
|
|
* NOTE: must be called at splsoftnet or equivalent.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
1994-05-13 10:01:27 +04:00
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_down(struct ifnet *ifp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifaddr *ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
ifp->if_flags &= ~IFF_UP;
|
2009-01-11 05:45:45 +03:00
|
|
|
nanotime(&ifp->if_lastchange);
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp)
|
1993-03-21 12:45:37 +03:00
|
|
|
pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
|
2000-12-14 20:47:26 +03:00
|
|
|
IFQ_PURGE(&ifp->if_snd);
|
2006-05-18 13:05:49 +04:00
|
|
|
#if NCARP > 0
|
|
|
|
if (ifp->if_carp)
|
|
|
|
carp_carpdev_state(ifp);
|
|
|
|
#endif
|
1994-05-13 10:01:27 +04:00
|
|
|
rt_ifmsg(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark an interface up and notify protocols of
|
|
|
|
* the transition.
|
1995-08-13 03:59:09 +04:00
|
|
|
* NOTE: must be called at splsoftnet or equivalent.
|
1994-05-13 10:01:27 +04:00
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
if_up(struct ifnet *ifp)
|
1994-05-13 10:01:27 +04:00
|
|
|
{
|
1996-02-14 00:59:53 +03:00
|
|
|
#ifdef notyet
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifaddr *ifa;
|
1996-02-14 00:59:53 +03:00
|
|
|
#endif
|
1994-05-13 10:01:27 +04:00
|
|
|
|
|
|
|
ifp->if_flags |= IFF_UP;
|
2009-01-11 05:45:45 +03:00
|
|
|
nanotime(&ifp->if_lastchange);
|
1994-05-13 10:01:27 +04:00
|
|
|
#ifdef notyet
|
|
|
|
/* this has no effect on IP, and will kill all ISO connections XXX */
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp)
|
1994-05-13 10:01:27 +04:00
|
|
|
pfctlinput(PRC_IFUP, ifa->ifa_addr);
|
2006-05-18 13:05:49 +04:00
|
|
|
#endif
|
|
|
|
#if NCARP > 0
|
|
|
|
if (ifp->if_carp)
|
|
|
|
carp_carpdev_state(ifp);
|
1994-05-13 10:01:27 +04:00
|
|
|
#endif
|
|
|
|
rt_ifmsg(ifp);
|
1999-07-01 12:12:45 +04:00
|
|
|
#ifdef INET6
|
|
|
|
in6_if_up(ifp);
|
|
|
|
#endif
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle interface watchdog timer routines. Called
|
|
|
|
* from softclock, we decrement timers (if set) and
|
|
|
|
* call the appropriate interface routine on expiration.
|
|
|
|
*/
|
1993-06-27 10:01:27 +04:00
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
if_slowtimo(void *arg)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
2001-04-14 03:29:55 +04:00
|
|
|
int s = splnet();
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
1993-03-21 12:45:37 +03:00
|
|
|
if (ifp->if_timer == 0 || --ifp->if_timer)
|
|
|
|
continue;
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifp->if_watchdog != NULL)
|
1996-05-07 06:40:22 +04:00
|
|
|
(*ifp->if_watchdog)(ifp);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
splx(s);
|
2007-03-18 23:59:38 +03:00
|
|
|
callout_reset(&if_slowtimo_ch, hz / IFNET_SLOWHZ, if_slowtimo, NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2000-07-04 22:46:49 +04:00
|
|
|
/*
|
|
|
|
* Set/clear promiscuous mode on interface ifp based on the truth value
|
|
|
|
* of pswitch. The calls are reference counted so that only the first
|
|
|
|
* "on" request actually has an effect, as does the final "off" request.
|
|
|
|
* Results are undefined if the "off" and "on" requests are not matched.
|
|
|
|
*/
|
|
|
|
int
|
2005-12-12 02:05:24 +03:00
|
|
|
ifpromisc(struct ifnet *ifp, int pswitch)
|
2000-07-04 22:46:49 +04:00
|
|
|
{
|
|
|
|
int pcount, ret;
|
|
|
|
short flags;
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
pcount = ifp->if_pcount;
|
|
|
|
flags = ifp->if_flags;
|
|
|
|
if (pswitch) {
|
|
|
|
/*
|
2000-10-02 03:16:07 +04:00
|
|
|
* Allow the device to be "placed" into promiscuous
|
|
|
|
* mode even if it is not configured up. It will
|
|
|
|
* consult IFF_PROMISC when it is is brought up.
|
2000-07-04 22:46:49 +04:00
|
|
|
*/
|
2000-07-21 02:00:48 +04:00
|
|
|
if (ifp->if_pcount++ != 0)
|
2007-03-18 23:59:38 +03:00
|
|
|
return 0;
|
2000-07-04 22:46:49 +04:00
|
|
|
ifp->if_flags |= IFF_PROMISC;
|
2000-10-02 03:16:07 +04:00
|
|
|
if ((ifp->if_flags & IFF_UP) == 0)
|
2007-03-18 23:59:38 +03:00
|
|
|
return 0;
|
2000-07-04 22:46:49 +04:00
|
|
|
} else {
|
|
|
|
if (--ifp->if_pcount > 0)
|
2007-03-18 23:59:38 +03:00
|
|
|
return 0;
|
2000-07-04 22:46:49 +04:00
|
|
|
ifp->if_flags &= ~IFF_PROMISC;
|
|
|
|
/*
|
|
|
|
* If the device is not configured up, we should not need to
|
|
|
|
* turn off promiscuous mode (device should have turned it
|
|
|
|
* off when interface went down; and will look at IFF_PROMISC
|
|
|
|
* again next time interface comes up).
|
|
|
|
*/
|
|
|
|
if ((ifp->if_flags & IFF_UP) == 0)
|
2007-03-18 23:59:38 +03:00
|
|
|
return 0;
|
2000-07-04 22:46:49 +04:00
|
|
|
}
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
|
|
ifr.ifr_flags = ifp->if_flags;
|
2008-10-25 01:46:09 +04:00
|
|
|
ret = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr);
|
2000-07-04 22:46:49 +04:00
|
|
|
/* Restore interface state if not successful. */
|
|
|
|
if (ret != 0) {
|
|
|
|
ifp->if_pcount = pcount;
|
|
|
|
ifp->if_flags = flags;
|
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return ret;
|
2000-07-04 22:46:49 +04:00
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Map interface name to
|
|
|
|
* interface structure pointer.
|
|
|
|
*/
|
|
|
|
struct ifnet *
|
2005-12-12 02:05:24 +03:00
|
|
|
ifunit(const char *name)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
2002-05-24 01:34:39 +04:00
|
|
|
const char *cp = name;
|
|
|
|
u_int unit = 0;
|
|
|
|
u_int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the entire name is a number, treat it as an ifindex.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < IFNAMSIZ && *cp >= '0' && *cp <= '9'; i++, cp++) {
|
|
|
|
unit = unit * 10 + (*cp - '0');
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the number took all of the name, then it's a valid ifindex.
|
|
|
|
*/
|
|
|
|
if (i == IFNAMSIZ || (cp != name && *cp == '\0')) {
|
2003-12-10 14:46:33 +03:00
|
|
|
if (unit >= if_indexlim)
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
2002-05-24 01:34:39 +04:00
|
|
|
ifp = ifindex2ifnet[unit];
|
|
|
|
if (ifp == NULL || ifp->if_output == if_nulloutput)
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
|
|
|
return ifp;
|
2002-05-24 01:34:39 +04:00
|
|
|
}
|
1996-05-07 06:40:22 +04:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2000-02-02 01:52:04 +03:00
|
|
|
if (ifp->if_output == if_nulloutput)
|
|
|
|
continue;
|
|
|
|
if (strcmp(ifp->if_xname, name) == 0)
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifp;
|
2000-02-02 01:52:04 +03:00
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2008-01-22 19:25:15 +03:00
|
|
|
/* common */
|
2008-02-07 04:21:52 +03:00
|
|
|
int
|
|
|
|
ifioctl_common(struct ifnet *ifp, u_long cmd, void *data)
|
2008-01-22 19:25:15 +03:00
|
|
|
{
|
2008-05-13 22:09:22 +04:00
|
|
|
int s;
|
2008-02-07 04:21:52 +03:00
|
|
|
struct ifreq *ifr;
|
|
|
|
struct ifcapreq *ifcr;
|
|
|
|
struct ifdatareq *ifdr;
|
2008-01-22 19:25:15 +03:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCSIFCAP:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifcr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
if ((ifcr->ifcr_capenable & ~ifp->if_capabilities) != 0)
|
|
|
|
return EINVAL;
|
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
if (ifcr->ifcr_capenable == ifp->if_capenable)
|
|
|
|
return 0;
|
2008-01-22 19:25:15 +03:00
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
ifp->if_capenable = ifcr->ifcr_capenable;
|
2008-01-22 19:25:15 +03:00
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
/* Pre-compute the checksum flags mask. */
|
|
|
|
ifp->if_csum_flags_tx = 0;
|
|
|
|
ifp->if_csum_flags_rx = 0;
|
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) {
|
|
|
|
ifp->if_csum_flags_tx |= M_CSUM_IPv4;
|
|
|
|
}
|
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) {
|
|
|
|
ifp->if_csum_flags_rx |= M_CSUM_IPv4;
|
|
|
|
}
|
2008-01-22 19:25:15 +03:00
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) {
|
|
|
|
ifp->if_csum_flags_tx |= M_CSUM_TCPv4;
|
|
|
|
}
|
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) {
|
|
|
|
ifp->if_csum_flags_rx |= M_CSUM_TCPv4;
|
|
|
|
}
|
2008-01-22 19:25:15 +03:00
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) {
|
|
|
|
ifp->if_csum_flags_tx |= M_CSUM_UDPv4;
|
|
|
|
}
|
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) {
|
|
|
|
ifp->if_csum_flags_rx |= M_CSUM_UDPv4;
|
|
|
|
}
|
2008-01-22 19:25:15 +03:00
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) {
|
|
|
|
ifp->if_csum_flags_tx |= M_CSUM_TCPv6;
|
|
|
|
}
|
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) {
|
|
|
|
ifp->if_csum_flags_rx |= M_CSUM_TCPv6;
|
|
|
|
}
|
2008-01-22 19:25:15 +03:00
|
|
|
|
2008-01-23 01:26:30 +03:00
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) {
|
|
|
|
ifp->if_csum_flags_tx |= M_CSUM_UDPv6;
|
2008-01-22 19:25:15 +03:00
|
|
|
}
|
2008-01-23 01:26:30 +03:00
|
|
|
if (ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) {
|
|
|
|
ifp->if_csum_flags_rx |= M_CSUM_UDPv6;
|
|
|
|
}
|
2008-02-07 04:21:52 +03:00
|
|
|
if (ifp->if_flags & IFF_UP)
|
|
|
|
return ENETRESET;
|
|
|
|
return 0;
|
2008-01-22 19:25:15 +03:00
|
|
|
case SIOCSIFFLAGS:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
|
|
|
|
s = splnet();
|
|
|
|
if_down(ifp);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
|
|
|
|
s = splnet();
|
|
|
|
if_up(ifp);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
|
|
|
|
(ifr->ifr_flags &~ IFF_CANTCHANGE);
|
|
|
|
break;
|
|
|
|
case SIOCGIFFLAGS:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifr->ifr_flags = ifp->if_flags;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFMETRIC:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifr->ifr_metric = ifp->if_metric;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFMTU:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifr->ifr_mtu = ifp->if_mtu;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFDLT:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifr->ifr_dlt = ifp->if_dlt;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFCAP:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifcr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifcr->ifcr_capabilities = ifp->if_capabilities;
|
|
|
|
ifcr->ifcr_capenable = ifp->if_capenable;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFMETRIC:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifp->if_metric = ifr->ifr_metric;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCGIFDATA:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifdr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifdr->ifdr_data = ifp->if_data;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCZIFDATA:
|
2008-02-07 04:21:52 +03:00
|
|
|
ifdr = data;
|
2008-01-22 19:25:15 +03:00
|
|
|
ifdr->ifdr_data = ifp->if_data;
|
|
|
|
/*
|
|
|
|
* Assumes that the volatile counters that can be
|
|
|
|
* zero'ed are at the end of if_data.
|
|
|
|
*/
|
|
|
|
memset(&ifp->if_data.ifi_ipackets, 0, sizeof(ifp->if_data) -
|
|
|
|
offsetof(struct if_data, ifi_ipackets));
|
|
|
|
break;
|
2008-02-07 04:21:52 +03:00
|
|
|
case SIOCSIFMTU:
|
|
|
|
ifr = data;
|
|
|
|
if (ifp->if_mtu == ifr->ifr_mtu)
|
|
|
|
break;
|
|
|
|
ifp->if_mtu = ifr->ifr_mtu;
|
|
|
|
/*
|
|
|
|
* If the link MTU changed, do network layer specific procedure.
|
|
|
|
*/
|
|
|
|
#ifdef INET6
|
|
|
|
nd6_setmtu(ifp);
|
|
|
|
#endif
|
|
|
|
return ENETRESET;
|
2008-01-22 19:25:15 +03:00
|
|
|
default:
|
2008-05-12 03:48:07 +04:00
|
|
|
return ENOTTY;
|
2008-01-22 19:25:15 +03:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
int
|
|
|
|
ifaddrpref_ioctl(struct socket *so, u_long cmd, void *data, struct ifnet *ifp,
|
|
|
|
lwp_t *l)
|
|
|
|
{
|
|
|
|
struct if_addrprefreq *ifap = (struct if_addrprefreq *)data;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
const struct sockaddr *any, *sa;
|
|
|
|
union {
|
|
|
|
struct sockaddr sa;
|
|
|
|
struct sockaddr_storage ss;
|
2009-09-16 03:24:34 +04:00
|
|
|
} u, v;
|
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
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCSIFADDRPREF:
|
|
|
|
if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE,
|
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
|
|
|
|
NULL) != 0)
|
|
|
|
return EPERM;
|
|
|
|
case SIOCGIFADDRPREF:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity checks */
|
|
|
|
if (data == NULL || ifp == NULL) {
|
|
|
|
panic("invalid argument to %s", __func__);
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/* address must be specified on ADD and DELETE */
|
|
|
|
sa = sstocsa(&ifap->ifap_addr);
|
|
|
|
if (sa->sa_family != sofamily(so))
|
|
|
|
return EINVAL;
|
|
|
|
if ((any = sockaddr_any(sa)) == NULL || sa->sa_len != any->sa_len)
|
|
|
|
return EINVAL;
|
|
|
|
|
2009-09-16 03:24:34 +04:00
|
|
|
sockaddr_externalize(&v.sa, sizeof(v.ss), sa);
|
|
|
|
|
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
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
|
|
|
if (ifa->ifa_addr->sa_family != sa->sa_family)
|
|
|
|
continue;
|
|
|
|
sockaddr_externalize(&u.sa, sizeof(u.ss), ifa->ifa_addr);
|
2009-09-16 03:24:34 +04:00
|
|
|
if (sockaddr_cmp(&u.sa, &v.sa) == 0)
|
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
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ifa == NULL)
|
|
|
|
return EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCSIFADDRPREF:
|
|
|
|
ifa->ifa_preference = ifap->ifap_preference;
|
|
|
|
return 0;
|
|
|
|
case SIOCGIFADDRPREF:
|
|
|
|
/* fill in the if_laddrreq structure */
|
|
|
|
(void)sockaddr_copy(sstosa(&ifap->ifap_addr),
|
|
|
|
sizeof(ifap->ifap_addr), ifa->ifa_addr);
|
|
|
|
ifap->ifap_preference = ifa->ifa_preference;
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Interface ioctls.
|
|
|
|
*/
|
1994-05-13 10:01:27 +04:00
|
|
|
int
|
2007-03-04 08:59:00 +03:00
|
|
|
ifioctl(struct socket *so, u_long cmd, void *data, struct lwp *l)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifreq *ifr;
|
2001-06-02 20:17:06 +04:00
|
|
|
struct ifcapreq *ifcr;
|
2002-05-24 01:34:39 +04:00
|
|
|
struct ifdatareq *ifdr;
|
2008-02-07 11:48:16 +03:00
|
|
|
int error = 0;
|
2007-06-01 19:41:15 +04:00
|
|
|
#if defined(COMPAT_OSOCK) || defined(COMPAT_OIFREQ)
|
|
|
|
u_long ocmd = cmd;
|
|
|
|
#endif
|
1999-07-01 12:12:45 +04:00
|
|
|
short oif_flags;
|
2007-05-30 01:32:27 +04:00
|
|
|
#ifdef COMPAT_OIFREQ
|
|
|
|
struct ifreq ifrb;
|
2007-05-30 02:05:01 +04:00
|
|
|
struct oifreq *oifr = NULL;
|
2007-05-30 01:32:27 +04:00
|
|
|
#endif
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
switch (cmd) {
|
2007-05-30 01:32:27 +04:00
|
|
|
#ifdef COMPAT_OIFREQ
|
1993-03-21 12:45:37 +03:00
|
|
|
case OSIOCGIFCONF:
|
2007-05-30 01:32:27 +04:00
|
|
|
case OOSIOCGIFCONF:
|
|
|
|
return compat_ifconf(cmd, data);
|
2009-01-11 05:45:45 +03:00
|
|
|
#endif
|
|
|
|
#ifdef COMPAT_OIFDATA
|
|
|
|
case OSIOCGIFDATA:
|
|
|
|
case OSIOCZIFDATA:
|
|
|
|
return compat_ifdatareq(l, cmd, data);
|
2007-05-30 01:32:27 +04:00
|
|
|
#endif
|
|
|
|
case SIOCGIFCONF:
|
2007-03-18 23:59:38 +03:00
|
|
|
return ifconf(cmd, data);
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
case SIOCINITIFADDR:
|
|
|
|
return EPERM;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2007-06-01 19:41:15 +04:00
|
|
|
|
2007-05-30 01:32:27 +04:00
|
|
|
#ifdef COMPAT_OIFREQ
|
2007-08-20 08:49:40 +04:00
|
|
|
cmd = compat_cvtcmd(cmd);
|
2007-05-30 01:32:27 +04:00
|
|
|
if (cmd != ocmd) {
|
|
|
|
oifr = data;
|
|
|
|
data = ifr = &ifrb;
|
|
|
|
ifreqo2n(oifr, ifr);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
ifr = data;
|
|
|
|
ifcr = data;
|
|
|
|
ifdr = data;
|
2000-07-02 04:20:48 +04:00
|
|
|
|
2006-10-26 00:28:45 +04:00
|
|
|
ifp = ifunit(ifr->ifr_name);
|
|
|
|
|
2000-07-02 04:20:48 +04:00
|
|
|
switch (cmd) {
|
|
|
|
case SIOCIFCREATE:
|
|
|
|
case SIOCIFDESTROY:
|
2007-03-18 23:59:38 +03:00
|
|
|
if (l != NULL) {
|
2006-10-26 00:28:45 +04:00
|
|
|
error = kauth_authorize_network(l->l_cred,
|
|
|
|
KAUTH_NETWORK_INTERFACE,
|
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp,
|
|
|
|
(void *)cmd, NULL);
|
2007-03-18 23:59:38 +03:00
|
|
|
if (error != 0)
|
2005-01-09 15:18:46 +03:00
|
|
|
return error;
|
|
|
|
}
|
2007-03-18 23:59:38 +03:00
|
|
|
return (cmd == SIOCIFCREATE) ?
|
2000-07-04 05:51:22 +04:00
|
|
|
if_clone_create(ifr->ifr_name) :
|
2007-03-18 23:59:38 +03:00
|
|
|
if_clone_destroy(ifr->ifr_name);
|
2000-07-20 22:40:26 +04:00
|
|
|
|
|
|
|
case SIOCIFGCLONERS:
|
2007-03-18 23:59:38 +03:00
|
|
|
return if_clone_list((struct if_clonereq *)data);
|
2000-07-02 04:20:48 +04:00
|
|
|
}
|
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
if (ifp == NULL)
|
|
|
|
return ENXIO;
|
2005-01-09 15:18:46 +03:00
|
|
|
|
|
|
|
switch (cmd) {
|
2009-02-12 22:05:36 +03:00
|
|
|
case SIOCALIFADDR:
|
|
|
|
case SIOCDLIFADDR:
|
|
|
|
case SIOCSIFADDRPREF:
|
2005-01-09 15:18:46 +03:00
|
|
|
case SIOCSIFFLAGS:
|
|
|
|
case SIOCSIFCAP:
|
|
|
|
case SIOCSIFMETRIC:
|
|
|
|
case SIOCZIFDATA:
|
|
|
|
case SIOCSIFMTU:
|
|
|
|
case SIOCSIFPHYADDR:
|
|
|
|
case SIOCDIFPHYADDR:
|
|
|
|
#ifdef INET6
|
|
|
|
case SIOCSIFPHYADDR_IN6:
|
|
|
|
#endif
|
|
|
|
case SIOCSLIFPHYADDR:
|
|
|
|
case SIOCADDMULTI:
|
|
|
|
case SIOCDELMULTI:
|
|
|
|
case SIOCSIFMEDIA:
|
2005-02-27 01:45:09 +03:00
|
|
|
case SIOCSDRVSPEC:
|
2007-08-20 08:49:40 +04:00
|
|
|
case SIOCG80211:
|
|
|
|
case SIOCS80211:
|
2005-01-09 15:18:46 +03:00
|
|
|
case SIOCS80211NWID:
|
|
|
|
case SIOCS80211NWKEY:
|
|
|
|
case SIOCS80211POWER:
|
|
|
|
case SIOCS80211BSSID:
|
|
|
|
case SIOCS80211CHANNEL:
|
2007-03-18 23:59:38 +03:00
|
|
|
if (l != NULL) {
|
2006-10-26 00:28:45 +04:00
|
|
|
error = kauth_authorize_network(l->l_cred,
|
|
|
|
KAUTH_NETWORK_INTERFACE,
|
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp,
|
|
|
|
(void *)cmd, NULL);
|
2007-03-18 23:59:38 +03:00
|
|
|
if (error != 0)
|
2005-01-09 15:18:46 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-01 12:12:45 +04:00
|
|
|
oif_flags = ifp->if_flags;
|
1993-08-14 10:29:28 +04:00
|
|
|
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
error = (*ifp->if_ioctl)(ifp, cmd, data);
|
|
|
|
if (error != ENOTTY)
|
|
|
|
;
|
|
|
|
else if (so->so_proto == NULL)
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
else {
|
2005-09-24 19:52:03 +04:00
|
|
|
#ifdef COMPAT_OSOCK
|
2007-05-30 01:32:27 +04:00
|
|
|
error = compat_ifioctl(so, ocmd, cmd, data, l);
|
1993-03-21 12:45:37 +03:00
|
|
|
#else
|
2008-04-24 15:38:36 +04:00
|
|
|
error = (*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
|
1996-05-22 17:54:55 +04:00
|
|
|
(struct mbuf *)cmd, (struct mbuf *)data,
|
2008-04-24 17:30:52 +04:00
|
|
|
(struct mbuf *)ifp, l);
|
2005-09-24 19:52:03 +04:00
|
|
|
#endif
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) {
|
|
|
|
#ifdef INET6
|
|
|
|
if ((ifp->if_flags & IFF_UP) != 0) {
|
2008-02-07 11:48:16 +03:00
|
|
|
int s = splnet();
|
1999-07-01 12:12:45 +04:00
|
|
|
in6_if_up(ifp);
|
|
|
|
splx(s);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
#endif
|
|
|
|
}
|
2007-05-30 01:32:27 +04:00
|
|
|
#ifdef COMPAT_OIFREQ
|
|
|
|
if (cmd != ocmd)
|
|
|
|
ifreqn2o(oifr, ifr);
|
|
|
|
#endif
|
1999-07-01 12:12:45 +04:00
|
|
|
|
2007-03-18 23:59:38 +03:00
|
|
|
return error;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return interface configuration
|
|
|
|
* of system. List may be used
|
|
|
|
* in later ioctl's (above) to get
|
|
|
|
* other information.
|
2007-09-11 23:31:22 +04:00
|
|
|
*
|
|
|
|
* Each record is a struct ifreq. Before the addition of
|
|
|
|
* sockaddr_storage, the API rule was that sockaddr flavors that did
|
|
|
|
* not fit would extend beyond the struct ifreq, with the next struct
|
|
|
|
* ifreq starting sa_len beyond the struct sockaddr. Because the
|
|
|
|
* union in struct ifreq includes struct sockaddr_storage, every kind
|
|
|
|
* of sockaddr must fit. Thus, there are no longer any overlength
|
|
|
|
* records.
|
|
|
|
*
|
|
|
|
* Records are added to the user buffer if they fit, and ifc_len is
|
|
|
|
* adjusted to the length that was written. Thus, the user is only
|
|
|
|
* assured of getting the complete list if ifc_len on return is at
|
|
|
|
* least sizeof(struct ifreq) less than it was on entry.
|
|
|
|
*
|
|
|
|
* If the user buffer pointer is NULL, this routine copies no data and
|
|
|
|
* returns the amount of space that would be needed.
|
|
|
|
*
|
|
|
|
* Invariants:
|
|
|
|
* ifrp points to the next part of the user's buffer to be used. If
|
|
|
|
* ifrp != NULL, space holds the number of bytes remaining that we may
|
|
|
|
* write at ifrp. Otherwise, space holds the number of bytes that
|
|
|
|
* would have been written had there been adequate space.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
1994-05-13 10:01:27 +04:00
|
|
|
int
|
2007-03-04 08:59:00 +03:00
|
|
|
ifconf(u_long cmd, void *data)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifconf *ifc = (struct ifconf *)data;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
struct ifaddr *ifa;
|
1993-03-21 12:45:37 +03:00
|
|
|
struct ifreq ifr, *ifrp;
|
2007-06-01 13:35:47 +04:00
|
|
|
int space, error = 0;
|
2007-09-11 23:31:22 +04:00
|
|
|
const int sz = (int)sizeof(struct ifreq);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2007-06-01 13:35:47 +04:00
|
|
|
if ((ifrp = ifc->ifc_req) == NULL)
|
2003-08-09 22:13:03 +04:00
|
|
|
space = 0;
|
2007-06-01 13:35:47 +04:00
|
|
|
else
|
|
|
|
space = ifc->ifc_len;
|
2005-01-25 00:25:09 +03:00
|
|
|
IFNET_FOREACH(ifp) {
|
2006-10-27 19:33:11 +04:00
|
|
|
(void)strncpy(ifr.ifr_name, ifp->if_xname,
|
2006-10-22 23:21:26 +04:00
|
|
|
sizeof(ifr.ifr_name));
|
2006-10-27 19:33:11 +04:00
|
|
|
if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0')
|
|
|
|
return ENAMETOOLONG;
|
2007-12-06 01:51:01 +03:00
|
|
|
if (IFADDR_EMPTY(ifp)) {
|
2007-09-11 23:31:22 +04:00
|
|
|
/* Interface with no addresses - send zero sockaddr. */
|
2003-08-09 22:13:03 +04:00
|
|
|
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
|
2008-03-01 00:23:55 +03:00
|
|
|
if (ifrp == NULL) {
|
2007-09-11 23:31:22 +04:00
|
|
|
space += sz;
|
2008-03-01 00:23:55 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (space >= sz) {
|
|
|
|
error = copyout(&ifr, ifrp, sz);
|
|
|
|
if (error != 0)
|
|
|
|
return error;
|
|
|
|
ifrp++;
|
|
|
|
space -= sz;
|
|
|
|
}
|
2003-08-09 22:13:03 +04:00
|
|
|
}
|
|
|
|
|
2007-12-04 13:31:14 +03:00
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
2000-03-30 13:45:33 +04:00
|
|
|
struct sockaddr *sa = ifa->ifa_addr;
|
2007-09-11 23:31:22 +04:00
|
|
|
/* all sockaddrs must fit in sockaddr_storage */
|
|
|
|
KASSERT(sa->sa_len <= sizeof(ifr.ifr_ifru));
|
|
|
|
|
2008-03-01 00:23:55 +03:00
|
|
|
if (ifrp == NULL) {
|
2007-09-11 23:31:22 +04:00
|
|
|
space += sz;
|
2008-03-01 00:23:55 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
memcpy(&ifr.ifr_space, sa, sa->sa_len);
|
|
|
|
if (space >= sz) {
|
|
|
|
error = copyout(&ifr, ifrp, sz);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
ifrp++; space -= sz;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
2008-03-01 00:23:55 +03:00
|
|
|
if (ifrp != NULL) {
|
2007-09-11 23:31:22 +04:00
|
|
|
KASSERT(0 <= space && space <= ifc->ifc_len);
|
2003-08-09 22:13:03 +04:00
|
|
|
ifc->ifc_len -= space;
|
2008-03-01 00:23:55 +03:00
|
|
|
} else {
|
2007-09-11 23:31:22 +04:00
|
|
|
KASSERT(space >= 0);
|
|
|
|
ifc->ifc_len = space;
|
|
|
|
}
|
2007-06-01 13:35:47 +04:00
|
|
|
return (0);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2003-11-10 23:03:29 +03:00
|
|
|
|
2007-09-01 01:02:15 +04:00
|
|
|
int
|
|
|
|
ifreq_setaddr(const u_long cmd, struct ifreq *ifr, const struct sockaddr *sa)
|
|
|
|
{
|
|
|
|
uint8_t len;
|
|
|
|
u_long ncmd;
|
|
|
|
|
2007-09-01 11:03:32 +04:00
|
|
|
if ((ncmd = compat_cvtcmd(cmd)) != cmd)
|
2009-11-14 02:11:08 +03:00
|
|
|
len = sizeof(ifr->ifr_addr);
|
2007-10-12 00:47:27 +04:00
|
|
|
else
|
2009-11-14 02:11:08 +03:00
|
|
|
len = sizeof(ifr->ifr_ifru.ifru_space);
|
2007-09-01 01:02:15 +04:00
|
|
|
if (len < sa->sa_len)
|
|
|
|
return EFBIG;
|
2009-11-14 02:11:08 +03:00
|
|
|
memset(&ifr->ifr_addr, 0, len);
|
2007-10-12 00:47:27 +04:00
|
|
|
sockaddr_copy(&ifr->ifr_addr, len, sa);
|
2007-09-01 01:02:15 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-31 19:48:13 +04:00
|
|
|
/*
|
|
|
|
* Queue message on interface, and start output if interface
|
|
|
|
* not yet active.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ifq_enqueue(struct ifnet *ifp, struct mbuf *m
|
|
|
|
ALTQ_COMMA ALTQ_DECL(struct altq_pktattr *pktattr))
|
|
|
|
{
|
|
|
|
int len = m->m_pkthdr.len;
|
|
|
|
int mflags = m->m_flags;
|
|
|
|
int s = splnet();
|
|
|
|
int error;
|
|
|
|
|
2005-04-01 01:14:52 +04:00
|
|
|
IFQ_ENQUEUE(&ifp->if_snd, m, pktattr, error);
|
2007-03-18 23:59:38 +03:00
|
|
|
if (error != 0)
|
|
|
|
goto out;
|
2005-03-31 19:48:13 +04:00
|
|
|
ifp->if_obytes += len;
|
|
|
|
if (mflags & M_MCAST)
|
|
|
|
ifp->if_omcasts++;
|
|
|
|
if ((ifp->if_flags & IFF_OACTIVE) == 0)
|
|
|
|
(*ifp->if_start)(ifp);
|
2007-03-18 23:59:38 +03:00
|
|
|
out:
|
2005-03-31 19:48:13 +04:00
|
|
|
splx(s);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Queue message on interface, possibly using a second fast queue
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ifq_enqueue2(struct ifnet *ifp, struct ifqueue *ifq, struct mbuf *m
|
|
|
|
ALTQ_COMMA ALTQ_DECL(struct altq_pktattr *pktattr))
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (ifq != NULL
|
|
|
|
#ifdef ALTQ
|
|
|
|
&& ALTQ_IS_ENABLED(&ifp->if_snd) == 0
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
if (IF_QFULL(ifq)) {
|
|
|
|
IF_DROP(&ifp->if_snd);
|
|
|
|
m_freem(m);
|
|
|
|
if (error == 0)
|
|
|
|
error = ENOBUFS;
|
2007-03-18 23:59:38 +03:00
|
|
|
} else
|
2005-03-31 19:48:13 +04:00
|
|
|
IF_ENQUEUE(ifq, m);
|
|
|
|
} else
|
2005-04-01 01:14:52 +04:00
|
|
|
IFQ_ENQUEUE(&ifp->if_snd, m, pktattr, error);
|
2005-03-31 19:48:13 +04:00
|
|
|
if (error != 0) {
|
|
|
|
++ifp->if_oerrors;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-13 04:23:31 +04:00
|
|
|
static void
|
|
|
|
sysctl_sndq_setup(struct sysctllog **clog, const char *ifname,
|
|
|
|
struct ifaltq *ifq)
|
|
|
|
{
|
|
|
|
const struct sysctlnode *cnode, *rnode;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, NULL, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "net", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, &rnode, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "interfaces",
|
|
|
|
SYSCTL_DESCR("Per-interface controls"),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, &rnode, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, ifname,
|
|
|
|
SYSCTL_DESCR("Interface controls"),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, &rnode, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "sndq",
|
|
|
|
SYSCTL_DESCR("Interface output queue controls"),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, &rnode, &cnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_INT, "len",
|
|
|
|
SYSCTL_DESCR("Current output queue length"),
|
|
|
|
NULL, 0, &ifq->ifq_len, 0,
|
|
|
|
CTL_CREATE, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, &rnode, &cnode,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "maxlen",
|
|
|
|
SYSCTL_DESCR("Maximum allowed output queue length"),
|
|
|
|
NULL, 0, &ifq->ifq_maxlen, 0,
|
|
|
|
CTL_CREATE, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (sysctl_createv(clog, 0, &rnode, &cnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_INT, "drops",
|
|
|
|
SYSCTL_DESCR("Packets dropped due to full output queue"),
|
|
|
|
NULL, 0, &ifq->ifq_drops, 0,
|
|
|
|
CTL_CREATE, CTL_EOL) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
return;
|
|
|
|
bad:
|
|
|
|
printf("%s: could not attach sysctl nodes\n", ifname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-01-29 19:33:14 +03:00
|
|
|
#if defined(INET) || defined(INET6)
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
static void
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_net_ifq_setup(struct sysctllog **clog,
|
|
|
|
int pf, const char *pfname,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
int ipn, const char *ipname,
|
|
|
|
int qid, struct ifqueue *ifq)
|
2003-11-10 23:03:29 +03:00
|
|
|
{
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "net", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, pfname, NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, pf, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, ipname, NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, pf, ipn, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_NODE, "ifq",
|
|
|
|
SYSCTL_DESCR("Protocol input queue controls"),
|
2004-03-24 18:34:46 +03:00
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, pf, ipn, qid, CTL_EOL);
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "len",
|
|
|
|
SYSCTL_DESCR("Current input queue length"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ifq->ifq_len, 0,
|
|
|
|
CTL_NET, pf, ipn, qid, IFQCTL_LEN, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "maxlen",
|
|
|
|
SYSCTL_DESCR("Maximum allowed input queue length"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ifq->ifq_maxlen, 0,
|
|
|
|
CTL_NET, pf, ipn, qid, IFQCTL_MAXLEN, CTL_EOL);
|
2003-11-10 23:03:29 +03:00
|
|
|
#ifdef notyet
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "peak",
|
|
|
|
SYSCTL_DESCR("Highest input queue length"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ifq->ifq_peak, 0,
|
|
|
|
CTL_NET, pf, ipn, qid, IFQCTL_PEAK, CTL_EOL);
|
2003-11-10 23:03:29 +03:00
|
|
|
#endif
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "drops",
|
|
|
|
SYSCTL_DESCR("Packets dropped due to full input queue"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ifq->ifq_drops, 0,
|
|
|
|
CTL_NET, pf, ipn, qid, IFQCTL_DROPS, CTL_EOL);
|
|
|
|
}
|
2004-01-29 19:33:14 +03:00
|
|
|
#endif /* INET || INET6 */
|