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:
parent
efe4b0eb61
commit
9e52b98271
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=11152
1310
sys/net/bpf.c
Normal file
1310
sys/net/bpf.c
Normal file
File diff suppressed because it is too large
Load Diff
252
sys/net/bpf.h
Normal file
252
sys/net/bpf.h
Normal 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
671
sys/net/if.c
Normal 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
363
sys/net/if.h
Normal 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
247
sys/net/if_loop.c
Normal 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 *)⁡
|
||||
|
||||
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
842
sys/net/if_sl.c
Normal 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
80
sys/net/if_slvar.h
Normal 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
95
sys/net/if_types.h
Normal 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
912
sys/net/radix.c
Normal 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
162
sys/net/radix.h
Normal 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
538
sys/net/route.c
Normal 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
263
sys/net/route.h
Normal 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
837
sys/net/rtsock.c
Normal 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])] };
|
Loading…
Reference in New Issue
Block a user