summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1994-05-24 10:09:53 +0000
committerrgrimes <rgrimes@FreeBSD.org>1994-05-24 10:09:53 +0000
commit8fb65ce818b3e3c6f165b583b910af24000768a5 (patch)
treeba751e4f2166aefec707c9d7401c7ff432506642 /sys/net
parenta6ce65d368e623088a4c1a29865889f431b15420 (diff)
downloadFreeBSD-src-8fb65ce818b3e3c6f165b583b910af24000768a5.zip
FreeBSD-src-8fb65ce818b3e3c6f165b583b910af24000768a5.tar.gz
BSD 4.4 Lite Kernel Sources
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bpf.c1316
-rw-r--r--sys/net/bpf.h252
-rw-r--r--sys/net/bpf_compat.h50
-rw-r--r--sys/net/bpf_filter.c548
-rw-r--r--sys/net/bpfdesc.h98
-rw-r--r--sys/net/if.c670
-rw-r--r--sys/net/if.h363
-rw-r--r--sys/net/if_arp.h85
-rw-r--r--sys/net/if_dl.h80
-rw-r--r--sys/net/if_ethersubr.c675
-rw-r--r--sys/net/if_llc.h145
-rw-r--r--sys/net/if_loop.c247
-rw-r--r--sys/net/if_sl.c839
-rw-r--r--sys/net/if_slvar.h80
-rw-r--r--sys/net/if_types.h95
-rw-r--r--sys/net/netisr.h87
-rw-r--r--sys/net/radix.c757
-rw-r--r--sys/net/radix.h153
-rw-r--r--sys/net/raw_cb.c144
-rw-r--r--sys/net/raw_cb.h69
-rw-r--r--sys/net/raw_usrreq.c306
-rw-r--r--sys/net/route.c538
-rw-r--r--sys/net/route.h261
-rw-r--r--sys/net/rtsock.c833
-rw-r--r--sys/net/slcompress.c535
-rw-r--r--sys/net/slcompress.h157
-rw-r--r--sys/net/slip.h51
27 files changed, 9434 insertions, 0 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
new file mode 100644
index 0000000..e40b769
--- /dev/null
+++ b/sys/net/bpf.c
@@ -0,0 +1,1316 @@
+/*
+ * 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.c 8.2 (Berkeley) 3/28/94
+ *
+ * static char rcsid[] =
+ * "$Header: bpf.c,v 1.33 91/10/27 21:21:58 mccanne Exp $";
+ */
+
+#include "bpfilter.h"
+
+#if NBPFILTER > 0
+
+#ifndef __GNUC__
+#define inline
+#else
+#define inline __inline
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <sys/map.h>
+
+#include <sys/file.h>
+#if defined(sparc) && BSD < 199103
+#include <sys/stream.h>
+#endif
+#include <sys/tty.h>
+#include <sys/uio.h>
+
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <sys/errno.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <sys/kernel.h>
+
+/*
+ * Older BSDs don't have kernel malloc.
+ */
+#if BSD < 199103
+extern bcopy();
+static caddr_t bpf_alloc();
+#include <net/bpf_compat.h>
+#define BPF_BUFSIZE (MCLBYTES-8)
+#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio)
+#else
+#define BPF_BUFSIZE 4096
+#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio)
+#endif
+
+#define PRINET 26 /* interruptible */
+
+/*
+ * The default read buffer size is patchable.
+ */
+int bpf_bufsize = BPF_BUFSIZE;
+
+/*
+ * bpf_iflist is the list of interfaces; each corresponds to an ifnet
+ * bpf_dtab holds the descriptors, indexed by minor device #
+ */
+struct bpf_if *bpf_iflist;
+struct bpf_d bpf_dtab[NBPFILTER];
+
+#if BSD >= 199207
+/*
+ * bpfilterattach() is called at boot time in new systems. We do
+ * nothing here since old systems will not call this.
+ */
+/* ARGSUSED */
+void
+bpfilterattach(n)
+ int n;
+{
+}
+#endif
+
+static int bpf_allocbufs __P((struct bpf_d *));
+static int bpf_allocbufs __P((struct bpf_d *));
+static void bpf_freed __P((struct bpf_d *));
+static void bpf_freed __P((struct bpf_d *));
+static void bpf_ifname __P((struct ifnet *, struct ifreq *));
+static void bpf_ifname __P((struct ifnet *, struct ifreq *));
+static void bpf_mcopy __P((const void *, void *, u_int));
+static int bpf_movein __P((struct uio *, int,
+ struct mbuf **, struct sockaddr *, int *));
+static int bpf_setif __P((struct bpf_d *, struct ifreq *));
+static int bpf_setif __P((struct bpf_d *, struct ifreq *));
+static inline void
+ bpf_wakeup __P((struct bpf_d *));
+static void catchpacket __P((struct bpf_d *, u_char *, u_int,
+ u_int, void (*)(const void *, void *, u_int)));
+static void reset_d __P((struct bpf_d *));
+
+static int
+bpf_movein(uio, linktype, mp, sockp, datlen)
+ register struct uio *uio;
+ int linktype, *datlen;
+ register struct mbuf **mp;
+ register struct sockaddr *sockp;
+{
+ struct mbuf *m;
+ int error;
+ int len;
+ int hlen;
+
+ /*
+ * Build a sockaddr based on the data link layer type.
+ * We do this at this level because the ethernet header
+ * is copied directly into the data field of the sockaddr.
+ * In the case of SLIP, there is no header and the packet
+ * is forwarded as is.
+ * Also, we are careful to leave room at the front of the mbuf
+ * for the link level header.
+ */
+ switch (linktype) {
+
+ case DLT_SLIP:
+ sockp->sa_family = AF_INET;
+ hlen = 0;
+ break;
+
+ case DLT_EN10MB:
+ sockp->sa_family = AF_UNSPEC;
+ /* XXX Would MAXLINKHDR be better? */
+ hlen = sizeof(struct ether_header);
+ break;
+
+ case DLT_FDDI:
+ sockp->sa_family = AF_UNSPEC;
+ /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */
+ hlen = 24;
+ break;
+
+ case DLT_NULL:
+ sockp->sa_family = AF_UNSPEC;
+ hlen = 0;
+ break;
+
+ default:
+ return (EIO);
+ }
+
+ len = uio->uio_resid;
+ *datlen = len - hlen;
+ if ((unsigned)len > MCLBYTES)
+ return (EIO);
+
+ MGET(m, M_WAIT, MT_DATA);
+ if (m == 0)
+ return (ENOBUFS);
+ if (len > MLEN) {
+#if BSD >= 199103
+ MCLGET(m, M_WAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+#else
+ MCLGET(m);
+ if (m->m_len != MCLBYTES) {
+#endif
+ error = ENOBUFS;
+ goto bad;
+ }
+ }
+ m->m_len = len;
+ *mp = m;
+ /*
+ * Make room for link header.
+ */
+ if (hlen != 0) {
+ m->m_len -= hlen;
+#if BSD >= 199103
+ m->m_data += hlen; /* XXX */
+#else
+ m->m_off += hlen;
+#endif
+ error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio);
+ if (error)
+ goto bad;
+ }
+ error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio);
+ if (!error)
+ return (0);
+ bad:
+ m_freem(m);
+ return (error);
+}
+
+/*
+ * Attach file to the bpf interface, i.e. make d listen on bp.
+ * Must be called at splimp.
+ */
+static void
+bpf_attachd(d, bp)
+ struct bpf_d *d;
+ struct bpf_if *bp;
+{
+ /*
+ * Point d at bp, and add d to the interface's list of listeners.
+ * Finally, point the driver's bpf cookie at the interface so
+ * it will divert packets to bpf.
+ */
+ d->bd_bif = bp;
+ d->bd_next = bp->bif_dlist;
+ bp->bif_dlist = d;
+
+ *bp->bif_driverp = bp;
+}
+
+/*
+ * Detach a file from its interface.
+ */
+static void
+bpf_detachd(d)
+ struct bpf_d *d;
+{
+ struct bpf_d **p;
+ struct bpf_if *bp;
+
+ bp = d->bd_bif;
+ /*
+ * Check if this descriptor had requested promiscuous mode.
+ * If so, turn it off.
+ */
+ if (d->bd_promisc) {
+ d->bd_promisc = 0;
+ if (ifpromisc(bp->bif_ifp, 0))
+ /*
+ * Something is really wrong if we were able to put
+ * the driver into promiscuous mode, but can't
+ * take it out.
+ */
+ panic("bpf: ifpromisc failed");
+ }
+ /* Remove d from the interface's descriptor list. */
+ p = &bp->bif_dlist;
+ while (*p != d) {
+ p = &(*p)->bd_next;
+ if (*p == 0)
+ panic("bpf_detachd: descriptor not in list");
+ }
+ *p = (*p)->bd_next;
+ if (bp->bif_dlist == 0)
+ /*
+ * Let the driver know that there are no more listeners.
+ */
+ *d->bd_bif->bif_driverp = 0;
+ d->bd_bif = 0;
+}
+
+
+/*
+ * Mark a descriptor free by making it point to itself.
+ * This is probably cheaper than marking with a constant since
+ * the address should be in a register anyway.
+ */
+#define D_ISFREE(d) ((d) == (d)->bd_next)
+#define D_MARKFREE(d) ((d)->bd_next = (d))
+#define D_MARKUSED(d) ((d)->bd_next = 0)
+
+/*
+ * Open ethernet device. Returns ENXIO for illegal minor device number,
+ * EBUSY if file is open by another process.
+ */
+/* ARGSUSED */
+int
+bpfopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct bpf_d *d;
+
+ if (minor(dev) >= NBPFILTER)
+ return (ENXIO);
+ /*
+ * Each minor can be opened by only one process. If the requested
+ * minor is in use, return EBUSY.
+ */
+ d = &bpf_dtab[minor(dev)];
+ if (!D_ISFREE(d))
+ return (EBUSY);
+
+ /* Mark "free" and do most initialization. */
+ bzero((char *)d, sizeof(*d));
+ d->bd_bufsize = bpf_bufsize;
+
+ return (0);
+}
+
+/*
+ * Close the descriptor by detaching it from its interface,
+ * deallocating its buffers, and marking it free.
+ */
+/* ARGSUSED */
+int
+bpfclose(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct bpf_d *d = &bpf_dtab[minor(dev)];
+ register int s;
+
+ s = splimp();
+ if (d->bd_bif)
+ bpf_detachd(d);
+ splx(s);
+ bpf_freed(d);
+
+ return (0);
+}
+
+/*
+ * Support for SunOS, which does not have tsleep.
+ */
+#if BSD < 199103
+static
+bpf_timeout(arg)
+ caddr_t arg;
+{
+ struct bpf_d *d = (struct bpf_d *)arg;
+ d->bd_timedout = 1;
+ wakeup(arg);
+}
+
+#define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan)
+
+int
+bpf_sleep(d)
+ register struct bpf_d *d;
+{
+ register int rto = d->bd_rtout;
+ register int st;
+
+ if (rto != 0) {
+ d->bd_timedout = 0;
+ timeout(bpf_timeout, (caddr_t)d, rto);
+ }
+ st = sleep((caddr_t)d, PRINET|PCATCH);
+ if (rto != 0) {
+ if (d->bd_timedout == 0)
+ untimeout(bpf_timeout, (caddr_t)d);
+ else if (st == 0)
+ return EWOULDBLOCK;
+ }
+ return (st != 0) ? EINTR : 0;
+}
+#else
+#define BPF_SLEEP tsleep
+#endif
+
+/*
+ * Rotate the packet buffers in descriptor d. Move the store buffer
+ * into the hold slot, and the free buffer into the store slot.
+ * Zero the length of the new store buffer.
+ */
+#define ROTATE_BUFFERS(d) \
+ (d)->bd_hbuf = (d)->bd_sbuf; \
+ (d)->bd_hlen = (d)->bd_slen; \
+ (d)->bd_sbuf = (d)->bd_fbuf; \
+ (d)->bd_slen = 0; \
+ (d)->bd_fbuf = 0;
+/*
+ * bpfread - read next chunk of packets from buffers
+ */
+int
+bpfread(dev, uio)
+ dev_t dev;
+ register struct uio *uio;
+{
+ register struct bpf_d *d = &bpf_dtab[minor(dev)];
+ int error;
+ int s;
+
+ /*
+ * Restrict application to use a buffer the same size as
+ * as kernel buffers.
+ */
+ if (uio->uio_resid != d->bd_bufsize)
+ return (EINVAL);
+
+ s = splimp();
+ /*
+ * If the hold buffer is empty, then do a timed sleep, which
+ * ends when the timeout expires or when enough packets
+ * have arrived to fill the store buffer.
+ */
+ while (d->bd_hbuf == 0) {
+ if (d->bd_immediate && d->bd_slen != 0) {
+ /*
+ * A packet(s) either arrived since the previous
+ * read or arrived while we were asleep.
+ * Rotate the buffers and return what's here.
+ */
+ ROTATE_BUFFERS(d);
+ break;
+ }
+ error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf",
+ d->bd_rtout);
+ if (error == EINTR || error == ERESTART) {
+ splx(s);
+ return (error);
+ }
+ if (error == EWOULDBLOCK) {
+ /*
+ * On a timeout, return what's in the buffer,
+ * which may be nothing. If there is something
+ * in the store buffer, we can rotate the buffers.
+ */
+ if (d->bd_hbuf)
+ /*
+ * We filled up the buffer in between
+ * getting the timeout and arriving
+ * here, so we don't need to rotate.
+ */
+ break;
+
+ if (d->bd_slen == 0) {
+ splx(s);
+ return (0);
+ }
+ ROTATE_BUFFERS(d);
+ break;
+ }
+ }
+ /*
+ * At this point, we know we have something in the hold slot.
+ */
+ splx(s);
+
+ /*
+ * Move data from hold buffer into user space.
+ * We know the entire buffer is transferred since
+ * we checked above that the read buffer is bpf_bufsize bytes.
+ */
+ error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio);
+
+ s = splimp();
+ d->bd_fbuf = d->bd_hbuf;
+ d->bd_hbuf = 0;
+ d->bd_hlen = 0;
+ splx(s);
+
+ return (error);
+}
+
+
+/*
+ * If there are processes sleeping on this descriptor, wake them up.
+ */
+static inline void
+bpf_wakeup(d)
+ register struct bpf_d *d;
+{
+ wakeup((caddr_t)d);
+#if BSD >= 199103
+ selwakeup(&d->bd_sel);
+ /* XXX */
+ d->bd_sel.si_pid = 0;
+#else
+ if (d->bd_selproc) {
+ selwakeup(d->bd_selproc, (int)d->bd_selcoll);
+ d->bd_selcoll = 0;
+ d->bd_selproc = 0;
+ }
+#endif
+}
+
+int
+bpfwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct bpf_d *d = &bpf_dtab[minor(dev)];
+ struct ifnet *ifp;
+ struct mbuf *m;
+ int error, s;
+ static struct sockaddr dst;
+ int datlen;
+
+ if (d->bd_bif == 0)
+ return (ENXIO);
+
+ ifp = d->bd_bif->bif_ifp;
+
+ if (uio->uio_resid == 0)
+ return (0);
+
+ error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen);
+ if (error)
+ return (error);
+
+ if (datlen > ifp->if_mtu)
+ return (EMSGSIZE);
+
+ s = splnet();
+#if BSD >= 199103
+ error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0);
+#else
+ error = (*ifp->if_output)(ifp, m, &dst);
+#endif
+ splx(s);
+ /*
+ * The driver frees the mbuf.
+ */
+ return (error);
+}
+
+/*
+ * Reset a descriptor by flushing its packet buffer and clearing the
+ * receive and drop counts. Should be called at splimp.
+ */
+static void
+reset_d(d)
+ struct bpf_d *d;
+{
+ if (d->bd_hbuf) {
+ /* Free the hold buffer. */
+ d->bd_fbuf = d->bd_hbuf;
+ d->bd_hbuf = 0;
+ }
+ d->bd_slen = 0;
+ d->bd_hlen = 0;
+ d->bd_rcount = 0;
+ d->bd_dcount = 0;
+}
+
+/*
+ * FIONREAD Check for read packet available.
+ * SIOCGIFADDR Get interface address - convenient hook to driver.
+ * BIOCGBLEN Get buffer len [for read()].
+ * BIOCSETF Set ethernet read filter.
+ * BIOCFLUSH Flush read packet buffer.
+ * BIOCPROMISC Put interface into promiscuous mode.
+ * BIOCGDLT Get link layer type.
+ * BIOCGETIF Get interface name.
+ * BIOCSETIF Set interface.
+ * BIOCSRTIMEOUT Set read timeout.
+ * BIOCGRTIMEOUT Get read timeout.
+ * BIOCGSTATS Get packet stats.
+ * BIOCIMMEDIATE Set immediate mode.
+ * BIOCVERSION Get filter language version.
+ */
+/* ARGSUSED */
+int
+bpfioctl(dev, cmd, addr, flag)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+{
+ register struct bpf_d *d = &bpf_dtab[minor(dev)];
+ int s, error = 0;
+
+ switch (cmd) {
+
+ default:
+ error = EINVAL;
+ break;
+
+ /*
+ * Check for read packet available.
+ */
+ case FIONREAD:
+ {
+ int n;
+
+ s = splimp();
+ n = d->bd_slen;
+ if (d->bd_hbuf)
+ n += d->bd_hlen;
+ splx(s);
+
+ *(int *)addr = n;
+ break;
+ }
+
+ case SIOCGIFADDR:
+ {
+ struct ifnet *ifp;
+
+ if (d->bd_bif == 0)
+ error = EINVAL;
+ else {
+ ifp = d->bd_bif->bif_ifp;
+ error = (*ifp->if_ioctl)(ifp, cmd, addr);
+ }
+ break;
+ }
+
+ /*
+ * Get buffer len [for read()].
+ */
+ case BIOCGBLEN:
+ *(u_int *)addr = d->bd_bufsize;
+ break;
+
+ /*
+ * Set buffer length.
+ */
+ case BIOCSBLEN:
+#if BSD < 199103
+ error = EINVAL;
+#else
+ if (d->bd_bif != 0)
+ error = EINVAL;
+ else {
+ register u_int size = *(u_int *)addr;
+
+ if (size > BPF_MAXBUFSIZE)
+ *(u_int *)addr = size = BPF_MAXBUFSIZE;
+ else if (size < BPF_MINBUFSIZE)
+ *(u_int *)addr = size = BPF_MINBUFSIZE;
+ d->bd_bufsize = size;
+ }
+#endif
+ break;
+
+ /*
+ * Set link layer read filter.
+ */
+ case BIOCSETF:
+ error = bpf_setf(d, (struct bpf_program *)addr);
+ break;
+
+ /*
+ * Flush read packet buffer.
+ */
+ case BIOCFLUSH:
+ s = splimp();
+ reset_d(d);
+ splx(s);
+ break;
+
+ /*
+ * Put interface into promiscuous mode.
+ */
+ case BIOCPROMISC:
+ if (d->bd_bif == 0) {
+ /*
+ * No interface attached yet.
+ */
+ error = EINVAL;
+ break;
+ }
+ s = splimp();
+ if (d->bd_promisc == 0) {
+ error = ifpromisc(d->bd_bif->bif_ifp, 1);
+ if (error == 0)
+ d->bd_promisc = 1;
+ }
+ splx(s);
+ break;
+
+ /*
+ * Get device parameters.
+ */
+ case BIOCGDLT:
+ if (d->bd_bif == 0)
+ error = EINVAL;
+ else
+ *(u_int *)addr = d->bd_bif->bif_dlt;
+ break;
+
+ /*
+ * Set interface name.
+ */
+ case BIOCGETIF:
+ if (d->bd_bif == 0)
+ error = EINVAL;
+ else
+ bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
+ break;
+
+ /*
+ * Set interface.
+ */
+ case BIOCSETIF:
+ error = bpf_setif(d, (struct ifreq *)addr);
+ break;
+
+ /*
+ * Set read timeout.
+ */
+ case BIOCSRTIMEOUT:
+ {
+ struct timeval *tv = (struct timeval *)addr;
+ u_long msec;
+
+ /* Compute number of milliseconds. */
+ msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
+ /* Scale milliseconds to ticks. Assume hard
+ clock has millisecond or greater resolution
+ (i.e. tick >= 1000). For 10ms hardclock,
+ tick/1000 = 10, so rtout<-msec/10. */
+ d->bd_rtout = msec / (tick / 1000);
+ break;
+ }
+
+ /*
+ * Get read timeout.
+ */
+ case BIOCGRTIMEOUT:
+ {
+ struct timeval *tv = (struct timeval *)addr;
+ u_long msec = d->bd_rtout;
+
+ msec *= tick / 1000;
+ tv->tv_sec = msec / 1000;
+ tv->tv_usec = msec % 1000;
+ break;
+ }
+
+ /*
+ * Get packet stats.
+ */
+ case BIOCGSTATS:
+ {
+ struct bpf_stat *bs = (struct bpf_stat *)addr;
+
+ bs->bs_recv = d->bd_rcount;
+ bs->bs_drop = d->bd_dcount;
+ break;
+ }
+
+ /*
+ * Set immediate mode.
+ */
+ case BIOCIMMEDIATE:
+ d->bd_immediate = *(u_int *)addr;
+ break;
+
+ case BIOCVERSION:
+ {
+ struct bpf_version *bv = (struct bpf_version *)addr;
+
+ bv->bv_major = BPF_MAJOR_VERSION;
+ bv->bv_minor = BPF_MINOR_VERSION;
+ break;
+ }
+ }
+ return (error);
+}
+
+/*
+ * Set d's packet filter program to fp. If this file already has a filter,
+ * free it and replace it. Returns EINVAL for bogus requests.
+ */
+int
+bpf_setf(d, fp)
+ struct bpf_d *d;
+ struct bpf_program *fp;
+{
+ struct bpf_insn *fcode, *old;
+ u_int flen, size;
+ int s;
+
+ old = d->bd_filter;
+ if (fp->bf_insns == 0) {
+ if (fp->bf_len != 0)
+ return (EINVAL);
+ s = splimp();
+ d->bd_filter = 0;
+ reset_d(d);
+ splx(s);
+ if (old != 0)
+ free((caddr_t)old, M_DEVBUF);
+ return (0);
+ }
+ flen = fp->bf_len;
+ if (flen > BPF_MAXINSNS)
+ return (EINVAL);
+
+ size = flen * sizeof(*fp->bf_insns);
+ fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK);
+ if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 &&
+ bpf_validate(fcode, (int)flen)) {
+ s = splimp();
+ d->bd_filter = fcode;
+ reset_d(d);
+ splx(s);
+ if (old != 0)
+ free((caddr_t)old, M_DEVBUF);
+
+ return (0);
+ }
+ free((caddr_t)fcode, M_DEVBUF);
+ return (EINVAL);
+}
+
+/*
+ * Detach a file from its current interface (if attached at all) and attach
+ * to the interface indicated by the name stored in ifr.
+ * Return an errno or 0.
+ */
+static int
+bpf_setif(d, ifr)
+ struct bpf_d *d;
+ struct ifreq *ifr;
+{
+ struct bpf_if *bp;
+ char *cp;
+ int unit, s, error;
+
+ /*
+ * Separate string into name part and unit number. Put a null
+ * byte at the end of the name part, and compute the number.
+ * If the a unit number is unspecified, the default is 0,
+ * as initialized above. XXX This should be common code.
+ */
+ unit = 0;
+ cp = ifr->ifr_name;
+ cp[sizeof(ifr->ifr_name) - 1] = '\0';
+ while (*cp++) {
+ if (*cp >= '0' && *cp <= '9') {
+ unit = *cp - '0';
+ *cp++ = '\0';
+ while (*cp)
+ unit = 10 * unit + *cp++ - '0';
+ break;
+ }
+ }
+ /*
+ * Look through attached interfaces for the named one.
+ */
+ for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) {
+ struct ifnet *ifp = bp->bif_ifp;
+
+ if (ifp == 0 || unit != ifp->if_unit
+ || strcmp(ifp->if_name, ifr->ifr_name) != 0)
+ continue;
+ /*
+ * We found the requested interface.
+ * If it's not up, return an error.
+ * Allocate the packet buffers if we need to.
+ * If we're already attached to requested interface,
+ * just flush the buffer.
+ */
+ if ((ifp->if_flags & IFF_UP) == 0)
+ return (ENETDOWN);
+
+ if (d->bd_sbuf == 0) {
+ error = bpf_allocbufs(d);
+ if (error != 0)
+ return (error);
+ }
+ s = splimp();
+ if (bp != d->bd_bif) {
+ if (d->bd_bif)
+ /*
+ * Detach if attached to something else.
+ */
+ bpf_detachd(d);
+
+ bpf_attachd(d, bp);
+ }
+ reset_d(d);
+ splx(s);
+ return (0);
+ }
+ /* Not found. */
+ return (ENXIO);
+}
+
+/*
+ * Convert an interface name plus unit number of an ifp to a single
+ * name which is returned in the ifr.
+ */
+static void
+bpf_ifname(ifp, ifr)
+ struct ifnet *ifp;
+ struct ifreq *ifr;
+{
+ char *s = ifp->if_name;
+ char *d = ifr->ifr_name;
+
+ while (*d++ = *s++)
+ continue;
+ /* XXX Assume that unit number is less than 10. */
+ *d++ = ifp->if_unit + '0';
+ *d = '\0';
+}
+
+/*
+ * The new select interface passes down the proc pointer; the old select
+ * stubs had to grab it out of the user struct. This glue allows either case.
+ */
+#if BSD >= 199103
+#define bpf_select bpfselect
+#else
+int
+bpfselect(dev, rw)
+ register dev_t dev;
+ int rw;
+{
+ return (bpf_select(dev, rw, u.u_procp));
+}
+#endif
+
+/*
+ * Support for select() system call
+ *
+ * Return true iff the specific operation will not block indefinitely.
+ * Otherwise, return false but make a note that a selwakeup() must be done.
+ */
+int
+bpf_select(dev, rw, p)
+ register dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct bpf_d *d;
+ register int s;
+
+ if (rw != FREAD)
+ return (0);
+ /*
+ * An imitation of the FIONREAD ioctl code.
+ */
+ d = &bpf_dtab[minor(dev)];
+
+ s = splimp();
+ if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) {
+ /*
+ * There is data waiting.
+ */
+ splx(s);
+ return (1);
+ }
+#if BSD >= 199103
+ selrecord(p, &d->bd_sel);
+#else
+ /*
+ * No data ready. If there's already a select() waiting on this
+ * minor device then this is a collision. This shouldn't happen
+ * because minors really should not be shared, but if a process
+ * forks while one of these is open, it is possible that both
+ * processes could select on the same descriptor.
+ */
+ if (d->bd_selproc && d->bd_selproc->p_wchan == (caddr_t)&selwait)
+ d->bd_selcoll = 1;
+ else
+ d->bd_selproc = p;
+#endif
+ splx(s);
+ return (0);
+}
+
+/*
+ * Incoming linkage from device drivers. Process the packet pkt, of length
+ * pktlen, which is stored in a contiguous buffer. The packet is parsed
+ * by each process' filter, and if accepted, stashed into the corresponding
+ * buffer.
+ */
+void
+bpf_tap(arg, pkt, pktlen)
+ caddr_t arg;
+ register u_char *pkt;
+ register u_int pktlen;
+{
+ struct bpf_if *bp;
+ register struct bpf_d *d;
+ register u_int slen;
+ /*
+ * Note that the ipl does not have to be raised at this point.
+ * The only problem that could arise here is that if two different
+ * interfaces shared any data. This is not the case.
+ */
+ bp = (struct bpf_if *)arg;
+ for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
+ ++d->bd_rcount;
+ slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen);
+ if (slen != 0)
+ catchpacket(d, pkt, pktlen, slen, bcopy);
+ }
+}
+
+/*
+ * Copy data from an mbuf chain into a buffer. This code is derived
+ * from m_copydata in sys/uipc_mbuf.c.
+ */
+static void
+bpf_mcopy(src_arg, dst_arg, len)
+ const void *src_arg;
+ void *dst_arg;
+ register u_int len;
+{
+ register const struct mbuf *m;
+ register u_int count;
+ u_char *dst;
+
+ m = src_arg;
+ dst = dst_arg;
+ while (len > 0) {
+ if (m == 0)
+ panic("bpf_mcopy");
+ count = min(m->m_len, len);
+ bcopy(mtod(m, caddr_t), (caddr_t)dst, count);
+ m = m->m_next;
+ dst += count;
+ len -= count;
+ }
+}
+
+/*
+ * Incoming linkage from device drivers, when packet is in an mbuf chain.
+ */
+void
+bpf_mtap(arg, m)
+ caddr_t arg;
+ struct mbuf *m;
+{
+ struct bpf_if *bp = (struct bpf_if *)arg;
+ struct bpf_d *d;
+ u_int pktlen, slen;
+ struct mbuf *m0;
+
+ pktlen = 0;
+ for (m0 = m; m0 != 0; m0 = m0->m_next)
+ pktlen += m0->m_len;
+
+ for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
+ ++d->bd_rcount;
+ slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0);
+ if (slen != 0)
+ catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy);
+ }
+}
+
+/*
+ * Move the packet data from interface memory (pkt) into the
+ * store buffer. Return 1 if it's time to wakeup a listener (buffer full),
+ * otherwise 0. "copy" is the routine called to do the actual data
+ * transfer. bcopy is passed in to copy contiguous chunks, while
+ * bpf_mcopy is passed in to copy mbuf chains. In the latter case,
+ * pkt is really an mbuf.
+ */
+static void
+catchpacket(d, pkt, pktlen, snaplen, cpfn)
+ register struct bpf_d *d;
+ register u_char *pkt;
+ register u_int pktlen, snaplen;
+ register void (*cpfn)(const void *, void *, u_int);
+{
+ register struct bpf_hdr *hp;
+ register int totlen, curlen;
+ register int hdrlen = d->bd_bif->bif_hdrlen;
+ /*
+ * Figure out how many bytes to move. If the packet is
+ * greater or equal to the snapshot length, transfer that
+ * much. Otherwise, transfer the whole packet (unless
+ * we hit the buffer size limit).
+ */
+ totlen = hdrlen + min(snaplen, pktlen);
+ if (totlen > d->bd_bufsize)
+ totlen = d->bd_bufsize;
+
+ /*
+ * Round up the end of the previous packet to the next longword.
+ */
+ curlen = BPF_WORDALIGN(d->bd_slen);
+ if (curlen + totlen > d->bd_bufsize) {
+ /*
+ * This packet will overflow the storage buffer.
+ * Rotate the buffers if we can, then wakeup any
+ * pending reads.
+ */
+ if (d->bd_fbuf == 0) {
+ /*
+ * We haven't completed the previous read yet,
+ * so drop the packet.
+ */
+ ++d->bd_dcount;
+ return;
+ }
+ ROTATE_BUFFERS(d);
+ bpf_wakeup(d);
+ curlen = 0;
+ }
+ else if (d->bd_immediate)
+ /*
+ * Immediate mode is set. A packet arrived so any
+ * reads should be woken up.
+ */
+ bpf_wakeup(d);
+
+ /*
+ * Append the bpf header.
+ */
+ hp = (struct bpf_hdr *)(d->bd_sbuf + curlen);
+#if BSD >= 199103
+ microtime(&hp->bh_tstamp);
+#elif defined(sun)
+ uniqtime(&hp->bh_tstamp);
+#else
+ hp->bh_tstamp = time;
+#endif
+ hp->bh_datalen = pktlen;
+ hp->bh_hdrlen = hdrlen;
+ /*
+ * Copy the packet data into the store buffer and update its length.
+ */
+ (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen));
+ d->bd_slen = curlen + totlen;
+}
+
+/*
+ * Initialize all nonzero fields of a descriptor.
+ */
+static int
+bpf_allocbufs(d)
+ register struct bpf_d *d;
+{
+ d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK);
+ if (d->bd_fbuf == 0)
+ return (ENOBUFS);
+
+ d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK);
+ if (d->bd_sbuf == 0) {
+ free(d->bd_fbuf, M_DEVBUF);
+ return (ENOBUFS);
+ }
+ d->bd_slen = 0;
+ d->bd_hlen = 0;
+ return (0);
+}
+
+/*
+ * Free buffers currently in use by a descriptor.
+ * Called on close.
+ */
+static void
+bpf_freed(d)
+ register struct bpf_d *d;
+{
+ /*
+ * We don't need to lock out interrupts since this descriptor has
+ * been detached from its interface and it yet hasn't been marked
+ * free.
+ */
+ if (d->bd_sbuf != 0) {
+ free(d->bd_sbuf, M_DEVBUF);
+ if (d->bd_hbuf != 0)
+ free(d->bd_hbuf, M_DEVBUF);
+ if (d->bd_fbuf != 0)
+ free(d->bd_fbuf, M_DEVBUF);
+ }
+ if (d->bd_filter)
+ free((caddr_t)d->bd_filter, M_DEVBUF);
+
+ D_MARKFREE(d);
+}
+
+/*
+ * Attach an interface to bpf. driverp is a pointer to a (struct bpf_if *)
+ * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
+ * size of the link header (variable length headers not yet supported).
+ */
+void
+bpfattach(driverp, ifp, dlt, hdrlen)
+ caddr_t *driverp;
+ struct ifnet *ifp;
+ u_int dlt, hdrlen;
+{
+ struct bpf_if *bp;
+ int i;
+#if BSD < 199103
+ static struct bpf_if bpf_ifs[NBPFILTER];
+ static int bpfifno;
+
+ bp = (bpfifno < NBPFILTER) ? &bpf_ifs[bpfifno++] : 0;
+#else
+ bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT);
+#endif
+ if (bp == 0)
+ panic("bpfattach");
+
+ bp->bif_dlist = 0;
+ bp->bif_driverp = (struct bpf_if **)driverp;
+ bp->bif_ifp = ifp;
+ bp->bif_dlt = dlt;
+
+ bp->bif_next = bpf_iflist;
+ bpf_iflist = bp;
+
+ *bp->bif_driverp = 0;
+
+ /*
+ * Compute the length of the bpf header. This is not necessarily
+ * equal to SIZEOF_BPF_HDR because we want to insert spacing such
+ * that the network layer header begins on a longword boundary (for
+ * performance reasons and to alleviate alignment restrictions).
+ */
+ bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
+
+ /*
+ * Mark all the descriptors free if this hasn't been done.
+ */
+ if (!D_ISFREE(&bpf_dtab[0]))
+ for (i = 0; i < NBPFILTER; ++i)
+ D_MARKFREE(&bpf_dtab[i]);
+
+ printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit);
+}
+
+#if BSD >= 199103
+/* XXX This routine belongs in net/if.c. */
+/*
+ * 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 the device is not configured up, we cannot put it in
+ * promiscuous mode.
+ */
+ if ((ifp->if_flags & IFF_UP) == 0)
+ return (ENETDOWN);
+
+ if (pswitch) {
+ if (ifp->if_pcount++ != 0)
+ return (0);
+ ifp->if_flags |= IFF_PROMISC;
+ } 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));
+}
+#endif
+
+#if BSD < 199103
+/*
+ * Allocate some memory for bpf. This is temporary SunOS support, and
+ * is admittedly a hack.
+ * If resources unavaiable, return 0.
+ */
+static caddr_t
+bpf_alloc(size, canwait)
+ register int size;
+ register int canwait;
+{
+ register struct mbuf *m;
+
+ if ((unsigned)size > (MCLBYTES-8))
+ return 0;
+
+ MGET(m, canwait, MT_DATA);
+ if (m == 0)
+ return 0;
+ if ((unsigned)size > (MLEN-8)) {
+ MCLGET(m);
+ if (m->m_len != MCLBYTES) {
+ m_freem(m);
+ return 0;
+ }
+ }
+ *mtod(m, struct mbuf **) = m;
+ return mtod(m, caddr_t) + 8;
+}
+#endif
+#endif
diff --git a/sys/net/bpf.h b/sys/net/bpf.h
new file mode 100644
index 0000000..2e093ac
--- /dev/null
+++ b/sys/net/bpf.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 1990, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 8.1 (Berkeley) 6/10/93
+ *
+ * @(#) $Header: bpf.h,v 1.24 91/10/27 21:22:32 mccanne Exp $ (LBL)
+ */
+
+/*
+ * Alignment macros. BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ */
+#define BPF_ALIGNMENT sizeof(long)
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXINSNS 512
+#define BPF_MAXBUFSIZE 0x8000
+#define BPF_MINBUFSIZE 32
+
+/*
+ * Structure for BIOCSETF.
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+/*
+ * Struct returned by BIOCGSTATS.
+ */
+struct bpf_stat {
+ u_int bs_recv; /* number of packets received */
+ u_int bs_drop; /* number of packets dropped */
+};
+
+/*
+ * Struct return by BIOCVERSION. This represents the version number of
+ * the filter language described by the instruction encodings below.
+ * bpf understands a program iff kernel_major == filter_major &&
+ * kernel_minor >= filter_minor, that is, if the value returned by the
+ * running kernel has the same major number and a minor number equal
+ * equal to or less than the filter being downloaded. Otherwise, the
+ * results are undefined, meaning an error may be returned or packets
+ * may be accepted haphazardly.
+ * It has nothing to do with the source code version.
+ */
+struct bpf_version {
+ u_short bv_major;
+ u_short bv_minor;
+};
+/* Current version number. */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ * BPF ioctls
+ *
+ * The first set is for compatibility with Sun's pcc style
+ * header files. If your using gcc, we assume that you
+ * have run fixincludes so the latter set should work.
+ */
+#if (defined(sun) || defined(ibm032)) && !defined(__GNUC__)
+#define BIOCGBLEN _IOR(B,102, u_int)
+#define BIOCSBLEN _IOWR(B,102, u_int)
+#define BIOCSETF _IOW(B,103, struct bpf_program)
+#define BIOCFLUSH _IO(B,104)
+#define BIOCPROMISC _IO(B,105)
+#define BIOCGDLT _IOR(B,106, u_int)
+#define BIOCGETIF _IOR(B,107, struct ifreq)
+#define BIOCSETIF _IOW(B,108, struct ifreq)
+#define BIOCSRTIMEOUT _IOW(B,109, struct timeval)
+#define BIOCGRTIMEOUT _IOR(B,110, struct timeval)
+#define BIOCGSTATS _IOR(B,111, struct bpf_stat)
+#define BIOCIMMEDIATE _IOW(B,112, u_int)
+#define BIOCVERSION _IOR(B,113, struct bpf_version)
+#else
+#define BIOCGBLEN _IOR('B',102, u_int)
+#define BIOCSBLEN _IOWR('B',102, u_int)
+#define BIOCSETF _IOW('B',103, struct bpf_program)
+#define BIOCFLUSH _IO('B',104)
+#define BIOCPROMISC _IO('B',105)
+#define BIOCGDLT _IOR('B',106, u_int)
+#define BIOCGETIF _IOR('B',107, struct ifreq)
+#define BIOCSETIF _IOW('B',108, struct ifreq)
+#define BIOCSRTIMEOUT _IOW('B',109, struct timeval)
+#define BIOCGRTIMEOUT _IOR('B',110, struct timeval)
+#define BIOCGSTATS _IOR('B',111, struct bpf_stat)
+#define BIOCIMMEDIATE _IOW('B',112, u_int)
+#define BIOCVERSION _IOR('B',113, struct bpf_version)
+#endif
+
+/*
+ * Structure prepended to each packet.
+ */
+struct bpf_hdr {
+ struct timeval bh_tstamp; /* time stamp */
+ u_long bh_caplen; /* length of captured portion */
+ u_long bh_datalen; /* original length of packet */
+ u_short bh_hdrlen; /* length of bpf header (this struct
+ plus alignment padding) */
+};
+/*
+ * Because the structure above is not a multiple of 4 bytes, some compilers
+ * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
+ * Only the kernel needs to know about it; applications use bh_hdrlen.
+ */
+#ifdef KERNEL
+#define SIZEOF_BPF_HDR 18
+#endif
+
+/*
+ * Data-link level type codes.
+ * Currently, only DLT_EN10MB and DLT_SLIP are supported.
+ */
+#define DLT_NULL 0 /* no link-layer encapsulation */
+#define DLT_EN10MB 1 /* Ethernet (10Mb) */
+#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
+#define DLT_AX25 3 /* Amateur Radio AX.25 */
+#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
+#define DLT_CHAOS 5 /* Chaos */
+#define DLT_IEEE802 6 /* IEEE 802 Networks */
+#define DLT_ARCNET 7 /* ARCNET */
+#define DLT_SLIP 8 /* Serial Line IP */
+#define DLT_PPP 9 /* Point-to-point Protocol */
+#define DLT_FDDI 10 /* FDDI */
+
+/*
+ * The instruction encondings.
+ */
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+#define BPF_TXA 0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+ u_short code;
+ u_char jt;
+ u_char jf;
+ long k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#ifdef KERNEL
+int bpf_validate __P((struct bpf_insn *, int));
+int bpfopen __P((dev_t, int));
+int bpfclose __P((dev_t, int));
+int bpfread __P((dev_t, struct uio *));
+int bpfwrite __P((dev_t, struct uio *));
+int bpfioctl __P((dev_t, int, caddr_t, int));
+int bpf_select __P((dev_t, int, struct proc *));
+void bpf_tap __P((caddr_t, u_char *, u_int));
+void bpf_mtap __P((caddr_t, struct mbuf *));
+void bpfattach __P((caddr_t *, struct ifnet *, u_int, u_int));
+void bpfilterattach __P((int));
+u_int bpf_filter __P((struct bpf_insn *, u_char *, u_int, u_int));
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
diff --git a/sys/net/bpf_compat.h b/sys/net/bpf_compat.h
new file mode 100644
index 0000000..132a6df
--- /dev/null
+++ b/sys/net/bpf_compat.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf_compat.h 8.1 (Berkeley) 6/10/93
+ */
+
+/* from: $Header: bpf_compat.h,v 1.1 92/05/22 15:33:20 mccanne Exp $ (LBL) */
+
+/*
+ * Some hacks for compatibility across SunOS and 4.4BSD. We emulate malloc
+ * and free with mbuf clusters. We store a pointer to the mbuf in the first
+ * word of the mbuf and return 8 bytes passed the start of data (for double
+ * word alignment). We cannot just use offsets because clusters are not at
+ * a fixed offset from the associated mbuf. Sorry for this kludge.
+ */
+#define malloc(size, type, canwait) bpf_alloc(size, canwait)
+#define free(cp, type) m_free(*(struct mbuf **)(cp - 8))
+#define M_WAITOK M_WAIT
+
+/* This mapping works for our purposes. */
+#define ERESTART EINTR
diff --git a/sys/net/bpf_filter.c b/sys/net/bpf_filter.c
new file mode 100644
index 0000000..6a30a66
--- /dev/null
+++ b/sys/net/bpf_filter.c
@@ -0,0 +1,548 @@
+/*
+ * 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_filter.c 8.1 (Berkeley) 6/10/93
+ *
+ * static char rcsid[] =
+ * "$Header: bpf_filter.c,v 1.16 91/10/27 21:22:35 mccanne Exp $";
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef sun
+#include <netinet/in.h>
+#endif
+
+#if defined(sparc) || defined(mips) || defined(ibm032)
+#define BPF_ALIGN
+#endif
+
+#ifndef BPF_ALIGN
+#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p) (ntohl(*(u_long *)p))
+#else
+#define EXTRACT_SHORT(p)\
+ ((u_short)\
+ ((u_short)*((u_char *)p+0)<<8|\
+ (u_short)*((u_char *)p+1)<<0))
+#define EXTRACT_LONG(p)\
+ ((u_long)*((u_char *)p+0)<<24|\
+ (u_long)*((u_char *)p+1)<<16|\
+ (u_long)*((u_char *)p+2)<<8|\
+ (u_long)*((u_char *)p+3)<<0)
+#endif
+
+#ifdef KERNEL
+#include <sys/mbuf.h>
+#define MINDEX(m, k) \
+{ \
+ register int len = m->m_len; \
+ \
+ while (k >= len) { \
+ k -= len; \
+ m = m->m_next; \
+ if (m == 0) \
+ return 0; \
+ len = m->m_len; \
+ } \
+}
+
+static int
+m_xword(m, k, err)
+ register struct mbuf *m;
+ register int k, *err;
+{
+ register int len;
+ register u_char *cp, *np;
+ register struct mbuf *m0;
+
+ len = m->m_len;
+ while (k >= len) {
+ k -= len;
+ m = m->m_next;
+ if (m == 0)
+ goto bad;
+ len = m->m_len;
+ }
+ cp = mtod(m, u_char *) + k;
+ if (len - k >= 4) {
+ *err = 0;
+ return EXTRACT_LONG(cp);
+ }
+ m0 = m->m_next;
+ if (m0 == 0 || m0->m_len + len - k < 4)
+ goto bad;
+ *err = 0;
+ np = mtod(m0, u_char *);
+ switch (len - k) {
+
+ case 1:
+ return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
+
+ case 2:
+ return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) |
+ np[1];
+
+ default:
+ return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
+ np[0];
+ }
+ bad:
+ *err = 1;
+ return 0;
+}
+
+static int
+m_xhalf(m, k, err)
+ register struct mbuf *m;
+ register int k, *err;
+{
+ register int len;
+ register u_char *cp;
+ register struct mbuf *m0;
+
+ len = m->m_len;
+ while (k >= len) {
+ k -= len;
+ m = m->m_next;
+ if (m == 0)
+ goto bad;
+ len = m->m_len;
+ }
+ cp = mtod(m, u_char *) + k;
+ if (len - k >= 2) {
+ *err = 0;
+ return EXTRACT_SHORT(cp);
+ }
+ m0 = m->m_next;
+ if (m0 == 0)
+ goto bad;
+ *err = 0;
+ return (cp[k] << 8) | mtod(m0, u_char *)[0];
+ bad:
+ *err = 1;
+ return 0;
+}
+#endif
+
+#include <net/bpf.h>
+/*
+ * Execute the filter program starting at pc on the packet p
+ * wirelen is the length of the original packet
+ * buflen is the amount of data present
+ */
+u_int
+bpf_filter(pc, p, wirelen, buflen)
+ register struct bpf_insn *pc;
+ register u_char *p;
+ u_int wirelen;
+ register u_int buflen;
+{
+ register u_long A, X;
+ register int k;
+ long mem[BPF_MEMWORDS];
+
+ if (pc == 0)
+ /*
+ * No filter means accept all.
+ */
+ return (u_int)-1;
+#ifdef lint
+ A = 0;
+ X = 0;
+#endif
+ --pc;
+ while (1) {
+ ++pc;
+ switch (pc->code) {
+
+ default:
+#ifdef KERNEL
+ return 0;
+#else
+ abort();
+#endif
+ case BPF_RET|BPF_K:
+ return (u_int)pc->k;
+
+ case BPF_RET|BPF_A:
+ return (u_int)A;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ k = pc->k;
+ if (k + sizeof(long) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xword((struct mbuf *)p, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+#else
+ return 0;
+#endif
+ }
+#ifdef BPF_ALIGN
+ if (((int)(p + k) & 3) != 0)
+ A = EXTRACT_LONG(&p[k]);
+ else
+#endif
+ A = ntohl(*(long *)(p + k));
+ continue;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ k = pc->k;
+ if (k + sizeof(short) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xhalf((struct mbuf *)p, k, &merr);
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ k = pc->k;
+ if (k >= buflen) {
+#ifdef KERNEL
+ register struct mbuf *m;
+
+ if (buflen != 0)
+ return 0;
+ m = (struct mbuf *)p;
+ MINDEX(m, k);
+ A = mtod(m, u_char *)[k];
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ A = wirelen;
+ continue;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+ X = wirelen;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ k = X + pc->k;
+ if (k + sizeof(long) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xword((struct mbuf *)p, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+#else
+ return 0;
+#endif
+ }
+#ifdef BPF_ALIGN
+ if (((int)(p + k) & 3) != 0)
+ A = EXTRACT_LONG(&p[k]);
+ else
+#endif
+ A = ntohl(*(long *)(p + k));
+ continue;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ k = X + pc->k;
+ if (k + sizeof(short) > buflen) {
+#ifdef KERNEL
+ int merr;
+
+ if (buflen != 0)
+ return 0;
+ A = m_xhalf((struct mbuf *)p, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ k = X + pc->k;
+ if (k >= buflen) {
+#ifdef KERNEL
+ register struct mbuf *m;
+
+ if (buflen != 0)
+ return 0;
+ m = (struct mbuf *)p;
+ MINDEX(m, k);
+ A = mtod(m, char *)[k];
+ continue;
+#else
+ return 0;
+#endif
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ k = pc->k;
+ if (k >= buflen) {
+#ifdef KERNEL
+ register struct mbuf *m;
+
+ if (buflen != 0)
+ return 0;
+ m = (struct mbuf *)p;
+ MINDEX(m, k);
+ X = (mtod(m, char *)[k] & 0xf) << 2;
+ continue;
+#else
+ return 0;
+#endif
+ }
+ X = (p[pc->k] & 0xf) << 2;
+ continue;
+
+ case BPF_LD|BPF_IMM:
+ A = pc->k;
+ continue;
+
+ case BPF_LDX|BPF_IMM:
+ X = pc->k;
+ continue;
+
+ case BPF_LD|BPF_MEM:
+ A = mem[pc->k];
+ continue;
+
+ case BPF_LDX|BPF_MEM:
+ X = mem[pc->k];
+ continue;
+
+ case BPF_ST:
+ mem[pc->k] = A;
+ continue;
+
+ case BPF_STX:
+ mem[pc->k] = X;
+ continue;
+
+ case BPF_JMP|BPF_JA:
+ pc += pc->k;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ pc += (A > pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ pc += (A >= pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ pc += (A == pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ pc += (A & pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ pc += (A > X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ pc += (A >= X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ pc += (A == X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ pc += (A & X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ A += X;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ A -= X;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ A *= X;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ if (X == 0)
+ return 0;
+ A /= X;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ A &= X;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ A |= X;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ A <<= X;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ A >>= X;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ A += pc->k;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ A -= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ A *= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ A /= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ A &= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ A |= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ A <<= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ A >>= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_NEG:
+ A = -A;
+ continue;
+
+ case BPF_MISC|BPF_TAX:
+ X = A;
+ continue;
+
+ case BPF_MISC|BPF_TXA:
+ A = X;
+ continue;
+ }
+ }
+}
+
+#ifdef KERNEL
+/*
+ * Return true if the 'fcode' is a valid filter program.
+ * The constraints are that each jump be forward and to a valid
+ * code. The code must terminate with either an accept or reject.
+ * 'valid' is an array for use by the routine (it must be at least
+ * 'len' bytes long).
+ *
+ * The kernel needs to be able to verify an application's filter code.
+ * Otherwise, a bogus program could easily crash the system.
+ */
+int
+bpf_validate(f, len)
+ struct bpf_insn *f;
+ int len;
+{
+ register int i;
+ register struct bpf_insn *p;
+
+ for (i = 0; i < len; ++i) {
+ /*
+ * Check that that jumps are forward, and within
+ * the code block.
+ */
+ p = &f[i];
+ if (BPF_CLASS(p->code) == BPF_JMP) {
+ register int from = i + 1;
+
+ if (BPF_OP(p->code) == BPF_JA) {
+ if (from + p->k >= len)
+ return 0;
+ }
+ else if (from + p->jt >= len || from + p->jf >= len)
+ return 0;
+ }
+ /*
+ * Check that memory operations use valid addresses.
+ */
+ if ((BPF_CLASS(p->code) == BPF_ST ||
+ (BPF_CLASS(p->code) == BPF_LD &&
+ (p->code & 0xe0) == BPF_MEM)) &&
+ (p->k >= BPF_MEMWORDS || p->k < 0))
+ return 0;
+ /*
+ * Check for constant division by 0.
+ */
+ if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
+ return 0;
+ }
+ return BPF_CLASS(f[len - 1].code) == BPF_RET;
+}
+#endif
diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h
new file mode 100644
index 0000000..a13320e
--- /dev/null
+++ b/sys/net/bpfdesc.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ * @(#)bpfdesc.h 8.1 (Berkeley) 6/10/93
+ *
+ * @(#) $Header: bpfdesc.h,v 1.9 91/10/27 21:22:38 mccanne Exp $ (LBL)
+ */
+
+/*
+ * Descriptor associated with each open bpf file.
+ */
+struct bpf_d {
+ struct bpf_d *bd_next; /* Linked list of descriptors */
+ /*
+ * Buffer slots: two mbuf clusters buffer the incoming packets.
+ * The model has three slots. Sbuf is always occupied.
+ * sbuf (store) - Receive interrupt puts packets here.
+ * hbuf (hold) - When sbuf is full, put cluster here and
+ * wakeup read (replace sbuf with fbuf).
+ * fbuf (free) - When read is done, put cluster here.
+ * On receiving, if sbuf is full and fbuf is 0, packet is dropped.
+ */
+ caddr_t bd_sbuf; /* store slot */
+ caddr_t bd_hbuf; /* hold slot */
+ caddr_t bd_fbuf; /* free slot */
+ int bd_slen; /* current length of store buffer */
+ int bd_hlen; /* current length of hold buffer */
+
+ int bd_bufsize; /* absolute length of buffers */
+
+ struct bpf_if * bd_bif; /* interface descriptor */
+ u_long bd_rtout; /* Read timeout in 'ticks' */
+ struct bpf_insn *bd_filter; /* filter code */
+ u_long bd_rcount; /* number of packets received */
+ u_long bd_dcount; /* number of packets dropped */
+
+ u_char bd_promisc; /* true if listening promiscuously */
+ u_char bd_state; /* idle, waiting, or timed out */
+ u_char bd_immediate; /* true to return on packet arrival */
+#if BSD < 199103
+ u_char bd_selcoll; /* true if selects collide */
+ int bd_timedout;
+ struct proc * bd_selproc; /* process that last selected us */
+#else
+ u_char bd_pad; /* explicit alignment */
+ struct selinfo bd_sel; /* bsd select info */
+#endif
+};
+
+/*
+ * Descriptor associated with each attached hardware interface.
+ */
+struct bpf_if {
+ struct bpf_if *bif_next; /* list of all interfaces */
+ struct bpf_d *bif_dlist; /* descriptor list */
+ struct bpf_if **bif_driverp; /* pointer into softc */
+ u_int bif_dlt; /* link layer type */
+ u_int bif_hdrlen; /* length of header (with padding) */
+ struct ifnet *bif_ifp; /* correspoding interface */
+};
+
+#ifdef KERNEL
+int bpf_setf __P((struct bpf_d *, struct bpf_program *));
+#endif
diff --git a/sys/net/if.c b/sys/net/if.c
new file mode 100644
index 0000000..3696388
--- /dev/null
+++ b/sys/net/if.c
@@ -0,0 +1,670 @@
+/*
+ * 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
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+int ifqmaxlen = IFQ_MAXLEN;
+void if_slowtimo __P((void *arg));
+
+/*
+ * Network interface utility routines.
+ *
+ * Routines with ifa_ifwith* names take sockaddr *'s as
+ * parameters.
+ */
+void
+ifinit()
+{
+ register struct ifnet *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ if_slowtimo(0);
+}
+
+#ifdef vax
+/*
+ * Call each interface on a Unibus reset.
+ */
+void
+ifubareset(uban)
+ int uban;
+{
+ register struct ifnet *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (ifp->if_reset)
+ (*ifp->if_reset)(ifp->if_unit, uban);
+}
+#endif
+
+int if_index = 0;
+struct ifaddr **ifnet_addrs;
+static char *sprint_d __P((u_int, char *, int));
+
+/*
+ * Attach an interface to the
+ * list of "active" interfaces.
+ */
+void
+if_attach(ifp)
+ struct ifnet *ifp;
+{
+ unsigned socksize, ifasize;
+ int namelen, unitlen, masklen, ether_output();
+ char workbuf[12], *unitname;
+ register struct ifnet **p = &ifnet;
+ register struct sockaddr_dl *sdl;
+ register struct ifaddr *ifa;
+ static int if_indexlim = 8;
+ extern void link_rtrequest();
+
+ while (*p)
+ p = &((*p)->if_next);
+ *p = ifp;
+ ifp->if_index = ++if_index;
+ if (ifnet_addrs == 0 || if_index >= if_indexlim) {
+ unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
+ struct ifaddr **q = (struct ifaddr **)
+ malloc(n, M_IFADDR, M_WAITOK);
+ if (ifnet_addrs) {
+ bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
+ free((caddr_t)ifnet_addrs, M_IFADDR);
+ }
+ ifnet_addrs = q;
+ }
+ /*
+ * create a Link Level name for this device
+ */
+ unitname = sprint_d((u_int)ifp->if_unit, workbuf, sizeof(workbuf));
+ namelen = strlen(ifp->if_name);
+ unitlen = strlen(unitname);
+#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
+ masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) +
+ unitlen + namelen;
+ socksize = masklen + ifp->if_addrlen;
+#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
+ socksize = ROUNDUP(socksize);
+ if (socksize < sizeof(*sdl))
+ socksize = sizeof(*sdl);
+ ifasize = sizeof(*ifa) + 2 * socksize;
+ if (ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK)) {
+ bzero((caddr_t)ifa, ifasize);
+ sdl = (struct sockaddr_dl *)(ifa + 1);
+ sdl->sdl_len = socksize;
+ sdl->sdl_family = AF_LINK;
+ bcopy(ifp->if_name, sdl->sdl_data, namelen);
+ bcopy(unitname, namelen + (caddr_t)sdl->sdl_data, unitlen);
+ sdl->sdl_nlen = (namelen += unitlen);
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = ifp->if_type;
+ ifnet_addrs[if_index - 1] = ifa;
+ ifa->ifa_ifp = ifp;
+ ifa->ifa_next = ifp->if_addrlist;
+ ifa->ifa_rtrequest = link_rtrequest;
+ ifp->if_addrlist = ifa;
+ ifa->ifa_addr = (struct sockaddr *)sdl;
+ sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
+ ifa->ifa_netmask = (struct sockaddr *)sdl;
+ sdl->sdl_len = masklen;
+ while (namelen != 0)
+ sdl->sdl_data[--namelen] = 0xff;
+ }
+ /* XXX -- Temporary fix before changing 10 ethernet drivers */
+ if (ifp->if_output == ether_output)
+ ether_ifattach(ifp);
+}
+/*
+ * Locate an interface based on a complete address.
+ */
+/*ARGSUSED*/
+struct ifaddr *
+ifa_ifwithaddr(addr)
+ register struct sockaddr *addr;
+{
+ register struct ifnet *ifp;
+ register struct ifaddr *ifa;
+
+#define equal(a1, a2) \
+ (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != addr->sa_family)
+ continue;
+ if (equal(addr, ifa->ifa_addr))
+ return (ifa);
+ if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
+ equal(ifa->ifa_broadaddr, addr))
+ return (ifa);
+ }
+ return ((struct ifaddr *)0);
+}
+/*
+ * Locate the point to point interface with a given destination address.
+ */
+/*ARGSUSED*/
+struct ifaddr *
+ifa_ifwithdstaddr(addr)
+ register struct sockaddr *addr;
+{
+ register struct ifnet *ifp;
+ register struct ifaddr *ifa;
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (ifp->if_flags & IFF_POINTOPOINT)
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != addr->sa_family)
+ continue;
+ if (equal(addr, ifa->ifa_dstaddr))
+ return (ifa);
+ }
+ return ((struct ifaddr *)0);
+}
+
+/*
+ * Find an interface on a specific network. If many, choice
+ * is most specific found.
+ */
+struct ifaddr *
+ifa_ifwithnet(addr)
+ struct sockaddr *addr;
+{
+ register struct ifnet *ifp;
+ register struct ifaddr *ifa;
+ struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
+ u_int af = addr->sa_family;
+ char *addr_data = addr->sa_data, *cplim;
+
+ if (af == AF_LINK) {
+ register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
+ if (sdl->sdl_index && sdl->sdl_index <= if_index)
+ return (ifnet_addrs[sdl->sdl_index - 1]);
+ }
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+ register char *cp, *cp2, *cp3;
+
+ if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
+ next: continue;
+ cp = addr_data;
+ cp2 = ifa->ifa_addr->sa_data;
+ cp3 = ifa->ifa_netmask->sa_data;
+ cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+ while (cp3 < cplim)
+ if ((*cp++ ^ *cp2++) & *cp3++)
+ goto next;
+ if (ifa_maybe == 0 ||
+ rn_refines((caddr_t)ifa->ifa_netmask,
+ (caddr_t)ifa_maybe->ifa_netmask))
+ ifa_maybe = ifa;
+ }
+ return (ifa_maybe);
+}
+
+/*
+ * Find an interface using a specific address family
+ */
+struct ifaddr *
+ifa_ifwithaf(af)
+ register int af;
+{
+ register struct ifnet *ifp;
+ register struct ifaddr *ifa;
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == af)
+ return (ifa);
+ return ((struct ifaddr *)0);
+}
+
+/*
+ * Find an interface address specific to an interface best matching
+ * a given address.
+ */
+struct ifaddr *
+ifaof_ifpforaddr(addr, ifp)
+ struct sockaddr *addr;
+ register struct ifnet *ifp;
+{
+ register struct ifaddr *ifa;
+ register char *cp, *cp2, *cp3;
+ register char *cplim;
+ struct ifaddr *ifa_maybe = 0;
+ u_int af = addr->sa_family;
+
+ if (af >= AF_MAX)
+ return (0);
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != af)
+ continue;
+ ifa_maybe = ifa;
+ if (ifa->ifa_netmask == 0) {
+ if (equal(addr, ifa->ifa_addr) ||
+ (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
+ return (ifa);
+ continue;
+ }
+ cp = addr->sa_data;
+ cp2 = ifa->ifa_addr->sa_data;
+ cp3 = ifa->ifa_netmask->sa_data;
+ cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+ for (; cp3 < cplim; cp3++)
+ if ((*cp++ ^ *cp2++) & *cp3)
+ break;
+ if (cp3 == cplim)
+ return (ifa);
+ }
+ return (ifa_maybe);
+}
+
+#include <net/route.h>
+
+/*
+ * Default action when installing a route with a Link Level gateway.
+ * Lookup an appropriate real ifa to point to.
+ * This should be moved to /sys/net/link.c eventually.
+ */
+void
+link_rtrequest(cmd, rt, sa)
+ int cmd;
+ register struct rtentry *rt;
+ struct sockaddr *sa;
+{
+ register struct ifaddr *ifa;
+ struct sockaddr *dst;
+ struct ifnet *ifp;
+
+ if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
+ ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
+ return;
+ if (ifa = ifaof_ifpforaddr(dst, ifp)) {
+ IFAFREE(rt->rt_ifa);
+ rt->rt_ifa = ifa;
+ ifa->ifa_refcnt++;
+ if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
+ ifa->ifa_rtrequest(cmd, rt, sa);
+ }
+}
+
+/*
+ * Mark an interface down and notify protocols of
+ * the transition.
+ * NOTE: must be called at splnet or eqivalent.
+ */
+void
+if_down(ifp)
+ register struct ifnet *ifp;
+{
+ register struct ifaddr *ifa;
+
+ ifp->if_flags &= ~IFF_UP;
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+ pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
+ if_qflush(&ifp->if_snd);
+ rt_ifmsg(ifp);
+}
+
+/*
+ * Mark an interface up and notify protocols of
+ * the transition.
+ * NOTE: must be called at splnet or eqivalent.
+ */
+void
+if_up(ifp)
+ register struct ifnet *ifp;
+{
+ register struct ifaddr *ifa;
+
+ ifp->if_flags |= IFF_UP;
+#ifdef notyet
+ /* this has no effect on IP, and will kill all iso connections XXX */
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
+ pfctlinput(PRC_IFUP, ifa->ifa_addr);
+#endif
+ rt_ifmsg(ifp);
+}
+
+/*
+ * Flush an interface queue.
+ */
+void
+if_qflush(ifq)
+ register struct ifqueue *ifq;
+{
+ register struct mbuf *m, *n;
+
+ n = ifq->ifq_head;
+ while (m = n) {
+ n = m->m_act;
+ m_freem(m);
+ }
+ ifq->ifq_head = 0;
+ ifq->ifq_tail = 0;
+ ifq->ifq_len = 0;
+}
+
+/*
+ * Handle interface watchdog timer routines. Called
+ * from softclock, we decrement timers (if set) and
+ * call the appropriate interface routine on expiration.
+ */
+void
+if_slowtimo(arg)
+ void *arg;
+{
+ register struct ifnet *ifp;
+ int s = splimp();
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ if (ifp->if_timer == 0 || --ifp->if_timer)
+ continue;
+ if (ifp->if_watchdog)
+ (*ifp->if_watchdog)(ifp->if_unit);
+ }
+ splx(s);
+ timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
+}
+
+/*
+ * Map interface name to
+ * interface structure pointer.
+ */
+struct ifnet *
+ifunit(name)
+ register char *name;
+{
+ register char *cp;
+ register struct ifnet *ifp;
+ int unit;
+ unsigned len;
+ char *ep, c;
+
+ for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
+ if (*cp >= '0' && *cp <= '9')
+ break;
+ if (*cp == '\0' || cp == name + IFNAMSIZ)
+ return ((struct ifnet *)0);
+ /*
+ * Save first char of unit, and pointer to it,
+ * so we can put a null there to avoid matching
+ * initial substrings of interface names.
+ */
+ len = cp - name + 1;
+ c = *cp;
+ ep = cp;
+ for (unit = 0; *cp >= '0' && *cp <= '9'; )
+ unit = unit * 10 + *cp++ - '0';
+ *ep = 0;
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ if (bcmp(ifp->if_name, name, len))
+ continue;
+ if (unit == ifp->if_unit)
+ break;
+ }
+ *ep = c;
+ return (ifp);
+}
+
+/*
+ * Interface ioctls.
+ */
+int
+ifioctl(so, cmd, data, p)
+ struct socket *so;
+ 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 SIOCSIFFLAGS:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
+ int s = splimp();
+ if_down(ifp);
+ splx(s);
+ }
+ if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
+ int s = splimp();
+ if_up(ifp);
+ splx(s);
+ }
+ ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
+ (ifr->ifr_flags &~ IFF_CANTCHANGE);
+ if (ifp->if_ioctl)
+ (void) (*ifp->if_ioctl)(ifp, cmd, data);
+ break;
+
+ case SIOCSIFMETRIC:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ ifp->if_metric = ifr->ifr_metric;
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ if (ifp->if_ioctl == NULL)
+ return (EOPNOTSUPP);
+ return ((*ifp->if_ioctl)(ifp, cmd, data));
+
+ default:
+ if (so->so_proto == 0)
+ return (EOPNOTSUPP);
+#ifndef COMPAT_43
+ return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
+ cmd, data, ifp));
+#else
+ {
+ int ocmd = cmd;
+
+ switch (cmd) {
+
+ case SIOCSIFDSTADDR:
+ case SIOCSIFADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCSIFNETMASK:
+#if BYTE_ORDER != BIG_ENDIAN
+ if (ifr->ifr_addr.sa_family == 0 &&
+ ifr->ifr_addr.sa_len < 16) {
+ ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
+ ifr->ifr_addr.sa_len = 16;
+ }
+#else
+ if (ifr->ifr_addr.sa_len == 0)
+ ifr->ifr_addr.sa_len = 16;
+#endif
+ break;
+
+ case OSIOCGIFADDR:
+ cmd = SIOCGIFADDR;
+ break;
+
+ case OSIOCGIFDSTADDR:
+ cmd = SIOCGIFDSTADDR;
+ break;
+
+ case OSIOCGIFBRDADDR:
+ cmd = SIOCGIFBRDADDR;
+ break;
+
+ case OSIOCGIFNETMASK:
+ cmd = SIOCGIFNETMASK;
+ }
+ error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
+ cmd, data, ifp));
+ switch (ocmd) {
+
+ case OSIOCGIFADDR:
+ case OSIOCGIFDSTADDR:
+ case OSIOCGIFBRDADDR:
+ case OSIOCGIFNETMASK:
+ *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
+ }
+ return (error);
+
+ }
+#endif
+ }
+ return (0);
+}
+
+/*
+ * Return interface configuration
+ * of system. List may be used
+ * in later ioctl's (above) to get
+ * other information.
+ */
+/*ARGSUSED*/
+int
+ifconf(cmd, data)
+ int cmd;
+ caddr_t data;
+{
+ register struct ifconf *ifc = (struct ifconf *)data;
+ register struct ifnet *ifp = ifnet;
+ register struct ifaddr *ifa;
+ register char *cp, *ep;
+ struct ifreq ifr, *ifrp;
+ int space = ifc->ifc_len, error = 0;
+
+ ifrp = ifc->ifc_req;
+ ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
+ for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
+ strncpy(ifr.ifr_name, ifp->if_name, sizeof (ifr.ifr_name) - 2);
+ for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
+ continue;
+ *cp++ = '0' + ifp->if_unit; *cp = '\0';
+ if ((ifa = ifp->if_addrlist) == 0) {
+ bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr));
+ if (error)
+ break;
+ space -= sizeof (ifr), ifrp++;
+ } else
+ for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
+ register struct sockaddr *sa = ifa->ifa_addr;
+#ifdef COMPAT_43
+ if (cmd == OSIOCGIFCONF) {
+ struct osockaddr *osa =
+ (struct osockaddr *)&ifr.ifr_addr;
+ ifr.ifr_addr = *sa;
+ osa->sa_family = sa->sa_family;
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr));
+ ifrp++;
+ } else
+#endif
+ if (sa->sa_len <= sizeof(*sa)) {
+ ifr.ifr_addr = *sa;
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr));
+ ifrp++;
+ } else {
+ space -= sa->sa_len - sizeof(*sa);
+ if (space < sizeof (ifr))
+ break;
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr.ifr_name));
+ if (error == 0)
+ error = copyout((caddr_t)sa,
+ (caddr_t)&ifrp->ifr_addr, sa->sa_len);
+ ifrp = (struct ifreq *)
+ (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
+ }
+ if (error)
+ break;
+ space -= sizeof (ifr);
+ }
+ }
+ ifc->ifc_len -= space;
+ return (error);
+}
+
+static char *
+sprint_d(n, buf, buflen)
+ u_int n;
+ char *buf;
+ int buflen;
+{
+ register char *cp = buf + buflen - 1;
+
+ *cp = 0;
+ do {
+ cp--;
+ *cp = "0123456789"[n % 10];
+ n /= 10;
+ } while (n != 0);
+ return (cp);
+}
diff --git a/sys/net/if.h b/sys/net/if.h
new file mode 100644
index 0000000..c27c4f9
--- /dev/null
+++ b/sys/net/if.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if.h 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * Structures defining a network interface, providing a packet
+ * transport mechanism (ala level 0 of the PUP protocols).
+ *
+ * Each interface accepts output datagrams of a specified maximum
+ * length, and provides higher level routines with input datagrams
+ * received from its medium.
+ *
+ * Output occurs when the routine if_output is called, with three parameters:
+ * (*ifp->if_output)(ifp, m, dst, rt)
+ * Here m is the mbuf chain to be sent and dst is the destination address.
+ * The output routine encapsulates the supplied datagram if necessary,
+ * and then transmits it on its medium.
+ *
+ * On input, each interface unwraps the data received by it, and either
+ * places it on the input queue of a internetwork datagram routine
+ * and posts the associated software interrupt, or passes the datagram to a raw
+ * packet input routine.
+ *
+ * Routines exist for locating interfaces by their addresses
+ * or for locating a interface on a certain network, as well as more general
+ * routing and gateway routines maintaining information used to locate
+ * interfaces. These routines live in the files if.c and route.c
+ */
+#ifndef _TIME_ /* XXX fast fix for SNMP, going away soon */
+#include <sys/time.h>
+#endif
+
+#ifdef __STDC__
+/*
+ * Forward structure declarations for function prototypes [sic].
+ */
+struct mbuf;
+struct proc;
+struct rtentry;
+struct socket;
+struct ether_header;
+#endif
+/*
+ * Structure describing information about an interface
+ * which may be of interest to management entities.
+ */
+/*
+ * Structure defining a queue for a network interface.
+ *
+ * (Would like to call this struct ``if'', but C isn't PL/1.)
+ */
+
+struct ifnet {
+ char *if_name; /* name, e.g. ``en'' or ``lo'' */
+ struct ifnet *if_next; /* all struct ifnets are chained */
+ struct ifaddr *if_addrlist; /* linked list of addresses per if */
+ int if_pcount; /* number of promiscuous listeners */
+ caddr_t if_bpf; /* packet filter structure */
+ u_short if_index; /* numeric abbreviation for this if */
+ short if_unit; /* sub-unit for lower level driver */
+ short if_timer; /* time 'til if_watchdog called */
+ short if_flags; /* up/down, broadcast, etc. */
+ struct if_data {
+/* generic interface information */
+ u_char ifi_type; /* ethernet, tokenring, etc */
+ u_char ifi_addrlen; /* media address length */
+ u_char ifi_hdrlen; /* media header length */
+ u_long ifi_mtu; /* maximum transmission unit */
+ u_long ifi_metric; /* routing metric (external only) */
+ u_long ifi_baudrate; /* linespeed */
+/* volatile statistics */
+ u_long ifi_ipackets; /* packets received on interface */
+ u_long ifi_ierrors; /* input errors on interface */
+ u_long ifi_opackets; /* packets sent on interface */
+ u_long ifi_oerrors; /* output errors on interface */
+ u_long ifi_collisions; /* collisions on csma interfaces */
+ u_long ifi_ibytes; /* total number of octets received */
+ u_long ifi_obytes; /* total number of octets sent */
+ u_long ifi_imcasts; /* packets received via multicast */
+ u_long ifi_omcasts; /* packets sent via multicast */
+ u_long ifi_iqdrops; /* dropped on input, this interface */
+ u_long ifi_noproto; /* destined for unsupported protocol */
+ struct timeval ifi_lastchange;/* last updated */
+ } if_data;
+/* procedure handles */
+ int (*if_init) /* init routine */
+ __P((int));
+ int (*if_output) /* output routine (enqueue) */
+ __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *));
+ int (*if_start) /* initiate output routine */
+ __P((struct ifnet *));
+ int (*if_done) /* output complete routine */
+ __P((struct ifnet *)); /* (XXX not used; fake prototype) */
+ int (*if_ioctl) /* ioctl routine */
+ __P((struct ifnet *, int, caddr_t));
+ int (*if_reset)
+ __P((int)); /* new autoconfig will permit removal */
+ int (*if_watchdog) /* timer routine */
+ __P((int));
+ struct ifqueue {
+ struct mbuf *ifq_head;
+ struct mbuf *ifq_tail;
+ int ifq_len;
+ int ifq_maxlen;
+ int ifq_drops;
+ } if_snd; /* output queue */
+};
+#define if_mtu if_data.ifi_mtu
+#define if_type if_data.ifi_type
+#define if_addrlen if_data.ifi_addrlen
+#define if_hdrlen if_data.ifi_hdrlen
+#define if_metric if_data.ifi_metric
+#define if_baudrate if_data.ifi_baudrate
+#define if_ipackets if_data.ifi_ipackets
+#define if_ierrors if_data.ifi_ierrors
+#define if_opackets if_data.ifi_opackets
+#define if_oerrors if_data.ifi_oerrors
+#define if_collisions if_data.ifi_collisions
+#define if_ibytes if_data.ifi_ibytes
+#define if_obytes if_data.ifi_obytes
+#define if_imcasts if_data.ifi_imcasts
+#define if_omcasts if_data.ifi_omcasts
+#define if_iqdrops if_data.ifi_iqdrops
+#define if_noproto if_data.ifi_noproto
+#define if_lastchange if_data.ifi_lastchange
+
+#define IFF_UP 0x1 /* interface is up */
+#define IFF_BROADCAST 0x2 /* broadcast address valid */
+#define IFF_DEBUG 0x4 /* turn on debugging */
+#define IFF_LOOPBACK 0x8 /* is a loopback net */
+#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
+#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */
+#define IFF_RUNNING 0x40 /* resources allocated */
+#define IFF_NOARP 0x80 /* no address resolution protocol */
+#define IFF_PROMISC 0x100 /* receive all packets */
+#define IFF_ALLMULTI 0x200 /* receive all multicast packets */
+#define IFF_OACTIVE 0x400 /* transmission in progress */
+#define IFF_SIMPLEX 0x800 /* can't hear own transmissions */
+#define IFF_LINK0 0x1000 /* per link layer defined bit */
+#define IFF_LINK1 0x2000 /* per link layer defined bit */
+#define IFF_LINK2 0x4000 /* per link layer defined bit */
+#define IFF_MULTICAST 0x8000 /* supports multicast */
+
+/* flags set internally only: */
+#define IFF_CANTCHANGE \
+ (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
+ IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI)
+
+/*
+ * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)
+ * input routines have queues of messages stored on ifqueue structures
+ * (defined above). Entries are added to and deleted from these structures
+ * by these macros, which should be called with ipl raised to splimp().
+ */
+#define IF_QFULL(ifq) ((ifq)->ifq_len >= (ifq)->ifq_maxlen)
+#define IF_DROP(ifq) ((ifq)->ifq_drops++)
+#define IF_ENQUEUE(ifq, m) { \
+ (m)->m_nextpkt = 0; \
+ if ((ifq)->ifq_tail == 0) \
+ (ifq)->ifq_head = m; \
+ else \
+ (ifq)->ifq_tail->m_nextpkt = m; \
+ (ifq)->ifq_tail = m; \
+ (ifq)->ifq_len++; \
+}
+#define IF_PREPEND(ifq, m) { \
+ (m)->m_nextpkt = (ifq)->ifq_head; \
+ if ((ifq)->ifq_tail == 0) \
+ (ifq)->ifq_tail = (m); \
+ (ifq)->ifq_head = (m); \
+ (ifq)->ifq_len++; \
+}
+#define IF_DEQUEUE(ifq, m) { \
+ (m) = (ifq)->ifq_head; \
+ if (m) { \
+ if (((ifq)->ifq_head = (m)->m_nextpkt) == 0) \
+ (ifq)->ifq_tail = 0; \
+ (m)->m_nextpkt = 0; \
+ (ifq)->ifq_len--; \
+ } \
+}
+
+#define IFQ_MAXLEN 50
+#define IFNET_SLOWHZ 1 /* granularity is 1 second */
+
+/*
+ * The ifaddr structure contains information about one address
+ * of an interface. They are maintained by the different address families,
+ * are allocated and attached when an address is set, and are linked
+ * together so all addresses for an interface can be located.
+ */
+struct ifaddr {
+ struct sockaddr *ifa_addr; /* address of interface */
+ struct sockaddr *ifa_dstaddr; /* other end of p-to-p link */
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+ struct sockaddr *ifa_netmask; /* used to determine subnet */
+ struct ifnet *ifa_ifp; /* back-pointer to interface */
+ struct ifaddr *ifa_next; /* next address for interface */
+ void (*ifa_rtrequest)(); /* check or clean routes (+ or -)'d */
+ u_short ifa_flags; /* mostly rt_flags for cloning */
+ short ifa_refcnt; /* extra to malloc for link info */
+ int ifa_metric; /* cost of going out this interface */
+#ifdef notdef
+ struct rtentry *ifa_rt; /* XXXX for ROUTETOIF ????? */
+#endif
+};
+#define IFA_ROUTE RTF_UP /* route installed */
+
+/*
+ * Message format for use in obtaining information about interfaces
+ * from getkerninfo and the routing socket
+ */
+struct if_msghdr {
+ u_short ifm_msglen; /* to skip over non-understood messages */
+ u_char ifm_version; /* future binary compatability */
+ u_char ifm_type; /* message type */
+ int ifm_addrs; /* like rtm_addrs */
+ int ifm_flags; /* value of if_flags */
+ u_short ifm_index; /* index for associated ifp */
+ struct if_data ifm_data;/* statistics and other data about if */
+};
+
+/*
+ * Message format for use in obtaining information about interface addresses
+ * from getkerninfo and the routing socket
+ */
+struct ifa_msghdr {
+ u_short ifam_msglen; /* to skip over non-understood messages */
+ u_char ifam_version; /* future binary compatability */
+ u_char ifam_type; /* message type */
+ int ifam_addrs; /* like rtm_addrs */
+ int ifam_flags; /* value of ifa_flags */
+ u_short ifam_index; /* index for associated ifp */
+ int ifam_metric; /* value of ifa_metric */
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's. All interface ioctl's must have parameter
+ * definitions which begin with ifr_name. The
+ * remainder may be interface specific.
+ */
+struct ifreq {
+#define IFNAMSIZ 16
+ char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ short ifru_flags;
+ int ifru_metric;
+ caddr_t ifru_data;
+ } ifr_ifru;
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_data ifr_ifru.ifru_data /* for use by interface */
+};
+
+struct ifaliasreq {
+ char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ struct sockaddr ifra_addr;
+ struct sockaddr ifra_broadaddr;
+ struct sockaddr ifra_mask;
+};
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+struct ifconf {
+ int ifc_len; /* size of associated buffer */
+ union {
+ caddr_t ifcu_buf;
+ struct ifreq *ifcu_req;
+ } ifc_ifcu;
+#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
+#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */
+};
+
+#include <net/if_arp.h>
+
+#ifdef KERNEL
+#define IFAFREE(ifa) \
+ if ((ifa)->ifa_refcnt <= 0) \
+ ifafree(ifa); \
+ else \
+ (ifa)->ifa_refcnt--;
+
+struct ifnet *ifnet;
+
+void ether_ifattach __P((struct ifnet *));
+void ether_input __P((struct ifnet *, struct ether_header *, struct mbuf *));
+int ether_output __P((struct ifnet *,
+ struct mbuf *, struct sockaddr *, struct rtentry *));
+char *ether_sprintf __P((u_char *));
+
+void if_attach __P((struct ifnet *));
+void if_down __P((struct ifnet *));
+void if_qflush __P((struct ifqueue *));
+void if_slowtimo __P((void *));
+void if_up __P((struct ifnet *));
+#ifdef vax
+void ifubareset __P((int));
+#endif
+int ifconf __P((int, caddr_t));
+void ifinit __P((void));
+int ifioctl __P((struct socket *, int, caddr_t, struct proc *));
+int ifpromisc __P((struct ifnet *, int));
+struct ifnet *ifunit __P((char *));
+
+struct ifaddr *ifa_ifwithaddr __P((struct sockaddr *));
+struct ifaddr *ifa_ifwithaf __P((int));
+struct ifaddr *ifa_ifwithdstaddr __P((struct sockaddr *));
+struct ifaddr *ifa_ifwithnet __P((struct sockaddr *));
+struct ifaddr *ifa_ifwithroute __P((int, struct sockaddr *,
+ struct sockaddr *));
+struct ifaddr *ifaof_ifpforaddr __P((struct sockaddr *, struct ifnet *));
+void ifafree __P((struct ifaddr *));
+void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));
+
+int loioctl __P((struct ifnet *, int, caddr_t));
+void loopattach __P((int));
+int looutput __P((struct ifnet *,
+ struct mbuf *, struct sockaddr *, struct rtentry *));
+void lortrequest __P((int, struct rtentry *, struct sockaddr *));
+#endif
diff --git a/sys/net/if_arp.h b/sys/net/if_arp.h
new file mode 100644
index 0000000..84581cb
--- /dev/null
+++ b/sys/net/if_arp.h
@@ -0,0 +1,85 @@
+/*
+ * 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
+ */
+
+/*
+ * 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 */
diff --git a/sys/net/if_dl.h b/sys/net/if_dl.h
new file mode 100644
index 0000000..3e53449
--- /dev/null
+++ b/sys/net/if_dl.h
@@ -0,0 +1,80 @@
+/*
+ * 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
+ */
+
+/*
+ * 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 <sys/cdefs.h>
+
+__BEGIN_DECLS
+void link_addr __P((const char *, struct sockaddr_dl *));
+char *link_ntoa __P((const struct sockaddr_dl *));
+__END_DECLS
+
+#endif /* !KERNEL */
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
new file mode 100644
index 0000000..d4d6680
--- /dev/null
+++ b/sys/net/if_ethersubr.c
@@ -0,0 +1,675 @@
+/*
+ * 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
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/if_llc.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#endif
+#include <netinet/if_ether.h>
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#ifdef ISO
+#include <netiso/argo_debug.h>
+#include <netiso/iso.h>
+#include <netiso/iso_var.h>
+#include <netiso/iso_snpac.h>
+#endif
+
+#ifdef LLC
+#include <netccitt/dll.h>
+#include <netccitt/llc_var.h>
+#endif
+
+#if defined(LLC) && defined(CCITT)
+extern struct ifqueue pkintrq;
+#endif
+
+u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+extern struct ifnet loif;
+#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 edst[6];
+ register struct mbuf *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;
+
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+ senderr(ENETDOWN);
+ ifp->if_lastchange = time;
+ if (rt = rt0) {
+ if ((rt->rt_flags & RTF_UP) == 0) {
+ if (rt0 = rt = rtalloc1(dst, 1))
+ 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);
+ if ((rt = rt->rt_gwroute) == 0)
+ senderr(EHOSTUNREACH);
+ }
+ }
+ if (rt->rt_flags & RTF_REJECT)
+ if (rt->rt_rmx.rmx_expire == 0 ||
+ time.tv_sec < 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))
+ 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 = ETHERTYPE_IP;
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ type = ETHERTYPE_NS;
+ 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)))
+ 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 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 = 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 = 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;
+ bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, 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 *);
+ type = htons((u_short)type);
+ bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
+ sizeof(eh->ether_type));
+ bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
+ bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
+ 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;
+ register struct llc *l;
+ struct arpcom *ac = (struct arpcom *)ifp;
+ int s;
+
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ m_freem(m);
+ return;
+ }
+ ifp->if_lastchange = time;
+ 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++;
+
+ switch (eh->ether_type) {
+#ifdef INET
+ case ETHERTYPE_IP:
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+
+ case ETHERTYPE_ARP:
+ schednetisr(NETISR_ARP);
+ inq = &arpintrq;
+ break;
+#endif
+#ifdef NS
+ case ETHERTYPE_NS:
+ schednetisr(NETISR_NS);
+ inq = &nsintrq;
+ break;
+
+#endif
+ default:
+#if defined (ISO) || defined (LLC)
+ if (eh->ether_type > ETHERMTU)
+ goto dropanyway;
+ l = mtod(m, struct llc *);
+ switch (l->llc_dsap) {
+#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 > eh->ether_type)
+ m_adj(m, eh->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 > eh->ether_type)
+ m_adj(m, eh->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 = eh->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 */
+ m_freem(m);
+ return;
+#endif /* ISO || LLC */
+ }
+
+ s = splimp();
+ if (IF_QFULL(inq)) {
+ IF_DROP(inq);
+ m_freem(m);
+ } else
+ IF_ENQUEUE(inq, m);
+ splx(s);
+}
+
+/*
+ * Convert Ethernet address to printable (loggable) representation.
+ */
+static char digits[] = "0123456789abcdef";
+char *
+ether_sprintf(ap)
+ register u_char *ap;
+{
+ register i;
+ static char etherbuf[18];
+ register char *cp = etherbuf;
+
+ for (i = 0; i < 6; i++) {
+ *cp++ = digits[*ap >> 4];
+ *cp++ = digits[*ap++ & 0xf];
+ *cp++ = ':';
+ }
+ *--cp = 0;
+ return (etherbuf);
+}
+
+/*
+ * 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;
+ 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;
+ }
+}
+
+u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
+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 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);
+ }
+ 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);
+ /*
+ * 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 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);
+ }
+ 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);
+ /*
+ * Return ENETRESET to inform the driver that the list has changed
+ * and its reception filter should be adjusted accordingly.
+ */
+ return (ENETRESET);
+}
diff --git a/sys/net/if_llc.h b/sys/net/if_llc.h
new file mode 100644
index 0000000..90dcb07
--- /dev/null
+++ b/sys/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
+ */
+
+/*
+ * 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 shortcommings 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
+
+
+
+
+
+
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
new file mode 100644
index 0000000..f09295e
--- /dev/null
+++ b/sys/net/if_loop.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_loop.c 8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * Loopback interface driver for protocol testing and timing.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#ifdef ISO
+#include <netiso/iso.h>
+#include <netiso/iso_var.h>
+#endif
+
+#include "bpfilter.h"
+
+#define LOMTU (1024+512)
+
+struct ifnet loif;
+
+/* ARGSUSED */
+void
+loopattach(n)
+ int n;
+{
+ register struct ifnet *ifp = &loif;
+
+#ifdef lint
+ n = n; /* Highlander: there can only be one... */
+#endif
+ ifp->if_name = "lo";
+ ifp->if_mtu = LOMTU;
+ ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
+ ifp->if_ioctl = loioctl;
+ ifp->if_output = looutput;
+ ifp->if_type = IFT_LOOP;
+ ifp->if_hdrlen = 0;
+ ifp->if_addrlen = 0;
+ if_attach(ifp);
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
+#endif
+}
+
+int
+looutput(ifp, m, dst, rt)
+ struct ifnet *ifp;
+ register struct mbuf *m;
+ struct sockaddr *dst;
+ register struct rtentry *rt;
+{
+ int s, isr;
+ register struct ifqueue *ifq = 0;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("looutput no HDR");
+ ifp->if_lastchange = time;
+#if NBPFILTER > 0
+ if (loif.if_bpf) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a dummy header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ struct mbuf m0;
+ u_int af = dst->sa_family;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+ bpf_mtap(loif.if_bpf, &m0);
+ }
+#endif
+ m->m_pkthdr.rcvif = ifp;
+
+ if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
+ m_freem(m);
+ return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
+ rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
+ }
+ ifp->if_opackets++;
+ ifp->if_obytes += m->m_pkthdr.len;
+ switch (dst->sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ ifq = &ipintrq;
+ isr = NETISR_IP;
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ ifq = &nsintrq;
+ isr = NETISR_NS;
+ break;
+#endif
+#ifdef ISO
+ case AF_ISO:
+ ifq = &clnlintrq;
+ isr = NETISR_ISO;
+ break;
+#endif
+ default:
+ printf("lo%d: can't handle af%d\n", ifp->if_unit,
+ dst->sa_family);
+ m_freem(m);
+ return (EAFNOSUPPORT);
+ }
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+ m_freem(m);
+ splx(s);
+ return (ENOBUFS);
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(isr);
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+ splx(s);
+ return (0);
+}
+
+/* ARGSUSED */
+void
+lortrequest(cmd, rt, sa)
+ int cmd;
+ struct rtentry *rt;
+ struct sockaddr *sa;
+{
+
+ if (rt)
+ rt->rt_rmx.rmx_mtu = LOMTU;
+}
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+int
+loioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa;
+ register struct ifreq *ifr;
+ register int error = 0;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ ifa = (struct ifaddr *)data;
+ if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
+ ifa->ifa_rtrequest = lortrequest;
+ /*
+ * Everything else is done at a higher level.
+ */
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ if (ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
diff --git a/sys/net/if_sl.c b/sys/net/if_sl.c
new file mode 100644
index 0000000..56ce96f
--- /dev/null
+++ b/sys/net/if_sl.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (c) 1987, 1989, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_sl.c 8.6 (Berkeley) 2/1/94
+ */
+
+/*
+ * Serial Line interface
+ *
+ * Rick Adams
+ * Center for Seismic Studies
+ * 1300 N 17th Street, Suite 1450
+ * Arlington, Virginia 22209
+ * (703)276-7900
+ * rick@seismo.ARPA
+ * seismo!rick
+ *
+ * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
+ * N.B.: this belongs in netinet, not net, the way it stands now.
+ * Should have a link-layer type designation, but wouldn't be
+ * backwards-compatible.
+ *
+ * Converted to 4.3BSD Beta by Chris Torek.
+ * Other changes made at Berkeley, based in part on code by Kirk Smith.
+ * W. Jolitz added slip abort.
+ *
+ * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov).
+ * Added priority queuing for "interactive" traffic; hooks for TCP
+ * header compression; ICMP filtering (at 2400 baud, some cretin
+ * pinging you can use up all your bandwidth). Made low clist behavior
+ * more robust and slightly less likely to hang serial line.
+ * Sped up a bunch of things.
+ *
+ * Note that splimp() is used throughout to block both (tty) input
+ * interrupts and network activity; thus, splimp must be >= spltty.
+ */
+
+#include "sl.h"
+#if NSL > 0
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/dkstat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/tty.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+
+#include <machine/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#if INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#else
+Huh? Slip without inet?
+#endif
+
+#include <net/slcompress.h>
+#include <net/if_slvar.h>
+#include <net/slip.h>
+
+#if NBPFILTER > 0
+#include <sys/time.h>
+#include <net/bpf.h>
+#endif
+
+/*
+ * SLMAX is a hard limit on input packet size. To simplify the code
+ * and improve performance, we require that packets fit in an mbuf
+ * cluster, and if we get a compressed packet, there's enough extra
+ * room to expand the header into a max length tcp/ip header (128
+ * bytes). So, SLMAX can be at most
+ * MCLBYTES - 128
+ *
+ * SLMTU is a hard limit on output packet size. To insure good
+ * interactive response, SLMTU wants to be the smallest size that
+ * amortizes the header cost. (Remember that even with
+ * type-of-service queuing, we have to wait for any in-progress
+ * packet to finish. I.e., we wait, on the average, 1/2 * mtu /
+ * cps, where cps is the line speed in characters per second.
+ * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The
+ * average compressed header size is 6-8 bytes so any MTU > 90
+ * bytes will give us 90% of the line bandwidth. A 100ms wait is
+ * tolerable (500ms is not), so want an MTU around 296. (Since TCP
+ * will send 256 byte segments (to allow for 40 byte headers), the
+ * typical packet size on the wire will be around 260 bytes). In
+ * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
+ * leave the interface MTU relatively high (so we don't IP fragment
+ * when acting as a gateway to someone using a stupid MTU).
+ *
+ * Similar considerations apply to SLIP_HIWAT: It's the amount of
+ * data that will be queued 'downstream' of us (i.e., in clists
+ * waiting to be picked up by the tty output interrupt). If we
+ * queue a lot of data downstream, it's immune to our t.o.s. queuing.
+ * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
+ * telnet/ftp will see a 1 sec wait, independent of the mtu (the
+ * wait is dependent on the ftp window size but that's typically
+ * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize
+ * the cost (in idle time on the wire) of the tty driver running
+ * off the end of its clists & having to call back slstart for a
+ * new packet. For a tty interface with any buffering at all, this
+ * cost will be zero. Even with a totally brain dead interface (like
+ * the one on a typical workstation), the cost will be <= 1 character
+ * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
+ * at most 1% while maintaining good interactive response.
+ */
+#if NBPFILTER > 0
+#define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
+#else
+#define BUFOFFSET (128+sizeof(struct ifnet **))
+#endif
+#define SLMAX (MCLBYTES - BUFOFFSET)
+#define SLBUFSIZE (SLMAX + BUFOFFSET)
+#define SLMTU 296
+#define SLIP_HIWAT roundup(50,CBSIZE)
+#define CLISTRESERVE 1024 /* Can't let clists get too low */
+
+/*
+ * SLIP ABORT ESCAPE MECHANISM:
+ * (inspired by HAYES modem escape arrangement)
+ * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
+ * within window time signals a "soft" exit from slip mode by remote end
+ * if the IFF_DEBUG flag is on.
+ */
+#define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/
+#define ABT_IDLE 1 /* in seconds - idle before an escape */
+#define ABT_COUNT 3 /* count of escapes for abort */
+#define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */
+
+struct sl_softc sl_softc[NSL];
+
+#define FRAME_END 0xc0 /* Frame End */
+#define FRAME_ESCAPE 0xdb /* Frame Esc */
+#define TRANS_FRAME_END 0xdc /* transposed frame end */
+#define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */
+
+extern struct timeval time;
+
+static int slinit __P((struct sl_softc *));
+static struct mbuf *sl_btom __P((struct sl_softc *, int));
+
+/*
+ * Called from boot code to establish sl interfaces.
+ */
+void
+slattach()
+{
+ register struct sl_softc *sc;
+ register int i = 0;
+
+ for (sc = sl_softc; i < NSL; sc++) {
+ sc->sc_if.if_name = "sl";
+ sc->sc_if.if_next = NULL;
+ sc->sc_if.if_unit = i++;
+ sc->sc_if.if_mtu = SLMTU;
+ sc->sc_if.if_flags =
+ IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
+ sc->sc_if.if_type = IFT_SLIP;
+ sc->sc_if.if_ioctl = slioctl;
+ sc->sc_if.if_output = sloutput;
+ sc->sc_if.if_snd.ifq_maxlen = 50;
+ sc->sc_fastq.ifq_maxlen = 32;
+ if_attach(&sc->sc_if);
+#if NBPFILTER > 0
+ bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
+#endif
+ }
+}
+
+static int
+slinit(sc)
+ register struct sl_softc *sc;
+{
+ register caddr_t p;
+
+ if (sc->sc_ep == (u_char *) 0) {
+ MCLALLOC(p, M_WAIT);
+ if (p)
+ sc->sc_ep = (u_char *)p + SLBUFSIZE;
+ else {
+ printf("sl%d: can't allocate buffer\n", sc - sl_softc);
+ sc->sc_if.if_flags &= ~IFF_UP;
+ return (0);
+ }
+ }
+ sc->sc_buf = sc->sc_ep - SLMAX;
+ sc->sc_mp = sc->sc_buf;
+ sl_compress_init(&sc->sc_comp);
+ return (1);
+}
+
+/*
+ * Line specific open routine.
+ * Attach the given tty to the first available sl unit.
+ */
+/* ARGSUSED */
+int
+slopen(dev, tp)
+ dev_t dev;
+ register struct tty *tp;
+{
+ struct proc *p = curproc; /* XXX */
+ register struct sl_softc *sc;
+ register int nsl;
+ int error;
+
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+
+ if (tp->t_line == SLIPDISC)
+ return (0);
+
+ for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++)
+ if (sc->sc_ttyp == NULL) {
+ if (slinit(sc) == 0)
+ return (ENOBUFS);
+ tp->t_sc = (caddr_t)sc;
+ sc->sc_ttyp = tp;
+ sc->sc_if.if_baudrate = tp->t_ospeed;
+ ttyflush(tp, FREAD | FWRITE);
+ return (0);
+ }
+ return (ENXIO);
+}
+
+/*
+ * Line specific close routine.
+ * Detach the tty from the sl unit.
+ */
+void
+slclose(tp)
+ struct tty *tp;
+{
+ register struct sl_softc *sc;
+ int s;
+
+ ttywflush(tp);
+ s = splimp(); /* actually, max(spltty, splnet) */
+ tp->t_line = 0;
+ sc = (struct sl_softc *)tp->t_sc;
+ if (sc != NULL) {
+ if_down(&sc->sc_if);
+ sc->sc_ttyp = NULL;
+ tp->t_sc = NULL;
+ MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE));
+ sc->sc_ep = 0;
+ sc->sc_mp = 0;
+ sc->sc_buf = 0;
+ }
+ splx(s);
+}
+
+/*
+ * Line specific (tty) ioctl routine.
+ * Provide a way to get the sl unit number.
+ */
+/* ARGSUSED */
+int
+sltioctl(tp, cmd, data, flag)
+ struct tty *tp;
+ int cmd;
+ caddr_t data;
+ int flag;
+{
+ struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
+
+ switch (cmd) {
+ case SLIOCGUNIT:
+ *(int *)data = sc->sc_if.if_unit;
+ break;
+
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Queue a packet. Start transmission if not active.
+ * Compression happens in slstart; if we do it here, IP TOS
+ * will cause us to not compress "background" packets, because
+ * ordering gets trashed. It can be done for all packets in slstart.
+ */
+int
+sloutput(ifp, m, dst, rtp)
+ struct ifnet *ifp;
+ register struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rtp;
+{
+ register struct sl_softc *sc = &sl_softc[ifp->if_unit];
+ register struct ip *ip;
+ register struct ifqueue *ifq;
+ int s;
+
+ /*
+ * `Cannot happen' (see slioctl). Someday we will extend
+ * the line protocol to support other address families.
+ */
+ if (dst->sa_family != AF_INET) {
+ printf("sl%d: af%d not supported\n", sc->sc_if.if_unit,
+ dst->sa_family);
+ m_freem(m);
+ sc->sc_if.if_noproto++;
+ return (EAFNOSUPPORT);
+ }
+
+ if (sc->sc_ttyp == NULL) {
+ m_freem(m);
+ return (ENETDOWN); /* sort of */
+ }
+ if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
+ (sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
+ m_freem(m);
+ return (EHOSTUNREACH);
+ }
+ ifq = &sc->sc_if.if_snd;
+ ip = mtod(m, struct ip *);
+ if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
+ m_freem(m);
+ return (ENETRESET); /* XXX ? */
+ }
+ if (ip->ip_tos & IPTOS_LOWDELAY)
+ ifq = &sc->sc_fastq;
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+ m_freem(m);
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ return (ENOBUFS);
+ }
+ IF_ENQUEUE(ifq, m);
+ sc->sc_if.if_lastchange = time;
+ if (sc->sc_ttyp->t_outq.c_cc == 0)
+ slstart(sc->sc_ttyp);
+ splx(s);
+ return (0);
+}
+
+/*
+ * Start output on interface. Get another datagram
+ * to send from the interface queue and map it to
+ * the interface before starting output.
+ */
+void
+slstart(tp)
+ register struct tty *tp;
+{
+ register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
+ register struct mbuf *m;
+ register u_char *cp;
+ register struct ip *ip;
+ int s;
+ struct mbuf *m2;
+#if NBPFILTER > 0
+ u_char bpfbuf[SLMTU + SLIP_HDRLEN];
+ register int len;
+#endif
+ extern int cfreecount;
+
+ for (;;) {
+ /*
+ * If there is more in the output queue, just send it now.
+ * We are being called in lieu of ttstart and must do what
+ * it would.
+ */
+ if (tp->t_outq.c_cc != 0) {
+ (*tp->t_oproc)(tp);
+ if (tp->t_outq.c_cc > SLIP_HIWAT)
+ return;
+ }
+ /*
+ * This happens briefly when the line shuts down.
+ */
+ if (sc == NULL)
+ return;
+
+ /*
+ * Get a packet and send it to the interface.
+ */
+ s = splimp();
+ IF_DEQUEUE(&sc->sc_fastq, m);
+ if (m)
+ sc->sc_if.if_omcasts++; /* XXX */
+ else
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
+ splx(s);
+ if (m == NULL)
+ return;
+
+ /*
+ * We do the header compression here rather than in sloutput
+ * because the packets will be out of order if we are using TOS
+ * queueing, and the connection id compression will get
+ * munged when this happens.
+ */
+#if NBPFILTER > 0
+ if (sc->sc_bpf) {
+ /*
+ * We need to save the TCP/IP header before it's
+ * compressed. To avoid complicated code, we just
+ * copy the entire packet into a stack buffer (since
+ * this is a serial line, packets should be short
+ * and/or the copy should be negligible cost compared
+ * to the packet transmission time).
+ */
+ register struct mbuf *m1 = m;
+ register u_char *cp = bpfbuf + SLIP_HDRLEN;
+
+ len = 0;
+ do {
+ register int mlen = m1->m_len;
+
+ bcopy(mtod(m1, caddr_t), cp, mlen);
+ cp += mlen;
+ len += mlen;
+ } while (m1 = m1->m_next);
+ }
+#endif
+ if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
+ if (sc->sc_if.if_flags & SC_COMPRESS)
+ *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
+ &sc->sc_comp, 1);
+ }
+#if NBPFILTER > 0
+ if (sc->sc_bpf) {
+ /*
+ * Put the SLIP pseudo-"link header" in place. The
+ * compressed header is now at the beginning of the
+ * mbuf.
+ */
+ bpfbuf[SLX_DIR] = SLIPDIR_OUT;
+ bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN);
+ bpf_tap(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN);
+ }
+#endif
+ sc->sc_if.if_lastchange = time;
+
+ /*
+ * If system is getting low on clists, just flush our
+ * output queue (if the stuff was important, it'll get
+ * retransmitted).
+ */
+ if (cfreecount < CLISTRESERVE + SLMTU) {
+ m_freem(m);
+ sc->sc_if.if_collisions++;
+ continue;
+ }
+ /*
+ * The extra FRAME_END will start up a new packet, and thus
+ * will flush any accumulated garbage. We do this whenever
+ * the line may have been idle for some time.
+ */
+ if (tp->t_outq.c_cc == 0) {
+ ++sc->sc_if.if_obytes;
+ (void) putc(FRAME_END, &tp->t_outq);
+ }
+
+ while (m) {
+ register u_char *ep;
+
+ cp = mtod(m, u_char *); ep = cp + m->m_len;
+ while (cp < ep) {
+ /*
+ * Find out how many bytes in the string we can
+ * handle without doing something special.
+ */
+ register u_char *bp = cp;
+
+ while (cp < ep) {
+ switch (*cp++) {
+ case FRAME_ESCAPE:
+ case FRAME_END:
+ --cp;
+ goto out;
+ }
+ }
+ out:
+ if (cp > bp) {
+ /*
+ * Put n characters at once
+ * into the tty output queue.
+ */
+ if (b_to_q((char *)bp, cp - bp,
+ &tp->t_outq))
+ break;
+ sc->sc_if.if_obytes += cp - bp;
+ }
+ /*
+ * If there are characters left in the mbuf,
+ * the first one must be special..
+ * Put it out in a different form.
+ */
+ if (cp < ep) {
+ if (putc(FRAME_ESCAPE, &tp->t_outq))
+ break;
+ if (putc(*cp++ == FRAME_ESCAPE ?
+ TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
+ &tp->t_outq)) {
+ (void) unputc(&tp->t_outq);
+ break;
+ }
+ sc->sc_if.if_obytes += 2;
+ }
+ }
+ MFREE(m, m2);
+ m = m2;
+ }
+
+ if (putc(FRAME_END, &tp->t_outq)) {
+ /*
+ * Not enough room. Remove a char to make room
+ * and end the packet normally.
+ * If you get many collisions (more than one or two
+ * a day) you probably do not have enough clists
+ * and you should increase "nclist" in param.c.
+ */
+ (void) unputc(&tp->t_outq);
+ (void) putc(FRAME_END, &tp->t_outq);
+ sc->sc_if.if_collisions++;
+ } else {
+ ++sc->sc_if.if_obytes;
+ sc->sc_if.if_opackets++;
+ }
+ }
+}
+
+/*
+ * Copy data buffer to mbuf chain; add ifnet pointer.
+ */
+static struct mbuf *
+sl_btom(sc, len)
+ register struct sl_softc *sc;
+ register int len;
+{
+ register struct mbuf *m;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (NULL);
+
+ /*
+ * If we have more than MHLEN bytes, it's cheaper to
+ * queue the cluster we just filled & allocate a new one
+ * for the input buffer. Otherwise, fill the mbuf we
+ * allocated above. Note that code in the input routine
+ * guarantees that packet will fit in a cluster.
+ */
+ if (len >= MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ /*
+ * we couldn't get a cluster - if memory's this
+ * low, it's time to start dropping packets.
+ */
+ (void) m_free(m);
+ return (NULL);
+ }
+ sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE;
+ m->m_data = (caddr_t)sc->sc_buf;
+ m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET);
+ } else
+ bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len);
+
+ m->m_len = len;
+ m->m_pkthdr.len = len;
+ m->m_pkthdr.rcvif = &sc->sc_if;
+ return (m);
+}
+
+/*
+ * tty interface receiver interrupt.
+ */
+void
+slinput(c, tp)
+ register int c;
+ register struct tty *tp;
+{
+ register struct sl_softc *sc;
+ register struct mbuf *m;
+ register int len;
+ int s;
+#if NBPFILTER > 0
+ u_char chdr[CHDR_LEN];
+#endif
+
+ tk_nin++;
+ sc = (struct sl_softc *)tp->t_sc;
+ if (sc == NULL)
+ return;
+ if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 &&
+ (tp->t_cflag & CLOCAL) == 0)) {
+ sc->sc_flags |= SC_ERROR;
+ return;
+ }
+ c &= TTY_CHARMASK;
+
+ ++sc->sc_if.if_ibytes;
+
+ if (sc->sc_if.if_flags & IFF_DEBUG) {
+ if (c == ABT_ESC) {
+ /*
+ * If we have a previous abort, see whether
+ * this one is within the time limit.
+ */
+ if (sc->sc_abortcount &&
+ time.tv_sec >= sc->sc_starttime + ABT_WINDOW)
+ sc->sc_abortcount = 0;
+ /*
+ * If we see an abort after "idle" time, count it;
+ * record when the first abort escape arrived.
+ */
+ if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) {
+ if (++sc->sc_abortcount == 1)
+ sc->sc_starttime = time.tv_sec;
+ if (sc->sc_abortcount >= ABT_COUNT) {
+ slclose(tp);
+ return;
+ }
+ }
+ } else
+ sc->sc_abortcount = 0;
+ sc->sc_lasttime = time.tv_sec;
+ }
+
+ switch (c) {
+
+ case TRANS_FRAME_ESCAPE:
+ if (sc->sc_escape)
+ c = FRAME_ESCAPE;
+ break;
+
+ case TRANS_FRAME_END:
+ if (sc->sc_escape)
+ c = FRAME_END;
+ break;
+
+ case FRAME_ESCAPE:
+ sc->sc_escape = 1;
+ return;
+
+ case FRAME_END:
+ if(sc->sc_flags & SC_ERROR) {
+ sc->sc_flags &= ~SC_ERROR;
+ goto newpack;
+ }
+ len = sc->sc_mp - sc->sc_buf;
+ if (len < 3)
+ /* less than min length packet - ignore */
+ goto newpack;
+
+#if NBPFILTER > 0
+ if (sc->sc_bpf) {
+ /*
+ * Save the compressed header, so we
+ * can tack it on later. Note that we
+ * will end up copying garbage in some
+ * cases but this is okay. We remember
+ * where the buffer started so we can
+ * compute the new header length.
+ */
+ bcopy(sc->sc_buf, chdr, CHDR_LEN);
+ }
+#endif
+
+ if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
+ if (c & 0x80)
+ c = TYPE_COMPRESSED_TCP;
+ else if (c == TYPE_UNCOMPRESSED_TCP)
+ *sc->sc_buf &= 0x4f; /* XXX */
+ /*
+ * We've got something that's not an IP packet.
+ * If compression is enabled, try to decompress it.
+ * Otherwise, if `auto-enable' compression is on and
+ * it's a reasonable packet, decompress it and then
+ * enable compression. Otherwise, drop it.
+ */
+ if (sc->sc_if.if_flags & SC_COMPRESS) {
+ len = sl_uncompress_tcp(&sc->sc_buf, len,
+ (u_int)c, &sc->sc_comp);
+ if (len <= 0)
+ goto error;
+ } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
+ c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
+ len = sl_uncompress_tcp(&sc->sc_buf, len,
+ (u_int)c, &sc->sc_comp);
+ if (len <= 0)
+ goto error;
+ sc->sc_if.if_flags |= SC_COMPRESS;
+ } else
+ goto error;
+ }
+#if NBPFILTER > 0
+ if (sc->sc_bpf) {
+ /*
+ * Put the SLIP pseudo-"link header" in place.
+ * We couldn't do this any earlier since
+ * decompression probably moved the buffer
+ * pointer. Then, invoke BPF.
+ */
+ register u_char *hp = sc->sc_buf - SLIP_HDRLEN;
+
+ hp[SLX_DIR] = SLIPDIR_IN;
+ bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN);
+ bpf_tap(sc->sc_bpf, hp, len + SLIP_HDRLEN);
+ }
+#endif
+ m = sl_btom(sc, len);
+ if (m == NULL)
+ goto error;
+
+ sc->sc_if.if_ipackets++;
+ sc->sc_if.if_lastchange = time;
+ s = splimp();
+ if (IF_QFULL(&ipintrq)) {
+ IF_DROP(&ipintrq);
+ sc->sc_if.if_ierrors++;
+ sc->sc_if.if_iqdrops++;
+ m_freem(m);
+ } else {
+ IF_ENQUEUE(&ipintrq, m);
+ schednetisr(NETISR_IP);
+ }
+ splx(s);
+ goto newpack;
+ }
+ if (sc->sc_mp < sc->sc_ep) {
+ *sc->sc_mp++ = c;
+ sc->sc_escape = 0;
+ return;
+ }
+
+ /* can't put lower; would miss an extra frame */
+ sc->sc_flags |= SC_ERROR;
+
+error:
+ sc->sc_if.if_ierrors++;
+newpack:
+ sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
+ sc->sc_escape = 0;
+}
+
+/*
+ * Process an ioctl request.
+ */
+int
+slioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ register struct ifreq *ifr;
+ register int s = splimp(), error = 0;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ ifp->if_flags |= IFF_UP;
+ else
+ error = EAFNOSUPPORT;
+ break;
+
+ case SIOCSIFDSTADDR:
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ error = EAFNOSUPPORT;
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ if (ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
+}
+#endif
diff --git a/sys/net/if_slvar.h b/sys/net/if_slvar.h
new file mode 100644
index 0000000..e7b2764
--- /dev/null
+++ b/sys/net/if_slvar.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_slvar.h 8.3 (Berkeley) 2/1/94
+ *
+ * $Header: if_slvar.h,v 1.3 89/05/31 02:25:18 van Exp $
+ */
+
+/*
+ * Definitions for SLIP interface data structures
+ *
+ * (This exists so programs like slstats can get at the definition
+ * of sl_softc.)
+ */
+struct sl_softc {
+ struct ifnet sc_if; /* network-visible interface */
+ struct ifqueue sc_fastq; /* interactive output queue */
+ struct tty *sc_ttyp; /* pointer to tty structure */
+ u_char *sc_mp; /* pointer to next available buf char */
+ u_char *sc_ep; /* pointer to last available buf char */
+ u_char *sc_buf; /* input buffer */
+ u_int sc_flags; /* see below */
+ u_int sc_escape; /* =1 if last char input was FRAME_ESCAPE */
+ long sc_lasttime; /* last time a char arrived */
+ long sc_abortcount; /* number of abort esacpe chars */
+ long sc_starttime; /* time of first abort in window */
+#ifdef INET /* XXX */
+ struct slcompress sc_comp; /* tcp compression data */
+#endif
+ caddr_t sc_bpf; /* BPF data */
+};
+
+/* internal flags */
+#define SC_ERROR 0x0001 /* had an input error */
+
+/* visible flags */
+#define SC_COMPRESS IFF_LINK0 /* compress TCP traffic */
+#define SC_NOICMP IFF_LINK1 /* supress ICMP traffic */
+#define SC_AUTOCOMP IFF_LINK2 /* auto-enable TCP compression */
+
+#ifdef KERNEL
+void slattach __P((void));
+void slclose __P((struct tty *));
+void slinput __P((int, struct tty *));
+int slioctl __P((struct ifnet *, int, caddr_t));
+int slopen __P((dev_t, struct tty *));
+int sloutput __P((struct ifnet *,
+ struct mbuf *, struct sockaddr *, struct rtentry *));
+void slstart __P((struct tty *));
+int sltioctl __P((struct tty *, int, caddr_t, int));
+#endif /* KERNEL */
diff --git a/sys/net/if_types.h b/sys/net/if_types.h
new file mode 100644
index 0000000..030f234
--- /dev/null
+++ b/sys/net/if_types.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_types.h 8.2 (Berkeley) 4/20/94
+ */
+
+/*
+ * 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 10MBit 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 */
diff --git a/sys/net/netisr.h b/sys/net/netisr.h
new file mode 100644
index 0000000..e2e4653
--- /dev/null
+++ b/sys/net/netisr.h
@@ -0,0 +1,87 @@
+/*
+ * 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
+ */
+
+/*
+ * 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_ARP 18 /* same as AF_LINK */
+
+#define schednetisr(anisr) { netisr |= 1<<(anisr); setsoftnet(); }
+
+#ifdef i386
+/* XXX Temporary -- soon to vanish - wfj */
+#define NETISR_SCLK 11 /* softclock */
+#define NETISR_AST 12 /* ast -- resched */
+
+#undef schednetisr
+#define schednetisr(anisr) {\
+ if(netisr == 0) { \
+ softem++; \
+ } \
+ netisr |= 1<<(anisr); \
+}
+#ifndef LOCORE
+#ifdef KERNEL
+int softem;
+#endif
+#endif
+#endif /* i386 */
+
+#ifndef LOCORE
+#ifdef KERNEL
+int netisr; /* scheduling bits for network */
+#endif
+#endif
diff --git a/sys/net/radix.c b/sys/net/radix.c
new file mode 100644
index 0000000..f182eb7
--- /dev/null
+++ b/sys/net/radix.c
@@ -0,0 +1,757 @@
+/*
+ * 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.2 (Berkeley) 1/4/94
+ */
+
+/*
+ * Routines to build and maintain radix trees for routing lookups.
+ */
+#ifndef RNF_NORMAL
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#define M_DONTWAIT M_NOWAIT
+#ifdef KERNEL
+#include <sys/domain.h>
+#endif
+#endif
+
+#include <net/radix.h>
+
+int max_keylen;
+struct radix_mask *rn_mkfreelist;
+struct radix_node_head *mask_rnhead;
+static int gotOddMasks;
+static char *maskedKey;
+static char *rn_zeros, *rn_ones;
+
+#define rn_masktop (mask_rnhead->rnh_treetop)
+#undef Bcmp
+#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
+/*
+ * The data structure for the keys is a radix tree with one way
+ * branching removed. The index rn_b at an internal node n represents a bit
+ * position to be tested. The tree is arranged so that all descendants
+ * of a node n have keys whose bits all agree up to position rn_b - 1.
+ * (We say the index of n is rn_b.)
+ *
+ * There is at least one descendant which has a one bit at position rn_b,
+ * and at least one with a zero there.
+ *
+ * A route is determined by a pair of key and mask. We require that the
+ * bit-wise logical and of the key and mask to be the key.
+ * We define the index of a route to associated with the mask to be
+ * the first bit number in the mask where 0 occurs (with bit number 0
+ * representing the highest order bit).
+ *
+ * We say a mask is normal if every bit is 0, past the index of the mask.
+ * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
+ * and m is a normal mask, then the route applies to every descendant of n.
+ * If the index(m) < rn_b, this implies the trailing last few bits of k
+ * before bit b are all 0, (and hence consequently true of every descendant
+ * of n), so the route applies to all descendants of the node as well.
+ *
+ * The present version of the code makes no use of normal routes,
+ * but 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.
+ */
+
+struct radix_node *
+rn_search(v_arg, head)
+ void *v_arg;
+ struct radix_node *head;
+{
+ register struct radix_node *x;
+ register caddr_t v;
+
+ for (x = head, v = v_arg; x->rn_b >= 0;) {
+ if (x->rn_bmask & v[x->rn_off])
+ x = x->rn_r;
+ else
+ x = x->rn_l;
+ }
+ return (x);
+};
+
+struct radix_node *
+rn_search_m(v_arg, head, m_arg)
+ struct radix_node *head;
+ void *v_arg, *m_arg;
+{
+ register struct radix_node *x;
+ register caddr_t v = v_arg, m = m_arg;
+
+ for (x = head; x->rn_b >= 0;) {
+ if ((x->rn_bmask & m[x->rn_off]) &&
+ (x->rn_bmask & v[x->rn_off]))
+ x = x->rn_r;
+ else
+ x = x->rn_l;
+ }
+ return x;
+};
+
+int
+rn_refines(m_arg, n_arg)
+ void *m_arg, *n_arg;
+{
+ register caddr_t m = m_arg, n = n_arg;
+ register caddr_t lim, lim2 = lim = n + *(u_char *)n;
+ int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
+ int masks_are_equal = 1;
+
+ if (longer > 0)
+ lim -= longer;
+ while (n < lim) {
+ if (*n & ~(*m))
+ return 0;
+ if (*n++ != *m++)
+ masks_are_equal = 0;
+
+ }
+ while (n < lim2)
+ if (*n++)
+ return 0;
+ if (masks_are_equal && (longer < 0))
+ for (lim2 = m - longer; m < lim2; )
+ if (*m++)
+ return 1;
+ return (!masks_are_equal);
+}
+
+
+struct radix_node *
+rn_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, cp3;
+ caddr_t cplim, mstart;
+ struct radix_node *saved_t, *top = t;
+ int off = t->rn_off, vlen = *(u_char *)cp, matched_off;
+
+ /*
+ * 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
+ */
+ 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:
+ matched_off = cp - v;
+ saved_t = t;
+ do {
+ if (t->rn_mask) {
+ /*
+ * Even if we don't match exactly as a hosts;
+ * we may match if the leaf we wound up at is
+ * a route to a net.
+ */
+ cp3 = matched_off + t->rn_mask;
+ cp2 = matched_off + t->rn_key;
+ for (; cp < cplim; cp++)
+ if ((*cp2++ ^ *cp) & *cp3++)
+ break;
+ if (cp == cplim)
+ return t;
+ cp = matched_off + v;
+ }
+ } while (t = t->rn_dupedkey);
+ t = saved_t;
+ /* start searching up the tree */
+ do {
+ register struct radix_mask *m;
+ t = t->rn_p;
+ if (m = t->rn_mklist) {
+ /*
+ * After doing measurements here, it may
+ * turn out to be faster to open code
+ * rn_search_m here instead of always
+ * copying and masking.
+ */
+ off = min(t->rn_off, matched_off);
+ mstart = maskedKey + off;
+ do {
+ cp2 = mstart;
+ cp3 = m->rm_mask + off;
+ for (cp = v + off; cp < cplim;)
+ *cp2++ = *cp++ & *cp3++;
+ x = rn_search(maskedKey, t);
+ while (x && x->rn_mask != m->rm_mask)
+ x = x->rn_dupedkey;
+ if (x &&
+ (Bcmp(mstart, x->rn_key + off,
+ vlen - off) == 0))
+ return x;
+ } while (m = m->rm_mklist);
+ }
+ } while (t != top);
+ return 0;
+};
+
+#ifdef RN_DEBUG
+int rn_nodenum;
+struct radix_node *rn_clist;
+int rn_saveinfo;
+int rn_debug = 1;
+#endif
+
+struct radix_node *
+rn_newpair(v, b, nodes)
+ void *v;
+ int b;
+ struct radix_node nodes[2];
+{
+ register struct radix_node *tt = nodes, *t = tt + 1;
+ t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7);
+ t->rn_l = tt; t->rn_off = b >> 3;
+ tt->rn_b = -1; tt->rn_key = (caddr_t)v; tt->rn_p = t;
+ tt->rn_flags = t->rn_flags = RNF_ACTIVE;
+#ifdef RN_DEBUG
+ tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+ tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
+#endif
+ return t;
+}
+
+struct radix_node *
+rn_insert(v_arg, head, dupentry, nodes)
+ void *v_arg;
+ struct radix_node_head *head;
+ int *dupentry;
+ struct radix_node nodes[2];
+{
+ caddr_t v = v_arg;
+ struct radix_node *top = head->rnh_treetop;
+ int head_off = top->rn_off, vlen = (int)*((u_char *)v);
+ register struct radix_node *t = rn_search(v_arg, top);
+ register caddr_t cp = v + head_off;
+ register int b;
+ struct radix_node *tt;
+ /*
+ *find first bit at which v and t->rn_key differ
+ */
+ {
+ register caddr_t cp2 = t->rn_key + head_off;
+ register int cmp_res;
+ caddr_t cplim = v + vlen;
+
+ while (cp < cplim)
+ if (*cp2++ != *cp++)
+ goto on1;
+ *dupentry = 1;
+ return t;
+on1:
+ *dupentry = 0;
+ cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
+ for (b = (cp - v) << 3; cmp_res; b--)
+ cmp_res >>= 1;
+ }
+ {
+ register struct radix_node *p, *x = top;
+ cp = v;
+ do {
+ p = x;
+ if (cp[x->rn_off] & x->rn_bmask)
+ x = x->rn_r;
+ else x = x->rn_l;
+ } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */
+#ifdef RN_DEBUG
+ if (rn_debug)
+ printf("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)
+ printf("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, mlen, j;
+ int maskduplicated;
+
+ mlen = *(u_char *)netmask;
+ if (search) {
+ x = rn_search(netmask, rn_masktop);
+ mlen = *(u_char *)netmask;
+ if (Bcmp(netmask, x->rn_key, mlen) == 0)
+ return (x);
+ }
+ R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
+ if (x == 0)
+ return (0);
+ Bzero(x, max_keylen + 2 * sizeof (*x));
+ cp = (caddr_t)(x + 2);
+ Bcopy(netmask, cp, mlen);
+ netmask = cp;
+ x = rn_insert(netmask, mask_rnhead, &maskduplicated, x);
+ /*
+ * Calculate index of mask.
+ */
+ cplim = netmask + mlen;
+ for (cp = netmask + skip; cp < cplim; cp++)
+ if (*(u_char *)cp != 0xff)
+ break;
+ b = (cp - netmask) << 3;
+ if (cp != cplim) {
+ if (*cp != 0) {
+ gotOddMasks = 1;
+ for (j = 0x80; j; b++, j >>= 1)
+ if ((j & *cp) == 0)
+ break;
+ }
+ }
+ x->rn_b = -1 - b;
+ return (x);
+}
+
+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, *tt;
+ struct radix_node *saved_tt, *top = head->rnh_treetop;
+ short b = 0, b_leaf;
+ int mlen, keyduplicated;
+ caddr_t cplim;
+ 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) {
+ x = rn_search(netmask, rn_masktop);
+ mlen = *(u_char *)netmask;
+ if (Bcmp(netmask, x->rn_key, mlen) != 0) {
+ x = rn_addmask(netmask, 0, top->rn_off);
+ if (x == 0)
+ return (0);
+ }
+ netmask = x->rn_key;
+ b = -1 - x->rn_b;
+ }
+ /*
+ * Deal with duplicated keys: attach node to previous instance
+ */
+ saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
+ if (keyduplicated) {
+ do {
+ if (tt->rn_mask == netmask)
+ return (0);
+ t = tt;
+ if (netmask == 0 ||
+ (tt->rn_mask && rn_refines(netmask, tt->rn_mask)))
+ break;
+ } while (tt = tt->rn_dupedkey);
+ /*
+ * 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 && t == 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;
+ 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;
+ }
+#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
+ t = saved_tt;
+ tt->rn_key = (caddr_t) v;
+ tt->rn_b = -1;
+ tt->rn_flags = t->rn_flags & ~RNF_ROOT;
+ }
+ /*
+ * Put mask in tree.
+ */
+ if (netmask) {
+ tt->rn_mask = netmask;
+ tt->rn_b = x->rn_b;
+ }
+ t = saved_tt->rn_p;
+ 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) {
+ if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) {
+ MKGet(m);
+ if (m) {
+ Bzero(m, sizeof *m);
+ m->rm_b = x->rn_b;
+ m->rm_mask = x->rn_mask;
+ x->rn_mklist = t->rn_mklist = m;
+ }
+ }
+ } 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;
+ }
+ /* 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.
+ * For nodes of equal index, place more specific
+ * masks first.
+ */
+ cplim = netmask + mlen;
+ 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_mask == netmask) {
+ m->rm_refs++;
+ tt->rn_mklist = m;
+ return tt;
+ }
+ if (rn_refines(netmask, m->rm_mask))
+ break;
+ }
+ MKGet(m);
+ if (m == 0) {
+ printf("Mask for route not entered\n");
+ return (tt);
+ }
+ Bzero(m, sizeof *m);
+ m->rm_b = b_leaf;
+ m->rm_mask = netmask;
+ m->rm_mklist = *mp;
+ *mp = m;
+ tt->rn_mklist = m;
+ return tt;
+}
+
+struct radix_node *
+rn_delete(v_arg, netmask_arg, head)
+ void *v_arg, *netmask_arg;
+ struct radix_node_head *head;
+{
+ register struct radix_node *t, *p, *x, *tt;
+ struct radix_mask *m, *saved_m, **mp;
+ struct radix_node *dupedkey, *saved_tt, *top;
+ caddr_t v, netmask;
+ int b, head_off, vlen;
+
+ v = v_arg;
+ netmask = netmask_arg;
+ x = head->rnh_treetop;
+ tt = rn_search(v, x);
+ head_off = x->rn_off;
+ vlen = *(u_char *)v;
+ saved_tt = tt;
+ top = x;
+ if (tt == 0 ||
+ Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
+ return (0);
+ /*
+ * Delete our route from mask lists.
+ */
+ if (dupedkey = tt->rn_dupedkey) {
+ if (netmask)
+ netmask = rn_search(netmask, rn_masktop)->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 (m->rm_mask != tt->rn_mask) {
+ printf("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)
+ printf("rn_delete: couldn't find our annotation\n");
+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;
+ if (dupedkey) {
+ if (tt == saved_tt) {
+ x = dupedkey; x->rn_p = t;
+ if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x;
+ } else {
+ for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
+ p = p->rn_dupedkey;
+ if (p) p->rn_dupedkey = tt->rn_dupedkey;
+ else printf("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 {
+ for (m = t->rn_mklist; m;) {
+ struct radix_mask *mm = m->rm_mklist;
+ if (m == x->rn_mklist && (--(m->rm_refs) < 0)) {
+ x->rn_mklist = 0;
+ MKFree(m);
+ } else
+ printf("%s %x at %x\n",
+ "rn_delete: Orphaned Mask", m, x);
+ m = mm;
+ }
+ }
+ }
+ /*
+ * We may be holding an active internal node in the tree.
+ */
+ x = tt + 1;
+ if (t != x) {
+#ifndef RN_DEBUG
+ *t = *x;
+#else
+ b = t->rn_info; *t = *x; t->rn_info = b;
+#endif
+ t->rn_l->rn_p = t; t->rn_r->rn_p = t;
+ p = x->rn_p;
+ if (p->rn_l == x) p->rn_l = t; else p->rn_r = t;
+ }
+out:
+ tt->rn_flags &= ~RNF_ACTIVE;
+ tt[1].rn_flags &= ~RNF_ACTIVE;
+ return (tt);
+}
+
+int
+rn_walktree(h, f, w)
+ struct radix_node_head *h;
+ register int (*f)();
+ void *w;
+{
+ int error;
+ struct radix_node *base, *next;
+ register struct radix_node *rn = h->rnh_treetop;
+ /*
+ * This gets complicated because we may delete the node
+ * while applying the function f to it, so we need to calculate
+ * the successor node in advance.
+ */
+ /* First time through node, go left */
+ while (rn->rn_b >= 0)
+ rn = rn->rn_l;
+ for (;;) {
+ base = rn;
+ /* If at right child go back up, otherwise, go right */
+ while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0)
+ rn = rn->rn_p;
+ /* Find the next *leaf* since next node might vanish, too */
+ for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;)
+ rn = rn->rn_l;
+ next = rn;
+ /* Process leaves */
+ while (rn = base) {
+ base = rn->rn_dupedkey;
+ if (!(rn->rn_flags & RNF_ROOT) && (error = (*f)(rn, w)))
+ return (error);
+ }
+ rn = next;
+ if (rn->rn_flags & RNF_ROOT)
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+int
+rn_inithead(head, off)
+ void **head;
+ int off;
+{
+ register struct radix_node_head *rnh;
+ register struct radix_node *t, *tt, *ttt;
+ if (*head)
+ return (1);
+ R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh));
+ if (rnh == 0)
+ return (0);
+ Bzero(rnh, sizeof (*rnh));
+ *head = rnh;
+ t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
+ ttt = rnh->rnh_nodes + 2;
+ t->rn_r = ttt;
+ t->rn_p = t;
+ tt = t->rn_l;
+ tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
+ tt->rn_b = -1 - off;
+ *ttt = *tt;
+ ttt->rn_key = rn_ones;
+ rnh->rnh_addaddr = rn_addroute;
+ rnh->rnh_deladdr = rn_delete;
+ rnh->rnh_matchaddr = rn_match;
+ rnh->rnh_walktree = rn_walktree;
+ rnh->rnh_treetop = t;
+ return (1);
+}
+
+void
+rn_init()
+{
+ char *cp, *cplim;
+#ifdef KERNEL
+ struct domain *dom;
+
+ for (dom = domains; dom; dom = dom->dom_next)
+ if (dom->dom_maxrtkey > max_keylen)
+ max_keylen = dom->dom_maxrtkey;
+#endif
+ if (max_keylen == 0) {
+ printf("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;
+ maskedKey = 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/sys/net/radix.h b/sys/net/radix.h
new file mode 100644
index 0000000..a11057f
--- /dev/null
+++ b/sys/net/radix.h
@@ -0,0 +1,153 @@
+/*
+ * 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.1 (Berkeley) 6/10/93
+ */
+
+#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 */
+ caddr_t rm_mask; /* the mask */
+ int rm_refs; /* # of references to this struct */
+} *rn_mkfreelist;
+
+#define MKGet(m) {\
+ if (rn_mkfreelist) {\
+ m = rn_mkfreelist; \
+ rn_mkfreelist = (m)->rm_mklist; \
+ } else \
+ R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\
+
+#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
+
+struct radix_node_head {
+ struct radix_node *rnh_treetop;
+ int rnh_addrsize; /* permit, but not require fixed keys */
+ int rnh_pktsize; /* permit, but not require fixed keys */
+ struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
+ __P((void *v, void *mask,
+ struct radix_node_head *head, struct radix_node nodes[]));
+ struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
+ __P((void *v, void *mask,
+ struct radix_node_head *head, struct radix_node nodes[]));
+ struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
+ __P((void *v, void *mask, struct radix_node_head *head));
+ struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
+ __P((void *v, void *mask, struct radix_node_head *head));
+ struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
+ __P((void *v, struct radix_node_head *head));
+ struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
+ __P((void *v, struct radix_node_head *head));
+ int (*rnh_walktree) /* traverse tree */
+ __P((struct radix_node_head *head, int (*f)(), void *w));
+ struct radix_node rnh_nodes[3]; /* empty tree for common case */
+};
+
+
+#ifndef KERNEL
+#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n))
+#define 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);
+
+void rn_init __P((void));
+int rn_inithead __P((void **, int));
+int rn_refines __P((void *, void *));
+int rn_walktree __P((struct radix_node_head *, int (*)(), void *));
+struct radix_node
+ *rn_addmask __P((void *, int, int)),
+ *rn_addroute __P((void *, void *, struct radix_node_head *,
+ struct radix_node [2])),
+ *rn_delete __P((void *, void *, struct radix_node_head *)),
+ *rn_insert __P((void *, struct radix_node_head *, int *,
+ struct radix_node [2])),
+ *rn_match __P((void *, struct radix_node_head *)),
+ *rn_newpair __P((void *, int, struct radix_node[2])),
+ *rn_search __P((void *, struct radix_node *)),
+ *rn_search_m __P((void *, struct radix_node *, void *));
+
+#endif /*KERNEL*/
+#endif /* _RADIX_H_ */
diff --git a/sys/net/raw_cb.c b/sys/net/raw_cb.c
new file mode 100644
index 0000000..e44192d
--- /dev/null
+++ b/sys/net/raw_cb.c
@@ -0,0 +1,144 @@
+/*
+ * 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
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/raw_cb.h>
+#include <netinet/in.h>
+
+/*
+ * 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
+ */
+
+u_long raw_sendspace = RAWSNDQ;
+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);
+ if (error = soreserve(so, raw_sendspace, raw_recvspace))
+ 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/sys/net/raw_cb.h b/sys/net/raw_cb.h
new file mode 100644
index 0000000..6003e18
--- /dev/null
+++ b/sys/net/raw_cb.h
@@ -0,0 +1,69 @@
+/*
+ * 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
+ */
+
+/*
+ * 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
+struct rawcb rawcb; /* head of list */
+
+int raw_attach __P((struct socket *, int));
+void raw_ctlinput __P((int, struct sockaddr *));
+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
diff --git a/sys/net/raw_usrreq.c b/sys/net/raw_usrreq.c
new file mode 100644
index 0000000..560106e
--- /dev/null
+++ b/sys/net/raw_usrreq.c
@@ -0,0 +1,306 @@
+/*
+ * 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
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/raw_cb.h>
+
+/*
+ * 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;
+ if (n = m_copy(m, 0, (int)M_COPYALL)) {
+ 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)
+ int cmd;
+ struct sockaddr *arg;
+{
+
+ 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;
+
+#ifdef notdef
+ /*
+ * 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:
+ 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);
+ break;
+
+ case PRU_BIND:
+ if (rp->rcb_laddr) {
+ error = EINVAL; /* XXX */
+ break;
+ }
+ error = raw_bind(so, nam);
+ break;
+#endif
+
+ 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/sys/net/route.c b/sys/net/route.c
new file mode 100644
index 0000000..96902da
--- /dev/null
+++ b/sys/net/route.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 1980, 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)route.c 8.2 (Berkeley) 11/15/93
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/raw_cb.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+#ifdef NS
+#include <netns/ns.h>
+#endif
+
+#define SA(p) ((struct sockaddr *)(p))
+
+int rttrash; /* routes not in table but not freed */
+struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
+
+void
+rtable_init(table)
+ void **table;
+{
+ struct domain *dom;
+ for (dom = domains; dom; dom = dom->dom_next)
+ if (dom->dom_rtattach)
+ dom->dom_rtattach(&table[dom->dom_family],
+ dom->dom_rtoffset);
+}
+
+void
+route_init()
+{
+ rn_init(); /* initialize all zeroes, all ones, mask table */
+ rtable_init((void **)rt_tables);
+}
+
+/*
+ * Packet routing routines.
+ */
+void
+rtalloc(ro)
+ register struct route *ro;
+{
+ if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
+ return; /* XXX */
+ ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
+}
+
+struct rtentry *
+rtalloc1(dst, report)
+ register struct sockaddr *dst;
+ int report;
+{
+ register struct radix_node_head *rnh = rt_tables[dst->sa_family];
+ register struct rtentry *rt;
+ register struct radix_node *rn;
+ struct rtentry *newrt = 0;
+ struct rt_addrinfo info;
+ int s = splnet(), err = 0, msgtype = RTM_MISS;
+
+ if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
+ ((rn->rn_flags & RNF_ROOT) == 0)) {
+ newrt = rt = (struct rtentry *)rn;
+ if (report && (rt->rt_flags & RTF_CLONING)) {
+ err = rtrequest(RTM_RESOLVE, dst, SA(0),
+ SA(0), 0, &newrt);
+ if (err) {
+ newrt = rt;
+ rt->rt_refcnt++;
+ goto miss;
+ }
+ if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
+ msgtype = RTM_RESOLVE;
+ goto miss;
+ }
+ } else
+ rt->rt_refcnt++;
+ } else {
+ rtstat.rts_unreach++;
+ miss: if (report) {
+ bzero((caddr_t)&info, sizeof(info));
+ info.rti_info[RTAX_DST] = dst;
+ rt_missmsg(msgtype, &info, 0, err);
+ }
+ }
+ splx(s);
+ return (newrt);
+}
+
+void
+rtfree(rt)
+ register struct rtentry *rt;
+{
+ register struct ifaddr *ifa;
+
+ if (rt == 0)
+ panic("rtfree");
+ rt->rt_refcnt--;
+ if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
+ if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+ panic ("rtfree 2");
+ rttrash--;
+ if (rt->rt_refcnt < 0) {
+ printf("rtfree: %x not freed (neg refs)\n", rt);
+ return;
+ }
+ ifa = rt->rt_ifa;
+ IFAFREE(ifa);
+ Free(rt_key(rt));
+ Free(rt);
+ }
+}
+
+void
+ifafree(ifa)
+ register struct ifaddr *ifa;
+{
+ if (ifa == NULL)
+ panic("ifafree");
+ if (ifa->ifa_refcnt == 0)
+ free(ifa, M_IFADDR);
+ else
+ ifa->ifa_refcnt--;
+}
+
+/*
+ * Force a routing table entry to the specified
+ * destination to go through the given gateway.
+ * Normally called as a result of a routing redirect
+ * message from the network layer.
+ *
+ * N.B.: must be called at splnet
+ *
+ */
+int
+rtredirect(dst, gateway, netmask, flags, src, rtp)
+ struct sockaddr *dst, *gateway, *netmask, *src;
+ int flags;
+ struct rtentry **rtp;
+{
+ register struct rtentry *rt;
+ int error = 0;
+ short *stat = 0;
+ struct rt_addrinfo info;
+ struct ifaddr *ifa;
+
+ /* verify the gateway is directly reachable */
+ if ((ifa = ifa_ifwithnet(gateway)) == 0) {
+ error = ENETUNREACH;
+ goto out;
+ }
+ rt = rtalloc1(dst, 0);
+ /*
+ * If the redirect isn't from our current router for this dst,
+ * it's either old or wrong. If it redirects us to ourselves,
+ * we have a routing loop, perhaps as a result of an interface
+ * going down recently.
+ */
+#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
+ if (!(flags & RTF_DONE) && rt &&
+ (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
+ error = EINVAL;
+ else if (ifa_ifwithaddr(gateway))
+ error = EHOSTUNREACH;
+ if (error)
+ goto done;
+ /*
+ * Create a new entry if we just got back a wildcard entry
+ * or the the lookup failed. This is necessary for hosts
+ * which use routing redirects generated by smart gateways
+ * to dynamically build the routing tables.
+ */
+ if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
+ goto create;
+ /*
+ * Don't listen to the redirect if it's
+ * for a route to an interface.
+ */
+ if (rt->rt_flags & RTF_GATEWAY) {
+ if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
+ /*
+ * Changing from route to net => route to host.
+ * Create new route, rather than smashing route to net.
+ */
+ create:
+ flags |= RTF_GATEWAY | RTF_DYNAMIC;
+ error = rtrequest((int)RTM_ADD, dst, gateway,
+ netmask, flags,
+ (struct rtentry **)0);
+ stat = &rtstat.rts_dynamic;
+ } else {
+ /*
+ * Smash the current notion of the gateway to
+ * this destination. Should check about netmask!!!
+ */
+ rt->rt_flags |= RTF_MODIFIED;
+ flags |= RTF_MODIFIED;
+ stat = &rtstat.rts_newgateway;
+ rt_setgate(rt, rt_key(rt), gateway);
+ }
+ } else
+ error = EHOSTUNREACH;
+done:
+ if (rt) {
+ if (rtp && !error)
+ *rtp = rt;
+ else
+ rtfree(rt);
+ }
+out:
+ if (error)
+ rtstat.rts_badredirect++;
+ else if (stat != NULL)
+ (*stat)++;
+ bzero((caddr_t)&info, sizeof(info));
+ info.rti_info[RTAX_DST] = dst;
+ info.rti_info[RTAX_GATEWAY] = gateway;
+ info.rti_info[RTAX_NETMASK] = netmask;
+ info.rti_info[RTAX_AUTHOR] = src;
+ rt_missmsg(RTM_REDIRECT, &info, flags, error);
+}
+
+/*
+* Routing table ioctl interface.
+*/
+int
+rtioctl(req, data, p)
+ int req;
+ caddr_t data;
+ struct proc *p;
+{
+ return (EOPNOTSUPP);
+}
+
+struct ifaddr *
+ifa_ifwithroute(flags, dst, gateway)
+ int flags;
+ struct sockaddr *dst, *gateway;
+{
+ register struct ifaddr *ifa;
+ if ((flags & RTF_GATEWAY) == 0) {
+ /*
+ * If we are adding a route to an interface,
+ * and the interface is a pt to pt link
+ * we should search for the destination
+ * as our clue to the interface. Otherwise
+ * we can use the local address.
+ */
+ ifa = 0;
+ if (flags & RTF_HOST)
+ ifa = ifa_ifwithdstaddr(dst);
+ if (ifa == 0)
+ ifa = ifa_ifwithaddr(gateway);
+ } else {
+ /*
+ * If we are adding a route to a remote net
+ * or host, the gateway may still be on the
+ * other end of a pt to pt link.
+ */
+ ifa = ifa_ifwithdstaddr(gateway);
+ }
+ if (ifa == 0)
+ ifa = ifa_ifwithnet(gateway);
+ if (ifa == 0) {
+ struct rtentry *rt = rtalloc1(dst, 0);
+ if (rt == 0)
+ return (0);
+ rt->rt_refcnt--;
+ if ((ifa = rt->rt_ifa) == 0)
+ return (0);
+ }
+ if (ifa->ifa_addr->sa_family != dst->sa_family) {
+ struct ifaddr *oifa = ifa;
+ ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
+ if (ifa == 0)
+ ifa = oifa;
+ }
+ return (ifa);
+}
+
+#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+int
+rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
+ int req, flags;
+ struct sockaddr *dst, *gateway, *netmask;
+ struct rtentry **ret_nrt;
+{
+ int s = splnet(); int error = 0;
+ register struct rtentry *rt;
+ register struct radix_node *rn;
+ register struct radix_node_head *rnh;
+ struct ifaddr *ifa;
+ struct sockaddr *ndst;
+#define senderr(x) { error = x ; goto bad; }
+
+ if ((rnh = rt_tables[dst->sa_family]) == 0)
+ senderr(ESRCH);
+ if (flags & RTF_HOST)
+ netmask = 0;
+ switch (req) {
+ case RTM_DELETE:
+ if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
+ senderr(ESRCH);
+ if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+ panic ("rtrequest delete");
+ rt = (struct rtentry *)rn;
+ rt->rt_flags &= ~RTF_UP;
+ if (rt->rt_gwroute) {
+ rt = rt->rt_gwroute; RTFREE(rt);
+ (rt = (struct rtentry *)rn)->rt_gwroute = 0;
+ }
+ if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
+ ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
+ rttrash++;
+ if (ret_nrt)
+ *ret_nrt = rt;
+ else if (rt->rt_refcnt <= 0) {
+ rt->rt_refcnt++;
+ rtfree(rt);
+ }
+ break;
+
+ case RTM_RESOLVE:
+ if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
+ senderr(EINVAL);
+ ifa = rt->rt_ifa;
+ flags = rt->rt_flags & ~RTF_CLONING;
+ gateway = rt->rt_gateway;
+ if ((netmask = rt->rt_genmask) == 0)
+ flags |= RTF_HOST;
+ goto makeroute;
+
+ case RTM_ADD:
+ if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
+ senderr(ENETUNREACH);
+ makeroute:
+ R_Malloc(rt, struct rtentry *, sizeof(*rt));
+ if (rt == 0)
+ senderr(ENOBUFS);
+ Bzero(rt, sizeof(*rt));
+ rt->rt_flags = RTF_UP | flags;
+ if (rt_setgate(rt, dst, gateway)) {
+ Free(rt);
+ senderr(ENOBUFS);
+ }
+ ndst = rt_key(rt);
+ if (netmask) {
+ rt_maskedcopy(dst, ndst, netmask);
+ } else
+ Bcopy(dst, ndst, dst->sa_len);
+ rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
+ rnh, rt->rt_nodes);
+ if (rn == 0) {
+ if (rt->rt_gwroute)
+ rtfree(rt->rt_gwroute);
+ Free(rt_key(rt));
+ Free(rt);
+ senderr(EEXIST);
+ }
+ ifa->ifa_refcnt++;
+ rt->rt_ifa = ifa;
+ rt->rt_ifp = ifa->ifa_ifp;
+ if (req == RTM_RESOLVE)
+ rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
+ if (ifa->ifa_rtrequest)
+ ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
+ if (ret_nrt) {
+ *ret_nrt = rt;
+ rt->rt_refcnt++;
+ }
+ break;
+ }
+bad:
+ splx(s);
+ return (error);
+}
+
+int
+rt_setgate(rt0, dst, gate)
+ struct rtentry *rt0;
+ struct sockaddr *dst, *gate;
+{
+ caddr_t new, old;
+ int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
+ register struct rtentry *rt = rt0;
+
+ if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
+ old = (caddr_t)rt_key(rt);
+ R_Malloc(new, caddr_t, dlen + glen);
+ if (new == 0)
+ return 1;
+ rt->rt_nodes->rn_key = new;
+ } else {
+ new = rt->rt_nodes->rn_key;
+ old = 0;
+ }
+ Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
+ if (old) {
+ Bcopy(dst, new, dlen);
+ Free(old);
+ }
+ if (rt->rt_gwroute) {
+ rt = rt->rt_gwroute; RTFREE(rt);
+ rt = rt0; rt->rt_gwroute = 0;
+ }
+ if (rt->rt_flags & RTF_GATEWAY) {
+ rt->rt_gwroute = rtalloc1(gate, 1);
+ }
+ return 0;
+}
+
+void
+rt_maskedcopy(src, dst, netmask)
+ struct sockaddr *src, *dst, *netmask;
+{
+ register u_char *cp1 = (u_char *)src;
+ register u_char *cp2 = (u_char *)dst;
+ register u_char *cp3 = (u_char *)netmask;
+ u_char *cplim = cp2 + *cp3;
+ u_char *cplim2 = cp2 + *cp1;
+
+ *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
+ cp3 += 2;
+ if (cplim > cplim2)
+ cplim = cplim2;
+ while (cp2 < cplim)
+ *cp2++ = *cp1++ & *cp3++;
+ if (cp2 < cplim2)
+ bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
+}
+
+/*
+ * Set up a routing table entry, normally
+ * for an interface.
+ */
+int
+rtinit(ifa, cmd, flags)
+ register struct ifaddr *ifa;
+ int cmd, flags;
+{
+ register struct rtentry *rt;
+ register struct sockaddr *dst;
+ register struct sockaddr *deldst;
+ struct mbuf *m = 0;
+ struct rtentry *nrt = 0;
+ int error;
+
+ dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
+ if (cmd == RTM_DELETE) {
+ if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
+ m = m_get(M_WAIT, MT_SONAME);
+ deldst = mtod(m, struct sockaddr *);
+ rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
+ dst = deldst;
+ }
+ if (rt = rtalloc1(dst, 0)) {
+ rt->rt_refcnt--;
+ if (rt->rt_ifa != ifa) {
+ if (m)
+ (void) m_free(m);
+ return (flags & RTF_HOST ? EHOSTUNREACH
+ : ENETUNREACH);
+ }
+ }
+ }
+ error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
+ flags | ifa->ifa_flags, &nrt);
+ if (m)
+ (void) m_free(m);
+ if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
+ rt_newaddrmsg(cmd, ifa, error, nrt);
+ if (rt->rt_refcnt <= 0) {
+ rt->rt_refcnt++;
+ rtfree(rt);
+ }
+ }
+ if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
+ rt->rt_refcnt--;
+ if (rt->rt_ifa != ifa) {
+ printf("rtinit: wrong ifa (%x) was (%x)\n", ifa,
+ rt->rt_ifa);
+ if (rt->rt_ifa->ifa_rtrequest)
+ rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
+ IFAFREE(rt->rt_ifa);
+ rt->rt_ifa = ifa;
+ rt->rt_ifp = ifa->ifa_ifp;
+ ifa->ifa_refcnt++;
+ if (ifa->ifa_rtrequest)
+ ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
+ }
+ rt_newaddrmsg(cmd, ifa, error, nrt);
+ }
+ return (error);
+}
diff --git a/sys/net/route.h b/sys/net/route.h
new file mode 100644
index 0000000..2fbed9e
--- /dev/null
+++ b/sys/net/route.h
@@ -0,0 +1,261 @@
+/*
+ * 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
+ */
+
+/*
+ * Kernel resident routing tables.
+ *
+ * The routing tables are initialized when interface addresses
+ * are set by making entries for all directly connected interfaces.
+ */
+
+/*
+ * A route consists of a destination address and a reference
+ * to a routing entry. These are often held by protocols
+ * in their control blocks, e.g. inpcb.
+ */
+struct route {
+ struct rtentry *ro_rt;
+ struct sockaddr ro_dst;
+};
+
+/*
+ * These numbers are used by reliable protocols for determining
+ * retransmission behavior and are included in the routing structure.
+ */
+struct rt_metrics {
+ u_long rmx_locks; /* Kernel must leave these values alone */
+ u_long rmx_mtu; /* MTU for this path */
+ u_long rmx_hopcount; /* max hops expected */
+ u_long rmx_expire; /* lifetime for route, e.g. redirect */
+ u_long rmx_recvpipe; /* inbound delay-bandwith product */
+ u_long rmx_sendpipe; /* outbound delay-bandwith product */
+ u_long rmx_ssthresh; /* outbound gateway buffer limit */
+ u_long rmx_rtt; /* estimated round trip time */
+ u_long rmx_rttvar; /* estimated rtt variance */
+ u_long rmx_pksent; /* packets sent using this route */
+};
+
+/*
+ * rmx_rtt and rmx_rttvar are stored as microseconds;
+ * RTTTOPRHZ(rtt) converts to a value suitable for use
+ * by a protocol slowtimo counter.
+ */
+#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */
+#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ))
+
+/*
+ * We distinguish between routes to hosts and routes to networks,
+ * preferring the former if available. For each route we infer
+ * the interface to use from the gateway address supplied when
+ * the route was entered. Routes that forward packets through
+ * gateways are marked so that the output routines know to address the
+ * gateway rather than the ultimate destination.
+ */
+#ifndef RNF_NORMAL
+#include <net/radix.h>
+#endif
+struct rtentry {
+ struct radix_node rt_nodes[2]; /* tree glue, and other values */
+#define rt_key(r) ((struct sockaddr *)((r)->rt_nodes->rn_key))
+#define rt_mask(r) ((struct sockaddr *)((r)->rt_nodes->rn_mask))
+ struct sockaddr *rt_gateway; /* value */
+ short rt_flags; /* up/down?, host/net */
+ short rt_refcnt; /* # held references */
+ u_long rt_use; /* raw # packets forwarded */
+ struct ifnet *rt_ifp; /* the answer: interface to use */
+ struct ifaddr *rt_ifa; /* the answer: interface to use */
+ struct sockaddr *rt_genmask; /* for generation of cloned routes */
+ caddr_t rt_llinfo; /* pointer to link level info cache */
+ struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */
+ struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */
+};
+
+/*
+ * Following structure necessary for 4.3 compatibility;
+ * We should eventually move it to a compat file.
+ */
+struct ortentry {
+ u_long rt_hash; /* to speed lookups */
+ struct sockaddr rt_dst; /* key */
+ struct sockaddr rt_gateway; /* value */
+ short rt_flags; /* up/down?, host/net */
+ short rt_refcnt; /* # held references */
+ u_long rt_use; /* raw # packets forwarded */
+ struct ifnet *rt_ifp; /* the answer: interface to use */
+};
+
+#define RTF_UP 0x1 /* route usable */
+#define RTF_GATEWAY 0x2 /* destination is a gateway */
+#define RTF_HOST 0x4 /* host entry (net otherwise) */
+#define RTF_REJECT 0x8 /* host or net unreachable */
+#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */
+#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */
+#define RTF_DONE 0x40 /* message confirmed */
+#define RTF_MASK 0x80 /* subnet mask present */
+#define RTF_CLONING 0x100 /* generate new routes on use */
+#define RTF_XRESOLVE 0x200 /* external daemon resolves name */
+#define RTF_LLINFO 0x400 /* generated by ARP or ESIS */
+#define RTF_STATIC 0x800 /* manually added */
+#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */
+#define RTF_PROTO2 0x4000 /* protocol specific routing flag */
+#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
+
+
+/*
+ * Routing statistics.
+ */
+struct rtstat {
+ short rts_badredirect; /* bogus redirect calls */
+ short rts_dynamic; /* routes created by redirects */
+ short rts_newgateway; /* routes modified by redirects */
+ short rts_unreach; /* lookups which failed */
+ short rts_wildcard; /* lookups satisfied by a wildcard */
+};
+/*
+ * Structures for routing messages.
+ */
+struct rt_msghdr {
+ u_short rtm_msglen; /* to skip over non-understood messages */
+ u_char rtm_version; /* future binary compatibility */
+ u_char rtm_type; /* message type */
+ u_short rtm_index; /* index for associated ifp */
+ int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
+ int rtm_addrs; /* bitmask identifying sockaddrs in msg */
+ pid_t rtm_pid; /* identify sender */
+ int rtm_seq; /* for sender to identify action */
+ int rtm_errno; /* why failed */
+ int rtm_use; /* from rtentry */
+ u_long rtm_inits; /* which metrics we are initializing */
+ struct rt_metrics rtm_rmx; /* metrics themselves */
+};
+
+#define RTM_VERSION 3 /* Up the ante and ignore older versions */
+
+#define RTM_ADD 0x1 /* Add Route */
+#define RTM_DELETE 0x2 /* Delete Route */
+#define RTM_CHANGE 0x3 /* Change Metrics or flags */
+#define RTM_GET 0x4 /* Report Metrics */
+#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */
+#define RTM_REDIRECT 0x6 /* Told to use different route */
+#define RTM_MISS 0x7 /* Lookup failed on this address */
+#define RTM_LOCK 0x8 /* fix specified metrics */
+#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */
+#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */
+#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */
+#define RTM_NEWADDR 0xc /* address being added to iface */
+#define RTM_DELADDR 0xd /* address being removed from iface */
+#define RTM_IFINFO 0xe /* iface going up/down etc. */
+
+#define RTV_MTU 0x1 /* init or lock _mtu */
+#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */
+#define RTV_EXPIRE 0x4 /* init or lock _hopcount */
+#define RTV_RPIPE 0x8 /* init or lock _recvpipe */
+#define RTV_SPIPE 0x10 /* init or lock _sendpipe */
+#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */
+#define RTV_RTT 0x40 /* init or lock _rtt */
+#define RTV_RTTVAR 0x80 /* init or lock _rttvar */
+
+/*
+ * Bitmask values for rtm_addr.
+ */
+#define RTA_DST 0x1 /* destination sockaddr present */
+#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
+#define RTA_NETMASK 0x4 /* netmask sockaddr present */
+#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */
+#define RTA_IFP 0x10 /* interface name sockaddr present */
+#define RTA_IFA 0x20 /* interface addr sockaddr present */
+#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
+#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */
+
+/*
+ * Index offsets for sockaddr array for alternate internal encoding.
+ */
+#define RTAX_DST 0 /* destination sockaddr present */
+#define RTAX_GATEWAY 1 /* gateway sockaddr present */
+#define RTAX_NETMASK 2 /* netmask sockaddr present */
+#define RTAX_GENMASK 3 /* cloning mask sockaddr present */
+#define RTAX_IFP 4 /* interface name sockaddr present */
+#define RTAX_IFA 5 /* interface addr sockaddr present */
+#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */
+#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */
+#define RTAX_MAX 8 /* size of array to allocate */
+
+struct rt_addrinfo {
+ int rti_addrs;
+ struct sockaddr *rti_info[RTAX_MAX];
+};
+
+struct route_cb {
+ int ip_count;
+ int ns_count;
+ int iso_count;
+ int any_count;
+};
+
+#ifdef KERNEL
+#define RTFREE(rt) \
+ if ((rt)->rt_refcnt <= 1) \
+ rtfree(rt); \
+ else \
+ (rt)->rt_refcnt--;
+
+struct route_cb route_cb;
+struct rtstat rtstat;
+struct radix_node_head *rt_tables[AF_MAX+1];
+
+void route_init __P((void));
+int route_output __P((struct mbuf *, struct socket *));
+int route_usrreq __P((struct socket *,
+ int, struct mbuf *, struct mbuf *, struct mbuf *));
+void rt_ifmsg __P((struct ifnet *));
+void rt_maskedcopy __P((struct sockaddr *,
+ struct sockaddr *, struct sockaddr *));
+void rt_missmsg __P((int, struct rt_addrinfo *, int, int));
+void rt_newaddrmsg __P((int, struct ifaddr *, int, struct rtentry *));
+int rt_setgate __P((struct rtentry *,
+ struct sockaddr *, struct sockaddr *));
+void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *));
+void rtable_init __P((void **));
+void rtalloc __P((struct route *));
+struct rtentry *
+ rtalloc1 __P((struct sockaddr *, int));
+void rtfree __P((struct rtentry *));
+int rtinit __P((struct ifaddr *, int, int));
+int rtioctl __P((int, caddr_t, struct proc *));
+int rtredirect __P((struct sockaddr *, struct sockaddr *,
+ struct sockaddr *, int, struct sockaddr *, struct rtentry **));
+int rtrequest __P((int, struct sockaddr *,
+ struct sockaddr *, struct sockaddr *, int, struct rtentry **));
+#endif
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
new file mode 100644
index 0000000..d128121
--- /dev/null
+++ b/sys/net/rtsock.c
@@ -0,0 +1,833 @@
+/*
+ * 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.3 (Berkeley) 1/4/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/raw_cb.h>
+
+struct sockaddr route_dst = { 2, PF_ROUTE, };
+struct sockaddr route_src = { 2, PF_ROUTE, };
+struct sockproto route_proto = { PF_ROUTE, };
+
+struct walkarg {
+ int w_op, w_arg, w_given, w_needed, w_tmemsize;
+ caddr_t w_where, w_tmem;
+};
+
+static struct mbuf *
+ rt_msg1 __P((int, struct rt_addrinfo *));
+static int rt_msg2 __P((int,
+ struct rt_addrinfo *, caddr_t, struct walkarg *));
+static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
+
+/* Sleazy use of local variables throughout file, warning!!!! */
+#define dst info.rti_info[RTAX_DST]
+#define gate info.rti_info[RTAX_GATEWAY]
+#define netmask info.rti_info[RTAX_NETMASK]
+#define genmask info.rti_info[RTAX_GENMASK]
+#define ifpaddr info.rti_info[RTAX_IFP]
+#define ifaaddr info.rti_info[RTAX_IFA]
+#define brdaddr info.rti_info[RTAX_BRD]
+
+/*ARGSUSED*/
+int
+route_usrreq(so, req, m, nam, control)
+ register struct socket *so;
+ int req;
+ struct mbuf *m, *nam, *control;
+{
+ register int error = 0;
+ register struct rawcb *rp = sotorawcb(so);
+ int s;
+
+ if (req == PRU_ATTACH) {
+ MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
+ if (so->so_pcb = (caddr_t)rp)
+ bzero(so->so_pcb, sizeof(*rp));
+
+ }
+ if (req == PRU_DETACH && rp) {
+ int af = rp->rcb_proto.sp_protocol;
+ if (af == AF_INET)
+ route_cb.ip_count--;
+ else if (af == AF_NS)
+ route_cb.ns_count--;
+ else if (af == AF_ISO)
+ route_cb.iso_count--;
+ route_cb.any_count--;
+ }
+ s = splnet();
+ error = raw_usrreq(so, req, m, nam, control);
+ rp = sotorawcb(so);
+ if (req == PRU_ATTACH && rp) {
+ int af = rp->rcb_proto.sp_protocol;
+ if (error) {
+ free((caddr_t)rp, M_PCB);
+ splx(s);
+ return (error);
+ }
+ if (af == AF_INET)
+ route_cb.ip_count++;
+ else if (af == AF_NS)
+ route_cb.ns_count++;
+ else if (af == AF_ISO)
+ route_cb.iso_count++;
+ rp->rcb_faddr = &route_src;
+ route_cb.any_count++;
+ soisconnected(so);
+ so->so_options |= SO_USELOOPBACK;
+ }
+ splx(s);
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+route_output(m, so)
+ register struct mbuf *m;
+ struct socket *so;
+{
+ register struct rt_msghdr *rtm = 0;
+ register struct rtentry *rt = 0;
+ struct rtentry *saved_nrt = 0;
+ struct rt_addrinfo info;
+ int len, error = 0;
+ struct ifnet *ifp = 0;
+ struct ifaddr *ifa = 0;
+
+#define senderr(e) { error = e; goto flush;}
+ if (m == 0 || ((m->m_len < sizeof(long)) &&
+ (m = m_pullup(m, sizeof(long))) == 0))
+ return (ENOBUFS);
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("route_output");
+ len = m->m_pkthdr.len;
+ if (len < sizeof(*rtm) ||
+ len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
+ dst = 0;
+ senderr(EINVAL);
+ }
+ R_Malloc(rtm, struct rt_msghdr *, len);
+ if (rtm == 0) {
+ dst = 0;
+ senderr(ENOBUFS);
+ }
+ m_copydata(m, 0, len, (caddr_t)rtm);
+ if (rtm->rtm_version != RTM_VERSION) {
+ dst = 0;
+ senderr(EPROTONOSUPPORT);
+ }
+ rtm->rtm_pid = curproc->p_pid;
+ info.rti_addrs = rtm->rtm_addrs;
+ rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
+ if (dst == 0)
+ senderr(EINVAL);
+ if (genmask) {
+ struct radix_node *t;
+ t = rn_addmask((caddr_t)genmask, 1, 2);
+ if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
+ genmask = (struct sockaddr *)(t->rn_key);
+ else
+ senderr(ENOBUFS);
+ }
+ switch (rtm->rtm_type) {
+
+ case RTM_ADD:
+ if (gate == 0)
+ senderr(EINVAL);
+ error = rtrequest(RTM_ADD, dst, gate, netmask,
+ rtm->rtm_flags, &saved_nrt);
+ if (error == 0 && saved_nrt) {
+ rt_setmetrics(rtm->rtm_inits,
+ &rtm->rtm_rmx, &saved_nrt->rt_rmx);
+ saved_nrt->rt_refcnt--;
+ saved_nrt->rt_genmask = genmask;
+ }
+ break;
+
+ case RTM_DELETE:
+ error = rtrequest(RTM_DELETE, dst, gate, netmask,
+ rtm->rtm_flags, (struct rtentry **)0);
+ break;
+
+ case RTM_GET:
+ case RTM_CHANGE:
+ case RTM_LOCK:
+ rt = rtalloc1(dst, 0);
+ if (rt == 0)
+ senderr(ESRCH);
+ if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */
+ struct radix_node *rn;
+ extern struct radix_node_head *mask_rnhead;
+
+ if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
+ senderr(ESRCH);
+ if (netmask && (rn = rn_search(netmask,
+ mask_rnhead->rnh_treetop)))
+ netmask = (struct sockaddr *)rn->rn_key;
+ for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey)
+ if (netmask == (struct sockaddr *)rn->rn_mask)
+ break;
+ if (rn == 0)
+ senderr(ETOOMANYREFS);
+ rt = (struct rtentry *)rn;
+ }
+ switch(rtm->rtm_type) {
+
+ case RTM_GET:
+ dst = rt_key(rt);
+ gate = rt->rt_gateway;
+ netmask = rt_mask(rt);
+ genmask = rt->rt_genmask;
+ if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
+ if (ifp = rt->rt_ifp) {
+ ifpaddr = ifp->if_addrlist->ifa_addr;
+ ifaaddr = rt->rt_ifa->ifa_addr;
+ rtm->rtm_index = ifp->if_index;
+ } else {
+ ifpaddr = 0;
+ ifaaddr = 0;
+ }
+ }
+ len = rt_msg2(RTM_GET, &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_GET, &info, (caddr_t)rtm,
+ (struct walkarg *)0);
+ rtm->rtm_flags = rt->rt_flags;
+ rtm->rtm_rmx = rt->rt_rmx;
+ rtm->rtm_addrs = info.rti_addrs;
+ break;
+
+ case RTM_CHANGE:
+ if (gate && rt_setgate(rt, rt_key(rt), gate))
+ senderr(EDQUOT);
+ /* new gateway could require new ifaddr, ifp;
+ flags may also be different; ifp may be specified
+ by ll sockaddr when protocol address is ambiguous */
+ if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
+ (ifp = ifa->ifa_ifp))
+ ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
+ ifp);
+ else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
+ (ifa = ifa_ifwithroute(rt->rt_flags,
+ rt_key(rt), gate)))
+ ifp = ifa->ifa_ifp;
+ if (ifa) {
+ register struct ifaddr *oifa = rt->rt_ifa;
+ if (oifa != ifa) {
+ if (oifa && oifa->ifa_rtrequest)
+ oifa->ifa_rtrequest(RTM_DELETE,
+ rt, gate);
+ IFAFREE(rt->rt_ifa);
+ rt->rt_ifa = ifa;
+ ifa->ifa_refcnt++;
+ rt->rt_ifp = ifp;
+ }
+ }
+ rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
+ &rt->rt_rmx);
+ if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
+ rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
+ if (genmask)
+ rt->rt_genmask = genmask;
+ /*
+ * Fall into
+ */
+ case RTM_LOCK:
+ rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
+ rt->rt_rmx.rmx_locks |=
+ (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
+ break;
+ }
+ break;
+
+ default:
+ senderr(EOPNOTSUPP);
+ }
+
+flush:
+ if (rtm) {
+ if (error)
+ rtm->rtm_errno = error;
+ else
+ rtm->rtm_flags |= RTF_DONE;
+ }
+ if (rt)
+ rtfree(rt);
+ {
+ register struct rawcb *rp = 0;
+ /*
+ * Check to see if we don't want our own messages.
+ */
+ if ((so->so_options & SO_USELOOPBACK) == 0) {
+ if (route_cb.any_count <= 1) {
+ if (rtm)
+ Free(rtm);
+ m_freem(m);
+ return (error);
+ }
+ /* There is another listener, so construct message */
+ rp = sotorawcb(so);
+ }
+ if (rtm) {
+ m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
+ Free(rtm);
+ }
+ if (rp)
+ rp->rcb_proto.sp_family = 0; /* Avoid us */
+ if (dst)
+ route_proto.sp_protocol = dst->sa_family;
+ raw_input(m, &route_proto, &route_src, &route_dst);
+ if (rp)
+ rp->rcb_proto.sp_family = PF_ROUTE;
+ }
+ return (error);
+}
+
+void
+rt_setmetrics(which, in, out)
+ u_long which;
+ register struct rt_metrics *in, *out;
+{
+#define metric(f, e) if (which & (f)) out->e = in->e;
+ metric(RTV_RPIPE, rmx_recvpipe);
+ metric(RTV_SPIPE, rmx_sendpipe);
+ metric(RTV_SSTHRESH, rmx_ssthresh);
+ metric(RTV_RTT, rmx_rtt);
+ metric(RTV_RTTVAR, rmx_rttvar);
+ metric(RTV_HOPCOUNT, rmx_hopcount);
+ metric(RTV_MTU, rmx_mtu);
+ metric(RTV_EXPIRE, rmx_expire);
+#undef metric
+}
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static void
+rt_xaddrs(cp, cplim, rtinfo)
+ register caddr_t cp, cplim;
+ register struct rt_addrinfo *rtinfo;
+{
+ register struct sockaddr *sa;
+ register int i;
+
+ bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ ADVANCE(cp, sa);
+ }
+}
+
+/*
+ * Copy data from a buffer back into the indicated mbuf chain,
+ * starting "off" bytes from the beginning, extending the mbuf
+ * chain if necessary.
+ */
+void
+m_copyback(m0, off, len, cp)
+ struct mbuf *m0;
+ register int off;
+ register int len;
+ caddr_t cp;
+{
+ register int mlen;
+ register struct mbuf *m = m0, *n;
+ int totlen = 0;
+
+ if (m0 == 0)
+ return;
+ while (off > (mlen = m->m_len)) {
+ off -= mlen;
+ totlen += mlen;
+ if (m->m_next == 0) {
+ n = m_getclr(M_DONTWAIT, m->m_type);
+ if (n == 0)
+ goto out;
+ n->m_len = min(MLEN, len + off);
+ m->m_next = n;
+ }
+ m = m->m_next;
+ }
+ while (len > 0) {
+ mlen = min (m->m_len - off, len);
+ bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
+ cp += mlen;
+ len -= mlen;
+ mlen += off;
+ off = 0;
+ totlen += mlen;
+ if (len == 0)
+ break;
+ if (m->m_next == 0) {
+ n = m_get(M_DONTWAIT, m->m_type);
+ if (n == 0)
+ break;
+ n->m_len = min(MLEN, len);
+ m->m_next = n;
+ }
+ m = m->m_next;
+ }
+out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
+ m->m_pkthdr.len = totlen;
+}
+
+static struct mbuf *
+rt_msg1(type, rtinfo)
+ int type;
+ register struct rt_addrinfo *rtinfo;
+{
+ register struct rt_msghdr *rtm;
+ register struct mbuf *m;
+ register int i;
+ register struct sockaddr *sa;
+ int len, dlen;
+
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (m);
+ switch (type) {
+
+ case RTM_DELADDR:
+ case RTM_NEWADDR:
+ len = sizeof(struct ifa_msghdr);
+ break;
+
+ case RTM_IFINFO:
+ len = sizeof(struct if_msghdr);
+ break;
+
+ default:
+ len = sizeof(struct rt_msghdr);
+ }
+ if (len > MHLEN)
+ panic("rt_msg1");
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_pkthdr.rcvif = 0;
+ rtm = mtod(m, struct rt_msghdr *);
+ bzero((caddr_t)rtm, len);
+ for (i = 0; i < RTAX_MAX; i++) {
+ if ((sa = rtinfo->rti_info[i]) == NULL)
+ continue;
+ rtinfo->rti_addrs |= (1 << i);
+ dlen = ROUNDUP(sa->sa_len);
+ m_copyback(m, len, dlen, (caddr_t)sa);
+ len += dlen;
+ }
+ if (m->m_pkthdr.len != len) {
+ m_freem(m);
+ return (NULL);
+ }
+ rtm->rtm_msglen = len;
+ rtm->rtm_version = RTM_VERSION;
+ rtm->rtm_type = type;
+ return (m);
+}
+
+static int
+rt_msg2(type, rtinfo, cp, w)
+ int type;
+ register struct rt_addrinfo *rtinfo;
+ caddr_t cp;
+ struct walkarg *w;
+{
+ register int i;
+ int len, dlen, second_time = 0;
+ caddr_t cp0;
+
+ rtinfo->rti_addrs = 0;
+again:
+ switch (type) {
+
+ case RTM_DELADDR:
+ case RTM_NEWADDR:
+ len = sizeof(struct ifa_msghdr);
+ break;
+
+ case RTM_IFINFO:
+ len = sizeof(struct if_msghdr);
+ break;
+
+ default:
+ len = sizeof(struct rt_msghdr);
+ }
+ if (cp0 = cp)
+ cp += len;
+ for (i = 0; i < RTAX_MAX; i++) {
+ register struct sockaddr *sa;
+
+ if ((sa = rtinfo->rti_info[i]) == 0)
+ continue;
+ rtinfo->rti_addrs |= (1 << i);
+ dlen = ROUNDUP(sa->sa_len);
+ if (cp) {
+ bcopy((caddr_t)sa, cp, (unsigned)dlen);
+ cp += dlen;
+ }
+ len += dlen;
+ }
+ if (cp == 0 && w != NULL && !second_time) {
+ register struct walkarg *rw = w;
+
+ rw->w_needed += len;
+ if (rw->w_needed <= 0 && rw->w_where) {
+ if (rw->w_tmemsize < len) {
+ if (rw->w_tmem)
+ free(rw->w_tmem, M_RTABLE);
+ if (rw->w_tmem = (caddr_t)
+ malloc(len, M_RTABLE, M_NOWAIT))
+ rw->w_tmemsize = len;
+ }
+ if (rw->w_tmem) {
+ cp = rw->w_tmem;
+ second_time = 1;
+ goto again;
+ } else
+ rw->w_where = 0;
+ }
+ }
+ if (cp) {
+ register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
+
+ rtm->rtm_version = RTM_VERSION;
+ rtm->rtm_type = type;
+ rtm->rtm_msglen = len;
+ }
+ return (len);
+}
+
+/*
+ * This routine is called to generate a message from the routing
+ * socket indicating that a redirect has occured, a routing lookup
+ * has failed, or that a protocol has detected timeouts to a particular
+ * destination.
+ */
+void
+rt_missmsg(type, rtinfo, flags, error)
+ int type, flags, error;
+ register struct rt_addrinfo *rtinfo;
+{
+ register struct rt_msghdr *rtm;
+ register struct mbuf *m;
+ struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
+
+ if (route_cb.any_count == 0)
+ return;
+ m = rt_msg1(type, rtinfo);
+ if (m == 0)
+ return;
+ rtm = mtod(m, struct rt_msghdr *);
+ rtm->rtm_flags = RTF_DONE | flags;
+ rtm->rtm_errno = error;
+ rtm->rtm_addrs = rtinfo->rti_addrs;
+ route_proto.sp_protocol = sa ? sa->sa_family : 0;
+ raw_input(m, &route_proto, &route_src, &route_dst);
+}
+
+/*
+ * This routine is called to generate a message from the routing
+ * socket indicating that the status of a network interface has changed.
+ */
+void
+rt_ifmsg(ifp)
+ register struct ifnet *ifp;
+{
+ register struct if_msghdr *ifm;
+ struct mbuf *m;
+ struct rt_addrinfo info;
+
+ if (route_cb.any_count == 0)
+ return;
+ bzero((caddr_t)&info, sizeof(info));
+ m = rt_msg1(RTM_IFINFO, &info);
+ if (m == 0)
+ return;
+ ifm = mtod(m, struct if_msghdr *);
+ ifm->ifm_index = ifp->if_index;
+ ifm->ifm_flags = ifp->if_flags;
+ ifm->ifm_data = ifp->if_data;
+ ifm->ifm_addrs = 0;
+ route_proto.sp_protocol = 0;
+ raw_input(m, &route_proto, &route_src, &route_dst);
+}
+
+/*
+ * This is called to generate messages from the routing socket
+ * indicating a network interface has had addresses associated with it.
+ * if we ever reverse the logic and replace messages TO the routing
+ * socket indicate a request to configure interfaces, then it will
+ * be unnecessary as the routing socket will automatically generate
+ * copies of it.
+ */
+void
+rt_newaddrmsg(cmd, ifa, error, rt)
+ int cmd, error;
+ register struct ifaddr *ifa;
+ register struct rtentry *rt;
+{
+ struct rt_addrinfo info;
+ struct sockaddr *sa;
+ int pass;
+ struct mbuf *m;
+ struct ifnet *ifp = ifa->ifa_ifp;
+
+ if (route_cb.any_count == 0)
+ return;
+ for (pass = 1; pass < 3; pass++) {
+ bzero((caddr_t)&info, sizeof(info));
+ if ((cmd == RTM_ADD && pass == 1) ||
+ (cmd == RTM_DELETE && pass == 2)) {
+ register struct ifa_msghdr *ifam;
+ int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
+
+ ifaaddr = sa = ifa->ifa_addr;
+ ifpaddr = ifp->if_addrlist->ifa_addr;
+ netmask = ifa->ifa_netmask;
+ brdaddr = ifa->ifa_dstaddr;
+ if ((m = rt_msg1(ncmd, &info)) == NULL)
+ continue;
+ ifam = mtod(m, struct ifa_msghdr *);
+ ifam->ifam_index = ifp->if_index;
+ ifam->ifam_metric = ifa->ifa_metric;
+ ifam->ifam_flags = ifa->ifa_flags;
+ ifam->ifam_addrs = info.rti_addrs;
+ }
+ if ((cmd == RTM_ADD && pass == 2) ||
+ (cmd == RTM_DELETE && pass == 1)) {
+ register struct rt_msghdr *rtm;
+
+ if (rt == 0)
+ continue;
+ netmask = rt_mask(rt);
+ dst = sa = rt_key(rt);
+ gate = rt->rt_gateway;
+ if ((m = rt_msg1(cmd, &info)) == NULL)
+ continue;
+ rtm = mtod(m, struct rt_msghdr *);
+ rtm->rtm_index = ifp->if_index;
+ rtm->rtm_flags |= rt->rt_flags;
+ rtm->rtm_errno = error;
+ rtm->rtm_addrs = info.rti_addrs;
+ }
+ route_proto.sp_protocol = sa ? sa->sa_family : 0;
+ raw_input(m, &route_proto, &route_src, &route_dst);
+ }
+}
+
+/*
+ * This is used in dumping the kernel table via sysctl().
+ */
+int
+sysctl_dumpentry(rn, w)
+ struct radix_node *rn;
+ register struct walkarg *w;
+{
+ register struct rtentry *rt = (struct rtentry *)rn;
+ int error = 0, size;
+ struct rt_addrinfo info;
+
+ if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
+ return 0;
+ bzero((caddr_t)&info, sizeof(info));
+ dst = rt_key(rt);
+ gate = rt->rt_gateway;
+ netmask = rt_mask(rt);
+ genmask = rt->rt_genmask;
+ size = rt_msg2(RTM_GET, &info, 0, w);
+ if (w->w_where && w->w_tmem) {
+ register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
+
+ rtm->rtm_flags = rt->rt_flags;
+ rtm->rtm_use = rt->rt_use;
+ rtm->rtm_rmx = rt->rt_rmx;
+ rtm->rtm_index = rt->rt_ifp->if_index;
+ rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
+ rtm->rtm_addrs = info.rti_addrs;
+ if (error = copyout((caddr_t)rtm, w->w_where, size))
+ w->w_where = NULL;
+ else
+ w->w_where += size;
+ }
+ return (error);
+}
+
+int
+sysctl_iflist(af, w)
+ int af;
+ register struct walkarg *w;
+{
+ register struct ifnet *ifp;
+ register struct ifaddr *ifa;
+ struct rt_addrinfo info;
+ int len, error = 0;
+
+ bzero((caddr_t)&info, sizeof(info));
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ if (w->w_arg && w->w_arg != ifp->if_index)
+ continue;
+ ifa = ifp->if_addrlist;
+ ifpaddr = ifa->ifa_addr;
+ len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
+ ifpaddr = 0;
+ if (w->w_where && w->w_tmem) {
+ register struct if_msghdr *ifm;
+
+ ifm = (struct if_msghdr *)w->w_tmem;
+ ifm->ifm_index = ifp->if_index;
+ ifm->ifm_flags = ifp->if_flags;
+ ifm->ifm_data = ifp->if_data;
+ ifm->ifm_addrs = info.rti_addrs;
+ if (error = copyout((caddr_t)ifm, w->w_where, len))
+ return (error);
+ w->w_where += len;
+ }
+ while (ifa = ifa->ifa_next) {
+ if (af && af != ifa->ifa_addr->sa_family)
+ continue;
+ ifaaddr = ifa->ifa_addr;
+ netmask = ifa->ifa_netmask;
+ brdaddr = ifa->ifa_dstaddr;
+ len = rt_msg2(RTM_NEWADDR, &info, 0, w);
+ if (w->w_where && w->w_tmem) {
+ register struct ifa_msghdr *ifam;
+
+ ifam = (struct ifa_msghdr *)w->w_tmem;
+ ifam->ifam_index = ifa->ifa_ifp->if_index;
+ ifam->ifam_flags = ifa->ifa_flags;
+ ifam->ifam_metric = ifa->ifa_metric;
+ ifam->ifam_addrs = info.rti_addrs;
+ if (error = copyout(w->w_tmem, w->w_where, len))
+ return (error);
+ w->w_where += len;
+ }
+ }
+ ifaaddr = netmask = brdaddr = 0;
+ }
+ return (0);
+}
+
+int
+sysctl_rtable(name, namelen, where, given, new, newlen)
+ int *name;
+ int namelen;
+ caddr_t where;
+ size_t *given;
+ caddr_t *new;
+ size_t newlen;
+{
+ register struct radix_node_head *rnh;
+ int i, s, error = EINVAL;
+ u_char af;
+ struct walkarg w;
+
+ if (new)
+ return (EPERM);
+ if (namelen != 3)
+ return (EINVAL);
+ af = name[0];
+ Bzero(&w, sizeof(w));
+ w.w_where = where;
+ w.w_given = *given;
+ w.w_needed = 0 - w.w_given;
+ w.w_op = name[1];
+ w.w_arg = name[2];
+
+ s = splnet();
+ switch (w.w_op) {
+
+ case NET_RT_DUMP:
+ case NET_RT_FLAGS:
+ for (i = 1; i <= AF_MAX; i++)
+ if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
+ (error = rnh->rnh_walktree(rnh,
+ sysctl_dumpentry, &w)))
+ break;
+ break;
+
+ case NET_RT_IFLIST:
+ error = sysctl_iflist(af, &w);
+ }
+ splx(s);
+ if (w.w_tmem)
+ free(w.w_tmem, M_RTABLE);
+ w.w_needed += w.w_given;
+ if (where) {
+ *given = w.w_where - where;
+ if (*given < w.w_needed)
+ return (ENOMEM);
+ } else {
+ *given = (11 * w.w_needed) / 10;
+ }
+ return (error);
+}
+
+/*
+ * Definitions of protocols supported in the ROUTE domain.
+ */
+
+extern struct domain routedomain; /* or at least forward */
+
+struct protosw routesw[] = {
+{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
+ raw_input, route_output, raw_ctlinput, 0,
+ route_usrreq,
+ raw_init, 0, 0, 0,
+ sysctl_rtable,
+}
+};
+
+struct domain routedomain =
+ { PF_ROUTE, "route", route_init, 0, 0,
+ routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
diff --git a/sys/net/slcompress.c b/sys/net/slcompress.c
new file mode 100644
index 0000000..70af935
--- /dev/null
+++ b/sys/net/slcompress.c
@@ -0,0 +1,535 @@
+/*-
+ * 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.
+ *
+ * @(#)slcompress.c 8.2 (Berkeley) 4/16/94
+ */
+
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ *
+ * static char rcsid[] =
+ * "$Header: slcompress.c,v 1.19 89/12/31 08:52:59 van Exp $";
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <net/slcompress.h>
+
+#ifndef SL_NO_STATS
+#define INCR(counter) ++comp->counter;
+#else
+#define INCR(counter)
+#endif
+
+#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
+#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
+#ifndef KERNEL
+#define ovbcopy bcopy
+#endif
+
+void
+sl_compress_init(comp)
+ struct slcompress *comp;
+{
+ register u_int i;
+ register struct cstate *tstate = comp->tstate;
+
+ bzero((char *)comp, sizeof(*comp));
+ for (i = MAX_STATES - 1; i > 0; --i) {
+ tstate[i].cs_id = i;
+ tstate[i].cs_next = &tstate[i - 1];
+ }
+ tstate[0].cs_next = &tstate[MAX_STATES - 1];
+ tstate[0].cs_id = 0;
+ comp->last_cs = &tstate[0];
+ comp->last_recv = 255;
+ comp->last_xmit = 255;
+ comp->flags = SLF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero. ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+ if ((u_short)(n) >= 256) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+#define ENCODEZ(n) { \
+ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
+ *cp++ = 0; \
+ cp[1] = (n); \
+ cp[0] = (n) >> 8; \
+ cp += 2; \
+ } else { \
+ *cp++ = (n); \
+ } \
+}
+
+#define DECODEL(f) { \
+ if (*cp == 0) {\
+ (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
+ cp += 3; \
+ } else { \
+ (f) = htonl(ntohl(f) + (u_long)*cp++); \
+ } \
+}
+
+#define DECODES(f) { \
+ if (*cp == 0) {\
+ (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
+ cp += 3; \
+ } else { \
+ (f) = htons(ntohs(f) + (u_long)*cp++); \
+ } \
+}
+
+#define DECODEU(f) { \
+ if (*cp == 0) {\
+ (f) = htons((cp[1] << 8) | cp[2]); \
+ cp += 3; \
+ } else { \
+ (f) = htons((u_long)*cp++); \
+ } \
+}
+
+u_int
+sl_compress_tcp(m, ip, comp, compress_cid)
+ struct mbuf *m;
+ register struct ip *ip;
+ struct slcompress *comp;
+ int compress_cid;
+{
+ register struct cstate *cs = comp->last_cs->cs_next;
+ register u_int hlen = ip->ip_hl;
+ register struct tcphdr *oth;
+ register struct tcphdr *th;
+ register u_int deltaS, deltaA;
+ register u_int changes = 0;
+ u_char new_seq[16];
+ register u_char *cp = new_seq;
+
+ /*
+ * Bail if this is an IP fragment or if the TCP packet isn't
+ * `compressible' (i.e., ACK isn't set or some other control bit is
+ * set). (We assume that the caller has already made sure the
+ * packet is IP proto TCP).
+ */
+ if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
+ return (TYPE_IP);
+
+ th = (struct tcphdr *)&((int *)ip)[hlen];
+ if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
+ return (TYPE_IP);
+ /*
+ * Packet is compressible -- we're going to send either a
+ * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
+ * to locate (or create) the connection state. Special case the
+ * most recently used connection since it's most likely to be used
+ * again & we don't have to do any reordering if it's used.
+ */
+ INCR(sls_packets)
+ if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+ ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+ *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
+ /*
+ * Wasn't the first -- search for it.
+ *
+ * States are kept in a circularly linked list with
+ * last_cs pointing to the end of the list. The
+ * list is kept in lru order by moving a state to the
+ * head of the list whenever it is referenced. Since
+ * the list is short and, empirically, the connection
+ * we want is almost always near the front, we locate
+ * states via linear search. If we don't find a state
+ * for the datagram, the oldest state is (re-)used.
+ */
+ register struct cstate *lcs;
+ register struct cstate *lastcs = comp->last_cs;
+
+ do {
+ lcs = cs; cs = cs->cs_next;
+ INCR(sls_searches)
+ if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+ && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+ && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
+ goto found;
+ } while (cs != lastcs);
+
+ /*
+ * Didn't find it -- re-use oldest cstate. Send an
+ * uncompressed packet that tells the other side what
+ * connection number we're using for this conversation.
+ * Note that since the state list is circular, the oldest
+ * state points to the newest and we only need to set
+ * last_cs to update the lru linkage.
+ */
+ INCR(sls_misses)
+ comp->last_cs = lcs;
+ hlen += th->th_off;
+ hlen <<= 2;
+ goto uncompressed;
+
+ found:
+ /*
+ * Found it -- move to the front on the connection list.
+ */
+ if (cs == lastcs)
+ comp->last_cs = lcs;
+ else {
+ lcs->cs_next = cs->cs_next;
+ cs->cs_next = lastcs->cs_next;
+ lastcs->cs_next = cs;
+ }
+ }
+
+ /*
+ * Make sure that only what we expect to change changed. The first
+ * line of the `if' checks the IP protocol version, header length &
+ * type of service. The 2nd line checks the "Don't fragment" bit.
+ * The 3rd line checks the time-to-live and protocol (the protocol
+ * check is unnecessary but costless). The 4th line checks the TCP
+ * header length. The 5th line checks IP options, if any. The 6th
+ * line checks TCP options, if any. If any of these things are
+ * different between the previous & current datagram, we send the
+ * current datagram `uncompressed'.
+ */
+ oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
+ deltaS = hlen;
+ hlen += th->th_off;
+ hlen <<= 2;
+
+ if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
+ ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
+ ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
+ th->th_off != oth->th_off ||
+ (deltaS > 5 &&
+ BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+ (th->th_off > 5 &&
+ BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
+ goto uncompressed;
+
+ /*
+ * Figure out which of the changing fields changed. The
+ * receiver expects changes in the order: urgent, window,
+ * ack, seq (the order minimizes the number of temporaries
+ * needed in this section of code).
+ */
+ if (th->th_flags & TH_URG) {
+ deltaS = ntohs(th->th_urp);
+ ENCODEZ(deltaS);
+ changes |= NEW_U;
+ } else if (th->th_urp != oth->th_urp)
+ /* argh! URG not set but urp changed -- a sensible
+ * implementation should never do this but RFC793
+ * doesn't prohibit the change so we have to deal
+ * with it. */
+ goto uncompressed;
+
+ if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) {
+ ENCODE(deltaS);
+ changes |= NEW_W;
+ }
+
+ if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
+ if (deltaA > 0xffff)
+ goto uncompressed;
+ ENCODE(deltaA);
+ changes |= NEW_A;
+ }
+
+ if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
+ if (deltaS > 0xffff)
+ goto uncompressed;
+ ENCODE(deltaS);
+ changes |= NEW_S;
+ }
+
+ switch(changes) {
+
+ case 0:
+ /*
+ * Nothing changed. If this packet contains data and the
+ * last one didn't, this is probably a data packet following
+ * an ack (normal on an interactive connection) and we send
+ * it compressed. Otherwise it's probably a retransmit,
+ * retransmitted ack or window probe. Send it uncompressed
+ * in case the other side missed the compressed version.
+ */
+ if (ip->ip_len != cs->cs_ip.ip_len &&
+ ntohs(cs->cs_ip.ip_len) == hlen)
+ break;
+
+ /* (fall through) */
+
+ case SPECIAL_I:
+ case SPECIAL_D:
+ /*
+ * actual changes match one of our special case encodings --
+ * send packet uncompressed.
+ */
+ goto uncompressed;
+
+ case NEW_S|NEW_A:
+ if (deltaS == deltaA &&
+ deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for echoed terminal traffic */
+ changes = SPECIAL_I;
+ cp = new_seq;
+ }
+ break;
+
+ case NEW_S:
+ if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+ /* special case for data xfer */
+ changes = SPECIAL_D;
+ cp = new_seq;
+ }
+ break;
+ }
+
+ deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+ if (deltaS != 1) {
+ ENCODEZ(deltaS);
+ changes |= NEW_I;
+ }
+ if (th->th_flags & TH_PUSH)
+ changes |= TCP_PUSH_BIT;
+ /*
+ * Grab the cksum before we overwrite it below. Then update our
+ * state with this packet's header.
+ */
+ deltaA = ntohs(th->th_sum);
+ BCOPY(ip, &cs->cs_ip, hlen);
+
+ /*
+ * We want to use the original packet as our compressed packet.
+ * (cp - new_seq) is the number of bytes we need for compressed
+ * sequence numbers. In addition we need one byte for the change
+ * mask, one for the connection id and two for the tcp checksum.
+ * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
+ * many bytes of the original packet to toss so subtract the two to
+ * get the new packet size.
+ */
+ deltaS = cp - new_seq;
+ cp = (u_char *)ip;
+ if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
+ comp->last_xmit = cs->cs_id;
+ hlen -= deltaS + 4;
+ cp += hlen;
+ *cp++ = changes | NEW_C;
+ *cp++ = cs->cs_id;
+ } else {
+ hlen -= deltaS + 3;
+ cp += hlen;
+ *cp++ = changes;
+ }
+ m->m_len -= hlen;
+ m->m_data += hlen;
+ *cp++ = deltaA >> 8;
+ *cp++ = deltaA;
+ BCOPY(new_seq, cp, deltaS);
+ INCR(sls_compressed)
+ return (TYPE_COMPRESSED_TCP);
+
+ /*
+ * Update connection state cs & send uncompressed packet ('uncompressed'
+ * means a regular ip/tcp packet but with the 'conversation id' we hope
+ * to use on future compressed packets in the protocol field).
+ */
+uncompressed:
+ BCOPY(ip, &cs->cs_ip, hlen);
+ ip->ip_p = cs->cs_id;
+ comp->last_xmit = cs->cs_id;
+ return (TYPE_UNCOMPRESSED_TCP);
+}
+
+
+int
+sl_uncompress_tcp(bufp, len, type, comp)
+ u_char **bufp;
+ int len;
+ u_int type;
+ struct slcompress *comp;
+{
+ register u_char *cp;
+ register u_int hlen, changes;
+ register struct tcphdr *th;
+ register struct cstate *cs;
+ register struct ip *ip;
+
+ switch (type) {
+
+ case TYPE_UNCOMPRESSED_TCP:
+ ip = (struct ip *) *bufp;
+ if (ip->ip_p >= MAX_STATES)
+ goto bad;
+ cs = &comp->rstate[comp->last_recv = ip->ip_p];
+ comp->flags &=~ SLF_TOSS;
+ ip->ip_p = IPPROTO_TCP;
+ hlen = ip->ip_hl;
+ hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
+ hlen <<= 2;
+ BCOPY(ip, &cs->cs_ip, hlen);
+ cs->cs_ip.ip_sum = 0;
+ cs->cs_hlen = hlen;
+ INCR(sls_uncompressedin)
+ return (len);
+
+ default:
+ goto bad;
+
+ case TYPE_COMPRESSED_TCP:
+ break;
+ }
+ /* We've got a compressed packet. */
+ INCR(sls_compressedin)
+ cp = *bufp;
+ changes = *cp++;
+ if (changes & NEW_C) {
+ /* Make sure the state index is in range, then grab the state.
+ * If we have a good state index, clear the 'discard' flag. */
+ if (*cp >= MAX_STATES)
+ goto bad;
+
+ comp->flags &=~ SLF_TOSS;
+ comp->last_recv = *cp++;
+ } else {
+ /* this packet has an implicit state index. If we've
+ * had a line error since the last time we got an
+ * explicit state index, we have to toss the packet. */
+ if (comp->flags & SLF_TOSS) {
+ INCR(sls_tossed)
+ return (0);
+ }
+ }
+ cs = &comp->rstate[comp->last_recv];
+ hlen = cs->cs_ip.ip_hl << 2;
+ th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+ th->th_sum = htons((*cp << 8) | cp[1]);
+ cp += 2;
+ if (changes & TCP_PUSH_BIT)
+ th->th_flags |= TH_PUSH;
+ else
+ th->th_flags &=~ TH_PUSH;
+
+ switch (changes & SPECIALS_MASK) {
+ case SPECIAL_I:
+ {
+ register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+ th->th_ack = htonl(ntohl(th->th_ack) + i);
+ th->th_seq = htonl(ntohl(th->th_seq) + i);
+ }
+ break;
+
+ case SPECIAL_D:
+ th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
+ - cs->cs_hlen);
+ break;
+
+ default:
+ if (changes & NEW_U) {
+ th->th_flags |= TH_URG;
+ DECODEU(th->th_urp)
+ } else
+ th->th_flags &=~ TH_URG;
+ if (changes & NEW_W)
+ DECODES(th->th_win)
+ if (changes & NEW_A)
+ DECODEL(th->th_ack)
+ if (changes & NEW_S)
+ DECODEL(th->th_seq)
+ break;
+ }
+ if (changes & NEW_I) {
+ DECODES(cs->cs_ip.ip_id)
+ } else
+ cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
+
+ /*
+ * At this point, cp points to the first byte of data in the
+ * packet. If we're not aligned on a 4-byte boundary, copy the
+ * data down so the ip & tcp headers will be aligned. Then back up
+ * cp by the tcp/ip header length to make room for the reconstructed
+ * header (we assume the packet we were handed has enough space to
+ * prepend 128 bytes of header). Adjust the length to account for
+ * the new header & fill in the IP total length.
+ */
+ len -= (cp - *bufp);
+ if (len < 0)
+ /* we must have dropped some characters (crc should detect
+ * this but the old slip framing won't) */
+ goto bad;
+
+ if ((int)cp & 3) {
+ if (len > 0)
+ (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
+ cp = (u_char *)((int)cp &~ 3);
+ }
+ cp -= cs->cs_hlen;
+ len += cs->cs_hlen;
+ cs->cs_ip.ip_len = htons(len);
+ BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
+ *bufp = cp;
+
+ /* recompute the ip header checksum */
+ {
+ register u_short *bp = (u_short *)cp;
+ for (changes = 0; hlen > 0; hlen -= 2)
+ changes += *bp++;
+ changes = (changes & 0xffff) + (changes >> 16);
+ changes = (changes & 0xffff) + (changes >> 16);
+ ((struct ip *)cp)->ip_sum = ~ changes;
+ }
+ return (len);
+bad:
+ comp->flags |= SLF_TOSS;
+ INCR(sls_errorin)
+ return (0);
+}
diff --git a/sys/net/slcompress.h b/sys/net/slcompress.h
new file mode 100644
index 0000000..cefe940
--- /dev/null
+++ b/sys/net/slcompress.h
@@ -0,0 +1,157 @@
+/* slcompress.h 8.1 93/06/10 */
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
+ *
+ * Copyright (c) 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.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#define MAX_STATES 16 /* must be > 2 and < 256 */
+#define MAX_HDR MLEN /* XXX 4bsd-ism: should really be 128 */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowlegement, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ struct cstate *cs_next; /* next most recently used cstate (xmit only) */
+ u_short cs_hlen; /* size of hdr (receive only) */
+ u_char cs_id; /* connection # associated with this state */
+ u_char cs_filler;
+ union {
+ char csu_hdr[MAX_HDR];
+ struct ip csu_ip; /* ip/tcp hdr from most recent packet */
+ } slcs_u;
+};
+#define cs_ip slcs_u.csu_ip
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these
+ * per line).
+ */
+struct slcompress {
+ struct cstate *last_cs; /* most recently used tstate */
+ u_char last_recv; /* last rcvd conn. id */
+ u_char last_xmit; /* last sent conn. id */
+ u_short flags;
+#ifndef SL_NO_STATS
+ int sls_packets; /* outbound packets */
+ int sls_compressed; /* outbound compressed packets */
+ int sls_searches; /* searches for connection state */
+ int sls_misses; /* times couldn't find conn. state */
+ int sls_uncompressedin; /* inbound uncompressed packets */
+ int sls_compressedin; /* inbound compressed packets */
+ int sls_errorin; /* inbound unknown type packets */
+ int sls_tossed; /* inbound packets tossed because of error */
+#endif
+ struct cstate tstate[MAX_STATES]; /* xmit connection states */
+ struct cstate rstate[MAX_STATES]; /* receive connection states */
+};
+/* flag values */
+#define SLF_TOSS 1 /* tossing rcvd frames because of input err */
+
+void sl_compress_init __P((struct slcompress *));
+u_int sl_compress_tcp __P((struct mbuf *,
+ struct ip *, struct slcompress *, int));
+int sl_uncompress_tcp __P((u_char **, int, u_int, struct slcompress *));
diff --git a/sys/net/slip.h b/sys/net/slip.h
new file mode 100644
index 0000000..4caeb46
--- /dev/null
+++ b/sys/net/slip.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 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.
+ *
+ * @(#)slip.h 8.1 (Berkeley) 2/12/94
+ */
+
+/* Ioctls operating on SLIP ttys. */
+#define SLIOCGUNIT _IOR('t', 88, int) /* get slip unit number */
+
+/*
+ * Definitions of the pseudo-link-level header attached to slip
+ * packets grabbed by the packet filter (bpf) traffic monitor.
+ */
+#define SLIP_HDRLEN 16 /* BPF SLIP header length */
+
+/* Offsets into BPF SLIP header. */
+#define SLX_DIR 0 /* direction; see below */
+#define SLX_CHDR 1 /* compressed header data */
+#define CHDR_LEN 15 /* length of compressed header data */
+
+#define SLIPDIR_IN 0 /* incoming */
+#define SLIPDIR_OUT 1 /* outgoing */
OpenPOWER on IntegriCloud