1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-26 16:18:31 +00:00

Import of 4.4-Lite-2 sys/net to make merge and examination easier. Since we

are not on the vendor branch for any of these files, the conflicts shown make
no matter.

Obtained from:	4.4BSD-Lite-2
This commit is contained in:
Garrett Wollman 1995-10-03 20:01:07 +00:00
parent efe4b0eb61
commit 9e52b98271
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=11152
13 changed files with 6572 additions and 0 deletions

1310
sys/net/bpf.c Normal file

File diff suppressed because it is too large Load Diff

252
sys/net/bpf.h Normal file
View File

@ -0,0 +1,252 @@
/*
* Copyright (c) 1990, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from the Stanford/CMU enet packet filter,
* (net/enet.c) distributed as part of 4.3BSD, and code contributed
* to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
* Berkeley Laboratory.
*
* 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.
*
* @(#)bpf.h 8.2 (Berkeley) 1/9/95
*
* @(#) $Header: bpf.h,v 1.24 91/10/27 21:22:32 mccanne Exp $ (LBL)
*/
/*
* Alignment macros. BPF_WORDALIGN rounds up to the next
* even multiple of BPF_ALIGNMENT.
*/
#define BPF_ALIGNMENT sizeof(long)
#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
#define BPF_MAXINSNS 512
#define BPF_MAXBUFSIZE 0x8000
#define BPF_MINBUFSIZE 32
/*
* Structure for BIOCSETF.
*/
struct bpf_program {
u_int bf_len;
struct bpf_insn *bf_insns;
};
/*
* Struct returned by BIOCGSTATS.
*/
struct bpf_stat {
u_int bs_recv; /* number of packets received */
u_int bs_drop; /* number of packets dropped */
};
/*
* Struct return by BIOCVERSION. This represents the version number of
* the filter language described by the instruction encodings below.
* bpf understands a program iff kernel_major == filter_major &&
* kernel_minor >= filter_minor, that is, if the value returned by the
* running kernel has the same major number and a minor number equal
* equal to or less than the filter being downloaded. Otherwise, the
* results are undefined, meaning an error may be returned or packets
* may be accepted haphazardly.
* It has nothing to do with the source code version.
*/
struct bpf_version {
u_short bv_major;
u_short bv_minor;
};
/* Current version number. */
#define BPF_MAJOR_VERSION 1
#define BPF_MINOR_VERSION 1
/*
* BPF ioctls
*
* The first set is for compatibility with Sun's pcc style
* header files. If your using gcc, we assume that you
* have run fixincludes so the latter set should work.
*/
#if (defined(sun) || defined(ibm032)) && !defined(__GNUC__)
#define BIOCGBLEN _IOR(B,102, u_int)
#define BIOCSBLEN _IOWR(B,102, u_int)
#define BIOCSETF _IOW(B,103, struct bpf_program)
#define BIOCFLUSH _IO(B,104)
#define BIOCPROMISC _IO(B,105)
#define BIOCGDLT _IOR(B,106, u_int)
#define BIOCGETIF _IOR(B,107, struct ifreq)
#define BIOCSETIF _IOW(B,108, struct ifreq)
#define BIOCSRTIMEOUT _IOW(B,109, struct timeval)
#define BIOCGRTIMEOUT _IOR(B,110, struct timeval)
#define BIOCGSTATS _IOR(B,111, struct bpf_stat)
#define BIOCIMMEDIATE _IOW(B,112, u_int)
#define BIOCVERSION _IOR(B,113, struct bpf_version)
#else
#define BIOCGBLEN _IOR('B',102, u_int)
#define BIOCSBLEN _IOWR('B',102, u_int)
#define BIOCSETF _IOW('B',103, struct bpf_program)
#define BIOCFLUSH _IO('B',104)
#define BIOCPROMISC _IO('B',105)
#define BIOCGDLT _IOR('B',106, u_int)
#define BIOCGETIF _IOR('B',107, struct ifreq)
#define BIOCSETIF _IOW('B',108, struct ifreq)
#define BIOCSRTIMEOUT _IOW('B',109, struct timeval)
#define BIOCGRTIMEOUT _IOR('B',110, struct timeval)
#define BIOCGSTATS _IOR('B',111, struct bpf_stat)
#define BIOCIMMEDIATE _IOW('B',112, u_int)
#define BIOCVERSION _IOR('B',113, struct bpf_version)
#endif
/*
* Structure prepended to each packet.
*/
struct bpf_hdr {
struct timeval bh_tstamp; /* time stamp */
u_long bh_caplen; /* length of captured portion */
u_long bh_datalen; /* original length of packet */
u_short bh_hdrlen; /* length of bpf header (this struct
plus alignment padding) */
};
/*
* Because the structure above is not a multiple of 4 bytes, some compilers
* will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
* Only the kernel needs to know about it; applications use bh_hdrlen.
*/
#ifdef KERNEL
#define SIZEOF_BPF_HDR 18
#endif
/*
* Data-link level type codes.
* Currently, only DLT_EN10MB and DLT_SLIP are supported.
*/
#define DLT_NULL 0 /* no link-layer encapsulation */
#define DLT_EN10MB 1 /* Ethernet (10Mb) */
#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
#define DLT_AX25 3 /* Amateur Radio AX.25 */
#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
#define DLT_CHAOS 5 /* Chaos */
#define DLT_IEEE802 6 /* IEEE 802 Networks */
#define DLT_ARCNET 7 /* ARCNET */
#define DLT_SLIP 8 /* Serial Line IP */
#define DLT_PPP 9 /* Point-to-point Protocol */
#define DLT_FDDI 10 /* FDDI */
/*
* The instruction encondings.
*/
/* instruction classes */
#define BPF_CLASS(code) ((code) & 0x07)
#define BPF_LD 0x00
#define BPF_LDX 0x01
#define BPF_ST 0x02
#define BPF_STX 0x03
#define BPF_ALU 0x04
#define BPF_JMP 0x05
#define BPF_RET 0x06
#define BPF_MISC 0x07
/* ld/ldx fields */
#define BPF_SIZE(code) ((code) & 0x18)
#define BPF_W 0x00
#define BPF_H 0x08
#define BPF_B 0x10
#define BPF_MODE(code) ((code) & 0xe0)
#define BPF_IMM 0x00
#define BPF_ABS 0x20
#define BPF_IND 0x40
#define BPF_MEM 0x60
#define BPF_LEN 0x80
#define BPF_MSH 0xa0
/* alu/jmp fields */
#define BPF_OP(code) ((code) & 0xf0)
#define BPF_ADD 0x00
#define BPF_SUB 0x10
#define BPF_MUL 0x20
#define BPF_DIV 0x30
#define BPF_OR 0x40
#define BPF_AND 0x50
#define BPF_LSH 0x60
#define BPF_RSH 0x70
#define BPF_NEG 0x80
#define BPF_JA 0x00
#define BPF_JEQ 0x10
#define BPF_JGT 0x20
#define BPF_JGE 0x30
#define BPF_JSET 0x40
#define BPF_SRC(code) ((code) & 0x08)
#define BPF_K 0x00
#define BPF_X 0x08
/* ret - BPF_K and BPF_X also apply */
#define BPF_RVAL(code) ((code) & 0x18)
#define BPF_A 0x10
/* misc */
#define BPF_MISCOP(code) ((code) & 0xf8)
#define BPF_TAX 0x00
#define BPF_TXA 0x80
/*
* The instruction data structure.
*/
struct bpf_insn {
u_short code;
u_char jt;
u_char jf;
long k;
};
/*
* Macros for insn array initializers.
*/
#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
#ifdef KERNEL
int bpf_validate __P((struct bpf_insn *, int));
int bpfopen __P((dev_t, int));
int bpfclose __P((dev_t, int));
int bpfread __P((dev_t, struct uio *));
int bpfwrite __P((dev_t, struct uio *));
int bpfioctl __P((dev_t, u_long, caddr_t, int));
int bpf_select __P((dev_t, int, struct proc *));
void bpf_tap __P((caddr_t, u_char *, u_int));
void bpf_mtap __P((caddr_t, struct mbuf *));
void bpfattach __P((caddr_t *, struct ifnet *, u_int, u_int));
void bpfilterattach __P((int));
u_int bpf_filter __P((struct bpf_insn *, u_char *, u_int, u_int));
#endif
/*
* Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
*/
#define BPF_MEMWORDS 16

671
sys/net/if.c Normal file
View File

@ -0,0 +1,671 @@
/*
* 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.5 (Berkeley) 1/9/95
*/
#include <sys/param.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/ioctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
int ifqmaxlen = IFQ_MAXLEN;
void if_slowtimo __P((void *arg));
/*
* Network interface utility routines.
*
* Routines with ifa_ifwith* names take sockaddr *'s as
* parameters.
*/
void
ifinit()
{
register struct ifnet *ifp;
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if (ifp->if_snd.ifq_maxlen == 0)
ifp->if_snd.ifq_maxlen = ifqmaxlen;
if_slowtimo(0);
}
#ifdef vax
/*
* Call each interface on a Unibus reset.
*/
void
ifubareset(uban)
int uban;
{
register struct ifnet *ifp;
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if (ifp->if_reset)
(*ifp->if_reset)(ifp->if_unit, uban);
}
#endif
int if_index = 0;
struct ifaddr **ifnet_addrs;
static char *sprint_d __P((u_int, char *, int));
/*
* Attach an interface to the
* list of "active" interfaces.
*/
void
if_attach(ifp)
struct ifnet *ifp;
{
unsigned socksize, ifasize;
int namelen, unitlen, masklen, ether_output();
char workbuf[12], *unitname;
register struct ifnet **p = &ifnet;
register struct sockaddr_dl *sdl;
register struct ifaddr *ifa;
static int if_indexlim = 8;
extern void link_rtrequest();
while (*p)
p = &((*p)->if_next);
*p = ifp;
ifp->if_index = ++if_index;
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);
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
*/
unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
namelen = strlen(ifp->if_name);
unitlen = strlen(unitname);
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
unitlen + namelen;
socksize = masklen + ifp->if_addrlen;
#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
socksize = ROUNDUP(socksize);
if (socksize < sizeof(*sdl))
socksize = sizeof(*sdl);
ifasize = sizeof(*ifa) + 2 * socksize;
if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
bzero((caddr_t)ifa, ifasize);
sdl = (struct sockaddr_dl *)(ifa + 1);
sdl->sdl_len = socksize;
sdl->sdl_family = AF_LINK;
bcopy(ifp->if_name, sdl->sdl_data, namelen);
bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
sdl->sdl_nlen = (namelen += unitlen);
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = ifp->if_type;
ifnet_addrs[if_index - 1] = ifa;
ifa->ifa_ifp = ifp;
ifa->ifa_next = ifp->if_addrlist;
ifa->ifa_rtrequest = link_rtrequest;
ifp->if_addrlist = ifa;
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;
}
/* XXX -- Temporary fix before changing 10 ethernet drivers */
if (ifp->if_output == ether_output)
ether_ifattach(ifp);
}
/*
* 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; ifp; ifp = ifp->if_next)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_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; ifp; ifp = ifp->if_next)
if (ifp->if_flags & IFF_POINTOPOINT)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != addr->sa_family ||
ifa->ifa_dstaddr == NULL)
continue;
if (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;
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]);
}
for (ifp = ifnet; ifp; ifp = ifp->if_next)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
register char *cp, *cp2, *cp3;
if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
next: 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;
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 using a specific address family
*/
struct ifaddr *
ifa_ifwithaf(af)
register int af;
{
register struct ifnet *ifp;
register struct ifaddr *ifa;
for (ifp = ifnet; ifp; ifp = ifp->if_next)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr->sa_family == af)
return (ifa);
return ((struct ifaddr *)0);
}
/*
* 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_addrlist; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != af)
continue;
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;
}
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.
*/
void
link_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;
if (ifa = ifaof_ifpforaddr(dst, ifp)) {
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.
*/
void
if_down(ifp)
register struct ifnet *ifp;
{
register struct ifaddr *ifa;
ifp->if_flags &= ~IFF_UP;
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
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.
*/
void
if_up(ifp)
register struct ifnet *ifp;
{
register struct ifaddr *ifa;
ifp->if_flags |= IFF_UP;
#ifdef notyet
/* this has no effect on IP, and will kill all iso connections XXX */
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
pfctlinput(PRC_IFUP, ifa->ifa_addr);
#endif
rt_ifmsg(ifp);
}
/*
* Flush an interface queue.
*/
void
if_qflush(ifq)
register struct ifqueue *ifq;
{
register struct mbuf *m, *n;
n = ifq->ifq_head;
while (m = n) {
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.
*/
void
if_slowtimo(arg)
void *arg;
{
register struct ifnet *ifp;
int s = splimp();
for (ifp = ifnet; ifp; ifp = ifp->if_next) {
if (ifp->if_timer == 0 || --ifp->if_timer)
continue;
if (ifp->if_watchdog)
(*ifp->if_watchdog)(ifp->if_unit);
}
splx(s);
timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
}
/*
* Map interface name to
* interface structure pointer.
*/
struct ifnet *
ifunit(name)
register char *name;
{
register char *cp;
register struct ifnet *ifp;
int unit;
unsigned len;
char *ep, c;
for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
if (*cp >= '0' && *cp <= '9')
break;
if (*cp == '\0' || cp == name + IFNAMSIZ)
return ((struct ifnet *)0);
/*
* Save first char of unit, and pointer to it,
* so we can put a null there to avoid matching
* initial substrings of interface names.
*/
len = cp - name + 1;
c = *cp;
ep = cp;
for (unit = 0; *cp >= '0' && *cp <= '9'; )
unit = unit * 10 + *cp++ - '0';
*ep = 0;
for (ifp = ifnet; ifp; ifp = ifp->if_next) {
if (bcmp(ifp->if_name, name, len))
continue;
if (unit == ifp->if_unit)
break;
}
*ep = c;
return (ifp);
}
/*
* Interface ioctls.
*/
int
ifioctl(so, cmd, data, p)
struct socket *so;
u_long cmd;
caddr_t data;
struct proc *p;
{
register struct ifnet *ifp;
register struct ifreq *ifr;
int error;
switch (cmd) {
case SIOCGIFCONF:
case OSIOCGIFCONF:
return (ifconf(cmd, data));
}
ifr = (struct ifreq *)data;
ifp = ifunit(ifr->ifr_name);
if (ifp == 0)
return (ENXIO);
switch (cmd) {
case SIOCGIFFLAGS:
ifr->ifr_flags = ifp->if_flags;
break;
case SIOCGIFMETRIC:
ifr->ifr_metric = ifp->if_metric;
break;
case SIOCSIFFLAGS:
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
int s = splimp();
if_down(ifp);
splx(s);
}
if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
int s = splimp();
if_up(ifp);
splx(s);
}
ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
(ifr->ifr_flags &~ IFF_CANTCHANGE);
if (ifp->if_ioctl)
(void) (*ifp->if_ioctl)(ifp, cmd, data);
break;
case SIOCSIFMETRIC:
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
ifp->if_metric = ifr->ifr_metric;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (ifp->if_ioctl == NULL)
return (EOPNOTSUPP);
return ((*ifp->if_ioctl)(ifp, cmd, data));
default:
if (so->so_proto == 0)
return (EOPNOTSUPP);
#ifndef COMPAT_43
return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
cmd, data, ifp));
#else
{
int ocmd = cmd;
switch (cmd) {
case SIOCSIFDSTADDR:
case SIOCSIFADDR:
case SIOCSIFBRDADDR:
case SIOCSIFNETMASK:
#if BYTE_ORDER != BIG_ENDIAN
if (ifr->ifr_addr.sa_family == 0 &&
ifr->ifr_addr.sa_len < 16) {
ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
ifr->ifr_addr.sa_len = 16;
}
#else
if (ifr->ifr_addr.sa_len == 0)
ifr->ifr_addr.sa_len = 16;
#endif
break;
case OSIOCGIFADDR:
cmd = SIOCGIFADDR;
break;
case OSIOCGIFDSTADDR:
cmd = SIOCGIFDSTADDR;
break;
case OSIOCGIFBRDADDR:
cmd = SIOCGIFBRDADDR;
break;
case OSIOCGIFNETMASK:
cmd = SIOCGIFNETMASK;
}
error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
cmd, data, ifp));
switch (ocmd) {
case OSIOCGIFADDR:
case OSIOCGIFDSTADDR:
case OSIOCGIFBRDADDR:
case OSIOCGIFNETMASK:
*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
}
return (error);
}
#endif
}
return (0);
}
/*
* Return interface configuration
* of system. List may be used
* in later ioctl's (above) to get
* other information.
*/
/*ARGSUSED*/
int
ifconf(cmd, data)
int cmd;
caddr_t data;
{
register struct ifconf *ifc = (struct ifconf *)data;
register struct ifnet *ifp = ifnet;
register struct ifaddr *ifa;
register char *cp, *ep;
struct ifreq ifr, *ifrp;
int space = ifc->ifc_len, error = 0;
ifrp = ifc->ifc_req;
ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
strncpy(ifr.ifr_name, ifp->if_name, sizeof (ifr.ifr_name) - 2);
for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
continue;
*cp++ = '0' + ifp->if_unit; *cp = '\0';
if ((ifa = ifp->if_addrlist) == 0) {
bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
sizeof (ifr));
if (error)
break;
space -= sizeof (ifr), ifrp++;
} else
for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
register struct sockaddr *sa = ifa->ifa_addr;
#ifdef COMPAT_43
if (cmd == OSIOCGIFCONF) {
struct osockaddr *osa =
(struct osockaddr *)&ifr.ifr_addr;
ifr.ifr_addr = *sa;
osa->sa_family = sa->sa_family;
error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
sizeof (ifr));
ifrp++;
} else
#endif
if (sa->sa_len <= sizeof(*sa)) {
ifr.ifr_addr = *sa;
error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
sizeof (ifr));
ifrp++;
} else {
space -= sa->sa_len - sizeof(*sa);
if (space < sizeof (ifr))
break;
error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
sizeof (ifr.ifr_name));
if (error == 0)
error = copyout((caddr_t)sa,
(caddr_t)&ifrp->ifr_addr, sa->sa_len);
ifrp = (struct ifreq *)
(sa->sa_len + (caddr_t)&ifrp->ifr_addr);
}
if (error)
break;
space -= sizeof (ifr);
}
}
ifc->ifc_len -= space;
return (error);
}
static char *
sprint_d(n, buf, buflen)
u_int n;
char *buf;
int buflen;
{
register char *cp = buf + buflen - 1;
*cp = 0;
do {
cp--;
*cp = "0123456789"[n % 10];
n /= 10;
} while (n != 0);
return (cp);
}

