From 39e6e65a2c5a3312f365d59f23c469641e049c82 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 19 Aug 1998 21:32:28 +0000 Subject: Base files --- c/src/exec/libnetworking/net/bpf.h | 236 ++++++ c/src/exec/libnetworking/net/ethernet.h | 63 ++ c/src/exec/libnetworking/net/if.c | 783 ++++++++++++++++++++ c/src/exec/libnetworking/net/if.h | 467 ++++++++++++ c/src/exec/libnetworking/net/if_arp.h | 91 +++ c/src/exec/libnetworking/net/if_dl.h | 86 +++ c/src/exec/libnetworking/net/if_ethersubr.c | 981 +++++++++++++++++++++++++ c/src/exec/libnetworking/net/if_llc.h | 145 ++++ c/src/exec/libnetworking/net/if_loop.c | 301 ++++++++ c/src/exec/libnetworking/net/if_types.h | 101 +++ c/src/exec/libnetworking/net/netisr.h | 90 +++ c/src/exec/libnetworking/net/radix.c | 1028 +++++++++++++++++++++++++++ c/src/exec/libnetworking/net/radix.h | 165 +++++ c/src/exec/libnetworking/net/raw_cb.c | 148 ++++ c/src/exec/libnetworking/net/raw_cb.h | 75 ++ c/src/exec/libnetworking/net/raw_usrreq.c | 315 ++++++++ c/src/exec/libnetworking/net/route.c | 959 +++++++++++++++++++++++++ c/src/exec/libnetworking/net/route.h | 284 ++++++++ c/src/exec/libnetworking/net/rtsock.c | 829 +++++++++++++++++++++ 19 files changed, 7147 insertions(+) create mode 100644 c/src/exec/libnetworking/net/bpf.h create mode 100644 c/src/exec/libnetworking/net/ethernet.h create mode 100644 c/src/exec/libnetworking/net/if.c create mode 100644 c/src/exec/libnetworking/net/if.h create mode 100644 c/src/exec/libnetworking/net/if_arp.h create mode 100644 c/src/exec/libnetworking/net/if_dl.h create mode 100644 c/src/exec/libnetworking/net/if_ethersubr.c create mode 100644 c/src/exec/libnetworking/net/if_llc.h create mode 100644 c/src/exec/libnetworking/net/if_loop.c create mode 100644 c/src/exec/libnetworking/net/if_types.h create mode 100644 c/src/exec/libnetworking/net/netisr.h create mode 100644 c/src/exec/libnetworking/net/radix.c create mode 100644 c/src/exec/libnetworking/net/radix.h create mode 100644 c/src/exec/libnetworking/net/raw_cb.c create mode 100644 c/src/exec/libnetworking/net/raw_cb.h create mode 100644 c/src/exec/libnetworking/net/raw_usrreq.c create mode 100644 c/src/exec/libnetworking/net/route.c create mode 100644 c/src/exec/libnetworking/net/route.h create mode 100644 c/src/exec/libnetworking/net/rtsock.c (limited to 'c/src/exec/libnetworking/net') diff --git a/c/src/exec/libnetworking/net/bpf.h b/c/src/exec/libnetworking/net/bpf.h new file mode 100644 index 0000000000..7847d72470 --- /dev/null +++ b/c/src/exec/libnetworking/net/bpf.h @@ -0,0 +1,236 @@ +/* + * 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.1 (Berkeley) 6/10/93 + * @(#)bpf.h 1.34 (LBL) 6/16/96 + * + * $Id$ + */ + +#ifndef _NET_BPF_H_ +#define _NET_BPF_H_ + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +typedef int32_t bpf_int32; +typedef u_int32_t bpf_u_int32; + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#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 of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +#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) +#define BIOCGRSIG _IOR('B',114, u_int) +#define BIOCSRSIG _IOW('B',115, u_int) + +/* + * Structure prepended to each packet. + */ +struct bpf_hdr { + struct timeval bh_tstamp; /* time stamp */ + bpf_u_int32 bh_caplen; /* length of captured portion */ + bpf_u_int32 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. + */ +#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 */ +#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ + +/* + * The instruction encodings. + */ +/* 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; + bpf_u_int32 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)); +void bpf_tap __P((struct ifnet *, u_char *, u_int)); +void bpf_mtap __P((struct ifnet *, struct mbuf *)); +void bpfattach __P((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 + +#endif diff --git a/c/src/exec/libnetworking/net/ethernet.h b/c/src/exec/libnetworking/net/ethernet.h new file mode 100644 index 0000000000..c6c07189ec --- /dev/null +++ b/c/src/exec/libnetworking/net/ethernet.h @@ -0,0 +1,63 @@ +/* + * Fundamental constants relating to ethernet. + * + * $Id$ + * + */ + +#ifndef _NET_ETHERNET_H_ +#define _NET_ETHERNET_H_ + +/* + * The number of bytes in an ethernet (MAC) address. + */ +#define ETHER_ADDR_LEN 6 + +/* + * The number of bytes in the type field. + */ +#define ETHER_TYPE_LEN 2 + +/* + * The number of bytes in the trailing CRC field. + */ +#define ETHER_CRC_LEN 4 + +/* + * The length of the combined header. + */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN) + +/* + * The minimum packet length. + */ +#define ETHER_MIN_LEN 64 + +/* + * The maximum packet length. + */ +#define ETHER_MAX_LEN 1518 + +/* + * A macro to validate a length with + */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +/* + * Structure of a 10Mb/s Ethernet header. + */ +struct ether_header { + u_char ether_dhost[ETHER_ADDR_LEN]; + u_char ether_shost[ETHER_ADDR_LEN]; + u_short ether_type; +}; + +/* + * Structure of a 48-bit Ethernet address. + */ +struct ether_addr { + u_char octet[ETHER_ADDR_LEN]; +}; + +#endif diff --git a/c/src/exec/libnetworking/net/if.c b/c/src/exec/libnetworking/net/if.c new file mode 100644 index 0000000000..af6f003de3 --- /dev/null +++ b/c/src/exec/libnetworking/net/if.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if.c 8.3 (Berkeley) 1/4/94 + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * System initialization + */ + +static int ifconf __P((int, caddr_t)); + void ifinit __P((void *)); +static void if_qflush __P((struct ifqueue *)); +static void if_slowtimo __P((void *)); +static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *)); + +SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) + + +int ifqmaxlen = IFQ_MAXLEN; +struct ifnet *ifnet; + +/* + * Network interface utility routines. + * + * Routines with ifa_ifwith* names take sockaddr *'s as + * parameters. + * + * This routine assumes that it will be called at splimp() or higher. + */ +/* ARGSUSED*/ +void +ifinit(dummy) + void *dummy; +{ + 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); +} + +int if_index = 0; +struct ifaddr **ifnet_addrs; + + +/* + * Attach an interface to the + * list of "active" interfaces. + */ +void +if_attach(ifp) + struct ifnet *ifp; +{ + unsigned socksize, ifasize; + int namelen, masklen; + char workbuf[64]; + register struct ifnet **p = &ifnet; + register struct sockaddr_dl *sdl; + register struct ifaddr *ifa; + static int if_indexlim = 8; + + + while (*p) + p = &((*p)->if_next); + *p = ifp; + ifp->if_index = ++if_index; + microtime(&ifp->if_lastchange); + if (ifnet_addrs == 0 || if_index >= if_indexlim) { + unsigned n = (if_indexlim <<= 1) * sizeof(ifa); + struct ifaddr **q = (struct ifaddr **) + malloc(n, M_IFADDR, M_WAITOK); + bzero((caddr_t)q, n); + if (ifnet_addrs) { + bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); + free((caddr_t)ifnet_addrs, M_IFADDR); + } + ifnet_addrs = q; + } + /* + * create a Link Level name for this device + */ + namelen = sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); +#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) + masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; + socksize = masklen + ifp->if_addrlen; +#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) + socksize = ROUNDUP(socksize); + if (socksize < sizeof(*sdl)) + socksize = sizeof(*sdl); + ifasize = sizeof(*ifa) + 2 * socksize; + ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); + if (ifa) { + bzero((caddr_t)ifa, ifasize); + sdl = (struct sockaddr_dl *)(ifa + 1); + sdl->sdl_len = socksize; + sdl->sdl_family = AF_LINK; + bcopy(workbuf, sdl->sdl_data, namelen); + sdl->sdl_nlen = namelen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + ifnet_addrs[if_index - 1] = ifa; + ifa->ifa_ifp = ifp; + ifa->ifa_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; + } +} +/* + * 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) + continue; + if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) + return (ifa); + } + return ((struct ifaddr *)0); +} + +/* + * Find an interface on a specific network. If many, choice + * is most specific found. + */ +struct ifaddr * +ifa_ifwithnet(addr) + struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + struct ifaddr *ifa_maybe = (struct ifaddr *) 0; + u_int af = addr->sa_family; + char *addr_data = addr->sa_data, *cplim; + + 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) + next: continue; + if (ifp->if_flags & IFF_POINTOPOINT) { + if (ifa->ifa_dstaddr != 0 + && equal(addr, ifa->ifa_dstaddr)) + return (ifa); + } else { + /* + * if we have a special address handler, + * then use it instead of the generic one. + */ + if (ifa->ifa_claim_addr) { + if ((*ifa->ifa_claim_addr)(ifa, addr)) { + return (ifa); + } else { + continue; + } + } + + /* + * Scan all the bits in the ifa's address. + * If a bit dissagrees with what we are + * looking for, mask it with the netmask + * to see if it really matters. + * (A byte at a time) + */ + if (ifa->ifa_netmask == 0) + continue; + cp = addr_data; + cp2 = ifa->ifa_addr->sa_data; + cp3 = ifa->ifa_netmask->sa_data; + cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; + while (cp3 < cplim) + if ((*cp++ ^ *cp2++) & *cp3++) + goto next; + if (ifa_maybe == 0 || + rn_refines((caddr_t)ifa->ifa_netmask, + (caddr_t)ifa_maybe->ifa_netmask)) + ifa_maybe = ifa; + } + } + } + return (ifa_maybe); +} + +/* + * Find an interface address specific to an interface best matching + * a given address. + */ +struct ifaddr * +ifaof_ifpforaddr(addr, ifp) + struct sockaddr *addr; + register struct ifnet *ifp; +{ + register struct ifaddr *ifa; + register char *cp, *cp2, *cp3; + register char *cplim; + struct ifaddr *ifa_maybe = 0; + u_int af = addr->sa_family; + + if (af >= AF_MAX) + return (0); + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != af) + continue; + if (ifa_maybe == 0) + ifa_maybe = ifa; + if (ifa->ifa_netmask == 0) { + if (equal(addr, ifa->ifa_addr) || + (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) + return (ifa); + continue; + } + if (ifp->if_flags & IFF_POINTOPOINT) { + if (equal(addr, ifa->ifa_dstaddr)) + return (ifa); + } else { + cp = addr->sa_data; + cp2 = ifa->ifa_addr->sa_data; + cp3 = ifa->ifa_netmask->sa_data; + cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; + for (; cp3 < cplim; cp3++) + if ((*cp++ ^ *cp2++) & *cp3) + break; + if (cp3 == cplim) + return (ifa); + } + } + return (ifa_maybe); +} + +#include + +/* + * Default action when installing a route with a Link Level gateway. + * Lookup an appropriate real ifa to point to. + * This should be moved to /sys/net/link.c eventually. + */ +static 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; + ifa = ifaof_ifpforaddr(dst, ifp); + if (ifa) { + IFAFREE(rt->rt_ifa); + rt->rt_ifa = ifa; + ifa->ifa_refcnt++; + if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) + ifa->ifa_rtrequest(cmd, rt, sa); + } +} + +/* + * Mark an interface down and notify protocols of + * the transition. + * NOTE: must be called at splnet or eqivalent. + */ +void +if_down(ifp) + register struct ifnet *ifp; +{ + register struct ifaddr *ifa; + + ifp->if_flags &= ~IFF_UP; + microtime(&ifp->if_lastchange); + 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; +{ + + ifp->if_flags |= IFF_UP; + microtime(&ifp->if_lastchange); +#ifdef notyet + register struct ifaddr *ifa; + /* 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. + */ +static void +if_qflush(ifq) + register struct ifqueue *ifq; +{ + register struct mbuf *m, *n; + + n = ifq->ifq_head; + while ((m = n) != 0) { + n = m->m_act; + m_freem(m); + } + ifq->ifq_head = 0; + ifq->ifq_tail = 0; + ifq->ifq_len = 0; +} + +/* + * Handle interface watchdog timer routines. Called + * from softclock, we decrement timers (if set) and + * call the appropriate interface routine on expiration. + */ +static 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); + } + 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'; + if (*cp != '\0') + return 0; /* no trailing garbage allowed */ + *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; + int 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 SIOCGIFMTU: + ifr->ifr_mtu = ifp->if_mtu; + break; + + case SIOCGIFPHYS: + ifr->ifr_phys = ifp->if_physical; + break; + + case SIOCSIFFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + 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); + microtime(&ifp->if_lastchange); + break; + + case SIOCSIFMETRIC: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + ifp->if_metric = ifr->ifr_metric; + microtime(&ifp->if_lastchange); + break; + + case SIOCSIFPHYS: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return error; + if (!ifp->if_ioctl) + return EOPNOTSUPP; + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return(error); + + case SIOCSIFMTU: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_ioctl == NULL) + return (EOPNOTSUPP); + /* + * 72 was chosen below because it is the size of a TCP/IP + * header (40) + the minimum mss (32). + */ + if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535) + return (EINVAL); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return(error); + + case SIOCADDMULTI: + case SIOCDELMULTI: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_ioctl == NULL) + return (EOPNOTSUPP); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0 ) + microtime(&ifp->if_lastchange); + return(error); + + case SIOCSIFMEDIA: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + return (error); + if (ifp->if_ioctl == 0) + return (EOPNOTSUPP); + error = (*ifp->if_ioctl)(ifp, cmd, data); + if (error == 0) + microtime(&ifp->if_lastchange); + return error; + + case SIOCGIFMEDIA: + if (ifp->if_ioctl == 0) + 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_usrreqs->pru_control)(so, 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_usrreqs->pru_control)(so, + 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); +} + +/* + * Set/clear promiscuous mode on interface ifp based on the truth value + * of pswitch. The calls are reference counted so that only the first + * "on" request actually has an effect, as does the final "off" request. + * Results are undefined if the "off" and "on" requests are not matched. + */ +int +ifpromisc(ifp, pswitch) + struct ifnet *ifp; + int pswitch; +{ + struct ifreq ifr; + + if (pswitch) { + /* + * If the device is not configured up, we cannot put it in + * promiscuous mode. + */ + if ((ifp->if_flags & IFF_UP) == 0) + return (ENETDOWN); + if (ifp->if_pcount++ != 0) + return (0); + ifp->if_flags |= IFF_PROMISC; + log(LOG_INFO, "%s%d: promiscuous mode enabled\n", + ifp->if_name, ifp->if_unit); + } else { + if (--ifp->if_pcount > 0) + return (0); + ifp->if_flags &= ~IFF_PROMISC; + } + ifr.ifr_flags = ifp->if_flags; + return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); +} + +/* + * Return interface configuration + * of system. List may be used + * in later ioctl's (above) to get + * other information. + */ +/*ARGSUSED*/ +static 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; + struct ifreq ifr, *ifrp; + int space = ifc->ifc_len, error = 0; + + ifrp = ifc->ifc_req; + for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) { + char workbuf[64]; + int ifnlen; + + ifnlen = sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); + if(ifnlen + 1 > sizeof ifr.ifr_name) { + error = ENAMETOOLONG; + } else { + strcpy(ifr.ifr_name, workbuf); + } + + 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); +} + +SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); +SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); diff --git a/c/src/exec/libnetworking/net/if.h b/c/src/exec/libnetworking/net/if.h new file mode 100644 index 0000000000..acddd4f095 --- /dev/null +++ b/c/src/exec/libnetworking/net/if.h @@ -0,0 +1,467 @@ +/* + * 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.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_H_ +#define _NET_IF_H_ + +/* + * 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 +#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. + */ +struct if_data { + /* generic interface information */ + u_char ifi_type; /* ethernet, tokenring, etc */ + u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ + u_char ifi_addrlen; /* media address length */ + u_char ifi_hdrlen; /* media header length */ + u_char ifi_recvquota; /* polling quota for receive intrs */ + u_char ifi_xmitquota; /* polling quota for xmit intrs */ + 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 */ + u_long ifi_recvtiming; /* usec spent receiving when timing */ + u_long ifi_xmittiming; /* usec spent xmitting when timing */ + struct timeval ifi_lastchange; /* time of last administrative change */ +}; + +/* + * Structure defining a queue for a network interface. + */ +struct ifqueue { + struct mbuf *ifq_head; + struct mbuf *ifq_tail; + int ifq_len; + int ifq_maxlen; + int ifq_drops; +}; + +/* + * Structure defining a network interface. + * + * (Would like to call this struct ``if'', but C isn't PL/1.) + */ +struct ifnet { + void *if_softc; /* pointer to driver state */ + 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 */ + struct bpf_if *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. */ + int if_ipending; /* interrupts pending */ + void *if_linkmib; /* link-type-specific MIB data */ + size_t if_linkmiblen; /* length of above data */ + struct if_data if_data; +/* procedure handles */ + int (*if_output) /* output routine (enqueue) */ + __P((struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *)); + void (*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 *, int, caddr_t)); + void (*if_watchdog) /* timer routine */ + __P((struct ifnet *)); + int (*if_poll_recv) /* polled receive routine */ + __P((struct ifnet *, int *)); + int (*if_poll_xmit) /* polled transmit routine */ + __P((struct ifnet *, int *)); + void (*if_poll_intren) /* polled interrupt reenable routine */ + __P((struct ifnet *)); + void (*if_poll_slowinput) /* input routine for slow devices */ + __P((struct ifnet *, struct mbuf *)); + void (*if_init) /* Init routine */ + __P((void *)); + struct ifqueue if_snd; /* output queue */ + struct ifqueue *if_poll_slowq; /* input queue for slow devices */ +}; +typedef void if_init_f_t __P((void *)); + +#define if_mtu if_data.ifi_mtu +#define if_type if_data.ifi_type +#define if_physical if_data.ifi_physical +#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 if_recvquota if_data.ifi_recvquota +#define if_xmitquota if_data.ifi_xmitquota +#define if_rawoutput(if, m, sa) if_output(if, m, sa, (struct rtentry *)0) + +#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 * obsolete: 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_ALTPHYS IFF_LINK2 /* use alternate physical connection */ +#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) + + +/* + * These really don't belong here, but there's no other obviously appropriate + * location. + */ +#define IFP_AUI 0 +#define IFP_10BASE2 1 +#define IFP_10BASET 2 +/* etc. */ + +/* + * Bit values in if_ipending + */ +#define IFI_RECV 1 /* I want to receive */ +#define IFI_XMIT 2 /* I want to transmit */ + +/* + * Output queues (ifp->if_snd) and slow device input queues (*ifp->if_slowq) + * are 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--; \ + } \ +} + +#ifdef KERNEL +#define IF_ENQ_DROP(ifq, m) if_enq_drop(ifq, m) + +#if defined(__GNUC__) && defined(MT_HEADER) +static inline int +if_queue_drop(struct ifqueue *ifq, struct mbuf *m) +{ + IF_DROP(ifq); + return 0; +} + +static inline int +if_enq_drop(struct ifqueue *ifq, struct mbuf *m) +{ + if (IF_QFULL(ifq) && + !if_queue_drop(ifq, m)) + return 0; + IF_ENQUEUE(ifq, m); + return 1; +} +#else + +#ifdef MT_HEADER +int if_enq_drop __P((struct ifqueue *, struct mbuf *)); +#endif + +#endif +#endif /* KERNEL */ + +#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 */ + __P((int, struct rtentry *, struct sockaddr *)); + u_short ifa_flags; /* mostly rt_flags for cloning */ + short ifa_refcnt; /* references to this structure */ + int ifa_metric; /* cost of going out this interface */ +#ifdef notdef + struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */ +#endif + int (*ifa_claim_addr) /* check if an addr goes to this if */ + __P((struct ifaddr *, struct sockaddr *)); + +}; +#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; + int ifru_mtu; + int ifru_phys; + int ifru_media; + 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_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_phys ifr_ifru.ifru_phys /* physical wire */ +#define ifr_media ifr_ifru.ifru_media /* physical media */ +#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; +}; + +struct ifmediareq { + char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + int ifm_current; /* current media options */ + int ifm_mask; /* don't care mask */ + int ifm_status; /* media status */ + int ifm_active; /* active options */ + int ifm_count; /* # entries in ifm_ulist array */ + int *ifm_ulist; /* media words */ +}; +/* + * 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 + +#ifdef KERNEL +#define IFAFREE(ifa) \ + if ((ifa)->ifa_refcnt <= 0) \ + ifafree(ifa); \ + else \ + (ifa)->ifa_refcnt--; + +extern struct ifnet *ifnet; +extern int ifqmaxlen; +extern struct ifnet loif[]; +extern int if_index; +extern struct ifaddr **ifnet_addrs; + +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 *)); +int ether_ioctl __P((struct ifnet *, int , caddr_t )); + +void if_attach __P((struct ifnet *)); +void if_down __P((struct ifnet *)); +void if_up __P((struct ifnet *)); +#ifdef vax +void ifubareset __P((int)); +#endif +/*void ifinit __P((void));*/ /* declared in systm.h for main() */ +int ifioctl __P((struct socket *, int, caddr_t, struct proc *)); +int ifpromisc __P((struct ifnet *, int)); +struct ifnet *ifunit __P((char *)); + +int if_poll_recv_slow __P((struct ifnet *ifp, int *quotap)); +void if_poll_xmit_slow __P((struct ifnet *ifp, int *quotap)); +void if_poll_throttle __P((void)); +void if_poll_unthrottle __P((void *)); +void if_poll_init __P((void)); +void if_poll __P((void)); + +struct ifaddr *ifa_ifwithaddr __P((struct sockaddr *)); +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 *)); + +int looutput __P((struct ifnet *, + struct mbuf *, struct sockaddr *, struct rtentry *)); +#endif /* KERNEL */ + +#endif /* !_NET_IF_H_ */ diff --git a/c/src/exec/libnetworking/net/if_arp.h b/c/src/exec/libnetworking/net/if_arp.h new file mode 100644 index 0000000000..dd726bf856 --- /dev/null +++ b/c/src/exec/libnetworking/net/if_arp.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 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_arp.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_ARP_H_ +#define _NET_IF_ARP_H_ + +/* + * Address Resolution Protocol. + * + * See RFC 826 for protocol description. ARP packets are variable + * in size; the arphdr structure defines the fixed-length portion. + * Protocol type values are the same as those for 10 Mb/s Ethernet. + * It is followed by the variable-sized fields ar_sha, arp_spa, + * arp_tha and arp_tpa in that order, according to the lengths + * specified. Field names used correspond to RFC 826. + */ +struct arphdr { + u_short ar_hrd; /* format of hardware address */ +#define ARPHRD_ETHER 1 /* ethernet hardware format */ +#define ARPHRD_FRELAY 15 /* frame relay hardware format */ + u_short ar_pro; /* format of protocol address */ + u_char ar_hln; /* length of hardware address */ + u_char ar_pln; /* length of protocol address */ + u_short ar_op; /* one of: */ +#define ARPOP_REQUEST 1 /* request to resolve address */ +#define ARPOP_REPLY 2 /* response to previous request */ +#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ +#define ARPOP_REVREPLY 4 /* response giving protocol address */ +#define ARPOP_INVREQUEST 8 /* request to identify peer */ +#define ARPOP_INVREPLY 9 /* response identifying peer */ +/* + * The remaining fields are variable in size, + * according to the sizes above. + */ +#ifdef COMMENT_ONLY + u_char ar_sha[]; /* sender hardware address */ + u_char ar_spa[]; /* sender protocol address */ + u_char ar_tha[]; /* target hardware address */ + u_char ar_tpa[]; /* target protocol address */ +#endif +}; + +/* + * ARP ioctl request + */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ +}; +/* arp_flags and at_flags field values */ +#define ATF_INUSE 0x01 /* entry in use */ +#define ATF_COM 0x02 /* completed entry (enaddr valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry (respond for other host) */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ + +#endif /* !_NET_IF_ARP_H_ */ diff --git a/c/src/exec/libnetworking/net/if_dl.h b/c/src/exec/libnetworking/net/if_dl.h new file mode 100644 index 0000000000..053ae3e92f --- /dev/null +++ b/c/src/exec/libnetworking/net/if_dl.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1990, 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_dl.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_DL_H_ +#define _NET_IF_DL_H_ + +/* + * A Link-Level Sockaddr may specify the interface in one of two + * ways: either by means of a system-provided index number (computed + * anew and possibly differently on every reboot), or by a human-readable + * string such as "il0" (for managerial convenience). + * + * Census taking actions, such as something akin to SIOCGCONF would return + * both the index and the human name. + * + * High volume transactions (such as giving a link-level ``from'' address + * in a recvfrom or recvmsg call) may be likely only to provide the indexed + * form, (which requires fewer copy operations and less space). + * + * The form and interpretation of the link-level address is purely a matter + * of convention between the device driver and its consumers; however, it is + * expected that all drivers for an interface of a given if_type will agree. + */ + +/* + * Structure of a Link-Level sockaddr: + */ +struct sockaddr_dl { + u_char sdl_len; /* Total length of sockaddr */ + u_char sdl_family; /* AF_DLI */ + u_short sdl_index; /* if != 0, system given index for interface */ + u_char sdl_type; /* interface type */ + u_char sdl_nlen; /* interface name length, no trailing 0 reqd. */ + u_char sdl_alen; /* link level address length */ + u_char sdl_slen; /* link layer selector length */ + char sdl_data[12]; /* minimum work area, can be larger; + contains both if name and ll address */ +}; + +#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) + +#ifndef KERNEL + +#include + +__BEGIN_DECLS +void link_addr __P((const char *, struct sockaddr_dl *)); +char *link_ntoa __P((const struct sockaddr_dl *)); +__END_DECLS + +#endif /* !KERNEL */ + +#endif diff --git a/c/src/exec/libnetworking/net/if_ethersubr.c b/c/src/exec/libnetworking/net/if_ethersubr.c new file mode 100644 index 0000000000..9ff1a5932a --- /dev/null +++ b/c/src/exec/libnetworking/net/if_ethersubr.c @@ -0,0 +1,981 @@ +/* + * Copyright (c) 1982, 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_ethersubr.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#endif +#include + +#ifdef IPX +#include +#include +#endif + +#ifdef NS +#include +#include +ushort ns_nettype; +int ether_outputdebug = 0; +int ether_inputdebug = 0; +#endif + +#ifdef ISO +#include +#include +#include +#include +#endif + +/*#ifdef LLC +#include +#include +#endif*/ + +#if defined(LLC) && defined(CCITT) +extern struct ifqueue pkintrq; +#endif + +#ifdef NETATALK +#include +#include +#include + +#define llc_snap_org_code llc_un.type_snap.org_code +#define llc_snap_ether_type llc_un.type_snap.ether_type + +extern u_char at_org_code[ 3 ]; +extern u_char aarp_org_code[ 3 ]; +#endif NETATALK + +u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#define senderr(e) { error = (e); goto bad;} + +/* + * Ethernet output routine. + * Encapsulate a packet of type family for the local net. + * Use trailer local net encapsulation if enough data in first + * packet leaves a multiple of 512 bytes of data in remainder. + * Assumes that ifp is actually pointer to arpcom structure. + */ +int +ether_output(ifp, m0, dst, rt0) + register struct ifnet *ifp; + struct mbuf *m0; + struct sockaddr *dst; + struct rtentry *rt0; +{ + short type; + int s, error = 0; + u_char *cp, edst[6]; + register struct mbuf *m2, *m = m0; + register struct rtentry *rt; + struct mbuf *mcopy = (struct mbuf *)0; + register struct ether_header *eh; + int off, len = m->m_pkthdr.len; + struct arpcom *ac = (struct arpcom *)ifp; + register struct ifqueue *inq; +#ifdef NETATALK + struct at_ifaddr *aa; +#endif NETATALK + + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) + senderr(ENETDOWN); + rt = rt0; + if (rt) { + if ((rt->rt_flags & RTF_UP) == 0) { + rt0 = rt = rtalloc1(dst, 1, 0UL); + if (rt0) + rt->rt_refcnt--; + else + senderr(EHOSTUNREACH); + } + if (rt->rt_flags & RTF_GATEWAY) { + if (rt->rt_gwroute == 0) + goto lookup; + if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { + rtfree(rt); rt = rt0; + lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, + 0UL); + if ((rt = rt->rt_gwroute) == 0) + senderr(EHOSTUNREACH); + } + } + if (rt->rt_flags & RTF_REJECT) + if (rt->rt_rmx.rmx_expire == 0 || + rtems_bsdnet_seconds_since_boot() < rt->rt_rmx.rmx_expire) + senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); + } + switch (dst->sa_family) { + +#ifdef INET + case AF_INET: + if (!arpresolve(ac, rt, m, dst, edst, rt0)) + return (0); /* if not yet resolved */ + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + off = m->m_pkthdr.len - m->m_len; + type = htons(ETHERTYPE_IP); + break; +#endif +#ifdef IPX + case AF_IPX: + { + struct ifaddr *ia; + + type = htons(ETHERTYPE_IPX); + bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), + (caddr_t)edst, sizeof (edst)); + for (ia = ifp->if_addrlist; ia != NULL; ia = ia->ifa_next) + if(ia->ifa_addr->sa_family == AF_IPX && + !bcmp((caddr_t)edst, + (caddr_t)&((struct ipx_ifaddr *)ia)->ia_addr.sipx_addr.x_host, + sizeof(edst))) + return (looutput(ifp, m, dst, rt)); + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + break; + } +#endif +#ifdef NETATALK + case AF_APPLETALK: + { + struct sockaddr_at *sat = (struct sockaddr_at *)dst; + + /* + * super hack.. + * Most of this loopback code should move into the appletalk + * code, but it's here for now.. remember to move it! [JRE] + * This may not get the same interface we started with + * fix asap. XXX + */ + aa = at_ifawithnet( sat ); + if (aa == NULL) { + goto bad; + } + if( aa->aa_ifa.ifa_ifp != ifp ) { + (*aa->aa_ifa.ifa_ifp->if_output)(aa->aa_ifa.ifa_ifp, + m,dst,rt); + } + if (((sat->sat_addr.s_net == ATADDR_ANYNET) + && (sat->sat_addr.s_node == ATADDR_ANYNODE)) + || ((sat->sat_addr.s_net == aa->aa_addr.sat_addr.s_net ) + && (sat->sat_addr.s_node == aa->aa_addr.sat_addr.s_node))) { + (void) looutput(ifp, m, dst, rt); + return(0); + } + + if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { +#ifdef NETATALKDEBUG + extern char *prsockaddr(struct sockaddr *); + printf("aarpresolv: failed for %s\n", prsockaddr(dst)); +#endif NETATALKDEBUG + return (0); + } + + /* + * If broadcasting on a simplex interface, loopback a copy + */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) + mcopy = m_copy(m, 0, (int)M_COPYALL); + } + /* + * In the phase 2 case, we need to prepend an mbuf for the llc header. + * Since we must preserve the value of m, which is passed to us by + * value, we m_copy() the first mbuf, and use it for our llc header. + */ + if ( aa->aa_flags & AFA_PHASE2 ) { + struct llc llc; + + M_PREPEND(m, sizeof(struct llc), M_WAIT); + len += sizeof(struct llc); + llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; + llc.llc_control = LLC_UI; + bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); + llc.llc_snap_ether_type = htons( ETHERTYPE_AT ); + bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); + type = htons(m->m_pkthdr.len); + } else { + type = htons(ETHERTYPE_AT); + } + break; +#endif NETATALK +#ifdef NS + case AF_NS: + switch(ns_nettype){ + default: + case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ + type = 0x8137; + break; + case 0x0: /* Novell 802.3 */ + type = htons( m->m_pkthdr.len); + break; + case 0xe0e0: /* Novell 802.2 and Token-Ring */ + M_PREPEND(m, 3, M_WAIT); + type = htons( m->m_pkthdr.len); + cp = mtod(m, u_char *); + *cp++ = 0xE0; + *cp++ = 0xE0; + *cp++ = 0x03; + break; + } + bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), + (caddr_t)edst, sizeof (edst)); + if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){ + m->m_pkthdr.rcvif = ifp; + schednetisr(NETISR_NS); + inq = &nsintrq; + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else + IF_ENQUEUE(inq, m); + splx(s); + return (error); + } + if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){ + m2 = m_copy(m, 0, (int)M_COPYALL); + m2->m_pkthdr.rcvif = ifp; + schednetisr(NETISR_NS); + inq = &nsintrq; + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m2); + } else + IF_ENQUEUE(inq, m2); + splx(s); + } + /* If broadcasting on a simplex interface, loopback a copy */ + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)){ + mcopy = m_copy(m, 0, (int)M_COPYALL); + } + break; +#endif /* NS */ +#ifdef ISO + case AF_ISO: { + int snpalen; + struct llc *l; + register struct sockaddr_dl *sdl; + + if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && + sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { + bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); + } else if (error = + iso_snparesolve(ifp, (struct sockaddr_iso *)dst, + (char *)edst, &snpalen)) + goto bad; /* Not Resolved */ + /* If broadcasting on a simplex interface, loopback a copy */ + if (*edst & 1) + m->m_flags |= (M_BCAST|M_MCAST); + if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && + (mcopy = m_copy(m, 0, (int)M_COPYALL))) { + M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); + if (mcopy) { + eh = mtod(mcopy, struct ether_header *); + bcopy((caddr_t)edst, + (caddr_t)eh->ether_dhost, sizeof (edst)); + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)eh->ether_shost, sizeof (edst)); + } + } + M_PREPEND(m, 3, M_DONTWAIT); + if (m == NULL) + return (0); + type = htons(m->m_pkthdr.len); + l = mtod(m, struct llc *); + l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; + l->llc_control = LLC_UI; + len += 3; + IFDEBUG(D_ETHER) + int i; + printf("unoutput: sending pkt to: "); + for (i=0; i<6; i++) + printf("%x ", edst[i] & 0xff); + printf("\n"); + ENDDEBUG + } break; +#endif /* ISO */ +#ifdef LLC +/* case AF_NSAP: */ + case AF_CCITT: { + register struct sockaddr_dl *sdl = + (struct sockaddr_dl *) rt -> rt_gateway; + + if (sdl && sdl->sdl_family == AF_LINK + && sdl->sdl_alen > 0) { + bcopy(LLADDR(sdl), (char *)edst, + sizeof(edst)); + } else goto bad; /* Not a link interface ? Funny ... */ + if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && + (mcopy = m_copy(m, 0, (int)M_COPYALL))) { + M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); + if (mcopy) { + eh = mtod(mcopy, struct ether_header *); + bcopy((caddr_t)edst, + (caddr_t)eh->ether_dhost, sizeof (edst)); + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)eh->ether_shost, sizeof (edst)); + } + } + type = htons(m->m_pkthdr.len); +#ifdef LLC_DEBUG + { + int i; + register struct llc *l = mtod(m, struct llc *); + + printf("ether_output: sending LLC2 pkt to: "); + for (i=0; i<6; i++) + printf("%x ", edst[i] & 0xff); + printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", + type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, + l->llc_control & 0xff); + + } +#endif /* LLC_DEBUG */ + } break; +#endif /* LLC */ + + case AF_UNSPEC: + eh = (struct ether_header *)dst->sa_data; + (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); + type = eh->ether_type; + break; + + default: + printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, + dst->sa_family); + senderr(EAFNOSUPPORT); + } + + + if (mcopy) + (void) looutput(ifp, mcopy, dst, rt); + /* + * Add local net header. If no space in first mbuf, + * allocate another. + */ + M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); + if (m == 0) + senderr(ENOBUFS); + eh = mtod(m, struct ether_header *); + (void)memcpy(&eh->ether_type, &type, + sizeof(eh->ether_type)); + (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); + (void)memcpy(eh->ether_shost, ac->ac_enaddr, + sizeof(eh->ether_shost)); + s = splimp(); + /* + * Queue message on interface, and start output if interface + * not yet active. + */ + if (IF_QFULL(&ifp->if_snd)) { + IF_DROP(&ifp->if_snd); + splx(s); + senderr(ENOBUFS); + } + IF_ENQUEUE(&ifp->if_snd, m); + if ((ifp->if_flags & IFF_OACTIVE) == 0) + (*ifp->if_start)(ifp); + splx(s); + ifp->if_obytes += len + sizeof (struct ether_header); + if (m->m_flags & M_MCAST) + ifp->if_omcasts++; + return (error); + +bad: + if (m) + m_freem(m); + return (error); +} + +/* + * Process a received Ethernet packet; + * the packet is in the mbuf chain m without + * the ether header, which is provided separately. + */ +void +ether_input(ifp, eh, m) + struct ifnet *ifp; + register struct ether_header *eh; + struct mbuf *m; +{ + register struct ifqueue *inq; + u_short ether_type, *checksum; + int s; +#if defined (ISO) || defined (LLC) || defined(NETATALK) + register struct llc *l; +#endif + + if ((ifp->if_flags & IFF_UP) == 0) { + m_freem(m); + return; + } + ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); + if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, + sizeof(etherbroadcastaddr)) == 0) + m->m_flags |= M_BCAST; + else if (eh->ether_dhost[0] & 1) + m->m_flags |= M_MCAST; + if (m->m_flags & (M_BCAST|M_MCAST)) + ifp->if_imcasts++; + + ether_type = ntohs(eh->ether_type); + + switch (ether_type) { +#ifdef INET + case ETHERTYPE_IP: + schednetisr(NETISR_IP); + inq = &ipintrq; + break; + + case ETHERTYPE_ARP: + schednetisr(NETISR_ARP); + inq = &arpintrq; + break; +#endif +#ifdef IPX + case ETHERTYPE_IPX: + schednetisr(NETISR_IPX); + inq = &ipxintrq; + break; +#endif +#ifdef NS + case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ + schednetisr(NETISR_NS); + inq = &nsintrq; + break; + +#endif /* NS */ +#ifdef NETATALK + case ETHERTYPE_AT: + schednetisr(NETISR_ATALK); + inq = &atintrq1; + break; + case ETHERTYPE_AARP: + /* probably this should be done with a NETISR as well */ + aarpinput((struct arpcom *)ifp, m); /* XXX */ + return; +#endif NETATALK + default: +#ifdef NS + checksum = mtod(m, ushort *); + /* Novell 802.3 */ + if ((ether_type <= ETHERMTU) && + ((*checksum == 0xffff) || (*checksum == 0xE0E0))){ + if(*checksum == 0xE0E0) { + m->m_pkthdr.len -= 3; + m->m_len -= 3; + m->m_data += 3; + } + schednetisr(NETISR_NS); + inq = &nsintrq; + break; + } +#endif /* NS */ +#if defined (ISO) || defined (LLC) || defined(NETATALK) + if (ether_type > ETHERMTU) + goto dropanyway; + l = mtod(m, struct llc *); + switch (l->llc_dsap) { +#ifdef NETATALK + case LLC_SNAP_LSAP: + switch (l->llc_control) { + case LLC_UI: + if (l->llc_ssap != LLC_SNAP_LSAP) + goto dropanyway; + + if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, + sizeof(at_org_code)) == 0 && + ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { + inq = &atintrq2; + m_adj( m, sizeof( struct llc )); + schednetisr(NETISR_ATALK); + break; + } + + if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, + sizeof(aarp_org_code)) == 0 && + ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { + m_adj( m, sizeof( struct llc )); + aarpinput((struct arpcom *)ifp, m); /* XXX */ + return; + } + + default: + goto dropanyway; + } + break; +#endif NETATALK +#ifdef ISO + case LLC_ISO_LSAP: + switch (l->llc_control) { + case LLC_UI: + /* LLC_UI_P forbidden in class 1 service */ + if ((l->llc_dsap == LLC_ISO_LSAP) && + (l->llc_ssap == LLC_ISO_LSAP)) { + /* LSAP for ISO */ + if (m->m_pkthdr.len > ether_type) + m_adj(m, ether_type - m->m_pkthdr.len); + m->m_data += 3; /* XXX */ + m->m_len -= 3; /* XXX */ + m->m_pkthdr.len -= 3; /* XXX */ + M_PREPEND(m, sizeof *eh, M_DONTWAIT); + if (m == 0) + return; + *mtod(m, struct ether_header *) = *eh; + IFDEBUG(D_ETHER) + printf("clnp packet"); + ENDDEBUG + schednetisr(NETISR_ISO); + inq = &clnlintrq; + break; + } + goto dropanyway; + + case LLC_XID: + case LLC_XID_P: + if(m->m_len < 6) + goto dropanyway; + l->llc_window = 0; + l->llc_fid = 9; + l->llc_class = 1; + l->llc_dsap = l->llc_ssap = 0; + /* Fall through to */ + case LLC_TEST: + case LLC_TEST_P: + { + struct sockaddr sa; + register struct ether_header *eh2; + int i; + u_char c = l->llc_dsap; + + l->llc_dsap = l->llc_ssap; + l->llc_ssap = c; + if (m->m_flags & (M_BCAST | M_MCAST)) + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)eh->ether_dhost, 6); + sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); + eh2 = (struct ether_header *)sa.sa_data; + for (i = 0; i < 6; i++) { + eh2->ether_shost[i] = c = eh->ether_dhost[i]; + eh2->ether_dhost[i] = + eh->ether_dhost[i] = eh->ether_shost[i]; + eh->ether_shost[i] = c; + } + ifp->if_output(ifp, m, &sa, NULL); + return; + } + default: + m_freem(m); + return; + } + break; +#endif /* ISO */ +#ifdef LLC + case LLC_X25_LSAP: + { + if (m->m_pkthdr.len > ether_type) + m_adj(m, ether_type - m->m_pkthdr.len); + M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); + if (m == 0) + return; + if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, + eh->ether_dhost, LLC_X25_LSAP, 6, + mtod(m, struct sdl_hdr *))) + panic("ETHER cons addr failure"); + mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type; +#ifdef LLC_DEBUG + printf("llc packet\n"); +#endif /* LLC_DEBUG */ + schednetisr(NETISR_CCITT); + inq = &llcintrq; + break; + } +#endif /* LLC */ + dropanyway: + default: + m_freem(m); + return; + } +#else /* ISO || LLC || NETATALK */ + m_freem(m); + return; +#endif /* ISO || LLC || NETATALK */ + } + + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else + IF_ENQUEUE(inq, m); + splx(s); +} + +/* + * Perform common duties while attaching to interface list + */ +void +ether_ifattach(ifp) + register struct ifnet *ifp; +{ + register struct ifaddr *ifa; + register struct sockaddr_dl *sdl; + + ifp->if_type = IFT_ETHER; + ifp->if_addrlen = 6; + ifp->if_hdrlen = 14; + ifp->if_mtu = ETHERMTU; + if (ifp->if_baudrate == 0) + ifp->if_baudrate = 10000000; + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) + if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && + sdl->sdl_family == AF_LINK) { + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ifp->if_addrlen; + bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, + LLADDR(sdl), ifp->if_addrlen); + break; + } +} + +static u_char ether_ipmulticast_min[6] = + { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; +static u_char ether_ipmulticast_max[6] = + { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff }; +/* + * Add an Ethernet multicast address or range of addresses to the list for a + * given interface. + */ +int +ether_addmulti(ifr, ac) + struct ifreq *ifr; + register struct arpcom *ac; +{ + register struct ether_multi *enm; + struct sockaddr_in *sin; + u_char addrlo[6]; + u_char addrhi[6]; + int set_allmulti = 0; + int s = splimp(); + + switch (ifr->ifr_addr.sa_family) { + + case AF_UNSPEC: + bcopy(ifr->ifr_addr.sa_data, addrlo, 6); + bcopy(addrlo, addrhi, 6); + break; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&(ifr->ifr_addr); + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* + * An IP address of INADDR_ANY means listen to all + * of the Ethernet multicast addresses used for IP. + * (This is for the sake of IP multicast routers.) + */ + bcopy(ether_ipmulticast_min, addrlo, 6); + bcopy(ether_ipmulticast_max, addrhi, 6); + set_allmulti = 1; + } + else { + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); + bcopy(addrlo, addrhi, 6); + } + break; +#endif + + default: + splx(s); + return (EAFNOSUPPORT); + } + + /* + * Verify that we have valid Ethernet multicast addresses. + */ + if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { + splx(s); + return (EINVAL); + } + /* + * See if the address range is already in the list. + */ + ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); + if (enm != NULL) { + /* + * Found it; just increment the reference count. + */ + ++enm->enm_refcount; + splx(s); + return (0); + } + /* + * New address or range; malloc a new multicast record + * and link it into the interface's multicast list. + */ + enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); + if (enm == NULL) { + splx(s); + return (ENOBUFS); + } + bcopy(addrlo, enm->enm_addrlo, 6); + bcopy(addrhi, enm->enm_addrhi, 6); + enm->enm_ac = ac; + enm->enm_refcount = 1; + enm->enm_next = ac->ac_multiaddrs; + ac->ac_multiaddrs = enm; + ac->ac_multicnt++; + splx(s); + if (set_allmulti) + ac->ac_if.if_flags |= IFF_ALLMULTI; + + /* + * Return ENETRESET to inform the driver that the list has changed + * and its reception filter should be adjusted accordingly. + */ + return (ENETRESET); +} + +/* + * Delete a multicast address record. + */ +int +ether_delmulti(ifr, ac) + struct ifreq *ifr; + register struct arpcom *ac; +{ + register struct ether_multi *enm; + register struct ether_multi **p; + struct sockaddr_in *sin; + u_char addrlo[6]; + u_char addrhi[6]; + int unset_allmulti = 0; + int s = splimp(); + + switch (ifr->ifr_addr.sa_family) { + + case AF_UNSPEC: + bcopy(ifr->ifr_addr.sa_data, addrlo, 6); + bcopy(addrlo, addrhi, 6); + break; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&(ifr->ifr_addr); + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* + * An IP address of INADDR_ANY means stop listening + * to the range of Ethernet multicast addresses used + * for IP. + */ + bcopy(ether_ipmulticast_min, addrlo, 6); + bcopy(ether_ipmulticast_max, addrhi, 6); + unset_allmulti = 1; + } + else { + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); + bcopy(addrlo, addrhi, 6); + } + break; +#endif + + default: + splx(s); + return (EAFNOSUPPORT); + } + + /* + * Look up the address in our list. + */ + ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); + if (enm == NULL) { + splx(s); + return (ENXIO); + } + if (--enm->enm_refcount != 0) { + /* + * Still some claims to this record. + */ + splx(s); + return (0); + } + /* + * No remaining claims to this record; unlink and free it. + */ + for (p = &enm->enm_ac->ac_multiaddrs; + *p != enm; + p = &(*p)->enm_next) + continue; + *p = (*p)->enm_next; + free(enm, M_IFMADDR); + ac->ac_multicnt--; + splx(s); + if (unset_allmulti) + ac->ac_if.if_flags &= ~IFF_ALLMULTI; + + /* + * Return ENETRESET to inform the driver that the list has changed + * and its reception filter should be adjusted accordingly. + */ + return (ENETRESET); +} + +SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); + +int +ether_ioctl(struct ifnet *ifp, int command, caddr_t data) +{ + struct ifaddr *ifa = (struct ifaddr *) data; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; + + switch (command) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + ifp->if_init(ifp->if_softc); /* before arpwhohas */ + arp_ifinit((struct arpcom *)ifp, ifa); + break; +#endif +#ifdef IPX + /* + * XXX - This code is probably wrong + */ + case AF_IPX: + { + register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); + struct arpcom *ac = (struct arpcom *) (ifp->if_softc); + + if (ipx_nullhost(*ina)) + ina->x_host = + *(union ipx_host *) + ac->ac_enaddr; + else { + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) ac->ac_enaddr, + sizeof(ac->ac_enaddr)); + } + + /* + * Set new address + */ + ifp->if_init(ifp->if_softc); + break; + } +#endif +#ifdef NS + /* + * XXX - This code is probably wrong + */ + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + struct arpcom *ac = (struct arpcom *) (ifp->if_softc); + + if (ns_nullhost(*ina)) + ina->x_host = + *(union ns_host *) (ac->ac_enaddr); + else { + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) ac->ac_enaddr, + sizeof(ac->ac_enaddr)); + } + + /* + * Set new address + */ + ifp->if_init(ifp->if_softc); + break; + } +#endif + default: + ifp->if_init(ifp->if_softc); + break; + } + break; + + case SIOCGIFADDR: + { + struct sockaddr *sa; + + sa = (struct sockaddr *) & ifr->ifr_data; + bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, + (caddr_t) sa->sa_data, ETHER_ADDR_LEN); + } + break; + + case SIOCSIFMTU: + /* + * Set the interface MTU. + */ + if (ifr->ifr_mtu > ETHERMTU) { + error = EINVAL; + } else { + ifp->if_mtu = ifr->ifr_mtu; + } + break; + } + return (error); +} diff --git a/c/src/exec/libnetworking/net/if_llc.h b/c/src/exec/libnetworking/net/if_llc.h new file mode 100644 index 0000000000..3cdf652167 --- /dev/null +++ b/c/src/exec/libnetworking/net/if_llc.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1988, 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_llc.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_IF_LLC_H_ +#define _NET_IF_LLC_H_ + +/* + * IEEE 802.2 Link Level Control headers, for use in conjunction with + * 802.{3,4,5} media access control methods. + * + * Headers here do not use bit fields due to shortcomings in many + * compilers. + */ + +struct llc { + u_char llc_dsap; + u_char llc_ssap; + union { + struct { + u_char control; + u_char format_id; + u_char class; + u_char window_x2; + } type_u; + struct { + u_char num_snd_x2; + u_char num_rcv_x2; + } type_i; + struct { + u_char control; + u_char num_rcv_x2; + } type_s; + struct { + u_char control; + struct frmrinfo { + u_char rej_pdu_0; + u_char rej_pdu_1; + u_char frmr_control; + u_char frmr_control_ext; + u_char frmr_cause; + } frmrinfo; + } type_frmr; + struct { + u_char control; + u_char org_code[3]; + u_short ether_type; + } type_snap; + struct { + u_char control; + u_char control_ext; + } type_raw; + } llc_un; +}; +#define llc_control llc_un.type_u.control +#define llc_control_ext llc_un.type_raw.control_ext +#define llc_fid llc_un.type_u.format_id +#define llc_class llc_un.type_u.class +#define llc_window llc_un.type_u.window_x2 +#define llc_frmrinfo llc_un.type_frmr.frmrinfo +#define llc_frmr_pdu0 llc_un.type_frmr.frmrinfo.rej_pdu0 +#define llc_frmr_pdu1 llc_un.type_frmr.frmrinfo.rej_pdu1 +#define llc_frmr_control llc_un.type_frmr.frmrinfo.frmr_control +#define llc_frmr_control_ext llc_un.type_frmr.frmrinfo.frmr_control_ext +#define llc_frmr_cause llc_un.type_frmr.frmrinfo.frmr_control_ext + +/* + * Don't use sizeof(struct llc_un) for LLC header sizes + */ +#define LLC_ISFRAMELEN 4 +#define LLC_UFRAMELEN 3 +#define LLC_FRMRLEN 7 + +/* + * Unnumbered LLC format commands + */ +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_DISC 0x43 +#define LLC_DISC_P 0x53 +#define LLC_UA 0x63 +#define LLC_UA_P 0x73 +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 +#define LLC_FRMR 0x87 +#define LLC_FRMR_P 0x97 +#define LLC_DM 0x0f +#define LLC_DM_P 0x1f +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_SABME 0x6f +#define LLC_SABME_P 0x7f + +/* + * Supervisory LLC commands + */ +#define LLC_RR 0x01 +#define LLC_RNR 0x05 +#define LLC_REJ 0x09 + +/* + * Info format - dummy only + */ +#define LLC_INFO 0x00 + +/* + * ISO PDTR 10178 contains among others + */ +#define LLC_X25_LSAP 0x7e +#define LLC_SNAP_LSAP 0xaa +#define LLC_ISO_LSAP 0xfe + +#endif diff --git a/c/src/exec/libnetworking/net/if_loop.c b/c/src/exec/libnetworking/net/if_loop.c new file mode 100644 index 0000000000..3823c28744 --- /dev/null +++ b/c/src/exec/libnetworking/net/if_loop.c @@ -0,0 +1,301 @@ +/* + * 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.1 (Berkeley) 6/10/93 + * $Id$ + */ + +/* + * Loopback interface driver for protocol testing and timing. + */ +#include "loop.h" +#if NLOOP > 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#endif + +#ifdef IPX +#include +#include +#endif + +#ifdef NS +#include +#include +#endif + +#ifdef ISO +#include +#include +#endif + +#ifdef NETATALK +#include +#include +#include +#endif NETATALK + +#include "bpfilter.h" + +static int loioctl __P((struct ifnet *, int, caddr_t)); +static void lortrequest __P((int, struct rtentry *, struct sockaddr *)); + + void rtems_bsdnet_loopattach __P((void *)); +PSEUDO_SET(loopattach, if_loop); + +#ifdef TINY_LOMTU +#define LOMTU (1024+512) +#else +#define LOMTU 16384 +#endif + +struct ifnet loif[NLOOP]; + +/* ARGSUSED */ +void +rtems_bsdnet_loopattach(dummy) + void *dummy; +{ + register struct ifnet *ifp; + register int i = 0; + + for (ifp = loif; i < NLOOP; ifp++) { + ifp->if_name = "lo"; + ifp->if_next = NULL; + ifp->if_unit = i++; + 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, 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"); +#if NBPFILTER > 0 + /* BPF write needs to be handled specially */ + if (dst->sa_family == AF_UNSPEC) { + dst->sa_family = *(mtod(m, int *)); + m->m_len -= sizeof(int); + m->m_pkthdr.len -= sizeof(int); + m->m_data += sizeof(int); + } + + if (ifp->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(ifp, &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 IPX + case AF_IPX: + ifq = &ipxintrq; + isr = NETISR_IPX; + 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 +#ifdef NETATALK + case AF_APPLETALK: + ifq = &atintrq2; + isr = NETISR_ATALK; + break; +#endif NETATALK + 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 */ +static void +lortrequest(cmd, rt, sa) + int cmd; + struct rtentry *rt; + struct sockaddr *sa; +{ + if (rt) { + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */ + /* + * For optimal performance, the send and receive buffers + * should be at least twice the MTU plus a little more for + * overhead. + */ + rt->rt_rmx.rmx_recvpipe = + rt->rt_rmx.rmx_sendpipe = 3 * LOMTU; + } +} + +/* + * Process an ioctl request. + */ +/* ARGSUSED */ +static int +loioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + register struct ifaddr *ifa; + register struct ifreq *ifr = (struct ifreq *)data; + register int error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP | IFF_RUNNING; + ifa = (struct ifaddr *)data; + ifa->ifa_rtrequest = lortrequest; + /* + * Everything else is done at a higher level. + */ + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + 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; + + case SIOCSIFMTU: + ifp->if_mtu = ifr->ifr_mtu; + break; + + default: + error = EINVAL; + } + return (error); +} +#endif /* NLOOP > 0 */ diff --git a/c/src/exec/libnetworking/net/if_types.h b/c/src/exec/libnetworking/net/if_types.h new file mode 100644 index 0000000000..833ba471c3 --- /dev/null +++ b/c/src/exec/libnetworking/net/if_types.h @@ -0,0 +1,101 @@ +/* + * 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.2 (Berkeley) 4/20/94 + * $Id$ + */ + +#ifndef _NET_IF_TYPES_H_ +#define _NET_IF_TYPES_H_ + +/* + * 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 */ + +#endif diff --git a/c/src/exec/libnetworking/net/netisr.h b/c/src/exec/libnetworking/net/netisr.h new file mode 100644 index 0000000000..73269a4442 --- /dev/null +++ b/c/src/exec/libnetworking/net/netisr.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1980, 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. + * + * @(#)netisr.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_NETISR_H_ +#define _NET_NETISR_H_ + +/* + * The networking code runs off software interrupts. + * + * You can switch into the network by doing splnet() and return by splx(). + * The software interrupt level for the network is higher than the software + * level for the clock (so you can enter the network in routines called + * at timeout time). + */ +#if defined(vax) || defined(tahoe) +#define setsoftnet() mtpr(SIRR, 12) +#endif + +/* + * Each ``pup-level-1'' input queue has a bit in a ``netisr'' status + * word which is used to de-multiplex a single software + * interrupt used for scheduling the network code to calls + * on the lowest level routine of each protocol. + */ +#define NETISR_RAW 0 /* same as AF_UNSPEC */ +#define NETISR_IP 2 /* same as AF_INET */ +#define NETISR_IMP 3 /* same as AF_IMPLINK */ +#define NETISR_NS 6 /* same as AF_NS */ +#define NETISR_ISO 7 /* same as AF_ISO */ +#define NETISR_CCITT 10 /* same as AF_CCITT */ +#define NETISR_ATALK 16 /* same as AF_APPLETALK */ +#define NETISR_ARP 18 /* same as AF_LINK */ +#define NETISR_IPX 23 /* same as AF_IPX */ +#define NETISR_ISDN 26 /* same as AF_E164 */ +#define NETISR_PPP 27 /* PPP soft interrupt */ + +#define schednetisr(anisr) rtems_bsdnet_schednetisr(anisr) + +#ifndef LOCORE +#ifdef KERNEL +extern volatile unsigned int netisr; /* scheduling bits for network */ + +typedef void netisr_t(void); + +struct netisrtab { + int nit_num; + netisr_t *nit_isr; +}; + +#define NETISR_SET(num, isr) + +int register_netisr __P((int, netisr_t *)); + +#endif +#endif + +#endif diff --git a/c/src/exec/libnetworking/net/radix.c b/c/src/exec/libnetworking/net/radix.c new file mode 100644 index 0000000000..bc1b7ee1d1 --- /dev/null +++ b/c/src/exec/libnetworking/net/radix.c @@ -0,0 +1,1028 @@ +/* + * 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.4 (Berkeley) 11/2/94 + * $Id$ + */ + +/* + * Routines to build and maintain radix trees for routing lookups. + */ +#ifndef _RADIX_H_ +#include +#ifdef KERNEL +#include +#include +#define M_DONTWAIT M_NOWAIT +#include +#else +#include +#endif +#include +#include +#endif + +static struct radix_node * + rn_lookup __P((void *v_arg, void *m_arg, + struct radix_node_head *head)); +static int rn_walktree_from __P((struct radix_node_head *h, void *a, + void *m, walktree_f_t *f, void *w)); +static int rn_walktree __P((struct radix_node_head *, walktree_f_t *, void *)); +static struct radix_node + *rn_delete __P((void *, void *, struct radix_node_head *)), + *rn_insert __P((void *, struct radix_node_head *, int *, + struct radix_node [2])), + *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 *)); + +static int max_keylen; +static struct radix_mask *rn_mkfreelist; +static 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)) + +static int rn_lexobetter __P((void *m_arg, void *n_arg)); +static struct radix_mask * + rn_new_radix_mask __P((struct radix_node *tt, + struct radix_mask *next)); +static int rn_satsifies_leaf __P((char *trial, struct radix_node *leaf, + int skip)); + +/* + * 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. + */ + +static 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); +}; + +static 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 + +static 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; +} + +static 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. + */ + 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; /* parent */ + 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; /* parent */ + if (tt->rn_dupedkey) /* parent */ + tt->rn_dupedkey->rn_p = tt; /* parent */ + } +#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; +} + +static 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) { + /* + * at this point, tt is the deletion target and saved_tt + * is the head of the dupekey chain + */ + if (tt == saved_tt) { + /* remove from head of chain */ + 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) /* parent */ + tt->rn_dupedkey->rn_p = p; /* parent */ + } 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 %p 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); +} + +/* + * This is the same as rn_walktree() except for the parameters and the + * exit. + */ +static int +rn_walktree_from(h, a, m, f, w) + struct radix_node_head *h; + void *a, *m; + walktree_f_t *f; + void *w; +{ + int error; + struct radix_node *base, *next; + u_char *xa = (u_char *)a; + u_char *xm = (u_char *)m; + register struct radix_node *rn, *last = 0 /* shut up gcc */; + int stopping = 0; + int lastb; + + /* + * rn_search_m is sort-of-open-coded here. + */ + /* printf("about to search\n"); */ + for (rn = h->rnh_treetop; rn->rn_b >= 0; ) { + last = rn; + /* printf("rn_b %d, rn_bmask %x, xm[rn_off] %x\n", + rn->rn_b, rn->rn_bmask, xm[rn->rn_off]); */ + if (!(rn->rn_bmask & xm[rn->rn_off])) { + break; + } + if (rn->rn_bmask & xa[rn->rn_off]) { + rn = rn->rn_r; + } else { + rn = rn->rn_l; + } + } + /* printf("done searching\n"); */ + + /* + * Two cases: either we stepped off the end of our mask, + * in which case last == rn, or we reached a leaf, in which + * case we want to start from the last node we looked at. + * Either way, last is the node we want to start from. + */ + rn = last; + lastb = rn->rn_b; + + /* printf("rn %p, lastb %d\n", rn, lastb);*/ + + /* + * 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. + */ + while (rn->rn_b >= 0) + rn = rn->rn_l; + + while (!stopping) { + /* printf("node %p (%d)\n", rn, rn->rn_b); */ + base = rn; + /* If at right child go back up, otherwise, go right */ + while (rn->rn_p->rn_r == rn && !(rn->rn_flags & RNF_ROOT)) { + rn = rn->rn_p; + + /* if went up beyond last, stop */ + if (rn->rn_b < lastb) { + stopping = 1; + /* printf("up too far\n"); */ + } + } + + /* 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) != 0) { + base = rn->rn_dupedkey; + /* printf("leaf %p\n", rn); */ + if (!(rn->rn_flags & RNF_ROOT) + && (error = (*f)(rn, w))) + return (error); + } + rn = next; + + if (rn->rn_flags & RNF_ROOT) { + /* printf("root, stopping"); */ + stopping = 1; + } + + } + return 0; +} + +static int +rn_walktree(h, f, w) + struct radix_node_head *h; + walktree_f_t *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_walktree_from = rn_walktree_from; + 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"); +} diff --git a/c/src/exec/libnetworking/net/radix.h b/c/src/exec/libnetworking/net/radix.h new file mode 100644 index 0000000000..6ef9aafbac --- /dev/null +++ b/c/src/exec/libnetworking/net/radix.h @@ -0,0 +1,165 @@ +/* + * 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 + * $Id$ + */ + +#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);} + +typedef int walktree_f_t __P((struct radix_node *, void *)); + +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, walktree_f_t *f, void *w)); + int (*rnh_walktree_from) /* traverse tree below a */ + __P((struct radix_node_head *head, void *a, void *m, + walktree_f_t *f, void *w)); + void (*rnh_close) /* do something when the last ref drops */ + __P((struct radix_node *rn, struct radix_node_head *head)); + 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*/ + +extern struct radix_node_head *mask_rnhead; + +void rn_init __P((void)); +int rn_inithead __P((void **, int)); +int rn_refines __P((void *, void *)); +struct radix_node + *rn_addmask __P((void *, int, int)), + *rn_addroute __P((void *, void *, struct radix_node_head *, + struct radix_node [2])), + *rn_match __P((void *, struct radix_node_head *)); + + +#endif /* _RADIX_H_ */ diff --git a/c/src/exec/libnetworking/net/raw_cb.c b/c/src/exec/libnetworking/net/raw_cb.c new file mode 100644 index 0000000000..0676931cdc --- /dev/null +++ b/c/src/exec/libnetworking/net/raw_cb.c @@ -0,0 +1,148 @@ +/* + * 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. + * + * @(#)raw_cb.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Routines to manage the raw protocol control blocks. + * + * TODO: + * hash lookups by protocol family/protocol + address family + * take care of unique address problems per AF? + * redo address binding to allow wildcards + */ + +struct rawcb rawcb; +static u_long raw_sendspace = RAWSNDQ; +static u_long raw_recvspace = RAWRCVQ; + +/* + * Allocate a control block and a nominal amount + * of buffer space for the socket. + */ +int +raw_attach(so, proto) + register struct socket *so; + int proto; +{ + register struct rawcb *rp = sotorawcb(so); + int error; + + /* + * It is assumed that raw_attach is called + * after space has been allocated for the + * rawcb. + */ + if (rp == 0) + return (ENOBUFS); + error = soreserve(so, raw_sendspace, raw_recvspace); + if (error) + return (error); + rp->rcb_socket = so; + rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family; + rp->rcb_proto.sp_protocol = proto; + insque(rp, &rawcb); + return (0); +} + +/* + * Detach the raw connection block and discard + * socket resources. + */ +void +raw_detach(rp) + register struct rawcb *rp; +{ + struct socket *so = rp->rcb_socket; + + so->so_pcb = 0; + sofree(so); + remque(rp); +#ifdef notdef + if (rp->rcb_laddr) + m_freem(dtom(rp->rcb_laddr)); + rp->rcb_laddr = 0; +#endif + free((caddr_t)(rp), M_PCB); +} + +/* + * Disconnect and possibly release resources. + */ +void +raw_disconnect(rp) + struct rawcb *rp; +{ + +#ifdef notdef + if (rp->rcb_faddr) + m_freem(dtom(rp->rcb_faddr)); + rp->rcb_faddr = 0; +#endif + if (rp->rcb_socket->so_state & SS_NOFDREF) + raw_detach(rp); +} + +#ifdef notdef +int +raw_bind(so, nam) + register struct socket *so; + struct mbuf *nam; +{ + struct sockaddr *addr = mtod(nam, struct sockaddr *); + register struct rawcb *rp; + + if (ifnet == 0) + return (EADDRNOTAVAIL); + rp = sotorawcb(so); + nam = m_copym(nam, 0, M_COPYALL, M_WAITOK); + rp->rcb_laddr = mtod(nam, struct sockaddr *); + return (0); +} +#endif diff --git a/c/src/exec/libnetworking/net/raw_cb.h b/c/src/exec/libnetworking/net/raw_cb.h new file mode 100644 index 0000000000..c1ed5e5e0a --- /dev/null +++ b/c/src/exec/libnetworking/net/raw_cb.h @@ -0,0 +1,75 @@ +/* + * 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. + * + * @(#)raw_cb.h 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#ifndef _NET_RAW_CB_H_ +#define _NET_RAW_CB_H_ + +/* + * Raw protocol interface control block. Used + * to tie a socket to the generic raw interface. + */ +struct rawcb { + struct rawcb *rcb_next; /* doubly linked list */ + struct rawcb *rcb_prev; + struct socket *rcb_socket; /* back pointer to socket */ + struct sockaddr *rcb_faddr; /* destination address */ + struct sockaddr *rcb_laddr; /* socket's address */ + struct sockproto rcb_proto; /* protocol family, protocol */ +}; + +#define sotorawcb(so) ((struct rawcb *)(so)->so_pcb) + +/* + * Nominal space allocated to a raw socket. + */ +#define RAWSNDQ 8192 +#define RAWRCVQ 8192 + +#ifdef KERNEL +extern struct rawcb rawcb; /* head of list */ + +int raw_attach __P((struct socket *, int)); +void raw_ctlinput __P((int, struct sockaddr *, void *)); +void raw_detach __P((struct rawcb *)); +void raw_disconnect __P((struct rawcb *)); +void raw_init __P((void)); +void raw_input __P((struct mbuf *, + struct sockproto *, struct sockaddr *, struct sockaddr *)); +int raw_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +#endif + +#endif diff --git a/c/src/exec/libnetworking/net/raw_usrreq.c b/c/src/exec/libnetworking/net/raw_usrreq.c new file mode 100644 index 0000000000..fb4faf4d6d --- /dev/null +++ b/c/src/exec/libnetworking/net/raw_usrreq.c @@ -0,0 +1,315 @@ +/* + * 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. + * + * @(#)raw_usrreq.c 8.1 (Berkeley) 6/10/93 + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Initialize raw connection block q. + */ +void +raw_init() +{ + + rawcb.rcb_next = rawcb.rcb_prev = &rawcb; +} + + +/* + * Raw protocol input routine. Find the socket + * associated with the packet(s) and move them over. If + * nothing exists for this packet, drop it. + */ +/* + * Raw protocol interface. + */ +void +raw_input(m0, proto, src, dst) + struct mbuf *m0; + register struct sockproto *proto; + struct sockaddr *src, *dst; +{ + register struct rawcb *rp; + register struct mbuf *m = m0; + register int sockets = 0; + struct socket *last; + + last = 0; + for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { + if (rp->rcb_proto.sp_family != proto->sp_family) + continue; + if (rp->rcb_proto.sp_protocol && + rp->rcb_proto.sp_protocol != proto->sp_protocol) + continue; + /* + * We assume the lower level routines have + * placed the address in a canonical format + * suitable for a structure comparison. + * + * Note that if the lengths are not the same + * the comparison will fail at the first byte. + */ +#define equal(a1, a2) \ + (bcmp((caddr_t)(a1), (caddr_t)(a2), a1->sa_len) == 0) + if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) + continue; + if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) + continue; + if (last) { + struct mbuf *n; + n = m_copy(m, 0, (int)M_COPYALL); + if (n) { + if (sbappendaddr(&last->so_rcv, src, + n, (struct mbuf *)0) == 0) + /* should notify about lost packet */ + m_freem(n); + else { + sorwakeup(last); + sockets++; + } + } + } + last = rp->rcb_socket; + } + if (last) { + if (sbappendaddr(&last->so_rcv, src, + m, (struct mbuf *)0) == 0) + m_freem(m); + else { + sorwakeup(last); + sockets++; + } + } else + m_freem(m); +} + +/*ARGSUSED*/ +void +raw_ctlinput(cmd, arg, dummy) + int cmd; + struct sockaddr *arg; + void *dummy; +{ + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + /* INCOMPLETE */ +} + +/*ARGSUSED*/ +int +raw_usrreq(so, req, m, nam, control) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register struct rawcb *rp = sotorawcb(so); + register int error = 0; + int len; + + if (req == PRU_CONTROL) + return (EOPNOTSUPP); + if (control && control->m_len) { + error = EOPNOTSUPP; + goto release; + } + if (rp == 0) { + error = EINVAL; + goto release; + } + switch (req) { + + /* + * Allocate a raw control block and fill in the + * necessary info to allow packets to be routed to + * the appropriate raw interface routine. + */ + case PRU_ATTACH: + if ((so->so_state & SS_PRIV) == 0) { + error = EACCES; + break; + } + error = raw_attach(so, (int)nam); + break; + + /* + * Destroy state just before socket deallocation. + * Flush data or not depending on the options. + */ + case PRU_DETACH: + if (rp == 0) { + error = ENOTCONN; + break; + } + raw_detach(rp); + break; + + /* + * If a socket isn't bound to a single address, + * the raw input routine will hand it anything + * within that protocol family (assuming there's + * nothing else around it should go to). + */ + case PRU_CONNECT: + error = EINVAL; +#if 0 + if (rp->rcb_faddr) { + error = EISCONN; + break; + } + nam = m_copym(nam, 0, M_COPYALL, M_WAIT); + rp->rcb_faddr = mtod(nam, struct sockaddr *); + soisconnected(so); +#endif + break; + + case PRU_BIND: + error = EINVAL; +#if 0 + if (rp->rcb_laddr) { + error = EINVAL; /* XXX */ + break; + } + error = raw_bind(so, nam); +#endif + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; + goto release; + + case PRU_DISCONNECT: + if (rp->rcb_faddr == 0) { + error = ENOTCONN; + break; + } + raw_disconnect(rp); + soisdisconnected(so); + break; + + /* + * Mark the connection as being incapable of further input. + */ + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + /* + * Ship a packet out. The appropriate raw output + * routine handles any massaging necessary. + */ + case PRU_SEND: + if (nam) { + if (rp->rcb_faddr) { + error = EISCONN; + break; + } + rp->rcb_faddr = mtod(nam, struct sockaddr *); + } else if (rp->rcb_faddr == 0) { + error = ENOTCONN; + break; + } + error = (*so->so_proto->pr_output)(m, so); + m = NULL; + if (nam) + rp->rcb_faddr = 0; + break; + + case PRU_ABORT: + raw_disconnect(rp); + sofree(so); + soisdisconnected(so); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + /* + * Not supported. + */ + case PRU_RCVOOB: + case PRU_RCVD: + return(EOPNOTSUPP); + + case PRU_LISTEN: + case PRU_ACCEPT: + case PRU_SENDOOB: + error = EOPNOTSUPP; + break; + + case PRU_SOCKADDR: + if (rp->rcb_laddr == 0) { + error = EINVAL; + break; + } + len = rp->rcb_laddr->sa_len; + bcopy((caddr_t)rp->rcb_laddr, mtod(nam, caddr_t), (unsigned)len); + nam->m_len = len; + break; + + case PRU_PEERADDR: + if (rp->rcb_faddr == 0) { + error = ENOTCONN; + break; + } + len = rp->rcb_faddr->sa_len; + bcopy((caddr_t)rp->rcb_faddr, mtod(nam, caddr_t), (unsigned)len); + nam->m_len = len; + break; + + default: + panic("raw_usrreq"); + } +release: + if (m != NULL) + m_freem(m); + return (error); +} diff --git a/c/src/exec/libnetworking/net/route.c b/c/src/exec/libnetworking/net/route.c new file mode 100644 index 0000000000..0bea64f747 --- /dev/null +++ b/c/src/exec/libnetworking/net/route.c @@ -0,0 +1,959 @@ +/* + * 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.2 (Berkeley) 11/15/93 + * $Id$ + */ + +#include "opt_mrouting.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define SA(p) ((struct sockaddr *)(p)) + +struct route_cb route_cb; +static struct rtstat rtstat; +struct radix_node_head *rt_tables[AF_MAX+1]; + +static int rttrash; /* routes not in table but not freed */ + +static void rt_maskedcopy __P((struct sockaddr *, + struct sockaddr *, struct sockaddr *)); +static void rtable_init __P((void **)); + +static 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, 0UL); +} + +void +rtalloc_ign(ro, ignore) + register struct route *ro; + u_long ignore; +{ + 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, ignore); +} + +/* + * Look up the route that matches the address given + * Or, at least try.. Create a cloned route if needed. + */ +struct rtentry * +rtalloc1(dst, report, ignflags) + register struct sockaddr *dst; + int report; + u_long ignflags; +{ + 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; + u_long nflags; + int s = splnet(), err = 0, msgtype = RTM_MISS; + + /* + * Look up the address in the table for that Address Family + */ + if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && + ((rn->rn_flags & RNF_ROOT) == 0)) { + /* + * If we find it and it's not the root node, then + * get a refernce on the rtentry associated. + */ + newrt = rt = (struct rtentry *)rn; + nflags = rt->rt_flags & ~ignflags; + if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) { + /* + * We are apparently adding (report = 0 in delete). + * If it requires that it be cloned, do so. + * (This implies it wasn't a HOST route.) + */ + err = rtrequest(RTM_RESOLVE, dst, SA(0), + SA(0), 0, &newrt); + if (err) { + /* + * If the cloning didn't succeed, maybe + * what we have will do. Return that. + */ + newrt = rt; + rt->rt_refcnt++; + goto miss; + } + if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { + /* + * If the new route specifies it be + * externally resolved, then go do that. + */ + msgtype = RTM_RESOLVE; + goto miss; + } + } else + rt->rt_refcnt++; + } else { + /* + * Either we hit the root or couldn't find any match, + * Which basically means + * "caint get there frm here" + */ + rtstat.rts_unreach++; + miss: if (report) { + /* + * If required, report the failure to the supervising + * Authorities. + * For a delete, this is not an error. (report == 0) + */ + 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 radix_node_head *rnh = + rt_tables[rt_key(rt)->sa_family]; + register struct ifaddr *ifa; + + if (rt == 0 || rnh == 0) + panic("rtfree"); + rt->rt_refcnt--; + if(rnh->rnh_close && rt->rt_refcnt == 0) { + rnh->rnh_close((struct radix_node *)rt, rnh); + } + 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: %p not freed (neg refs)\n", rt); + return; + } + ifa = rt->rt_ifa; + IFAFREE(ifa); + if (rt->rt_parent) { + RTFREE(rt->rt_parent); + } + 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 + * + */ +void +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, 0UL); + /* + * 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) + int req; + caddr_t data; + struct proc *p; +{ +#ifdef INET + /* Multicast goop, grrr... */ +#ifdef MROUTING + return mrt_ioctl(req, data); +#else + return mrt_ioctl(req, data, p); +#endif +#else /* INET */ + return ENXIO; +#endif /* INET */ +} + +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, 0UL); + 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)) + +static int rt_fixdelete(struct radix_node *, void *); +static int rt_fixchange(struct radix_node *, void *); + +struct rtfc_arg { + struct rtentry *rt0; + struct radix_node_head *rnh; +}; + +/* + * Do appropriate manipulations of a routing tree given + * all the bits of info needed + */ +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; } + + /* + * Find the correct routing tree to use for this Address Family + */ + if ((rnh = rt_tables[dst->sa_family]) == 0) + senderr(ESRCH); + /* + * If we are adding a host route then we don't want to put + * a netmask in the tree + */ + if (flags & RTF_HOST) + netmask = 0; + switch (req) { + case RTM_DELETE: + /* + * Remove the item from the tree and return it. + * Complain if it is not there and do no more processing. + */ + 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; + + /* + * Now search what's left of the subtree for any cloned + * routes which might have been formed from this node. + */ + if ((rt->rt_flags & RTF_PRCLONING) && netmask) { + rnh->rnh_walktree_from(rnh, dst, netmask, + rt_fixdelete, rt); + } + + /* + * Remove any external references we may have. + * This might result in another rtentry being freed if + * we held it's last reference. + */ + if (rt->rt_gwroute) { + rt = rt->rt_gwroute; + RTFREE(rt); + (rt = (struct rtentry *)rn)->rt_gwroute = 0; + } + + /* + * NB: RTF_UP must be set during the search above, + * because we might delete the last ref, causing + * rt to get freed prematurely. + */ + rt->rt_flags &= ~RTF_UP; + + /* + * If there is llinfo or similar associated with the + * route, give the interface a chance to deal with it.. + */ + if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) + ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); + rttrash++; + /* + * If the caller wants it, then it can have it, but it's up to it + * to free the rtentry as we won't be doing it. + */ + if (ret_nrt) + *ret_nrt = rt; + else if (rt->rt_refcnt <= 0) { + rt->rt_refcnt++; /* make a 1->0 transition */ + 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 | RTF_PRCLONING | RTF_STATIC); + flags |= RTF_WASCLONED; + gateway = rt->rt_gateway; + if ((netmask = rt->rt_genmask) == 0) + flags |= RTF_HOST; + goto makeroute; + + case RTM_ADD: + if ((flags & RTF_GATEWAY) && !gateway) + panic("rtrequest: GATEWAY but no gateway"); + + 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 (error = rt_setgate(rt, dst, gateway)) { + Free(rt); + senderr(error); + } + ndst = rt_key(rt); + if (netmask) { + rt_maskedcopy(dst, ndst, netmask); + } else + Bcopy(dst, ndst, dst->sa_len); + + /* + * This moved from below so that rnh->rnh_addaddr() can + * examine the ifa and ifp if it so desires. + */ + ifa->ifa_refcnt++; + rt->rt_ifa = ifa; + rt->rt_ifp = ifa->ifa_ifp; + + rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask, + rnh, rt->rt_nodes); + if (rn == 0) { + struct rtentry *rt2; + /* + * Uh-oh, we already have one of these in the tree. + * We do a special hack: if the route that's already + * there was generated by the protocol-cloning + * mechanism, then we just blow it away and retry + * the insertion of the new one. + */ + rt2 = rtalloc1(dst, 0, RTF_PRCLONING); + if (rt2 && rt2->rt_parent) { + rtrequest(RTM_DELETE, + (struct sockaddr *)rt_key(rt2), + rt2->rt_gateway, + rt_mask(rt2), rt2->rt_flags, 0); + RTFREE(rt2); + rn = rnh->rnh_addaddr((caddr_t)ndst, + (caddr_t)netmask, + rnh, rt->rt_nodes); + } else if (rt2) { + RTFREE(rt2); + } + } + + if (rn == 0) { + if (rt->rt_gwroute) + rtfree(rt->rt_gwroute); + if (rt->rt_ifa) { + IFAFREE(rt->rt_ifa); + } + Free(rt_key(rt)); + Free(rt); + senderr(EEXIST); + } + rt->rt_parent = 0; + + if (req == RTM_RESOLVE) { + rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ + if ((*ret_nrt)->rt_flags & RTF_PRCLONING) { + rt->rt_parent = (*ret_nrt); + (*ret_nrt)->rt_refcnt++; + } + } + if (ifa->ifa_rtrequest) + ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); + /* + * We repeat the same procedure from rt_setgate() here because + * it doesn't fire when we call it there because the node + * hasn't been added to the tree yet. + */ + if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { + struct rtfc_arg arg; + arg.rnh = rnh; + arg.rt0 = rt; + rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), + rt_fixchange, &arg); + } + + if (ret_nrt) { + *ret_nrt = rt; + rt->rt_refcnt++; + } + break; + } +bad: + splx(s); + return (error); +} + +/* + * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family'' + * (i.e., the routes related to it by the operation of cloning). This + * routine is iterated over all potential former-child-routes by way of + * rnh->rnh_walktree_from() above, and those that actually are children of + * the late parent (passed in as VP here) are themselves deleted. + */ +static int +rt_fixdelete(struct radix_node *rn, void *vp) +{ + struct rtentry *rt = (struct rtentry *)rn; + struct rtentry *rt0 = vp; + + if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) { + return rtrequest(RTM_DELETE, rt_key(rt), + (struct sockaddr *)0, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + } + return 0; +} + +/* + * This routine is called from rt_setgate() to do the analogous thing for + * adds and changes. There is the added complication in this case of a + * middle insert; i.e., insertion of a new network route between an older + * network route and (cloned) host routes. For this reason, a simple check + * of rt->rt_parent is insufficient; each candidate route must be tested + * against the (mask, value) of the new route (passed as before in vp) + * to see if the new route matches it. Unfortunately, this has the obnoxious + * property of also triggering for insertion /above/ a pre-existing network + * route and clones. Sigh. This may be fixed some day. + * + * XXX - it may be possible to do fixdelete() for changes and reserve this + * routine just for adds. I'm not sure why I thought it was necessary to do + * changes this way. + */ +#ifdef DEBUG +int rtfcdebug = 0; +#endif + +static int +rt_fixchange(struct radix_node *rn, void *vp) +{ + struct rtentry *rt = (struct rtentry *)rn; + struct rtfc_arg *ap = vp; + struct rtentry *rt0 = ap->rt0; + struct radix_node_head *rnh = ap->rnh; + u_char *xk1, *xm1, *xk2; + int i, len; + +#ifdef DEBUG + if (rtfcdebug) + printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0); +#endif + + if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) { +#ifdef DEBUG + if(rtfcdebug) printf("no parent or pinned\n"); +#endif + return 0; + } + + if (rt->rt_parent == rt0) { +#ifdef DEBUG + if(rtfcdebug) printf("parent match\n"); +#endif + return rtrequest(RTM_DELETE, rt_key(rt), + (struct sockaddr *)0, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + } + + /* + * There probably is a function somewhere which does this... + * if not, there should be. + */ + len = imin(((struct sockaddr *)rt_key(rt0))->sa_len, + ((struct sockaddr *)rt_key(rt))->sa_len); + + xk1 = (u_char *)rt_key(rt0); + xm1 = (u_char *)rt_mask(rt0); + xk2 = (u_char *)rt_key(rt); + + for (i = rnh->rnh_treetop->rn_off; i < len; i++) { + if ((xk2[i] & xm1[i]) != xk1[i]) { +#ifdef DEBUG + if(rtfcdebug) printf("no match\n"); +#endif + return 0; + } + } + + /* + * OK, this node is a clone, and matches the node currently being + * changed/added under the node's mask. So, get rid of it. + */ +#ifdef DEBUG + if(rtfcdebug) printf("deleting\n"); +#endif + return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, + rt_mask(rt), rt->rt_flags, (struct rtentry **)0); +} + +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; + struct radix_node_head *rnh = rt_tables[dst->sa_family]; + + /* + * A host route with the destination equal to the gateway + * will interfere with keeping LLINFO in the routing + * table, so disallow it. + */ + if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) == + (RTF_HOST|RTF_GATEWAY)) && + (dst->sa_len == gate->sa_len) && + (bcmp(dst, gate, dst->sa_len) == 0)) { + /* + * The route might already exist if this is an RTM_CHANGE + * or a routing redirect, so try to delete it. + */ + if (rt_key(rt0)) + rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0), + rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0); + return EADDRNOTAVAIL; + } + + 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 ENOBUFS; + 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; + } + /* + * Cloning loop avoidance: + * In the presence of protocol-cloning and bad configuration, + * it is possible to get stuck in bottomless mutual recursion + * (rtrequest rt_setgate rtalloc1). We avoid this by not allowing + * protocol-cloning to operate for gateways (which is probably the + * correct choice anyway), and avoid the resulting reference loops + * by disallowing any route to run through itself as a gateway. + * This is obviuosly mandatory when we get rt->rt_output(). + */ + if (rt->rt_flags & RTF_GATEWAY) { + rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING); + if (rt->rt_gwroute == rt) { + RTFREE(rt->rt_gwroute); + rt->rt_gwroute = 0; + return EDQUOT; /* failure */ + } + } + + /* + * This isn't going to do anything useful for host routes, so + * don't bother. Also make sure we have a reasonable mask + * (we don't yet have one during adds). + */ + if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { + struct rtfc_arg arg; + arg.rnh = rnh; + arg.rt0 = rt; + rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), + rt_fixchange, &arg); + } + + return 0; +} + +static 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 it's a delete, check that if it exists, it's on the correct + * interface or we might scrub a route to another ifa which would + * be confusing at best and possibly worse. + */ + if (cmd == RTM_DELETE) { + /* + * It's a delete, so it should already exist.. + * If it's a net, mask off the host bits + * (Assuming we have a mask) + */ + 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; + } + /* + * Get an rtentry that is in the routing tree and + * contains the correct info. (if this fails we can't get there). + * We set "report" to FALSE so that if it doesn't exist, + * it doesn't report an error or clone a route, etc. etc. + */ + rt = rtalloc1(dst, 0, 0UL); + if (rt) { + /* + * Ok so we found the rtentry. it has an extra reference + * for us at this stage. we won't need that so + * lop that off now. + */ + rt->rt_refcnt--; + if (rt->rt_ifa != ifa) { + /* + * If the interface in the rtentry doesn't match + * the interface we are using, then we don't + * want to delete it, so return an error. + * This seems to be the only point of + * this whole RTM_DELETE clause. + */ + if (m) + (void) m_free(m); + return (flags & RTF_HOST ? EHOSTUNREACH + : ENETUNREACH); + } + } + /* XXX */ +#if 0 + else { + /* + * One would think that as we are deleting, and we know + * it doesn't exist, we could just return at this point + * with an "ELSE" clause, but apparently not.. + */ + return (flags & RTF_HOST ? EHOSTUNREACH + : ENETUNREACH); + } +#endif + } + /* + * Do the actual request + */ + error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, + flags | ifa->ifa_flags, &nrt); + if (m) + (void) m_free(m); + /* + * If we are deleting, and we found an entry, then + * it's been removed from the tree.. now throw it away. + */ + if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) { + /* + * notify any listenning routing agents of the change + */ + rt_newaddrmsg(cmd, ifa, error, nrt); + if (rt->rt_refcnt <= 0) { + rt->rt_refcnt++; /* need a 1->0 transition to free */ + rtfree(rt); + } + } + + /* + * We are adding, and we have a returned routing entry. + * We need to sanity check the result. + */ + if (cmd == RTM_ADD && error == 0 && (rt = nrt)) { + /* + * We just wanted to add it.. we don't actually need a reference + */ + rt->rt_refcnt--; + /* + * If it came back with an unexpected interface, then it must + * have already existed or something. (XXX) + */ + if (rt->rt_ifa != ifa) { + printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, + rt->rt_ifa); + /* + * Ask that the route we got back be removed + * from the routing tables as we are trying + * to supersede it. + */ + if (rt->rt_ifa->ifa_rtrequest) + rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0)); + /* + * Remove the referenve to the it's ifaddr. + */ + IFAFREE(rt->rt_ifa); + /* + * And substitute in references to the ifaddr + * we are adding. + */ + rt->rt_ifa = ifa; + rt->rt_ifp = ifa->ifa_ifp; + ifa->ifa_refcnt++; + /* + * Now add it to the routing table + * XXX could we have just left it? + * as it might have been in the right place.. + */ + if (ifa->ifa_rtrequest) + ifa->ifa_rtrequest(RTM_ADD, rt, SA(0)); + } + /* + * notify any listenning routing agents of the change + */ + rt_newaddrmsg(cmd, ifa, error, nrt); + } + return (error); +} diff --git a/c/src/exec/libnetworking/net/route.h b/c/src/exec/libnetworking/net/route.h new file mode 100644 index 0000000000..69d76909fc --- /dev/null +++ b/c/src/exec/libnetworking/net/route.h @@ -0,0 +1,284 @@ +/* + * 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.3 (Berkeley) 4/19/94 + * $Id$ + */ + +#ifndef _NET_ROUTE_H_ +#define _NET_ROUTE_H_ + +/* + * 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-bandwidth product */ + u_long rmx_sendpipe; /* outbound delay-bandwidth 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 */ + u_long rmx_filler[4]; /* will be used for T/TCP later */ +}; + +/* + * 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)) + +/* + * XXX kernel function pointer `rt_output' is visible to applications. + */ +struct mbuf; + +/* + * 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 +#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_filler; /* was short flags field */ + short rt_refcnt; /* # held references */ + u_long rt_flags; /* up/down?, host/net */ + 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 */ + int (*rt_output) __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); + /* output routine for this (rt,if) */ + struct rtentry *rt_parent; /* cloning parent of this route */ + void *rt_filler2; /* more filler */ +}; + +/* + * 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 rt_use rt_rmx.rmx_pksent + +#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 */ +/* 0x80 unused */ +#define RTF_CLONING 0x100 /* generate new routes on use */ +#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ +#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ +#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 */ + +#define RTF_PRCLONING 0x10000 /* protocol requires cloning */ +#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +#define RTF_PROTO3 0x40000 /* protocol specific routing flag */ +/* 0x80000 unused */ +#define RTF_PINNED 0x100000 /* future use */ +#define RTF_LOCAL 0x200000 /* route represents a local address */ +#define RTF_BROADCAST 0x400000 /* route represents a bcast address */ +#define RTF_MULTICAST 0x800000 /* route represents a mcast address */ + /* 0x1000000 and up unassigned */ + +/* + * 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 5 /* 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 ipx_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--; + +extern struct route_cb route_cb; +extern struct rtstat rtstat; +extern struct radix_node_head *rt_tables[AF_MAX+1]; + +void route_init __P((void)); +void rt_ifmsg __P((struct ifnet *)); +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 rtalloc __P((struct route *)); +void rtalloc_ign __P((struct route *, unsigned long)); +struct rtentry * + rtalloc1 __P((struct sockaddr *, int, unsigned long)); +void rtfree __P((struct rtentry *)); +int rtinit __P((struct ifaddr *, int, int)); +int rtioctl __P((int, caddr_t, struct proc *)); +void 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 + +#endif diff --git a/c/src/exec/libnetworking/net/rtsock.c b/c/src/exec/libnetworking/net/rtsock.c new file mode 100644 index 0000000000..2a08181000 --- /dev/null +++ b/c/src/exec/libnetworking/net/rtsock.c @@ -0,0 +1,829 @@ +/* + * 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.5 (Berkeley) 11/2/94 + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct sockaddr route_dst = { 2, PF_ROUTE, }; +static struct sockaddr route_src = { 2, PF_ROUTE, }; +static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, }; +static struct sockproto route_proto = { PF_ROUTE, }; + +struct walkarg { + int w_tmemsize; + int w_op, w_arg; + caddr_t w_tmem; + struct sysctl_req *w_req; +}; + +static struct mbuf * + rt_msg1 __P((int, struct rt_addrinfo *)); +static int rt_msg2 __P((int, + struct rt_addrinfo *, caddr_t, struct walkarg *)); +static int rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); +static int sysctl_dumpentry __P((struct radix_node *rn, void *vw)); +static int sysctl_iflist __P((int af, struct walkarg *w)); +static int route_output __P((struct mbuf *, struct socket *)); +static int route_usrreq __P((struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *)); +static void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *)); + +/* 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*/ +static 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); + so->so_pcb = (caddr_t)rp; + if (so->so_pcb) + 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_IPX) + route_cb.ipx_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_IPX) + route_cb.ipx_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*/ +static 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); + } + info.rti_addrs = rtm->rtm_addrs; + if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) { + dst = 0; + senderr(EINVAL); + } + if (dst == 0 || (dst->sa_family >= AF_MAX) + || (gate != 0 && (gate->sa_family >= AF_MAX))) + 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_rmx.rmx_locks &= ~(rtm->rtm_inits); + saved_nrt->rt_rmx.rmx_locks |= + (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); + 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) { + if ((rt = saved_nrt)) + rt->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)) { + ifp = rt->rt_ifp; + if (ifp) { + ifpaddr = ifp->if_addrlist->ifa_addr; + ifaaddr = rt->rt_ifa->ifa_addr; + 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 && (error = rt_setgate(rt, rt_key(rt), gate))) + senderr(error); + + /* + * If they tried to change things but didn't specify + * the required gateway, then just use the old one. + * This can happen if the user tries to change the + * flags on the default route without changing the + * default gateway. Changing flags still doesn't work. + */ + if ((rt->rt_flags & RTF_GATEWAY) && !gate) + gate = rt->rt_gateway; + + /* 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) && (ifaaddr || gate)) + ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate, + ifp); + else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) || + (gate && (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); +} + +static 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)) + + +/* + * Extract the addresses of the passed sockaddrs. + * Do a little sanity checking so as to avoid bad memory references. + * This data is derived straight from userland. + */ +static int +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; + sa = (struct sockaddr *)cp; + /* + * It won't fit. + */ + if ( (cp + sa->sa_len) > cplim ) { + return (EINVAL); + } + + /* + * there are no more.. quit now + * If there are more bits, they are in error. + * I've seen this. route(1) can evidently generate these. + * This causes kernel to core dump. + * for compatibility, If we see this, point to a safe address. + */ + if (sa->sa_len == 0) { + rtinfo->rti_info[i] = &sa_zero; + return (0); /* should be EINVAL but for compat */ + } + + /* accept it */ + rtinfo->rti_info[i] = sa; + ADVANCE(cp, sa); + } + return (0); +} + +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); + } + cp0 = cp; + if (cp0) + 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; + + if (rw->w_req) { + if (rw->w_tmemsize < len) { + if (rw->w_tmem) + free(rw->w_tmem, M_RTABLE); + rw->w_tmem = (caddr_t) + malloc(len, M_RTABLE, M_NOWAIT); + if (rw->w_tmem) + rw->w_tmemsize = len; + } + if (rw->w_tmem) { + cp = rw->w_tmem; + second_time = 1; + goto again; + } + } + } + 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 = (u_short)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 = 0; + int pass; + struct mbuf *m = 0; + 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, vw) + struct radix_node *rn; + void *vw; +{ + register struct walkarg *w = vw; + 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; + size = rt_msg2(RTM_GET, &info, 0, w); + if (w->w_req && 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; + error = 0; + return (error); + } + 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_req && w->w_tmem) { + register struct if_msghdr *ifm; + + ifm = (struct if_msghdr *)w->w_tmem; + ifm->ifm_index = ifp->if_index; + ifm->ifm_flags = (u_short)ifp->if_flags; + ifm->ifm_data = ifp->if_data; + ifm->ifm_addrs = info.rti_addrs; + error =0; + if (error) + return (error); + } + while ((ifa = ifa->ifa_next) != 0) { + 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_req && 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; + error = 0; + if (error) + return (error); + } + } + ifaaddr = netmask = brdaddr = 0; + } + return (0); +} + +static int +sysctl_rtsock SYSCTL_HANDLER_ARGS +{ + int *name = (int *)arg1; + u_int namelen = arg2; + register struct radix_node_head *rnh; + int i, s, error = EINVAL; + u_char af; + struct walkarg w; + + name ++; + namelen--; + if (req->newptr) + return (EPERM); + if (namelen != 3) + return (EINVAL); + af = name[0]; + Bzero(&w, sizeof(w)); + w.w_op = name[1]; + w.w_arg = name[2]; + w.w_req = req; + + 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); + return (error); +} + +SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock,""); + +/* + * Definitions of protocols supported in the ROUTE domain. + */ + +extern struct domain routedomain; /* or at least forward */ + +static struct protosw routesw[] = { +{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, + 0, route_output, raw_ctlinput, 0, + route_usrreq, + raw_init +} +}; + +struct domain routedomain = + { PF_ROUTE, "route", route_init, 0, 0, + routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; + +DOMAIN_SET(route); -- cgit v1.2.3