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); 1100b59d917SJonathan Lemon static void if_slowtimo(void *); 1118614fb12SMax Laier static void if_unroute(struct ifnet *, int flag, int fam); 1128071913dSRuslan Ermilov static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); 1130b59d917SJonathan Lemon static int if_rtdel(struct radix_node *, void *); 114f13ad206SJonathan Lemon static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *); 115af5e59bfSRobert Watson static void if_start_deferred(void *context, int pending); 11668a3482fSGleb Smirnoff static void do_link_state_change(void *, int); 11782cd038dSYoshinobu Inoue #ifdef INET6 11882cd038dSYoshinobu Inoue /* 11982cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 12082cd038dSYoshinobu Inoue * should be more generalized? 12182cd038dSYoshinobu Inoue */ 122929ddbbbSAlfred Perlstein extern void nd6_setmtu(struct ifnet *); 12382cd038dSYoshinobu Inoue #endif 12482cd038dSYoshinobu Inoue 1250b59d917SJonathan Lemon int if_index = 0; 126f9132cebSJonathan Lemon struct ifindex_entry *ifindex_table = NULL; 1270b59d917SJonathan Lemon int ifqmaxlen = IFQ_MAXLEN; 1280b59d917SJonathan Lemon struct ifnethead ifnet; /* depend on static init XXX */ 129b30a244cSJeffrey Hsu struct mtx ifnet_lock; 1300b59d917SJonathan Lemon 131f9132cebSJonathan Lemon static int if_indexlim = 8; 132ad3b9257SJohn-Mark Gurney static struct knlist ifklist; 133f9132cebSJonathan Lemon 1349a2a57a1SJonathan Lemon static void filt_netdetach(struct knote *kn); 1359a2a57a1SJonathan Lemon static int filt_netdev(struct knote *kn, long hint); 1369a2a57a1SJonathan Lemon 1379a2a57a1SJonathan Lemon static struct filterops netdev_filtops = 1389a2a57a1SJonathan Lemon { 1, NULL, filt_netdetach, filt_netdev }; 1399a2a57a1SJonathan Lemon 1400b59d917SJonathan Lemon /* 1410b59d917SJonathan Lemon * System initialization 1420b59d917SJonathan Lemon */ 143f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL) 144f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL) 1450b59d917SJonathan Lemon 1460b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 1470b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 14830aad87dSBrooks Davis 149f13ad206SJonathan Lemon static d_open_t netopen; 150f13ad206SJonathan Lemon static d_close_t netclose; 151f13ad206SJonathan Lemon static d_ioctl_t netioctl; 1529a2a57a1SJonathan Lemon static d_kqfilter_t netkqfilter; 153f13ad206SJonathan Lemon 154f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = { 155dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 156dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1577ac40f5fSPoul-Henning Kamp .d_open = netopen, 1587ac40f5fSPoul-Henning Kamp .d_close = netclose, 1597ac40f5fSPoul-Henning Kamp .d_ioctl = netioctl, 1607ac40f5fSPoul-Henning Kamp .d_name = "net", 1617ac40f5fSPoul-Henning Kamp .d_kqfilter = netkqfilter, 162f13ad206SJonathan Lemon }; 163f13ad206SJonathan Lemon 164f13ad206SJonathan Lemon static int 16589c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td) 166f13ad206SJonathan Lemon { 167f13ad206SJonathan Lemon return (0); 168f13ad206SJonathan Lemon } 169f13ad206SJonathan Lemon 170f13ad206SJonathan Lemon static int 17189c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td) 172f13ad206SJonathan Lemon { 173f13ad206SJonathan Lemon return (0); 174f13ad206SJonathan Lemon } 175f13ad206SJonathan Lemon 176f13ad206SJonathan Lemon static int 17789c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 178f13ad206SJonathan Lemon { 179f13ad206SJonathan Lemon struct ifnet *ifp; 180f13ad206SJonathan Lemon int error, idx; 181f13ad206SJonathan Lemon 182f13ad206SJonathan Lemon /* only support interface specific ioctls */ 183f13ad206SJonathan Lemon if (IOCGROUP(cmd) != 'i') 184f13ad206SJonathan Lemon return (EOPNOTSUPP); 185f13ad206SJonathan Lemon idx = minor(dev); 186f13ad206SJonathan Lemon if (idx == 0) { 187f13ad206SJonathan Lemon /* 188f13ad206SJonathan Lemon * special network device, not interface. 189f13ad206SJonathan Lemon */ 190f13ad206SJonathan Lemon if (cmd == SIOCGIFCONF) 191f13ad206SJonathan Lemon return (ifconf(cmd, data)); /* XXX remove cmd */ 192f13ad206SJonathan Lemon return (EOPNOTSUPP); 193f13ad206SJonathan Lemon } 194f13ad206SJonathan Lemon 195f13ad206SJonathan Lemon ifp = ifnet_byindex(idx); 196f13ad206SJonathan Lemon if (ifp == NULL) 197f13ad206SJonathan Lemon return (ENXIO); 198f13ad206SJonathan Lemon 199f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 200f13ad206SJonathan Lemon if (error == ENOIOCTL) 201f13ad206SJonathan Lemon error = EOPNOTSUPP; 202f13ad206SJonathan Lemon return (error); 203f13ad206SJonathan Lemon } 204f13ad206SJonathan Lemon 2059a2a57a1SJonathan Lemon static int 20689c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn) 2079a2a57a1SJonathan Lemon { 208ad3b9257SJohn-Mark Gurney struct knlist *klist; 2099a2a57a1SJonathan Lemon struct ifnet *ifp; 2109a2a57a1SJonathan Lemon int idx; 2119a2a57a1SJonathan Lemon 212ad3b9257SJohn-Mark Gurney switch (kn->kn_filter) { 213ad3b9257SJohn-Mark Gurney case EVFILT_NETDEV: 214ad3b9257SJohn-Mark Gurney kn->kn_fop = &netdev_filtops; 215ad3b9257SJohn-Mark Gurney break; 216ad3b9257SJohn-Mark Gurney default: 217ad3b9257SJohn-Mark Gurney return (1); 218ad3b9257SJohn-Mark Gurney } 219ad3b9257SJohn-Mark Gurney 2209a2a57a1SJonathan Lemon idx = minor(dev); 2219a2a57a1SJonathan Lemon if (idx == 0) { 2229a2a57a1SJonathan Lemon klist = &ifklist; 2239a2a57a1SJonathan Lemon } else { 2249a2a57a1SJonathan Lemon ifp = ifnet_byindex(idx); 2259a2a57a1SJonathan Lemon if (ifp == NULL) 2269a2a57a1SJonathan Lemon return (1); 2279a2a57a1SJonathan Lemon klist = &ifp->if_klist; 2289a2a57a1SJonathan Lemon } 2299a2a57a1SJonathan Lemon 2309a2a57a1SJonathan Lemon kn->kn_hook = (caddr_t)klist; 2319a2a57a1SJonathan Lemon 232ad3b9257SJohn-Mark Gurney knlist_add(klist, kn, 0); 2339a2a57a1SJonathan Lemon 2349a2a57a1SJonathan Lemon return (0); 2359a2a57a1SJonathan Lemon } 2369a2a57a1SJonathan Lemon 2379a2a57a1SJonathan Lemon static void 2389a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn) 2399a2a57a1SJonathan Lemon { 240ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2419a2a57a1SJonathan Lemon 242ad3b9257SJohn-Mark Gurney knlist_remove(klist, kn, 0); 2439a2a57a1SJonathan Lemon } 2449a2a57a1SJonathan Lemon 2459a2a57a1SJonathan Lemon static int 2469a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint) 2479a2a57a1SJonathan Lemon { 248ad3b9257SJohn-Mark Gurney struct knlist *klist = (struct knlist *)kn->kn_hook; 2499a2a57a1SJonathan Lemon 2509a2a57a1SJonathan Lemon /* 2519a2a57a1SJonathan Lemon * Currently NOTE_EXIT is abused to indicate device detach. 2529a2a57a1SJonathan Lemon */ 2539a2a57a1SJonathan Lemon if (hint == NOTE_EXIT) { 2549a2a57a1SJonathan Lemon kn->kn_data = NOTE_LINKINV; 2559a2a57a1SJonathan Lemon kn->kn_flags |= (EV_EOF | EV_ONESHOT); 256ad3b9257SJohn-Mark Gurney knlist_remove_inevent(klist, kn); 2579a2a57a1SJonathan Lemon return (1); 2589a2a57a1SJonathan Lemon } 259ad3b9257SJohn-Mark Gurney if (hint != 0) 2609a2a57a1SJonathan Lemon kn->kn_data = hint; /* current status */ 2619a2a57a1SJonathan Lemon if (kn->kn_sfflags & hint) 2629a2a57a1SJonathan Lemon kn->kn_fflags |= hint; 2639a2a57a1SJonathan Lemon return (kn->kn_fflags != 0); 2649a2a57a1SJonathan Lemon } 2659a2a57a1SJonathan Lemon 266df8bae1dSRodney W. Grimes /* 267df8bae1dSRodney W. Grimes * Network interface utility routines. 268df8bae1dSRodney W. Grimes * 269df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 270df8bae1dSRodney W. Grimes * parameters. 271df8bae1dSRodney W. Grimes */ 2722b14f991SJulian Elischer /* ARGSUSED*/ 273f9132cebSJonathan Lemon static void 27472fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused) 275f9132cebSJonathan Lemon { 276f9132cebSJonathan Lemon 277b30a244cSJeffrey Hsu IFNET_LOCK_INIT(); 278f9132cebSJonathan Lemon TAILQ_INIT(&ifnet); 279ad3b9257SJohn-Mark Gurney knlist_init(&ifklist, NULL); 280f9132cebSJonathan Lemon if_grow(); /* create initial table */ 281f13ad206SJonathan Lemon ifdev_byindex(0) = make_dev(&net_cdevsw, 0, 282f13ad206SJonathan Lemon UID_ROOT, GID_WHEEL, 0600, "network"); 283f889d2efSBrooks Davis if_clone_init(); 284f9132cebSJonathan Lemon } 285f9132cebSJonathan Lemon 286f9132cebSJonathan Lemon static void 287f9132cebSJonathan Lemon if_grow(void) 288f9132cebSJonathan Lemon { 289f9132cebSJonathan Lemon u_int n; 290f9132cebSJonathan Lemon struct ifindex_entry *e; 291f9132cebSJonathan Lemon 292f9132cebSJonathan Lemon if_indexlim <<= 1; 293f9132cebSJonathan Lemon n = if_indexlim * sizeof(*e); 294a163d034SWarner Losh e = malloc(n, M_IFADDR, M_WAITOK | M_ZERO); 295f9132cebSJonathan Lemon if (ifindex_table != NULL) { 296f9132cebSJonathan Lemon memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2); 297f9132cebSJonathan Lemon free((caddr_t)ifindex_table, M_IFADDR); 298f9132cebSJonathan Lemon } 299f9132cebSJonathan Lemon ifindex_table = e; 300f9132cebSJonathan Lemon } 301f9132cebSJonathan Lemon 302f9132cebSJonathan Lemon /* ARGSUSED*/ 303f9132cebSJonathan Lemon static void 30472fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused) 305df8bae1dSRodney W. Grimes { 3068ba5bdaeSPeter Wemm struct ifnet *ifp; 3078ba5bdaeSPeter Wemm int s; 308df8bae1dSRodney W. Grimes 3098ba5bdaeSPeter Wemm s = splimp(); 310b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep on rare error; mostly okay XXX */ 311fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 312e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 31313fb40dfSBrooks Davis if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n"); 314df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 315e0ea20bcSPoul-Henning Kamp } 3165e980e22SJohn Baldwin if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 31713fb40dfSBrooks Davis if_printf(ifp, 31813fb40dfSBrooks Davis "XXX: driver didn't initialize queue mtx\n"); 3196008862bSJohn Baldwin mtx_init(&ifp->if_snd.ifq_mtx, "unknown", 3206008862bSJohn Baldwin MTX_NETWORK_LOCK, MTX_DEF); 321df5e1987SJonathan Lemon } 322df5e1987SJonathan Lemon } 323b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 3248ba5bdaeSPeter Wemm splx(s); 325df8bae1dSRodney W. Grimes if_slowtimo(0); 326df8bae1dSRodney W. Grimes } 327df8bae1dSRodney W. Grimes 328ffb5a104SJonathan Lemon static int 329ffb5a104SJonathan Lemon if_findindex(struct ifnet *ifp) 330ffb5a104SJonathan Lemon { 331ffb5a104SJonathan Lemon int i, unit; 332ffb5a104SJonathan Lemon char eaddr[18], devname[32]; 333d2b4566aSJonathan Lemon const char *name, *p; 334ffb5a104SJonathan Lemon 335ffb5a104SJonathan Lemon switch (ifp->if_type) { 336ffb5a104SJonathan Lemon case IFT_ETHER: /* these types use struct arpcom */ 337ffb5a104SJonathan Lemon case IFT_FDDI: 338ffb5a104SJonathan Lemon case IFT_XETHER: 339ffb5a104SJonathan Lemon case IFT_ISO88025: 340ffb5a104SJonathan Lemon case IFT_L2VLAN: 3418f867517SAndrew Thompson case IFT_BRIDGE: 3428bbfdc98SRobert Watson snprintf(eaddr, 18, "%6D", IFP2AC(ifp)->ac_enaddr, ":"); 343ffb5a104SJonathan Lemon break; 344ffb5a104SJonathan Lemon default: 345ffb5a104SJonathan Lemon eaddr[0] = '\0'; 346ffb5a104SJonathan Lemon break; 347ffb5a104SJonathan Lemon } 3489bf40edeSBrooks Davis strlcpy(devname, ifp->if_xname, sizeof(devname)); 349ffb5a104SJonathan Lemon name = net_cdevsw.d_name; 350ffb5a104SJonathan Lemon i = 0; 351ffb5a104SJonathan Lemon while ((resource_find_dev(&i, name, &unit, NULL, NULL)) == 0) { 352ffb5a104SJonathan Lemon if (resource_string_value(name, unit, "ether", &p) == 0) 353ffb5a104SJonathan Lemon if (strcmp(p, eaddr) == 0) 354ffb5a104SJonathan Lemon goto found; 355ffb5a104SJonathan Lemon if (resource_string_value(name, unit, "dev", &p) == 0) 356ffb5a104SJonathan Lemon if (strcmp(p, devname) == 0) 357ffb5a104SJonathan Lemon goto found; 358ffb5a104SJonathan Lemon } 359ffb5a104SJonathan Lemon unit = 0; 360ffb5a104SJonathan Lemon found: 361ffb5a104SJonathan Lemon if (unit != 0) { 362ffb5a104SJonathan Lemon if (ifaddr_byindex(unit) == NULL) 363ffb5a104SJonathan Lemon return (unit); 364ffb5a104SJonathan Lemon printf("%s%d in use, cannot hardwire it to %s.\n", 365ffb5a104SJonathan Lemon name, unit, devname); 366ffb5a104SJonathan Lemon } 367ffb5a104SJonathan Lemon for (unit = 1; ; unit++) { 36805153c61SBill Fenner if (unit <= if_index && ifaddr_byindex(unit) != NULL) 369ffb5a104SJonathan Lemon continue; 370ffb5a104SJonathan Lemon if (resource_string_value(name, unit, "ether", &p) == 0 || 371ffb5a104SJonathan Lemon resource_string_value(name, unit, "dev", &p) == 0) 372ffb5a104SJonathan Lemon continue; 373ffb5a104SJonathan Lemon break; 374ffb5a104SJonathan Lemon } 375ffb5a104SJonathan Lemon return (unit); 376ffb5a104SJonathan Lemon } 377ffb5a104SJonathan Lemon 378df8bae1dSRodney W. Grimes /* 379df8bae1dSRodney W. Grimes * Attach an interface to the 380df8bae1dSRodney W. Grimes * list of "active" interfaces. 381df8bae1dSRodney W. Grimes */ 382df8bae1dSRodney W. Grimes void 38372fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp) 384df8bae1dSRodney W. Grimes { 385df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 3861ce9bf88SPoul-Henning Kamp int namelen, masklen; 38772fd1b6aSDag-Erling Smørgrav struct sockaddr_dl *sdl; 38872fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 389df8bae1dSRodney W. Grimes 390af5e59bfSRobert Watson TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp); 39168a3482fSGleb Smirnoff TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); 392234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK_INIT(ifp); 393234a35c7SHajimu UMEMOTO ifp->if_afdata_initialized = 0; 394b30a244cSJeffrey Hsu IFNET_WLOCK(); 39529412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 396b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 39759562606SGarrett Wollman /* 39859562606SGarrett Wollman * XXX - 39959562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 40059562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 40159562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 40259562606SGarrett Wollman * this unlikely case. 40359562606SGarrett Wollman */ 40459562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 40582cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 4066817526dSPoul-Henning Kamp TAILQ_INIT(&ifp->if_multiaddrs); 407ad3b9257SJohn-Mark Gurney knlist_init(&ifp->if_klist, NULL); 40898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 409bc9d2991SBrooks Davis ifp->if_data.ifi_epoch = time_uptime; 410e70cd263SRobert Watson 411e70cd263SRobert Watson #ifdef MAC 412e70cd263SRobert Watson mac_init_ifnet(ifp); 413e70cd263SRobert Watson mac_create_ifnet(ifp); 414e70cd263SRobert Watson #endif 415e70cd263SRobert Watson 416ffb5a104SJonathan Lemon ifp->if_index = if_findindex(ifp); 41705153c61SBill Fenner if (ifp->if_index > if_index) 41805153c61SBill Fenner if_index = ifp->if_index; 419f9132cebSJonathan Lemon if (if_index >= if_indexlim) 420f9132cebSJonathan Lemon if_grow(); 4219e734b44SBrooks Davis ifp->if_data.ifi_datalen = sizeof(struct if_data); 42282cd038dSYoshinobu Inoue 423ffb5a104SJonathan Lemon ifnet_byindex(ifp->if_index) = ifp; 42412b8b80eSRuslan Ermilov ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw, 42512b8b80eSRuslan Ermilov unit2minor(ifp->if_index), 4269bf40edeSBrooks Davis UID_ROOT, GID_WHEEL, 0600, "%s/%s", 4279bf40edeSBrooks Davis net_cdevsw.d_name, ifp->if_xname); 428ffb5a104SJonathan Lemon make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", 429ffb5a104SJonathan Lemon net_cdevsw.d_name, ifp->if_index); 430f13ad206SJonathan Lemon 4319bf40edeSBrooks Davis mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF); 432df5e1987SJonathan Lemon 433df8bae1dSRodney W. Grimes /* 434df8bae1dSRodney W. Grimes * create a Link Level name for this device 435df8bae1dSRodney W. Grimes */ 4369bf40edeSBrooks Davis namelen = strlen(ifp->if_xname); 43736c19a57SBrooks Davis /* 43836c19a57SBrooks Davis * Always save enough space for any possiable name so we can do 43936c19a57SBrooks Davis * a rename in place later. 44036c19a57SBrooks Davis */ 44136c19a57SBrooks Davis masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; 442df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 443df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 444df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 445ccb82468SBrooks Davis socksize = roundup2(socksize, sizeof(long)); 446df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 447a8773564SBrooks Davis ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 44819fc74fbSJeffrey Hsu IFA_LOCK_INIT(ifa); 449df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 450df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 451df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 4529bf40edeSBrooks Davis bcopy(ifp->if_xname, sdl->sdl_data, namelen); 4531ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 454df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 455df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 456ffb5a104SJonathan Lemon ifaddr_byindex(ifp->if_index) = ifa; 457df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 458df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 459df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 460df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 461df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 462df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 463df8bae1dSRodney W. Grimes while (namelen != 0) 464df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 46519fc74fbSJeffrey Hsu ifa->ifa_refcnt = 1; 46659562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 4676237419dSRobert Watson ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */ 46802b199f1SMax Laier ifp->if_snd.altq_type = 0; 46902b199f1SMax Laier ifp->if_snd.altq_disc = NULL; 47002b199f1SMax Laier ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE; 47102b199f1SMax Laier ifp->if_snd.altq_tbr = NULL; 47202b199f1SMax Laier ifp->if_snd.altq_ifp = ifp; 4737b6edd04SRuslan Ermilov 47469fb23b7SMax Laier if (domain_init_status >= 2) 47531b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 47631b1bfe1SHajimu UMEMOTO 47725a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 47825a4adceSMax Laier 4797b6edd04SRuslan Ermilov /* Announce the interface. */ 4807b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 481df8bae1dSRodney W. Grimes } 4826182fdbdSPeter Wemm 48331b1bfe1SHajimu UMEMOTO static void 48472fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy) 48531b1bfe1SHajimu UMEMOTO { 48631b1bfe1SHajimu UMEMOTO struct ifnet *ifp; 48731b1bfe1SHajimu UMEMOTO int s; 48831b1bfe1SHajimu UMEMOTO 48931b1bfe1SHajimu UMEMOTO s = splnet(); 4909046571fSLuigi Rizzo TAILQ_FOREACH(ifp, &ifnet, if_link) 49131b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 49231b1bfe1SHajimu UMEMOTO splx(s); 49331b1bfe1SHajimu UMEMOTO } 49469fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND, 49531b1bfe1SHajimu UMEMOTO if_attachdomain, NULL); 49631b1bfe1SHajimu UMEMOTO 49731b1bfe1SHajimu UMEMOTO static void 49872fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp) 49931b1bfe1SHajimu UMEMOTO { 50031b1bfe1SHajimu UMEMOTO struct domain *dp; 50131b1bfe1SHajimu UMEMOTO int s; 50231b1bfe1SHajimu UMEMOTO 50331b1bfe1SHajimu UMEMOTO s = splnet(); 50431b1bfe1SHajimu UMEMOTO 505234a35c7SHajimu UMEMOTO /* 506234a35c7SHajimu UMEMOTO * Since dp->dom_ifattach calls malloc() with M_WAITOK, we 507234a35c7SHajimu UMEMOTO * cannot lock ifp->if_afdata initialization, entirely. 508234a35c7SHajimu UMEMOTO */ 509234a35c7SHajimu UMEMOTO if (IF_AFDATA_TRYLOCK(ifp) == 0) { 510234a35c7SHajimu UMEMOTO splx(s); 511234a35c7SHajimu UMEMOTO return; 512234a35c7SHajimu UMEMOTO } 51369fb23b7SMax Laier if (ifp->if_afdata_initialized >= domain_init_status) { 514234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 515234a35c7SHajimu UMEMOTO splx(s); 5166237419dSRobert Watson printf("if_attachdomain called more than once on %s\n", 5176237419dSRobert Watson ifp->if_xname); 518234a35c7SHajimu UMEMOTO return; 519234a35c7SHajimu UMEMOTO } 52069fb23b7SMax Laier ifp->if_afdata_initialized = domain_init_status; 521234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 522234a35c7SHajimu UMEMOTO 52331b1bfe1SHajimu UMEMOTO /* address family dependent data region */ 52431b1bfe1SHajimu UMEMOTO bzero(ifp->if_afdata, sizeof(ifp->if_afdata)); 52531b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 52631b1bfe1SHajimu UMEMOTO if (dp->dom_ifattach) 52731b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family] = 52831b1bfe1SHajimu UMEMOTO (*dp->dom_ifattach)(ifp); 52931b1bfe1SHajimu UMEMOTO } 53031b1bfe1SHajimu UMEMOTO 53131b1bfe1SHajimu UMEMOTO splx(s); 53231b1bfe1SHajimu UMEMOTO } 53331b1bfe1SHajimu UMEMOTO 5346182fdbdSPeter Wemm /* 53545778b37SPeter Edwards * Remove any network addresses from an interface. 53645778b37SPeter Edwards */ 53745778b37SPeter Edwards 53845778b37SPeter Edwards void 53945778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp) 54045778b37SPeter Edwards { 54145778b37SPeter Edwards struct ifaddr *ifa, *next; 54245778b37SPeter Edwards 54345778b37SPeter Edwards TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { 54445778b37SPeter Edwards 54545778b37SPeter Edwards if (ifa->ifa_addr->sa_family == AF_LINK) 54645778b37SPeter Edwards continue; 54745778b37SPeter Edwards #ifdef INET 54845778b37SPeter Edwards /* XXX: Ugly!! ad hoc just for INET */ 54945778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 55045778b37SPeter Edwards struct ifaliasreq ifr; 55145778b37SPeter Edwards 55245778b37SPeter Edwards bzero(&ifr, sizeof(ifr)); 55345778b37SPeter Edwards ifr.ifra_addr = *ifa->ifa_addr; 55445778b37SPeter Edwards if (ifa->ifa_dstaddr) 55545778b37SPeter Edwards ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 55645778b37SPeter Edwards if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 55745778b37SPeter Edwards NULL) == 0) 55845778b37SPeter Edwards continue; 55945778b37SPeter Edwards } 56045778b37SPeter Edwards #endif /* INET */ 56145778b37SPeter Edwards #ifdef INET6 56245778b37SPeter Edwards if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 56345778b37SPeter Edwards in6_purgeaddr(ifa); 56445778b37SPeter Edwards /* ifp_addrhead is already updated */ 56545778b37SPeter Edwards continue; 56645778b37SPeter Edwards } 56745778b37SPeter Edwards #endif /* INET6 */ 56845778b37SPeter Edwards TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 56945778b37SPeter Edwards IFAFREE(ifa); 57045778b37SPeter Edwards } 57145778b37SPeter Edwards } 57245778b37SPeter Edwards 57345778b37SPeter Edwards /* 5746182fdbdSPeter Wemm * Detach an interface, removing it from the 5756182fdbdSPeter Wemm * list of "active" interfaces. 5766182fdbdSPeter Wemm */ 5776182fdbdSPeter Wemm void 57872fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp) 5796182fdbdSPeter Wemm { 58045778b37SPeter Edwards struct ifaddr *ifa; 5815500d3beSWarner Losh struct radix_node_head *rnh; 5825500d3beSWarner Losh int s; 5835500d3beSWarner Losh int i; 58431b1bfe1SHajimu UMEMOTO struct domain *dp; 5853f35d515SPeter Pentchev struct ifnet *iter; 5863f35d515SPeter Pentchev int found; 5876182fdbdSPeter Wemm 58868a3482fSGleb Smirnoff /* 58968a3482fSGleb Smirnoff * Remove/wait for pending events. 59068a3482fSGleb Smirnoff */ 59168a3482fSGleb Smirnoff taskqueue_drain(taskqueue_swi, &ifp->if_linktask); 59268a3482fSGleb Smirnoff 59325a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 594a9771948SGleb Smirnoff #ifdef DEV_CARP 595a9771948SGleb Smirnoff /* Maybe hook to the generalized departure handler above?!? */ 596a9771948SGleb Smirnoff if (ifp->if_carp) 597a9771948SGleb Smirnoff carp_ifdetach(ifp); 598a9771948SGleb Smirnoff #endif 599a9771948SGleb Smirnoff 6006182fdbdSPeter Wemm /* 6016182fdbdSPeter Wemm * Remove routes and flush queues. 6026182fdbdSPeter Wemm */ 6035500d3beSWarner Losh s = splnet(); 6046182fdbdSPeter Wemm if_down(ifp); 60502b199f1SMax Laier #ifdef ALTQ 60602b199f1SMax Laier if (ALTQ_IS_ENABLED(&ifp->if_snd)) 60702b199f1SMax Laier altq_disable(&ifp->if_snd); 60802b199f1SMax Laier if (ALTQ_IS_ATTACHED(&ifp->if_snd)) 60902b199f1SMax Laier altq_detach(&ifp->if_snd); 61002b199f1SMax Laier #endif 6116182fdbdSPeter Wemm 61245778b37SPeter Edwards if_purgeaddrs(ifp); 6136182fdbdSPeter Wemm 61433841545SHajimu UMEMOTO #ifdef INET6 61533841545SHajimu UMEMOTO /* 61633841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 61733841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 61833841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 61933841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 62033841545SHajimu UMEMOTO */ 62133841545SHajimu UMEMOTO in6_ifdetach(ifp); 62233841545SHajimu UMEMOTO #endif 623f4247b59SLuigi Rizzo /* 624f4247b59SLuigi Rizzo * Remove address from ifindex_table[] and maybe decrement if_index. 625f4247b59SLuigi Rizzo * Clean up all addresses. 626f4247b59SLuigi Rizzo */ 627b9907cd4SBrooks Davis ifnet_byindex(ifp->if_index) = NULL; 628f4247b59SLuigi Rizzo ifaddr_byindex(ifp->if_index) = NULL; 629f4247b59SLuigi Rizzo destroy_dev(ifdev_byindex(ifp->if_index)); 630f4247b59SLuigi Rizzo ifdev_byindex(ifp->if_index) = NULL; 631f4247b59SLuigi Rizzo 632f4247b59SLuigi Rizzo while (if_index > 0 && ifaddr_byindex(if_index) == NULL) 633f4247b59SLuigi Rizzo if_index--; 634f4247b59SLuigi Rizzo 63533841545SHajimu UMEMOTO 636212bd869SHajimu UMEMOTO /* We can now free link ifaddr. */ 6373f35d515SPeter Pentchev if (!TAILQ_EMPTY(&ifp->if_addrhead)) { 638212bd869SHajimu UMEMOTO ifa = TAILQ_FIRST(&ifp->if_addrhead); 639212bd869SHajimu UMEMOTO TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 640212bd869SHajimu UMEMOTO IFAFREE(ifa); 6413f35d515SPeter Pentchev } 642212bd869SHajimu UMEMOTO 6435500d3beSWarner Losh /* 6445500d3beSWarner Losh * Delete all remaining routes using this interface 6455500d3beSWarner Losh * Unfortuneatly the only way to do this is to slog through 6465500d3beSWarner Losh * the entire routing table looking for routes which point 6475500d3beSWarner Losh * to this interface...oh well... 6485500d3beSWarner Losh */ 6495500d3beSWarner Losh for (i = 1; i <= AF_MAX; i++) { 6505500d3beSWarner Losh if ((rnh = rt_tables[i]) == NULL) 6515500d3beSWarner Losh continue; 652956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 6535500d3beSWarner Losh (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 654956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 6555500d3beSWarner Losh } 6565500d3beSWarner Losh 6577b6edd04SRuslan Ermilov /* Announce that the interface is gone. */ 6587b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 6597b6edd04SRuslan Ermilov 660234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK(ifp); 66131b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 66231b1bfe1SHajimu UMEMOTO if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) 66331b1bfe1SHajimu UMEMOTO (*dp->dom_ifdetach)(ifp, 66431b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family]); 66531b1bfe1SHajimu UMEMOTO } 666234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 66731b1bfe1SHajimu UMEMOTO 668e70cd263SRobert Watson #ifdef MAC 669e70cd263SRobert Watson mac_destroy_ifnet(ifp); 670e70cd263SRobert Watson #endif /* MAC */ 671ad3b9257SJohn-Mark Gurney KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT); 672ad3b9257SJohn-Mark Gurney knlist_clear(&ifp->if_klist, 0); 673ad3b9257SJohn-Mark Gurney knlist_destroy(&ifp->if_klist); 674b30a244cSJeffrey Hsu IFNET_WLOCK(); 6753f35d515SPeter Pentchev found = 0; 6763f35d515SPeter Pentchev TAILQ_FOREACH(iter, &ifnet, if_link) 6773f35d515SPeter Pentchev if (iter == ifp) { 6783f35d515SPeter Pentchev found = 1; 6793f35d515SPeter Pentchev break; 6803f35d515SPeter Pentchev } 6813f35d515SPeter Pentchev if (found) 6826182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 683b30a244cSJeffrey Hsu IFNET_WUNLOCK(); 684df5e1987SJonathan Lemon mtx_destroy(&ifp->if_snd.ifq_mtx); 685234a35c7SHajimu UMEMOTO IF_AFDATA_DESTROY(ifp); 6865500d3beSWarner Losh splx(s); 6875500d3beSWarner Losh } 6885500d3beSWarner Losh 6895500d3beSWarner Losh /* 6905500d3beSWarner Losh * Delete Routes for a Network Interface 6915500d3beSWarner Losh * 6925500d3beSWarner Losh * Called for each routing entry via the rnh->rnh_walktree() call above 6935500d3beSWarner Losh * to delete all route entries referencing a detaching network interface. 6945500d3beSWarner Losh * 6955500d3beSWarner Losh * Arguments: 6965500d3beSWarner Losh * rn pointer to node in the routing table 6975500d3beSWarner Losh * arg argument passed to rnh->rnh_walktree() - detaching interface 6985500d3beSWarner Losh * 6995500d3beSWarner Losh * Returns: 7005500d3beSWarner Losh * 0 successful 7015500d3beSWarner Losh * errno failed - reason indicated 7025500d3beSWarner Losh * 7035500d3beSWarner Losh */ 7045500d3beSWarner Losh static int 70572fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg) 7065500d3beSWarner Losh { 7075500d3beSWarner Losh struct rtentry *rt = (struct rtentry *)rn; 7085500d3beSWarner Losh struct ifnet *ifp = arg; 7095500d3beSWarner Losh int err; 7105500d3beSWarner Losh 7115500d3beSWarner Losh if (rt->rt_ifp == ifp) { 7125500d3beSWarner Losh 7135500d3beSWarner Losh /* 7145500d3beSWarner Losh * Protect (sorta) against walktree recursion problems 7155500d3beSWarner Losh * with cloned routes 7165500d3beSWarner Losh */ 7175500d3beSWarner Losh if ((rt->rt_flags & RTF_UP) == 0) 7185500d3beSWarner Losh return (0); 7195500d3beSWarner Losh 7205500d3beSWarner Losh err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 7215500d3beSWarner Losh rt_mask(rt), rt->rt_flags, 7225500d3beSWarner Losh (struct rtentry **) NULL); 7235500d3beSWarner Losh if (err) { 7245500d3beSWarner Losh log(LOG_WARNING, "if_rtdel: error %d\n", err); 7255500d3beSWarner Losh } 7265500d3beSWarner Losh } 7275500d3beSWarner Losh 7285500d3beSWarner Losh return (0); 7296182fdbdSPeter Wemm } 7306182fdbdSPeter Wemm 731d1dd20beSSam Leffler #define equal(a1, a2) (bcmp((a1), (a2), ((a1))->sa_len) == 0) 73219fc74fbSJeffrey Hsu 73330aad87dSBrooks Davis /* 734df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 735df8bae1dSRodney W. Grimes */ 736df8bae1dSRodney W. Grimes /*ARGSUSED*/ 737df8bae1dSRodney W. Grimes struct ifaddr * 73872fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr) 739df8bae1dSRodney W. Grimes { 7400b59d917SJonathan Lemon struct ifnet *ifp; 7410b59d917SJonathan Lemon struct ifaddr *ifa; 742df8bae1dSRodney W. Grimes 743b30a244cSJeffrey Hsu IFNET_RLOCK(); 744fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 74537d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 746df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 747df8bae1dSRodney W. Grimes continue; 748df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr)) 7490b59d917SJonathan Lemon goto done; 75082cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 7510b59d917SJonathan Lemon if ((ifp->if_flags & IFF_BROADCAST) && 7520b59d917SJonathan Lemon ifa->ifa_broadaddr && 75382cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 754df8bae1dSRodney W. Grimes equal(ifa->ifa_broadaddr, addr)) 7550b59d917SJonathan Lemon goto done; 7560b59d917SJonathan Lemon } 7570b59d917SJonathan Lemon ifa = NULL; 7580b59d917SJonathan Lemon done: 759b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 760df8bae1dSRodney W. Grimes return (ifa); 761df8bae1dSRodney W. Grimes } 7620b59d917SJonathan Lemon 763df8bae1dSRodney W. Grimes /* 764df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 765df8bae1dSRodney W. Grimes */ 766df8bae1dSRodney W. Grimes /*ARGSUSED*/ 767df8bae1dSRodney W. Grimes struct ifaddr * 76872fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr) 769df8bae1dSRodney W. Grimes { 7700b59d917SJonathan Lemon struct ifnet *ifp; 7710b59d917SJonathan Lemon struct ifaddr *ifa; 772df8bae1dSRodney W. Grimes 773b30a244cSJeffrey Hsu IFNET_RLOCK(); 7740b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 7750b59d917SJonathan Lemon if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 7760b59d917SJonathan Lemon continue; 77737d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 778df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 779df8bae1dSRodney W. Grimes continue; 78055088a1cSDavid Greenman if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 7810b59d917SJonathan Lemon goto done; 782df8bae1dSRodney W. Grimes } 7830b59d917SJonathan Lemon } 7840b59d917SJonathan Lemon ifa = NULL; 7850b59d917SJonathan Lemon done: 786b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 7870b59d917SJonathan Lemon return (ifa); 788df8bae1dSRodney W. Grimes } 789df8bae1dSRodney W. Grimes 790df8bae1dSRodney W. Grimes /* 791df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 792df8bae1dSRodney W. Grimes * is most specific found. 793df8bae1dSRodney W. Grimes */ 794df8bae1dSRodney W. Grimes struct ifaddr * 79572fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr) 796df8bae1dSRodney W. Grimes { 79772fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 79872fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 799df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 800df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 801df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 802df8bae1dSRodney W. Grimes 8037e2a6151SJulian Elischer /* 8047e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 8057e2a6151SJulian Elischer * so do that if we can. 8067e2a6151SJulian Elischer */ 807df8bae1dSRodney W. Grimes if (af == AF_LINK) { 808d1dd20beSSam Leffler struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 809df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 810f9132cebSJonathan Lemon return (ifaddr_byindex(sdl->sdl_index)); 811df8bae1dSRodney W. Grimes } 8127e2a6151SJulian Elischer 8137e2a6151SJulian Elischer /* 8147e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 8157e2a6151SJulian Elischer * addresses in this address family. 8167e2a6151SJulian Elischer */ 817b30a244cSJeffrey Hsu IFNET_RLOCK(); 818fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 81937d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 82072fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 821df8bae1dSRodney W. Grimes 822523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 823df8bae1dSRodney W. Grimes next: continue; 824c61cd599SHajimu UMEMOTO if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) { 8257e2a6151SJulian Elischer /* 8267e2a6151SJulian Elischer * This is a bit broken as it doesn't 8277e2a6151SJulian Elischer * take into account that the remote end may 8287e2a6151SJulian Elischer * be a single node in the network we are 8297e2a6151SJulian Elischer * looking for. 8307e2a6151SJulian Elischer * The trouble is that we don't know the 8317e2a6151SJulian Elischer * netmask for the remote end. 8327e2a6151SJulian Elischer */ 833fcd6781aSGarrett Wollman if (ifa->ifa_dstaddr != 0 834fcd6781aSGarrett Wollman && equal(addr, ifa->ifa_dstaddr)) 8350b59d917SJonathan Lemon goto done; 8363740e2adSDavid Greenman } else { 8377e2a6151SJulian Elischer /* 8387ed8f465SJulian Elischer * if we have a special address handler, 8397ed8f465SJulian Elischer * then use it instead of the generic one. 8407ed8f465SJulian Elischer */ 8417ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 8420b59d917SJonathan Lemon if ((*ifa->ifa_claim_addr)(ifa, addr)) 8430b59d917SJonathan Lemon goto done; 8447ed8f465SJulian Elischer continue; 8457ed8f465SJulian Elischer } 8467ed8f465SJulian Elischer 8477ed8f465SJulian Elischer /* 8487e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 8497e2a6151SJulian Elischer * If a bit dissagrees with what we are 8507e2a6151SJulian Elischer * looking for, mask it with the netmask 8517e2a6151SJulian Elischer * to see if it really matters. 8527e2a6151SJulian Elischer * (A byte at a time) 8537e2a6151SJulian Elischer */ 854523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 855523a02aaSDavid Greenman continue; 856df8bae1dSRodney W. Grimes cp = addr_data; 857df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 858df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 8597e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 8607e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 861df8bae1dSRodney W. Grimes while (cp3 < cplim) 862df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 8637e2a6151SJulian Elischer goto next; /* next address! */ 8647e2a6151SJulian Elischer /* 8657e2a6151SJulian Elischer * If the netmask of what we just found 8667e2a6151SJulian Elischer * is more specific than what we had before 8677e2a6151SJulian Elischer * (if we had one) then remember the new one 8687e2a6151SJulian Elischer * before continuing to search 8697e2a6151SJulian Elischer * for an even better one. 8707e2a6151SJulian Elischer */ 871df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 872df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 873df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 874df8bae1dSRodney W. Grimes ifa_maybe = ifa; 875df8bae1dSRodney W. Grimes } 876b2af64fdSDavid Greenman } 877b2af64fdSDavid Greenman } 8780b59d917SJonathan Lemon ifa = ifa_maybe; 8790b59d917SJonathan Lemon done: 880b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 8810b59d917SJonathan Lemon return (ifa); 882df8bae1dSRodney W. Grimes } 883df8bae1dSRodney W. Grimes 884df8bae1dSRodney W. Grimes /* 885df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 886df8bae1dSRodney W. Grimes * a given address. 887df8bae1dSRodney W. Grimes */ 888df8bae1dSRodney W. Grimes struct ifaddr * 88972fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) 890df8bae1dSRodney W. Grimes { 89172fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 89272fd1b6aSDag-Erling Smørgrav char *cp, *cp2, *cp3; 89372fd1b6aSDag-Erling Smørgrav char *cplim; 894df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 895df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 896df8bae1dSRodney W. Grimes 897df8bae1dSRodney W. Grimes if (af >= AF_MAX) 898df8bae1dSRodney W. Grimes return (0); 89937d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 900df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 901df8bae1dSRodney W. Grimes continue; 902381dd1d2SJulian Elischer if (ifa_maybe == 0) 903df8bae1dSRodney W. Grimes ifa_maybe = ifa; 904df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 905df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr) || 906df8bae1dSRodney W. Grimes (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 9072defe5cdSJonathan Lemon goto done; 908df8bae1dSRodney W. Grimes continue; 909df8bae1dSRodney W. Grimes } 910b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 911b2af64fdSDavid Greenman if (equal(addr, ifa->ifa_dstaddr)) 912a8637146SJonathan Lemon goto done; 9133740e2adSDavid Greenman } else { 914df8bae1dSRodney W. Grimes cp = addr->sa_data; 915df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 916df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 917df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 918df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 919df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 920df8bae1dSRodney W. Grimes break; 921df8bae1dSRodney W. Grimes if (cp3 == cplim) 9222defe5cdSJonathan Lemon goto done; 923df8bae1dSRodney W. Grimes } 924b2af64fdSDavid Greenman } 925f9132cebSJonathan Lemon ifa = ifa_maybe; 926f9132cebSJonathan Lemon done: 927f9132cebSJonathan Lemon return (ifa); 928df8bae1dSRodney W. Grimes } 929df8bae1dSRodney W. Grimes 930df8bae1dSRodney W. Grimes #include <net/route.h> 931df8bae1dSRodney W. Grimes 932df8bae1dSRodney W. Grimes /* 933df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 934df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 935df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 936df8bae1dSRodney W. Grimes */ 9373bda9f9bSPoul-Henning Kamp static void 93872fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 939df8bae1dSRodney W. Grimes { 94072fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa, *oifa; 941df8bae1dSRodney W. Grimes struct sockaddr *dst; 942df8bae1dSRodney W. Grimes struct ifnet *ifp; 943df8bae1dSRodney W. Grimes 944d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 945d1dd20beSSam Leffler 946df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 947df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 948df8bae1dSRodney W. Grimes return; 9499448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 9509448326fSPoul-Henning Kamp if (ifa) { 95119fc74fbSJeffrey Hsu IFAREF(ifa); /* XXX */ 952d1dd20beSSam Leffler oifa = rt->rt_ifa; 953df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 954d1dd20beSSam Leffler IFAFREE(oifa); 955df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 9568071913dSRuslan Ermilov ifa->ifa_rtrequest(cmd, rt, info); 957df8bae1dSRodney W. Grimes } 958df8bae1dSRodney W. Grimes } 959df8bae1dSRodney W. Grimes 960df8bae1dSRodney W. Grimes /* 961df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 962df8bae1dSRodney W. Grimes * the transition. 963df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 964df8bae1dSRodney W. Grimes */ 9658614fb12SMax Laier static void 96672fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam) 967df8bae1dSRodney W. Grimes { 96872fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 969df8bae1dSRodney W. Grimes 970e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 97198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 972e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 973e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 974df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 975df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 976a9771948SGleb Smirnoff #ifdef DEV_CARP 977a9771948SGleb Smirnoff if (ifp->if_carp) 978a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 979a9771948SGleb Smirnoff #endif 980df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 981df8bae1dSRodney W. Grimes } 982df8bae1dSRodney W. Grimes 983df8bae1dSRodney W. Grimes /* 984df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 985df8bae1dSRodney W. Grimes * the transition. 986df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 987df8bae1dSRodney W. Grimes */ 9888614fb12SMax Laier static void 98972fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam) 990df8bae1dSRodney W. Grimes { 99172fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 992df8bae1dSRodney W. Grimes 993e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 99498b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 995e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 996e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 997df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 998a9771948SGleb Smirnoff #ifdef DEV_CARP 999a9771948SGleb Smirnoff if (ifp->if_carp) 1000a9771948SGleb Smirnoff carp_carpdev_state(ifp->if_carp); 1001a9771948SGleb Smirnoff #endif 1002df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 100382cd038dSYoshinobu Inoue #ifdef INET6 100482cd038dSYoshinobu Inoue in6_if_up(ifp); 100582cd038dSYoshinobu Inoue #endif 1006df8bae1dSRodney W. Grimes } 1007df8bae1dSRodney W. Grimes 100894f5c9cfSSam Leffler void (*vlan_link_state_p)(struct ifnet *, int); /* XXX: private from if_vlan */ 100994f5c9cfSSam Leffler 101094f5c9cfSSam Leffler /* 101168a3482fSGleb Smirnoff * Handle a change in the interface link state. To avoid LORs 101268a3482fSGleb Smirnoff * between driver lock and upper layer locks, as well as possible 101368a3482fSGleb Smirnoff * recursions, we post event to taskqueue, and all job 101468a3482fSGleb Smirnoff * is done in static do_link_state_change(). 101594f5c9cfSSam Leffler */ 101694f5c9cfSSam Leffler void 101794f5c9cfSSam Leffler if_link_state_change(struct ifnet *ifp, int link_state) 101894f5c9cfSSam Leffler { 10194d96314fSGleb Smirnoff /* Return if state hasn't changed. */ 10204d96314fSGleb Smirnoff if (ifp->if_link_state == link_state) 10214d96314fSGleb Smirnoff return; 10224d96314fSGleb Smirnoff 102394f5c9cfSSam Leffler ifp->if_link_state = link_state; 10244d96314fSGleb Smirnoff 102568a3482fSGleb Smirnoff taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask); 102668a3482fSGleb Smirnoff } 102768a3482fSGleb Smirnoff 102868a3482fSGleb Smirnoff static void 102968a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending) 103068a3482fSGleb Smirnoff { 103168a3482fSGleb Smirnoff struct ifnet *ifp = (struct ifnet *)arg; 103268a3482fSGleb Smirnoff int link_state = ifp->if_link_state; 103368a3482fSGleb Smirnoff int link; 103468a3482fSGleb Smirnoff 10354d96314fSGleb Smirnoff /* Notify that the link state has changed. */ 103694f5c9cfSSam Leffler rt_ifmsg(ifp); 103794f5c9cfSSam Leffler if (link_state == LINK_STATE_UP) 103894f5c9cfSSam Leffler link = NOTE_LINKUP; 103994f5c9cfSSam Leffler else if (link_state == LINK_STATE_DOWN) 104094f5c9cfSSam Leffler link = NOTE_LINKDOWN; 104194f5c9cfSSam Leffler else 104294f5c9cfSSam Leffler link = NOTE_LINKINV; 104394f5c9cfSSam Leffler KNOTE_UNLOCKED(&ifp->if_klist, link); 104494f5c9cfSSam Leffler if (ifp->if_nvlans != 0) 104594f5c9cfSSam Leffler (*vlan_link_state_p)(ifp, link); 10461c7899c7SGleb Smirnoff 10471c7899c7SGleb Smirnoff if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && 10481c7899c7SGleb Smirnoff IFP2AC(ifp)->ac_netgraph != NULL) 10491c7899c7SGleb Smirnoff (*ng_ether_link_state_p)(ifp, link_state); 10504d96314fSGleb Smirnoff #ifdef DEV_CARP 10514d96314fSGleb Smirnoff if (ifp->if_carp) 10524d96314fSGleb Smirnoff carp_carpdev_state(ifp->if_carp); 10534d96314fSGleb Smirnoff #endif 10548f867517SAndrew Thompson if (ifp->if_bridge) { 10558f867517SAndrew Thompson KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); 10568f867517SAndrew Thompson (*bstp_linkstate_p)(ifp, link_state); 10578f867517SAndrew Thompson } 10588f867517SAndrew Thompson 10599d80a330SBrooks Davis devctl_notify("IFNET", ifp->if_xname, 10609d80a330SBrooks Davis (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", NULL); 106168a3482fSGleb Smirnoff if (pending > 1) 106268a3482fSGleb Smirnoff if_printf(ifp, "%d link states coalesced\n", pending); 10635515c2e7SGleb Smirnoff if (log_link_state_change) 10648b02df24SGleb Smirnoff log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname, 10658b02df24SGleb Smirnoff (link_state == LINK_STATE_UP) ? "UP" : "DOWN" ); 106694f5c9cfSSam Leffler } 106794f5c9cfSSam Leffler 1068df8bae1dSRodney W. Grimes /* 1069e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 1070e8c2601dSPoul-Henning Kamp * the transition. 1071e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1072e8c2601dSPoul-Henning Kamp */ 1073e8c2601dSPoul-Henning Kamp void 107472fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp) 1075e8c2601dSPoul-Henning Kamp { 1076e8c2601dSPoul-Henning Kamp 1077e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 1078e8c2601dSPoul-Henning Kamp } 1079e8c2601dSPoul-Henning Kamp 1080e8c2601dSPoul-Henning Kamp /* 1081e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 1082e8c2601dSPoul-Henning Kamp * the transition. 1083e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 1084e8c2601dSPoul-Henning Kamp */ 1085e8c2601dSPoul-Henning Kamp void 108672fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp) 1087e8c2601dSPoul-Henning Kamp { 1088e8c2601dSPoul-Henning Kamp 1089e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 1090e8c2601dSPoul-Henning Kamp } 1091e8c2601dSPoul-Henning Kamp 1092e8c2601dSPoul-Henning Kamp /* 1093df8bae1dSRodney W. Grimes * Flush an interface queue. 1094df8bae1dSRodney W. Grimes */ 10953bda9f9bSPoul-Henning Kamp static void 109602b199f1SMax Laier if_qflush(struct ifaltq *ifq) 1097df8bae1dSRodney W. Grimes { 109872fd1b6aSDag-Erling Smørgrav struct mbuf *m, *n; 1099df8bae1dSRodney W. Grimes 11007b21048cSMax Laier IFQ_LOCK(ifq); 110102b199f1SMax Laier #ifdef ALTQ 110202b199f1SMax Laier if (ALTQ_IS_ENABLED(ifq)) 110302b199f1SMax Laier ALTQ_PURGE(ifq); 110402b199f1SMax Laier #endif 1105df8bae1dSRodney W. Grimes n = ifq->ifq_head; 11069448326fSPoul-Henning Kamp while ((m = n) != 0) { 1107df8bae1dSRodney W. Grimes n = m->m_act; 1108df8bae1dSRodney W. Grimes m_freem(m); 1109df8bae1dSRodney W. Grimes } 1110df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 1111df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 1112df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 11137b21048cSMax Laier IFQ_UNLOCK(ifq); 1114df8bae1dSRodney W. Grimes } 1115df8bae1dSRodney W. Grimes 1116df8bae1dSRodney W. Grimes /* 1117df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 1118df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 1119df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 1120af5e59bfSRobert Watson * 1121af5e59bfSRobert Watson * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called 1122af5e59bfSRobert Watson * holding Giant. If we switch to an MPSAFE callout, we likely need to grab 1123af5e59bfSRobert Watson * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface. 1124df8bae1dSRodney W. Grimes */ 11253bda9f9bSPoul-Henning Kamp static void 112672fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg) 1127df8bae1dSRodney W. Grimes { 112872fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 1129df8bae1dSRodney W. Grimes int s = splimp(); 1130df8bae1dSRodney W. Grimes 1131b30a244cSJeffrey Hsu IFNET_RLOCK(); 1132fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 1133df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 1134df8bae1dSRodney W. Grimes continue; 1135df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 11364a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 1137df8bae1dSRodney W. Grimes } 1138b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1139df8bae1dSRodney W. Grimes splx(s); 1140df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 1141df8bae1dSRodney W. Grimes } 1142df8bae1dSRodney W. Grimes 1143df8bae1dSRodney W. Grimes /* 1144df8bae1dSRodney W. Grimes * Map interface name to 1145df8bae1dSRodney W. Grimes * interface structure pointer. 1146df8bae1dSRodney W. Grimes */ 1147df8bae1dSRodney W. Grimes struct ifnet * 114830aad87dSBrooks Davis ifunit(const char *name) 1149df8bae1dSRodney W. Grimes { 11508b7805e4SBoris Popov struct ifnet *ifp; 1151df8bae1dSRodney W. Grimes 1152b30a244cSJeffrey Hsu IFNET_RLOCK(); 1153fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 115436c19a57SBrooks Davis if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0) 1155df8bae1dSRodney W. Grimes break; 1156df8bae1dSRodney W. Grimes } 1157b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 1158df8bae1dSRodney W. Grimes return (ifp); 1159df8bae1dSRodney W. Grimes } 1160df8bae1dSRodney W. Grimes 116182cd038dSYoshinobu Inoue /* 1162f13ad206SJonathan Lemon * Hardware specific interface ioctls. 1163df8bae1dSRodney W. Grimes */ 1164f13ad206SJonathan Lemon static int 1165f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) 1166df8bae1dSRodney W. Grimes { 1167f13ad206SJonathan Lemon struct ifreq *ifr; 1168413dd0baSPoul-Henning Kamp struct ifstat *ifs; 1169f13ad206SJonathan Lemon int error = 0; 117062f76486SMaxim Sobolev int new_flags; 117136c19a57SBrooks Davis size_t namelen, onamelen; 117236c19a57SBrooks Davis char new_name[IFNAMSIZ]; 117336c19a57SBrooks Davis struct ifaddr *ifa; 117436c19a57SBrooks Davis struct sockaddr_dl *sdl; 1175df8bae1dSRodney W. Grimes 1176df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 117730aad87dSBrooks Davis switch (cmd) { 1178de593450SJonathan Lemon case SIOCGIFINDEX: 1179de593450SJonathan Lemon ifr->ifr_index = ifp->if_index; 1180de593450SJonathan Lemon break; 1181de593450SJonathan Lemon 1182df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 118362f76486SMaxim Sobolev ifr->ifr_flags = ifp->if_flags & 0xffff; 118462f76486SMaxim Sobolev ifr->ifr_flagshigh = ifp->if_flags >> 16; 1185df8bae1dSRodney W. Grimes break; 1186df8bae1dSRodney W. Grimes 1187016da741SJonathan Lemon case SIOCGIFCAP: 1188016da741SJonathan Lemon ifr->ifr_reqcap = ifp->if_capabilities; 1189016da741SJonathan Lemon ifr->ifr_curcap = ifp->if_capenable; 1190016da741SJonathan Lemon break; 1191016da741SJonathan Lemon 11928f293a63SRobert Watson #ifdef MAC 11938f293a63SRobert Watson case SIOCGIFMAC: 119431566c96SJohn Baldwin error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp); 11958f293a63SRobert Watson break; 11968f293a63SRobert Watson #endif 11978f293a63SRobert Watson 1198df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 1199df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 1200df8bae1dSRodney W. Grimes break; 1201df8bae1dSRodney W. Grimes 1202a7028af7SDavid Greenman case SIOCGIFMTU: 1203a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 1204a7028af7SDavid Greenman break; 1205a7028af7SDavid Greenman 1206074c4a4eSGarrett Wollman case SIOCGIFPHYS: 1207074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 1208074c4a4eSGarrett Wollman break; 1209074c4a4eSGarrett Wollman 1210df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 121144731cabSJohn Baldwin error = suser(td); 12129448326fSPoul-Henning Kamp if (error) 1213df8bae1dSRodney W. Grimes return (error); 121462f76486SMaxim Sobolev new_flags = (ifr->ifr_flags & 0xffff) | 121562f76486SMaxim Sobolev (ifr->ifr_flagshigh << 16); 1216cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 1217cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 12182f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 121962f76486SMaxim Sobolev (new_flags & IFF_UP) == 0) { 1220df8bae1dSRodney W. Grimes int s = splimp(); 1221df8bae1dSRodney W. Grimes if_down(ifp); 1222df8bae1dSRodney W. Grimes splx(s); 122362f76486SMaxim Sobolev } else if (new_flags & IFF_UP && 1224cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 1225df8bae1dSRodney W. Grimes int s = splimp(); 1226df8bae1dSRodney W. Grimes if_up(ifp); 1227df8bae1dSRodney W. Grimes splx(s); 1228df8bae1dSRodney W. Grimes } 1229df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 123062f76486SMaxim Sobolev (new_flags &~ IFF_CANTCHANGE); 1231ffb079beSMaxim Sobolev if (new_flags & IFF_PPROMISC) { 1232ffb079beSMaxim Sobolev /* Permanently promiscuous mode requested */ 1233ffb079beSMaxim Sobolev ifp->if_flags |= IFF_PROMISC; 1234ffb079beSMaxim Sobolev } else if (ifp->if_pcount == 0) { 1235ffb079beSMaxim Sobolev ifp->if_flags &= ~IFF_PROMISC; 1236ffb079beSMaxim Sobolev } 123731302ebfSRobert Watson if (ifp->if_ioctl) { 123831302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1239df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 124031302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 124131302ebfSRobert Watson } 124298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1243df8bae1dSRodney W. Grimes break; 1244df8bae1dSRodney W. Grimes 1245016da741SJonathan Lemon case SIOCSIFCAP: 124644731cabSJohn Baldwin error = suser(td); 1247016da741SJonathan Lemon if (error) 1248016da741SJonathan Lemon return (error); 1249efb4018bSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1250efb4018bSYaroslav Tykhiy return (EOPNOTSUPP); 1251016da741SJonathan Lemon if (ifr->ifr_reqcap & ~ifp->if_capabilities) 1252016da741SJonathan Lemon return (EINVAL); 125331302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1254efb4018bSYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, cmd, data); 125531302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1256efb4018bSYaroslav Tykhiy if (error == 0) 1257efb4018bSYaroslav Tykhiy getmicrotime(&ifp->if_lastchange); 1258016da741SJonathan Lemon break; 1259016da741SJonathan Lemon 12608f293a63SRobert Watson #ifdef MAC 12618f293a63SRobert Watson case SIOCSIFMAC: 126231566c96SJohn Baldwin error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp); 12638f293a63SRobert Watson break; 12648f293a63SRobert Watson #endif 12658f293a63SRobert Watson 126636c19a57SBrooks Davis case SIOCSIFNAME: 126736c19a57SBrooks Davis error = suser(td); 1268bc1470f1SBrooks Davis if (error != 0) 126936c19a57SBrooks Davis return (error); 127036c19a57SBrooks Davis error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL); 1271bc1470f1SBrooks Davis if (error != 0) 127236c19a57SBrooks Davis return (error); 1273bc1470f1SBrooks Davis if (new_name[0] == '\0') 1274bc1470f1SBrooks Davis return (EINVAL); 127536c19a57SBrooks Davis if (ifunit(new_name) != NULL) 127636c19a57SBrooks Davis return (EEXIST); 127736c19a57SBrooks Davis 127825a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 127936c19a57SBrooks Davis /* Announce the departure of the interface. */ 128036c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 128136c19a57SBrooks Davis 128271672bb6SBrooks Davis log(LOG_INFO, "%s: changing name to '%s'\n", 128371672bb6SBrooks Davis ifp->if_xname, new_name); 128471672bb6SBrooks Davis 128536c19a57SBrooks Davis strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); 12869b98ee2cSLuigi Rizzo ifa = ifaddr_byindex(ifp->if_index); 128736c19a57SBrooks Davis IFA_LOCK(ifa); 128836c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_addr; 128936c19a57SBrooks Davis namelen = strlen(new_name); 129036c19a57SBrooks Davis onamelen = sdl->sdl_nlen; 129136c19a57SBrooks Davis /* 129236c19a57SBrooks Davis * Move the address if needed. This is safe because we 129336c19a57SBrooks Davis * allocate space for a name of length IFNAMSIZ when we 129436c19a57SBrooks Davis * create this in if_attach(). 129536c19a57SBrooks Davis */ 129636c19a57SBrooks Davis if (namelen != onamelen) { 129736c19a57SBrooks Davis bcopy(sdl->sdl_data + onamelen, 129836c19a57SBrooks Davis sdl->sdl_data + namelen, sdl->sdl_alen); 129936c19a57SBrooks Davis } 130036c19a57SBrooks Davis bcopy(new_name, sdl->sdl_data, namelen); 130136c19a57SBrooks Davis sdl->sdl_nlen = namelen; 130236c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_netmask; 130336c19a57SBrooks Davis bzero(sdl->sdl_data, onamelen); 130436c19a57SBrooks Davis while (namelen != 0) 130536c19a57SBrooks Davis sdl->sdl_data[--namelen] = 0xff; 130636c19a57SBrooks Davis IFA_UNLOCK(ifa); 130736c19a57SBrooks Davis 130825a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 130936c19a57SBrooks Davis /* Announce the return of the interface. */ 131036c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 131136c19a57SBrooks Davis break; 131236c19a57SBrooks Davis 1313df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 131444731cabSJohn Baldwin error = suser(td); 13159448326fSPoul-Henning Kamp if (error) 1316df8bae1dSRodney W. Grimes return (error); 1317df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 131898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1319df8bae1dSRodney W. Grimes break; 1320df8bae1dSRodney W. Grimes 1321074c4a4eSGarrett Wollman case SIOCSIFPHYS: 132244731cabSJohn Baldwin error = suser(td); 1323e39a0280SGary Palmer if (error) 1324913e410eSYaroslav Tykhiy return (error); 1325913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1326913e410eSYaroslav Tykhiy return (EOPNOTSUPP); 132731302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1328e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 132931302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1330e39a0280SGary Palmer if (error == 0) 133198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1332913e410eSYaroslav Tykhiy break; 1333074c4a4eSGarrett Wollman 1334a7028af7SDavid Greenman case SIOCSIFMTU: 133582cd038dSYoshinobu Inoue { 133682cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 133782cd038dSYoshinobu Inoue 133844731cabSJohn Baldwin error = suser(td); 13399448326fSPoul-Henning Kamp if (error) 1340a7028af7SDavid Greenman return (error); 1341aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 134275ee03cbSDavid Greenman return (EINVAL); 1343f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1344f13ad206SJonathan Lemon return (EOPNOTSUPP); 134531302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1346e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 134731302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 134848f71763SRuslan Ermilov if (error == 0) { 134998b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 135048f71763SRuslan Ermilov rt_ifmsg(ifp); 135148f71763SRuslan Ermilov } 135282cd038dSYoshinobu Inoue /* 135382cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 135482cd038dSYoshinobu Inoue */ 135582cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 135682cd038dSYoshinobu Inoue #ifdef INET6 135782cd038dSYoshinobu Inoue nd6_setmtu(ifp); 135882cd038dSYoshinobu Inoue #endif 135982cd038dSYoshinobu Inoue } 1360f13ad206SJonathan Lemon break; 136182cd038dSYoshinobu Inoue } 1362a7028af7SDavid Greenman 1363df8bae1dSRodney W. Grimes case SIOCADDMULTI: 1364df8bae1dSRodney W. Grimes case SIOCDELMULTI: 136544731cabSJohn Baldwin error = suser(td); 13669448326fSPoul-Henning Kamp if (error) 1367df8bae1dSRodney W. Grimes return (error); 1368477180fbSGarrett Wollman 1369477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 1370477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 1371f13ad206SJonathan Lemon return (EOPNOTSUPP); 1372477180fbSGarrett Wollman 1373477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 1374477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 1375f13ad206SJonathan Lemon return (EINVAL); 1376477180fbSGarrett Wollman 1377477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 1378477180fbSGarrett Wollman struct ifmultiaddr *ifma; 1379477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1380477180fbSGarrett Wollman } else { 1381477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 1382477180fbSGarrett Wollman } 1383e39a0280SGary Palmer if (error == 0) 138498b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1385f13ad206SJonathan Lemon break; 1386df8bae1dSRodney W. Grimes 138741b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 138841b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 138941b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 139041b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 139141b3e8e5SJun-ichiro itojun Hagino #endif 139233841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 1393a912e453SPeter Wemm case SIOCSIFMEDIA: 1394d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 139544731cabSJohn Baldwin error = suser(td); 1396a912e453SPeter Wemm if (error) 1397a912e453SPeter Wemm return (error); 1398f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 1399a912e453SPeter Wemm return (EOPNOTSUPP); 140031302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1401a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 140231302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1403a912e453SPeter Wemm if (error == 0) 140498b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1405f13ad206SJonathan Lemon break; 1406a912e453SPeter Wemm 1407413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 1408413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 1409413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 1410413dd0baSPoul-Henning Kamp 141133841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 141233841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 141333841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 1414a912e453SPeter Wemm case SIOCGIFMEDIA: 1415d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 1416913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 1417a912e453SPeter Wemm return (EOPNOTSUPP); 141831302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1419f13ad206SJonathan Lemon error = (*ifp->if_ioctl)(ifp, cmd, data); 142031302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1421f13ad206SJonathan Lemon break; 1422a912e453SPeter Wemm 1423b106252cSBill Paul case SIOCSIFLLADDR: 142444731cabSJohn Baldwin error = suser(td); 1425b106252cSBill Paul if (error) 1426b106252cSBill Paul return (error); 1427f13ad206SJonathan Lemon error = if_setlladdr(ifp, 142866ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 1429f13ad206SJonathan Lemon break; 143066ce51ceSArchie Cobbs 1431df8bae1dSRodney W. Grimes default: 1432f13ad206SJonathan Lemon error = ENOIOCTL; 1433f13ad206SJonathan Lemon break; 1434f13ad206SJonathan Lemon } 1435f13ad206SJonathan Lemon return (error); 1436f13ad206SJonathan Lemon } 1437f13ad206SJonathan Lemon 1438f13ad206SJonathan Lemon /* 1439f13ad206SJonathan Lemon * Interface ioctls. 1440f13ad206SJonathan Lemon */ 1441f13ad206SJonathan Lemon int 144272fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) 1443f13ad206SJonathan Lemon { 1444f13ad206SJonathan Lemon struct ifnet *ifp; 1445f13ad206SJonathan Lemon struct ifreq *ifr; 1446f13ad206SJonathan Lemon int error; 144762f76486SMaxim Sobolev int oif_flags; 1448f13ad206SJonathan Lemon 1449f13ad206SJonathan Lemon switch (cmd) { 1450f13ad206SJonathan Lemon case SIOCGIFCONF: 1451f13ad206SJonathan Lemon case OSIOCGIFCONF: 1452f13ad206SJonathan Lemon return (ifconf(cmd, data)); 1453f13ad206SJonathan Lemon } 1454f13ad206SJonathan Lemon ifr = (struct ifreq *)data; 1455f13ad206SJonathan Lemon 1456f13ad206SJonathan Lemon switch (cmd) { 1457f13ad206SJonathan Lemon case SIOCIFCREATE: 1458f13ad206SJonathan Lemon case SIOCIFDESTROY: 145944731cabSJohn Baldwin if ((error = suser(td)) != 0) 1460f13ad206SJonathan Lemon return (error); 1461f13ad206SJonathan Lemon return ((cmd == SIOCIFCREATE) ? 1462f13ad206SJonathan Lemon if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 1463f13ad206SJonathan Lemon if_clone_destroy(ifr->ifr_name)); 1464f13ad206SJonathan Lemon 1465f13ad206SJonathan Lemon case SIOCIFGCLONERS: 1466f13ad206SJonathan Lemon return (if_clone_list((struct if_clonereq *)data)); 1467f13ad206SJonathan Lemon } 1468f13ad206SJonathan Lemon 1469f13ad206SJonathan Lemon ifp = ifunit(ifr->ifr_name); 1470f13ad206SJonathan Lemon if (ifp == 0) 1471f13ad206SJonathan Lemon return (ENXIO); 1472f13ad206SJonathan Lemon 1473f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 1474f13ad206SJonathan Lemon if (error != ENOIOCTL) 1475f13ad206SJonathan Lemon return (error); 1476f13ad206SJonathan Lemon 147782cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 1478df8bae1dSRodney W. Grimes if (so->so_proto == 0) 1479df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1480df8bae1dSRodney W. Grimes #ifndef COMPAT_43 148182cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 14822c37256eSGarrett Wollman data, 1483b40ce416SJulian Elischer ifp, td)); 1484df8bae1dSRodney W. Grimes #else 1485df8bae1dSRodney W. Grimes { 1486df8bae1dSRodney W. Grimes int ocmd = cmd; 1487df8bae1dSRodney W. Grimes 1488df8bae1dSRodney W. Grimes switch (cmd) { 1489df8bae1dSRodney W. Grimes 1490df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 1491df8bae1dSRodney W. Grimes case SIOCSIFADDR: 1492df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 1493df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 1494df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 1495df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 1496df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 1497df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1498df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1499df8bae1dSRodney W. Grimes } 1500df8bae1dSRodney W. Grimes #else 1501df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 1502df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1503df8bae1dSRodney W. Grimes #endif 1504df8bae1dSRodney W. Grimes break; 1505df8bae1dSRodney W. Grimes 1506df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1507df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 1508df8bae1dSRodney W. Grimes break; 1509df8bae1dSRodney W. Grimes 1510df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1511df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 1512df8bae1dSRodney W. Grimes break; 1513df8bae1dSRodney W. Grimes 1514df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1515df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 1516df8bae1dSRodney W. Grimes break; 1517df8bae1dSRodney W. Grimes 1518df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1519df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 1520df8bae1dSRodney W. Grimes } 15212c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 15222c37256eSGarrett Wollman cmd, 15232c37256eSGarrett Wollman data, 1524b40ce416SJulian Elischer ifp, td)); 1525df8bae1dSRodney W. Grimes switch (ocmd) { 1526df8bae1dSRodney W. Grimes 1527df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1528df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1529df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1530df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1531df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 153282cd038dSYoshinobu Inoue 153382cd038dSYoshinobu Inoue } 153482cd038dSYoshinobu Inoue } 153582cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 153682cd038dSYoshinobu Inoue 153782cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 153882cd038dSYoshinobu Inoue #ifdef INET6 153988ff5695SSUZUKI Shinsuke DELAY(100);/* XXX: temporary workaround for fxp issue*/ 154082cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 154182cd038dSYoshinobu Inoue int s = splimp(); 154282cd038dSYoshinobu Inoue in6_if_up(ifp); 154382cd038dSYoshinobu Inoue splx(s); 154482cd038dSYoshinobu Inoue } 154582cd038dSYoshinobu Inoue #endif 1546df8bae1dSRodney W. Grimes } 1547df8bae1dSRodney W. Grimes return (error); 1548df8bae1dSRodney W. Grimes } 1549df8bae1dSRodney W. Grimes 1550df8bae1dSRodney W. Grimes /* 1551963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 1552963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 1553963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 1554963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 1555963e4c2aSGarrett Wollman */ 1556963e4c2aSGarrett Wollman int 155772fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch) 1558963e4c2aSGarrett Wollman { 1559963e4c2aSGarrett Wollman struct ifreq ifr; 15604a26224cSGarrett Wollman int error; 15614f3c11a6SBill Fenner int oldflags, oldpcount; 1562963e4c2aSGarrett Wollman 15634f3c11a6SBill Fenner oldpcount = ifp->if_pcount; 15642c514a31SBrian Somers oldflags = ifp->if_flags; 1565ffb079beSMaxim Sobolev if (ifp->if_flags & IFF_PPROMISC) { 1566ffb079beSMaxim Sobolev /* Do nothing if device is in permanently promiscuous mode */ 1567ffb079beSMaxim Sobolev ifp->if_pcount += pswitch ? 1 : -1; 1568ffb079beSMaxim Sobolev return (0); 1569ffb079beSMaxim Sobolev } 1570963e4c2aSGarrett Wollman if (pswitch) { 1571963e4c2aSGarrett Wollman /* 1572963e4c2aSGarrett Wollman * If the device is not configured up, we cannot put it in 1573963e4c2aSGarrett Wollman * promiscuous mode. 1574963e4c2aSGarrett Wollman */ 1575963e4c2aSGarrett Wollman if ((ifp->if_flags & IFF_UP) == 0) 1576963e4c2aSGarrett Wollman return (ENETDOWN); 1577963e4c2aSGarrett Wollman if (ifp->if_pcount++ != 0) 1578963e4c2aSGarrett Wollman return (0); 1579963e4c2aSGarrett Wollman ifp->if_flags |= IFF_PROMISC; 1580963e4c2aSGarrett Wollman } else { 1581963e4c2aSGarrett Wollman if (--ifp->if_pcount > 0) 1582963e4c2aSGarrett Wollman return (0); 1583963e4c2aSGarrett Wollman ifp->if_flags &= ~IFF_PROMISC; 1584963e4c2aSGarrett Wollman } 158562f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 158662f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 158731302ebfSRobert Watson IFF_LOCKGIANT(ifp); 15884a26224cSGarrett Wollman error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 158931302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 15904f3c11a6SBill Fenner if (error == 0) { 15919bf40edeSBrooks Davis log(LOG_INFO, "%s: promiscuous mode %s\n", 15929bf40edeSBrooks Davis ifp->if_xname, 15934f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 15944a26224cSGarrett Wollman rt_ifmsg(ifp); 15954f3c11a6SBill Fenner } else { 15964f3c11a6SBill Fenner ifp->if_pcount = oldpcount; 15972c514a31SBrian Somers ifp->if_flags = oldflags; 15984f3c11a6SBill Fenner } 15994a26224cSGarrett Wollman return error; 1600963e4c2aSGarrett Wollman } 1601963e4c2aSGarrett Wollman 1602963e4c2aSGarrett Wollman /* 1603df8bae1dSRodney W. Grimes * Return interface configuration 1604df8bae1dSRodney W. Grimes * of system. List may be used 1605df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 1606df8bae1dSRodney W. Grimes * other information. 1607df8bae1dSRodney W. Grimes */ 1608df8bae1dSRodney W. Grimes /*ARGSUSED*/ 16093bda9f9bSPoul-Henning Kamp static int 161072fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data) 1611df8bae1dSRodney W. Grimes { 16120b59d917SJonathan Lemon struct ifconf *ifc = (struct ifconf *)data; 16130b59d917SJonathan Lemon struct ifnet *ifp; 16140b59d917SJonathan Lemon struct ifaddr *ifa; 16154dcf2bbbSBrooks Davis struct ifreq ifr; 16164dcf2bbbSBrooks Davis struct sbuf *sb; 16174dcf2bbbSBrooks Davis int error, full = 0, valid_len, max_len; 1618df8bae1dSRodney W. Grimes 16194dcf2bbbSBrooks Davis /* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */ 16204dcf2bbbSBrooks Davis max_len = MAXPHYS - 1; 16214dcf2bbbSBrooks Davis 1622b0b4b28bSXin LI /* Prevent hostile input from being able to crash the system */ 1623b0b4b28bSXin LI if (ifc->ifc_len <= 0) 1624b0b4b28bSXin LI return (EINVAL); 1625b0b4b28bSXin LI 16264dcf2bbbSBrooks Davis again: 16274dcf2bbbSBrooks Davis if (ifc->ifc_len <= max_len) { 16284dcf2bbbSBrooks Davis max_len = ifc->ifc_len; 16294dcf2bbbSBrooks Davis full = 1; 16304dcf2bbbSBrooks Davis } 16314dcf2bbbSBrooks Davis sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN); 16324dcf2bbbSBrooks Davis max_len = 0; 16334dcf2bbbSBrooks Davis valid_len = 0; 16344dcf2bbbSBrooks Davis 1635b30a244cSJeffrey Hsu IFNET_RLOCK(); /* could sleep XXX */ 16360b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 16379bf40edeSBrooks Davis int addrs; 16382624cf89SGarrett Wollman 1639fbd24c5eSColin Percival /* 1640fbd24c5eSColin Percival * Zero the ifr_name buffer to make sure we don't 1641fbd24c5eSColin Percival * disclose the contents of the stack. 1642fbd24c5eSColin Percival */ 1643fbd24c5eSColin Percival memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name)); 1644fbd24c5eSColin Percival 16459bf40edeSBrooks Davis if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)) 16464dcf2bbbSBrooks Davis >= sizeof(ifr.ifr_name)) 16474dcf2bbbSBrooks Davis return (ENAMETOOLONG); 16482624cf89SGarrett Wollman 164975c13541SPoul-Henning Kamp addrs = 0; 16502defe5cdSJonathan Lemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 16512defe5cdSJonathan Lemon struct sockaddr *sa = ifa->ifa_addr; 16522defe5cdSJonathan Lemon 1653a854ed98SJohn Baldwin if (jailed(curthread->td_ucred) && 1654a854ed98SJohn Baldwin prison_if(curthread->td_ucred, sa)) 165575c13541SPoul-Henning Kamp continue; 165675c13541SPoul-Henning Kamp addrs++; 1657df8bae1dSRodney W. Grimes #ifdef COMPAT_43 1658df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 1659df8bae1dSRodney W. Grimes struct osockaddr *osa = 1660df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 1661df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1662df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 16634dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 16644dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1665df8bae1dSRodney W. Grimes } else 1666df8bae1dSRodney W. Grimes #endif 1667df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 1668df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 16694dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 16704dcf2bbbSBrooks Davis max_len += sizeof(ifr); 1671df8bae1dSRodney W. Grimes } else { 16724dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, 16734dcf2bbbSBrooks Davis offsetof(struct ifreq, ifr_addr)); 16744dcf2bbbSBrooks Davis max_len += offsetof(struct ifreq, ifr_addr); 16754dcf2bbbSBrooks Davis sbuf_bcat(sb, sa, sa->sa_len); 16764dcf2bbbSBrooks Davis max_len += sa->sa_len; 1677df8bae1dSRodney W. Grimes } 16784dcf2bbbSBrooks Davis 16794dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 16804dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 1681df8bae1dSRodney W. Grimes } 16824dcf2bbbSBrooks Davis if (addrs == 0) { 168375c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 16844dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 16854dcf2bbbSBrooks Davis max_len += sizeof(ifr); 16864dcf2bbbSBrooks Davis 16874dcf2bbbSBrooks Davis if (!sbuf_overflowed(sb)) 16884dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 168975c13541SPoul-Henning Kamp } 1690df8bae1dSRodney W. Grimes } 1691b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 16924dcf2bbbSBrooks Davis 16934dcf2bbbSBrooks Davis /* 16944dcf2bbbSBrooks Davis * If we didn't allocate enough space (uncommon), try again. If 16954dcf2bbbSBrooks Davis * we have already allocated as much space as we are allowed, 16964dcf2bbbSBrooks Davis * return what we've got. 16974dcf2bbbSBrooks Davis */ 16984dcf2bbbSBrooks Davis if (valid_len != max_len && !full) { 16994dcf2bbbSBrooks Davis sbuf_delete(sb); 17004dcf2bbbSBrooks Davis goto again; 17014dcf2bbbSBrooks Davis } 17024dcf2bbbSBrooks Davis 17034dcf2bbbSBrooks Davis ifc->ifc_len = valid_len; 17045ed8cedcSBrian Feldman sbuf_finish(sb); 17054dcf2bbbSBrooks Davis error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len); 17064dcf2bbbSBrooks Davis sbuf_delete(sb); 1707df8bae1dSRodney W. Grimes return (error); 1708df8bae1dSRodney W. Grimes } 1709df8bae1dSRodney W. Grimes 17101158dfb7SGarrett Wollman /* 17118b25904eSGleb Smirnoff * Just like ifpromisc(), but for all-multicast-reception mode. 17121158dfb7SGarrett Wollman */ 17131158dfb7SGarrett Wollman int 171472fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch) 17151158dfb7SGarrett Wollman { 17161158dfb7SGarrett Wollman int error = 0; 17171158dfb7SGarrett Wollman int s = splimp(); 1718ee0a4f7eSSUZUKI Shinsuke struct ifreq ifr; 17191158dfb7SGarrett Wollman 17201158dfb7SGarrett Wollman if (onswitch) { 17211158dfb7SGarrett Wollman if (ifp->if_amcount++ == 0) { 17221158dfb7SGarrett Wollman ifp->if_flags |= IFF_ALLMULTI; 172362f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 172462f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 172531302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1726ee0a4f7eSSUZUKI Shinsuke error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 172731302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 17281158dfb7SGarrett Wollman } 17291158dfb7SGarrett Wollman } else { 17301158dfb7SGarrett Wollman if (ifp->if_amcount > 1) { 17311158dfb7SGarrett Wollman ifp->if_amcount--; 17321158dfb7SGarrett Wollman } else { 17331158dfb7SGarrett Wollman ifp->if_amcount = 0; 17341158dfb7SGarrett Wollman ifp->if_flags &= ~IFF_ALLMULTI; 173562f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff;; 173662f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 173731302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1738ee0a4f7eSSUZUKI Shinsuke error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 173931302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 17401158dfb7SGarrett Wollman } 17411158dfb7SGarrett Wollman } 17421158dfb7SGarrett Wollman splx(s); 17434a26224cSGarrett Wollman 17444a26224cSGarrett Wollman if (error == 0) 17454a26224cSGarrett Wollman rt_ifmsg(ifp); 17461158dfb7SGarrett Wollman return error; 17471158dfb7SGarrett Wollman } 17481158dfb7SGarrett Wollman 17491158dfb7SGarrett Wollman /* 17501158dfb7SGarrett Wollman * Add a multicast listenership to the interface in question. 17511158dfb7SGarrett Wollman * The link layer provides a routine which converts 17521158dfb7SGarrett Wollman */ 17531158dfb7SGarrett Wollman int 175472fd1b6aSDag-Erling Smørgrav if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct ifmultiaddr **retifma) 17551158dfb7SGarrett Wollman { 17561158dfb7SGarrett Wollman struct sockaddr *llsa, *dupsa; 17571158dfb7SGarrett Wollman int error, s; 17581158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 17591158dfb7SGarrett Wollman 176057af7922SJulian Elischer /* 176157af7922SJulian Elischer * If the matching multicast address already exists 176257af7922SJulian Elischer * then don't add a new one, just add a reference 176357af7922SJulian Elischer */ 17646817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 176557af7922SJulian Elischer if (equal(sa, ifma->ifma_addr)) { 17661158dfb7SGarrett Wollman ifma->ifma_refcount++; 176757af7922SJulian Elischer if (retifma) 176857af7922SJulian Elischer *retifma = ifma; 17691158dfb7SGarrett Wollman return 0; 17701158dfb7SGarrett Wollman } 177157af7922SJulian Elischer } 17721158dfb7SGarrett Wollman 17731158dfb7SGarrett Wollman /* 17741158dfb7SGarrett Wollman * Give the link layer a chance to accept/reject it, and also 17751158dfb7SGarrett Wollman * find out which AF_LINK address this maps to, if it isn't one 17761158dfb7SGarrett Wollman * already. 17771158dfb7SGarrett Wollman */ 17781158dfb7SGarrett Wollman if (ifp->if_resolvemulti) { 17791158dfb7SGarrett Wollman error = ifp->if_resolvemulti(ifp, &llsa, sa); 17801158dfb7SGarrett Wollman if (error) return error; 17811158dfb7SGarrett Wollman } else { 17821158dfb7SGarrett Wollman llsa = 0; 17831158dfb7SGarrett Wollman } 17841158dfb7SGarrett Wollman 1785a163d034SWarner Losh MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); 1786a163d034SWarner Losh MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); 17871158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 17881158dfb7SGarrett Wollman 17891158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 17901158dfb7SGarrett Wollman ifma->ifma_lladdr = llsa; 17911158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 17921158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1793d4d22970SGleb Smirnoff ifma->ifma_protospec = NULL; 1794477180fbSGarrett Wollman rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1795373f88edSGarrett Wollman 17961158dfb7SGarrett Wollman /* 17971158dfb7SGarrett Wollman * Some network interfaces can scan the address list at 17981158dfb7SGarrett Wollman * interrupt time; lock them out. 17991158dfb7SGarrett Wollman */ 18001158dfb7SGarrett Wollman s = splimp(); 18016817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 18021158dfb7SGarrett Wollman splx(s); 180313990766SJonathan Mini if (retifma != NULL) 1804373f88edSGarrett Wollman *retifma = ifma; 18051158dfb7SGarrett Wollman 18061158dfb7SGarrett Wollman if (llsa != 0) { 18076817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 18081158dfb7SGarrett Wollman if (equal(ifma->ifma_addr, llsa)) 18091158dfb7SGarrett Wollman break; 18101158dfb7SGarrett Wollman } 18111158dfb7SGarrett Wollman if (ifma) { 18121158dfb7SGarrett Wollman ifma->ifma_refcount++; 18131158dfb7SGarrett Wollman } else { 18141158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, 1815a163d034SWarner Losh M_IFMADDR, M_WAITOK); 1816477180fbSGarrett Wollman MALLOC(dupsa, struct sockaddr *, llsa->sa_len, 1817a163d034SWarner Losh M_IFMADDR, M_WAITOK); 1818477180fbSGarrett Wollman bcopy(llsa, dupsa, llsa->sa_len); 1819477180fbSGarrett Wollman ifma->ifma_addr = dupsa; 182089eaef50SHajimu UMEMOTO ifma->ifma_lladdr = NULL; 18211158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 18221158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1823d4d22970SGleb Smirnoff ifma->ifma_protospec = NULL; 18241158dfb7SGarrett Wollman s = splimp(); 18256817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 18261158dfb7SGarrett Wollman splx(s); 18271158dfb7SGarrett Wollman } 182857af7922SJulian Elischer } 18291158dfb7SGarrett Wollman /* 18301158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 18311158dfb7SGarrett Wollman * interface to let them know about it. 18321158dfb7SGarrett Wollman */ 18331158dfb7SGarrett Wollman s = splimp(); 183431302ebfSRobert Watson IFF_LOCKGIANT(ifp); 18351158dfb7SGarrett Wollman ifp->if_ioctl(ifp, SIOCADDMULTI, 0); 183631302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 18371158dfb7SGarrett Wollman splx(s); 18381158dfb7SGarrett Wollman 18391158dfb7SGarrett Wollman return 0; 18401158dfb7SGarrett Wollman } 18411158dfb7SGarrett Wollman 18421158dfb7SGarrett Wollman /* 18431158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 18441158dfb7SGarrett Wollman * if the request does not match an existing membership. 18451158dfb7SGarrett Wollman */ 18461158dfb7SGarrett Wollman int 184772fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa) 18481158dfb7SGarrett Wollman { 18491158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 18501158dfb7SGarrett Wollman int s; 18511158dfb7SGarrett Wollman 18526817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 18531158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 18541158dfb7SGarrett Wollman break; 18551158dfb7SGarrett Wollman if (ifma == 0) 18561158dfb7SGarrett Wollman return ENOENT; 18571158dfb7SGarrett Wollman 18581158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 18591158dfb7SGarrett Wollman ifma->ifma_refcount--; 18601158dfb7SGarrett Wollman return 0; 18611158dfb7SGarrett Wollman } 18621158dfb7SGarrett Wollman 1863477180fbSGarrett Wollman rt_newmaddrmsg(RTM_DELMADDR, ifma); 18641158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 18651158dfb7SGarrett Wollman s = splimp(); 18666817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1867ccb7cc8dSYaroslav Tykhiy /* 1868ccb7cc8dSYaroslav Tykhiy * Make sure the interface driver is notified 1869ccb7cc8dSYaroslav Tykhiy * in the case of a link layer mcast group being left. 1870ccb7cc8dSYaroslav Tykhiy */ 187131302ebfSRobert Watson if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) { 187231302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1873ccb7cc8dSYaroslav Tykhiy ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 187431302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 187531302ebfSRobert Watson } 18761158dfb7SGarrett Wollman splx(s); 18771158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 18781158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 18791158dfb7SGarrett Wollman if (sa == 0) 18801158dfb7SGarrett Wollman return 0; 18811158dfb7SGarrett Wollman 18821158dfb7SGarrett Wollman /* 18831158dfb7SGarrett Wollman * Now look for the link-layer address which corresponds to 18841158dfb7SGarrett Wollman * this network address. It had been squirreled away in 18851158dfb7SGarrett Wollman * ifma->ifma_lladdr for this purpose (so we don't have 18861158dfb7SGarrett Wollman * to call ifp->if_resolvemulti() again), and we saved that 18871158dfb7SGarrett Wollman * value in sa above. If some nasty deleted the 18881158dfb7SGarrett Wollman * link-layer address out from underneath us, we can deal because 18891158dfb7SGarrett Wollman * the address we stored was is not the same as the one which was 18901158dfb7SGarrett Wollman * in the record for the link-layer address. (So we don't complain 18911158dfb7SGarrett Wollman * in that case.) 18921158dfb7SGarrett Wollman */ 18936817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 18941158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 18951158dfb7SGarrett Wollman break; 18961158dfb7SGarrett Wollman if (ifma == 0) 18971158dfb7SGarrett Wollman return 0; 18981158dfb7SGarrett Wollman 18991158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 19001158dfb7SGarrett Wollman ifma->ifma_refcount--; 19011158dfb7SGarrett Wollman return 0; 19021158dfb7SGarrett Wollman } 19031158dfb7SGarrett Wollman 19041158dfb7SGarrett Wollman s = splimp(); 19056817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 190631302ebfSRobert Watson IFF_LOCKGIANT(ifp); 1907c7323482SBill Paul ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 190831302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 19091158dfb7SGarrett Wollman splx(s); 19101158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 19111158dfb7SGarrett Wollman free(sa, M_IFMADDR); 19121158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 19131158dfb7SGarrett Wollman 19141158dfb7SGarrett Wollman return 0; 19151158dfb7SGarrett Wollman } 19161158dfb7SGarrett Wollman 191766ce51ceSArchie Cobbs /* 191866ce51ceSArchie Cobbs * Set the link layer address on an interface. 191966ce51ceSArchie Cobbs * 192066ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 192166ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 192266ce51ceSArchie Cobbs */ 192366ce51ceSArchie Cobbs int 192466ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 192566ce51ceSArchie Cobbs { 192666ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 192766ce51ceSArchie Cobbs struct ifaddr *ifa; 1928d637e989SPeter Wemm struct ifreq ifr; 192966ce51ceSArchie Cobbs 1930f9132cebSJonathan Lemon ifa = ifaddr_byindex(ifp->if_index); 193166ce51ceSArchie Cobbs if (ifa == NULL) 193266ce51ceSArchie Cobbs return (EINVAL); 193366ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 193466ce51ceSArchie Cobbs if (sdl == NULL) 193566ce51ceSArchie Cobbs return (EINVAL); 193666ce51ceSArchie Cobbs if (len != sdl->sdl_alen) /* don't allow length to change */ 193766ce51ceSArchie Cobbs return (EINVAL); 193866ce51ceSArchie Cobbs switch (ifp->if_type) { 193966ce51ceSArchie Cobbs case IFT_ETHER: /* these types use struct arpcom */ 194066ce51ceSArchie Cobbs case IFT_FDDI: 194166ce51ceSArchie Cobbs case IFT_XETHER: 194266ce51ceSArchie Cobbs case IFT_ISO88025: 1943b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 19448f867517SAndrew Thompson case IFT_BRIDGE: 19453fefbff0SLuigi Rizzo bcopy(lladdr, IFP2AC(ifp)->ac_enaddr, len); 19469046571fSLuigi Rizzo /* 19479046571fSLuigi Rizzo * XXX We also need to store the lladdr in LLADDR(sdl), 19489046571fSLuigi Rizzo * which is done below. This is a pain because we must 19499046571fSLuigi Rizzo * remember to keep the info in sync. 19509046571fSLuigi Rizzo */ 19516cdcc159SMax Khon /* FALLTHROUGH */ 19526cdcc159SMax Khon case IFT_ARCNET: 195366ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 195466ce51ceSArchie Cobbs break; 195566ce51ceSArchie Cobbs default: 195666ce51ceSArchie Cobbs return (ENODEV); 195766ce51ceSArchie Cobbs } 195866ce51ceSArchie Cobbs /* 195966ce51ceSArchie Cobbs * If the interface is already up, we need 196066ce51ceSArchie Cobbs * to re-init it in order to reprogram its 196166ce51ceSArchie Cobbs * address filter. 196266ce51ceSArchie Cobbs */ 196366ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 196431302ebfSRobert Watson IFF_LOCKGIANT(ifp); 196566ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 196662f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 196762f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 1968ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 196966ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 197062f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 197162f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 1972ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 197331302ebfSRobert Watson IFF_UNLOCKGIANT(ifp); 1974b2c08f43SLuigi Rizzo #ifdef INET 1975b2c08f43SLuigi Rizzo /* 1976b2c08f43SLuigi Rizzo * Also send gratuitous ARPs to notify other nodes about 1977b2c08f43SLuigi Rizzo * the address change. 1978b2c08f43SLuigi Rizzo */ 1979b2c08f43SLuigi Rizzo TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1980b2c08f43SLuigi Rizzo if (ifa->ifa_addr != NULL && 1981b2c08f43SLuigi Rizzo ifa->ifa_addr->sa_family == AF_INET) 1982c0933269SPeter Wemm arp_ifinit(ifp, ifa); 1983b2c08f43SLuigi Rizzo } 1984b2c08f43SLuigi Rizzo #endif 198566ce51ceSArchie Cobbs } 198666ce51ceSArchie Cobbs return (0); 198766ce51ceSArchie Cobbs } 198866ce51ceSArchie Cobbs 1989373f88edSGarrett Wollman struct ifmultiaddr * 199072fd1b6aSDag-Erling Smørgrav ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp) 1991373f88edSGarrett Wollman { 1992373f88edSGarrett Wollman struct ifmultiaddr *ifma; 1993373f88edSGarrett Wollman 19946817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1995373f88edSGarrett Wollman if (equal(ifma->ifma_addr, sa)) 1996373f88edSGarrett Wollman break; 1997373f88edSGarrett Wollman 1998373f88edSGarrett Wollman return ifma; 1999373f88edSGarrett Wollman } 2000373f88edSGarrett Wollman 20019bf40edeSBrooks Davis /* 20029bf40edeSBrooks Davis * The name argument must be a pointer to storage which will last as 20039bf40edeSBrooks Davis * long as the interface does. For physical devices, the result of 20049bf40edeSBrooks Davis * device_get_name(dev) is a good choice and for pseudo-devices a 20059bf40edeSBrooks Davis * static string works well. 20069bf40edeSBrooks Davis */ 20079bf40edeSBrooks Davis void 20089bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit) 20099bf40edeSBrooks Davis { 20109bf40edeSBrooks Davis ifp->if_dname = name; 20119bf40edeSBrooks Davis ifp->if_dunit = unit; 20129bf40edeSBrooks Davis if (unit != IF_DUNIT_NONE) 20139bf40edeSBrooks Davis snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit); 20149bf40edeSBrooks Davis else 20159bf40edeSBrooks Davis strlcpy(ifp->if_xname, name, IFNAMSIZ); 20169bf40edeSBrooks Davis } 20179bf40edeSBrooks Davis 2018fa882e87SBrooks Davis int 2019fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...) 2020fa882e87SBrooks Davis { 2021fa882e87SBrooks Davis va_list ap; 2022fa882e87SBrooks Davis int retval; 2023fa882e87SBrooks Davis 20249bf40edeSBrooks Davis retval = printf("%s: ", ifp->if_xname); 2025fa882e87SBrooks Davis va_start(ap, fmt); 2026fa882e87SBrooks Davis retval += vprintf(fmt, ap); 2027fa882e87SBrooks Davis va_end(ap); 2028fa882e87SBrooks Davis return (retval); 2029fa882e87SBrooks Davis } 2030fa882e87SBrooks Davis 2031af5e59bfSRobert Watson /* 2032af5e59bfSRobert Watson * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot 2033af5e59bfSRobert Watson * be called without Giant. However, we often can't acquire the Giant lock 2034af5e59bfSRobert Watson * at those points; instead, we run it via a task queue that holds Giant via 2035af5e59bfSRobert Watson * if_start_deferred. 2036af5e59bfSRobert Watson * 2037af5e59bfSRobert Watson * XXXRW: We need to make sure that the ifnet isn't fully detached until any 2038af5e59bfSRobert Watson * outstanding if_start_deferred() tasks that will run after the free. This 2039af5e59bfSRobert Watson * probably means waiting in if_detach(). 2040af5e59bfSRobert Watson */ 2041af5e59bfSRobert Watson void 2042af5e59bfSRobert Watson if_start(struct ifnet *ifp) 2043af5e59bfSRobert Watson { 2044af5e59bfSRobert Watson 2045af5e59bfSRobert Watson NET_ASSERT_GIANT(); 2046af5e59bfSRobert Watson 2047af5e59bfSRobert Watson if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) { 2048af5e59bfSRobert Watson if (mtx_owned(&Giant)) 2049af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2050af5e59bfSRobert Watson else 2051af5e59bfSRobert Watson taskqueue_enqueue(taskqueue_swi_giant, 2052af5e59bfSRobert Watson &ifp->if_starttask); 2053af5e59bfSRobert Watson } else 2054af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 2055af5e59bfSRobert Watson } 2056af5e59bfSRobert Watson 2057af5e59bfSRobert Watson static void 2058af5e59bfSRobert Watson if_start_deferred(void *context, int pending) 2059af5e59bfSRobert Watson { 2060af5e59bfSRobert Watson struct ifnet *ifp; 2061af5e59bfSRobert Watson 2062af5e59bfSRobert Watson /* 2063af5e59bfSRobert Watson * This code must be entered with Giant, and should never run if 2064af5e59bfSRobert Watson * we're not running with debug.mpsafenet. 2065af5e59bfSRobert Watson */ 2066af5e59bfSRobert Watson KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet")); 2067af5e59bfSRobert Watson GIANT_REQUIRED; 2068af5e59bfSRobert Watson 2069af5e59bfSRobert Watson ifp = (struct ifnet *)context; 2070af5e59bfSRobert Watson (ifp->if_start)(ifp); 2071af5e59bfSRobert Watson } 2072af5e59bfSRobert Watson 20730b762445SRobert Watson int 20740b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) 20750b762445SRobert Watson { 20760b762445SRobert Watson int active = 0; 20770b762445SRobert Watson 20780b762445SRobert Watson IF_LOCK(ifq); 20790b762445SRobert Watson if (_IF_QFULL(ifq)) { 20800b762445SRobert Watson _IF_DROP(ifq); 20810b762445SRobert Watson IF_UNLOCK(ifq); 20820b762445SRobert Watson m_freem(m); 20830b762445SRobert Watson return (0); 20840b762445SRobert Watson } 20850b762445SRobert Watson if (ifp != NULL) { 20860b762445SRobert Watson ifp->if_obytes += m->m_pkthdr.len + adjust; 20870b762445SRobert Watson if (m->m_flags & (M_BCAST|M_MCAST)) 20880b762445SRobert Watson ifp->if_omcasts++; 20890b762445SRobert Watson active = ifp->if_flags & IFF_OACTIVE; 20900b762445SRobert Watson } 20910b762445SRobert Watson _IF_ENQUEUE(ifq, m); 20920b762445SRobert Watson IF_UNLOCK(ifq); 20930b762445SRobert Watson if (ifp != NULL && !active) 20940b762445SRobert Watson if_start(ifp); 20950b762445SRobert Watson return (1); 20960b762445SRobert Watson } 2097