363
sys/net/if.h Normal file
View File

@ -0,0 +1,363 @@
/*
* Copyright (c) 1982, 1986, 1989, 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.h 8.3 (Berkeley) 2/9/95
*/
/*
* Structures defining a network interface, providing a packet
* transport mechanism (ala level 0 of the PUP protocols).
*
* Each interface accepts output datagrams of a specified maximum
* length, and provides higher level routines with input datagrams
* received from its medium.
*
* Output occurs when the routine if_output is called, with three parameters:
* (*ifp->if_output)(ifp, m, dst, rt)
* Here m is the mbuf chain to be sent and dst is the destination address.
* The output routine encapsulates the supplied datagram if necessary,
* and then transmits it on its medium.
*
* On input, each interface unwraps the data received by it, and either
* places it on the input queue of a internetwork datagram routine
* and posts the associated software interrupt, or passes the datagram to a raw
* packet input routine.
*
* Routines exist for locating interfaces by their addresses
* or for locating a interface on a certain network, as well as more general
* routing and gateway routines maintaining information used to locate
* interfaces. These routines live in the files if.c and route.c
*/
#ifndef _TIME_ /* XXX fast fix for SNMP, going away soon */
#include <sys/time.h>
#endif
#ifdef __STDC__
/*
* Forward structure declarations for function prototypes [sic].
*/
struct mbuf;
struct proc;
struct rtentry;
struct socket;
struct ether_header;
#endif
/*
* Structure describing information about an interface
* which may be of interest to management entities.
*/
/*
* Structure defining a queue for a network interface.
*
* (Would like to call this struct ``if'', but C isn't PL/1.)
*/
struct ifnet {
char *if_name; /* name, e.g. ``en'' or ``lo'' */
struct ifnet *if_next; /* all struct ifnets are chained */
struct ifaddr *if_addrlist; /* linked list of addresses per if */
int if_pcount; /* number of promiscuous listeners */
caddr_t if_bpf; /* packet filter structure */
u_short if_index; /* numeric abbreviation for this if */
short if_unit; /* sub-unit for lower level driver */
short if_timer; /* time 'til if_watchdog called */
short if_flags; /* up/down, broadcast, etc. */
struct if_data {
/* generic interface information */
u_char ifi_type; /* ethernet, tokenring, etc */
u_char ifi_addrlen; /* media address length */
u_char ifi_hdrlen; /* media header length */
u_long ifi_mtu; /* maximum transmission unit */
u_long ifi_metric; /* routing metric (external only) */
u_long ifi_baudrate; /* linespeed */
/* volatile statistics */
u_long ifi_ipackets; /* packets received on interface */
u_long ifi_ierrors; /* input errors on interface */
u_long ifi_opackets; /* packets sent on interface */
u_long ifi_oerrors; /* output errors on interface */
u_long ifi_collisions; /* collisions on csma interfaces */
u_long ifi_ibytes; /* total number of octets received */
u_long ifi_obytes; /* total number of octets sent */
u_long ifi_imcasts; /* packets received via multicast */
u_long ifi_omcasts; /* packets sent via multicast */
u_long ifi_iqdrops; /* dropped on input, this interface */
u_long ifi_noproto; /* destined for unsupported protocol */
struct timeval ifi_lastchange;/* last updated */
} if_data;
/* procedure handles */
int (*if_init) /* init routine */
__P((int));
int (*if_output) /* output routine (enqueue) */
__P((struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *));
int (*if_start) /* initiate output routine */
__P((struct ifnet *));
int (*if_done) /* output complete routine */
__P((struct ifnet *)); /* (XXX not used; fake prototype) */
int (*if_ioctl) /* ioctl routine */
__P((struct ifnet *, u_long, caddr_t));
int (*if_reset)
__P((int)); /* new autoconfig will permit removal */
int (*if_watchdog) /* timer routine */
__P((int));
struct ifqueue {
struct mbuf *ifq_head;
struct mbuf *ifq_tail;
int ifq_len;
int ifq_maxlen;
int ifq_drops;
} if_snd; /* output queue */
};
#define if_mtu if_data.ifi_mtu
#define if_type if_data.ifi_type
#define if_addrlen if_data.ifi_addrlen
#define if_hdrlen if_data.ifi_hdrlen
#define if_metric if_data.ifi_metric
#define if_baudrate if_data.ifi_baudrate
#define if_ipackets if_data.ifi_ipackets
#define if_ierrors if_data.ifi_ierrors
#define if_opackets if_data.ifi_opackets
#define if_oerrors if_data.ifi_oerrors
#define if_collisions if_data.ifi_collisions
#define if_ibytes if_data.ifi_ibytes
#define if_obytes if_data.ifi_obytes
#define if_imcasts if_data.ifi_imcasts
#define if_omcasts if_data.ifi_omcasts
#define if_iqdrops if_data.ifi_iqdrops
#define if_noproto if_data.ifi_noproto
#define if_lastchange if_data.ifi_lastchange
#define IFF_UP 0x1 /* interface is up */
#define IFF_BROADCAST 0x2 /* broadcast address valid */
#define IFF_DEBUG 0x4 /* turn on debugging */
#define IFF_LOOPBACK 0x8 /* is a loopback net */
#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */
#define IFF_RUNNING 0x40 /* resources allocated */
#define IFF_NOARP 0x80 /* no address resolution protocol */
#define IFF_PROMISC 0x100 /* receive all packets */
#define IFF_ALLMULTI 0x200 /* receive all multicast packets */
#define IFF_OACTIVE 0x400 /* transmission in progress */
#define IFF_SIMPLEX 0x800 /* can't hear own transmissions */
#define IFF_LINK0 0x1000 /* per link layer defined bit */
#define IFF_LINK1 0x2000 /* per link layer defined bit */
#define IFF_LINK2 0x4000 /* per link layer defined bit */
#define IFF_MULTICAST 0x8000 /* supports multicast */
/* flags set internally only: */
#define IFF_CANTCHANGE \
(IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI)
/*
* Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
* input routines have queues of messages stored on ifqueue structures
* (defined above). Entries are added to and deleted from these structures
* by these macros, which should be called with ipl raised to splimp().
*/
#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen)
#define IF_DROP(ifq) ((ifq)->ifq_drops++)
#define IF_ENQUEUE(ifq, m) { \
(m)->m_nextpkt = 0; \
if ((ifq)->ifq_tail == 0) \
(ifq)->ifq_head = m; \
else \
(ifq)->ifq_tail->m_nextpkt = m; \
(ifq)->ifq_tail = m; \
(ifq)->ifq_len++; \
}
#define IF_PREPEND(ifq, m) { \
(m)->m_nextpkt = (ifq)->ifq_head; \
if ((ifq)->ifq_tail == 0) \
(ifq)->ifq_tail = (m); \
(ifq)->ifq_head = (m); \
(ifq)->ifq_len++; \
}
#define IF_DEQUEUE(ifq, m) { \
(m) = (ifq)->ifq_head; \
if (m) { \
if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \
(ifq)->ifq_tail = 0; \
(m)->m_nextpkt = 0; \
(ifq)->ifq_len--; \
} \
}
#define IFQ_MAXLEN 50
#define IFNET_SLOWHZ 1 /* granularity is 1 second */
/*
* The ifaddr structure contains information about one address
* of an interface. They are maintained by the different address families,
* are allocated and attached when an address is set, and are linked
* together so all addresses for an interface can be located.
*/
struct ifaddr {
struct sockaddr *ifa_addr; /* address of interface */
struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
struct sockaddr *ifa_netmask; /* used to determine subnet */
struct ifnet *ifa_ifp; /* back-pointer to interface */
struct ifaddr *ifa_next; /* next address for interface */
void (*ifa_rtrequest)(); /* check or clean routes (+ or -)'d */
u_short ifa_flags; /* mostly rt_flags for cloning */
short ifa_refcnt; /* extra to malloc for link info */
int ifa_metric; /* cost of going out this interface */
#ifdef notdef
struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */
#endif
};
#define IFA_ROUTE RTF_UP /* route installed */
/*
* Message format for use in obtaining information about interfaces
* from getkerninfo and the routing socket
*/
struct if_msghdr {
u_short ifm_msglen; /* to skip over non-understood messages */
u_char ifm_version; /* future binary compatability */
u_char ifm_type; /* message type */
int ifm_addrs; /* like rtm_addrs */
int ifm_flags; /* value of if_flags */
u_short ifm_index; /* index for associated ifp */
struct if_data ifm_data;/* statistics and other data about if */
};
/*
* Message format for use in obtaining information about interface addresses
* from getkerninfo and the routing socket
*/
struct ifa_msghdr {
u_short ifam_msglen; /* to skip over non-understood messages */
u_char ifam_version; /* future binary compatability */
u_char ifam_type; /* message type */
int ifam_addrs; /* like rtm_addrs */
int ifam_flags; /* value of ifa_flags */
u_short ifam_index; /* index for associated ifp */
int ifam_metric; /* value of ifa_metric */
};
/*
* Interface request structure used for socket
* ioctl's. All interface ioctl's must have parameter
* definitions which begin with ifr_name. The
* remainder may be interface specific.
*/
struct ifreq {
#define IFNAMSIZ 16
char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
caddr_t ifru_data;
} ifr_ifru;
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_metric ifr_ifru.ifru_metric /* metric */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
};
struct ifaliasreq {
char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */
struct sockaddr ifra_addr;
struct sockaddr ifra_broadaddr;
struct sockaddr ifra_mask;
};
/*
* Structure used in SIOCGIFCONF request.
* Used to retrieve interface configuration
* for machine (useful for programs which
* must know all networks accessible).
*/
struct ifconf {
int ifc_len; /* size of associated buffer */
union {
caddr_t ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */
};
#include <net/if_arp.h>
#ifdef KERNEL
#define IFAFREE(ifa) \
if ((ifa)->ifa_refcnt <= 0) \
ifafree(ifa); \
else \
(ifa)->ifa_refcnt--;
struct ifnet *ifnet;
void ether_ifattach __P((struct ifnet *));
void ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *));
int ether_output __P((struct ifnet *,
struct mbuf *, struct sockaddr *, struct rtentry *));
char *ether_sprintf __P((u_char *));
void if_attach __P((struct ifnet *));
void if_down __P((struct ifnet *));
void if_qflush __P((struct ifqueue *));
void if_slowtimo __P((void *));
void if_up __P((struct ifnet *));
#ifdef vax
void ifubareset __P((int));
#endif
int ifconf __P((int, caddr_t));
void ifinit __P((void));
int ifioctl __P((struct socket *, u_long, caddr_t, struct proc *));
int ifpromisc __P((struct ifnet *, int));
struct ifnet *ifunit __P((char *));
struct ifaddr *ifa_ifwithaddr __P((struct sockaddr *));
struct ifaddr *ifa_ifwithaf __P((int));
struct ifaddr *ifa_ifwithdstaddr __P((struct sockaddr *));
struct ifaddr *ifa_ifwithnet __P((struct sockaddr *));
struct ifaddr *ifa_ifwithroute __P((int, struct sockaddr *,
struct sockaddr *));
struct ifaddr *ifaof_ifpforaddr __P((struct sockaddr *, struct ifnet *));
void ifafree __P((struct ifaddr *));
void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));
int loioctl __P((struct ifnet *, u_long, caddr_t));
void loopattach __P((int));
int looutput __P((struct ifnet *,
struct mbuf *, struct sockaddr *, struct rtentry *));
void lortrequest __P((int, struct rtentry *, struct sockaddr *));
#endif

247
sys/net/if_loop.c Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright (c) 1982, 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_loop.c 8.2 (Berkeley) 1/9/95
*/
/*
* Loopback interface driver for protocol testing and timing.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <machine/cpu.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
#include <net/bpf.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#endif
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
#endif
#ifdef ISO
#include <netiso/iso.h>
#include <netiso/iso_var.h>
#endif
#include "bpfilter.h"
#define LOMTU (1024+512)
struct ifnet loif;
/* ARGSUSED */
void
loopattach(n)
int n;
{
register struct ifnet *ifp = &loif;
#ifdef lint
n = n; /* Highlander: there can only be one... */
#endif
ifp->if_name = "lo";
ifp->if_mtu = LOMTU;
ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
ifp->if_ioctl = loioctl;
ifp->if_output = looutput;
ifp->if_type = IFT_LOOP;
ifp->if_hdrlen = 0;
ifp->if_addrlen = 0;
if_attach(ifp);
#if NBPFILTER > 0
bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
#endif
}
int
looutput(ifp, m, dst, rt)
struct ifnet *ifp;
register struct mbuf *m;
struct sockaddr *dst;
register struct rtentry *rt;
{
int s, isr;
register struct ifqueue *ifq = 0;
if ((m->m_flags & M_PKTHDR) == 0)
panic("looutput no HDR");
ifp->if_lastchange = time;
#if NBPFILTER > 0
if (loif.if_bpf) {
/*
* We need to prepend the address family as
* a four byte field. Cons up a dummy header
* to pacify bpf. This is safe because bpf
* will only read from the mbuf (i.e., it won't
* try to free it or keep a pointer a to it).
*/
struct mbuf m0;
u_int af = dst->sa_family;
m0.m_next = m;
m0.m_len = 4;
m0.m_data = (char *)&af;
bpf_mtap(loif.if_bpf, &m0);
}
#endif
m->m_pkthdr.rcvif = ifp;
if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
m_freem(m);
return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
}
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
ifq = &ipintrq;
isr = NETISR_IP;
break;
#endif
#ifdef NS
case AF_NS:
ifq = &nsintrq;
isr = NETISR_NS;
break;
#endif
#ifdef ISO
case AF_ISO:
ifq = &clnlintrq;
isr = NETISR_ISO;
break;
#endif
default:
printf("lo%d: can't handle af%d\n", ifp->if_unit,
dst->sa_family);
m_freem(m);
return (EAFNOSUPPORT);
}
s = splimp();
if (IF_QFULL(ifq)) {
IF_DROP(ifq);
m_freem(m);
splx(s);
return (ENOBUFS);
}
IF_ENQUEUE(ifq, m);
schednetisr(isr);
ifp->if_ipackets++;
ifp->if_ibytes += m->m_pkthdr.len;
splx(s);
return (0);
}
/* ARGSUSED */
void
lortrequest(cmd, rt, sa)
int cmd;
struct rtentry *rt;
struct sockaddr *sa;
{
if (rt)
rt->rt_rmx.rmx_mtu = LOMTU;
}
/*
* Process an ioctl request.
*/
/* ARGSUSED */
int
loioctl(ifp, cmd, data)
register struct ifnet *ifp;
u_long cmd;
caddr_t data;
{
register struct ifaddr *ifa;
register struct ifreq *ifr;
register int error = 0;
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
ifa = (struct ifaddr *)data;
if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
ifa->ifa_rtrequest = lortrequest;
/*
* Everything else is done at a higher level.
*/
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
ifr = (struct ifreq *)data;
if (ifr == 0) {
error = EAFNOSUPPORT; /* XXX */
break;
}
switch (ifr->ifr_addr.sa_family) {
#ifdef INET
case AF_INET:
break;
#endif
default:
error = EAFNOSUPPORT;
break;
}
break;
default:
error = EINVAL;
}
return (error);
}

