This commit is contained in:
seta75D
2021-10-11 18:37:13 -03:00
commit ff309bfe1c
14130 changed files with 3180272 additions and 0 deletions

13
sys/net/Makefile Normal file
View File

@@ -0,0 +1,13 @@
#
# @(#)Makefile 1.1 94/10/31 SMI
#
HFILES = af.h if.h if_arp.h if_ieee802.h netisr.h nit.h nit_buf.h nit_if.h \
nit_pf.h packetfilt.h raw_cb.h route.h
HDIR=$(DESTDIR)/usr/include/net
install_h: $(HFILES) FRC
install -d -m 755 $(HDIR)
install -m 444 $(HFILES) $(HDIR)
FRC:

84
sys/net/af.c Normal file
View File

@@ -0,0 +1,84 @@
/* @(#)af.c 1.1 94/10/31 SMI; from UCB 7.1 6/4/86 */
/*
* Copyright (c) 1983, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <net/af.h>
/*
* Address family support routines
*/
int null_hash(), null_netmatch();
#define AFNULL \
{ null_hash, null_netmatch }
#ifdef INET
extern int inet_hash(), inet_netmatch();
#define AFINET \
{ inet_hash, inet_netmatch }
#else
#define AFINET AFNULL
#endif
struct afswitch afswitch[AF_MAX] = {
AFNULL, AFNULL, AFINET, AFINET, AFNULL, /* 0 - 4 */
AFNULL, AFNULL, AFNULL, AFNULL, AFNULL, /* 5 - 9 */
AFNULL, AFNULL, AFNULL, AFNULL, AFNULL, /* 10 - 14 */
AFNULL, AFNULL, AFNULL, AFNULL /* 15 - 19 */
};
null_init()
{
register struct afswitch *af;
for (af = afswitch; af < &afswitch[AF_MAX]; af++)
if (af->af_hash == (int (*)())NULL) {
af->af_hash = null_hash;
}
}
/*ARGSUSED*/
null_hash(addr, hp)
struct sockaddr *addr;
struct afhash *hp;
{
hp->afh_nethash = hp->afh_hosthash = 0;
}
/*ARGSUSED*/
null_netmatch(a1, a2)
struct sockaddr *a1, *a2;
{
return (0);
}
/*
* Add a new protocol family to the socket system.
*/
protocol_family(dp, hash, netmatch)
register struct domain *dp;
int (*hash)();
int (*netmatch)();
{
# ifdef lint
if (dp != dp) protocol_family(dp, hash, netmatch);
# endif lint
if (hash != (int (*)())NULL)
afswitch[dp->dom_family].af_hash = hash;
if (netmatch != (int (*)())NULL)
afswitch[dp->dom_family].af_netmatch = netmatch;
dp->dom_next = domains;
domains = dp;
}

40
sys/net/af.h Normal file
View File

@@ -0,0 +1,40 @@
/* @(#)af.h 1.1 94/10/31 SMI; from UCB 7.1 */
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef _net_af_h
#define _net_af_h
/*
* Address family routines,
* used in handling generic sockaddr structures.
*
* Hash routine is called
* af_hash(addr, h);
* struct sockaddr *addr; struct afhash *h;
* producing an afhash structure for addr.
*
* Netmatch routine is called
* af_netmatch(addr1, addr2);
* where addr1 and addr2 are sockaddr *. Returns 1 if network
* values match, 0 otherwise.
*/
struct afswitch {
int (*af_hash)();
int (*af_netmatch)();
};
struct afhash {
u_int afh_hosthash;
u_int afh_nethash;
};
#ifdef KERNEL
extern struct afswitch afswitch[];
#endif
#endif /*!_net_af_h*/

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

@@ -0,0 +1,592 @@
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*
* @(#)if.c 1.1 94/10/31 SMI; from UCB 7.3 4/7/88
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/user.h>
#include <sys/kernel.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/mbuf.h>
#include <net/if.h>
#include <net/af.h>
#include <net/if_arp.h>
#ifdef OPENPROMS
#include <mon/obpdefs.h>
#else OPENPROMS
#include <mon/sunromvec.h>
#endif OPENPROMS
#include <sun/autoconf.h>
#include <sun/openprom.h>
#include "ether.h"
#ifdef OPENPROMS
#ifdef MULTIPROCESSOR
/*
* We can't risk user processes on other cpus bashing the output device
* while the boot prom is also bashing it, so go through the code
* that coordinates the output device.
*/
#define prom_printf mpprom_printf
#endif MULTIPROCESSOR
/*
* Undefine DPRINTF to remove compiled debug code.
* #define DPRINTF if (bootpath_debug) prom_printf
*/
#ifdef DPRINTF
static int bootpath_debug = 1;
#endif DPRINTF
#endif OPENPROMS
/*LINTLIBRARY*/
int ifqmaxlen = IFQ_MAXLEN;
/*
* Network interface utility routines.
*
* Routines with ifa_ifwith* names typically take sockaddr *'s as
* parameters.
*/
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();
}
#ifdef vax
/*
* Call each interface on a Unibus reset.
*/
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
/*
* Attach an interface to the
* list of "active" interfaces.
*/
if_attach(ifp)
struct ifnet *ifp;
{
register struct ifnet **p = &ifnet;
while (*p)
p = &((*p)->if_next);
*p = ifp;
}
/*
* Locate an interface based on a complete address.
*/
/*ARGSUSED*/
struct ifaddr *
ifa_ifwithaddr(addr)
struct sockaddr *addr;
{
register struct ifnet *ifp;
register struct ifaddr *ifa;
#define equal(a1, a2) \
(bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 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(&ifa->ifa_addr, addr))
return (ifa);
if ((ifp->if_flags & IFF_BROADCAST) &&
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)
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(&ifa->ifa_dstaddr, addr))
return (ifa);
}
return ((struct ifaddr *)0);
}
/*
* Find an interface on a specific network. If many, choice
* is first found.
*/
struct ifaddr *
ifa_ifwithnet(addr)
register struct sockaddr *addr;
{
register struct ifnet *ifp;
register struct ifaddr *ifa;
register u_int af = addr->sa_family;
register int (*netmatch)();
if (af >= AF_MAX)
return (0);
netmatch = afswitch[af].af_netmatch;
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 ((*netmatch)(&ifa->ifa_addr, addr))
return (ifa);
}
return ((struct ifaddr *)0);
}
/*
* Find an interface using a specific address family.
* First try for one with the UP bit set, then accept anyone.
*/
struct ifaddr *
ifa_ifwithaf(af)
register int af;
{
register struct ifnet *ifp;
register struct ifaddr *ifa;
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if (ifp->if_flags & IFF_UP)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr.sa_family == af)
return (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);
}
/*
* At this point, we have not initialised any interface (except
* loopback!), so we choose an arbitrary interface on which to
* try a revarp.
*/
/*ARGSUSED*/
struct ifnet *
ifb_ifwithaf(af)
int af;
{
#ifndef OPENPROMS
register struct bootparam *bp;
#endif
register struct ifnet *ifp;
#ifdef OPENPROMS
char name[OBP_MAXDEVNAME];
#else OPENPROMS
char name[32];
#endif OPENPROMS
short unit;
#ifdef DPRINTF
int i;
#endif DPRINTF
extern char *strcpy(), *strncpy();
struct ifnet *ifname();
#ifdef OPENPROMS
extern char *prom_bootpath(); /* For debug only! */
#ifdef DPRINTF
char *path;
path = prom_bootpath();
DPRINTF("ifb_ifwithaf: prom bootpath %s --> ", path ? path : "<NONE>");
#endif DPRINTF
name[0] = (char)0; /* In case of error getting name */
#ifdef DPRINTF
i = prom_get_boot_dev_name(name, sizeof name);
#else
(void) prom_get_boot_dev_name(name, sizeof name);
#endif
#ifdef DPRINTF
if (i == 0)
DPRINTF("device %s, ", name);
else
DPRINTF("device <NONE?>, ");
#endif DPRINTF
unit = (short)prom_get_boot_dev_unit();
#ifdef DPRINTF
DPRINTF("unit %d\n", (int)unit);
#endif DPRINTF
#else OPENPROMS
bp = *romp->v_bootparam;
name[0] = bp->bp_dev[0];
name[1] = bp->bp_dev[1];
name[2] = '\0';
unit = (short) bp->bp_ctlr;
#endif
/*
* Translate "gn" to "fddi"
* -- this hack for the Narya VME FDDI/DX interface.
*/
if (!strcmp(name, "gn"))
(void) strcpy(name, "fddi");
/*
* Look for matching name/unit in the ifnet linked list.
*/
if (ifp = ifname(name, unit))
return (ifp);
/*
* Otherwise, default to first found non-point-to-point,
* non-loopback interface.
*/
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if (!(ifp->if_flags & IFF_POINTOPOINT) &&
!(ifp->if_flags & IFF_LOOPBACK))
return (ifp);
return (NULL);
}
/*
* Mark an interface down and notify protocols of
* the transition.
* NOTE: must be called at splnet or eqivalent.
*/
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);
}
/*
* Flush an interface queue.
*/
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.
*/
if_slowtimo()
{
register struct ifnet *ifp;
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);
}
timeout(if_slowtimo, (caddr_t)0, hz / IFNET_SLOWHZ);
}
/*
* Map interface name to
* interface structure pointer.
*/
struct ifnet *
ifunit(name, size)
register char *name;
int size;
{
register char *cp;
register struct ifnet *ifp;
int unit;
int namlen = 0;
for (cp = name; cp < name + size && *cp; cp++) {
if (*cp >= '0' && *cp <= '9')
break;
namlen++;
}
if (*cp == '\0' || cp == name + size || cp == name)
return ((struct ifnet *)0);
unit = 0;
while (*cp && cp < name + size)
unit = 10*unit + (*cp++ - '0');
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if (unit == ifp->if_unit && namlen == strlen(ifp->if_name) &&
bcmp(ifp->if_name, name, namlen) == 0)
return (ifp);
return ((struct ifnet *)0);
}
/*
* Map interface name and unit
* to interface structure pointer.
* Return NULL if not found.
*/
struct ifnet *
ifname(name, unit)
char *name;
short unit;
{
register struct ifnet *ifp;
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if (!strcmp(ifp->if_name, name) && (ifp->if_unit == unit))
return (ifp);
return (NULL);
}
/*
* Interface ioctls.
*/
ifioctl(so, cmd, data)
struct socket *so;
int cmd;
caddr_t data;
{
register struct ifnet *ifp, *oifp;
register struct ifreq *ifr;
switch (cmd) {
case SIOCGIFCONF:
return (ifconf(cmd, data));
#if defined(INET) && NETHER > 0
case SIOCSARP:
case SIOCDARP:
if (!suser())
return (u.u_error);
/* FALL THROUGH */
case SIOCGARP:
return (arpioctl(cmd, data));
#endif
}
ifr = (struct ifreq *)data;
ifp = ifunit(ifr->ifr_name, IFNAMSIZ);
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 (!suser())
return (u.u_error);
if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
int s = splimp();
if_down(ifp);
(void) splx(s);
}
#ifdef VDDRV
/*
* For a loadable driver, we need to set ifqmaxlen here,
* since it wasn't done in ifinit.
*/
if (ifp->if_snd.ifq_maxlen == 0)
ifp->if_snd.ifq_maxlen = ifqmaxlen;
#endif
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 (!suser())
return (u.u_error);
ifp->if_metric = ifr->ifr_metric;
break;
case SIOCUPPER:
oifp = ifunit(ifr->ifr_oname, IFNAMSIZ);
if (oifp == 0)
return (ENXIO);
if (oifp->if_input == 0)
return (EINVAL);
ifp->if_upper = oifp;
break;
case SIOCLOWER:
oifp = ifunit(ifr->ifr_oname, IFNAMSIZ);
if (oifp == 0)
return (ENXIO);
if (oifp->if_output == 0)
return (EINVAL);
ifp->if_lower = oifp;
break;
case SIOCSPROMISC:
if (!suser())
return (u.u_error);
return (ifpromisc(ifp, *(int *)data));
/*
* Set/zap multicast address. We demand root privilege,
* but otherwise leave it to the protocol to decide what
* to do with it. This strategy has the same coordination
* problems among multiple protocols that setting the
* individual address does...
*/
case SIOCADDMULTI:
case SIOCDELMULTI:
if (!suser())
return (u.u_error);
/* FALL THROUGH */
default:
if (so->so_proto == 0)
return (EOPNOTSUPP);
return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
cmd, data, ifp));
}
return (0);
}
/*
* Handle transitions into and out of promiscuous mode. Keep track
* of how many outstanding requests there are for the mode and call
* the interface to change mode on transitions to and from zero.
*/
int
ifpromisc(ifp, on)
register struct ifnet *ifp;
register int on;
{
register int change;
if (on)
change = ifp->if_promisc++ == 0;
else
change = (ifp->if_promisc != 0) ? (--ifp->if_promisc == 0) : 0;
if (!change)
return (0);
/*
* Force the IFF_PROMISC bit to match the
* value implied by the if_promisc field.
*/
if (on)
ifp->if_flags |= IFF_PROMISC;
else
ifp->if_flags &= ~IFF_PROMISC;
return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t) 0));
}
/*
* Return interface configuration
* of system. List may be used
* in later ioctl's (above) to get
* other information.
*/
/*ARGSUSED*/
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) - 4;
for (; space >= sizeof (ifr) && ifp; ifp = ifp->if_next) {
bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
;
if (ifp->if_unit > 99)
*cp++ = '0' + (ifp->if_unit / 100);
if (ifp->if_unit > 9)
*cp++ = '0' + (ifp->if_unit % 100)/10;
*cp++ = '0' + (ifp->if_unit % 10);
*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,
(u_int)(sizeof ifr));
if (error)
break;
space -= sizeof (ifr), ifrp++;
} else
for (; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
ifr.ifr_addr = ifa->ifa_addr;
error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
sizeof (ifr));
if (error)
break;
space -= sizeof (ifr), ifrp++;
}
}
ifc->ifc_len -= space;
return (error);
}

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

