if.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,096 行 · 第 1/2 页
C
1,096 行
/* * 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 * $Id: if.c,v 1.64 1998/12/16 18:30:42 phk Exp $ */#include "opt_compat.h"#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/protosw.h>#include <sys/kernel.h>#include <sys/sockio.h>#include <sys/syslog.h>#include <sys/sysctl.h>#include <net/if.h>#include <net/if_dl.h>#include <net/radix.h>/* * System initialization */static int ifconf __P((u_long, caddr_t));#ifdef OSKITvoid ifinit __P((void *));#elsestatic void ifinit __P((void *));#endifstatic void if_qflush __P((struct ifqueue *));static void if_slowtimo __P((void *));static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));#ifndef OSKITSYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL)#endif /* !OSKIT */MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");int ifqmaxlen = IFQ_MAXLEN;struct ifnethead ifnet; /* depend on static init XXX *//* * Network interface utility routines. * * Routines with ifa_ifwith* names take sockaddr *'s as * parameters. * * This routine assumes that it will be called at splimp() or higher. *//* ARGSUSED*/voidifinit(dummy) void *dummy;{ register struct ifnet *ifp; for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; if_slowtimo(0);}int if_index = 0;struct ifaddr **ifnet_addrs;/* * 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; } 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); LIST_INIT(&ifp->if_multiaddrs); getmicrotime(&ifp->if_lastchange); if (ifnet_addrs == 0 || if_index >= if_indexlim) { unsigned n = (if_indexlim <<= 1) * sizeof(ifa); struct ifaddr **q = (struct ifaddr **) malloc(n, M_IFADDR, M_WAITOK); bzero((caddr_t)q, n); if (ifnet_addrs) { bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); free((caddr_t)ifnet_addrs, M_IFADDR); } ifnet_addrs = q; } /* * 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); }}/* * Locate an interface based on a complete address. *//*ARGSUSED*/struct ifaddr *ifa_ifwithaddr(addr) register struct sockaddr *addr;{ register struct ifnet *ifp; register struct ifaddr *ifa;#define equal(a1, a2) \ (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (equal(addr, ifa->ifa_addr)) return (ifa); if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && equal(ifa->ifa_broadaddr, addr)) return (ifa); } return ((struct ifaddr *)0);}/* * Locate the point to point interface with a given destination address. *//*ARGSUSED*/struct ifaddr *ifa_ifwithdstaddr(addr) register struct sockaddr *addr;{ register struct ifnet *ifp; register struct ifaddr *ifa; for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) if (ifp->if_flags & IFF_POINTOPOINT) for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) return (ifa); } return ((struct ifaddr *)0);}/* * Find an interface on a specific network. If many, choice * is most specific found. */struct ifaddr *ifa_ifwithnet(addr) struct sockaddr *addr;{ register struct ifnet *ifp; register struct ifaddr *ifa; struct ifaddr *ifa_maybe = (struct ifaddr *) 0; u_int af = addr->sa_family; char *addr_data = addr->sa_data, *cplim; /* * AF_LINK addresses can be looked up directly by their index number, * so do that if we can. */ if (af == AF_LINK) { register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; if (sdl->sdl_index && sdl->sdl_index <= if_index) return (ifnet_addrs[sdl->sdl_index - 1]); } /* * Scan though each interface, looking for ones that have * addresses in this address family. */ for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { register char *cp, *cp2, *cp3; if (ifa->ifa_addr->sa_family != af)next: continue; if (ifp->if_flags & IFF_POINTOPOINT) { /* * This is a bit broken as it doesn't * take into account that the remote end may * be a single node in the network we are * looking for. * The trouble is that we don't know the * netmask for the remote end. */ if (ifa->ifa_dstaddr != 0 && equal(addr, ifa->ifa_dstaddr)) return (ifa); } else { /* * if we have a special address handler, * then use it instead of the generic one. */ if (ifa->ifa_claim_addr) { if ((*ifa->ifa_claim_addr)(ifa, addr)) { return (ifa); } else { continue; } } /* * Scan all the bits in the ifa's address. * If a bit dissagrees with what we are * looking for, mask it with the netmask * to see if it really matters. * (A byte at a time) */ if (ifa->ifa_netmask == 0) continue; cp = addr_data; cp2 = ifa->ifa_addr->sa_data; cp3 = ifa->ifa_netmask->sa_data; cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; while (cp3 < cplim) if ((*cp++ ^ *cp2++) & *cp3++) goto next; /* next address! */ /* * If the netmask of what we just found * is more specific than what we had before * (if we had one) then remember the new one * before continuing to search * for an even better one. */ if (ifa_maybe == 0 || rn_refines((caddr_t)ifa->ifa_netmask, (caddr_t)ifa_maybe->ifa_netmask)) ifa_maybe = ifa; } } } return (ifa_maybe);}/* * Find an interface address specific to an interface best matching * a given address. */struct ifaddr *ifaof_ifpforaddr(addr, ifp) struct sockaddr *addr; register struct ifnet *ifp;{ register struct ifaddr *ifa; register char *cp, *cp2, *cp3; register char *cplim; struct ifaddr *ifa_maybe = 0; u_int af = addr->sa_family; if (af >= AF_MAX) return (0); for (ifa = ifp->if_addrhead.tqh_first; ifa; ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != af) continue; if (ifa_maybe == 0) ifa_maybe = ifa; if (ifa->ifa_netmask == 0) { if (equal(addr, ifa->ifa_addr) || (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) return (ifa); continue; } if (ifp->if_flags & IFF_POINTOPOINT) { if (equal(addr, ifa->ifa_dstaddr)) return (ifa); } else { cp = addr->sa_data; cp2 = ifa->ifa_addr->sa_data; cp3 = ifa->ifa_netmask->sa_data; cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; for (; cp3 < cplim; cp3++) if ((*cp++ ^ *cp2++) & *cp3) break; if (cp3 == cplim) return (ifa); } } return (ifa_maybe);}#include <net/route.h>/* * Default action when installing a route with a Link Level gateway. * Lookup an appropriate real ifa to point to. * This should be moved to /sys/net/link.c eventually. */static voidlink_rtrequest(cmd, rt, sa) int cmd; register struct rtentry *rt; struct sockaddr *sa;{ register struct ifaddr *ifa; struct sockaddr *dst; struct ifnet *ifp; if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) return; ifa = ifaof_ifpforaddr(dst, ifp); if (ifa) { IFAFREE(rt->rt_ifa); rt->rt_ifa = ifa; ifa->ifa_refcnt++; if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) ifa->ifa_rtrequest(cmd, rt, sa); }}/* * Mark an interface down and notify protocols of * the transition. * NOTE: must be called at splnet or eqivalent. */voidif_unroute(ifp, flag, fam) register struct ifnet *ifp; int flag, fam;{ register struct ifaddr *ifa; ifp->if_flags &= ~flag; getmicrotime(&ifp->if_lastchange); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFDOWN, ifa->ifa_addr); if_qflush(&ifp->if_snd); rt_ifmsg(ifp);}/* * Mark an interface up and notify protocols of * the transition. * NOTE: must be called at splnet or eqivalent. */voidif_route(ifp, flag, fam) register struct ifnet *ifp; int flag, fam;{ register struct ifaddr *ifa; ifp->if_flags |= flag; getmicrotime(&ifp->if_lastchange); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFUP, ifa->ifa_addr); rt_ifmsg(ifp);}/* * Mark an interface down and notify protocols of * the transition. * NOTE: must be called at splnet or eqivalent. */voidif_down(ifp) register struct ifnet *ifp;{ if_unroute(ifp, IFF_UP, AF_UNSPEC);}/* * Mark an interface up and notify protocols of * the transition. * NOTE: must be called at splnet or eqivalent. */voidif_up(ifp) register struct ifnet *ifp;{ if_route(ifp, IFF_UP, AF_UNSPEC);}/* * Flush an interface queue. */static voidif_qflush(ifq) register struct ifqueue *ifq;{ register struct mbuf *m, *n; n = ifq->ifq_head; while ((m = n) != 0) { n = m->m_act; m_freem(m); } ifq->ifq_head = 0; ifq->ifq_tail = 0; ifq->ifq_len = 0;}/* * Handle interface watchdog timer routines. Called * from softclock, we decrement timers (if set) and * call the appropriate interface routine on expiration. */static voidif_slowtimo(arg) void *arg;{ register struct ifnet *ifp; int s = splimp(); for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { if (ifp->if_timer == 0 || --ifp->if_timer) continue; if (ifp->if_watchdog) (*ifp->if_watchdog)(ifp); } splx(s); timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);}/* * Map interface name to * interface structure pointer. */struct ifnet *ifunit(name) register char *name;{ char namebuf[IFNAMSIZ + 1]; register char *cp, *cp2; char *end; register struct ifnet *ifp; int unit; unsigned len; register char c = '\0'; /* * Look for a non numeric part */ end = name + IFNAMSIZ; cp2 = namebuf; cp = name; while ((cp < end) && (c = *cp)) { if (c >= '0' && c <= '9') break; *cp2++ = c; cp++; } if ((cp == end) || (c == '\0') || (cp == name)) return ((struct ifnet *)0); *cp2 = '\0'; /* * check we have a legal number (limit to 7 digits?) */ len = cp - name + 1; for (unit = 0; ((c = *cp) >= '0') && (c <= '9') && (unit < 1000000); cp++ )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?