1c398230bSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1980, 1986, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 2966afbd68SRuslan Ermilov * @(#)if.c 8.5 (Berkeley) 1/9/95 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 32df8bae1dSRodney W. Grimes 335591b823SEivind Eklund #include "opt_compat.h" 34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 350d0f9d1eSYoshinobu Inoue #include "opt_inet.h" 36e70cd263SRobert Watson #include "opt_mac.h" 37a9771948SGleb Smirnoff #include "opt_carp.h" 385591b823SEivind Eklund 39df8bae1dSRodney W. Grimes #include <sys/param.h> 404dcf2bbbSBrooks Davis #include <sys/types.h> 41f13ad206SJonathan Lemon #include <sys/conf.h> 42e70cd263SRobert Watson #include <sys/mac.h> 434d1d4912SBruce Evans #include <sys/malloc.h> 444dcf2bbbSBrooks Davis #include <sys/sbuf.h> 45d2b4566aSJonathan Lemon #include <sys/bus.h> 46df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 47df8bae1dSRodney W. Grimes #include <sys/systm.h> 48df8bae1dSRodney W. Grimes #include <sys/proc.h> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 50df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 51df8bae1dSRodney W. Grimes #include <sys/protosw.h> 52df8bae1dSRodney W. Grimes #include <sys/kernel.h> 5351a53488SBruce Evans #include <sys/sockio.h> 54963e4c2aSGarrett Wollman #include <sys/syslog.h> 55602d513cSGarrett Wollman #include <sys/sysctl.h> 56af5e59bfSRobert Watson #include <sys/taskqueue.h> 5731b1bfe1SHajimu UMEMOTO #include <sys/domain.h> 5891421ba2SRobert Watson #include <sys/jail.h> 59fa882e87SBrooks Davis #include <machine/stdarg.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <net/if.h> 62b106252cSBill Paul #include <net/if_arp.h> 63f889d2efSBrooks Davis #include <net/if_clone.h> 64df8bae1dSRodney W. Grimes #include <net/if_dl.h> 6566ce51ceSArchie Cobbs #include <net/if_types.h> 6630aad87dSBrooks Davis #include <net/if_var.h> 679448326fSPoul-Henning Kamp #include <net/radix.h> 685500d3beSWarner Losh #include <net/route.h> 69df8bae1dSRodney W. Grimes 700d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6) 7182cd038dSYoshinobu Inoue /*XXX*/ 7282cd038dSYoshinobu Inoue #include <netinet/in.h> 730d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h> 743411310dSYoshinobu Inoue #ifdef INET6 75978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h> 76978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h> 773411310dSYoshinobu Inoue #endif 7882cd038dSYoshinobu Inoue #endif 79c0933269SPeter Wemm #ifdef INET 80c0933269SPeter Wemm #include <netinet/if_ether.h> 81c0933269SPeter Wemm #endif 82a9771948SGleb Smirnoff #ifdef DEV_CARP 83a9771948SGleb Smirnoff #include <netinet/ip_carp.h> 84a9771948SGleb Smirnoff #endif 8582cd038dSYoshinobu Inoue 865515c2e7SGleb Smirnoff SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 875515c2e7SGleb Smirnoff SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 885515c2e7SGleb Smirnoff 895515c2e7SGleb Smirnoff /* Log link state change events */ 905515c2e7SGleb Smirnoff static int log_link_state_change = 1; 915515c2e7SGleb Smirnoff 925515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, 935515c2e7SGleb Smirnoff &log_link_state_change, 0, 945515c2e7SGleb Smirnoff "log interface link state change events"); 955515c2e7SGleb Smirnoff 968f867517SAndrew Thompson void (*bstp_linkstate_p)(struct ifnet *ifp, int state); 971c7899c7SGleb Smirnoff void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 981c7899c7SGleb Smirnoff 994cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; 1004cb655c0SMax Laier 10131b1bfe1SHajimu UMEMOTO static void if_attachdomain(void *); 10231b1bfe1SHajimu UMEMOTO static void if_attachdomain1(struct ifnet *); 1030b59d917SJonathan Lemon static int ifconf(u_long, caddr_t); 104f9132cebSJonathan Lemon static void if_grow(void); 105f9132cebSJonathan Lemon static void if_init(void *); 106f9132cebSJonathan Lemon static void if_check(void *); 10702b199f1SMax Laier static void if_qflush(struct ifaltq *); 1088614fb12SMax Laier static void if_route(struct ifnet *, int flag, int fam); 1091a3b6859SYaroslav Tykhiy static int if_setflag(struct ifnet *, int, int, int *, int); 1100b59d917SJonathan Lemon static void if_slowtimo(void *); 1118614fb12SMax Laier static void if_unroute(struct ifnet *, int flag, int fam); 1128071913dSRuslan Ermilov static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); 1130b59d917SJonathan Lemon static int if_rtdel(struct radix_node *, void *); 114f13ad206SJonathan Lemon static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *); 115af5e59bfSRobert Watson static void if_start_deferred(void *context, int pending); 11668a3482fSGleb Smirnoff static void do_link_state_change(void *, int); 11782cd038dSYoshinobu Inoue #ifdef INET6 11882cd038dSYoshinobu Inoue /* 11982cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 12082cd038dSYoshinobu Inoue * should be more generalized? 12182cd038dSYoshinobu Inoue */ 122929ddbbbSAlfred Perlstein extern void nd6_setmtu(struct ifnet *); 12382cd038dSYoshinobu Inoue #endif 12482cd038dSYoshinobu Inoue 1250b59d917SJonathan Lemon int if_index = 0; 126f9132cebSJonathan Lemon struct ifindex_entry *ifindex_table = NULL; 1270b59d917SJonathan Lemon int ifqmaxlen = IFQ_MAXLEN; 1280b59d917SJonathan Lemon struct ifnethead ifnet; /* depend on static init XXX */ 129b30a244cSJeffrey Hsu struct mtx ifnet_lock; 130fc74a9f9SBrooks Davis static if_com_alloc_t *if_com_alloc[256]; 131fc74a9f9SBrooks Davis static if_com_free_t *if_com_free[256]; 1320b59d917SJonathan Lemon 133f9132cebSJonathan Lemon static int if_indexlim = 8; 134ad3b9257SJohn-Mark Gurney static struct knlist ifklist; 135f9132cebSJonathan Lemon 1369a2a57a1SJonathan Lemon static void filt_netdetach(struct knote *kn); 1379a2a57a1SJonathan Lemon static int filt_netdev(struct knote *kn, long hint); 1389a2a57a1SJonathan Lemon 1399a2a57a1SJonathan Lemon static struct filterops netdev_filtops = 1409a2a57a1SJonathan Lemon { 1, NULL, filt_netdetach, filt_netdev }; 1419a2a57a1SJonathan Lemon 1420b59d917SJonathan Lemon /* 1430b59d917SJonathan Lemon * System initialization 1440b59d917SJonathan Lemon */ 145f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL) 146f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL) 1470b59d917SJonathan Lemon 148fc74a9f9SBrooks Davis MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals"); 1490b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 1500b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 15130aad87dSBrooks Davis 152f13ad206SJonathan Lemon static d_open_t netopen; 153f13ad206SJonathan Lemon static d_close_t netclose; 154f13ad206SJonathan Lemon static d_ioctl_t netioctl; 1559a2a57a1SJonathan Lemon static d_kqfilter_t netkqfilter; 156f13ad206SJonathan Lemon 157f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = { 158dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 159dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1607ac40f5fSPoul-Henning Kamp .d_open = netopen, 1617ac40f5fSPoul-Henning Kamp .d_close = netclose, 1627ac40f5fSPoul-Henning Kamp .d_ioctl = netioctl, 1637ac40f5fSPoul-Henning Kamp .d_name = "net", 1647ac40f5fSPoul-Henning Kamp .d_kqfilter = netkqfilter, 165f13ad206SJonathan Lemon }; 166f13ad206SJonathan Lemon 167f13ad206SJonathan Lemon static int 16889c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td) 169f13ad206SJonathan Lemon { 170f13ad206SJonathan Lemon return (0); 171f13ad206SJonathan Lemon } 172f13ad206SJonathan Lemon 173f13ad206SJonathan Lemon static int 17489c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td) 175f13ad206SJonathan Lemon { 176f13ad206SJonathan Lemon return (0); 177f13ad206SJonathan Lemon } 178f13ad206SJonathan Lemon 179f13ad206SJonathan Lemon static int 18089c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 181f13ad206SJonathan Lemon { 182f13ad206SJonathan Lemon struct ifnet *ifp; 183f13ad206SJonathan Lemon int error, idx; 184f13ad206SJonathan Lemon 185f13ad206SJonathan Lemon /* only support interface specific ioctls */ 186f13ad206SJonathan Lemon if (IOCGROUP(cmd) != 'i') 187f13ad206SJonathan Lemon return (EOPNOTSUPP); 188f13ad206SJonathan Lemon idx = minor(dev); 189f13ad206SJonathan Lemon if (idx == 0) { 190f13ad206SJonathan Lemon /* 191f13ad206SJonathan Lemon * special network device, not interface. 192f13ad206SJonathan Lemon */ 193f13ad206SJonathan Lemon if (cmd == SIOCGIFCONF) 194f13ad206SJonathan Lemon return (ifconf(cmd, data)); /* XXX remove cmd */ 195f13ad206SJonathan Lemon return (EOPNOTSUPP); 196f13ad206SJonathan Lemon } 197f13ad206SJonathan Lemon 198f13ad206SJonathan Lemon ifp = ifnet_byindex(idx); 199f13ad206SJonathan Lemon if (ifp == NULL) 200f13ad206SJonathan Lemon return (ENXIO); 201f13ad206SJonathan Lemon 202f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 203f13ad206SJonathan Lemon if (error == ENOIOCTL) 204f13ad206SJonathan Lemon error = EOPNOTSUPP; 205f13ad206SJonathan Lemon return (error); 206f13ad206SJonathan Lemon } 207f13ad206SJonathan Lemon 2089a2a57a1SJonathan Lemon static int 20989c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn) 2109a2a57a1SJonathan Lemon { 211ad3b9257SJohn-Mark Gurney struct knlist *klist; 2129a2a57a1SJonathan Lemon struct ifnet *ifp; 2139a2a57a1SJonathan Lemon int idx; 2149a2a57a1SJonathan Lemon 215ad3b9257SJohn-Mark Gurney switch (kn->kn_filter) { 216ad3b9257SJohn-Mark Gurney case EVFILT_NETDEV: 217ad3b9257SJohn-Mark Gurney kn->kn_fop = &netdev_filtops; 218ad3b9257SJohn-Mark Gurney break; 219ad3b9257SJohn-Mark Gurney default: 220ad3b9257SJohn-Mark Gurney return (1); 221ad3b9257SJohn-Mark Gurney } 222ad3b9257SJohn-Mark Gurney 2239a2a57a1SJonathan Lemon idx = minor(dev); 2249a2a57a1SJonathan Lemon if (idx == 0) { 2259a2a57a1SJonathan Lemon klist = &ifklist; 2269a2a57a1SJonathan Lemon } else { 2279a2a57a1SJonathan Lemon ifp = ifnet_byindex(idx); 2289a2a57a1SJonathan Lemon if (ifp == NULL) 2299a2a57a1SJonathan Lemon return (1); 2309a2a57a1SJonathan Lemon klist = &ifp->if_klist; 2319a2a57a1SJonathan Lemon } 2329a2a57a1SJonathan Lemon 2339a2a57a1SJonathan Lemon kn->kn_hook = (caddr_t)klist; 2349a2a57a1SJonathan Lemon 235ad3b9257SJohn-Mark Gurney knlist_add(klist, kn, 0); 2369a2a57a1SJonathan Lemon 2379a2a57a1SJonathan Lemon return (0); 2389a2a57a1SJonathan Lemon } 2399a2a57a1SJonathan Lemon 2409a2a57a1SJonathan Lemon static void 2419a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn) 2429a2a57a1SJonathan Lemon { 243ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2449a2a57a1SJonathan Lemon 245ad3b9257SJohn-Mark Gurney knlist_remove(klist, kn, 0); 2469a2a57a1SJonathan Lemon } 2479a2a57a1SJonathan Lemon 2489a2a57a1SJonathan Lemon static int 2499a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint) 2509a2a57a1SJonathan Lemon { 251ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2529a2a57a1SJonathan Lemon 2539a2a57a1SJonathan Lemon /* 2549a2a57a1SJonathan Lemon * Currently NOTE_EXIT is abused to indicate device detach. 2559a2a57a1SJonathan Lemon */ 2569a2a57a1SJonathan Lemon if (hint == NOTE_EXIT) { 2579a2a57a1SJonathan Lemon kn->kn_data = NOTE_LINKINV; 2589a2a57a1SJonathan Lemon kn->kn_flags |= (EV_EOF | EV_ONESHOT); 259ad3b9257SJohn-Mark Gurney knlist_remove_inevent(klist, kn); 2609a2a57a1SJonathan Lemon return (1); 2619a2a57a1SJonathan Lemon } 262ad3b9257SJohn-Mark Gurney if (hint != 0) 2639a2a57a1SJonathan Lemon kn->kn_data = hint; /* current status */ 2649a2a57a1SJonathan Lemon if (kn->kn_sfflags & hint) 2659a2a57a1SJonathan Lemon kn->kn_fflags |= hint; 2669a2a57a1SJonathan Lemon return (kn->kn_fflags != 0); 2679a2a57a1SJonathan Lemon } 2689a2a57a1SJonathan Lemon 269df8bae1dSRodney W. Grimes /* 270df8bae1dSRodney W. Grimes * Network interface utility routines. 271df8bae1dSRodney W. Grimes * 272df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 273df8bae1dSRodney W. Grimes * parameters. 274df8bae1dSRodney W. Grimes */ 2752b14f991SJulian Elischer /* ARGSUSED*/ 276f9132cebSJonathan Lemon static void 27772fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused) 278f9132cebSJonathan Lemon { 279f9132cebSJonathan Lemon 280b30a244cSJeffrey Hsu IFNET_LOCK_INIT(); 281f9132cebSJonathan Lemon TAILQ_INIT(&ifnet); 282571dcd15SSuleiman Souhlal knlist_init(&ifklist, NULL, NULL, NULL, NULL); 283f9132cebSJonathan Lemon if_grow(); /* create initial table */ 284f13ad206SJonathan Lemon ifdev_byindex(0) = make_dev(&net_cdevsw, 0, 285f13ad206SJonathan Lemon UID_ROOT, GID_WHEEL, 0600, "network"); 286f889d2efSBrooks Davis if_clone_init(); 287f9132cebSJonathan Lemon } 288f9132cebSJonathan Lemon 289f9132cebSJonathan Lemon static void 290f9132cebSJonathan Lemon if_grow(void) 291f9132cebSJonathan Lemon { 292f9132cebSJonathan Lemon u_int n; 293f9132cebSJonathan Lemon struct ifindex_entry *e; 294f9132cebSJonathan Lemon 295f9132cebSJonathan Lemon if_indexlim <<= 1; 296f9132cebSJonathan Lemon n = if_indexlim * sizeof(*e); 297fc74a9f9SBrooks Davis e = malloc(n, M_IFNET, M_WAITOK | M_ZERO); 298f9132cebSJonathan Lemon if (ifindex_table != NULL) { 299f9132cebSJonathan Lemon memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2); 300fc74a9f9SBrooks Davis free((caddr_t)ifindex_table, M_IFNET); 301f9132cebSJonathan Lemon } 302f9132cebSJonathan Lemon ifindex_table = e; 303f9132cebSJonathan Lemon } 304f9132cebSJonathan Lemon 305f9132cebSJonathan Lemon /* ARGSUSED*/ 306f9132cebSJonathan Lemon static void 30772fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused) 308df8bae1dSRodney W. Grimes { 3098ba5bdaeSPeter Wemm struct ifnet *ifp; 3108ba5bdaeSPeter Wemm int s; 311df8bae1dSRodney W. Grimes 3128ba5bdaeSPeter Wemm s = splimp(); 313b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep on rare error; mostly okay XXX */ 314fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 315e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 31613fb40dfSBrooks Davis if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n"); 317df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 318e0ea20bcSPoul-Henning Kamp } 3195e980e22SJohn Baldwin if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 32013fb40dfSBrooks Davis if_printf(ifp, 32113fb40dfSBrooks Davis "XXX: driver didn't initialize queue mtx\n"); 3226008862bSJohn Baldwin mtx_init(&ifp->if_snd.ifq_mtx, "unknown", 3236008862bSJohn Baldwin MTX_NETWORK_LOCK, MTX_DEF); 324df5e1987SJonathan Lemon } 325df5e1987SJonathan Lemon } 326b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 3278ba5bdaeSPeter Wemm splx(s); 328df8bae1dSRodney W. Grimes if_slowtimo(0); 329df8bae1dSRodney W. Grimes } 330df8bae1dSRodney W. Grimes 331df8bae1dSRodney W. Grimes /* 332fc74a9f9SBrooks Davis * Allocate a struct ifnet and in index for an interface. 333fc74a9f9SBrooks Davis */ 334fc74a9f9SBrooks Davis struct ifnet* 335fc74a9f9SBrooks Davis if_alloc(u_char type) 336fc74a9f9SBrooks Davis { 337fc74a9f9SBrooks Davis struct ifnet *ifp; 338fc74a9f9SBrooks Davis 339fc74a9f9SBrooks Davis ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO); 340fc74a9f9SBrooks Davis 341dc7c539eSBrooks Davis /* 342dc7c539eSBrooks Davis * Try to find an empty slot below if_index. If we fail, take 343dc7c539eSBrooks Davis * the next slot. 344dc7c539eSBrooks Davis * 345dc7c539eSBrooks Davis * XXX: should be locked! 346dc7c539eSBrooks Davis */ 347dc7c539eSBrooks Davis for (ifp->if_index = 1; ifp->if_index <= if_index; ifp->if_index++) { 348dc7c539eSBrooks Davis if (ifnet_byindex(ifp->if_index) == NULL) 349dc7c539eSBrooks Davis break; 350dc7c539eSBrooks Davis } 351dc7c539eSBrooks Davis /* Catch if_index overflow. */ 352dc7c539eSBrooks Davis if (ifp->if_index < 1) { 353dc7c539eSBrooks Davis free(ifp, M_IFNET); 354dc7c539eSBrooks Davis return (NULL); 355dc7c539eSBrooks Davis } 356fc74a9f9SBrooks Davis if (ifp->if_index > if_index) 357fc74a9f9SBrooks Davis if_index = ifp->if_index; 358fc74a9f9SBrooks Davis if (if_index >= if_indexlim) 359fc74a9f9SBrooks Davis if_grow(); 360fc74a9f9SBrooks Davis ifnet_byindex(ifp->if_index) = ifp; 361fc74a9f9SBrooks Davis 362fc74a9f9SBrooks Davis ifp->if_type = type; 363fc74a9f9SBrooks Davis 364fc74a9f9SBrooks Davis if (if_com_alloc[type] != NULL) { 365fc74a9f9SBrooks Davis ifp->if_l2com = if_com_alloc[type](type, ifp); 36628ef2db4SBrooks Davis if (ifp->if_l2com == NULL) { 367fc74a9f9SBrooks Davis free(ifp, M_IFNET); 36828ef2db4SBrooks Davis return (NULL); 36928ef2db4SBrooks Davis } 370fc74a9f9SBrooks Davis } 3716da3131aSJohn Baldwin IF_ADDR_LOCK_INIT(ifp); 372fc74a9f9SBrooks Davis 373fc74a9f9SBrooks Davis return (ifp); 374fc74a9f9SBrooks Davis } 375fc74a9f9SBrooks Davis 376fc74a9f9SBrooks Davis void 377fc74a9f9SBrooks Davis if_free(struct ifnet *ifp) 378fc74a9f9SBrooks Davis { 379fc74a9f9SBrooks Davis 3807cf30146SBrooks Davis /* Do not add code to this function! Add it to if_free_type(). */ 381456d182dSSam Leffler if_free_type(ifp, ifp->if_type); 382fc74a9f9SBrooks Davis } 383fc74a9f9SBrooks Davis 384fc74a9f9SBrooks Davis void 385fc74a9f9SBrooks Davis if_free_type(struct ifnet *ifp, u_char type) 386fc74a9f9SBrooks Davis { 387fc74a9f9SBrooks Davis 388fc74a9f9SBrooks Davis if (ifp != ifnet_byindex(ifp->if_index)) { 389fc74a9f9SBrooks Davis if_printf(ifp, "%s: value was not if_alloced, skipping\n", 390fc74a9f9SBrooks Davis __func__); 391fc74a9f9SBrooks Davis return; 392fc74a9f9SBrooks Davis } 393fc74a9f9SBrooks Davis 3947cf30146SBrooks Davis IF_ADDR_LOCK_DESTROY(ifp); 3957cf30146SBrooks Davis 39628ef2db4SBrooks Davis ifnet_byindex(ifp->if_index) = NULL; 39728ef2db4SBrooks Davis 39828ef2db4SBrooks Davis /* XXX: should be locked with if_findindex() */ 399dc7c539eSBrooks Davis while (if_index > 0 && ifnet_byindex(if_index) == NULL) 40028ef2db4SBrooks Davis if_index--; 40128ef2db4SBrooks Davis 402fc74a9f9SBrooks Davis if (if_com_free[type] != NULL) 403fc74a9f9SBrooks Davis if_com_free[type](ifp->if_l2com, type); 404fc74a9f9SBrooks Davis 405fc74a9f9SBrooks Davis free(ifp, M_IFNET); 406fc74a9f9SBrooks Davis }; 407fc74a9f9SBrooks Davis 408fc74a9f9SBrooks Davis /* 409df8bae1dSRodney W. Grimes * Attach an interface to the 410df8bae1dSRodney W. Grimes * list of "active" interfaces. 411df8bae1dSRodney W. Grimes */ 412df8bae1dSRodney W. Grimes void 41372fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp) 414df8bae1dSRodney W. Grimes { 415df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 4161ce9bf88SPoul-Henning Kamp int namelen, masklen; 41772fd1b6aSDag-Erling Smørgrav struct sockaddr_dl *sdl; 41872fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 419df8bae1dSRodney W. Grimes 420fc74a9f9SBrooks Davis if (ifp->if_index == 0 || ifp != ifnet_byindex(ifp->if_index)) 421fc74a9f9SBrooks Davis panic ("%s: BUG: if_attach called without if_alloc'd input()\n", 422fc74a9f9SBrooks Davis ifp->if_xname); 423fc74a9f9SBrooks Davis 424af5e59bfSRobert Watson TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp); 42568a3482fSGleb Smirnoff TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); 426234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK_INIT(ifp); 427234a35c7SHajimu UMEMOTO ifp->if_afdata_initialized = 0; 428b30a244cSJeffrey Hsu IFNET_WLOCK(); 42929412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 430b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 43159562606SGarrett Wollman /* 43259562606SGarrett Wollman * XXX - 43359562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 43459562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 43559562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 43659562606SGarrett Wollman * this unlikely case. 43759562606SGarrett Wollman */ 43859562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 43982cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 4406817526dSPoul-Henning Kamp TAILQ_INIT(&ifp->if_multiaddrs); 441571dcd15SSuleiman Souhlal knlist_init(&ifp->if_klist, NULL, NULL, NULL, NULL); 44298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 443bc9d2991SBrooks Davis ifp->if_data.ifi_epoch = time_uptime; 444fc74a9f9SBrooks Davis ifp->if_data.ifi_datalen = sizeof(struct if_data); 445e70cd263SRobert Watson 446e70cd263SRobert Watson #ifdef MAC 447e70cd263SRobert Watson mac_init_ifnet(ifp); 448e70cd263SRobert Watson mac_create_ifnet(ifp); 449e70cd263SRobert Watson #endif 450e70cd263SRobert Watson 45112b8b80eSRuslan Ermilov ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw, 45212b8b80eSRuslan Ermilov unit2minor(ifp->if_index), 4539bf40edeSBrooks Davis UID_ROOT, GID_WHEEL, 0600, "%s/%s", 4549bf40edeSBrooks Davis net_cdevsw.d_name, ifp->if_xname); 455ffb5a104SJonathan Lemon make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", 456ffb5a104SJonathan Lemon net_cdevsw.d_name, ifp->if_index); 457f13ad206SJonathan Lemon 4589bf40edeSBrooks Davis mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF); 459df5e1987SJonathan Lemon 460df8bae1dSRodney W. Grimes /* 461df8bae1dSRodney W. Grimes * create a Link Level name for this device 462df8bae1dSRodney W. Grimes */ 4639bf40edeSBrooks Davis namelen = strlen(ifp->if_xname); 46436c19a57SBrooks Davis /* 46536c19a57SBrooks Davis * Always save enough space for any possiable name so we can do 46636c19a57SBrooks Davis * a rename in place later. 46736c19a57SBrooks Davis */ 46836c19a57SBrooks Davis masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; 469df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 470df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 471df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 472ccb82468SBrooks Davis socksize = roundup2(socksize, sizeof(long)); 473df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 474a8773564SBrooks Davis ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 47519fc74fbSJeffrey Hsu IFA_LOCK_INIT(ifa); 476df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 477df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 478df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 4799bf40edeSBrooks Davis bcopy(ifp->if_xname, sdl->sdl_data, namelen); 4801ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 481df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 482df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 483ffb5a104SJonathan Lemon ifaddr_byindex(ifp->if_index) = ifa; 484df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 485df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 486df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 487df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 488df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 489df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 490df8bae1dSRodney W. Grimes while (namelen != 0) 491df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 49219fc74fbSJeffrey Hsu ifa->ifa_refcnt = 1; 49359562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 4946237419dSRobert Watson ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */ 49502b199f1SMax Laier ifp->if_snd.altq_type = 0; 49602b199f1SMax Laier ifp->if_snd.altq_disc = NULL; 49702b199f1SMax Laier ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE; 49802b199f1SMax Laier ifp->if_snd.altq_tbr = NULL; 49902b199f1SMax Laier ifp->if_snd.altq_ifp = ifp; 5007b6edd04SRuslan Ermilov 50169fb23b7SMax Laier if (domain_init_status >= 2) 50231b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 50331b1bfe1SHajimu UMEMOTO 50425a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 50525a4adceSMax Laier 5067b6edd04SRuslan Ermilov /* Announce the interface. */ 5077b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 508df8bae1dSRodney W. Grimes } 5096182fdbdSPeter Wemm 51031b1bfe1SHajimu UMEMOTO static void 51172fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy) 51231b1bfe1SHajimu UMEMOTO { 51331b1bfe1SHajimu UMEMOTO struct ifnet *ifp; 51431b1bfe1SHajimu UMEMOTO int s; 51531b1bfe1SHajimu UMEMOTO 51631b1bfe1SHajimu UMEMOTO s = splnet(); 5179046571fSLuigi Rizzo TAILQ_FOREACH(ifp, &ifnet, if_link) 51831b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 51931b1bfe1SHajimu UMEMOTO splx(s); 52031b1bfe1SHajimu UMEMOTO } 52169fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND, 52231b1bfe1SHajimu UMEMOTO if_attachdomain, NULL); 52331b1bfe1SHajimu UMEMOTO 52431b1bfe1SHajimu UMEMOTO static void 52572fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp) 52631b1bfe1SHajimu UMEMOTO { 52731b1bfe1SHajimu UMEMOTO struct domain *dp; 52831b1bfe1SHajimu UMEMOTO int s; 52931b1bfe1SHajimu UMEMOTO 53031b1bfe1SHajimu UMEMOTO s = splnet(); 53131b1bfe1SHajimu UMEMOTO 532234a35c7SHajimu UMEMOTO /* 533234a35c7SHajimu UMEMOTO * Since dp->dom_ifattach calls malloc() with M_WAITOK, we 534234a35c7SHajimu UMEMOTO * cannot lock ifp->if_afdata initialization, entirely. 535234a35c7SHajimu UMEMOTO */ 536234a35c7SHajimu UMEMOTO if (IF_AFDATA_TRYLOCK(ifp) == 0) { 537234a35c7SHajimu UMEMOTO splx(s); 538234a35c7SHajimu UMEMOTO return; 539234a35c7SHajimu UMEMOTO } 54069fb23b7SMax Laier if (ifp->if_afdata_initialized >= domain_init_status) { 541234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 542234a35c7SHajimu UMEMOTO splx(s); 5436237419dSRobert Watson printf("if_attachdomain called more than once on %s\n", 5446237419dSRobert Watson ifp->if_xname); 545234a35c7SHajimu UMEMOTO return; 546234a35c7SHajimu UMEMOTO } 54769fb23b7SMax Laier ifp->if_afdata_initialized = domain_init_status; 548234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 549234a35c7SHajimu UMEMOTO 55031b1bfe1SHajimu UMEMOTO /* address family dependent data region */ 55131b1bfe1SHajimu UMEMOTO bzero(ifp->if_afdata, sizeof(ifp->if_afdata)); 55231b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 55331b1bfe1SHajimu UMEMOTO if (dp->dom_ifattach) 55431b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family] = 55531b1bfe1SHajimu UMEMOTO (*dp->dom_ifattach)(ifp); 55631b1bfe1SHajimu UMEMOTO } 55731b1bfe1SHajimu UMEMOTO 55831b1bfe1SHajimu UMEMOTO splx(s); 55931b1bfe1SHajimu UMEMOTO } 56031b1bfe1SHajimu UMEMOTO 5616182fdbdSPeter Wemm /* 56245778b37SPeter Edwards * Remove any network addresses from an interface. 56345778b37SPeter Edwards */ 56445778b37SPeter Edwards 56545778b37SPeter Edwards void 56645778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp) 56745778b37SPeter Edwards { 56845778b37SPeter Edwards struct ifaddr *ifa, *next; 56945778b37SPeter Edwards 57045778b37SPeter Edwards TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { 57145778b37SPeter Edwards 57245778b37SPeter Edwards if (ifa->ifa_addr->sa_family == AF_LINK) 57345778b37SPeter Edwards continue; 57445778b37SPeter Edwards #ifdef INET 57545778b37SPeter Edwards /* XXX: Ugly!! ad hoc just for INET */ 57645778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 57745778b37SPeter Edwards struct ifaliasreq ifr; 57845778b37SPeter Edwards 57945778b37SPeter Edwards bzero(&ifr, sizeof(ifr)); 58045778b37SPeter Edwards ifr.ifra_addr = *ifa->ifa_addr; 58145778b37SPeter Edwards if (ifa->ifa_dstaddr) 58245778b37SPeter Edwards ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 58345778b37SPeter Edwards if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 58445778b37SPeter Edwards NULL) == 0) 58545778b37SPeter Edwards continue; 58645778b37SPeter Edwards } 58745778b37SPeter Edwards #endif /* INET */ 58845778b37SPeter Edwards #ifdef INET6 58945778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 59045778b37SPeter Edwards in6_purgeaddr(ifa); 59145778b37SPeter Edwards /* ifp_addrhead is already updated */ 59245778b37SPeter Edwards continue; 59345778b37SPeter Edwards } 59445778b37SPeter Edwards #endif /* INET6 */ 59545778b37SPeter Edwards TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 59645778b37SPeter Edwards IFAFREE(ifa); 59745778b37SPeter Edwards } 59845778b37SPeter Edwards } 59945778b37SPeter Edwards 60045778b37SPeter Edwards /* 6016182fdbdSPeter Wemm * Detach an interface, removing it from the 602fc74a9f9SBrooks Davis * list of "active" interfaces and freeing the struct ifnet. 6036182fdbdSPeter Wemm */ 6046182fdbdSPeter Wemm void 60572fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp) 6066182fdbdSPeter Wemm { 60745778b37SPeter Edwards struct ifaddr *ifa; 6085500d3beSWarner Losh struct radix_node_head *rnh; 6095500d3beSWarner Losh int s; 6105500d3beSWarner Losh int i; 61131b1bfe1SHajimu UMEMOTO struct domain *dp; 6123f35d515SPeter Pentchev struct ifnet *iter; 6133f35d515SPeter Pentchev int found; 6146182fdbdSPeter Wemm 61568a3482fSGleb Smirnoff /* 61668a3482fSGleb Smirnoff * Remove/wait for pending events. 61768a3482fSGleb Smirnoff */ 61868a3482fSGleb Smirnoff taskqueue_drain(taskqueue_swi, &ifp->if_linktask); 61968a3482fSGleb Smirnoff 620a9771948SGleb Smirnoff #ifdef DEV_CARP 621a9771948SGleb Smirnoff /* Maybe hook to the generalized departure handler above?!? */ 622a9771948SGleb Smirnoff if (ifp->if_carp) 623a9771948SGleb Smirnoff carp_ifdetach(ifp); 624a9771948SGleb Smirnoff #endif 625a9771948SGleb Smirnoff 6266182fdbdSPeter Wemm /* 6276182fdbdSPeter Wemm * Remove routes and flush queues. 6286182fdbdSPeter Wemm */ 6295500d3beSWarner Losh s = splnet(); 6306182fdbdSPeter Wemm if_down(ifp); 63102b199f1SMax Laier #ifdef ALTQ 63202b199f1SMax Laier if (ALTQ_IS_ENABLED(&ifp->if_snd)) 63302b199f1SMax Laier altq_disable(&ifp->if_snd); 63402b199f1SMax Laier if (ALTQ_IS_ATTACHED(&ifp->if_snd)) 63502b199f1SMax Laier altq_detach(&ifp->if_snd); 63602b199f1SMax Laier #endif 6376182fdbdSPeter Wemm 63845778b37SPeter Edwards if_purgeaddrs(ifp); 6396182fdbdSPeter Wemm 64033841545SHajimu UMEMOTO #ifdef INET6 64133841545SHajimu UMEMOTO /* 64233841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 64333841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 64433841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 64533841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 64633841545SHajimu UMEMOTO */ 64733841545SHajimu UMEMOTO in6_ifdetach(ifp); 64833841545SHajimu UMEMOTO #endif 649f4247b59SLuigi Rizzo /* 650f4247b59SLuigi Rizzo * Remove address from ifindex_table[] and maybe decrement if_index. 651f4247b59SLuigi Rizzo * Clean up all addresses. 652f4247b59SLuigi Rizzo */ 653f4247b59SLuigi Rizzo ifaddr_byindex(ifp->if_index) = NULL; 654f4247b59SLuigi Rizzo destroy_dev(ifdev_byindex(ifp->if_index)); 655f4247b59SLuigi Rizzo ifdev_byindex(ifp->if_index) = NULL; 656f4247b59SLuigi Rizzo 657212bd869SHajimu UMEMOTO /* We can now free link ifaddr. */ 6583f35d515SPeter Pentchev if (!TAILQ_EMPTY(&ifp->if_addrhead)) { 659212bd869SHajimu UMEMOTO ifa = TAILQ_FIRST(&ifp->if_addrhead); 660212bd869SHajimu UMEMOTO TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 661212bd869SHajimu UMEMOTO IFAFREE(ifa); 6623f35d515SPeter Pentchev } 663212bd869SHajimu UMEMOTO 6645500d3beSWarner Losh /* 6655500d3beSWarner Losh * Delete all remaining routes using this interface 6665500d3beSWarner Losh * Unfortuneatly the only way to do this is to slog through 6675500d3beSWarner Losh * the entire routing table looking for routes which point 6685500d3beSWarner Losh * to this interface...oh well... 6695500d3beSWarner Losh */ 6705500d3beSWarner Losh for (i = 1; i <= AF_MAX; i++) { 6715500d3beSWarner Losh if ((rnh = rt_tables[i]) == NULL) 6725500d3beSWarner Losh continue; 673956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 6745500d3beSWarner Losh (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 675956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 6765500d3beSWarner Losh } 6775500d3beSWarner Losh 6787b6edd04SRuslan Ermilov /* Announce that the interface is gone. */ 6797b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 68052023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 6817b6edd04SRuslan Ermilov 682234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK(ifp); 68331b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 68431b1bfe1SHajimu UMEMOTO if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) 68531b1bfe1SHajimu UMEMOTO (*dp->dom_ifdetach)(ifp, 68631b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family]); 68731b1bfe1SHajimu UMEMOTO } 688234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 68931b1bfe1SHajimu UMEMOTO 690e70cd263SRobert Watson #ifdef MAC 691e70cd263SRobert Watson mac_destroy_ifnet(ifp); 692e70cd263SRobert Watson #endif /* MAC */ 693ad3b9257SJohn-Mark Gurney KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT); 694ad3b9257SJohn-Mark Gurney knlist_clear(&ifp->if_klist, 0); 695ad3b9257SJohn-Mark Gurney knlist_destroy(&ifp->if_klist); 696b30a244cSJeffrey Hsu IFNET_WLOCK(); 6973f35d515SPeter Pentchev found = 0; 6983f35d515SPeter Pentchev TAILQ_FOREACH(iter, &ifnet, if_link) 6993f35d515SPeter Pentchev if (iter == ifp) { 7003f35d515SPeter Pentchev found = 1; 7013f35d515SPeter Pentchev break; 7023f35d515SPeter Pentchev } 7033f35d515SPeter Pentchev if (found) 7046182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 705b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 706df5e1987SJonathan Lemon mtx_destroy(&ifp->if_snd.ifq_mtx); 707234a35c7SHajimu UMEMOTO IF_AFDATA_DESTROY(ifp); 7085500d3beSWarner Losh splx(s); 7095500d3beSWarner Losh } 7105500d3beSWarner Losh 7115500d3beSWarner Losh /* 7125500d3beSWarner Losh * Delete Routes for a Network Interface 7135500d3beSWarner Losh * 7145500d3beSWarner Losh * Called for each routing entry via the rnh->rnh_walktree() call above 7155500d3beSWarner Losh * to delete all route entries referencing a detaching network interface. 7165500d3beSWarner Losh * 7175500d3beSWarner Losh * Arguments: 7185500d3beSWarner Losh * rn pointer to node in the routing table 7195500d3beSWarner Losh * arg argument passed to rnh->rnh_walktree() - detaching interface 7205500d3beSWarner Losh * 7215500d3beSWarner Losh * Returns: 7225500d3beSWarner Losh * 0 successful 7235500d3beSWarner Losh * errno failed - reason indicated 7245500d3beSWarner Losh * 7255500d3beSWarner Losh */ 7265500d3beSWarner Losh static int 72772fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg) 7285500d3beSWarner Losh { 7295500d3beSWarner Losh struct rtentry *rt = (struct rtentry *)rn; 7305500d3beSWarner Losh struct ifnet *ifp = arg; 7315500d3beSWarner Losh int err; 7325500d3beSWarner Losh 7335500d3beSWarner Losh if (rt->rt_ifp == ifp) { 7345500d3beSWarner Losh 7355500d3beSWarner Losh /* 7365500d3beSWarner Losh * Protect (sorta) against walktree recursion problems 7375500d3beSWarner Losh * with cloned routes 7385500d3beSWarner Losh */ 7395500d3beSWarner Losh if ((rt->rt_flags & RTF_UP) == 0) 7405500d3beSWarner Losh return (0); 7415500d3beSWarner Losh 7425500d3beSWarner Losh err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 7435500d3beSWarner Losh rt_mask(rt), rt->rt_flags, 7445500d3beSWarner Losh (struct rtentry **) NULL); 7455500d3beSWarner Losh if (err) { 7465500d3beSWarner Losh log(LOG_WARNING, "if_rtdel: error %d\n", err); 7475500d3beSWarner Losh } 7485500d3beSWarner Losh } 7495500d3beSWarner Losh 7505500d3beSWarner Losh return (0); 7516182fdbdSPeter Wemm } 7526182fdbdSPeter Wemm 753d8d5b10eSRobert Watson #define sa_equal(a1, a2) (bcmp((a1), (a2), ((a1))->sa_len) == 0) 75419fc74fbSJeffrey Hsu 75530aad87dSBrooks Davis /* 756df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 757df8bae1dSRodney W. Grimes */ 758df8bae1dSRodney W. Grimes /*ARGSUSED*/ 759df8bae1dSRodney W. Grimes struct ifaddr * 76072fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr) 761df8bae1dSRodney W. Grimes { 7620b59d917SJonathan Lemon struct ifnet *ifp; 7630b59d917SJonathan Lemon struct ifaddr *ifa; 764df8bae1dSRodney W. Grimes 765b30a244cSJeffrey Hsu IFNET_RLOCK(); 766fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 76737d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 768df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 769df8bae1dSRodney W. Grimes continue; 770d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_addr)) 7710b59d917SJonathan Lemon goto done; 77282cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 7730b59d917SJonathan Lemon if ((ifp->if_flags & IFF_BROADCAST) && 7740b59d917SJonathan Lemon ifa->ifa_broadaddr && 77582cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 776d8d5b10eSRobert Watson sa_equal(ifa->ifa_broadaddr, addr)) 7770b59d917SJonathan Lemon goto done; 7780b59d917SJonathan Lemon } 7790b59d917SJonathan Lemon ifa = NULL; 7800b59d917SJonathan Lemon done: 781b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 782df8bae1dSRodney W. Grimes return (ifa); 783df8bae1dSRodney W. Grimes } 7840b59d917SJonathan Lemon 785df8bae1dSRodney W. Grimes /* 786df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 787df8bae1dSRodney W. Grimes */ 788df8bae1dSRodney W. Grimes /*ARGSUSED*/ 789df8bae1dSRodney W. Grimes struct ifaddr * 79072fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr) 791df8bae1dSRodney W. Grimes { 7920b59d917SJonathan Lemon struct ifnet *ifp; 7930b59d917SJonathan Lemon struct ifaddr *ifa; 794df8bae1dSRodney W. Grimes 795b30a244cSJeffrey Hsu IFNET_RLOCK(); 7960b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 7970b59d917SJonathan Lemon if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 7980b59d917SJonathan Lemon continue; 79937d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 800df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 801df8bae1dSRodney W. Grimes continue; 802d8d5b10eSRobert Watson if (ifa->ifa_dstaddr && 803d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) 8040b59d917SJonathan Lemon goto done; 805df8bae1dSRodney W. Grimes } 8060b59d917SJonathan Lemon } 8070b59d917SJonathan Lemon ifa = NULL; 8080b59d917SJonathan Lemon done: 809b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 8100b59d917SJonathan Lemon return (ifa); 811df8bae1dSRodney W. Grimes } 812df8bae1dSRodney W. Grimes 813df8bae1dSRodney W. Grimes /* 814df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 815df8bae1dSRodney W. Grimes * is most specific found. 816df8bae1dSRodney W. Grimes */ 817df8bae1dSRodney W. Grimes struct ifaddr * 81872fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr) 819df8bae1dSRodney W. Grimes { 82072fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 82172fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 822df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 823df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 824df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 825df8bae1dSRodney W. Grimes 8267e2a6151SJulian Elischer /* 8277e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 8287e2a6151SJulian Elischer * so do that if we can. 8297e2a6151SJulian Elischer */ 830df8bae1dSRodney W. Grimes if (af == AF_LINK) { 831d1dd20beSSam Leffler struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 832df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 833f9132cebSJonathan Lemon return (ifaddr_byindex(sdl->sdl_index)); 834df8bae1dSRodney W. Grimes } 8357e2a6151SJulian Elischer 8367e2a6151SJulian Elischer /* 8377e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 8387e2a6151SJulian Elischer * addresses in this address family. 8397e2a6151SJulian Elischer */ 840b30a244cSJeffrey Hsu IFNET_RLOCK(); 841fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 84237d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 84372fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 844df8bae1dSRodney W. Grimes 845523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 846df8bae1dSRodney W. Grimes next: continue; 847c61cd599SHajimu UMEMOTO if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) { 8487e2a6151SJulian Elischer /* 8497e2a6151SJulian Elischer * This is a bit broken as it doesn't 8507e2a6151SJulian Elischer * take into account that the remote end may 8517e2a6151SJulian Elischer * be a single node in the network we are 8527e2a6151SJulian Elischer * looking for. 8537e2a6151SJulian Elischer * The trouble is that we don't know the 8547e2a6151SJulian Elischer * netmask for the remote end. 8557e2a6151SJulian Elischer */ 856d8d5b10eSRobert Watson if (ifa->ifa_dstaddr != 0 && 857d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) 8580b59d917SJonathan Lemon goto done; 8593740e2adSDavid Greenman } else { 8607e2a6151SJulian Elischer /* 8617ed8f465SJulian Elischer * if we have a special address handler, 8627ed8f465SJulian Elischer * then use it instead of the generic one. 8637ed8f465SJulian Elischer */ 8647ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 8650b59d917SJonathan Lemon if ((*ifa->ifa_claim_addr)(ifa, addr)) 8660b59d917SJonathan Lemon goto done; 8677ed8f465SJulian Elischer continue; 8687ed8f465SJulian Elischer } 8697ed8f465SJulian Elischer 8707ed8f465SJulian Elischer /* 8717e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 8727e2a6151SJulian Elischer * If a bit dissagrees with what we are 8737e2a6151SJulian Elischer * looking for, mask it with the netmask 8747e2a6151SJulian Elischer * to see if it really matters. 8757e2a6151SJulian Elischer * (A byte at a time) 8767e2a6151SJulian Elischer */ 877523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 878523a02aaSDavid Greenman continue; 879df8bae1dSRodney W. Grimes cp = addr_data; 880df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 881df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 8827e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 8837e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 884df8bae1dSRodney W. Grimes while (cp3 < cplim) 885df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 8867e2a6151SJulian Elischer goto next; /* next address! */ 8877e2a6151SJulian Elischer /* 8887e2a6151SJulian Elischer * If the netmask of what we just found 8897e2a6151SJulian Elischer * is more specific than what we had before 8907e2a6151SJulian Elischer * (if we had one) then remember the new one 8917e2a6151SJulian Elischer * before continuing to search 8927e2a6151SJulian Elischer * for an even better one. 8937e2a6151SJulian Elischer */ 894df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 895df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 896df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 897df8bae1dSRodney W. Grimes ifa_maybe = ifa; 898df8bae1dSRodney W. Grimes } 899b2af64fdSDavid Greenman } 900b2af64fdSDavid Greenman } 9010b59d917SJonathan Lemon ifa = ifa_maybe; 9020b59d917SJonathan Lemon done: 903b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 9040b59d917SJonathan Lemon return (ifa); 905df8bae1dSRodney W. Grimes } 906df8bae1dSRodney W. Grimes 907df8bae1dSRodney W. Grimes /* 908df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 909df8bae1dSRodney W. Grimes * a given address. 910df8bae1dSRodney W. Grimes */ 911df8bae1dSRodney W. Grimes struct ifaddr * 91272fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) 913df8bae1dSRodney W. Grimes { 91472fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 91572fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 91672fd1b6aSDag-Erling Smørgrav char *cplim; 917df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 918df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 919df8bae1dSRodney W. Grimes 920df8bae1dSRodney W. Grimes if (af >= AF_MAX) 921df8bae1dSRodney W. Grimes return (0); 92237d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 923df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 924df8bae1dSRodney W. Grimes continue; 925381dd1d2SJulian Elischer if (ifa_maybe == 0) 926df8bae1dSRodney W. Grimes ifa_maybe = ifa; 927df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 928d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_addr) || 929d8d5b10eSRobert Watson (ifa->ifa_dstaddr && 930d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr))) 9312defe5cdSJonathan Lemon goto done; 932df8bae1dSRodney W. Grimes continue; 933df8bae1dSRodney W. Grimes } 934b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 935d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_dstaddr)) 936a8637146SJonathan Lemon goto done; 9373740e2adSDavid Greenman } else { 938df8bae1dSRodney W. Grimes cp = addr->sa_data; 939df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 940df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 941df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 942df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 943df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 944df8bae1dSRodney W. Grimes break; 945df8bae1dSRodney W. Grimes if (cp3 == cplim) 9462defe5cdSJonathan Lemon goto done; 947df8bae1dSRodney W. Grimes } 948b2af64fdSDavid Greenman } 949f9132cebSJonathan Lemon ifa = ifa_maybe; 950f9132cebSJonathan Lemon done: 951f9132cebSJonathan Lemon return (ifa); 952df8bae1dSRodney W. Grimes } 953df8bae1dSRodney W. Grimes 954df8bae1dSRodney W. Grimes #include <net/route.h> 955df8bae1dSRodney W. Grimes 956df8bae1dSRodney W. Grimes /* 957df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 958df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 959df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 960df8bae1dSRodney W. Grimes */ 9613bda9f9bSPoul-Henning Kamp static void 96272fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 963df8bae1dSRodney W. Grimes { 96472fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa, *oifa; 965df8bae1dSRodney W. Grimes struct sockaddr *dst; 966df8bae1dSRodney W. Grimes struct ifnet *ifp; 967df8bae1dSRodney W. Grimes 968d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 969d1dd20beSSam Leffler 970df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 971df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 972df8bae1dSRodney W. Grimes return; 9739448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 9749448326fSPoul-Henning Kamp if (ifa) { 97519fc74fbSJeffrey Hsu IFAREF(ifa); /* XXX */ 976d1dd20beSSam Leffler oifa = rt->rt_ifa; 977df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 978d1dd20beSSam Leffler IFAFREE(oifa); 979df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 9808071913dSRuslan Ermilov ifa->ifa_rtrequest(cmd, rt, info); 981df8bae1dSRodney W. Grimes } 982df8bae1dSRodney W. Grimes } 983df8bae1dSRodney W. Grimes 984df8bae1dSRodney W. Grimes /* 985df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 986df8bae1dSRodney W. Grimes * the transition. 987df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 988df8bae1dSRodney W. Grimes */ 9898614fb12SMax Laier static void 99072fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam) 991df8bae1dSRodney W. Grimes { 99272fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 993df8bae1dSRodney W. Grimes 994292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_unroute: flag != IFF_UP")); 995292ee7beSRobert Watson 996e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 99798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 998e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 999e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 1000df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 1001df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 1002a9771948SGleb Smirnoff #ifdef DEV_CARP 1003a9771948SGleb Smirnoff if (ifp->if_carp) 1004a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1005a9771948SGleb Smirnoff #endif 1006df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 1007df8bae1dSRodney W. Grimes } 1008df8bae1dSRodney W. Grimes 1009df8bae1dSRodney W. Grimes /* 1010df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 1011df8bae1dSRodney W. Grimes * the transition. 1012df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 1013df8bae1dSRodney W. Grimes */ 10148614fb12SMax Laier static void 101572fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam) 1016df8bae1dSRodney W. Grimes { 101772fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 1018df8bae1dSRodney W. Grimes 1019292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_route: flag != IFF_UP")); 1020292ee7beSRobert Watson 1021e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 102298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1023e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1024e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 1025df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 1026a9771948SGleb Smirnoff #ifdef DEV_CARP 1027a9771948SGleb Smirnoff if (ifp->if_carp) 1028a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1029a9771948SGleb Smirnoff #endif 1030df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 103182cd038dSYoshinobu Inoue #ifdef INET6 103282cd038dSYoshinobu Inoue in6_if_up(ifp); 103382cd038dSYoshinobu Inoue #endif 1034df8bae1dSRodney W. Grimes } 1035df8bae1dSRodney W. Grimes 103694f5c9cfSSam Leffler void (*vlan_link_state_p)(struct ifnet *, int); /* XXX: private from if_vlan */ 103794f5c9cfSSam Leffler 103894f5c9cfSSam Leffler /* 103968a3482fSGleb Smirnoff * Handle a change in the interface link state. To avoid LORs 104068a3482fSGleb Smirnoff * between driver lock and upper layer locks, as well as possible 104168a3482fSGleb Smirnoff * recursions, we post event to taskqueue, and all job 104268a3482fSGleb Smirnoff * is done in static do_link_state_change(). 104394f5c9cfSSam Leffler */ 104494f5c9cfSSam Leffler void 104594f5c9cfSSam Leffler if_link_state_change(struct ifnet *ifp, int link_state) 104694f5c9cfSSam Leffler { 10474d96314fSGleb Smirnoff /* Return if state hasn't changed. */ 10484d96314fSGleb Smirnoff if (ifp->if_link_state == link_state) 10494d96314fSGleb Smirnoff return; 10504d96314fSGleb Smirnoff 105194f5c9cfSSam Leffler ifp->if_link_state = link_state; 10524d96314fSGleb Smirnoff 105368a3482fSGleb Smirnoff taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask); 105468a3482fSGleb Smirnoff } 105568a3482fSGleb Smirnoff 105668a3482fSGleb Smirnoff static void 105768a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending) 105868a3482fSGleb Smirnoff { 105968a3482fSGleb Smirnoff struct ifnet *ifp = (struct ifnet *)arg; 106068a3482fSGleb Smirnoff int link_state = ifp->if_link_state; 106168a3482fSGleb Smirnoff int link; 106268a3482fSGleb Smirnoff 10634d96314fSGleb Smirnoff /* Notify that the link state has changed. */ 106494f5c9cfSSam Leffler rt_ifmsg(ifp); 106594f5c9cfSSam Leffler if (link_state == LINK_STATE_UP) 106694f5c9cfSSam Leffler link = NOTE_LINKUP; 106794f5c9cfSSam Leffler else if (link_state == LINK_STATE_DOWN) 106894f5c9cfSSam Leffler link = NOTE_LINKDOWN; 106994f5c9cfSSam Leffler else 107094f5c9cfSSam Leffler link = NOTE_LINKINV; 107194f5c9cfSSam Leffler KNOTE_UNLOCKED(&ifp->if_klist, link); 107294f5c9cfSSam Leffler if (ifp->if_nvlans != 0) 107394f5c9cfSSam Leffler (*vlan_link_state_p)(ifp, link); 10741c7899c7SGleb Smirnoff 10751c7899c7SGleb Smirnoff if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && 10761c7899c7SGleb Smirnoff IFP2AC(ifp)->ac_netgraph != NULL) 10771c7899c7SGleb Smirnoff (*ng_ether_link_state_p)(ifp, link_state); 10784d96314fSGleb Smirnoff #ifdef DEV_CARP 10794d96314fSGleb Smirnoff if (ifp->if_carp) 10804d96314fSGleb Smirnoff carp_carpdev_state(ifp->if_carp); 10814d96314fSGleb Smirnoff #endif 10828f867517SAndrew Thompson if (ifp->if_bridge) { 10838f867517SAndrew Thompson KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); 10848f867517SAndrew Thompson (*bstp_linkstate_p)(ifp, link_state); 10858f867517SAndrew Thompson } 10868f867517SAndrew Thompson 10879d80a330SBrooks Davis devctl_notify("IFNET", ifp->if_xname, 10889d80a330SBrooks Davis (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", NULL); 108968a3482fSGleb Smirnoff if (pending > 1) 109068a3482fSGleb Smirnoff if_printf(ifp, "%d link states coalesced\n", pending); 10915515c2e7SGleb Smirnoff if (log_link_state_change) 10928b02df24SGleb Smirnoff log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname, 10938b02df24SGleb Smirnoff (link_state == LINK_STATE_UP) ? "UP" : "DOWN" ); 109494f5c9cfSSam Leffler } 109594f5c9cfSSam Leffler 1096df8bae1dSRodney W. Grimes /* 1097e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 1098e8c2601dSPoul-Henning Kamp * the transition. 1099e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1100e8c2601dSPoul-Henning Kamp */ 1101e8c2601dSPoul-Henning Kamp void 110272fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp) 1103e8c2601dSPoul-Henning Kamp { 1104e8c2601dSPoul-Henning Kamp 1105e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 1106e8c2601dSPoul-Henning Kamp } 1107e8c2601dSPoul-Henning Kamp 1108e8c2601dSPoul-Henning Kamp /* 1109e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 1110e8c2601dSPoul-Henning Kamp * the transition. 1111e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1112e8c2601dSPoul-Henning Kamp */ 1113e8c2601dSPoul-Henning Kamp void 111472fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp) 1115e8c2601dSPoul-Henning Kamp { 1116e8c2601dSPoul-Henning Kamp 1117e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 1118e8c2601dSPoul-Henning Kamp } 1119e8c2601dSPoul-Henning Kamp 1120e8c2601dSPoul-Henning Kamp /* 1121df8bae1dSRodney W. Grimes * Flush an interface queue. 1122df8bae1dSRodney W. Grimes */ 11233bda9f9bSPoul-Henning Kamp static void 112402b199f1SMax Laier if_qflush(struct ifaltq *ifq) 1125df8bae1dSRodney W. Grimes { 112672fd1b6aSDag-Erling Smørgrav struct mbuf *m, *n; 1127df8bae1dSRodney W. Grimes 11287b21048cSMax Laier IFQ_LOCK(ifq); 112902b199f1SMax Laier #ifdef ALTQ 113002b199f1SMax Laier if (ALTQ_IS_ENABLED(ifq)) 113102b199f1SMax Laier ALTQ_PURGE(ifq); 113202b199f1SMax Laier #endif 1133df8bae1dSRodney W. Grimes n = ifq->ifq_head; 11349448326fSPoul-Henning Kamp while ((m = n) != 0) { 1135df8bae1dSRodney W. Grimes n = m->m_act; 1136df8bae1dSRodney W. Grimes m_freem(m); 1137df8bae1dSRodney W. Grimes } 1138df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 1139df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 1140df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 11417b21048cSMax Laier IFQ_UNLOCK(ifq); 1142df8bae1dSRodney W. Grimes } 1143df8bae1dSRodney W. Grimes 1144df8bae1dSRodney W. Grimes /* 1145df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 1146df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 1147df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 1148af5e59bfSRobert Watson * 1149af5e59bfSRobert Watson * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called 1150af5e59bfSRobert Watson * holding Giant. If we switch to an MPSAFE callout, we likely need to grab 1151af5e59bfSRobert Watson * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface. 1152df8bae1dSRodney W. Grimes */ 11533bda9f9bSPoul-Henning Kamp static void 115472fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg) 1155df8bae1dSRodney W. Grimes { 115672fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 1157df8bae1dSRodney W. Grimes int s = splimp(); 1158df8bae1dSRodney W. Grimes 1159b30a244cSJeffrey Hsu IFNET_RLOCK(); 1160fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 1161df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 1162df8bae1dSRodney W. Grimes continue; 1163df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 11644a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 1165df8bae1dSRodney W. Grimes } 1166b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1167df8bae1dSRodney W. Grimes splx(s); 1168df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 1169df8bae1dSRodney W. Grimes } 1170df8bae1dSRodney W. Grimes 1171df8bae1dSRodney W. Grimes /* 1172df8bae1dSRodney W. Grimes * Map interface name to 1173df8bae1dSRodney W. Grimes * interface structure pointer. 1174df8bae1dSRodney W. Grimes */ 1175df8bae1dSRodney W. Grimes struct ifnet * 117630aad87dSBrooks Davis ifunit(const char *name) 1177df8bae1dSRodney W. Grimes { 11788b7805e4SBoris Popov struct ifnet *ifp; 1179df8bae1dSRodney W. Grimes 1180b30a244cSJeffrey Hsu IFNET_RLOCK(); 1181fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 118236c19a57SBrooks Davis if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0) 1183df8bae1dSRodney W. Grimes break; 1184df8bae1dSRodney W. Grimes } 1185b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1186df8bae1dSRodney W. Grimes return (ifp); 1187df8bae1dSRodney W. Grimes } 1188df8bae1dSRodney W. Grimes 118982cd038dSYoshinobu Inoue /* 1190f13ad206SJonathan Lemon * Hardware specific interface ioctls. 1191df8bae1dSRodney W. Grimes */ 1192f13ad206SJonathan Lemon static int 1193f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) 1194df8bae1dSRodney W. Grimes { 1195f13ad206SJonathan Lemon struct ifreq *ifr; 1196413dd0baSPoul-Henning Kamp struct ifstat *ifs; 1197f13ad206SJonathan Lemon int error = 0; 1198292ee7beSRobert Watson int new_flags, temp_flags; 119936c19a57SBrooks Davis size_t namelen, onamelen; 120036c19a57SBrooks Davis char new_name[IFNAMSIZ]; 120136c19a57SBrooks Davis struct ifaddr *ifa; 120236c19a57SBrooks Davis struct sockaddr_dl *sdl; 1203df8bae1dSRodney W. Grimes 1204df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 120530aad87dSBrooks Davis switch (cmd) { 1206de593450SJonathan Lemon case SIOCGIFINDEX: 1207de593450SJonathan Lemon ifr->ifr_index = ifp->if_index; 1208de593450SJonathan Lemon break; 1209de593450SJonathan Lemon 1210df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 1211292ee7beSRobert Watson temp_flags = ifp->if_flags | ifp->if_drv_flags; 1212292ee7beSRobert Watson ifr->ifr_flags = temp_flags & 0xffff; 1213292ee7beSRobert Watson ifr->ifr_flagshigh = temp_flags >> 16; 1214df8bae1dSRodney W. Grimes break; 1215df8bae1dSRodney W. Grimes 1216016da741SJonathan Lemon case SIOCGIFCAP: 1217016da741SJonathan Lemon ifr->ifr_reqcap = ifp->if_capabilities; 1218016da741SJonathan Lemon ifr->ifr_curcap = ifp->if_capenable; 1219016da741SJonathan Lemon break; 1220016da741SJonathan Lemon 12218f293a63SRobert Watson #ifdef MAC 12228f293a63SRobert Watson case SIOCGIFMAC: 122331566c96SJohn Baldwin error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp); 12248f293a63SRobert Watson break; 12258f293a63SRobert Watson #endif 12268f293a63SRobert Watson 1227df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 1228df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 1229df8bae1dSRodney W. Grimes break; 1230df8bae1dSRodney W. Grimes 1231a7028af7SDavid Greenman case SIOCGIFMTU: 1232a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 1233a7028af7SDavid Greenman break; 1234a7028af7SDavid Greenman 1235074c4a4eSGarrett Wollman case SIOCGIFPHYS: 1236074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 1237074c4a4eSGarrett Wollman break; 1238074c4a4eSGarrett Wollman 1239df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 124044731cabSJohn Baldwin error = suser(td); 12419448326fSPoul-Henning Kamp if (error) 1242df8bae1dSRodney W. Grimes return (error); 1243292ee7beSRobert Watson /* 1244292ee7beSRobert Watson * Currently, no driver owned flags pass the IFF_CANTCHANGE 1245292ee7beSRobert Watson * check, so we don't need special handling here yet. 1246292ee7beSRobert Watson */ 124762f76486SMaxim Sobolev new_flags = (ifr->ifr_flags & 0xffff) | 124862f76486SMaxim Sobolev (ifr->ifr_flagshigh << 16); 1249cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 1250cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 12512f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 125262f76486SMaxim Sobolev (new_flags & IFF_UP) == 0) { 1253df8bae1dSRodney W. Grimes int s = splimp(); 1254df8bae1dSRodney W. Grimes if_down(ifp); 1255df8bae1dSRodney W. Grimes splx(s); 125662f76486SMaxim Sobolev } else if (new_flags & IFF_UP && 1257cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 1258df8bae1dSRodney W. Grimes int s = splimp(); 1259df8bae1dSRodney W. Grimes if_up(ifp); 1260df8bae1dSRodney W. Grimes splx(s); 1261df8bae1dSRodney W. Grimes } 1262df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 126362f76486SMaxim Sobolev (new_flags &~ IFF_CANTCHANGE); 1264ffb079beSMaxim Sobolev if (new_flags & IFF_PPROMISC) { 1265ffb079beSMaxim Sobolev /* Permanently promiscuous mode requested */ 1266ffb079beSMaxim Sobolev ifp->if_flags |= IFF_PROMISC; 1267ffb079beSMaxim Sobolev } else if (ifp->if_pcount == 0) { 1268ffb079beSMaxim Sobolev ifp->if_flags &= ~IFF_PROMISC; 1269ffb079beSMaxim Sobolev } 127031302ebfSRobert Watson if (ifp->if_ioctl) { 127131302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1272df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 127331302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 127431302ebfSRobert Watson } 127598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1276df8bae1dSRodney W. Grimes break; 1277df8bae1dSRodney W. Grimes 1278016da741SJonathan Lemon case SIOCSIFCAP: 127944731cabSJohn Baldwin error = suser(td); 1280016da741SJonathan Lemon if (error) 1281016da741SJonathan Lemon return (error); 1282efb4018bSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1283efb4018bSYaroslav Tykhiy return (EOPNOTSUPP); 1284016da741SJonathan Lemon if (ifr->ifr_reqcap & ~ifp->if_capabilities) 1285016da741SJonathan Lemon return (EINVAL); 128631302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1287efb4018bSYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, cmd, data); 128831302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1289efb4018bSYaroslav Tykhiy if (error == 0) 1290efb4018bSYaroslav Tykhiy getmicrotime(&ifp->if_lastchange); 1291016da741SJonathan Lemon break; 1292016da741SJonathan Lemon 12938f293a63SRobert Watson #ifdef MAC 12948f293a63SRobert Watson case SIOCSIFMAC: 129531566c96SJohn Baldwin error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp); 12968f293a63SRobert Watson break; 12978f293a63SRobert Watson #endif 12988f293a63SRobert Watson 129936c19a57SBrooks Davis case SIOCSIFNAME: 130036c19a57SBrooks Davis error = suser(td); 1301bc1470f1SBrooks Davis if (error != 0) 130236c19a57SBrooks Davis return (error); 130336c19a57SBrooks Davis error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL); 1304bc1470f1SBrooks Davis if (error != 0) 130536c19a57SBrooks Davis return (error); 1306bc1470f1SBrooks Davis if (new_name[0] == '\0') 1307bc1470f1SBrooks Davis return (EINVAL); 130836c19a57SBrooks Davis if (ifunit(new_name) != NULL) 130936c19a57SBrooks Davis return (EEXIST); 131036c19a57SBrooks Davis 131136c19a57SBrooks Davis /* Announce the departure of the interface. */ 131236c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 131352023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 131436c19a57SBrooks Davis 131571672bb6SBrooks Davis log(LOG_INFO, "%s: changing name to '%s'\n", 131671672bb6SBrooks Davis ifp->if_xname, new_name); 131771672bb6SBrooks Davis 131836c19a57SBrooks Davis strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); 13199b98ee2cSLuigi Rizzo ifa = ifaddr_byindex(ifp->if_index); 132036c19a57SBrooks Davis IFA_LOCK(ifa); 132136c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_addr; 132236c19a57SBrooks Davis namelen = strlen(new_name); 132336c19a57SBrooks Davis onamelen = sdl->sdl_nlen; 132436c19a57SBrooks Davis /* 132536c19a57SBrooks Davis * Move the address if needed. This is safe because we 132636c19a57SBrooks Davis * allocate space for a name of length IFNAMSIZ when we 132736c19a57SBrooks Davis * create this in if_attach(). 132836c19a57SBrooks Davis */ 132936c19a57SBrooks Davis if (namelen != onamelen) { 133036c19a57SBrooks Davis bcopy(sdl->sdl_data + onamelen, 133136c19a57SBrooks Davis sdl->sdl_data + namelen, sdl->sdl_alen); 133236c19a57SBrooks Davis } 133336c19a57SBrooks Davis bcopy(new_name, sdl->sdl_data, namelen); 133436c19a57SBrooks Davis sdl->sdl_nlen = namelen; 133536c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_netmask; 133636c19a57SBrooks Davis bzero(sdl->sdl_data, onamelen); 133736c19a57SBrooks Davis while (namelen != 0) 133836c19a57SBrooks Davis sdl->sdl_data[--namelen] = 0xff; 133936c19a57SBrooks Davis IFA_UNLOCK(ifa); 134036c19a57SBrooks Davis 134125a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 134236c19a57SBrooks Davis /* Announce the return of the interface. */ 134336c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 134436c19a57SBrooks Davis break; 134536c19a57SBrooks Davis 1346df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 134744731cabSJohn Baldwin error = suser(td); 13489448326fSPoul-Henning Kamp if (error) 1349df8bae1dSRodney W. Grimes return (error); 1350df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 135198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1352df8bae1dSRodney W. Grimes break; 1353df8bae1dSRodney W. Grimes 1354074c4a4eSGarrett Wollman case SIOCSIFPHYS: 135544731cabSJohn Baldwin error = suser(td); 1356e39a0280SGary Palmer if (error) 1357913e410eSYaroslav Tykhiy return (error); 1358913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1359913e410eSYaroslav Tykhiy return (EOPNOTSUPP); 136031302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1361e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 136231302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1363e39a0280SGary Palmer if (error == 0) 136498b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1365913e410eSYaroslav Tykhiy break; 1366074c4a4eSGarrett Wollman 1367a7028af7SDavid Greenman case SIOCSIFMTU: 136882cd038dSYoshinobu Inoue { 136982cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 137082cd038dSYoshinobu Inoue 137144731cabSJohn Baldwin error = suser(td); 13729448326fSPoul-Henning Kamp if (error) 1373a7028af7SDavid Greenman return (error); 1374aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 137575ee03cbSDavid Greenman return (EINVAL); 1376f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1377f13ad206SJonathan Lemon return (EOPNOTSUPP); 137831302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1379e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 138031302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 138148f71763SRuslan Ermilov if (error == 0) { 138298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 138348f71763SRuslan Ermilov rt_ifmsg(ifp); 138448f71763SRuslan Ermilov } 138582cd038dSYoshinobu Inoue /* 138682cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 138782cd038dSYoshinobu Inoue */ 138882cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 138982cd038dSYoshinobu Inoue #ifdef INET6 139082cd038dSYoshinobu Inoue nd6_setmtu(ifp); 139182cd038dSYoshinobu Inoue #endif 139282cd038dSYoshinobu Inoue } 1393f13ad206SJonathan Lemon break; 139482cd038dSYoshinobu Inoue } 1395a7028af7SDavid Greenman 1396df8bae1dSRodney W. Grimes case SIOCADDMULTI: 1397df8bae1dSRodney W. Grimes case SIOCDELMULTI: 139844731cabSJohn Baldwin error = suser(td); 13999448326fSPoul-Henning Kamp if (error) 1400df8bae1dSRodney W. Grimes return (error); 1401477180fbSGarrett Wollman 1402477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 1403477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 1404f13ad206SJonathan Lemon return (EOPNOTSUPP); 1405477180fbSGarrett Wollman 1406477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 1407477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 1408f13ad206SJonathan Lemon return (EINVAL); 1409477180fbSGarrett Wollman 1410477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 1411477180fbSGarrett Wollman struct ifmultiaddr *ifma; 1412477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1413477180fbSGarrett Wollman } else { 1414477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 1415477180fbSGarrett Wollman } 1416e39a0280SGary Palmer if (error == 0) 141798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1418f13ad206SJonathan Lemon break; 1419df8bae1dSRodney W. Grimes 142041b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 142141b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 142241b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 142341b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 142441b3e8e5SJun-ichiro itojun Hagino #endif 142533841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 1426a912e453SPeter Wemm case SIOCSIFMEDIA: 1427d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 142844731cabSJohn Baldwin error = suser(td); 1429a912e453SPeter Wemm if (error) 1430a912e453SPeter Wemm return (error); 1431f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1432a912e453SPeter Wemm return (EOPNOTSUPP); 143331302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1434a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 143531302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1436a912e453SPeter Wemm if (error == 0) 143798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1438f13ad206SJonathan Lemon break; 1439a912e453SPeter Wemm 1440413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 1441413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 1442413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 1443413dd0baSPoul-Henning Kamp 144433841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 144533841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 144633841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 1447a912e453SPeter Wemm case SIOCGIFMEDIA: 1448d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 1449913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1450a912e453SPeter Wemm return (EOPNOTSUPP); 145131302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1452f13ad206SJonathan Lemon error = (*ifp->if_ioctl)(ifp, cmd, data); 145331302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1454f13ad206SJonathan Lemon break; 1455a912e453SPeter Wemm 1456b106252cSBill Paul case SIOCSIFLLADDR: 145744731cabSJohn Baldwin error = suser(td); 1458b106252cSBill Paul if (error) 1459b106252cSBill Paul return (error); 1460f13ad206SJonathan Lemon error = if_setlladdr(ifp, 146166ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 1462f13ad206SJonathan Lemon break; 146366ce51ceSArchie Cobbs 1464df8bae1dSRodney W. Grimes default: 1465f13ad206SJonathan Lemon error = ENOIOCTL; 1466f13ad206SJonathan Lemon break; 1467f13ad206SJonathan Lemon } 1468f13ad206SJonathan Lemon return (error); 1469f13ad206SJonathan Lemon } 1470f13ad206SJonathan Lemon 1471f13ad206SJonathan Lemon /* 1472f13ad206SJonathan Lemon * Interface ioctls. 1473f13ad206SJonathan Lemon */ 1474f13ad206SJonathan Lemon int 147572fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) 1476f13ad206SJonathan Lemon { 1477f13ad206SJonathan Lemon struct ifnet *ifp; 1478f13ad206SJonathan Lemon struct ifreq *ifr; 1479f13ad206SJonathan Lemon int error; 148062f76486SMaxim Sobolev int oif_flags; 1481f13ad206SJonathan Lemon 1482f13ad206SJonathan Lemon switch (cmd) { 1483f13ad206SJonathan Lemon case SIOCGIFCONF: 1484f13ad206SJonathan Lemon case OSIOCGIFCONF: 1485f13ad206SJonathan Lemon return (ifconf(cmd, data)); 1486f13ad206SJonathan Lemon } 1487f13ad206SJonathan Lemon ifr = (struct ifreq *)data; 1488f13ad206SJonathan Lemon 1489f13ad206SJonathan Lemon switch (cmd) { 1490f13ad206SJonathan Lemon case SIOCIFCREATE: 1491f13ad206SJonathan Lemon case SIOCIFDESTROY: 149244731cabSJohn Baldwin if ((error = suser(td)) != 0) 1493f13ad206SJonathan Lemon return (error); 1494f13ad206SJonathan Lemon return ((cmd == SIOCIFCREATE) ? 1495f13ad206SJonathan Lemon if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 1496f13ad206SJonathan Lemon if_clone_destroy(ifr->ifr_name)); 1497f13ad206SJonathan Lemon 1498f13ad206SJonathan Lemon case SIOCIFGCLONERS: 1499f13ad206SJonathan Lemon return (if_clone_list((struct if_clonereq *)data)); 1500f13ad206SJonathan Lemon } 1501f13ad206SJonathan Lemon 1502f13ad206SJonathan Lemon ifp = ifunit(ifr->ifr_name); 1503f13ad206SJonathan Lemon if (ifp == 0) 1504f13ad206SJonathan Lemon return (ENXIO); 1505f13ad206SJonathan Lemon 1506f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 1507f13ad206SJonathan Lemon if (error != ENOIOCTL) 1508f13ad206SJonathan Lemon return (error); 1509f13ad206SJonathan Lemon 151082cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 1511df8bae1dSRodney W. Grimes if (so->so_proto == 0) 1512df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1513df8bae1dSRodney W. Grimes #ifndef COMPAT_43 151482cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 15152c37256eSGarrett Wollman data, 1516b40ce416SJulian Elischer ifp, td)); 1517df8bae1dSRodney W. Grimes #else 1518df8bae1dSRodney W. Grimes { 1519df8bae1dSRodney W. Grimes int ocmd = cmd; 1520df8bae1dSRodney W. Grimes 1521df8bae1dSRodney W. Grimes switch (cmd) { 1522df8bae1dSRodney W. Grimes 1523df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 1524df8bae1dSRodney W. Grimes case SIOCSIFADDR: 1525df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 1526df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 1527df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 1528df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 1529df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 1530df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1531df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1532df8bae1dSRodney W. Grimes } 1533df8bae1dSRodney W. Grimes #else 1534df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 1535df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1536df8bae1dSRodney W. Grimes #endif 1537df8bae1dSRodney W. Grimes break; 1538df8bae1dSRodney W. Grimes 1539df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1540df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 1541df8bae1dSRodney W. Grimes break; 1542df8bae1dSRodney W. Grimes 1543df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1544df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 1545df8bae1dSRodney W. Grimes break; 1546df8bae1dSRodney W. Grimes 1547df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1548df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 1549df8bae1dSRodney W. Grimes break; 1550df8bae1dSRodney W. Grimes 1551df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1552df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 1553df8bae1dSRodney W. Grimes } 15542c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 15552c37256eSGarrett Wollman cmd, 15562c37256eSGarrett Wollman data, 1557b40ce416SJulian Elischer ifp, td)); 1558df8bae1dSRodney W. Grimes switch (ocmd) { 1559df8bae1dSRodney W. Grimes 1560df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1561df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1562df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1563df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1564df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 156582cd038dSYoshinobu Inoue 156682cd038dSYoshinobu Inoue } 156782cd038dSYoshinobu Inoue } 156882cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 156982cd038dSYoshinobu Inoue 157082cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 157182cd038dSYoshinobu Inoue #ifdef INET6 157288ff5695SSUZUKI Shinsuke DELAY(100);/* XXX: temporary workaround for fxp issue*/ 157382cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 157482cd038dSYoshinobu Inoue int s = splimp(); 157582cd038dSYoshinobu Inoue in6_if_up(ifp); 157682cd038dSYoshinobu Inoue splx(s); 157782cd038dSYoshinobu Inoue } 157882cd038dSYoshinobu Inoue #endif 1579df8bae1dSRodney W. Grimes } 1580df8bae1dSRodney W. Grimes return (error); 1581df8bae1dSRodney W. Grimes } 1582df8bae1dSRodney W. Grimes 1583df8bae1dSRodney W. Grimes /* 1584292ee7beSRobert Watson * The code common to handling reference counted flags, 15851a3b6859SYaroslav Tykhiy * e.g., in ifpromisc() and if_allmulti(). 15861a3b6859SYaroslav Tykhiy * The "pflag" argument can specify a permanent mode flag, 15871a3b6859SYaroslav Tykhiy * such as IFF_PPROMISC for promiscuous mode; should be 0 if none. 1588292ee7beSRobert Watson * 1589292ee7beSRobert Watson * Only to be used on stack-owned flags, not driver-owned flags. 15901a3b6859SYaroslav Tykhiy */ 15911a3b6859SYaroslav Tykhiy static int 15921a3b6859SYaroslav Tykhiy if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch) 15931a3b6859SYaroslav Tykhiy { 15941a3b6859SYaroslav Tykhiy struct ifreq ifr; 15951a3b6859SYaroslav Tykhiy int error; 15961a3b6859SYaroslav Tykhiy int oldflags, oldcount; 15971a3b6859SYaroslav Tykhiy 1598292ee7beSRobert Watson KASSERT((flag & (IFF_DRV_OACTIVE|IFF_DRV_RUNNING)) == 0, 1599292ee7beSRobert Watson ("if_setflag: setting driver-ownded flag %d", flag)); 1600292ee7beSRobert Watson 16011a3b6859SYaroslav Tykhiy /* Sanity checks to catch programming errors */ 16021a3b6859SYaroslav Tykhiy if (onswitch) { 16031a3b6859SYaroslav Tykhiy if (*refcount < 0) { 16041a3b6859SYaroslav Tykhiy if_printf(ifp, 16051a3b6859SYaroslav Tykhiy "refusing to increment negative refcount %d " 16061a3b6859SYaroslav Tykhiy "for interface flag %d\n", *refcount, flag); 16071a3b6859SYaroslav Tykhiy return (EINVAL); 16081a3b6859SYaroslav Tykhiy } 16091a3b6859SYaroslav Tykhiy } else { 16101a3b6859SYaroslav Tykhiy if (*refcount <= 0) { 16111a3b6859SYaroslav Tykhiy if_printf(ifp, 16121a3b6859SYaroslav Tykhiy "refusing to decrement non-positive refcount %d" 16131a3b6859SYaroslav Tykhiy "for interface flag %d\n", *refcount, flag); 16141a3b6859SYaroslav Tykhiy return (EINVAL); 16151a3b6859SYaroslav Tykhiy } 16161a3b6859SYaroslav Tykhiy } 16171a3b6859SYaroslav Tykhiy 16181a3b6859SYaroslav Tykhiy /* In case this mode is permanent, just touch refcount */ 16191a3b6859SYaroslav Tykhiy if (ifp->if_flags & pflag) { 16201a3b6859SYaroslav Tykhiy *refcount += onswitch ? 1 : -1; 16211a3b6859SYaroslav Tykhiy return (0); 16221a3b6859SYaroslav Tykhiy } 16231a3b6859SYaroslav Tykhiy 16241a3b6859SYaroslav Tykhiy /* Save ifnet parameters for if_ioctl() may fail */ 16251a3b6859SYaroslav Tykhiy oldcount = *refcount; 16261a3b6859SYaroslav Tykhiy oldflags = ifp->if_flags; 16271a3b6859SYaroslav Tykhiy 16281a3b6859SYaroslav Tykhiy /* 16291a3b6859SYaroslav Tykhiy * See if we aren't the only and touching refcount is enough. 16301a3b6859SYaroslav Tykhiy * Actually toggle interface flag if we are the first or last. 16311a3b6859SYaroslav Tykhiy */ 16321a3b6859SYaroslav Tykhiy if (onswitch) { 16331a3b6859SYaroslav Tykhiy if ((*refcount)++) 16341a3b6859SYaroslav Tykhiy return (0); 16351a3b6859SYaroslav Tykhiy ifp->if_flags |= flag; 16361a3b6859SYaroslav Tykhiy } else { 16371a3b6859SYaroslav Tykhiy if (--(*refcount)) 16381a3b6859SYaroslav Tykhiy return (0); 16391a3b6859SYaroslav Tykhiy ifp->if_flags &= ~flag; 16401a3b6859SYaroslav Tykhiy } 16411a3b6859SYaroslav Tykhiy 16421a3b6859SYaroslav Tykhiy /* Call down the driver since we've changed interface flags */ 16431a3b6859SYaroslav Tykhiy if (ifp->if_ioctl == NULL) { 16441a3b6859SYaroslav Tykhiy error = EOPNOTSUPP; 16451a3b6859SYaroslav Tykhiy goto recover; 16461a3b6859SYaroslav Tykhiy } 16471a3b6859SYaroslav Tykhiy ifr.ifr_flags = ifp->if_flags & 0xffff; 16481a3b6859SYaroslav Tykhiy ifr.ifr_flagshigh = ifp->if_flags >> 16; 16491a3b6859SYaroslav Tykhiy IFF_LOCKGIANT(ifp); 16501a3b6859SYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 16511a3b6859SYaroslav Tykhiy IFF_UNLOCKGIANT(ifp); 16521a3b6859SYaroslav Tykhiy if (error) 16531a3b6859SYaroslav Tykhiy goto recover; 16541a3b6859SYaroslav Tykhiy /* Notify userland that interface flags have changed */ 16551a3b6859SYaroslav Tykhiy rt_ifmsg(ifp); 16561a3b6859SYaroslav Tykhiy return (0); 16571a3b6859SYaroslav Tykhiy 16581a3b6859SYaroslav Tykhiy recover: 16591a3b6859SYaroslav Tykhiy /* Recover after driver error */ 16601a3b6859SYaroslav Tykhiy *refcount = oldcount; 16611a3b6859SYaroslav Tykhiy ifp->if_flags = oldflags; 16621a3b6859SYaroslav Tykhiy return (error); 16631a3b6859SYaroslav Tykhiy } 16641a3b6859SYaroslav Tykhiy 16651a3b6859SYaroslav Tykhiy /* 1666963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 1667963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 1668963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 1669963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 1670963e4c2aSGarrett Wollman */ 1671963e4c2aSGarrett Wollman int 167272fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch) 1673963e4c2aSGarrett Wollman { 16744a26224cSGarrett Wollman int error; 16751a3b6859SYaroslav Tykhiy int oldflags = ifp->if_flags; 1676963e4c2aSGarrett Wollman 16771a3b6859SYaroslav Tykhiy error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC, 16781a3b6859SYaroslav Tykhiy &ifp->if_pcount, pswitch); 16791a3b6859SYaroslav Tykhiy /* If promiscuous mode status has changed, log a message */ 16801a3b6859SYaroslav Tykhiy if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC)) 16819bf40edeSBrooks Davis log(LOG_INFO, "%s: promiscuous mode %s\n", 16829bf40edeSBrooks Davis ifp->if_xname, 16834f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 16841a3b6859SYaroslav Tykhiy return (error); 1685963e4c2aSGarrett Wollman } 1686963e4c2aSGarrett Wollman 1687963e4c2aSGarrett Wollman /* 1688df8bae1dSRodney W. Grimes * Return interface configuration 1689df8bae1dSRodney W. Grimes * of system. List may be used 1690df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 1691df8bae1dSRodney W. Grimes * other information. 1692df8bae1dSRodney W. Grimes */ 1693df8bae1dSRodney W. Grimes /*ARGSUSED*/ 16943bda9f9bSPoul-Henning Kamp static int 169572fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data) 1696df8bae1dSRodney W. Grimes { 16970b59d917SJonathan Lemon struct ifconf *ifc = (struct ifconf *)data; 16980b59d917SJonathan Lemon struct ifnet *ifp; 16990b59d917SJonathan Lemon struct ifaddr *ifa; 17004dcf2bbbSBrooks Davis struct ifreq ifr; 17014dcf2bbbSBrooks Davis struct sbuf *sb; 17024dcf2bbbSBrooks Davis int error, full = 0, valid_len, max_len; 1703df8bae1dSRodney W. Grimes 17044dcf2bbbSBrooks Davis /* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */ 17054dcf2bbbSBrooks Davis max_len = MAXPHYS - 1; 17064dcf2bbbSBrooks Davis 1707b0b4b28bSXin LI /* Prevent hostile input from being able to crash the system */ 1708b0b4b28bSXin LI if (ifc->ifc_len <= 0) 1709b0b4b28bSXin LI return (EINVAL); 1710b0b4b28bSXin LI 17114dcf2bbbSBrooks Davis again: 17124dcf2bbbSBrooks Davis if (ifc->ifc_len <= max_len) { 17134dcf2bbbSBrooks Davis max_len = ifc->ifc_len; 17144dcf2bbbSBrooks Davis full = 1; 17154dcf2bbbSBrooks Davis } 17164dcf2bbbSBrooks Davis sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN); 17174dcf2bbbSBrooks Davis max_len = 0; 17184dcf2bbbSBrooks Davis valid_len = 0; 17194dcf2bbbSBrooks Davis 1720b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep XXX */ 17210b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 17229bf40edeSBrooks Davis int addrs; 17232624cf89SGarrett Wollman 1724fbd24c5eSColin Percival /* 1725fbd24c5eSColin Percival * Zero the ifr_name buffer to make sure we don't 1726fbd24c5eSColin Percival * disclose the contents of the stack. 1727fbd24c5eSColin Percival */ 1728fbd24c5eSColin Percival memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name)); 1729fbd24c5eSColin Percival 17309bf40edeSBrooks Davis if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)) 173162313e4cSSam Leffler >= sizeof(ifr.ifr_name)) { 173262313e4cSSam Leffler sbuf_delete(sb); 173362313e4cSSam Leffler IFNET_RUNLOCK(); 17344dcf2bbbSBrooks Davis return (ENAMETOOLONG); 173562313e4cSSam Leffler } 17362624cf89SGarrett Wollman 173775c13541SPoul-Henning Kamp addrs = 0; 17382defe5cdSJonathan Lemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 17392defe5cdSJonathan Lemon struct sockaddr *sa = ifa->ifa_addr; 17402defe5cdSJonathan Lemon 1741a854ed98SJohn Baldwin if (jailed(curthread->td_ucred) && 1742a854ed98SJohn Baldwin prison_if(curthread->td_ucred, sa)) 174375c13541SPoul-Henning Kamp continue; 174475c13541SPoul-Henning Kamp addrs++; 1745df8bae1dSRodney W. Grimes #ifdef COMPAT_43 1746df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 1747df8bae1dSRodney W. Grimes struct osockaddr *osa = 1748df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 1749df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1750df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 17514dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17524dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1753df8bae1dSRodney W. Grimes } else 1754df8bae1dSRodney W. Grimes #endif 1755df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 1756df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 17574dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17584dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1759df8bae1dSRodney W. Grimes } else { 17604dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, 17614dcf2bbbSBrooks Davis offsetof(struct ifreq, ifr_addr)); 17624dcf2bbbSBrooks Davis max_len += offsetof(struct ifreq, ifr_addr); 17634dcf2bbbSBrooks Davis sbuf_bcat(sb, sa, sa->sa_len); 17644dcf2bbbSBrooks Davis max_len += sa->sa_len; 1765df8bae1dSRodney W. Grimes } 17664dcf2bbbSBrooks Davis 17674dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 17684dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 1769df8bae1dSRodney W. Grimes } 17704dcf2bbbSBrooks Davis if (addrs == 0) { 177175c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 17724dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17734dcf2bbbSBrooks Davis max_len += sizeof(ifr); 17744dcf2bbbSBrooks Davis 17754dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 17764dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 177775c13541SPoul-Henning Kamp } 1778df8bae1dSRodney W. Grimes } 1779b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 17804dcf2bbbSBrooks Davis 17814dcf2bbbSBrooks Davis /* 17824dcf2bbbSBrooks Davis * If we didn't allocate enough space (uncommon), try again. If 17834dcf2bbbSBrooks Davis * we have already allocated as much space as we are allowed, 17844dcf2bbbSBrooks Davis * return what we've got. 17854dcf2bbbSBrooks Davis */ 17864dcf2bbbSBrooks Davis if (valid_len != max_len && !full) { 17874dcf2bbbSBrooks Davis sbuf_delete(sb); 17884dcf2bbbSBrooks Davis goto again; 17894dcf2bbbSBrooks Davis } 17904dcf2bbbSBrooks Davis 17914dcf2bbbSBrooks Davis ifc->ifc_len = valid_len; 17925ed8cedcSBrian Feldman sbuf_finish(sb); 17934dcf2bbbSBrooks Davis error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len); 17944dcf2bbbSBrooks Davis sbuf_delete(sb); 1795df8bae1dSRodney W. Grimes return (error); 1796df8bae1dSRodney W. Grimes } 1797df8bae1dSRodney W. Grimes 17981158dfb7SGarrett Wollman /* 17998b25904eSGleb Smirnoff * Just like ifpromisc(), but for all-multicast-reception mode. 18001158dfb7SGarrett Wollman */ 18011158dfb7SGarrett Wollman int 180272fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch) 18031158dfb7SGarrett Wollman { 18041158dfb7SGarrett Wollman 18051a3b6859SYaroslav Tykhiy return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch)); 18061158dfb7SGarrett Wollman } 18071158dfb7SGarrett Wollman 1808c3b31afdSRobert Watson static struct ifmultiaddr * 1809c3b31afdSRobert Watson if_findmulti(struct ifnet *ifp, struct sockaddr *sa) 18101158dfb7SGarrett Wollman { 18111158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 18121158dfb7SGarrett Wollman 1813c3b31afdSRobert Watson IF_ADDR_LOCK_ASSERT(ifp); 1814c3b31afdSRobert Watson 18156817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1816c3b31afdSRobert Watson if (sa_equal(ifma->ifma_addr, sa)) 1817c3b31afdSRobert Watson break; 18181158dfb7SGarrett Wollman } 1819c3b31afdSRobert Watson 1820c3b31afdSRobert Watson return ifma; 182157af7922SJulian Elischer } 18221158dfb7SGarrett Wollman 18231158dfb7SGarrett Wollman /* 1824c3b31afdSRobert Watson * Allocate a new ifmultiaddr and initialize based on passed arguments. We 1825c3b31afdSRobert Watson * make copies of passed sockaddrs. The ifmultiaddr will not be added to 1826c3b31afdSRobert Watson * the ifnet multicast address list here, so the caller must do that and 1827c3b31afdSRobert Watson * other setup work (such as notifying the device driver). The reference 1828c3b31afdSRobert Watson * count is initialized to 1. 18291158dfb7SGarrett Wollman */ 1830c3b31afdSRobert Watson static struct ifmultiaddr * 1831c3b31afdSRobert Watson if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa, 1832c3b31afdSRobert Watson int mflags) 1833c3b31afdSRobert Watson { 1834c3b31afdSRobert Watson struct ifmultiaddr *ifma; 1835c3b31afdSRobert Watson struct sockaddr *dupsa; 1836c3b31afdSRobert Watson 1837c3b31afdSRobert Watson MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, mflags | 1838c3b31afdSRobert Watson M_ZERO); 1839c3b31afdSRobert Watson if (ifma == NULL) 1840c3b31afdSRobert Watson return (NULL); 1841c3b31afdSRobert Watson 1842c3b31afdSRobert Watson MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, mflags); 1843c3b31afdSRobert Watson if (dupsa == NULL) { 1844c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1845c3b31afdSRobert Watson return (NULL); 18461158dfb7SGarrett Wollman } 18471158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 18481158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 1849c3b31afdSRobert Watson 18501158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 18511158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1852d4d22970SGleb Smirnoff ifma->ifma_protospec = NULL; 1853c3b31afdSRobert Watson 1854c3b31afdSRobert Watson if (llsa == NULL) { 1855c3b31afdSRobert Watson ifma->ifma_lladdr = NULL; 1856c3b31afdSRobert Watson return (ifma); 1857c3b31afdSRobert Watson } 1858c3b31afdSRobert Watson 1859c3b31afdSRobert Watson MALLOC(dupsa, struct sockaddr *, llsa->sa_len, M_IFMADDR, mflags); 1860c3b31afdSRobert Watson if (dupsa == NULL) { 1861c3b31afdSRobert Watson FREE(ifma->ifma_addr, M_IFMADDR); 1862c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1863c3b31afdSRobert Watson return (NULL); 1864c3b31afdSRobert Watson } 1865c3b31afdSRobert Watson bcopy(llsa, dupsa, llsa->sa_len); 1866c3b31afdSRobert Watson ifma->ifma_lladdr = dupsa; 1867c3b31afdSRobert Watson 1868c3b31afdSRobert Watson return (ifma); 1869c3b31afdSRobert Watson } 1870373f88edSGarrett Wollman 18711158dfb7SGarrett Wollman /* 1872c3b31afdSRobert Watson * if_freemulti: free ifmultiaddr structure and possibly attached related 1873c3b31afdSRobert Watson * addresses. The caller is responsible for implementing reference 1874c3b31afdSRobert Watson * counting, notifying the driver, handling routing messages, and releasing 1875c3b31afdSRobert Watson * any dependent link layer state. 18761158dfb7SGarrett Wollman */ 1877c3b31afdSRobert Watson static void 1878c3b31afdSRobert Watson if_freemulti(struct ifmultiaddr *ifma) 1879c3b31afdSRobert Watson { 1880c3b31afdSRobert Watson 1881c3b31afdSRobert Watson KASSERT(ifma->ifma_refcount == 1, ("if_freemulti: refcount %d", 1882c3b31afdSRobert Watson ifma->ifma_refcount)); 1883c3b31afdSRobert Watson KASSERT(ifma->ifma_protospec == NULL, 1884c3b31afdSRobert Watson ("if_freemulti: protospec not NULL")); 1885c3b31afdSRobert Watson 1886c3b31afdSRobert Watson if (ifma->ifma_lladdr != NULL) 1887c3b31afdSRobert Watson FREE(ifma->ifma_lladdr, M_IFMADDR); 1888c3b31afdSRobert Watson FREE(ifma->ifma_addr, M_IFMADDR); 1889c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1890c3b31afdSRobert Watson } 1891c3b31afdSRobert Watson 1892c3b31afdSRobert Watson /* 1893c3b31afdSRobert Watson * Register an additional multicast address with a network interface. 1894c3b31afdSRobert Watson * 1895c3b31afdSRobert Watson * - If the address is already present, bump the reference count on the 1896c3b31afdSRobert Watson * address and return. 1897c3b31afdSRobert Watson * - If the address is not link-layer, look up a link layer address. 1898c3b31afdSRobert Watson * - Allocate address structures for one or both addresses, and attach to the 1899c3b31afdSRobert Watson * multicast address list on the interface. If automatically adding a link 1900c3b31afdSRobert Watson * layer address, the protocol address will own a reference to the link 1901c3b31afdSRobert Watson * layer address, to be freed when it is freed. 1902c3b31afdSRobert Watson * - Notify the network device driver of an addition to the multicast address 1903c3b31afdSRobert Watson * list. 1904c3b31afdSRobert Watson * 1905c3b31afdSRobert Watson * 'sa' points to caller-owned memory with the desired multicast address. 1906c3b31afdSRobert Watson * 1907c3b31afdSRobert Watson * 'retifma' will be used to return a pointer to the resulting multicast 1908c3b31afdSRobert Watson * address reference, if desired. 1909c3b31afdSRobert Watson */ 1910c3b31afdSRobert Watson int 1911c3b31afdSRobert Watson if_addmulti(struct ifnet *ifp, struct sockaddr *sa, 1912c3b31afdSRobert Watson struct ifmultiaddr **retifma) 1913c3b31afdSRobert Watson { 1914c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 1915c3b31afdSRobert Watson struct sockaddr *llsa; 1916c3b31afdSRobert Watson int error; 1917c3b31afdSRobert Watson 1918c3b31afdSRobert Watson /* 1919c3b31afdSRobert Watson * If the address is already present, return a new reference to it; 1920c3b31afdSRobert Watson * otherwise, allocate storage and set up a new address. 1921c3b31afdSRobert Watson */ 1922c3b31afdSRobert Watson IF_ADDR_LOCK(ifp); 1923c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 1924c3b31afdSRobert Watson if (ifma != NULL) { 1925c3b31afdSRobert Watson ifma->ifma_refcount++; 1926c3b31afdSRobert Watson if (retifma != NULL) 1927c3b31afdSRobert Watson *retifma = ifma; 1928c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 1929c3b31afdSRobert Watson return (0); 1930c3b31afdSRobert Watson } 1931c3b31afdSRobert Watson 1932c3b31afdSRobert Watson /* 1933c3b31afdSRobert Watson * The address isn't already present; resolve the protocol address 1934c3b31afdSRobert Watson * into a link layer address, and then look that up, bump its 1935c3b31afdSRobert Watson * refcount or allocate an ifma for that also. If 'llsa' was 1936c3b31afdSRobert Watson * returned, we will need to free it later. 1937c3b31afdSRobert Watson */ 1938c3b31afdSRobert Watson llsa = NULL; 1939c3b31afdSRobert Watson ll_ifma = NULL; 1940c3b31afdSRobert Watson if (ifp->if_resolvemulti != NULL) { 1941c3b31afdSRobert Watson error = ifp->if_resolvemulti(ifp, &llsa, sa); 1942c3b31afdSRobert Watson if (error) 1943c3b31afdSRobert Watson goto unlock_out; 1944c3b31afdSRobert Watson } 1945c3b31afdSRobert Watson 1946c3b31afdSRobert Watson /* 1947c3b31afdSRobert Watson * Allocate the new address. Don't hook it up yet, as we may also 1948c3b31afdSRobert Watson * need to allocate a link layer multicast address. 1949c3b31afdSRobert Watson */ 1950c3b31afdSRobert Watson ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT); 1951c3b31afdSRobert Watson if (ifma == NULL) { 1952c3b31afdSRobert Watson error = ENOMEM; 1953c3b31afdSRobert Watson goto free_llsa_out; 1954c3b31afdSRobert Watson } 1955c3b31afdSRobert Watson 1956c3b31afdSRobert Watson /* 1957c3b31afdSRobert Watson * If a link layer address is found, we'll need to see if it's 1958c3b31afdSRobert Watson * already present in the address list, or allocate is as well. 1959c3b31afdSRobert Watson * When this block finishes, the link layer address will be on the 1960c3b31afdSRobert Watson * list. 1961c3b31afdSRobert Watson */ 1962c3b31afdSRobert Watson if (llsa != NULL) { 1963c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, llsa); 1964c3b31afdSRobert Watson if (ll_ifma == NULL) { 1965c3b31afdSRobert Watson ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT); 1966c3b31afdSRobert Watson if (ll_ifma == NULL) { 1967c3b31afdSRobert Watson if_freemulti(ifma); 1968c3b31afdSRobert Watson error = ENOMEM; 1969c3b31afdSRobert Watson goto free_llsa_out; 1970c3b31afdSRobert Watson } 1971c3b31afdSRobert Watson TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, 1972c3b31afdSRobert Watson ifma_link); 1973c3b31afdSRobert Watson } else 1974c3b31afdSRobert Watson ll_ifma->ifma_refcount++; 1975c3b31afdSRobert Watson } 1976c3b31afdSRobert Watson 1977c3b31afdSRobert Watson /* 1978c3b31afdSRobert Watson * We now have a new multicast address, ifma, and possibly a new or 1979c3b31afdSRobert Watson * referenced link layer address. Add the primary address to the 1980c3b31afdSRobert Watson * ifnet address list. 1981c3b31afdSRobert Watson */ 19826817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 1983c3b31afdSRobert Watson 198413990766SJonathan Mini if (retifma != NULL) 1985373f88edSGarrett Wollman *retifma = ifma; 19861158dfb7SGarrett Wollman 1987c3b31afdSRobert Watson /* 1988c3b31afdSRobert Watson * Must generate the message while holding the lock so that 'ifma' 1989c3b31afdSRobert Watson * pointer is still valid. 1990c3b31afdSRobert Watson * 1991c3b31afdSRobert Watson * XXXRW: How come we don't announce ll_ifma? 1992c3b31afdSRobert Watson */ 1993c3b31afdSRobert Watson rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1994c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 1995c3b31afdSRobert Watson 19961158dfb7SGarrett Wollman /* 19971158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 19981158dfb7SGarrett Wollman * interface to let them know about it. 19991158dfb7SGarrett Wollman */ 20002432c31cSRobert Watson if (ifp->if_ioctl != NULL) { 200131302ebfSRobert Watson IFF_LOCKGIANT(ifp); 20021a3b6859SYaroslav Tykhiy (void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0); 200331302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 20041a3b6859SYaroslav Tykhiy } 20051158dfb7SGarrett Wollman 2006c3b31afdSRobert Watson if (llsa != NULL) 2007c3b31afdSRobert Watson FREE(llsa, M_IFMADDR); 2008c3b31afdSRobert Watson 2009c3b31afdSRobert Watson return (0); 2010c3b31afdSRobert Watson 2011c3b31afdSRobert Watson free_llsa_out: 2012c3b31afdSRobert Watson if (llsa != NULL) 2013c3b31afdSRobert Watson FREE(llsa, M_IFMADDR); 2014c3b31afdSRobert Watson 2015c3b31afdSRobert Watson unlock_out: 2016c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2017c3b31afdSRobert Watson return (error); 20181158dfb7SGarrett Wollman } 20191158dfb7SGarrett Wollman 20201158dfb7SGarrett Wollman /* 20211158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 20221158dfb7SGarrett Wollman * if the request does not match an existing membership. 20231158dfb7SGarrett Wollman */ 20241158dfb7SGarrett Wollman int 202572fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa) 20261158dfb7SGarrett Wollman { 2027c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 20281158dfb7SGarrett Wollman 2029c3b31afdSRobert Watson IF_ADDR_LOCK(ifp); 2030c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 2031c3b31afdSRobert Watson if (ifma == NULL) { 2032c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 20331158dfb7SGarrett Wollman return ENOENT; 2034c3b31afdSRobert Watson } 20351158dfb7SGarrett Wollman 20361158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 20371158dfb7SGarrett Wollman ifma->ifma_refcount--; 2038c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 20391158dfb7SGarrett Wollman return 0; 20401158dfb7SGarrett Wollman } 20411158dfb7SGarrett Wollman 20421158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 2043c3b31afdSRobert Watson if (sa != NULL) 2044c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, sa); 2045c3b31afdSRobert Watson else 2046c3b31afdSRobert Watson ll_ifma = NULL; 2047c3b31afdSRobert Watson 2048c3b31afdSRobert Watson /* 2049c3b31afdSRobert Watson * XXXRW: How come we don't announce ll_ifma? 2050c3b31afdSRobert Watson */ 2051c3b31afdSRobert Watson rt_newmaddrmsg(RTM_DELMADDR, ifma); 2052c3b31afdSRobert Watson 20536817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 2054c3b31afdSRobert Watson if_freemulti(ifma); 2055c3b31afdSRobert Watson 2056c3b31afdSRobert Watson if (ll_ifma != NULL) { 2057c3b31afdSRobert Watson if (ll_ifma->ifma_refcount == 1) { 2058c3b31afdSRobert Watson TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifma_link); 2059c3b31afdSRobert Watson if_freemulti(ll_ifma); 2060c3b31afdSRobert Watson } else 2061c3b31afdSRobert Watson ll_ifma->ifma_refcount--; 2062c3b31afdSRobert Watson } 2063c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2064c3b31afdSRobert Watson 2065ccb7cc8dSYaroslav Tykhiy /* 2066ccb7cc8dSYaroslav Tykhiy * Make sure the interface driver is notified 2067ccb7cc8dSYaroslav Tykhiy * in the case of a link layer mcast group being left. 2068ccb7cc8dSYaroslav Tykhiy */ 2069c3b31afdSRobert Watson if (ifp->if_ioctl) { 207031302ebfSRobert Watson IFF_LOCKGIANT(ifp); 20711a3b6859SYaroslav Tykhiy (void) (*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0); 207231302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 207331302ebfSRobert Watson } 20741158dfb7SGarrett Wollman 20751158dfb7SGarrett Wollman return 0; 20761158dfb7SGarrett Wollman } 20771158dfb7SGarrett Wollman 207866ce51ceSArchie Cobbs /* 207966ce51ceSArchie Cobbs * Set the link layer address on an interface. 208066ce51ceSArchie Cobbs * 208166ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 208266ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 208366ce51ceSArchie Cobbs */ 208466ce51ceSArchie Cobbs int 208566ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 208666ce51ceSArchie Cobbs { 208766ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 208866ce51ceSArchie Cobbs struct ifaddr *ifa; 2089d637e989SPeter Wemm struct ifreq ifr; 209066ce51ceSArchie Cobbs 2091f9132cebSJonathan Lemon ifa = ifaddr_byindex(ifp->if_index); 209266ce51ceSArchie Cobbs if (ifa == NULL) 209366ce51ceSArchie Cobbs return (EINVAL); 209466ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 209566ce51ceSArchie Cobbs if (sdl == NULL) 209666ce51ceSArchie Cobbs return (EINVAL); 209766ce51ceSArchie Cobbs if (len != sdl->sdl_alen) /* don't allow length to change */ 209866ce51ceSArchie Cobbs return (EINVAL); 209966ce51ceSArchie Cobbs switch (ifp->if_type) { 210066ce51ceSArchie Cobbs case IFT_ETHER: /* these types use struct arpcom */ 210166ce51ceSArchie Cobbs case IFT_FDDI: 210266ce51ceSArchie Cobbs case IFT_XETHER: 210366ce51ceSArchie Cobbs case IFT_ISO88025: 2104b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 21058f867517SAndrew Thompson case IFT_BRIDGE: 2106fc74a9f9SBrooks Davis bcopy(lladdr, IFP2ENADDR(ifp), len); 21079046571fSLuigi Rizzo /* 21089046571fSLuigi Rizzo * XXX We also need to store the lladdr in LLADDR(sdl), 21099046571fSLuigi Rizzo * which is done below. This is a pain because we must 21109046571fSLuigi Rizzo * remember to keep the info in sync. 21119046571fSLuigi Rizzo */ 21126cdcc159SMax Khon /* FALLTHROUGH */ 21136cdcc159SMax Khon case IFT_ARCNET: 211466ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 211566ce51ceSArchie Cobbs break; 211666ce51ceSArchie Cobbs default: 211766ce51ceSArchie Cobbs return (ENODEV); 211866ce51ceSArchie Cobbs } 211966ce51ceSArchie Cobbs /* 212066ce51ceSArchie Cobbs * If the interface is already up, we need 212166ce51ceSArchie Cobbs * to re-init it in order to reprogram its 212266ce51ceSArchie Cobbs * address filter. 212366ce51ceSArchie Cobbs */ 212466ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 21251a3b6859SYaroslav Tykhiy if (ifp->if_ioctl) { 212631302ebfSRobert Watson IFF_LOCKGIANT(ifp); 212766ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 212862f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 212962f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 2130ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 213166ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 213262f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 213362f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 2134ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 213531302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 21361a3b6859SYaroslav Tykhiy } 2137b2c08f43SLuigi Rizzo #ifdef INET 2138b2c08f43SLuigi Rizzo /* 2139b2c08f43SLuigi Rizzo * Also send gratuitous ARPs to notify other nodes about 2140b2c08f43SLuigi Rizzo * the address change. 2141b2c08f43SLuigi Rizzo */ 2142b2c08f43SLuigi Rizzo TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2143b2c08f43SLuigi Rizzo if (ifa->ifa_addr != NULL && 2144b2c08f43SLuigi Rizzo ifa->ifa_addr->sa_family == AF_INET) 2145c0933269SPeter Wemm arp_ifinit(ifp, ifa); 2146b2c08f43SLuigi Rizzo } 2147b2c08f43SLuigi Rizzo #endif 214866ce51ceSArchie Cobbs } 214966ce51ceSArchie Cobbs return (0); 215066ce51ceSArchie Cobbs } 215166ce51ceSArchie Cobbs 21529bf40edeSBrooks Davis /* 21539bf40edeSBrooks Davis * The name argument must be a pointer to storage which will last as 21549bf40edeSBrooks Davis * long as the interface does. For physical devices, the result of 21559bf40edeSBrooks Davis * device_get_name(dev) is a good choice and for pseudo-devices a 21569bf40edeSBrooks Davis * static string works well. 21579bf40edeSBrooks Davis */ 21589bf40edeSBrooks Davis void 21599bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit) 21609bf40edeSBrooks Davis { 21619bf40edeSBrooks Davis ifp->if_dname = name; 21629bf40edeSBrooks Davis ifp->if_dunit = unit; 21639bf40edeSBrooks Davis if (unit != IF_DUNIT_NONE) 21649bf40edeSBrooks Davis snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit); 21659bf40edeSBrooks Davis else 21669bf40edeSBrooks Davis strlcpy(ifp->if_xname, name, IFNAMSIZ); 21679bf40edeSBrooks Davis } 21689bf40edeSBrooks Davis 2169fa882e87SBrooks Davis int 2170fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...) 2171fa882e87SBrooks Davis { 2172fa882e87SBrooks Davis va_list ap; 2173fa882e87SBrooks Davis int retval; 2174fa882e87SBrooks Davis 21759bf40edeSBrooks Davis retval = printf("%s: ", ifp->if_xname); 2176fa882e87SBrooks Davis va_start(ap, fmt); 2177fa882e87SBrooks Davis retval += vprintf(fmt, ap); 2178fa882e87SBrooks Davis va_end(ap); 2179fa882e87SBrooks Davis return (retval); 2180fa882e87SBrooks Davis } 2181fa882e87SBrooks Davis 2182af5e59bfSRobert Watson /* 2183af5e59bfSRobert Watson * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot 2184af5e59bfSRobert Watson * be called without Giant. However, we often can't acquire the Giant lock 2185af5e59bfSRobert Watson * at those points; instead, we run it via a task queue that holds Giant via 2186af5e59bfSRobert Watson * if_start_deferred. 2187af5e59bfSRobert Watson * 2188af5e59bfSRobert Watson * XXXRW: We need to make sure that the ifnet isn't fully detached until any 2189af5e59bfSRobert Watson * outstanding if_start_deferred() tasks that will run after the free. This 2190af5e59bfSRobert Watson * probably means waiting in if_detach(). 2191af5e59bfSRobert Watson */ 2192af5e59bfSRobert Watson void 2193af5e59bfSRobert Watson if_start(struct ifnet *ifp) 2194af5e59bfSRobert Watson { 2195af5e59bfSRobert Watson 2196af5e59bfSRobert Watson NET_ASSERT_GIANT(); 2197af5e59bfSRobert Watson 2198af5e59bfSRobert Watson if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) { 2199af5e59bfSRobert Watson if (mtx_owned(&Giant)) 2200af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2201af5e59bfSRobert Watson else 2202af5e59bfSRobert Watson taskqueue_enqueue(taskqueue_swi_giant, 2203af5e59bfSRobert Watson &ifp->if_starttask); 2204af5e59bfSRobert Watson } else 2205af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2206af5e59bfSRobert Watson } 2207af5e59bfSRobert Watson 2208af5e59bfSRobert Watson static void 2209af5e59bfSRobert Watson if_start_deferred(void *context, int pending) 2210af5e59bfSRobert Watson { 2211af5e59bfSRobert Watson struct ifnet *ifp; 2212af5e59bfSRobert Watson 2213af5e59bfSRobert Watson /* 2214af5e59bfSRobert Watson * This code must be entered with Giant, and should never run if 2215af5e59bfSRobert Watson * we're not running with debug.mpsafenet. 2216af5e59bfSRobert Watson */ 2217af5e59bfSRobert Watson KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet")); 2218af5e59bfSRobert Watson GIANT_REQUIRED; 2219af5e59bfSRobert Watson 2220fc74a9f9SBrooks Davis ifp = context; 2221af5e59bfSRobert Watson (ifp->if_start)(ifp); 2222af5e59bfSRobert Watson } 2223af5e59bfSRobert Watson 22240b762445SRobert Watson int 22250b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) 22260b762445SRobert Watson { 22270b762445SRobert Watson int active = 0; 22280b762445SRobert Watson 22290b762445SRobert Watson IF_LOCK(ifq); 22300b762445SRobert Watson if (_IF_QFULL(ifq)) { 22310b762445SRobert Watson _IF_DROP(ifq); 22320b762445SRobert Watson IF_UNLOCK(ifq); 22330b762445SRobert Watson m_freem(m); 22340b762445SRobert Watson return (0); 22350b762445SRobert Watson } 22360b762445SRobert Watson if (ifp != NULL) { 22370b762445SRobert Watson ifp->if_obytes += m->m_pkthdr.len + adjust; 22380b762445SRobert Watson if (m->m_flags & (M_BCAST|M_MCAST)) 22390b762445SRobert Watson ifp->if_omcasts++; 2240292ee7beSRobert Watson active = ifp->if_drv_flags & IFF_DRV_OACTIVE; 22410b762445SRobert Watson } 22420b762445SRobert Watson _IF_ENQUEUE(ifq, m); 22430b762445SRobert Watson IF_UNLOCK(ifq); 22440b762445SRobert Watson if (ifp != NULL && !active) 22450b762445SRobert Watson if_start(ifp); 22460b762445SRobert Watson return (1); 22470b762445SRobert Watson } 2248fc74a9f9SBrooks Davis 2249fc74a9f9SBrooks Davis void 2250fc74a9f9SBrooks Davis if_register_com_alloc(u_char type, 2251fc74a9f9SBrooks Davis if_com_alloc_t *a, if_com_free_t *f) 2252fc74a9f9SBrooks Davis { 2253fc74a9f9SBrooks Davis 2254fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 2255fc74a9f9SBrooks Davis ("if_register_com_alloc: %d already registered", type)); 2256fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 2257fc74a9f9SBrooks Davis ("if_register_com_alloc: %d free already registered", type)); 2258fc74a9f9SBrooks Davis 2259fc74a9f9SBrooks Davis if_com_alloc[type] = a; 2260fc74a9f9SBrooks Davis if_com_free[type] = f; 2261fc74a9f9SBrooks Davis } 2262fc74a9f9SBrooks Davis 2263fc74a9f9SBrooks Davis void 2264fc74a9f9SBrooks Davis if_deregister_com_alloc(u_char type) 2265fc74a9f9SBrooks Davis { 2266fc74a9f9SBrooks Davis 2267fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 2268fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d not registered", type)); 2269fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 2270fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d free not registered", type)); 2271fc74a9f9SBrooks Davis if_com_alloc[type] = NULL; 2272fc74a9f9SBrooks Davis if_com_free[type] = NULL; 2273fc74a9f9SBrooks Davis } 2274