@@ -0,0 +1,268 @@
/* @(#)if.h 1.1 94/10/31 SMI; from UCB 7.1 6/4/86 */
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef _net_if_h
#define _net_if_h
/*
* Structures defining a network interface, providing a packet
* transport mechanism (ala level 0 of the PUP protocols).
*
* Each interface accepts output datagrams of a specified maximum
* length, and provides higher level routines with input datagrams
* received from its medium.
*
* Output occurs when the routine if_output is called, with three parameters:
* (*ifp->if_output)(ifp, m, dst)
* 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
*/
/*
* 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'' */
short if_unit; /* sub-unit for lower level driver */
short if_mtu; /* maximum transmission unit */
short if_flags; /* up/down, broadcast, etc. */
short if_timer; /* time 'til if_watchdog called */
u_short if_promisc; /* net # of requests for promisc mode */
int if_metric; /* routing metric (external only) */
struct ifaddr *if_addrlist; /* linked list of addresses per if */
struct ifqueue {
struct mbuf *ifq_head;
struct mbuf *ifq_tail;
int ifq_len;
int ifq_maxlen;
int ifq_drops;
} if_snd; /* output queue */
/* procedure handles */
int (*if_init)(); /* init routine */
int (*if_output)(); /* output routine */
int (*if_ioctl)(); /* ioctl routine */
int (*if_reset)(); /* bus reset routine */
int (*if_watchdog)(); /* timer routine */
/* generic interface statistics */
int if_ipackets; /* packets received on interface */
int if_ierrors; /* input errors on interface */
int if_opackets; /* packets sent on interface */
int if_oerrors; /* output errors on interface */
int if_collisions; /* collisions on csma interfaces */
/* end statistics */
struct ifnet *if_next;
struct ifnet *if_upper; /* next layer up */
struct ifnet *if_lower; /* next layer down */
int (*if_input)(); /* input routine */
int (*if_ctlin)(); /* control input routine */
int (*if_ctlout)(); /* control output routine */
#ifdef sun
struct map *if_memmap; /* rmap for interface specific memory */
#endif
};
#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_PRIVATE 0x8000 /* do not advertise */
/* flags set internally only: */
#define IFF_CANTCHANGE \
(IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING | IFF_PROMISC)
/*
* 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_act = 0; \
if ((ifq)->ifq_tail == 0) \
(ifq)->ifq_head = m; \
else \
(ifq)->ifq_tail->m_act = m; \
(ifq)->ifq_tail = m; \
(ifq)->ifq_len++; \
}
#define IF_PREPEND(ifq, m) { \
(m)->m_act = (ifq)->ifq_head; \
if ((ifq)->ifq_tail == 0) \
(ifq)->ifq_tail = (m); \
(ifq)->ifq_head = (m); \
(ifq)->ifq_len++; \
}
/*
* Packets destined for level-1 protocol input routines
* have a pointer to the receiving interface prepended to the data.
* IF_DEQUEUEIF extracts and returns this pointer when dequeueing the packet.
* IF_ADJ should be used otherwise to adjust for its presence.
*/
#define IF_ADJ(m) { \
(m)->m_off += sizeof(struct ifnet *); \
(m)->m_len -= sizeof(struct ifnet *); \
if ((m)->m_len == 0) { \
struct mbuf *n; \
MFREE((m), n); \
(m) = n; \
} \
}
#define IF_DEQUEUEIF(ifq, m, ifp) { \
(m) = (ifq)->ifq_head; \
if (m) { \
if (((ifq)->ifq_head = (m)->m_act) == 0) \
(ifq)->ifq_tail = 0; \
(m)->m_act = 0; \
(ifq)->ifq_len--; \
(ifp) = *(mtod((m), struct ifnet **)); \
IF_ADJ(m); \
} \
}
#define IF_DEQUEUE(ifq, m) { \
(m) = (ifq)->ifq_head; \
if (m) { \
if (((ifq)->ifq_head = (m)->m_act) == 0) \
(ifq)->ifq_tail = 0; \
(m)->m_act = 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 */
union {
struct sockaddr ifu_broadaddr;
struct sockaddr ifu_dstaddr;
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */
#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of p-to-p link */
struct ifnet *ifa_ifp; /* back-pointer to interface */
struct ifaddr *ifa_next; /* next address for interface */
};
/*
* 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;
char ifru_oname[IFNAMSIZ]; /* other if name */
struct sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
char ifru_data[1]; /* interface dependent data */
/* Struct for FDDI ioctl's */
struct ifr_dnld_reqs {
caddr_t v_addr;
caddr_t m_addr;
caddr_t ex_addr;
u_int size;
} ifru_dnld_req;
/* Struct for FDDI stats */
struct ifr_fddi_stats {
u_int stat_size;
caddr_t fddi_stats;
} ifru_fddi_stat;
struct ifr_netmapents {
u_int map_ent_size, /* size of netmap structure */
entry_number; /* index into netmap list */
caddr_t fddi_map_ent; /* pointer to user structure */
} ifru_netmapent;
/* Field for generic ioctl for fddi */
struct ifr_fddi_gen_struct {
int ifru_fddi_gioctl; /* field for gen ioctl */
caddr_t ifru_fddi_gaddr ; /* Generic ptr to a field */
} ifru_fddi_gstruct;
} 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_oname ifr_ifru.ifru_oname /* other if name */
#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 */
/* FDDI specific */
#define ifr_dnld_req ifr_ifru.ifru_dnld_req
#define ifr_fddi_stat ifr_ifru.ifru_fddi_stat
#define ifr_fddi_netmap ifr_ifru.ifru_netmapent /* FDDI network map entries */
#define ifr_fddi_gstruct ifr_ifru.ifru_fddi_gstruct
};
/*
* 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 */
};
#ifdef KERNEL
struct ifqueue rawintrq; /* raw packet input queue */
struct ifnet *ifnet;
struct ifaddr *ifa_ifwithaddr(), *ifa_ifwithnet();
struct ifaddr *ifa_ifwithdstaddr();
struct ifaddr *ifa_ifwithaf();
struct ifnet *ifunit();
struct ifnet *ifname();
#endif KERNEL
#endif /*!_net_if_h*/

75
sys/net/if_arp.h Normal file
View File

@@ -0,0 +1,75 @@
/* @(#)if_arp.h 1.1 94/10/31 SMI; from UCB 7.1 1/24/86 */
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef _net_if_arp_h
#define _net_if_arp_h
/*
* Address Resolution Protocol.
*
* See RFC 826 for protocol description. ARP packets are variable
* in size; the arphdr structure defines the fixed-length portion.
* Protocol type values are the same as those for 10 Mb/s Ethernet.
* It is followed by the variable-sized fields ar_sha, arp_spa,
* arp_tha and arp_tpa in that order, according to the lengths
* specified. Field names used correspond to RFC 826.
*/
struct arphdr {
u_short ar_hrd; /* format of hardware address */
#define ARPHRD_ETHER 1 /* ethernet hardware address */
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 REVARP_REQUEST 3 /* Reverse ARP request */
#define REVARP_REPLY 4 /* Reverse ARP reply */
/*
* The remaining fields are variable in size,
* according to the sizes above, and are defined
* as appropriate for specific hardware/protocol
* combinations. (E.g., see <netinet/if_ether.h>.)
*/
#ifdef notdef
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 notdef
};
/*
* 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 */
/*
* This data structure is used by kernel protocol modules to register
* their interest in a particular packet type with the Ethernet drivers.
* For example, other kinds of ARP would use this, XNS, ApleTalk, etc.
*/
struct ether_family {
int ef_family; /* address family */
u_short ef_ethertype; /* ethernet type field */
struct ifqueue *(*ef_infunc)(); /* input function */
int (*ef_outfunc)();/* output function */
int (*ef_netisr)(); /* soft interrupt function */
struct ether_family *ef_next; /* link to next on list */
};
#endif /*!_net_if_arp_h*/

56
sys/net/if_ieee802.h Normal file
View File

@@ -0,0 +1,56 @@
/* @(#)if_ieee802.h 1.1 94/10/31 Copyright 1987 Sun Micro */
#ifndef _net_if_ieee802_h
#define _net_if_ieee802_h
/*
* Structure of a IEEE 802.3 header
*/
struct ieee8023_header {
u_char ieee8023_dhost[6];
u_char ieee8023_shost[6];
u_short ieee8023_length;
};
#define MAX_8023_DLEN 1500
/*
* sepcial Ether Family type used for registering for 802.3 packets.
*/
#define EF_8023_TYPE 1500
/*
* Address as seen by IEEE 802
*/
/* IEEE 802.[2|4] media access address */
union mac_addr_802 {
u_char l_fmt[6]; /* 48-bit address */
};
/* IEEE 802.2 link address */
struct link_addr_802 {
union mac_addr_802 l_mac_addr; /* media access address */
u_char l_sel; /* link layer selector */
};
#define SIZE_LINK_ADDR_802 7 /* DON'T use "sizeof" */
#define S802_PAD_LEN (16 - sizeof (struct link_addr_802) - \
sizeof (u_short))
struct sockaddr_802 {
u_short s802_family;
struct link_addr_802 s802_addr;
#define s802_macaddr s802_addr.l_mac_addr
#define s802_lsel s802_addr.l_sel
u_char pad[S802_PAD_LEN];
};
/*
* Well known LSAPs
*/
#define LSAP_ISONET 0xfe /* ISO subnet point of attachment */
#define LSAP_SNAP 0xaa /* "ethernet" subnet attachment point */
#endif /*!_net_if_ieee802_h*/

