📄 if.c
字号:
//==========================================================================//// src/sys/net/if.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* * Copyright (c) 1980, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if.c 8.3 (Berkeley) 1/4/94 * $FreeBSD: src/sys/net/if.c,v 1.85.2.9 2001/07/24 19:10:17 brooks Exp $ */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/protosw.h>#include <sys/sockio.h>#include <sys/sysctl.h>#include <net/if.h>#include <net/if_arp.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/radix.h>#include <net/route.h>#if defined(INET) || defined(INET6)/*XXX*/#include <netinet/in.h>#include <netinet/in_var.h>#ifdef INET6#include <netinet6/in6_var.h>#include <netinet6/in6_ifattach.h>#endif#endif/* * System initialization */static int ifconf __P((u_long, caddr_t));static void ifinit __P((void *));static void if_qflush __P((struct ifqueue *));static void if_slowtimo __P((void *));static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));static int if_rtdel __P((struct radix_node *, void *));SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL)int ifqmaxlen = IFQ_MAXLEN;struct ifnethead ifnet; /* depend on static init XXX */#ifdef INET6/* * XXX: declare here to avoid to include many inet6 related files.. * should be more generalized? */extern void nd6_setmtu __P((struct ifnet *));#endifstruct if_clone *if_clone_lookup __P((const char *, int *));int if_clone_list __P((struct if_clonereq *));LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);int if_cloners_count;/* * Network interface utility routines. * * Routines with ifa_ifwith* names take sockaddr *'s as * parameters. *//* ARGSUSED*/voidifinit(dummy) void *dummy;{#ifdef DEBUG_IFINIT struct ifnet *ifp; int s; s = splimp(); for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { log(LOG_INIT, "IFP: %p, next: %p\n", ifp, ifp->if_link.tqe_next); } splx(s);#endif if_slowtimo(0);}int if_index = 0;struct ifaddr **ifnet_addrs;struct ifnet **ifindex2ifnet = NULL;char *_sa(struct ifaddr *ifa){ struct sockaddr *sa = ifa->ifa_addr; static char _unknown[128]; switch (sa->sa_family) { case AF_INET: return inet_ntoa((struct in_addr)((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr);#ifdef INET6 case AF_INET6: diag_sprintf(_unknown, "%s/%d", ip6_sprintf(IFA_IN6(ifa)), in6_mask2len(&((struct in6_ifaddr *)ifa)->ia_prefixmask.sin6_addr, NULL)); return _unknown;#endif case AF_LINK: diag_sprintf(_unknown, "<<%p>>", sa); return _unknown; default: diag_sprintf(_unknown, "[%d]", sa->sa_family); return _unknown; }}void_show_ifp(struct ifnet *ifp){ log_(LOG_ADDR) { struct ifaddr *ifa; diag_printf("IFP: %p (%s%d)\n", ifp, ifp->if_name, ifp->if_unit); TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { diag_printf("IFA: %p - %s\n", ifa, _sa(ifa)); } }}/* * Attach an interface to the * list of "active" interfaces. */voidif_attach(ifp) struct ifnet *ifp;{ unsigned socksize, ifasize; int namelen, masklen; char workbuf[64]; register struct sockaddr_dl *sdl; register struct ifaddr *ifa; static int if_indexlim = 8; static int inited; if (!inited) { TAILQ_INIT(&ifnet); inited = 1; } if (ifp->if_snd.ifq_maxlen == 0) { ifp->if_snd.ifq_maxlen = ifqmaxlen; } TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); ifp->if_index = ++if_index; /* * XXX - * The old code would work if the interface passed a pre-existing * chain of ifaddrs to this code. We don't trust our callers to * properly initialize the tailq, however, so we no longer allow * this unlikely case. */ TAILQ_INIT(&ifp->if_addrhead); log_(LOG_ADDR) { diag_printf("%s.%d - After initialize list %p\n", __FUNCTION__, __LINE__, &ifp->if_addrlist); _show_ifp(ifp); } TAILQ_INIT(&ifp->if_prefixhead); LIST_INIT(&ifp->if_multiaddrs); getmicrotime(&ifp->if_lastchange); if (ifnet_addrs == 0 || if_index >= if_indexlim) { unsigned n = (if_indexlim <<= 1) * sizeof(ifa); caddr_t q = malloc(n, M_IFADDR, M_WAITOK); bzero(q, n); if (ifnet_addrs) { bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); free((caddr_t)ifnet_addrs, M_IFADDR); } ifnet_addrs = (struct ifaddr **)q; /* grow ifindex2ifnet */ n = if_indexlim * sizeof(struct ifnet *); q = malloc(n, M_IFADDR, M_WAITOK); bzero(q, n); if (ifindex2ifnet) { bcopy((caddr_t)ifindex2ifnet, q, n/2); free((caddr_t)ifindex2ifnet, M_IFADDR); } ifindex2ifnet = (struct ifnet **)q; } ifindex2ifnet[if_index] = ifp; /* * create a Link Level name for this device */ namelen = snprintf(workbuf, sizeof(workbuf), "%s%d", ifp->if_name, ifp->if_unit);#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; socksize = masklen + ifp->if_addrlen;#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) if (socksize < sizeof(*sdl)) socksize = sizeof(*sdl); socksize = ROUNDUP(socksize); ifasize = sizeof(*ifa) + 2 * socksize; ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); if (ifa) { bzero((caddr_t)ifa, ifasize); sdl = (struct sockaddr_dl *)(ifa + 1); sdl->sdl_len = socksize; sdl->sdl_family = AF_LINK; bcopy(workbuf, sdl->sdl_data, namelen); sdl->sdl_nlen = namelen; sdl->sdl_index = ifp->if_index; sdl->sdl_type = ifp->if_type; ifnet_addrs[if_index - 1] = ifa; ifa->ifa_ifp = ifp; ifa->ifa_rtrequest = link_rtrequest; ifa->ifa_addr = (struct sockaddr *)sdl; sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); ifa->ifa_netmask = (struct sockaddr *)sdl; sdl->sdl_len = masklen; while (namelen != 0) sdl->sdl_data[--namelen] = 0xff; TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); log_(LOG_ADDR) { diag_printf("%s.%d - After inserting %p into list %p\n", __FUNCTION__, __LINE__, ifa, &ifp->if_addrlist); _show_ifp(ifp); } }#ifdef ALTQ ifp->if_snd.altq_type = 0; ifp->if_snd.altq_disc = NULL; ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE; ifp->if_snd.altq_tbr = NULL; ifp->if_snd.altq_ifp = ifp;#endif}/* * Detach an interface, removing it from the * list of "active" interfaces. */voidif_detach(ifp) struct ifnet *ifp;{ struct ifaddr *ifa; struct radix_node_head *rnh; int s; int i; /* * Remove routes and flush queues. */ s = splnet(); if_down(ifp);#ifdef ALTQ if (ALTQ_IS_ENABLED(&ifp->if_snd)) altq_disable(&ifp->if_snd); if (ALTQ_IS_ATTACHED(&ifp->if_snd)) altq_detach(&ifp->if_snd);#endif /* * Remove address from ifnet_addrs[] and maybe decrement if_index. * Clean up all addresses. */ ifnet_addrs[ifp->if_index - 1] = 0; while (if_index > 0 && ifnet_addrs[if_index - 1] == 0) if_index--; for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = TAILQ_FIRST(&ifp->if_addrhead)) {#ifdef INET /* XXX: Ugly!! ad hoc just for INET */ if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { struct ifaliasreq ifr; bzero(&ifr, sizeof(ifr)); ifr.ifra_addr = *ifa->ifa_addr; if (ifa->ifa_dstaddr) ifr.ifra_broadaddr = *ifa->ifa_dstaddr; if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, NULL) == 0) continue; }#endif /* INET */#ifdef INET6 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { in6_purgeaddr(ifa); /* ifp_addrhead is already updated */ continue; }#endif /* INET6 */ TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); IFAFREE(ifa); }#ifdef INET6 /* * Remove all IPv6 kernel structs related to ifp. This should be done * before removing routing entries below, since IPv6 interface direct * routes are expected to be removed by the IPv6-specific kernel API. * Otherwise, the kernel will detect some inconsistency and bark it. */ in6_ifdetach(ifp);#endif /* * Delete all remaining routes using this interface * Unfortuneatly the only way to do this is to slog through * the entire routing table looking for routes which point * to this interface...oh well... */ for (i = 1; i <= AF_MAX; i++) { if ((rnh = rt_tables[i]) == NULL) continue; (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); } TAILQ_REMOVE(&ifnet, ifp, if_link); splx(s);}/* * Delete Routes for a Network Interface * * Called for each routing entry via the rnh->rnh_walktree() call above * to delete all route entries referencing a detaching network interface. * * Arguments: * rn pointer to node in the routing table * arg argument passed to rnh->rnh_walktree() - detaching interface * * Returns: * 0 successful * errno failed - reason indicated * */static intif_rtdel(rn, arg) struct radix_node *rn; void *arg;{ struct rtentry *rt = (struct rtentry *)rn; struct ifnet *ifp = arg; int err; if (rt->rt_ifp == ifp) { /* * Protect (sorta) against walktree recursion problems * with cloned routes */ if ((rt->rt_flags & RTF_UP) == 0) return (0); err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, (struct rtentry **) NULL); if (err) { log(LOG_WARNING, "if_rtdel: error %d\n", err); } } return (0);}/* * Create a clone network interface. */intif_clone_create(name, len) char *name; int len;{ struct if_clone *ifc; char *dp; int wildcard; int unit; int err; ifc = if_clone_lookup(name, &unit); if (ifc == NULL) return (EINVAL); if (ifunit(name) != NULL) return (EEXIST); wildcard = (unit < 0); err = (*ifc->ifc_create)(ifc, &unit); if (err != 0) return (err); /* In the wildcard case, we need to update the name. */ if (wildcard) { for (dp = name; *dp != '\0'; dp++); if (snprintf(dp, len - (dp-name), "%d", unit) > len - (dp-name) - 1) { /* * This can only be a programmer error and * there's no straightforward way to recover if * it happens. */ panic("if_clone_create(): interface name too long"); } } return (0);}/* * Destroy a clone network interface. */intif_clone_destroy(name) const char *name;{ struct if_clone *ifc; struct ifnet *ifp; ifc = if_clone_lookup(name, NULL); if (ifc == NULL) return (EINVAL); ifp = ifunit(name); if (ifp == NULL) return (ENXIO); if (ifc->ifc_destroy == NULL) return (EOPNOTSUPP); (*ifc->ifc_destroy)(ifp); return (0);}/* * Look up a network interface cloner. */struct if_clone *if_clone_lookup(name, unitp) const char *name; int *unitp;{ struct if_clone *ifc; const char *cp; int i; for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { if (ifc->ifc_name[i] != *cp) goto next_ifc; } goto found_name; next_ifc: ifc = LIST_NEXT(ifc, ifc_list); } /* No match. */ return ((struct if_clone *)NULL); found_name: if (*cp == '\0') { i = -1; } else { for (i = 0; *cp != '\0'; cp++) { if (*cp < '0' || *cp > '9') { /* Bogus unit number. */ return (NULL); } i = (i * 10) + (*cp - '0'); } } if (unitp != NULL) *unitp = i; return (ifc);}/* * Register a network interface cloner. */voidif_clone_attach(ifc) struct if_clone *ifc;{ LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); if_cloners_count++;}/* * Unregister a network interface cloner. */voidif_clone_detach(ifc) struct if_clone *ifc;{ LIST_REMOVE(ifc, ifc_list); if_cloners_count--;}/* * Provide list of interface cloners to userspace. */intif_clone_list(ifcr) struct if_clonereq *ifcr;{ char outbuf[IFNAMSIZ], *dst; struct if_clone *ifc; int count, error = 0; ifcr->ifcr_total = if_cloners_count; if ((dst = ifcr->ifcr_buffer) == NULL) { /* Just asking how many there are. */ return (0); } if (ifcr->ifcr_count < 0) return (EINVAL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -