1c398230bSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1980, 1986, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 2966afbd68SRuslan Ermilov * @(#)if.c 8.5 (Berkeley) 1/9/95 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 32df8bae1dSRodney W. Grimes 335591b823SEivind Eklund #include "opt_compat.h" 34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 350d0f9d1eSYoshinobu Inoue #include "opt_inet.h" 36e70cd263SRobert Watson #include "opt_mac.h" 37a9771948SGleb Smirnoff #include "opt_carp.h" 385591b823SEivind Eklund 39df8bae1dSRodney W. Grimes #include <sys/param.h> 404dcf2bbbSBrooks Davis #include <sys/types.h> 41f13ad206SJonathan Lemon #include <sys/conf.h> 42e70cd263SRobert Watson #include <sys/mac.h> 434d1d4912SBruce Evans #include <sys/malloc.h> 444dcf2bbbSBrooks Davis #include <sys/sbuf.h> 45d2b4566aSJonathan Lemon #include <sys/bus.h> 46df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 47df8bae1dSRodney W. Grimes #include <sys/systm.h> 48df8bae1dSRodney W. Grimes #include <sys/proc.h> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 50df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 51df8bae1dSRodney W. Grimes #include <sys/protosw.h> 52df8bae1dSRodney W. Grimes #include <sys/kernel.h> 5351a53488SBruce Evans #include <sys/sockio.h> 54963e4c2aSGarrett Wollman #include <sys/syslog.h> 55602d513cSGarrett Wollman #include <sys/sysctl.h> 56af5e59bfSRobert Watson #include <sys/taskqueue.h> 5731b1bfe1SHajimu UMEMOTO #include <sys/domain.h> 5891421ba2SRobert Watson #include <sys/jail.h> 59fa882e87SBrooks Davis #include <machine/stdarg.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <net/if.h> 62b106252cSBill Paul #include <net/if_arp.h> 63f889d2efSBrooks Davis #include <net/if_clone.h> 64df8bae1dSRodney W. Grimes #include <net/if_dl.h> 6566ce51ceSArchie Cobbs #include <net/if_types.h> 6630aad87dSBrooks Davis #include <net/if_var.h> 679448326fSPoul-Henning Kamp #include <net/radix.h> 685500d3beSWarner Losh #include <net/route.h> 69df8bae1dSRodney W. Grimes 700d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6) 7182cd038dSYoshinobu Inoue /*XXX*/ 7282cd038dSYoshinobu Inoue #include <netinet/in.h> 730d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h> 743411310dSYoshinobu Inoue #ifdef INET6 75978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h> 76978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h> 773411310dSYoshinobu Inoue #endif 7882cd038dSYoshinobu Inoue #endif 79c0933269SPeter Wemm #ifdef INET 80c0933269SPeter Wemm #include <netinet/if_ether.h> 81c0933269SPeter Wemm #endif 82a9771948SGleb Smirnoff #ifdef DEV_CARP 83a9771948SGleb Smirnoff #include <netinet/ip_carp.h> 84a9771948SGleb Smirnoff #endif 8582cd038dSYoshinobu Inoue 865515c2e7SGleb Smirnoff SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 875515c2e7SGleb Smirnoff SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 885515c2e7SGleb Smirnoff 895515c2e7SGleb Smirnoff /* Log link state change events */ 905515c2e7SGleb Smirnoff static int log_link_state_change = 1; 915515c2e7SGleb Smirnoff 925515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, 935515c2e7SGleb Smirnoff &log_link_state_change, 0, 945515c2e7SGleb Smirnoff "log interface link state change events"); 955515c2e7SGleb Smirnoff 968f867517SAndrew Thompson void (*bstp_linkstate_p)(struct ifnet *ifp, int state); 971c7899c7SGleb Smirnoff void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 981c7899c7SGleb Smirnoff 994cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; 1004cb655c0SMax Laier 10131b1bfe1SHajimu UMEMOTO static void if_attachdomain(void *); 10231b1bfe1SHajimu UMEMOTO static void if_attachdomain1(struct ifnet *); 1030b59d917SJonathan Lemon static int ifconf(u_long, caddr_t); 104f9132cebSJonathan Lemon static void if_grow(void); 105f9132cebSJonathan Lemon static void if_init(void *); 106f9132cebSJonathan Lemon static void if_check(void *); 107ffb5a104SJonathan Lemon static int if_findindex(struct ifnet *); 10802b199f1SMax Laier static void if_qflush(struct ifaltq *); 1098614fb12SMax Laier static void if_route(struct ifnet *, int flag, int fam); 1101a3b6859SYaroslav Tykhiy static int if_setflag(struct ifnet *, int, int, int *, int); 1110b59d917SJonathan Lemon static void if_slowtimo(void *); 1128614fb12SMax Laier static void if_unroute(struct ifnet *, int flag, int fam); 1138071913dSRuslan Ermilov static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); 1140b59d917SJonathan Lemon static int if_rtdel(struct radix_node *, void *); 115f13ad206SJonathan Lemon static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *); 116af5e59bfSRobert Watson static void if_start_deferred(void *context, int pending); 11768a3482fSGleb Smirnoff static void do_link_state_change(void *, int); 11882cd038dSYoshinobu Inoue #ifdef INET6 11982cd038dSYoshinobu Inoue /* 12082cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 12182cd038dSYoshinobu Inoue * should be more generalized? 12282cd038dSYoshinobu Inoue */ 123929ddbbbSAlfred Perlstein extern void nd6_setmtu(struct ifnet *); 12482cd038dSYoshinobu Inoue #endif 12582cd038dSYoshinobu Inoue 1260b59d917SJonathan Lemon int if_index = 0; 127f9132cebSJonathan Lemon struct ifindex_entry *ifindex_table = NULL; 1280b59d917SJonathan Lemon int ifqmaxlen = IFQ_MAXLEN; 1290b59d917SJonathan Lemon struct ifnethead ifnet; /* depend on static init XXX */ 130b30a244cSJeffrey Hsu struct mtx ifnet_lock; 131fc74a9f9SBrooks Davis static if_com_alloc_t *if_com_alloc[256]; 132fc74a9f9SBrooks Davis static if_com_free_t *if_com_free[256]; 1330b59d917SJonathan Lemon 134f9132cebSJonathan Lemon static int if_indexlim = 8; 135ad3b9257SJohn-Mark Gurney static struct knlist ifklist; 136f9132cebSJonathan Lemon 1379a2a57a1SJonathan Lemon static void filt_netdetach(struct knote *kn); 1389a2a57a1SJonathan Lemon static int filt_netdev(struct knote *kn, long hint); 1399a2a57a1SJonathan Lemon 1409a2a57a1SJonathan Lemon static struct filterops netdev_filtops = 1419a2a57a1SJonathan Lemon { 1, NULL, filt_netdetach, filt_netdev }; 1429a2a57a1SJonathan Lemon 1430b59d917SJonathan Lemon /* 1440b59d917SJonathan Lemon * System initialization 1450b59d917SJonathan Lemon */ 146f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL) 147f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL) 1480b59d917SJonathan Lemon 149fc74a9f9SBrooks Davis MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals"); 1500b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 1510b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 15230aad87dSBrooks Davis 153f13ad206SJonathan Lemon static d_open_t netopen; 154f13ad206SJonathan Lemon static d_close_t netclose; 155f13ad206SJonathan Lemon static d_ioctl_t netioctl; 1569a2a57a1SJonathan Lemon static d_kqfilter_t netkqfilter; 157f13ad206SJonathan Lemon 158f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = { 159dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 160dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1617ac40f5fSPoul-Henning Kamp .d_open = netopen, 1627ac40f5fSPoul-Henning Kamp .d_close = netclose, 1637ac40f5fSPoul-Henning Kamp .d_ioctl = netioctl, 1647ac40f5fSPoul-Henning Kamp .d_name = "net", 1657ac40f5fSPoul-Henning Kamp .d_kqfilter = netkqfilter, 166f13ad206SJonathan Lemon }; 167f13ad206SJonathan Lemon 168f13ad206SJonathan Lemon static int 16989c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td) 170f13ad206SJonathan Lemon { 171f13ad206SJonathan Lemon return (0); 172f13ad206SJonathan Lemon } 173f13ad206SJonathan Lemon 174f13ad206SJonathan Lemon static int 17589c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td) 176f13ad206SJonathan Lemon { 177f13ad206SJonathan Lemon return (0); 178f13ad206SJonathan Lemon } 179f13ad206SJonathan Lemon 180f13ad206SJonathan Lemon static int 18189c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 182f13ad206SJonathan Lemon { 183f13ad206SJonathan Lemon struct ifnet *ifp; 184f13ad206SJonathan Lemon int error, idx; 185f13ad206SJonathan Lemon 186f13ad206SJonathan Lemon /* only support interface specific ioctls */ 187f13ad206SJonathan Lemon if (IOCGROUP(cmd) != 'i') 188f13ad206SJonathan Lemon return (EOPNOTSUPP); 189f13ad206SJonathan Lemon idx = minor(dev); 190f13ad206SJonathan Lemon if (idx == 0) { 191f13ad206SJonathan Lemon /* 192f13ad206SJonathan Lemon * special network device, not interface. 193f13ad206SJonathan Lemon */ 194f13ad206SJonathan Lemon if (cmd == SIOCGIFCONF) 195f13ad206SJonathan Lemon return (ifconf(cmd, data)); /* XXX remove cmd */ 196f13ad206SJonathan Lemon return (EOPNOTSUPP); 197f13ad206SJonathan Lemon } 198f13ad206SJonathan Lemon 199f13ad206SJonathan Lemon ifp = ifnet_byindex(idx); 200f13ad206SJonathan Lemon if (ifp == NULL) 201f13ad206SJonathan Lemon return (ENXIO); 202f13ad206SJonathan Lemon 203f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 204f13ad206SJonathan Lemon if (error == ENOIOCTL) 205f13ad206SJonathan Lemon error = EOPNOTSUPP; 206f13ad206SJonathan Lemon return (error); 207f13ad206SJonathan Lemon } 208f13ad206SJonathan Lemon 2099a2a57a1SJonathan Lemon static int 21089c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn) 2119a2a57a1SJonathan Lemon { 212ad3b9257SJohn-Mark Gurney struct knlist *klist; 2139a2a57a1SJonathan Lemon struct ifnet *ifp; 2149a2a57a1SJonathan Lemon int idx; 2159a2a57a1SJonathan Lemon 216ad3b9257SJohn-Mark Gurney switch (kn->kn_filter) { 217ad3b9257SJohn-Mark Gurney case EVFILT_NETDEV: 218ad3b9257SJohn-Mark Gurney kn->kn_fop = &netdev_filtops; 219ad3b9257SJohn-Mark Gurney break; 220ad3b9257SJohn-Mark Gurney default: 221ad3b9257SJohn-Mark Gurney return (1); 222ad3b9257SJohn-Mark Gurney } 223ad3b9257SJohn-Mark Gurney 2249a2a57a1SJonathan Lemon idx = minor(dev); 2259a2a57a1SJonathan Lemon if (idx == 0) { 2269a2a57a1SJonathan Lemon klist = &ifklist; 2279a2a57a1SJonathan Lemon } else { 2289a2a57a1SJonathan Lemon ifp = ifnet_byindex(idx); 2299a2a57a1SJonathan Lemon if (ifp == NULL) 2309a2a57a1SJonathan Lemon return (1); 2319a2a57a1SJonathan Lemon klist = &ifp->if_klist; 2329a2a57a1SJonathan Lemon } 2339a2a57a1SJonathan Lemon 2349a2a57a1SJonathan Lemon kn->kn_hook = (caddr_t)klist; 2359a2a57a1SJonathan Lemon 236ad3b9257SJohn-Mark Gurney knlist_add(klist, kn, 0); 2379a2a57a1SJonathan Lemon 2389a2a57a1SJonathan Lemon return (0); 2399a2a57a1SJonathan Lemon } 2409a2a57a1SJonathan Lemon 2419a2a57a1SJonathan Lemon static void 2429a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn) 2439a2a57a1SJonathan Lemon { 244ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2459a2a57a1SJonathan Lemon 246ad3b9257SJohn-Mark Gurney knlist_remove(klist, kn, 0); 2479a2a57a1SJonathan Lemon } 2489a2a57a1SJonathan Lemon 2499a2a57a1SJonathan Lemon static int 2509a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint) 2519a2a57a1SJonathan Lemon { 252ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2539a2a57a1SJonathan Lemon 2549a2a57a1SJonathan Lemon /* 2559a2a57a1SJonathan Lemon * Currently NOTE_EXIT is abused to indicate device detach. 2569a2a57a1SJonathan Lemon */ 2579a2a57a1SJonathan Lemon if (hint == NOTE_EXIT) { 2589a2a57a1SJonathan Lemon kn->kn_data = NOTE_LINKINV; 2599a2a57a1SJonathan Lemon kn->kn_flags |= (EV_EOF | EV_ONESHOT); 260ad3b9257SJohn-Mark Gurney knlist_remove_inevent(klist, kn); 2619a2a57a1SJonathan Lemon return (1); 2629a2a57a1SJonathan Lemon } 263ad3b9257SJohn-Mark Gurney if (hint != 0) 2649a2a57a1SJonathan Lemon kn->kn_data = hint; /* current status */ 2659a2a57a1SJonathan Lemon if (kn->kn_sfflags & hint) 2669a2a57a1SJonathan Lemon kn->kn_fflags |= hint; 2679a2a57a1SJonathan Lemon return (kn->kn_fflags != 0); 2689a2a57a1SJonathan Lemon } 2699a2a57a1SJonathan Lemon 270df8bae1dSRodney W. Grimes /* 271df8bae1dSRodney W. Grimes * Network interface utility routines. 272df8bae1dSRodney W. Grimes * 273df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 274df8bae1dSRodney W. Grimes * parameters. 275df8bae1dSRodney W. Grimes */ 2762b14f991SJulian Elischer /* ARGSUSED*/ 277f9132cebSJonathan Lemon static void 27872fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused) 279f9132cebSJonathan Lemon { 280f9132cebSJonathan Lemon 281b30a244cSJeffrey Hsu IFNET_LOCK_INIT(); 282f9132cebSJonathan Lemon TAILQ_INIT(&ifnet); 283571dcd15SSuleiman Souhlal knlist_init(&ifklist, NULL, NULL, NULL, NULL); 284f9132cebSJonathan Lemon if_grow(); /* create initial table */ 285f13ad206SJonathan Lemon ifdev_byindex(0) = make_dev(&net_cdevsw, 0, 286f13ad206SJonathan Lemon UID_ROOT, GID_WHEEL, 0600, "network"); 287f889d2efSBrooks Davis if_clone_init(); 288f9132cebSJonathan Lemon } 289f9132cebSJonathan Lemon 290f9132cebSJonathan Lemon static void 291f9132cebSJonathan Lemon if_grow(void) 292f9132cebSJonathan Lemon { 293f9132cebSJonathan Lemon u_int n; 294f9132cebSJonathan Lemon struct ifindex_entry *e; 295f9132cebSJonathan Lemon 296f9132cebSJonathan Lemon if_indexlim <<= 1; 297f9132cebSJonathan Lemon n = if_indexlim * sizeof(*e); 298fc74a9f9SBrooks Davis e = malloc(n, M_IFNET, M_WAITOK | M_ZERO); 299f9132cebSJonathan Lemon if (ifindex_table != NULL) { 300f9132cebSJonathan Lemon memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2); 301fc74a9f9SBrooks Davis free((caddr_t)ifindex_table, M_IFNET); 302f9132cebSJonathan Lemon } 303f9132cebSJonathan Lemon ifindex_table = e; 304f9132cebSJonathan Lemon } 305f9132cebSJonathan Lemon 306f9132cebSJonathan Lemon /* ARGSUSED*/ 307f9132cebSJonathan Lemon static void 30872fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused) 309df8bae1dSRodney W. Grimes { 3108ba5bdaeSPeter Wemm struct ifnet *ifp; 3118ba5bdaeSPeter Wemm int s; 312df8bae1dSRodney W. Grimes 3138ba5bdaeSPeter Wemm s = splimp(); 314b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep on rare error; mostly okay XXX */ 315fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 316e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 31713fb40dfSBrooks Davis if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n"); 318df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 319e0ea20bcSPoul-Henning Kamp } 3205e980e22SJohn Baldwin if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 32113fb40dfSBrooks Davis if_printf(ifp, 32213fb40dfSBrooks Davis "XXX: driver didn't initialize queue mtx\n"); 3236008862bSJohn Baldwin mtx_init(&ifp->if_snd.ifq_mtx, "unknown", 3246008862bSJohn Baldwin MTX_NETWORK_LOCK, MTX_DEF); 325df5e1987SJonathan Lemon } 326df5e1987SJonathan Lemon } 327b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 3288ba5bdaeSPeter Wemm splx(s); 329df8bae1dSRodney W. Grimes if_slowtimo(0); 330df8bae1dSRodney W. Grimes } 331df8bae1dSRodney W. Grimes 332fc74a9f9SBrooks Davis /* XXX: should be locked. */ 333ffb5a104SJonathan Lemon static int 334ffb5a104SJonathan Lemon if_findindex(struct ifnet *ifp) 335ffb5a104SJonathan Lemon { 336ffb5a104SJonathan Lemon int i, unit; 337ffb5a104SJonathan Lemon char eaddr[18], devname[32]; 338d2b4566aSJonathan Lemon const char *name, *p; 339ffb5a104SJonathan Lemon 340ffb5a104SJonathan Lemon switch (ifp->if_type) { 341ffb5a104SJonathan Lemon case IFT_ETHER: /* these types use struct arpcom */ 342ffb5a104SJonathan Lemon case IFT_FDDI: 343ffb5a104SJonathan Lemon case IFT_XETHER: 344ffb5a104SJonathan Lemon case IFT_ISO88025: 345ffb5a104SJonathan Lemon case IFT_L2VLAN: 3468f867517SAndrew Thompson case IFT_BRIDGE: 347fc74a9f9SBrooks Davis snprintf(eaddr, 18, "%6D", IFP2ENADDR(ifp), ":"); 348ffb5a104SJonathan Lemon break; 349ffb5a104SJonathan Lemon default: 350ffb5a104SJonathan Lemon eaddr[0] = '\0'; 351ffb5a104SJonathan Lemon break; 352ffb5a104SJonathan Lemon } 3539bf40edeSBrooks Davis strlcpy(devname, ifp->if_xname, sizeof(devname)); 354ffb5a104SJonathan Lemon name = net_cdevsw.d_name; 355ffb5a104SJonathan Lemon i = 0; 356ffb5a104SJonathan Lemon while ((resource_find_dev(&i, name, &unit, NULL, NULL)) == 0) { 357ffb5a104SJonathan Lemon if (resource_string_value(name, unit, "ether", &p) == 0) 358ffb5a104SJonathan Lemon if (strcmp(p, eaddr) == 0) 359ffb5a104SJonathan Lemon goto found; 360ffb5a104SJonathan Lemon if (resource_string_value(name, unit, "dev", &p) == 0) 361ffb5a104SJonathan Lemon if (strcmp(p, devname) == 0) 362ffb5a104SJonathan Lemon goto found; 363ffb5a104SJonathan Lemon } 364ffb5a104SJonathan Lemon unit = 0; 365ffb5a104SJonathan Lemon found: 366ffb5a104SJonathan Lemon if (unit != 0) { 367ffb5a104SJonathan Lemon if (ifaddr_byindex(unit) == NULL) 368ffb5a104SJonathan Lemon return (unit); 369ffb5a104SJonathan Lemon printf("%s%d in use, cannot hardwire it to %s.\n", 370ffb5a104SJonathan Lemon name, unit, devname); 371ffb5a104SJonathan Lemon } 372ffb5a104SJonathan Lemon for (unit = 1; ; unit++) { 37305153c61SBill Fenner if (unit <= if_index && ifaddr_byindex(unit) != NULL) 374ffb5a104SJonathan Lemon continue; 375ffb5a104SJonathan Lemon if (resource_string_value(name, unit, "ether", &p) == 0 || 376ffb5a104SJonathan Lemon resource_string_value(name, unit, "dev", &p) == 0) 377ffb5a104SJonathan Lemon continue; 378ffb5a104SJonathan Lemon break; 379ffb5a104SJonathan Lemon } 380ffb5a104SJonathan Lemon return (unit); 381ffb5a104SJonathan Lemon } 382ffb5a104SJonathan Lemon 383df8bae1dSRodney W. Grimes /* 384fc74a9f9SBrooks Davis * Allocate a struct ifnet and in index for an interface. 385fc74a9f9SBrooks Davis */ 386fc74a9f9SBrooks Davis struct ifnet* 387fc74a9f9SBrooks Davis if_alloc(u_char type) 388fc74a9f9SBrooks Davis { 389fc74a9f9SBrooks Davis struct ifnet *ifp; 390fc74a9f9SBrooks Davis 391fc74a9f9SBrooks Davis ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO); 392fc74a9f9SBrooks Davis 3931436936aSBrooks Davis /* XXX: This should fail if if_index is too big */ 394fc74a9f9SBrooks Davis ifp->if_index = if_findindex(ifp); 395fc74a9f9SBrooks Davis if (ifp->if_index > if_index) 396fc74a9f9SBrooks Davis if_index = ifp->if_index; 397fc74a9f9SBrooks Davis if (if_index >= if_indexlim) 398fc74a9f9SBrooks Davis if_grow(); 399fc74a9f9SBrooks Davis 400fc74a9f9SBrooks Davis ifnet_byindex(ifp->if_index) = ifp; 401fc74a9f9SBrooks Davis 402fc74a9f9SBrooks Davis ifp->if_type = type; 403fc74a9f9SBrooks Davis 404fc74a9f9SBrooks Davis if (if_com_alloc[type] != NULL) { 405fc74a9f9SBrooks Davis ifp->if_l2com = if_com_alloc[type](type, ifp); 40628ef2db4SBrooks Davis if (ifp->if_l2com == NULL) { 407fc74a9f9SBrooks Davis free(ifp, M_IFNET); 40828ef2db4SBrooks Davis return (NULL); 40928ef2db4SBrooks Davis } 410fc74a9f9SBrooks Davis } 4116da3131aSJohn Baldwin IF_ADDR_LOCK_INIT(ifp); 412fc74a9f9SBrooks Davis 413fc74a9f9SBrooks Davis return (ifp); 414fc74a9f9SBrooks Davis } 415fc74a9f9SBrooks Davis 416fc74a9f9SBrooks Davis void 417fc74a9f9SBrooks Davis if_free(struct ifnet *ifp) 418fc74a9f9SBrooks Davis { 419fc74a9f9SBrooks Davis 420c3b31afdSRobert Watson IF_ADDR_LOCK_DESTROY(ifp); 421456d182dSSam Leffler if_free_type(ifp, ifp->if_type); 422fc74a9f9SBrooks Davis } 423fc74a9f9SBrooks Davis 424fc74a9f9SBrooks Davis void 425fc74a9f9SBrooks Davis if_free_type(struct ifnet *ifp, u_char type) 426fc74a9f9SBrooks Davis { 427fc74a9f9SBrooks Davis 428fc74a9f9SBrooks Davis if (ifp != ifnet_byindex(ifp->if_index)) { 429fc74a9f9SBrooks Davis if_printf(ifp, "%s: value was not if_alloced, skipping\n", 430fc74a9f9SBrooks Davis __func__); 431fc74a9f9SBrooks Davis return; 432fc74a9f9SBrooks Davis } 433fc74a9f9SBrooks Davis 43428ef2db4SBrooks Davis ifnet_byindex(ifp->if_index) = NULL; 43528ef2db4SBrooks Davis 43628ef2db4SBrooks Davis /* XXX: should be locked with if_findindex() */ 43728ef2db4SBrooks Davis while (if_index > 0 && ifaddr_byindex(if_index) == NULL) 43828ef2db4SBrooks Davis if_index--; 43928ef2db4SBrooks Davis 440fc74a9f9SBrooks Davis if (if_com_free[type] != NULL) 441fc74a9f9SBrooks Davis if_com_free[type](ifp->if_l2com, type); 442fc74a9f9SBrooks Davis 443fc74a9f9SBrooks Davis free(ifp, M_IFNET); 444fc74a9f9SBrooks Davis }; 445fc74a9f9SBrooks Davis 446fc74a9f9SBrooks Davis /* 447df8bae1dSRodney W. Grimes * Attach an interface to the 448df8bae1dSRodney W. Grimes * list of "active" interfaces. 449df8bae1dSRodney W. Grimes */ 450df8bae1dSRodney W. Grimes void 45172fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp) 452df8bae1dSRodney W. Grimes { 453df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 4541ce9bf88SPoul-Henning Kamp int namelen, masklen; 45572fd1b6aSDag-Erling Smørgrav struct sockaddr_dl *sdl; 45672fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 457df8bae1dSRodney W. Grimes 458fc74a9f9SBrooks Davis if (ifp->if_index == 0 || ifp != ifnet_byindex(ifp->if_index)) 459fc74a9f9SBrooks Davis panic ("%s: BUG: if_attach called without if_alloc'd input()\n", 460fc74a9f9SBrooks Davis ifp->if_xname); 461fc74a9f9SBrooks Davis 462af5e59bfSRobert Watson TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp); 46368a3482fSGleb Smirnoff TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); 464234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK_INIT(ifp); 465234a35c7SHajimu UMEMOTO ifp->if_afdata_initialized = 0; 466b30a244cSJeffrey Hsu IFNET_WLOCK(); 46729412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 468b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 46959562606SGarrett Wollman /* 47059562606SGarrett Wollman * XXX - 47159562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 47259562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 47359562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 47459562606SGarrett Wollman * this unlikely case. 47559562606SGarrett Wollman */ 47659562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 47782cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 4786817526dSPoul-Henning Kamp TAILQ_INIT(&ifp->if_multiaddrs); 479571dcd15SSuleiman Souhlal knlist_init(&ifp->if_klist, NULL, NULL, NULL, NULL); 48098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 481bc9d2991SBrooks Davis ifp->if_data.ifi_epoch = time_uptime; 482fc74a9f9SBrooks Davis ifp->if_data.ifi_datalen = sizeof(struct if_data); 483e70cd263SRobert Watson 484e70cd263SRobert Watson #ifdef MAC 485e70cd263SRobert Watson mac_init_ifnet(ifp); 486e70cd263SRobert Watson mac_create_ifnet(ifp); 487e70cd263SRobert Watson #endif 488e70cd263SRobert Watson 48912b8b80eSRuslan Ermilov ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw, 49012b8b80eSRuslan Ermilov unit2minor(ifp->if_index), 4919bf40edeSBrooks Davis UID_ROOT, GID_WHEEL, 0600, "%s/%s", 4929bf40edeSBrooks Davis net_cdevsw.d_name, ifp->if_xname); 493ffb5a104SJonathan Lemon make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", 494ffb5a104SJonathan Lemon net_cdevsw.d_name, ifp->if_index); 495f13ad206SJonathan Lemon 4969bf40edeSBrooks Davis mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF); 497df5e1987SJonathan Lemon 498df8bae1dSRodney W. Grimes /* 499df8bae1dSRodney W. Grimes * create a Link Level name for this device 500df8bae1dSRodney W. Grimes */ 5019bf40edeSBrooks Davis namelen = strlen(ifp->if_xname); 50236c19a57SBrooks Davis /* 50336c19a57SBrooks Davis * Always save enough space for any possiable name so we can do 50436c19a57SBrooks Davis * a rename in place later. 50536c19a57SBrooks Davis */ 50636c19a57SBrooks Davis masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; 507df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 508df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 509df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 510ccb82468SBrooks Davis socksize = roundup2(socksize, sizeof(long)); 511df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 512a8773564SBrooks Davis ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 51319fc74fbSJeffrey Hsu IFA_LOCK_INIT(ifa); 514df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 515df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 516df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 5179bf40edeSBrooks Davis bcopy(ifp->if_xname, sdl->sdl_data, namelen); 5181ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 519df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 520df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 521ffb5a104SJonathan Lemon ifaddr_byindex(ifp->if_index) = ifa; 522df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 523df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 524df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 525df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 526df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 527df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 528df8bae1dSRodney W. Grimes while (namelen != 0) 529df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 53019fc74fbSJeffrey Hsu ifa->ifa_refcnt = 1; 53159562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 5326237419dSRobert Watson ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */ 53302b199f1SMax Laier ifp->if_snd.altq_type = 0; 53402b199f1SMax Laier ifp->if_snd.altq_disc = NULL; 53502b199f1SMax Laier ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE; 53602b199f1SMax Laier ifp->if_snd.altq_tbr = NULL; 53702b199f1SMax Laier ifp->if_snd.altq_ifp = ifp; 5387b6edd04SRuslan Ermilov 53969fb23b7SMax Laier if (domain_init_status >= 2) 54031b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 54131b1bfe1SHajimu UMEMOTO 54225a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 54325a4adceSMax Laier 5447b6edd04SRuslan Ermilov /* Announce the interface. */ 5457b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 546df8bae1dSRodney W. Grimes } 5476182fdbdSPeter Wemm 54831b1bfe1SHajimu UMEMOTO static void 54972fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy) 55031b1bfe1SHajimu UMEMOTO { 55131b1bfe1SHajimu UMEMOTO struct ifnet *ifp; 55231b1bfe1SHajimu UMEMOTO int s; 55331b1bfe1SHajimu UMEMOTO 55431b1bfe1SHajimu UMEMOTO s = splnet(); 5559046571fSLuigi Rizzo TAILQ_FOREACH(ifp, &ifnet, if_link) 55631b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 55731b1bfe1SHajimu UMEMOTO splx(s); 55831b1bfe1SHajimu UMEMOTO } 55969fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND, 56031b1bfe1SHajimu UMEMOTO if_attachdomain, NULL); 56131b1bfe1SHajimu UMEMOTO 56231b1bfe1SHajimu UMEMOTO static void 56372fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp) 56431b1bfe1SHajimu UMEMOTO { 56531b1bfe1SHajimu UMEMOTO struct domain *dp; 56631b1bfe1SHajimu UMEMOTO int s; 56731b1bfe1SHajimu UMEMOTO 56831b1bfe1SHajimu UMEMOTO s = splnet(); 56931b1bfe1SHajimu UMEMOTO 570234a35c7SHajimu UMEMOTO /* 571234a35c7SHajimu UMEMOTO * Since dp->dom_ifattach calls malloc() with M_WAITOK, we 572234a35c7SHajimu UMEMOTO * cannot lock ifp->if_afdata initialization, entirely. 573234a35c7SHajimu UMEMOTO */ 574234a35c7SHajimu UMEMOTO if (IF_AFDATA_TRYLOCK(ifp) == 0) { 575234a35c7SHajimu UMEMOTO splx(s); 576234a35c7SHajimu UMEMOTO return; 577234a35c7SHajimu UMEMOTO } 57869fb23b7SMax Laier if (ifp->if_afdata_initialized >= domain_init_status) { 579234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 580234a35c7SHajimu UMEMOTO splx(s); 5816237419dSRobert Watson printf("if_attachdomain called more than once on %s\n", 5826237419dSRobert Watson ifp->if_xname); 583234a35c7SHajimu UMEMOTO return; 584234a35c7SHajimu UMEMOTO } 58569fb23b7SMax Laier ifp->if_afdata_initialized = domain_init_status; 586234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 587234a35c7SHajimu UMEMOTO 58831b1bfe1SHajimu UMEMOTO /* address family dependent data region */ 58931b1bfe1SHajimu UMEMOTO bzero(ifp->if_afdata, sizeof(ifp->if_afdata)); 59031b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 59131b1bfe1SHajimu UMEMOTO if (dp->dom_ifattach) 59231b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family] = 59331b1bfe1SHajimu UMEMOTO (*dp->dom_ifattach)(ifp); 59431b1bfe1SHajimu UMEMOTO } 59531b1bfe1SHajimu UMEMOTO 59631b1bfe1SHajimu UMEMOTO splx(s); 59731b1bfe1SHajimu UMEMOTO } 59831b1bfe1SHajimu UMEMOTO 5996182fdbdSPeter Wemm /* 60045778b37SPeter Edwards * Remove any network addresses from an interface. 60145778b37SPeter Edwards */ 60245778b37SPeter Edwards 60345778b37SPeter Edwards void 60445778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp) 60545778b37SPeter Edwards { 60645778b37SPeter Edwards struct ifaddr *ifa, *next; 60745778b37SPeter Edwards 60845778b37SPeter Edwards TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { 60945778b37SPeter Edwards 61045778b37SPeter Edwards if (ifa->ifa_addr->sa_family == AF_LINK) 61145778b37SPeter Edwards continue; 61245778b37SPeter Edwards #ifdef INET 61345778b37SPeter Edwards /* XXX: Ugly!! ad hoc just for INET */ 61445778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 61545778b37SPeter Edwards struct ifaliasreq ifr; 61645778b37SPeter Edwards 61745778b37SPeter Edwards bzero(&ifr, sizeof(ifr)); 61845778b37SPeter Edwards ifr.ifra_addr = *ifa->ifa_addr; 61945778b37SPeter Edwards if (ifa->ifa_dstaddr) 62045778b37SPeter Edwards ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 62145778b37SPeter Edwards if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 62245778b37SPeter Edwards NULL) == 0) 62345778b37SPeter Edwards continue; 62445778b37SPeter Edwards } 62545778b37SPeter Edwards #endif /* INET */ 62645778b37SPeter Edwards #ifdef INET6 62745778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 62845778b37SPeter Edwards in6_purgeaddr(ifa); 62945778b37SPeter Edwards /* ifp_addrhead is already updated */ 63045778b37SPeter Edwards continue; 63145778b37SPeter Edwards } 63245778b37SPeter Edwards #endif /* INET6 */ 63345778b37SPeter Edwards TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 63445778b37SPeter Edwards IFAFREE(ifa); 63545778b37SPeter Edwards } 63645778b37SPeter Edwards } 63745778b37SPeter Edwards 63845778b37SPeter Edwards /* 6396182fdbdSPeter Wemm * Detach an interface, removing it from the 640fc74a9f9SBrooks Davis * list of "active" interfaces and freeing the struct ifnet. 6416182fdbdSPeter Wemm */ 6426182fdbdSPeter Wemm void 64372fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp) 6446182fdbdSPeter Wemm { 64545778b37SPeter Edwards struct ifaddr *ifa; 6465500d3beSWarner Losh struct radix_node_head *rnh; 6475500d3beSWarner Losh int s; 6485500d3beSWarner Losh int i; 64931b1bfe1SHajimu UMEMOTO struct domain *dp; 6503f35d515SPeter Pentchev struct ifnet *iter; 6513f35d515SPeter Pentchev int found; 6526182fdbdSPeter Wemm 65368a3482fSGleb Smirnoff /* 65468a3482fSGleb Smirnoff * Remove/wait for pending events. 65568a3482fSGleb Smirnoff */ 65668a3482fSGleb Smirnoff taskqueue_drain(taskqueue_swi, &ifp->if_linktask); 65768a3482fSGleb Smirnoff 658a9771948SGleb Smirnoff #ifdef DEV_CARP 659a9771948SGleb Smirnoff /* Maybe hook to the generalized departure handler above?!? */ 660a9771948SGleb Smirnoff if (ifp->if_carp) 661a9771948SGleb Smirnoff carp_ifdetach(ifp); 662a9771948SGleb Smirnoff #endif 663a9771948SGleb Smirnoff 6646182fdbdSPeter Wemm /* 6656182fdbdSPeter Wemm * Remove routes and flush queues. 6666182fdbdSPeter Wemm */ 6675500d3beSWarner Losh s = splnet(); 6686182fdbdSPeter Wemm if_down(ifp); 66902b199f1SMax Laier #ifdef ALTQ 67002b199f1SMax Laier if (ALTQ_IS_ENABLED(&ifp->if_snd)) 67102b199f1SMax Laier altq_disable(&ifp->if_snd); 67202b199f1SMax Laier if (ALTQ_IS_ATTACHED(&ifp->if_snd)) 67302b199f1SMax Laier altq_detach(&ifp->if_snd); 67402b199f1SMax Laier #endif 6756182fdbdSPeter Wemm 67645778b37SPeter Edwards if_purgeaddrs(ifp); 6776182fdbdSPeter Wemm 67833841545SHajimu UMEMOTO #ifdef INET6 67933841545SHajimu UMEMOTO /* 68033841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 68133841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 68233841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 68333841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 68433841545SHajimu UMEMOTO */ 68533841545SHajimu UMEMOTO in6_ifdetach(ifp); 68633841545SHajimu UMEMOTO #endif 687f4247b59SLuigi Rizzo /* 688f4247b59SLuigi Rizzo * Remove address from ifindex_table[] and maybe decrement if_index. 689f4247b59SLuigi Rizzo * Clean up all addresses. 690f4247b59SLuigi Rizzo */ 691f4247b59SLuigi Rizzo ifaddr_byindex(ifp->if_index) = NULL; 692f4247b59SLuigi Rizzo destroy_dev(ifdev_byindex(ifp->if_index)); 693f4247b59SLuigi Rizzo ifdev_byindex(ifp->if_index) = NULL; 694f4247b59SLuigi Rizzo 695212bd869SHajimu UMEMOTO /* We can now free link ifaddr. */ 6963f35d515SPeter Pentchev if (!TAILQ_EMPTY(&ifp->if_addrhead)) { 697212bd869SHajimu UMEMOTO ifa = TAILQ_FIRST(&ifp->if_addrhead); 698212bd869SHajimu UMEMOTO TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 699212bd869SHajimu UMEMOTO IFAFREE(ifa); 7003f35d515SPeter Pentchev } 701212bd869SHajimu UMEMOTO 7025500d3beSWarner Losh /* 7035500d3beSWarner Losh * Delete all remaining routes using this interface 7045500d3beSWarner Losh * Unfortuneatly the only way to do this is to slog through 7055500d3beSWarner Losh * the entire routing table looking for routes which point 7065500d3beSWarner Losh * to this interface...oh well... 7075500d3beSWarner Losh */ 7085500d3beSWarner Losh for (i = 1; i <= AF_MAX; i++) { 7095500d3beSWarner Losh if ((rnh = rt_tables[i]) == NULL) 7105500d3beSWarner Losh continue; 711956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 7125500d3beSWarner Losh (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 713956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 7145500d3beSWarner Losh } 7155500d3beSWarner Losh 7167b6edd04SRuslan Ermilov /* Announce that the interface is gone. */ 7177b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 71852023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 7197b6edd04SRuslan Ermilov 720234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK(ifp); 72131b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 72231b1bfe1SHajimu UMEMOTO if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) 72331b1bfe1SHajimu UMEMOTO (*dp->dom_ifdetach)(ifp, 72431b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family]); 72531b1bfe1SHajimu UMEMOTO } 726234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 72731b1bfe1SHajimu UMEMOTO 728e70cd263SRobert Watson #ifdef MAC 729e70cd263SRobert Watson mac_destroy_ifnet(ifp); 730e70cd263SRobert Watson #endif /* MAC */ 731ad3b9257SJohn-Mark Gurney KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT); 732ad3b9257SJohn-Mark Gurney knlist_clear(&ifp->if_klist, 0); 733ad3b9257SJohn-Mark Gurney knlist_destroy(&ifp->if_klist); 734b30a244cSJeffrey Hsu IFNET_WLOCK(); 7353f35d515SPeter Pentchev found = 0; 7363f35d515SPeter Pentchev TAILQ_FOREACH(iter, &ifnet, if_link) 7373f35d515SPeter Pentchev if (iter == ifp) { 7383f35d515SPeter Pentchev found = 1; 7393f35d515SPeter Pentchev break; 7403f35d515SPeter Pentchev } 7413f35d515SPeter Pentchev if (found) 7426182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 743b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 744df5e1987SJonathan Lemon mtx_destroy(&ifp->if_snd.ifq_mtx); 745234a35c7SHajimu UMEMOTO IF_AFDATA_DESTROY(ifp); 7465500d3beSWarner Losh splx(s); 7475500d3beSWarner Losh } 7485500d3beSWarner Losh 7495500d3beSWarner Losh /* 7505500d3beSWarner Losh * Delete Routes for a Network Interface 7515500d3beSWarner Losh * 7525500d3beSWarner Losh * Called for each routing entry via the rnh->rnh_walktree() call above 7535500d3beSWarner Losh * to delete all route entries referencing a detaching network interface. 7545500d3beSWarner Losh * 7555500d3beSWarner Losh * Arguments: 7565500d3beSWarner Losh * rn pointer to node in the routing table 7575500d3beSWarner Losh * arg argument passed to rnh->rnh_walktree() - detaching interface 7585500d3beSWarner Losh * 7595500d3beSWarner Losh * Returns: 7605500d3beSWarner Losh * 0 successful 7615500d3beSWarner Losh * errno failed - reason indicated 7625500d3beSWarner Losh * 7635500d3beSWarner Losh */ 7645500d3beSWarner Losh static int 76572fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg) 7665500d3beSWarner Losh { 7675500d3beSWarner Losh struct rtentry *rt = (struct rtentry *)rn; 7685500d3beSWarner Losh struct ifnet *ifp = arg; 7695500d3beSWarner Losh int err; 7705500d3beSWarner Losh 7715500d3beSWarner Losh if (rt->rt_ifp == ifp) { 7725500d3beSWarner Losh 7735500d3beSWarner Losh /* 7745500d3beSWarner Losh * Protect (sorta) against walktree recursion problems 7755500d3beSWarner Losh * with cloned routes 7765500d3beSWarner Losh */ 7775500d3beSWarner Losh if ((rt->rt_flags & RTF_UP) == 0) 7785500d3beSWarner Losh return (0); 7795500d3beSWarner Losh 7805500d3beSWarner Losh err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 7815500d3beSWarner Losh rt_mask(rt), rt->rt_flags, 7825500d3beSWarner Losh (struct rtentry **) NULL); 7835500d3beSWarner Losh if (err) { 7845500d3beSWarner Losh log(LOG_WARNING, "if_rtdel: error %d\n", err); 7855500d3beSWarner Losh } 7865500d3beSWarner Losh } 7875500d3beSWarner Losh 7885500d3beSWarner Losh return (0); 7896182fdbdSPeter Wemm } 7906182fdbdSPeter Wemm 791d8d5b10eSRobert Watson #define sa_equal(a1, a2) (bcmp((a1), (a2), ((a1))->sa_len) == 0) 79219fc74fbSJeffrey Hsu 79330aad87dSBrooks Davis /* 794df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 795df8bae1dSRodney W. Grimes */ 796df8bae1dSRodney W. Grimes /*ARGSUSED*/ 797df8bae1dSRodney W. Grimes struct ifaddr * 79872fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr) 799df8bae1dSRodney W. Grimes { 8000b59d917SJonathan Lemon struct ifnet *ifp; 8010b59d917SJonathan Lemon struct ifaddr *ifa; 802df8bae1dSRodney W. Grimes 803b30a244cSJeffrey Hsu IFNET_RLOCK(); 804fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 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 (sa_equal(addr, ifa->ifa_addr)) 8090b59d917SJonathan Lemon goto done; 81082cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 8110b59d917SJonathan Lemon if ((ifp->if_flags & IFF_BROADCAST) && 8120b59d917SJonathan Lemon ifa->ifa_broadaddr && 81382cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 814d8d5b10eSRobert Watson sa_equal(ifa->ifa_broadaddr, addr)) 8150b59d917SJonathan Lemon goto done; 8160b59d917SJonathan Lemon } 8170b59d917SJonathan Lemon ifa = NULL; 8180b59d917SJonathan Lemon done: 819b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 820df8bae1dSRodney W. Grimes return (ifa); 821df8bae1dSRodney W. Grimes } 8220b59d917SJonathan Lemon 823df8bae1dSRodney W. Grimes /* 824df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 825df8bae1dSRodney W. Grimes */ 826df8bae1dSRodney W. Grimes /*ARGSUSED*/ 827df8bae1dSRodney W. Grimes struct ifaddr * 82872fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr) 829df8bae1dSRodney W. Grimes { 8300b59d917SJonathan Lemon struct ifnet *ifp; 8310b59d917SJonathan Lemon struct ifaddr *ifa; 832df8bae1dSRodney W. Grimes 833b30a244cSJeffrey Hsu IFNET_RLOCK(); 8340b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 8350b59d917SJonathan Lemon if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 8360b59d917SJonathan Lemon continue; 83737d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 838df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 839df8bae1dSRodney W. Grimes continue; 840d8d5b10eSRobert Watson if (ifa->ifa_dstaddr && 841d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) 8420b59d917SJonathan Lemon goto done; 843df8bae1dSRodney W. Grimes } 8440b59d917SJonathan Lemon } 8450b59d917SJonathan Lemon ifa = NULL; 8460b59d917SJonathan Lemon done: 847b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 8480b59d917SJonathan Lemon return (ifa); 849df8bae1dSRodney W. Grimes } 850df8bae1dSRodney W. Grimes 851df8bae1dSRodney W. Grimes /* 852df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 853df8bae1dSRodney W. Grimes * is most specific found. 854df8bae1dSRodney W. Grimes */ 855df8bae1dSRodney W. Grimes struct ifaddr * 85672fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr) 857df8bae1dSRodney W. Grimes { 85872fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 85972fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 860df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 861df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 862df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 863df8bae1dSRodney W. Grimes 8647e2a6151SJulian Elischer /* 8657e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 8667e2a6151SJulian Elischer * so do that if we can. 8677e2a6151SJulian Elischer */ 868df8bae1dSRodney W. Grimes if (af == AF_LINK) { 869d1dd20beSSam Leffler struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 870df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 871f9132cebSJonathan Lemon return (ifaddr_byindex(sdl->sdl_index)); 872df8bae1dSRodney W. Grimes } 8737e2a6151SJulian Elischer 8747e2a6151SJulian Elischer /* 8757e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 8767e2a6151SJulian Elischer * addresses in this address family. 8777e2a6151SJulian Elischer */ 878b30a244cSJeffrey Hsu IFNET_RLOCK(); 879fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 88037d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 88172fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 882df8bae1dSRodney W. Grimes 883523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 884df8bae1dSRodney W. Grimes next: continue; 885c61cd599SHajimu UMEMOTO if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) { 8867e2a6151SJulian Elischer /* 8877e2a6151SJulian Elischer * This is a bit broken as it doesn't 8887e2a6151SJulian Elischer * take into account that the remote end may 8897e2a6151SJulian Elischer * be a single node in the network we are 8907e2a6151SJulian Elischer * looking for. 8917e2a6151SJulian Elischer * The trouble is that we don't know the 8927e2a6151SJulian Elischer * netmask for the remote end. 8937e2a6151SJulian Elischer */ 894d8d5b10eSRobert Watson if (ifa->ifa_dstaddr != 0 && 895d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) 8960b59d917SJonathan Lemon goto done; 8973740e2adSDavid Greenman } else { 8987e2a6151SJulian Elischer /* 8997ed8f465SJulian Elischer * if we have a special address handler, 9007ed8f465SJulian Elischer * then use it instead of the generic one. 9017ed8f465SJulian Elischer */ 9027ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 9030b59d917SJonathan Lemon if ((*ifa->ifa_claim_addr)(ifa, addr)) 9040b59d917SJonathan Lemon goto done; 9057ed8f465SJulian Elischer continue; 9067ed8f465SJulian Elischer } 9077ed8f465SJulian Elischer 9087ed8f465SJulian Elischer /* 9097e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 9107e2a6151SJulian Elischer * If a bit dissagrees with what we are 9117e2a6151SJulian Elischer * looking for, mask it with the netmask 9127e2a6151SJulian Elischer * to see if it really matters. 9137e2a6151SJulian Elischer * (A byte at a time) 9147e2a6151SJulian Elischer */ 915523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 916523a02aaSDavid Greenman continue; 917df8bae1dSRodney W. Grimes cp = addr_data; 918df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 919df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 9207e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 9217e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 922df8bae1dSRodney W. Grimes while (cp3 < cplim) 923df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 9247e2a6151SJulian Elischer goto next; /* next address! */ 9257e2a6151SJulian Elischer /* 9267e2a6151SJulian Elischer * If the netmask of what we just found 9277e2a6151SJulian Elischer * is more specific than what we had before 9287e2a6151SJulian Elischer * (if we had one) then remember the new one 9297e2a6151SJulian Elischer * before continuing to search 9307e2a6151SJulian Elischer * for an even better one. 9317e2a6151SJulian Elischer */ 932df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 933df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 934df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 935df8bae1dSRodney W. Grimes ifa_maybe = ifa; 936df8bae1dSRodney W. Grimes } 937b2af64fdSDavid Greenman } 938b2af64fdSDavid Greenman } 9390b59d917SJonathan Lemon ifa = ifa_maybe; 9400b59d917SJonathan Lemon done: 941b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 9420b59d917SJonathan Lemon return (ifa); 943df8bae1dSRodney W. Grimes } 944df8bae1dSRodney W. Grimes 945df8bae1dSRodney W. Grimes /* 946df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 947df8bae1dSRodney W. Grimes * a given address. 948df8bae1dSRodney W. Grimes */ 949df8bae1dSRodney W. Grimes struct ifaddr * 95072fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) 951df8bae1dSRodney W. Grimes { 95272fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 95372fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 95472fd1b6aSDag-Erling Smørgrav char *cplim; 955df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 956df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 957df8bae1dSRodney W. Grimes 958df8bae1dSRodney W. Grimes if (af >= AF_MAX) 959df8bae1dSRodney W. Grimes return (0); 96037d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 961df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 962df8bae1dSRodney W. Grimes continue; 963381dd1d2SJulian Elischer if (ifa_maybe == 0) 964df8bae1dSRodney W. Grimes ifa_maybe = ifa; 965df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 966d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_addr) || 967d8d5b10eSRobert Watson (ifa->ifa_dstaddr && 968d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr))) 9692defe5cdSJonathan Lemon goto done; 970df8bae1dSRodney W. Grimes continue; 971df8bae1dSRodney W. Grimes } 972b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 973d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_dstaddr)) 974a8637146SJonathan Lemon goto done; 9753740e2adSDavid Greenman } else { 976df8bae1dSRodney W. Grimes cp = addr->sa_data; 977df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 978df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 979df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 980df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 981df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 982df8bae1dSRodney W. Grimes break; 983df8bae1dSRodney W. Grimes if (cp3 == cplim) 9842defe5cdSJonathan Lemon goto done; 985df8bae1dSRodney W. Grimes } 986b2af64fdSDavid Greenman } 987f9132cebSJonathan Lemon ifa = ifa_maybe; 988f9132cebSJonathan Lemon done: 989f9132cebSJonathan Lemon return (ifa); 990df8bae1dSRodney W. Grimes } 991df8bae1dSRodney W. Grimes 992df8bae1dSRodney W. Grimes #include <net/route.h> 993df8bae1dSRodney W. Grimes 994df8bae1dSRodney W. Grimes /* 995df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 996df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 997df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 998df8bae1dSRodney W. Grimes */ 9993bda9f9bSPoul-Henning Kamp static void 100072fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 1001df8bae1dSRodney W. Grimes { 100272fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa, *oifa; 1003df8bae1dSRodney W. Grimes struct sockaddr *dst; 1004df8bae1dSRodney W. Grimes struct ifnet *ifp; 1005df8bae1dSRodney W. Grimes 1006d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 1007d1dd20beSSam Leffler 1008df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 1009df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 1010df8bae1dSRodney W. Grimes return; 10119448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 10129448326fSPoul-Henning Kamp if (ifa) { 101319fc74fbSJeffrey Hsu IFAREF(ifa); /* XXX */ 1014d1dd20beSSam Leffler oifa = rt->rt_ifa; 1015df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 1016d1dd20beSSam Leffler IFAFREE(oifa); 1017df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 10188071913dSRuslan Ermilov ifa->ifa_rtrequest(cmd, rt, info); 1019df8bae1dSRodney W. Grimes } 1020df8bae1dSRodney W. Grimes } 1021df8bae1dSRodney W. Grimes 1022df8bae1dSRodney W. Grimes /* 1023df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 1024df8bae1dSRodney W. Grimes * the transition. 1025df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 1026df8bae1dSRodney W. Grimes */ 10278614fb12SMax Laier static void 102872fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam) 1029df8bae1dSRodney W. Grimes { 103072fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 1031df8bae1dSRodney W. Grimes 1032292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_unroute: flag != IFF_UP")); 1033292ee7beSRobert Watson 1034e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 103598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1036e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1037e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 1038df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 1039df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 1040a9771948SGleb Smirnoff #ifdef DEV_CARP 1041a9771948SGleb Smirnoff if (ifp->if_carp) 1042a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1043a9771948SGleb Smirnoff #endif 1044df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 1045df8bae1dSRodney W. Grimes } 1046df8bae1dSRodney W. Grimes 1047df8bae1dSRodney W. Grimes /* 1048df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 1049df8bae1dSRodney W. Grimes * the transition. 1050df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 1051df8bae1dSRodney W. Grimes */ 10528614fb12SMax Laier static void 105372fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam) 1054df8bae1dSRodney W. Grimes { 105572fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 1056df8bae1dSRodney W. Grimes 1057292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_route: flag != IFF_UP")); 1058292ee7beSRobert Watson 1059e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 106098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1061e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 1062e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 1063df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 1064a9771948SGleb Smirnoff #ifdef DEV_CARP 1065a9771948SGleb Smirnoff if (ifp->if_carp) 1066a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1067a9771948SGleb Smirnoff #endif 1068df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 106982cd038dSYoshinobu Inoue #ifdef INET6 107082cd038dSYoshinobu Inoue in6_if_up(ifp); 107182cd038dSYoshinobu Inoue #endif 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes 107494f5c9cfSSam Leffler void (*vlan_link_state_p)(struct ifnet *, int); /* XXX: private from if_vlan */ 107594f5c9cfSSam Leffler 107694f5c9cfSSam Leffler /* 107768a3482fSGleb Smirnoff * Handle a change in the interface link state. To avoid LORs 107868a3482fSGleb Smirnoff * between driver lock and upper layer locks, as well as possible 107968a3482fSGleb Smirnoff * recursions, we post event to taskqueue, and all job 108068a3482fSGleb Smirnoff * is done in static do_link_state_change(). 108194f5c9cfSSam Leffler */ 108294f5c9cfSSam Leffler void 108394f5c9cfSSam Leffler if_link_state_change(struct ifnet *ifp, int link_state) 108494f5c9cfSSam Leffler { 10854d96314fSGleb Smirnoff /* Return if state hasn't changed. */ 10864d96314fSGleb Smirnoff if (ifp->if_link_state == link_state) 10874d96314fSGleb Smirnoff return; 10884d96314fSGleb Smirnoff 108994f5c9cfSSam Leffler ifp->if_link_state = link_state; 10904d96314fSGleb Smirnoff 109168a3482fSGleb Smirnoff taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask); 109268a3482fSGleb Smirnoff } 109368a3482fSGleb Smirnoff 109468a3482fSGleb Smirnoff static void 109568a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending) 109668a3482fSGleb Smirnoff { 109768a3482fSGleb Smirnoff struct ifnet *ifp = (struct ifnet *)arg; 109868a3482fSGleb Smirnoff int link_state = ifp->if_link_state; 109968a3482fSGleb Smirnoff int link; 110068a3482fSGleb Smirnoff 11014d96314fSGleb Smirnoff /* Notify that the link state has changed. */ 110294f5c9cfSSam Leffler rt_ifmsg(ifp); 110394f5c9cfSSam Leffler if (link_state == LINK_STATE_UP) 110494f5c9cfSSam Leffler link = NOTE_LINKUP; 110594f5c9cfSSam Leffler else if (link_state == LINK_STATE_DOWN) 110694f5c9cfSSam Leffler link = NOTE_LINKDOWN; 110794f5c9cfSSam Leffler else 110894f5c9cfSSam Leffler link = NOTE_LINKINV; 110994f5c9cfSSam Leffler KNOTE_UNLOCKED(&ifp->if_klist, link); 111094f5c9cfSSam Leffler if (ifp->if_nvlans != 0) 111194f5c9cfSSam Leffler (*vlan_link_state_p)(ifp, link); 11121c7899c7SGleb Smirnoff 11131c7899c7SGleb Smirnoff if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && 11141c7899c7SGleb Smirnoff IFP2AC(ifp)->ac_netgraph != NULL) 11151c7899c7SGleb Smirnoff (*ng_ether_link_state_p)(ifp, link_state); 11164d96314fSGleb Smirnoff #ifdef DEV_CARP 11174d96314fSGleb Smirnoff if (ifp->if_carp) 11184d96314fSGleb Smirnoff carp_carpdev_state(ifp->if_carp); 11194d96314fSGleb Smirnoff #endif 11208f867517SAndrew Thompson if (ifp->if_bridge) { 11218f867517SAndrew Thompson KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); 11228f867517SAndrew Thompson (*bstp_linkstate_p)(ifp, link_state); 11238f867517SAndrew Thompson } 11248f867517SAndrew Thompson 11259d80a330SBrooks Davis devctl_notify("IFNET", ifp->if_xname, 11269d80a330SBrooks Davis (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", NULL); 112768a3482fSGleb Smirnoff if (pending > 1) 112868a3482fSGleb Smirnoff if_printf(ifp, "%d link states coalesced\n", pending); 11295515c2e7SGleb Smirnoff if (log_link_state_change) 11308b02df24SGleb Smirnoff log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname, 11318b02df24SGleb Smirnoff (link_state == LINK_STATE_UP) ? "UP" : "DOWN" ); 113294f5c9cfSSam Leffler } 113394f5c9cfSSam Leffler 1134df8bae1dSRodney W. Grimes /* 1135e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 1136e8c2601dSPoul-Henning Kamp * the transition. 1137e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1138e8c2601dSPoul-Henning Kamp */ 1139e8c2601dSPoul-Henning Kamp void 114072fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp) 1141e8c2601dSPoul-Henning Kamp { 1142e8c2601dSPoul-Henning Kamp 1143e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 1144e8c2601dSPoul-Henning Kamp } 1145e8c2601dSPoul-Henning Kamp 1146e8c2601dSPoul-Henning Kamp /* 1147e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 1148e8c2601dSPoul-Henning Kamp * the transition. 1149e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1150e8c2601dSPoul-Henning Kamp */ 1151e8c2601dSPoul-Henning Kamp void 115272fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp) 1153e8c2601dSPoul-Henning Kamp { 1154e8c2601dSPoul-Henning Kamp 1155e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 1156e8c2601dSPoul-Henning Kamp } 1157e8c2601dSPoul-Henning Kamp 1158e8c2601dSPoul-Henning Kamp /* 1159df8bae1dSRodney W. Grimes * Flush an interface queue. 1160df8bae1dSRodney W. Grimes */ 11613bda9f9bSPoul-Henning Kamp static void 116202b199f1SMax Laier if_qflush(struct ifaltq *ifq) 1163df8bae1dSRodney W. Grimes { 116472fd1b6aSDag-Erling Smørgrav struct mbuf *m, *n; 1165df8bae1dSRodney W. Grimes 11667b21048cSMax Laier IFQ_LOCK(ifq); 116702b199f1SMax Laier #ifdef ALTQ 116802b199f1SMax Laier if (ALTQ_IS_ENABLED(ifq)) 116902b199f1SMax Laier ALTQ_PURGE(ifq); 117002b199f1SMax Laier #endif 1171df8bae1dSRodney W. Grimes n = ifq->ifq_head; 11729448326fSPoul-Henning Kamp while ((m = n) != 0) { 1173df8bae1dSRodney W. Grimes n = m->m_act; 1174df8bae1dSRodney W. Grimes m_freem(m); 1175df8bae1dSRodney W. Grimes } 1176df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 1177df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 1178df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 11797b21048cSMax Laier IFQ_UNLOCK(ifq); 1180df8bae1dSRodney W. Grimes } 1181df8bae1dSRodney W. Grimes 1182df8bae1dSRodney W. Grimes /* 1183df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 1184df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 1185df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 1186af5e59bfSRobert Watson * 1187af5e59bfSRobert Watson * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called 1188af5e59bfSRobert Watson * holding Giant. If we switch to an MPSAFE callout, we likely need to grab 1189af5e59bfSRobert Watson * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface. 1190df8bae1dSRodney W. Grimes */ 11913bda9f9bSPoul-Henning Kamp static void 119272fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg) 1193df8bae1dSRodney W. Grimes { 119472fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 1195df8bae1dSRodney W. Grimes int s = splimp(); 1196df8bae1dSRodney W. Grimes 1197b30a244cSJeffrey Hsu IFNET_RLOCK(); 1198fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 1199df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 1200df8bae1dSRodney W. Grimes continue; 1201df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 12024a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 1203df8bae1dSRodney W. Grimes } 1204b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1205df8bae1dSRodney W. Grimes splx(s); 1206df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 1207df8bae1dSRodney W. Grimes } 1208df8bae1dSRodney W. Grimes 1209df8bae1dSRodney W. Grimes /* 1210df8bae1dSRodney W. Grimes * Map interface name to 1211df8bae1dSRodney W. Grimes * interface structure pointer. 1212df8bae1dSRodney W. Grimes */ 1213df8bae1dSRodney W. Grimes struct ifnet * 121430aad87dSBrooks Davis ifunit(const char *name) 1215df8bae1dSRodney W. Grimes { 12168b7805e4SBoris Popov struct ifnet *ifp; 1217df8bae1dSRodney W. Grimes 1218b30a244cSJeffrey Hsu IFNET_RLOCK(); 1219fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 122036c19a57SBrooks Davis if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0) 1221df8bae1dSRodney W. Grimes break; 1222df8bae1dSRodney W. Grimes } 1223b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1224df8bae1dSRodney W. Grimes return (ifp); 1225df8bae1dSRodney W. Grimes } 1226df8bae1dSRodney W. Grimes 122782cd038dSYoshinobu Inoue /* 1228f13ad206SJonathan Lemon * Hardware specific interface ioctls. 1229df8bae1dSRodney W. Grimes */ 1230f13ad206SJonathan Lemon static int 1231f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) 1232df8bae1dSRodney W. Grimes { 1233f13ad206SJonathan Lemon struct ifreq *ifr; 1234413dd0baSPoul-Henning Kamp struct ifstat *ifs; 1235f13ad206SJonathan Lemon int error = 0; 1236292ee7beSRobert Watson int new_flags, temp_flags; 123736c19a57SBrooks Davis size_t namelen, onamelen; 123836c19a57SBrooks Davis char new_name[IFNAMSIZ]; 123936c19a57SBrooks Davis struct ifaddr *ifa; 124036c19a57SBrooks Davis struct sockaddr_dl *sdl; 1241df8bae1dSRodney W. Grimes 1242df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 124330aad87dSBrooks Davis switch (cmd) { 1244de593450SJonathan Lemon case SIOCGIFINDEX: 1245de593450SJonathan Lemon ifr->ifr_index = ifp->if_index; 1246de593450SJonathan Lemon break; 1247de593450SJonathan Lemon 1248df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 1249292ee7beSRobert Watson temp_flags = ifp->if_flags | ifp->if_drv_flags; 1250292ee7beSRobert Watson ifr->ifr_flags = temp_flags & 0xffff; 1251292ee7beSRobert Watson ifr->ifr_flagshigh = temp_flags >> 16; 1252df8bae1dSRodney W. Grimes break; 1253df8bae1dSRodney W. Grimes 1254016da741SJonathan Lemon case SIOCGIFCAP: 1255016da741SJonathan Lemon ifr->ifr_reqcap = ifp->if_capabilities; 1256016da741SJonathan Lemon ifr->ifr_curcap = ifp->if_capenable; 1257016da741SJonathan Lemon break; 1258016da741SJonathan Lemon 12598f293a63SRobert Watson #ifdef MAC 12608f293a63SRobert Watson case SIOCGIFMAC: 126131566c96SJohn Baldwin error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp); 12628f293a63SRobert Watson break; 12638f293a63SRobert Watson #endif 12648f293a63SRobert Watson 1265df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 1266df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 1267df8bae1dSRodney W. Grimes break; 1268df8bae1dSRodney W. Grimes 1269a7028af7SDavid Greenman case SIOCGIFMTU: 1270a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 1271a7028af7SDavid Greenman break; 1272a7028af7SDavid Greenman 1273074c4a4eSGarrett Wollman case SIOCGIFPHYS: 1274074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 1275074c4a4eSGarrett Wollman break; 1276074c4a4eSGarrett Wollman 1277df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 127844731cabSJohn Baldwin error = suser(td); 12799448326fSPoul-Henning Kamp if (error) 1280df8bae1dSRodney W. Grimes return (error); 1281292ee7beSRobert Watson /* 1282292ee7beSRobert Watson * Currently, no driver owned flags pass the IFF_CANTCHANGE 1283292ee7beSRobert Watson * check, so we don't need special handling here yet. 1284292ee7beSRobert Watson */ 128562f76486SMaxim Sobolev new_flags = (ifr->ifr_flags & 0xffff) | 128662f76486SMaxim Sobolev (ifr->ifr_flagshigh << 16); 1287cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 1288cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 12892f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 129062f76486SMaxim Sobolev (new_flags & IFF_UP) == 0) { 1291df8bae1dSRodney W. Grimes int s = splimp(); 1292df8bae1dSRodney W. Grimes if_down(ifp); 1293df8bae1dSRodney W. Grimes splx(s); 129462f76486SMaxim Sobolev } else if (new_flags & IFF_UP && 1295cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 1296df8bae1dSRodney W. Grimes int s = splimp(); 1297df8bae1dSRodney W. Grimes if_up(ifp); 1298df8bae1dSRodney W. Grimes splx(s); 1299df8bae1dSRodney W. Grimes } 1300df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 130162f76486SMaxim Sobolev (new_flags &~ IFF_CANTCHANGE); 1302ffb079beSMaxim Sobolev if (new_flags & IFF_PPROMISC) { 1303ffb079beSMaxim Sobolev /* Permanently promiscuous mode requested */ 1304ffb079beSMaxim Sobolev ifp->if_flags |= IFF_PROMISC; 1305ffb079beSMaxim Sobolev } else if (ifp->if_pcount == 0) { 1306ffb079beSMaxim Sobolev ifp->if_flags &= ~IFF_PROMISC; 1307ffb079beSMaxim Sobolev } 130831302ebfSRobert Watson if (ifp->if_ioctl) { 130931302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1310df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 131131302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 131231302ebfSRobert Watson } 131398b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1314df8bae1dSRodney W. Grimes break; 1315df8bae1dSRodney W. Grimes 1316016da741SJonathan Lemon case SIOCSIFCAP: 131744731cabSJohn Baldwin error = suser(td); 1318016da741SJonathan Lemon if (error) 1319016da741SJonathan Lemon return (error); 1320efb4018bSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1321efb4018bSYaroslav Tykhiy return (EOPNOTSUPP); 1322016da741SJonathan Lemon if (ifr->ifr_reqcap & ~ifp->if_capabilities) 1323016da741SJonathan Lemon return (EINVAL); 132431302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1325efb4018bSYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, cmd, data); 132631302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1327efb4018bSYaroslav Tykhiy if (error == 0) 1328efb4018bSYaroslav Tykhiy getmicrotime(&ifp->if_lastchange); 1329016da741SJonathan Lemon break; 1330016da741SJonathan Lemon 13318f293a63SRobert Watson #ifdef MAC 13328f293a63SRobert Watson case SIOCSIFMAC: 133331566c96SJohn Baldwin error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp); 13348f293a63SRobert Watson break; 13358f293a63SRobert Watson #endif 13368f293a63SRobert Watson 133736c19a57SBrooks Davis case SIOCSIFNAME: 133836c19a57SBrooks Davis error = suser(td); 1339bc1470f1SBrooks Davis if (error != 0) 134036c19a57SBrooks Davis return (error); 134136c19a57SBrooks Davis error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL); 1342bc1470f1SBrooks Davis if (error != 0) 134336c19a57SBrooks Davis return (error); 1344bc1470f1SBrooks Davis if (new_name[0] == '\0') 1345bc1470f1SBrooks Davis return (EINVAL); 134636c19a57SBrooks Davis if (ifunit(new_name) != NULL) 134736c19a57SBrooks Davis return (EEXIST); 134836c19a57SBrooks Davis 134936c19a57SBrooks Davis /* Announce the departure of the interface. */ 135036c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 135152023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 135236c19a57SBrooks Davis 135371672bb6SBrooks Davis log(LOG_INFO, "%s: changing name to '%s'\n", 135471672bb6SBrooks Davis ifp->if_xname, new_name); 135571672bb6SBrooks Davis 135636c19a57SBrooks Davis strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); 13579b98ee2cSLuigi Rizzo ifa = ifaddr_byindex(ifp->if_index); 135836c19a57SBrooks Davis IFA_LOCK(ifa); 135936c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_addr; 136036c19a57SBrooks Davis namelen = strlen(new_name); 136136c19a57SBrooks Davis onamelen = sdl->sdl_nlen; 136236c19a57SBrooks Davis /* 136336c19a57SBrooks Davis * Move the address if needed. This is safe because we 136436c19a57SBrooks Davis * allocate space for a name of length IFNAMSIZ when we 136536c19a57SBrooks Davis * create this in if_attach(). 136636c19a57SBrooks Davis */ 136736c19a57SBrooks Davis if (namelen != onamelen) { 136836c19a57SBrooks Davis bcopy(sdl->sdl_data + onamelen, 136936c19a57SBrooks Davis sdl->sdl_data + namelen, sdl->sdl_alen); 137036c19a57SBrooks Davis } 137136c19a57SBrooks Davis bcopy(new_name, sdl->sdl_data, namelen); 137236c19a57SBrooks Davis sdl->sdl_nlen = namelen; 137336c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_netmask; 137436c19a57SBrooks Davis bzero(sdl->sdl_data, onamelen); 137536c19a57SBrooks Davis while (namelen != 0) 137636c19a57SBrooks Davis sdl->sdl_data[--namelen] = 0xff; 137736c19a57SBrooks Davis IFA_UNLOCK(ifa); 137836c19a57SBrooks Davis 137925a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 138036c19a57SBrooks Davis /* Announce the return of the interface. */ 138136c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 138236c19a57SBrooks Davis break; 138336c19a57SBrooks Davis 1384df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 138544731cabSJohn Baldwin error = suser(td); 13869448326fSPoul-Henning Kamp if (error) 1387df8bae1dSRodney W. Grimes return (error); 1388df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 138998b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1390df8bae1dSRodney W. Grimes break; 1391df8bae1dSRodney W. Grimes 1392074c4a4eSGarrett Wollman case SIOCSIFPHYS: 139344731cabSJohn Baldwin error = suser(td); 1394e39a0280SGary Palmer if (error) 1395913e410eSYaroslav Tykhiy return (error); 1396913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1397913e410eSYaroslav Tykhiy return (EOPNOTSUPP); 139831302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1399e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 140031302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1401e39a0280SGary Palmer if (error == 0) 140298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1403913e410eSYaroslav Tykhiy break; 1404074c4a4eSGarrett Wollman 1405a7028af7SDavid Greenman case SIOCSIFMTU: 140682cd038dSYoshinobu Inoue { 140782cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 140882cd038dSYoshinobu Inoue 140944731cabSJohn Baldwin error = suser(td); 14109448326fSPoul-Henning Kamp if (error) 1411a7028af7SDavid Greenman return (error); 1412aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 141375ee03cbSDavid Greenman return (EINVAL); 1414f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1415f13ad206SJonathan Lemon return (EOPNOTSUPP); 141631302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1417e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 141831302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 141948f71763SRuslan Ermilov if (error == 0) { 142098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 142148f71763SRuslan Ermilov rt_ifmsg(ifp); 142248f71763SRuslan Ermilov } 142382cd038dSYoshinobu Inoue /* 142482cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 142582cd038dSYoshinobu Inoue */ 142682cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 142782cd038dSYoshinobu Inoue #ifdef INET6 142882cd038dSYoshinobu Inoue nd6_setmtu(ifp); 142982cd038dSYoshinobu Inoue #endif 143082cd038dSYoshinobu Inoue } 1431f13ad206SJonathan Lemon break; 143282cd038dSYoshinobu Inoue } 1433a7028af7SDavid Greenman 1434df8bae1dSRodney W. Grimes case SIOCADDMULTI: 1435df8bae1dSRodney W. Grimes case SIOCDELMULTI: 143644731cabSJohn Baldwin error = suser(td); 14379448326fSPoul-Henning Kamp if (error) 1438df8bae1dSRodney W. Grimes return (error); 1439477180fbSGarrett Wollman 1440477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 1441477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 1442f13ad206SJonathan Lemon return (EOPNOTSUPP); 1443477180fbSGarrett Wollman 1444477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 1445477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 1446f13ad206SJonathan Lemon return (EINVAL); 1447477180fbSGarrett Wollman 1448477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 1449477180fbSGarrett Wollman struct ifmultiaddr *ifma; 1450477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1451477180fbSGarrett Wollman } else { 1452477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 1453477180fbSGarrett Wollman } 1454e39a0280SGary Palmer if (error == 0) 145598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1456f13ad206SJonathan Lemon break; 1457df8bae1dSRodney W. Grimes 145841b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 145941b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 146041b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 146141b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 146241b3e8e5SJun-ichiro itojun Hagino #endif 146333841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 1464a912e453SPeter Wemm case SIOCSIFMEDIA: 1465d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 146644731cabSJohn Baldwin error = suser(td); 1467a912e453SPeter Wemm if (error) 1468a912e453SPeter Wemm return (error); 1469f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1470a912e453SPeter Wemm return (EOPNOTSUPP); 147131302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1472a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 147331302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1474a912e453SPeter Wemm if (error == 0) 147598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1476f13ad206SJonathan Lemon break; 1477a912e453SPeter Wemm 1478413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 1479413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 1480413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 1481413dd0baSPoul-Henning Kamp 148233841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 148333841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 148433841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 1485a912e453SPeter Wemm case SIOCGIFMEDIA: 1486d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 1487913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1488a912e453SPeter Wemm return (EOPNOTSUPP); 148931302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1490f13ad206SJonathan Lemon error = (*ifp->if_ioctl)(ifp, cmd, data); 149131302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1492f13ad206SJonathan Lemon break; 1493a912e453SPeter Wemm 1494b106252cSBill Paul case SIOCSIFLLADDR: 149544731cabSJohn Baldwin error = suser(td); 1496b106252cSBill Paul if (error) 1497b106252cSBill Paul return (error); 1498f13ad206SJonathan Lemon error = if_setlladdr(ifp, 149966ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 1500f13ad206SJonathan Lemon break; 150166ce51ceSArchie Cobbs 1502df8bae1dSRodney W. Grimes default: 1503f13ad206SJonathan Lemon error = ENOIOCTL; 1504f13ad206SJonathan Lemon break; 1505f13ad206SJonathan Lemon } 1506f13ad206SJonathan Lemon return (error); 1507f13ad206SJonathan Lemon } 1508f13ad206SJonathan Lemon 1509f13ad206SJonathan Lemon /* 1510f13ad206SJonathan Lemon * Interface ioctls. 1511f13ad206SJonathan Lemon */ 1512f13ad206SJonathan Lemon int 151372fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) 1514f13ad206SJonathan Lemon { 1515f13ad206SJonathan Lemon struct ifnet *ifp; 1516f13ad206SJonathan Lemon struct ifreq *ifr; 1517f13ad206SJonathan Lemon int error; 151862f76486SMaxim Sobolev int oif_flags; 1519f13ad206SJonathan Lemon 1520f13ad206SJonathan Lemon switch (cmd) { 1521f13ad206SJonathan Lemon case SIOCGIFCONF: 1522f13ad206SJonathan Lemon case OSIOCGIFCONF: 1523f13ad206SJonathan Lemon return (ifconf(cmd, data)); 1524f13ad206SJonathan Lemon } 1525f13ad206SJonathan Lemon ifr = (struct ifreq *)data; 1526f13ad206SJonathan Lemon 1527f13ad206SJonathan Lemon switch (cmd) { 1528f13ad206SJonathan Lemon case SIOCIFCREATE: 1529f13ad206SJonathan Lemon case SIOCIFDESTROY: 153044731cabSJohn Baldwin if ((error = suser(td)) != 0) 1531f13ad206SJonathan Lemon return (error); 1532f13ad206SJonathan Lemon return ((cmd == SIOCIFCREATE) ? 1533f13ad206SJonathan Lemon if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 1534f13ad206SJonathan Lemon if_clone_destroy(ifr->ifr_name)); 1535f13ad206SJonathan Lemon 1536f13ad206SJonathan Lemon case SIOCIFGCLONERS: 1537f13ad206SJonathan Lemon return (if_clone_list((struct if_clonereq *)data)); 1538f13ad206SJonathan Lemon } 1539f13ad206SJonathan Lemon 1540f13ad206SJonathan Lemon ifp = ifunit(ifr->ifr_name); 1541f13ad206SJonathan Lemon if (ifp == 0) 1542f13ad206SJonathan Lemon return (ENXIO); 1543f13ad206SJonathan Lemon 1544f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 1545f13ad206SJonathan Lemon if (error != ENOIOCTL) 1546f13ad206SJonathan Lemon return (error); 1547f13ad206SJonathan Lemon 154882cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 1549df8bae1dSRodney W. Grimes if (so->so_proto == 0) 1550df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1551df8bae1dSRodney W. Grimes #ifndef COMPAT_43 155282cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 15532c37256eSGarrett Wollman data, 1554b40ce416SJulian Elischer ifp, td)); 1555df8bae1dSRodney W. Grimes #else 1556df8bae1dSRodney W. Grimes { 1557df8bae1dSRodney W. Grimes int ocmd = cmd; 1558df8bae1dSRodney W. Grimes 1559df8bae1dSRodney W. Grimes switch (cmd) { 1560df8bae1dSRodney W. Grimes 1561df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 1562df8bae1dSRodney W. Grimes case SIOCSIFADDR: 1563df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 1564df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 1565df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 1566df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 1567df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 1568df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1569df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1570df8bae1dSRodney W. Grimes } 1571df8bae1dSRodney W. Grimes #else 1572df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 1573df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1574df8bae1dSRodney W. Grimes #endif 1575df8bae1dSRodney W. Grimes break; 1576df8bae1dSRodney W. Grimes 1577df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1578df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 1579df8bae1dSRodney W. Grimes break; 1580df8bae1dSRodney W. Grimes 1581df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1582df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 1583df8bae1dSRodney W. Grimes break; 1584df8bae1dSRodney W. Grimes 1585df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1586df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 1587df8bae1dSRodney W. Grimes break; 1588df8bae1dSRodney W. Grimes 1589df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1590df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 1591df8bae1dSRodney W. Grimes } 15922c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 15932c37256eSGarrett Wollman cmd, 15942c37256eSGarrett Wollman data, 1595b40ce416SJulian Elischer ifp, td)); 1596df8bae1dSRodney W. Grimes switch (ocmd) { 1597df8bae1dSRodney W. Grimes 1598df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1599df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1600df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1601df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1602df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 160382cd038dSYoshinobu Inoue 160482cd038dSYoshinobu Inoue } 160582cd038dSYoshinobu Inoue } 160682cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 160782cd038dSYoshinobu Inoue 160882cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 160982cd038dSYoshinobu Inoue #ifdef INET6 161088ff5695SSUZUKI Shinsuke DELAY(100);/* XXX: temporary workaround for fxp issue*/ 161182cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 161282cd038dSYoshinobu Inoue int s = splimp(); 161382cd038dSYoshinobu Inoue in6_if_up(ifp); 161482cd038dSYoshinobu Inoue splx(s); 161582cd038dSYoshinobu Inoue } 161682cd038dSYoshinobu Inoue #endif 1617df8bae1dSRodney W. Grimes } 1618df8bae1dSRodney W. Grimes return (error); 1619df8bae1dSRodney W. Grimes } 1620df8bae1dSRodney W. Grimes 1621df8bae1dSRodney W. Grimes /* 1622292ee7beSRobert Watson * The code common to handling reference counted flags, 16231a3b6859SYaroslav Tykhiy * e.g., in ifpromisc() and if_allmulti(). 16241a3b6859SYaroslav Tykhiy * The "pflag" argument can specify a permanent mode flag, 16251a3b6859SYaroslav Tykhiy * such as IFF_PPROMISC for promiscuous mode; should be 0 if none. 1626292ee7beSRobert Watson * 1627292ee7beSRobert Watson * Only to be used on stack-owned flags, not driver-owned flags. 16281a3b6859SYaroslav Tykhiy */ 16291a3b6859SYaroslav Tykhiy static int 16301a3b6859SYaroslav Tykhiy if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch) 16311a3b6859SYaroslav Tykhiy { 16321a3b6859SYaroslav Tykhiy struct ifreq ifr; 16331a3b6859SYaroslav Tykhiy int error; 16341a3b6859SYaroslav Tykhiy int oldflags, oldcount; 16351a3b6859SYaroslav Tykhiy 1636292ee7beSRobert Watson KASSERT((flag & (IFF_DRV_OACTIVE|IFF_DRV_RUNNING)) == 0, 1637292ee7beSRobert Watson ("if_setflag: setting driver-ownded flag %d", flag)); 1638292ee7beSRobert Watson 16391a3b6859SYaroslav Tykhiy /* Sanity checks to catch programming errors */ 16401a3b6859SYaroslav Tykhiy if (onswitch) { 16411a3b6859SYaroslav Tykhiy if (*refcount < 0) { 16421a3b6859SYaroslav Tykhiy if_printf(ifp, 16431a3b6859SYaroslav Tykhiy "refusing to increment negative refcount %d " 16441a3b6859SYaroslav Tykhiy "for interface flag %d\n", *refcount, flag); 16451a3b6859SYaroslav Tykhiy return (EINVAL); 16461a3b6859SYaroslav Tykhiy } 16471a3b6859SYaroslav Tykhiy } else { 16481a3b6859SYaroslav Tykhiy if (*refcount <= 0) { 16491a3b6859SYaroslav Tykhiy if_printf(ifp, 16501a3b6859SYaroslav Tykhiy "refusing to decrement non-positive refcount %d" 16511a3b6859SYaroslav Tykhiy "for interface flag %d\n", *refcount, flag); 16521a3b6859SYaroslav Tykhiy return (EINVAL); 16531a3b6859SYaroslav Tykhiy } 16541a3b6859SYaroslav Tykhiy } 16551a3b6859SYaroslav Tykhiy 16561a3b6859SYaroslav Tykhiy /* In case this mode is permanent, just touch refcount */ 16571a3b6859SYaroslav Tykhiy if (ifp->if_flags & pflag) { 16581a3b6859SYaroslav Tykhiy *refcount += onswitch ? 1 : -1; 16591a3b6859SYaroslav Tykhiy return (0); 16601a3b6859SYaroslav Tykhiy } 16611a3b6859SYaroslav Tykhiy 16621a3b6859SYaroslav Tykhiy /* Save ifnet parameters for if_ioctl() may fail */ 16631a3b6859SYaroslav Tykhiy oldcount = *refcount; 16641a3b6859SYaroslav Tykhiy oldflags = ifp->if_flags; 16651a3b6859SYaroslav Tykhiy 16661a3b6859SYaroslav Tykhiy /* 16671a3b6859SYaroslav Tykhiy * See if we aren't the only and touching refcount is enough. 16681a3b6859SYaroslav Tykhiy * Actually toggle interface flag if we are the first or last. 16691a3b6859SYaroslav Tykhiy */ 16701a3b6859SYaroslav Tykhiy if (onswitch) { 16711a3b6859SYaroslav Tykhiy if ((*refcount)++) 16721a3b6859SYaroslav Tykhiy return (0); 16731a3b6859SYaroslav Tykhiy ifp->if_flags |= flag; 16741a3b6859SYaroslav Tykhiy } else { 16751a3b6859SYaroslav Tykhiy if (--(*refcount)) 16761a3b6859SYaroslav Tykhiy return (0); 16771a3b6859SYaroslav Tykhiy ifp->if_flags &= ~flag; 16781a3b6859SYaroslav Tykhiy } 16791a3b6859SYaroslav Tykhiy 16801a3b6859SYaroslav Tykhiy /* Call down the driver since we've changed interface flags */ 16811a3b6859SYaroslav Tykhiy if (ifp->if_ioctl == NULL) { 16821a3b6859SYaroslav Tykhiy error = EOPNOTSUPP; 16831a3b6859SYaroslav Tykhiy goto recover; 16841a3b6859SYaroslav Tykhiy } 16851a3b6859SYaroslav Tykhiy ifr.ifr_flags = ifp->if_flags & 0xffff; 16861a3b6859SYaroslav Tykhiy ifr.ifr_flagshigh = ifp->if_flags >> 16; 16871a3b6859SYaroslav Tykhiy IFF_LOCKGIANT(ifp); 16881a3b6859SYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 16891a3b6859SYaroslav Tykhiy IFF_UNLOCKGIANT(ifp); 16901a3b6859SYaroslav Tykhiy if (error) 16911a3b6859SYaroslav Tykhiy goto recover; 16921a3b6859SYaroslav Tykhiy /* Notify userland that interface flags have changed */ 16931a3b6859SYaroslav Tykhiy rt_ifmsg(ifp); 16941a3b6859SYaroslav Tykhiy return (0); 16951a3b6859SYaroslav Tykhiy 16961a3b6859SYaroslav Tykhiy recover: 16971a3b6859SYaroslav Tykhiy /* Recover after driver error */ 16981a3b6859SYaroslav Tykhiy *refcount = oldcount; 16991a3b6859SYaroslav Tykhiy ifp->if_flags = oldflags; 17001a3b6859SYaroslav Tykhiy return (error); 17011a3b6859SYaroslav Tykhiy } 17021a3b6859SYaroslav Tykhiy 17031a3b6859SYaroslav Tykhiy /* 1704963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 1705963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 1706963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 1707963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 1708963e4c2aSGarrett Wollman */ 1709963e4c2aSGarrett Wollman int 171072fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch) 1711963e4c2aSGarrett Wollman { 17124a26224cSGarrett Wollman int error; 17131a3b6859SYaroslav Tykhiy int oldflags = ifp->if_flags; 1714963e4c2aSGarrett Wollman 17151a3b6859SYaroslav Tykhiy error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC, 17161a3b6859SYaroslav Tykhiy &ifp->if_pcount, pswitch); 17171a3b6859SYaroslav Tykhiy /* If promiscuous mode status has changed, log a message */ 17181a3b6859SYaroslav Tykhiy if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC)) 17199bf40edeSBrooks Davis log(LOG_INFO, "%s: promiscuous mode %s\n", 17209bf40edeSBrooks Davis ifp->if_xname, 17214f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 17221a3b6859SYaroslav Tykhiy return (error); 1723963e4c2aSGarrett Wollman } 1724963e4c2aSGarrett Wollman 1725963e4c2aSGarrett Wollman /* 1726df8bae1dSRodney W. Grimes * Return interface configuration 1727df8bae1dSRodney W. Grimes * of system. List may be used 1728df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 1729df8bae1dSRodney W. Grimes * other information. 1730df8bae1dSRodney W. Grimes */ 1731df8bae1dSRodney W. Grimes /*ARGSUSED*/ 17323bda9f9bSPoul-Henning Kamp static int 173372fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data) 1734df8bae1dSRodney W. Grimes { 17350b59d917SJonathan Lemon struct ifconf *ifc = (struct ifconf *)data; 17360b59d917SJonathan Lemon struct ifnet *ifp; 17370b59d917SJonathan Lemon struct ifaddr *ifa; 17384dcf2bbbSBrooks Davis struct ifreq ifr; 17394dcf2bbbSBrooks Davis struct sbuf *sb; 17404dcf2bbbSBrooks Davis int error, full = 0, valid_len, max_len; 1741df8bae1dSRodney W. Grimes 17424dcf2bbbSBrooks Davis /* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */ 17434dcf2bbbSBrooks Davis max_len = MAXPHYS - 1; 17444dcf2bbbSBrooks Davis 1745b0b4b28bSXin LI /* Prevent hostile input from being able to crash the system */ 1746b0b4b28bSXin LI if (ifc->ifc_len <= 0) 1747b0b4b28bSXin LI return (EINVAL); 1748b0b4b28bSXin LI 17494dcf2bbbSBrooks Davis again: 17504dcf2bbbSBrooks Davis if (ifc->ifc_len <= max_len) { 17514dcf2bbbSBrooks Davis max_len = ifc->ifc_len; 17524dcf2bbbSBrooks Davis full = 1; 17534dcf2bbbSBrooks Davis } 17544dcf2bbbSBrooks Davis sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN); 17554dcf2bbbSBrooks Davis max_len = 0; 17564dcf2bbbSBrooks Davis valid_len = 0; 17574dcf2bbbSBrooks Davis 1758b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep XXX */ 17590b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 17609bf40edeSBrooks Davis int addrs; 17612624cf89SGarrett Wollman 1762fbd24c5eSColin Percival /* 1763fbd24c5eSColin Percival * Zero the ifr_name buffer to make sure we don't 1764fbd24c5eSColin Percival * disclose the contents of the stack. 1765fbd24c5eSColin Percival */ 1766fbd24c5eSColin Percival memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name)); 1767fbd24c5eSColin Percival 17689bf40edeSBrooks Davis if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)) 17694dcf2bbbSBrooks Davis >= sizeof(ifr.ifr_name)) 17704dcf2bbbSBrooks Davis return (ENAMETOOLONG); 17712624cf89SGarrett Wollman 177275c13541SPoul-Henning Kamp addrs = 0; 17732defe5cdSJonathan Lemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 17742defe5cdSJonathan Lemon struct sockaddr *sa = ifa->ifa_addr; 17752defe5cdSJonathan Lemon 1776a854ed98SJohn Baldwin if (jailed(curthread->td_ucred) && 1777a854ed98SJohn Baldwin prison_if(curthread->td_ucred, sa)) 177875c13541SPoul-Henning Kamp continue; 177975c13541SPoul-Henning Kamp addrs++; 1780df8bae1dSRodney W. Grimes #ifdef COMPAT_43 1781df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 1782df8bae1dSRodney W. Grimes struct osockaddr *osa = 1783df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 1784df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1785df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 17864dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17874dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1788df8bae1dSRodney W. Grimes } else 1789df8bae1dSRodney W. Grimes #endif 1790df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 1791df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 17924dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 17934dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1794df8bae1dSRodney W. Grimes } else { 17954dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, 17964dcf2bbbSBrooks Davis offsetof(struct ifreq, ifr_addr)); 17974dcf2bbbSBrooks Davis max_len += offsetof(struct ifreq, ifr_addr); 17984dcf2bbbSBrooks Davis sbuf_bcat(sb, sa, sa->sa_len); 17994dcf2bbbSBrooks Davis max_len += sa->sa_len; 1800df8bae1dSRodney W. Grimes } 18014dcf2bbbSBrooks Davis 18024dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 18034dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 1804df8bae1dSRodney W. Grimes } 18054dcf2bbbSBrooks Davis if (addrs == 0) { 180675c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 18074dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 18084dcf2bbbSBrooks Davis max_len += sizeof(ifr); 18094dcf2bbbSBrooks Davis 18104dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 18114dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 181275c13541SPoul-Henning Kamp } 1813df8bae1dSRodney W. Grimes } 1814b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 18154dcf2bbbSBrooks Davis 18164dcf2bbbSBrooks Davis /* 18174dcf2bbbSBrooks Davis * If we didn't allocate enough space (uncommon), try again. If 18184dcf2bbbSBrooks Davis * we have already allocated as much space as we are allowed, 18194dcf2bbbSBrooks Davis * return what we've got. 18204dcf2bbbSBrooks Davis */ 18214dcf2bbbSBrooks Davis if (valid_len != max_len && !full) { 18224dcf2bbbSBrooks Davis sbuf_delete(sb); 18234dcf2bbbSBrooks Davis goto again; 18244dcf2bbbSBrooks Davis } 18254dcf2bbbSBrooks Davis 18264dcf2bbbSBrooks Davis ifc->ifc_len = valid_len; 18275ed8cedcSBrian Feldman sbuf_finish(sb); 18284dcf2bbbSBrooks Davis error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len); 18294dcf2bbbSBrooks Davis sbuf_delete(sb); 1830df8bae1dSRodney W. Grimes return (error); 1831df8bae1dSRodney W. Grimes } 1832df8bae1dSRodney W. Grimes 18331158dfb7SGarrett Wollman /* 18348b25904eSGleb Smirnoff * Just like ifpromisc(), but for all-multicast-reception mode. 18351158dfb7SGarrett Wollman */ 18361158dfb7SGarrett Wollman int 183772fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch) 18381158dfb7SGarrett Wollman { 18391158dfb7SGarrett Wollman 18401a3b6859SYaroslav Tykhiy return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch)); 18411158dfb7SGarrett Wollman } 18421158dfb7SGarrett Wollman 1843c3b31afdSRobert Watson static struct ifmultiaddr * 1844c3b31afdSRobert Watson if_findmulti(struct ifnet *ifp, struct sockaddr *sa) 18451158dfb7SGarrett Wollman { 18461158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 18471158dfb7SGarrett Wollman 1848c3b31afdSRobert Watson IF_ADDR_LOCK_ASSERT(ifp); 1849c3b31afdSRobert Watson 18506817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1851c3b31afdSRobert Watson if (sa_equal(ifma->ifma_addr, sa)) 1852c3b31afdSRobert Watson break; 18531158dfb7SGarrett Wollman } 1854c3b31afdSRobert Watson 1855c3b31afdSRobert Watson return ifma; 185657af7922SJulian Elischer } 18571158dfb7SGarrett Wollman 18581158dfb7SGarrett Wollman /* 1859c3b31afdSRobert Watson * Allocate a new ifmultiaddr and initialize based on passed arguments. We 1860c3b31afdSRobert Watson * make copies of passed sockaddrs. The ifmultiaddr will not be added to 1861c3b31afdSRobert Watson * the ifnet multicast address list here, so the caller must do that and 1862c3b31afdSRobert Watson * other setup work (such as notifying the device driver). The reference 1863c3b31afdSRobert Watson * count is initialized to 1. 18641158dfb7SGarrett Wollman */ 1865c3b31afdSRobert Watson static struct ifmultiaddr * 1866c3b31afdSRobert Watson if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa, 1867c3b31afdSRobert Watson int mflags) 1868c3b31afdSRobert Watson { 1869c3b31afdSRobert Watson struct ifmultiaddr *ifma; 1870c3b31afdSRobert Watson struct sockaddr *dupsa; 1871c3b31afdSRobert Watson 1872c3b31afdSRobert Watson MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, mflags | 1873c3b31afdSRobert Watson M_ZERO); 1874c3b31afdSRobert Watson if (ifma == NULL) 1875c3b31afdSRobert Watson return (NULL); 1876c3b31afdSRobert Watson 1877c3b31afdSRobert Watson MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, mflags); 1878c3b31afdSRobert Watson if (dupsa == NULL) { 1879c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1880c3b31afdSRobert Watson return (NULL); 18811158dfb7SGarrett Wollman } 18821158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 18831158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 1884c3b31afdSRobert Watson 18851158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 18861158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1887d4d22970SGleb Smirnoff ifma->ifma_protospec = NULL; 1888c3b31afdSRobert Watson 1889c3b31afdSRobert Watson if (llsa == NULL) { 1890c3b31afdSRobert Watson ifma->ifma_lladdr = NULL; 1891c3b31afdSRobert Watson return (ifma); 1892c3b31afdSRobert Watson } 1893c3b31afdSRobert Watson 1894c3b31afdSRobert Watson MALLOC(dupsa, struct sockaddr *, llsa->sa_len, M_IFMADDR, mflags); 1895c3b31afdSRobert Watson if (dupsa == NULL) { 1896c3b31afdSRobert Watson FREE(ifma->ifma_addr, M_IFMADDR); 1897c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1898c3b31afdSRobert Watson return (NULL); 1899c3b31afdSRobert Watson } 1900c3b31afdSRobert Watson bcopy(llsa, dupsa, llsa->sa_len); 1901c3b31afdSRobert Watson ifma->ifma_lladdr = dupsa; 1902c3b31afdSRobert Watson 1903c3b31afdSRobert Watson return (ifma); 1904c3b31afdSRobert Watson } 1905373f88edSGarrett Wollman 19061158dfb7SGarrett Wollman /* 1907c3b31afdSRobert Watson * if_freemulti: free ifmultiaddr structure and possibly attached related 1908c3b31afdSRobert Watson * addresses. The caller is responsible for implementing reference 1909c3b31afdSRobert Watson * counting, notifying the driver, handling routing messages, and releasing 1910c3b31afdSRobert Watson * any dependent link layer state. 19111158dfb7SGarrett Wollman */ 1912c3b31afdSRobert Watson static void 1913c3b31afdSRobert Watson if_freemulti(struct ifmultiaddr *ifma) 1914c3b31afdSRobert Watson { 1915c3b31afdSRobert Watson 1916c3b31afdSRobert Watson KASSERT(ifma->ifma_refcount == 1, ("if_freemulti: refcount %d", 1917c3b31afdSRobert Watson ifma->ifma_refcount)); 1918c3b31afdSRobert Watson KASSERT(ifma->ifma_protospec == NULL, 1919c3b31afdSRobert Watson ("if_freemulti: protospec not NULL")); 1920c3b31afdSRobert Watson 1921c3b31afdSRobert Watson if (ifma->ifma_lladdr != NULL) 1922c3b31afdSRobert Watson FREE(ifma->ifma_lladdr, M_IFMADDR); 1923c3b31afdSRobert Watson FREE(ifma->ifma_addr, M_IFMADDR); 1924c3b31afdSRobert Watson FREE(ifma, M_IFMADDR); 1925c3b31afdSRobert Watson } 1926c3b31afdSRobert Watson 1927c3b31afdSRobert Watson /* 1928c3b31afdSRobert Watson * Register an additional multicast address with a network interface. 1929c3b31afdSRobert Watson * 1930c3b31afdSRobert Watson * - If the address is already present, bump the reference count on the 1931c3b31afdSRobert Watson * address and return. 1932c3b31afdSRobert Watson * - If the address is not link-layer, look up a link layer address. 1933c3b31afdSRobert Watson * - Allocate address structures for one or both addresses, and attach to the 1934c3b31afdSRobert Watson * multicast address list on the interface. If automatically adding a link 1935c3b31afdSRobert Watson * layer address, the protocol address will own a reference to the link 1936c3b31afdSRobert Watson * layer address, to be freed when it is freed. 1937c3b31afdSRobert Watson * - Notify the network device driver of an addition to the multicast address 1938c3b31afdSRobert Watson * list. 1939c3b31afdSRobert Watson * 1940c3b31afdSRobert Watson * 'sa' points to caller-owned memory with the desired multicast address. 1941c3b31afdSRobert Watson * 1942c3b31afdSRobert Watson * 'retifma' will be used to return a pointer to the resulting multicast 1943c3b31afdSRobert Watson * address reference, if desired. 1944c3b31afdSRobert Watson */ 1945c3b31afdSRobert Watson int 1946c3b31afdSRobert Watson if_addmulti(struct ifnet *ifp, struct sockaddr *sa, 1947c3b31afdSRobert Watson struct ifmultiaddr **retifma) 1948c3b31afdSRobert Watson { 1949c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 1950c3b31afdSRobert Watson struct sockaddr *llsa; 1951c3b31afdSRobert Watson int error; 1952c3b31afdSRobert Watson 1953c3b31afdSRobert Watson /* 1954c3b31afdSRobert Watson * If the address is already present, return a new reference to it; 1955c3b31afdSRobert Watson * otherwise, allocate storage and set up a new address. 1956c3b31afdSRobert Watson */ 1957c3b31afdSRobert Watson IF_ADDR_LOCK(ifp); 1958c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 1959c3b31afdSRobert Watson if (ifma != NULL) { 1960c3b31afdSRobert Watson ifma->ifma_refcount++; 1961c3b31afdSRobert Watson if (retifma != NULL) 1962c3b31afdSRobert Watson *retifma = ifma; 1963c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 1964c3b31afdSRobert Watson return (0); 1965c3b31afdSRobert Watson } 1966c3b31afdSRobert Watson 1967c3b31afdSRobert Watson /* 1968c3b31afdSRobert Watson * The address isn't already present; resolve the protocol address 1969c3b31afdSRobert Watson * into a link layer address, and then look that up, bump its 1970c3b31afdSRobert Watson * refcount or allocate an ifma for that also. If 'llsa' was 1971c3b31afdSRobert Watson * returned, we will need to free it later. 1972c3b31afdSRobert Watson */ 1973c3b31afdSRobert Watson llsa = NULL; 1974c3b31afdSRobert Watson ll_ifma = NULL; 1975c3b31afdSRobert Watson if (ifp->if_resolvemulti != NULL) { 1976c3b31afdSRobert Watson error = ifp->if_resolvemulti(ifp, &llsa, sa); 1977c3b31afdSRobert Watson if (error) 1978c3b31afdSRobert Watson goto unlock_out; 1979c3b31afdSRobert Watson } 1980c3b31afdSRobert Watson 1981c3b31afdSRobert Watson /* 1982c3b31afdSRobert Watson * Allocate the new address. Don't hook it up yet, as we may also 1983c3b31afdSRobert Watson * need to allocate a link layer multicast address. 1984c3b31afdSRobert Watson */ 1985c3b31afdSRobert Watson ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT); 1986c3b31afdSRobert Watson if (ifma == NULL) { 1987c3b31afdSRobert Watson error = ENOMEM; 1988c3b31afdSRobert Watson goto free_llsa_out; 1989c3b31afdSRobert Watson } 1990c3b31afdSRobert Watson 1991c3b31afdSRobert Watson /* 1992c3b31afdSRobert Watson * If a link layer address is found, we'll need to see if it's 1993c3b31afdSRobert Watson * already present in the address list, or allocate is as well. 1994c3b31afdSRobert Watson * When this block finishes, the link layer address will be on the 1995c3b31afdSRobert Watson * list. 1996c3b31afdSRobert Watson */ 1997c3b31afdSRobert Watson if (llsa != NULL) { 1998c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, llsa); 1999c3b31afdSRobert Watson if (ll_ifma == NULL) { 2000c3b31afdSRobert Watson ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT); 2001c3b31afdSRobert Watson if (ll_ifma == NULL) { 2002c3b31afdSRobert Watson if_freemulti(ifma); 2003c3b31afdSRobert Watson error = ENOMEM; 2004c3b31afdSRobert Watson goto free_llsa_out; 2005c3b31afdSRobert Watson } 2006c3b31afdSRobert Watson TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, 2007c3b31afdSRobert Watson ifma_link); 2008c3b31afdSRobert Watson } else 2009c3b31afdSRobert Watson ll_ifma->ifma_refcount++; 2010c3b31afdSRobert Watson } 2011c3b31afdSRobert Watson 2012c3b31afdSRobert Watson /* 2013c3b31afdSRobert Watson * We now have a new multicast address, ifma, and possibly a new or 2014c3b31afdSRobert Watson * referenced link layer address. Add the primary address to the 2015c3b31afdSRobert Watson * ifnet address list. 2016c3b31afdSRobert Watson */ 20176817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 2018c3b31afdSRobert Watson 201913990766SJonathan Mini if (retifma != NULL) 2020373f88edSGarrett Wollman *retifma = ifma; 20211158dfb7SGarrett Wollman 2022c3b31afdSRobert Watson /* 2023c3b31afdSRobert Watson * Must generate the message while holding the lock so that 'ifma' 2024c3b31afdSRobert Watson * pointer is still valid. 2025c3b31afdSRobert Watson * 2026c3b31afdSRobert Watson * XXXRW: How come we don't announce ll_ifma? 2027c3b31afdSRobert Watson */ 2028c3b31afdSRobert Watson rt_newmaddrmsg(RTM_NEWMADDR, ifma); 2029c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2030c3b31afdSRobert Watson 20311158dfb7SGarrett Wollman /* 20321158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 20331158dfb7SGarrett Wollman * interface to let them know about it. 20341158dfb7SGarrett Wollman */ 20352432c31cSRobert Watson if (ifp->if_ioctl != NULL) { 203631302ebfSRobert Watson IFF_LOCKGIANT(ifp); 20371a3b6859SYaroslav Tykhiy (void) (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0); 203831302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 20391a3b6859SYaroslav Tykhiy } 20401158dfb7SGarrett Wollman 2041c3b31afdSRobert Watson if (llsa != NULL) 2042c3b31afdSRobert Watson FREE(llsa, M_IFMADDR); 2043c3b31afdSRobert Watson 2044c3b31afdSRobert Watson return (0); 2045c3b31afdSRobert Watson 2046c3b31afdSRobert Watson free_llsa_out: 2047c3b31afdSRobert Watson if (llsa != NULL) 2048c3b31afdSRobert Watson FREE(llsa, M_IFMADDR); 2049c3b31afdSRobert Watson 2050c3b31afdSRobert Watson unlock_out: 2051c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2052c3b31afdSRobert Watson return (error); 20531158dfb7SGarrett Wollman } 20541158dfb7SGarrett Wollman 20551158dfb7SGarrett Wollman /* 20561158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 20571158dfb7SGarrett Wollman * if the request does not match an existing membership. 20581158dfb7SGarrett Wollman */ 20591158dfb7SGarrett Wollman int 206072fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa) 20611158dfb7SGarrett Wollman { 2062c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 20631158dfb7SGarrett Wollman 2064c3b31afdSRobert Watson IF_ADDR_LOCK(ifp); 2065c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 2066c3b31afdSRobert Watson if (ifma == NULL) { 2067c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 20681158dfb7SGarrett Wollman return ENOENT; 2069c3b31afdSRobert Watson } 20701158dfb7SGarrett Wollman 20711158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 20721158dfb7SGarrett Wollman ifma->ifma_refcount--; 2073c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 20741158dfb7SGarrett Wollman return 0; 20751158dfb7SGarrett Wollman } 20761158dfb7SGarrett Wollman 20771158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 2078c3b31afdSRobert Watson if (sa != NULL) 2079c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, sa); 2080c3b31afdSRobert Watson else 2081c3b31afdSRobert Watson ll_ifma = NULL; 2082c3b31afdSRobert Watson 2083c3b31afdSRobert Watson /* 2084c3b31afdSRobert Watson * XXXRW: How come we don't announce ll_ifma? 2085c3b31afdSRobert Watson */ 2086c3b31afdSRobert Watson rt_newmaddrmsg(RTM_DELMADDR, ifma); 2087c3b31afdSRobert Watson 20886817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 2089c3b31afdSRobert Watson if_freemulti(ifma); 2090c3b31afdSRobert Watson 2091c3b31afdSRobert Watson if (ll_ifma != NULL) { 2092c3b31afdSRobert Watson if (ll_ifma->ifma_refcount == 1) { 2093c3b31afdSRobert Watson TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifma_link); 2094c3b31afdSRobert Watson if_freemulti(ll_ifma); 2095c3b31afdSRobert Watson } else 2096c3b31afdSRobert Watson ll_ifma->ifma_refcount--; 2097c3b31afdSRobert Watson } 2098c3b31afdSRobert Watson IF_ADDR_UNLOCK(ifp); 2099c3b31afdSRobert Watson 2100ccb7cc8dSYaroslav Tykhiy /* 2101ccb7cc8dSYaroslav Tykhiy * Make sure the interface driver is notified 2102ccb7cc8dSYaroslav Tykhiy * in the case of a link layer mcast group being left. 2103ccb7cc8dSYaroslav Tykhiy */ 2104c3b31afdSRobert Watson if (ifp->if_ioctl) { 210531302ebfSRobert Watson IFF_LOCKGIANT(ifp); 21061a3b6859SYaroslav Tykhiy (void) (*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0); 210731302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 210831302ebfSRobert Watson } 21091158dfb7SGarrett Wollman 21101158dfb7SGarrett Wollman return 0; 21111158dfb7SGarrett Wollman } 21121158dfb7SGarrett Wollman 211366ce51ceSArchie Cobbs /* 211466ce51ceSArchie Cobbs * Set the link layer address on an interface. 211566ce51ceSArchie Cobbs * 211666ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 211766ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 211866ce51ceSArchie Cobbs */ 211966ce51ceSArchie Cobbs int 212066ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 212166ce51ceSArchie Cobbs { 212266ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 212366ce51ceSArchie Cobbs struct ifaddr *ifa; 2124d637e989SPeter Wemm struct ifreq ifr; 212566ce51ceSArchie Cobbs 2126f9132cebSJonathan Lemon ifa = ifaddr_byindex(ifp->if_index); 212766ce51ceSArchie Cobbs if (ifa == NULL) 212866ce51ceSArchie Cobbs return (EINVAL); 212966ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 213066ce51ceSArchie Cobbs if (sdl == NULL) 213166ce51ceSArchie Cobbs return (EINVAL); 213266ce51ceSArchie Cobbs if (len != sdl->sdl_alen) /* don't allow length to change */ 213366ce51ceSArchie Cobbs return (EINVAL); 213466ce51ceSArchie Cobbs switch (ifp->if_type) { 213566ce51ceSArchie Cobbs case IFT_ETHER: /* these types use struct arpcom */ 213666ce51ceSArchie Cobbs case IFT_FDDI: 213766ce51ceSArchie Cobbs case IFT_XETHER: 213866ce51ceSArchie Cobbs case IFT_ISO88025: 2139b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 21408f867517SAndrew Thompson case IFT_BRIDGE: 2141fc74a9f9SBrooks Davis bcopy(lladdr, IFP2ENADDR(ifp), len); 21429046571fSLuigi Rizzo /* 21439046571fSLuigi Rizzo * XXX We also need to store the lladdr in LLADDR(sdl), 21449046571fSLuigi Rizzo * which is done below. This is a pain because we must 21459046571fSLuigi Rizzo * remember to keep the info in sync. 21469046571fSLuigi Rizzo */ 21476cdcc159SMax Khon /* FALLTHROUGH */ 21486cdcc159SMax Khon case IFT_ARCNET: 214966ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 215066ce51ceSArchie Cobbs break; 215166ce51ceSArchie Cobbs default: 215266ce51ceSArchie Cobbs return (ENODEV); 215366ce51ceSArchie Cobbs } 215466ce51ceSArchie Cobbs /* 215566ce51ceSArchie Cobbs * If the interface is already up, we need 215666ce51ceSArchie Cobbs * to re-init it in order to reprogram its 215766ce51ceSArchie Cobbs * address filter. 215866ce51ceSArchie Cobbs */ 215966ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 21601a3b6859SYaroslav Tykhiy if (ifp->if_ioctl) { 216131302ebfSRobert Watson IFF_LOCKGIANT(ifp); 216266ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 216362f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 216462f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 2165ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 216666ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 216762f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 216862f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 2169ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 217031302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 21711a3b6859SYaroslav Tykhiy } 2172b2c08f43SLuigi Rizzo #ifdef INET 2173b2c08f43SLuigi Rizzo /* 2174b2c08f43SLuigi Rizzo * Also send gratuitous ARPs to notify other nodes about 2175b2c08f43SLuigi Rizzo * the address change. 2176b2c08f43SLuigi Rizzo */ 2177b2c08f43SLuigi Rizzo TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2178b2c08f43SLuigi Rizzo if (ifa->ifa_addr != NULL && 2179b2c08f43SLuigi Rizzo ifa->ifa_addr->sa_family == AF_INET) 2180c0933269SPeter Wemm arp_ifinit(ifp, ifa); 2181b2c08f43SLuigi Rizzo } 2182b2c08f43SLuigi Rizzo #endif 218366ce51ceSArchie Cobbs } 218466ce51ceSArchie Cobbs return (0); 218566ce51ceSArchie Cobbs } 218666ce51ceSArchie Cobbs 21879bf40edeSBrooks Davis /* 21889bf40edeSBrooks Davis * The name argument must be a pointer to storage which will last as 21899bf40edeSBrooks Davis * long as the interface does. For physical devices, the result of 21909bf40edeSBrooks Davis * device_get_name(dev) is a good choice and for pseudo-devices a 21919bf40edeSBrooks Davis * static string works well. 21929bf40edeSBrooks Davis */ 21939bf40edeSBrooks Davis void 21949bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit) 21959bf40edeSBrooks Davis { 21969bf40edeSBrooks Davis ifp->if_dname = name; 21979bf40edeSBrooks Davis ifp->if_dunit = unit; 21989bf40edeSBrooks Davis if (unit != IF_DUNIT_NONE) 21999bf40edeSBrooks Davis snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit); 22009bf40edeSBrooks Davis else 22019bf40edeSBrooks Davis strlcpy(ifp->if_xname, name, IFNAMSIZ); 22029bf40edeSBrooks Davis } 22039bf40edeSBrooks Davis 2204fa882e87SBrooks Davis int 2205fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...) 2206fa882e87SBrooks Davis { 2207fa882e87SBrooks Davis va_list ap; 2208fa882e87SBrooks Davis int retval; 2209fa882e87SBrooks Davis 22109bf40edeSBrooks Davis retval = printf("%s: ", ifp->if_xname); 2211fa882e87SBrooks Davis va_start(ap, fmt); 2212fa882e87SBrooks Davis retval += vprintf(fmt, ap); 2213fa882e87SBrooks Davis va_end(ap); 2214fa882e87SBrooks Davis return (retval); 2215fa882e87SBrooks Davis } 2216fa882e87SBrooks Davis 2217af5e59bfSRobert Watson /* 2218af5e59bfSRobert Watson * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot 2219af5e59bfSRobert Watson * be called without Giant. However, we often can't acquire the Giant lock 2220af5e59bfSRobert Watson * at those points; instead, we run it via a task queue that holds Giant via 2221af5e59bfSRobert Watson * if_start_deferred. 2222af5e59bfSRobert Watson * 2223af5e59bfSRobert Watson * XXXRW: We need to make sure that the ifnet isn't fully detached until any 2224af5e59bfSRobert Watson * outstanding if_start_deferred() tasks that will run after the free. This 2225af5e59bfSRobert Watson * probably means waiting in if_detach(). 2226af5e59bfSRobert Watson */ 2227af5e59bfSRobert Watson void 2228af5e59bfSRobert Watson if_start(struct ifnet *ifp) 2229af5e59bfSRobert Watson { 2230af5e59bfSRobert Watson 2231af5e59bfSRobert Watson NET_ASSERT_GIANT(); 2232af5e59bfSRobert Watson 2233af5e59bfSRobert Watson if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) { 2234af5e59bfSRobert Watson if (mtx_owned(&Giant)) 2235af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2236af5e59bfSRobert Watson else 2237af5e59bfSRobert Watson taskqueue_enqueue(taskqueue_swi_giant, 2238af5e59bfSRobert Watson &ifp->if_starttask); 2239af5e59bfSRobert Watson } else 2240af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2241af5e59bfSRobert Watson } 2242af5e59bfSRobert Watson 2243af5e59bfSRobert Watson static void 2244af5e59bfSRobert Watson if_start_deferred(void *context, int pending) 2245af5e59bfSRobert Watson { 2246af5e59bfSRobert Watson struct ifnet *ifp; 2247af5e59bfSRobert Watson 2248af5e59bfSRobert Watson /* 2249af5e59bfSRobert Watson * This code must be entered with Giant, and should never run if 2250af5e59bfSRobert Watson * we're not running with debug.mpsafenet. 2251af5e59bfSRobert Watson */ 2252af5e59bfSRobert Watson KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet")); 2253af5e59bfSRobert Watson GIANT_REQUIRED; 2254af5e59bfSRobert Watson 2255fc74a9f9SBrooks Davis ifp = context; 2256af5e59bfSRobert Watson (ifp->if_start)(ifp); 2257af5e59bfSRobert Watson } 2258af5e59bfSRobert Watson 22590b762445SRobert Watson int 22600b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) 22610b762445SRobert Watson { 22620b762445SRobert Watson int active = 0; 22630b762445SRobert Watson 22640b762445SRobert Watson IF_LOCK(ifq); 22650b762445SRobert Watson if (_IF_QFULL(ifq)) { 22660b762445SRobert Watson _IF_DROP(ifq); 22670b762445SRobert Watson IF_UNLOCK(ifq); 22680b762445SRobert Watson m_freem(m); 22690b762445SRobert Watson return (0); 22700b762445SRobert Watson } 22710b762445SRobert Watson if (ifp != NULL) { 22720b762445SRobert Watson ifp->if_obytes += m->m_pkthdr.len + adjust; 22730b762445SRobert Watson if (m->m_flags & (M_BCAST|M_MCAST)) 22740b762445SRobert Watson ifp->if_omcasts++; 2275292ee7beSRobert Watson active = ifp->if_drv_flags & IFF_DRV_OACTIVE; 22760b762445SRobert Watson } 22770b762445SRobert Watson _IF_ENQUEUE(ifq, m); 22780b762445SRobert Watson IF_UNLOCK(ifq); 22790b762445SRobert Watson if (ifp != NULL && !active) 22800b762445SRobert Watson if_start(ifp); 22810b762445SRobert Watson return (1); 22820b762445SRobert Watson } 2283fc74a9f9SBrooks Davis 2284fc74a9f9SBrooks Davis void 2285fc74a9f9SBrooks Davis if_register_com_alloc(u_char type, 2286fc74a9f9SBrooks Davis if_com_alloc_t *a, if_com_free_t *f) 2287fc74a9f9SBrooks Davis { 2288fc74a9f9SBrooks Davis 2289fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 2290fc74a9f9SBrooks Davis ("if_register_com_alloc: %d already registered", type)); 2291fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 2292fc74a9f9SBrooks Davis ("if_register_com_alloc: %d free already registered", type)); 2293fc74a9f9SBrooks Davis 2294fc74a9f9SBrooks Davis if_com_alloc[type] = a; 2295fc74a9f9SBrooks Davis if_com_free[type] = f; 2296fc74a9f9SBrooks Davis } 2297fc74a9f9SBrooks Davis 2298fc74a9f9SBrooks Davis void 2299fc74a9f9SBrooks Davis if_deregister_com_alloc(u_char type) 2300fc74a9f9SBrooks Davis { 2301fc74a9f9SBrooks Davis 2302fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 2303fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d not registered", type)); 2304fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 2305fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d free not registered", type)); 2306fc74a9f9SBrooks Davis if_com_alloc[type] = NULL; 2307fc74a9f9SBrooks Davis if_com_free[type] = NULL; 2308fc74a9f9SBrooks Davis } 2309