47
sys/net/netisr.h Normal file
View File

@@ -0,0 +1,47 @@
/* @(#)netisr.h 1.1 94/10/31 SMI; from UCB 7.1 6/4/86 */
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/*
* 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).
*/
/*
* These definitions are only to provide compatibility
* with old code; new stuff should use softcall directly.
*/
#ifndef _net_netisr_h
#define _net_netisr_h
#define schednetisr(isrname) softcall(isrname, (caddr_t)0)
#define NETISR_RAW rawintr /* raw net intr */
#define NETISR_IP ipintr /* IP net intr */
#define NETISR_NS nsintr /* NS net intr */
#define NETISR_IMP impintr /* IMP-host protocol interrupts */
int rawintr();
#ifdef INET
int ipintr();
#endif INET
#ifdef NS
int nsintr();
#endif NS
#if NIMP>0
int impintr();
#endif NIMP
#endif /*!_net_netisr_h*/

1002
sys/net/nit.c Normal file

File diff suppressed because it is too large Load Diff

109
sys/net/nit.h Normal file
View File

@@ -0,0 +1,109 @@
/* @(#)nit.h 1.1 94/10/31 SMI */
/*
* Copyright (c) 1986 by Sun Microsystems, Inc.
*/
/*
* Constants and structures defined for nit
*/
#ifndef _net_nit_h
#define _net_nit_h
#define NITIFSIZ 10 /* size of ifname in sockaddr */
#define NITBUFSIZ 1024 /* buffers are rounded up to a
* multiple of this size (MCLBYTES) */
/*
* Protocols
*/
#define NITPROTO_RAW 1 /* raw protocol */
#define NITPROTO_MAX 2
/*
* Sockaddr_nit, as the "local address" associated with a raw socket,
* needs to uniquely identify the associated process, since this is
* what rawintr will use to distribute packets. We do not distribute
* on the "foreign address", as we need it to provide the outgoing
* network address.
*/
struct sockaddr_nit {
u_short snit_family;
caddr_t snit_cookie; /* link to filtering */
char snit_ifname[NITIFSIZ]; /* interface name (ie0) */
};
/* Header preceeding each packet returned to user */
struct nit_hdr {
int nh_state; /* state of tap -- see below */
struct timeval nh_timestamp; /* time of arriving packet */
int nh_wirelen; /* length (with header) off wire */
union {
int info; /* generic information */
int datalen; /* length of saved packet portion */
int dropped; /* number of dropped matched packets */
int seqno; /* sequence number */
} nh_un;
};
#define nh_info nh_un.info
#define nh_datalen nh_un.datalen
#define nh_dropped nh_un.dropped
#define nh_seqno nh_un.seqno
/*
* Ioctl parameter block
* When setting parameter values, values that
* are otherwise impossible mean "don't change".
*
* Nioc_bufalign and nioc_bufoffset control packet placement
* within buffers. The (nit) header for each packet in a buffer
* starts nioc_bufoffset bytes past some multiple of nioc_bufalign
* bytes from the beginning. The packet itself appears immediately
* beyond the header.
*/
struct nit_ioc {
int nioc_bufspace; /* total buffer space to use */
int nioc_chunksize; /* size of chunks to send */
u_int nioc_typetomatch; /* magic type with which to match */
int nioc_snaplen; /* length of packet portion to snap */
int nioc_bufalign; /* packet header alignment multiple */
int nioc_bufoffset; /* packet header alignment offset */
struct timeval nioc_timeout; /* delay after packet before flush */
int nioc_flags; /* see below */
};
#define NT_NOTYPES ((u_int)0) /* match no packet types */
#define NT_ALLTYPES ((u_int)-1) /* match all packet types */
#define NF_PROMISC 0x01 /* enter promiscuous mode */
#define NF_TIMEOUT 0x02 /* timeout value valid */
#define NF_BUSY 0x04 /* buffer is busy (has data) */
/*
* States for the packet capture portion of nit,
* some of which are passed to the user.
*/
#define NIT_QUIET 0 /* inactive */
#define NIT_CATCH 1 /* capturing packets */
#define NIT_NOMBUF 2 /* discarding -- out of mbufs */
#define NIT_NOCLUSTER 3 /* discarding -- out of mclusters */
#define NIT_NOSPACE 4 /* discarding -- would exceed buffer */
/* Pseudo-states returned in information packets */
#define NIT_SEQNO 5 /* sequence number of buffer -- helps
to detect other software drops */
#define NIT_MAXSTATE 6 /* state count */
#if defined(KERNEL) && defined(NIT)
struct ifnet *nit_ifwithaddr();
/* Interface provided information */
struct nit_ii {
caddr_t nii_header; /* header to be prepended to mbuf */
int nii_hdrlen; /* length of header to prepend */
u_int nii_type; /* magic "type" field for matching */
int nii_datalen; /* lenght (sans header) off wire */
int nii_promisc; /* packet not destined for host */
};
#endif defined(KERNEL) && defined(NIT)
#endif /*!_net_nit_h*/

747
sys/net/nit_buf.c Normal file
View File

@@ -0,0 +1,747 @@
#ifndef lint
static char sccsid[] = "@(#)nit_buf.c 1.1 94/10/31 Copyr 1988 Sun Micro";
#endif lint
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* NIT buffering module
*
* This streams module collects incoming messages from modules below
* it on the stream and buffers them up into a smaller number of
* aggregated messages. Its main purpose is to reduce overhead by
* cutting down on the number of read (or getmsg) calls its client
* user process makes.
*/
/* #define NBDEBUG */
#include "nbuf.h"
#if NNBUF > 0
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/debug.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/ioctl.h>
#include <sys/user.h> /* only for u.u_error */
#include <net/nit_buf.h>
int nbclosechunk();
/*
* Stereotyped streams glue.
*/
int nbopen();
int nbclose(); /* really void, not int */
int nbrput(); /* really void, not int */
int nbwput(); /* really void, not int */
struct module_info nb_minfo = {
21, /* module id XXX: define real value */
"nitbuf",
0,
INFPSZ, /* max msg size */
STRHIGH, /* high water XXX: make reasonable */
STRLOW /* low water XXX: make reasonable */
};
struct qinit nb_rinit = {
nbrput,
NULL,
nbopen,
nbclose,
NULL,
&nb_minfo,
NULL
};
struct qinit nb_winit = {
nbwput,
NULL,
NULL,
NULL,
NULL,
&nb_minfo,
NULL
};
struct streamtab nb_info = {
&nb_rinit,
&nb_winit,
NULL,
NULL
};
/*
* Per-module instance state information.
*
* Each instance is dynamically allocated from the dblk pool.
* nb_soft cross-references back to the mblk whose associated dblk
* contains the instance.
*
* If nb_ticks is negative, we don't deliver chunks until they're
* full. If it's zero, we deliver every packet as it arrives. (In
* this case we force nb_chunk to zero, to make the implementation
* easier.) Otherwise, nb_ticks gives the number of ticks from
* the last delivery time to the next one.
*/
typedef struct nb_softc {
mblk_t *nb_soft; /* cross-link to containing mblk */
queue_t *nb_rq; /* cross-link to read queue */
mblk_t *nb_mp; /* partially accumulated aggregate */
u_int nb_mlen; /* nb_mp length */
u_int nb_chunk; /* max aggregate packet data size */
int nb_ticks; /* timeout interval */
} nb_softc_t;
/* ARGSUSED */
int
nbopen(q, dev, oflag, sflag)
struct queue *q;
dev_t dev;
int oflag,
sflag;
{
register nb_softc_t *nbp;
register mblk_t *bp;
#ifdef NBDEBUG
printf("nbopen: q: %x, WR(q): %x, dev: %x, oflag: %x, sflag: %x\n",
q, WR(q), dev, oflag, sflag);
#endif NBDEBUG
/* We must be called with MODOPEN. */
if (sflag != MODOPEN)
return (OPENFAIL);
/*
* If someone else already has us open, there's
* nothing further to do.
*/
if (q->q_ptr)
return (0);
/*
* Allocate space for per-open-instance information
* and set up internal cross-links.
*
* XXX: If the allocation fails, I suppose we could
* try a bufcall...
*/
bp = allocb((int) sizeof *nbp, BPRI_MED);
if (! bp) {
u.u_error = ENOMEM; /* gag */
return (OPENFAIL);
}
bp->b_wptr += sizeof *nbp;
nbp = (nb_softc_t *)bp->b_rptr;
nbp->nb_soft = bp;
/*
* Set up cross-links between queues and the softc structure.
*/
nbp->nb_rq = q;
q->q_ptr = WR(q)->q_ptr = (char *)nbp;
/*
* Set default buffering values.
*/
nbp->nb_ticks = -1;
nbp->nb_chunk = NB_DFLT_CHUNK;
/*
* Initialize the first chunk.
*/
nbp->nb_mp = NULL;
nbp->nb_mlen = 0;
nbstartchunk(nbp);
return (0);
}
nbclose(q)
register queue_t *q;
{
register nb_softc_t *nbp = (nb_softc_t *)q->q_ptr;
register int s = splstr();
#ifdef NBDEBUG
printf("nbclose: q: %x, WR(q): %x ", q, WR(q));
#endif NBDEBUG
/*
* Flush outstanding traffic on its way
* downstream to us.
* Is this appropriate for this module?
*/
flushq(WR(q), FLUSHALL);
/*
* Clean up state: free partially accumulated chunk
* and cancel pending timeout.
*/
if (nbp->nb_mp)
freemsg(nbp->nb_mp);
nbp->nb_mp = NULL;
untimeout(nbclosechunk, (caddr_t)nbp);
/*
* Free the softc structure itself, then unlink it.
*/
freeb(nbp->nb_soft);
q->q_ptr = NULL;
(void) splx(s);
}
/*
* Write-side put procedure. Its main task is to detect ioctls
* for manipulating the buffering state and hand them to nbioctl.
* Other message types are passed on through.
*/
nbwput(q, mp)
queue_t *q;
mblk_t *mp;
{
switch (mp->b_datap->db_type) {
case M_FLUSH:
/*
* Only worry about FLUSHW here. We'll catch FLUSHR
* on the way back up. We don't flush control messages,
* although it's not clear that this is correct.
*/
if (*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
putnext(q, mp);
break;
case M_IOCTL:
nbioctl(q,mp);
break;
default:
putnext(q, mp);
break;
}
}
/*
* Read-side put procedure. It's responsible for buffering up incoming
* messages and grouping them into aggregates according to the current
* buffering parameters.
*/
nbrput(q, mp)
queue_t *q;
mblk_t *mp;
{
register mblk_t *mnp;
register nb_softc_t *nbp;
/*
* Sanity check: make sure our corresponding device
* instance is still open.
*/
nbp = (nb_softc_t *)q->q_ptr;
if (!nbp) {
printf("nbrput: called on closed device instance\n");
freemsg(mp);
return;
}
switch (mp->b_datap->db_type) {
case M_PROTO:
/*
* Convert M_PROTO header to M_DATA header.
*/
for (mnp = mp; mnp && mnp->b_datap->db_type == M_PROTO;
mnp = mnp->b_cont)
mnp->b_datap->db_type = M_DATA;
/* Fall through... */
case M_DATA:
nbaddmsg(q, mp);
break;
case M_FLUSH:
/*
* Symmetrically to M_FLUSH in nbwput,
* we only worry about FLUSHR here.
*/
if (*mp->b_rptr & FLUSHR) {
/*
* Prevent interference from new messages
* arriving from below.
*/
register int s = splstr();
flushq(q, FLUSHDATA);
/*
* Reset timeout, flush the chunk currently in
* progress, and start a new chunk.
*/
untimeout(nbclosechunk, (caddr_t)nbp);
if (nbp->nb_mp) {
freemsg(nbp->nb_mp);
nbp->nb_mp = NULL;
nbp->nb_mlen = 0;
nbstartchunk(nbp);
}
if (nbp->nb_ticks > 0) {
/*
* XXX: Set new timeout or does it suffice
* merely to start a new chunk?
*/
timeout(nbclosechunk, (caddr_t)nbp,
nbp->nb_ticks);
}
(void) splx(s);
}
putnext(q, mp);
break;
default:
putnext(q, mp);
break;
}
}
/*
* Handle write-side M_IOCTL messages.
*/
nbioctl(q, mp)
queue_t *q;
mblk_t *mp;
{
register nb_softc_t *nbp = (nb_softc_t *)q->q_ptr;
register struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
register int cmd = iocp->ioc_cmd;
#ifdef NBDEBUG
printf("nb %x M_IOCTL, cmd: %x\n", nbp, iocp->ioc_cmd);
#endif NBDEBUG
switch (cmd) {
case NIOCSTIME: {
register struct timeval *t;
register long ticks;
/*
* Verify argument length.
*/
if (iocp->ioc_count < sizeof (struct timeval)) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
break;
}
t = (struct timeval *)mp->b_cont->b_rptr;
if (t->tv_sec < 0 || t->tv_usec < 0) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
break;
}
ticks = (1000000 * t->tv_sec + t->tv_usec) * hz;
ticks /= 1000000;
nbp->nb_ticks = ticks;
if (ticks == 0)
nbp->nb_chunk = 0;
#ifdef NBDEBUG
printf("NIOCSTIME: ticks %d, sec %d, usec %d\n",
nbp->nb_ticks, t->tv_sec, t->tv_usec);
#endif NBDEBUG
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = 0;
break;
}
case NIOCGTIME: {
register struct timeval *t;
register long usec;
/*
* Verify argument length.
*/
if (iocp->ioc_count < sizeof (struct timeval)) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
break;
}
/*
* If infinite timeout, return range error
* for the ioctl.
*/
if (nbp->nb_ticks < 0) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = ERANGE;
break;
}
usec = 1000000 * nbp->nb_ticks;
usec /= hz;
t = (struct timeval *)mp->b_cont->b_rptr;
t->tv_usec = usec % 1000000;
t->tv_sec = usec / 1000000;
#ifdef NBDEBUG
printf("NIOCGTIME: ticks %d, sec %d, usec %d\n",
nbp->nb_ticks, t->tv_sec, t->tv_usec);
#endif NBDEBUG
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = sizeof (struct timeval);
break;
}
case NIOCCTIME:
nbp->nb_ticks = -1;
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = 0;
break;
case NIOCSCHUNK:
/*
* Verify argument length.
*/
if (iocp->ioc_count < sizeof (int)) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
break;
}
nbp->nb_chunk = *(u_int *)mp->b_cont->b_rptr;
#ifdef NBDEBUG
printf("NIOCSCHUNK: chunk size %d\n", nbp->nb_chunk);
#endif NBDEBUG
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = 0;
break;
case NIOCGCHUNK:
/*
* Verify argument length.
*/
if (iocp->ioc_count < sizeof (int)) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
break;
}
*(u_int *)mp->b_cont->b_rptr = nbp->nb_chunk;
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = sizeof (u_int);
break;
default:
/*
* Pass unrecognized ioctls through to
* give modules below us a chance at them.
*/
putnext(q, mp);
return;
}
/*
* Send the response back upstream.
*/
qreply(q,mp);
}
/*
* Given a length l, calculate the amount of extra storage
* required to round it up to the next multiple of the alignment a.
*/
#define RoundUpAmt(l, a) ((l) % (a) ? (a) - ((l) % (a)) : 0)
/*
* Calculate additional amount of space required for alignment.
*/
#define Align(l) RoundUpAmt(l, sizeof (u_long))
/*
* Augment the message given as argument with a nit_bufhdr header
* and with enough trailing padding to satisfy alignment constraints.
* Return a pointer to the augmented message, or NULL if allocation
* failed.
*/
mblk_t *
nbaugmsg(mp)
register mblk_t *mp;
{
register struct nit_bufhdr *hp;
register u_int len = msgdsize(mp);
register int pad;
/*
* Get space for the header. If there's room for it in the
* message's leading dblk and it would be correctly aligned,
* stash it there; otherwise hook in a fresh one.
*
* Some slight sleaze: the last clause of the test relies on
* sizeof (struct nit_bufhdr) being a multiple of sizeof (u_int).
*/
if (mp->b_rptr - mp->b_datap->db_base >= sizeof (struct nit_bufhdr) &&
mp->b_datap->db_ref == 1 &&
((u_int)mp->b_rptr & (sizeof (u_int) - 1)) == 0) {
/*
* Adjust data pointers to precede old beginning.
*/
mp->b_rptr -= sizeof (struct nit_bufhdr);
}
else {
register mblk_t *mpnew;
mpnew = allocb(sizeof (struct nit_bufhdr), BPRI_MED);
if (!mpnew) {
freemsg(mp);
return ((mblk_t *)NULL);
}
mpnew->b_datap->db_type = M_DATA;
mpnew->b_wptr += sizeof (struct nit_bufhdr);
/*
* Link it in place.
*/
linkb(mpnew, mp);
mp = mpnew;
}
/*
* Fill it in.
*
* We maintain the invariant: nb_m_len % sizeof (u_long) == 0.
* Since x % a == 0 && y % a == 0 ==> (x + y) % a == 0, we can
* pad the message out to the correct alignment boundary without
* having to worry about how long the currently accumulating
* chunk is already.
*/
hp = (struct nit_bufhdr *)mp->b_rptr;
hp->nhb_msglen = len;
len += sizeof (struct nit_bufhdr);
pad = Align(len);
hp->nhb_totlen = len + pad;
/*
* Add padding. If there's room at the end of the message
* (which there always should be so long as we retain the
* power-of-2 dblk allocation scheme), simply extend the wptr
* for the last mblk. Otherwise allocate a new mblk and
* tack it on.
*/
if (pad) {
register mblk_t *mep;
/*
* Find the message's last mblk.
*/
for (mep = mp; mep->b_cont; mep = mep->b_cont)
continue;
if (mep->b_datap->db_lim - mep->b_wptr >= pad &&
mep->b_datap->db_ref == 1)
mep->b_wptr += pad;
else {
register mblk_t *mpnew = allocb(pad, BPRI_MED);
if (!mpnew) {
freemsg(mp);
return ((mblk_t *) NULL);
}
mpnew->b_datap->db_type = M_DATA;
mpnew->b_wptr += pad;
linkb(mep, mpnew);
}
}
return (mp);
}
/*
* Process a read-side M_DATA message.
*
* First condition the message for inclusion in a chunk, by adding
* a nit_bufhdr header and trailing alignment padding.
*
* If the currently accumulating chunk doesn't have enough room
* for the message, close off the chunk, pass it upward, and start
* a new one. Then add the message to the current chunk, taking
* account of the possibility that the message's size exceeds the
* chunk size.
*/
nbaddmsg(q, mp)
queue_t *q;
mblk_t *mp;
{
register nb_softc_t *nbp = (nb_softc_t *)q->q_ptr;
register u_int mlen,
mnew;
/*
* Add header and padding to the message.
*/
if (!(mp = nbaugmsg(mp))) {
#ifdef NBDEBUG
printf("nb %x: out of space for header or padding\n",
nbp);
#endif NBDEBUG
return;
}
/*
* If the padded message won't fit in the current chunk,
* close the chunk off and start a new one. The second
* clause of the test compensates for allocation failures
* in nbstartchunk the last time around.
*/
mlen = ((struct nit_bufhdr *)mp->b_rptr)->nhb_totlen;
mnew = nbp->nb_mlen + mlen;
if (mnew > nbp->nb_chunk || !nbp->nb_mp)
nbclosechunk((caddr_t)nbp);
/*
* If it still doesn't fit, pass it on directly, bypassing
* the chunking mechanism. Note that if we're not chunking
* things up at all (chunk == 0), we'll pass the message
* upward here.
*/
mnew = nbp->nb_mlen + mlen;
if (mnew > nbp->nb_chunk || !nbp->nb_mp) {
putnext(q, mp);
return;
}
/*
* We now know that there's a chunk in progress
* and that the message will fit in it. Glue it
* in place.
*/
linkb(nbp->nb_mp, mp);
nbp->nb_mlen = mnew;
}
/*
* Start a fresh chunk. If the chunk size is positive,
* add a zero-length message at the beginning, to make
* sure that nbclosechunk has something to deliver when
* the timeout period expires with nothing having arrived.
*/
nbstartchunk(nbp)
register nb_softc_t *nbp;
{
register mblk_t *mp;
if (nbp->nb_mp) {
/*
* This should probably be a panic.
*/
printf("nb %x: nbstartchunk called with existent chunk\n",
nbp);
freemsg(nbp->nb_mp);
}
nbp->nb_mp = NULL;
nbp->nb_mlen = 0;
if (nbp->nb_chunk) {
/*
* Set up the leading zero-length message. If this
* fails, we'll be unable to deliver chunks until
* allocation once more succeeds, but then will revert
* back to accumulating chunks, since control will
* flow through nbclosechunk and from there to here.
*/
if (mp = allocb(0, BPRI_MED)) {
mp->b_datap->db_type = M_DATA;
nbp->nb_mp = mp;
}
#ifdef NBDEBUG
else
printf("nb %x: null chunk allocation failed\n",
nbp);
#endif NBDEBUG
}
}
/*
* Close off the currently accumulating chunk and pass
* it upward. Takes care of resetting timers as well.
*
* This routine is called both directly and as a result
* of the chunk timeout expiring.
*/
nbclosechunk(arg)
caddr_t arg;
{
register nb_softc_t *nbp;
register mblk_t *mp;
register queue_t *q;
register int s;
/*
* Prevent interference from timeouts expiring
* and from new messages being passed up from below.
*/
s = splstr();
untimeout(nbclosechunk, arg);
nbp = (nb_softc_t *)arg;
mp = nbp->nb_mp;
/*
* Guard against being in the middle of closing the stream
* when a timeout goes off and brings us here.
*/
q = nbp->nb_rq;
if (!q) {
if (mp)
freemsg(mp);
nbp->nb_mp = NULL;
(void) splx(s);
return;
}
/*
* If there's currently a chunk in progress, close it off
* and send it up, provided that we won't violate flow control
* constraints by doing so. The hard case here is handling
* data that we generate as opposed to data that come to us
* from below. The only thing we generate is the zero-length
* message that heads a chunk, so if that's all there is, flow
* control applies. If not, the module(s) feeding us from below
* should have checked canput, so we won't. (If we checked
* as well, we could end up exceeding the chunk size.)
*/
if (mp && (nbp->nb_mlen != 0 || canput(q))) {
putnext(q, mp);
mp = nbp->nb_mp = NULL;
}
/*
* Re-establish the desired invariant that there's
* always a chunk in progress (subject to resource
* availability).
*/
if (!mp)
nbstartchunk(nbp);
/*
* Establish timeout until next message delivery time,
* but only if the user has requested timeouts.
*/
if (nbp->nb_ticks > 0)
timeout(nbclosechunk, arg, nbp->nb_ticks);
(void) splx(s);
}
#endif NNBUF > 0

68
sys/net/nit_buf.h Normal file
View File

@@ -0,0 +1,68 @@
/* @(#)nit_buf.h 1.1 94/10/31 SMI */
/*
* Copyright (c) 1986 by Sun Microsystems, Inc.
*/
#ifndef _net_nit_buf_h
#define _net_nit_buf_h
/*
* Definitions for the streams NIT buffering module.
*
* The module gathers incoming (read-side) messages together into
* "chunks" and passes completed chunks up to the next module in
* line. The gathering process is controlled by two ioctl-settable
* parameters:
*
* timeout The maximum delay after passing the previous chunk
* upward before passing the current one up, even if the
* chunk isn't full. If the timeout value passed in is
* a null pointer, the timeout is infinite (as in the
* select system call); this is the default.
* chunksize The maximum size of a chunk of accumulated messages,
* unless a single message exceeds the chunksize, in
* which case it's passed up in a chunk containing only
* that message. Note that a given message's size includes
* the length of any leading M_PROTO blocks it may have.
*
* There is one important side-effect: setting the timeout to zero
* (polling) will force the chunksize to zero, regardless of its
* previous setting.
*/
/*
* Ioctls.
*/
#define NIOCSTIME _IOW(p, 6, struct timeval) /* set timeout info */
#define NIOCGTIME _IOWR(p, 7, struct timeval) /* get timeout info */
#define NIOCCTIME _IO(p, 8) /* clear timeout */
#define NIOCSCHUNK _IOW(p, 9, u_int) /* set chunksize */
#define NIOCGCHUNK _IOWR(p, 10, u_int) /* get chunksize */
/*
* Default chunk size.
*/
#define NB_DFLT_CHUNK 8192 /* arbitrary */
/*
* When adding a given message to an accumulating chunk, the module
* first converts all leading M_PROTO data blocks to M_DATA data blocks.
* It then constructs a nit_bufhdr (defined below), prepends it to
* the message, and pads the result out to force its length to a
* multiple of a machine-dependent alignment size guaranteed to be
* at least sizeof (u_long). It then adds the padded message to the
* chunk.
*
* The first field of the header is length of the message after the
* M_PROTO => M_DATA conversion, but before adding the header.
*
* The second header field is the total length of the message,
* including both the header itself and the trailing padding bytes.
*/
struct nit_bufhdr { /* see above commentary */
u_int nhb_msglen;
u_int nhb_totlen;
};
#endif /*!_net_nit_buf_h*/

1127
sys/net/nit_if.c Normal file

File diff suppressed because it is too large Load Diff

91
sys/net/nit_if.h Normal file
View File

@@ -0,0 +1,91 @@
/* @(#)nit_if.h 1.1 94/10/31 SMI */
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
#ifndef _net_nit_if_h
#define _net_nit_if_h
/*
* Definitions for the streams link-level network interface.
*/
/*
* Ioctls.
*/
#define NIOCBIND _IOW(p, 3, struct ifreq) /* bind to interface */
#define NIOCSFLAGS _IOW(p, 4, u_long) /* set nit_if flags */
#define NIOCGFLAGS _IOWR(p, 5, u_long) /* get nit_if flags */
#define NIOCSSNAP _IOW(p, 6, u_long) /* set snapshot len */
#define NIOCGSNAP _IOWR(p, 7, u_long) /* get snapshot len */
/*
* User-visible flag bits, accessible with the NIOC[GS]FLAGS ioctls.
*
*/
/* interface state */
#define NI_PROMISC 0x01 /* put underlying if into promiscuous mode */
/* packet headers to be prepended to each packet */
#define NI_TIMESTAMP 0x02 /* timestamp */
#define NI_LEN 0x04 /* length of packet as received */
#define NI_DROPS 0x08 /* cumulative number of dropped packets */
#define NI_USERBITS 0x0f /* mask for state bits users may see */
/*
* Headers.
*
* Depending on the state of the flag bits set with the NIOCSFLAGS ioctl,
* each packet will have one or more headers prepended. These headers are
* packed contiguous to the packet and themselves with no intervening
* space. Their lengths are chosen to avoid alignment problems. Prepending
* occurs in the order of the header definitions given below, with each
* successive header appearing in front of everything that's already in place.
*/
/*
* Header prepended to each packet when the NI_LEN flag bit is set.
* It contains the packet's length as of the time it was received,
* including the link-level header. It does not account for any of the
* headers that nit_if adds nor for trimming the packet to the snaplen.
*/
struct nit_iflen {
u_long nh_pktlen; /* packet length as received */
};
/*
* Header prepended to each packet when the NI_DROPS flag is set.
* It records the cumulative number of packets dropped on this stream
* because of flow control requirements since the stream was opened.
*/
struct nit_ifdrops {
u_long nh_drops; /* cum # of packets lost to flow ctl */
};
/*
* Header prepended to each packet when the NI_TIMESTAMP flag bit is set.
*/
struct nit_iftime {
struct timeval nh_timestamp; /* packet arrival time */
};
#ifdef KERNEL
/*
* Bridge between hardware interface and nit subsystem.
*/
struct nit_if {
caddr_t nif_header; /* pointer to packet header */
u_int nif_hdrlen; /* length of packet header */
u_int nif_bodylen; /* length of packet body */
int nif_promisc; /* packet not addressed to host */
};
#endif KERNEL
#endif /*!_net_nit_if_h*/

476
sys/net/nit_pf.c Normal file
View File

