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> 62f889d2efSBrooks Davis #include <net/if_clone.h> 63df8bae1dSRodney W. Grimes #include <net/if_dl.h> 6466ce51ceSArchie Cobbs #include <net/if_types.h> 6530aad87dSBrooks Davis #include <net/if_var.h> 669448326fSPoul-Henning Kamp #include <net/radix.h> 675500d3beSWarner Losh #include <net/route.h> 68df8bae1dSRodney W. Grimes 690d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6) 7082cd038dSYoshinobu Inoue /*XXX*/ 7182cd038dSYoshinobu Inoue #include <netinet/in.h> 720d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h> 733411310dSYoshinobu Inoue #ifdef INET6 74978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h> 75978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h> 763411310dSYoshinobu Inoue #endif 7782cd038dSYoshinobu Inoue #endif 78c0933269SPeter Wemm #ifdef INET 79c0933269SPeter Wemm #include <netinet/if_ether.h> 80c0933269SPeter Wemm #endif 81a9771948SGleb Smirnoff #ifdef DEV_CARP 82a9771948SGleb Smirnoff #include <netinet/ip_carp.h> 83a9771948SGleb Smirnoff #endif 8482cd038dSYoshinobu Inoue 855515c2e7SGleb Smirnoff SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 865515c2e7SGleb Smirnoff SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 875515c2e7SGleb Smirnoff 885515c2e7SGleb Smirnoff /* Log link state change events */ 895515c2e7SGleb Smirnoff static int log_link_state_change = 1; 905515c2e7SGleb Smirnoff 915515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, 925515c2e7SGleb Smirnoff &log_link_state_change, 0, 935515c2e7SGleb Smirnoff "log interface link state change events"); 945515c2e7SGleb Smirnoff 958f867517SAndrew Thompson void (*bstp_linkstate_p)(struct ifnet *ifp, int state); 961c7899c7SGleb Smirnoff void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 971c7899c7SGleb Smirnoff 984cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; 994cb655c0SMax Laier 10031b1bfe1SHajimu UMEMOTO static void if_attachdomain(void *); 10131b1bfe1SHajimu UMEMOTO static void if_attachdomain1(struct ifnet *); 1020b59d917SJonathan Lemon static int ifconf(u_long, caddr_t); 103f9132cebSJonathan Lemon static void if_grow(void); 104f9132cebSJonathan Lemon static void if_init(void *); 105f9132cebSJonathan Lemon static void if_check(void *); 10602b199f1SMax Laier static void if_qflush(struct ifaltq *); 1078614fb12SMax Laier static void if_route(struct ifnet *, int flag, int fam); 1081a3b6859SYaroslav Tykhiy static int if_setflag(struct ifnet *, int, int, int *, int); 1090b59d917SJonathan Lemon static void if_slowtimo(void *); 1108614fb12SMax Laier static void if_unroute(struct ifnet *, int flag, int fam); 1118071913dSRuslan Ermilov static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); 1120b59d917SJonathan Lemon static int if_rtdel(struct radix_node *, void *); 113f13ad206SJonathan Lemon static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *); 114af5e59bfSRobert Watson static void if_start_deferred(void *context, int pending); 11568a3482fSGleb Smirnoff static void do_link_state_change(void *, int); 11682cd038dSYoshinobu Inoue #ifdef INET6 11782cd038dSYoshinobu Inoue /* 11882cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 11982cd038dSYoshinobu Inoue * should be more generalized? 12082cd038dSYoshinobu Inoue */ 121929ddbbbSAlfred Perlstein extern void nd6_setmtu(struct ifnet *); 12282cd038dSYoshinobu Inoue #endif 12382cd038dSYoshinobu Inoue 1240b59d917SJonathan Lemon int if_index = 0; 125f9132cebSJonathan Lemon struct ifindex_entry *ifindex_table = NULL; 1260b59d917SJonathan Lemon int ifqmaxlen = IFQ_MAXLEN; 1270b59d917SJonathan Lemon struct ifnethead ifnet; /* depend on static init XXX */ 128b30a244cSJeffrey Hsu struct mtx ifnet_lock; 129fc74a9f9SBrooks Davis static if_com_alloc_t *if_com_alloc[256]; 130fc74a9f9SBrooks Davis static if_com_free_t *if_com_free[256]; 1310b59d917SJonathan Lemon 132f9132cebSJonathan Lemon static int if_indexlim = 8; 133ad3b9257SJohn-Mark Gurney static struct knlist ifklist; 134f9132cebSJonathan Lemon 1359a2a57a1SJonathan Lemon static void filt_netdetach(struct knote *kn); 1369a2a57a1SJonathan Lemon static int filt_netdev(struct knote *kn, long hint); 1379a2a57a1SJonathan Lemon 1389a2a57a1SJonathan Lemon static struct filterops netdev_filtops = 1399a2a57a1SJonathan Lemon { 1, NULL, filt_netdetach, filt_netdev }; 1409a2a57a1SJonathan Lemon 1410b59d917SJonathan Lemon /* 1420b59d917SJonathan Lemon * System initialization 1430b59d917SJonathan Lemon */ 144f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL) 145f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL) 1460b59d917SJonathan Lemon 147fc74a9f9SBrooks Davis MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals"); 1480b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 1490b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 15030aad87dSBrooks Davis 151f13ad206SJonathan Lemon static d_open_t netopen; 152f13ad206SJonathan Lemon static d_close_t netclose; 153f13ad206SJonathan Lemon static d_ioctl_t netioctl; 1549a2a57a1SJonathan Lemon static d_kqfilter_t netkqfilter; 155f13ad206SJonathan Lemon 156f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = { 157dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 158dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1597ac40f5fSPoul-Henning Kamp .d_open = netopen, 1607ac40f5fSPoul-Henning Kamp .d_close = netclose, 1617ac40f5fSPoul-Henning Kamp .d_ioctl = netioctl, 1627ac40f5fSPoul-Henning Kamp .d_name = "net", 1637ac40f5fSPoul-Henning Kamp .d_kqfilter = netkqfilter, 164f13ad206SJonathan Lemon }; 165f13ad206SJonathan Lemon 166f13ad206SJonathan Lemon static int 16789c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td) 168f13ad206SJonathan Lemon { 169f13ad206SJonathan Lemon return (0); 170f13ad206SJonathan Lemon } 171f13ad206SJonathan Lemon 172f13ad206SJonathan Lemon static int 17389c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td) 174f13ad206SJonathan Lemon { 175f13ad206SJonathan Lemon return (0); 176f13ad206SJonathan Lemon } 177f13ad206SJonathan Lemon 178f13ad206SJonathan Lemon static int 17989c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 180f13ad206SJonathan Lemon { 181f13ad206SJonathan Lemon struct ifnet *ifp; 182f13ad206SJonathan Lemon int error, idx; 183f13ad206SJonathan Lemon 184f13ad206SJonathan Lemon /* only support interface specific ioctls */ 185f13ad206SJonathan Lemon if (IOCGROUP(cmd) != 'i') 186f13ad206SJonathan Lemon return (EOPNOTSUPP); 187f13ad206SJonathan Lemon idx = minor(dev); 188f13ad206SJonathan Lemon if (idx == 0) { 189f13ad206SJonathan Lemon /* 190f13ad206SJonathan Lemon * special network device, not interface. 191f13ad206SJonathan Lemon */ 192f13ad206SJonathan Lemon if (cmd == SIOCGIFCONF) 193f13ad206SJonathan Lemon return (ifconf(cmd, data)); /* XXX remove cmd */ 194f13ad206SJonathan Lemon return (EOPNOTSUPP); 195f13ad206SJonathan Lemon } 196f13ad206SJonathan Lemon 197f13ad206SJonathan Lemon ifp = ifnet_byindex(idx); 198f13ad206SJonathan Lemon if (ifp == NULL) 199f13ad206SJonathan Lemon return (ENXIO); 200f13ad206SJonathan Lemon 201f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 202f13ad206SJonathan Lemon if (error == ENOIOCTL) 203f13ad206SJonathan Lemon error = EOPNOTSUPP; 204f13ad206SJonathan Lemon return (error); 205f13ad206SJonathan Lemon } 206f13ad206SJonathan Lemon 2079a2a57a1SJonathan Lemon static int 20889c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn) 2099a2a57a1SJonathan Lemon { 210ad3b9257SJohn-Mark Gurney struct knlist *klist; 2119a2a57a1SJonathan Lemon struct ifnet *ifp; 2129a2a57a1SJonathan Lemon int idx; 2139a2a57a1SJonathan Lemon 214ad3b9257SJohn-Mark Gurney switch (kn->kn_filter) { 215ad3b9257SJohn-Mark Gurney case EVFILT_NETDEV: 216ad3b9257SJohn-Mark Gurney kn->kn_fop = &netdev_filtops; 217ad3b9257SJohn-Mark Gurney break; 218ad3b9257SJohn-Mark Gurney default: 2190a53be46SRobert Watson return (EINVAL); 220ad3b9257SJohn-Mark Gurney } 221ad3b9257SJohn-Mark Gurney 2229a2a57a1SJonathan Lemon idx = minor(dev); 2239a2a57a1SJonathan Lemon if (idx == 0) { 2249a2a57a1SJonathan Lemon klist = &ifklist; 2259a2a57a1SJonathan Lemon } else { 2269a2a57a1SJonathan Lemon ifp = ifnet_byindex(idx); 2279a2a57a1SJonathan Lemon if (ifp == NULL) 2289a2a57a1SJonathan Lemon return (1); 2299a2a57a1SJonathan Lemon klist = &ifp->if_klist; 2309a2a57a1SJonathan Lemon } 2319a2a57a1SJonathan Lemon 2329a2a57a1SJonathan Lemon kn->kn_hook = (caddr_t)klist; 2339a2a57a1SJonathan Lemon 234ad3b9257SJohn-Mark Gurney knlist_add(klist, kn, 0); 2359a2a57a1SJonathan Lemon 2369a2a57a1SJonathan Lemon return (0); 2379a2a57a1SJonathan Lemon } 2389a2a57a1SJonathan Lemon 2399a2a57a1SJonathan Lemon static void 2409a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn) 2419a2a57a1SJonathan Lemon { 242ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2439a2a57a1SJonathan Lemon 244ad3b9257SJohn-Mark Gurney knlist_remove(klist, kn, 0); 2459a2a57a1SJonathan Lemon } 2469a2a57a1SJonathan Lemon 2479a2a57a1SJonathan Lemon static int 2489a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint) 2499a2a57a1SJonathan Lemon { 250ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2519a2a57a1SJonathan Lemon 2529a2a57a1SJonathan Lemon /* 2539a2a57a1SJonathan Lemon * Currently NOTE_EXIT is abused to indicate device detach. 2549a2a57a1SJonathan Lemon */ 2559a2a57a1SJonathan Lemon if (hint == NOTE_EXIT) { 2569a2a57a1SJonathan Lemon kn->kn_data = NOTE_LINKINV; 2579a2a57a1SJonathan Lemon kn->kn_flags |= (EV_EOF | EV_ONESHOT); 258ad3b9257SJohn-Mark Gurney knlist_remove_inevent(klist, kn); 2599a2a57a1SJonathan Lemon return (1); 2609a2a57a1SJonathan Lemon } 261ad3b9257SJohn-Mark Gurney if (hint != 0) 2629a2a57a1SJonathan Lemon kn->kn_data = hint; /* current status */ 2639a2a57a1SJonathan Lemon if (kn->kn_sfflags & hint) 2649a2a57a1SJonathan Lemon kn->kn_fflags |= hint; 2659a2a57a1SJonathan Lemon return (kn->kn_fflags != 0); 2669a2a57a1SJonathan Lemon } 2679a2a57a1SJonathan Lemon 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * Network interface utility routines. 270df8bae1dSRodney W. Grimes * 271df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 272df8bae1dSRodney W. Grimes * parameters. 273df8bae1dSRodney W. Grimes */ 2742b14f991SJulian Elischer /* ARGSUSED*/ 275f9132cebSJonathan Lemon static void 27672fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused) 277f9132cebSJonathan Lemon { 278f9132cebSJonathan Lemon 279b30a244cSJeffrey Hsu IFNET_LOCK_INIT(); 280f9132cebSJonathan Lemon TAILQ_INIT(&ifnet); 281571dcd15SSuleiman Souhlal knlist_init(&ifklist, NULL, NULL, NULL, NULL); 282f9132cebSJonathan Lemon if_grow(); /* create initial table */ 283f13ad206SJonathan Lemon ifdev_byindex(0) = make_dev(&net_cdevsw, 0, 284f13ad206SJonathan Lemon UID_ROOT, GID_WHEEL, 0600, "network"); 285f889d2efSBrooks Davis if_clone_init(); 286f9132cebSJonathan Lemon } 287f9132cebSJonathan Lemon 288f9132cebSJonathan Lemon static void 289f9132cebSJonathan Lemon if_grow(void) 290f9132cebSJonathan Lemon { 291f9132cebSJonathan Lemon u_int n; 292f9132cebSJonathan Lemon struct ifindex_entry *e; 293f9132cebSJonathan Lemon 294f9132cebSJonathan Lemon if_indexlim <<= 1; 295f9132cebSJonathan Lemon n = if_indexlim * sizeof(*e); 296fc74a9f9SBrooks Davis e = malloc(n, M_IFNET, M_WAITOK | M_ZERO); 297f9132cebSJonathan Lemon if (ifindex_table != NULL) { 298f9132cebSJonathan Lemon memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2); 299fc74a9f9SBrooks Davis free((caddr_t)ifindex_table, M_IFNET); 300f9132cebSJonathan Lemon } 301f9132cebSJonathan Lemon ifindex_table = e; 302f9132cebSJonathan Lemon } 303f9132cebSJonathan Lemon 304f9132cebSJonathan Lemon /* ARGSUSED*/ 305f9132cebSJonathan Lemon static void 30672fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused) 307df8bae1dSRodney W. Grimes { 3088ba5bdaeSPeter Wemm struct ifnet *ifp; 3098ba5bdaeSPeter Wemm int s; 310df8bae1dSRodney W. Grimes 3118ba5bdaeSPeter Wemm s = splimp(); 312b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep on rare error; mostly okay XXX */ 313fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 314e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 31513fb40dfSBrooks Davis if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n"); 316df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 317e0ea20bcSPoul-Henning Kamp } 3185e980e22SJohn Baldwin if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 31913fb40dfSBrooks Davis if_printf(ifp, 32013fb40dfSBrooks Davis "XXX: driver didn't initialize queue mtx\n"); 3216008862bSJohn Baldwin mtx_init(&ifp->if_snd.ifq_mtx, "unknown", 3226008862bSJohn Baldwin MTX_NETWORK_LOCK, MTX_DEF); 323df5e1987SJonathan Lemon } 324df5e1987SJonathan Lemon } 325b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 3268ba5bdaeSPeter Wemm splx(s); 327df8bae1dSRodney W. Grimes if_slowtimo(0); 328df8bae1dSRodney W. Grimes } 329df8bae1dSRodney W. Grimes 330df8bae1dSRodney W. Grimes /* 331fc74a9f9SBrooks Davis * Allocate a struct ifnet and in index for an interface. 332fc74a9f9SBrooks Davis */ 333fc74a9f9SBrooks Davis struct ifnet* 334fc74a9f9SBrooks Davis if_alloc(u_char type) 335fc74a9f9SBrooks Davis { 336fc74a9f9SBrooks Davis struct ifnet *ifp; 337fc74a9f9SBrooks Davis 338fc74a9f9SBrooks Davis ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO); 339fc74a9f9SBrooks Davis 340dc7c539eSBrooks Davis /* 341dc7c539eSBrooks Davis * Try to find an empty slot below if_index. If we fail, take 342dc7c539eSBrooks Davis * the next slot. 343dc7c539eSBrooks Davis * 344dc7c539eSBrooks Davis * XXX: should be locked! 345dc7c539eSBrooks Davis */ 346dc7c539eSBrooks Davis for (ifp->if_index = 1; ifp->if_index <= if_index; ifp->if_index++) { 347dc7c539eSBrooks Davis if (ifnet_byindex(ifp->if_index) == NULL) 348dc7c539eSBrooks Davis break; 349dc7c539eSBrooks Davis } 350dc7c539eSBrooks Davis /* Catch if_index overflow. */ 351dc7c539eSBrooks Davis if (ifp->if_index < 1) { 352dc7c539eSBrooks Davis free(ifp, M_IFNET); 353dc7c539eSBrooks Davis return (NULL); 354dc7c539eSBrooks Davis } 355fc74a9f9SBrooks Davis if (ifp->if_index > if_index) 356fc74a9f9SBrooks Davis if_index = ifp->if_index; 357fc74a9f9SBrooks Davis if (if_index >= if_indexlim) 358fc74a9f9SBrooks Davis if_grow(); 359fc74a9f9SBrooks Davis ifnet_byindex(ifp->if_index) = ifp; 360fc74a9f9SBrooks Davis 361fc74a9f9SBrooks Davis ifp->if_type = type; 362fc74a9f9SBrooks Davis 363fc74a9f9SBrooks Davis if (if_com_alloc[type] != NULL) { 364fc74a9f9SBrooks Davis ifp->if_l2com = if_com_alloc[type](type, ifp); 36528ef2db4SBrooks Davis if (ifp->if_l2com == NULL) { 366fc74a9f9SBrooks Davis free(ifp, M_IFNET); 36728ef2db4SBrooks Davis return (NULL); 36828ef2db4SBrooks Davis } 369fc74a9f9SBrooks Davis } 3706da3131aSJohn Baldwin IF_ADDR_LOCK_INIT(ifp); 371fc74a9f9SBrooks Davis 372fc74a9f9SBrooks Davis return (ifp); 373fc74a9f9SBrooks Davis } 374fc74a9f9SBrooks Davis 375fc74a9f9SBrooks Davis void 376fc74a9f9SBrooks Davis if_free(struct ifnet *ifp) 377fc74a9f9SBrooks Davis { 378fc74a9f9SBrooks Davis 3797cf30146SBrooks Davis /* Do not add code to this function! Add it to if_free_type(). */ 380456d182dSSam Leffler if_free_type(ifp, ifp->if_type); 381fc74a9f9SBrooks Davis } 382fc74a9f9SBrooks Davis 383fc74a9f9SBrooks Davis void 384fc74a9f9SBrooks Davis if_free_type(struct ifnet *ifp, u_char type) 385fc74a9f9SBrooks Davis { 386fc74a9f9SBrooks Davis 387fc74a9f9SBrooks Davis if (ifp != ifnet_byindex(ifp->if_index)) { 388fc74a9f9SBrooks Davis if_printf(ifp, "%s: value was not if_alloced, skipping\n", 389fc74a9f9SBrooks Davis __func__); 390fc74a9f9SBrooks Davis return; 391fc74a9f9SBrooks Davis } 392fc74a9f9SBrooks Davis 3937cf30146SBrooks Davis IF_ADDR_LOCK_DESTROY(ifp); 3947cf30146SBrooks Davis 39528ef2db4SBrooks Davis ifnet_byindex(ifp->if_index) = NULL; 39628ef2db4SBrooks Davis 39728ef2db4SBrooks Davis /* XXX: should be locked with if_findindex() */ 398dc7c539eSBrooks Davis while (if_index > 0 && ifnet_byindex(if_index) == NULL) 39928ef2db4SBrooks Davis if_index--; 40028ef2db4SBrooks Davis 401fc74a9f9SBrooks Davis if (if_com_free[type] != NULL) 402fc74a9f9SBrooks Davis if_com_free[type](ifp->if_l2com, type); 403fc74a9f9SBrooks Davis 404fc74a9f9SBrooks Davis free(ifp, M_IFNET); 405fc74a9f9SBrooks Davis }; 406fc74a9f9SBrooks Davis 407fc74a9f9SBrooks Davis /* 408df8bae1dSRodney W. Grimes * Attach an interface to the 409df8bae1dSRodney W. Grimes * list of "active" interfaces. 410df8bae1dSRodney W. Grimes */ 411df8bae1dSRodney W. Grimes void 41272fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp) 413df8bae1dSRodney W. Grimes { 414df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 4151ce9bf88SPoul-Henning Kamp int namelen, masklen; 41672fd1b6aSDag-Erling Smørgrav struct sockaddr_dl *sdl; 41772fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 418df8bae1dSRodney W. Grimes 419fc74a9f9SBrooks Davis if (ifp->if_index == 0 || ifp != ifnet_byindex(ifp->if_index)) 420fc74a9f9SBrooks Davis panic ("%s: BUG: if_attach called without if_alloc'd input()\n", 421fc74a9f9SBrooks Davis ifp->if_xname); 422fc74a9f9SBrooks Davis 423af5e59bfSRobert Watson TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp); 42468a3482fSGleb Smirnoff TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); 425234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK_INIT(ifp); 426234a35c7SHajimu UMEMOTO ifp->if_afdata_initialized = 0; 427b30a244cSJeffrey Hsu IFNET_WLOCK(); 42829412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 429b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 43059562606SGarrett Wollman /* 43159562606SGarrett Wollman * XXX - 43259562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 43359562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 43459562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 43559562606SGarrett Wollman * this unlikely case. 43659562606SGarrett Wollman */ 43759562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 43882cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 4396817526dSPoul-Henning Kamp TAILQ_INIT(&ifp->if_multiaddrs); 440571dcd15SSuleiman Souhlal knlist_init(&ifp->if_klist, NULL, NULL, NULL, NULL); 44198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 442bc9d2991SBrooks Davis ifp->if_data.ifi_epoch = time_uptime; 443fc74a9f9SBrooks Davis ifp->if_data.ifi_datalen = sizeof(struct if_data); 444e70cd263SRobert Watson 445e70cd263SRobert Watson #ifdef MAC 446e70cd263SRobert Watson mac_init_ifnet(ifp); 447e70cd263SRobert Watson mac_create_ifnet(ifp); 448e70cd263SRobert Watson #endif 449e70cd263SRobert Watson 45012b8b80eSRuslan Ermilov ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw, 45112b8b80eSRuslan Ermilov unit2minor(ifp->if_index), 4529bf40edeSBrooks Davis UID_ROOT, GID_WHEEL, 0600, "%s/%s", 4539bf40edeSBrooks Davis net_cdevsw.d_name, ifp->if_xname); 454ffb5a104SJonathan Lemon make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", 455ffb5a104SJonathan Lemon net_cdevsw.d_name, ifp->if_index); 456f13ad206SJonathan Lemon 4579bf40edeSBrooks Davis mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF); 458df5e1987SJonathan Lemon 459df8bae1dSRodney W. Grimes /* 460df8bae1dSRodney W. Grimes * create a Link Level name for this device 461df8bae1dSRodney W. Grimes */ 4629bf40edeSBrooks Davis namelen = strlen(ifp->if_xname); 46336c19a57SBrooks Davis /* 46436c19a57SBrooks Davis * Always save enough space for any possiable name so we can do 46536c19a57SBrooks Davis * a rename in place later. 46636c19a57SBrooks Davis */ 46736c19a57SBrooks Davis masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; 468df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 469df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 470df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 471ccb82468SBrooks Davis socksize = roundup2(socksize, sizeof(long)); 472df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 473a8773564SBrooks Davis ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 47419fc74fbSJeffrey Hsu IFA_LOCK_INIT(ifa); 475df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 476df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 477df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 4789bf40edeSBrooks Davis bcopy(ifp->if_xname, sdl->sdl_data, namelen); 4791ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 480df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 481df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 4824a0d6638SRuslan Ermilov ifp->if_addr = ifa; 483df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 484df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 485df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 486df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 487df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 488df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 489df8bae1dSRodney W. Grimes while (namelen != 0) 490df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 49119fc74fbSJeffrey Hsu ifa->ifa_refcnt = 1; 49259562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 4936237419dSRobert Watson ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */ 49402b199f1SMax Laier ifp->if_snd.altq_type = 0; 49502b199f1SMax Laier ifp->if_snd.altq_disc = NULL; 49602b199f1SMax Laier ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE; 49702b199f1SMax Laier ifp->if_snd.altq_tbr = NULL; 49802b199f1SMax Laier ifp->if_snd.altq_ifp = ifp; 4997b6edd04SRuslan Ermilov 50069fb23b7SMax Laier if (domain_init_status >= 2) 50131b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 50231b1bfe1SHajimu UMEMOTO 50325a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 50425a4adceSMax Laier 5057b6edd04SRuslan Ermilov /* Announce the interface. */ 5067b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 507df8bae1dSRodney W. Grimes } 5086182fdbdSPeter Wemm 50931b1bfe1SHajimu UMEMOTO static void 51072fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy) 51131b1bfe1SHajimu UMEMOTO { 51231b1bfe1SHajimu UMEMOTO struct ifnet *ifp; 51331b1bfe1SHajimu UMEMOTO int s; 51431b1bfe1SHajimu UMEMOTO 51531b1bfe1SHajimu UMEMOTO s = splnet(); 5169046571fSLuigi Rizzo TAILQ_FOREACH(ifp, &ifnet, if_link) 51731b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 51831b1bfe1SHajimu UMEMOTO splx(s); 51931b1bfe1SHajimu UMEMOTO } 52069fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND, 52131b1bfe1SHajimu UMEMOTO if_attachdomain, NULL); 52231b1bfe1SHajimu UMEMOTO 52331b1bfe1SHajimu UMEMOTO static void 52472fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp) 52531b1bfe1SHajimu UMEMOTO { 52631b1bfe1SHajimu UMEMOTO struct domain *dp; 52731b1bfe1SHajimu UMEMOTO int s; 52831b1bfe1SHajimu UMEMOTO 52931b1bfe1SHajimu UMEMOTO s = splnet(); 53031b1bfe1SHajimu UMEMOTO 531234a35c7SHajimu UMEMOTO /* 532234a35c7SHajimu UMEMOTO * Since dp->dom_ifattach calls malloc() with M_WAITOK, we 533234a35c7SHajimu UMEMOTO * cannot lock ifp->if_afdata initialization, entirely. 534234a35c7SHajimu UMEMOTO */ 535234a35c7SHajimu UMEMOTO if (IF_AFDATA_TRYLOCK(ifp) == 0) { 536234a35c7SHajimu UMEMOTO splx(s); 537234a35c7SHajimu UMEMOTO return; 538234a35c7SHajimu UMEMOTO } 53969fb23b7SMax Laier if (ifp->if_afdata_initialized >= domain_init_status) { 540234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 541234a35c7SHajimu UMEMOTO splx(s); 5426237419dSRobert Watson printf("if_attachdomain called more than once on %s\n", 5436237419dSRobert Watson ifp->if_xname); 544234a35c7SHajimu UMEMOTO return; 545234a35c7SHajimu UMEMOTO } 54669fb23b7SMax Laier ifp->if_afdata_initialized = domain_init_status; 547234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 548234a35c7SHajimu UMEMOTO 54931b1bfe1SHajimu UMEMOTO /* address family dependent data region */ 55031b1bfe1SHajimu UMEMOTO bzero(ifp->if_afdata, sizeof(ifp->if_afdata)); 55131b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 55231b1bfe1SHajimu UMEMOTO if (dp->dom_ifattach) 55331b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family] = 55431b1bfe1SHajimu UMEMOTO (*dp->dom_ifattach)(ifp); 55531b1bfe1SHajimu UMEMOTO } 55631b1bfe1SHajimu UMEMOTO 55731b1bfe1SHajimu UMEMOTO splx(s); 55831b1bfe1SHajimu UMEMOTO } 55931b1bfe1SHajimu UMEMOTO 5606182fdbdSPeter Wemm /* 56145778b37SPeter Edwards * Remove any network addresses from an interface. 56245778b37SPeter Edwards */ 56345778b37SPeter Edwards 56445778b37SPeter Edwards void 56545778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp) 56645778b37SPeter Edwards { 56745778b37SPeter Edwards struct ifaddr *ifa, *next; 56845778b37SPeter Edwards 56945778b37SPeter Edwards TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { 57045778b37SPeter Edwards 57183ec464fSYaroslav Tykhiy if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK) 57245778b37SPeter Edwards continue; 57345778b37SPeter Edwards #ifdef INET 57445778b37SPeter Edwards /* XXX: Ugly!! ad hoc just for INET */ 57545778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 57645778b37SPeter Edwards struct ifaliasreq ifr; 57745778b37SPeter Edwards 57845778b37SPeter Edwards bzero(&ifr, sizeof(ifr)); 57945778b37SPeter Edwards ifr.ifra_addr = *ifa->ifa_addr; 58045778b37SPeter Edwards if (ifa->ifa_dstaddr) 58145778b37SPeter Edwards ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 58245778b37SPeter Edwards if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 58345778b37SPeter Edwards NULL) == 0) 58445778b37SPeter Edwards continue; 58545778b37SPeter Edwards } 58645778b37SPeter Edwards #endif /* INET */ 58745778b37SPeter Edwards #ifdef INET6 58845778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 58945778b37SPeter Edwards in6_purgeaddr(ifa); 59045778b37SPeter Edwards /* ifp_addrhead is already updated */ 59145778b37SPeter Edwards continue; 59245778b37SPeter Edwards } 59345778b37SPeter Edwards #endif /* INET6 */ 59445778b37SPeter Edwards TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 59545778b37SPeter Edwards IFAFREE(ifa); 59645778b37SPeter Edwards } 59745778b37SPeter Edwards } 59845778b37SPeter Edwards 59945778b37SPeter Edwards /* 6006182fdbdSPeter Wemm * Detach an interface, removing it from the 6014a0d6638SRuslan Ermilov * list of "active" interfaces. 602b1c53bc9SRobert Watson * 603b1c53bc9SRobert Watson * XXXRW: There are some significant questions about event ordering, and 604b1c53bc9SRobert Watson * how to prevent things from starting to use the interface during detach. 6056182fdbdSPeter Wemm */ 6066182fdbdSPeter Wemm void 60772fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp) 6086182fdbdSPeter Wemm { 60945778b37SPeter Edwards struct ifaddr *ifa; 6105500d3beSWarner Losh struct radix_node_head *rnh; 6115500d3beSWarner Losh int s; 6125500d3beSWarner Losh int i; 61331b1bfe1SHajimu UMEMOTO struct domain *dp; 6143f35d515SPeter Pentchev struct ifnet *iter; 6153f35d515SPeter Pentchev int found; 6166182fdbdSPeter Wemm 61768a3482fSGleb Smirnoff /* 61868a3482fSGleb Smirnoff * Remove/wait for pending events. 61968a3482fSGleb Smirnoff */ 62068a3482fSGleb Smirnoff taskqueue_drain(taskqueue_swi, &ifp->if_linktask); 62168a3482fSGleb Smirnoff 622a9771948SGleb Smirnoff #ifdef DEV_CARP 623a9771948SGleb Smirnoff /* Maybe hook to the generalized departure handler above?!? */ 624a9771948SGleb Smirnoff if (ifp->if_carp) 625a9771948SGleb Smirnoff carp_ifdetach(ifp); 626a9771948SGleb Smirnoff #endif 627a9771948SGleb Smirnoff 6286182fdbdSPeter Wemm /* 6296182fdbdSPeter Wemm * Remove routes and flush queues. 6306182fdbdSPeter Wemm */ 6315500d3beSWarner Losh s = splnet(); 6326182fdbdSPeter Wemm if_down(ifp); 63302b199f1SMax Laier #ifdef ALTQ 63402b199f1SMax Laier if (ALTQ_IS_ENABLED(&ifp->if_snd)) 63502b199f1SMax Laier altq_disable(&ifp->if_snd); 63602b199f1SMax Laier if (ALTQ_IS_ATTACHED(&ifp->if_snd)) 63702b199f1SMax Laier altq_detach(&ifp->if_snd); 63802b199f1SMax Laier #endif 6396182fdbdSPeter Wemm 64045778b37SPeter Edwards if_purgeaddrs(ifp); 6416182fdbdSPeter Wemm 642b1c53bc9SRobert Watson #ifdef INET 643b1c53bc9SRobert Watson in_ifdetach(ifp); 644b1c53bc9SRobert Watson #endif 645b1c53bc9SRobert Watson 64633841545SHajimu UMEMOTO #ifdef INET6 64733841545SHajimu UMEMOTO /* 64833841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 64933841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 65033841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 65133841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 65233841545SHajimu UMEMOTO */ 65333841545SHajimu UMEMOTO in6_ifdetach(ifp); 65433841545SHajimu UMEMOTO #endif 655f4247b59SLuigi Rizzo /* 6564a0d6638SRuslan Ermilov * Remove link ifaddr pointer and maybe decrement if_index. 657f4247b59SLuigi Rizzo * Clean up all addresses. 658f4247b59SLuigi Rizzo */ 6594a0d6638SRuslan Ermilov ifp->if_addr = NULL; 660f4247b59SLuigi Rizzo destroy_dev(ifdev_byindex(ifp->if_index)); 661f4247b59SLuigi Rizzo ifdev_byindex(ifp->if_index) = NULL; 662f4247b59SLuigi Rizzo 663212bd869SHajimu UMEMOTO /* We can now free link ifaddr. */ 6643f35d515SPeter Pentchev if (!TAILQ_EMPTY(&ifp->if_addrhead)) { 665212bd869SHajimu UMEMOTO ifa = TAILQ_FIRST(&ifp->if_addrhead); 666212bd869SHajimu UMEMOTO TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 667212bd869SHajimu UMEMOTO IFAFREE(ifa); 6683f35d515SPeter Pentchev } 669212bd869SHajimu UMEMOTO 6705500d3beSWarner Losh /* 6715500d3beSWarner Losh * Delete all remaining routes using this interface 6725500d3beSWarner Losh * Unfortuneatly the only way to do this is to slog through 6735500d3beSWarner Losh * the entire routing table looking for routes which point 6745500d3beSWarner Losh * to this interface...oh well... 6755500d3beSWarner Losh */ 6765500d3beSWarner Losh for (i = 1; i <= AF_MAX; i++) { 6775500d3beSWarner Losh if ((rnh = rt_tables[i]) == NULL) 6785500d3beSWarner Losh continue; 679956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 6805500d3beSWarner Losh (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 681956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 6825500d3beSWarner Losh } 6835500d3beSWarner Losh 6847b6edd04SRuslan Ermilov /* Announce that the interface is gone. */ 6857b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 68652023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 6877b6edd04SRuslan Ermilov 688234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK(ifp); 68931b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 69031b1bfe1SHajimu UMEMOTO if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) 69131b1bfe1SHajimu UMEMOTO (*dp->dom_ifdetach)(ifp, 69231b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family]); 69331b1bfe1SHajimu UMEMOTO } 694234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 69531b1bfe1SHajimu UMEMOTO 696e70cd263SRobert Watson #ifdef MAC 697e70cd263SRobert Watson mac_destroy_ifnet(ifp); 698e70cd263SRobert Watson #endif /* MAC */ 699ad3b9257SJohn-Mark Gurney KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT); 700ad3b9257SJohn-Mark Gurney knlist_clear(&ifp->if_klist, 0); 701ad3b9257SJohn-Mark Gurney knlist_destroy(&ifp->if_klist); 702b30a244cSJeffrey Hsu IFNET_WLOCK(); 7033f35d515SPeter Pentchev found = 0; 7043f35d515SPeter Pentchev TAILQ_FOREACH(iter, &ifnet, if_link) 7053f35d515SPeter Pentchev if (iter == ifp) { 7063f35d515SPeter Pentchev found = 1; 7073f35d515SPeter Pentchev break; 7083f35d515SPeter Pentchev } 7093f35d515SPeter Pentchev if (found) 7106182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 711b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 712df5e1987SJonathan Lemon mtx_destroy(&ifp->if_snd.ifq_mtx); 713234a35c7SHajimu UMEMOTO IF_AFDATA_DESTROY(ifp); 7145500d3beSWarner Losh splx(s); 7155500d3beSWarner Losh } 7165500d3beSWarner Losh 7175500d3beSWarner Losh /* 7185500d3beSWarner Losh * Delete Routes for a Network Interface 7195500d3beSWarner Losh * 7205500d3beSWarner Losh * Called for each routing entry via the rnh->rnh_walktree() call above 7215500d3beSWarner Losh * to delete all route entries referencing a detaching network interface. 7225500d3beSWarner Losh * 7235500d3beSWarner Losh * Arguments: 7245500d3beSWarner Losh * rn pointer to node in the routing table 7255500d3beSWarner Losh * arg argument passed to rnh->rnh_walktree() - detaching interface 7265500d3beSWarner Losh * 7275500d3beSWarner Losh * Returns: 7285500d3beSWarner Losh * 0 successful 7295500d3beSWarner Losh * errno failed - reason indicated 7305500d3beSWarner Losh * 7315500d3beSWarner Losh */ 7325500d3beSWarner Losh static int 73372fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg) 7345500d3beSWarner Losh { 7355500d3beSWarner Losh struct rtentry *rt = (struct rtentry *)rn; 7365500d3beSWarner Losh struct ifnet *ifp = arg; 7375500d3beSWarner Losh int err; 7385500d3beSWarner Losh 7395500d3beSWarner Losh if (rt->rt_ifp == ifp) { 7405500d3beSWarner Losh 7415500d3beSWarner Losh /* 7425500d3beSWarner Losh * Protect (sorta) against walktree recursion problems 7435500d3beSWarner Losh * with cloned routes 7445500d3beSWarner Losh */ 7455500d3beSWarner Losh if ((rt->rt_flags & RTF_UP) == 0) 7465500d3beSWarner Losh return (0); 7475500d3beSWarner Losh 7485500d3beSWarner Losh err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 7495500d3beSWarner Losh rt_mask(rt), rt->rt_flags, 7505500d3beSWarner Losh (struct rtentry **) NULL); 7515500d3beSWarner Losh if (err) { 7525500d3beSWarner Losh log(LOG_WARNING, "if_rtdel: error %d\n", err); 7535500d3beSWarner Losh } 7545500d3beSWarner Losh } 7555500d3beSWarner Losh 7565500d3beSWarner Losh return (0); 7576182fdbdSPeter Wemm } 7586182fdbdSPeter Wemm 759d8d5b10eSRobert Watson #define sa_equal(a1, a2) (bcmp((a1), (a2), ((a1))->sa_len) == 0) 76019fc74fbSJeffrey Hsu 76130aad87dSBrooks Davis /* 762df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 763df8bae1dSRodney W. Grimes */ 764df8bae1dSRodney W. Grimes /*ARGSUSED*/ 765df8bae1dSRodney W. Grimes struct ifaddr * 76672fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr) 767df8bae1dSRodney W. Grimes { 7680b59d917SJonathan Lemon struct ifnet *ifp; 7690b59d917SJonathan Lemon struct ifaddr *ifa; 770df8bae1dSRodney W. Grimes 771b30a244cSJeffrey Hsu IFNET_RLOCK(); 772fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 77337d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 774df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 775df8bae1dSRodney W. Grimes continue; 776d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_addr)) 7770b59d917SJonathan Lemon goto done; 77882cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 7790b59d917SJonathan Lemon if ((ifp->if_flags & IFF_BROADCAST) && 7800b59d917SJonathan Lemon ifa->ifa_broadaddr && 78182cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 782d8d5b10eSRobert Watson sa_equal(ifa->ifa_broadaddr, addr)) 7830b59d917SJonathan Lemon goto done; 7840b59d917SJonathan Lemon } 7850b59d917SJonathan Lemon ifa = NULL; 7860b59d917SJonathan Lemon done: 787b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 788df8bae1dSRodney W. Grimes return (ifa); 789df8bae1dSRodney W. Grimes } 7900b59d917SJonathan Lemon 791df8bae1dSRodney W. Grimes /* 792df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 793df8bae1dSRodney W. Grimes */ 794df8bae1dSRodney W. Grimes /*ARGSUSED*/ 795df8bae1dSRodney W. Grimes struct ifaddr * 79672fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr) 797df8bae1dSRodney W. Grimes { 7980b59d917SJonathan Lemon struct ifnet *ifp; 7990b59d917SJonathan Lemon struct ifaddr *ifa; 800df8bae1dSRodney W. Grimes 801b30a244cSJeffrey Hsu IFNET_RLOCK(); 8020b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 8030b59d917SJonathan Lemon if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 8040b59d917SJonathan Lemon continue; 80537d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 806df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 807df8bae1dSRodney W. Grimes continue; 808d8d5b10eSRobert Watson if (ifa->ifa_dstaddr && 809d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) 8100b59d917SJonathan Lemon goto done; 811df8bae1dSRodney W. Grimes } 8120b59d917SJonathan Lemon } 8130b59d917SJonathan Lemon ifa = NULL; 8140b59d917SJonathan Lemon done: 815b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 8160b59d917SJonathan Lemon return (ifa); 817df8bae1dSRodney W. Grimes } 818df8bae1dSRodney W. Grimes 819df8bae1dSRodney W. Grimes /* 820df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 821df8bae1dSRodney W. Grimes * is most specific found. 822df8bae1dSRodney W. Grimes */ 823df8bae1dSRodney W. Grimes struct ifaddr * 82472fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr) 825df8bae1dSRodney W. Grimes { 82672fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 82772fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 828df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 829df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 830df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 831df8bae1dSRodney W. Grimes 8327e2a6151SJulian Elischer /* 8337e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 8347e2a6151SJulian Elischer * so do that if we can. 8357e2a6151SJulian Elischer */ 836df8bae1dSRodney W. Grimes if (af == AF_LINK) { 837d1dd20beSSam Leffler struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 838df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 839f9132cebSJonathan Lemon return (ifaddr_byindex(sdl->sdl_index)); 840df8bae1dSRodney W. Grimes } 8417e2a6151SJulian Elischer 8427e2a6151SJulian Elischer /* 8437e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 8447e2a6151SJulian Elischer * addresses in this address family. 8457e2a6151SJulian Elischer */ 846b30a244cSJeffrey Hsu IFNET_RLOCK(); 847fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 84837d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 84972fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 850df8bae1dSRodney W. Grimes 851523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 852df8bae1dSRodney W. Grimes next: continue; 853c61cd599SHajimu UMEMOTO if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) { 8547e2a6151SJulian Elischer /* 8557e2a6151SJulian Elischer * This is a bit broken as it doesn't 8567e2a6151SJulian Elischer * take into account that the remote end may 8577e2a6151SJulian Elischer * be a single node in the network we are 8587e2a6151SJulian Elischer * looking for. 8597e2a6151SJulian Elischer * The trouble is that we don't know the 8607e2a6151SJulian Elischer * netmask for the remote end. 8617e2a6151SJulian Elischer */ 862d8d5b10eSRobert Watson if (ifa->ifa_dstaddr != 0 && 863d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) 8640b59d917SJonathan Lemon goto done; 8653740e2adSDavid Greenman } else { 8667e2a6151SJulian Elischer /* 8677ed8f465SJulian Elischer * if we have a special address handler, 8687ed8f465SJulian Elischer * then use it instead of the generic one. 8697ed8f465SJulian Elischer */ 8707ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 8710b59d917SJonathan Lemon if ((*ifa->ifa_claim_addr)(ifa, addr)) 8720b59d917SJonathan Lemon goto done; 8737ed8f465SJulian Elischer continue; 8747ed8f465SJulian Elischer } 8757ed8f465SJulian Elischer 8767ed8f465SJulian Elischer /* 8777e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 8787e2a6151SJulian Elischer * If a bit dissagrees with what we are 8797e2a6151SJulian Elischer * looking for, mask it with the netmask 8807e2a6151SJulian Elischer * to see if it really matters. 8817e2a6151SJulian Elischer * (A byte at a time) 8827e2a6151SJulian Elischer */ 883523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 884523a02aaSDavid Greenman continue; 885df8bae1dSRodney W. Grimes cp = addr_data; 886df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 887df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 8887e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 8897e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 890df8bae1dSRodney W. Grimes while (cp3 < cplim) 891df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 8927e2a6151SJulian Elischer goto next; /* next address! */ 8937e2a6151SJulian Elischer /* 8947e2a6151SJulian Elischer * If the netmask of what we just found 8957e2a6151SJulian Elischer * is more specific than what we had before 8967e2a6151SJulian Elischer * (if we had one) then remember the new one 8977e2a6151SJulian Elischer * before continuing to search 8987e2a6151SJulian Elischer * for an even better one. 8997e2a6151SJulian Elischer */ 900df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 901df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 902df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 903df8bae1dSRodney W. Grimes ifa_maybe = ifa; 904df8bae1dSRodney W. Grimes } 905b2af64fdSDavid Greenman } 906b2af64fdSDavid Greenman } 9070b59d917SJonathan Lemon ifa = ifa_maybe; 9080b59d917SJonathan Lemon done: 909b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 9100b59d917SJonathan Lemon return (ifa); 911df8bae1dSRodney W. Grimes } 912df8bae1dSRodney W. Grimes 913df8bae1dSRodney W. Grimes /* 914df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 915df8bae1dSRodney W. Grimes * a given address. 916df8bae1dSRodney W. Grimes */ 917df8bae1dSRodney W. Grimes struct ifaddr * 91872fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) 919df8bae1dSRodney W. Grimes { 92072fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 92172fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 92272fd1b6aSDag-Erling Smørgrav char *cplim; 923df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 924df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 925df8bae1dSRodney W. Grimes 926df8bae1dSRodney W. Grimes if (af >= AF_MAX) 927df8bae1dSRodney W. Grimes return (0); 92837d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 929df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 930df8bae1dSRodney W. Grimes continue; 931381dd1d2SJulian Elischer if (ifa_maybe == 0) 932df8bae1dSRodney W. Grimes ifa_maybe = ifa; 933df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 934d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_addr) || 935d8d5b10eSRobert Watson (ifa->ifa_dstaddr && 936d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr))) 9372defe5cdSJonathan Lemon goto done; 938df8bae1dSRodney W. Grimes continue; 939df8bae1dSRodney W. Grimes } 940b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 941d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_dstaddr)) 942a8637146SJonathan Lemon goto done; 9433740e2adSDavid Greenman } else { 944df8bae1dSRodney W. Grimes cp = addr->sa_data; 945df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 946df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 947df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 948df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 949df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 950df8bae1dSRodney W. Grimes break; 951df8bae1dSRodney W. Grimes if (cp3 == cplim) 9522defe5cdSJonathan Lemon goto done; 953df8bae1dSRodney W. Grimes } 954b2af64fdSDavid Greenman } 955f9132cebSJonathan Lemon ifa = ifa_maybe; 956f9132cebSJonathan Lemon done: 957f9132cebSJonathan Lemon return (ifa); 958df8bae1dSRodney W. Grimes } 959df8bae1dSRodney W. Grimes 960df8bae1dSRodney W. Grimes #include <net/route.h> 961df8bae1dSRodney W. Grimes 962df8bae1dSRodney W. Grimes /* 963df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 964df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 965df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 966df8bae1dSRodney W. Grimes */ 9673bda9f9bSPoul-Henning Kamp static void 96872fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 969df8bae1dSRodney W. Grimes { 97072fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa, *oifa; 971df8bae1dSRodney W. Grimes struct sockaddr *dst; 972df8bae1dSRodney W. Grimes struct ifnet *ifp; 973df8bae1dSRodney W. Grimes 974d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 975d1dd20beSSam Leffler 976df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 977df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 978df8bae1dSRodney W. Grimes return; 9799448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 9809448326fSPoul-Henning Kamp if (ifa) { 98119fc74fbSJeffrey Hsu IFAREF(ifa); /* XXX */ 982d1dd20beSSam Leffler oifa = rt->rt_ifa; 983df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 984d1dd20beSSam Leffler IFAFREE(oifa); 985df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 9868071913dSRuslan Ermilov ifa->ifa_rtrequest(cmd, rt, info); 987df8bae1dSRodney W. Grimes } 988df8bae1dSRodney W. Grimes } 989df8bae1dSRodney W. Grimes 990df8bae1dSRodney W. Grimes /* 991df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 992df8bae1dSRodney W. Grimes * the transition. 993df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 994df8bae1dSRodney W. Grimes */ 9958614fb12SMax Laier static void 99672fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam) 997df8bae1dSRodney W. Grimes { 99872fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 999df8bae1dSRodney W. Grimes 1000292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_unroute: flag != IFF_UP")); 1001292ee7beSRobert Watson 1002e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 100398b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1004e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1005e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 1006df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 1007df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 1008a9771948SGleb Smirnoff #ifdef DEV_CARP 1009a9771948SGleb Smirnoff if (ifp->if_carp) 1010a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1011a9771948SGleb Smirnoff #endif 1012df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 1013df8bae1dSRodney W. Grimes } 1014df8bae1dSRodney W. Grimes 1015df8bae1dSRodney W. Grimes /* 1016df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 1017df8bae1dSRodney W. Grimes * the transition. 1018df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 1019df8bae1dSRodney W. Grimes */ 10208614fb12SMax Laier static void 102172fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam) 1022df8bae1dSRodney W. Grimes { 102372fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 1024df8bae1dSRodney W. Grimes 1025292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_route: flag != IFF_UP")); 1026292ee7beSRobert Watson 1027e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 102898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1029e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1030e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 1031df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 1032a9771948SGleb Smirnoff #ifdef DEV_CARP 1033a9771948SGleb Smirnoff if (ifp->if_carp) 1034a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1035a9771948SGleb Smirnoff #endif 1036df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 103782cd038dSYoshinobu Inoue #ifdef INET6 103882cd038dSYoshinobu Inoue in6_if_up(ifp); 103982cd038dSYoshinobu Inoue #endif 1040df8bae1dSRodney W. Grimes } 1041df8bae1dSRodney W. Grimes 104294f5c9cfSSam Leffler void (*vlan_link_state_p)(struct ifnet *, int); /* XXX: private from if_vlan */ 104375ee267cSGleb Smirnoff void (*vlan_trunk_cap_p)(struct ifnet *); /* XXX: private from if_vlan */ 104494f5c9cfSSam Leffler 104594f5c9cfSSam Leffler /* 104668a3482fSGleb Smirnoff * Handle a change in the interface link state. To avoid LORs 104768a3482fSGleb Smirnoff * between driver lock and upper layer locks, as well as possible 104868a3482fSGleb Smirnoff * recursions, we post event to taskqueue, and all job 104968a3482fSGleb Smirnoff * is done in static do_link_state_change(). 105094f5c9cfSSam Leffler */ 105194f5c9cfSSam Leffler void 105294f5c9cfSSam Leffler if_link_state_change(struct ifnet *ifp, int link_state) 105394f5c9cfSSam Leffler { 10544d96314fSGleb Smirnoff /* Return if state hasn't changed. */ 10554d96314fSGleb Smirnoff if (ifp->if_link_state == link_state) 10564d96314fSGleb Smirnoff return; 10574d96314fSGleb Smirnoff 105894f5c9cfSSam Leffler ifp->if_link_state = link_state; 10594d96314fSGleb Smirnoff 106068a3482fSGleb Smirnoff taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask); 106168a3482fSGleb Smirnoff } 106268a3482fSGleb Smirnoff 106368a3482fSGleb Smirnoff static void 106468a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending) 106568a3482fSGleb Smirnoff { 106668a3482fSGleb Smirnoff struct ifnet *ifp = (struct ifnet *)arg; 106768a3482fSGleb Smirnoff int link_state = ifp->if_link_state; 106868a3482fSGleb Smirnoff int link; 106968a3482fSGleb Smirnoff 10704d96314fSGleb Smirnoff /* Notify that the link state has changed. */ 107194f5c9cfSSam Leffler rt_ifmsg(ifp); 107294f5c9cfSSam Leffler if (link_state == LINK_STATE_UP) 107394f5c9cfSSam Leffler link = NOTE_LINKUP; 107494f5c9cfSSam Leffler else if (link_state == LINK_STATE_DOWN) 107594f5c9cfSSam Leffler link = NOTE_LINKDOWN; 107694f5c9cfSSam Leffler else 107794f5c9cfSSam Leffler link = NOTE_LINKINV; 107894f5c9cfSSam Leffler KNOTE_UNLOCKED(&ifp->if_klist, link); 107975ee267cSGleb Smirnoff if (ifp->if_vlantrunk != NULL) 108094f5c9cfSSam Leffler (*vlan_link_state_p)(ifp, link); 10811c7899c7SGleb Smirnoff 10821c7899c7SGleb Smirnoff if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && 10831c7899c7SGleb Smirnoff IFP2AC(ifp)->ac_netgraph != NULL) 10841c7899c7SGleb Smirnoff (*ng_ether_link_state_p)(ifp, link_state); 10854d96314fSGleb Smirnoff #ifdef DEV_CARP 10864d96314fSGleb Smirnoff if (ifp->if_carp) 10874d96314fSGleb Smirnoff carp_carpdev_state(ifp->if_carp); 10884d96314fSGleb Smirnoff #endif 10898f867517SAndrew Thompson if (ifp->if_bridge) { 10908f867517SAndrew Thompson KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); 10918f867517SAndrew Thompson (*bstp_linkstate_p)(ifp, link_state); 10928f867517SAndrew Thompson } 10938f867517SAndrew Thompson 10949d80a330SBrooks Davis devctl_notify("IFNET", ifp->if_xname, 10959d80a330SBrooks Davis (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", NULL); 109668a3482fSGleb Smirnoff if (pending > 1) 109768a3482fSGleb Smirnoff if_printf(ifp, "%d link states coalesced\n", pending); 10985515c2e7SGleb Smirnoff if (log_link_state_change) 10998b02df24SGleb Smirnoff log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname, 11008b02df24SGleb Smirnoff (link_state == LINK_STATE_UP) ? "UP" : "DOWN" ); 110194f5c9cfSSam Leffler } 110294f5c9cfSSam Leffler 1103df8bae1dSRodney W. Grimes /* 1104e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 1105e8c2601dSPoul-Henning Kamp * the transition. 1106e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1107e8c2601dSPoul-Henning Kamp */ 1108e8c2601dSPoul-Henning Kamp void 110972fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp) 1110e8c2601dSPoul-Henning Kamp { 1111e8c2601dSPoul-Henning Kamp 1112e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 1113e8c2601dSPoul-Henning Kamp } 1114e8c2601dSPoul-Henning Kamp 1115e8c2601dSPoul-Henning Kamp /* 1116e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 1117e8c2601dSPoul-Henning Kamp * the transition. 1118e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1119e8c2601dSPoul-Henning Kamp */ 1120e8c2601dSPoul-Henning Kamp void 112172fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp) 1122e8c2601dSPoul-Henning Kamp { 1123e8c2601dSPoul-Henning Kamp 1124e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 1125e8c2601dSPoul-Henning Kamp } 1126e8c2601dSPoul-Henning Kamp 1127e8c2601dSPoul-Henning Kamp /* 1128df8bae1dSRodney W. Grimes * Flush an interface queue. 1129df8bae1dSRodney W. Grimes */ 11303bda9f9bSPoul-Henning Kamp static void 113102b199f1SMax Laier if_qflush(struct ifaltq *ifq) 1132df8bae1dSRodney W. Grimes { 113372fd1b6aSDag-Erling Smørgrav struct mbuf *m, *n; 1134df8bae1dSRodney W. Grimes 11357b21048cSMax Laier IFQ_LOCK(ifq); 113602b199f1SMax Laier #ifdef ALTQ 113702b199f1SMax Laier if (ALTQ_IS_ENABLED(ifq)) 113802b199f1SMax Laier ALTQ_PURGE(ifq); 113902b199f1SMax Laier #endif 1140df8bae1dSRodney W. Grimes n = ifq->ifq_head; 11419448326fSPoul-Henning Kamp while ((m = n) != 0) { 1142df8bae1dSRodney W. Grimes n = m->m_act; 1143df8bae1dSRodney W. Grimes m_freem(m); 1144df8bae1dSRodney W. Grimes } 1145df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 1146df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 1147df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 11487b21048cSMax Laier IFQ_UNLOCK(ifq); 1149df8bae1dSRodney W. Grimes } 1150df8bae1dSRodney W. Grimes 1151df8bae1dSRodney W. Grimes /* 1152df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 1153df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 1154df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 1155af5e59bfSRobert Watson * 1156af5e59bfSRobert Watson * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called 1157af5e59bfSRobert Watson * holding Giant. If we switch to an MPSAFE callout, we likely need to grab 1158af5e59bfSRobert Watson * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface. 1159df8bae1dSRodney W. Grimes */ 11603bda9f9bSPoul-Henning Kamp static void 116172fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg) 1162df8bae1dSRodney W. Grimes { 116372fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 1164df8bae1dSRodney W. Grimes int s = splimp(); 1165df8bae1dSRodney W. Grimes 1166b30a244cSJeffrey Hsu IFNET_RLOCK(); 1167fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 1168df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 1169df8bae1dSRodney W. Grimes continue; 1170df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 11714a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 1172df8bae1dSRodney W. Grimes } 1173b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1174df8bae1dSRodney W. Grimes splx(s); 1175df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 1176df8bae1dSRodney W. Grimes } 1177df8bae1dSRodney W. Grimes 1178df8bae1dSRodney W. Grimes /* 1179df8bae1dSRodney W. Grimes * Map interface name to 1180df8bae1dSRodney W. Grimes * interface structure pointer. 1181df8bae1dSRodney W. Grimes */ 1182df8bae1dSRodney W. Grimes struct ifnet * 118330aad87dSBrooks Davis ifunit(const char *name) 1184df8bae1dSRodney W. Grimes { 11858b7805e4SBoris Popov struct ifnet *ifp; 1186df8bae1dSRodney W. Grimes 1187b30a244cSJeffrey Hsu IFNET_RLOCK(); 1188fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 118936c19a57SBrooks Davis if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0) 1190df8bae1dSRodney W. Grimes break; 1191df8bae1dSRodney W. Grimes } 1192b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1193df8bae1dSRodney W. Grimes return (ifp); 1194df8bae1dSRodney W. Grimes } 1195df8bae1dSRodney W. Grimes 119682cd038dSYoshinobu Inoue /* 1197f13ad206SJonathan Lemon * Hardware specific interface ioctls. 1198df8bae1dSRodney W. Grimes */ 1199f13ad206SJonathan Lemon static int 1200f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) 1201df8bae1dSRodney W. Grimes { 1202f13ad206SJonathan Lemon struct ifreq *ifr; 1203413dd0baSPoul-Henning Kamp struct ifstat *ifs; 1204f13ad206SJonathan Lemon int error = 0; 1205292ee7beSRobert Watson int new_flags, temp_flags; 120636c19a57SBrooks Davis size_t namelen, onamelen; 120736c19a57SBrooks Davis char new_name[IFNAMSIZ]; 120836c19a57SBrooks Davis struct ifaddr *ifa; 120936c19a57SBrooks Davis struct sockaddr_dl *sdl; 1210df8bae1dSRodney W. Grimes 1211df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 121230aad87dSBrooks Davis switch (cmd) { 1213de593450SJonathan Lemon case SIOCGIFINDEX: 1214de593450SJonathan Lemon ifr->ifr_index = ifp->if_index; 1215de593450SJonathan Lemon break; 1216de593450SJonathan Lemon 1217df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 1218292ee7beSRobert Watson temp_flags = ifp->if_flags | ifp->if_drv_flags; 1219292ee7beSRobert Watson ifr->ifr_flags = temp_flags & 0xffff; 1220292ee7beSRobert Watson ifr->ifr_flagshigh = temp_flags >> 16; 1221df8bae1dSRodney W. Grimes break; 1222df8bae1dSRodney W. Grimes 1223016da741SJonathan Lemon case SIOCGIFCAP: 1224016da741SJonathan Lemon ifr->ifr_reqcap = ifp->if_capabilities; 1225016da741SJonathan Lemon ifr->ifr_curcap = ifp->if_capenable; 1226016da741SJonathan Lemon break; 1227016da741SJonathan Lemon 12288f293a63SRobert Watson #ifdef MAC 12298f293a63SRobert Watson case SIOCGIFMAC: 123031566c96SJohn Baldwin error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp); 12318f293a63SRobert Watson break; 12328f293a63SRobert Watson #endif 12338f293a63SRobert Watson 1234df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 1235df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 1236df8bae1dSRodney W. Grimes break; 1237df8bae1dSRodney W. Grimes 1238a7028af7SDavid Greenman case SIOCGIFMTU: 1239a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 1240a7028af7SDavid Greenman break; 1241a7028af7SDavid Greenman 1242074c4a4eSGarrett Wollman case SIOCGIFPHYS: 1243074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 1244074c4a4eSGarrett Wollman break; 1245074c4a4eSGarrett Wollman 1246df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 124744731cabSJohn Baldwin error = suser(td); 12489448326fSPoul-Henning Kamp if (error) 1249df8bae1dSRodney W. Grimes return (error); 1250292ee7beSRobert Watson /* 1251292ee7beSRobert Watson * Currently, no driver owned flags pass the IFF_CANTCHANGE 1252292ee7beSRobert Watson * check, so we don't need special handling here yet. 1253292ee7beSRobert Watson */ 125462f76486SMaxim Sobolev new_flags = (ifr->ifr_flags & 0xffff) | 125562f76486SMaxim Sobolev (ifr->ifr_flagshigh << 16); 1256cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 1257cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 12582f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 125962f76486SMaxim Sobolev (new_flags & IFF_UP) == 0) { 1260df8bae1dSRodney W. Grimes int s = splimp(); 1261df8bae1dSRodney W. Grimes if_down(ifp); 1262df8bae1dSRodney W. Grimes splx(s); 126362f76486SMaxim Sobolev } else if (new_flags & IFF_UP && 1264cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 1265df8bae1dSRodney W. Grimes int s = splimp(); 1266df8bae1dSRodney W. Grimes if_up(ifp); 1267df8bae1dSRodney W. Grimes splx(s); 1268df8bae1dSRodney W. Grimes } 12697aebc5e8SYaroslav Tykhiy /* See if permanently promiscuous mode bit is about to flip */ 12707aebc5e8SYaroslav Tykhiy if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) { 12717aebc5e8SYaroslav Tykhiy if (new_flags & IFF_PPROMISC) 12727aebc5e8SYaroslav Tykhiy ifp->if_flags |= IFF_PROMISC; 12737aebc5e8SYaroslav Tykhiy else if (ifp->if_pcount == 0) 12747aebc5e8SYaroslav Tykhiy ifp->if_flags &= ~IFF_PROMISC; 12757aebc5e8SYaroslav Tykhiy log(LOG_INFO, "%s: permanently promiscuous mode %s\n", 12767aebc5e8SYaroslav Tykhiy ifp->if_xname, 12777aebc5e8SYaroslav Tykhiy (new_flags & IFF_PPROMISC) ? "enabled" : "disabled"); 12787aebc5e8SYaroslav Tykhiy } 1279df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 128062f76486SMaxim Sobolev (new_flags &~ IFF_CANTCHANGE); 128131302ebfSRobert Watson if (ifp->if_ioctl) { 128231302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1283df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 128431302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 128531302ebfSRobert Watson } 128698b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1287df8bae1dSRodney W. Grimes break; 1288df8bae1dSRodney W. Grimes 1289016da741SJonathan Lemon case SIOCSIFCAP: 129044731cabSJohn Baldwin error = suser(td); 1291016da741SJonathan Lemon if (error) 1292016da741SJonathan Lemon return (error); 1293efb4018bSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1294efb4018bSYaroslav Tykhiy return (EOPNOTSUPP); 1295016da741SJonathan Lemon if (ifr->ifr_reqcap & ~ifp->if_capabilities) 1296016da741SJonathan Lemon return (EINVAL); 129731302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1298efb4018bSYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, cmd, data); 129931302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1300efb4018bSYaroslav Tykhiy if (error == 0) 1301efb4018bSYaroslav Tykhiy getmicrotime(&ifp->if_lastchange); 1302016da741SJonathan Lemon break; 1303016da741SJonathan Lemon 13048f293a63SRobert Watson #ifdef MAC 13058f293a63SRobert Watson case SIOCSIFMAC: 130631566c96SJohn Baldwin error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp); 13078f293a63SRobert Watson break; 13088f293a63SRobert Watson #endif 13098f293a63SRobert Watson 131036c19a57SBrooks Davis case SIOCSIFNAME: 131136c19a57SBrooks Davis error = suser(td); 1312bc1470f1SBrooks Davis if (error != 0) 131336c19a57SBrooks Davis return (error); 131436c19a57SBrooks Davis error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL); 1315bc1470f1SBrooks Davis if (error != 0) 131636c19a57SBrooks Davis return (error); 1317bc1470f1SBrooks Davis if (new_name[0] == '\0') 1318bc1470f1SBrooks Davis return (EINVAL); 131936c19a57SBrooks Davis if (ifunit(new_name) != NULL) 132036c19a57SBrooks Davis return (EEXIST); 132136c19a57SBrooks Davis 132236c19a57SBrooks Davis /* Announce the departure of the interface. */ 132336c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 132452023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 132536c19a57SBrooks Davis 132671672bb6SBrooks Davis log(LOG_INFO, "%s: changing name to '%s'\n", 132771672bb6SBrooks Davis ifp->if_xname, new_name); 132871672bb6SBrooks Davis 132936c19a57SBrooks Davis strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); 13304a0d6638SRuslan Ermilov ifa = ifp->if_addr; 133136c19a57SBrooks Davis IFA_LOCK(ifa); 133236c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_addr; 133336c19a57SBrooks Davis namelen = strlen(new_name); 133436c19a57SBrooks Davis onamelen = sdl->sdl_nlen; 133536c19a57SBrooks Davis /* 133636c19a57SBrooks Davis * Move the address if needed. This is safe because we 133736c19a57SBrooks Davis * allocate space for a name of length IFNAMSIZ when we 133836c19a57SBrooks Davis * create this in if_attach(). 133936c19a57SBrooks Davis */ 134036c19a57SBrooks Davis if (namelen != onamelen) { 134136c19a57SBrooks Davis bcopy(sdl->sdl_data + onamelen, 134236c19a57SBrooks Davis sdl->sdl_data + namelen, sdl->sdl_alen); 134336c19a57SBrooks Davis } 134436c19a57SBrooks Davis bcopy(new_name, sdl->sdl_data, namelen); 134536c19a57SBrooks Davis sdl->sdl_nlen = namelen; 134636c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_netmask; 134736c19a57SBrooks Davis bzero(sdl->sdl_data, onamelen); 134836c19a57SBrooks Davis while (namelen != 0) 134936c19a57SBrooks Davis sdl->sdl_data[--namelen] = 0xff; 135036c19a57SBrooks Davis IFA_UNLOCK(ifa); 135136c19a57SBrooks Davis 135225a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 135336c19a57SBrooks Davis /* Announce the return of the interface. */ 135436c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 135536c19a57SBrooks Davis break; 135636c19a57SBrooks Davis 1357df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 135844731cabSJohn Baldwin error = suser(td); 13599448326fSPoul-Henning Kamp if (error) 1360df8bae1dSRodney W. Grimes return (error); 1361df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 136298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1363df8bae1dSRodney W. Grimes break; 1364df8bae1dSRodney W. Grimes 1365074c4a4eSGarrett Wollman case SIOCSIFPHYS: 136644731cabSJohn Baldwin error = suser(td); 1367e39a0280SGary Palmer if (error) 1368913e410eSYaroslav Tykhiy return (error); 1369913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1370913e410eSYaroslav Tykhiy return (EOPNOTSUPP); 137131302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1372e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 137331302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1374e39a0280SGary Palmer if (error == 0) 137598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1376913e410eSYaroslav Tykhiy break; 1377074c4a4eSGarrett Wollman 1378a7028af7SDavid Greenman case SIOCSIFMTU: 137982cd038dSYoshinobu Inoue { 138082cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 138182cd038dSYoshinobu Inoue 138244731cabSJohn Baldwin error = suser(td); 13839448326fSPoul-Henning Kamp if (error) 1384a7028af7SDavid Greenman return (error); 1385aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 138675ee03cbSDavid Greenman return (EINVAL); 1387f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1388f13ad206SJonathan Lemon return (EOPNOTSUPP); 138931302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1390e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 139131302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 139248f71763SRuslan Ermilov if (error == 0) { 139398b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 139448f71763SRuslan Ermilov rt_ifmsg(ifp); 139548f71763SRuslan Ermilov } 139682cd038dSYoshinobu Inoue /* 139782cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 139882cd038dSYoshinobu Inoue */ 139982cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 140082cd038dSYoshinobu Inoue #ifdef INET6 140182cd038dSYoshinobu Inoue nd6_setmtu(ifp); 140282cd038dSYoshinobu Inoue #endif 140382cd038dSYoshinobu Inoue } 1404f13ad206SJonathan Lemon break; 140582cd038dSYoshinobu Inoue } 1406a7028af7SDavid Greenman 1407df8bae1dSRodney W. Grimes case SIOCADDMULTI: 1408df8bae1dSRodney W. Grimes case SIOCDELMULTI: 140944731cabSJohn Baldwin error = suser(td); 14109448326fSPoul-Henning Kamp if (error) 1411df8bae1dSRodney W. Grimes return (error); 1412477180fbSGarrett Wollman 1413477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 1414477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 1415f13ad206SJonathan Lemon return (EOPNOTSUPP); 1416477180fbSGarrett Wollman 1417477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 1418477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 1419f13ad206SJonathan Lemon return (EINVAL); 1420477180fbSGarrett Wollman 1421477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 1422477180fbSGarrett Wollman struct ifmultiaddr *ifma; 1423477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1424477180fbSGarrett Wollman } else { 1425477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 1426477180fbSGarrett Wollman } 1427e39a0280SGary Palmer if (error == 0) 142898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1429f13ad206SJonathan Lemon break; 1430df8bae1dSRodney W. Grimes 143141b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 143241b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 143341b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 143441b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 143541b3e8e5SJun-ichiro itojun Hagino #endif 143633841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 1437a912e453SPeter Wemm case SIOCSIFMEDIA: 1438d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 143944731cabSJohn Baldwin error = suser(td); 1440a912e453SPeter Wemm if (error) 1441a912e453SPeter Wemm return (error); 1442f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1443a912e453SPeter Wemm return (EOPNOTSUPP); 144431302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1445a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 144631302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1447a912e453SPeter Wemm if (error == 0) 144898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1449f13ad206SJonathan Lemon break; 1450a912e453SPeter Wemm 1451413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 1452413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 1453413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 1454413dd0baSPoul-Henning Kamp 145533841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 145633841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 145733841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 1458a912e453SPeter Wemm case SIOCGIFMEDIA: 1459d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 1460913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1461a912e453SPeter Wemm return (EOPNOTSUPP); 146231302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1463f13ad206SJonathan Lemon error = (*ifp->if_ioctl)(ifp, cmd, data); 146431302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1465f13ad206SJonathan Lemon break; 1466a912e453SPeter Wemm 1467b106252cSBill Paul case SIOCSIFLLADDR: 146844731cabSJohn Baldwin error = suser(td); 1469b106252cSBill Paul if (error) 1470b106252cSBill Paul return (error); 1471f13ad206SJonathan Lemon error = if_setlladdr(ifp, 147266ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 1473f13ad206SJonathan Lemon break; 147466ce51ceSArchie Cobbs 1475df8bae1dSRodney W. Grimes default: 1476f13ad206SJonathan Lemon error = ENOIOCTL; 1477f13ad206SJonathan Lemon break; 1478f13ad206SJonathan Lemon } 1479f13ad206SJonathan Lemon return (error); 1480f13ad206SJonathan Lemon } 1481f13ad206SJonathan Lemon 1482f13ad206SJonathan Lemon /* 1483f13ad206SJonathan Lemon * Interface ioctls. 1484f13ad206SJonathan Lemon */ 1485f13ad206SJonathan Lemon int 148672fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) 1487f13ad206SJonathan Lemon { 1488f13ad206SJonathan Lemon struct ifnet *ifp; 1489f13ad206SJonathan Lemon struct ifreq *ifr; 1490f13ad206SJonathan Lemon int error; 149162f76486SMaxim Sobolev int oif_flags; 1492f13ad206SJonathan Lemon 1493f13ad206SJonathan Lemon switch (cmd) { 1494f13ad206SJonathan Lemon case SIOCGIFCONF: 1495f13ad206SJonathan Lemon case OSIOCGIFCONF: 1496f13ad206SJonathan Lemon return (ifconf(cmd, data)); 1497f13ad206SJonathan Lemon } 1498f13ad206SJonathan Lemon ifr = (struct ifreq *)data; 1499f13ad206SJonathan Lemon 1500f13ad206SJonathan Lemon switch (cmd) { 1501f13ad206SJonathan Lemon case SIOCIFCREATE: 1502f13ad206SJonathan Lemon case SIOCIFDESTROY: 150344731cabSJohn Baldwin if ((error = suser(td)) != 0) 1504f13ad206SJonathan Lemon return (error); 1505f13ad206SJonathan Lemon return ((cmd == SIOCIFCREATE) ? 1506f13ad206SJonathan Lemon if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 1507f13ad206SJonathan Lemon if_clone_destroy(ifr->ifr_name)); 1508f13ad206SJonathan Lemon 1509f13ad206SJonathan Lemon case SIOCIFGCLONERS: 1510f13ad206SJonathan Lemon return (if_clone_list((struct if_clonereq *)data)); 1511f13ad206SJonathan Lemon } 1512f13ad206SJonathan Lemon 1513f13ad206SJonathan Lemon ifp = ifunit(ifr->ifr_name); 1514f13ad206SJonathan Lemon if (ifp == 0) 1515f13ad206SJonathan Lemon return (ENXIO); 1516f13ad206SJonathan Lemon 1517f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 1518f13ad206SJonathan Lemon if (error != ENOIOCTL) 1519f13ad206SJonathan Lemon return (error); 1520f13ad206SJonathan Lemon 152182cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 1522df8bae1dSRodney W. Grimes if (so->so_proto == 0) 1523df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1524df8bae1dSRodney W. Grimes #ifndef COMPAT_43 152582cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 15262c37256eSGarrett Wollman data, 1527b40ce416SJulian Elischer ifp, td)); 1528df8bae1dSRodney W. Grimes #else 1529df8bae1dSRodney W. Grimes { 1530df8bae1dSRodney W. Grimes int ocmd = cmd; 1531df8bae1dSRodney W. Grimes 1532df8bae1dSRodney W. Grimes switch (cmd) { 1533df8bae1dSRodney W. Grimes 1534df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 1535df8bae1dSRodney W. Grimes case SIOCSIFADDR: 1536df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 1537df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 1538df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 1539df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 1540df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 1541df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1542df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1543df8bae1dSRodney W. Grimes } 1544df8bae1dSRodney W. Grimes #else 1545df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 1546df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1547df8bae1dSRodney W. Grimes #endif 1548df8bae1dSRodney W. Grimes break; 1549df8bae1dSRodney W. Grimes 1550df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1551df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 1552df8bae1dSRodney W. Grimes break; 1553df8bae1dSRodney W. Grimes 1554df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1555df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 1556df8bae1dSRodney W. Grimes break; 1557df8bae1dSRodney W. Grimes 1558df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1559df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 1560df8bae1dSRodney W. Grimes break; 1561df8bae1dSRodney W. Grimes 1562df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1563df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 1564df8bae1dSRodney W. Grimes } 15652c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 15662c37256eSGarrett Wollman cmd, 15672c37256eSGarrett Wollman data, 1568b40ce416SJulian Elischer ifp, td)); 1569df8bae1dSRodney W. Grimes switch (ocmd) { 1570df8bae1dSRodney W. Grimes 1571df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1572df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1573df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1574df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1575df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 157682cd038dSYoshinobu Inoue 157782cd038dSYoshinobu Inoue } 157882cd038dSYoshinobu Inoue } 157982cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 158082cd038dSYoshinobu Inoue 158182cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 158282cd038dSYoshinobu Inoue #ifdef INET6 158388ff5695SSUZUKI Shinsuke DELAY(100);/* XXX: temporary workaround for fxp issue*/ 158482cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 158582cd038dSYoshinobu Inoue int s = splimp(); 158682cd038dSYoshinobu Inoue in6_if_up(ifp); 158782cd038dSYoshinobu Inoue splx(s); 158882cd038dSYoshinobu Inoue } 158982cd038dSYoshinobu Inoue #endif 1590df8bae1dSRodney W. Grimes } 1591df8bae1dSRodney W. Grimes return (error); 1592df8bae1dSRodney W. Grimes } 1593df8bae1dSRodney W. Grimes 1594df8bae1dSRodney W. Grimes /* 1595292ee7beSRobert Watson * The code common to handling reference counted flags, 15961a3b6859SYaroslav Tykhiy * e.g., in ifpromisc() and if_allmulti(). 1597b5c8bd59SYaroslav Tykhiy * The "pflag" argument can specify a permanent mode flag to check, 15981a3b6859SYaroslav Tykhiy * such as IFF_PPROMISC for promiscuous mode; should be 0 if none. 1599292ee7beSRobert Watson * 1600292ee7beSRobert Watson * Only to be used on stack-owned flags, not driver-owned flags. 16011a3b6859SYaroslav Tykhiy */ 16021a3b6859SYaroslav Tykhiy static int 16031a3b6859SYaroslav Tykhiy if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch) 16041a3b6859SYaroslav Tykhiy { 16051a3b6859SYaroslav Tykhiy struct ifreq ifr; 16061a3b6859SYaroslav Tykhiy int error; 16071a3b6859SYaroslav Tykhiy int oldflags, oldcount; 16081a3b6859SYaroslav Tykhiy 16091a3b6859SYaroslav Tykhiy /* Sanity checks to catch programming errors */ 1610b5c8bd59SYaroslav Tykhiy KASSERT((flag & (IFF_DRV_OACTIVE|IFF_DRV_RUNNING)) == 0, 1611b5c8bd59SYaroslav Tykhiy ("%s: setting driver-owned flag %d", __func__, flag)); 1612b5c8bd59SYaroslav Tykhiy 1613b5c8bd59SYaroslav Tykhiy if (onswitch) 1614b5c8bd59SYaroslav Tykhiy KASSERT(*refcount >= 0, 1615b5c8bd59SYaroslav Tykhiy ("%s: increment negative refcount %d for flag %d", 1616b5c8bd59SYaroslav Tykhiy __func__, *refcount, flag)); 1617b5c8bd59SYaroslav Tykhiy else 1618b5c8bd59SYaroslav Tykhiy KASSERT(*refcount > 0, 1619b5c8bd59SYaroslav Tykhiy ("%s: decrement non-positive refcount %d for flag %d", 1620b5c8bd59SYaroslav Tykhiy __func__, *refcount, flag)); 16211a3b6859SYaroslav Tykhiy 16221a3b6859SYaroslav Tykhiy /* In case this mode is permanent, just touch refcount */ 16231a3b6859SYaroslav Tykhiy if (ifp->if_flags & pflag) { 16241a3b6859SYaroslav Tykhiy *refcount += onswitch ? 1 : -1; 16251a3b6859SYaroslav Tykhiy return (0); 16261a3b6859SYaroslav Tykhiy } 16271a3b6859SYaroslav Tykhiy 16281a3b6859SYaroslav Tykhiy /* Save ifnet parameters for if_ioctl() may fail */ 16291a3b6859SYaroslav Tykhiy oldcount = *refcount; 16301a3b6859SYaroslav Tykhiy oldflags = ifp->if_flags; 16311a3b6859SYaroslav Tykhiy 16321a3b6859SYaroslav Tykhiy /* 16331a3b6859SYaroslav Tykhiy * See if we aren't the only and touching refcount is enough. 16341a3b6859SYaroslav Tykhiy * Actually toggle interface flag if we are the first or last. 16351a3b6859SYaroslav Tykhiy */ 16361a3b6859SYaroslav Tykhiy if (onswitch) { 16371a3b6859SYaroslav Tykhiy if ((*refcount)++) 16381a3b6859SYaroslav Tykhiy return (0); 16391a3b6859SYaroslav Tykhiy ifp->if_flags |= flag; 16401a3b6859SYaroslav Tykhiy } else { 16411a3b6859SYaroslav Tykhiy if (--(*refcount)) 16421a3b6859SYaroslav Tykhiy return (0); 16431a3b6859SYaroslav Tykhiy ifp->if_flags &= ~flag; 16441a3b6859SYaroslav Tykhiy } 16451a3b6859SYaroslav Tykhiy 16461a3b6859SYaroslav Tykhiy /* Call down the driver since we've changed interface flags */ 16471a3b6859SYaroslav Tykhiy if (ifp->if_ioctl == NULL) { 16481a3b6859SYaroslav Tykhiy error = EOPNOTSUPP; 16491a3b6859SYaroslav Tykhiy goto recover; 16501a3b6859SYaroslav Tykhiy } 16511a3b6859SYaroslav Tykhiy ifr.ifr_flags = ifp->if_flags & 0xffff; 16521a3b6859SYaroslav Tykhiy ifr.ifr_flagshigh = ifp->if_flags >> 16; 16531a3b6859SYaroslav Tykhiy IFF_LOCKGIANT(ifp); 16541a3b6859SYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 16551a3b6859SYaroslav Tykhiy IFF_UNLOCKGIANT(ifp); 16561a3b6859SYaroslav Tykhiy if (error) 16571a3b6859SYaroslav Tykhiy goto recover; 16581a3b6859SYaroslav Tykhiy /* Notify userland that interface flags have changed */ 16591a3b6859SYaroslav Tykhiy rt_ifmsg(ifp); 16601a3b6859SYaroslav Tykhiy return (0); 16611a3b6859SYaroslav Tykhiy 16621a3b6859SYaroslav Tykhiy recover: 16631a3b6859SYaroslav Tykhiy /* Recover after driver error */ 16641a3b6859SYaroslav Tykhiy *refcount = oldcount; 16651a3b6859SYaroslav Tykhiy ifp->if_flags = oldflags; 16661a3b6859SYaroslav Tykhiy return (error); 16671a3b6859SYaroslav Tykhiy } 16681a3b6859SYaroslav Tykhiy 16691a3b6859SYaroslav Tykhiy /* 1670963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 1671963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 1672963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 1673963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 1674963e4c2aSGarrett Wollman */ 1675963e4c2aSGarrett Wollman int 167672fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch) 1677963e4c2aSGarrett Wollman { 16784a26224cSGarrett Wollman int error; 16791a3b6859SYaroslav Tykhiy int oldflags = ifp->if_flags; 1680963e4c2aSGarrett Wollman 16811a3b6859SYaroslav Tykhiy error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC, 16821a3b6859SYaroslav Tykhiy &ifp->if_pcount, pswitch); 16831a3b6859SYaroslav Tykhiy /* If promiscuous mode status has changed, log a message */ 16841a3b6859SYaroslav Tykhiy if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC)) 16859bf40edeSBrooks Davis log(LOG_INFO, "%s: promiscuous mode %s\n", 16869bf40edeSBrooks Davis ifp->if_xname, 16874f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 16881a3b6859SYaroslav Tykhiy return (error); 1689963e4c2aSGarrett Wollman } 1690963e4c2aSGarrett Wollman 1691963e4c2aSGarrett Wollman /* 1692df8bae1dSRodney W. Grimes * Return interface configuration 1693df8bae1dSRodney W. Grimes * of system. List may be used 1694df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 1695df8bae1dSRodney W. Grimes * other information. 1696df8bae1dSRodney W. Grimes */ 1697df8bae1dSRodney W. Grimes /*ARGSUSED*/ 16983bda9f9bSPoul-Henning Kamp static int 169972fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data) 1700df8bae1dSRodney W. Grimes { 17010b59d917SJonathan Lemon struct ifconf *ifc = (struct ifconf *)data; 17020b59d917SJonathan Lemon struct ifnet *ifp; 17030b59d917SJonathan Lemon struct ifaddr *ifa; 17044dcf2bbbSBrooks Davis struct ifreq ifr; 17054dcf2bbbSBrooks Davis struct sbuf *sb; 17064dcf2bbbSBrooks Davis int error, full = 0, valid_len, max_len; 1707df8bae1dSRodney W. Grimes 17084dcf2bbbSBrooks Davis /* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */ 17094dcf2bbbSBrooks Davis max_len = MAXPHYS - 1; 17104dcf2bbbSBrooks Davis 1711b0b4b28bSXin LI /* Prevent hostile input from being able to crash the system */ 1712b0b4b28bSXin LI if (ifc->ifc_len <= 0) 1713b0b4b28bSXin LI return (EINVAL); 1714b0b4b28bSXin LI 17154dcf2bbbSBrooks Davis again: 17164dcf2bbbSBrooks Davis if (ifc->ifc_len <= max_len) { 17174dcf2bbbSBrooks Davis max_len = ifc->ifc_len; 17184dcf2bbbSBrooks Davis full = 1; 17194dcf2bbbSBrooks Davis } 17204dcf2bbbSBrooks Davis sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN); 17214dcf2bbbSBrooks Davis max_len = 0; 17224dcf2bbbSBrooks Davis valid_len = 0; 17234dcf2bbbSBrooks Davis 1724b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep XXX */ 17250b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 17269bf40edeSBrooks Davis int addrs; 17272624cf89SGarrett Wollman 1728fbd24c5eSColin Percival /* 1729fbd24c5eSColin Percival * Zero the ifr_name buffer to make sure we don't 1730fbd24c5eSColin Percival * disclose the contents of the stack. 1731fbd24c5eSColin Percival */ 1732fbd24c5eSColin Percival memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name)); 1733fbd24c5eSColin Percival 17349bf40edeSBrooks Davis if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)) 173562313e4cSSam Leffler >= sizeof(ifr.ifr_name)) { 173662313e4cSSam Leffler sbuf_delete(sb); 173762313e4cSSam Leffler IFNET_RUNLOCK(); 17384dcf2bbbSBrooks Davis return (ENAMETOOLONG); 173962313e4cSSam Leffler } 17402624cf89SGarrett Wollman 174175c13541SPoul-Henning Kamp addrs = 0; 17422defe5cdSJonathan Lemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 17432defe5cdSJonathan Lemon struct sockaddr *sa = ifa->ifa_addr; 17442defe5cdSJonathan Lemon 1745a854ed98SJohn Baldwin if (jailed(curthread->td_ucred) && 1746a854ed98SJohn Baldwin prison_if(curthread->td_ucred, sa)) 174775c13541SPoul-Henning Kamp continue; 174875c13541SPoul-Henning Kamp addrs++; 1749df8bae1dSRodney W. Grimes #ifdef COMPAT_43 1750df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 1751df8bae1dSRodney W. Grimes struct osockaddr *osa = 1752df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 1753df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1754df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 17554dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17564dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1757df8bae1dSRodney W. Grimes } else 1758df8bae1dSRodney W. Grimes #endif 1759df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 1760df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 17614dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17624dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1763df8bae1dSRodney W. Grimes } else { 17644dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, 17654dcf2bbbSBrooks Davis offsetof(struct ifreq, ifr_addr)); 17664dcf2bbbSBrooks Davis max_len += offsetof(struct ifreq, ifr_addr); 17674dcf2bbbSBrooks Davis sbuf_bcat(sb, sa, sa->sa_len); 17684dcf2bbbSBrooks Davis max_len += sa->sa_len; 1769df8bae1dSRodney W. Grimes } 17704dcf2bbbSBrooks Davis 17714dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 17724dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 1773df8bae1dSRodney W. Grimes } 17744dcf2bbbSBrooks Davis if (addrs == 0) { 177575c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 17764dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17774dcf2bbbSBrooks Davis max_len += sizeof(ifr); 17784dcf2bbbSBrooks Davis 17794dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 17804dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 178175c13541SPoul-Henning Kamp } 1782df8bae1dSRodney W. Grimes } 1783b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 17844dcf2bbbSBrooks Davis 17854dcf2bbbSBrooks Davis /* 17864dcf2bbbSBrooks Davis * If we didn't allocate enough space (uncommon), try again. If 17874dcf2bbbSBrooks Davis * we have already allocated as much space as we are allowed, 17884dcf2bbbSBrooks Davis * return what we've got. 17894dcf2bbbSBrooks Davis */ 17904dcf2bbbSBrooks Davis if (valid_len != max_len && !full) { 17914dcf2bbbSBrooks Davis sbuf_delete(sb); 17924dcf2bbbSBrooks Davis goto again; 17934dcf2bbbSBrooks Davis } 17944dcf2bbbSBrooks Davis 17954dcf2bbbSBrooks Davis ifc->ifc_len = valid_len; 17965ed8cedcSBrian Feldman sbuf_finish(sb); 17974dcf2bbbSBrooks Davis error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len); 17984dcf2bbbSBrooks Davis sbuf_delete(sb); 1799df8bae1dSRodney W. Grimes return (error); 1800df8bae1dSRodney W. Grimes } 1801df8bae1dSRodney W. Grimes 18021158dfb7SGarrett Wollman /* 18038b25904eSGleb Smirnoff * Just like ifpromisc(), but for all-multicast-reception mode. 18041158dfb7SGarrett Wollman */ 18051158dfb7SGarrett Wollman int 180672fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch) 18071158dfb7SGarrett Wollman { 18081158dfb7SGarrett Wollman 18091a3b6859SYaroslav Tykhiy return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch)); 18101158dfb7SGarrett Wollman } 18111158dfb7SGarrett Wollman 1812c3b31afdSRobert Watson static struct ifmultiaddr * 1813c3b31afdSRobert Watson if_findmulti(struct ifnet *ifp, struct sockaddr *sa) 18141158dfb7SGarrett Wollman { 18151158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 18161158dfb7SGarrett Wollman 1817c3b31afdSRobert Watson IF_ADDR_LOCK_ASSERT(ifp); 1818c3b31afdSRobert Watson 18196817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1820c3b31afdSRobert Watson if (sa_equal(ifma->ifma_addr, sa)) 1821c3b31afdSRobert Watson break; 18221158dfb7SGarrett Wollman } 1823c3b31afdSRobert Watson 1824c3b31afdSRobert Watson return ifma; 182557af7922SJulian Elischer } 18261158dfb7SGarrett Wollman 18271158dfb7SGarrett Wollman /* 1828c3b31afdSRobert Watson * Allocate a new ifmultiaddr and initialize based on passed arguments. We 1829c3b31afdSRobert Watson * make copies of passed sockaddrs. The ifmultiaddr will not be added to 1830c3b31afdSRobert Watson * the ifnet multicast address list here, so the caller must do that and 1831c3b31afdSRobert Watson * other setup work (such as notifying the device driver). The reference 1832c3b31afdSRobert Watson * count is initialized to 1. 18331158dfb7SGarrett Wollman */ 1834c3b31afdSRobert Watson static struct ifmultiaddr * 1835c3b31afdSRobert Watson if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa, 1836c3b31afdSRobert Watson int mflags) 1837c3b31afdSRobert Watson { 1838c3b31afdSRobert Watson struct ifmultiaddr *ifma; 1839c3b31afdSRobert Watson struct sockaddr *dupsa; 1840c3b31afdSRobert Watson 1841c3b31afdSRobert Watson MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, mflags | 1842c3b31afdSRobert Watson M_ZERO); 1843c3b31afdSRobert Watson if (ifma == NULL) 1844c3b31afdSRobert Watson return (NULL); 1845c3b31afdSRobert Watson 1846c3b31afdSRobert Watson MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, mflags); 1847c3b31afdSRobert Watson if (dupsa == NULL) { 1848c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1849c3b31afdSRobert Watson return (NULL); 18501158dfb7SGarrett Wollman } 18511158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 18521158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 1853c3b31afdSRobert Watson 18541158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 18551158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1856d4d22970SGleb Smirnoff ifma->ifma_protospec = NULL; 1857c3b31afdSRobert Watson 1858c3b31afdSRobert Watson if (llsa == NULL) { 1859c3b31afdSRobert Watson ifma->ifma_lladdr = NULL; 1860c3b31afdSRobert Watson return (ifma); 1861c3b31afdSRobert Watson } 1862c3b31afdSRobert Watson 1863c3b31afdSRobert Watson MALLOC(dupsa, struct sockaddr *, llsa->sa_len, M_IFMADDR, mflags); 1864c3b31afdSRobert Watson if (dupsa == NULL) { 1865c3b31afdSRobert Watson FREE(ifma->ifma_addr, M_IFMADDR); 1866c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1867c3b31afdSRobert Watson return (NULL); 1868c3b31afdSRobert Watson } 1869c3b31afdSRobert Watson bcopy(llsa, dupsa, llsa->sa_len); 1870c3b31afdSRobert Watson ifma->ifma_lladdr = dupsa; 1871c3b31afdSRobert Watson 1872c3b31afdSRobert Watson return (ifma); 1873c3b31afdSRobert Watson } 1874373f88edSGarrett Wollman 18751158dfb7SGarrett Wollman /* 1876c3b31afdSRobert Watson * if_freemulti: free ifmultiaddr structure and possibly attached related 1877c3b31afdSRobert Watson * addresses. The caller is responsible for implementing reference 1878c3b31afdSRobert Watson * counting, notifying the driver, handling routing messages, and releasing 1879c3b31afdSRobert Watson * any dependent link layer state. 18801158dfb7SGarrett Wollman */ 1881c3b31afdSRobert Watson static void 1882c3b31afdSRobert Watson if_freemulti(struct ifmultiaddr *ifma) 1883c3b31afdSRobert Watson { 1884c3b31afdSRobert Watson 1885c3b31afdSRobert Watson KASSERT(ifma->ifma_refcount == 1, ("if_freemulti: refcount %d", 1886c3b31afdSRobert Watson ifma->ifma_refcount)); 1887c3b31afdSRobert Watson KASSERT(ifma->ifma_protospec == NULL, 1888c3b31afdSRobert Watson ("if_freemulti: protospec not NULL")); 1889c3b31afdSRobert Watson 1890c3b31afdSRobert Watson if (ifma->ifma_lladdr != NULL) 1891c3b31afdSRobert Watson FREE(ifma->ifma_lladdr, M_IFMADDR); 1892c3b31afdSRobert Watson FREE(ifma->ifma_addr, M_IFMADDR); 1893c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1894c3b31afdSRobert Watson } 1895c3b31afdSRobert Watson 1896c3b31afdSRobert Watson /* 1897c3b31afdSRobert Watson * Register an additional multicast address with a network interface. 1898c3b31afdSRobert Watson * 1899c3b31afdSRobert Watson * - If the address is already present, bump the reference count on the 1900c3b31afdSRobert Watson * address and return. 1901c3b31afdSRobert Watson * - If the address is not link-layer, look up a link layer address. 1902c3b31afdSRobert Watson * - Allocate address structures for one or both addresses, and attach to the 1903c3b31afdSRobert Watson * multicast address list on the interface. If automatically adding a link 1904c3b31afdSRobert Watson * layer address, the protocol address will own a reference to the link 1905c3b31afdSRobert Watson * layer address, to be freed when it is freed. 1906c3b31afdSRobert Watson * - Notify the network device driver of an addition to the multicast address 1907c3b31afdSRobert Watson * list. 1908c3b31afdSRobert Watson * 1909c3b31afdSRobert Watson * 'sa' points to caller-owned memory with the desired multicast address. 1910c3b31afdSRobert Watson * 1911c3b31afdSRobert Watson * 'retifma' will be used to return a pointer to the resulting multicast 1912c3b31afdSRobert Watson * address reference, if desired. 1913c3b31afdSRobert Watson */ 1914c3b31afdSRobert Watson int 1915c3b31afdSRobert Watson if_addmulti(struct ifnet *ifp, struct sockaddr *sa, 1916c3b31afdSRobert Watson struct ifmultiaddr **retifma) 1917c3b31afdSRobert Watson { 1918c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 1919c3b31afdSRobert Watson struct sockaddr *llsa; 1920c3b31afdSRobert Watson int error; 1921c3b31afdSRobert Watson 1922c3b31afdSRobert Watson /* 1923c3b31afdSRobert Watson * If the address is already present, return a new reference to it; 1924c3b31afdSRobert Watson * otherwise, allocate storage and set up a new address. 1925c3b31afdSRobert Watson */ 1926c3b31afdSRobert Watson IF_ADDR_LOCK(ifp); 1927c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 1928c3b31afdSRobert Watson if (ifma != NULL) { 1929c3b31afdSRobert Watson ifma->ifma_refcount++; 1930c3b31afdSRobert Watson if (retifma != NULL) 1931c3b31afdSRobert Watson *retifma = ifma; 1932c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 1933c3b31afdSRobert Watson return (0); 1934c3b31afdSRobert Watson } 1935c3b31afdSRobert Watson 1936c3b31afdSRobert Watson /* 1937c3b31afdSRobert Watson * The address isn't already present; resolve the protocol address 1938c3b31afdSRobert Watson * into a link layer address, and then look that up, bump its 1939c3b31afdSRobert Watson * refcount or allocate an ifma for that also. If 'llsa' was 1940c3b31afdSRobert Watson * returned, we will need to free it later. 1941c3b31afdSRobert Watson */ 1942c3b31afdSRobert Watson llsa = NULL; 1943c3b31afdSRobert Watson ll_ifma = NULL; 1944c3b31afdSRobert Watson if (ifp->if_resolvemulti != NULL) { 1945c3b31afdSRobert Watson error = ifp->if_resolvemulti(ifp, &llsa, sa); 1946c3b31afdSRobert Watson if (error) 1947c3b31afdSRobert Watson goto unlock_out; 1948c3b31afdSRobert Watson } 1949c3b31afdSRobert Watson 1950c3b31afdSRobert Watson /* 1951c3b31afdSRobert Watson * Allocate the new address. Don't hook it up yet, as we may also 1952c3b31afdSRobert Watson * need to allocate a link layer multicast address. 1953c3b31afdSRobert Watson */ 1954c3b31afdSRobert Watson ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT); 1955c3b31afdSRobert Watson if (ifma == NULL) { 1956c3b31afdSRobert Watson error = ENOMEM; 1957c3b31afdSRobert Watson goto free_llsa_out; 1958c3b31afdSRobert Watson } 1959c3b31afdSRobert Watson 1960c3b31afdSRobert Watson /* 1961c3b31afdSRobert Watson * If a link layer address is found, we'll need to see if it's 1962c3b31afdSRobert Watson * already present in the address list, or allocate is as well. 1963c3b31afdSRobert Watson * When this block finishes, the link layer address will be on the 1964c3b31afdSRobert Watson * list. 1965c3b31afdSRobert Watson */ 1966c3b31afdSRobert Watson if (llsa != NULL) { 1967c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, llsa); 1968c3b31afdSRobert Watson if (ll_ifma == NULL) { 1969c3b31afdSRobert Watson ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT); 1970c3b31afdSRobert Watson if (ll_ifma == NULL) { 1971c3b31afdSRobert Watson if_freemulti(ifma); 1972c3b31afdSRobert Watson error = ENOMEM; 1973c3b31afdSRobert Watson goto free_llsa_out; 1974c3b31afdSRobert Watson } 1975c3b31afdSRobert Watson TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, 1976c3b31afdSRobert Watson ifma_link); 1977c3b31afdSRobert Watson } else 1978c3b31afdSRobert Watson ll_ifma->ifma_refcount++; 1979c3b31afdSRobert Watson } 1980c3b31afdSRobert Watson 1981c3b31afdSRobert Watson /* 1982c3b31afdSRobert Watson * We now have a new multicast address, ifma, and possibly a new or 1983c3b31afdSRobert Watson * referenced link layer address. Add the primary address to the 1984c3b31afdSRobert Watson * ifnet address list. 1985c3b31afdSRobert Watson */ 19866817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 1987c3b31afdSRobert Watson 198813990766SJonathan Mini if (retifma != NULL) 1989373f88edSGarrett Wollman *retifma = ifma; 19901158dfb7SGarrett Wollman 1991c3b31afdSRobert Watson /* 1992c3b31afdSRobert Watson * Must generate the message while holding the lock so that 'ifma' 1993c3b31afdSRobert Watson * pointer is still valid. 1994c3b31afdSRobert Watson * 1995c3b31afdSRobert Watson * XXXRW: How come we don't announce ll_ifma? 1996c3b31afdSRobert Watson */ 1997c3b31afdSRobert Watson rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1998c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 1999c3b31afdSRobert Watson 20001158dfb7SGarrett Wollman /* 20011158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 20021158dfb7SGarrett Wollman * interface to let them know about it. 20031158dfb7SGarrett Wollman */ 20042432c31cSRobert Watson if (ifp->if_ioctl != NULL) { 200531302ebfSRobert Watson IFF_LOCKGIANT(ifp); 20061a3b6859SYaroslav Tykhiy (void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0); 200731302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 20081a3b6859SYaroslav Tykhiy } 20091158dfb7SGarrett Wollman 2010c3b31afdSRobert Watson if (llsa != NULL) 2011c3b31afdSRobert Watson FREE(llsa, M_IFMADDR); 2012c3b31afdSRobert Watson 2013c3b31afdSRobert Watson return (0); 2014c3b31afdSRobert Watson 2015c3b31afdSRobert Watson free_llsa_out: 2016c3b31afdSRobert Watson if (llsa != NULL) 2017c3b31afdSRobert Watson FREE(llsa, M_IFMADDR); 2018c3b31afdSRobert Watson 2019c3b31afdSRobert Watson unlock_out: 2020c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2021c3b31afdSRobert Watson return (error); 20221158dfb7SGarrett Wollman } 20231158dfb7SGarrett Wollman 20241158dfb7SGarrett Wollman /* 20251158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 20261158dfb7SGarrett Wollman * if the request does not match an existing membership. 20271158dfb7SGarrett Wollman */ 20281158dfb7SGarrett Wollman int 202972fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa) 20301158dfb7SGarrett Wollman { 2031c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 20321158dfb7SGarrett Wollman 2033c3b31afdSRobert Watson IF_ADDR_LOCK(ifp); 2034c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 2035c3b31afdSRobert Watson if (ifma == NULL) { 2036c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 20371158dfb7SGarrett Wollman return ENOENT; 2038c3b31afdSRobert Watson } 20391158dfb7SGarrett Wollman 20401158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 20411158dfb7SGarrett Wollman ifma->ifma_refcount--; 2042c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 20431158dfb7SGarrett Wollman return 0; 20441158dfb7SGarrett Wollman } 20451158dfb7SGarrett Wollman 20461158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 2047c3b31afdSRobert Watson if (sa != NULL) 2048c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, sa); 2049c3b31afdSRobert Watson else 2050c3b31afdSRobert Watson ll_ifma = NULL; 2051c3b31afdSRobert Watson 2052c3b31afdSRobert Watson /* 2053c3b31afdSRobert Watson * XXXRW: How come we don't announce ll_ifma? 2054c3b31afdSRobert Watson */ 2055c3b31afdSRobert Watson rt_newmaddrmsg(RTM_DELMADDR, ifma); 2056c3b31afdSRobert Watson 20576817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 2058c3b31afdSRobert Watson if_freemulti(ifma); 2059c3b31afdSRobert Watson 2060c3b31afdSRobert Watson if (ll_ifma != NULL) { 2061c3b31afdSRobert Watson if (ll_ifma->ifma_refcount == 1) { 2062c3b31afdSRobert Watson TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifma_link); 2063c3b31afdSRobert Watson if_freemulti(ll_ifma); 2064c3b31afdSRobert Watson } else 2065c3b31afdSRobert Watson ll_ifma->ifma_refcount--; 2066c3b31afdSRobert Watson } 2067c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2068c3b31afdSRobert Watson 2069ccb7cc8dSYaroslav Tykhiy /* 2070ccb7cc8dSYaroslav Tykhiy * Make sure the interface driver is notified 2071ccb7cc8dSYaroslav Tykhiy * in the case of a link layer mcast group being left. 2072ccb7cc8dSYaroslav Tykhiy */ 2073c3b31afdSRobert Watson if (ifp->if_ioctl) { 207431302ebfSRobert Watson IFF_LOCKGIANT(ifp); 20751a3b6859SYaroslav Tykhiy (void) (*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0); 207631302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 207731302ebfSRobert Watson } 20781158dfb7SGarrett Wollman 20791158dfb7SGarrett Wollman return 0; 20801158dfb7SGarrett Wollman } 20811158dfb7SGarrett Wollman 208266ce51ceSArchie Cobbs /* 208366ce51ceSArchie Cobbs * Set the link layer address on an interface. 208466ce51ceSArchie Cobbs * 208566ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 208666ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 208766ce51ceSArchie Cobbs */ 208866ce51ceSArchie Cobbs int 208966ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 209066ce51ceSArchie Cobbs { 209166ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 209266ce51ceSArchie Cobbs struct ifaddr *ifa; 2093d637e989SPeter Wemm struct ifreq ifr; 209466ce51ceSArchie Cobbs 20954a0d6638SRuslan Ermilov ifa = ifp->if_addr; 209666ce51ceSArchie Cobbs if (ifa == NULL) 209766ce51ceSArchie Cobbs return (EINVAL); 209866ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 209966ce51ceSArchie Cobbs if (sdl == NULL) 210066ce51ceSArchie Cobbs return (EINVAL); 210166ce51ceSArchie Cobbs if (len != sdl->sdl_alen) /* don't allow length to change */ 210266ce51ceSArchie Cobbs return (EINVAL); 210366ce51ceSArchie Cobbs switch (ifp->if_type) { 2104d09ed26fSRuslan Ermilov case IFT_ETHER: 210566ce51ceSArchie Cobbs case IFT_FDDI: 210666ce51ceSArchie Cobbs case IFT_XETHER: 210766ce51ceSArchie Cobbs case IFT_ISO88025: 2108b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 21098f867517SAndrew Thompson case IFT_BRIDGE: 21106cdcc159SMax Khon case IFT_ARCNET: 211166ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 211266ce51ceSArchie Cobbs break; 211366ce51ceSArchie Cobbs default: 211466ce51ceSArchie Cobbs return (ENODEV); 211566ce51ceSArchie Cobbs } 211666ce51ceSArchie Cobbs /* 211766ce51ceSArchie Cobbs * If the interface is already up, we need 211866ce51ceSArchie Cobbs * to re-init it in order to reprogram its 211966ce51ceSArchie Cobbs * address filter. 212066ce51ceSArchie Cobbs */ 212166ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 21221a3b6859SYaroslav Tykhiy if (ifp->if_ioctl) { 212331302ebfSRobert Watson IFF_LOCKGIANT(ifp); 212466ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 212562f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 212662f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 2127ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 212866ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 212962f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 213062f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 2131ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 213231302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 21331a3b6859SYaroslav Tykhiy } 2134b2c08f43SLuigi Rizzo #ifdef INET 2135b2c08f43SLuigi Rizzo /* 2136b2c08f43SLuigi Rizzo * Also send gratuitous ARPs to notify other nodes about 2137b2c08f43SLuigi Rizzo * the address change. 2138b2c08f43SLuigi Rizzo */ 2139b2c08f43SLuigi Rizzo TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2140b2c08f43SLuigi Rizzo if (ifa->ifa_addr != NULL && 2141b2c08f43SLuigi Rizzo ifa->ifa_addr->sa_family == AF_INET) 2142c0933269SPeter Wemm arp_ifinit(ifp, ifa); 2143b2c08f43SLuigi Rizzo } 2144b2c08f43SLuigi Rizzo #endif 214566ce51ceSArchie Cobbs } 214666ce51ceSArchie Cobbs return (0); 214766ce51ceSArchie Cobbs } 214866ce51ceSArchie Cobbs 21499bf40edeSBrooks Davis /* 21509bf40edeSBrooks Davis * The name argument must be a pointer to storage which will last as 21519bf40edeSBrooks Davis * long as the interface does. For physical devices, the result of 21529bf40edeSBrooks Davis * device_get_name(dev) is a good choice and for pseudo-devices a 21539bf40edeSBrooks Davis * static string works well. 21549bf40edeSBrooks Davis */ 21559bf40edeSBrooks Davis void 21569bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit) 21579bf40edeSBrooks Davis { 21589bf40edeSBrooks Davis ifp->if_dname = name; 21599bf40edeSBrooks Davis ifp->if_dunit = unit; 21609bf40edeSBrooks Davis if (unit != IF_DUNIT_NONE) 21619bf40edeSBrooks Davis snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit); 21629bf40edeSBrooks Davis else 21639bf40edeSBrooks Davis strlcpy(ifp->if_xname, name, IFNAMSIZ); 21649bf40edeSBrooks Davis } 21659bf40edeSBrooks Davis 2166fa882e87SBrooks Davis int 2167fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...) 2168fa882e87SBrooks Davis { 2169fa882e87SBrooks Davis va_list ap; 2170fa882e87SBrooks Davis int retval; 2171fa882e87SBrooks Davis 21729bf40edeSBrooks Davis retval = printf("%s: ", ifp->if_xname); 2173fa882e87SBrooks Davis va_start(ap, fmt); 2174fa882e87SBrooks Davis retval += vprintf(fmt, ap); 2175fa882e87SBrooks Davis va_end(ap); 2176fa882e87SBrooks Davis return (retval); 2177fa882e87SBrooks Davis } 2178fa882e87SBrooks Davis 2179af5e59bfSRobert Watson /* 2180af5e59bfSRobert Watson * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot 2181af5e59bfSRobert Watson * be called without Giant. However, we often can't acquire the Giant lock 2182af5e59bfSRobert Watson * at those points; instead, we run it via a task queue that holds Giant via 2183af5e59bfSRobert Watson * if_start_deferred. 2184af5e59bfSRobert Watson * 2185af5e59bfSRobert Watson * XXXRW: We need to make sure that the ifnet isn't fully detached until any 2186af5e59bfSRobert Watson * outstanding if_start_deferred() tasks that will run after the free. This 2187af5e59bfSRobert Watson * probably means waiting in if_detach(). 2188af5e59bfSRobert Watson */ 2189af5e59bfSRobert Watson void 2190af5e59bfSRobert Watson if_start(struct ifnet *ifp) 2191af5e59bfSRobert Watson { 2192af5e59bfSRobert Watson 2193af5e59bfSRobert Watson NET_ASSERT_GIANT(); 2194af5e59bfSRobert Watson 2195af5e59bfSRobert Watson if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) { 2196af5e59bfSRobert Watson if (mtx_owned(&Giant)) 2197af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2198af5e59bfSRobert Watson else 2199af5e59bfSRobert Watson taskqueue_enqueue(taskqueue_swi_giant, 2200af5e59bfSRobert Watson &ifp->if_starttask); 2201af5e59bfSRobert Watson } else 2202af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2203af5e59bfSRobert Watson } 2204af5e59bfSRobert Watson 2205af5e59bfSRobert Watson static void 2206af5e59bfSRobert Watson if_start_deferred(void *context, int pending) 2207af5e59bfSRobert Watson { 2208af5e59bfSRobert Watson struct ifnet *ifp; 2209af5e59bfSRobert Watson 2210af5e59bfSRobert Watson /* 2211af5e59bfSRobert Watson * This code must be entered with Giant, and should never run if 2212af5e59bfSRobert Watson * we're not running with debug.mpsafenet. 2213af5e59bfSRobert Watson */ 2214af5e59bfSRobert Watson KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet")); 2215af5e59bfSRobert Watson GIANT_REQUIRED; 2216af5e59bfSRobert Watson 2217fc74a9f9SBrooks Davis ifp = context; 2218af5e59bfSRobert Watson (ifp->if_start)(ifp); 2219af5e59bfSRobert Watson } 2220af5e59bfSRobert Watson 22210b762445SRobert Watson int 22220b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) 22230b762445SRobert Watson { 22240b762445SRobert Watson int active = 0; 22250b762445SRobert Watson 22260b762445SRobert Watson IF_LOCK(ifq); 22270b762445SRobert Watson if (_IF_QFULL(ifq)) { 22280b762445SRobert Watson _IF_DROP(ifq); 22290b762445SRobert Watson IF_UNLOCK(ifq); 22300b762445SRobert Watson m_freem(m); 22310b762445SRobert Watson return (0); 22320b762445SRobert Watson } 22330b762445SRobert Watson if (ifp != NULL) { 22340b762445SRobert Watson ifp->if_obytes += m->m_pkthdr.len + adjust; 22350b762445SRobert Watson if (m->m_flags & (M_BCAST|M_MCAST)) 22360b762445SRobert Watson ifp->if_omcasts++; 2237292ee7beSRobert Watson active = ifp->if_drv_flags & IFF_DRV_OACTIVE; 22380b762445SRobert Watson } 22390b762445SRobert Watson _IF_ENQUEUE(ifq, m); 22400b762445SRobert Watson IF_UNLOCK(ifq); 22410b762445SRobert Watson if (ifp != NULL && !active) 22420b762445SRobert Watson if_start(ifp); 22430b762445SRobert Watson return (1); 22440b762445SRobert Watson } 2245fc74a9f9SBrooks Davis 2246fc74a9f9SBrooks Davis void 2247fc74a9f9SBrooks Davis if_register_com_alloc(u_char type, 2248fc74a9f9SBrooks Davis if_com_alloc_t *a, if_com_free_t *f) 2249fc74a9f9SBrooks Davis { 2250fc74a9f9SBrooks Davis 2251fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 2252fc74a9f9SBrooks Davis ("if_register_com_alloc: %d already registered", type)); 2253fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 2254fc74a9f9SBrooks Davis ("if_register_com_alloc: %d free already registered", type)); 2255fc74a9f9SBrooks Davis 2256fc74a9f9SBrooks Davis if_com_alloc[type] = a; 2257fc74a9f9SBrooks Davis if_com_free[type] = f; 2258fc74a9f9SBrooks Davis } 2259fc74a9f9SBrooks Davis 2260fc74a9f9SBrooks Davis void 2261fc74a9f9SBrooks Davis if_deregister_com_alloc(u_char type) 2262fc74a9f9SBrooks Davis { 2263fc74a9f9SBrooks Davis 2264fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 2265fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d not registered", type)); 2266fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 2267fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d free not registered", type)); 2268fc74a9f9SBrooks Davis if_com_alloc[type] = NULL; 2269fc74a9f9SBrooks Davis if_com_free[type] = NULL; 2270fc74a9f9SBrooks Davis } 2271