842
sys/net/if_sl.c Normal file
View File

@ -0,0 +1,842 @@
/*
* Copyright (c) 1987, 1989, 1992, 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_sl.c 8.9 (Berkeley) 1/9/95
*/
/*
* Serial Line interface
*
* Rick Adams
* Center for Seismic Studies
* 1300 N 17th Street, Suite 1450
* Arlington, Virginia 22209
* (703)276-7900
* rick@seismo.ARPA
* seismo!rick
*
* Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
* N.B.: this belongs in netinet, not net, the way it stands now.
* Should have a link-layer type designation, but wouldn't be
* backwards-compatible.
*
* Converted to 4.3BSD Beta by Chris Torek.
* Other changes made at Berkeley, based in part on code by Kirk Smith.
* W. Jolitz added slip abort.
*
* Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov).
* Added priority queuing for "interactive" traffic; hooks for TCP
* header compression; ICMP filtering (at 2400 baud, some cretin
* pinging you can use up all your bandwidth). Made low clist behavior
* more robust and slightly less likely to hang serial line.
* Sped up a bunch of things.
*
* Note that splimp() is used throughout to block both (tty) input
* interrupts and network activity; thus, splimp must be >= spltty.
*/
#include "sl.h"
#if NSL > 0
#include "bpfilter.h"
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/mbuf.h>
#include <sys/buf.h>
#include <sys/dkstat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/tty.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <machine/cpu.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
#if INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#else
Huh? Slip without inet?
#endif
#include <net/slcompress.h>
#include <net/if_slvar.h>
#include <net/slip.h>
#if NBPFILTER > 0
#include <sys/time.h>
#include <net/bpf.h>
#endif
/*
* SLMAX is a hard limit on input packet size. To simplify the code
* and improve performance, we require that packets fit in an mbuf
* cluster, and if we get a compressed packet, there's enough extra
* room to expand the header into a max length tcp/ip header (128
* bytes). So, SLMAX can be at most
* MCLBYTES - 128
*
* SLMTU is a hard limit on output packet size. To insure good
* interactive response, SLMTU wants to be the smallest size that
* amortizes the header cost. (Remember that even with
* type-of-service queuing, we have to wait for any in-progress
* packet to finish. I.e., we wait, on the average, 1/2 * mtu /
* cps, where cps is the line speed in characters per second.
* E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The
* average compressed header size is 6-8 bytes so any MTU > 90
* bytes will give us 90% of the line bandwidth. A 100ms wait is
* tolerable (500ms is not), so want an MTU around 296. (Since TCP
* will send 256 byte segments (to allow for 40 byte headers), the
* typical packet size on the wire will be around 260 bytes). In
* 4.3tahoe+ systems, we can set an MTU in a route so we do that &
* leave the interface MTU relatively high (so we don't IP fragment
* when acting as a gateway to someone using a stupid MTU).
*
* Similar considerations apply to SLIP_HIWAT: It's the amount of
* data that will be queued 'downstream' of us (i.e., in clists
* waiting to be picked up by the tty output interrupt). If we
* queue a lot of data downstream, it's immune to our t.o.s. queuing.
* E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
* telnet/ftp will see a 1 sec wait, independent of the mtu (the
* wait is dependent on the ftp window size but that's typically
* 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize
* the cost (in idle time on the wire) of the tty driver running
* off the end of its clists & having to call back slstart for a
* new packet. For a tty interface with any buffering at all, this
* cost will be zero. Even with a totally brain dead interface (like
* the one on a typical workstation), the cost will be <= 1 character
* time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
* at most 1% while maintaining good interactive response.
*/
#if NBPFILTER > 0
#define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
#else
#define BUFOFFSET (128+sizeof(struct ifnet **))
#endif
#define SLMAX (MCLBYTES - BUFOFFSET)
#define SLBUFSIZE (SLMAX + BUFOFFSET)
#define SLMTU 296
#define SLIP_HIWAT roundup(50,CBSIZE)
#define CLISTRESERVE 1024 /* Can't let clists get too low */
/*
* SLIP ABORT ESCAPE MECHANISM:
* (inspired by HAYES modem escape arrangement)
* 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
* within window time signals a "soft" exit from slip mode by remote end
* if the IFF_DEBUG flag is on.
*/
#define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/
#define ABT_IDLE 1 /* in seconds - idle before an escape */
#define ABT_COUNT 3 /* count of escapes for abort */
#define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */
struct sl_softc sl_softc[NSL];
#define FRAME_END 0xc0 /* Frame End */
#define FRAME_ESCAPE 0xdb /* Frame Esc */
#define TRANS_FRAME_END 0xdc /* transposed frame end */
#define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */
static int slinit __P((struct sl_softc *));
static struct mbuf *sl_btom __P((struct sl_softc *, int));
/*
* Called from boot code to establish sl interfaces.
*/
void
slattach()
{
register struct sl_softc *sc;
register int i = 0;
for (sc = sl_softc; i < NSL; sc++) {
sc->sc_if.if_name = "sl";
sc->sc_if.if_next = NULL;
sc->sc_if.if_unit = i++;
sc->sc_if.if_mtu = SLMTU;
sc->sc_if.if_flags =
IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
sc->sc_if.if_type = IFT_SLIP;
sc->sc_if.if_ioctl = slioctl;
sc->sc_if.if_output = sloutput;
sc->sc_if.if_snd.ifq_maxlen = 50;
sc->sc_fastq.ifq_maxlen = 32;
if_attach(&sc->sc_if);
#if NBPFILTER > 0
bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
#endif
}
}
static int
slinit(sc)
register struct sl_softc *sc;
{
register caddr_t p;
if (sc->sc_ep == (u_char *) 0) {
MCLALLOC(p, M_WAIT);
if (p)
sc->sc_ep = (u_char *)p + SLBUFSIZE;
else {
printf("sl%d: can't allocate buffer\n", sc - sl_softc);
sc->sc_if.if_flags &= ~IFF_UP;
return (0);
}
}
sc->sc_buf = sc->sc_ep - SLMAX;
sc->sc_mp = sc->sc_buf;
sl_compress_init(&sc->sc_comp);
return (1);
}
/*
* Line specific open routine.
* Attach the given tty to the first available sl unit.
*/
/* ARGSUSED */
int
slopen(dev, tp)
dev_t dev;
register struct tty *tp;
{
struct proc *p = curproc; /* XXX */
register struct sl_softc *sc;
register int nsl;
int error;
int s;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (tp->t_line == SLIPDISC)
return (0);
for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++)
if (sc->sc_ttyp == NULL) {
if (slinit(sc) == 0)
return (ENOBUFS);
tp->t_sc = (caddr_t)sc;
sc->sc_ttyp = tp;
sc->sc_if.if_baudrate = tp->t_ospeed;
s = spltty();
tp->t_state |= TS_ISOPEN | TS_XCLUDE;
splx(s);
ttyflush(tp, FREAD | FWRITE);
return (0);
}
return (ENXIO);
}
/*
* Line specific close routine.
* Detach the tty from the sl unit.
*/
void
slclose(tp)
struct tty *tp;
{
register struct sl_softc *sc;
int s;
ttywflush(tp);
s = splimp(); /* actually, max(spltty, splnet) */
tp->t_line = 0;
tp->t_state = 0;
sc = (struct sl_softc *)tp->t_sc;
if (sc != NULL) {
if_down(&sc->sc_if);
sc->sc_ttyp = NULL;
tp->t_sc = NULL;
MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE));
sc->sc_ep = 0;
sc->sc_mp = 0;
sc->sc_buf = 0;
}
splx(s);
}
/*
* Line specific (tty) ioctl routine.
* Provide a way to get the sl unit number.
*/
/* ARGSUSED */
int
sltioctl(tp, cmd, data, flag)
struct tty *tp;
u_long cmd;
caddr_t data;
int flag;
{
struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
switch (cmd) {
case SLIOCGUNIT:
*(int *)data = sc->sc_if.if_unit;
break;
default:
return (-1);
}
return (0);
}
/*
* Queue a packet. Start transmission if not active.
* Compression happens in slstart; if we do it here, IP TOS
* will cause us to not compress "background" packets, because
* ordering gets trashed. It can be done for all packets in slstart.
*/
int
sloutput(ifp, m, dst, rtp)
struct ifnet *ifp;
register struct mbuf *m;
struct sockaddr *dst;
struct rtentry *rtp;
{
register struct sl_softc *sc = &sl_softc[ifp->if_unit];
register struct ip *ip;
register struct ifqueue *ifq;
int s;
/*
* `Cannot happen' (see slioctl). Someday we will extend
* the line protocol to support other address families.
*/
if (dst->sa_family != AF_INET) {
printf("sl%d: af%d not supported\n", sc->sc_if.if_unit,
dst->sa_family);
m_freem(m);
sc->sc_if.if_noproto++;
return (EAFNOSUPPORT);
}
if (sc->sc_ttyp == NULL) {
m_freem(m);
return (ENETDOWN); /* sort of */
}
if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
(sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
m_freem(m);
return (EHOSTUNREACH);
}
ifq = &sc->sc_if.if_snd;
ip = mtod(m, struct ip *);
if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
m_freem(m);
return (ENETRESET); /* XXX ? */
}
if (ip->ip_tos & IPTOS_LOWDELAY)
ifq = &sc->sc_fastq;
s = splimp();
if (IF_QFULL(ifq)) {
IF_DROP(ifq);
m_freem(m);
splx(s);
sc->sc_if.if_oerrors++;
return (ENOBUFS);
}
IF_ENQUEUE(ifq, m);
sc->sc_if.if_lastchange = time;
if (sc->sc_ttyp->t_outq.c_cc == 0)
slstart(sc->sc_ttyp);
splx(s);
return (0);
}
/*
* Start output on interface. Get another datagram
* to send from the interface queue and map it to
* the interface before starting output.
*/
void
slstart(tp)
register struct tty *tp;
{
register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
register struct mbuf *m;
register u_char *cp;
register struct ip *ip;
int s;
struct mbuf *m2;
#if NBPFILTER > 0
u_char bpfbuf[SLMTU + SLIP_HDRLEN];
register int len;
#endif
extern int cfreecount;
for (;;) {
/*
* If there is more in the output queue, just send it now.
* We are being called in lieu of ttstart and must do what
* it would.
*/
if (tp->t_outq.c_cc != 0) {
(*tp->t_oproc)(tp);
if (tp->t_outq.c_cc > SLIP_HIWAT)
return;
}
/*
* This happens briefly when the line shuts down.
*/
if (sc == NULL)
return;
/*
* Get a packet and send it to the interface.
*/
s = splimp();
IF_DEQUEUE(&sc->sc_fastq, m);
if (m)
sc->sc_if.if_omcasts++; /* XXX */
else
IF_DEQUEUE(&sc->sc_if.if_snd, m);
splx(s);
if (m == NULL)
return;
/*
* We do the header compression here rather than in sloutput
* because the packets will be out of order if we are using TOS
* queueing, and the connection id compression will get
* munged when this happens.
*/
#if NBPFILTER > 0
if (sc->sc_bpf) {
/*
* We need to save the TCP/IP header before it's
* compressed. To avoid complicated code, we just
* copy the entire packet into a stack buffer (since
* this is a serial line, packets should be short
* and/or the copy should be negligible cost compared
* to the packet transmission time).
*/
register struct mbuf *m1 = m;
register u_char *cp = bpfbuf + SLIP_HDRLEN;
len = 0;
do {
register int mlen = m1->m_len;
bcopy(mtod(m1, caddr_t), cp, mlen);
cp += mlen;
len += mlen;
} while (m1 = m1->m_next);
}
#endif
if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
if (sc->sc_if.if_flags & SC_COMPRESS)
*mtod(m, u_char *) |= sl_compress_tcp(m, ip,
&sc->sc_comp, 1);
}
#if NBPFILTER > 0
if (sc->sc_bpf) {
/*
* Put the SLIP pseudo-"link header" in place. The
* compressed header is now at the beginning of the
* mbuf.
*/
bpfbuf[SLX_DIR] = SLIPDIR_OUT;
bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN);
bpf_tap(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN);
}
#endif
sc->sc_if.if_lastchange = time;
/*
* If system is getting low on clists, just flush our
* output queue (if the stuff was important, it'll get
* retransmitted).
*/
if (cfreecount < CLISTRESERVE + SLMTU) {
m_freem(m);
sc->sc_if.if_collisions++;
continue;
}
/*
* The extra FRAME_END will start up a new packet, and thus
* will flush any accumulated garbage. We do this whenever
* the line may have been idle for some time.
*/
if (tp->t_outq.c_cc == 0) {
++sc->sc_if.if_obytes;
(void) putc(FRAME_END, &tp->t_outq);
}
while (m) {
register u_char *ep;
cp = mtod(m, u_char *); ep = cp + m->m_len;
while (cp < ep) {
/*
* Find out how many bytes in the string we can
* handle without doing something special.
*/
register u_char *bp = cp;
while (cp < ep) {
switch (*cp++) {
case FRAME_ESCAPE:
case FRAME_END:
--cp;
goto out;
}
}
out:
if (cp > bp) {
/*
* Put n characters at once
* into the tty output queue.
*/
if (b_to_q((char *)bp, cp - bp,
&tp->t_outq))
break;
sc->sc_if.if_obytes += cp - bp;
}
/*
* If there are characters left in the mbuf,
* the first one must be special..
* Put it out in a different form.
*/
if (cp < ep) {
if (putc(FRAME_ESCAPE, &tp->t_outq))
break;
if (putc(*cp++ == FRAME_ESCAPE ?
TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
&tp->t_outq)) {
(void) unputc(&tp->t_outq);
break;
}
sc->sc_if.if_obytes += 2;
}
}
MFREE(m, m2);
m = m2;
}
if (putc(FRAME_END, &tp->t_outq)) {
/*
* Not enough room. Remove a char to make room
* and end the packet normally.
* If you get many collisions (more than one or two
* a day) you probably do not have enough clists
* and you should increase "nclist" in param.c.
*/
(void) unputc(&tp->t_outq);
(void) putc(FRAME_END, &tp->t_outq);
sc->sc_if.if_collisions++;
} else {
++sc->sc_if.if_obytes;
sc->sc_if.if_opackets++;
}
}
}
/*
* Copy data buffer to mbuf chain; add ifnet pointer.
*/
static struct mbuf *
sl_btom(sc, len)
register struct sl_softc *sc;
register int len;
{
register struct mbuf *m;
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
return (NULL);
/*
* If we have more than MHLEN bytes, it's cheaper to
* queue the cluster we just filled & allocate a new one
* for the input buffer. Otherwise, fill the mbuf we
* allocated above. Note that code in the input routine
* guarantees that packet will fit in a cluster.
*/
if (len >= MHLEN) {
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
/*
* we couldn't get a cluster - if memory's this
* low, it's time to start dropping packets.
*/
(void) m_free(m);
return (NULL);
}
sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE;
m->m_data = (caddr_t)sc->sc_buf;
m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET);
} else
bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len);
m->m_len = len;
m->m_pkthdr.len = len;
m->m_pkthdr.rcvif = &sc->sc_if;
return (m);
}
/*
* tty interface receiver interrupt.
*/
void
slinput(c, tp)
register int c;
register struct tty *tp;
{
register struct sl_softc *sc;
register struct mbuf *m;
register int len;
int s;
#if NBPFILTER > 0
u_char chdr[CHDR_LEN];
#endif
tk_nin++;
sc = (struct sl_softc *)tp->t_sc;
if (sc == NULL)
return;
if ((c & TTY_ERRORMASK) || ((tp->t_state & TS_CARR_ON) == 0 &&
(tp->t_cflag & CLOCAL) == 0)) {
sc->sc_flags |= SC_ERROR;
return;
}
c &= TTY_CHARMASK;
++sc->sc_if.if_ibytes;
if (sc->sc_if.if_flags & IFF_DEBUG) {
if (c == ABT_ESC) {
/*
* If we have a previous abort, see whether
* this one is within the time limit.
*/
if (sc->sc_abortcount &&
time.tv_sec >= sc->sc_starttime + ABT_WINDOW)
sc->sc_abortcount = 0;
/*
* If we see an abort after "idle" time, count it;
* record when the first abort escape arrived.
*/
if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) {
if (++sc->sc_abortcount == 1)
sc->sc_starttime = time.tv_sec;
if (sc->sc_abortcount >= ABT_COUNT) {
slclose(tp);
return;
}
}
} else
sc->sc_abortcount = 0;
sc->sc_lasttime = time.tv_sec;
}
switch (c) {
case TRANS_FRAME_ESCAPE:
if (sc->sc_escape)
c = FRAME_ESCAPE;
break;
case TRANS_FRAME_END:
if (sc->sc_escape)
c = FRAME_END;
break;
case FRAME_ESCAPE:
sc->sc_escape = 1;
return;
case FRAME_END:
if(sc->sc_flags & SC_ERROR) {
sc->sc_flags &= ~SC_ERROR;
goto newpack;
}
len = sc->sc_mp - sc->sc_buf;
if (len < 3)
/* less than min length packet - ignore */
goto newpack;
#if NBPFILTER > 0
if (sc->sc_bpf) {
/*
* Save the compressed header, so we
* can tack it on later. Note that we
* will end up copying garbage in some
* cases but this is okay. We remember
* where the buffer started so we can
* compute the new header length.
*/
bcopy(sc->sc_buf, chdr, CHDR_LEN);
}
#endif
if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
if (c & 0x80)
c = TYPE_COMPRESSED_TCP;
else if (c == TYPE_UNCOMPRESSED_TCP)
*sc->sc_buf &= 0x4f; /* XXX */
/*
* We've got something that's not an IP packet.
* If compression is enabled, try to decompress it.
* Otherwise, if `auto-enable' compression is on and
* it's a reasonable packet, decompress it and then
* enable compression. Otherwise, drop it.
*/
if (sc->sc_if.if_flags & SC_COMPRESS) {
len = sl_uncompress_tcp(&sc->sc_buf, len,
(u_int)c, &sc->sc_comp);
if (len <= 0)
goto error;
} else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
len = sl_uncompress_tcp(&sc->sc_buf, len,
(u_int)c, &sc->sc_comp);
if (len <= 0)
goto error;
sc->sc_if.if_flags |= SC_COMPRESS;
} else
goto error;
}
#if NBPFILTER > 0
if (sc->sc_bpf) {
/*
* Put the SLIP pseudo-"link header" in place.
* We couldn't do this any earlier since
* decompression probably moved the buffer
* pointer. Then, invoke BPF.
*/
register u_char *hp = sc->sc_buf - SLIP_HDRLEN;
hp[SLX_DIR] = SLIPDIR_IN;
bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN);
bpf_tap(sc->sc_bpf, hp, len + SLIP_HDRLEN);
}
#endif
m = sl_btom(sc, len);
if (m == NULL)
goto error;
sc->sc_if.if_ipackets++;
sc->sc_if.if_lastchange = time;
s = splimp();
if (IF_QFULL(&ipintrq)) {
IF_DROP(&ipintrq);
sc->sc_if.if_ierrors++;
sc->sc_if.if_iqdrops++;
m_freem(m);
} else {
IF_ENQUEUE(&ipintrq, m);
schednetisr(NETISR_IP);
}
splx(s);
goto newpack;
}
if (sc->sc_mp < sc->sc_ep) {
*sc->sc_mp++ = c;
sc->sc_escape = 0;
return;
}
/* can't put lower; would miss an extra frame */
sc->sc_flags |= SC_ERROR;
error:
sc->sc_if.if_ierrors++;
newpack:
sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
sc->sc_escape = 0;
}
/*
* Process an ioctl request.
*/
int
slioctl(ifp, cmd, data)
register struct ifnet *ifp;
u_long cmd;
caddr_t data;
{
register struct ifaddr *ifa = (struct ifaddr *)data;
register struct ifreq *ifr;
register int s = splimp(), error = 0;
switch (cmd) {
case SIOCSIFADDR:
if (ifa->ifa_addr->sa_family == AF_INET)
ifp->if_flags |= IFF_UP;
else
error = EAFNOSUPPORT;
break;
case SIOCSIFDSTADDR:
if (ifa->ifa_addr->sa_family != AF_INET)
error = EAFNOSUPPORT;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
ifr = (struct ifreq *)data;
if (ifr == 0) {
error = EAFNOSUPPORT; /* XXX */
break;
}
switch (ifr->ifr_addr.sa_family) {
#ifdef INET
case AF_INET:
break;
#endif
default:
error = EAFNOSUPPORT;
break;
}
break;
default:
error = EINVAL;
}
splx(s);
return (error);
}
#endif