@@ -0,0 +1,476 @@
#ifndef lint
static char sccsid[] = "@(#)nit_pf.c 1.1 94/10/31 Copyr 1988 Sun Micro";
#endif lint
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
/*
* Streams NIT packet filter module
*
* This module applies a filter to messages arriving on its read
* queue, passing on messages that the filter accepts and dropping
* the others. It supports ioctls for setting and (eventually)
* getting the filter.
*
* On the write side, the module simply passes everything through
* unchanged.
*
* The module is intended to sit on top of a network interface driver
* or pseudo-driver such as the one defined in nit_if.c.
*
* XXX: Make sure that correct processor levels are observed throughout.
*/
/* #define PFDEBUG */
#include "pf.h"
#if NPF > 0
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/debug.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/user.h> /* for u.u_error */
#include <net/packetfilt.h>
#include <net/nit_pf.h>
/*
* Stereotyped streams glue.
*/
int pfopen();
int pfclose(); /* really void, not int */
int pfrput(); /* really void, not int */
int pfwput(); /* really void, not int */
struct module_info pf_minfo = {
20, /* module id XXX: define real value */
"pf",
0,
32767, /* max msg size XXX: make reasonable */
STRHIGH, /* high water XXX: make reasonable */
STRLOW /* low water XXX: make reasonable */
};
struct qinit pf_rinit = {
pfrput,
NULL, /* srvp (XXX: can we do without one?) */
pfopen,
pfclose,
NULL,
&pf_minfo,
NULL
};
struct qinit pf_winit = {
pfwput,
NULL, /* srvp (XXX: can we do without one?) */
NULL,
NULL,
NULL,
&pf_minfo,
NULL
};
struct streamtab pf_info = {
&pf_rinit,
&pf_winit,
NULL,
NULL
};
/*
* Per-module instance state information.
*
* Each instance is dynamically allocated from the dblk pool.
* p_mb cross-references back to the mblk whose associated dblk
* contains the instance.
*/
typedef struct pf_softc {
mblk_t *p_mb; /* cross-link to containing mblk */
queue_t *p_rq; /* cross-link to read queue */
dev_t p_dev; /* used for error printouts only */
struct epacketfilt p_pf; /* filter to apply */
} pf_softc_t;
/* ARGSUSED */
int
pfopen(q, dev, oflag, sflag)
struct queue *q;
dev_t dev;
int oflag,
sflag;
{
register pf_softc_t *pp;
register mblk_t *bp;
register struct epacketfilt *pfp;
#ifdef PFDEBUG
printf("pfopen: q: %x, WR(q): %x, dev: %x, oflag: %x, sflag: %x\n",
q, WR(q), dev, oflag, sflag);
#endif PFDEBUG
/* We must be called with MODOPEN. */
if (sflag != MODOPEN)
return (OPENFAIL);
/*
* If someone else already has us open, there's
* nothing further to do.
*/
if (q->q_ptr)
return (0);
/*
* Allocate space for per-open-instance information
* and set up internal cross-links.
*
* XXX: If the allocation fails, I suppose we could
* try a bufcall...
*/
bp = allocb((int) sizeof *pp, BPRI_MED);
if (! bp) {
u.u_error = ENOMEM; /* gag */
return (OPENFAIL);
}
bp->b_wptr += sizeof *pp;
pp = (pf_softc_t *)bp->b_rptr;
pp->p_mb = bp;
/*
* Set up cross-links between queues and the softc structure.
*/
pp->p_rq = q;
q->q_ptr = (char *)pp;
WR(q)->q_ptr = (char *)pp;
/*
* Record dev for later use in error messages.
*/
pp->p_dev = dev;
/*
* Initialize to zero-length filter.
*/
pfp = &pp->p_pf;
pfp->pf_FilterLen = 0;
pfp->pf_FilterEnd = &pfp->pf_Filter[0];
return (0);
}
pfclose(q)
register queue_t *q;
{
register pf_softc_t *pp = (pf_softc_t *)q->q_ptr;
#ifdef PFDEBUG
printf("pfclose: q: %x, WR(q): %x ", q, WR(q));
#endif PFDEBUG
/*
* Flush outstanding traffic on its way
* downstream to us.
* Is this appropriate for this module?
*/
flushq(WR(q), FLUSHALL);
/*
* Free the softc structure itself, then unlink it.
*/
freeb(pp->p_mb);
q->q_ptr = NULL;
}
/*
* Write-side put procedure. Its main task is to handle the
* ioctls for manipulating the packet filter. Other message
* types are passed on through.
*/
pfwput(q, mp)
queue_t *q;
mblk_t *mp;
{
register pf_softc_t *pp;
register struct iocblk *iocp;
switch (mp->b_datap->db_type) {
case M_FLUSH:
/*
* Only worry about FLUSHW here. We'll catch FLUSHR
* on the way back up. We don't flush control messages,
* although it's not clear that this is correct.
*/
if (*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
putnext(q, mp);
break;
case M_IOCTL:
pp = (pf_softc_t *)q->q_ptr;
iocp = (struct iocblk *)mp->b_rptr;
#ifdef PFDEBUG
printf("pf M_IOCTL, cmd: %x\n", iocp->ioc_cmd);
#endif PFDEBUG
switch (iocp->ioc_cmd) {
case NIOCSETF: {
register struct epacketfilt *pfp;
register struct packetfilt *upfp;
register u_short *fwp;
register int maxoff;
int s;
pfp = &pp->p_pf;
/*
* Verify argument length.
*/
if (iocp->ioc_count < sizeof (struct packetfilt)) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
qreply(q, mp);
break;
}
/*
* Do a bit of validity checking before
* committing to the new filter.
*/
upfp = (struct packetfilt *)mp->b_cont->b_rptr;
if (upfp->Pf_FilterLen > ENMAXFILTERS) {
mp->b_datap->db_type = M_IOCNAK;
iocp->ioc_error = EINVAL;
qreply(q, mp);
break;
}
/*
* Install the new filter atomically.
*
* We move to splstr to prevent inconsistencies
* from scheduling the read side while we're
* part way through setting up the filter.
*/
s = splstr();
bcopy((caddr_t)upfp, (caddr_t)pfp, (u_int)sizeof *upfp);
pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen];
/*
* Find and record maximum byte offset that the
* filter uses. We use this when executing the
* filter to determine how much of the packet
* body to pull up. This code depends on the
* filter encoding.
*/
maxoff = 0;
for (fwp = pfp->pf_Filter; fwp < pfp->pf_FilterEnd; fwp++) {
register u_int arg;
arg = *fwp & ((1 << ENF_NBPA) - 1);
switch (arg) {
default:
if ((arg -= ENF_PUSHWORD) > maxoff)
maxoff = arg;
break;
case ENF_PUSHLIT:
/* Skip over the literal. */
fwp++;
break;
case ENF_PUSHZERO:
case ENF_NOPUSH:
break;
}
}
/* Convert word offset to length in bytes. */
pfp->pf_PByteLen = (maxoff + 1) * sizeof (u_short);
(void) splx(s);
#ifdef PFDEBUG
printf("pf NIOCSETF installed at %x, len %d, PByteLen %d\n",
pfp, pfp->pf_FilterLen, pfp->pf_PByteLen);
#endif PFDEBUG
/* Acknowledge with no data returned. */
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_count = 0;
qreply(q,mp);
break;
}
#ifdef notdef
case PF_GETF:
/* I suppose we should support this someday... */
#endif notdef
default:
/*
* Pass unrecognized ioctls through to
* give modules below us a chance at them.
*/
putnext(q, mp);
break;
}
break;
default:
putnext(q, mp);
break;
}
}
/*
* Read-side put procedure. It's responsible for applying the
* packet filter and passing an incoming message on or discarding
* it depending on the results.
*
* Incoming messages can start with zero or more M_PROTO mblks.
* Such header information does not participate in the filtering
* process.
*
* Design question: How should M_PROTO-only messages be handled?
* The current implementation passes them through, but it's not
* clear that this is the right thing to do.
*/
pfrput(q, mp)
queue_t *q;
mblk_t *mp;
{
register struct epacketfilt *pfp;
register mblk_t *mbp,
*mpp;
struct packdesc pd;
ASSERT(mp && mp->b_datap);
switch (mp->b_datap->db_type) {
case M_PROTO:
case M_DATA: {
register int need;
ASSERT(q->q_ptr);
pfp = &((pf_softc_t *)q->q_ptr)->p_pf;
/*
* Skip over protocol information and find the start
* of the message body, saving the overall message
* start in mpp.
*/
mpp = mp;
while (mp && mp->b_datap->db_type == M_PROTO)
mp = mp->b_cont;
/*
* Null body (exclusive of M_PROTO blocks) ==> accept.
* Note that a null body is not the same as an empty body.
*/
if (!mp) {
putnext(q, mpp);
break;
}
/*
* Pull the packet up to the length required by
* the filter. Note that doing so destroys sharing
* relationships, which is unfortunate, since the
* results of pulling up here are likely to be useful
* for shared messages applied to a filter on a sibling
* stream.
*
* Most packet sources will provide the packet in two
* logical pieces: an initial header in a single mblk,
* and a body in a sequence of mblks hooked to the
* header. We're prepared to deal with variant forms,
* but in any case, the pullup applies only to the body
* part.
*/
mbp = mp->b_cont;
need = pfp->pf_PByteLen;
if (mbp && mbp->b_wptr - mbp->b_rptr < need) {
register int len = msgdsize(mbp);
if (pullupmsg(mbp, MIN(need, len)) == 0) {
dev_t dev;
dev = ((pf_softc_t *)q->q_ptr)->p_dev;
printf("pf<%d,%d>: pullupmsg failed\n",
major(dev), minor(dev));
freemsg(mpp);
break;
}
}
/*
* Misaliagnment (not on short boundary) ==> reject.
*/
if (((u_int)mp->b_rptr & (sizeof (u_short) - 1)) ||
(mbp && ((u_int)mbp->b_rptr & (sizeof (u_short) - 1)))) {
dev_t dev = ((pf_softc_t *)q->q_ptr)->p_dev;
printf ("pf<%d,%d>: misaligned packet\n",
major(dev), minor(dev));
freemsg(mpp);
break;
}
/*
* These assignments are distasteful, but necessary,
* since the packet filter wants to work in terms of
* shorts. Odd bytes at the end of header or data can't
* participate in the filtering operation.
*/
pd.pd_hdr = (u_short *)mp->b_rptr;
pd.pd_hdrlen = (mp->b_wptr - mp->b_rptr) / sizeof (u_short);
if (mbp) {
pd.pd_body = (u_short *)mbp->b_rptr;
pd.pd_bodylen = (mbp->b_wptr - mbp->b_rptr) /
sizeof (u_short);
}
else {
pd.pd_body = NULL;
pd.pd_bodylen = 0;
}
/*
* Apply the filter.
*/
if (FilterPacket(&pd, pfp))
putnext(q, mpp);
else
freemsg(mpp);
break;
}
case M_FLUSH:
/*
* Symmetrically to M_FLUSH in pfwput,
* we only worry about FLUSHR here.
*/
if (*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
putnext(q, mp);
break;
default:
putnext(q, mp);
break;
}
}
#endif NPF > 0

16
sys/net/nit_pf.h Normal file
View File

@@ -0,0 +1,16 @@
/* @(#)nit_pf.h 1.1 94/10/31 SMI */
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
#ifndef _net_nit_pf_h
#define _net_nit_pf_h
/*
* Definitions for the streams packet filter module.
*/
#define NIOCSETF _IOW(p, 2, struct packetfilt) /* set packet filter */
#endif /*!_net_nit_pf_h*/

203
sys/net/packetfilt.c Normal file
View File

@@ -0,0 +1,203 @@
#ifndef lint
static char sccsid[] = "@(#)packetfilt.c 1.1 94/10/31 SMI";
#endif
#include <sys/param.h>
#include <net/packetfilt.h>
/* #define DEBUG 1 */
/* #define INNERDEBUG 1 */ /* define only when debugging enDoFilter()
or enInputDone() */
#ifdef INNERDEBUG
#define enprintf(flags) if (enDebug&(flags)) printf
/*
* Symbolic definitions for enDebug flag bits
* ENDBG_TRACE should be 1 because it is the most common
* use in the code, and the compiler generates faster code
* for testing the low bit in a word.
*/
#define ENDBG_TRACE 1 /* trace most operations */
#define ENDBG_DESQ 2 /* trace descriptor queues */
#define ENDBG_INIT 4 /* initialization info */
#define ENDBG_SCAV 8 /* scavenger operation */
#define ENDBG_ABNORM 16 /* abnormal events */
int enDebug = /* ENDBG_ABNORM | ENDBG_INIT | ENDBG_TRACE */ -1;
#endif /* INNERDEBUG */
/*
* Apply the packet filter given by pfp to the packet given by
* pp. Return nonzero iff the filter accepts the packet.
*
* The packet comes in two pieces, a header and a body, since
* that's the most convenient form for our caller. The header
* is in contiguous memory, whereas the body is in a mbuf.
* Our caller will have adjusted the mbuf chain so that its first
* min(MLEN, length(body)) bytes are guaranteed contiguous. For
* the sake of efficiency (and some laziness) the filter is prepared
* to examine only these two contiguous pieces. Furthermore, it
* assumes that the header length is even, so that there's no need
* to glue the last byte of header to the first byte of data.
*/
#define opx(i) ((i) >> ENF_NBPA)
int
FilterPacket(pp, pfp)
struct packdesc *pp;
struct epacketfilt *pfp;
{
register int maxhdr = pp->pd_hdrlen;
int maxword = maxhdr + pp->pd_bodylen;
register u_short *sp;
register u_short *fp;
register u_short *fpe;
register unsigned op;
register unsigned arg;
u_short stack[ENMAXFILTERS+1];
fp = &pfp->pf_Filter[0];
fpe = pfp->pf_FilterEnd;
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("FilterPacket(%x, %x, %x, %x):\n", pp, pfp, fp, fpe);
#endif
/*
* Push TRUE on stack to start. The stack size is chosen such
* that overflow can't occur -- each operation can push at most
* one item on the stack, and the stack size equals the maximum
* program length.
*/
sp = &stack[ENMAXFILTERS];
*sp = 1;
for ( ; fp < fpe; ) {
op = *fp >> ENF_NBPA;
arg = *fp & ((1 << ENF_NBPA) - 1);
fp++;
switch (arg) {
default:
arg -= ENF_PUSHWORD;
/*
* Since arg is unsigned,
* if it were less than ENF_PUSHWORD before,
* it would now be huge.
*/
if (arg < maxhdr)
*--sp = pp->pd_hdr[arg];
else if (arg < maxword)
*--sp = pp->pd_body[arg - maxhdr];
else {
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>0(len)\n");
#endif
return (0);
}
break;
case ENF_PUSHLIT:
*--sp = *fp++;
break;
case ENF_PUSHZERO:
*--sp = 0;
case ENF_NOPUSH:
break;
}
if (sp < &stack[2]) { /* check stack overflow: small yellow zone */
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>0(--sp)\n");
#endif
return (0);
}
if (op == ENF_NOP)
continue;
/*
* all non-NOP operators binary, must have at least two operands
* on stack to evaluate.
*/
if (sp > &stack[ENMAXFILTERS-2]) {
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>0(sp++)\n");
#endif
return (0);
}
arg = *sp++;
switch (op) {
default:
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>0(def)\n");
#endif
return (0);
case opx(ENF_AND):
*sp &= arg;
break;
case opx(ENF_OR):
*sp |= arg;
break;
case opx(ENF_XOR):
*sp ^= arg;
break;
case opx(ENF_EQ):
*sp = (*sp == arg);
break;
case opx(ENF_NEQ):
*sp = (*sp != arg);
break;
case opx(ENF_LT):
*sp = (*sp < arg);
break;
case opx(ENF_LE):
*sp = (*sp <= arg);
break;
case opx(ENF_GT):
*sp = (*sp > arg);
break;
case opx(ENF_GE):
*sp = (*sp >= arg);
break;
/* short-circuit operators */
case opx(ENF_COR):
if (*sp++ == arg) {
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>COR %x\n", *sp);
#endif
return (1);
}
break;
case opx(ENF_CAND):
if (*sp++ != arg) {
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp);
#endif
return (0);
}
break;
case opx(ENF_CNOR):
if (*sp++ == arg) {
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>COR %x\n", *sp);
#endif
return (0);
}
break;
case opx(ENF_CNAND):
if (*sp++ != arg) {
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>CNAND %x\n", *sp);
#endif
return (1);
}
break;
}
}
#ifdef INNERDEBUG
enprintf(ENDBG_TRACE)("=>%x\n", *sp);
#endif
return (*sp);
}

93
sys/net/packetfilt.h Normal file
View File

