if.c revision 101184
136285Sbrian/* 236285Sbrian * Copyright (c) 1980, 1986, 1993 336285Sbrian * The Regents of the University of California. All rights reserved. 436285Sbrian * 536285Sbrian * Redistribution and use in source and binary forms, with or without 636285Sbrian * modification, are permitted provided that the following conditions 736285Sbrian * are met: 836285Sbrian * 1. Redistributions of source code must retain the above copyright 936285Sbrian * notice, this list of conditions and the following disclaimer. 1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer in the 1236285Sbrian * documentation and/or other materials provided with the distribution. 1336285Sbrian * 3. All advertising materials mentioning features or use of this software 1436285Sbrian * must display the following acknowledgement: 1536285Sbrian * This product includes software developed by the University of 1636285Sbrian * California, Berkeley and its contributors. 1736285Sbrian * 4. Neither the name of the University nor the names of its contributors 1836285Sbrian * may be used to endorse or promote products derived from this software 1936285Sbrian * without specific prior written permission. 2036285Sbrian * 2136285Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2236285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2336285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2436285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2536285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2650479Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2736285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2836285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2943313Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3036285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3136285Sbrian * SUCH DAMAGE. 3236285Sbrian * 3336285Sbrian * @(#)if.c 8.5 (Berkeley) 1/9/95 3436285Sbrian * $FreeBSD: head/sys/net/if.c 101184 2002-08-01 21:15:53Z rwatson $ 3536285Sbrian */ 3636285Sbrian 3736285Sbrian#include "opt_compat.h" 3836285Sbrian#include "opt_inet6.h" 3936285Sbrian#include "opt_inet.h" 4036285Sbrian#include "opt_mac.h" 4136285Sbrian 4236285Sbrian#include <sys/param.h> 4336285Sbrian#include <sys/conf.h> 4436285Sbrian#include <sys/mac.h> 4536285Sbrian#include <sys/malloc.h> 4636285Sbrian#include <sys/bus.h> 4746686Sbrian#include <sys/mbuf.h> 4850059Sbrian#include <sys/systm.h> 4951075Sbrian#include <sys/proc.h> 5046686Sbrian#include <sys/socket.h> 5146686Sbrian#include <sys/socketvar.h> 5238814Sbrian#include <sys/protosw.h> 5337009Sbrian#include <sys/kernel.h> 5436285Sbrian#include <sys/sockio.h> 5536285Sbrian#include <sys/syslog.h> 5636285Sbrian#include <sys/sysctl.h> 5736285Sbrian#include <sys/jail.h> 5836285Sbrian 5936285Sbrian#include <net/if.h> 6036285Sbrian#include <net/if_arp.h> 6136285Sbrian#include <net/if_dl.h> 6238557Sbrian#include <net/if_types.h> 6338557Sbrian#include <net/if_var.h> 6436285Sbrian#include <net/radix.h> 6536285Sbrian#include <net/route.h> 6636285Sbrian 6736285Sbrian#if defined(INET) || defined(INET6) 6836285Sbrian/*XXX*/ 6936285Sbrian#include <netinet/in.h> 7036285Sbrian#include <netinet/in_var.h> 7136285Sbrian#ifdef INET6 7236285Sbrian#include <netinet6/in6_var.h> 7346686Sbrian#include <netinet6/in6_ifattach.h> 7436285Sbrian#endif 7536285Sbrian#endif 7636285Sbrian#ifdef INET 7738174Sbrian#include <netinet/if_ether.h> 7836285Sbrian#endif 7943313Sbrian 8043313Sbrianstatic int ifconf(u_long, caddr_t); 8143313Sbrianstatic void if_grow(void); 8236285Sbrianstatic void if_init(void *); 8336285Sbrianstatic void if_check(void *); 8436285Sbrianstatic int if_findindex(struct ifnet *); 8536285Sbrianstatic void if_qflush(struct ifqueue *); 8636285Sbrianstatic void if_slowtimo(void *); 8736285Sbrianstatic void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); 8836285Sbrianstatic int if_rtdel(struct radix_node *, void *); 8936285Sbrianstatic struct if_clone *if_clone_lookup(const char *, int *); 9036285Sbrianstatic int if_clone_list(struct if_clonereq *); 9136285Sbrianstatic int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *); 9236285Sbrian#ifdef INET6 9336285Sbrian/* 9436285Sbrian * XXX: declare here to avoid to include many inet6 related files.. 9536285Sbrian * should be more generalized? 9636285Sbrian */ 9736285Sbrianextern void nd6_setmtu(struct ifnet *); 9836285Sbrian#endif 9936285Sbrian 10036285Sbrianint if_index = 0; 10136285Sbrianstruct ifindex_entry *ifindex_table = NULL; 10236285Sbrianint ifqmaxlen = IFQ_MAXLEN; 10336285Sbrianstruct ifnethead ifnet; /* depend on static init XXX */ 10436285Sbrianint if_cloners_count; 10536285SbrianLIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 10636285Sbrian 10736285Sbrianstatic int if_indexlim = 8; 10836285Sbrianstatic struct klist ifklist; 10936285Sbrian 11036285Sbrianstatic void filt_netdetach(struct knote *kn); 11136285Sbrianstatic int filt_netdev(struct knote *kn, long hint); 11236285Sbrian 11336285Sbrianstatic struct filterops netdev_filtops = 11436285Sbrian { 1, NULL, filt_netdetach, filt_netdev }; 11536285Sbrian 11636285Sbrian/* 11736285Sbrian * System initialization 11836285Sbrian */ 11936285SbrianSYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL) 12036285SbrianSYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL) 12136285Sbrian 12236285SbrianMALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 12336285SbrianMALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 12436285SbrianMALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 12536285Sbrian 12636285Sbrian#define CDEV_MAJOR 165 12736285Sbrian 12836285Sbrianstatic d_open_t netopen; 12936285Sbrianstatic d_close_t netclose; 13036285Sbrianstatic d_ioctl_t netioctl; 13136285Sbrianstatic d_kqfilter_t netkqfilter; 13236285Sbrian 13336285Sbrianstatic struct cdevsw net_cdevsw = { 13436285Sbrian /* open */ netopen, 13536285Sbrian /* close */ netclose, 13638814Sbrian /* read */ noread, 13738814Sbrian /* write */ nowrite, 13838814Sbrian /* ioctl */ netioctl, 13938814Sbrian /* poll */ nopoll, 14036285Sbrian /* mmap */ nommap, 14136285Sbrian /* strategy */ nostrategy, 14236285Sbrian /* name */ "net", 14338814Sbrian /* maj */ CDEV_MAJOR, 14438814Sbrian /* dump */ nodump, 14538814Sbrian /* psize */ nopsize, 14636285Sbrian /* flags */ D_KQFILTER, 14736285Sbrian /* kqfilter */ netkqfilter, 14838814Sbrian}; 14936285Sbrian 15036285Sbrianstatic int 15136285Sbriannetopen(dev_t dev, int flag, int mode, struct thread *td) 15236285Sbrian{ 15336285Sbrian return (0); 15436285Sbrian} 15536285Sbrian 15636285Sbrianstatic int 15736285Sbriannetclose(dev_t dev, int flags, int fmt, struct thread *td) 15836285Sbrian{ 15936285Sbrian return (0); 16036285Sbrian} 16136285Sbrian 16236285Sbrianstatic int 16336285Sbriannetioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 16436285Sbrian{ 16536285Sbrian struct ifnet *ifp; 16636285Sbrian int error, idx; 16736285Sbrian 16836285Sbrian /* only support interface specific ioctls */ 16936285Sbrian if (IOCGROUP(cmd) != 'i') 17036285Sbrian return (EOPNOTSUPP); 17136285Sbrian idx = minor(dev); 17236285Sbrian if (idx == 0) { 17336285Sbrian /* 17436285Sbrian * special network device, not interface. 17536285Sbrian */ 17636285Sbrian if (cmd == SIOCGIFCONF) 17736285Sbrian return (ifconf(cmd, data)); /* XXX remove cmd */ 17836285Sbrian return (EOPNOTSUPP); 17936285Sbrian } 18036285Sbrian 18136285Sbrian ifp = ifnet_byindex(idx); 18236285Sbrian if (ifp == NULL) 18336285Sbrian return (ENXIO); 18436285Sbrian 18536285Sbrian error = ifhwioctl(cmd, ifp, data, td); 18649434Sbrian if (error == ENOIOCTL) 18749434Sbrian error = EOPNOTSUPP; 18849434Sbrian return (error); 18949434Sbrian} 19049434Sbrian 19149434Sbrianstatic int 19249434Sbriannetkqfilter(dev_t dev, struct knote *kn) 19349434Sbrian{ 19449434Sbrian struct klist *klist; 19549434Sbrian struct ifnet *ifp; 19649434Sbrian int idx; 19749434Sbrian 19849434Sbrian idx = minor(dev); 19949434Sbrian if (idx == 0) { 20049434Sbrian klist = &ifklist; 20149434Sbrian } else { 20236285Sbrian ifp = ifnet_byindex(idx); 20349434Sbrian if (ifp == NULL) 20449434Sbrian return (1); 20549434Sbrian klist = &ifp->if_klist; 20649434Sbrian } 20749434Sbrian 20849434Sbrian switch (kn->kn_filter) { 20949434Sbrian case EVFILT_NETDEV: 21049434Sbrian kn->kn_fop = &netdev_filtops; 21149434Sbrian break; 21249434Sbrian default: 21349434Sbrian return (1); 21449434Sbrian } 21549434Sbrian 21649434Sbrian kn->kn_hook = (caddr_t)klist; 21749434Sbrian 21849434Sbrian /* XXX locking? */ 21949434Sbrian SLIST_INSERT_HEAD(klist, kn, kn_selnext); 22049434Sbrian 22149434Sbrian return (0); 22249434Sbrian} 22349434Sbrian 22449434Sbrianstatic void 22549434Sbrianfilt_netdetach(struct knote *kn) 22649434Sbrian{ 22749434Sbrian struct klist *klist = (struct klist *)kn->kn_hook; 22849434Sbrian 22949434Sbrian if (kn->kn_status & KN_DETACHED) 23049434Sbrian return; 23149434Sbrian SLIST_REMOVE(klist, kn, knote, kn_selnext); 23249434Sbrian} 23336285Sbrian 23436285Sbrianstatic int 23536285Sbrianfilt_netdev(struct knote *kn, long hint) 23636285Sbrian{ 23736285Sbrian 23836285Sbrian /* 23936285Sbrian * Currently NOTE_EXIT is abused to indicate device detach. 24036285Sbrian */ 24136285Sbrian if (hint == NOTE_EXIT) { 24236285Sbrian kn->kn_data = NOTE_LINKINV; 24336285Sbrian kn->kn_status |= KN_DETACHED; 24436285Sbrian kn->kn_flags |= (EV_EOF | EV_ONESHOT); 24536285Sbrian return (1); 24636285Sbrian } 24746686Sbrian kn->kn_data = hint; /* current status */ 24836285Sbrian if (kn->kn_sfflags & hint) 24936285Sbrian kn->kn_fflags |= hint; 25036285Sbrian return (kn->kn_fflags != 0); 25149434Sbrian} 25249434Sbrian 25349434Sbrian/* 25449434Sbrian * Network interface utility routines. 25536285Sbrian * 25636285Sbrian * Routines with ifa_ifwith* names take sockaddr *'s as 25736285Sbrian * parameters. 25836285Sbrian */ 25936285Sbrian/* ARGSUSED*/ 26036285Sbrianstatic void 26136285Sbrianif_init(dummy) 26236285Sbrian void *dummy; 26336285Sbrian{ 26436285Sbrian 26536285Sbrian TAILQ_INIT(&ifnet); 26636285Sbrian SLIST_INIT(&ifklist); 26736285Sbrian if_grow(); /* create initial table */ 26836285Sbrian ifdev_byindex(0) = make_dev(&net_cdevsw, 0, 26947858Sbrian UID_ROOT, GID_WHEEL, 0600, "network"); 27036285Sbrian} 27136285Sbrian 27236285Sbrianstatic void 27336285Sbrianif_grow(void) 27436285Sbrian{ 27536285Sbrian u_int n; 27646686Sbrian struct ifindex_entry *e; 27746686Sbrian 27846686Sbrian if_indexlim <<= 1; 27946686Sbrian n = if_indexlim * sizeof(*e); 28046686Sbrian e = malloc(n, M_IFADDR, M_WAITOK | M_ZERO); 28150059Sbrian if (ifindex_table != NULL) { 28250059Sbrian memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2); 28346686Sbrian free((caddr_t)ifindex_table, M_IFADDR); 28436285Sbrian } 28536285Sbrian ifindex_table = e; 28636285Sbrian} 28736285Sbrian 28836285Sbrian/* ARGSUSED*/ 28936285Sbrianstatic void 29036285Sbrianif_check(dummy) 29136285Sbrian void *dummy; 29236285Sbrian{ 29336285Sbrian struct ifnet *ifp; 29436285Sbrian int s; 29560778Sbrian 29660778Sbrian s = splimp(); 29760778Sbrian TAILQ_FOREACH(ifp, &ifnet, if_link) { 29860778Sbrian if (ifp->if_snd.ifq_maxlen == 0) { 29960778Sbrian printf("%s%d XXX: driver didn't set ifq_maxlen\n", 30060778Sbrian ifp->if_name, ifp->if_unit); 30136285Sbrian ifp->if_snd.ifq_maxlen = ifqmaxlen; 30236285Sbrian } 30336285Sbrian if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 30436285Sbrian printf("%s%d XXX: driver didn't initialize queue mtx\n", 30536285Sbrian ifp->if_name, ifp->if_unit); 30636285Sbrian mtx_init(&ifp->if_snd.ifq_mtx, "unknown", 30736285Sbrian MTX_NETWORK_LOCK, MTX_DEF); 30836285Sbrian } 30936285Sbrian } 31036285Sbrian splx(s); 31136285Sbrian if_slowtimo(0); 31236285Sbrian} 31336285Sbrian 31436285Sbrianstatic int 31536285Sbrianif_findindex(struct ifnet *ifp) 31636285Sbrian{ 31736285Sbrian int i, unit; 31836285Sbrian char eaddr[18], devname[32]; 31936285Sbrian const char *name, *p; 32036285Sbrian 32149434Sbrian switch (ifp->if_type) { 32249434Sbrian case IFT_ETHER: /* these types use struct arpcom */ 32349434Sbrian case IFT_FDDI: 32436285Sbrian case IFT_XETHER: 32536285Sbrian case IFT_ISO88025: 32636285Sbrian case IFT_L2VLAN: 32736285Sbrian snprintf(eaddr, 18, "%6D", 32836285Sbrian ((struct arpcom *)ifp->if_softc)->ac_enaddr, ":"); 32936285Sbrian break; 33036285Sbrian default: 33136285Sbrian eaddr[0] = '\0'; 33236285Sbrian break; 33336285Sbrian } 33436285Sbrian snprintf(devname, 32, "%s%d", ifp->if_name, ifp->if_unit); 33536285Sbrian name = net_cdevsw.d_name; 33636285Sbrian i = 0; 33736285Sbrian while ((resource_find_dev(&i, name, &unit, NULL, NULL)) == 0) { 33836285Sbrian if (resource_string_value(name, unit, "ether", &p) == 0) 33936285Sbrian if (strcmp(p, eaddr) == 0) 34036285Sbrian goto found; 34136285Sbrian if (resource_string_value(name, unit, "dev", &p) == 0) 34236285Sbrian if (strcmp(p, devname) == 0) 34336285Sbrian goto found; 34436285Sbrian } 34536285Sbrian unit = 0; 34636285Sbrianfound: 34736285Sbrian if (unit != 0) { 34836285Sbrian if (ifaddr_byindex(unit) == NULL) 34936285Sbrian return (unit); 35036285Sbrian printf("%s%d in use, cannot hardwire it to %s.\n", 35136285Sbrian name, unit, devname); 35236285Sbrian } 35337320Sbrian for (unit = 1; ; unit++) { 35437320Sbrian if (unit <= if_index && ifaddr_byindex(unit) != NULL) 35537320Sbrian continue; 35637320Sbrian if (resource_string_value(name, unit, "ether", &p) == 0 || 35736285Sbrian resource_string_value(name, unit, "dev", &p) == 0) 35836285Sbrian continue; 35936285Sbrian break; 36036285Sbrian } 36136285Sbrian return (unit); 36236285Sbrian} 36336285Sbrian 36436285Sbrian/* 36536285Sbrian * Attach an interface to the 36636285Sbrian * list of "active" interfaces. 36736285Sbrian */ 36836285Sbrianvoid 36936285Sbrianif_attach(ifp) 37036285Sbrian struct ifnet *ifp; 37136285Sbrian{ 37249434Sbrian unsigned socksize, ifasize; 37349434Sbrian int namelen, masklen; 37449434Sbrian char workbuf[64]; 37536285Sbrian register struct sockaddr_dl *sdl; 37636285Sbrian register struct ifaddr *ifa; 37736285Sbrian 37836285Sbrian TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 37937060Sbrian /* 38036285Sbrian * XXX - 38136285Sbrian * The old code would work if the interface passed a pre-existing 38236285Sbrian * chain of ifaddrs to this code. We don't trust our callers to 38354912Sbrian * properly initialize the tailq, however, so we no longer allow 38454912Sbrian * this unlikely case. 38536285Sbrian */ 38636285Sbrian TAILQ_INIT(&ifp->if_addrhead); 38736285Sbrian TAILQ_INIT(&ifp->if_prefixhead); 38836285Sbrian TAILQ_INIT(&ifp->if_multiaddrs); 38936285Sbrian SLIST_INIT(&ifp->if_klist); 39036285Sbrian getmicrotime(&ifp->if_lastchange); 39136285Sbrian 39236285Sbrian#ifdef MAC 39336285Sbrian mac_init_ifnet(ifp); 39436285Sbrian mac_create_ifnet(ifp); 39536285Sbrian#endif 39636285Sbrian 39749434Sbrian ifp->if_index = if_findindex(ifp); 39836285Sbrian if (ifp->if_index > if_index) 39936285Sbrian if_index = ifp->if_index; 40046686Sbrian if (if_index >= if_indexlim) 40146686Sbrian if_grow(); 40236285Sbrian 40336285Sbrian ifnet_byindex(ifp->if_index) = ifp; 40436285Sbrian ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw, ifp->if_index, 40536285Sbrian UID_ROOT, GID_WHEEL, 0600, "%s/%s%d", 40636285Sbrian net_cdevsw.d_name, ifp->if_name, ifp->if_unit); 40736312Sbrian make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d", 40836312Sbrian net_cdevsw.d_name, ifp->if_index); 40936312Sbrian 41036312Sbrian mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_name, "if send queue", MTX_DEF); 41136312Sbrian 41236312Sbrian /* 41336312Sbrian * create a Link Level name for this device 41454912Sbrian */ 41536285Sbrian namelen = snprintf(workbuf, sizeof(workbuf), 41636285Sbrian "%s%d", ifp->if_name, ifp->if_unit); 41736285Sbrian#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 41836312Sbrian masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; 41936312Sbrian socksize = masklen + ifp->if_addrlen; 42036312Sbrian#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 42136312Sbrian if (socksize < sizeof(*sdl)) 42236312Sbrian socksize = sizeof(*sdl); 42336312Sbrian socksize = ROUNDUP(socksize); 42436285Sbrian ifasize = sizeof(*ifa) + 2 * socksize; 42536285Sbrian ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 42636285Sbrian if (ifa) { 42736285Sbrian sdl = (struct sockaddr_dl *)(ifa + 1); 42836285Sbrian sdl->sdl_len = socksize; 42936285Sbrian sdl->sdl_family = AF_LINK; 43036285Sbrian bcopy(workbuf, sdl->sdl_data, namelen); 43136312Sbrian sdl->sdl_nlen = namelen; 43236285Sbrian sdl->sdl_index = ifp->if_index; 43336312Sbrian sdl->sdl_type = ifp->if_type; 43436312Sbrian ifaddr_byindex(ifp->if_index) = ifa; 43536312Sbrian ifa->ifa_ifp = ifp; 43636285Sbrian ifa->ifa_rtrequest = link_rtrequest; 43736285Sbrian ifa->ifa_addr = (struct sockaddr *)sdl; 43836285Sbrian sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 43936285Sbrian ifa->ifa_netmask = (struct sockaddr *)sdl; 44036285Sbrian sdl->sdl_len = masklen; 44136285Sbrian while (namelen != 0) 44236285Sbrian sdl->sdl_data[--namelen] = 0xff; 44336285Sbrian TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 44436285Sbrian } 44536285Sbrian ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */ 44636285Sbrian 44736285Sbrian /* Announce the interface. */ 44836285Sbrian rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 44936285Sbrian} 45036285Sbrian 45136285Sbrian/* 45236285Sbrian * Detach an interface, removing it from the 45336285Sbrian * list of "active" interfaces. 45436285Sbrian */ 45536285Sbrianvoid 45636285Sbrianif_detach(ifp) 45736285Sbrian struct ifnet *ifp; 45854912Sbrian{ 45936285Sbrian struct ifaddr *ifa; 46036285Sbrian struct radix_node_head *rnh; 46154912Sbrian int s; 46236285Sbrian int i; 46336285Sbrian 46436285Sbrian /* 46536285Sbrian * Remove routes and flush queues. 46636285Sbrian */ 46736285Sbrian s = splnet(); 46836285Sbrian if_down(ifp); 46947712Sbrian 47036285Sbrian /* 47136285Sbrian * Remove address from ifindex_table[] and maybe decrement if_index. 47236285Sbrian * Clean up all addresses. 47336285Sbrian */ 47436285Sbrian ifaddr_byindex(ifp->if_index) = NULL; 47536285Sbrian revoke_and_destroy_dev(ifdev_byindex(ifp->if_index)); 47654912Sbrian ifdev_byindex(ifp->if_index) = NULL; 47754912Sbrian 47836285Sbrian while (if_index > 0 && ifaddr_byindex(if_index) == NULL) 47936285Sbrian if_index--; 48036285Sbrian 48136285Sbrian for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 48236285Sbrian ifa = TAILQ_FIRST(&ifp->if_addrhead)) { 48336285Sbrian#ifdef INET 48436285Sbrian /* XXX: Ugly!! ad hoc just for INET */ 48536285Sbrian if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 48636285Sbrian struct ifaliasreq ifr; 48736285Sbrian 48836285Sbrian bzero(&ifr, sizeof(ifr)); 48936285Sbrian ifr.ifra_addr = *ifa->ifa_addr; 49036285Sbrian if (ifa->ifa_dstaddr) 49136285Sbrian ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 49236285Sbrian if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 49354912Sbrian NULL) == 0) 49436285Sbrian continue; 49554912Sbrian } 49636285Sbrian#endif /* INET */ 49747712Sbrian#ifdef INET6 49847712Sbrian if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 49936285Sbrian in6_purgeaddr(ifa); 50036285Sbrian /* ifp_addrhead is already updated */ 50136285Sbrian continue; 50236285Sbrian } 50336285Sbrian#endif /* INET6 */ 50436285Sbrian TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 50536285Sbrian IFAFREE(ifa); 50636285Sbrian } 50736285Sbrian 50836285Sbrian#ifdef INET6 50936285Sbrian /* 51036285Sbrian * Remove all IPv6 kernel structs related to ifp. This should be done 51136285Sbrian * before removing routing entries below, since IPv6 interface direct 51236285Sbrian * routes are expected to be removed by the IPv6-specific kernel API. 51336285Sbrian * Otherwise, the kernel will detect some inconsistency and bark it. 51436285Sbrian */ 51536285Sbrian in6_ifdetach(ifp); 51636285Sbrian#endif 51736285Sbrian 51836285Sbrian /* 51936285Sbrian * Delete all remaining routes using this interface 52036285Sbrian * Unfortuneatly the only way to do this is to slog through 52136285Sbrian * the entire routing table looking for routes which point 52254912Sbrian * to this interface...oh well... 52336285Sbrian */ 52436285Sbrian for (i = 1; i <= AF_MAX; i++) { 52536285Sbrian if ((rnh = rt_tables[i]) == NULL) 52654912Sbrian continue; 52754912Sbrian (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 52854912Sbrian } 52936285Sbrian 53036285Sbrian /* Announce that the interface is gone. */ 53136285Sbrian rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 53254912Sbrian 53336285Sbrian#ifdef MAC 53436285Sbrian mac_destroy_ifnet(ifp); 53536285Sbrian#endif /* MAC */ 53636285Sbrian KNOTE(&ifp->if_klist, NOTE_EXIT); 53736285Sbrian TAILQ_REMOVE(&ifnet, ifp, if_link); 53836285Sbrian mtx_destroy(&ifp->if_snd.ifq_mtx); 53936285Sbrian splx(s); 54036285Sbrian} 54154912Sbrian 54236285Sbrian/* 54336285Sbrian * Delete Routes for a Network Interface 54454912Sbrian * 54536285Sbrian * Called for each routing entry via the rnh->rnh_walktree() call above 54636285Sbrian * to delete all route entries referencing a detaching network interface. 54736285Sbrian * 54836285Sbrian * Arguments: 54936285Sbrian * rn pointer to node in the routing table 55054912Sbrian * arg argument passed to rnh->rnh_walktree() - detaching interface 55136285Sbrian * 55236285Sbrian * Returns: 55336285Sbrian * 0 successful 55436285Sbrian * errno failed - reason indicated 55554912Sbrian * 55647061Sbrian */ 55754912Sbrianstatic int 55854912Sbrianif_rtdel(rn, arg) 55954912Sbrian struct radix_node *rn; 56036285Sbrian void *arg; 56136285Sbrian{ 56236285Sbrian struct rtentry *rt = (struct rtentry *)rn; 56336285Sbrian struct ifnet *ifp = arg; 56436285Sbrian int err; 56536285Sbrian 56636285Sbrian if (rt->rt_ifp == ifp) { 56736285Sbrian 56836285Sbrian /* 56954912Sbrian * Protect (sorta) against walktree recursion problems 57036285Sbrian * with cloned routes 57136285Sbrian */ 57236285Sbrian if ((rt->rt_flags & RTF_UP) == 0) 57336285Sbrian return (0); 57436285Sbrian 57536285Sbrian err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 57654912Sbrian rt_mask(rt), rt->rt_flags, 57736285Sbrian (struct rtentry **) NULL); 57836285Sbrian if (err) { 57936285Sbrian log(LOG_WARNING, "if_rtdel: error %d\n", err); 58036285Sbrian } 58136285Sbrian } 58236285Sbrian 58354912Sbrian return (0); 58436285Sbrian} 58536285Sbrian 58654912Sbrian/* 58736285Sbrian * Create a clone network interface. 58836285Sbrian */ 58936285Sbrianint 59046686Sbrianif_clone_create(name, len) 59146686Sbrian char *name; 59246686Sbrian int len; 59346686Sbrian{ 59446686Sbrian struct if_clone *ifc; 59546686Sbrian char *dp; 59646686Sbrian int wildcard, bytoff, bitoff; 59746686Sbrian int unit; 59846686Sbrian int err; 59946686Sbrian 60046686Sbrian ifc = if_clone_lookup(name, &unit); 60154912Sbrian if (ifc == NULL) 60247695Sbrian return (EINVAL); 60354912Sbrian 60446686Sbrian if (ifunit(name) != NULL) 60547695Sbrian return (EEXIST); 60646686Sbrian 60746686Sbrian bytoff = bitoff = 0; 60846686Sbrian wildcard = (unit < 0); 60946686Sbrian /* 61036285Sbrian * Find a free unit if none was given. 61146686Sbrian */ 61246686Sbrian if (wildcard) { 61336285Sbrian while ((bytoff < ifc->ifc_bmlen) 61454912Sbrian && (ifc->ifc_units[bytoff] == 0xff)) 61536285Sbrian bytoff++; 61636285Sbrian if (bytoff >= ifc->ifc_bmlen) 61754912Sbrian return (ENOSPC); 61836285Sbrian while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 61938814Sbrian bitoff++; 62036285Sbrian unit = (bytoff << 3) + bitoff; 62138814Sbrian } 62254912Sbrian 62354912Sbrian if (unit > ifc->ifc_maxunit) 62436285Sbrian return (ENXIO); 62538814Sbrian 62636285Sbrian err = (*ifc->ifc_create)(ifc, unit); 62738814Sbrian if (err != 0) 62854912Sbrian return (err); 62954912Sbrian 63036285Sbrian if (!wildcard) { 63136285Sbrian bytoff = unit >> 3; 63236285Sbrian bitoff = unit - (bytoff << 3); 63354912Sbrian } 63436285Sbrian 63536285Sbrian /* 63654912Sbrian * Allocate the unit in the bitmap. 63736285Sbrian */ 63836285Sbrian KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 63936285Sbrian ("%s: bit is already set", __func__)); 64036285Sbrian ifc->ifc_units[bytoff] |= (1 << bitoff); 64136285Sbrian 64236285Sbrian /* In the wildcard case, we need to update the name. */ 64336285Sbrian if (wildcard) { 64454912Sbrian for (dp = name; *dp != '\0'; dp++); 64554912Sbrian if (snprintf(dp, len - (dp-name), "%d", unit) > 64636285Sbrian len - (dp-name) - 1) { 64736285Sbrian /* 64836285Sbrian * This can only be a programmer error and 64936285Sbrian * there's no straightforward way to recover if 65036285Sbrian * it happens. 65136312Sbrian */ 65236285Sbrian panic("if_clone_create(): interface name too long"); 65336285Sbrian } 65436285Sbrian 65536285Sbrian } 65636285Sbrian 65736285Sbrian return (0); 65836285Sbrian} 65936285Sbrian 66036285Sbrian/* 66136285Sbrian * Destroy a clone network interface. 66236285Sbrian */ 66336285Sbrianint 66436285Sbrianif_clone_destroy(name) 66536285Sbrian const char *name; 66636285Sbrian{ 66736285Sbrian struct if_clone *ifc; 66836285Sbrian struct ifnet *ifp; 66936285Sbrian int bytoff, bitoff; 67036285Sbrian int unit; 67136285Sbrian 67236285Sbrian ifc = if_clone_lookup(name, &unit); 67336285Sbrian if (ifc == NULL) 67436285Sbrian return (EINVAL); 67536285Sbrian 67636285Sbrian if (unit < ifc->ifc_minifs) 67736285Sbrian return (EINVAL); 67836285Sbrian 67936285Sbrian ifp = ifunit(name); 68036285Sbrian if (ifp == NULL) 68136285Sbrian return (ENXIO); 68236285Sbrian 68336285Sbrian if (ifc->ifc_destroy == NULL) 68436285Sbrian return (EOPNOTSUPP); 68536285Sbrian 68636285Sbrian (*ifc->ifc_destroy)(ifp); 68736285Sbrian 68846686Sbrian /* 68936285Sbrian * Compute offset in the bitmap and deallocate the unit. 69036285Sbrian */ 69136285Sbrian bytoff = unit >> 3; 69236285Sbrian bitoff = unit - (bytoff << 3); 69354912Sbrian KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 69436285Sbrian ("%s: bit is already cleared", __func__)); 69536285Sbrian ifc->ifc_units[bytoff] &= ~(1 << bitoff); 69636285Sbrian return (0); 69736285Sbrian} 69836285Sbrian 69949434Sbrian/* 70049434Sbrian * Look up a network interface cloner. 70136285Sbrian */ 70236285Sbrianstatic struct if_clone * 70354912Sbrianif_clone_lookup(name, unitp) 70436285Sbrian const char *name; 70549434Sbrian int *unitp; 70654912Sbrian{ 70754912Sbrian struct if_clone *ifc; 70854912Sbrian const char *cp; 70936285Sbrian int i; 71046686Sbrian 71136285Sbrian for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 71236285Sbrian for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 71336285Sbrian if (ifc->ifc_name[i] != *cp) 71436285Sbrian goto next_ifc; 71536285Sbrian } 71636285Sbrian goto found_name; 71736285Sbrian next_ifc: 71836285Sbrian ifc = LIST_NEXT(ifc, ifc_list); 71936285Sbrian } 72036285Sbrian 72136285Sbrian /* No match. */ 72236285Sbrian return ((struct if_clone *)NULL); 72336285Sbrian 72436285Sbrian found_name: 72536285Sbrian if (*cp == '\0') { 72636285Sbrian i = -1; 72736285Sbrian } else { 72836285Sbrian for (i = 0; *cp != '\0'; cp++) { 72936285Sbrian if (*cp < '0' || *cp > '9') { 73036285Sbrian /* Bogus unit number. */ 73149434Sbrian return (NULL); 73236285Sbrian } 73336285Sbrian i = (i * 10) + (*cp - '0'); 73436285Sbrian } 73536285Sbrian } 73636285Sbrian 73736285Sbrian if (unitp != NULL) 73836285Sbrian *unitp = i; 73949434Sbrian return (ifc); 74049434Sbrian} 74136285Sbrian 74236285Sbrian/* 74349434Sbrian * Register a network interface cloner. 74449434Sbrian */ 74549434Sbrianvoid 74649434Sbrianif_clone_attach(ifc) 74749434Sbrian struct if_clone *ifc; 74836285Sbrian{ 74936285Sbrian int bytoff, bitoff; 75036285Sbrian int err; 75136285Sbrian int len, maxclone; 75236285Sbrian int unit; 75336285Sbrian 75436285Sbrian KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit, 75536285Sbrian ("%s: %s requested more units then allowed (%d > %d)", 75636285Sbrian __func__, ifc->ifc_name, ifc->ifc_minifs, 75736285Sbrian ifc->ifc_maxunit + 1)); 75847695Sbrian /* 75936285Sbrian * Compute bitmap size and allocate it. 76036285Sbrian */ 76147700Sbrian maxclone = ifc->ifc_maxunit + 1; 76236285Sbrian len = maxclone >> 3; 76336285Sbrian if ((len << 3) < maxclone) 76454912Sbrian len++; 76536285Sbrian ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO); 76647695Sbrian ifc->ifc_bmlen = len; 76747695Sbrian 76847695Sbrian LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 76947695Sbrian if_cloners_count++; 77047695Sbrian 77147695Sbrian for (unit = 0; unit < ifc->ifc_minifs; unit++) { 77247695Sbrian err = (*ifc->ifc_create)(ifc, unit); 77347695Sbrian KASSERT(err == 0, 77447695Sbrian ("%s: failed to create required interface %s%d", 77547712Sbrian __func__, ifc->ifc_name, unit)); 77647695Sbrian 77747695Sbrian /* Allocate the unit in the bitmap. */ 77847712Sbrian bytoff = unit >> 3; 77947712Sbrian bitoff = unit - (bytoff << 3); 78047695Sbrian ifc->ifc_units[bytoff] |= (1 << bitoff); 78147695Sbrian } 78236285Sbrian} 78336285Sbrian 78436285Sbrian/* 78536285Sbrian * Unregister a network interface cloner. 78649434Sbrian */ 78736285Sbrianvoid 78836285Sbrianif_clone_detach(ifc) 78936285Sbrian struct if_clone *ifc; 79036285Sbrian{ 79136285Sbrian 79236285Sbrian LIST_REMOVE(ifc, ifc_list); 79336285Sbrian free(ifc->ifc_units, M_CLONE); 79436285Sbrian if_cloners_count--; 79536285Sbrian} 79636285Sbrian 79736285Sbrian/* 79849434Sbrian * Provide list of interface cloners to userspace. 79936285Sbrian */ 80036285Sbrianstatic int 80136285Sbrianif_clone_list(ifcr) 80236285Sbrian struct if_clonereq *ifcr; 80336285Sbrian{ 80436285Sbrian char outbuf[IFNAMSIZ], *dst; 80536285Sbrian struct if_clone *ifc; 80636285Sbrian int count, error = 0; 80736285Sbrian 80836285Sbrian ifcr->ifcr_total = if_cloners_count; 80936285Sbrian if ((dst = ifcr->ifcr_buffer) == NULL) { 81036285Sbrian /* Just asking how many there are. */ 81136285Sbrian return (0); 81236285Sbrian } 81336285Sbrian 81436285Sbrian if (ifcr->ifcr_count < 0) 81536285Sbrian return (EINVAL); 81647858Sbrian 81747858Sbrian count = (if_cloners_count < ifcr->ifcr_count) ? 81849434Sbrian if_cloners_count : ifcr->ifcr_count; 81949434Sbrian 82049434Sbrian for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 82136285Sbrian ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 82236285Sbrian strncpy(outbuf, ifc->ifc_name, IFNAMSIZ); 82336285Sbrian outbuf[IFNAMSIZ - 1] = '\0'; /* sanity */ 82436285Sbrian error = copyout(outbuf, dst, IFNAMSIZ); 82536285Sbrian if (error) 82636285Sbrian break; 82736285Sbrian } 82837010Sbrian 82936285Sbrian return (error); 83036285Sbrian} 83136285Sbrian 83236285Sbrian/* 83336285Sbrian * Locate an interface based on a complete address. 83436285Sbrian */ 83536285Sbrian/*ARGSUSED*/ 83636285Sbrianstruct ifaddr * 83736285Sbrianifa_ifwithaddr(addr) 83836285Sbrian struct sockaddr *addr; 83936285Sbrian{ 84036285Sbrian struct ifnet *ifp; 84136285Sbrian struct ifaddr *ifa; 84236285Sbrian 84336285Sbrian#define equal(a1, a2) \ 84436285Sbrian (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 84536285Sbrian TAILQ_FOREACH(ifp, &ifnet, if_link) 84636285Sbrian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 84736285Sbrian if (ifa->ifa_addr->sa_family != addr->sa_family) 84836285Sbrian continue; 84936285Sbrian if (equal(addr, ifa->ifa_addr)) 85036285Sbrian goto done; 85136285Sbrian /* IP6 doesn't have broadcast */ 85236285Sbrian if ((ifp->if_flags & IFF_BROADCAST) && 85336285Sbrian ifa->ifa_broadaddr && 85436285Sbrian ifa->ifa_broadaddr->sa_len != 0 && 85536285Sbrian equal(ifa->ifa_broadaddr, addr)) 85636285Sbrian goto done; 85736285Sbrian } 85836285Sbrian ifa = NULL; 85936285Sbriandone: 86036285Sbrian return (ifa); 86136285Sbrian} 86236285Sbrian 86336285Sbrian/* 86436285Sbrian * Locate the point to point interface with a given destination address. 86536285Sbrian */ 86636285Sbrian/*ARGSUSED*/ 86736285Sbrianstruct ifaddr * 86836285Sbrianifa_ifwithdstaddr(addr) 86936285Sbrian struct sockaddr *addr; 87036285Sbrian{ 87136285Sbrian struct ifnet *ifp; 87236285Sbrian struct ifaddr *ifa; 87336285Sbrian 87436285Sbrian TAILQ_FOREACH(ifp, &ifnet, if_link) { 87536285Sbrian if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 87636285Sbrian continue; 87736285Sbrian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 87836285Sbrian if (ifa->ifa_addr->sa_family != addr->sa_family) 87936285Sbrian continue; 88036285Sbrian if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 88136285Sbrian goto done; 88236285Sbrian } 88336285Sbrian } 88436285Sbrian ifa = NULL; 88536285Sbriandone: 88636285Sbrian return (ifa); 88736285Sbrian} 88840622Sbrian 88940622Sbrian/* 89040622Sbrian * Find an interface on a specific network. If many, choice 89140622Sbrian * is most specific found. 89240622Sbrian */ 89340622Sbrianstruct ifaddr * 89440622Sbrianifa_ifwithnet(addr) 89540622Sbrian struct sockaddr *addr; 89640622Sbrian{ 89740622Sbrian register struct ifnet *ifp; 89840622Sbrian register struct ifaddr *ifa; 89940622Sbrian struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 90040622Sbrian u_int af = addr->sa_family; 90140622Sbrian char *addr_data = addr->sa_data, *cplim; 90236285Sbrian 90336285Sbrian /* 90436285Sbrian * AF_LINK addresses can be looked up directly by their index number, 90536285Sbrian * so do that if we can. 90636285Sbrian */ 90736285Sbrian if (af == AF_LINK) { 90836285Sbrian register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 90936285Sbrian if (sdl->sdl_index && sdl->sdl_index <= if_index) 91036285Sbrian return (ifaddr_byindex(sdl->sdl_index)); 91136285Sbrian } 91236285Sbrian 91336285Sbrian /* 91436285Sbrian * Scan though each interface, looking for ones that have 91536285Sbrian * addresses in this address family. 91636285Sbrian */ 91736285Sbrian TAILQ_FOREACH(ifp, &ifnet, if_link) { 91836285Sbrian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 91936285Sbrian register char *cp, *cp2, *cp3; 92036285Sbrian 92136285Sbrian if (ifa->ifa_addr->sa_family != af) 92236285Sbriannext: continue; 92336285Sbrian if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) { 92436285Sbrian /* 92536285Sbrian * This is a bit broken as it doesn't 92636285Sbrian * take into account that the remote end may 92736285Sbrian * be a single node in the network we are 92836285Sbrian * looking for. 92936285Sbrian * The trouble is that we don't know the 93036285Sbrian * netmask for the remote end. 93136285Sbrian */ 93236285Sbrian if (ifa->ifa_dstaddr != 0 93336285Sbrian && equal(addr, ifa->ifa_dstaddr)) 93436285Sbrian goto done; 93536285Sbrian } else { 93636285Sbrian /* 93736285Sbrian * if we have a special address handler, 93836285Sbrian * then use it instead of the generic one. 93936285Sbrian */ 94036285Sbrian if (ifa->ifa_claim_addr) { 94136285Sbrian if ((*ifa->ifa_claim_addr)(ifa, addr)) 94236285Sbrian goto done; 94336285Sbrian continue; 94436285Sbrian } 94536285Sbrian 94636285Sbrian /* 94736285Sbrian * Scan all the bits in the ifa's address. 94836285Sbrian * If a bit dissagrees with what we are 94936285Sbrian * looking for, mask it with the netmask 95036285Sbrian * to see if it really matters. 95136285Sbrian * (A byte at a time) 95236285Sbrian */ 95336285Sbrian if (ifa->ifa_netmask == 0) 95436285Sbrian continue; 95536285Sbrian cp = addr_data; 95636285Sbrian cp2 = ifa->ifa_addr->sa_data; 95736285Sbrian cp3 = ifa->ifa_netmask->sa_data; 95836285Sbrian cplim = ifa->ifa_netmask->sa_len 95936285Sbrian + (char *)ifa->ifa_netmask; 96036285Sbrian while (cp3 < cplim) 96136285Sbrian if ((*cp++ ^ *cp2++) & *cp3++) 96236285Sbrian goto next; /* next address! */ 96336285Sbrian /* 96436285Sbrian * If the netmask of what we just found 96536285Sbrian * is more specific than what we had before 96636285Sbrian * (if we had one) then remember the new one 96736285Sbrian * before continuing to search 96836285Sbrian * for an even better one. 96936285Sbrian */ 97036285Sbrian if (ifa_maybe == 0 || 97136285Sbrian rn_refines((caddr_t)ifa->ifa_netmask, 97236285Sbrian (caddr_t)ifa_maybe->ifa_netmask)) 97336285Sbrian ifa_maybe = ifa; 97436285Sbrian } 97558028Sbrian } 97636285Sbrian } 97736285Sbrian ifa = ifa_maybe; 97836285Sbriandone: 97936314Sbrian return (ifa); 98036285Sbrian} 98136314Sbrian 98236285Sbrian/* 98336285Sbrian * Find an interface address specific to an interface best matching 98436285Sbrian * a given address. 98536285Sbrian */ 98636285Sbrianstruct ifaddr * 98736314Sbrianifaof_ifpforaddr(addr, ifp) 98836285Sbrian struct sockaddr *addr; 98936285Sbrian register struct ifnet *ifp; 99036285Sbrian{ 99136285Sbrian register struct ifaddr *ifa; 99236285Sbrian register char *cp, *cp2, *cp3; 99336314Sbrian register char *cplim; 99436285Sbrian struct ifaddr *ifa_maybe = 0; 99536285Sbrian u_int af = addr->sa_family; 99636285Sbrian 99736285Sbrian if (af >= AF_MAX) 99836285Sbrian return (0); 99936314Sbrian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 100036285Sbrian if (ifa->ifa_addr->sa_family != af) 100136314Sbrian continue; 100236285Sbrian if (ifa_maybe == 0) 100336285Sbrian ifa_maybe = ifa; 100436285Sbrian if (ifa->ifa_netmask == 0) { 100558028Sbrian if (equal(addr, ifa->ifa_addr) || 100636285Sbrian (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 100736285Sbrian goto done; 100836285Sbrian continue; 100936285Sbrian } 101036285Sbrian if (ifp->if_flags & IFF_POINTOPOINT) { 101136285Sbrian if (equal(addr, ifa->ifa_dstaddr)) 101258028Sbrian goto done; 101336285Sbrian } else { 101436285Sbrian cp = addr->sa_data; 101536285Sbrian cp2 = ifa->ifa_addr->sa_data; 101653684Sbrian cp3 = ifa->ifa_netmask->sa_data; 101736285Sbrian cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 101836285Sbrian for (; cp3 < cplim; cp3++) 101937141Sbrian if ((*cp++ ^ *cp2++) & *cp3) 102058028Sbrian break; 102136285Sbrian if (cp3 == cplim) 102236285Sbrian goto done; 102337019Sbrian } 102437141Sbrian } 102536285Sbrian ifa = ifa_maybe; 102636285Sbriandone: 102736285Sbrian return (ifa); 102836285Sbrian} 102936285Sbrian 103036285Sbrian#include <net/route.h> 103136285Sbrian 103236285Sbrian/* 103336285Sbrian * Default action when installing a route with a Link Level gateway. 103436285Sbrian * Lookup an appropriate real ifa to point to. 103536285Sbrian * This should be moved to /sys/net/link.c eventually. 103636285Sbrian */ 103736285Sbrianstatic void 103836285Sbrianlink_rtrequest(cmd, rt, info) 103936285Sbrian int cmd; 104036285Sbrian register struct rtentry *rt; 104136285Sbrian struct rt_addrinfo *info; 104236285Sbrian{ 104353970Sbrian register struct ifaddr *ifa; 104436285Sbrian struct sockaddr *dst; 104536285Sbrian struct ifnet *ifp; 104636285Sbrian 104737019Sbrian if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 104836285Sbrian ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 104936285Sbrian return; 105036285Sbrian ifa = ifaof_ifpforaddr(dst, ifp); 105136285Sbrian if (ifa) { 105236285Sbrian IFAFREE(rt->rt_ifa); 105336285Sbrian rt->rt_ifa = ifa; 105436285Sbrian ifa->ifa_refcnt++; 105536285Sbrian if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 105636285Sbrian ifa->ifa_rtrequest(cmd, rt, info); 105736285Sbrian } 105836285Sbrian} 105936285Sbrian 106036285Sbrian/* 106136285Sbrian * Mark an interface down and notify protocols of 106253684Sbrian * the transition. 106336285Sbrian * NOTE: must be called at splnet or eqivalent. 106453684Sbrian */ 106536285Sbrianvoid 106636285Sbrianif_unroute(ifp, flag, fam) 106736285Sbrian register struct ifnet *ifp; 106836285Sbrian int flag, fam; 106936285Sbrian{ 107036285Sbrian register struct ifaddr *ifa; 107153684Sbrian 107253684Sbrian ifp->if_flags &= ~flag; 107353970Sbrian getmicrotime(&ifp->if_lastchange); 107453970Sbrian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 107553684Sbrian if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 107653684Sbrian pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 107736285Sbrian if_qflush(&ifp->if_snd); 107836285Sbrian rt_ifmsg(ifp); 107936285Sbrian} 108036285Sbrian 108136285Sbrian/* 108236285Sbrian * Mark an interface up and notify protocols of 108336285Sbrian * the transition. 108436285Sbrian * NOTE: must be called at splnet or eqivalent. 108536285Sbrian */ 108653684Sbrianvoid 108753970Sbrianif_route(ifp, flag, fam) 108836285Sbrian register struct ifnet *ifp; 108936285Sbrian int flag, fam; 109036285Sbrian{ 109136285Sbrian register struct ifaddr *ifa; 109236285Sbrian 109353684Sbrian ifp->if_flags |= flag; 109436285Sbrian getmicrotime(&ifp->if_lastchange); 109536285Sbrian TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 109636285Sbrian if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 109736285Sbrian pfctlinput(PRC_IFUP, ifa->ifa_addr); 109836285Sbrian rt_ifmsg(ifp); 109936285Sbrian#ifdef INET6 110036285Sbrian in6_if_up(ifp); 110136285Sbrian#endif 110236285Sbrian} 110336285Sbrian 110436285Sbrian/* 110536285Sbrian * Mark an interface down and notify protocols of 110636285Sbrian * the transition. 110736285Sbrian * NOTE: must be called at splnet or eqivalent. 110836285Sbrian */ 110936285Sbrianvoid 111036285Sbrianif_down(ifp) 111136285Sbrian register struct ifnet *ifp; 111236285Sbrian{ 111336285Sbrian 111436285Sbrian if_unroute(ifp, IFF_UP, AF_UNSPEC); 111536285Sbrian} 111636285Sbrian 111736285Sbrian/* 111836285Sbrian * Mark an interface up and notify protocols of 111936285Sbrian * the transition. 112036285Sbrian * NOTE: must be called at splnet or eqivalent. 112136285Sbrian */ 112236312Sbrianvoid 112336312Sbrianif_up(ifp) 112436312Sbrian register struct ifnet *ifp; 112536312Sbrian{ 112636312Sbrian 112736312Sbrian if_route(ifp, IFF_UP, AF_UNSPEC); 112846686Sbrian} 112936312Sbrian 113038544Sbrian/* 113138544Sbrian * Flush an interface queue. 113238544Sbrian */ 113338544Sbrianstatic void 113438544Sbrianif_qflush(ifq) 113538544Sbrian register struct ifqueue *ifq; 1136{ 1137 register struct mbuf *m, *n; 1138 1139 n = ifq->ifq_head; 1140 while ((m = n) != 0) { 1141 n = m->m_act; 1142 m_freem(m); 1143 } 1144 ifq->ifq_head = 0; 1145 ifq->ifq_tail = 0; 1146 ifq->ifq_len = 0; 1147} 1148 1149/* 1150 * Handle interface watchdog timer routines. Called 1151 * from softclock, we decrement timers (if set) and 1152 * call the appropriate interface routine on expiration. 1153 */ 1154static void 1155if_slowtimo(arg) 1156 void *arg; 1157{ 1158 register struct ifnet *ifp; 1159 int s = splimp(); 1160 1161 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1162 if (ifp->if_timer == 0 || --ifp->if_timer) 1163 continue; 1164 if (ifp->if_watchdog) 1165 (*ifp->if_watchdog)(ifp); 1166 } 1167 splx(s); 1168 timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 1169} 1170 1171/* 1172 * Map interface name to 1173 * interface structure pointer. 1174 */ 1175struct ifnet * 1176ifunit(const char *name) 1177{ 1178 char namebuf[IFNAMSIZ + 1]; 1179 struct ifnet *ifp; 1180 dev_t dev; 1181 1182 /* 1183 * Now search all the interfaces for this name/number 1184 */ 1185 1186 /* 1187 * XXX 1188 * Devices should really be known as /dev/fooN, not /dev/net/fooN. 1189 */ 1190 snprintf(namebuf, IFNAMSIZ, "%s/%s", net_cdevsw.d_name, name); 1191 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1192 dev = ifdev_byindex(ifp->if_index); 1193 if (strcmp(devtoname(dev), namebuf) == 0) 1194 break; 1195 if (dev_named(dev, name)) 1196 break; 1197 } 1198 return (ifp); 1199} 1200 1201/* 1202 * Map interface name in a sockaddr_dl to 1203 * interface structure pointer. 1204 */ 1205struct ifnet * 1206if_withname(sa) 1207 struct sockaddr *sa; 1208{ 1209 char ifname[IFNAMSIZ+1]; 1210 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 1211 1212 if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) || 1213 (sdl->sdl_nlen > IFNAMSIZ) ) 1214 return NULL; 1215 1216 /* 1217 * ifunit wants a null-terminated name. It may not be null-terminated 1218 * in the sockaddr. We don't want to change the caller's sockaddr, 1219 * and there might not be room to put the trailing null anyway, so we 1220 * make a local copy that we know we can null terminate safely. 1221 */ 1222 1223 bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen); 1224 ifname[sdl->sdl_nlen] = '\0'; 1225 return ifunit(ifname); 1226} 1227 1228/* 1229 * Hardware specific interface ioctls. 1230 */ 1231static int 1232ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) 1233{ 1234 struct ifreq *ifr; 1235 struct ifstat *ifs; 1236 int error = 0; 1237 1238 ifr = (struct ifreq *)data; 1239 switch (cmd) { 1240 case SIOCGIFINDEX: 1241 ifr->ifr_index = ifp->if_index; 1242 break; 1243 1244 case SIOCGIFFLAGS: 1245 ifr->ifr_flags = ifp->if_flags; 1246 break; 1247 1248 case SIOCGIFCAP: 1249 ifr->ifr_reqcap = ifp->if_capabilities; 1250 ifr->ifr_curcap = ifp->if_capenable; 1251 break; 1252 1253#ifdef MAC 1254 case SIOCGIFMAC: 1255 error = mac_ioctl_ifnet_get(td->td_proc->p_ucred, ifr, ifp); 1256 break; 1257#endif 1258 1259 case SIOCGIFMETRIC: 1260 ifr->ifr_metric = ifp->if_metric; 1261 break; 1262 1263 case SIOCGIFMTU: 1264 ifr->ifr_mtu = ifp->if_mtu; 1265 break; 1266 1267 case SIOCGIFPHYS: 1268 ifr->ifr_phys = ifp->if_physical; 1269 break; 1270 1271 case SIOCSIFFLAGS: 1272 error = suser(td); 1273 if (error) 1274 return (error); 1275 ifr->ifr_prevflags = ifp->if_flags; 1276 if (ifp->if_flags & IFF_SMART) { 1277 /* Smart drivers twiddle their own routes */ 1278 } else if (ifp->if_flags & IFF_UP && 1279 (ifr->ifr_flags & IFF_UP) == 0) { 1280 int s = splimp(); 1281 if_down(ifp); 1282 splx(s); 1283 } else if (ifr->ifr_flags & IFF_UP && 1284 (ifp->if_flags & IFF_UP) == 0) { 1285 int s = splimp(); 1286 if_up(ifp); 1287 splx(s); 1288 } 1289 ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 1290 (ifr->ifr_flags &~ IFF_CANTCHANGE); 1291 if (ifp->if_ioctl) 1292 (void) (*ifp->if_ioctl)(ifp, cmd, data); 1293 getmicrotime(&ifp->if_lastchange); 1294 break; 1295 1296 case SIOCSIFCAP: 1297 error = suser(td); 1298 if (error) 1299 return (error); 1300 if (ifr->ifr_reqcap & ~ifp->if_capabilities) 1301 return (EINVAL); 1302 (void) (*ifp->if_ioctl)(ifp, cmd, data); 1303 break; 1304 1305#ifdef MAC 1306 case SIOCSIFMAC: 1307 error = mac_ioctl_ifnet_set(td->td_proc->p_ucred, ifr, ifp); 1308 break; 1309#endif 1310 1311 case SIOCSIFMETRIC: 1312 error = suser(td); 1313 if (error) 1314 return (error); 1315 ifp->if_metric = ifr->ifr_metric; 1316 getmicrotime(&ifp->if_lastchange); 1317 break; 1318 1319 case SIOCSIFPHYS: 1320 error = suser(td); 1321 if (error) 1322 return error; 1323 if (!ifp->if_ioctl) 1324 return EOPNOTSUPP; 1325 error = (*ifp->if_ioctl)(ifp, cmd, data); 1326 if (error == 0) 1327 getmicrotime(&ifp->if_lastchange); 1328 return(error); 1329 1330 case SIOCSIFMTU: 1331 { 1332 u_long oldmtu = ifp->if_mtu; 1333 1334 error = suser(td); 1335 if (error) 1336 return (error); 1337 if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 1338 return (EINVAL); 1339 if (ifp->if_ioctl == NULL) 1340 return (EOPNOTSUPP); 1341 error = (*ifp->if_ioctl)(ifp, cmd, data); 1342 if (error == 0) { 1343 getmicrotime(&ifp->if_lastchange); 1344 rt_ifmsg(ifp); 1345 } 1346 /* 1347 * If the link MTU changed, do network layer specific procedure. 1348 */ 1349 if (ifp->if_mtu != oldmtu) { 1350#ifdef INET6 1351 nd6_setmtu(ifp); 1352#endif 1353 } 1354 break; 1355 } 1356 1357 case SIOCADDMULTI: 1358 case SIOCDELMULTI: 1359 error = suser(td); 1360 if (error) 1361 return (error); 1362 1363 /* Don't allow group membership on non-multicast interfaces. */ 1364 if ((ifp->if_flags & IFF_MULTICAST) == 0) 1365 return (EOPNOTSUPP); 1366 1367 /* Don't let users screw up protocols' entries. */ 1368 if (ifr->ifr_addr.sa_family != AF_LINK) 1369 return (EINVAL); 1370 1371 if (cmd == SIOCADDMULTI) { 1372 struct ifmultiaddr *ifma; 1373 error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1374 } else { 1375 error = if_delmulti(ifp, &ifr->ifr_addr); 1376 } 1377 if (error == 0) 1378 getmicrotime(&ifp->if_lastchange); 1379 break; 1380 1381 case SIOCSIFPHYADDR: 1382 case SIOCDIFPHYADDR: 1383#ifdef INET6 1384 case SIOCSIFPHYADDR_IN6: 1385#endif 1386 case SIOCSLIFPHYADDR: 1387 case SIOCSIFMEDIA: 1388 case SIOCSIFGENERIC: 1389 error = suser(td); 1390 if (error) 1391 return (error); 1392 if (ifp->if_ioctl == NULL) 1393 return (EOPNOTSUPP); 1394 error = (*ifp->if_ioctl)(ifp, cmd, data); 1395 if (error == 0) 1396 getmicrotime(&ifp->if_lastchange); 1397 break; 1398 1399 case SIOCGIFSTATUS: 1400 ifs = (struct ifstat *)data; 1401 ifs->ascii[0] = '\0'; 1402 1403 case SIOCGIFPSRCADDR: 1404 case SIOCGIFPDSTADDR: 1405 case SIOCGLIFPHYADDR: 1406 case SIOCGIFMEDIA: 1407 case SIOCGIFGENERIC: 1408 if (ifp->if_ioctl == 0) 1409 return (EOPNOTSUPP); 1410 error = (*ifp->if_ioctl)(ifp, cmd, data); 1411 break; 1412 1413 case SIOCSIFLLADDR: 1414 error = suser(td); 1415 if (error) 1416 return (error); 1417 error = if_setlladdr(ifp, 1418 ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 1419 break; 1420 1421 default: 1422 error = ENOIOCTL; 1423 break; 1424 } 1425 return (error); 1426} 1427 1428/* 1429 * Interface ioctls. 1430 */ 1431int 1432ifioctl(so, cmd, data, td) 1433 struct socket *so; 1434 u_long cmd; 1435 caddr_t data; 1436 struct thread *td; 1437{ 1438 struct ifnet *ifp; 1439 struct ifreq *ifr; 1440 int error; 1441 short oif_flags; 1442 1443 switch (cmd) { 1444 case SIOCGIFCONF: 1445 case OSIOCGIFCONF: 1446 return (ifconf(cmd, data)); 1447 } 1448 ifr = (struct ifreq *)data; 1449 1450 switch (cmd) { 1451 case SIOCIFCREATE: 1452 case SIOCIFDESTROY: 1453 if ((error = suser(td)) != 0) 1454 return (error); 1455 return ((cmd == SIOCIFCREATE) ? 1456 if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 1457 if_clone_destroy(ifr->ifr_name)); 1458 1459 case SIOCIFGCLONERS: 1460 return (if_clone_list((struct if_clonereq *)data)); 1461 } 1462 1463 ifp = ifunit(ifr->ifr_name); 1464 if (ifp == 0) 1465 return (ENXIO); 1466 1467 error = ifhwioctl(cmd, ifp, data, td); 1468 if (error != ENOIOCTL) 1469 return (error); 1470 1471 oif_flags = ifp->if_flags; 1472 if (so->so_proto == 0) 1473 return (EOPNOTSUPP); 1474#ifndef COMPAT_43 1475 error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 1476 data, 1477 ifp, td)); 1478#else 1479 { 1480 int ocmd = cmd; 1481 1482 switch (cmd) { 1483 1484 case SIOCSIFDSTADDR: 1485 case SIOCSIFADDR: 1486 case SIOCSIFBRDADDR: 1487 case SIOCSIFNETMASK: 1488#if BYTE_ORDER != BIG_ENDIAN 1489 if (ifr->ifr_addr.sa_family == 0 && 1490 ifr->ifr_addr.sa_len < 16) { 1491 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1492 ifr->ifr_addr.sa_len = 16; 1493 } 1494#else 1495 if (ifr->ifr_addr.sa_len == 0) 1496 ifr->ifr_addr.sa_len = 16; 1497#endif 1498 break; 1499 1500 case OSIOCGIFADDR: 1501 cmd = SIOCGIFADDR; 1502 break; 1503 1504 case OSIOCGIFDSTADDR: 1505 cmd = SIOCGIFDSTADDR; 1506 break; 1507 1508 case OSIOCGIFBRDADDR: 1509 cmd = SIOCGIFBRDADDR; 1510 break; 1511 1512 case OSIOCGIFNETMASK: 1513 cmd = SIOCGIFNETMASK; 1514 } 1515 error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 1516 cmd, 1517 data, 1518 ifp, td)); 1519 switch (ocmd) { 1520 1521 case OSIOCGIFADDR: 1522 case OSIOCGIFDSTADDR: 1523 case OSIOCGIFBRDADDR: 1524 case OSIOCGIFNETMASK: 1525 *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 1526 1527 } 1528 } 1529#endif /* COMPAT_43 */ 1530 1531 if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 1532#ifdef INET6 1533 DELAY(100);/* XXX: temporary workaround for fxp issue*/ 1534 if (ifp->if_flags & IFF_UP) { 1535 int s = splimp(); 1536 in6_if_up(ifp); 1537 splx(s); 1538 } 1539#endif 1540 } 1541 return (error); 1542} 1543 1544/* 1545 * Set/clear promiscuous mode on interface ifp based on the truth value 1546 * of pswitch. The calls are reference counted so that only the first 1547 * "on" request actually has an effect, as does the final "off" request. 1548 * Results are undefined if the "off" and "on" requests are not matched. 1549 */ 1550int 1551ifpromisc(ifp, pswitch) 1552 struct ifnet *ifp; 1553 int pswitch; 1554{ 1555 struct ifreq ifr; 1556 int error; 1557 int oldflags, oldpcount; 1558 1559 oldpcount = ifp->if_pcount; 1560 oldflags = ifp->if_flags; 1561 if (pswitch) { 1562 /* 1563 * If the device is not configured up, we cannot put it in 1564 * promiscuous mode. 1565 */ 1566 if ((ifp->if_flags & IFF_UP) == 0) 1567 return (ENETDOWN); 1568 if (ifp->if_pcount++ != 0) 1569 return (0); 1570 ifp->if_flags |= IFF_PROMISC; 1571 } else { 1572 if (--ifp->if_pcount > 0) 1573 return (0); 1574 ifp->if_flags &= ~IFF_PROMISC; 1575 } 1576 ifr.ifr_flags = ifp->if_flags; 1577 error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 1578 if (error == 0) { 1579 log(LOG_INFO, "%s%d: promiscuous mode %s\n", 1580 ifp->if_name, ifp->if_unit, 1581 (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 1582 rt_ifmsg(ifp); 1583 } else { 1584 ifp->if_pcount = oldpcount; 1585 ifp->if_flags = oldflags; 1586 } 1587 return error; 1588} 1589 1590/* 1591 * Return interface configuration 1592 * of system. List may be used 1593 * in later ioctl's (above) to get 1594 * other information. 1595 */ 1596/*ARGSUSED*/ 1597static int 1598ifconf(cmd, data) 1599 u_long cmd; 1600 caddr_t data; 1601{ 1602 struct ifconf *ifc = (struct ifconf *)data; 1603 struct ifnet *ifp; 1604 struct ifaddr *ifa; 1605 struct ifreq ifr, *ifrp; 1606 int space = ifc->ifc_len, error = 0; 1607 1608 ifrp = ifc->ifc_req; 1609 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1610 char workbuf[64]; 1611 int ifnlen, addrs; 1612 1613 if (space < sizeof(ifr)) 1614 break; 1615 ifnlen = snprintf(workbuf, sizeof(workbuf), 1616 "%s%d", ifp->if_name, ifp->if_unit); 1617 if(ifnlen + 1 > sizeof ifr.ifr_name) { 1618 error = ENAMETOOLONG; 1619 break; 1620 } else { 1621 strcpy(ifr.ifr_name, workbuf); 1622 } 1623 1624 addrs = 0; 1625 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1626 struct sockaddr *sa = ifa->ifa_addr; 1627 1628 if (space < sizeof(ifr)) 1629 break; 1630 if (jailed(curthread->td_ucred) && 1631 prison_if(curthread->td_ucred, sa)) 1632 continue; 1633 addrs++; 1634#ifdef COMPAT_43 1635 if (cmd == OSIOCGIFCONF) { 1636 struct osockaddr *osa = 1637 (struct osockaddr *)&ifr.ifr_addr; 1638 ifr.ifr_addr = *sa; 1639 osa->sa_family = sa->sa_family; 1640 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1641 sizeof (ifr)); 1642 ifrp++; 1643 } else 1644#endif 1645 if (sa->sa_len <= sizeof(*sa)) { 1646 ifr.ifr_addr = *sa; 1647 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1648 sizeof (ifr)); 1649 ifrp++; 1650 } else { 1651 if (space < sizeof (ifr) + sa->sa_len - 1652 sizeof(*sa)) 1653 break; 1654 space -= sa->sa_len - sizeof(*sa); 1655 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1656 sizeof (ifr.ifr_name)); 1657 if (error == 0) 1658 error = copyout((caddr_t)sa, 1659 (caddr_t)&ifrp->ifr_addr, sa->sa_len); 1660 ifrp = (struct ifreq *) 1661 (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 1662 } 1663 if (error) 1664 break; 1665 space -= sizeof (ifr); 1666 } 1667 if (error) 1668 break; 1669 if (!addrs) { 1670 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 1671 error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1672 sizeof (ifr)); 1673 if (error) 1674 break; 1675 space -= sizeof (ifr); 1676 ifrp++; 1677 } 1678 } 1679 ifc->ifc_len -= space; 1680 return (error); 1681} 1682 1683/* 1684 * Just like if_promisc(), but for all-multicast-reception mode. 1685 */ 1686int 1687if_allmulti(ifp, onswitch) 1688 struct ifnet *ifp; 1689 int onswitch; 1690{ 1691 int error = 0; 1692 int s = splimp(); 1693 struct ifreq ifr; 1694 1695 if (onswitch) { 1696 if (ifp->if_amcount++ == 0) { 1697 ifp->if_flags |= IFF_ALLMULTI; 1698 ifr.ifr_flags = ifp->if_flags; 1699 error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 1700 } 1701 } else { 1702 if (ifp->if_amcount > 1) { 1703 ifp->if_amcount--; 1704 } else { 1705 ifp->if_amcount = 0; 1706 ifp->if_flags &= ~IFF_ALLMULTI; 1707 ifr.ifr_flags = ifp->if_flags; 1708 error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 1709 } 1710 } 1711 splx(s); 1712 1713 if (error == 0) 1714 rt_ifmsg(ifp); 1715 return error; 1716} 1717 1718/* 1719 * Add a multicast listenership to the interface in question. 1720 * The link layer provides a routine which converts 1721 */ 1722int 1723if_addmulti(ifp, sa, retifma) 1724 struct ifnet *ifp; /* interface to manipulate */ 1725 struct sockaddr *sa; /* address to add */ 1726 struct ifmultiaddr **retifma; 1727{ 1728 struct sockaddr *llsa, *dupsa; 1729 int error, s; 1730 struct ifmultiaddr *ifma; 1731 1732 /* 1733 * If the matching multicast address already exists 1734 * then don't add a new one, just add a reference 1735 */ 1736 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1737 if (equal(sa, ifma->ifma_addr)) { 1738 ifma->ifma_refcount++; 1739 if (retifma) 1740 *retifma = ifma; 1741 return 0; 1742 } 1743 } 1744 1745 /* 1746 * Give the link layer a chance to accept/reject it, and also 1747 * find out which AF_LINK address this maps to, if it isn't one 1748 * already. 1749 */ 1750 if (ifp->if_resolvemulti) { 1751 error = ifp->if_resolvemulti(ifp, &llsa, sa); 1752 if (error) return error; 1753 } else { 1754 llsa = 0; 1755 } 1756 1757 MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); 1758 MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); 1759 bcopy(sa, dupsa, sa->sa_len); 1760 1761 ifma->ifma_addr = dupsa; 1762 ifma->ifma_lladdr = llsa; 1763 ifma->ifma_ifp = ifp; 1764 ifma->ifma_refcount = 1; 1765 ifma->ifma_protospec = 0; 1766 rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1767 1768 /* 1769 * Some network interfaces can scan the address list at 1770 * interrupt time; lock them out. 1771 */ 1772 s = splimp(); 1773 TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 1774 splx(s); 1775 if (retifma != NULL) 1776 *retifma = ifma; 1777 1778 if (llsa != 0) { 1779 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1780 if (equal(ifma->ifma_addr, llsa)) 1781 break; 1782 } 1783 if (ifma) { 1784 ifma->ifma_refcount++; 1785 } else { 1786 MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, 1787 M_IFMADDR, M_WAITOK); 1788 MALLOC(dupsa, struct sockaddr *, llsa->sa_len, 1789 M_IFMADDR, M_WAITOK); 1790 bcopy(llsa, dupsa, llsa->sa_len); 1791 ifma->ifma_addr = dupsa; 1792 ifma->ifma_ifp = ifp; 1793 ifma->ifma_refcount = 1; 1794 s = splimp(); 1795 TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 1796 splx(s); 1797 } 1798 } 1799 /* 1800 * We are certain we have added something, so call down to the 1801 * interface to let them know about it. 1802 */ 1803 s = splimp(); 1804 ifp->if_ioctl(ifp, SIOCADDMULTI, 0); 1805 splx(s); 1806 1807 return 0; 1808} 1809 1810/* 1811 * Remove a reference to a multicast address on this interface. Yell 1812 * if the request does not match an existing membership. 1813 */ 1814int 1815if_delmulti(ifp, sa) 1816 struct ifnet *ifp; 1817 struct sockaddr *sa; 1818{ 1819 struct ifmultiaddr *ifma; 1820 int s; 1821 1822 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1823 if (equal(sa, ifma->ifma_addr)) 1824 break; 1825 if (ifma == 0) 1826 return ENOENT; 1827 1828 if (ifma->ifma_refcount > 1) { 1829 ifma->ifma_refcount--; 1830 return 0; 1831 } 1832 1833 rt_newmaddrmsg(RTM_DELMADDR, ifma); 1834 sa = ifma->ifma_lladdr; 1835 s = splimp(); 1836 TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1837 /* 1838 * Make sure the interface driver is notified 1839 * in the case of a link layer mcast group being left. 1840 */ 1841 if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) 1842 ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 1843 splx(s); 1844 free(ifma->ifma_addr, M_IFMADDR); 1845 free(ifma, M_IFMADDR); 1846 if (sa == 0) 1847 return 0; 1848 1849 /* 1850 * Now look for the link-layer address which corresponds to 1851 * this network address. It had been squirreled away in 1852 * ifma->ifma_lladdr for this purpose (so we don't have 1853 * to call ifp->if_resolvemulti() again), and we saved that 1854 * value in sa above. If some nasty deleted the 1855 * link-layer address out from underneath us, we can deal because 1856 * the address we stored was is not the same as the one which was 1857 * in the record for the link-layer address. (So we don't complain 1858 * in that case.) 1859 */ 1860 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1861 if (equal(sa, ifma->ifma_addr)) 1862 break; 1863 if (ifma == 0) 1864 return 0; 1865 1866 if (ifma->ifma_refcount > 1) { 1867 ifma->ifma_refcount--; 1868 return 0; 1869 } 1870 1871 s = splimp(); 1872 TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1873 ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 1874 splx(s); 1875 free(ifma->ifma_addr, M_IFMADDR); 1876 free(sa, M_IFMADDR); 1877 free(ifma, M_IFMADDR); 1878 1879 return 0; 1880} 1881 1882/* 1883 * Set the link layer address on an interface. 1884 * 1885 * At this time we only support certain types of interfaces, 1886 * and we don't allow the length of the address to change. 1887 */ 1888int 1889if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 1890{ 1891 struct sockaddr_dl *sdl; 1892 struct ifaddr *ifa; 1893 struct ifreq ifr; 1894 1895 ifa = ifaddr_byindex(ifp->if_index); 1896 if (ifa == NULL) 1897 return (EINVAL); 1898 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 1899 if (sdl == NULL) 1900 return (EINVAL); 1901 if (len != sdl->sdl_alen) /* don't allow length to change */ 1902 return (EINVAL); 1903 switch (ifp->if_type) { 1904 case IFT_ETHER: /* these types use struct arpcom */ 1905 case IFT_FDDI: 1906 case IFT_XETHER: 1907 case IFT_ISO88025: 1908 case IFT_L2VLAN: 1909 bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len); 1910 bcopy(lladdr, LLADDR(sdl), len); 1911 break; 1912 default: 1913 return (ENODEV); 1914 } 1915 /* 1916 * If the interface is already up, we need 1917 * to re-init it in order to reprogram its 1918 * address filter. 1919 */ 1920 if ((ifp->if_flags & IFF_UP) != 0) { 1921 ifp->if_flags &= ~IFF_UP; 1922 ifr.ifr_flags = ifp->if_flags; 1923 (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 1924 ifp->if_flags |= IFF_UP; 1925 ifr.ifr_flags = ifp->if_flags; 1926 (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 1927#ifdef INET 1928 /* 1929 * Also send gratuitous ARPs to notify other nodes about 1930 * the address change. 1931 */ 1932 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1933 if (ifa->ifa_addr != NULL && 1934 ifa->ifa_addr->sa_family == AF_INET) 1935 arp_ifinit(ifp, ifa); 1936 } 1937#endif 1938 } 1939 return (0); 1940} 1941 1942struct ifmultiaddr * 1943ifmaof_ifpforaddr(sa, ifp) 1944 struct sockaddr *sa; 1945 struct ifnet *ifp; 1946{ 1947 struct ifmultiaddr *ifma; 1948 1949 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1950 if (equal(ifma->ifma_addr, sa)) 1951 break; 1952 1953 return ifma; 1954} 1955 1956SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 1957SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 1958