80
sys/net/if_slvar.h Normal file
View File

@ -0,0 +1,80 @@
/*-
* Copyright (c) 1991, 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_slvar.h 8.4 (Berkeley) 1/9/95
*
* $Header: if_slvar.h,v 1.3 89/05/31 02:25:18 van Exp $
*/
/*
* Definitions for SLIP interface data structures
*
* (This exists so programs like slstats can get at the definition
* of sl_softc.)
*/
struct sl_softc {
struct ifnet sc_if; /* network-visible interface */
struct ifqueue sc_fastq; /* interactive output queue */
struct tty *sc_ttyp; /* pointer to tty structure */
u_char *sc_mp; /* pointer to next available buf char */
u_char *sc_ep; /* pointer to last available buf char */
u_char *sc_buf; /* input buffer */
u_int sc_flags; /* see below */
u_int sc_escape; /* =1 if last char input was FRAME_ESCAPE */
long sc_lasttime; /* last time a char arrived */
long sc_abortcount; /* number of abort esacpe chars */
long sc_starttime; /* time of first abort in window */
#ifdef INET /* XXX */
struct slcompress sc_comp; /* tcp compression data */
#endif
caddr_t sc_bpf; /* BPF data */
};
/* internal flags */
#define SC_ERROR 0x0001 /* had an input error */
/* visible flags */
#define SC_COMPRESS IFF_LINK0 /* compress TCP traffic */
#define SC_NOICMP IFF_LINK1 /* supress ICMP traffic */
#define SC_AUTOCOMP IFF_LINK2 /* auto-enable TCP compression */
#ifdef KERNEL
void slattach __P((void));
void slclose __P((struct tty *));
void slinput __P((int, struct tty *));
int slioctl __P((struct ifnet *, u_long, caddr_t));
int slopen __P((dev_t, struct tty *));
int sloutput __P((struct ifnet *,
struct mbuf *, struct sockaddr *, struct rtentry *));
void slstart __P((struct tty *));
int sltioctl __P((struct tty *, u_long, caddr_t, int));
#endif /* KERNEL */

95
sys/net/if_types.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 1989, 1993, 1994
* 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_types.h 8.3 (Berkeley) 4/28/95
*/
/*
* Interface types for benefit of parsing media address headers.
* This list is derived from the SNMP list of ifTypes, currently
* documented in RFC1573.
*/
#define IFT_OTHER 0x1 /* none of the following */
#define IFT_1822 0x2 /* old-style arpanet imp */
#define IFT_HDH1822 0x3 /* HDH arpanet imp */
#define IFT_X25DDN 0x4 /* x25 to imp */
#define IFT_X25 0x5 /* PDN X25 interface (RFC877) */
#define IFT_ETHER 0x6 /* Ethernet CSMACD */
#define IFT_ISO88023 0x7 /* CMSA CD */
#define IFT_ISO88024 0x8 /* Token Bus */
#define IFT_ISO88025 0x9 /* Token Ring */
#define IFT_ISO88026 0xa /* MAN */
#define IFT_STARLAN 0xb
#define IFT_P10 0xc /* Proteon 10MBit ring */
#define IFT_P80 0xd /* Proteon 80MBit ring */
#define IFT_HY 0xe /* Hyperchannel */
#define IFT_FDDI 0xf
#define IFT_LAPB 0x10
#define IFT_SDLC 0x11
#define IFT_T1 0x12
#define IFT_CEPT 0x13 /* E1 - european T1 */
#define IFT_ISDNBASIC 0x14
#define IFT_ISDNPRIMARY 0x15
#define IFT_PTPSERIAL 0x16 /* Proprietary PTP serial */
#define IFT_PPP 0x17 /* RFC 1331 */
#define IFT_LOOP 0x18 /* loopback */
#define IFT_EON 0x19 /* ISO over IP */
#define IFT_XETHER 0x1a /* obsolete 3MB experimental ethernet */
#define IFT_NSIP 0x1b /* XNS over IP */
#define IFT_SLIP 0x1c /* IP over generic TTY */
#define IFT_ULTRA 0x1d /* Ultra Technologies */
#define IFT_DS3 0x1e /* Generic T3 */
#define IFT_SIP 0x1f /* SMDS */
#define IFT_FRELAY 0x20 /* Frame Relay DTE only */
#define IFT_RS232 0x21
#define IFT_PARA 0x22 /* parallel-port */
#define IFT_ARCNET 0x23
#define IFT_ARCNETPLUS 0x24
#define IFT_ATM 0x25 /* ATM cells */
#define IFT_MIOX25 0x26
#define IFT_SONET 0x27 /* SONET or SDH */
#define IFT_X25PLE 0x28
#define IFT_ISO88022LLC 0x29
#define IFT_LOCALTALK 0x2a
#define IFT_SMDSDXI 0x2b
#define IFT_FRELAYDCE 0x2c /* Frame Relay DCE */
#define IFT_V35 0x2d
#define IFT_HSSI 0x2e
#define IFT_HIPPI 0x2f
#define IFT_MODEM 0x30 /* Generic Modem */
#define IFT_AAL5 0x31 /* AAL5 over ATM */
#define IFT_SONETPATH 0x32
#define IFT_SONETVT 0x33
#define IFT_SMDSICIP 0x34 /* SMDS InterCarrier Interface */
#define IFT_PROPVIRTUAL 0x35 /* Proprietary Virtual/internal */
#define IFT_PROPMUX 0x36 /* Proprietary Multiplexing */

912
sys/net/radix.c Normal file
View File