@@ -0,0 +1,93 @@
/* @(#)packetfilt.h 1.1 94/10/31 SMI */
#ifndef _net_packetfilt_h
#define _net_packetfilt_h
#define ENMAXFILTERS 40 /* maximum filter short words */
/*
* filter structure for SETF
*/
struct packetfilt {
u_char Pf_Priority; /* priority of filter */
u_char Pf_FilterLen; /* length of filter cmd list */
u_short Pf_Filter[ENMAXFILTERS];
/* the filter command list */
};
/*
* We now allow specification of up to MAXFILTERS (short) words of a filter
* command list to be applied to incoming packets to determine if
* those packets should be given to a particular open ethernet file.
*
* In this context, "word" means a short (16-bit) integer.
*
* Each open enet file specifies the filter command list via ioctl.
* Each filter command list specifies a sequence of actions that leaves a
* boolean value on the top of an internal stack. Each word of the
* command list specifies an action from the set {PUSHLIT, PUSHZERO,
* PUSHWORD+N} which respectively push the next word of the filter, zero,
* or word N of the incoming packet on the stack, and a binary operator
* from the set {EQ, LT, LE, GT, GE, AND, OR, XOR} which operates on the
* top two elements of the stack and replaces them with its result. The
* special action NOPUSH and the special operator NOP can be used to only
* perform the binary operation or to only push a value on the stack.
*
* If the final value of the filter operation is true, then the packet is
* accepted for the open file which specified the filter.
*/
/* these must sum to sizeof(u_short)! */
#define ENF_NBPA 10 /* # bits / action */
#define ENF_NBPO 6 /* # bits / operator */
/* binary operators */
#define ENF_NOP ( 0 << ENF_NBPA)
#define ENF_EQ ( 1 << ENF_NBPA)
#define ENF_LT ( 2 << ENF_NBPA)
#define ENF_LE ( 3 << ENF_NBPA)
#define ENF_GT ( 4 << ENF_NBPA)
#define ENF_GE ( 5 << ENF_NBPA)
#define ENF_AND ( 6 << ENF_NBPA)
#define ENF_OR ( 7 << ENF_NBPA)
#define ENF_XOR ( 8 << ENF_NBPA)
#define ENF_COR ( 9 << ENF_NBPA)
#define ENF_CAND (10 << ENF_NBPA)
#define ENF_CNOR (11 << ENF_NBPA)
#define ENF_CNAND (12 << ENF_NBPA)
#define ENF_NEQ (13 << ENF_NBPA)
/* stack actions */
#define ENF_NOPUSH 0
#define ENF_PUSHLIT 1
#define ENF_PUSHZERO 2
#define ENF_PUSHWORD 16
#ifdef KERNEL
/*
* Expanded version of the Packetfilt structure that includes
* some additional fields that aid filter execution efficiency.
*/
struct epacketfilt {
struct packetfilt pf;
#define pf_Priority pf.Pf_Priority
#define pf_FilterLen pf.Pf_FilterLen
#define pf_Filter pf.Pf_Filter
u_short *pf_FilterEnd; /* pointer to word immediately
past end of filter */
u_short pf_PByteLen; /* length in bytes of packet
prefix the filter examines */
};
/*
* (Internal) packet descriptor for FilterPacket
*/
struct packdesc {
u_short *pd_hdr; /* header starting address */
u_int pd_hdrlen; /* header length in shorts */
u_short *pd_body; /* body starting address */
u_int pd_bodylen; /* body length in shorts */
};
#endif KERNEL
#endif /*!_net_packetfilt_h*/

166
sys/net/raw_cb.c Normal file
View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*
* @(#)raw_cb.c 1.1 94/10/31 SMI; from UCB 7.4 12/30/87
*/
#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 <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <net/route.h>
#include <net/raw_cb.h>
#include <net/nit.h>
#include <netinet/in.h>
#ifdef vax
#include <vax/mtpr.h>
#endif
/*
* 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
*/
/*
* Allocate a control block and a nominal amount
* of buffer space for the socket.
*/
raw_attach(so, proto)
register struct socket *so;
int proto;
{
struct mbuf *m;
register struct rawcb *rp;
m = m_getclr(M_DONTWAIT, MT_PCB);
if (m == 0)
return (ENOBUFS);
if (sbreserve(&so->so_snd, RAWSNDQ) == 0)
goto bad;
/* recvfrom needs extra space for address */
if (sbreserve(&so->so_rcv, RAWRCVQ + sizeof(struct sockaddr)) == 0)
goto bad2;
rp = mtod(m, struct rawcb *);
rp->rcb_socket = so;
so->so_pcb = (caddr_t)rp;
rp->rcb_pcb = 0;
rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family;
rp->rcb_proto.sp_protocol = proto;
insque(rp, &rawcb);
return (0);
bad2:
sbrelease(&so->so_snd);
bad:
(void) m_free(m);
return (ENOBUFS);
}
/*
* Detach the raw connection block and discard
* socket resources.
*/
raw_detach(rp)
register struct rawcb *rp;
{
struct socket *so = rp->rcb_socket;
if (rp->rcb_route.ro_rt)
rtfree(rp->rcb_route.ro_rt);
so->so_pcb = 0;
sofree(so);
remque(rp);
if (rp->rcb_options)
m_freem(rp->rcb_options);
m_freem(dtom(rp));
}
/*
* Disconnect and possibly release resources.
*/
raw_disconnect(rp)
struct rawcb *rp;
{
rp->rcb_flags &= ~RAW_FADDR;
if (rp->rcb_socket->so_state & SS_NOFDREF)
raw_detach(rp);
}
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);
/* BEGIN DUBIOUS */
/*
* Should we verify address not already in use?
* Some say yes, others no.
*/
switch (addr->sa_family) {
#ifdef NIT
case AF_NIT:
if (nit_ifwithaddr(addr) == 0)
return (EADDRNOTAVAIL);
break;
#endif NIT
#ifdef INET
case AF_IMPLINK:
case AF_INET: {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr &&
ifa_ifwithaddr(addr) == 0)
return (EADDRNOTAVAIL);
break;
}
#endif
default:
return (EAFNOSUPPORT);
}
/* END DUBIOUS */
rp = sotorawcb(so);
bcopy((caddr_t)addr, (caddr_t)&rp->rcb_laddr, sizeof (*addr));
rp->rcb_flags |= RAW_LADDR;
return (0);
}
/*
* Associate a peer's address with a
* raw connection block.
*/
raw_connaddr(rp, nam)
struct rawcb *rp;
struct mbuf *nam;
{
struct sockaddr *addr = mtod(nam, struct sockaddr *);
bcopy((caddr_t)addr, (caddr_t)&rp->rcb_faddr, sizeof(*addr));
rp->rcb_flags |= RAW_FADDR;
}

63
sys/net/raw_cb.h Normal file
View File

@@ -0,0 +1,63 @@
/* @(#)raw_cb.h 1.1 94/10/31 SMI; from UCB 7.1 6/5/86 */
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef _net_raw_cb_h
#define _net_raw_cb_h
/*
* Raw protocol interface control block. Used
* to tie a socket to the generic raw interface.
*/
struct rawcb {
struct rawcb *rcb_next; /* doubly linked list */
struct rawcb *rcb_prev;
struct socket *rcb_socket; /* back pointer to socket */
struct sockaddr rcb_faddr; /* destination address */
struct sockaddr rcb_laddr; /* socket's address */
struct sockproto rcb_proto; /* protocol family, protocol */
caddr_t rcb_pcb; /* protocol specific stuff */
struct mbuf *rcb_options; /* protocol specific options */
struct route rcb_route; /* routing information */
int rcb_cc; /* bytes of rawintr queued data */
int rcb_mbcnt; /* bytes of rawintr queued mbufs */
short rcb_flags;
};
/*
* Since we can't interpret canonical addresses,
* we mark an address present in the flags field.
*/
#define RAW_LADDR 0x01
#define RAW_FADDR 0x02
#define RAW_DONTROUTE 0x04 /* no routing, XXX: Q/default */
#define RAW_TALLY 0x08 /* tally delivered packets */
#define sotorawcb(so) ((struct rawcb *)(so)->so_pcb)
/*
* Nominal space allocated to a raw socket.
*/
#define RAWSNDQ 2048
#define RAWRCVQ 2048
/*
* Format of raw interface header prepended by
* raw_input after call from protocol specific
* input routine.
*/
struct raw_header {
struct sockproto raw_proto; /* format of packet */
struct sockaddr raw_dst; /* dst address for rawintr */
struct sockaddr raw_src; /* src address for sbappendaddr */
};
#ifdef KERNEL
struct rawcb rawcb; /* head of list */
#endif
#endif /*!_net_raw_cb_h*/

371
sys/net/raw_usrreq.c Normal file
View File

@@ -0,0 +1,371 @@
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)raw_usrreq.c 1.1 94/10/31 SMI; from UCB 7.1
*/
#include <sys/param.h>
#include <sys/mbuf.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>
#ifdef vax
#include <vax/mtpr.h>
#endif
/*
* Initialize raw connection block q.
*/
raw_init()
{
rawcb.rcb_next = rawcb.rcb_prev = &rawcb;
rawintrq.ifq_maxlen = IFQ_MAXLEN;
}
/*
* Raw protocol interface.
*/
raw_input(m0, proto, src, dst)
struct mbuf *m0;
struct sockproto *proto;
struct sockaddr *src, *dst;
{
register struct mbuf *m;
struct raw_header *rh;
int s;
/*
* Rip off an mbuf for a generic header.
*/
m = m_get(M_DONTWAIT, MT_HEADER);
if (m == 0) {
m_freem(m0);
return;
}
m->m_next = m0;
m->m_len = sizeof(struct raw_header);
rh = mtod(m, struct raw_header *);
rh->raw_dst = *dst;
rh->raw_src = *src;
rh->raw_proto = *proto;
/*
* Header now contains enough info to decide
* which socket to place packet in (if any).
* Queue it up for the raw protocol process
* running at software interrupt level.
*/
s = splimp();
if (IF_QFULL(&rawintrq)) {
IF_DROP(&rawintrq);
m_freem(m);
} else
IF_ENQUEUE(&rawintrq, m);
(void) splx(s);
schednetisr(NETISR_RAW);
}
/*
* Raw protocol input routine. Process packets entered
* into the queue at interrupt time. Find the socket
* associated with the packet(s) and move them over. If
* nothing exists for this packet, drop it. Depending on the
* requirements of the protocol associated with the receiving
* socket, we use one of sbappend{,addr,record} to accomplish
* the transfer. The convoluted replicated code is to avoid
* unnecessary m_copies.
*/
rawintr()
{
int s;
struct mbuf *m;
register struct rawcb *rp;
register struct raw_header *rh;
struct socket *lastso;
struct rawcb *lastrcb;
register short prflags;
next:
s = splimp();
IF_DEQUEUE(&rawintrq, m);
(void) splx(s);
if (m == 0)
return;
rh = mtod(m, struct raw_header *);
lastso = 0;
#ifdef lint
lastrcb = 0;
#endif lint
for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) {
if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family)
continue;
if (rp->rcb_proto.sp_protocol &&
rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol)
continue;
/*
* We assume the lower level routines have
* placed the address in a canonical format
* suitable for a structure comparison.
*/
#define equal(a1, a2) \
(bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0)
if ((rp->rcb_flags & RAW_LADDR) &&
!equal(rp->rcb_laddr, rh->raw_dst))
continue;
if ((rp->rcb_flags & RAW_FADDR) &&
!equal(rp->rcb_faddr, rh->raw_src))
continue;
if (lastso) {
/*
* Must fan this packet out to a second (or later)
* recipient. Do special processing for the
* previous recipient and produce a copy for
* the current recipient.
*/
register struct mbuf *n;
register int result;
/* Copy body only -- header only used locally. */
if ((n = m_copy(m->m_next, 0, (int)M_COPYALL)) == 0)
goto nospace;
if (lastrcb->rcb_flags & RAW_TALLY) {
s = splimp();
m_tally(n, -1,
&lastrcb->rcb_cc, &lastrcb->rcb_mbcnt);
(void) splx(s);
}
if ((prflags = lastso->so_proto->pr_flags) & PR_ADDR) {
result = sbappendaddr(&lastso->so_rcv,
&rh->raw_src, n, (struct mbuf *)0);
} else if (prflags & PR_ATOMIC) {
result = 1;
(void) sbappendrecord(&lastso->so_rcv, n);
} else {
result = 1;
(void) sbappend(&lastso->so_rcv, n);
}
if (result == 0) {
/* should notify about lost packet */
m_freem(n);
goto nospace;
}
sorwakeup(lastso);
}
nospace:
lastso = rp->rcb_socket;
lastrcb = rp;
}
if (lastso) {
register int result;
if (lastrcb->rcb_flags & RAW_TALLY) {
s = splimp();
m_tally(m->m_next, -1,
&lastrcb->rcb_cc, &lastrcb->rcb_mbcnt);
(void) splx(s);
}
if ((prflags = lastso->so_proto->pr_flags) & PR_ADDR) {
result = sbappendaddr(&lastso->so_rcv,
&rh->raw_src, m->m_next, (struct mbuf *)0);
} else if (prflags & PR_ATOMIC) {
result = 1;
(void) sbappendrecord(&lastso->so_rcv, m->m_next);
} else {
result = 1;
(void) sbappend(&lastso->so_rcv, m->m_next);
}
if (result == 0)
goto drop;
m = m_free(m); /* header */
sorwakeup(lastso);
goto next;
}
drop:
m_freem(m);
goto next;
}
/*ARGSUSED*/
raw_ctlinput(cmd, arg)
int cmd;
struct sockaddr *arg;
{
if (cmd < 0 || cmd > PRC_NCMDS)
return;
/* INCOMPLETE */
}
/*ARGSUSED*/
raw_usrreq(so, req, m, nam, rights)
struct socket *so;
int req;
struct mbuf *m, *nam, *rights;
{
register struct rawcb *rp = sotorawcb(so);
register int error = 0;
if (req == PRU_CONTROL)
return (EOPNOTSUPP);
if (rights && rights->m_len) {
error = EOPNOTSUPP;
goto release;
}
if (rp == 0 && req != PRU_ATTACH) {
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;
}
if (rp) {
error = EINVAL;
break;
}
error = raw_attach(so, (int)nam);
break;
/*
* Destroy state just before socket deallocation.
* Flush data or not depending on the options.
*/
case PRU_DETACH:
if (rp == 0) {
error = ENOTCONN;
break;
}
raw_detach(rp);
break;
/*
* If a socket isn't bound to a single address,
* the raw input routine will hand it anything
* within that protocol family (assuming there's
* nothing else around it should go to).
*/
case PRU_CONNECT:
if (rp->rcb_flags & RAW_FADDR) {
error = EISCONN;
break;
}
raw_connaddr(rp, nam);
soisconnected(so);
break;
case PRU_CONNECT2:
error = EOPNOTSUPP;
goto release;
case PRU_BIND:
if (rp->rcb_flags & RAW_LADDR) {
error = EINVAL; /* XXX */
break;
}
error = raw_bind(so, nam);
break;
case PRU_DISCONNECT:
if ((rp->rcb_flags & RAW_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_flags & RAW_FADDR) {
error = EISCONN;
break;
}
raw_connaddr(rp, nam);
/*
* clear RAW_FADDR to enable raw receive
* semantics by avoiding race between
* rawintr inception and pr_output completion
*/
rp->rcb_flags &= ~RAW_FADDR;
} else if ((rp->rcb_flags & RAW_FADDR) == 0) {
error = ENOTCONN;
break;
}
error = (*so->so_proto->pr_output)(m, so);
m = NULL;
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:
bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
sizeof (struct sockaddr));
nam->m_len = sizeof (struct sockaddr);
break;
case PRU_PEERADDR:
bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t),
sizeof (struct sockaddr));
nam->m_len = sizeof (struct sockaddr);
break;
default:
panic("raw_usrreq");
}
release:
if (m != NULL)
m_freem(m);
return (error);
}

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

