Init
This commit is contained in:
13
sys/net/Makefile
Normal file
13
sys/net/Makefile
Normal 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
84
sys/net/af.c
Normal 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
40
sys/net/af.h
Normal 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
592
sys/net/if.c
Normal 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
268
sys/net/if.h
Normal 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
75
sys/net/if_arp.h
Normal 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
56
sys/net/if_ieee802.h
Normal 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
47
sys/net/netisr.h
Normal 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
1002
sys/net/nit.c
Normal file
File diff suppressed because it is too large
Load Diff
109
sys/net/nit.h
Normal file
109
sys/net/nit.h
Normal 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
747
sys/net/nit_buf.c
Normal 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
68
sys/net/nit_buf.h
Normal 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
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
91
sys/net/nit_if.h
Normal 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
476
sys/net/nit_pf.c
Normal 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
16
sys/net/nit_pf.h
Normal 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
203
sys/net/packetfilt.c
Normal 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
93
sys/net/packetfilt.h
Normal 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
166
sys/net/raw_cb.c
Normal 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
63
sys/net/raw_cb.h
Normal 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
371
sys/net/raw_usrreq.c
Normal 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
350
sys/net/route.c
Normal 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
90
sys/net/route.h
Normal 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*/
|
||||
Reference in New Issue
Block a user