@ -0,0 +1,912 @@
/*
* Copyright (c) 1988, 1989, 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.
*
* @(#)radix.c 8.5 (Berkeley) 5/19/95
*/
/*
* Routines to build and maintain radix trees for routing lookups.
*/
#ifndef _RADIX_H_
#include <sys/param.h>
#ifdef KERNEL
#include <sys/systm.h>
#include <sys/malloc.h>
#define M_DONTWAIT M_NOWAIT
#include <sys/domain.h>
#else
#include <stdlib.h>
#endif
#include <sys/syslog.h>
#include <net/radix.h>
#endif
int max_keylen;
struct radix_mask *rn_mkfreelist;
struct radix_node_head *mask_rnhead;
static char *addmask_key;
static char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, -1};
static char *rn_zeros, *rn_ones;
#define rn_masktop (mask_rnhead->rnh_treetop)
#undef Bcmp
#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
/*
* The data structure for the keys is a radix tree with one way
* branching removed. The index rn_b at an internal node n represents a bit
* position to be tested. The tree is arranged so that all descendants
* of a node n have keys whose bits all agree up to position rn_b - 1.
* (We say the index of n is rn_b.)
*
* There is at least one descendant which has a one bit at position rn_b,
* and at least one with a zero there.
*
* A route is determined by a pair of key and mask. We require that the
* bit-wise logical and of the key and mask to be the key.
* We define the index of a route to associated with the mask to be
* the first bit number in the mask where 0 occurs (with bit number 0
* representing the highest order bit).
*
* We say a mask is normal if every bit is 0, past the index of the mask.
* If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
* and m is a normal mask, then the route applies to every descendant of n.
* If the index(m) < rn_b, this implies the trailing last few bits of k
* before bit b are all 0, (and hence consequently true of every descendant
* of n), so the route applies to all descendants of the node as well.
*
* Similar logic shows that a non-normal mask m such that
* index(m) <= index(n) could potentially apply to many children of n.
* Thus, for each non-host route, we attach its mask to a list at an internal
* node as high in the tree as we can go.
*
* The present version of the code makes use of normal routes in short-
* circuiting an explict mask and compare operation when testing whether
* a key satisfies a normal route, and also in remembering the unique leaf
* that governs a subtree.
*/
struct radix_node *
rn_search(v_arg, head)
void *v_arg;
struct radix_node *head;
{
register struct radix_node *x;
register caddr_t v;
for (x = head, v = v_arg; x->rn_b >= 0;) {
if (x->rn_bmask & v[x->rn_off])
x = x->rn_r;
else
x = x->rn_l;
}
return (x);
};
struct radix_node *
rn_search_m(v_arg, head, m_arg)
struct radix_node *head;
void *v_arg, *m_arg;
{
register struct radix_node *x;
register caddr_t v = v_arg, m = m_arg;
for (x = head; x->rn_b >= 0;) {
if ((x->rn_bmask & m[x->rn_off]) &&
(x->rn_bmask & v[x->rn_off]))
x = x->rn_r;
else
x = x->rn_l;
}
return x;
};
int
rn_refines(m_arg, n_arg)
void *m_arg, *n_arg;
{
register caddr_t m = m_arg, n = n_arg;
register caddr_t lim, lim2 = lim = n + *(u_char *)n;
int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
int masks_are_equal = 1;
if (longer > 0)
lim -= longer;
while (n < lim) {
if (*n & ~(*m))
return 0;
if (*n++ != *m++)
masks_are_equal = 0;
}
while (n < lim2)
if (*n++)
return 0;
if (masks_are_equal && (longer < 0))
for (lim2 = m - longer; m < lim2; )
if (*m++)
return 1;
return (!masks_are_equal);
}
struct radix_node *
rn_lookup(v_arg, m_arg, head)
void *v_arg, *m_arg;
struct radix_node_head *head;
{
register struct radix_node *x;
caddr_t netmask = 0;
if (m_arg) {
if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0)
return (0);
netmask = x->rn_key;
}
x = rn_match(v_arg, head);
if (x && netmask) {
while (x && x->rn_mask != netmask)
x = x->rn_dupedkey;
}
return x;
}
static int
rn_satsifies_leaf(trial, leaf, skip)
char *trial;
register struct radix_node *leaf;
int skip;
{
register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
char *cplim;
int length = min(*(u_char *)cp, *(u_char *)cp2);
if (cp3 == 0)
cp3 = rn_ones;
else
length = min(length, *(u_char *)cp3);
cplim = cp + length; cp3 += skip; cp2 += skip;
for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
if ((*cp ^ *cp2) & *cp3)
return 0;
return 1;
}
struct radix_node *
rn_match(v_arg, head)
void *v_arg;
struct radix_node_head *head;
{
caddr_t v = v_arg;
register struct radix_node *t = head->rnh_treetop, *x;
register caddr_t cp = v, cp2;
caddr_t cplim;
struct radix_node *saved_t, *top = t;
int off = t->rn_off, vlen = *(u_char *)cp, matched_off;
register int test, b, rn_b;
/*
* Open code rn_search(v, top) to avoid overhead of extra
* subroutine call.
*/
for (; t->rn_b >= 0; ) {
if (t->rn_bmask & cp[t->rn_off])
t = t->rn_r;
else
t = t->rn_l;
}
/*
* See if we match exactly as a host destination
* or at least learn how many bits match, for normal mask finesse.
*
* It doesn't hurt us to limit how many bytes to check
* to the length of the mask, since if it matches we had a genuine
* match and the leaf we have is the most specific one anyway;
* if it didn't match with a shorter length it would fail
* with a long one. This wins big for class B&C netmasks which
* are probably the most common case...
*/
if (t->rn_mask)
vlen = *(u_char *)t->rn_mask;
cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
for (; cp < cplim; cp++, cp2++)
if (*cp != *cp2)
goto on1;
/*
* This extra grot is in case we are explicitly asked
* to look up the default. Ugh!
*/
if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey)
t = t->rn_dupedkey;
return t;
on1:
test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
for (b = 7; (test >>= 1) > 0;)
b--;
matched_off = cp - v;
b += matched_off << 3;
rn_b = -1 - b;
/*
* If there is a host route in a duped-key chain, it will be first.
*/
if ((saved_t = t)->rn_mask == 0)
t = t->rn_dupedkey;
for (; t; t = t->rn_dupedkey)
/*
* Even if we don't match exactly as a host,
* we may match if the leaf we wound up at is
* a route to a net.
*/
if (t->rn_flags & RNF_NORMAL) {
if (rn_b <= t->rn_b)
return t;
} else if (rn_satsifies_leaf(v, t, matched_off))
return t;
t = saved_t;
/* start searching up the tree */
do {
register struct radix_mask *m;
t = t->rn_p;
m = t->rn_mklist;
if (m) {
/*
* If non-contiguous masks ever become important
* we can restore the masking and open coding of
* the search and satisfaction test and put the
* calculation of "off" back before the "do".
*/
do {
if (m->rm_flags & RNF_NORMAL) {
if (rn_b <= m->rm_b)
return (m->rm_leaf);
} else {
off = min(t->rn_off, matched_off);
x = rn_search_m(v, t, m->rm_mask);
while (x && x->rn_mask != m->rm_mask)
x = x->rn_dupedkey;
if (x && rn_satsifies_leaf(v, x, off))
return x;
}
m = m->rm_mklist;
} while (m);
}
} while (t != top);
return 0;
};
#ifdef RN_DEBUG
int rn_nodenum;
struct radix_node *rn_clist;
int rn_saveinfo;
int rn_debug = 1;
#endif
struct radix_node *
rn_newpair(v, b, nodes)
void *v;
int b;
struct radix_node nodes[2];
{
register struct radix_node *tt = nodes, *t = tt + 1;
t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7);
t->rn_l = tt; t->rn_off = b >> 3;
tt->rn_b = -1; tt->rn_key = (caddr_t)v; tt->rn_p = t;
tt->rn_flags = t->rn_flags = RNF_ACTIVE;
#ifdef RN_DEBUG
tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
#endif
return t;
}
struct radix_node *
rn_insert(v_arg, head, dupentry, nodes)
void *v_arg;
struct radix_node_head *head;
int *dupentry;
struct radix_node nodes[2];
{
caddr_t v = v_arg;
struct radix_node *top = head->rnh_treetop;
int head_off = top->rn_off, vlen = (int)*((u_char *)v);
register struct radix_node *t = rn_search(v_arg, top);
register caddr_t cp = v + head_off;
register int b;
struct radix_node *tt;
/*
* Find first bit at which v and t->rn_key differ
*/
{
register caddr_t cp2 = t->rn_key + head_off;
register int cmp_res;
caddr_t cplim = v + vlen;
while (cp < cplim)
if (*cp2++ != *cp++)
goto on1;
*dupentry = 1;
return t;
on1:
*dupentry = 0;
cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
for (b = (cp - v) << 3; cmp_res; b--)
cmp_res >>= 1;
}
{
register struct radix_node *p, *x = top;
cp = v;
do {
p = x;
if (cp[x->rn_off] & x->rn_bmask)
x = x->rn_r;
else x = x->rn_l;
} while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */
#ifdef RN_DEBUG
if (rn_debug)
log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
#endif
t = rn_newpair(v_arg, b, nodes); tt = t->rn_l;
if ((cp[p->rn_off] & p->rn_bmask) == 0)
p->rn_l = t;
else
p->rn_r = t;
x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */
if ((cp[t->rn_off] & t->rn_bmask) == 0) {
t->rn_r = x;
} else {
t->rn_r = tt; t->rn_l = x;
}
#ifdef RN_DEBUG
if (rn_debug)
log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
#endif
}
return (tt);
}
struct radix_node *
rn_addmask(n_arg, search, skip)
int search, skip;
void *n_arg;
{
caddr_t netmask = (caddr_t)n_arg;
register struct radix_node *x;
register caddr_t cp, cplim;
register int b = 0, mlen, j;
int maskduplicated, m0, isnormal;
struct radix_node *saved_x;
static int last_zeroed = 0;
if ((mlen = *(u_char *)netmask) > max_keylen)
mlen = max_keylen;
if (skip == 0)
skip = 1;
if (mlen <= skip)
return (mask_rnhead->rnh_nodes);
if (skip > 1)
Bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
if ((m0 = mlen) > skip)
Bcopy(netmask + skip, addmask_key + skip, mlen - skip);
/*
* Trim trailing zeroes.
*/
for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
cp--;
mlen = cp - addmask_key;
if (mlen <= skip) {
if (m0 >= last_zeroed)
last_zeroed = mlen;
return (mask_rnhead->rnh_nodes);
}
if (m0 < last_zeroed)
Bzero(addmask_key + m0, last_zeroed - m0);
*addmask_key = last_zeroed = mlen;
x = rn_search(addmask_key, rn_masktop);
if (Bcmp(addmask_key, x->rn_key, mlen) != 0)
x = 0;
if (x || search)
return (x);
R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
if ((saved_x = x) == 0)
return (0);
Bzero(x, max_keylen + 2 * sizeof (*x));
netmask = cp = (caddr_t)(x + 2);
Bcopy(addmask_key, cp, mlen);
x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
if (maskduplicated) {
log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
Free(saved_x);
return (x);
}
/*
* Calculate index of mask, and check for normalcy.
*/
cplim = netmask + mlen; isnormal = 1;
for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)
cp++;
if (cp != cplim) {
for (j = 0x80; (j & *cp) != 0; j >>= 1)
b++;
if (*cp != normal_chars[b] || cp != (cplim - 1))
isnormal = 0;
}
b += (cp - netmask) << 3;
x->rn_b = -1 - b;
if (isnormal)
x->rn_flags |= RNF_NORMAL;
return (x);
}
static int /* XXX: arbitrary ordering for non-contiguous masks */
rn_lexobetter(m_arg, n_arg)
void *m_arg, *n_arg;
{
register u_char *mp = m_arg, *np = n_arg, *lim;
if (*mp > *np)
return 1; /* not really, but need to check longer one first */
if (*mp == *np)
for (lim = mp + *mp; mp < lim;)
if (*mp++ > *np++)
return 1;
return 0;
}
static struct radix_mask *
rn_new_radix_mask(tt, next)
register struct radix_node *tt;
register struct radix_mask *next;
{
register struct radix_mask *m;
MKGet(m);
if (m == 0) {
log(LOG_ERR, "Mask for route not entered\n");
return (0);
}
Bzero(m, sizeof *m);
m->rm_b = tt->rn_b;
m->rm_flags = tt->rn_flags;
if (tt->rn_flags & RNF_NORMAL)
m->rm_leaf = tt;
else
m->rm_mask = tt->rn_mask;
m->rm_mklist = next;
tt->rn_mklist = m;
return m;
}
struct radix_node *
rn_addroute(v_arg, n_arg, head, treenodes)
void *v_arg, *n_arg;
struct radix_node_head *head;
struct radix_node treenodes[2];
{
caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
register struct radix_node *t, *x = 0, *tt;
struct radix_node *saved_tt, *top = head->rnh_treetop;
short b = 0, b_leaf = 0;
int keyduplicated;
caddr_t mmask;
struct radix_mask *m, **mp;
/*
* In dealing with non-contiguous masks, there may be
* many different routes which have the same mask.
* We will find it useful to have a unique pointer to
* the mask to speed avoiding duplicate references at
* nodes and possibly save time in calculating indices.
*/
if (netmask) {
if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0)
return (0);
b_leaf = x->rn_b;
b = -1 - x->rn_b;
netmask = x->rn_key;
}
/*
* Deal with duplicated keys: attach node to previous instance
*/
saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
if (keyduplicated) {
for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
if (tt->rn_mask == netmask)
return (0);
if (netmask == 0 ||
(tt->rn_mask &&
((b_leaf < tt->rn_b) || /* index(netmask) > node */
rn_refines(netmask, tt->rn_mask) ||
rn_lexobetter(netmask, tt->rn_mask))))
break;
}
/*
* If the mask is not duplicated, we wouldn't
* find it among possible duplicate key entries
* anyway, so the above test doesn't hurt.
*
* We sort the masks for a duplicated key the same way as
* in a masklist -- most specific to least specific.
* This may require the unfortunate nuisance of relocating
* the head of the list.
*
* We also reverse, or doubly link the list through the
* parent pointer.
*/
if (tt == saved_tt) {
struct radix_node *xx = x;
/* link in at head of list */
(tt = treenodes)->rn_dupedkey = t;
tt->rn_flags = t->rn_flags;
tt->rn_p = x = t->rn_p;
t->rn_p = tt;
if (x->rn_l == t) x->rn_l = tt; else x->rn_r = tt;
saved_tt = tt; x = xx;
} else {
(tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
t->rn_dupedkey = tt;
tt->rn_p = t;
if (tt->rn_dupedkey)
tt->rn_dupedkey->rn_p = tt;
}
#ifdef RN_DEBUG
t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
#endif
tt->rn_key = (caddr_t) v;
tt->rn_b = -1;
tt->rn_flags = RNF_ACTIVE;
}
/*
* Put mask in tree.
*/
if (netmask) {
tt->rn_mask = netmask;
tt->rn_b = x->rn_b;
tt->rn_flags |= x->rn_flags & RNF_NORMAL;
}
t = saved_tt->rn_p;
if (keyduplicated)
goto on2;
b_leaf = -1 - t->rn_b;
if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r;
/* Promote general routes from below */
if (x->rn_b < 0) {
for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) {
*mp = m = rn_new_radix_mask(x, 0);
if (m)
mp = &m->rm_mklist;
}
} else if (x->rn_mklist) {
/*
* Skip over masks whose index is > that of new node
*/
for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
if (m->rm_b >= b_leaf)
break;
t->rn_mklist = m; *mp = 0;
}
on2:
/* Add new route to highest possible ancestor's list */
if ((netmask == 0) || (b > t->rn_b ))
return tt; /* can't lift at all */
b_leaf = tt->rn_b;
do {
x = t;
t = t->rn_p;
} while (b <= t->rn_b && x != top);
/*
* Search through routes associated with node to
* insert new route according to index.
* Need same criteria as when sorting dupedkeys to avoid
* double loop on deletion.
*/
for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {
if (m->rm_b < b_leaf)
continue;
if (m->rm_b > b_leaf)
break;
if (m->rm_flags & RNF_NORMAL) {
mmask = m->rm_leaf->rn_mask;
if (tt->rn_flags & RNF_NORMAL) {
log(LOG_ERR,
"Non-unique normal route, mask not entered");
return tt;
}
} else
mmask = m->rm_mask;
if (mmask == netmask) {
m->rm_refs++;
tt->rn_mklist = m;
return tt;
}
if (rn_refines(netmask, mmask) || rn_lexobetter(netmask, mmask))
break;
}
*mp = rn_new_radix_mask(tt, *mp);
return tt;
}
struct radix_node *
rn_delete(v_arg, netmask_arg, head)
void *v_arg, *netmask_arg;
struct radix_node_head *head;
{
register struct radix_node *t, *p, *x, *tt;
struct radix_mask *m, *saved_m, **mp;
struct radix_node *dupedkey, *saved_tt, *top;
caddr_t v, netmask;
int b, head_off, vlen;
v = v_arg;
netmask = netmask_arg;
x = head->rnh_treetop;
tt = rn_search(v, x);
head_off = x->rn_off;
vlen = *(u_char *)v;
saved_tt = tt;
top = x;
if (tt == 0 ||
Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
return (0);
/*
* Delete our route from mask lists.
*/
if (netmask) {
if ((x = rn_addmask(netmask, 1, head_off)) == 0)
return (0);
netmask = x->rn_key;
while (tt->rn_mask != netmask)
if ((tt = tt->rn_dupedkey) == 0)
return (0);
}
if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
goto on1;
if (tt->rn_flags & RNF_NORMAL) {
if (m->rm_leaf != tt || m->rm_refs > 0) {
log(LOG_ERR, "rn_delete: inconsistent annotation\n");
return 0; /* dangling ref could cause disaster */
}
} else {
if (m->rm_mask != tt->rn_mask) {
log(LOG_ERR, "rn_delete: inconsistent annotation\n");
goto on1;
}
if (--m->rm_refs >= 0)
goto on1;
}
b = -1 - tt->rn_b;
t = saved_tt->rn_p;
if (b > t->rn_b)
goto on1; /* Wasn't lifted at all */
do {
x = t;
t = t->rn_p;
} while (b <= t->rn_b && x != top);
for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
if (m == saved_m) {
*mp = m->rm_mklist;
MKFree(m);
break;
}
if (m == 0) {
log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
if (tt->rn_flags & RNF_NORMAL)
return (0); /* Dangling ref to us */
}
on1:
/*
* Eliminate us from tree
*/
if (tt->rn_flags & RNF_ROOT)
return (0);
#ifdef RN_DEBUG
/* Get us out of the creation list */
for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
if (t) t->rn_ybro = tt->rn_ybro;
#endif
t = tt->rn_p;
dupedkey = saved_tt->rn_dupedkey;
if (dupedkey) {
/*
* Here, tt is the deletion target, and
* saved_tt is the head of the dupedkey chain.
*/
if (tt == saved_tt) {
x = dupedkey; x->rn_p = t;
if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x;
} else {
/* find node in front of tt on the chain */
for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
p = p->rn_dupedkey;
if (p) {
p->rn_dupedkey = tt->rn_dupedkey;
if (tt->rn_dupedkey)
tt->rn_dupedkey->rn_p = p;
} else log(LOG_ERR, "rn_delete: couldn't find us\n");
}
t = tt + 1;
if (t->rn_flags & RNF_ACTIVE) {
#ifndef RN_DEBUG
*++x = *t; p = t->rn_p;
#else
b = t->rn_info; *++x = *t; t->rn_info = b; p = t->rn_p;
#endif
if (p->rn_l == t) p->rn_l = x; else p->rn_r = x;
x->rn_l->rn_p = x; x->rn_r->rn_p = x;
}
goto out;
}
if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l;
p = t->rn_p;
if (p->rn_r == t) p->rn_r = x; else p->rn_l = x;
x->rn_p = p;
/*
* Demote routes attached to us.
*/
if (t->rn_mklist) {
if (x->rn_b >= 0) {
for (mp = &x->rn_mklist; (m = *mp);)
mp = &m->rm_mklist;
*mp = t->rn_mklist;
} else {
/* If there are any key,mask pairs in a sibling
duped-key chain, some subset will appear sorted
in the same order attached to our mklist */
for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
if (m == x->rn_mklist) {
struct radix_mask *mm = m->rm_mklist;
x->rn_mklist = 0;
if (--(m->rm_refs) < 0)
MKFree(m);
m = mm;
}
if (m)
log(LOG_ERR, "%s %x at %x\n",
"rn_delete: Orphaned Mask", m, x);
}
}
/*
* We may be holding an active internal node in the tree.
*/
x = tt + 1;
if (t != x) {
#ifndef RN_DEBUG
*t = *x;
#else
b = t->rn_info; *t = *x; t->rn_info = b;
#endif
t->rn_l->rn_p = t; t->rn_r->rn_p = t;
p = x->rn_p;
if (p->rn_l == x) p->rn_l = t; else p->rn_r = t;
}
out:
tt->rn_flags &= ~RNF_ACTIVE;
tt[1].rn_flags &= ~RNF_ACTIVE;
return (tt);
}
int
rn_walktree(h, f, w)
struct radix_node_head *h;
register int (*f)();
void *w;
{
int error;
struct radix_node *base, *next;
register struct radix_node *rn = h->rnh_treetop;
/*
* This gets complicated because we may delete the node
* while applying the function f to it, so we need to calculate
* the successor node in advance.
*/
/* First time through node, go left */
while (rn->rn_b >= 0)
rn = rn->rn_l;
for (;;) {
base = rn;
/* If at right child go back up, otherwise, go right */
while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0)
rn = rn->rn_p;
/* Find the next *leaf* since next node might vanish, too */
for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;)
rn = rn->rn_l;
next = rn;
/* Process leaves */
while (rn = base) {
base = rn->rn_dupedkey;
if (!(rn->rn_flags & RNF_ROOT) && (error = (*f)(rn, w)))
return (error);
}
rn = next;
if (rn->rn_flags & RNF_ROOT)
return (0);
}
/* NOTREACHED */
}
int
rn_inithead(head, off)
void **head;
int off;
{
register struct radix_node_head *rnh;
register struct radix_node *t, *tt, *ttt;
if (*head)
return (1);
R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh));
if (rnh == 0)
return (0);
Bzero(rnh, sizeof (*rnh));
*head = rnh;
t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
ttt = rnh->rnh_nodes + 2;
t->rn_r = ttt;
t->rn_p = t;
tt = t->rn_l;
tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
tt->rn_b = -1 - off;
*ttt = *tt;
ttt->rn_key = rn_ones;
rnh->rnh_addaddr = rn_addroute;
rnh->rnh_deladdr = rn_delete;
rnh->rnh_matchaddr = rn_match;
rnh->rnh_lookup = rn_lookup;
rnh->rnh_walktree = rn_walktree;
rnh->rnh_treetop = t;
return (1);
}
void
rn_init()
{
char *cp, *cplim;
#ifdef KERNEL
struct domain *dom;
for (dom = domains; dom; dom = dom->dom_next)
if (dom->dom_maxrtkey > max_keylen)
max_keylen = dom->dom_maxrtkey;
#endif
if (max_keylen == 0) {
log(LOG_ERR,
"rn_init: radix functions require max_keylen be set\n");
return;
}
R_Malloc(rn_zeros, char *, 3 * max_keylen);
if (rn_zeros == NULL)
panic("rn_init");
Bzero(rn_zeros, 3 * max_keylen);
rn_ones = cp = rn_zeros + max_keylen;
addmask_key = cplim = rn_ones + max_keylen;
while (cp < cplim)
*cp++ = -1;
if (rn_inithead((void **)&mask_rnhead, 0) == 0)
panic("rn_init 2");
}