@@ -0,0 +1,350 @@
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*
* @(#)route.c 1.1 94/10/31 SMI; from UCB 7.3 12/30/87
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/user.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <net/if.h>
#include <net/af.h>
#include <net/route.h>
int rttrash; /* routes not in table but not freed */
struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
#ifndef lint
int rthashsize = RTHASHSIZ; /* for netstat, etc. */
# endif lint
/*
* Packet routing routines.
*/
rtalloc(ro)
register struct route *ro;
{
register struct rtentry *rt;
register struct mbuf *m;
register u_long hash;
struct sockaddr *dst = &ro->ro_dst;
int (*match)(), doinghost, s;
struct afhash h;
u_int af = dst->sa_family;
struct mbuf **table;
if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
return; /* XXX */
if (af >= AF_MAX)
return;
(*afswitch[af].af_hash)(dst, &h);
match = afswitch[af].af_netmatch;
hash = h.afh_hosthash, table = rthost, doinghost = 1;
s = splnet();
again:
for (m = table[RTHASHMOD(hash)]; m; m = m->m_next) {
rt = mtod(m, struct rtentry *);
if (rt->rt_hash != hash)
continue;
if ((rt->rt_flags & RTF_UP) == 0 ||
(rt->rt_ifp->if_flags & IFF_UP) == 0)
continue;
if (doinghost) {
if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst,
sizeof (*dst)))
continue;
} else {
if (rt->rt_dst.sa_family != af ||
!(*match)(&rt->rt_dst, dst))
continue;
}
rt->rt_refcnt++;
(void) splx(s);
if (dst == &wildcard)
rtstat.rts_wildcard++;
ro->ro_rt = rt;
return;
}
if (doinghost) {
doinghost = 0;
hash = h.afh_nethash, table = rtnet;
goto again;
}
/*
* Check for wildcard gateway, by convention network 0.
*/
if (dst != &wildcard) {
dst = &wildcard, hash = 0;
goto again;
}
(void) splx(s);
rtstat.rts_unreach++;
}
rtfree(rt)
register struct rtentry *rt;
{
int s;
if (rt == 0)
panic("rtfree");
s = splnet();
rt->rt_refcnt--;
if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) {
rttrash--;
(void) m_free(dtom(rt));
}
(void) splx(s);
}
/*
* 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 or higher
*
*/
rtredirect(dst, gateway, flags, src)
struct sockaddr *dst, *gateway, *src;
int flags;
{
struct route ro;
register struct rtentry *rt;
/* verify the gateway is directly reachable */
if (ifa_ifwithnet(gateway) == 0) {
rtstat.rts_badredirect++;
return;
}
ro.ro_dst = *dst;
ro.ro_rt = 0;
rtalloc(&ro);
rt = ro.ro_rt;
#define equal(a1, a2) \
(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 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.
*/
if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) {
rtstat.rts_badredirect++;
if (rt)
rtfree(rt);
return;
}
/*
* 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 &&
(*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) {
rtfree(rt);
rt = 0;
}
if (rt == 0) {
rtinit(dst, gateway, (int)SIOCADDRT,
(flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
rtstat.rts_dynamic++;
return;
}
/*
* 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.
*/
rtinit(dst, gateway, (int)SIOCADDRT,
flags | RTF_DYNAMIC);
rtstat.rts_dynamic++;
} else {
/*
* Smash the current notion of the gateway to
* this destination.
*/
rt->rt_gateway = *gateway;
rt->rt_flags |= RTF_MODIFIED;
rtstat.rts_newgateway++;
}
} else
rtstat.rts_badredirect++;
rtfree(rt);
}
/*
* Routing table ioctl interface.
*/
rtioctl(cmd, data)
int cmd;
caddr_t data;
{
if (cmd != SIOCADDRT && cmd != SIOCDELRT)
return (EINVAL);
if (!suser())
return (u.u_error);
return (rtrequest(cmd, (struct rtentry *)data));
}
/*
* Carry out a request to change the routing table. Called by
* interfaces at boot time to make their ``local routes'' known,
* for ioctl's, and as the result of routing redirects.
*/
rtrequest(req, entry)
int req;
register struct rtentry *entry;
{
register struct mbuf *m, **mprev;
struct mbuf **mfirst;
register struct rtentry *rt;
struct afhash h;
int s, error = 0, (*match)();
u_int af;
u_long hash;
struct ifaddr *ifa;
struct ifaddr *ifa_ifwithdstaddr();
af = entry->rt_dst.sa_family;
if (af >= AF_MAX || af == 0)
return (EAFNOSUPPORT);
(*afswitch[af].af_hash)(&entry->rt_dst, &h);
if (entry->rt_flags & RTF_HOST) {
hash = h.afh_hosthash;
mprev = &rthost[RTHASHMOD(hash)];
} else {
hash = h.afh_nethash;
mprev = &rtnet[RTHASHMOD(hash)];
}
match = afswitch[af].af_netmatch;
s = splimp();
for (mfirst = mprev; m = *mprev; mprev = &m->m_next) {
rt = mtod(m, struct rtentry *);
if (rt->rt_hash != hash)
continue;
if (entry->rt_flags & RTF_HOST) {
if (!equal(&rt->rt_dst, &entry->rt_dst))
continue;
} else {
if (rt->rt_dst.sa_family != entry->rt_dst.sa_family ||
(*match)(&rt->rt_dst, &entry->rt_dst) == 0)
continue;
}
if (equal(&rt->rt_gateway, &entry->rt_gateway))
break;
}
switch (req) {
case SIOCDELRT:
if (m == 0) {
error = ESRCH;
goto bad;
}
*mprev = m->m_next;
if (rt->rt_refcnt > 0) {
rt->rt_flags &= ~RTF_UP;
rttrash++;
m->m_next = 0;
} else
(void) m_free(m);
break;
case SIOCADDRT:
if (m) {
error = EEXIST;
goto bad;
}
if (af != entry->rt_gateway.sa_family) {
error = EAFNOSUPPORT;
goto bad;
}
if ((entry->rt_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 (entry->rt_flags & RTF_HOST)
ifa = ifa_ifwithdstaddr(&entry->rt_dst);
if (ifa == 0)
ifa = ifa_ifwithaddr(&entry->rt_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(&entry->rt_gateway);
}
if (ifa == 0) {
ifa = ifa_ifwithnet(&entry->rt_gateway);
if (ifa == 0) {
error = ENETUNREACH;
goto bad;
}
}
m = m_get(M_DONTWAIT, MT_RTABLE);
if (m == 0) {
error = ENOBUFS;
goto bad;
}
m->m_next = *mfirst;
*mfirst = m;
m->m_off = MMINOFF;
m->m_len = sizeof (struct rtentry);
rt = mtod(m, struct rtentry *);
rt->rt_hash = hash;
rt->rt_dst = entry->rt_dst;
rt->rt_gateway = entry->rt_gateway;
rt->rt_flags = RTF_UP | entry->rt_flags;
rt->rt_refcnt = 0;
rt->rt_use = 0;
rt->rt_ifp = ifa->ifa_ifp;
break;
}
bad:
(void) splx(s);
return (error);
}
/*
* Set up a routing table entry, normally
* for an interface.
*/
rtinit(dst, gateway, cmd, flags)
struct sockaddr *dst, *gateway;
int cmd, flags;
{
struct rtentry route;
bzero((caddr_t)&route, sizeof (route));
route.rt_dst = *dst;
route.rt_gateway = *gateway;
route.rt_flags = flags;
(void) rtrequest(cmd, &route);
}

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

@@ -0,0 +1,90 @@
/* @(#)route.h 1.1 94/10/31 SMI; from UCB 7.3 12/30/87 */
/*
* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
/*
* Kernel resident routing tables.
*
* The routing tables are initialized when interface addresses
* are set by making entries for all directly connected interfaces.
*/
#ifndef _net_route_h
#define _net_route_h
/*
* 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;
};
/*
* 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.
*/
struct rtentry {
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 useable */
#define RTF_GATEWAY 0x2 /* destination is a gateway */
#define RTF_HOST 0x4 /* host entry (net otherwise) */
#define RTF_REINSTATE 0x8 /* re-instate route after timeout */
#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */
#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */
/*
* 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 */
};
#ifdef KERNEL
#define RTFREE(rt) rtfree(rt);
#ifdef GATEWAY
#define RTHASHSIZ 64
#else
#define RTHASHSIZ 8
#endif
#if (RTHASHSIZ & (RTHASHSIZ - 1)) == 0
#define RTHASHMOD(h) ((h) & (RTHASHSIZ - 1))
#else
#define RTHASHMOD(h) ((h) % RTHASHSIZ)
#endif
struct mbuf *rthost[RTHASHSIZ];
struct mbuf *rtnet[RTHASHSIZ];
struct rtstat rtstat;
#endif
#endif /*!_net_route_h*/