162
sys/net/radix.h Normal file
View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 1988, 1989, 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.
*
* @(#)radix.h 8.2 (Berkeley) 10/31/94
*/
#ifndef _RADIX_H_
#define _RADIX_H_
/*
* Radix search tree node layout.
*/
struct radix_node {
struct radix_mask *rn_mklist; /* list of masks contained in subtree */
struct radix_node *rn_p; /* parent */
short rn_b; /* bit offset; -1-index(netmask) */
char rn_bmask; /* node: mask for bit test*/
u_char rn_flags; /* enumerated next */
#define RNF_NORMAL 1 /* leaf contains normal route */
#define RNF_ROOT 2 /* leaf is root leaf for tree */
#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */
union {
struct { /* leaf only data: */
caddr_t rn_Key; /* object of search */
caddr_t rn_Mask; /* netmask, if present */
struct radix_node *rn_Dupedkey;
} rn_leaf;
struct { /* node only data: */
int rn_Off; /* where to start compare */
struct radix_node *rn_L;/* progeny */
struct radix_node *rn_R;/* progeny */
}rn_node;
} rn_u;
#ifdef RN_DEBUG
int rn_info;
struct radix_node *rn_twin;
struct radix_node *rn_ybro;
#endif
};
#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
#define rn_key rn_u.rn_leaf.rn_Key
#define rn_mask rn_u.rn_leaf.rn_Mask
#define rn_off rn_u.rn_node.rn_Off
#define rn_l rn_u.rn_node.rn_L
#define rn_r rn_u.rn_node.rn_R
/*
* Annotations to tree concerning potential routes applying to subtrees.
*/
extern struct radix_mask {
short rm_b; /* bit offset; -1-index(netmask) */
char rm_unused; /* cf. rn_bmask */
u_char rm_flags; /* cf. rn_flags */
struct radix_mask *rm_mklist; /* more masks to try */
union {
caddr_t rmu_mask; /* the mask */
struct radix_node *rmu_leaf; /* for normal routes */
} rm_rmu;
int rm_refs; /* # of references to this struct */
} *rn_mkfreelist;
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
#define MKGet(m) {\
if (rn_mkfreelist) {\
m = rn_mkfreelist; \
rn_mkfreelist = (m)->rm_mklist; \
} else \
R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
struct radix_node_head {
struct radix_node *rnh_treetop;
int rnh_addrsize; /* permit, but not require fixed keys */
int rnh_pktsize; /* permit, but not require fixed keys */
struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
__P((void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]));
struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
__P((void *v, void *mask,
struct radix_node_head *head, struct radix_node nodes[]));
struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
__P((void *v, void *mask, struct radix_node_head *head));
struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
__P((void *v, void *mask, struct radix_node_head *head));
struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
__P((void *v, struct radix_node_head *head));
struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
__P((void *v, void *mask, struct radix_node_head *head));
struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
__P((void *v, struct radix_node_head *head));
int (*rnh_walktree) /* traverse tree */
__P((struct radix_node_head *head, int (*f)(), void *w));
struct radix_node rnh_nodes[3]; /* empty tree for common case */
};
#ifndef KERNEL
#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((char *)(p), (int)(n));
#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
#define Free(p) free((char *)p);
#else
#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n))
#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n));
#define R_Malloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_DONTWAIT))
#define Free(p) free((caddr_t)p, M_RTABLE);
#endif /*KERNEL*/
void rn_init __P((void));
int rn_inithead __P((void **, int));
int rn_refines __P((void *, void *));
int rn_walktree __P((struct radix_node_head *, int (*)(), void *));
struct radix_node
*rn_addmask __P((void *, int, int)),
*rn_addroute __P((void *, void *, struct radix_node_head *,
struct radix_node [2])),
*rn_delete __P((void *, void *, struct radix_node_head *)),
*rn_insert __P((void *, struct radix_node_head *, int *,
struct radix_node [2])),
*rn_match __P((void *, struct radix_node_head *)),
*rn_newpair __P((void *, int, struct radix_node[2])),
*rn_search __P((void *, struct radix_node *)),
*rn_search_m __P((void *, struct radix_node *, void *));
#endif /* _RADIX_H_ */

538
sys/net/route.c Normal file
View File

@ -0,0 +1,538 @@
/*
* Copyright (c) 1980, 1986, 1991, 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.
*
* @(#)route.c 8.3 (Berkeley) 1/9/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/route.h>
#include <net/raw_cb.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#ifdef NS
#include <netns/ns.h>
#endif
#define SA(p) ((struct sockaddr *)(p))
int rttrash; /* routes not in table but not freed */
struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
void
rtable_init(table)
void **table;
{
struct domain *dom;
for (dom = domains; dom; dom = dom->dom_next)
if (dom->dom_rtattach)
dom->dom_rtattach(&table[dom->dom_family],
dom->dom_rtoffset);
}
void
route_init()
{
rn_init(); /* initialize all zeroes, all ones, mask table */
rtable_init((void **)rt_tables);
}
/*
* Packet routing routines.
*/
void
rtalloc(ro)
register struct route *ro;
{
if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
return; /* XXX */
ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
}
struct rtentry *
rtalloc1(dst, report)
register struct sockaddr *dst;
int report;
{
register struct radix_node_head *rnh = rt_tables[dst->sa_family];
register struct rtentry *rt;
register struct radix_node *rn;
struct rtentry *newrt = 0;
struct rt_addrinfo info;
int s = splnet(), err = 0, msgtype = RTM_MISS;
if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
((rn->rn_flags & RNF_ROOT) == 0)) {
newrt = rt = (struct rtentry *)rn;
if (report && (rt->rt_flags & RTF_CLONING)) {
err = rtrequest(RTM_RESOLVE, dst, SA(0),
SA(0), 0, &newrt);
if (err) {
newrt = rt;
rt->rt_refcnt++;
goto miss;
}
if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
msgtype = RTM_RESOLVE;
goto miss;
}
} else
rt->rt_refcnt++;
} else {
rtstat.rts_unreach++;
miss: if (report) {
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = dst;
rt_missmsg(msgtype, &info, 0, err);
}
}
splx(s);
return (newrt);
}
void
rtfree(rt)
register struct rtentry *rt;
{
register struct ifaddr *ifa;
if (rt == 0)
panic("rtfree");
rt->rt_refcnt--;
if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
panic ("rtfree 2");
rttrash--;
if (rt->rt_refcnt < 0) {
printf("rtfree: %x not freed (neg refs)\n", rt);
return;
}
ifa = rt->rt_ifa;
IFAFREE(ifa);
Free(rt_key(rt));
Free(rt);
}
}
void
ifafree(ifa)
register struct ifaddr *ifa;
{
if (ifa == NULL)
panic("ifafree");
if (ifa->ifa_refcnt == 0)
free(ifa, M_IFADDR);
else
ifa->ifa_refcnt--;
}
/*
* Force a routing table entry to the specified
* destination to go through the given gateway.
* Normally called as a result of a routing redirect
* message from the network layer.
*
* N.B.: must be called at splnet
*
*/
int
rtredirect(dst, gateway, netmask, flags, src, rtp)
struct sockaddr *dst, *gateway, *netmask, *src;
int flags;
struct rtentry **rtp;
{
register struct rtentry *rt;
int error = 0;
short *stat = 0;
struct rt_addrinfo info;
struct ifaddr *ifa;
/* verify the gateway is directly reachable */
if ((ifa = ifa_ifwithnet(gateway)) == 0) {
error = ENETUNREACH;
goto out;
}
rt = rtalloc1(dst, 0);
/*
* If the redirect isn't from our current router for this dst,
* it's either old or wrong. If it redirects us to ourselves,
* we have a routing loop, perhaps as a result of an interface
* going down recently.
*/
#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
if (!(flags & RTF_DONE) && rt &&
(!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
error = EINVAL;
else if (ifa_ifwithaddr(gateway))
error = EHOSTUNREACH;
if (error)
goto done;
/*
* Create a new entry if we just got back a wildcard entry
* or the the lookup failed. This is necessary for hosts
* which use routing redirects generated by smart gateways
* to dynamically build the routing tables.
*/
if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
goto create;
/*
* Don't listen to the redirect if it's
* for a route to an interface.
*/
if (rt->rt_flags & RTF_GATEWAY) {
if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
/*
* Changing from route to net => route to host.
* Create new route, rather than smashing route to net.
*/
create:
flags |= RTF_GATEWAY | RTF_DYNAMIC;
error = rtrequest((int)RTM_ADD, dst, gateway,
netmask, flags,
(struct rtentry **)0);
stat = &rtstat.rts_dynamic;
} else {
/*
* Smash the current notion of the gateway to
* this destination. Should check about netmask!!!
*/
rt->rt_flags |= RTF_MODIFIED;
flags |= RTF_MODIFIED;
stat = &rtstat.rts_newgateway;
rt_setgate(rt, rt_key(rt), gateway);
}
} else
error = EHOSTUNREACH;
done:
if (rt) {
if (rtp && !error)
*rtp = rt;
else
rtfree(rt);
}
out:
if (error)
rtstat.rts_badredirect++;
else if (stat != NULL)
(*stat)++;
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = dst;
info.rti_info[RTAX_GATEWAY] = gateway;
info.rti_info[RTAX_NETMASK] = netmask;
info.rti_info[RTAX_AUTHOR] = src;
rt_missmsg(RTM_REDIRECT, &info, flags, error);
}
/*
* Routing table ioctl interface.
*/
int
rtioctl(req, data, p)
u_long req;
caddr_t data;
struct proc *p;
{
return (EOPNOTSUPP);
}
struct ifaddr *
ifa_ifwithroute(flags, dst, gateway)
int flags;
struct sockaddr *dst, *gateway;
{
register struct ifaddr *ifa;
if ((flags & RTF_GATEWAY) == 0) {
/*
* If we are adding a route to an interface,
* and the interface is a pt to pt link
* we should search for the destination
* as our clue to the interface. Otherwise
* we can use the local address.
*/
ifa = 0;
if (flags & RTF_HOST)
ifa = ifa_ifwithdstaddr(dst);
if (ifa == 0)
ifa = ifa_ifwithaddr(gateway);
} else {
/*
* If we are adding a route to a remote net
* or host, the gateway may still be on the
* other end of a pt to pt link.
*/
ifa = ifa_ifwithdstaddr(gateway);
}
if (ifa == 0)
ifa = ifa_ifwithnet(gateway);
if (ifa == 0) {
struct rtentry *rt = rtalloc1(dst, 0);
if (rt == 0)
return (0);
rt->rt_refcnt--;
if ((ifa = rt->rt_ifa) == 0)
return (0);
}
if (ifa->ifa_addr->sa_family != dst->sa_family) {
struct ifaddr *oifa = ifa;
ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
if (ifa == 0)
ifa = oifa;
}
return (ifa);
}
#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int
rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
int req, flags;
struct sockaddr *dst, *gateway, *netmask;
struct rtentry **ret_nrt;
{
int s = splnet(); int error = 0;
register struct rtentry *rt;
register struct radix_node *rn;
register struct radix_node_head *rnh;
struct ifaddr *ifa;
struct sockaddr *ndst;
#define senderr(x) { error = x ; goto bad; }
if ((rnh = rt_tables[dst->sa_family]) == 0)
senderr(ESRCH);
if (flags & RTF_HOST)
netmask = 0;
switch (req) {
case RTM_DELETE:
if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
senderr(ESRCH);
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
panic ("rtrequest delete");
rt = (struct rtentry *)rn;
rt->rt_flags &= ~RTF_UP;
if (rt->rt_gwroute) {
rt = rt->rt_gwroute; RTFREE(rt);
(rt = (struct rtentry *)rn)->rt_gwroute = 0;
}
if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
rttrash++;
if (ret_nrt)
*ret_nrt = rt;
else if (rt->rt_refcnt <= 0) {
rt->rt_refcnt++;
rtfree(rt);
}
break;
case RTM_RESOLVE:
if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
senderr(EINVAL);
ifa = rt->rt_ifa;
flags = rt->rt_flags & ~RTF_CLONING;
gateway = rt->rt_gateway;
if ((netmask = rt->rt_genmask) == 0)
flags |= RTF_HOST;
goto makeroute;
case RTM_ADD:
if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
senderr(ENETUNREACH);
makeroute:
R_Malloc(rt, struct rtentry *, sizeof(*rt));
if (rt == 0)
senderr(ENOBUFS);
Bzero(rt, sizeof(*rt));
rt->rt_flags = RTF_UP | flags;
if (rt_setgate(rt, dst, gateway)) {
Free(rt);
senderr(ENOBUFS);
}
ndst = rt_key(rt);
if (netmask) {
rt_maskedcopy(dst, ndst, netmask);
} else
Bcopy(dst, ndst, dst->sa_len);
rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
rnh, rt->rt_nodes);
if (rn == 0) {
if (rt->rt_gwroute)
rtfree(rt->rt_gwroute);
Free(rt_key(rt));
Free(rt);
senderr(EEXIST);
}
ifa->ifa_refcnt++;
rt->rt_ifa = ifa;
rt->rt_ifp = ifa->ifa_ifp;
if (req == RTM_RESOLVE)
rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
if (ret_nrt) {
*ret_nrt = rt;
rt->rt_refcnt++;
}
break;
}
bad:
splx(s);
return (error);
}
int
rt_setgate(rt0, dst, gate)
struct rtentry *rt0;
struct sockaddr *dst, *gate;
{
caddr_t new, old;
int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
register struct rtentry *rt = rt0;
if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
old = (caddr_t)rt_key(rt);
R_Malloc(new, caddr_t, dlen + glen);
if (new == 0)
return 1;
rt->rt_nodes->rn_key = new;
} else {
new = rt->rt_nodes->rn_key;
old = 0;
}
Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
if (old) {
Bcopy(dst, new, dlen);
Free(old);
}
if (rt->rt_gwroute) {
rt = rt->rt_gwroute; RTFREE(rt);
rt = rt0; rt->rt_gwroute = 0;
}
if (rt->rt_flags & RTF_GATEWAY) {
rt->rt_gwroute = rtalloc1(gate, 1);
}
return 0;
}
void
rt_maskedcopy(src, dst, netmask)
struct sockaddr *src, *dst, *netmask;
{
register u_char *cp1 = (u_char *)src;
register u_char *cp2 = (u_char *)dst;
register u_char *cp3 = (u_char *)netmask;
u_char *cplim = cp2 + *cp3;
u_char *cplim2 = cp2 + *cp1;
*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
cp3 += 2;
if (cplim > cplim2)
cplim = cplim2;
while (cp2 < cplim)
*cp2++ = *cp1++ & *cp3++;
if (cp2 < cplim2)
bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
}
/*
* Set up a routing table entry, normally
* for an interface.
*/
int
rtinit(ifa, cmd, flags)
register struct ifaddr *ifa;
int cmd, flags;
{
register struct rtentry *rt;
register struct sockaddr *dst;
register struct sockaddr *deldst;
struct mbuf *m = 0;
struct rtentry *nrt = 0;
int error;
dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
if (cmd == RTM_DELETE) {
if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
m = m_get(M_WAIT, MT_SONAME);
deldst = mtod(m, struct sockaddr *);
rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
dst = deldst;
}
if (rt = rtalloc1(dst, 0)) {
rt->rt_refcnt--;
if (rt->rt_ifa != ifa) {
if (m)
(void) m_free(m);
return (flags & RTF_HOST ? EHOSTUNREACH
: ENETUNREACH);
}
}
}
error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
flags | ifa->ifa_flags, &nrt);
if (m)
(void) m_free(m);
if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
rt_newaddrmsg(cmd, ifa, error, nrt);
if (rt->rt_refcnt <= 0) {
rt->rt_refcnt++;
rtfree(rt);
}
}
if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
rt->rt_refcnt--;
if (rt->rt_ifa != ifa) {
printf("rtinit: wrong ifa (%x) was (%x)\n", ifa,
rt->rt_ifa);
if (rt->rt_ifa->ifa_rtrequest)
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
IFAFREE(rt->rt_ifa);
rt->rt_ifa = ifa;
rt->rt_ifp = ifa->ifa_ifp;
ifa->ifa_refcnt++;
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
}
rt_newaddrmsg(cmd, ifa, error, nrt);
}
return (error);
}

263
sys/net/route.h Normal file
View File

@ -0,0 +1,263 @@
/*
* 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.
*
* @(#)route.h 8.5 (Berkeley) 2/8/95
*/
/*
* Kernel resident routing tables.
*
* The routing tables are initialized when interface addresses
* are set by making entries for all directly connected interfaces.
*/
/*
* A route consists of a destination address and a reference
* to a routing entry. These are often held by protocols
* in their control blocks, e.g. inpcb.
*/
struct route {
struct rtentry *ro_rt;
struct sockaddr ro_dst;
};
/*
* These numbers are used by reliable protocols for determining
* retransmission behavior and are included in the routing structure.
*/
struct rt_metrics {
u_long rmx_locks; /* Kernel must leave these values alone */
u_long rmx_mtu; /* MTU for this path */
u_long rmx_hopcount; /* max hops expected */
u_long rmx_expire; /* lifetime for route, e.g. redirect */
u_long rmx_recvpipe; /* inbound delay-bandwith product */
u_long rmx_sendpipe; /* outbound delay-bandwith product */
u_long rmx_ssthresh; /* outbound gateway buffer limit */
u_long rmx_rtt; /* estimated round trip time */
u_long rmx_rttvar; /* estimated rtt variance */
u_long rmx_pksent; /* packets sent using this route */
};
/*
* rmx_rtt and rmx_rttvar are stored as microseconds;
* RTTTOPRHZ(rtt) converts to a value suitable for use
* by a protocol slowtimo counter.
*/
#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */
#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ))
/*
* We distinguish between routes to hosts and routes to networks,
* preferring the former if available. For each route we infer
* the interface to use from the gateway address supplied when
* the route was entered. Routes that forward packets through
* gateways are marked so that the output routines know to address the
* gateway rather than the ultimate destination.
*/
#ifndef RNF_NORMAL
#include <net/radix.h>
#endif
struct rtentry {
struct radix_node rt_nodes[2]; /* tree glue, and other values */
#define rt_key(r) ((struct sockaddr *)((r)->rt_nodes->rn_key))
#define rt_mask(r) ((struct sockaddr *)((r)->rt_nodes->rn_mask))
struct sockaddr *rt_gateway; /* value */
short rt_flags; /* up/down?, host/net */
short rt_refcnt; /* # held references */
u_long rt_use; /* raw # packets forwarded */
struct ifnet *rt_ifp; /* the answer: interface to use */
struct ifaddr *rt_ifa; /* the answer: interface to use */
struct sockaddr *rt_genmask; /* for generation of cloned routes */
caddr_t rt_llinfo; /* pointer to link level info cache */
struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */
struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */
};
/*
* Following structure necessary for 4.3 compatibility;
* We should eventually move it to a compat file.
*/
struct ortentry {
u_long rt_hash; /* to speed lookups */
struct sockaddr rt_dst; /* key */
struct sockaddr rt_gateway; /* value */
short rt_flags; /* up/down?, host/net */
short rt_refcnt; /* # held references */
u_long rt_use; /* raw # packets forwarded */
struct ifnet *rt_ifp; /* the answer: interface to use */
};
#define RTF_UP 0x1 /* route usable */
#define RTF_GATEWAY 0x2 /* destination is a gateway */
#define RTF_HOST 0x4 /* host entry (net otherwise) */
#define RTF_REJECT 0x8 /* host or net unreachable */
#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */
#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */
#define RTF_DONE 0x40 /* message confirmed */
#define RTF_MASK 0x80 /* subnet mask present */
#define RTF_CLONING 0x100 /* generate new routes on use */
#define RTF_XRESOLVE 0x200 /* external daemon resolves name */
#define RTF_LLINFO 0x400 /* generated by ARP or ESIS */
#define RTF_STATIC 0x800 /* manually added */
#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */
#define RTF_PROTO2 0x4000 /* protocol specific routing flag */
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
/*
* Routing statistics.
*/
struct rtstat {
short rts_badredirect; /* bogus redirect calls */
short rts_dynamic; /* routes created by redirects */
short rts_newgateway; /* routes modified by redirects */
short rts_unreach; /* lookups which failed */
short rts_wildcard; /* lookups satisfied by a wildcard */
};
/*
* Structures for routing messages.
*/
struct rt_msghdr {
u_short rtm_msglen; /* to skip over non-understood messages */
u_char rtm_version; /* future binary compatibility */
u_char rtm_type; /* message type */
u_short rtm_index; /* index for associated ifp */
int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
int rtm_addrs; /* bitmask identifying sockaddrs in msg */
pid_t rtm_pid; /* identify sender */
int rtm_seq; /* for sender to identify action */
int rtm_errno; /* why failed */
int rtm_use; /* from rtentry */
u_long rtm_inits; /* which metrics we are initializing */
struct rt_metrics rtm_rmx; /* metrics themselves */
};
#define RTM_VERSION 3 /* Up the ante and ignore older versions */
#define RTM_ADD 0x1 /* Add Route */
#define RTM_DELETE 0x2 /* Delete Route */
#define RTM_CHANGE 0x3 /* Change Metrics or flags */
#define RTM_GET 0x4 /* Report Metrics */
#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */
#define RTM_REDIRECT 0x6 /* Told to use different route */
#define RTM_MISS 0x7 /* Lookup failed on this address */
#define RTM_LOCK 0x8 /* fix specified metrics */
#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */
#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */
#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */
#define RTM_NEWADDR 0xc /* address being added to iface */
#define RTM_DELADDR 0xd /* address being removed from iface */
#define RTM_IFINFO 0xe /* iface going up/down etc. */
#define RTV_MTU 0x1 /* init or lock _mtu */
#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */
#define RTV_EXPIRE 0x4 /* init or lock _hopcount */
#define RTV_RPIPE 0x8 /* init or lock _recvpipe */
#define RTV_SPIPE 0x10 /* init or lock _sendpipe */
#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */
#define RTV_RTT 0x40 /* init or lock _rtt */
#define RTV_RTTVAR 0x80 /* init or lock _rttvar */
/*
* Bitmask values for rtm_addr.
*/
#define RTA_DST 0x1 /* destination sockaddr present */
#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
#define RTA_NETMASK 0x4 /* netmask sockaddr present */
#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */
#define RTA_IFP 0x10 /* interface name sockaddr present */
#define RTA_IFA 0x20 /* interface addr sockaddr present */
#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */
/*
* Index offsets for sockaddr array for alternate internal encoding.
*/
#define RTAX_DST 0 /* destination sockaddr present */
#define RTAX_GATEWAY 1 /* gateway sockaddr present */
#define RTAX_NETMASK 2 /* netmask sockaddr present */
#define RTAX_GENMASK 3 /* cloning mask sockaddr present */
#define RTAX_IFP 4 /* interface name sockaddr present */
#define RTAX_IFA 5 /* interface addr sockaddr present */
#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */
#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */
#define RTAX_MAX 8 /* size of array to allocate */
struct rt_addrinfo {
int rti_addrs;
struct sockaddr *rti_info[RTAX_MAX];
};
struct route_cb {
int ip_count;
int ns_count;
int iso_count;
int any_count;
};
#ifdef KERNEL
#define RTFREE(rt) \
if ((rt)->rt_refcnt <= 1) \
rtfree(rt); \
else \
(rt)->rt_refcnt--;
struct route_cb route_cb;
struct rtstat rtstat;
struct radix_node_head *rt_tables[AF_MAX+1];
struct socket;
void route_init __P((void));
int route_output __P((struct mbuf *, struct socket *));
int route_usrreq __P((struct socket *,
int, struct mbuf *, struct mbuf *, struct mbuf *));
void rt_ifmsg __P((struct ifnet *));
void rt_maskedcopy __P((struct sockaddr *,
struct sockaddr *, struct sockaddr *));
void rt_missmsg __P((int, struct rt_addrinfo *, int, int));
void rt_newaddrmsg __P((int, struct ifaddr *, int, struct rtentry *));
int rt_setgate __P((struct rtentry *,
struct sockaddr *, struct sockaddr *));
void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *));
void rtable_init __P((void **));
void rtalloc __P((struct route *));
struct rtentry *
rtalloc1 __P((struct sockaddr *, int));
void rtfree __P((struct rtentry *));
int rtinit __P((struct ifaddr *, int, int));
int rtioctl __P((u_long, caddr_t, struct proc *));
int rtredirect __P((struct sockaddr *, struct sockaddr *,
struct sockaddr *, int, struct sockaddr *, struct rtentry **));
int rtrequest __P((int, struct sockaddr *,
struct sockaddr *, struct sockaddr *, int, struct rtentry **));
#endif

837
sys/net/rtsock.c Normal file
View File

@ -0,0 +1,837 @@
/*
* Copyright (c) 1988, 1991, 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.
*
* @(#)rtsock.c 8.6 (Berkeley) 2/11/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <net/if.h>
#include <net/route.h>
#include <net/raw_cb.h>
struct sockaddr route_dst = { 2, PF_ROUTE, };
struct sockaddr route_src = { 2, PF_ROUTE, };
struct sockproto route_proto = { PF_ROUTE, };
struct walkarg {
int w_op, w_arg, w_given, w_needed, w_tmemsize;
caddr_t w_where, w_tmem;
};
static struct mbuf *
rt_msg1 __P((int, struct rt_addrinfo *));
static int rt_msg2 __P((int,
struct rt_addrinfo *, caddr_t, struct walkarg *));
static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
/* Sleazy use of local variables throughout file, warning!!!! */
#define dst info.rti_info[RTAX_DST]
#define gate info.rti_info[RTAX_GATEWAY]
#define netmask info.rti_info[RTAX_NETMASK]
#define genmask info.rti_info[RTAX_GENMASK]
#define ifpaddr info.rti_info[RTAX_IFP]
#define ifaaddr info.rti_info[RTAX_IFA]
#define brdaddr info.rti_info[RTAX_BRD]
/*ARGSUSED*/
int
route_usrreq(so, req, m, nam, control)
register struct socket *so;
int req;
struct mbuf *m, *nam, *control;
{
register int error = 0;
register struct rawcb *rp = sotorawcb(so);
int s;
if (req == PRU_ATTACH) {
MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
if (so->so_pcb = (caddr_t)rp)
bzero(so->so_pcb, sizeof(*rp));
}
if (req == PRU_DETACH && rp) {
int af = rp->rcb_proto.sp_protocol;
if (af == AF_INET)
route_cb.ip_count--;
else if (af == AF_NS)
route_cb.ns_count--;
else if (af == AF_ISO)
route_cb.iso_count--;
route_cb.any_count--;
}
s = splnet();
error = raw_usrreq(so, req, m, nam, control);
rp = sotorawcb(so);
if (req == PRU_ATTACH && rp) {
int af = rp->rcb_proto.sp_protocol;
if (error) {
free((caddr_t)rp, M_PCB);
splx(s);
return (error);
}
if (af == AF_INET)
route_cb.ip_count++;
else if (af == AF_NS)
route_cb.ns_count++;
else if (af == AF_ISO)
route_cb.iso_count++;
rp->rcb_faddr = &route_src;
route_cb.any_count++;
soisconnected(so);
so->so_options |= SO_USELOOPBACK;
}
splx(s);
return (error);
}
/*ARGSUSED*/
int
route_output(m, so)
register struct mbuf *m;
struct socket *so;
{
register struct rt_msghdr *rtm = 0;
register struct rtentry *rt = 0;
struct rtentry *saved_nrt = 0;
struct radix_node_head *rnh;
struct rt_addrinfo info;
int len, error = 0;
struct ifnet *ifp = 0;
struct ifaddr *ifa = 0;
#define senderr(e) { error = e; goto flush;}
if (m == 0 || ((m->m_len < sizeof(long)) &&
(m = m_pullup(m, sizeof(long))) == 0))
return (ENOBUFS);
if ((m->m_flags & M_PKTHDR) == 0)
panic("route_output");
len = m->m_pkthdr.len;
if (len < sizeof(*rtm) ||
len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
dst = 0;
senderr(EINVAL);
}
R_Malloc(rtm, struct rt_msghdr *, len);
if (rtm == 0) {
dst = 0;
senderr(ENOBUFS);
}
m_copydata(m, 0, len, (caddr_t)rtm);
if (rtm->rtm_version != RTM_VERSION) {
dst = 0;
senderr(EPROTONOSUPPORT);
}
rtm->rtm_pid = curproc->p_pid;
info.rti_addrs = rtm->rtm_addrs;
rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
if (dst == 0)
senderr(EINVAL);
if (genmask) {
struct radix_node *t;
t = rn_addmask((caddr_t)genmask, 0, 1);
if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
genmask = (struct sockaddr *)(t->rn_key);
else
senderr(ENOBUFS);
}
switch (rtm->rtm_type) {
case RTM_ADD:
if (gate == 0)
senderr(EINVAL);
error = rtrequest(RTM_ADD, dst, gate, netmask,
rtm->rtm_flags, &saved_nrt);
if (error == 0 && saved_nrt) {
rt_setmetrics(rtm->rtm_inits,
&rtm->rtm_rmx, &saved_nrt->rt_rmx);
saved_nrt->rt_refcnt--;
saved_nrt->rt_genmask = genmask;
}
break;
case RTM_DELETE:
error = rtrequest(RTM_DELETE, dst, gate, netmask,
rtm->rtm_flags, &saved_nrt);
if (error == 0) {
(rt = saved_nrt)->rt_refcnt++;
goto report;
}
break;
case RTM_GET:
case RTM_CHANGE:
case RTM_LOCK:
if ((rnh = rt_tables[dst->sa_family]) == 0) {
senderr(EAFNOSUPPORT);
} else if (rt = (struct rtentry *)
rnh->rnh_lookup(dst, netmask, rnh))
rt->rt_refcnt++;
else
senderr(ESRCH);
switch(rtm->rtm_type) {
case RTM_GET:
report:
dst = rt_key(rt);
gate = rt->rt_gateway;
netmask = rt_mask(rt);
genmask = rt->rt_genmask;
if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
if (ifp = rt->rt_ifp) {
ifpaddr = ifp->if_addrlist->ifa_addr;
ifaaddr = rt->rt_ifa->ifa_addr;
if (ifp->if_flags & IFF_POINTOPOINT)
brdaddr = rt->rt_ifa->ifa_dstaddr;
else
brdaddr = 0;
rtm->rtm_index = ifp->if_index;
} else {
ifpaddr = 0;
ifaaddr = 0;
}
}
len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0,
(struct walkarg *)0);
if (len > rtm->rtm_msglen) {
struct rt_msghdr *new_rtm;
R_Malloc(new_rtm, struct rt_msghdr *, len);
if (new_rtm == 0)
senderr(ENOBUFS);
Bcopy(rtm, new_rtm, rtm->rtm_msglen);
Free(rtm); rtm = new_rtm;
}
(void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,
(struct walkarg *)0);
rtm->rtm_flags = rt->rt_flags;
rtm->rtm_rmx = rt->rt_rmx;
rtm->rtm_addrs = info.rti_addrs;
break;
case RTM_CHANGE:
if (gate && rt_setgate(rt, rt_key(rt), gate))
senderr(EDQUOT);
/* new gateway could require new ifaddr, ifp;
flags may also be different; ifp may be specified
by ll sockaddr when protocol address is ambiguous */
if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
(ifp = ifa->ifa_ifp))
ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
ifp);
else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
(ifa = ifa_ifwithroute(rt->rt_flags,
rt_key(rt), gate)))
ifp = ifa->ifa_ifp;
if (ifa) {
register struct ifaddr *oifa = rt->rt_ifa;
if (oifa != ifa) {
if (oifa && oifa->ifa_rtrequest)
oifa->ifa_rtrequest(RTM_DELETE,
rt, gate);
IFAFREE(rt->rt_ifa);
rt->rt_ifa = ifa;
ifa->ifa_refcnt++;
rt->rt_ifp = ifp;
}
}
rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
&rt->rt_rmx);
if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
if (genmask)
rt->rt_genmask = genmask;
/*
* Fall into
*/
case RTM_LOCK:
rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
rt->rt_rmx.rmx_locks |=
(rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
break;
}
break;
default:
senderr(EOPNOTSUPP);
}
flush:
if (rtm) {
if (error)
rtm->rtm_errno = error;
else
rtm->rtm_flags |= RTF_DONE;
}
if (rt)
rtfree(rt);
{
register struct rawcb *rp = 0;
/*
* Check to see if we don't want our own messages.
*/
if ((so->so_options & SO_USELOOPBACK) == 0) {
if (route_cb.any_count <= 1) {
if (rtm)
Free(rtm);
m_freem(m);
return (error);
}
/* There is another listener, so construct message */
rp = sotorawcb(so);
}
if (rtm) {
m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
Free(rtm);
}
if (rp)
rp->rcb_proto.sp_family = 0; /* Avoid us */
if (dst)
route_proto.sp_protocol = dst->sa_family;
raw_input(m, &route_proto, &route_src, &route_dst);
if (rp)
rp->rcb_proto.sp_family = PF_ROUTE;
}
return (error);
}
void
rt_setmetrics(which, in, out)
u_long which;
register struct rt_metrics *in, *out;
{
#define metric(f, e) if (which & (f)) out->e = in->e;
metric(RTV_RPIPE, rmx_recvpipe);
metric(RTV_SPIPE, rmx_sendpipe);
metric(RTV_SSTHRESH, rmx_ssthresh);
metric(RTV_RTT, rmx_rtt);
metric(RTV_RTTVAR, rmx_rttvar);
metric(RTV_HOPCOUNT, rmx_hopcount);
metric(RTV_MTU, rmx_mtu);
metric(RTV_EXPIRE, rmx_expire);
#undef metric
}
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
static void
rt_xaddrs(cp, cplim, rtinfo)
register caddr_t cp, cplim;
register struct rt_addrinfo *rtinfo;
{
register struct sockaddr *sa;
register int i;
bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
if ((rtinfo->rti_addrs & (1 << i)) == 0)
continue;
rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
ADVANCE(cp, sa);
}
}
/*
* Copy data from a buffer back into the indicated mbuf chain,
* starting "off" bytes from the beginning, extending the mbuf
* chain if necessary.
*/
void
m_copyback(m0, off, len, cp)
struct mbuf *m0;
register int off;
register int len;
caddr_t cp;
{
register int mlen;
register struct mbuf *m = m0, *n;
int totlen = 0;
if (m0 == 0)
return;
while (off > (mlen = m->m_len)) {
off -= mlen;
totlen += mlen;
if (m->m_next == 0) {
n = m_getclr(M_DONTWAIT, m->m_type);
if (n == 0)
goto out;
n->m_len = min(MLEN, len + off);
m->m_next = n;
}
m = m->m_next;
}
while (len > 0) {
mlen = min (m->m_len - off, len);
bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
cp += mlen;
len -= mlen;
mlen += off;
off = 0;
totlen += mlen;
if (len == 0)
break;
if (m->m_next == 0) {
n = m_get(M_DONTWAIT, m->m_type);
if (n == 0)
break;
n->m_len = min(MLEN, len);
m->m_next = n;
}
m = m->m_next;
}
out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
m->m_pkthdr.len = totlen;
}
static struct mbuf *
rt_msg1(type, rtinfo)
int type;
register struct rt_addrinfo *rtinfo;
{
register struct rt_msghdr *rtm;
register struct mbuf *m;
register int i;
register struct sockaddr *sa;
int len, dlen;
m = m_gethdr(M_DONTWAIT, MT_DATA);
if (m == 0)
return (m);
switch (type) {
case RTM_DELADDR:
case RTM_NEWADDR:
len = sizeof(struct ifa_msghdr);
break;
case RTM_IFINFO:
len = sizeof(struct if_msghdr);
break;
default:
len = sizeof(struct rt_msghdr);
}
if (len > MHLEN)
panic("rt_msg1");
m->m_pkthdr.len = m->m_len = len;
m->m_pkthdr.rcvif = 0;
rtm = mtod(m, struct rt_msghdr *);
bzero((caddr_t)rtm, len);
for (i = 0; i < RTAX_MAX; i++) {
if ((sa = rtinfo->rti_info[i]) == NULL)
continue;
rtinfo->rti_addrs |= (1 << i);
dlen = ROUNDUP(sa->sa_len);
m_copyback(m, len, dlen, (caddr_t)sa);
len += dlen;
}
if (m->m_pkthdr.len != len) {
m_freem(m);
return (NULL);
}
rtm->rtm_msglen = len;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_type = type;
return (m);
}
static int
rt_msg2(type, rtinfo, cp, w)
int type;
register struct rt_addrinfo *rtinfo;
caddr_t cp;
struct walkarg *w;
{
register int i;
int len, dlen, second_time = 0;
caddr_t cp0;
rtinfo->rti_addrs = 0;
again:
switch (type) {
case RTM_DELADDR:
case RTM_NEWADDR:
len = sizeof(struct ifa_msghdr);
break;
case RTM_IFINFO:
len = sizeof(struct if_msghdr);
break;
default:
len = sizeof(struct rt_msghdr);
}
if (cp0 = cp)
cp += len;
for (i = 0; i < RTAX_MAX; i++) {
register struct sockaddr *sa;
if ((sa = rtinfo->rti_info[i]) == 0)
continue;
rtinfo->rti_addrs |= (1 << i);
dlen = ROUNDUP(sa->sa_len);
if (cp) {
bcopy((caddr_t)sa, cp, (unsigned)dlen);
cp += dlen;
}
len += dlen;
}
if (cp == 0 && w != NULL && !second_time) {
register struct walkarg *rw = w;
rw->w_needed += len;
if (rw->w_needed <= 0 && rw->w_where) {
if (rw->w_tmemsize < len) {
if (rw->w_tmem)
free(rw->w_tmem, M_RTABLE);
if (rw->w_tmem = (caddr_t)
malloc(len, M_RTABLE, M_NOWAIT))
rw->w_tmemsize = len;
}
if (rw->w_tmem) {
cp = rw->w_tmem;
second_time = 1;
goto again;
} else
rw->w_where = 0;
}
}
if (cp) {
register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_type = type;
rtm->rtm_msglen = len;
}
return (len);
}
/*
* This routine is called to generate a message from the routing
* socket indicating that a redirect has occured, a routing lookup
* has failed, or that a protocol has detected timeouts to a particular
* destination.
*/
void
rt_missmsg(type, rtinfo, flags, error)
int type, flags, error;
register struct rt_addrinfo *rtinfo;
{
register struct rt_msghdr *rtm;
register struct mbuf *m;
struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
if (route_cb.any_count == 0)
return;
m = rt_msg1(type, rtinfo);
if (m == 0)
return;
rtm = mtod(m, struct rt_msghdr *);
rtm->rtm_flags = RTF_DONE | flags;
rtm->rtm_errno = error;
rtm->rtm_addrs = rtinfo->rti_addrs;
route_proto.sp_protocol = sa ? sa->sa_family : 0;
raw_input(m, &route_proto, &route_src, &route_dst);
}
/*
* This routine is called to generate a message from the routing
* socket indicating that the status of a network interface has changed.
*/
void
rt_ifmsg(ifp)
register struct ifnet *ifp;
{
register struct if_msghdr *ifm;
struct mbuf *m;
struct rt_addrinfo info;
if (route_cb.any_count == 0)
return;
bzero((caddr_t)&info, sizeof(info));
m = rt_msg1(RTM_IFINFO, &info);
if (m == 0)
return;
ifm = mtod(m, struct if_msghdr *);
ifm->ifm_index = ifp->if_index;
ifm->ifm_flags = ifp->if_flags;
ifm->ifm_data = ifp->if_data;
ifm->ifm_addrs = 0;
route_proto.sp_protocol = 0;
raw_input(m, &route_proto, &route_src, &route_dst);
}
/*
* This is called to generate messages from the routing socket
* indicating a network interface has had addresses associated with it.
* if we ever reverse the logic and replace messages TO the routing
* socket indicate a request to configure interfaces, then it will
* be unnecessary as the routing socket will automatically generate
* copies of it.
*/
void
rt_newaddrmsg(cmd, ifa, error, rt)
int cmd, error;
register struct ifaddr *ifa;
register struct rtentry *rt;
{
struct rt_addrinfo info;
struct sockaddr *sa;
int pass;
struct mbuf *m;
struct ifnet *ifp = ifa->ifa_ifp;
if (route_cb.any_count == 0)
return;
for (pass = 1; pass < 3; pass++) {
bzero((caddr_t)&info, sizeof(info));
if ((cmd == RTM_ADD && pass == 1) ||
(cmd == RTM_DELETE && pass == 2)) {
register struct ifa_msghdr *ifam;
int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
ifaaddr = sa = ifa->ifa_addr;
ifpaddr = ifp->if_addrlist->ifa_addr;
netmask = ifa->ifa_netmask;
brdaddr = ifa->ifa_dstaddr;
if ((m = rt_msg1(ncmd, &info)) == NULL)
continue;
ifam = mtod(m, struct ifa_msghdr *);
ifam->ifam_index = ifp->if_index;
ifam->ifam_metric = ifa->ifa_metric;
ifam->ifam_flags = ifa->ifa_flags;
ifam->ifam_addrs = info.rti_addrs;
}
if ((cmd == RTM_ADD && pass == 2) ||
(cmd == RTM_DELETE && pass == 1)) {
register struct rt_msghdr *rtm;
if (rt == 0)
continue;
netmask = rt_mask(rt);
dst = sa = rt_key(rt);
gate = rt->rt_gateway;
if ((m = rt_msg1(cmd, &info)) == NULL)
continue;
rtm = mtod(m, struct rt_msghdr *);
rtm->rtm_index = ifp->if_index;
rtm->rtm_flags |= rt->rt_flags;
rtm->rtm_errno = error;
rtm->rtm_addrs = info.rti_addrs;
}
route_proto.sp_protocol = sa ? sa->sa_family : 0;
raw_input(m, &route_proto, &route_src, &route_dst);
}
}
/*
* This is used in dumping the kernel table via sysctl().
*/
int
sysctl_dumpentry(rn, w)
struct radix_node *rn;
register struct walkarg *w;
{
register struct rtentry *rt = (struct rtentry *)rn;
int error = 0, size;
struct rt_addrinfo info;
if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
return 0;
bzero((caddr_t)&info, sizeof(info));
dst = rt_key(rt);
gate = rt->rt_gateway;
netmask = rt_mask(rt);
genmask = rt->rt_genmask;
if (rt->rt_ifp) {
ifpaddr = rt->rt_ifp->if_addrlist->ifa_addr;
ifaaddr = rt->rt_ifa->ifa_addr;
if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
brdaddr = rt->rt_ifa->ifa_dstaddr;
}
size = rt_msg2(RTM_GET, &info, 0, w);
if (w->w_where && w->w_tmem) {
register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
rtm->rtm_flags = rt->rt_flags;
rtm->rtm_use = rt->rt_use;
rtm->rtm_rmx = rt->rt_rmx;
rtm->rtm_index = rt->rt_ifp->if_index;
rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
rtm->rtm_addrs = info.rti_addrs;
if (error = copyout((caddr_t)rtm, w->w_where, size))
w->w_where = NULL;
else
w->w_where += size;
}
return (error);
}
int
sysctl_iflist(af, w)
int af;
register struct walkarg *w;
{
register struct ifnet *ifp;
register struct ifaddr *ifa;
struct rt_addrinfo info;
int len, error = 0;
bzero((caddr_t)&info, sizeof(info));
for (ifp = ifnet; ifp; ifp = ifp->if_next) {
if (w->w_arg && w->w_arg != ifp->if_index)
continue;
ifa = ifp->if_addrlist;
ifpaddr = ifa->ifa_addr;
len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
ifpaddr = 0;
if (w->w_where && w->w_tmem) {
register struct if_msghdr *ifm;
ifm = (struct if_msghdr *)w->w_tmem;
ifm->ifm_index = ifp->if_index;
ifm->ifm_flags = ifp->if_flags;
ifm->ifm_data = ifp->if_data;
ifm->ifm_addrs = info.rti_addrs;
if (error = copyout((caddr_t)ifm, w->w_where, len))
return (error);
w->w_where += len;
}
while (ifa = ifa->ifa_next) {
if (af && af != ifa->ifa_addr->sa_family)
continue;
ifaaddr = ifa->ifa_addr;
netmask = ifa->ifa_netmask;
brdaddr = ifa->ifa_dstaddr;
len = rt_msg2(RTM_NEWADDR, &info, 0, w);
if (w->w_where && w->w_tmem) {
register struct ifa_msghdr *ifam;
ifam = (struct ifa_msghdr *)w->w_tmem;
ifam->ifam_index = ifa->ifa_ifp->if_index;
ifam->ifam_flags = ifa->ifa_flags;
ifam->ifam_metric = ifa->ifa_metric;
ifam->ifam_addrs = info.rti_addrs;
if (error = copyout(w->w_tmem, w->w_where, len))
return (error);
w->w_where += len;
}
}
ifaaddr = netmask = brdaddr = 0;
}
return (0);
}
int
sysctl_rtable(name, namelen, where, given, new, newlen)
int *name;
int namelen;
caddr_t where;
size_t *given;
caddr_t *new;
size_t newlen;
{
register struct radix_node_head *rnh;
int i, s, error = EINVAL;
u_char af;
struct walkarg w;
if (new)
return (EPERM);
if (namelen != 3)
return (EINVAL);
af = name[0];
Bzero(&w, sizeof(w));
w.w_where = where;
w.w_given = *given;
w.w_needed = 0 - w.w_given;
w.w_op = name[1];
w.w_arg = name[2];
s = splnet();
switch (w.w_op) {
case NET_RT_DUMP:
case NET_RT_FLAGS:
for (i = 1; i <= AF_MAX; i++)
if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
(error = rnh->rnh_walktree(rnh,
sysctl_dumpentry, &w)))
break;
break;
case NET_RT_IFLIST:
error = sysctl_iflist(af, &w);
}
splx(s);
if (w.w_tmem)
free(w.w_tmem, M_RTABLE);
w.w_needed += w.w_given;
if (where) {
*given = w.w_where - where;
if (*given < w.w_needed)
return (ENOMEM);
} else {
*given = (11 * w.w_needed) / 10;
}
return (error);
}
/*
* Definitions of protocols supported in the ROUTE domain.
*/
extern struct domain routedomain; /* or at least forward */
struct protosw routesw[] = {
{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
raw_input, route_output, raw_ctlinput, 0,
route_usrreq,
raw_init, 0, 0, 0,
sysctl_rtable,
}
};
struct domain routedomain =
{ PF_ROUTE, "route", route_init, 0, 0,
routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };