summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES18
-rw-r--r--sys/conf/files13
-rw-r--r--sys/conf/options18
-rw-r--r--sys/dev/ar/if_ar.c538
-rw-r--r--sys/dev/ar/if_ar.h23
-rw-r--r--sys/dev/ar/if_ar_isa.c538
-rw-r--r--sys/dev/sr/if_sr.c699
-rw-r--r--sys/dev/sr/if_sr.h23
-rw-r--r--sys/dev/sr/if_sr_isa.c699
-rw-r--r--sys/i386/conf/LINT18
-rw-r--r--sys/i386/conf/NOTES18
-rw-r--r--sys/i386/isa/if_ar.c538
-rw-r--r--sys/i386/isa/if_ar.h23
-rw-r--r--sys/i386/isa/if_sr.c699
-rw-r--r--sys/i386/isa/if_sr.h23
-rw-r--r--sys/modules/Makefile4
-rw-r--r--sys/modules/netgraph/Makefile2
-rw-r--r--sys/modules/netgraph/Makefile.inc7
-rw-r--r--sys/modules/netgraph/UI/Makefile9
-rw-r--r--sys/modules/netgraph/UI/ng_UI.486
-rw-r--r--sys/modules/netgraph/UI/ng_UI.886
-rw-r--r--sys/modules/netgraph/async/Makefile9
-rw-r--r--sys/modules/netgraph/async/ng_async.4160
-rw-r--r--sys/modules/netgraph/async/ng_async.8160
-rw-r--r--sys/modules/netgraph/cisco/Makefile35
-rw-r--r--sys/modules/netgraph/cisco/ng_cisco.4159
-rw-r--r--sys/modules/netgraph/cisco/ng_cisco.8159
-rw-r--r--sys/modules/netgraph/echo/Makefile9
-rw-r--r--sys/modules/netgraph/echo/ng_echo.467
-rw-r--r--sys/modules/netgraph/echo/ng_echo.867
-rw-r--r--sys/modules/netgraph/frame_relay/Makefile9
-rw-r--r--sys/modules/netgraph/frame_relay/ng_frame_relay.493
-rw-r--r--sys/modules/netgraph/frame_relay/ng_frame_relay.893
-rw-r--r--sys/modules/netgraph/hole/Makefile9
-rw-r--r--sys/modules/netgraph/hole/ng_hole.467
-rw-r--r--sys/modules/netgraph/hole/ng_hole.867
-rw-r--r--sys/modules/netgraph/iface/Makefile39
-rw-r--r--sys/modules/netgraph/iface/ng_iface.4126
-rw-r--r--sys/modules/netgraph/iface/ng_iface.8126
-rw-r--r--sys/modules/netgraph/lmi/Makefile9
-rw-r--r--sys/modules/netgraph/lmi/ng_lmi.4130
-rw-r--r--sys/modules/netgraph/lmi/ng_lmi.8130
-rw-r--r--sys/modules/netgraph/netgraph/Makefile8
-rw-r--r--sys/modules/netgraph/netgraph/netgraph.4876
-rw-r--r--sys/modules/netgraph/ppp/Makefile9
-rw-r--r--sys/modules/netgraph/ppp/ng_ppp.4164
-rw-r--r--sys/modules/netgraph/ppp/ng_ppp.8164
-rw-r--r--sys/modules/netgraph/pppoe/Makefile9
-rw-r--r--sys/modules/netgraph/pppoe/ng_pppoe.4130
-rw-r--r--sys/modules/netgraph/pppoe/ng_pppoe.8130
-rw-r--r--sys/modules/netgraph/rfc1490/Makefile9
-rw-r--r--sys/modules/netgraph/rfc1490/ng_rfc1490.4109
-rw-r--r--sys/modules/netgraph/rfc1490/ng_rfc1490.8109
-rw-r--r--sys/modules/netgraph/socket/Makefile9
-rw-r--r--sys/modules/netgraph/socket/ng_socket.4127
-rw-r--r--sys/modules/netgraph/socket/ng_socket.8127
-rw-r--r--sys/modules/netgraph/tee/Makefile9
-rw-r--r--sys/modules/netgraph/tee/ng_tee.4110
-rw-r--r--sys/modules/netgraph/tee/ng_tee.8110
-rw-r--r--sys/modules/netgraph/tty/Makefile9
-rw-r--r--sys/modules/netgraph/tty/ng_tty.4141
-rw-r--r--sys/modules/netgraph/tty/ng_tty.8141
-rw-r--r--sys/modules/netgraph/vjc/Makefile9
-rw-r--r--sys/modules/netgraph/vjc/ng_vjc.4188
-rw-r--r--sys/modules/netgraph/vjc/ng_vjc.8188
-rw-r--r--sys/net/if_arp.h3
-rw-r--r--sys/net/if_ethersubr.c349
-rw-r--r--sys/net/netisr.h1
-rw-r--r--sys/netgraph/NOTES81
-rw-r--r--sys/netgraph/netgraph.h255
-rw-r--r--sys/netgraph/ng_UI.c242
-rw-r--r--sys/netgraph/ng_UI.h55
-rw-r--r--sys/netgraph/ng_async.c586
-rw-r--r--sys/netgraph/ng_async.h89
-rw-r--r--sys/netgraph/ng_base.c1633
-rw-r--r--sys/netgraph/ng_cisco.c557
-rw-r--r--sys/netgraph/ng_cisco.h76
-rw-r--r--sys/netgraph/ng_echo.c121
-rw-r--r--sys/netgraph/ng_echo.h50
-rw-r--r--sys/netgraph/ng_ether.h55
-rw-r--r--sys/netgraph/ng_frame_relay.c526
-rw-r--r--sys/netgraph/ng_frame_relay.h55
-rw-r--r--sys/netgraph/ng_hole.c97
-rw-r--r--sys/netgraph/ng_hole.h50
-rw-r--r--sys/netgraph/ng_iface.c778
-rw-r--r--sys/netgraph/ng_iface.h75
-rw-r--r--sys/netgraph/ng_lmi.c1090
-rw-r--r--sys/netgraph/ng_lmi.h80
-rw-r--r--sys/netgraph/ng_message.h209
-rw-r--r--sys/netgraph/ng_ppp.c406
-rw-r--r--sys/netgraph/ng_ppp.h91
-rw-r--r--sys/netgraph/ng_pppoe.c1343
-rw-r--r--sys/netgraph/ng_pppoe.h224
-rw-r--r--sys/netgraph/ng_rfc1490.c347
-rw-r--r--sys/netgraph/ng_rfc1490.h55
-rw-r--r--sys/netgraph/ng_sample.c441
-rw-r--r--sys/netgraph/ng_sample.h75
-rw-r--r--sys/netgraph/ng_socket.c957
-rw-r--r--sys/netgraph/ng_socket.h62
-rw-r--r--sys/netgraph/ng_socketvar.h63
-rw-r--r--sys/netgraph/ng_tee.c268
-rw-r--r--sys/netgraph/ng_tee.h56
-rw-r--r--sys/netgraph/ng_tty.c706
-rw-r--r--sys/netgraph/ng_tty.h62
-rw-r--r--sys/netgraph/ng_vjc.c439
-rw-r--r--sys/netgraph/ng_vjc.h75
-rw-r--r--sys/sys/mount.h2
-rw-r--r--sys/sys/socket.h3
108 files changed, 21336 insertions, 142 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 66af687..2a55351 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -387,6 +387,24 @@ options NETATALK #Appletalk communications protocols
#options EON #ISO CLNP over IP
#options NSIP #XNS over IP
+# netgraph(4). Enable the base netgraph code with the NETGRAPH option.
+# Individual node types can be enabled with the corresponding option
+# listed below; however, this is not strictly necessary as netgraph
+# will automatically load the corresponding KLD module if the node type
+# is not already compiled into the kernel.
+options NETGRAPH #netgraph(4) system
+options NETGRAPH_ASYNC
+options NETGRAPH_CISCO
+options NETGRAPH_ECHO
+options NETGRAPH_FRAME_RELAY
+options NETGRAPH_HOLE
+options NETGRAPH_IFACE
+options NETGRAPH_LMI
+options NETGRAPH_RFC1490
+options NETGRAPH_TEE
+options NETGRAPH_TTY
+options NETGRAPH_UI
+
#
# Network interfaces:
# The `loop' pseudo-device is MANDATORY when networking is enabled.
diff --git a/sys/conf/files b/sys/conf/files
index 2a65eb0..23e5ded 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -563,6 +563,19 @@ netatm/uni/unisig_sigmgr_state.c optional atm_uni atm_core
netatm/uni/unisig_subr.c optional atm_uni atm_core
netatm/uni/unisig_util.c optional atm_uni atm_core
netatm/uni/unisig_vc_state.c optional atm_uni atm_core
+netgraph/ng_base.c optional netgraph
+netgraph/ng_async.c optional netgraph_async
+netgraph/ng_cisco.c optional netgraph_cisco
+netgraph/ng_echo.c optional netgraph_echo
+netgraph/ng_frame_relay.c optional netgraph_frame_relay
+netgraph/ng_hole.c optional netgraph_hole
+netgraph/ng_iface.c optional netgraph_iface
+netgraph/ng_lmi.c optional netgraph_lmi
+netgraph/ng_rfc1490.c optional netgraph_rfc1490
+netgraph/ng_socket.c optional netgraph_socket
+netgraph/ng_tee.c optional netgraph_tee
+netgraph/ng_tty.c optional netgraph_tty
+netgraph/ng_UI.c optional netgraph_UI
netinet/if_atm.c optional atm
netinet/if_ether.c optional ether
netinet/igmp.c optional inet
diff --git a/sys/conf/options b/sys/conf/options
index 5894d64..26beba5 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -237,6 +237,24 @@ TCPDEBUG
TCP_DROP_SYNFIN opt_tcp_input.h
TCP_RESTRICT_RST opt_tcp_input.h
+# Netgraph(4). Use option NETGRAPH to enable the base netgraph code.
+# Each netgraph node type can be either be compiled into the kernel
+# or loaded dynamically. To get the former, include the corresponding
+# option below.
+NETGRAPH
+NETGRAPH_ASYNC opt_netgraph.h
+NETGRAPH_CISCO opt_netgraph.h
+NETGRAPH_ECHO opt_netgraph.h
+NETGRAPH_FRAME_RELAY opt_netgraph.h
+NETGRAPH_HOLE opt_netgraph.h
+NETGRAPH_IFACE opt_netgraph.h
+NETGRAPH_LMI opt_netgraph.h
+NETGRAPH_RFC1490 opt_netgraph.h
+NETGRAPH_SOCKET opt_netgraph.h
+NETGRAPH_TEE opt_netgraph.h
+NETGRAPH_TTY opt_netgraph.h
+NETGRAPH_UI opt_netgraph.h
+
# ATM (HARP version)
ATM_CORE opt_atm.h
ATM_IP opt_atm.h
diff --git a/sys/dev/ar/if_ar.c b/sys/dev/ar/if_ar.c
index 3e78c79..0eec2cf 100644
--- a/sys/dev/ar/if_ar.c
+++ b/sys/dev/ar/if_ar.c
@@ -45,6 +45,7 @@
*
*/
+#include "opt_netgraph.h"
#include "ar.h"
#include <sys/param.h>
@@ -55,9 +56,16 @@
#include <sys/socket.h>
#include <net/if.h>
+#ifdef NETGRAPH
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <i386/isa/if_ar.h>
+#else /* NETGRAPH */
#include <net/if_sppp.h>
-
#include <net/bpf.h>
+#endif /* NETGRAPH */
#include <machine/clock.h>
#include <machine/md_var.h>
@@ -66,10 +74,12 @@
#include <i386/isa/ic/hd64570.h>
#include <i386/isa/isa_device.h>
+#ifndef NETGRAPH
#include "sppp.h"
#if NSPPP <= 0
#error device 'ar' require sppp.
-#endif
+#endif /* NSPPP <= 0 */
+#endif /* NETGRAPH */
#ifdef TRACE
#define TRC(x) x
@@ -118,7 +128,9 @@ static int next_ar_unit = 0;
static struct ar_hardc ar_hardc[NAR];
struct ar_softc {
+#ifndef NETGRAPH
struct sppp ifsppp;
+#endif /* NETGRAPH */
int unit; /* With regards to all ar devices */
int subunit; /* With regards to this card */
struct ar_hardc *hc;
@@ -146,8 +158,38 @@ struct ar_softc {
int scano;
int scachan;
sca_regs *sca;
+#ifdef NETGRAPH
+ int running; /* something is attached so we are running */
+ int dcd; /* do we have dcd? */
+ /* ---netgraph bits --- */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ hook_p hook; /* data hook */
+ hook_p debug_hook;
+ struct ifqueue xmitq_hipri; /* hi-priority transmit queue */
+ struct ifqueue xmitq; /* transmit queue */
+ int flags; /* state */
+#define SCF_RUNNING 0x01 /* board is active */
+#define SCF_OACTIVE 0x02 /* output is active */
+ int out_dog; /* watchdog cycles output count-down */
+ struct callout_handle handle; /* timeout(9) handle */
+ u_long inbytes, outbytes; /* stats */
+ u_long lastinbytes, lastoutbytes; /* a second ago */
+ u_long inrate, outrate; /* highest rate seen */
+ u_long inlast; /* last input N secs ago */
+ u_long out_deficit; /* output since last input */
+ u_long oerrors, ierrors[6];
+ u_long opackets, ipackets;
+#endif /* NETGRAPH */
};
+#ifdef NETGRAPH
+#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */
+#define QUITE_A_WHILE 300 /* 5 MINUTES */
+#define LOTS_OF_PACKETS 100
+#endif /* NETGRAPH */
+
static int arprobe(struct isa_device *id);
static int arattach_isa(struct isa_device *id);
@@ -184,9 +226,14 @@ void arintr_hc(struct ar_hardc *hc);
static ointhand2_t arintr;
static int arattach(struct ar_hardc *hc);
static void ar_xmit(struct ar_softc *sc);
+#ifndef NETGRAPH
static void arstart(struct ifnet *ifp);
static int arioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void arwatchdog(struct ifnet *ifp);
+#else /* NETGRAPH */
+static void arstart(struct ar_softc *sc);
+static void arwatchdog(struct ar_softc *sc);
+#endif /* NETGRAPH */
static int ar_packet_avail(struct ar_softc *sc, int *len, u_char *rxstat);
static void ar_copy_rxbuf(struct mbuf *m, struct ar_softc *sc, int len);
static void ar_eat_packet(struct ar_softc *sc, int single);
@@ -204,6 +251,37 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr);
+#ifdef NETGRAPH
+static void ngar_watchdog_frame(void * arg);
+static void ngar_init(void* ignored);
+static int ngar_constructor(node_p *nodep);
+static int ngar_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngar_rmnode(node_p node);
+static int ngar_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngar_findhook(node_p node, char *name);*/
+static int ngar_connect(hook_p hook); /* already PARTLY linked */
+static int ngar_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngar_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_AR_NODE_TYPE,
+ NULL,
+ ngar_constructor,
+ ngar_rcvmsg,
+ ngar_rmnode,
+ ngar_newhook,
+ NULL,
+ ngar_connect,
+ ngar_rcvdata,
+ ngar_rcvdata,
+ ngar_disconnect
+};
+
+static int ngar_done_init = 0;
+#endif /* NETGRAPH */
+
/*
* Register the Adapter.
* Probe to see if it is there.
@@ -348,7 +426,9 @@ static int
arattach(struct ar_hardc *hc)
{
struct ar_softc *sc;
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
int unit;
char *iface;
@@ -380,6 +460,7 @@ arattach(struct ar_hardc *hc)
ar_init_tx_dmac(sc);
ar_init_msci(sc);
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
ifp->if_softc = sc;
@@ -412,6 +493,25 @@ arattach(struct ar_hardc *hc)
if_attach(ifp);
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
+#else /* NETGRAPH */
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngar_done_init == 0) ngar_init(NULL);
+ if (ng_make_node_common(&typestruct, &sc->node) != 0)
+ return (0);
+ sc->node->private = sc;
+ callout_handle_init(&sc->handle);
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(sc->nodename, "%s%d", NG_AR_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ return (0);
+ }
+ sc->running = 0;
+#endif /* NETGRAPH */
}
if(hc->bustype == AR_BUS_ISA)
@@ -511,10 +611,14 @@ arintr_hc(struct ar_hardc *hc)
static void
ar_xmit(struct ar_softc *sc)
{
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
dmac_channel *dmac;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
dmac = &sc->sca->dmac[DMAC_TXCH(sc->scachan)];
if(sc->hc->bustype == AR_BUS_ISA)
@@ -530,7 +634,11 @@ ar_xmit(struct ar_softc *sc)
if(sc->txb_next_tx == AR_TX_BLOCKS)
sc->txb_next_tx = 0;
+#ifndef NETGRAPH
ifp->if_timer = 2; /* Value in seconds. */
+#else /* NETGRAPH */
+ sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_OFF(sc->hc->iobase);
}
@@ -549,30 +657,51 @@ ar_xmit(struct ar_softc *sc)
* that clears that should ensure that the transmitter and its DMA is
* in a "good" idle state.
*/
+#ifndef NETGRAPH
static void
arstart(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+#else /* NETGRAPH */
+static void
+arstart(struct ar_softc *sc)
+{
+#endif /* NETGRAPH */
int i, len, tlen;
struct mbuf *mtx;
u_char *txdata;
sca_descriptor *txdesc;
struct buf_block *blkp;
+#ifndef NETGRAPH
if(!(ifp->if_flags & IFF_RUNNING))
return;
+#else /* NETGRAPH */
+/* XXX */
+#endif /* NETGRAPH */
top_arstart:
/*
* See if we have space for more packets.
*/
+#ifndef NETGRAPH
if(sc->txb_inuse == AR_TX_BLOCKS) {
- ifp->if_flags |= IFF_OACTIVE;
+ ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */
+#else /* NETGRAPH */
+/*XXX*/ /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */
+#endif /* NETGRAPH */
return;
}
+#ifndef NETGRAPH
mtx = sppp_dequeue(ifp);
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if(!mtx)
return;
@@ -618,10 +747,16 @@ top_arstart:
txdata += AR_BUF_SIZ;
i++;
+#ifndef NETGRAPH
if(ifp->if_bpf)
bpf_mtap(ifp, mtx);
m_freem(mtx);
++sc->ifsppp.pp_if.if_opackets;
+#else /* NETGRAPH */
+ m_freem(mtx);
+ sc->outbytes += len;
+ ++sc->opackets;
+#endif /* NETGRAPH */
/*
* Check if we have space for another mbuf.
@@ -631,7 +766,14 @@ top_arstart:
if((i + 3) >= blkp->txmax)
break;
+#ifndef NETGRAPH
mtx = sppp_dequeue(ifp);
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if(!mtx)
break;
}
@@ -670,6 +812,7 @@ top_arstart:
goto top_arstart;
}
+#ifndef NETGRAPH
static int
arioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -711,18 +854,26 @@ arioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
splx(s);
return 0;
}
+#endif /* NETGRAPH */
/*
* This is to catch lost tx interrupts.
*/
static void
+#ifndef NETGRAPH
arwatchdog(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+#else /* NETGRAPH */
+arwatchdog(struct ar_softc *sc)
+{
+#endif /* NETGRAPH */
msci_channel *msci = &sc->sca->msci[sc->scachan];
+#ifndef NETGRAPH
if(!(ifp->if_flags & IFF_RUNNING))
return;
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -730,7 +881,7 @@ arwatchdog(struct ifnet *ifp)
/* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
printf("ar%d: transmit failed, "
"ST0 %x, ST1 %x, ST3 %x, DSR %x.\n",
- ifp->if_unit,
+ sc->unit,
msci->st0,
msci->st1,
msci->st3,
@@ -743,12 +894,20 @@ arwatchdog(struct ifnet *ifp)
}
sc->xmit_busy = 0;
+#ifndef NETGRAPH
ifp->if_flags &= ~IFF_OACTIVE;
+#else /* NETGRAPH */
+ /* XXX ifp->if_flags &= ~IFF_OACTIVE; */
+#endif /* NETGRAPH */
if(sc->txb_inuse && --sc->txb_inuse)
ar_xmit(sc);
+#ifndef NETGRAPH
arstart(ifp);
+#else /* NETGRAPH */
+ arstart(sc);
+#endif /* NETGRAPH */
}
static void
@@ -803,6 +962,11 @@ ar_up(struct ar_softc *sc)
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_OFF(sc->hc->iobase);
+#ifdef NETGRAPH
+ untimeout(ngar_watchdog_frame, sc, sc->handle);
+ sc->handle = timeout(ngar_watchdog_frame, sc, hz);
+ sc->running = 1;
+#endif /* NETGRAPH */
}
static void
@@ -814,6 +978,10 @@ ar_down(struct ar_softc *sc)
sca = sc->sca;
msci = &sca->msci[sc->scachan];
+#ifdef NETGRAPH
+ untimeout(ngar_watchdog_frame, sc, sc->handle);
+ sc->running = 0;
+#endif /* NETGRAPH */
/*
* Disable transmitter and receiver.
* Lower DTR and RTS.
@@ -958,9 +1126,12 @@ arc_init(struct ar_hardc *hc)
u_int descneeded;
u_char isr, mar;
- sc = hc->sc = malloc(hc->numports * sizeof(struct ar_softc),
- M_DEVBUF, M_WAITOK);
+ MALLOC(sc, struct ar_softc *,
+ hc->numports * sizeof(struct ar_softc), M_DEVBUF, M_WAITOK);
+ if (sc == NULL)
+ return (ENOMEM);
bzero(sc, hc->numports * sizeof(struct ar_softc));
+ hc->sc = sc;
hc->txc_dtr[0] = AR_TXC_DTR_NOTRESET |
AR_TXC_DTR_DTR0 | AR_TXC_DTR_DTR1;
@@ -1088,7 +1259,6 @@ arc_init(struct ar_hardc *hc)
if(hc->bustype == AR_BUS_PCI)
hc->orbase[AR_PIMCTRL] = AR_PIM_MODEG | AR_PIM_AUTO_LED;
-
}
@@ -1105,7 +1275,6 @@ ar_init_sca(struct ar_hardc *hc, int scano)
sca_regs *sca;
sca = hc->sca[scano];
-
if(hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(hc->iobase, scano);
@@ -1562,7 +1731,13 @@ ar_get_packets(struct ar_softc *sc)
ar_eat_packet(sc, 1);
continue;
}
+#ifndef NETGRAPH
m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
+#else /* NETGRAPH */
+ m->m_pkthdr.rcvif = NULL;
+ sc->inbytes += len;
+ sc->inlast = 0;
+#endif /* NETGRAPH */
m->m_pkthdr.len = m->m_len = len;
if(len > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -1573,10 +1748,15 @@ ar_get_packets(struct ar_softc *sc)
}
}
ar_copy_rxbuf(m, sc, len);
+#ifndef NETGRAPH
if(sc->ifsppp.pp_if.if_bpf)
bpf_mtap(&sc->ifsppp.pp_if, m);
sppp_input(&sc->ifsppp.pp_if, m);
sc->ifsppp.pp_if.if_ipackets++;
+#else /* NETGRAPH */
+ ng_queue_data(sc->hook, m, NULL);
+ sc->ipackets++;
+#endif /* NETGRAPH */
/*
* Update the eda to the previous descriptor.
@@ -1609,7 +1789,11 @@ ar_get_packets(struct ar_softc *sc)
ar_eat_packet(sc, 1);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[0]++;
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -1678,8 +1862,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
printf("ar%d: TX DMA Counter overflow, "
"txpacket no %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_opackets);
sc->ifsppp.pp_if.if_oerrors++;
+#else /* NETGRAPH */
+ sc->opackets);
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/* Buffer overflow */
@@ -1688,11 +1877,19 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
"txpacket no %lu, dsr %02x, "
"cda %04x, eda %04x.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_opackets,
+#else /* NETGRAPH */
+ sc->opackets,
+#endif /* NETGRAPH */
dsr,
dmac->cda,
dmac->eda);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_oerrors++;
+#else /* NETGRAPH */
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/* End of Transfer */
@@ -1706,8 +1903,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
* there is data to transmit.
*/
sc->xmit_busy = 0;
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
sc->ifsppp.pp_if.if_timer = 0;
+#else /* NETGRAPH */
+ /* XXX c->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; */
+ sc->out_dog = 0; /* XXX */
+#endif /* NETGRAPH */
if(sc->txb_inuse && --sc->txb_inuse)
ar_xmit(sc);
@@ -1735,7 +1937,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
ar_get_packets(sc);
TRC(
+#ifndef NETGRAPH
if(tt == sc->ifsppp.pp_if.if_ipackets) {
+#else /* NETGRAPH */
+ if(tt == sc->ipackets) {
+#endif /* NETGRAPH */
sca_descriptor *rxdesc;
int i;
@@ -1779,8 +1985,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
printf("ar%d: RX DMA Counter overflow, "
"rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ipackets);
+ sc->ierrors[1]++;
+#endif /* NETGRAPH */
}
/* Buffer overflow */
@@ -1791,7 +2002,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets,
+#else /* NETGRAPH */
+ sc->ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
dmac->cda,
dmac->eda,
@@ -1801,7 +2016,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
* Then get the system running again.
*/
ar_eat_packet(sc, 0);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[2]++;
+#endif /* NETGRAPH */
if(hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(hc->iobase, scano);
sca->msci[mch].cmd = SCA_CMD_RXMSGREJ;
@@ -1829,8 +2048,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
*/
printf("ar%d: RX End of transfer, rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ipackets);
+ sc->ierrors[3]++;
+#endif /* NETGRAPH */
}
}
@@ -1846,7 +2070,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
for(mch = 0; mch < NCHAN; mch++) {
if(dotxstart & 0x0C) {
sc = &hc->sc[mch + (NCHAN * scano)];
+#ifndef NETGRAPH
arstart(&sc->ifsppp.pp_if);
+#else /* NETGRAPH */
+ arstart(sc);
+#endif /* NETGRAPH */
}
dotxstart >>= 4;
}
@@ -1864,7 +2092,299 @@ ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
printf("arc%d: ARINTR: TIMER\n", hc->cunit);
}
+
+#ifdef NETGRAPH
+/*****************************************
+ * Device timeout/watchdog routine.
+ * called once per second.
+ * checks to see that if activity was expected, that it hapenned.
+ * At present we only look to see if expected output was completed.
+ */
+static void
+ngar_watchdog_frame(void * arg)
+{
+ struct ar_softc * sc = arg;
+ int s;
+ int speed;
+
+ if(sc->running == 0)
+ return; /* if we are not running let timeouts die */
+ /*
+ * calculate the apparent throughputs
+ * XXX a real hack
+ */
+ s = splimp();
+ speed = sc->inbytes - sc->lastinbytes;
+ sc->lastinbytes = sc->inbytes;
+ if ( sc->inrate < speed )
+ sc->inrate = speed;
+ speed = sc->outbytes - sc->lastoutbytes;
+ sc->lastoutbytes = sc->outbytes;
+ if ( sc->outrate < speed )
+ sc->outrate = speed;
+ sc->inlast++;
+ splx(s);
+
+ if ((sc->inlast > QUITE_A_WHILE)
+ && (sc->out_deficit > LOTS_OF_PACKETS)) {
+ log(LOG_ERR, "ar%d: No response from remote end\n", sc->unit);
+ s = splimp();
+ ar_down(sc);
+ ar_up(sc);
+ sc->inlast = sc->out_deficit = 0;
+ splx(s);
+ } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */
+ if (sc->out_dog == 0) {
+ log(LOG_ERR, "ar%d: Transmit failure.. no clock?\n",
+ sc->unit);
+ arwatchdog(sc);
+#if 0
+ s = splimp();
+ ar_down(sc);
+ ar_up(sc);
+ splx(s);
+#endif
+ sc->inlast = sc->out_deficit = 0;
+ } else {
+ sc->out_dog--;
+ }
+ }
+ sc->handle = timeout(ngar_watchdog_frame, sc, hz);
+}
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
/*
- ********************************* END ************************************
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngar_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * give our ok for a hook to be added...
+ * If we are not running this should kick the device into life.
+ * We allow hooks called "control" and dlci[1-1023]
+ * The hook's private info points to our stash of info about that
+ * channel.
+ */
+static int
+ngar_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct ar_softc * sc = node->private;
+
+ /*
+ * check if it's our friend the debug hook
+ */
+ if (strcmp(name, NG_AR_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ sc->debug_hook = hook;
+ return (0);
+ }
+
+ /*
+ * Check for raw mode hook.
+ */
+ if (strcmp(name, NG_AR_HOOK_RAW) != 0) {
+ return (EINVAL);
+ }
+ hook->private = sc;
+ sc->hook = hook;
+ sc->datahooks++;
+ ar_up(sc);
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
*/
+static int
+ngar_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct ar_softc * sc;
+ int error = 0;
+
+ sc = node->private;
+ switch (msg->header.typecookie) {
+ case NG_AR_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n"
+ "highest rate seen: %ld B/S in, %ld B/S out\n",
+ sc->inbytes, sc->outbytes,
+ sc->inrate, sc->outrate);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ sc->oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld, %ld, %ld, %ld\n",
+ sc->ierrors[0],
+ sc->ierrors[1],
+ sc->ierrors[2],
+ sc->ierrors[3]);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NG_AR_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * get data from another node and transmit it to the correct channel
+ */
+static int
+ngar_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int s;
+ int error = 0;
+ struct ar_softc * sc = hook->node->private;
+ struct ifqueue *xmitq_p;
+
+ /*
+ * data doesn't come in from just anywhere (e.g control hook)
+ */
+ if ( hook->private == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splimp();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ splx(s);
+ arstart(sc);
+ return (0);
+
+bad:
+ /*
+ * It was an error case.
+ * check if we need to free the mbuf, and then return the error
+ */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * do local shutdown processing..
+ * this node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngar_rmnode(node_p node)
+{
+ struct ar_softc * sc = node->private;
+
+ ar_down(sc);
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngar_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ * As the device still exists, the shutdown method will not actually
+ * destroy the node, but reset the device and leave it 'fresh' :)
+ *
+ * The node removal code will remove all references except that owned by the
+ * driver.
+ */
+static int
+ngar_disconnect(hook_p hook)
+{
+ struct ar_softc * sc = hook->node->private;
+ int s;
+ /*
+ * If it's the data hook, then free resources etc.
+ */
+ if (hook->private) {
+ s = splimp();
+ sc->datahooks--;
+ if (sc->datahooks == 0)
+ ar_down(sc);
+ splx(s);
+ } else {
+ sc->debug_hook = NULL;
+ }
+ return (0);
+}
+
+/*
+ * called during bootup
+ * or LKM loading to put this type into the list of known modules
+ */
+static void
+ngar_init(void *ignored)
+{
+ if (ng_newtype(&typestruct))
+ printf("ngar install failed\n");
+ ngar_done_init = 1;
+}
+#endif /* NETGRAPH */
+/*
+ ********************************* END ************************************
+ */
diff --git a/sys/dev/ar/if_ar.h b/sys/dev/ar/if_ar.h
new file mode 100644
index 0000000..a40ccb9
--- /dev/null
+++ b/sys/dev/ar/if_ar.h
@@ -0,0 +1,23 @@
+/*
+ * if_ar.h
+ *
+ * Copyright (C) 1997-1999 Whistle Communications Inc.
+ * All rights reserved.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _I386_ISA_IF_AR_H_
+#define _I386_ISA_IF_AR_H_
+
+/* Node type name and type cookie */
+#define NG_AR_NODE_TYPE "sync_ar"
+#define NG_AR_COOKIE 860552149
+
+/* Netgraph hooks */
+#define NG_AR_HOOK_DEBUG "debug"
+#define NG_AR_HOOK_CONTROL "control"
+#define NG_AR_HOOK_RAW "rawdata"
+
+#endif /* _I386_ISA_IF_AR_H_ */
+
diff --git a/sys/dev/ar/if_ar_isa.c b/sys/dev/ar/if_ar_isa.c
index 3e78c79..0eec2cf 100644
--- a/sys/dev/ar/if_ar_isa.c
+++ b/sys/dev/ar/if_ar_isa.c
@@ -45,6 +45,7 @@
*
*/
+#include "opt_netgraph.h"
#include "ar.h"
#include <sys/param.h>
@@ -55,9 +56,16 @@
#include <sys/socket.h>
#include <net/if.h>
+#ifdef NETGRAPH
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <i386/isa/if_ar.h>
+#else /* NETGRAPH */
#include <net/if_sppp.h>
-
#include <net/bpf.h>
+#endif /* NETGRAPH */
#include <machine/clock.h>
#include <machine/md_var.h>
@@ -66,10 +74,12 @@
#include <i386/isa/ic/hd64570.h>
#include <i386/isa/isa_device.h>
+#ifndef NETGRAPH
#include "sppp.h"
#if NSPPP <= 0
#error device 'ar' require sppp.
-#endif
+#endif /* NSPPP <= 0 */
+#endif /* NETGRAPH */
#ifdef TRACE
#define TRC(x) x
@@ -118,7 +128,9 @@ static int next_ar_unit = 0;
static struct ar_hardc ar_hardc[NAR];
struct ar_softc {
+#ifndef NETGRAPH
struct sppp ifsppp;
+#endif /* NETGRAPH */
int unit; /* With regards to all ar devices */
int subunit; /* With regards to this card */
struct ar_hardc *hc;
@@ -146,8 +158,38 @@ struct ar_softc {
int scano;
int scachan;
sca_regs *sca;
+#ifdef NETGRAPH
+ int running; /* something is attached so we are running */
+ int dcd; /* do we have dcd? */
+ /* ---netgraph bits --- */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ hook_p hook; /* data hook */
+ hook_p debug_hook;
+ struct ifqueue xmitq_hipri; /* hi-priority transmit queue */
+ struct ifqueue xmitq; /* transmit queue */
+ int flags; /* state */
+#define SCF_RUNNING 0x01 /* board is active */
+#define SCF_OACTIVE 0x02 /* output is active */
+ int out_dog; /* watchdog cycles output count-down */
+ struct callout_handle handle; /* timeout(9) handle */
+ u_long inbytes, outbytes; /* stats */
+ u_long lastinbytes, lastoutbytes; /* a second ago */
+ u_long inrate, outrate; /* highest rate seen */
+ u_long inlast; /* last input N secs ago */
+ u_long out_deficit; /* output since last input */
+ u_long oerrors, ierrors[6];
+ u_long opackets, ipackets;
+#endif /* NETGRAPH */
};
+#ifdef NETGRAPH
+#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */
+#define QUITE_A_WHILE 300 /* 5 MINUTES */
+#define LOTS_OF_PACKETS 100
+#endif /* NETGRAPH */
+
static int arprobe(struct isa_device *id);
static int arattach_isa(struct isa_device *id);
@@ -184,9 +226,14 @@ void arintr_hc(struct ar_hardc *hc);
static ointhand2_t arintr;
static int arattach(struct ar_hardc *hc);
static void ar_xmit(struct ar_softc *sc);
+#ifndef NETGRAPH
static void arstart(struct ifnet *ifp);
static int arioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void arwatchdog(struct ifnet *ifp);
+#else /* NETGRAPH */
+static void arstart(struct ar_softc *sc);
+static void arwatchdog(struct ar_softc *sc);
+#endif /* NETGRAPH */
static int ar_packet_avail(struct ar_softc *sc, int *len, u_char *rxstat);
static void ar_copy_rxbuf(struct mbuf *m, struct ar_softc *sc, int len);
static void ar_eat_packet(struct ar_softc *sc, int single);
@@ -204,6 +251,37 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr);
+#ifdef NETGRAPH
+static void ngar_watchdog_frame(void * arg);
+static void ngar_init(void* ignored);
+static int ngar_constructor(node_p *nodep);
+static int ngar_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngar_rmnode(node_p node);
+static int ngar_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngar_findhook(node_p node, char *name);*/
+static int ngar_connect(hook_p hook); /* already PARTLY linked */
+static int ngar_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngar_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_AR_NODE_TYPE,
+ NULL,
+ ngar_constructor,
+ ngar_rcvmsg,
+ ngar_rmnode,
+ ngar_newhook,
+ NULL,
+ ngar_connect,
+ ngar_rcvdata,
+ ngar_rcvdata,
+ ngar_disconnect
+};
+
+static int ngar_done_init = 0;
+#endif /* NETGRAPH */
+
/*
* Register the Adapter.
* Probe to see if it is there.
@@ -348,7 +426,9 @@ static int
arattach(struct ar_hardc *hc)
{
struct ar_softc *sc;
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
int unit;
char *iface;
@@ -380,6 +460,7 @@ arattach(struct ar_hardc *hc)
ar_init_tx_dmac(sc);
ar_init_msci(sc);
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
ifp->if_softc = sc;
@@ -412,6 +493,25 @@ arattach(struct ar_hardc *hc)
if_attach(ifp);
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
+#else /* NETGRAPH */
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngar_done_init == 0) ngar_init(NULL);
+ if (ng_make_node_common(&typestruct, &sc->node) != 0)
+ return (0);
+ sc->node->private = sc;
+ callout_handle_init(&sc->handle);
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(sc->nodename, "%s%d", NG_AR_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ return (0);
+ }
+ sc->running = 0;
+#endif /* NETGRAPH */
}
if(hc->bustype == AR_BUS_ISA)
@@ -511,10 +611,14 @@ arintr_hc(struct ar_hardc *hc)
static void
ar_xmit(struct ar_softc *sc)
{
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
dmac_channel *dmac;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
dmac = &sc->sca->dmac[DMAC_TXCH(sc->scachan)];
if(sc->hc->bustype == AR_BUS_ISA)
@@ -530,7 +634,11 @@ ar_xmit(struct ar_softc *sc)
if(sc->txb_next_tx == AR_TX_BLOCKS)
sc->txb_next_tx = 0;
+#ifndef NETGRAPH
ifp->if_timer = 2; /* Value in seconds. */
+#else /* NETGRAPH */
+ sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_OFF(sc->hc->iobase);
}
@@ -549,30 +657,51 @@ ar_xmit(struct ar_softc *sc)
* that clears that should ensure that the transmitter and its DMA is
* in a "good" idle state.
*/
+#ifndef NETGRAPH
static void
arstart(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+#else /* NETGRAPH */
+static void
+arstart(struct ar_softc *sc)
+{
+#endif /* NETGRAPH */
int i, len, tlen;
struct mbuf *mtx;
u_char *txdata;
sca_descriptor *txdesc;
struct buf_block *blkp;
+#ifndef NETGRAPH
if(!(ifp->if_flags & IFF_RUNNING))
return;
+#else /* NETGRAPH */
+/* XXX */
+#endif /* NETGRAPH */
top_arstart:
/*
* See if we have space for more packets.
*/
+#ifndef NETGRAPH
if(sc->txb_inuse == AR_TX_BLOCKS) {
- ifp->if_flags |= IFF_OACTIVE;
+ ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */
+#else /* NETGRAPH */
+/*XXX*/ /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */
+#endif /* NETGRAPH */
return;
}
+#ifndef NETGRAPH
mtx = sppp_dequeue(ifp);
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if(!mtx)
return;
@@ -618,10 +747,16 @@ top_arstart:
txdata += AR_BUF_SIZ;
i++;
+#ifndef NETGRAPH
if(ifp->if_bpf)
bpf_mtap(ifp, mtx);
m_freem(mtx);
++sc->ifsppp.pp_if.if_opackets;
+#else /* NETGRAPH */
+ m_freem(mtx);
+ sc->outbytes += len;
+ ++sc->opackets;
+#endif /* NETGRAPH */
/*
* Check if we have space for another mbuf.
@@ -631,7 +766,14 @@ top_arstart:
if((i + 3) >= blkp->txmax)
break;
+#ifndef NETGRAPH
mtx = sppp_dequeue(ifp);
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if(!mtx)
break;
}
@@ -670,6 +812,7 @@ top_arstart:
goto top_arstart;
}
+#ifndef NETGRAPH
static int
arioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -711,18 +854,26 @@ arioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
splx(s);
return 0;
}
+#endif /* NETGRAPH */
/*
* This is to catch lost tx interrupts.
*/
static void
+#ifndef NETGRAPH
arwatchdog(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+#else /* NETGRAPH */
+arwatchdog(struct ar_softc *sc)
+{
+#endif /* NETGRAPH */
msci_channel *msci = &sc->sca->msci[sc->scachan];
+#ifndef NETGRAPH
if(!(ifp->if_flags & IFF_RUNNING))
return;
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -730,7 +881,7 @@ arwatchdog(struct ifnet *ifp)
/* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
printf("ar%d: transmit failed, "
"ST0 %x, ST1 %x, ST3 %x, DSR %x.\n",
- ifp->if_unit,
+ sc->unit,
msci->st0,
msci->st1,
msci->st3,
@@ -743,12 +894,20 @@ arwatchdog(struct ifnet *ifp)
}
sc->xmit_busy = 0;
+#ifndef NETGRAPH
ifp->if_flags &= ~IFF_OACTIVE;
+#else /* NETGRAPH */
+ /* XXX ifp->if_flags &= ~IFF_OACTIVE; */
+#endif /* NETGRAPH */
if(sc->txb_inuse && --sc->txb_inuse)
ar_xmit(sc);
+#ifndef NETGRAPH
arstart(ifp);
+#else /* NETGRAPH */
+ arstart(sc);
+#endif /* NETGRAPH */
}
static void
@@ -803,6 +962,11 @@ ar_up(struct ar_softc *sc)
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_OFF(sc->hc->iobase);
+#ifdef NETGRAPH
+ untimeout(ngar_watchdog_frame, sc, sc->handle);
+ sc->handle = timeout(ngar_watchdog_frame, sc, hz);
+ sc->running = 1;
+#endif /* NETGRAPH */
}
static void
@@ -814,6 +978,10 @@ ar_down(struct ar_softc *sc)
sca = sc->sca;
msci = &sca->msci[sc->scachan];
+#ifdef NETGRAPH
+ untimeout(ngar_watchdog_frame, sc, sc->handle);
+ sc->running = 0;
+#endif /* NETGRAPH */
/*
* Disable transmitter and receiver.
* Lower DTR and RTS.
@@ -958,9 +1126,12 @@ arc_init(struct ar_hardc *hc)
u_int descneeded;
u_char isr, mar;
- sc = hc->sc = malloc(hc->numports * sizeof(struct ar_softc),
- M_DEVBUF, M_WAITOK);
+ MALLOC(sc, struct ar_softc *,
+ hc->numports * sizeof(struct ar_softc), M_DEVBUF, M_WAITOK);
+ if (sc == NULL)
+ return (ENOMEM);
bzero(sc, hc->numports * sizeof(struct ar_softc));
+ hc->sc = sc;
hc->txc_dtr[0] = AR_TXC_DTR_NOTRESET |
AR_TXC_DTR_DTR0 | AR_TXC_DTR_DTR1;
@@ -1088,7 +1259,6 @@ arc_init(struct ar_hardc *hc)
if(hc->bustype == AR_BUS_PCI)
hc->orbase[AR_PIMCTRL] = AR_PIM_MODEG | AR_PIM_AUTO_LED;
-
}
@@ -1105,7 +1275,6 @@ ar_init_sca(struct ar_hardc *hc, int scano)
sca_regs *sca;
sca = hc->sca[scano];
-
if(hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(hc->iobase, scano);
@@ -1562,7 +1731,13 @@ ar_get_packets(struct ar_softc *sc)
ar_eat_packet(sc, 1);
continue;
}
+#ifndef NETGRAPH
m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
+#else /* NETGRAPH */
+ m->m_pkthdr.rcvif = NULL;
+ sc->inbytes += len;
+ sc->inlast = 0;
+#endif /* NETGRAPH */
m->m_pkthdr.len = m->m_len = len;
if(len > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -1573,10 +1748,15 @@ ar_get_packets(struct ar_softc *sc)
}
}
ar_copy_rxbuf(m, sc, len);
+#ifndef NETGRAPH
if(sc->ifsppp.pp_if.if_bpf)
bpf_mtap(&sc->ifsppp.pp_if, m);
sppp_input(&sc->ifsppp.pp_if, m);
sc->ifsppp.pp_if.if_ipackets++;
+#else /* NETGRAPH */
+ ng_queue_data(sc->hook, m, NULL);
+ sc->ipackets++;
+#endif /* NETGRAPH */
/*
* Update the eda to the previous descriptor.
@@ -1609,7 +1789,11 @@ ar_get_packets(struct ar_softc *sc)
ar_eat_packet(sc, 1);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[0]++;
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -1678,8 +1862,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
printf("ar%d: TX DMA Counter overflow, "
"txpacket no %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_opackets);
sc->ifsppp.pp_if.if_oerrors++;
+#else /* NETGRAPH */
+ sc->opackets);
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/* Buffer overflow */
@@ -1688,11 +1877,19 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
"txpacket no %lu, dsr %02x, "
"cda %04x, eda %04x.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_opackets,
+#else /* NETGRAPH */
+ sc->opackets,
+#endif /* NETGRAPH */
dsr,
dmac->cda,
dmac->eda);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_oerrors++;
+#else /* NETGRAPH */
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/* End of Transfer */
@@ -1706,8 +1903,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
* there is data to transmit.
*/
sc->xmit_busy = 0;
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
sc->ifsppp.pp_if.if_timer = 0;
+#else /* NETGRAPH */
+ /* XXX c->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; */
+ sc->out_dog = 0; /* XXX */
+#endif /* NETGRAPH */
if(sc->txb_inuse && --sc->txb_inuse)
ar_xmit(sc);
@@ -1735,7 +1937,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
ar_get_packets(sc);
TRC(
+#ifndef NETGRAPH
if(tt == sc->ifsppp.pp_if.if_ipackets) {
+#else /* NETGRAPH */
+ if(tt == sc->ipackets) {
+#endif /* NETGRAPH */
sca_descriptor *rxdesc;
int i;
@@ -1779,8 +1985,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
printf("ar%d: RX DMA Counter overflow, "
"rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ipackets);
+ sc->ierrors[1]++;
+#endif /* NETGRAPH */
}
/* Buffer overflow */
@@ -1791,7 +2002,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets,
+#else /* NETGRAPH */
+ sc->ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
dmac->cda,
dmac->eda,
@@ -1801,7 +2016,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
* Then get the system running again.
*/
ar_eat_packet(sc, 0);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[2]++;
+#endif /* NETGRAPH */
if(hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(hc->iobase, scano);
sca->msci[mch].cmd = SCA_CMD_RXMSGREJ;
@@ -1829,8 +2048,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
*/
printf("ar%d: RX End of transfer, rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ipackets);
+ sc->ierrors[3]++;
+#endif /* NETGRAPH */
}
}
@@ -1846,7 +2070,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
for(mch = 0; mch < NCHAN; mch++) {
if(dotxstart & 0x0C) {
sc = &hc->sc[mch + (NCHAN * scano)];
+#ifndef NETGRAPH
arstart(&sc->ifsppp.pp_if);
+#else /* NETGRAPH */
+ arstart(sc);
+#endif /* NETGRAPH */
}
dotxstart >>= 4;
}
@@ -1864,7 +2092,299 @@ ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
printf("arc%d: ARINTR: TIMER\n", hc->cunit);
}
+
+#ifdef NETGRAPH
+/*****************************************
+ * Device timeout/watchdog routine.
+ * called once per second.
+ * checks to see that if activity was expected, that it hapenned.
+ * At present we only look to see if expected output was completed.
+ */
+static void
+ngar_watchdog_frame(void * arg)
+{
+ struct ar_softc * sc = arg;
+ int s;
+ int speed;
+
+ if(sc->running == 0)
+ return; /* if we are not running let timeouts die */
+ /*
+ * calculate the apparent throughputs
+ * XXX a real hack
+ */
+ s = splimp();
+ speed = sc->inbytes - sc->lastinbytes;
+ sc->lastinbytes = sc->inbytes;
+ if ( sc->inrate < speed )
+ sc->inrate = speed;
+ speed = sc->outbytes - sc->lastoutbytes;
+ sc->lastoutbytes = sc->outbytes;
+ if ( sc->outrate < speed )
+ sc->outrate = speed;
+ sc->inlast++;
+ splx(s);
+
+ if ((sc->inlast > QUITE_A_WHILE)
+ && (sc->out_deficit > LOTS_OF_PACKETS)) {
+ log(LOG_ERR, "ar%d: No response from remote end\n", sc->unit);
+ s = splimp();
+ ar_down(sc);
+ ar_up(sc);
+ sc->inlast = sc->out_deficit = 0;
+ splx(s);
+ } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */
+ if (sc->out_dog == 0) {
+ log(LOG_ERR, "ar%d: Transmit failure.. no clock?\n",
+ sc->unit);
+ arwatchdog(sc);
+#if 0
+ s = splimp();
+ ar_down(sc);
+ ar_up(sc);
+ splx(s);
+#endif
+ sc->inlast = sc->out_deficit = 0;
+ } else {
+ sc->out_dog--;
+ }
+ }
+ sc->handle = timeout(ngar_watchdog_frame, sc, hz);
+}
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
/*
- ********************************* END ************************************
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngar_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * give our ok for a hook to be added...
+ * If we are not running this should kick the device into life.
+ * We allow hooks called "control" and dlci[1-1023]
+ * The hook's private info points to our stash of info about that
+ * channel.
+ */
+static int
+ngar_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct ar_softc * sc = node->private;
+
+ /*
+ * check if it's our friend the debug hook
+ */
+ if (strcmp(name, NG_AR_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ sc->debug_hook = hook;
+ return (0);
+ }
+
+ /*
+ * Check for raw mode hook.
+ */
+ if (strcmp(name, NG_AR_HOOK_RAW) != 0) {
+ return (EINVAL);
+ }
+ hook->private = sc;
+ sc->hook = hook;
+ sc->datahooks++;
+ ar_up(sc);
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
*/
+static int
+ngar_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct ar_softc * sc;
+ int error = 0;
+
+ sc = node->private;
+ switch (msg->header.typecookie) {
+ case NG_AR_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n"
+ "highest rate seen: %ld B/S in, %ld B/S out\n",
+ sc->inbytes, sc->outbytes,
+ sc->inrate, sc->outrate);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ sc->oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld, %ld, %ld, %ld\n",
+ sc->ierrors[0],
+ sc->ierrors[1],
+ sc->ierrors[2],
+ sc->ierrors[3]);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NG_AR_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * get data from another node and transmit it to the correct channel
+ */
+static int
+ngar_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int s;
+ int error = 0;
+ struct ar_softc * sc = hook->node->private;
+ struct ifqueue *xmitq_p;
+
+ /*
+ * data doesn't come in from just anywhere (e.g control hook)
+ */
+ if ( hook->private == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splimp();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ splx(s);
+ arstart(sc);
+ return (0);
+
+bad:
+ /*
+ * It was an error case.
+ * check if we need to free the mbuf, and then return the error
+ */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * do local shutdown processing..
+ * this node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngar_rmnode(node_p node)
+{
+ struct ar_softc * sc = node->private;
+
+ ar_down(sc);
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngar_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ * As the device still exists, the shutdown method will not actually
+ * destroy the node, but reset the device and leave it 'fresh' :)
+ *
+ * The node removal code will remove all references except that owned by the
+ * driver.
+ */
+static int
+ngar_disconnect(hook_p hook)
+{
+ struct ar_softc * sc = hook->node->private;
+ int s;
+ /*
+ * If it's the data hook, then free resources etc.
+ */
+ if (hook->private) {
+ s = splimp();
+ sc->datahooks--;
+ if (sc->datahooks == 0)
+ ar_down(sc);
+ splx(s);
+ } else {
+ sc->debug_hook = NULL;
+ }
+ return (0);
+}
+
+/*
+ * called during bootup
+ * or LKM loading to put this type into the list of known modules
+ */
+static void
+ngar_init(void *ignored)
+{
+ if (ng_newtype(&typestruct))
+ printf("ngar install failed\n");
+ ngar_done_init = 1;
+}
+#endif /* NETGRAPH */
+/*
+ ********************************* END ************************************
+ */
diff --git a/sys/dev/sr/if_sr.c b/sys/dev/sr/if_sr.c
index 6be7958..f50f7a5 100644
--- a/sys/dev/sr/if_sr.c
+++ b/sys/dev/sr/if_sr.c
@@ -48,16 +48,23 @@
*/
#include "sr.h"
+#include "opt_netgraph.h"
+#ifdef NETGRAPH
+#include <i386/isa/if_sr.h>
+#else /* NETGRAPH */
#ifdef notyet
#include "fr.h"
#else
#define NFR 0
#endif
+#endif /* NETGRAPH */
+#ifdef NETGRAPH
#include "sppp.h"
#if NSPPP <= 0
#error Device 'sr' requires sppp.
#endif
+#endif /* NETGRAPH */
#include <sys/param.h>
#include <sys/systm.h>
@@ -68,9 +75,13 @@
#include <sys/socket.h>
#include <net/if.h>
+#ifdef NETGRAPH
+#include <sys/syslog.h>
+#else /* NETGRAPH */
#include <net/if_sppp.h>
#include <net/bpf.h>
+#endif /* NETGRAPH */
#include <machine/md_var.h>
@@ -78,13 +89,19 @@
#include <i386/isa/ic/hd64570.h>
#include <i386/isa/isa_device.h>
+#ifdef NETGRAPH
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#endif /* NETGRAPH */
/* #define USE_MODEMCK */
#ifndef BUGGY
#define BUGGY 0
#endif
+#ifndef NETGRAPH
#define PPP_HEADER_LEN 4
+#endif /* NETGRAPH */
/*
* These macros are used to hide the difference between the way the
@@ -142,7 +159,9 @@ struct sr_hardc {
};
static int next_sc_unit = 0;
+#ifndef NETGRAPH
static int sr_watcher = 0;
+#endif /* NETGRAPH */
static struct sr_hardc sr_hardc[NSR];
static struct sr_hardc *sr_hardc_pci;
@@ -151,17 +170,20 @@ static struct sr_hardc *sr_hardc_pci;
* every channel (port).
*/
struct sr_softc {
+#ifndef NETGRAPH
struct sppp ifsppp; /* PPP service w/in system */
+#endif /* NETGRAPH */
struct sr_hardc *hc; /* card-level information */
int unit; /* With regard to all sr devices */
int subunit; /* With regard to this card */
+#ifndef NETGRAPH
int attached; /* attached to FR or PPP */
int protocol; /* FR or PPP */
#define N2_USE_FRP 2 /* Frame Relay Protocol */
#define N2_USE_PPP 1 /* Point-to-Point Protocol */
-
+#endif /* NETGRAPH */
struct buf_block {
u_int txdesc; /* DPRAM offset */
u_int txstart;/* DPRAM offset */
@@ -185,8 +207,40 @@ struct sr_softc {
u_int clk_cfg; /* Clock configuration */
int scachan; /* channel # on card */
+#ifdef NETGRAPH
+ int running; /* something is attached so we are running */
+ int dcd; /* do we have dcd? */
+ /* ---netgraph bits --- */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ hook_p hook; /* data hook */
+ hook_p debug_hook;
+ struct ifqueue xmitq_hipri; /* hi-priority transmit queue */
+ struct ifqueue xmitq; /* transmit queue */
+ int flags; /* state */
+#define SCF_RUNNING 0x01 /* board is active */
+#define SCF_OACTIVE 0x02 /* output is active */
+ int out_dog; /* watchdog cycles output count-down */
+#if ( __FreeBSD__ >= 3 )
+ struct callout_handle handle; /* timeout(9) handle */
+#endif
+ u_long inbytes, outbytes; /* stats */
+ u_long lastinbytes, lastoutbytes; /* a second ago */
+ u_long inrate, outrate; /* highest rate seen */
+ u_long inlast; /* last input N secs ago */
+ u_long out_deficit; /* output since last input */
+ u_long oerrors, ierrors[6];
+ u_long opackets, ipackets;
+#endif /* NETGRAPH */
};
+#ifdef NETGRAPH
+#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */
+#define QUITE_A_WHILE 300 /* 5 MINUTES */
+#define LOTS_OF_PACKETS 100
+#endif /* NETGRAPH */
+
/*
* List of valid interrupt numbers for the N2 ISA card.
*/
@@ -267,11 +321,17 @@ struct sr_hardc *srattach_pci(int unit, vm_offset_t plx_vaddr,
void srintr_hc(struct sr_hardc *hc);
static ointhand2_t srintr;
+
static int srattach(struct sr_hardc *hc);
static void sr_xmit(struct sr_softc *sc);
+#ifndef NETGRAPH
static void srstart(struct ifnet *ifp);
static int srioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void srwatchdog(struct ifnet *ifp);
+#else
+static void srstart(struct sr_softc *sc);
+static void srwatchdog(struct sr_softc *sc);
+#endif /* NETGRAPH */
static int sr_packet_avail(struct sr_softc *sc, int *len, u_char *rxstat);
static void sr_copy_rxbuf(struct mbuf *m, struct sr_softc *sc, int len);
static void sr_eat_packet(struct sr_softc *sc, int single);
@@ -287,7 +347,11 @@ static void sr_init_tx_dmac(struct sr_softc *sc);
static void sr_dmac_intr(struct sr_hardc *hc, u_char isr);
static void sr_msci_intr(struct sr_hardc *hc, u_char isr);
static void sr_timer_intr(struct sr_hardc *hc, u_char isr);
+#ifndef NETGRAPH
static void sr_modemck(void *x);
+#else
+static void sr_modemck(struct sr_softc *x);
+#endif /* NETGRAPH */
static u_int src_get8_io(u_int base, u_int off);
static u_int src_get16_io(u_int base, u_int off);
@@ -298,6 +362,7 @@ static u_int src_get16_mem(u_int base, u_int off);
static void src_put8_mem(u_int base, u_int off, u_int val);
static void src_put16_mem(u_int base, u_int off, u_int val);
+#ifndef NETGRAPH
#if NFR > 0
extern void fr_detach(struct ifnet *);
extern int fr_attach(struct ifnet *);
@@ -306,6 +371,36 @@ extern void fr_flush(struct ifnet *);
extern int fr_input(struct ifnet *, struct mbuf *);
extern struct mbuf *fr_dequeue(struct ifnet *);
#endif
+#else
+static void ngsr_watchdog_frame(void * arg);
+static void ngsr_init(void* ignored);
+static int ngsr_constructor(node_p *nodep);
+static int ngsr_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngsr_rmnode(node_p node);
+static int ngsr_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngsr_findhook(node_p node, char *name);*/
+static int ngsr_connect(hook_p hook); /* already PARTLY linked */
+static int ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngsr_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_SR_NODE_TYPE,
+ NULL,
+ ngsr_constructor,
+ ngsr_rcvmsg,
+ ngsr_rmnode,
+ ngsr_newhook,
+ NULL,
+ ngsr_connect,
+ ngsr_rcvdata,
+ ngsr_rcvdata,
+ ngsr_disconnect
+};
+
+static int ngsr_done_init = 0;
+#endif /* NETGRAPH */
/*
* I/O for ISA N2 card(s)
@@ -569,6 +664,15 @@ srattach_isa(struct isa_device *id)
u_char mar;
struct sr_hardc *hc = &sr_hardc[id->id_unit];
+ /*
+ * Allocate the software interface table(s)
+ */
+ MALLOC(hc->sc, struct sr_softc *,
+ hc->numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK);
+ if (hc->sc == NULL)
+ return(0);
+ bzero(hc->sc, hc->numports * sizeof(struct sr_softc));
+
id->id_ointr = srintr;
outb(hc->iobase + SR_PCR, inb(hc->iobase + SR_PCR) | SR_PCR_SCARUN);
@@ -588,13 +692,6 @@ srattach_isa(struct isa_device *id)
outb(hc->iobase + SR_BAR, mar);
/*
- * Allocate the software interface table(s)
- */
- hc->sc = malloc(hc->numports * sizeof(struct sr_softc),
- M_DEVBUF, M_WAITOK);
- bzero(hc->sc, hc->numports * sizeof(struct sr_softc));
-
- /*
* Get the TX clock direction and configuration. The default is a
* single external clock which is used by RX and TX.
*/
@@ -680,13 +777,19 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr)
hc = hc->next;
}
- hc = malloc(sizeof(struct sr_hardc), M_DEVBUF, M_WAITOK);
- *hcp = hc;
- bzero(hc, sizeof(struct sr_hardc));
+ MALLOC(hc, struct sr_hardc *, sizeof(*hc), M_DEVBUF, M_WAITOK);
+ if (hc == NULL)
+ return NULL;
+ bzero(hc, sizeof(*hc));
- hc->sc = malloc(numports * sizeof(struct sr_softc),
- M_DEVBUF, M_WAITOK);
+ MALLOC(hc->sc, struct sr_softc *,
+ numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK);
+ if (hc->sc == NULL) {
+ FREE(hc, M_DEVBUF);
+ return NULL;
+ }
bzero(hc->sc, numports * sizeof(struct sr_softc));
+ *hcp = hc;
hc->numports = numports;
hc->cunit = unit;
@@ -779,13 +882,17 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr)
/*
* Register the ports on the adapter.
* Fill in the info for each port.
+#ifndef NETGRAPH
* Attach each port to sppp and bpf.
+#endif
*/
static int
srattach(struct sr_hardc *hc)
{
struct sr_softc *sc = hc->sc;
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
int unit; /* index: channel w/in card */
/*
@@ -813,6 +920,10 @@ srattach(struct sr_hardc *hc)
sr_init_tx_dmac(sc);
sr_init_msci(sc);
+ printf("sr%d: Adapter %d, port %d.\n",
+ sc->unit, hc->cunit, sc->subunit);
+
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
ifp->if_softc = sc;
ifp->if_unit = sc->unit;
@@ -823,9 +934,6 @@ srattach(struct sr_hardc *hc)
ifp->if_start = srstart;
ifp->if_watchdog = srwatchdog;
- printf("sr%d: Adapter %d, port %d.\n",
- sc->unit, hc->cunit, sc->subunit);
-
/*
* Despite the fact that we want to allow both PPP *and*
* Frame Relay access to a channel, due to the architecture
@@ -846,6 +954,25 @@ srattach(struct sr_hardc *hc)
if_attach(ifp);
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
+#else /* NETGRAPH */
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngsr_done_init == 0) ngsr_init(NULL);
+ if (ng_make_node_common(&typestruct, &sc->node) != 0)
+ return (0);
+ sc->node->private = sc;
+ callout_handle_init(&sc->handle);
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(sc->nodename, "%s%d", NG_SR_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ return (0);
+ }
+ sc->running = 0;
+#endif /* NETGRAPH */
}
if (hc->mempages)
@@ -855,26 +982,24 @@ srattach(struct sr_hardc *hc)
}
/*
- * N2 Interrupt Service Routine.
- * Get the ISA interrupts.
- *
+ * N2 Interrupt Service Routine
+ *
* First figure out which SCA gave the interrupt.
- *
+ * Process it.
+ * See if there is other interrupts pending.
+ * Repeat until there no interrupts remain.
*/
static void
srintr(int unit)
-{
- struct sr_hardc *hc;
+{
+ struct sr_hardc *hc;
hc = &sr_hardc[unit];
srintr_hc(hc);
- return;
+ return;
}
-/*
- * PCI interrupts come straight here
- */
void
srintr_hc(struct sr_hardc *hc)
{
@@ -908,7 +1033,11 @@ srintr_hc(struct sr_hardc *hc)
#if BUGGY > 2
printf("src%d: srintr_hc isr0 %x, isr1 %x, isr2 %x\n",
+#ifndef NETGRAPH
unit, isr0, isr1, isr2);
+#else
+ hc->cunit, isr0, isr1, isr2);
+#endif /* NETGRAPH */
#endif
/*
@@ -938,7 +1067,9 @@ sr_xmit(struct sr_softc *sc)
u_short cda_value; /* starting descriptor */
u_short eda_value; /* ending descriptor */
struct sr_hardc *hc;
+#ifndef NETGRAPH
struct ifnet *ifp; /* O/S Network Services */
+#endif /* NETGRAPH */
dmac_channel *dmac; /* DMA channel registers */
#if BUGGY > 0
@@ -946,7 +1077,9 @@ sr_xmit(struct sr_softc *sc)
#endif
hc = sc->hc;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
dmac = &hc->sca->dmac[DMAC_TXCH(sc->scachan)];
/*
@@ -979,11 +1112,18 @@ sr_xmit(struct sr_softc *sc)
if (sc->txb_next_tx == SR_TX_BLOCKS) /* handle wrap... */
sc->txb_next_tx = 0;
+#ifndef NETGRAPH
/*
* Finally, we'll set a timout (which will start srwatchdog())
* within the O/S network services layer...
*/
ifp->if_timer = 2; /* Value in seconds. */
+#else
+ /*
+ * Don't time out for a while.
+ */
+ sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/
+#endif /* NETGRAPH */
}
/*
@@ -1000,10 +1140,16 @@ sr_xmit(struct sr_softc *sc)
* The function that clears that should ensure that the transmitter
* and its DMA is in a "good" idle state.
*/
+#ifndef NETGRAPH
static void
srstart(struct ifnet *ifp)
{
struct sr_softc *sc; /* channel control structure */
+#else
+static void
+srstart(struct sr_softc *sc)
+{
+#endif /* NETGRAPH */
struct sr_hardc *hc; /* card control/config block */
int len; /* total length of a packet */
int pkts; /* packets placed in DPRAM */
@@ -1014,16 +1160,15 @@ srstart(struct ifnet *ifp)
sca_descriptor *txdesc; /* working descriptor pointr */
struct buf_block *blkp;
+ hc = sc->hc;
+#ifndef NETGRAPH
#if BUGGY > 0
printf("sr: srstart( ifp=%08x)\n", ifp);
#endif
-
sc = ifp->if_softc;
- hc = sc->hc;
-
if ((ifp->if_flags & IFF_RUNNING) == 0)
return;
-
+#endif /* NETGRAPH */
/*
* It is OK to set the memory window outside the loop because all tx
* buffers and descriptors are assumed to be in the same 16K window.
@@ -1045,7 +1190,11 @@ top_srstart:
* See if we have space for more packets.
*/
if (sc->txb_inuse == SR_TX_BLOCKS) { /* out of space? */
+#ifndef NETGRAPH
ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */
+#else
+ /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */
+#endif /* NETGRAPH */
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
@@ -1071,6 +1220,7 @@ top_srstart:
* dispatch table to select the service we're getting a packet
* from...
*/
+#ifndef NETGRAPH
switch (sc->protocol) {
#if NFR > 0
case N2_USE_FRP:
@@ -1081,7 +1231,12 @@ top_srstart:
default:
mtx = sppp_dequeue(ifp);
}
-
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if (!mtx) {
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
@@ -1114,8 +1269,12 @@ top_srstart:
sc->unit, mtx, len);
#endif
+#ifndef NETGRAPH
if (ifp->if_bpf)
bpf_mtap(ifp, mtx);
+#else /* NETGRAPH */
+ sc->outbytes += len;
+#endif /* NETGRAPH */
/*
* We can perform a straight copy because the tranmit
@@ -1159,7 +1318,11 @@ top_srstart:
* and update the statistics...
*/
m_freem(mtx);
+#ifndef NETGRAPH
++sc->ifsppp.pp_if.if_opackets;
+#else /* NETGRAPH */
+ sc->opackets++;
+#endif /* NETGRAPH */
/*
* Check if we have space for another packet. XXX This is
@@ -1176,6 +1339,7 @@ top_srstart:
/*
* We'll pull the next message to be sent (if any)
*/
+#ifndef NETGRAPH
switch (sc->protocol) {
#if NFR > 0
case N2_USE_FRP:
@@ -1186,7 +1350,12 @@ top_srstart:
default:
mtx = sppp_dequeue(ifp);
}
-
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if (!mtx) { /* no message? We're done! */
#if BUGGY > 9
printf("sr%d.srstart: pending=0, pkts=%d\n",
@@ -1231,6 +1400,7 @@ top_srstart:
goto top_srstart;
}
+#ifndef NETGRAPH
/*
* Handle ioctl's at the device level, though we *will* call up
* a layer...
@@ -1407,37 +1577,56 @@ srioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return 0;
}
+#endif /* NETGRAPH */
/*
* This is to catch lost tx interrupts.
*/
static void
+#ifndef NETGRAPH
srwatchdog(struct ifnet *ifp)
+#else
+srwatchdog(struct sr_softc *sc)
+#endif /* NETGRAPH */
{
int got_st0, got_st1, got_st3, got_dsr;
+#ifndef NETGRAPH
struct sr_softc *sc = ifp->if_softc;
+#endif /* NETGRAPH */
struct sr_hardc *hc = sc->hc;
msci_channel *msci = &hc->sca->msci[sc->scachan];
dmac_channel *dmac = &sc->hc->sca->dmac[sc->scachan];
#if BUGGY > 0
+#ifndef NETGRAPH
printf("srwatchdog(unit=%d)\n", unit);
+#else
+ printf("srwatchdog(unit=%d)\n", sc->unit);
+#endif /* NETGRAPH */
#endif
+#ifndef NETGRAPH
if (!(ifp->if_flags & IFF_RUNNING))
return;
ifp->if_oerrors++; /* update output error count */
+#else /* NETGRAPH */
+ sc->oerrors++; /* update output error count */
+#endif /* NETGRAPH */
got_st0 = SRC_GET8(hc->sca_base, msci->st0);
got_st1 = SRC_GET8(hc->sca_base, msci->st1);
got_st3 = SRC_GET8(hc->sca_base, msci->st3);
got_dsr = SRC_GET8(hc->sca_base, dmac->dsr);
+#ifndef NETGRAPH
#if 0
if (ifp->if_flags & IFF_DEBUG)
#endif
printf("sr%d: transmit failed, "
+#else /* NETGRAPH */
+ printf("sr%d: transmit failed, "
+#endif /* NETGRAPH */
"ST0 %02x, ST1 %02x, ST3 %02x, DSR %02x.\n",
sc->unit,
got_st0, got_st1, got_st3, got_dsr);
@@ -1448,12 +1637,20 @@ srwatchdog(struct ifnet *ifp)
SRC_PUT8(hc->sca_base, msci->st1, SCA_ST1_UDRN);
}
sc->xmit_busy = 0;
+#ifndef NETGRAPH
ifp->if_flags &= ~IFF_OACTIVE;
+#else
+ /*ifp->if_flags &= ~IFF_OACTIVE; */
+#endif /* NETGRAPH */
if (sc->txb_inuse && --sc->txb_inuse)
sr_xmit(sc);
+#ifndef NETGRAPH
srstart(ifp); /* restart transmitter */
+#else
+ srstart(sc); /* restart transmitter */
+#endif /* NETGRAPH */
}
static void
@@ -1468,6 +1665,7 @@ sr_up(struct sr_softc *sc)
printf("sr_up(sc=%08x)\n", sc);
#endif
+#ifndef NETGRAPH
/*
* This section should really do the attach to the appropriate
* system service, be it frame relay or PPP...
@@ -1489,6 +1687,7 @@ sr_up(struct sr_softc *sc)
sc->attached = sc->protocol;
}
+#endif /* NETGRAPH */
/*
* Enable transmitter and receiver. Raise DTR and RTS. Enable
* interrupts.
@@ -1537,10 +1736,16 @@ sr_up(struct sr_softc *sc)
inb(hc->iobase); /* XXX slow it down a bit. */
SRC_PUT8(hc->sca_base, msci->cmd, SCA_CMD_TXENABLE);
+#ifndef NETGRAPH
#ifdef USE_MODEMCK
if (sr_watcher == 0)
sr_modemck(NULL);
#endif
+#else /* NETGRAPH */
+ untimeout(ngsr_watchdog_frame, sc, sc->handle);
+ sc->handle = timeout(ngsr_watchdog_frame, sc, hz);
+ sc->running = 1;
+#endif /* NETGRAPH */
}
static void
@@ -1554,6 +1759,10 @@ sr_down(struct sr_softc *sc)
#if BUGGY > 0
printf("sr_down(sc=%08x)\n", sc);
#endif
+#ifdef NETGRAPH
+ untimeout(ngsr_watchdog_frame, sc, sc->handle);
+ sc->running = 0;
+#endif /* NETGRAPH */
/*
* Disable transmitter and receiver. Lower DTR and RTS. Disable
@@ -1601,6 +1810,7 @@ sr_down(struct sr_softc *sc)
SRC_GET8(hc->sca_base, sca->ier1) & ~0xF0);
}
+#ifndef NETGRAPH
/*
* This section does the detach from the currently configured net
* service, be it frame relay or PPP...
@@ -1617,6 +1827,7 @@ sr_down(struct sr_softc *sc)
}
sc->attached = 0;
+#endif /* NETGRAPH */
}
/*
@@ -2373,7 +2584,9 @@ sr_get_packets(struct sr_softc *sc)
u_int len; /* length of pending packet */
struct sr_hardc *hc; /* card-level information */
sca_descriptor *rxdesc; /* descriptor in memory */
+#ifndef NETGRAPH
struct ifnet *ifp; /* network intf ctl table */
+#endif /* NETGRAPH */
struct mbuf *m = NULL; /* message buffer */
#if BUGGY > 0
@@ -2381,7 +2594,9 @@ sr_get_packets(struct sr_softc *sc)
#endif
hc = sc->hc;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
if (hc->mempages) {
SRC_SET_MEM(hc->iobase, sc->rxdesc);
@@ -2412,6 +2627,10 @@ sr_get_packets(struct sr_softc *sc)
#endif
pkts++;
+#ifdef NETGRAPH
+ sc->inbytes += len;
+ sc->inlast = 0;
+#endif /* NETGRAPH */
/*
* OK, we've settled the incoming message status. We can now
@@ -2434,7 +2653,11 @@ sr_get_packets(struct sr_softc *sc)
/*
* construct control information for pass-off
*/
+#ifndef NETGRAPH
m->m_pkthdr.rcvif = ifp;
+#else
+ m->m_pkthdr.rcvif = NULL;
+#endif /* NETGRAPH */
m->m_pkthdr.len = m->m_len = len;
if (len > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -2455,6 +2678,7 @@ sr_get_packets(struct sr_softc *sc)
*/
sr_copy_rxbuf(m, sc, len); /* copy from DPRAM */
+#ifndef NETGRAPH
if (ifp->if_bpf)
bpf_mtap(ifp, m);
@@ -2469,7 +2693,6 @@ sr_get_packets(struct sr_softc *sc)
bp[4], bp[5], bp[6]);
}
#endif
-
/*
* Pass off the message to PPP, connecting it it to
* the system...
@@ -2487,6 +2710,24 @@ sr_get_packets(struct sr_softc *sc)
ifp->if_ipackets++;
+#else /* NETGRAPH */
+#if BUGGY > 3
+ {
+ u_char *bp;
+
+ bp = mtod(m,u_char *);
+ printf("sr%d: rd=%02x:%02x:%02x:%02x:%02x:%02x",
+ sc->unit,
+ bp[0], bp[1], bp[2],
+ bp[4], bp[5], bp[6]);
+ printf(":%02x:%02x:%02x:%02x:%02x:%02x\n",
+ bp[6], bp[7], bp[8],
+ bp[9], bp[10], bp[11]);
+ }
+#endif
+ ng_queue_data(sc->hook, m, NULL);
+ sc->ipackets++;
+#endif /* NETGRAPH */
/*
* Update the eda to the previous descriptor.
*/
@@ -2523,7 +2764,11 @@ sr_get_packets(struct sr_softc *sc)
*/
sr_eat_packet(sc, 1);
+#ifndef NETGRAPH
ifp->if_ierrors++;
+#else
+ sc->ierrors[0]++;
+#endif /* NETGRAPH */
got_st3 = SRC_GET8(hc->sca_base,
hc->sca->msci[sc->scachan].st3);
@@ -2605,8 +2850,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (dsr & SCA_DSR_COF) {
printf("sr%d: TX DMA Counter overflow, "
"txpacket no %lu.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_opackets);
sc->ifsppp.pp_if.if_oerrors++;
+#else
+ sc->unit, sc->opackets);
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/*
* Check for (& process) a Buffer overflow
@@ -2615,11 +2865,19 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: TX DMA Buffer overflow, "
"txpacket no %lu, dsr %02x, "
"cda %04x, eda %04x.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_opackets,
+#else
+ sc->unit, sc->opackets,
+#endif /* NETGRAPH */
dsr,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda));
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_oerrors++;
+#else
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/*
* Check for (& process) an End of Transfer (OK)
@@ -2637,8 +2895,14 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: TX Completed OK\n", sc->unit);
#endif
sc->xmit_busy = 0;
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
sc->ifsppp.pp_if.if_timer = 0;
+#else
+ /* XXX may need to mark tx inactive? */
+ sc->out_deficit++;
+ sc->out_dog = DOG_HOLDOFF;
+#endif /* NETGRAPH */
if (sc->txb_inuse && --sc->txb_inuse)
sr_xmit(sc);
@@ -2660,14 +2924,22 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
#if BUGGY > 0
int tt, ind;
+#ifndef NETGRAPH
tt = sc->ifsppp.pp_if.if_ipackets;
+#else /* NETGRAPH */
+ tt = sc->ipackets;
+#endif /* NETGRAPH */
ind = sc->rxhind;
#endif
sr_get_packets(sc);
-
#if BUGGY > 0
- if (tt == sc->ifsppp.pp_if.if_ipackets) {
+#ifndef NETGRAPH
+ if (tt == sc->ifsppp.pp_if.if_ipackets)
+#else /* NETGRAPH */
+ if (tt == sc->ipackets)
+#endif /* NETGRAPH */
+ {
sca_descriptor *rxdesc;
int i;
@@ -2702,7 +2974,7 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
}
-#endif
+#endif /* BUGGY */
}
/*
* Check for Counter overflow
@@ -2710,8 +2982,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (dsr & SCA_DSR_COF) {
printf("sr%d: RX DMA Counter overflow, "
"rxpkts %lu.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->unit, sc->ipackets);
+ sc->ierrors[1]++;
+#endif /* NETGRAPH */
}
/*
* Check for Buffer overflow
@@ -2720,7 +2997,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: RX DMA Buffer overflow, "
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_ipackets,
+#else /* NETGRAPH */
+ sc->unit, sc->ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda),
@@ -2734,7 +3015,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
SRC_SET_ON(hc->iobase);
sr_eat_packet(sc, 0);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[2]++;
+#endif /* NETGRAPH */
SRC_PUT8(hc->sca_base,
sca->msci[mch].cmd,
@@ -2747,7 +3032,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x. After\n",
sc->unit,
+#ifndef NETGRAPH
+ sc->ipackets,
+#else /* NETGRAPH */
sc->ifsppp.pp_if.if_ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda),
@@ -2770,8 +3059,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
*/
printf("sr%d: RX End of xfer, rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else
+ sc->ipackets);
+ sc->ierrors[3]++;
+#endif /* NETGRAPH */
}
}
isr1 >>= 4; /* process next half of ISR */
@@ -2785,12 +3079,16 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
for (mch = 0; mch < NCHAN; mch++) {
if (dotxstart & 0x0C) { /* TX initiation enabled? */
sc = &hc->sc[mch];
+#ifndef NETGRAPH
srstart(&sc->ifsppp.pp_if);
+#else
+ srstart(sc);
+#endif /* NETGRAPH */
}
dotxstart >>= 4;/* shift for next channel */
}
}
-
+#ifndef NETGRAPH
/*
* Perform timeout on an FR channel
*
@@ -2910,6 +3208,38 @@ sr_modemck(void *arg)
splx(s);
}
+#else /* NETGRAPH */
+/*
+ * If a port is open/active, it's DCD state is checked
+ * and a loss of DCD is recognized (and eventually processed?).
+ */
+static void
+sr_modemck(struct sr_softc *sc )
+{
+ u_int s;
+ u_char got_st3; /* contents of ST3 */
+ struct sr_hardc *hc = sc->hc; /* card's configuration */
+ msci_channel *msci; /* regs specific to channel */
+
+ s = splimp();
+
+
+ if (sc->running == 0)
+ return;
+ /*
+ * OK, now we can go looking at this channel's register contents...
+ */
+ msci = &hc->sca->msci[sc->scachan];
+ got_st3 = SRC_GET8(hc->sca_base, msci->st3);
+
+ /*
+ * We want to see if the DCD signal is up (DCD is true if zero)
+ */
+ sc->dcd = (got_st3 & SCA_ST3_DCD) == 0;
+ splx(s);
+}
+
+#endif /* NETGRAPH */
static void
sr_msci_intr(struct sr_hardc *hc, u_char isr0)
{
@@ -2922,6 +3252,301 @@ sr_timer_intr(struct sr_hardc *hc, u_char isr2)
printf("src%d: SRINTR: TIMER\n", hc->cunit);
}
+#ifdef NETGRAPH
+/*****************************************
+ * Device timeout/watchdog routine.
+ * called once per second.
+ * checks to see that if activity was expected, that it hapenned.
+ * At present we only look to see if expected output was completed.
+ */
+static void
+ngsr_watchdog_frame(void * arg)
+{
+ struct sr_softc * sc = arg;
+ int s;
+ int speed;
+
+ if(sc->running == 0)
+ return; /* if we are not running let timeouts die */
+ /*
+ * calculate the apparent throughputs
+ * XXX a real hack
+ */
+ s = splimp();
+ speed = sc->inbytes - sc->lastinbytes;
+ sc->lastinbytes = sc->inbytes;
+ if ( sc->inrate < speed )
+ sc->inrate = speed;
+ speed = sc->outbytes - sc->lastoutbytes;
+ sc->lastoutbytes = sc->outbytes;
+ if ( sc->outrate < speed )
+ sc->outrate = speed;
+ sc->inlast++;
+ splx(s);
+
+ if ((sc->inlast > QUITE_A_WHILE)
+ && (sc->out_deficit > LOTS_OF_PACKETS)) {
+ log(LOG_ERR, "sr%d: No response from remote end\n", sc->unit);
+ s = splimp();
+ sr_down(sc);
+ sr_up(sc);
+ sc->inlast = sc->out_deficit = 0;
+ splx(s);
+ } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */
+ if (sc->out_dog == 0) {
+ log(LOG_ERR, "sr%d: Transmit failure.. no clock?\n",
+ sc->unit);
+ srwatchdog(sc);
+#if 0
+ s = splimp();
+ sr_down(sc);
+ sr_up(sc);
+ splx(s);
+#endif
+ sc->inlast = sc->out_deficit = 0;
+ } else {
+ sc->out_dog--;
+ }
+ }
+ sr_modemck(sc); /* update the DCD status */
+ sc->handle = timeout(ngsr_watchdog_frame, sc, hz);
+}
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
+/*
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngsr_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * give our ok for a hook to be added...
+ * If we are not running this should kick the device into life.
+ * We allow hooks called "control" and dlci[1-1023]
+ * The hook's private info points to our stash of info about that
+ * channel.
+ */
+static int
+ngsr_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct sr_softc * sc = node->private;
+
+ /*
+ * check if it's our friend the debug hook
+ */
+ if (strcmp(name, NG_SR_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ sc->debug_hook = hook;
+ return (0);
+ }
+
+ /*
+ * Check for raw mode hook.
+ */
+ if (strcmp(name, NG_SR_HOOK_RAW) != 0) {
+ return (EINVAL);
+ }
+ hook->private = sc;
+ sc->hook = hook;
+ sc->datahooks++;
+ sr_up(sc);
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
+ */
+static int
+ngsr_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct sr_softc * sc;
+ int error = 0;
+
+ sc = node->private;
+ switch (msg->header.typecookie) {
+ case NG_SR_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n"
+ "highest rate seen: %ld B/S in, %ld B/S out\n",
+ sc->inbytes, sc->outbytes,
+ sc->inrate, sc->outrate);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ sc->oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld, %ld, %ld, %ld, %ld, %ld\n",
+ sc->ierrors[0],
+ sc->ierrors[1],
+ sc->ierrors[2],
+ sc->ierrors[3],
+ sc->ierrors[4],
+ sc->ierrors[5]);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NG_SR_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * get data from another node and transmit it to the correct channel
+ */
+static int
+ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int s;
+ int error = 0;
+ struct sr_softc * sc = hook->node->private;
+ struct ifqueue *xmitq_p;
+
+ /*
+ * data doesn't come in from just anywhere (e.g control hook)
+ */
+ if ( hook->private == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splimp();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ splx(s);
+ srstart(sc);
+ return (0);
+
+bad:
+ /*
+ * It was an error case.
+ * check if we need to free the mbuf, and then return the error
+ */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * do local shutdown processing..
+ * this node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngsr_rmnode(node_p node)
+{
+ struct sr_softc * sc = node->private;
+
+ sr_down(sc);
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngsr_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ * As the device still exists, the shutdown method will not actually
+ * destroy the node, but reset the device and leave it 'fresh' :)
+ *
+ * The node removal code will remove all references except that owned by the
+ * driver.
+ */
+static int
+ngsr_disconnect(hook_p hook)
+{
+ struct sr_softc * sc = hook->node->private;
+ int s;
+ /*
+ * If it's the data hook, then free resources etc.
+ */
+ if (hook->private) {
+ s = splimp();
+ sc->datahooks--;
+ if (sc->datahooks == 0)
+ sr_down(sc);
+ splx(s);
+ } else {
+ sc->debug_hook = NULL;
+ }
+ return (0);
+}
+
+/*
+ * called during bootup
+ * or LKM loading to put this type into the list of known modules
+ */
+static void
+ngsr_init(void *ignored)
+{
+ if (ng_newtype(&typestruct))
+ printf("ngsr install failed\n");
+ ngsr_done_init = 1;
+}
+#endif /* NETGRAPH */
+
/*
********************************* END ************************************
*/
diff --git a/sys/dev/sr/if_sr.h b/sys/dev/sr/if_sr.h
new file mode 100644
index 0000000..d01a2cb
--- /dev/null
+++ b/sys/dev/sr/if_sr.h
@@ -0,0 +1,23 @@
+/*
+ * if_sr.h
+ *
+ * Copyright (C) 1997-1999 Whistle Communications Inc.
+ * All rights reserved.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _I386_ISA_IF_SR_H_
+#define _I386_ISA_IF_SR_H_
+
+/* Node type name and type cookie */
+#define NG_SR_NODE_TYPE "sync_sr"
+#define NG_SR_COOKIE 860552148
+
+/* Netgraph hooks */
+#define NG_SR_HOOK_DEBUG "debug"
+#define NG_SR_HOOK_CONTROL "control"
+#define NG_SR_HOOK_RAW "rawdata"
+
+#endif /* _I386_ISA_IF_SR_H_ */
+
diff --git a/sys/dev/sr/if_sr_isa.c b/sys/dev/sr/if_sr_isa.c
index 6be7958..f50f7a5 100644
--- a/sys/dev/sr/if_sr_isa.c
+++ b/sys/dev/sr/if_sr_isa.c
@@ -48,16 +48,23 @@
*/
#include "sr.h"
+#include "opt_netgraph.h"
+#ifdef NETGRAPH
+#include <i386/isa/if_sr.h>
+#else /* NETGRAPH */
#ifdef notyet
#include "fr.h"
#else
#define NFR 0
#endif
+#endif /* NETGRAPH */
+#ifdef NETGRAPH
#include "sppp.h"
#if NSPPP <= 0
#error Device 'sr' requires sppp.
#endif
+#endif /* NETGRAPH */
#include <sys/param.h>
#include <sys/systm.h>
@@ -68,9 +75,13 @@
#include <sys/socket.h>
#include <net/if.h>
+#ifdef NETGRAPH
+#include <sys/syslog.h>
+#else /* NETGRAPH */
#include <net/if_sppp.h>
#include <net/bpf.h>
+#endif /* NETGRAPH */
#include <machine/md_var.h>
@@ -78,13 +89,19 @@
#include <i386/isa/ic/hd64570.h>
#include <i386/isa/isa_device.h>
+#ifdef NETGRAPH
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#endif /* NETGRAPH */
/* #define USE_MODEMCK */
#ifndef BUGGY
#define BUGGY 0
#endif
+#ifndef NETGRAPH
#define PPP_HEADER_LEN 4
+#endif /* NETGRAPH */
/*
* These macros are used to hide the difference between the way the
@@ -142,7 +159,9 @@ struct sr_hardc {
};
static int next_sc_unit = 0;
+#ifndef NETGRAPH
static int sr_watcher = 0;
+#endif /* NETGRAPH */
static struct sr_hardc sr_hardc[NSR];
static struct sr_hardc *sr_hardc_pci;
@@ -151,17 +170,20 @@ static struct sr_hardc *sr_hardc_pci;
* every channel (port).
*/
struct sr_softc {
+#ifndef NETGRAPH
struct sppp ifsppp; /* PPP service w/in system */
+#endif /* NETGRAPH */
struct sr_hardc *hc; /* card-level information */
int unit; /* With regard to all sr devices */
int subunit; /* With regard to this card */
+#ifndef NETGRAPH
int attached; /* attached to FR or PPP */
int protocol; /* FR or PPP */
#define N2_USE_FRP 2 /* Frame Relay Protocol */
#define N2_USE_PPP 1 /* Point-to-Point Protocol */
-
+#endif /* NETGRAPH */
struct buf_block {
u_int txdesc; /* DPRAM offset */
u_int txstart;/* DPRAM offset */
@@ -185,8 +207,40 @@ struct sr_softc {
u_int clk_cfg; /* Clock configuration */
int scachan; /* channel # on card */
+#ifdef NETGRAPH
+ int running; /* something is attached so we are running */
+ int dcd; /* do we have dcd? */
+ /* ---netgraph bits --- */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ hook_p hook; /* data hook */
+ hook_p debug_hook;
+ struct ifqueue xmitq_hipri; /* hi-priority transmit queue */
+ struct ifqueue xmitq; /* transmit queue */
+ int flags; /* state */
+#define SCF_RUNNING 0x01 /* board is active */
+#define SCF_OACTIVE 0x02 /* output is active */
+ int out_dog; /* watchdog cycles output count-down */
+#if ( __FreeBSD__ >= 3 )
+ struct callout_handle handle; /* timeout(9) handle */
+#endif
+ u_long inbytes, outbytes; /* stats */
+ u_long lastinbytes, lastoutbytes; /* a second ago */
+ u_long inrate, outrate; /* highest rate seen */
+ u_long inlast; /* last input N secs ago */
+ u_long out_deficit; /* output since last input */
+ u_long oerrors, ierrors[6];
+ u_long opackets, ipackets;
+#endif /* NETGRAPH */
};
+#ifdef NETGRAPH
+#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */
+#define QUITE_A_WHILE 300 /* 5 MINUTES */
+#define LOTS_OF_PACKETS 100
+#endif /* NETGRAPH */
+
/*
* List of valid interrupt numbers for the N2 ISA card.
*/
@@ -267,11 +321,17 @@ struct sr_hardc *srattach_pci(int unit, vm_offset_t plx_vaddr,
void srintr_hc(struct sr_hardc *hc);
static ointhand2_t srintr;
+
static int srattach(struct sr_hardc *hc);
static void sr_xmit(struct sr_softc *sc);
+#ifndef NETGRAPH
static void srstart(struct ifnet *ifp);
static int srioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void srwatchdog(struct ifnet *ifp);
+#else
+static void srstart(struct sr_softc *sc);
+static void srwatchdog(struct sr_softc *sc);
+#endif /* NETGRAPH */
static int sr_packet_avail(struct sr_softc *sc, int *len, u_char *rxstat);
static void sr_copy_rxbuf(struct mbuf *m, struct sr_softc *sc, int len);
static void sr_eat_packet(struct sr_softc *sc, int single);
@@ -287,7 +347,11 @@ static void sr_init_tx_dmac(struct sr_softc *sc);
static void sr_dmac_intr(struct sr_hardc *hc, u_char isr);
static void sr_msci_intr(struct sr_hardc *hc, u_char isr);
static void sr_timer_intr(struct sr_hardc *hc, u_char isr);
+#ifndef NETGRAPH
static void sr_modemck(void *x);
+#else
+static void sr_modemck(struct sr_softc *x);
+#endif /* NETGRAPH */
static u_int src_get8_io(u_int base, u_int off);
static u_int src_get16_io(u_int base, u_int off);
@@ -298,6 +362,7 @@ static u_int src_get16_mem(u_int base, u_int off);
static void src_put8_mem(u_int base, u_int off, u_int val);
static void src_put16_mem(u_int base, u_int off, u_int val);
+#ifndef NETGRAPH
#if NFR > 0
extern void fr_detach(struct ifnet *);
extern int fr_attach(struct ifnet *);
@@ -306,6 +371,36 @@ extern void fr_flush(struct ifnet *);
extern int fr_input(struct ifnet *, struct mbuf *);
extern struct mbuf *fr_dequeue(struct ifnet *);
#endif
+#else
+static void ngsr_watchdog_frame(void * arg);
+static void ngsr_init(void* ignored);
+static int ngsr_constructor(node_p *nodep);
+static int ngsr_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngsr_rmnode(node_p node);
+static int ngsr_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngsr_findhook(node_p node, char *name);*/
+static int ngsr_connect(hook_p hook); /* already PARTLY linked */
+static int ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngsr_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_SR_NODE_TYPE,
+ NULL,
+ ngsr_constructor,
+ ngsr_rcvmsg,
+ ngsr_rmnode,
+ ngsr_newhook,
+ NULL,
+ ngsr_connect,
+ ngsr_rcvdata,
+ ngsr_rcvdata,
+ ngsr_disconnect
+};
+
+static int ngsr_done_init = 0;
+#endif /* NETGRAPH */
/*
* I/O for ISA N2 card(s)
@@ -569,6 +664,15 @@ srattach_isa(struct isa_device *id)
u_char mar;
struct sr_hardc *hc = &sr_hardc[id->id_unit];
+ /*
+ * Allocate the software interface table(s)
+ */
+ MALLOC(hc->sc, struct sr_softc *,
+ hc->numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK);
+ if (hc->sc == NULL)
+ return(0);
+ bzero(hc->sc, hc->numports * sizeof(struct sr_softc));
+
id->id_ointr = srintr;
outb(hc->iobase + SR_PCR, inb(hc->iobase + SR_PCR) | SR_PCR_SCARUN);
@@ -588,13 +692,6 @@ srattach_isa(struct isa_device *id)
outb(hc->iobase + SR_BAR, mar);
/*
- * Allocate the software interface table(s)
- */
- hc->sc = malloc(hc->numports * sizeof(struct sr_softc),
- M_DEVBUF, M_WAITOK);
- bzero(hc->sc, hc->numports * sizeof(struct sr_softc));
-
- /*
* Get the TX clock direction and configuration. The default is a
* single external clock which is used by RX and TX.
*/
@@ -680,13 +777,19 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr)
hc = hc->next;
}
- hc = malloc(sizeof(struct sr_hardc), M_DEVBUF, M_WAITOK);
- *hcp = hc;
- bzero(hc, sizeof(struct sr_hardc));
+ MALLOC(hc, struct sr_hardc *, sizeof(*hc), M_DEVBUF, M_WAITOK);
+ if (hc == NULL)
+ return NULL;
+ bzero(hc, sizeof(*hc));
- hc->sc = malloc(numports * sizeof(struct sr_softc),
- M_DEVBUF, M_WAITOK);
+ MALLOC(hc->sc, struct sr_softc *,
+ numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK);
+ if (hc->sc == NULL) {
+ FREE(hc, M_DEVBUF);
+ return NULL;
+ }
bzero(hc->sc, numports * sizeof(struct sr_softc));
+ *hcp = hc;
hc->numports = numports;
hc->cunit = unit;
@@ -779,13 +882,17 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr)
/*
* Register the ports on the adapter.
* Fill in the info for each port.
+#ifndef NETGRAPH
* Attach each port to sppp and bpf.
+#endif
*/
static int
srattach(struct sr_hardc *hc)
{
struct sr_softc *sc = hc->sc;
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
int unit; /* index: channel w/in card */
/*
@@ -813,6 +920,10 @@ srattach(struct sr_hardc *hc)
sr_init_tx_dmac(sc);
sr_init_msci(sc);
+ printf("sr%d: Adapter %d, port %d.\n",
+ sc->unit, hc->cunit, sc->subunit);
+
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
ifp->if_softc = sc;
ifp->if_unit = sc->unit;
@@ -823,9 +934,6 @@ srattach(struct sr_hardc *hc)
ifp->if_start = srstart;
ifp->if_watchdog = srwatchdog;
- printf("sr%d: Adapter %d, port %d.\n",
- sc->unit, hc->cunit, sc->subunit);
-
/*
* Despite the fact that we want to allow both PPP *and*
* Frame Relay access to a channel, due to the architecture
@@ -846,6 +954,25 @@ srattach(struct sr_hardc *hc)
if_attach(ifp);
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
+#else /* NETGRAPH */
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngsr_done_init == 0) ngsr_init(NULL);
+ if (ng_make_node_common(&typestruct, &sc->node) != 0)
+ return (0);
+ sc->node->private = sc;
+ callout_handle_init(&sc->handle);
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(sc->nodename, "%s%d", NG_SR_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ return (0);
+ }
+ sc->running = 0;
+#endif /* NETGRAPH */
}
if (hc->mempages)
@@ -855,26 +982,24 @@ srattach(struct sr_hardc *hc)
}
/*
- * N2 Interrupt Service Routine.
- * Get the ISA interrupts.
- *
+ * N2 Interrupt Service Routine
+ *
* First figure out which SCA gave the interrupt.
- *
+ * Process it.
+ * See if there is other interrupts pending.
+ * Repeat until there no interrupts remain.
*/
static void
srintr(int unit)
-{
- struct sr_hardc *hc;
+{
+ struct sr_hardc *hc;
hc = &sr_hardc[unit];
srintr_hc(hc);
- return;
+ return;
}
-/*
- * PCI interrupts come straight here
- */
void
srintr_hc(struct sr_hardc *hc)
{
@@ -908,7 +1033,11 @@ srintr_hc(struct sr_hardc *hc)
#if BUGGY > 2
printf("src%d: srintr_hc isr0 %x, isr1 %x, isr2 %x\n",
+#ifndef NETGRAPH
unit, isr0, isr1, isr2);
+#else
+ hc->cunit, isr0, isr1, isr2);
+#endif /* NETGRAPH */
#endif
/*
@@ -938,7 +1067,9 @@ sr_xmit(struct sr_softc *sc)
u_short cda_value; /* starting descriptor */
u_short eda_value; /* ending descriptor */
struct sr_hardc *hc;
+#ifndef NETGRAPH
struct ifnet *ifp; /* O/S Network Services */
+#endif /* NETGRAPH */
dmac_channel *dmac; /* DMA channel registers */
#if BUGGY > 0
@@ -946,7 +1077,9 @@ sr_xmit(struct sr_softc *sc)
#endif
hc = sc->hc;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
dmac = &hc->sca->dmac[DMAC_TXCH(sc->scachan)];
/*
@@ -979,11 +1112,18 @@ sr_xmit(struct sr_softc *sc)
if (sc->txb_next_tx == SR_TX_BLOCKS) /* handle wrap... */
sc->txb_next_tx = 0;
+#ifndef NETGRAPH
/*
* Finally, we'll set a timout (which will start srwatchdog())
* within the O/S network services layer...
*/
ifp->if_timer = 2; /* Value in seconds. */
+#else
+ /*
+ * Don't time out for a while.
+ */
+ sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/
+#endif /* NETGRAPH */
}
/*
@@ -1000,10 +1140,16 @@ sr_xmit(struct sr_softc *sc)
* The function that clears that should ensure that the transmitter
* and its DMA is in a "good" idle state.
*/
+#ifndef NETGRAPH
static void
srstart(struct ifnet *ifp)
{
struct sr_softc *sc; /* channel control structure */
+#else
+static void
+srstart(struct sr_softc *sc)
+{
+#endif /* NETGRAPH */
struct sr_hardc *hc; /* card control/config block */
int len; /* total length of a packet */
int pkts; /* packets placed in DPRAM */
@@ -1014,16 +1160,15 @@ srstart(struct ifnet *ifp)
sca_descriptor *txdesc; /* working descriptor pointr */
struct buf_block *blkp;
+ hc = sc->hc;
+#ifndef NETGRAPH
#if BUGGY > 0
printf("sr: srstart( ifp=%08x)\n", ifp);
#endif
-
sc = ifp->if_softc;
- hc = sc->hc;
-
if ((ifp->if_flags & IFF_RUNNING) == 0)
return;
-
+#endif /* NETGRAPH */
/*
* It is OK to set the memory window outside the loop because all tx
* buffers and descriptors are assumed to be in the same 16K window.
@@ -1045,7 +1190,11 @@ top_srstart:
* See if we have space for more packets.
*/
if (sc->txb_inuse == SR_TX_BLOCKS) { /* out of space? */
+#ifndef NETGRAPH
ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */
+#else
+ /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */
+#endif /* NETGRAPH */
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
@@ -1071,6 +1220,7 @@ top_srstart:
* dispatch table to select the service we're getting a packet
* from...
*/
+#ifndef NETGRAPH
switch (sc->protocol) {
#if NFR > 0
case N2_USE_FRP:
@@ -1081,7 +1231,12 @@ top_srstart:
default:
mtx = sppp_dequeue(ifp);
}
-
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if (!mtx) {
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
@@ -1114,8 +1269,12 @@ top_srstart:
sc->unit, mtx, len);
#endif
+#ifndef NETGRAPH
if (ifp->if_bpf)
bpf_mtap(ifp, mtx);
+#else /* NETGRAPH */
+ sc->outbytes += len;
+#endif /* NETGRAPH */
/*
* We can perform a straight copy because the tranmit
@@ -1159,7 +1318,11 @@ top_srstart:
* and update the statistics...
*/
m_freem(mtx);
+#ifndef NETGRAPH
++sc->ifsppp.pp_if.if_opackets;
+#else /* NETGRAPH */
+ sc->opackets++;
+#endif /* NETGRAPH */
/*
* Check if we have space for another packet. XXX This is
@@ -1176,6 +1339,7 @@ top_srstart:
/*
* We'll pull the next message to be sent (if any)
*/
+#ifndef NETGRAPH
switch (sc->protocol) {
#if NFR > 0
case N2_USE_FRP:
@@ -1186,7 +1350,12 @@ top_srstart:
default:
mtx = sppp_dequeue(ifp);
}
-
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if (!mtx) { /* no message? We're done! */
#if BUGGY > 9
printf("sr%d.srstart: pending=0, pkts=%d\n",
@@ -1231,6 +1400,7 @@ top_srstart:
goto top_srstart;
}
+#ifndef NETGRAPH
/*
* Handle ioctl's at the device level, though we *will* call up
* a layer...
@@ -1407,37 +1577,56 @@ srioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return 0;
}
+#endif /* NETGRAPH */
/*
* This is to catch lost tx interrupts.
*/
static void
+#ifndef NETGRAPH
srwatchdog(struct ifnet *ifp)
+#else
+srwatchdog(struct sr_softc *sc)
+#endif /* NETGRAPH */
{
int got_st0, got_st1, got_st3, got_dsr;
+#ifndef NETGRAPH
struct sr_softc *sc = ifp->if_softc;
+#endif /* NETGRAPH */
struct sr_hardc *hc = sc->hc;
msci_channel *msci = &hc->sca->msci[sc->scachan];
dmac_channel *dmac = &sc->hc->sca->dmac[sc->scachan];
#if BUGGY > 0
+#ifndef NETGRAPH
printf("srwatchdog(unit=%d)\n", unit);
+#else
+ printf("srwatchdog(unit=%d)\n", sc->unit);
+#endif /* NETGRAPH */
#endif
+#ifndef NETGRAPH
if (!(ifp->if_flags & IFF_RUNNING))
return;
ifp->if_oerrors++; /* update output error count */
+#else /* NETGRAPH */
+ sc->oerrors++; /* update output error count */
+#endif /* NETGRAPH */
got_st0 = SRC_GET8(hc->sca_base, msci->st0);
got_st1 = SRC_GET8(hc->sca_base, msci->st1);
got_st3 = SRC_GET8(hc->sca_base, msci->st3);
got_dsr = SRC_GET8(hc->sca_base, dmac->dsr);
+#ifndef NETGRAPH
#if 0
if (ifp->if_flags & IFF_DEBUG)
#endif
printf("sr%d: transmit failed, "
+#else /* NETGRAPH */
+ printf("sr%d: transmit failed, "
+#endif /* NETGRAPH */
"ST0 %02x, ST1 %02x, ST3 %02x, DSR %02x.\n",
sc->unit,
got_st0, got_st1, got_st3, got_dsr);
@@ -1448,12 +1637,20 @@ srwatchdog(struct ifnet *ifp)
SRC_PUT8(hc->sca_base, msci->st1, SCA_ST1_UDRN);
}
sc->xmit_busy = 0;
+#ifndef NETGRAPH
ifp->if_flags &= ~IFF_OACTIVE;
+#else
+ /*ifp->if_flags &= ~IFF_OACTIVE; */
+#endif /* NETGRAPH */
if (sc->txb_inuse && --sc->txb_inuse)
sr_xmit(sc);
+#ifndef NETGRAPH
srstart(ifp); /* restart transmitter */
+#else
+ srstart(sc); /* restart transmitter */
+#endif /* NETGRAPH */
}
static void
@@ -1468,6 +1665,7 @@ sr_up(struct sr_softc *sc)
printf("sr_up(sc=%08x)\n", sc);
#endif
+#ifndef NETGRAPH
/*
* This section should really do the attach to the appropriate
* system service, be it frame relay or PPP...
@@ -1489,6 +1687,7 @@ sr_up(struct sr_softc *sc)
sc->attached = sc->protocol;
}
+#endif /* NETGRAPH */
/*
* Enable transmitter and receiver. Raise DTR and RTS. Enable
* interrupts.
@@ -1537,10 +1736,16 @@ sr_up(struct sr_softc *sc)
inb(hc->iobase); /* XXX slow it down a bit. */
SRC_PUT8(hc->sca_base, msci->cmd, SCA_CMD_TXENABLE);
+#ifndef NETGRAPH
#ifdef USE_MODEMCK
if (sr_watcher == 0)
sr_modemck(NULL);
#endif
+#else /* NETGRAPH */
+ untimeout(ngsr_watchdog_frame, sc, sc->handle);
+ sc->handle = timeout(ngsr_watchdog_frame, sc, hz);
+ sc->running = 1;
+#endif /* NETGRAPH */
}
static void
@@ -1554,6 +1759,10 @@ sr_down(struct sr_softc *sc)
#if BUGGY > 0
printf("sr_down(sc=%08x)\n", sc);
#endif
+#ifdef NETGRAPH
+ untimeout(ngsr_watchdog_frame, sc, sc->handle);
+ sc->running = 0;
+#endif /* NETGRAPH */
/*
* Disable transmitter and receiver. Lower DTR and RTS. Disable
@@ -1601,6 +1810,7 @@ sr_down(struct sr_softc *sc)
SRC_GET8(hc->sca_base, sca->ier1) & ~0xF0);
}
+#ifndef NETGRAPH
/*
* This section does the detach from the currently configured net
* service, be it frame relay or PPP...
@@ -1617,6 +1827,7 @@ sr_down(struct sr_softc *sc)
}
sc->attached = 0;
+#endif /* NETGRAPH */
}
/*
@@ -2373,7 +2584,9 @@ sr_get_packets(struct sr_softc *sc)
u_int len; /* length of pending packet */
struct sr_hardc *hc; /* card-level information */
sca_descriptor *rxdesc; /* descriptor in memory */
+#ifndef NETGRAPH
struct ifnet *ifp; /* network intf ctl table */
+#endif /* NETGRAPH */
struct mbuf *m = NULL; /* message buffer */
#if BUGGY > 0
@@ -2381,7 +2594,9 @@ sr_get_packets(struct sr_softc *sc)
#endif
hc = sc->hc;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
if (hc->mempages) {
SRC_SET_MEM(hc->iobase, sc->rxdesc);
@@ -2412,6 +2627,10 @@ sr_get_packets(struct sr_softc *sc)
#endif
pkts++;
+#ifdef NETGRAPH
+ sc->inbytes += len;
+ sc->inlast = 0;
+#endif /* NETGRAPH */
/*
* OK, we've settled the incoming message status. We can now
@@ -2434,7 +2653,11 @@ sr_get_packets(struct sr_softc *sc)
/*
* construct control information for pass-off
*/
+#ifndef NETGRAPH
m->m_pkthdr.rcvif = ifp;
+#else
+ m->m_pkthdr.rcvif = NULL;
+#endif /* NETGRAPH */
m->m_pkthdr.len = m->m_len = len;
if (len > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -2455,6 +2678,7 @@ sr_get_packets(struct sr_softc *sc)
*/
sr_copy_rxbuf(m, sc, len); /* copy from DPRAM */
+#ifndef NETGRAPH
if (ifp->if_bpf)
bpf_mtap(ifp, m);
@@ -2469,7 +2693,6 @@ sr_get_packets(struct sr_softc *sc)
bp[4], bp[5], bp[6]);
}
#endif
-
/*
* Pass off the message to PPP, connecting it it to
* the system...
@@ -2487,6 +2710,24 @@ sr_get_packets(struct sr_softc *sc)
ifp->if_ipackets++;
+#else /* NETGRAPH */
+#if BUGGY > 3
+ {
+ u_char *bp;
+
+ bp = mtod(m,u_char *);
+ printf("sr%d: rd=%02x:%02x:%02x:%02x:%02x:%02x",
+ sc->unit,
+ bp[0], bp[1], bp[2],
+ bp[4], bp[5], bp[6]);
+ printf(":%02x:%02x:%02x:%02x:%02x:%02x\n",
+ bp[6], bp[7], bp[8],
+ bp[9], bp[10], bp[11]);
+ }
+#endif
+ ng_queue_data(sc->hook, m, NULL);
+ sc->ipackets++;
+#endif /* NETGRAPH */
/*
* Update the eda to the previous descriptor.
*/
@@ -2523,7 +2764,11 @@ sr_get_packets(struct sr_softc *sc)
*/
sr_eat_packet(sc, 1);
+#ifndef NETGRAPH
ifp->if_ierrors++;
+#else
+ sc->ierrors[0]++;
+#endif /* NETGRAPH */
got_st3 = SRC_GET8(hc->sca_base,
hc->sca->msci[sc->scachan].st3);
@@ -2605,8 +2850,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (dsr & SCA_DSR_COF) {
printf("sr%d: TX DMA Counter overflow, "
"txpacket no %lu.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_opackets);
sc->ifsppp.pp_if.if_oerrors++;
+#else
+ sc->unit, sc->opackets);
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/*
* Check for (& process) a Buffer overflow
@@ -2615,11 +2865,19 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: TX DMA Buffer overflow, "
"txpacket no %lu, dsr %02x, "
"cda %04x, eda %04x.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_opackets,
+#else
+ sc->unit, sc->opackets,
+#endif /* NETGRAPH */
dsr,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda));
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_oerrors++;
+#else
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/*
* Check for (& process) an End of Transfer (OK)
@@ -2637,8 +2895,14 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: TX Completed OK\n", sc->unit);
#endif
sc->xmit_busy = 0;
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
sc->ifsppp.pp_if.if_timer = 0;
+#else
+ /* XXX may need to mark tx inactive? */
+ sc->out_deficit++;
+ sc->out_dog = DOG_HOLDOFF;
+#endif /* NETGRAPH */
if (sc->txb_inuse && --sc->txb_inuse)
sr_xmit(sc);
@@ -2660,14 +2924,22 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
#if BUGGY > 0
int tt, ind;
+#ifndef NETGRAPH
tt = sc->ifsppp.pp_if.if_ipackets;
+#else /* NETGRAPH */
+ tt = sc->ipackets;
+#endif /* NETGRAPH */
ind = sc->rxhind;
#endif
sr_get_packets(sc);
-
#if BUGGY > 0
- if (tt == sc->ifsppp.pp_if.if_ipackets) {
+#ifndef NETGRAPH
+ if (tt == sc->ifsppp.pp_if.if_ipackets)
+#else /* NETGRAPH */
+ if (tt == sc->ipackets)
+#endif /* NETGRAPH */
+ {
sca_descriptor *rxdesc;
int i;
@@ -2702,7 +2974,7 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
}
-#endif
+#endif /* BUGGY */
}
/*
* Check for Counter overflow
@@ -2710,8 +2982,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (dsr & SCA_DSR_COF) {
printf("sr%d: RX DMA Counter overflow, "
"rxpkts %lu.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->unit, sc->ipackets);
+ sc->ierrors[1]++;
+#endif /* NETGRAPH */
}
/*
* Check for Buffer overflow
@@ -2720,7 +2997,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: RX DMA Buffer overflow, "
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_ipackets,
+#else /* NETGRAPH */
+ sc->unit, sc->ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda),
@@ -2734,7 +3015,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
SRC_SET_ON(hc->iobase);
sr_eat_packet(sc, 0);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[2]++;
+#endif /* NETGRAPH */
SRC_PUT8(hc->sca_base,
sca->msci[mch].cmd,
@@ -2747,7 +3032,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x. After\n",
sc->unit,
+#ifndef NETGRAPH
+ sc->ipackets,
+#else /* NETGRAPH */
sc->ifsppp.pp_if.if_ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda),
@@ -2770,8 +3059,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
*/
printf("sr%d: RX End of xfer, rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else
+ sc->ipackets);
+ sc->ierrors[3]++;
+#endif /* NETGRAPH */
}
}
isr1 >>= 4; /* process next half of ISR */
@@ -2785,12 +3079,16 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
for (mch = 0; mch < NCHAN; mch++) {
if (dotxstart & 0x0C) { /* TX initiation enabled? */
sc = &hc->sc[mch];
+#ifndef NETGRAPH
srstart(&sc->ifsppp.pp_if);
+#else
+ srstart(sc);
+#endif /* NETGRAPH */
}
dotxstart >>= 4;/* shift for next channel */
}
}
-
+#ifndef NETGRAPH
/*
* Perform timeout on an FR channel
*
@@ -2910,6 +3208,38 @@ sr_modemck(void *arg)
splx(s);
}
+#else /* NETGRAPH */
+/*
+ * If a port is open/active, it's DCD state is checked
+ * and a loss of DCD is recognized (and eventually processed?).
+ */
+static void
+sr_modemck(struct sr_softc *sc )
+{
+ u_int s;
+ u_char got_st3; /* contents of ST3 */
+ struct sr_hardc *hc = sc->hc; /* card's configuration */
+ msci_channel *msci; /* regs specific to channel */
+
+ s = splimp();
+
+
+ if (sc->running == 0)
+ return;
+ /*
+ * OK, now we can go looking at this channel's register contents...
+ */
+ msci = &hc->sca->msci[sc->scachan];
+ got_st3 = SRC_GET8(hc->sca_base, msci->st3);
+
+ /*
+ * We want to see if the DCD signal is up (DCD is true if zero)
+ */
+ sc->dcd = (got_st3 & SCA_ST3_DCD) == 0;
+ splx(s);
+}
+
+#endif /* NETGRAPH */
static void
sr_msci_intr(struct sr_hardc *hc, u_char isr0)
{
@@ -2922,6 +3252,301 @@ sr_timer_intr(struct sr_hardc *hc, u_char isr2)
printf("src%d: SRINTR: TIMER\n", hc->cunit);
}
+#ifdef NETGRAPH
+/*****************************************
+ * Device timeout/watchdog routine.
+ * called once per second.
+ * checks to see that if activity was expected, that it hapenned.
+ * At present we only look to see if expected output was completed.
+ */
+static void
+ngsr_watchdog_frame(void * arg)
+{
+ struct sr_softc * sc = arg;
+ int s;
+ int speed;
+
+ if(sc->running == 0)
+ return; /* if we are not running let timeouts die */
+ /*
+ * calculate the apparent throughputs
+ * XXX a real hack
+ */
+ s = splimp();
+ speed = sc->inbytes - sc->lastinbytes;
+ sc->lastinbytes = sc->inbytes;
+ if ( sc->inrate < speed )
+ sc->inrate = speed;
+ speed = sc->outbytes - sc->lastoutbytes;
+ sc->lastoutbytes = sc->outbytes;
+ if ( sc->outrate < speed )
+ sc->outrate = speed;
+ sc->inlast++;
+ splx(s);
+
+ if ((sc->inlast > QUITE_A_WHILE)
+ && (sc->out_deficit > LOTS_OF_PACKETS)) {
+ log(LOG_ERR, "sr%d: No response from remote end\n", sc->unit);
+ s = splimp();
+ sr_down(sc);
+ sr_up(sc);
+ sc->inlast = sc->out_deficit = 0;
+ splx(s);
+ } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */
+ if (sc->out_dog == 0) {
+ log(LOG_ERR, "sr%d: Transmit failure.. no clock?\n",
+ sc->unit);
+ srwatchdog(sc);
+#if 0
+ s = splimp();
+ sr_down(sc);
+ sr_up(sc);
+ splx(s);
+#endif
+ sc->inlast = sc->out_deficit = 0;
+ } else {
+ sc->out_dog--;
+ }
+ }
+ sr_modemck(sc); /* update the DCD status */
+ sc->handle = timeout(ngsr_watchdog_frame, sc, hz);
+}
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
+/*
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngsr_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * give our ok for a hook to be added...
+ * If we are not running this should kick the device into life.
+ * We allow hooks called "control" and dlci[1-1023]
+ * The hook's private info points to our stash of info about that
+ * channel.
+ */
+static int
+ngsr_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct sr_softc * sc = node->private;
+
+ /*
+ * check if it's our friend the debug hook
+ */
+ if (strcmp(name, NG_SR_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ sc->debug_hook = hook;
+ return (0);
+ }
+
+ /*
+ * Check for raw mode hook.
+ */
+ if (strcmp(name, NG_SR_HOOK_RAW) != 0) {
+ return (EINVAL);
+ }
+ hook->private = sc;
+ sc->hook = hook;
+ sc->datahooks++;
+ sr_up(sc);
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
+ */
+static int
+ngsr_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct sr_softc * sc;
+ int error = 0;
+
+ sc = node->private;
+ switch (msg->header.typecookie) {
+ case NG_SR_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n"
+ "highest rate seen: %ld B/S in, %ld B/S out\n",
+ sc->inbytes, sc->outbytes,
+ sc->inrate, sc->outrate);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ sc->oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld, %ld, %ld, %ld, %ld, %ld\n",
+ sc->ierrors[0],
+ sc->ierrors[1],
+ sc->ierrors[2],
+ sc->ierrors[3],
+ sc->ierrors[4],
+ sc->ierrors[5]);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NG_SR_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * get data from another node and transmit it to the correct channel
+ */
+static int
+ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int s;
+ int error = 0;
+ struct sr_softc * sc = hook->node->private;
+ struct ifqueue *xmitq_p;
+
+ /*
+ * data doesn't come in from just anywhere (e.g control hook)
+ */
+ if ( hook->private == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splimp();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ splx(s);
+ srstart(sc);
+ return (0);
+
+bad:
+ /*
+ * It was an error case.
+ * check if we need to free the mbuf, and then return the error
+ */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * do local shutdown processing..
+ * this node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngsr_rmnode(node_p node)
+{
+ struct sr_softc * sc = node->private;
+
+ sr_down(sc);
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngsr_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ * As the device still exists, the shutdown method will not actually
+ * destroy the node, but reset the device and leave it 'fresh' :)
+ *
+ * The node removal code will remove all references except that owned by the
+ * driver.
+ */
+static int
+ngsr_disconnect(hook_p hook)
+{
+ struct sr_softc * sc = hook->node->private;
+ int s;
+ /*
+ * If it's the data hook, then free resources etc.
+ */
+ if (hook->private) {
+ s = splimp();
+ sc->datahooks--;
+ if (sc->datahooks == 0)
+ sr_down(sc);
+ splx(s);
+ } else {
+ sc->debug_hook = NULL;
+ }
+ return (0);
+}
+
+/*
+ * called during bootup
+ * or LKM loading to put this type into the list of known modules
+ */
+static void
+ngsr_init(void *ignored)
+{
+ if (ng_newtype(&typestruct))
+ printf("ngsr install failed\n");
+ ngsr_done_init = 1;
+}
+#endif /* NETGRAPH */
+
/*
********************************* END ************************************
*/
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 66af687..2a55351 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -387,6 +387,24 @@ options NETATALK #Appletalk communications protocols
#options EON #ISO CLNP over IP
#options NSIP #XNS over IP
+# netgraph(4). Enable the base netgraph code with the NETGRAPH option.
+# Individual node types can be enabled with the corresponding option
+# listed below; however, this is not strictly necessary as netgraph
+# will automatically load the corresponding KLD module if the node type
+# is not already compiled into the kernel.
+options NETGRAPH #netgraph(4) system
+options NETGRAPH_ASYNC
+options NETGRAPH_CISCO
+options NETGRAPH_ECHO
+options NETGRAPH_FRAME_RELAY
+options NETGRAPH_HOLE
+options NETGRAPH_IFACE
+options NETGRAPH_LMI
+options NETGRAPH_RFC1490
+options NETGRAPH_TEE
+options NETGRAPH_TTY
+options NETGRAPH_UI
+
#
# Network interfaces:
# The `loop' pseudo-device is MANDATORY when networking is enabled.
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 66af687..2a55351 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -387,6 +387,24 @@ options NETATALK #Appletalk communications protocols
#options EON #ISO CLNP over IP
#options NSIP #XNS over IP
+# netgraph(4). Enable the base netgraph code with the NETGRAPH option.
+# Individual node types can be enabled with the corresponding option
+# listed below; however, this is not strictly necessary as netgraph
+# will automatically load the corresponding KLD module if the node type
+# is not already compiled into the kernel.
+options NETGRAPH #netgraph(4) system
+options NETGRAPH_ASYNC
+options NETGRAPH_CISCO
+options NETGRAPH_ECHO
+options NETGRAPH_FRAME_RELAY
+options NETGRAPH_HOLE
+options NETGRAPH_IFACE
+options NETGRAPH_LMI
+options NETGRAPH_RFC1490
+options NETGRAPH_TEE
+options NETGRAPH_TTY
+options NETGRAPH_UI
+
#
# Network interfaces:
# The `loop' pseudo-device is MANDATORY when networking is enabled.
diff --git a/sys/i386/isa/if_ar.c b/sys/i386/isa/if_ar.c
index 3e78c79..0eec2cf 100644
--- a/sys/i386/isa/if_ar.c
+++ b/sys/i386/isa/if_ar.c
@@ -45,6 +45,7 @@
*
*/
+#include "opt_netgraph.h"
#include "ar.h"
#include <sys/param.h>
@@ -55,9 +56,16 @@
#include <sys/socket.h>
#include <net/if.h>
+#ifdef NETGRAPH
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <i386/isa/if_ar.h>
+#else /* NETGRAPH */
#include <net/if_sppp.h>
-
#include <net/bpf.h>
+#endif /* NETGRAPH */
#include <machine/clock.h>
#include <machine/md_var.h>
@@ -66,10 +74,12 @@
#include <i386/isa/ic/hd64570.h>
#include <i386/isa/isa_device.h>
+#ifndef NETGRAPH
#include "sppp.h"
#if NSPPP <= 0
#error device 'ar' require sppp.
-#endif
+#endif /* NSPPP <= 0 */
+#endif /* NETGRAPH */
#ifdef TRACE
#define TRC(x) x
@@ -118,7 +128,9 @@ static int next_ar_unit = 0;
static struct ar_hardc ar_hardc[NAR];
struct ar_softc {
+#ifndef NETGRAPH
struct sppp ifsppp;
+#endif /* NETGRAPH */
int unit; /* With regards to all ar devices */
int subunit; /* With regards to this card */
struct ar_hardc *hc;
@@ -146,8 +158,38 @@ struct ar_softc {
int scano;
int scachan;
sca_regs *sca;
+#ifdef NETGRAPH
+ int running; /* something is attached so we are running */
+ int dcd; /* do we have dcd? */
+ /* ---netgraph bits --- */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ hook_p hook; /* data hook */
+ hook_p debug_hook;
+ struct ifqueue xmitq_hipri; /* hi-priority transmit queue */
+ struct ifqueue xmitq; /* transmit queue */
+ int flags; /* state */
+#define SCF_RUNNING 0x01 /* board is active */
+#define SCF_OACTIVE 0x02 /* output is active */
+ int out_dog; /* watchdog cycles output count-down */
+ struct callout_handle handle; /* timeout(9) handle */
+ u_long inbytes, outbytes; /* stats */
+ u_long lastinbytes, lastoutbytes; /* a second ago */
+ u_long inrate, outrate; /* highest rate seen */
+ u_long inlast; /* last input N secs ago */
+ u_long out_deficit; /* output since last input */
+ u_long oerrors, ierrors[6];
+ u_long opackets, ipackets;
+#endif /* NETGRAPH */
};
+#ifdef NETGRAPH
+#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */
+#define QUITE_A_WHILE 300 /* 5 MINUTES */
+#define LOTS_OF_PACKETS 100
+#endif /* NETGRAPH */
+
static int arprobe(struct isa_device *id);
static int arattach_isa(struct isa_device *id);
@@ -184,9 +226,14 @@ void arintr_hc(struct ar_hardc *hc);
static ointhand2_t arintr;
static int arattach(struct ar_hardc *hc);
static void ar_xmit(struct ar_softc *sc);
+#ifndef NETGRAPH
static void arstart(struct ifnet *ifp);
static int arioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void arwatchdog(struct ifnet *ifp);
+#else /* NETGRAPH */
+static void arstart(struct ar_softc *sc);
+static void arwatchdog(struct ar_softc *sc);
+#endif /* NETGRAPH */
static int ar_packet_avail(struct ar_softc *sc, int *len, u_char *rxstat);
static void ar_copy_rxbuf(struct mbuf *m, struct ar_softc *sc, int len);
static void ar_eat_packet(struct ar_softc *sc, int single);
@@ -204,6 +251,37 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr);
+#ifdef NETGRAPH
+static void ngar_watchdog_frame(void * arg);
+static void ngar_init(void* ignored);
+static int ngar_constructor(node_p *nodep);
+static int ngar_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngar_rmnode(node_p node);
+static int ngar_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngar_findhook(node_p node, char *name);*/
+static int ngar_connect(hook_p hook); /* already PARTLY linked */
+static int ngar_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngar_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_AR_NODE_TYPE,
+ NULL,
+ ngar_constructor,
+ ngar_rcvmsg,
+ ngar_rmnode,
+ ngar_newhook,
+ NULL,
+ ngar_connect,
+ ngar_rcvdata,
+ ngar_rcvdata,
+ ngar_disconnect
+};
+
+static int ngar_done_init = 0;
+#endif /* NETGRAPH */
+
/*
* Register the Adapter.
* Probe to see if it is there.
@@ -348,7 +426,9 @@ static int
arattach(struct ar_hardc *hc)
{
struct ar_softc *sc;
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
int unit;
char *iface;
@@ -380,6 +460,7 @@ arattach(struct ar_hardc *hc)
ar_init_tx_dmac(sc);
ar_init_msci(sc);
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
ifp->if_softc = sc;
@@ -412,6 +493,25 @@ arattach(struct ar_hardc *hc)
if_attach(ifp);
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
+#else /* NETGRAPH */
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngar_done_init == 0) ngar_init(NULL);
+ if (ng_make_node_common(&typestruct, &sc->node) != 0)
+ return (0);
+ sc->node->private = sc;
+ callout_handle_init(&sc->handle);
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(sc->nodename, "%s%d", NG_AR_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ return (0);
+ }
+ sc->running = 0;
+#endif /* NETGRAPH */
}
if(hc->bustype == AR_BUS_ISA)
@@ -511,10 +611,14 @@ arintr_hc(struct ar_hardc *hc)
static void
ar_xmit(struct ar_softc *sc)
{
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
dmac_channel *dmac;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
dmac = &sc->sca->dmac[DMAC_TXCH(sc->scachan)];
if(sc->hc->bustype == AR_BUS_ISA)
@@ -530,7 +634,11 @@ ar_xmit(struct ar_softc *sc)
if(sc->txb_next_tx == AR_TX_BLOCKS)
sc->txb_next_tx = 0;
+#ifndef NETGRAPH
ifp->if_timer = 2; /* Value in seconds. */
+#else /* NETGRAPH */
+ sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_OFF(sc->hc->iobase);
}
@@ -549,30 +657,51 @@ ar_xmit(struct ar_softc *sc)
* that clears that should ensure that the transmitter and its DMA is
* in a "good" idle state.
*/
+#ifndef NETGRAPH
static void
arstart(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+#else /* NETGRAPH */
+static void
+arstart(struct ar_softc *sc)
+{
+#endif /* NETGRAPH */
int i, len, tlen;
struct mbuf *mtx;
u_char *txdata;
sca_descriptor *txdesc;
struct buf_block *blkp;
+#ifndef NETGRAPH
if(!(ifp->if_flags & IFF_RUNNING))
return;
+#else /* NETGRAPH */
+/* XXX */
+#endif /* NETGRAPH */
top_arstart:
/*
* See if we have space for more packets.
*/
+#ifndef NETGRAPH
if(sc->txb_inuse == AR_TX_BLOCKS) {
- ifp->if_flags |= IFF_OACTIVE;
+ ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */
+#else /* NETGRAPH */
+/*XXX*/ /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */
+#endif /* NETGRAPH */
return;
}
+#ifndef NETGRAPH
mtx = sppp_dequeue(ifp);
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if(!mtx)
return;
@@ -618,10 +747,16 @@ top_arstart:
txdata += AR_BUF_SIZ;
i++;
+#ifndef NETGRAPH
if(ifp->if_bpf)
bpf_mtap(ifp, mtx);
m_freem(mtx);
++sc->ifsppp.pp_if.if_opackets;
+#else /* NETGRAPH */
+ m_freem(mtx);
+ sc->outbytes += len;
+ ++sc->opackets;
+#endif /* NETGRAPH */
/*
* Check if we have space for another mbuf.
@@ -631,7 +766,14 @@ top_arstart:
if((i + 3) >= blkp->txmax)
break;
+#ifndef NETGRAPH
mtx = sppp_dequeue(ifp);
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if(!mtx)
break;
}
@@ -670,6 +812,7 @@ top_arstart:
goto top_arstart;
}
+#ifndef NETGRAPH
static int
arioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -711,18 +854,26 @@ arioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
splx(s);
return 0;
}
+#endif /* NETGRAPH */
/*
* This is to catch lost tx interrupts.
*/
static void
+#ifndef NETGRAPH
arwatchdog(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+#else /* NETGRAPH */
+arwatchdog(struct ar_softc *sc)
+{
+#endif /* NETGRAPH */
msci_channel *msci = &sc->sca->msci[sc->scachan];
+#ifndef NETGRAPH
if(!(ifp->if_flags & IFF_RUNNING))
return;
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -730,7 +881,7 @@ arwatchdog(struct ifnet *ifp)
/* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
printf("ar%d: transmit failed, "
"ST0 %x, ST1 %x, ST3 %x, DSR %x.\n",
- ifp->if_unit,
+ sc->unit,
msci->st0,
msci->st1,
msci->st3,
@@ -743,12 +894,20 @@ arwatchdog(struct ifnet *ifp)
}
sc->xmit_busy = 0;
+#ifndef NETGRAPH
ifp->if_flags &= ~IFF_OACTIVE;
+#else /* NETGRAPH */
+ /* XXX ifp->if_flags &= ~IFF_OACTIVE; */
+#endif /* NETGRAPH */
if(sc->txb_inuse && --sc->txb_inuse)
ar_xmit(sc);
+#ifndef NETGRAPH
arstart(ifp);
+#else /* NETGRAPH */
+ arstart(sc);
+#endif /* NETGRAPH */
}
static void
@@ -803,6 +962,11 @@ ar_up(struct ar_softc *sc)
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_OFF(sc->hc->iobase);
+#ifdef NETGRAPH
+ untimeout(ngar_watchdog_frame, sc, sc->handle);
+ sc->handle = timeout(ngar_watchdog_frame, sc, hz);
+ sc->running = 1;
+#endif /* NETGRAPH */
}
static void
@@ -814,6 +978,10 @@ ar_down(struct ar_softc *sc)
sca = sc->sca;
msci = &sca->msci[sc->scachan];
+#ifdef NETGRAPH
+ untimeout(ngar_watchdog_frame, sc, sc->handle);
+ sc->running = 0;
+#endif /* NETGRAPH */
/*
* Disable transmitter and receiver.
* Lower DTR and RTS.
@@ -958,9 +1126,12 @@ arc_init(struct ar_hardc *hc)
u_int descneeded;
u_char isr, mar;
- sc = hc->sc = malloc(hc->numports * sizeof(struct ar_softc),
- M_DEVBUF, M_WAITOK);
+ MALLOC(sc, struct ar_softc *,
+ hc->numports * sizeof(struct ar_softc), M_DEVBUF, M_WAITOK);
+ if (sc == NULL)
+ return (ENOMEM);
bzero(sc, hc->numports * sizeof(struct ar_softc));
+ hc->sc = sc;
hc->txc_dtr[0] = AR_TXC_DTR_NOTRESET |
AR_TXC_DTR_DTR0 | AR_TXC_DTR_DTR1;
@@ -1088,7 +1259,6 @@ arc_init(struct ar_hardc *hc)
if(hc->bustype == AR_BUS_PCI)
hc->orbase[AR_PIMCTRL] = AR_PIM_MODEG | AR_PIM_AUTO_LED;
-
}
@@ -1105,7 +1275,6 @@ ar_init_sca(struct ar_hardc *hc, int scano)
sca_regs *sca;
sca = hc->sca[scano];
-
if(hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(hc->iobase, scano);
@@ -1562,7 +1731,13 @@ ar_get_packets(struct ar_softc *sc)
ar_eat_packet(sc, 1);
continue;
}
+#ifndef NETGRAPH
m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
+#else /* NETGRAPH */
+ m->m_pkthdr.rcvif = NULL;
+ sc->inbytes += len;
+ sc->inlast = 0;
+#endif /* NETGRAPH */
m->m_pkthdr.len = m->m_len = len;
if(len > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -1573,10 +1748,15 @@ ar_get_packets(struct ar_softc *sc)
}
}
ar_copy_rxbuf(m, sc, len);
+#ifndef NETGRAPH
if(sc->ifsppp.pp_if.if_bpf)
bpf_mtap(&sc->ifsppp.pp_if, m);
sppp_input(&sc->ifsppp.pp_if, m);
sc->ifsppp.pp_if.if_ipackets++;
+#else /* NETGRAPH */
+ ng_queue_data(sc->hook, m, NULL);
+ sc->ipackets++;
+#endif /* NETGRAPH */
/*
* Update the eda to the previous descriptor.
@@ -1609,7 +1789,11 @@ ar_get_packets(struct ar_softc *sc)
ar_eat_packet(sc, 1);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[0]++;
+#endif /* NETGRAPH */
if(sc->hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -1678,8 +1862,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
printf("ar%d: TX DMA Counter overflow, "
"txpacket no %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_opackets);
sc->ifsppp.pp_if.if_oerrors++;
+#else /* NETGRAPH */
+ sc->opackets);
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/* Buffer overflow */
@@ -1688,11 +1877,19 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
"txpacket no %lu, dsr %02x, "
"cda %04x, eda %04x.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_opackets,
+#else /* NETGRAPH */
+ sc->opackets,
+#endif /* NETGRAPH */
dsr,
dmac->cda,
dmac->eda);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_oerrors++;
+#else /* NETGRAPH */
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/* End of Transfer */
@@ -1706,8 +1903,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
* there is data to transmit.
*/
sc->xmit_busy = 0;
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
sc->ifsppp.pp_if.if_timer = 0;
+#else /* NETGRAPH */
+ /* XXX c->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; */
+ sc->out_dog = 0; /* XXX */
+#endif /* NETGRAPH */
if(sc->txb_inuse && --sc->txb_inuse)
ar_xmit(sc);
@@ -1735,7 +1937,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
ar_get_packets(sc);
TRC(
+#ifndef NETGRAPH
if(tt == sc->ifsppp.pp_if.if_ipackets) {
+#else /* NETGRAPH */
+ if(tt == sc->ipackets) {
+#endif /* NETGRAPH */
sca_descriptor *rxdesc;
int i;
@@ -1779,8 +1985,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
printf("ar%d: RX DMA Counter overflow, "
"rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ipackets);
+ sc->ierrors[1]++;
+#endif /* NETGRAPH */
}
/* Buffer overflow */
@@ -1791,7 +2002,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets,
+#else /* NETGRAPH */
+ sc->ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
dmac->cda,
dmac->eda,
@@ -1801,7 +2016,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
* Then get the system running again.
*/
ar_eat_packet(sc, 0);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[2]++;
+#endif /* NETGRAPH */
if(hc->bustype == AR_BUS_ISA)
ARC_SET_SCA(hc->iobase, scano);
sca->msci[mch].cmd = SCA_CMD_RXMSGREJ;
@@ -1829,8 +2048,13 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
*/
printf("ar%d: RX End of transfer, rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ipackets);
+ sc->ierrors[3]++;
+#endif /* NETGRAPH */
}
}
@@ -1846,7 +2070,11 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
for(mch = 0; mch < NCHAN; mch++) {
if(dotxstart & 0x0C) {
sc = &hc->sc[mch + (NCHAN * scano)];
+#ifndef NETGRAPH
arstart(&sc->ifsppp.pp_if);
+#else /* NETGRAPH */
+ arstart(sc);
+#endif /* NETGRAPH */
}
dotxstart >>= 4;
}
@@ -1864,7 +2092,299 @@ ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
printf("arc%d: ARINTR: TIMER\n", hc->cunit);
}
+
+#ifdef NETGRAPH
+/*****************************************
+ * Device timeout/watchdog routine.
+ * called once per second.
+ * checks to see that if activity was expected, that it hapenned.
+ * At present we only look to see if expected output was completed.
+ */
+static void
+ngar_watchdog_frame(void * arg)
+{
+ struct ar_softc * sc = arg;
+ int s;
+ int speed;
+
+ if(sc->running == 0)
+ return; /* if we are not running let timeouts die */
+ /*
+ * calculate the apparent throughputs
+ * XXX a real hack
+ */
+ s = splimp();
+ speed = sc->inbytes - sc->lastinbytes;
+ sc->lastinbytes = sc->inbytes;
+ if ( sc->inrate < speed )
+ sc->inrate = speed;
+ speed = sc->outbytes - sc->lastoutbytes;
+ sc->lastoutbytes = sc->outbytes;
+ if ( sc->outrate < speed )
+ sc->outrate = speed;
+ sc->inlast++;
+ splx(s);
+
+ if ((sc->inlast > QUITE_A_WHILE)
+ && (sc->out_deficit > LOTS_OF_PACKETS)) {
+ log(LOG_ERR, "ar%d: No response from remote end\n", sc->unit);
+ s = splimp();
+ ar_down(sc);
+ ar_up(sc);
+ sc->inlast = sc->out_deficit = 0;
+ splx(s);
+ } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */
+ if (sc->out_dog == 0) {
+ log(LOG_ERR, "ar%d: Transmit failure.. no clock?\n",
+ sc->unit);
+ arwatchdog(sc);
+#if 0
+ s = splimp();
+ ar_down(sc);
+ ar_up(sc);
+ splx(s);
+#endif
+ sc->inlast = sc->out_deficit = 0;
+ } else {
+ sc->out_dog--;
+ }
+ }
+ sc->handle = timeout(ngar_watchdog_frame, sc, hz);
+}
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
/*
- ********************************* END ************************************
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngar_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * give our ok for a hook to be added...
+ * If we are not running this should kick the device into life.
+ * We allow hooks called "control" and dlci[1-1023]
+ * The hook's private info points to our stash of info about that
+ * channel.
+ */
+static int
+ngar_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct ar_softc * sc = node->private;
+
+ /*
+ * check if it's our friend the debug hook
+ */
+ if (strcmp(name, NG_AR_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ sc->debug_hook = hook;
+ return (0);
+ }
+
+ /*
+ * Check for raw mode hook.
+ */
+ if (strcmp(name, NG_AR_HOOK_RAW) != 0) {
+ return (EINVAL);
+ }
+ hook->private = sc;
+ sc->hook = hook;
+ sc->datahooks++;
+ ar_up(sc);
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
*/
+static int
+ngar_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct ar_softc * sc;
+ int error = 0;
+
+ sc = node->private;
+ switch (msg->header.typecookie) {
+ case NG_AR_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n"
+ "highest rate seen: %ld B/S in, %ld B/S out\n",
+ sc->inbytes, sc->outbytes,
+ sc->inrate, sc->outrate);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ sc->oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld, %ld, %ld, %ld\n",
+ sc->ierrors[0],
+ sc->ierrors[1],
+ sc->ierrors[2],
+ sc->ierrors[3]);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NG_AR_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * get data from another node and transmit it to the correct channel
+ */
+static int
+ngar_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int s;
+ int error = 0;
+ struct ar_softc * sc = hook->node->private;
+ struct ifqueue *xmitq_p;
+
+ /*
+ * data doesn't come in from just anywhere (e.g control hook)
+ */
+ if ( hook->private == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splimp();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ splx(s);
+ arstart(sc);
+ return (0);
+
+bad:
+ /*
+ * It was an error case.
+ * check if we need to free the mbuf, and then return the error
+ */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * do local shutdown processing..
+ * this node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngar_rmnode(node_p node)
+{
+ struct ar_softc * sc = node->private;
+
+ ar_down(sc);
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngar_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ * As the device still exists, the shutdown method will not actually
+ * destroy the node, but reset the device and leave it 'fresh' :)
+ *
+ * The node removal code will remove all references except that owned by the
+ * driver.
+ */
+static int
+ngar_disconnect(hook_p hook)
+{
+ struct ar_softc * sc = hook->node->private;
+ int s;
+ /*
+ * If it's the data hook, then free resources etc.
+ */
+ if (hook->private) {
+ s = splimp();
+ sc->datahooks--;
+ if (sc->datahooks == 0)
+ ar_down(sc);
+ splx(s);
+ } else {
+ sc->debug_hook = NULL;
+ }
+ return (0);
+}
+
+/*
+ * called during bootup
+ * or LKM loading to put this type into the list of known modules
+ */
+static void
+ngar_init(void *ignored)
+{
+ if (ng_newtype(&typestruct))
+ printf("ngar install failed\n");
+ ngar_done_init = 1;
+}
+#endif /* NETGRAPH */
+/*
+ ********************************* END ************************************
+ */
diff --git a/sys/i386/isa/if_ar.h b/sys/i386/isa/if_ar.h
new file mode 100644
index 0000000..a40ccb9
--- /dev/null
+++ b/sys/i386/isa/if_ar.h
@@ -0,0 +1,23 @@
+/*
+ * if_ar.h
+ *
+ * Copyright (C) 1997-1999 Whistle Communications Inc.
+ * All rights reserved.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _I386_ISA_IF_AR_H_
+#define _I386_ISA_IF_AR_H_
+
+/* Node type name and type cookie */
+#define NG_AR_NODE_TYPE "sync_ar"
+#define NG_AR_COOKIE 860552149
+
+/* Netgraph hooks */
+#define NG_AR_HOOK_DEBUG "debug"
+#define NG_AR_HOOK_CONTROL "control"
+#define NG_AR_HOOK_RAW "rawdata"
+
+#endif /* _I386_ISA_IF_AR_H_ */
+
diff --git a/sys/i386/isa/if_sr.c b/sys/i386/isa/if_sr.c
index 6be7958..f50f7a5 100644
--- a/sys/i386/isa/if_sr.c
+++ b/sys/i386/isa/if_sr.c
@@ -48,16 +48,23 @@
*/
#include "sr.h"
+#include "opt_netgraph.h"
+#ifdef NETGRAPH
+#include <i386/isa/if_sr.h>
+#else /* NETGRAPH */
#ifdef notyet
#include "fr.h"
#else
#define NFR 0
#endif
+#endif /* NETGRAPH */
+#ifdef NETGRAPH
#include "sppp.h"
#if NSPPP <= 0
#error Device 'sr' requires sppp.
#endif
+#endif /* NETGRAPH */
#include <sys/param.h>
#include <sys/systm.h>
@@ -68,9 +75,13 @@
#include <sys/socket.h>
#include <net/if.h>
+#ifdef NETGRAPH
+#include <sys/syslog.h>
+#else /* NETGRAPH */
#include <net/if_sppp.h>
#include <net/bpf.h>
+#endif /* NETGRAPH */
#include <machine/md_var.h>
@@ -78,13 +89,19 @@
#include <i386/isa/ic/hd64570.h>
#include <i386/isa/isa_device.h>
+#ifdef NETGRAPH
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#endif /* NETGRAPH */
/* #define USE_MODEMCK */
#ifndef BUGGY
#define BUGGY 0
#endif
+#ifndef NETGRAPH
#define PPP_HEADER_LEN 4
+#endif /* NETGRAPH */
/*
* These macros are used to hide the difference between the way the
@@ -142,7 +159,9 @@ struct sr_hardc {
};
static int next_sc_unit = 0;
+#ifndef NETGRAPH
static int sr_watcher = 0;
+#endif /* NETGRAPH */
static struct sr_hardc sr_hardc[NSR];
static struct sr_hardc *sr_hardc_pci;
@@ -151,17 +170,20 @@ static struct sr_hardc *sr_hardc_pci;
* every channel (port).
*/
struct sr_softc {
+#ifndef NETGRAPH
struct sppp ifsppp; /* PPP service w/in system */
+#endif /* NETGRAPH */
struct sr_hardc *hc; /* card-level information */
int unit; /* With regard to all sr devices */
int subunit; /* With regard to this card */
+#ifndef NETGRAPH
int attached; /* attached to FR or PPP */
int protocol; /* FR or PPP */
#define N2_USE_FRP 2 /* Frame Relay Protocol */
#define N2_USE_PPP 1 /* Point-to-Point Protocol */
-
+#endif /* NETGRAPH */
struct buf_block {
u_int txdesc; /* DPRAM offset */
u_int txstart;/* DPRAM offset */
@@ -185,8 +207,40 @@ struct sr_softc {
u_int clk_cfg; /* Clock configuration */
int scachan; /* channel # on card */
+#ifdef NETGRAPH
+ int running; /* something is attached so we are running */
+ int dcd; /* do we have dcd? */
+ /* ---netgraph bits --- */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ hook_p hook; /* data hook */
+ hook_p debug_hook;
+ struct ifqueue xmitq_hipri; /* hi-priority transmit queue */
+ struct ifqueue xmitq; /* transmit queue */
+ int flags; /* state */
+#define SCF_RUNNING 0x01 /* board is active */
+#define SCF_OACTIVE 0x02 /* output is active */
+ int out_dog; /* watchdog cycles output count-down */
+#if ( __FreeBSD__ >= 3 )
+ struct callout_handle handle; /* timeout(9) handle */
+#endif
+ u_long inbytes, outbytes; /* stats */
+ u_long lastinbytes, lastoutbytes; /* a second ago */
+ u_long inrate, outrate; /* highest rate seen */
+ u_long inlast; /* last input N secs ago */
+ u_long out_deficit; /* output since last input */
+ u_long oerrors, ierrors[6];
+ u_long opackets, ipackets;
+#endif /* NETGRAPH */
};
+#ifdef NETGRAPH
+#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */
+#define QUITE_A_WHILE 300 /* 5 MINUTES */
+#define LOTS_OF_PACKETS 100
+#endif /* NETGRAPH */
+
/*
* List of valid interrupt numbers for the N2 ISA card.
*/
@@ -267,11 +321,17 @@ struct sr_hardc *srattach_pci(int unit, vm_offset_t plx_vaddr,
void srintr_hc(struct sr_hardc *hc);
static ointhand2_t srintr;
+
static int srattach(struct sr_hardc *hc);
static void sr_xmit(struct sr_softc *sc);
+#ifndef NETGRAPH
static void srstart(struct ifnet *ifp);
static int srioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void srwatchdog(struct ifnet *ifp);
+#else
+static void srstart(struct sr_softc *sc);
+static void srwatchdog(struct sr_softc *sc);
+#endif /* NETGRAPH */
static int sr_packet_avail(struct sr_softc *sc, int *len, u_char *rxstat);
static void sr_copy_rxbuf(struct mbuf *m, struct sr_softc *sc, int len);
static void sr_eat_packet(struct sr_softc *sc, int single);
@@ -287,7 +347,11 @@ static void sr_init_tx_dmac(struct sr_softc *sc);
static void sr_dmac_intr(struct sr_hardc *hc, u_char isr);
static void sr_msci_intr(struct sr_hardc *hc, u_char isr);
static void sr_timer_intr(struct sr_hardc *hc, u_char isr);
+#ifndef NETGRAPH
static void sr_modemck(void *x);
+#else
+static void sr_modemck(struct sr_softc *x);
+#endif /* NETGRAPH */
static u_int src_get8_io(u_int base, u_int off);
static u_int src_get16_io(u_int base, u_int off);
@@ -298,6 +362,7 @@ static u_int src_get16_mem(u_int base, u_int off);
static void src_put8_mem(u_int base, u_int off, u_int val);
static void src_put16_mem(u_int base, u_int off, u_int val);
+#ifndef NETGRAPH
#if NFR > 0
extern void fr_detach(struct ifnet *);
extern int fr_attach(struct ifnet *);
@@ -306,6 +371,36 @@ extern void fr_flush(struct ifnet *);
extern int fr_input(struct ifnet *, struct mbuf *);
extern struct mbuf *fr_dequeue(struct ifnet *);
#endif
+#else
+static void ngsr_watchdog_frame(void * arg);
+static void ngsr_init(void* ignored);
+static int ngsr_constructor(node_p *nodep);
+static int ngsr_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngsr_rmnode(node_p node);
+static int ngsr_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngsr_findhook(node_p node, char *name);*/
+static int ngsr_connect(hook_p hook); /* already PARTLY linked */
+static int ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngsr_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_SR_NODE_TYPE,
+ NULL,
+ ngsr_constructor,
+ ngsr_rcvmsg,
+ ngsr_rmnode,
+ ngsr_newhook,
+ NULL,
+ ngsr_connect,
+ ngsr_rcvdata,
+ ngsr_rcvdata,
+ ngsr_disconnect
+};
+
+static int ngsr_done_init = 0;
+#endif /* NETGRAPH */
/*
* I/O for ISA N2 card(s)
@@ -569,6 +664,15 @@ srattach_isa(struct isa_device *id)
u_char mar;
struct sr_hardc *hc = &sr_hardc[id->id_unit];
+ /*
+ * Allocate the software interface table(s)
+ */
+ MALLOC(hc->sc, struct sr_softc *,
+ hc->numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK);
+ if (hc->sc == NULL)
+ return(0);
+ bzero(hc->sc, hc->numports * sizeof(struct sr_softc));
+
id->id_ointr = srintr;
outb(hc->iobase + SR_PCR, inb(hc->iobase + SR_PCR) | SR_PCR_SCARUN);
@@ -588,13 +692,6 @@ srattach_isa(struct isa_device *id)
outb(hc->iobase + SR_BAR, mar);
/*
- * Allocate the software interface table(s)
- */
- hc->sc = malloc(hc->numports * sizeof(struct sr_softc),
- M_DEVBUF, M_WAITOK);
- bzero(hc->sc, hc->numports * sizeof(struct sr_softc));
-
- /*
* Get the TX clock direction and configuration. The default is a
* single external clock which is used by RX and TX.
*/
@@ -680,13 +777,19 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr)
hc = hc->next;
}
- hc = malloc(sizeof(struct sr_hardc), M_DEVBUF, M_WAITOK);
- *hcp = hc;
- bzero(hc, sizeof(struct sr_hardc));
+ MALLOC(hc, struct sr_hardc *, sizeof(*hc), M_DEVBUF, M_WAITOK);
+ if (hc == NULL)
+ return NULL;
+ bzero(hc, sizeof(*hc));
- hc->sc = malloc(numports * sizeof(struct sr_softc),
- M_DEVBUF, M_WAITOK);
+ MALLOC(hc->sc, struct sr_softc *,
+ numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK);
+ if (hc->sc == NULL) {
+ FREE(hc, M_DEVBUF);
+ return NULL;
+ }
bzero(hc->sc, numports * sizeof(struct sr_softc));
+ *hcp = hc;
hc->numports = numports;
hc->cunit = unit;
@@ -779,13 +882,17 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr)
/*
* Register the ports on the adapter.
* Fill in the info for each port.
+#ifndef NETGRAPH
* Attach each port to sppp and bpf.
+#endif
*/
static int
srattach(struct sr_hardc *hc)
{
struct sr_softc *sc = hc->sc;
+#ifndef NETGRAPH
struct ifnet *ifp;
+#endif /* NETGRAPH */
int unit; /* index: channel w/in card */
/*
@@ -813,6 +920,10 @@ srattach(struct sr_hardc *hc)
sr_init_tx_dmac(sc);
sr_init_msci(sc);
+ printf("sr%d: Adapter %d, port %d.\n",
+ sc->unit, hc->cunit, sc->subunit);
+
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
ifp->if_softc = sc;
ifp->if_unit = sc->unit;
@@ -823,9 +934,6 @@ srattach(struct sr_hardc *hc)
ifp->if_start = srstart;
ifp->if_watchdog = srwatchdog;
- printf("sr%d: Adapter %d, port %d.\n",
- sc->unit, hc->cunit, sc->subunit);
-
/*
* Despite the fact that we want to allow both PPP *and*
* Frame Relay access to a channel, due to the architecture
@@ -846,6 +954,25 @@ srattach(struct sr_hardc *hc)
if_attach(ifp);
bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN);
+#else /* NETGRAPH */
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngsr_done_init == 0) ngsr_init(NULL);
+ if (ng_make_node_common(&typestruct, &sc->node) != 0)
+ return (0);
+ sc->node->private = sc;
+ callout_handle_init(&sc->handle);
+ sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
+ sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
+ sprintf(sc->nodename, "%s%d", NG_SR_NODE_TYPE, sc->unit);
+ if (ng_name_node(sc->node, sc->nodename)) {
+ ng_rmnode(sc->node);
+ ng_unref(sc->node);
+ return (0);
+ }
+ sc->running = 0;
+#endif /* NETGRAPH */
}
if (hc->mempages)
@@ -855,26 +982,24 @@ srattach(struct sr_hardc *hc)
}
/*
- * N2 Interrupt Service Routine.
- * Get the ISA interrupts.
- *
+ * N2 Interrupt Service Routine
+ *
* First figure out which SCA gave the interrupt.
- *
+ * Process it.
+ * See if there is other interrupts pending.
+ * Repeat until there no interrupts remain.
*/
static void
srintr(int unit)
-{
- struct sr_hardc *hc;
+{
+ struct sr_hardc *hc;
hc = &sr_hardc[unit];
srintr_hc(hc);
- return;
+ return;
}
-/*
- * PCI interrupts come straight here
- */
void
srintr_hc(struct sr_hardc *hc)
{
@@ -908,7 +1033,11 @@ srintr_hc(struct sr_hardc *hc)
#if BUGGY > 2
printf("src%d: srintr_hc isr0 %x, isr1 %x, isr2 %x\n",
+#ifndef NETGRAPH
unit, isr0, isr1, isr2);
+#else
+ hc->cunit, isr0, isr1, isr2);
+#endif /* NETGRAPH */
#endif
/*
@@ -938,7 +1067,9 @@ sr_xmit(struct sr_softc *sc)
u_short cda_value; /* starting descriptor */
u_short eda_value; /* ending descriptor */
struct sr_hardc *hc;
+#ifndef NETGRAPH
struct ifnet *ifp; /* O/S Network Services */
+#endif /* NETGRAPH */
dmac_channel *dmac; /* DMA channel registers */
#if BUGGY > 0
@@ -946,7 +1077,9 @@ sr_xmit(struct sr_softc *sc)
#endif
hc = sc->hc;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
dmac = &hc->sca->dmac[DMAC_TXCH(sc->scachan)];
/*
@@ -979,11 +1112,18 @@ sr_xmit(struct sr_softc *sc)
if (sc->txb_next_tx == SR_TX_BLOCKS) /* handle wrap... */
sc->txb_next_tx = 0;
+#ifndef NETGRAPH
/*
* Finally, we'll set a timout (which will start srwatchdog())
* within the O/S network services layer...
*/
ifp->if_timer = 2; /* Value in seconds. */
+#else
+ /*
+ * Don't time out for a while.
+ */
+ sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/
+#endif /* NETGRAPH */
}
/*
@@ -1000,10 +1140,16 @@ sr_xmit(struct sr_softc *sc)
* The function that clears that should ensure that the transmitter
* and its DMA is in a "good" idle state.
*/
+#ifndef NETGRAPH
static void
srstart(struct ifnet *ifp)
{
struct sr_softc *sc; /* channel control structure */
+#else
+static void
+srstart(struct sr_softc *sc)
+{
+#endif /* NETGRAPH */
struct sr_hardc *hc; /* card control/config block */
int len; /* total length of a packet */
int pkts; /* packets placed in DPRAM */
@@ -1014,16 +1160,15 @@ srstart(struct ifnet *ifp)
sca_descriptor *txdesc; /* working descriptor pointr */
struct buf_block *blkp;
+ hc = sc->hc;
+#ifndef NETGRAPH
#if BUGGY > 0
printf("sr: srstart( ifp=%08x)\n", ifp);
#endif
-
sc = ifp->if_softc;
- hc = sc->hc;
-
if ((ifp->if_flags & IFF_RUNNING) == 0)
return;
-
+#endif /* NETGRAPH */
/*
* It is OK to set the memory window outside the loop because all tx
* buffers and descriptors are assumed to be in the same 16K window.
@@ -1045,7 +1190,11 @@ top_srstart:
* See if we have space for more packets.
*/
if (sc->txb_inuse == SR_TX_BLOCKS) { /* out of space? */
+#ifndef NETGRAPH
ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */
+#else
+ /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */
+#endif /* NETGRAPH */
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
@@ -1071,6 +1220,7 @@ top_srstart:
* dispatch table to select the service we're getting a packet
* from...
*/
+#ifndef NETGRAPH
switch (sc->protocol) {
#if NFR > 0
case N2_USE_FRP:
@@ -1081,7 +1231,12 @@ top_srstart:
default:
mtx = sppp_dequeue(ifp);
}
-
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if (!mtx) {
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
@@ -1114,8 +1269,12 @@ top_srstart:
sc->unit, mtx, len);
#endif
+#ifndef NETGRAPH
if (ifp->if_bpf)
bpf_mtap(ifp, mtx);
+#else /* NETGRAPH */
+ sc->outbytes += len;
+#endif /* NETGRAPH */
/*
* We can perform a straight copy because the tranmit
@@ -1159,7 +1318,11 @@ top_srstart:
* and update the statistics...
*/
m_freem(mtx);
+#ifndef NETGRAPH
++sc->ifsppp.pp_if.if_opackets;
+#else /* NETGRAPH */
+ sc->opackets++;
+#endif /* NETGRAPH */
/*
* Check if we have space for another packet. XXX This is
@@ -1176,6 +1339,7 @@ top_srstart:
/*
* We'll pull the next message to be sent (if any)
*/
+#ifndef NETGRAPH
switch (sc->protocol) {
#if NFR > 0
case N2_USE_FRP:
@@ -1186,7 +1350,12 @@ top_srstart:
default:
mtx = sppp_dequeue(ifp);
}
-
+#else /* NETGRAPH */
+ IF_DEQUEUE(&sc->xmitq_hipri, mtx);
+ if (mtx == NULL) {
+ IF_DEQUEUE(&sc->xmitq, mtx);
+ }
+#endif /* NETGRAPH */
if (!mtx) { /* no message? We're done! */
#if BUGGY > 9
printf("sr%d.srstart: pending=0, pkts=%d\n",
@@ -1231,6 +1400,7 @@ top_srstart:
goto top_srstart;
}
+#ifndef NETGRAPH
/*
* Handle ioctl's at the device level, though we *will* call up
* a layer...
@@ -1407,37 +1577,56 @@ srioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return 0;
}
+#endif /* NETGRAPH */
/*
* This is to catch lost tx interrupts.
*/
static void
+#ifndef NETGRAPH
srwatchdog(struct ifnet *ifp)
+#else
+srwatchdog(struct sr_softc *sc)
+#endif /* NETGRAPH */
{
int got_st0, got_st1, got_st3, got_dsr;
+#ifndef NETGRAPH
struct sr_softc *sc = ifp->if_softc;
+#endif /* NETGRAPH */
struct sr_hardc *hc = sc->hc;
msci_channel *msci = &hc->sca->msci[sc->scachan];
dmac_channel *dmac = &sc->hc->sca->dmac[sc->scachan];
#if BUGGY > 0
+#ifndef NETGRAPH
printf("srwatchdog(unit=%d)\n", unit);
+#else
+ printf("srwatchdog(unit=%d)\n", sc->unit);
+#endif /* NETGRAPH */
#endif
+#ifndef NETGRAPH
if (!(ifp->if_flags & IFF_RUNNING))
return;
ifp->if_oerrors++; /* update output error count */
+#else /* NETGRAPH */
+ sc->oerrors++; /* update output error count */
+#endif /* NETGRAPH */
got_st0 = SRC_GET8(hc->sca_base, msci->st0);
got_st1 = SRC_GET8(hc->sca_base, msci->st1);
got_st3 = SRC_GET8(hc->sca_base, msci->st3);
got_dsr = SRC_GET8(hc->sca_base, dmac->dsr);
+#ifndef NETGRAPH
#if 0
if (ifp->if_flags & IFF_DEBUG)
#endif
printf("sr%d: transmit failed, "
+#else /* NETGRAPH */
+ printf("sr%d: transmit failed, "
+#endif /* NETGRAPH */
"ST0 %02x, ST1 %02x, ST3 %02x, DSR %02x.\n",
sc->unit,
got_st0, got_st1, got_st3, got_dsr);
@@ -1448,12 +1637,20 @@ srwatchdog(struct ifnet *ifp)
SRC_PUT8(hc->sca_base, msci->st1, SCA_ST1_UDRN);
}
sc->xmit_busy = 0;
+#ifndef NETGRAPH
ifp->if_flags &= ~IFF_OACTIVE;
+#else
+ /*ifp->if_flags &= ~IFF_OACTIVE; */
+#endif /* NETGRAPH */
if (sc->txb_inuse && --sc->txb_inuse)
sr_xmit(sc);
+#ifndef NETGRAPH
srstart(ifp); /* restart transmitter */
+#else
+ srstart(sc); /* restart transmitter */
+#endif /* NETGRAPH */
}
static void
@@ -1468,6 +1665,7 @@ sr_up(struct sr_softc *sc)
printf("sr_up(sc=%08x)\n", sc);
#endif
+#ifndef NETGRAPH
/*
* This section should really do the attach to the appropriate
* system service, be it frame relay or PPP...
@@ -1489,6 +1687,7 @@ sr_up(struct sr_softc *sc)
sc->attached = sc->protocol;
}
+#endif /* NETGRAPH */
/*
* Enable transmitter and receiver. Raise DTR and RTS. Enable
* interrupts.
@@ -1537,10 +1736,16 @@ sr_up(struct sr_softc *sc)
inb(hc->iobase); /* XXX slow it down a bit. */
SRC_PUT8(hc->sca_base, msci->cmd, SCA_CMD_TXENABLE);
+#ifndef NETGRAPH
#ifdef USE_MODEMCK
if (sr_watcher == 0)
sr_modemck(NULL);
#endif
+#else /* NETGRAPH */
+ untimeout(ngsr_watchdog_frame, sc, sc->handle);
+ sc->handle = timeout(ngsr_watchdog_frame, sc, hz);
+ sc->running = 1;
+#endif /* NETGRAPH */
}
static void
@@ -1554,6 +1759,10 @@ sr_down(struct sr_softc *sc)
#if BUGGY > 0
printf("sr_down(sc=%08x)\n", sc);
#endif
+#ifdef NETGRAPH
+ untimeout(ngsr_watchdog_frame, sc, sc->handle);
+ sc->running = 0;
+#endif /* NETGRAPH */
/*
* Disable transmitter and receiver. Lower DTR and RTS. Disable
@@ -1601,6 +1810,7 @@ sr_down(struct sr_softc *sc)
SRC_GET8(hc->sca_base, sca->ier1) & ~0xF0);
}
+#ifndef NETGRAPH
/*
* This section does the detach from the currently configured net
* service, be it frame relay or PPP...
@@ -1617,6 +1827,7 @@ sr_down(struct sr_softc *sc)
}
sc->attached = 0;
+#endif /* NETGRAPH */
}
/*
@@ -2373,7 +2584,9 @@ sr_get_packets(struct sr_softc *sc)
u_int len; /* length of pending packet */
struct sr_hardc *hc; /* card-level information */
sca_descriptor *rxdesc; /* descriptor in memory */
+#ifndef NETGRAPH
struct ifnet *ifp; /* network intf ctl table */
+#endif /* NETGRAPH */
struct mbuf *m = NULL; /* message buffer */
#if BUGGY > 0
@@ -2381,7 +2594,9 @@ sr_get_packets(struct sr_softc *sc)
#endif
hc = sc->hc;
+#ifndef NETGRAPH
ifp = &sc->ifsppp.pp_if;
+#endif /* NETGRAPH */
if (hc->mempages) {
SRC_SET_MEM(hc->iobase, sc->rxdesc);
@@ -2412,6 +2627,10 @@ sr_get_packets(struct sr_softc *sc)
#endif
pkts++;
+#ifdef NETGRAPH
+ sc->inbytes += len;
+ sc->inlast = 0;
+#endif /* NETGRAPH */
/*
* OK, we've settled the incoming message status. We can now
@@ -2434,7 +2653,11 @@ sr_get_packets(struct sr_softc *sc)
/*
* construct control information for pass-off
*/
+#ifndef NETGRAPH
m->m_pkthdr.rcvif = ifp;
+#else
+ m->m_pkthdr.rcvif = NULL;
+#endif /* NETGRAPH */
m->m_pkthdr.len = m->m_len = len;
if (len > MHLEN) {
MCLGET(m, M_DONTWAIT);
@@ -2455,6 +2678,7 @@ sr_get_packets(struct sr_softc *sc)
*/
sr_copy_rxbuf(m, sc, len); /* copy from DPRAM */
+#ifndef NETGRAPH
if (ifp->if_bpf)
bpf_mtap(ifp, m);
@@ -2469,7 +2693,6 @@ sr_get_packets(struct sr_softc *sc)
bp[4], bp[5], bp[6]);
}
#endif
-
/*
* Pass off the message to PPP, connecting it it to
* the system...
@@ -2487,6 +2710,24 @@ sr_get_packets(struct sr_softc *sc)
ifp->if_ipackets++;
+#else /* NETGRAPH */
+#if BUGGY > 3
+ {
+ u_char *bp;
+
+ bp = mtod(m,u_char *);
+ printf("sr%d: rd=%02x:%02x:%02x:%02x:%02x:%02x",
+ sc->unit,
+ bp[0], bp[1], bp[2],
+ bp[4], bp[5], bp[6]);
+ printf(":%02x:%02x:%02x:%02x:%02x:%02x\n",
+ bp[6], bp[7], bp[8],
+ bp[9], bp[10], bp[11]);
+ }
+#endif
+ ng_queue_data(sc->hook, m, NULL);
+ sc->ipackets++;
+#endif /* NETGRAPH */
/*
* Update the eda to the previous descriptor.
*/
@@ -2523,7 +2764,11 @@ sr_get_packets(struct sr_softc *sc)
*/
sr_eat_packet(sc, 1);
+#ifndef NETGRAPH
ifp->if_ierrors++;
+#else
+ sc->ierrors[0]++;
+#endif /* NETGRAPH */
got_st3 = SRC_GET8(hc->sca_base,
hc->sca->msci[sc->scachan].st3);
@@ -2605,8 +2850,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (dsr & SCA_DSR_COF) {
printf("sr%d: TX DMA Counter overflow, "
"txpacket no %lu.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_opackets);
sc->ifsppp.pp_if.if_oerrors++;
+#else
+ sc->unit, sc->opackets);
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/*
* Check for (& process) a Buffer overflow
@@ -2615,11 +2865,19 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: TX DMA Buffer overflow, "
"txpacket no %lu, dsr %02x, "
"cda %04x, eda %04x.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_opackets,
+#else
+ sc->unit, sc->opackets,
+#endif /* NETGRAPH */
dsr,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda));
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_oerrors++;
+#else
+ sc->oerrors++;
+#endif /* NETGRAPH */
}
/*
* Check for (& process) an End of Transfer (OK)
@@ -2637,8 +2895,14 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: TX Completed OK\n", sc->unit);
#endif
sc->xmit_busy = 0;
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
sc->ifsppp.pp_if.if_timer = 0;
+#else
+ /* XXX may need to mark tx inactive? */
+ sc->out_deficit++;
+ sc->out_dog = DOG_HOLDOFF;
+#endif /* NETGRAPH */
if (sc->txb_inuse && --sc->txb_inuse)
sr_xmit(sc);
@@ -2660,14 +2924,22 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
#if BUGGY > 0
int tt, ind;
+#ifndef NETGRAPH
tt = sc->ifsppp.pp_if.if_ipackets;
+#else /* NETGRAPH */
+ tt = sc->ipackets;
+#endif /* NETGRAPH */
ind = sc->rxhind;
#endif
sr_get_packets(sc);
-
#if BUGGY > 0
- if (tt == sc->ifsppp.pp_if.if_ipackets) {
+#ifndef NETGRAPH
+ if (tt == sc->ifsppp.pp_if.if_ipackets)
+#else /* NETGRAPH */
+ if (tt == sc->ipackets)
+#endif /* NETGRAPH */
+ {
sca_descriptor *rxdesc;
int i;
@@ -2702,7 +2974,7 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (hc->mempages)
SRC_SET_OFF(hc->iobase);
}
-#endif
+#endif /* BUGGY */
}
/*
* Check for Counter overflow
@@ -2710,8 +2982,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
if (dsr & SCA_DSR_COF) {
printf("sr%d: RX DMA Counter overflow, "
"rxpkts %lu.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->unit, sc->ipackets);
+ sc->ierrors[1]++;
+#endif /* NETGRAPH */
}
/*
* Check for Buffer overflow
@@ -2720,7 +2997,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
printf("sr%d: RX DMA Buffer overflow, "
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x.\n",
+#ifndef NETGRAPH
sc->unit, sc->ifsppp.pp_if.if_ipackets,
+#else /* NETGRAPH */
+ sc->unit, sc->ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda),
@@ -2734,7 +3015,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
SRC_SET_ON(hc->iobase);
sr_eat_packet(sc, 0);
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ierrors++;
+#else /* NETGRAPH */
+ sc->ierrors[2]++;
+#endif /* NETGRAPH */
SRC_PUT8(hc->sca_base,
sca->msci[mch].cmd,
@@ -2747,7 +3032,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
"rxpkts %lu, rxind %d, "
"cda %x, eda %x, dsr %x. After\n",
sc->unit,
+#ifndef NETGRAPH
+ sc->ipackets,
+#else /* NETGRAPH */
sc->ifsppp.pp_if.if_ipackets,
+#endif /* NETGRAPH */
sc->rxhind,
SRC_GET16(hc->sca_base, dmac->cda),
SRC_GET16(hc->sca_base, dmac->eda),
@@ -2770,8 +3059,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
*/
printf("sr%d: RX End of xfer, rxpkts %lu.\n",
sc->unit,
+#ifndef NETGRAPH
sc->ifsppp.pp_if.if_ipackets);
sc->ifsppp.pp_if.if_ierrors++;
+#else
+ sc->ipackets);
+ sc->ierrors[3]++;
+#endif /* NETGRAPH */
}
}
isr1 >>= 4; /* process next half of ISR */
@@ -2785,12 +3079,16 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1)
for (mch = 0; mch < NCHAN; mch++) {
if (dotxstart & 0x0C) { /* TX initiation enabled? */
sc = &hc->sc[mch];
+#ifndef NETGRAPH
srstart(&sc->ifsppp.pp_if);
+#else
+ srstart(sc);
+#endif /* NETGRAPH */
}
dotxstart >>= 4;/* shift for next channel */
}
}
-
+#ifndef NETGRAPH
/*
* Perform timeout on an FR channel
*
@@ -2910,6 +3208,38 @@ sr_modemck(void *arg)
splx(s);
}
+#else /* NETGRAPH */
+/*
+ * If a port is open/active, it's DCD state is checked
+ * and a loss of DCD is recognized (and eventually processed?).
+ */
+static void
+sr_modemck(struct sr_softc *sc )
+{
+ u_int s;
+ u_char got_st3; /* contents of ST3 */
+ struct sr_hardc *hc = sc->hc; /* card's configuration */
+ msci_channel *msci; /* regs specific to channel */
+
+ s = splimp();
+
+
+ if (sc->running == 0)
+ return;
+ /*
+ * OK, now we can go looking at this channel's register contents...
+ */
+ msci = &hc->sca->msci[sc->scachan];
+ got_st3 = SRC_GET8(hc->sca_base, msci->st3);
+
+ /*
+ * We want to see if the DCD signal is up (DCD is true if zero)
+ */
+ sc->dcd = (got_st3 & SCA_ST3_DCD) == 0;
+ splx(s);
+}
+
+#endif /* NETGRAPH */
static void
sr_msci_intr(struct sr_hardc *hc, u_char isr0)
{
@@ -2922,6 +3252,301 @@ sr_timer_intr(struct sr_hardc *hc, u_char isr2)
printf("src%d: SRINTR: TIMER\n", hc->cunit);
}
+#ifdef NETGRAPH
+/*****************************************
+ * Device timeout/watchdog routine.
+ * called once per second.
+ * checks to see that if activity was expected, that it hapenned.
+ * At present we only look to see if expected output was completed.
+ */
+static void
+ngsr_watchdog_frame(void * arg)
+{
+ struct sr_softc * sc = arg;
+ int s;
+ int speed;
+
+ if(sc->running == 0)
+ return; /* if we are not running let timeouts die */
+ /*
+ * calculate the apparent throughputs
+ * XXX a real hack
+ */
+ s = splimp();
+ speed = sc->inbytes - sc->lastinbytes;
+ sc->lastinbytes = sc->inbytes;
+ if ( sc->inrate < speed )
+ sc->inrate = speed;
+ speed = sc->outbytes - sc->lastoutbytes;
+ sc->lastoutbytes = sc->outbytes;
+ if ( sc->outrate < speed )
+ sc->outrate = speed;
+ sc->inlast++;
+ splx(s);
+
+ if ((sc->inlast > QUITE_A_WHILE)
+ && (sc->out_deficit > LOTS_OF_PACKETS)) {
+ log(LOG_ERR, "sr%d: No response from remote end\n", sc->unit);
+ s = splimp();
+ sr_down(sc);
+ sr_up(sc);
+ sc->inlast = sc->out_deficit = 0;
+ splx(s);
+ } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */
+ if (sc->out_dog == 0) {
+ log(LOG_ERR, "sr%d: Transmit failure.. no clock?\n",
+ sc->unit);
+ srwatchdog(sc);
+#if 0
+ s = splimp();
+ sr_down(sc);
+ sr_up(sc);
+ splx(s);
+#endif
+ sc->inlast = sc->out_deficit = 0;
+ } else {
+ sc->out_dog--;
+ }
+ }
+ sr_modemck(sc); /* update the DCD status */
+ sc->handle = timeout(ngsr_watchdog_frame, sc, hz);
+}
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
+/*
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngsr_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * give our ok for a hook to be added...
+ * If we are not running this should kick the device into life.
+ * We allow hooks called "control" and dlci[1-1023]
+ * The hook's private info points to our stash of info about that
+ * channel.
+ */
+static int
+ngsr_newhook(node_p node, hook_p hook, const char *name)
+{
+ struct sr_softc * sc = node->private;
+
+ /*
+ * check if it's our friend the debug hook
+ */
+ if (strcmp(name, NG_SR_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ sc->debug_hook = hook;
+ return (0);
+ }
+
+ /*
+ * Check for raw mode hook.
+ */
+ if (strcmp(name, NG_SR_HOOK_RAW) != 0) {
+ return (EINVAL);
+ }
+ hook->private = sc;
+ sc->hook = hook;
+ sc->datahooks++;
+ sr_up(sc);
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
+ */
+static int
+ngsr_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct sr_softc * sc;
+ int error = 0;
+
+ sc = node->private;
+ switch (msg->header.typecookie) {
+ case NG_SR_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n"
+ "highest rate seen: %ld B/S in, %ld B/S out\n",
+ sc->inbytes, sc->outbytes,
+ sc->inrate, sc->outrate);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ sc->oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld, %ld, %ld, %ld, %ld, %ld\n",
+ sc->ierrors[0],
+ sc->ierrors[1],
+ sc->ierrors[2],
+ sc->ierrors[3],
+ sc->ierrors[4],
+ sc->ierrors[5]);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NG_SR_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * get data from another node and transmit it to the correct channel
+ */
+static int
+ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int s;
+ int error = 0;
+ struct sr_softc * sc = hook->node->private;
+ struct ifqueue *xmitq_p;
+
+ /*
+ * data doesn't come in from just anywhere (e.g control hook)
+ */
+ if ( hook->private == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /*
+ * Now queue the data for when it can be sent
+ */
+ if (meta && meta->priority > 0) {
+ xmitq_p = (&sc->xmitq_hipri);
+ } else {
+ xmitq_p = (&sc->xmitq);
+ }
+ s = splimp();
+ if (IF_QFULL(xmitq_p)) {
+ IF_DROP(xmitq_p);
+ splx(s);
+ error = ENOBUFS;
+ goto bad;
+ }
+ IF_ENQUEUE(xmitq_p, m);
+ splx(s);
+ srstart(sc);
+ return (0);
+
+bad:
+ /*
+ * It was an error case.
+ * check if we need to free the mbuf, and then return the error
+ */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * do local shutdown processing..
+ * this node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngsr_rmnode(node_p node)
+{
+ struct sr_softc * sc = node->private;
+
+ sr_down(sc);
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngsr_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ * As the device still exists, the shutdown method will not actually
+ * destroy the node, but reset the device and leave it 'fresh' :)
+ *
+ * The node removal code will remove all references except that owned by the
+ * driver.
+ */
+static int
+ngsr_disconnect(hook_p hook)
+{
+ struct sr_softc * sc = hook->node->private;
+ int s;
+ /*
+ * If it's the data hook, then free resources etc.
+ */
+ if (hook->private) {
+ s = splimp();
+ sc->datahooks--;
+ if (sc->datahooks == 0)
+ sr_down(sc);
+ splx(s);
+ } else {
+ sc->debug_hook = NULL;
+ }
+ return (0);
+}
+
+/*
+ * called during bootup
+ * or LKM loading to put this type into the list of known modules
+ */
+static void
+ngsr_init(void *ignored)
+{
+ if (ng_newtype(&typestruct))
+ printf("ngsr install failed\n");
+ ngsr_done_init = 1;
+}
+#endif /* NETGRAPH */
+
/*
********************************* END ************************************
*/
diff --git a/sys/i386/isa/if_sr.h b/sys/i386/isa/if_sr.h
new file mode 100644
index 0000000..d01a2cb
--- /dev/null
+++ b/sys/i386/isa/if_sr.h
@@ -0,0 +1,23 @@
+/*
+ * if_sr.h
+ *
+ * Copyright (C) 1997-1999 Whistle Communications Inc.
+ * All rights reserved.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _I386_ISA_IF_SR_H_
+#define _I386_ISA_IF_SR_H_
+
+/* Node type name and type cookie */
+#define NG_SR_NODE_TYPE "sync_sr"
+#define NG_SR_COOKIE 860552148
+
+/* Netgraph hooks */
+#define NG_SR_HOOK_DEBUG "debug"
+#define NG_SR_HOOK_CONTROL "control"
+#define NG_SR_HOOK_RAW "rawdata"
+
+#endif /* _I386_ISA_IF_SR_H_ */
+
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index c2cfed5..7aa5221 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -3,8 +3,8 @@
# XXX present but broken: atapi ip_mroute_mod joy pcic
SUBDIR= aha al ax ccd cd9660 coda dm fdesc fxp if_disc if_ppp if_sl if_tun \
- ipfw kernfs md mfs mii msdos mx nfs ntfs nullfs pn portal procfs rl \
- sf sis sk ste ti tl umapfs union vn vr wb xl
+ ipfw kernfs md mfs mii msdos mx netgraph nfs ntfs nullfs pn portal \
+ procfs rl sf sis sk ste ti tl umapfs union vn vr wb xl
# XXX some of these can move to the general case when de-i386'ed
.if ${MACHINE_ARCH} == "i386"
diff --git a/sys/modules/netgraph/Makefile b/sys/modules/netgraph/Makefile
index a522813..1068590 100644
--- a/sys/modules/netgraph/Makefile
+++ b/sys/modules/netgraph/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 1999/01/24 06:48:37 archie Exp $
+# $Whistle: Makefile,v 1.5 1999/01/24 06:48:37 archie Exp $
# $FreeBSD$
SUBDIR= async cisco echo frame_relay hole iface lmi netgraph ppp rfc1490 \
diff --git a/sys/modules/netgraph/Makefile.inc b/sys/modules/netgraph/Makefile.inc
new file mode 100644
index 0000000..16ca171
--- /dev/null
+++ b/sys/modules/netgraph/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+# $Whistle: Makefile.inc,v 1.4 1999/01/19 23:46:16 archie Exp $
+
+.PATH: ${.CURDIR}/../../../netgraph
+CFLAGS+= -Wall
+
+.include "../Makefile.inc"
diff --git a/sys/modules/netgraph/UI/Makefile b/sys/modules/netgraph/UI/Makefile
new file mode 100644
index 0000000..cf7542f
--- /dev/null
+++ b/sys/modules/netgraph/UI/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:20 archie Exp $
+
+KMOD= ng_UI
+SRCS= ng_UI.c
+MAN8= ng_UI.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/UI/ng_UI.4 b/sys/modules/netgraph/UI/ng_UI.4
new file mode 100644
index 0000000..f432fc4
--- /dev/null
+++ b/sys/modules/netgraph/UI/ng_UI.4
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_UI.8,v 1.4 1999/01/25 02:37:56 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_UI 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_UI
+.Nd UI netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_UI.h>
+.Sh DESCRIPTION
+The
+.Nm UI
+node type has two hooks,
+.Dv upstream
+and
+.Dv downstream .
+Packets received on
+.Dv downstream
+must have 0x03 (indicating unnumbered information) as their first byte;
+if not the packet is dropped. This byte is then stripped and the
+remainder of the packet sent out on
+.Dv upstream .
+.Pp
+Conversely, packets received on
+.Dv upstream
+will have a 0x03 byte prepended to them before being forwarded out on the
+.Dv downstream
+hook.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv downstream
+Downstream connection. Packets on this side of the node have a 0x03 as
+their first byte.
+.It Dv upstream
+Upstream connection. Packets on this side of the node have the
+initial 0x03 byte stripped off.
+.El
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when both hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elischer <julian@whistle.com>
diff --git a/sys/modules/netgraph/UI/ng_UI.8 b/sys/modules/netgraph/UI/ng_UI.8
new file mode 100644
index 0000000..f432fc4
--- /dev/null
+++ b/sys/modules/netgraph/UI/ng_UI.8
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_UI.8,v 1.4 1999/01/25 02:37:56 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_UI 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_UI
+.Nd UI netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_UI.h>
+.Sh DESCRIPTION
+The
+.Nm UI
+node type has two hooks,
+.Dv upstream
+and
+.Dv downstream .
+Packets received on
+.Dv downstream
+must have 0x03 (indicating unnumbered information) as their first byte;
+if not the packet is dropped. This byte is then stripped and the
+remainder of the packet sent out on
+.Dv upstream .
+.Pp
+Conversely, packets received on
+.Dv upstream
+will have a 0x03 byte prepended to them before being forwarded out on the
+.Dv downstream
+hook.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv downstream
+Downstream connection. Packets on this side of the node have a 0x03 as
+their first byte.
+.It Dv upstream
+Upstream connection. Packets on this side of the node have the
+initial 0x03 byte stripped off.
+.El
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when both hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elischer <julian@whistle.com>
diff --git a/sys/modules/netgraph/async/Makefile b/sys/modules/netgraph/async/Makefile
new file mode 100644
index 0000000..507d0e4
--- /dev/null
+++ b/sys/modules/netgraph/async/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:20 archie Exp $
+
+KMOD= ng_async
+SRCS= ng_async.c
+MAN8= ng_async.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/async/ng_async.4 b/sys/modules/netgraph/async/ng_async.4
new file mode 100644
index 0000000..cddaa1b6
--- /dev/null
+++ b/sys/modules/netgraph/async/ng_async.4
@@ -0,0 +1,160 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_async.8,v 1.6 1999/01/25 23:46:25 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_ASYNC 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_async
+.Nd asynchronous framing netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_async.h>
+.Sh DESCRIPTION
+The
+.Nm async
+node type performs conversion between synchronous frames and
+asynchronous frames, as defined for the PPP protocol in RFC 1662.
+Asynchronous framing uses flag bytes and octet-stuffing
+to simulate a frame oriented connection over an octet-oriented
+asynchronous line.
+.Pp
+The node trasmits and receives asynchronous data on the
+.Dv async
+hook. Incoming data mbuf boundaries are ignored, while
+outgoing data is sent as a complete frame at a time.
+.Pp
+There are two synchronous hooks,
+.Dv sync
+and
+.Dv sync2 .
+For both hooks, received packets are encoded as asynchronous frames
+and sent out on
+.Dv async .
+Hook
+.Dv sync2
+differs from
+.Dv sync
+only in that any configured address and control field compression
+and/or control character escaping is disabled when the frame is encoded.
+This is useful for transmitting PPP LCP packets, which are always sent
+this way.
+.Pp
+This node supports ``flag sharing'' for packets transmitted on
+.Dv async .
+This is an optimization where the trailing flag byte
+of one frame is shared with the opening flag byte of the next.
+Flag sharing between frames is disabled after one second of transmit
+idle time.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv async
+Asynchronous connection.
+Typically this hook would be connected to a
+.Xr ng_tty 8
+node, which handles transmission of serial data over a tty device.
+.It Dv sync
+Synchronous connection. This hook sends and receives synchronous frames.
+For PPP, these frames contain no address, control, or checksum fields;
+each frame begins with the PPP protocol number. Typically this hook would
+be connected to the
+.Dv downstream
+hook of a
+.Xr ng_ppp 8
+type node.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_ASYNC_CMD_GET_STATS
+This command returns a
+.Dv "struct ng_async_stat"
+containing node statistics for packet, octet, and error counts.
+.It Dv NGM_ASYNC_CMD_CLR_STATS
+Clears the node statistics.
+.It Dv NGM_ASYNC_CMD_SET_CONFIG
+Sets the node configuration, which is described by a
+.Dv "struct ng_async_cfg" :
+.Bd -literal -offset 4n
+struct ng_async_cfg {
+ u_char enabled; /* Turn encoding on/off */
+ u_char acfcomp; /* Address/control field comp. */
+ u_int16_t amru; /* Max receive async frame len */
+ u_int16_t smru; /* Max receive sync frame len */
+ u_int32_t accm; /* ACCM encoding */
+};
+.Ed
+.Pp
+The
+.Dv enabled
+field enables or disables all encoding/decoding functions (default disabled).
+When disabled, the node operates in simple ``pass through'' mode. Setting
+.Dv acfcomp
+enables address and control field compression on transmission (for packets
+received on the
+.Dv sync
+hook only; default off).
+.Dv amru
+and
+.Dv smru
+are the asynchronous and synchronous MRU (maximum receive unit) values,
+respectively. These both default to 1600; note that the async MRU
+applies to the incoming frame length after asynchronous decoding.
+Finally,
+.Dv accm
+is the asynchronous character control map, which controls the escaping
+of characters 0x00 thorough 0x1f (default 0xffffffff).
+.It Dv NGM_ASYNC_CMD_GET_CONFIG
+This command returns the current configuration structure.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_ppp 8 ,
+.Xr ng_tty 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A W. Simpson
+.%T "PPP in HDLC-link Framing"
+.%O RFC 1662
+.Re
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/async/ng_async.8 b/sys/modules/netgraph/async/ng_async.8
new file mode 100644
index 0000000..cddaa1b6
--- /dev/null
+++ b/sys/modules/netgraph/async/ng_async.8
@@ -0,0 +1,160 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_async.8,v 1.6 1999/01/25 23:46:25 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_ASYNC 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_async
+.Nd asynchronous framing netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_async.h>
+.Sh DESCRIPTION
+The
+.Nm async
+node type performs conversion between synchronous frames and
+asynchronous frames, as defined for the PPP protocol in RFC 1662.
+Asynchronous framing uses flag bytes and octet-stuffing
+to simulate a frame oriented connection over an octet-oriented
+asynchronous line.
+.Pp
+The node trasmits and receives asynchronous data on the
+.Dv async
+hook. Incoming data mbuf boundaries are ignored, while
+outgoing data is sent as a complete frame at a time.
+.Pp
+There are two synchronous hooks,
+.Dv sync
+and
+.Dv sync2 .
+For both hooks, received packets are encoded as asynchronous frames
+and sent out on
+.Dv async .
+Hook
+.Dv sync2
+differs from
+.Dv sync
+only in that any configured address and control field compression
+and/or control character escaping is disabled when the frame is encoded.
+This is useful for transmitting PPP LCP packets, which are always sent
+this way.
+.Pp
+This node supports ``flag sharing'' for packets transmitted on
+.Dv async .
+This is an optimization where the trailing flag byte
+of one frame is shared with the opening flag byte of the next.
+Flag sharing between frames is disabled after one second of transmit
+idle time.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv async
+Asynchronous connection.
+Typically this hook would be connected to a
+.Xr ng_tty 8
+node, which handles transmission of serial data over a tty device.
+.It Dv sync
+Synchronous connection. This hook sends and receives synchronous frames.
+For PPP, these frames contain no address, control, or checksum fields;
+each frame begins with the PPP protocol number. Typically this hook would
+be connected to the
+.Dv downstream
+hook of a
+.Xr ng_ppp 8
+type node.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_ASYNC_CMD_GET_STATS
+This command returns a
+.Dv "struct ng_async_stat"
+containing node statistics for packet, octet, and error counts.
+.It Dv NGM_ASYNC_CMD_CLR_STATS
+Clears the node statistics.
+.It Dv NGM_ASYNC_CMD_SET_CONFIG
+Sets the node configuration, which is described by a
+.Dv "struct ng_async_cfg" :
+.Bd -literal -offset 4n
+struct ng_async_cfg {
+ u_char enabled; /* Turn encoding on/off */
+ u_char acfcomp; /* Address/control field comp. */
+ u_int16_t amru; /* Max receive async frame len */
+ u_int16_t smru; /* Max receive sync frame len */
+ u_int32_t accm; /* ACCM encoding */
+};
+.Ed
+.Pp
+The
+.Dv enabled
+field enables or disables all encoding/decoding functions (default disabled).
+When disabled, the node operates in simple ``pass through'' mode. Setting
+.Dv acfcomp
+enables address and control field compression on transmission (for packets
+received on the
+.Dv sync
+hook only; default off).
+.Dv amru
+and
+.Dv smru
+are the asynchronous and synchronous MRU (maximum receive unit) values,
+respectively. These both default to 1600; note that the async MRU
+applies to the incoming frame length after asynchronous decoding.
+Finally,
+.Dv accm
+is the asynchronous character control map, which controls the escaping
+of characters 0x00 thorough 0x1f (default 0xffffffff).
+.It Dv NGM_ASYNC_CMD_GET_CONFIG
+This command returns the current configuration structure.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_ppp 8 ,
+.Xr ng_tty 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A W. Simpson
+.%T "PPP in HDLC-link Framing"
+.%O RFC 1662
+.Re
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/cisco/Makefile b/sys/modules/netgraph/cisco/Makefile
new file mode 100644
index 0000000..2a8d5be
--- /dev/null
+++ b/sys/modules/netgraph/cisco/Makefile
@@ -0,0 +1,35 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:20 archie Exp $
+
+KMOD= ng_cisco
+SRCS= ng_cisco.c opt_inet.h opt_atalk.h opt_ipx.h
+MAN8= ng_cisco.8
+KMODDEPS= netgraph
+
+IFACE_INET?= 1 # 0/1 - requires INET configured in kernel
+IFACE_NETATALK?= 0 # 0/1 - requires NETATALK configured in kernel
+IFACE_IPX?= 0 # 0/1 - requires IPX configured in kernel
+
+CFLAGS+= ${PROTOS}
+
+CLEANFILES+= opt_inet.h opt_atalk.h opt_ipx.h
+
+opt_inet.h:
+ touch opt_inet.h
+.if ${IFACE_INET} > 0
+ echo "#define INET 1" > opt_inet.h
+.endif
+
+opt_atalk.h:
+ touch opt_atalk.h
+.if ${IFACE_NETATALK} > 0
+ echo "#define NETATALK ${IFACE_NETATALK}" > opt_atalk.h
+.endif
+
+opt_ipx.h:
+ touch opt_ipx.h
+.if ${IFACE_IPX} > 0
+ echo "#define IPX ${IFACE_IPX}" > opt_ipx.h
+.endif
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/cisco/ng_cisco.4 b/sys/modules/netgraph/cisco/ng_cisco.4
new file mode 100644
index 0000000..30523f8
--- /dev/null
+++ b/sys/modules/netgraph/cisco/ng_cisco.4
@@ -0,0 +1,159 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_cisco.8,v 1.5 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_CISCO 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_cisco
+.Nd Cisco HDLC protocol netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_cisco.h>
+.Sh DESCRIPTION
+The
+.Nm cisco
+node type performs encapsulation and de-encapsulation of packets
+using the Cisco HDLC protocol. This is a fairly simple
+protocol for the transmission of packets across
+high speed synchronous lines. Each packet is prepended with
+an Ethertype, indicating the protocol. There is also a
+``keep alive'' and an ``inquire'' capability.
+.Pp
+The
+.Dv downstream
+hook should connect to the synchronous line. On the other side
+of the node are the
+.Dv inet ,
+.Dv atalk ,
+and
+.Dv ipx
+hooks, which transmit and receive raw IP, AppleTalk, and IPX packets,
+respectively. Typically these hooks would connect to the corresponding
+hooks on an
+.Xr ng_iface 8
+type node.
+.Sh IP Configuration
+In order to function properly for IP traffic, the node must be informed
+of the local IP address and netmask setting. This is because the protocol
+includes an ``inquire'' packet which we must be prepared to answer.
+There are two ways to acomplish this, manually and automatically.
+.Pp
+Whenever such an inquire packet is received, the node sends a
+.Dv NGM_CISCO_GET_IPADDR
+control message to the peer node connected to the
+.Dv inet
+hook (if any).
+If the peer responds, then that response is used. This is the automatic method.
+.Pp
+If the peer does not respond, the node falls back on its cached value
+for the IP address and netmask. This cached value can be set at any time
+with a
+.Dv NGM_CISCO_SET_IPADDR
+message, and this is the manual method.
+.Pp
+If the
+.Dv inet
+hook is connected to the
+.Dv inet
+hook of an
+.Xr ng_iface 8
+node, as is usually the case, then configuration is automatic as the
+.Xr ng_iface 8
+understands the
+.Dv NGM_CISCO_GET_IPADDR
+message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazio
+.It Dv downstream
+The connection to the synchronous line.
+.It Dv inet
+IP hook.
+.It Dv atalk
+AppleTalk hook.
+.It Dv ipx
+IPX hook
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_CISCO_SET_IPADDR
+This command takes an array of two
+.Dv "struct in_addr"
+arguments. The first is the IP address of the corresponding interface
+and the second is the netmask.
+.It Dv NGM_CISCO_GET_IPADDR
+This command returns the IP configuration in the same format used by
+.Dv NGM_CISCO_SET_IPADDR .
+This command is also
+.Em sent
+by this node type to the
+.Dv inet
+peer whenever an IP address inquiry packet is received.
+.It Dv NGM_CISCO_GET_STATUS
+Returns a
+.Dv "struct ngciscostat" :
+.Bd -literal -offset 4n
+struct ngciscostat {
+ u_int32_t seq_retries; /* # unack'd retries */
+ u_int32_t keepalive_period; /* in seconds */
+};
+.Ed
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+Not all of the functionality has been implemented. For example,
+the node does not support querying the remote end for its IP address
+and netmask.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_iface 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A D. Perkins
+.%T "Requirements for an Internet Standard Point-to-Point Protocol"
+.%O RFC 1547
+.Re
+.Sh LEGAL
+Cisco is a trademark of Cisco Systems, Inc.
+.Sh AUTHORS
+Julian Elisher <julian@whistle.com>,
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/cisco/ng_cisco.8 b/sys/modules/netgraph/cisco/ng_cisco.8
new file mode 100644
index 0000000..30523f8
--- /dev/null
+++ b/sys/modules/netgraph/cisco/ng_cisco.8
@@ -0,0 +1,159 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_cisco.8,v 1.5 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_CISCO 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_cisco
+.Nd Cisco HDLC protocol netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_cisco.h>
+.Sh DESCRIPTION
+The
+.Nm cisco
+node type performs encapsulation and de-encapsulation of packets
+using the Cisco HDLC protocol. This is a fairly simple
+protocol for the transmission of packets across
+high speed synchronous lines. Each packet is prepended with
+an Ethertype, indicating the protocol. There is also a
+``keep alive'' and an ``inquire'' capability.
+.Pp
+The
+.Dv downstream
+hook should connect to the synchronous line. On the other side
+of the node are the
+.Dv inet ,
+.Dv atalk ,
+and
+.Dv ipx
+hooks, which transmit and receive raw IP, AppleTalk, and IPX packets,
+respectively. Typically these hooks would connect to the corresponding
+hooks on an
+.Xr ng_iface 8
+type node.
+.Sh IP Configuration
+In order to function properly for IP traffic, the node must be informed
+of the local IP address and netmask setting. This is because the protocol
+includes an ``inquire'' packet which we must be prepared to answer.
+There are two ways to acomplish this, manually and automatically.
+.Pp
+Whenever such an inquire packet is received, the node sends a
+.Dv NGM_CISCO_GET_IPADDR
+control message to the peer node connected to the
+.Dv inet
+hook (if any).
+If the peer responds, then that response is used. This is the automatic method.
+.Pp
+If the peer does not respond, the node falls back on its cached value
+for the IP address and netmask. This cached value can be set at any time
+with a
+.Dv NGM_CISCO_SET_IPADDR
+message, and this is the manual method.
+.Pp
+If the
+.Dv inet
+hook is connected to the
+.Dv inet
+hook of an
+.Xr ng_iface 8
+node, as is usually the case, then configuration is automatic as the
+.Xr ng_iface 8
+understands the
+.Dv NGM_CISCO_GET_IPADDR
+message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazio
+.It Dv downstream
+The connection to the synchronous line.
+.It Dv inet
+IP hook.
+.It Dv atalk
+AppleTalk hook.
+.It Dv ipx
+IPX hook
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_CISCO_SET_IPADDR
+This command takes an array of two
+.Dv "struct in_addr"
+arguments. The first is the IP address of the corresponding interface
+and the second is the netmask.
+.It Dv NGM_CISCO_GET_IPADDR
+This command returns the IP configuration in the same format used by
+.Dv NGM_CISCO_SET_IPADDR .
+This command is also
+.Em sent
+by this node type to the
+.Dv inet
+peer whenever an IP address inquiry packet is received.
+.It Dv NGM_CISCO_GET_STATUS
+Returns a
+.Dv "struct ngciscostat" :
+.Bd -literal -offset 4n
+struct ngciscostat {
+ u_int32_t seq_retries; /* # unack'd retries */
+ u_int32_t keepalive_period; /* in seconds */
+};
+.Ed
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+Not all of the functionality has been implemented. For example,
+the node does not support querying the remote end for its IP address
+and netmask.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_iface 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A D. Perkins
+.%T "Requirements for an Internet Standard Point-to-Point Protocol"
+.%O RFC 1547
+.Re
+.Sh LEGAL
+Cisco is a trademark of Cisco Systems, Inc.
+.Sh AUTHORS
+Julian Elisher <julian@whistle.com>,
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/echo/Makefile b/sys/modules/netgraph/echo/Makefile
new file mode 100644
index 0000000..0c33d2f
--- /dev/null
+++ b/sys/modules/netgraph/echo/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:20 archie Exp $
+
+KMOD= ng_echo
+SRCS= ng_echo.c
+MAN8= ng_echo.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/echo/ng_echo.4 b/sys/modules/netgraph/echo/ng_echo.4
new file mode 100644
index 0000000..33ca729
--- /dev/null
+++ b/sys/modules/netgraph/echo/ng_echo.4
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_echo.8,v 1.4 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_ECHO 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_echo
+.Nd netgraph echo node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_echo.h>
+.Sh DESCRIPTION
+The
+.Nm echo
+node type reflects all data and control messages back to the sender.
+This node type is used for testing and debugging.
+.Sh HOOKS
+.Nm Echo
+nodes accept any request to connect, regardless of the hook name,
+as long as the name is unique.
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+Any other control messages are reflected back to the sender.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_hole 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/echo/ng_echo.8 b/sys/modules/netgraph/echo/ng_echo.8
new file mode 100644
index 0000000..33ca729
--- /dev/null
+++ b/sys/modules/netgraph/echo/ng_echo.8
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_echo.8,v 1.4 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_ECHO 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_echo
+.Nd netgraph echo node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_echo.h>
+.Sh DESCRIPTION
+The
+.Nm echo
+node type reflects all data and control messages back to the sender.
+This node type is used for testing and debugging.
+.Sh HOOKS
+.Nm Echo
+nodes accept any request to connect, regardless of the hook name,
+as long as the name is unique.
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+Any other control messages are reflected back to the sender.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_hole 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/frame_relay/Makefile b/sys/modules/netgraph/frame_relay/Makefile
new file mode 100644
index 0000000..3c0117a
--- /dev/null
+++ b/sys/modules/netgraph/frame_relay/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.1 1999/01/19 19:39:21 archie Exp $
+
+KMOD= ng_frame_relay
+SRCS= ng_frame_relay.c
+MAN8= ng_frame_relay.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/frame_relay/ng_frame_relay.4 b/sys/modules/netgraph/frame_relay/ng_frame_relay.4
new file mode 100644
index 0000000..790676d
--- /dev/null
+++ b/sys/modules/netgraph/frame_relay/ng_frame_relay.4
@@ -0,0 +1,93 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_frame_relay.8,v 1.4 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_FRAME_RELAY 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_frame_relay
+.Nd Frame relay netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_frame_relay.h>
+.Sh DESCRIPTION
+The
+.Nm frame_relay
+node type performs encapsulation, de-encapsulation, and multiplexing
+of packets using the frame relay protocol. It supports up to 1024 DLCI's.
+The LMI protocol is handled by a separate node type (see
+.Xr ng_lmi 8 ).
+.Pp
+The
+.Dv downstream
+hook should be connected to the synchronous line, i.e., the switch.
+Then hooks
+.Dv dlci0 ,
+.Dv dlci1 ,
+through
+.Dv dlci1023
+are available to connect to each of the DLCI channels.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv downstream
+The connection to the synchronous line.
+.It Dv dlciX
+Here X is a decimal number from 0 to 1023. This hook corresponds
+to the DLCI X frame relay virtual channel.
+.El
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+Technically, frames on DLCI X should not be transmitted to the switch
+until the LMI protocol entity on both ends has configured DLCI X as active.
+The
+.Nm frame_relay
+node type ignores this restriction, and will always pass data received
+on a DLCI hook to
+.Dv downstream .
+Instead, it should query the LMI node first.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_lmi 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/frame_relay/ng_frame_relay.8 b/sys/modules/netgraph/frame_relay/ng_frame_relay.8
new file mode 100644
index 0000000..790676d
--- /dev/null
+++ b/sys/modules/netgraph/frame_relay/ng_frame_relay.8
@@ -0,0 +1,93 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_frame_relay.8,v 1.4 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_FRAME_RELAY 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_frame_relay
+.Nd Frame relay netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_frame_relay.h>
+.Sh DESCRIPTION
+The
+.Nm frame_relay
+node type performs encapsulation, de-encapsulation, and multiplexing
+of packets using the frame relay protocol. It supports up to 1024 DLCI's.
+The LMI protocol is handled by a separate node type (see
+.Xr ng_lmi 8 ).
+.Pp
+The
+.Dv downstream
+hook should be connected to the synchronous line, i.e., the switch.
+Then hooks
+.Dv dlci0 ,
+.Dv dlci1 ,
+through
+.Dv dlci1023
+are available to connect to each of the DLCI channels.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv downstream
+The connection to the synchronous line.
+.It Dv dlciX
+Here X is a decimal number from 0 to 1023. This hook corresponds
+to the DLCI X frame relay virtual channel.
+.El
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+Technically, frames on DLCI X should not be transmitted to the switch
+until the LMI protocol entity on both ends has configured DLCI X as active.
+The
+.Nm frame_relay
+node type ignores this restriction, and will always pass data received
+on a DLCI hook to
+.Dv downstream .
+Instead, it should query the LMI node first.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_lmi 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/hole/Makefile b/sys/modules/netgraph/hole/Makefile
new file mode 100644
index 0000000..f7408c1
--- /dev/null
+++ b/sys/modules/netgraph/hole/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:21 archie Exp $
+
+KMOD= ng_hole
+SRCS= ng_hole.c
+MAN8= ng_hole.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/hole/ng_hole.4 b/sys/modules/netgraph/hole/ng_hole.4
new file mode 100644
index 0000000..4d34eb5
--- /dev/null
+++ b/sys/modules/netgraph/hole/ng_hole.4
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_hole.8,v 1.4 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_HOLE 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_hole
+.Nd netgraph discard node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_hole.h>
+.Sh DESCRIPTION
+The
+.Nm hole
+node type silently discards all data and control messages it receives.
+This type is used for testing and debugging.
+.Sh HOOKS
+.Nm Hole
+nodes accept any request to connect, regardless of the hook name,
+as long as the name is unique.
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+Other control messages are silently discarded.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_echo 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/hole/ng_hole.8 b/sys/modules/netgraph/hole/ng_hole.8
new file mode 100644
index 0000000..4d34eb5
--- /dev/null
+++ b/sys/modules/netgraph/hole/ng_hole.8
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_hole.8,v 1.4 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_HOLE 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_hole
+.Nd netgraph discard node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_hole.h>
+.Sh DESCRIPTION
+The
+.Nm hole
+node type silently discards all data and control messages it receives.
+This type is used for testing and debugging.
+.Sh HOOKS
+.Nm Hole
+nodes accept any request to connect, regardless of the hook name,
+as long as the name is unique.
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+Other control messages are silently discarded.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_echo 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/iface/Makefile b/sys/modules/netgraph/iface/Makefile
new file mode 100644
index 0000000..a761069
--- /dev/null
+++ b/sys/modules/netgraph/iface/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:21 archie Exp $
+
+KMOD= ng_iface
+SRCS= ng_iface.c bpfilter.h opt_inet.h opt_atalk.h opt_ipx.h
+MAN8= ng_iface.8
+KMODDEPS= netgraph
+
+IFACE_FILTER?= 0 # 0/1 - requires bpf configured in kernel
+IFACE_INET?= 1 # 0/1 - requires INET configured in kernel
+IFACE_NETATALK?= 0 # 0/1 - requires NETATALK configured in kernel
+IFACE_IPX?= 0 # 0/1 - requires IPX configured in kernel
+
+CFLAGS+= ${PROTOS}
+
+CLEANFILES+= bpfilter.h opt_inet.h opt_atalk.h opt_ipx.h
+
+bpfilter.h:
+ echo "#define NBPFILTER ${IFACE_FILTER}" > bpfilter.h
+
+opt_inet.h:
+ touch opt_inet.h
+.if ${IFACE_INET} > 0
+ echo "#define INET 1" > opt_inet.h
+.endif
+
+opt_atalk.h:
+ touch opt_atalk.h
+.if ${IFACE_NETATALK} > 0
+ echo "#define NETATALK ${IFACE_NETATALK}" > opt_atalk.h
+.endif
+
+opt_ipx.h:
+ touch opt_ipx.h
+.if ${IFACE_IPX} > 0
+ echo "#define IPX ${IFACE_IPX}" > opt_ipx.h
+.endif
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/iface/ng_iface.4 b/sys/modules/netgraph/iface/ng_iface.4
new file mode 100644
index 0000000..77167e6
--- /dev/null
+++ b/sys/modules/netgraph/iface/ng_iface.4
@@ -0,0 +1,126 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_iface.8,v 1.5 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_IFACE 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_iface
+.Nd interface netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_iface.h>
+.Sh DESCRIPTION
+An
+.Nm iface
+node is both a netgraph node and a system networking interface. When an
+.Nm iface
+node is created, a new point-to-point interface appears which is accessible via
+.Xr ifconfig 8 .
+The new interfaces are named
+.Dv ng0 ,
+.Dv ng1 ,
+etc. The node is assigned the same name as its interface, unless the name
+already exists, in which case the node remains unnamed.
+.Pp
+.Nm Iface
+nodes have a single hook corresponding to each supported protocol.
+Packets transmitted via the interface flow out the corresponding
+protocol-specific hook.
+Similarly, packets received on a hook appear on the interface as
+packets received in the corresponding protocol.
+.Pp
+The currently supported protocols are IP, IPX, AppleTalk, and NS.
+In the KLD module, only support for IP is compiled in by default.
+.Pp
+.Nm Iface
+nodes support the Berkeley Packet Filter (BPF).
+In the KLD module, this support is disabled by default.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv inet
+Transmission and reception of IP packets.
+.It Dv ipx
+Transmission and reception of IPX packets.
+.It Dv atalk
+Transmission and reception of AppleTalk packets.
+.It Dv ns
+Transmission and reception of NS packets.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_IFACE_GET_IFNAME
+Returns the name of the interface corresponding to this node in a
+.Dv "struct ng_iface_ifname" :
+.Bd -literal -offset 4n
+struct ng_iface_ifname {
+ char ngif_name[NG_IFACE_IFACE_NAME_MAX + 1];
+};
+.Ed
+.It Dv NGM_IFACE_GET_IFADDRS
+Returns the list of addresses associated with this interface.
+The list is returned in the same format as the
+.Dv SIOCGIFCONF
+ioctl().
+.It Dv NGM_CISCO_GET_IPADDR
+This message is defined by the
+.Xr ng_cisco 8
+node type; see
+.Xr ng_cisco 8
+for a description.
+.El
+.Sh SHUTDOWN
+Because it is currenly not possible to remove a system networking
+interface in FreeBSD,
+.Nm iface
+nodes are
+.Em persistent.
+That is, once created they are never destroyed.
+The receipt of a
+.Dv NGM_SHUTDOWN
+control message disconnects all hooks but does not remove the node.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr bpf 4 ,
+.Xr ng_cisco 8 ,
+.Xr ng_rfc1490 8 ,
+.Xr ngctl 8 ,
+.Xr ifconfig 8 .
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/iface/ng_iface.8 b/sys/modules/netgraph/iface/ng_iface.8
new file mode 100644
index 0000000..77167e6
--- /dev/null
+++ b/sys/modules/netgraph/iface/ng_iface.8
@@ -0,0 +1,126 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_iface.8,v 1.5 1999/01/25 23:46:26 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_IFACE 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_iface
+.Nd interface netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_iface.h>
+.Sh DESCRIPTION
+An
+.Nm iface
+node is both a netgraph node and a system networking interface. When an
+.Nm iface
+node is created, a new point-to-point interface appears which is accessible via
+.Xr ifconfig 8 .
+The new interfaces are named
+.Dv ng0 ,
+.Dv ng1 ,
+etc. The node is assigned the same name as its interface, unless the name
+already exists, in which case the node remains unnamed.
+.Pp
+.Nm Iface
+nodes have a single hook corresponding to each supported protocol.
+Packets transmitted via the interface flow out the corresponding
+protocol-specific hook.
+Similarly, packets received on a hook appear on the interface as
+packets received in the corresponding protocol.
+.Pp
+The currently supported protocols are IP, IPX, AppleTalk, and NS.
+In the KLD module, only support for IP is compiled in by default.
+.Pp
+.Nm Iface
+nodes support the Berkeley Packet Filter (BPF).
+In the KLD module, this support is disabled by default.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv inet
+Transmission and reception of IP packets.
+.It Dv ipx
+Transmission and reception of IPX packets.
+.It Dv atalk
+Transmission and reception of AppleTalk packets.
+.It Dv ns
+Transmission and reception of NS packets.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_IFACE_GET_IFNAME
+Returns the name of the interface corresponding to this node in a
+.Dv "struct ng_iface_ifname" :
+.Bd -literal -offset 4n
+struct ng_iface_ifname {
+ char ngif_name[NG_IFACE_IFACE_NAME_MAX + 1];
+};
+.Ed
+.It Dv NGM_IFACE_GET_IFADDRS
+Returns the list of addresses associated with this interface.
+The list is returned in the same format as the
+.Dv SIOCGIFCONF
+ioctl().
+.It Dv NGM_CISCO_GET_IPADDR
+This message is defined by the
+.Xr ng_cisco 8
+node type; see
+.Xr ng_cisco 8
+for a description.
+.El
+.Sh SHUTDOWN
+Because it is currenly not possible to remove a system networking
+interface in FreeBSD,
+.Nm iface
+nodes are
+.Em persistent.
+That is, once created they are never destroyed.
+The receipt of a
+.Dv NGM_SHUTDOWN
+control message disconnects all hooks but does not remove the node.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr bpf 4 ,
+.Xr ng_cisco 8 ,
+.Xr ng_rfc1490 8 ,
+.Xr ngctl 8 ,
+.Xr ifconfig 8 .
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/lmi/Makefile b/sys/modules/netgraph/lmi/Makefile
new file mode 100644
index 0000000..9b4c07e
--- /dev/null
+++ b/sys/modules/netgraph/lmi/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.1 1999/01/19 19:39:21 archie Exp $
+
+KMOD= ng_lmi
+SRCS= ng_lmi.c
+MAN8= ng_lmi.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/lmi/ng_lmi.4 b/sys/modules/netgraph/lmi/ng_lmi.4
new file mode 100644
index 0000000..fc0ba24
--- /dev/null
+++ b/sys/modules/netgraph/lmi/ng_lmi.4
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_lmi.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_LMI 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_lmi
+.Nd Frame relay LMI protocol netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_lmi.h>
+.Sh DESCRIPTION
+The
+.Nm lmi
+node type performs the frame relay LMI protocol. It supports
+the ITU Annex A, ANSI Annex D, and Group-of-four LMI types.
+It also supports auto-detection of the LMI type.
+.Pp
+To enable a specific LMI type, connect the corresponding hook (
+.Dv annexA ,
+.Dv annexD ,
+or
+.Dv group4 ")"
+to DLCI 0 or 1023 of a
+.Xr ng_frame_relay 8
+node.
+Typically, Annex A and Annex D live on DLCI 0 while Group-of-four
+lives on DLCI 1023.
+.Pp
+To enable LMI type auto-detection, connect the
+.Dv auto0
+hook to DLCI 0 and the
+.Dv auto1023
+hook to DLCI 1023. The node will attempt to automatically determine
+which LMI type is running at the switch, and go into that mode.
+.Pp
+Only one fixed LMI type, or auto-detection, can be active at any given time.
+.Pp
+The
+.Dv NGM_LMI_GET_STATUS
+control message can be used at any time to query the current status
+of the LMI protocol and each DLCI channel. This node also supports the
+.Dv NGM_TEXT_STATUS
+control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbaz
+.It Dv annexA
+ITU Annex A LMI hook.
+.It Dv annexD
+ANSI Annex D LMI hook.
+.It Dv group4
+Group-of-four LMI hook.
+.It Dv auto0
+Auto-detection hook for DLCI 0.
+.It Dv auto1023
+Auto-detection hook for DLCI 1023.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_LMI_GET_STATUS
+This command returns status information in a
+.Dv "struct nglmistat" :
+.Bd -literal -offset 4n
+#define NGM_LMI_STAT_ARYSIZE (1024/8)
+
+struct nglmistat {
+ u_char proto[12]; /* Active proto (same as hook name) */
+ u_char hook[12]; /* Active hook */
+ u_char fixed; /* If set to fixed LMI mode */
+ u_char autod; /* If currently auto-detecting */
+ u_char seen[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs seen */
+ u_char up[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs up */
+};
+.Ed
+.It Dv NGM_TEXT_STATUS
+This generic message returns is a human-readable version of the node status.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_frame_relay 8 ,
+.Xr ngctl 8 .
+.Rs
+.%T "ANSI T1.617-1991 Annex D"
+.Re
+.Rs
+.%T "ITU-T Q.933 Digital Subscriber Signalling System No. 1 - Signalling Specification for Frame Mode Basic Call Control, Annex A"
+.Re
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/lmi/ng_lmi.8 b/sys/modules/netgraph/lmi/ng_lmi.8
new file mode 100644
index 0000000..fc0ba24
--- /dev/null
+++ b/sys/modules/netgraph/lmi/ng_lmi.8
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_lmi.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_LMI 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_lmi
+.Nd Frame relay LMI protocol netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_lmi.h>
+.Sh DESCRIPTION
+The
+.Nm lmi
+node type performs the frame relay LMI protocol. It supports
+the ITU Annex A, ANSI Annex D, and Group-of-four LMI types.
+It also supports auto-detection of the LMI type.
+.Pp
+To enable a specific LMI type, connect the corresponding hook (
+.Dv annexA ,
+.Dv annexD ,
+or
+.Dv group4 ")"
+to DLCI 0 or 1023 of a
+.Xr ng_frame_relay 8
+node.
+Typically, Annex A and Annex D live on DLCI 0 while Group-of-four
+lives on DLCI 1023.
+.Pp
+To enable LMI type auto-detection, connect the
+.Dv auto0
+hook to DLCI 0 and the
+.Dv auto1023
+hook to DLCI 1023. The node will attempt to automatically determine
+which LMI type is running at the switch, and go into that mode.
+.Pp
+Only one fixed LMI type, or auto-detection, can be active at any given time.
+.Pp
+The
+.Dv NGM_LMI_GET_STATUS
+control message can be used at any time to query the current status
+of the LMI protocol and each DLCI channel. This node also supports the
+.Dv NGM_TEXT_STATUS
+control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbaz
+.It Dv annexA
+ITU Annex A LMI hook.
+.It Dv annexD
+ANSI Annex D LMI hook.
+.It Dv group4
+Group-of-four LMI hook.
+.It Dv auto0
+Auto-detection hook for DLCI 0.
+.It Dv auto1023
+Auto-detection hook for DLCI 1023.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_LMI_GET_STATUS
+This command returns status information in a
+.Dv "struct nglmistat" :
+.Bd -literal -offset 4n
+#define NGM_LMI_STAT_ARYSIZE (1024/8)
+
+struct nglmistat {
+ u_char proto[12]; /* Active proto (same as hook name) */
+ u_char hook[12]; /* Active hook */
+ u_char fixed; /* If set to fixed LMI mode */
+ u_char autod; /* If currently auto-detecting */
+ u_char seen[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs seen */
+ u_char up[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs up */
+};
+.Ed
+.It Dv NGM_TEXT_STATUS
+This generic message returns is a human-readable version of the node status.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_frame_relay 8 ,
+.Xr ngctl 8 .
+.Rs
+.%T "ANSI T1.617-1991 Annex D"
+.Re
+.Rs
+.%T "ITU-T Q.933 Digital Subscriber Signalling System No. 1 - Signalling Specification for Frame Mode Basic Call Control, Annex A"
+.Re
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/netgraph/Makefile b/sys/modules/netgraph/netgraph/Makefile
new file mode 100644
index 0000000..eb37f19
--- /dev/null
+++ b/sys/modules/netgraph/netgraph/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:22 archie Exp $
+
+KMOD= netgraph
+SRCS= ng_base.c
+MAN4= netgraph.4
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/netgraph/netgraph.4 b/sys/modules/netgraph/netgraph/netgraph.4
new file mode 100644
index 0000000..c90650e0
--- /dev/null
+++ b/sys/modules/netgraph/netgraph/netgraph.4
@@ -0,0 +1,876 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Authors: Julian Elischer <julian@whistle.com>
+.\" Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: netgraph.4,v 1.7 1999/01/28 23:54:52 julian Exp $
+.\"
+.Dd January 19, 1999
+.Dt NETGRAPH 4
+.Os FreeBSD
+.Sh NAME
+.Nm netgraph
+.Nd graph based kernel networking subsystem
+.Sh DESCRIPTION
+The
+.Nm
+system provides a uniform and modular system for the implementation
+of kernel objects which perform various networking functions. The objects,
+known as
+.Em nodes ,
+can be arranged into arbitrarily complicated graphs. Nodes have
+.Em hooks
+which are used to connect two nodes together, forming the edges in the graph.
+Nodes communicate along the edges to process data, implement protocols, etc.
+.Pp
+The aim of
+.Nm
+is to supplement rather than replace the existing kernel networking
+infrastructure. It provides:
+.Pp
+.Bl -bullet -compact -offset 2n
+.It
+A flexible way of combining protocol and link level drivers
+.It
+A modular way to implement new protocols
+.It
+A common framework for kernel entities to inter-communicate
+.It
+A reasonably fast, kernel-based implementation
+.El
+.Sh Nodes and Types
+The most fundamental concept in
+.Nm
+is that of a
+.Em node .
+All nodes implement a number of predefined methods which allow them
+to interact with other nodes in a well defined manner.
+.Pp
+Each node has a
+.Em type ,
+which is a static property of the node determined at node creation time.
+A node's type is described by a unique ASCII type name.
+The type implies what the node does and how it may be connected
+to other nodes.
+.Pp
+In object-oriented language, types are classes and nodes are instances
+of their respective class. All node types are subclasses of the generic node
+type, and hence inherit certain common functionality and capabilities
+(e.g., the ability to have an ASCII name).
+.Pp
+Nodes may be assigned a globally unique ASCII name which can be
+used to refer to the node.
+The name must not contain the characters ``.'' or ``:'' and is limited to
+.Dv "NG_NODELEN + 1"
+characters (including NUL byte).
+.Pp
+Each node instance has a unique
+.Em ID number
+which is expressed as a 32-bit hex value. This value may be used to
+refer to a node when there is no ASCII name assigned to it.
+.Sh Hooks
+Nodes are connected to other nodes by connecting a pair of
+.Em hooks ,
+one from each node. Data flows bidirectionally between nodes along
+connected pairs of hooks. A node may have as many hooks as it
+needs, and may assign whatever meaning it wants to a hook.
+.Pp
+Hooks have these properties:
+.Pp
+.Bl -bullet -compact -offset 2n
+.It
+A hook has an ASCII name which is unique among all hooks
+on that node (other hooks on other nodes may have the same name).
+The name must not contain a ``.'' or a ``:'' and is
+limited to
+.Dv "NG_HOOKLEN + 1"
+characters (including NUL byte).
+.It
+A hook is always connected to another hook. That is, hooks are
+created at the time they are connected, and breaking an edge by
+removing either hook destroys both hooks.
+.El
+.Pp
+A node may decide to assign special meaning to some hooks.
+For example, connecting to the hook named ``debug'' might trigger
+the node to start sending debugging information to that hook.
+.Sh Data Flow
+Two types of information flow between nodes: data messages and
+control messages. Data messages are passed in mbuf chains along the edges
+in the graph, one edge at a time. The first mbuf in a chain must have the
+.Dv M_PKTHDR
+flag set. Each node decides how to handle data coming in on its hooks.
+.Pp
+Control messages are type-specific structures sent from one node directly
+to an arbitrary other node. There are two ways to address such a message. If
+there is a sequence of edges connecting the two nodes, the message
+may be ``source routed'' by specifying the corresponding sequence
+of hooks as the destination address for the message (relative
+addressing). Otherwise, the recipient node global ASCII name
+(or equivalent ID based name) is used as the destination address
+for the message (absolute addressing). The two types of addressing
+may be combined, by specifying an absolute start node and a sequence
+of hooks.
+.Pp
+Messages often represent commands that are followed by a reply message
+in the reverse direction. To facilitate this, the recipient of a
+control message is supplied with a ``return address'' that is suitable
+for addressing a reply.
+.Pp
+Each control message contains a 32 bit value called a
+.Em typecookie
+indicating the type of the message, i.e., how to interpret it.
+Typically each type defines a unique typecookie for the messages
+that it understands. However, a node may choose to recognize and
+implement more than one type of message.
+.Sh Netgraph is Functional
+In order to minimize latency, most
+.Nm netgraph
+operations are functional.
+That is, data and control messages are delivered by making function
+calls rather than by using queues and mailboxes. For example, if node
+A wishes to send a data mbuf to neighboring node B, it calls the
+generic
+.Nm
+data delivery function. This function in turn locates
+node B and calls B's ``receive data'' method. While this mode of operation
+results in good performance, it has a few implications for node
+developers:
+.Pp
+.Bl -bullet -compact -offset 2n
+.It
+Whenever a node delivers a data or control message, the node
+may need to allow for the possibility of receiving a returning message
+before the original delivery function call returns.
+.It
+Netgraph nodes and support routines generally run at
+.Dv "splnet()" .
+However, some nodes may want to send data and control messages
+from a different priority level. Netgraph supplies queueing routines which
+utilize the NETISR system to move message delivery to
+.Dv "splnet()" .
+Note that messages are always received at
+.Dv "splnet()" .
+.It
+It's possible for an infinite loop to occur if the graph contains cycles.
+.El
+.Pp
+So far, these issues have not proven problematical in practice.
+.Sh Interaction With Other Parts of the Kernel
+A node may have a hidden interaction with other components of the
+kernel outside of the
+.Nm
+subsystem, such as device hardware,
+kernel protocol stacks, etc. In fact, one of the benefits of
+.Nm
+is the ability to join disparate kernel networking entities together in a
+consistent communication framework.
+.Pp
+An example is the node type
+.Em socket
+which is both a netgraph node and a
+.Xr socket 2
+BSD socket in the protocol family
+.Dv PF_NETGRAPH .
+Socket nodes allow user processes to participate in
+.Nm netgraph .
+Other nodes communicate with socket nodes using the usual methods, and the
+node hides the fact that it is also passing information to and from a
+cooperating user process.
+.Pp
+Another example is a device driver that presents
+a node interface to the hardware.
+.Sh Node Methods
+Nodes are notified of the following actions via function calls
+to the following node methods (all at
+.Dv "splnet()" )
+and may accept or reject that action (by returning the appropriate
+error code):
+.Bl -tag -width xxx
+.It Creation of a new node
+The constructor for the type is called. If creation of a new node is
+allowed, the constructor must call the generic node creation
+function (in object-oriented terms, the superclass constructor)
+and then allocate any special resources it needs. For nodes that
+correspond to hardware, this is typically done during the device
+attach routine. Often a global ASCII name corresponding to the
+device name is assigned here as well.
+.It Creation of a new hook
+The hook is created and tentatively
+linked to the node, and the node is told about the name that will be
+used to describe this hook. The node sets up any special data structures
+it needs, or may reject the connection, based on the name of the hook.
+.It Successful connection of two hooks
+After both ends have accepted their
+hooks, and the links have been made, the nodes get a chance to
+find out who their peer is across the link and can then decide to reject
+the connection. Tear-down is automatic.
+.It Destruction of a hook
+The node is notified of a broken connection. The node may consider some hooks
+to be critical to operation and others to be expendable: the disconnection
+of one hook may be an acceptable event while for another it
+may effect a total shutdown for the node.
+.It Shutdown of a node
+This method allows a node to clean up
+and to ensure that any actions that need to be performed
+at this time are taken. The method must call the generic (i.e., superclass)
+node destructor to get rid of the generic components of the node.
+Some nodes (usually associated with a piece of hardware) may be
+.Em persistent
+in that a shutdown breaks all edges and resets the node,
+but doesn't remove it, in which case the generic destructor is not called.
+.El
+.Sh Sending and Receiving Data
+Three other methods are also supported by all nodes:
+.Bl -tag -width xxx
+.It Receive data message
+An mbuf chain is passed to the node.
+The node is notified on which hook the data arrived,
+and can use this information in its processing decision.
+The node must must always
+.Dv m_freem()
+the mbuf chain on completion or error, or pass it on to another node
+(or kernel module) which will then be responsible for freeing it.
+.Pp
+In addition to the mbuf chain itself there is also a pointer to a
+structure describing meta-data about the message
+(e.g. priority information). This pointer may be
+.Dv NULL
+if there is no additional information. The format for this information is
+described in
+.Dv netgraph.h .
+The memory for meta-data must allocated via
+.Dv malloc()
+with type
+.Dv M_NETGRAPH .
+As with the data itself, it is the receiver's responsibility to
+.Dv free()
+the meta-data. If the mbuf chain is freed the meta-data must
+be freed at the same time. If the meta-data is freed but the
+real data on is passed on, then a
+.Dv NULL
+pointer must be substituted.
+.Pp
+The receiving node may decide to defer the data by queueing it in the
+.Nm
+NETISR system (see below).
+.Pp
+The structure and use of meta-data is still experimental, but is presently used in
+frame-relay to indicate that management packets should be queued for transmission
+at a higher priority than data packets. This is required for
+conformance with Frame Relay standards.
+.Pp
+.It Receive queued data message
+Usually this will be the same function as
+.Em Receive data message.
+This is the entry point called when a data message is being handed to
+the node after having been queued in the NETISR system.
+This allows a node to decide in the
+.Em Receive data message
+method that a message should be defered and queued,
+and be sure that when it is processed from the queue,
+it will not be queued again.
+.It Receive control message
+This method is called when a control message is addressed to the node.
+A return address is always supplied, giving the address of the node
+that originated the message so a reply message can be sent anytime later.
+.Pp
+It is possible for a synchronous reply to be made, and in fact this
+is more common in practice.
+This is done by setting a pointer (supplied as an extra function parameter)
+to point to the reply.
+Then when the control message delivery function returns,
+the caller can check if this pointer has been made non-NULL,
+and if so then it points to the reply message allocated via
+.Dv malloc()
+and containing the synchronous response. In both directions,
+(request and response) it is up to the
+receiver of that message to
+.Dv free()
+the control message buffer. All control messages and replies are
+allocated with
+.Dv malloc()
+type
+.Dv M_NETGRAPH .
+.El
+.Pp
+Much use has been made of reference counts, so that nodes being
+free'd of all references are automatically freed, and this behaviour
+has been tested and debugged to present a consistent and trustworthy
+framework for the ``type module'' writer to use.
+.Sh Addressing
+The
+.Nm
+framework provides an unambiguous and simple to use method of specifically
+addressing any single node in the graph. The naming of a node is
+independent of its type, in that another node, or external component
+need not know anything about the node's type in order to address it so as
+to send it a generic message type. Node and hook names should be
+chosen so as to make addresses meaningful.
+.Pp
+Addresses are either absolute or relative. An absolute address begins
+with a node name, (or ID), followed by a colon, followed by a sequence of hook
+names separated by periods. This addresses the node reached by starting
+at the named node and following the specified sequence of hooks.
+A relative address includes only the sequence of hook names, implicitly
+starting hook traversal at the local node.
+.Pp
+There are a couple of special possibilities for the node name.
+The name ``.'' (refered to as ``.:'') always refers to the local node.
+Also, nodes that have no global name may be addressed by their ID numbers,
+by enclosing the hex representation of the ID number within square brackets.
+Here are some examples of valid netgraph addresses:
+.Bd -literal -offset 4n -compact
+
+ .:
+ foo:
+ .:hook1
+ foo:hook1.hook2
+ [f057cd80]:hook1
+.Ed
+.Pp
+Consider the following set of nodes might be created for a site with
+a single physical frame relay line having two active logical DLCI channels,
+with RFC-1490 frames on DLCI 16 and PPP frames over DLCI 20:
+.Pp
+.Bd -literal
+[type SYNC ] [type FRAME] [type RFC1490]
+[ "Frame1" ](uplink)<-->(data)[<un-named>](dlci16)<-->(mux)[<un-named> ]
+[ A ] [ B ](dlci20)<---+ [ C ]
+ |
+ | [ type PPP ]
+ +>(mux)[<un-named>]
+ [ D ]
+.Ed
+.Pp
+One could always send a control message to node C from anywhere
+by using the name
+.Em "Frame1:uplink.dlci16" .
+Similarly,
+.Em "Frame1:uplink.dlci20"
+could reliably be used to reach node D, and node A could refer
+to node B as
+.Em ".:uplink" ,
+or simply
+.Em "uplink" .
+Conversely, B can refer to A as
+.Em "data" .
+The address
+.Em "mux.data"
+could be used by both nodes C and D to address a message to node A.
+.Pp
+Note that this is only for
+.Em control messages .
+Data messages are routed one hop at a time, by specifying the departing
+hook, with each node making the next routing decision. So when B
+receives a frame on hook
+.Em data
+it decodes the frame relay header to determine the DLCI,
+and then forwards the unwrapped frame to either C or D.
+.Pp
+A similar graph might be used to represent multi-link PPP running
+over an ISDN line:
+.Pp
+.Bd -literal
+[ type BRI ](B1)<--->(link1)[ type MPP ]
+[ "ISDN1" ](B2)<--->(link2)[ (no name) ]
+[ ](D) <-+
+ |
+ +----------------+
+ |
+ +->(switch)[ type Q.921 ](term1)<---->(datalink)[ type Q.931 ]
+ [ (no name) ] [ (no name) ]
+.Ed
+.Sh Netgraph Structures
+Interesting members of the node and hook structures are shown below:
+.Bd -literal
+struct ng_node {
+ char *name; /* Optional globally unique name */
+ void *private; /* Node implementation private info */
+ struct ng_type *type; /* The type of this node */
+ int refs; /* Number of references to this struct */
+ int numhooks; /* Number of connected hooks */
+ hook_p hooks; /* Linked list of (connected) hooks */
+};
+typedef struct ng_node *node_p;
+
+struct ng_hook {
+ char *name; /* This node's name for this hook */
+ void *private; /* Node implementation private info */
+ int refs; /* Number of references to this struct */
+ struct ng_node *node; /* The node this hook is attached to */
+ struct ng_hook *peer; /* The other hook in this connected pair */
+ struct ng_hook *next; /* Next in list of hooks for this node */
+};
+typedef struct ng_hook *hook_p;
+.Ed
+.Pp
+The maintenance of the name pointers, reference counts, and linked list
+of hooks for each node is handled automatically by the
+.Nm
+subsystem.
+Typically a node's private info contains a back-pointer to the node or hook
+structure, which counts as a new reference that must be registered by
+incrementing
+.Dv "node->refs" .
+.Pp
+From a hook you can obtain the corresponding node, and from
+a node the list of all active hooks.
+.Pp
+Node types are described by this structure:
+.Bd -literal
+struct ng_type {
+ u_int32_t version; /* Must equal NG_VERSION */
+ const char *name; /* Unique type name */
+
+ /* Module event handler */
+ modeventhand_t mod_event; /* Handle load/unload (optional) */
+
+ /* Constructor */
+ int (*constructor)(node_p *node); /* Create a new node */
+
+ /** Methods using the node **/
+ int (*rcvmsg)(node_p node, /* Receive control message */
+ struct ng_mesg *msg, /* The message */
+ const char *retaddr, /* Return address */
+ struct ng_mesg **resp); /* Synchronous response */
+ int (*shutdown)(node_p node); /* Shutdown this node */
+ int (*newhook)(node_p node, /* create a new hook */
+ hook_p hook, /* Pre-allocated struct */
+ const char *name); /* Name for new hook */
+
+ /** Methods using the hook **/
+ int (*connect)(hook_p hook); /* Confirm new hook attachment */
+ int (*rcvdata)(hook_p hook, /* Receive data on a hook */
+ struct mbuf *m, /* The data in an mbuf */
+ meta_p meta); /* Meta-data, if any */
+ int (*disconnect)(hook_p hook); /* Notify disconnection of hook */
+};
+.Ed
+.Pp
+Control messages have the following structure:
+.Bd -literal
+#define NG_CMDSTRLEN 15 /* Max command string (16 with null) */
+
+struct ng_mesg {
+ struct ng_msghdr {
+ u_char version; /* Must equal NG_VERSION */
+ u_char spare; /* Pad to 2 bytes */
+ u_short arglen; /* Length of cmd/resp data */
+ u_long flags; /* Message status flags */
+ u_long token; /* Reply should have the same token */
+ u_long typecookie; /* Node type understanding this message */
+ u_long cmd; /* Command identifier */
+ u_char cmdstr[NG_CMDSTRLEN+1]; /* Cmd string (for debug) */
+ } header;
+ char data[0]; /* Start of cmd/resp data */
+};
+
+#define NG_VERSION 1 /* Netgraph version */
+#define NGF_ORIG 0x0000 /* Command */
+#define NGF_RESP 0x0001 /* Response */
+.Ed
+.Pp
+Control messages have the fixed header shown above, followed by a
+variable length data section which depends on the type cookie
+and the command. Each field is explained below:
+.Bl -tag -width xxx
+.It Dv version
+Indicates the version of netgraph itself. The current version is
+.Dv NG_VERSION .
+.It Dv arglen
+This is the length of any extra arguments, which begin at
+.Dv data .
+.It Dv flags
+Indicates whether this is a command or a response control message.
+.It Dv token
+The
+.Dv token
+is a means by which a sender can match a reply message to the
+corresponding command message; the reply always has the same token.
+.Pp
+.It Dv typecookie
+The corresponding node type's unique 32-bit value.
+If a node doesn't recognize the type cookie it must reject the message
+by returning
+.Er EINVAL .
+.Pp
+Each type should have an include file that defines the commands,
+argument format, and cookie for its own messages.
+The typecookie
+insures that the same header file was included by both sender and
+receiver; when an incompatible change in the header file is made,
+the typecookie
+.Em must
+be changed.
+The de facto method for generating unique type cookies is to take the
+seconds from the epoch at the time the header file is written
+(i.e., the output of
+.Dv "date -u +'%s'" ")."
+.Pp
+There is a predefined typecookie
+.Dv NGM_GENERIC_COOKIE
+for the ``generic'' node type, and
+a corresponding set of generic messages which all nodes understand.
+The handling of these messages is automatic.
+.It Dv command
+The identifier for the message command. This is type specific,
+and is defined in the same header file as the typecookie.
+.It Dv cmdstr
+Room for a short human readable version of ``command'' (for debugging
+purposes only).
+.El
+.Pp
+Some modules may choose to implement messages from more than one
+of the header files and thus recognize more than one type cookie.
+.Sh Generic Control Messages
+There are a number of standard predefined messages that will work
+for any node, as they are supported directly by the framework itself.
+These are defined in
+.Dv ng_message.h
+along with the basic layout of messages and other similar information.
+.Bl -tag -width xxx
+.It Dv NGM_CONNECT
+Connect to another node, using the supplied hook names on either end.
+.It Dv NGM_MKPEER
+Construct a node of the given type and then connect to it using the
+supplied hook names.
+.It Dv NGM_SHUTDOWN
+The target node should disconnect from all its neighbours and shut down.
+Persistent nodes such as those representing physical hardware
+might not dissappear from the node namespace, but only reset themselves.
+The node must disconnect all of its hooks.
+This may result in neighbors shutting themselves down, and possibly a
+cascading shutdown of the entire connected graph.
+.It Dv NGM_NAME
+Assign a name to a node. Nodes can exist without having a name, and this
+is the default for nodes created using the
+.Dv NGM_MKPEER
+method. Such nodes can only be addressed relatively or by their ID number.
+.It Dv NGM_RMHOOK
+Ask the node to break a hook connection to one of its neighbours.
+Both nodes will have their ``disconnect'' method invoked.
+Either node may elect to totally shut down as a result.
+.It Dv NGM_NODEINFO
+Asks the target node to describe itself. The four returned fields
+are the node name (if named), the node type, the node ID and the
+number of hooks attached. The ID is an internal number unique to that node.
+.It Dv NGM_LISTHOOKS
+This returns the information given by
+.Dv NGM_NODEINFO ,
+but in addition
+includes an array of fields describing each link, and the desription for
+the node at the far end of that link.
+.It Dv NGM_LISTNAMES
+This returns an array of node descriptions (as for
+.Dv NGM_NODEINFO ")"
+where each entry of the array describes a named node.
+All named nodes will be described.
+.It Dv NGM_LISTNODES
+This is the same as
+.Dv NGM_LISTNAMES
+except that all nodes are listed regardless of whether they have a name or not.
+.It Dv NGM_LISTTYPES
+This returns a list of all currently installed netgraph types.
+.It Dv NGM_TEXT_STATUS
+The node may return a text formatted status message.
+The status information is determined entirely by the node type.
+It is the only "generic" message
+that requires any support within the node itself and as such the node may
+elect to not support this message. The text response must be less than
+.Dv NG_TEXTRESPONSE
+bytes in length (presently 1024). This can be used to return general
+status information in human readable form.
+.El
+.Sh Metadata
+Data moving through the
+.Nm
+system can be accompanied by meta-data that describes some
+aspect of that data. The form of the meta-data is a fixed header,
+which contains enough information for most uses, and can optionally
+be suplemented by trailing
+.Em option
+structures, which contain a
+.Em cookie
+(see the section on control messages), an identifier, a length and optional
+data. If a node does not recognize the cookie associated with an option,
+it should ignore that option.
+.Pp
+Meta data might include such things as priority, discard eligibility,
+or special processing requirements. It might also mark a packet for
+debug status, etc. The use of meta-data is still experimental.
+.Sh INITIALIZATION
+The base
+.Nm
+code may either be statically compiled
+into the kernel or else loaded dynamically as a KLD via
+.Xr kldload 8 .
+In the former case, include
+.Bd -literal -offset 4n -compact
+
+ options NETGRAPH
+
+.Ed
+in your kernel configuration file. You may also include selected
+node types in the kernel compilation, for example:
+.Bd -literal -offset 4n -compact
+
+ options NETGRAPH
+ options NETGRAPH_SOCKET
+ options NETGRAPH_ECHO
+
+.Ed
+.Pp
+Once the
+.Nm
+subsystem is loaded, individual node types may be loaded at any time
+as KLD modules via
+.Xr kldload 8 .
+Moreover,
+.Nm
+knows how to automatically do this; when a request to create a new
+node of unknown type
+.Em type
+is made,
+.Nm
+will attempt to load the KLD module
+.Dv ng_type.ko .
+.Pp
+Types can also be installed at boot time, as certain device drivers
+may want to export each instance of the device as a netgraph node.
+.Pp
+In general, new types can be installed at any time from within the
+kernel by calling
+.Dv ng_newtype() ,
+supplying a pointer to the type's
+.Dv struct ng_type
+structure.
+.Pp
+The
+.Dv "NETGRAPH_INIT()"
+macro automates this process by using a linker set.
+.Sh EXISTING NODE TYPES
+Several node types currently exist. Each is fully documented
+in its own man page:
+.Bl -tag -width xxx
+.It SOCKET
+The socket type implements two new sockets in the new protocol domain
+.Dv PF_NETGRAPH .
+The new sockets protocols are
+.Dv NG_DATA
+and
+.Dv NG_CONTROL ,
+both of type
+.Dv SOCK_DGRAM .
+Typically one of each is associated with a socket node.
+When both sockets have closed, the node will shut down. The
+.Dv NG_DATA
+socket is used for sending and receiving data, while the
+.Dv NG_CONTROL
+socket is used for sending and receiving control messages.
+Data and control messages are passed using the
+.Xr sendto 2
+and
+.Xr recvfrom 2
+calls, using a
+.Dv struct sockaddr_ng
+socket address.
+.Pp
+.It HOLE
+Responds only to generic messages and is a ``black hole'' for data,
+Useful for testing. Always accepts new hooks.
+.Pp
+.It ECHO
+Responds only to generic messages and always echoes data back through the
+hook from which it arrived. Returns any non generic messages as their
+own response. Useful for testing. Always accepts new hooks.
+.Pp
+.It TEE
+This node is useful for ``snooping.'' It has 4 hooks:
+.Dv left ,
+.Dv right ,
+.Dv left2right ,
+and
+.Dv right2left .
+Data entering from the right is passed to the left and duplicated on
+.Dv right2left,
+and data entering from the left is passed to the right and
+duplicated on
+.Dv left2right .
+Data entering from
+.Dv left2right
+is sent to the right and data from
+.Dv right2left
+to left.
+.Pp
+.It RFC1490 MUX
+Encapsulates/de-encapsulates frames encoded according to RFC 1490.
+Has a hook for the encapsulated packets (``downstream'') and one hook
+for each protocol (i.e., IP, PPP, etc.).
+.Pp
+.It FRAME RELAY MUX
+Encapsulates/de-encapsulates Frame Relay frames.
+Has a hook for the encapsulated packets (``downstream'') and one hook
+for each DLCI.
+.Pp
+.It FRAME RELAY LMI
+Automatically handles frame relay
+``LMI'' (link management interface) operations and packets.
+Automatically probes and detects whch of several LMI standards
+is in use at the exchange.
+.Pp
+.It TTY
+This node is also a line discipline. It simply converts between mbuf
+frames and sequential serial data, allowing a tty to appear as a netgraph
+node. It has a programmable ``hotkey'' character.
+.Pp
+.It ASYNC
+This node encapsulates and de-encapsulates asynchronous frames
+according to RFC 1662. This is used in conjunction with the TTY node
+type for supporting PPP links over asynchronous serial lines.
+.Pp
+.It INTERFACE
+This node is also a system networking interface. It has hooks representing
+each protocol family (IP, AppleTalk, IPX, etc.) and appears in the output of
+.Xr ifconfig 8 .
+The interfaces are named
+.Em ng0 ,
+.Em ng1 ,
+etc.
+.El
+.Sh NOTES
+Whether a named node exists can be checked by trying to send a control mesage
+to it (e.g.,
+.Dv NGM_NODEINFO
+).
+If it does not exist,
+.Er ENOENT
+will be returned.
+.Pp
+All data messages are mbuf chains with the M_PKTHDR flag set.
+.Pp
+Nodes are responsible for freeing what they allocate.
+There are three exceptions:
+.Bl -tag -width xxxx
+.It 1
+Mbufs sent across a data link are never to be freed by the sender.
+.It 2
+Any meta-data information travelling with the data has the same restriction.
+It might be freed by any node the data passes through, and a
+.Dv NULL
+passed onwards, but the caller will never free it.
+Two macros
+.Dv "NG_FREE_META(meta)"
+and
+.Dv "NG_FREE_DATA(m, meta)"
+should be used if possible to free data and meta data (see
+.Dv netgraph.h ")."
+.It 3
+Messages sent using
+.Dv ng_send_message()
+are freed by the callee. As in the case above, the addresses
+associated with the message are freed by whatever allocated them so the
+recipient should copy them if it wants to keep that information.
+.El
+.Sh FILES
+.Bl -tag -width xxxxx -compact
+.It Pa /sys/netgraph/netgraph.h
+Definitions for use soley within the kernel by
+.Nm
+nodes.
+.It Pa /sys/netgraph/ng_message.h
+Definitions needed by any file that needs to deal with
+.Nm
+messages.
+.It Pa /sys/netgraph/ng_socket.h
+Definitions needed to use
+.Nm
+socket type nodes.
+.It Pa /sys/netgraph/ng_{type}.h
+Definitions needed to use
+.Nm
+{type}
+nodes, including the type cookie definition.
+.It Pa /modules/netgraph.ko
+Netgraph subsystem loadable KLD module.
+.It Pa /modules/ng_{type}.ko
+Loadable KLD module for node type {type}.
+.El
+.Sh USER MODE SUPPORT
+There is a library for supporting user-mode programs that wish
+to interact with the netgraph system. See
+.Xr netgraph 3
+for details.
+.Pp
+Two user-mode support programs,
+.Xr ngctl 8
+and
+.Xr nghook 8 ,
+are available to assist manual configuration and debugging.
+.Pp
+There are a few useful techniques for debugging new node types.
+First, implementing new node types in user-mode first
+makes debugging easier.
+The
+.Em tee
+node type is also useful for debugging, especially in conjunction with
+.Xr ngctl 8
+and
+.Xr nghook 8 .
+.Sh SEE ALSO
+.Xr socket 2 ,
+.Xr netgraph 3 ,
+.Xr ngctl 8 ,
+.Xr nghook 8 ,
+.Xr ng_async 8 .
+.Xr ng_cisco 8 .
+.Xr ng_echo 8 .
+.Xr ng_frame_relay 8 .
+.Xr ng_hole 8 .
+.Xr ng_iface 8 .
+.Xr ng_lmi 8 .
+.Xr ng_rfc1490 8 .
+.Xr ng_socket 8 .
+.Xr ng_tee 8 .
+.Xr ng_tty 8 .
+.Xr ng_UI 8 .
+.Xr ng_{type} 8 .
+.Sh HISTORY
+The
+.Nm
+system was designed and first implemented at Whistle Communications, Inc.
+in a version FreeBSD 2.2 customized for the Whistle InterJet.
+.Sh AUTHORS
+Julian Elischer <julian@whistle.com>, with contributions by
+Archie Cobbs <archie@whistle.com>.
diff --git a/sys/modules/netgraph/ppp/Makefile b/sys/modules/netgraph/ppp/Makefile
new file mode 100644
index 0000000..590e10a
--- /dev/null
+++ b/sys/modules/netgraph/ppp/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.1 1999/01/24 02:52:12 archie Exp $
+
+KMOD= ng_ppp
+SRCS= ng_ppp.c
+MAN8= ng_ppp.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/ppp/ng_ppp.4 b/sys/modules/netgraph/ppp/ng_ppp.4
new file mode 100644
index 0000000..cffa78e
--- /dev/null
+++ b/sys/modules/netgraph/ppp/ng_ppp.4
@@ -0,0 +1,164 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_ppp.8,v 1.3 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_PPP 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_ppp
+.Nd PPP protocol multiplexor negraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_ppp.h>
+.Sh DESCRIPTION
+The
+.Nm ppp
+node type performs multiplexing for the PPP protocol. On the
+.Dv downstream
+hook it transmits and receives full PPP frames, which include the
+protocol field, but no address, control or checksum fields.
+On outgoing frames, when protocol compression has been enabled and
+the protocol number is suitable for compression, the protocol field will
+be compressed (i.e., sent as one byte instead of two).
+Either compressed or uncompressed protocol fields are accepted
+on incoming frames.
+.Pp
+For each 16-bit PPP procotol number there is a corresponding ``upstream'' hook.
+Packets on these hooks contain no PPP protocol header.
+The node simply multiplexes between the
+.Dv downstream
+hook and all of the upstream hooks by adding or subtracting the
+PPP protocol field, depending on the direction of flow.
+.Pp
+When a frame is received on
+.Dv downstream ,
+if the corresponding protocol hook is
+not connected, the packet is forwarded to a special upstream hook called
+.Dv bypass .
+This hook is a catch-all for any incoming frames not destined
+for another already connected hook. Packets sent out on the
+.Dv bypass
+hook always have the PPP protcol header prepended as the first
+two bytes (even if the
+original incoming frame was protocol compressed to one byte).
+.Pp
+Any frames received on the
+.Dv bypass
+hook are forwarded to
+.Dv downstream
+without modification.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazi
+.It Dv downstream
+Connection to the PPP link layer.
+.It Dv bypass
+Frames that do not correspond to a connected protocol hook;
+the PPP protocol header is included.
+.It Dv 0xNNNN
+Conection to the PPP protocol with 16-bit hex value
+.Dv NNNN .
+No PPP protocol header is included.
+.El
+.Pp
+For convenience, the
+.Nm
+node type defines several hook name aliases for common PPP protocols:
+.Pp
+.Bl -tag -width abcdefgh -compact -offset 4n
+.It Dv lcp
+LCP protocol data (0xc021)
+.It Dv ipcp
+IPCP protocol data (0x8021)
+.It Dv atcp
+ATCP protocol data (0x8029)
+.It Dv ccp
+CCP protocol data (0x80fd)
+.It Dv ecp
+ECP protocol data (0x8053)
+.It Dv ip
+IP protocol data (0x0021)
+.It Dv vjcomp
+Van Jacobsen compressed TCP data (0x002d)
+.It Dv vjuncomp
+Van Jacobsen uncompressed TCP data (0x002f)
+.It Dv mp
+Multi-link protocol data (0x003d)
+.It Dv compd
+Compressed protocol data (0x00fd)
+.It Dv cryptd
+Encrypted protocol data (0x0053)
+.It Dv pap
+PAP authentication protocol data (0xc023)
+.It Dv chap
+CHAP authentication protocol data (0xc223)
+.It Dv lqr
+LQR protocol data (0xc025)
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_PPP_SET_PROTOCOMP
+This command takes a single integer as argument and enables or disables
+protocol field compression as the value is zero or non-zero.
+Note that only protocols with high order byte equal to
+.Dv 0x00
+are compressible.
+.It Dv NGM_PPP_GET_STATS
+This command returns a
+.Dv "struct ng_ppp_stat"
+containing various node statistics.
+.It Dv NGM_PPP_CLR_STATS
+Clears the node statistics. Statistics are also cleared whenever the
+.Dv downstream
+hook is reconnected.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_async 8 ,
+.Xr ng_vjc 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A W. Simpson
+.%T "The Point-to-Point Protocol (PPP)"
+.%O RFC 1661
+.Re
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/ppp/ng_ppp.8 b/sys/modules/netgraph/ppp/ng_ppp.8
new file mode 100644
index 0000000..cffa78e
--- /dev/null
+++ b/sys/modules/netgraph/ppp/ng_ppp.8
@@ -0,0 +1,164 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_ppp.8,v 1.3 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_PPP 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_ppp
+.Nd PPP protocol multiplexor negraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_ppp.h>
+.Sh DESCRIPTION
+The
+.Nm ppp
+node type performs multiplexing for the PPP protocol. On the
+.Dv downstream
+hook it transmits and receives full PPP frames, which include the
+protocol field, but no address, control or checksum fields.
+On outgoing frames, when protocol compression has been enabled and
+the protocol number is suitable for compression, the protocol field will
+be compressed (i.e., sent as one byte instead of two).
+Either compressed or uncompressed protocol fields are accepted
+on incoming frames.
+.Pp
+For each 16-bit PPP procotol number there is a corresponding ``upstream'' hook.
+Packets on these hooks contain no PPP protocol header.
+The node simply multiplexes between the
+.Dv downstream
+hook and all of the upstream hooks by adding or subtracting the
+PPP protocol field, depending on the direction of flow.
+.Pp
+When a frame is received on
+.Dv downstream ,
+if the corresponding protocol hook is
+not connected, the packet is forwarded to a special upstream hook called
+.Dv bypass .
+This hook is a catch-all for any incoming frames not destined
+for another already connected hook. Packets sent out on the
+.Dv bypass
+hook always have the PPP protcol header prepended as the first
+two bytes (even if the
+original incoming frame was protocol compressed to one byte).
+.Pp
+Any frames received on the
+.Dv bypass
+hook are forwarded to
+.Dv downstream
+without modification.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazi
+.It Dv downstream
+Connection to the PPP link layer.
+.It Dv bypass
+Frames that do not correspond to a connected protocol hook;
+the PPP protocol header is included.
+.It Dv 0xNNNN
+Conection to the PPP protocol with 16-bit hex value
+.Dv NNNN .
+No PPP protocol header is included.
+.El
+.Pp
+For convenience, the
+.Nm
+node type defines several hook name aliases for common PPP protocols:
+.Pp
+.Bl -tag -width abcdefgh -compact -offset 4n
+.It Dv lcp
+LCP protocol data (0xc021)
+.It Dv ipcp
+IPCP protocol data (0x8021)
+.It Dv atcp
+ATCP protocol data (0x8029)
+.It Dv ccp
+CCP protocol data (0x80fd)
+.It Dv ecp
+ECP protocol data (0x8053)
+.It Dv ip
+IP protocol data (0x0021)
+.It Dv vjcomp
+Van Jacobsen compressed TCP data (0x002d)
+.It Dv vjuncomp
+Van Jacobsen uncompressed TCP data (0x002f)
+.It Dv mp
+Multi-link protocol data (0x003d)
+.It Dv compd
+Compressed protocol data (0x00fd)
+.It Dv cryptd
+Encrypted protocol data (0x0053)
+.It Dv pap
+PAP authentication protocol data (0xc023)
+.It Dv chap
+CHAP authentication protocol data (0xc223)
+.It Dv lqr
+LQR protocol data (0xc025)
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_PPP_SET_PROTOCOMP
+This command takes a single integer as argument and enables or disables
+protocol field compression as the value is zero or non-zero.
+Note that only protocols with high order byte equal to
+.Dv 0x00
+are compressible.
+.It Dv NGM_PPP_GET_STATS
+This command returns a
+.Dv "struct ng_ppp_stat"
+containing various node statistics.
+.It Dv NGM_PPP_CLR_STATS
+Clears the node statistics. Statistics are also cleared whenever the
+.Dv downstream
+hook is reconnected.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_async 8 ,
+.Xr ng_vjc 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A W. Simpson
+.%T "The Point-to-Point Protocol (PPP)"
+.%O RFC 1661
+.Re
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/pppoe/Makefile b/sys/modules/netgraph/pppoe/Makefile
new file mode 100644
index 0000000..ed3756f
--- /dev/null
+++ b/sys/modules/netgraph/pppoe/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.1 1999/01/19 19:39:21 archie Exp $
+
+KMOD= ng_pppoe
+SRCS= ng_pppoe.c
+MAN8= ng_pppoe.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/pppoe/ng_pppoe.4 b/sys/modules/netgraph/pppoe/ng_pppoe.4
new file mode 100644
index 0000000..fc0ba24
--- /dev/null
+++ b/sys/modules/netgraph/pppoe/ng_pppoe.4
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_lmi.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_LMI 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_lmi
+.Nd Frame relay LMI protocol netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_lmi.h>
+.Sh DESCRIPTION
+The
+.Nm lmi
+node type performs the frame relay LMI protocol. It supports
+the ITU Annex A, ANSI Annex D, and Group-of-four LMI types.
+It also supports auto-detection of the LMI type.
+.Pp
+To enable a specific LMI type, connect the corresponding hook (
+.Dv annexA ,
+.Dv annexD ,
+or
+.Dv group4 ")"
+to DLCI 0 or 1023 of a
+.Xr ng_frame_relay 8
+node.
+Typically, Annex A and Annex D live on DLCI 0 while Group-of-four
+lives on DLCI 1023.
+.Pp
+To enable LMI type auto-detection, connect the
+.Dv auto0
+hook to DLCI 0 and the
+.Dv auto1023
+hook to DLCI 1023. The node will attempt to automatically determine
+which LMI type is running at the switch, and go into that mode.
+.Pp
+Only one fixed LMI type, or auto-detection, can be active at any given time.
+.Pp
+The
+.Dv NGM_LMI_GET_STATUS
+control message can be used at any time to query the current status
+of the LMI protocol and each DLCI channel. This node also supports the
+.Dv NGM_TEXT_STATUS
+control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbaz
+.It Dv annexA
+ITU Annex A LMI hook.
+.It Dv annexD
+ANSI Annex D LMI hook.
+.It Dv group4
+Group-of-four LMI hook.
+.It Dv auto0
+Auto-detection hook for DLCI 0.
+.It Dv auto1023
+Auto-detection hook for DLCI 1023.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_LMI_GET_STATUS
+This command returns status information in a
+.Dv "struct nglmistat" :
+.Bd -literal -offset 4n
+#define NGM_LMI_STAT_ARYSIZE (1024/8)
+
+struct nglmistat {
+ u_char proto[12]; /* Active proto (same as hook name) */
+ u_char hook[12]; /* Active hook */
+ u_char fixed; /* If set to fixed LMI mode */
+ u_char autod; /* If currently auto-detecting */
+ u_char seen[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs seen */
+ u_char up[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs up */
+};
+.Ed
+.It Dv NGM_TEXT_STATUS
+This generic message returns is a human-readable version of the node status.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_frame_relay 8 ,
+.Xr ngctl 8 .
+.Rs
+.%T "ANSI T1.617-1991 Annex D"
+.Re
+.Rs
+.%T "ITU-T Q.933 Digital Subscriber Signalling System No. 1 - Signalling Specification for Frame Mode Basic Call Control, Annex A"
+.Re
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/pppoe/ng_pppoe.8 b/sys/modules/netgraph/pppoe/ng_pppoe.8
new file mode 100644
index 0000000..fc0ba24
--- /dev/null
+++ b/sys/modules/netgraph/pppoe/ng_pppoe.8
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_lmi.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_LMI 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_lmi
+.Nd Frame relay LMI protocol netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_lmi.h>
+.Sh DESCRIPTION
+The
+.Nm lmi
+node type performs the frame relay LMI protocol. It supports
+the ITU Annex A, ANSI Annex D, and Group-of-four LMI types.
+It also supports auto-detection of the LMI type.
+.Pp
+To enable a specific LMI type, connect the corresponding hook (
+.Dv annexA ,
+.Dv annexD ,
+or
+.Dv group4 ")"
+to DLCI 0 or 1023 of a
+.Xr ng_frame_relay 8
+node.
+Typically, Annex A and Annex D live on DLCI 0 while Group-of-four
+lives on DLCI 1023.
+.Pp
+To enable LMI type auto-detection, connect the
+.Dv auto0
+hook to DLCI 0 and the
+.Dv auto1023
+hook to DLCI 1023. The node will attempt to automatically determine
+which LMI type is running at the switch, and go into that mode.
+.Pp
+Only one fixed LMI type, or auto-detection, can be active at any given time.
+.Pp
+The
+.Dv NGM_LMI_GET_STATUS
+control message can be used at any time to query the current status
+of the LMI protocol and each DLCI channel. This node also supports the
+.Dv NGM_TEXT_STATUS
+control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbaz
+.It Dv annexA
+ITU Annex A LMI hook.
+.It Dv annexD
+ANSI Annex D LMI hook.
+.It Dv group4
+Group-of-four LMI hook.
+.It Dv auto0
+Auto-detection hook for DLCI 0.
+.It Dv auto1023
+Auto-detection hook for DLCI 1023.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_LMI_GET_STATUS
+This command returns status information in a
+.Dv "struct nglmistat" :
+.Bd -literal -offset 4n
+#define NGM_LMI_STAT_ARYSIZE (1024/8)
+
+struct nglmistat {
+ u_char proto[12]; /* Active proto (same as hook name) */
+ u_char hook[12]; /* Active hook */
+ u_char fixed; /* If set to fixed LMI mode */
+ u_char autod; /* If currently auto-detecting */
+ u_char seen[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs seen */
+ u_char up[NGM_LMI_STAT_ARYSIZE]; /* bitmap DLCIs up */
+};
+.Ed
+.It Dv NGM_TEXT_STATUS
+This generic message returns is a human-readable version of the node status.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_frame_relay 8 ,
+.Xr ngctl 8 .
+.Rs
+.%T "ANSI T1.617-1991 Annex D"
+.Re
+.Rs
+.%T "ITU-T Q.933 Digital Subscriber Signalling System No. 1 - Signalling Specification for Frame Mode Basic Call Control, Annex A"
+.Re
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/rfc1490/Makefile b/sys/modules/netgraph/rfc1490/Makefile
new file mode 100644
index 0000000..ac7562d
--- /dev/null
+++ b/sys/modules/netgraph/rfc1490/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:22 archie Exp $
+
+KMOD= ng_rfc1490
+SRCS= ng_rfc1490.c
+MAN8= ng_rfc1490.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/rfc1490/ng_rfc1490.4 b/sys/modules/netgraph/rfc1490/ng_rfc1490.4
new file mode 100644
index 0000000..c7fa859
--- /dev/null
+++ b/sys/modules/netgraph/rfc1490/ng_rfc1490.4
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_rfc1490.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_RFC1490 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_rfc1490
+.Nd RFC 1490 netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_rfc1490.h>
+.Sh DESCRIPTION
+The
+.Nm rfc1490
+node type performs protocol encapsulation, de-encapsulation, and
+multiplexing according to RFC 1490 (which has since been updated by RFC 2427).
+This particular type of encapsulation is often used on top of frame relay
+DLCI channels.
+.Pp
+The
+.Dv downstream
+hook is used to transmit and receive encapsulated frames. On the other
+side of the node, the
+.Dv inet
+and
+.Dv ppp
+hooks are used to transmit and receive raw IP frames and PPP frames,
+respectively. PPP frames are transmitted and received according to
+RFC 1973; in particular, frames appearing on the
+.Dv ppp
+hook begin with the PPP protocol number.
+.Pp
+Typically the
+.Dv inet
+hook is connected to the
+.Dv inet
+hook of an
+.Xr ng_iface 8
+node.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazum
+.It Dv downstream
+Connects to the RFC 1490 peer entity.
+.It Dv inet
+Transmits and receives raw IP frames.
+.It Dv ppp
+Transmits and receives PPP frames.
+.El
+.Sh CONTROL MESSAGES
+This node type only supports the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+Not all of RFC 1490 is implemented.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_frame_relay 8 ,
+.Xr ng_iface 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A C. Brown, A. Malis
+.%T "Multiprotocol Interconnect over Frame Relay"
+.%O RFC 2427
+.Re
+.Rs
+.%A W. Simpson
+.%T "PPP in Frame Relay"
+.%O RFC 1973
+.Re
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/rfc1490/ng_rfc1490.8 b/sys/modules/netgraph/rfc1490/ng_rfc1490.8
new file mode 100644
index 0000000..c7fa859
--- /dev/null
+++ b/sys/modules/netgraph/rfc1490/ng_rfc1490.8
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_rfc1490.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_RFC1490 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_rfc1490
+.Nd RFC 1490 netgraph node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_rfc1490.h>
+.Sh DESCRIPTION
+The
+.Nm rfc1490
+node type performs protocol encapsulation, de-encapsulation, and
+multiplexing according to RFC 1490 (which has since been updated by RFC 2427).
+This particular type of encapsulation is often used on top of frame relay
+DLCI channels.
+.Pp
+The
+.Dv downstream
+hook is used to transmit and receive encapsulated frames. On the other
+side of the node, the
+.Dv inet
+and
+.Dv ppp
+hooks are used to transmit and receive raw IP frames and PPP frames,
+respectively. PPP frames are transmitted and received according to
+RFC 1973; in particular, frames appearing on the
+.Dv ppp
+hook begin with the PPP protocol number.
+.Pp
+Typically the
+.Dv inet
+hook is connected to the
+.Dv inet
+hook of an
+.Xr ng_iface 8
+node.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazum
+.It Dv downstream
+Connects to the RFC 1490 peer entity.
+.It Dv inet
+Transmits and receives raw IP frames.
+.It Dv ppp
+Transmits and receives PPP frames.
+.El
+.Sh CONTROL MESSAGES
+This node type only supports the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+Not all of RFC 1490 is implemented.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_frame_relay 8 ,
+.Xr ng_iface 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A C. Brown, A. Malis
+.%T "Multiprotocol Interconnect over Frame Relay"
+.%O RFC 2427
+.Re
+.Rs
+.%A W. Simpson
+.%T "PPP in Frame Relay"
+.%O RFC 1973
+.Re
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/socket/Makefile b/sys/modules/netgraph/socket/Makefile
new file mode 100644
index 0000000..d2779b3
--- /dev/null
+++ b/sys/modules/netgraph/socket/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:22 archie Exp $
+
+KMOD= ng_socket
+SRCS= ng_socket.c
+MAN8= ng_socket.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/socket/ng_socket.4 b/sys/modules/netgraph/socket/ng_socket.4
new file mode 100644
index 0000000..31302a5
--- /dev/null
+++ b/sys/modules/netgraph/socket/ng_socket.4
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_socket.8,v 1.5 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_SOCKET 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_socket
+.Nd netgraph socket node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_message.h>
+.Fd #include <netgraph/ng_socket.h>
+.Sh DESCRIPTION
+A
+.Nm socket
+node is both a BSD socket and a netgraph node. The
+.Nm socket
+node type allows user-mode processes to participate in the kernel
+.Xr netgraph 4
+networking subsystem using the BSD socket interface.
+.Pp
+A new
+.Nm socket
+node is created by creating a new socket of type
+.Dv NG_CONTROL
+in the protocol family
+.Dv PF_NETGRAPH ,
+using the
+.Xr socket 2
+system call.
+Any control messages received by the node are received using
+.Xr recvfrom 2 ;
+the socket address argument is a
+.Dv "struct sockaddr_ng"
+containing the sender's netgraph address. Conversely, control messages
+can be sent to any node by calling
+.Xr sendto 2 ,
+supplying the recipient's address in a
+.Dv "struct sockaddr_ng" .
+The
+.Xr bind 2
+system call may be used to assign a global netgraph name to the node.
+.Pp
+To transmit and receive netgraph data packets, a
+.Dv NG_DATA
+socket must also be created using
+.Xr socket 2
+and associated with a
+.Nm socket
+node.
+.Dv NG_DATA sockets do not automatically
+have nodes associated with them; they are bound to a specific node via the
+.Xr connect 2
+system call. The address argument is the netgraph address of the
+.Nm socket
+node already created. Once a data socket is associated with a node,
+any data packets received by the node are read using
+.Xr recvfrom 2
+and any packets to be sent out from the node are written using
+.Xr sendto 2 .
+In the case of data sockets, the
+.Dv "struct sockaddr_ng"
+contains the name of the
+.Em hook
+on which the data was received or should be sent.
+.Pp
+There is a user library that simplifies using netgraph sockets; see
+.Xr netgraph 3 .
+.Sh HOOKS
+This node type supports hooks with arbitrary names (as long as
+they are unique) and always accepts hook connection requests.
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node type shuts down and disappears when both the associated
+.Dv NG_CONTROL
+and
+.Dv NG_DATA
+sockets have been closed, or a
+.Dv NGM_SHUTDOWN
+control message is received. In the latter case, attempts to write
+to the still-open sockets will return
+.Er ENOTCONN .
+.Sh BUGS
+It is not possible to reject the connection of a hook, though any
+data received on that hook can certainly be ignored.
+.Sh SEE ALSO
+.Xr socket 2 ,
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/socket/ng_socket.8 b/sys/modules/netgraph/socket/ng_socket.8
new file mode 100644
index 0000000..31302a5
--- /dev/null
+++ b/sys/modules/netgraph/socket/ng_socket.8
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_socket.8,v 1.5 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_SOCKET 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_socket
+.Nd netgraph socket node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_message.h>
+.Fd #include <netgraph/ng_socket.h>
+.Sh DESCRIPTION
+A
+.Nm socket
+node is both a BSD socket and a netgraph node. The
+.Nm socket
+node type allows user-mode processes to participate in the kernel
+.Xr netgraph 4
+networking subsystem using the BSD socket interface.
+.Pp
+A new
+.Nm socket
+node is created by creating a new socket of type
+.Dv NG_CONTROL
+in the protocol family
+.Dv PF_NETGRAPH ,
+using the
+.Xr socket 2
+system call.
+Any control messages received by the node are received using
+.Xr recvfrom 2 ;
+the socket address argument is a
+.Dv "struct sockaddr_ng"
+containing the sender's netgraph address. Conversely, control messages
+can be sent to any node by calling
+.Xr sendto 2 ,
+supplying the recipient's address in a
+.Dv "struct sockaddr_ng" .
+The
+.Xr bind 2
+system call may be used to assign a global netgraph name to the node.
+.Pp
+To transmit and receive netgraph data packets, a
+.Dv NG_DATA
+socket must also be created using
+.Xr socket 2
+and associated with a
+.Nm socket
+node.
+.Dv NG_DATA sockets do not automatically
+have nodes associated with them; they are bound to a specific node via the
+.Xr connect 2
+system call. The address argument is the netgraph address of the
+.Nm socket
+node already created. Once a data socket is associated with a node,
+any data packets received by the node are read using
+.Xr recvfrom 2
+and any packets to be sent out from the node are written using
+.Xr sendto 2 .
+In the case of data sockets, the
+.Dv "struct sockaddr_ng"
+contains the name of the
+.Em hook
+on which the data was received or should be sent.
+.Pp
+There is a user library that simplifies using netgraph sockets; see
+.Xr netgraph 3 .
+.Sh HOOKS
+This node type supports hooks with arbitrary names (as long as
+they are unique) and always accepts hook connection requests.
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node type shuts down and disappears when both the associated
+.Dv NG_CONTROL
+and
+.Dv NG_DATA
+sockets have been closed, or a
+.Dv NGM_SHUTDOWN
+control message is received. In the latter case, attempts to write
+to the still-open sockets will return
+.Er ENOTCONN .
+.Sh BUGS
+It is not possible to reject the connection of a hook, though any
+data received on that hook can certainly be ignored.
+.Sh SEE ALSO
+.Xr socket 2 ,
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/tee/Makefile b/sys/modules/netgraph/tee/Makefile
new file mode 100644
index 0000000..118668f
--- /dev/null
+++ b/sys/modules/netgraph/tee/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:22 archie Exp $
+
+KMOD= ng_tee
+SRCS= ng_tee.c
+MAN8= ng_tee.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/tee/ng_tee.4 b/sys/modules/netgraph/tee/ng_tee.4
new file mode 100644
index 0000000..cfcb02f
--- /dev/null
+++ b/sys/modules/netgraph/tee/ng_tee.4
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_tee.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_TEE 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_tee
+.Nd netgraph ``tee'' node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_tee.h>
+.Sh DESCRIPTION
+The
+.Nm tee
+node type has a purpose similar to the
+.Xr tee 1
+command.
+.Nm Tee
+nodes are useful for debugging or ``snooping'' on a connection
+between two netgraph nodes.
+.Nm Tee
+nodes have four hooks,
+.Dv right ,
+.Dv left ,
+.Dv right2left ,
+and
+.Dv left2right .
+All data received on
+.Dv right
+is sent unmodified to
+.Em both
+hooks
+.Dv left
+and
+.Dv right2left .
+Similarly, all data received on
+.Dv left
+is sent unmodified to both
+.Dv right
+and
+.Dv left2right .
+.Pp
+Packets may also be received on
+.Dv right2left
+and
+.Dv left2right ;
+if so, they are forwarded unchanged out hooks
+.Dv left
+and
+.Dv right ,
+respectively.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbarfoo
+.It Dv right
+The connection to the node on the right.
+.It Dv left
+The connection to the node on the left.
+.It Dv right2left
+Tap for right to left traffic.
+.It Dv left2right
+Tap for left to right traffic.
+.El
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr tee 1 ,
+.Xr netgraph 4 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/tee/ng_tee.8 b/sys/modules/netgraph/tee/ng_tee.8
new file mode 100644
index 0000000..cfcb02f
--- /dev/null
+++ b/sys/modules/netgraph/tee/ng_tee.8
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_tee.8,v 1.4 1999/01/25 23:46:27 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_TEE 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_tee
+.Nd netgraph ``tee'' node type
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_tee.h>
+.Sh DESCRIPTION
+The
+.Nm tee
+node type has a purpose similar to the
+.Xr tee 1
+command.
+.Nm Tee
+nodes are useful for debugging or ``snooping'' on a connection
+between two netgraph nodes.
+.Nm Tee
+nodes have four hooks,
+.Dv right ,
+.Dv left ,
+.Dv right2left ,
+and
+.Dv left2right .
+All data received on
+.Dv right
+is sent unmodified to
+.Em both
+hooks
+.Dv left
+and
+.Dv right2left .
+Similarly, all data received on
+.Dv left
+is sent unmodified to both
+.Dv right
+and
+.Dv left2right .
+.Pp
+Packets may also be received on
+.Dv right2left
+and
+.Dv left2right ;
+if so, they are forwarded unchanged out hooks
+.Dv left
+and
+.Dv right ,
+respectively.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbarfoo
+.It Dv right
+The connection to the node on the right.
+.It Dv left
+The connection to the node on the left.
+.It Dv right2left
+Tap for right to left traffic.
+.It Dv left2right
+Tap for left to right traffic.
+.El
+.Sh CONTROL MESSAGES
+This node type supports only the generic control messages.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr tee 1 ,
+.Xr netgraph 4 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Julian Elisher <julian@whistle.com>
diff --git a/sys/modules/netgraph/tty/Makefile b/sys/modules/netgraph/tty/Makefile
new file mode 100644
index 0000000..5b9bd20
--- /dev/null
+++ b/sys/modules/netgraph/tty/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.2 1999/01/19 19:39:22 archie Exp $
+
+KMOD= ng_tty
+SRCS= ng_tty.c
+MAN8= ng_tty.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/tty/ng_tty.4 b/sys/modules/netgraph/tty/ng_tty.4
new file mode 100644
index 0000000..660b46c
--- /dev/null
+++ b/sys/modules/netgraph/tty/ng_tty.4
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_tty.8,v 1.5 1999/01/25 23:46:28 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_TTY 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_tty
+.Nd netgraph node type that is also a line discipline
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_message.h>
+.Fd #include <netgraph/ng_tty.h>
+.Sh DESCRIPTION
+The
+.Nm tty
+node type is both a netgraph node type and a line discipline.
+A new node is created when the corresponding line discipline is
+registered on a tty device (see
+.Xr tty 4 ")."
+.Pp
+The node has a single hook called
+.Dv hook .
+Incoming bytes received on the tty device are sent out on this hook,
+and frames received on
+.Dv hook
+are transmitted out on the tty device.
+No modification to the data is performed in either direction.
+While the line discipline is installed on a tty, the normal
+read and write operations are unavailable, returning
+.Er EIO .
+.Pp
+The node supports an optional ``hot character.'' If set to non-zero, incoming
+data from the tty device is queued until this character is seen.
+This avoids sending lots of mbufs containing a small number of bytes,
+but introduces potentially infinite latency.
+The default hot character is 0x7e, consistent with
+.Dv hook
+being connected to a
+.Xr ng_async 8
+type node. The hot character has no effect on the transmission of data.
+.Pp
+The node will attempt to give itself the same netgraph name as the name
+of the tty device.
+In any case, information about the node is available via the netgraph
+.Xr ioctl 2
+command
+.Dv NGIOCGINFO .
+This command returns a
+.Dv "struct nodeinfo"
+similar to the
+.Dv NGM_NODEINFO
+netgraph control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv hook
+.Xr tty 4
+serial data contained in
+.Dv mbuf
+structures, with arbitrary inter-frame boundaries.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_TTY_SET_HOTCHAR
+This command takes an integer argument and sets the hot character
+from the lower 8 bits. A hot character of zero disables queueing,
+so that all received data is forwarded immediately.
+.It Dv NGM_TTY_GET_HOTCHAR
+Returns an integer containing the current hot character in the lower
+eight bits.
+.Sh SHUTDOWN
+This node shuts down when the corresponding device is closed
+(or the line discipline is uninstalled on the device).
+The
+.Dv NGM_SHUTDOWN
+control message is not valid, and always returns the error
+.Er EOPNOTSUPP .
+.Sh BUGS
+The
+.Nm tty
+type registers its line discipline when the type is installed,
+where it is dynamically assigned an integer index.
+Unfortunately, there's no way to know what this integer is
+except by reading the output of
+.Xr dmesg 8 .
+The fix for this is to have line disciplines identified by
+unique ASCII strings instead of fixed integer constants,
+or else to assign one of those constants to
+.Nm ng_tty .
+.Pp
+The serial driver code also has a notion of a ``hot character.''
+Unfortunately, this value is statically defined in terms of the
+line discipline and cannot be changed.
+Therefore, if a hot character other than 0x7e (the default) is set for the
+.Nm tty
+node, the node has no way to convey this information to the
+serial driver, and sub-optimal performance may result.
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr netgraph 4 ,
+.Xr tty 4 ,
+.Xr ng_async 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/tty/ng_tty.8 b/sys/modules/netgraph/tty/ng_tty.8
new file mode 100644
index 0000000..660b46c
--- /dev/null
+++ b/sys/modules/netgraph/tty/ng_tty.8
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_tty.8,v 1.5 1999/01/25 23:46:28 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_TTY 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_tty
+.Nd netgraph node type that is also a line discipline
+.Sh SYNOPSIS
+.Fd #include <netgraph/ng_message.h>
+.Fd #include <netgraph/ng_tty.h>
+.Sh DESCRIPTION
+The
+.Nm tty
+node type is both a netgraph node type and a line discipline.
+A new node is created when the corresponding line discipline is
+registered on a tty device (see
+.Xr tty 4 ")."
+.Pp
+The node has a single hook called
+.Dv hook .
+Incoming bytes received on the tty device are sent out on this hook,
+and frames received on
+.Dv hook
+are transmitted out on the tty device.
+No modification to the data is performed in either direction.
+While the line discipline is installed on a tty, the normal
+read and write operations are unavailable, returning
+.Er EIO .
+.Pp
+The node supports an optional ``hot character.'' If set to non-zero, incoming
+data from the tty device is queued until this character is seen.
+This avoids sending lots of mbufs containing a small number of bytes,
+but introduces potentially infinite latency.
+The default hot character is 0x7e, consistent with
+.Dv hook
+being connected to a
+.Xr ng_async 8
+type node. The hot character has no effect on the transmission of data.
+.Pp
+The node will attempt to give itself the same netgraph name as the name
+of the tty device.
+In any case, information about the node is available via the netgraph
+.Xr ioctl 2
+command
+.Dv NGIOCGINFO .
+This command returns a
+.Dv "struct nodeinfo"
+similar to the
+.Dv NGM_NODEINFO
+netgraph control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobar
+.It Dv hook
+.Xr tty 4
+serial data contained in
+.Dv mbuf
+structures, with arbitrary inter-frame boundaries.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_TTY_SET_HOTCHAR
+This command takes an integer argument and sets the hot character
+from the lower 8 bits. A hot character of zero disables queueing,
+so that all received data is forwarded immediately.
+.It Dv NGM_TTY_GET_HOTCHAR
+Returns an integer containing the current hot character in the lower
+eight bits.
+.Sh SHUTDOWN
+This node shuts down when the corresponding device is closed
+(or the line discipline is uninstalled on the device).
+The
+.Dv NGM_SHUTDOWN
+control message is not valid, and always returns the error
+.Er EOPNOTSUPP .
+.Sh BUGS
+The
+.Nm tty
+type registers its line discipline when the type is installed,
+where it is dynamically assigned an integer index.
+Unfortunately, there's no way to know what this integer is
+except by reading the output of
+.Xr dmesg 8 .
+The fix for this is to have line disciplines identified by
+unique ASCII strings instead of fixed integer constants,
+or else to assign one of those constants to
+.Nm ng_tty .
+.Pp
+The serial driver code also has a notion of a ``hot character.''
+Unfortunately, this value is statically defined in terms of the
+line discipline and cannot be changed.
+Therefore, if a hot character other than 0x7e (the default) is set for the
+.Nm tty
+node, the node has no way to convey this information to the
+serial driver, and sub-optimal performance may result.
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr netgraph 4 ,
+.Xr tty 4 ,
+.Xr ng_async 8 ,
+.Xr ngctl 8 .
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/vjc/Makefile b/sys/modules/netgraph/vjc/Makefile
new file mode 100644
index 0000000..510337f
--- /dev/null
+++ b/sys/modules/netgraph/vjc/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# $Whistle: Makefile,v 1.1 1999/01/24 06:48:07 archie Exp $
+
+KMOD= ng_vjc
+SRCS= ng_vjc.c
+MAN8= ng_vjc.8
+KMODDEPS= netgraph
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/vjc/ng_vjc.4 b/sys/modules/netgraph/vjc/ng_vjc.4
new file mode 100644
index 0000000..bc0a8b1
--- /dev/null
+++ b/sys/modules/netgraph/vjc/ng_vjc.4
@@ -0,0 +1,188 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_vjc.8,v 1.4 1999/01/25 23:46:28 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_VJC 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_vjc
+.Nd Van Jacobsen compression netgraph node type
+.Sh SYNOPSIS
+.Fd #include <net/slcompress.h>
+.Fd #include <netgraph/ng_vjc.h>
+.Sh DESCRIPTION
+The
+.Nm vjc
+node type performs Van Jacobsen compresion, which is used
+over PPP, SLIP, and other point-to-point IP connections to
+compress TCP packet headers. The
+.Dv ip
+hook represents the uncompressed side of the node, while the
+.Dv vjcomp ,
+.Dv vjuncomp ,
+and
+.Dv vjip
+nodes represent the compressed side of the node. Packets received on the
+.Dv ip
+will be compressed or passed through as appropriate. Packets received
+on the other three hooks will be uncompressed as appropriate.
+.Pp
+Van Jacobsen compression only applies to TCP packets.
+Only ``normal'' (i.e., common case) TCP packets are actually compressed.
+These are output on the
+.Dv vjcomp
+hook. Other TCP packets are run through the state machine but not
+compressed; these appear on the
+.Dv vjuncomp
+hook.
+Other non-TCP IP packets are forwarded unchanged to
+.Dv vjip .
+.Pp
+When connecting to a
+.Xr ng_ppp 8
+node, the
+.Dv vjuncomp ,
+.Dv vjcomp ,
+and
+.Dv vjip
+nodes should be connected to the
+.Xr ng_ppp 8
+node's
+.Dv vjcomp ,
+.Dv vjuncomp ,
+and
+.Dv ip
+nodes, respectively.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazi
+.It Dv ip
+Upstream (uncompressed) IP packets.
+.It Dv vjcomp
+Downstream compressed TCP packets.
+.It Dv vjuncomp
+Downstream uncompressed TCP packets.
+.It Dv vjip
+Downstream uncompressed IP packets.
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_VJC_CONFIG
+This command resets the compression state and configures it according
+to the supplied
+.Dv "struct ngm_vjc_config"
+argument. This structure contains the following fields:
+.Bd -literal -offset 4n
+struct ngm_vjc_config {
+ u_char enabled; /* Enable compression/decompression */
+ u_char numChannels; /* Number of outgoing channels */
+ u_char compressCID; /* OK to compress outgoing CID's */
+};
+.Ed
+.Pp
+When
+.Dv enabled
+is set to zero, the node operates in ``pass through'' mode, only
+accepting packets on the
+.Dv ip
+and
+.Dv vjip
+hooks.
+.Dv numChannels
+should be set to the number of compression channels, and is a value
+between 3 and 16, inclusive.
+.Pp
+The
+.Dv compressCID
+field indicates whether it is OK to compress the CID field for
+outgoing compressed TCP packets. This value should be zero unless
+either (a) it not possible for an incoming frame to be lost, or
+(b) lost frames can be reliably detected and a
+.Dv NGM_VJC_RECV_ERROR
+mesages is immediately sent whenever this occurs.
+.It Dv NGM_VJC_GET_STATE
+This command returns the node's current state described by the
+.Dv "struct slcompress"
+structure, which is defined in
+.Dv "net/slcompress.h" .
+.It Dv NGM_VJC_CLR_STATS
+Clears the node statistics counters. Statistics are also cleared whenever the
+.Dv enabled
+field is changed from zero to one by a
+.Dv NGM_VJC_CONFIG
+control message.
+.It Dv NGM_VJC_RECV_ERROR
+When the
+.Dv compressCID
+is set to one, this message must be sent to the node immediately
+after detecting that a recieved frame has been lost, due to a bad
+checksum or for any other reason. Failing to do this can result
+in corrupted TCP stream data.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+This node type requires that the file
+.Dv "net/slcompress.c"
+was compiled into the kernel. Currently the only way to insure this
+is to include the
+.Dv slip ,
+.Dv ppp ,
+or
+.Dv i4bipr
+pseudo-devices in your kernel compilation. In the future there should
+be a kernel option that causes inclusion of this file without requiring
+one of these drivers.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_ppp 8 ,
+.Xr ng_iface 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A V. Jacobsen
+.%T "Compressing TCP/IP Headers"
+.%O RFC 1144
+.Re
+.Rs
+.%A G. McGregor
+.%T "The PPP Internet Control Protocol (IPCP)"
+.%O RFC 1332
+.Re
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/modules/netgraph/vjc/ng_vjc.8 b/sys/modules/netgraph/vjc/ng_vjc.8
new file mode 100644
index 0000000..bc0a8b1
--- /dev/null
+++ b/sys/modules/netgraph/vjc/ng_vjc.8
@@ -0,0 +1,188 @@
+.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
+.\" All rights reserved.
+.\"
+.\" Subject to the following obligations and disclaimer of warranty, use and
+.\" redistribution of this software, in source or object code forms, with or
+.\" without modifications are expressly permitted by Whistle Communications;
+.\" provided, however, that:
+.\" 1. Any and all reproductions of the source or object code must include the
+.\" copyright notice above and the following disclaimer of warranties; and
+.\" 2. No rights are granted, in any manner or form, to use Whistle
+.\" Communications, Inc. trademarks, including the mark "WHISTLE
+.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+.\" such appears in the above copyright notice or in the software.
+.\"
+.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+.\" OF SUCH DAMAGE.
+.\"
+.\" Author: Archie Cobbs <archie@whistle.com>
+.\"
+.\" $FreeBSD$
+.\" $Whistle: ng_vjc.8,v 1.4 1999/01/25 23:46:28 archie Exp $
+.\"
+.Dd January 19, 1999
+.Dt NG_VJC 8
+.Os FreeBSD 3
+.Sh NAME
+.Nm ng_vjc
+.Nd Van Jacobsen compression netgraph node type
+.Sh SYNOPSIS
+.Fd #include <net/slcompress.h>
+.Fd #include <netgraph/ng_vjc.h>
+.Sh DESCRIPTION
+The
+.Nm vjc
+node type performs Van Jacobsen compresion, which is used
+over PPP, SLIP, and other point-to-point IP connections to
+compress TCP packet headers. The
+.Dv ip
+hook represents the uncompressed side of the node, while the
+.Dv vjcomp ,
+.Dv vjuncomp ,
+and
+.Dv vjip
+nodes represent the compressed side of the node. Packets received on the
+.Dv ip
+will be compressed or passed through as appropriate. Packets received
+on the other three hooks will be uncompressed as appropriate.
+.Pp
+Van Jacobsen compression only applies to TCP packets.
+Only ``normal'' (i.e., common case) TCP packets are actually compressed.
+These are output on the
+.Dv vjcomp
+hook. Other TCP packets are run through the state machine but not
+compressed; these appear on the
+.Dv vjuncomp
+hook.
+Other non-TCP IP packets are forwarded unchanged to
+.Dv vjip .
+.Pp
+When connecting to a
+.Xr ng_ppp 8
+node, the
+.Dv vjuncomp ,
+.Dv vjcomp ,
+and
+.Dv vjip
+nodes should be connected to the
+.Xr ng_ppp 8
+node's
+.Dv vjcomp ,
+.Dv vjuncomp ,
+and
+.Dv ip
+nodes, respectively.
+.Sh HOOKS
+This node type supports the following hooks:
+.Pp
+.Bl -tag -width foobarbazi
+.It Dv ip
+Upstream (uncompressed) IP packets.
+.It Dv vjcomp
+Downstream compressed TCP packets.
+.It Dv vjuncomp
+Downstream uncompressed TCP packets.
+.It Dv vjip
+Downstream uncompressed IP packets.
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_VJC_CONFIG
+This command resets the compression state and configures it according
+to the supplied
+.Dv "struct ngm_vjc_config"
+argument. This structure contains the following fields:
+.Bd -literal -offset 4n
+struct ngm_vjc_config {
+ u_char enabled; /* Enable compression/decompression */
+ u_char numChannels; /* Number of outgoing channels */
+ u_char compressCID; /* OK to compress outgoing CID's */
+};
+.Ed
+.Pp
+When
+.Dv enabled
+is set to zero, the node operates in ``pass through'' mode, only
+accepting packets on the
+.Dv ip
+and
+.Dv vjip
+hooks.
+.Dv numChannels
+should be set to the number of compression channels, and is a value
+between 3 and 16, inclusive.
+.Pp
+The
+.Dv compressCID
+field indicates whether it is OK to compress the CID field for
+outgoing compressed TCP packets. This value should be zero unless
+either (a) it not possible for an incoming frame to be lost, or
+(b) lost frames can be reliably detected and a
+.Dv NGM_VJC_RECV_ERROR
+mesages is immediately sent whenever this occurs.
+.It Dv NGM_VJC_GET_STATE
+This command returns the node's current state described by the
+.Dv "struct slcompress"
+structure, which is defined in
+.Dv "net/slcompress.h" .
+.It Dv NGM_VJC_CLR_STATS
+Clears the node statistics counters. Statistics are also cleared whenever the
+.Dv enabled
+field is changed from zero to one by a
+.Dv NGM_VJC_CONFIG
+control message.
+.It Dv NGM_VJC_RECV_ERROR
+When the
+.Dv compressCID
+is set to one, this message must be sent to the node immediately
+after detecting that a recieved frame has been lost, due to a bad
+checksum or for any other reason. Failing to do this can result
+in corrupted TCP stream data.
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh BUGS
+This node type requires that the file
+.Dv "net/slcompress.c"
+was compiled into the kernel. Currently the only way to insure this
+is to include the
+.Dv slip ,
+.Dv ppp ,
+or
+.Dv i4bipr
+pseudo-devices in your kernel compilation. In the future there should
+be a kernel option that causes inclusion of this file without requiring
+one of these drivers.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_ppp 8 ,
+.Xr ng_iface 8 ,
+.Xr ngctl 8 .
+.Rs
+.%A V. Jacobsen
+.%T "Compressing TCP/IP Headers"
+.%O RFC 1144
+.Re
+.Rs
+.%A G. McGregor
+.%T "The PPP Internet Control Protocol (IPCP)"
+.%O RFC 1332
+.Re
+.Sh AUTHOR
+Archie Cobbs <archie@whistle.com>
diff --git a/sys/net/if_arp.h b/sys/net/if_arp.h
index 97902a7..52eeb26 100644
--- a/sys/net/if_arp.h
+++ b/sys/net/if_arp.h
@@ -102,6 +102,9 @@ struct arpcom {
struct ifnet ac_if; /* network-visible interface */
u_char ac_enaddr[6]; /* ethernet hardware address */
int ac_multicnt; /* length of ac_multiaddrs list */
+/* #ifdef NETGRAPH */
+ void *ac_ng; /* hook to hang netgraph stuff off */
+/* #endif */
};
extern u_char etherbroadcastaddr[6];
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 9d59287..04e3ea8 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -38,6 +38,7 @@
#include "opt_inet.h"
#include "opt_ipx.h"
#include "opt_bdg.h"
+#include "opt_netgraph.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -117,6 +118,43 @@ u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#define senderr(e) do { error = (e); goto bad;} while (0)
#define IFP2AC(IFP) ((struct arpcom *)IFP)
+#ifdef NETGRAPH
+#include <netgraph/ng_ether.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+
+static void ngether_init(void* ignored);
+static void ngether_send(struct arpcom *ac,
+ struct ether_header *eh, struct mbuf *m);
+static int ngether_constructor(node_p *nodep);
+static int ngether_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngether_rmnode(node_p node);
+static int ngether_newhook(node_p node, hook_p hook, const char *name);
+/*static hook_p ngether_findhook(node_p node, char *name);*/
+static int ngether_connect(hook_p hook); /* already PARTLY linked */
+static int ngether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngether_disconnect(hook_p hook); /* notify on disconnect */
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_ETHER_NODE_TYPE,
+ NULL,
+ ngether_constructor,
+ ngether_rcvmsg,
+ ngether_rmnode,
+ ngether_newhook,
+ NULL,
+ ngether_connect,
+ ngether_rcvdata,
+ ngether_rcvdata,
+ ngether_disconnect
+};
+
+#define AC2NG(AC) ((node_p)((AC)->ac_ng))
+#define NGEF_DIVERT NGF_TYPE1 /* all packets sent to netgraph */
+#endif /* NETGRAPH */
+
/*
* Ethernet output routine.
* Encapsulate a packet of type family for the local net.
@@ -456,6 +494,16 @@ ether_input(ifp, eh, m)
ether_type = ntohs(eh->ether_type);
+#ifdef NETGRAPH
+ {
+ struct arpcom *ac = IFP2AC(ifp);
+ if (AC2NG(ac) && (AC2NG(ac)->flags & NGEF_DIVERT)) {
+ ngether_send(ac, eh, m);
+ return;
+ }
+ }
+#endif /* NETGRAPH */
+
#if NVLAN > 0
if (ether_type == vlan_proto) {
if (vlan_input(eh, m) < 0)
@@ -640,11 +688,19 @@ ether_input(ifp, eh, m)
#endif /* LLC */
dropanyway:
default:
+#ifdef NETGRAPH
+ ngether_send(IFP2AC(ifp), eh, m);
+#else /* NETGRAPH */
m_freem(m);
+#endif /* NETGRAPH */
return;
}
#else /* ISO || LLC || NETATALK */
+#ifdef NETGRAPH
+ ngether_send(IFP2AC(ifp), eh, m);
+#else /* NETGRAPH */
m_freem(m);
+#endif /* NETGRAPH */
return;
#endif /* ISO || LLC || NETATALK */
}
@@ -844,3 +900,296 @@ ether_resolvemulti(ifp, llsa, sa)
return EAFNOSUPPORT;
}
}
+
+#ifdef NETGRAPH
+
+/***********************************************************************
+ * This section contains the methods for the Netgraph interface
+ ***********************************************************************/
+/* It's Ascii-art time!
+ * The ifnet is the first part of the arpcom which must be
+ * the first part of the device's softc.. yuk.
+ *
+ * +--------------------------+-----+---------+
+ * | struct ifnet (*ifp) | | |
+ * | | | |
+ * +--------------------------+ | |
+ * +--|[ac_ng] struct arpcom (*ac) | |
+ * | +--------------------------------+ |
+ * | | struct softc (*ifp->if_softc) (device) |
+ * | +------------------------------------------+
+ * | ^
+ * AC2NG() |
+ * | v
+ * | +----------------------+
+ * | | [private] [flags] |
+ * +------>| struct ng_node |
+ * | [hooks] | ** we only allow one hook
+ * +----------------------+
+ * ^
+ * |
+ * v
+ * +-------------+
+ * | [node] |
+ * | hook |
+ * | [private]|-- *unused*
+ * +-------------+
+ */
+
+/*
+ * called during interface attaching
+ */
+static void
+ngether_init(void *ifpvoid)
+{
+ struct ifnet *ifp = ifpvoid;
+ struct arpcom *ac = IFP2AC(ifp);
+ static int ngether_done_init;
+ char namebuf[32];
+ node_p node;
+
+ /*
+ * we have found a node, make sure our 'type' is availabe.
+ */
+ if (ngether_done_init == 0) {
+ if (ng_newtype(&typestruct)) {
+ printf("ngether install failed\n");
+ return;
+ }
+ ngether_done_init = 1;
+ }
+ if (ng_make_node_common(&typestruct, &node) != 0)
+ return;
+ ac->ac_ng = node;
+ node->private = ifp;
+ sprintf(namebuf, "%s%d", ifp->if_name, ifp->if_unit);
+ ng_name_node(AC2NG(ac), namebuf);
+}
+
+/*
+ * It is not possible or allowable to create a node of this type.
+ * If the hardware exists, it will already have created it.
+ */
+static int
+ngether_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * Give our ok for a hook to be added...
+ *
+ * Allow one hook at a time (rawdata).
+ * It can eiteh rdivert everything or only unclaimed packets.
+ */
+static int
+ngether_newhook(node_p node, hook_p hook, const char *name)
+{
+
+ /* check if there is already a hook */
+ if (LIST_FIRST(&(node->hooks)))
+ return(EISCONN);
+ /*
+ * Check for which mode hook we want.
+ */
+ if (strcmp(name, NG_ETHER_HOOK_ORPHAN) != 0) {
+ if (strcmp(name, NG_ETHER_HOOK_DIVERT) != 0) {
+ return (EINVAL);
+ }
+ node->flags |= NGEF_DIVERT;
+ } else {
+ node->flags &= ~NGEF_DIVERT;
+ }
+ return (0);
+}
+
+/*
+ * incoming messages.
+ * Just respond to the generic TEXT_STATUS message
+ */
+static int
+ngether_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
+{
+ struct ifnet *ifp;
+ int error = 0;
+
+ ifp = node->private;
+ switch (msg->header.typecookie) {
+ case NGM_ETHER_COOKIE:
+ error = EINVAL;
+ break;
+ case NGM_GENERIC_COOKIE:
+ switch(msg->header.cmd) {
+ case NGM_TEXT_STATUS: {
+ char *arg;
+ int pos = 0;
+ int resplen = sizeof(struct ng_mesg) + 512;
+ MALLOC(*resp, struct ng_mesg *, resplen,
+ M_NETGRAPH, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bzero(*resp, resplen);
+ arg = (*resp)->data;
+
+ /*
+ * Put in the throughput information.
+ */
+ pos = sprintf(arg, "%ld bytes in, %ld bytes out\n",
+ ifp->if_ibytes, ifp->if_obytes);
+ pos += sprintf(arg + pos,
+ "%ld output errors\n",
+ ifp->if_oerrors);
+ pos += sprintf(arg + pos,
+ "ierrors = %ld\n",
+ ifp->if_ierrors);
+
+ (*resp)->header.version = NG_VERSION;
+ (*resp)->header.arglen = strlen(arg) + 1;
+ (*resp)->header.token = msg->header.token;
+ (*resp)->header.typecookie = NGM_ETHER_COOKIE;
+ (*resp)->header.cmd = msg->header.cmd;
+ strncpy((*resp)->header.cmdstr, "status",
+ NG_CMDSTRLEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ free(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Receive a completed ethernet packet.
+ * Queue it for output.
+ */
+static int
+ngether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ struct ifnet *ifp;
+ int error = 0;
+ int s;
+ struct ether_header *eh;
+
+ ifp = hook->node->private;
+
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+ senderr(ENETDOWN);
+ /*
+ * If a simplex interface, and the packet is being sent to our
+ * Ethernet address or a broadcast address, loopback a copy.
+ * XXX To make a simplex device behave exactly like a duplex
+ * device, we should copy in the case of sending to our own
+ * ethernet address (thus letting the original actually appear
+ * on the wire). However, we don't do that here for security
+ * reasons and compatibility with the original behavior.
+ */
+ if (ifp->if_flags & IFF_SIMPLEX) {
+ eh = mtod(m, struct ether_header *);
+ if (m->m_flags & M_BCAST) {
+ struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
+
+ ng_queue_data(hook, n, meta);
+ } else if (bcmp(eh->ether_dhost,
+ eh->ether_shost, ETHER_ADDR_LEN) == 0) {
+ ng_queue_data(hook, m, meta);
+ return (0); /* XXX */
+ }
+ }
+ s = splimp();
+ /*
+ * Queue message on interface, and start output if interface
+ * not yet active.
+ * XXX if we lookead at the priority in the meta data we could
+ * queue high priority items at the head.
+ */
+ if (IF_QFULL(&ifp->if_snd)) {
+ IF_DROP(&ifp->if_snd);
+ splx(s);
+ senderr(ENOBUFS);
+ }
+ IF_ENQUEUE(&ifp->if_snd, m);
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ splx(s);
+ ifp->if_obytes += m->m_pkthdr.len;
+ if (m->m_flags & M_MCAST)
+ ifp->if_omcasts++;
+ return (error);
+
+bad:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * pass an mbuf out to the connected hook
+ */
+static void
+ngether_send(struct arpcom *ac, struct ether_header *eh, struct mbuf *m)
+{
+ node_p node = AC2NG(ac);
+ struct ether_header *eh2;
+
+ if (node && LIST_FIRST(&(node->hooks))) {
+ M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
+ if (m == 0)
+ return;
+ eh2 = mtod(m, struct ether_header *);
+ /*
+ * Possibly 'eh' already points
+ * to the right place.
+ */
+ if (eh2 != eh)
+ bcopy(eh, eh2, sizeof(*eh));
+ ng_queue_data(LIST_FIRST(&(node->hooks)), m, NULL);
+ } else {
+ m_freem(m);
+ }
+}
+/*
+ * do local shutdown processing..
+ * This node will refuse to go away, unless the hardware says to..
+ * don't unref the node, or remove our name. just clear our links up.
+ */
+static int
+ngether_rmnode(node_p node)
+{
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/* already linked */
+static int
+ngether_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * notify on hook disconnection (destruction)
+ *
+ * For this type, removal of the last lins no effect. The interface can run
+ * independently.
+ * Since we have no per-hook information, this is rather simple.
+ */
+static int
+ngether_disconnect(hook_p hook)
+{
+ hook->node->flags &= ~NGEF_DIVERT;
+ return (0);
+}
+#endif /* NETGRAPH */
+
+/********************************** END *************************************/
diff --git a/sys/net/netisr.h b/sys/net/netisr.h
index 9ad7f6b..d09f31d 100644
--- a/sys/net/netisr.h
+++ b/sys/net/netisr.h
@@ -67,6 +67,7 @@
#define NETISR_ISDN 26 /* same as AF_E164 */
#define NETISR_PPP 27 /* PPP soft interrupt */
#define NETISR_NATM 29 /* same as AF_NATM */
+#define NETISR_NETGRAPH 31 /* same as AF_NETGRAPH */
#define schednetisr(anisr) { netisr |= 1<<(anisr); setsoftnet(); }
diff --git a/sys/netgraph/NOTES b/sys/netgraph/NOTES
new file mode 100644
index 0000000..69d8b71
--- /dev/null
+++ b/sys/netgraph/NOTES
@@ -0,0 +1,81 @@
+$FreeBSD$
+Development ideas..
+
+Archie's suggestions... :-)
+
+ - There should be a new malloc type: M_NETGRAPH
+ [DONE]
+ - all mallocs/frees now changed to use this.. JRE
+ - might further split them out some time.
+
+ - Use MALLOC and FREE macros instead of direct function calls
+ [DONE]
+ - They allow conditional compilation which keeps
+ statistics & counters on various memory allocation
+ (or so it seems)
+
+ - In struct ng_mesg: at least make "header" into "hdr", if not
+ getting rid of it altogether. It doesn't seem necessary and
+ makes all my C code lines too long.
+
+ - I understand.. one thought however.. consider..
+ if char data[0] were not legal, so that data[1] needed to be
+ used instead, then the only way to get the size of the header
+ would be sizeof(msg.header) as sizeof(msg) would include the dummy
+ following bytes. this is a portability issue and I hope
+ it will be ported eventually :)
+
+ - Baloney! you can use sizeof(msg) - 1 then.. or just
+ make it a macro, then its always portable:
+
+ #ifdef __GNU_C__
+ #define NG_MSG_HDR_SIZE (sizeof(struct ng_message))
+ #else
+ #define NG_MSG_HDR_SIZE (sizeof(struct ng_message) - 1)
+ #endif
+
+ - Have a user level program to print out and manipulate nodes, etc.
+ - [DONE]
+ see ngctl
+
+ - "Netgraph global" flags to turn on tracing, etc.
+
+ - ngctl needs to be rewritten using libnetgraph. Also it needs a
+ command to list all existing nodes (in case you don't know the
+ name of what you're looking for).
+ [DONE]
+
+ - Need a way to get a list of ALL nodes.
+ [DONE]
+ - see NGM_LISTNODES
+
+ - Enhance "netstat" to display all netgraph nodes -- or at least
+ all netgraph socket nodes.
+ [DONE]
+
+ - BUG FIX: bind() on a socket should neither require nor allow a
+ colon character at the end of the name. Note ngctl allows you
+ to do it either way!
+ [DONE] (I think)
+
+ - Need to implement passing meta information through socket nodes
+ using sendmsg() and recvmsg().
+
+ - Stuff needing to be added to manual:
+
+ - Awareness of SPL level, use ng_queue*() functions when necessary.
+ - Malloc all memory with type M_NETGRAPH.
+ - Write code so it can be an LKM or built into the kernel.. this means
+ be careful with things like #ifdef INET.
+ - All nodes assume that all data mbufs have the M_PKTHDR flag set!
+ The ng_send_data() and related functions should have an
+ #ifdef DIAGNOSTICS check to check this assumption for every mbuf.
+ - More generally, netgraph code should make liberal use of the
+ #ifdef DIAGNOSTICS definition.
+ - Since data and messages are sent functionally, programmers need
+ to watch out for infinite feedback loops. Should ng_base.c detect
+ this automatically?
+ - I've been thinking about this. each node could have a 'colour'
+ which is set to the colour of the packet as you pass through.
+ hitting a node already of your colour would abort. Each packet
+ has another (incremented) colour.
diff --git a/sys/netgraph/netgraph.h b/sys/netgraph/netgraph.h
new file mode 100644
index 0000000..e5e04e6
--- /dev/null
+++ b/sys/netgraph/netgraph.h
@@ -0,0 +1,255 @@
+
+/*
+ * netgraph.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: netgraph.h,v 1.24 1999/01/28 23:54:52 julian Exp $
+ */
+
+#ifndef _NETGRAPH_NETGRAPH_H_
+#define _NETGRAPH_NETGRAPH_H_ 1
+
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+
+#ifndef KERNEL
+#error "This file should not be included in user level programs"
+#endif
+
+/*
+ * Structure of a hook
+ */
+struct ng_hook {
+ char *name; /* what this node knows this link as */
+ void *private; /* node dependant ID for this hook */
+ int flags; /* info about this hook/link */
+ int refs; /* dont actually free this till 0 */
+ struct ng_hook *peer; /* the other end of this link */
+ struct ng_node *node; /* The node this hook is attached to */
+ LIST_ENTRY(ng_hook) hooks; /* linked list of all hooks on node */
+};
+typedef struct ng_hook *hook_p;
+
+/* Flags for a hook */
+#define HK_INVALID 0x0001 /* don't trust it! */
+
+/*
+ * Structure of a node
+ */
+struct ng_node {
+ char *name; /* optional globally unique name */
+ struct ng_type *type; /* the installed 'type' */
+ int flags; /* see below for bit definitions */
+ int sleepers; /* #procs sleeping on this node */
+ int refs; /* number of references to this node */
+ int numhooks; /* number of hooks */
+ int colour; /* for graph colouring algorithms */
+ void *private; /* node type dependant node ID */
+ LIST_HEAD(hooks, ng_hook) hooks; /* linked list of node hooks */
+ LIST_ENTRY(ng_node) nodes; /* linked list of all nodes */
+};
+typedef struct ng_node *node_p;
+
+/* Flags for a node */
+#define NG_INVALID 0x001 /* free when all sleepers and refs go to 0 */
+#define NG_BUSY 0x002 /* callers should sleep or wait */
+#define NG_TOUCHED 0x004 /* to avoid cycles when 'flooding' */
+#define NGF_TYPE1 0x10000000 /* reserved for type specific storage */
+#define NGF_TYPE2 0x20000000 /* reserved for type specific storage */
+#define NGF_TYPE3 0x40000000 /* reserved for type specific storage */
+#define NGF_TYPE4 0x80000000 /* reserved for type specific storage */
+
+/*
+ * The structure that holds meta_data about a data packet (e.g. priority)
+ * Nodes might add or subtract options as needed if there is room.
+ * They might reallocate the struct to make more room if they need to.
+ * Meta-data is still experimental.
+ */
+struct meta_field_header {
+ u_long cookie; /* cookie for the field. Skip fields you don't
+ * know about (same cookie as in messgaes) */
+ u_short type; /* field ID */
+ u_short len; /* total len of this field including extra
+ * data */
+ char data[0]; /* data starts here */
+};
+
+/* To zero out an option 'in place' set it's cookie to this */
+#define INVALID_COOKIE 865455152
+
+/* This part of the metadata is always present if the pointer is non NULL */
+struct ng_meta {
+ char priority; /* -ve is less priority, 0 is default */
+ char discardability; /* higher is less valuable.. discard first */
+ u_short allocated_len; /* amount malloc'd */
+ u_short used_len; /* sum of all fields, options etc. */
+ u_short flags; /* see below.. generic flags */
+ struct meta_field_header options[0]; /* add as (if) needed */
+};
+typedef struct ng_meta *meta_p;
+
+/* Flags for meta-data */
+#define NGMF_TEST 0x01 /* discard at the last moment before sending */
+#define NGMF_TRACE 0x02 /* trace when handing this data to a node */
+
+/*
+ * Structure of a node type
+ */
+struct ng_type {
+
+ /* Netgraph version number (must equal NG_VERSION) */
+ u_int32_t version;
+
+ /* Unique type name */
+ const char *name;
+
+ /* Module event handler (optional) */
+ modeventhand_t mod_event;
+
+ /* Node constructor */
+ int (*constructor)(node_p *node);
+
+ /* Calls using the node */
+ int (*rcvmsg)(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+ int (*shutdown)(node_p node);
+ int (*newhook)(node_p node, hook_p hook, const char *name);
+ hook_p (*findhook)(node_p node, const char *name);
+
+ /* Calls using the hook */
+ int (*connect)(hook_p hook); /* already linked in */
+ int (*rcvdata)(hook_p hook, struct mbuf *m, meta_p meta);
+ int (*rcvdataq)(hook_p hook, struct mbuf *m, meta_p meta);
+ int (*disconnect)(hook_p hook); /* notify on disconnect */
+
+ /* These are private to the base netgraph code */
+ LIST_ENTRY(ng_type) types; /* linked list of all types */
+ int refs; /* number of instances */
+};
+
+/* Send data packet with meta-data */
+#define NG_SEND_DATA(error, hook, m, a) \
+ do { \
+ (error) = ng_send_data((hook), (m), (a)); \
+ (m) = NULL; \
+ (a) = NULL; \
+ } while (0)
+
+/* Send queued data packet with meta-data */
+#define NG_SEND_DATAQ(error, hook, m, a) \
+ do { \
+ (error) = ng_send_dataq((hook), (m), (a)); \
+ (m) = NULL; \
+ (a) = NULL; \
+ } while (0)
+
+/* Free metadata */
+#define NG_FREE_META(a) \
+ do { \
+ if ((a)) { \
+ FREE((a), M_NETGRAPH); \
+ a = NULL; \
+ } \
+ } while (0)
+
+/* Free any data packet and/or meta-data */
+#define NG_FREE_DATA(m, a) \
+ do { \
+ if ((m)) { \
+ m_freem((m)); \
+ m = NULL; \
+ } \
+ NG_FREE_META((a)); \
+ } while (0)
+
+/*
+ * Use the NETGRAPH_INIT() macro to link a node type into the
+ * netgraph system. This works for types compiled into the kernel
+ * as well as KLD modules. The first argument should be the type
+ * name (eg, echo) and the second a pointer to the type struct.
+ *
+ * If a different link time is desired, e.g., a device driver that
+ * needs to install its netgraph type before probing, use the
+ * NETGRAPH_INIT_ORDERED() macro instead. Deivce drivers probably
+ * want to use SI_SUB_DRIVERS instead of SI_SUB_PSEUDO.
+ */
+
+#define NETGRAPH_INIT_ORDERED(typename, typestructp, sub, order) \
+static moduledata_t ng_##typename##_mod = { \
+ "ng_" #typename, \
+ ng_mod_event, \
+ (typestructp) \
+}; \
+DECLARE_MODULE(ng_##typename, ng_##typename##_mod, sub, order)
+
+#define NETGRAPH_INIT(tn, tp) \
+ NETGRAPH_INIT_ORDERED(tn, tp, SI_SUB_PSEUDO, SI_ORDER_ANY)
+
+/* Special malloc() type for netgraph structs and ctrl messages */
+MALLOC_DECLARE(M_NETGRAPH);
+
+void ng_cutlinks(node_p node);
+int ng_con_nodes(node_p node,
+ const char *name, node_p node2, const char *name2);
+void ng_destroy_hook(hook_p hook);
+node_p ng_findname(node_p node, const char *name);
+struct ng_type *ng_findtype(const char *type);
+int ng_make_node(const char *type, node_p *nodepp);
+int ng_make_node_common(struct ng_type *typep, node_p *nodep);
+int ng_mkpeer(node_p node, const char *name, const char *name2, char *type);
+int ng_mod_event(module_t mod, int what, void *arg);
+int ng_name_node(node_p node, const char *name);
+int ng_newtype(struct ng_type *tp);
+int ng_path2node(node_p here, const char *path, node_p *dest, char **rtnp);
+int ng_path_parse(char *addr, char **node, char **path, char **hook);
+int ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta);
+int ng_queue_msg(node_p here, struct ng_mesg *msg, int len,
+ const char *address);
+void ng_release_node(node_p node);
+void ng_rmnode(node_p node);
+int ng_send_data(hook_p hook, struct mbuf *m, meta_p meta);
+int ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta);
+int ng_send_msg(node_p here, struct ng_mesg *msg,
+ const char *address, struct ng_mesg **resp);
+void ng_unname(node_p node);
+void ng_unref(node_p node);
+int ng_bypass(hook_p hook1, hook_p hook2);
+int ng_wait_node(node_p node, char *msg);
+
+#endif /* _NETGRAPH_NETGRAPH_H_ */
+
diff --git a/sys/netgraph/ng_UI.c b/sys/netgraph/ng_UI.c
new file mode 100644
index 0000000..7295b4a
--- /dev/null
+++ b/sys/netgraph/ng_UI.c
@@ -0,0 +1,242 @@
+
+/*
+ * ng_UI.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_UI.c,v 1.11 1999/01/28 23:54:52 julian Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_UI.h>
+
+/*
+ * DEFINITIONS
+ */
+
+/* Everything, starting with sdlc on has defined UI as 0x03 */
+#define HDLC_UI 0x03
+
+/* Node private data */
+struct private {
+ hook_p downlink;
+ hook_p uplink;
+};
+typedef struct private *priv_p;
+
+/* Netgraph node methods */
+static int ng_UI_constructor(node_p *nodep);
+static int ng_UI_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_UI_rmnode(node_p node);
+static int ng_UI_newhook(node_p node, hook_p hook, const char *name);
+static int ng_UI_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_UI_disconnect(hook_p hook);
+
+/* Node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_UI_NODE_TYPE,
+ NULL,
+ ng_UI_constructor,
+ ng_UI_rcvmsg,
+ ng_UI_rmnode,
+ ng_UI_newhook,
+ NULL,
+ NULL,
+ ng_UI_rcvdata,
+ ng_UI_rcvdata,
+ ng_UI_disconnect
+};
+NETGRAPH_INIT(UI, &typestruct);
+
+/************************************************************************
+ NETGRAPH NODE STUFF
+ ************************************************************************/
+
+/*
+ * Create a newborn node. We start with an implicit reference.
+ */
+
+static int
+ng_UI_constructor(node_p *nodep)
+{
+ priv_p priv;
+ int error;
+
+ /* Allocate private structure */
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
+ if (priv == NULL)
+ return (ENOMEM);
+ bzero(priv, sizeof(*priv));
+
+ /* Call generic node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(priv, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = priv;
+
+ /* Done */
+ return (0);
+}
+
+/*
+ * Give our ok for a hook to be added
+ */
+static int
+ng_UI_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p priv = node->private;
+
+ if (!strcmp(name, NG_UI_HOOK_DOWNSTREAM)) {
+ if (priv->downlink)
+ return (EISCONN);
+ priv->downlink = hook;
+ } else if (!strcmp(name, NG_UI_HOOK_UPSTREAM)) {
+ if (priv->uplink)
+ return (EISCONN);
+ priv->uplink = hook;
+ } else
+ return (EINVAL);
+ return (0);
+}
+
+/*
+ * Receive a control message
+ */
+static int
+ng_UI_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *raddr, struct ng_mesg **rp)
+{
+ FREE(msg, M_NETGRAPH);
+ return (EINVAL);
+}
+
+#define MAX_ENCAPS_HDR 1
+#define ERROUT(x) do { error = (x); goto done; } while (0)
+
+/*
+ * Receive a data frame
+ */
+static int
+ng_UI_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const node_p node = hook->node;
+ const priv_p priv = node->private;
+ int error = 0;
+
+ if (hook == priv->downlink) {
+ u_char *start, *ptr;
+
+ if (!m || !(m = m_pullup(m, MAX_ENCAPS_HDR)))
+ ERROUT(ENOBUFS);
+ ptr = start = mtod(m, u_char *);
+
+ /* Must be UI frame */
+ if (*ptr++ != HDLC_UI)
+ ERROUT(0);
+
+ m_adj(m, ptr - start);
+ NG_SEND_DATA(error, priv->uplink, m, meta); /* m -> NULL */
+ } else if (hook == priv->uplink) {
+ M_PREPEND(m, 1, M_DONTWAIT); /* Prepend IP NLPID */
+ if (!m)
+ ERROUT(ENOBUFS);
+ mtod(m, u_char *)[0] = HDLC_UI;
+ NG_SEND_DATA(error, priv->downlink, m, meta); /* m -> NULL */
+ } else
+ panic(__FUNCTION__);
+
+done:
+ NG_FREE_DATA(m, meta); /* does nothing if m == NULL */
+ return (error);
+}
+
+/*
+ * Shutdown node
+ */
+static int
+ng_UI_rmnode(node_p node)
+{
+ const priv_p priv = node->private;
+
+ /* Take down netgraph node */
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ bzero(priv, sizeof(*priv));
+ FREE(priv, M_NETGRAPH);
+ node->private = NULL;
+ ng_unref(node);
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ng_UI_disconnect(hook_p hook)
+{
+ const priv_p priv = hook->node->private;
+
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ else if (hook == priv->downlink)
+ priv->downlink = NULL;
+ else if (hook == priv->uplink)
+ priv->uplink = NULL;
+ else
+ panic(__FUNCTION__);
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_UI.h b/sys/netgraph/ng_UI.h
new file mode 100644
index 0000000..f41e5a9
--- /dev/null
+++ b/sys/netgraph/ng_UI.h
@@ -0,0 +1,55 @@
+
+/*
+ * ng_UI.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_UI.h,v 1.6 1999/01/20 00:54:15 archie Exp $
+ */
+
+#ifndef _NETGRAPH_UI_H_
+#define _NETGRAPH_UI_H_
+
+/* Node type name and cookie */
+#define NG_UI_NODE_TYPE "UI"
+#define NGM_UI_NODE_COOKIE 884639499
+
+/* Hook names */
+#define NG_UI_HOOK_DOWNSTREAM "downstream"
+#define NG_UI_HOOK_UPSTREAM "upstream"
+
+#endif /* _NETGRAPH_UI_H_ */
+
diff --git a/sys/netgraph/ng_async.c b/sys/netgraph/ng_async.c
new file mode 100644
index 0000000..5dae651
--- /dev/null
+++ b/sys/netgraph/ng_async.c
@@ -0,0 +1,586 @@
+
+/*
+ * ng_async.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_async.c,v 1.15 1999/01/28 23:54:52 julian Exp $
+ */
+
+/*
+ * This node type implements a PPP style sync <-> async converter.
+ * See RFC 1661 for details of how asynchronous encoding works.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/tty.h>
+#include <sys/syslog.h>
+#include <sys/errno.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_async.h>
+
+#include <net/ppp_defs.h>
+
+/* Optimize opening and closing flags into one? Set to max # seconds delay */
+#define SYNC_OPT_TIME 1 /* one second maximum */
+
+/* Async decode state */
+#define MODE_HUNT 0
+#define MODE_NORMAL 1
+#define MODE_ESC 2
+
+/* Private data structure */
+struct private {
+ node_p node; /* Our node */
+ hook_p async; /* Asynchronous side */
+ hook_p sync; /* Synchronous side */
+ hook_p sync2; /* Synchronous side, full escapes */
+ u_char amode; /* Async hunt/esape mode */
+ u_int16_t fcs; /* Decoded async FCS (so far) */
+ u_char *abuf; /* Buffer to encode sync into */
+ u_char *sbuf; /* Buffer to decode async into */
+ u_int slen; /* Length of data in sbuf */
+#if SYNC_OPT_TIME
+ long lasttime; /* Time of last async packet sent */
+#endif
+ struct ng_async_cfg cfg; /* Configuration */
+ struct ng_async_stat stats; /* Statistics */
+};
+typedef struct private *sc_p;
+
+/* Useful macros */
+#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10)
+#define SYNC_BUF_SIZE(amru) ((amru) + 10)
+#define ERROUT(x) do { error = (x); goto done; } while (0)
+
+/* Netgraph methods */
+static int nga_constructor(node_p *node);
+static int nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int nga_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *rtn, struct ng_mesg **resp);
+static int nga_shutdown(node_p node);
+static int nga_newhook(node_p node, hook_p hook, const char *name);
+static int nga_disconnect(hook_p hook);
+
+/* Helper stuff */
+static int nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
+static int nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
+
+/* Define the netgraph node type */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_ASYNC_NODE_TYPE,
+ NULL,
+ nga_constructor,
+ nga_rcvmsg,
+ nga_shutdown,
+ nga_newhook,
+ NULL,
+ NULL,
+ nga_rcvdata,
+ nga_rcvdata,
+ nga_disconnect
+};
+NETGRAPH_INIT(async, &typestruct);
+
+/* CRC table */
+static const u_int16_t fcstab[];
+
+/******************************************************************
+ NETGRAPH NODE METHODS
+******************************************************************/
+
+/*
+ * Initialize a new node
+ */
+static int
+nga_constructor(node_p *nodep)
+{
+ sc_p sc;
+ int error;
+
+ if ((error = ng_make_node_common(&typestruct, nodep)))
+ return (error);
+ MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
+ if (sc == NULL)
+ return (ENOMEM);
+ bzero(sc, sizeof(*sc));
+ sc->amode = MODE_HUNT;
+ sc->cfg.accm = ~0;
+ sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
+ sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
+ MALLOC(sc->abuf, u_char *,
+ ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_WAITOK);
+ if (sc->abuf == NULL)
+ goto fail;
+ MALLOC(sc->sbuf, u_char *,
+ SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_WAITOK);
+ if (sc->sbuf == NULL) {
+ FREE(sc->abuf, M_NETGRAPH);
+fail:
+ FREE(sc, M_NETGRAPH);
+ return (ENOMEM);
+ }
+ (*nodep)->private = sc;
+ sc->node = *nodep;
+ return (0);
+}
+
+/*
+ * Reserve a hook for a pending connection
+ */
+static int
+nga_newhook(node_p node, hook_p hook, const char *name)
+{
+ const sc_p sc = node->private;
+ hook_p *hookp;
+
+ if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
+ hookp = &sc->async;
+ else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
+ hookp = &sc->sync;
+ else if (!strcmp(name, NG_ASYNC_HOOK_SYNC2))
+ hookp = &sc->sync2;
+ else
+ return (EINVAL);
+ if (*hookp)
+ return (EISCONN);
+ *hookp = hook;
+ return (0);
+}
+
+/*
+ * Receive incoming data
+ */
+static int
+nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const sc_p sc = hook->node->private;
+
+ if (hook == sc->sync)
+ return (nga_rcv_sync(sc, m, meta));
+ else if (hook == sc->sync2) {
+ const u_char acfcompSave = sc->cfg.acfcomp;
+ const u_int32_t accmSave = sc->cfg.accm;
+ int rtn;
+
+ sc->cfg.acfcomp = 0;
+ sc->cfg.accm = ~0;
+ rtn = nga_rcv_sync(sc, m, meta);
+ sc->cfg.acfcomp = acfcompSave;
+ sc->cfg.accm = accmSave;
+ return (rtn);
+ } else if (hook == sc->async)
+ return (nga_rcv_async(sc, m, meta));
+ panic(__FUNCTION__);
+}
+
+/*
+ * Receive incoming control message
+ */
+static int
+nga_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *rtn, struct ng_mesg **rptr)
+{
+ const sc_p sc = (sc_p) node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ switch (msg->header.typecookie) {
+ case NGM_ASYNC_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_ASYNC_CMD_GET_STATS:
+ NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
+ if (resp == NULL)
+ ERROUT(ENOMEM);
+ *((struct ng_async_stat *) resp->data) = sc->stats;
+ break;
+ case NGM_ASYNC_CMD_CLR_STATS:
+ bzero(&sc->stats, sizeof(sc->stats));
+ break;
+ case NGM_ASYNC_CMD_SET_CONFIG:
+ {
+ struct ng_async_cfg *const cfg =
+ (struct ng_async_cfg *) msg->data;
+ u_char *buf;
+
+ if (msg->header.arglen != sizeof(*cfg))
+ ERROUT(EINVAL);
+ if (cfg->amru < NG_ASYNC_MIN_MRU
+ || cfg->amru > NG_ASYNC_MAX_MRU
+ || cfg->smru < NG_ASYNC_MIN_MRU
+ || cfg->smru > NG_ASYNC_MAX_MRU)
+ ERROUT(EINVAL);
+ cfg->enabled = !!cfg->enabled; /* normalize */
+ cfg->acfcomp = !!cfg->acfcomp; /* normalize */
+ if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */
+ MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru),
+ M_NETGRAPH, M_NOWAIT);
+ if (!buf)
+ ERROUT(ENOMEM);
+ FREE(sc->abuf, M_NETGRAPH);
+ sc->abuf = buf;
+ }
+ if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */
+ MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru),
+ M_NETGRAPH, M_NOWAIT);
+ if (!buf)
+ ERROUT(ENOMEM);
+ FREE(sc->sbuf, M_NETGRAPH);
+ sc->sbuf = buf;
+ sc->amode = MODE_HUNT;
+ sc->slen = 0;
+ }
+ if (!cfg->enabled) {
+ sc->amode = MODE_HUNT;
+ sc->slen = 0;
+ }
+ sc->cfg = *cfg;
+ break;
+ }
+ case NGM_ASYNC_CMD_GET_CONFIG:
+ NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
+ if (!resp)
+ ERROUT(ENOMEM);
+ *((struct ng_async_cfg *) resp->data) = sc->cfg;
+ break;
+ default:
+ ERROUT(EINVAL);
+ }
+ break;
+ default:
+ ERROUT(EINVAL);
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+done:
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Shutdown this node
+ */
+static int
+nga_shutdown(node_p node)
+{
+ const sc_p sc = node->private;
+
+ ng_cutlinks(node);
+ ng_unname(node);
+ FREE(sc->abuf, M_NETGRAPH);
+ FREE(sc->sbuf, M_NETGRAPH);
+ bzero(sc, sizeof(*sc));
+ FREE(sc, M_NETGRAPH);
+ node->private = NULL;
+ ng_unref(node);
+ return (0);
+}
+
+/*
+ * Lose a hook. When both hooks go away, we disappear.
+ */
+static int
+nga_disconnect(hook_p hook)
+{
+ const sc_p sc = hook->node->private;
+ hook_p *hookp;
+
+ if (hook == sc->async)
+ hookp = &sc->async;
+ else if (hook == sc->sync)
+ hookp = &sc->sync;
+ else if (hook == sc->sync2)
+ hookp = &sc->sync2;
+ else
+ panic(__FUNCTION__);
+ if (!*hookp)
+ panic(__FUNCTION__ "2");
+ *hookp = NULL;
+ bzero(&sc->stats, sizeof(sc->stats));
+#if SYNC_OPT_TIME
+ sc->lasttime = 0;
+#endif
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
+/******************************************************************
+ INTERNAL HELPER STUFF
+******************************************************************/
+
+/*
+ * Encode a byte into the async buffer
+ */
+static __inline__ void
+nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
+{
+ *fcs = PPP_FCS(*fcs, x);
+ if ((x < 32 && ((1 << x) & accm))
+ || (x == PPP_ESCAPE)
+ || (x == PPP_FLAG)) {
+ sc->abuf[(*len)++] = PPP_ESCAPE;
+ x ^= PPP_TRANS;
+ }
+ sc->abuf[(*len)++] = x;
+}
+
+/*
+ * Receive incoming synchronous data. Any "meta" information means
+ * for us to apply full ACCM to this frame.
+ */
+static int
+nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
+{
+ struct ifnet *const rcvif = m->m_pkthdr.rcvif;
+ u_int16_t fcs, fcs0;
+ int alen, error = 0;
+
+#define ADD_BYTE(x) \
+ nga_async_add(sc, &fcs, meta ? ~0 : sc->cfg.accm, &alen, (x))
+
+ if (!sc->cfg.enabled) {
+ NG_SEND_DATA(error, sc->async, m, meta);
+ return (error);
+ }
+ if (m->m_pkthdr.len > sc->cfg.smru) {
+ sc->stats.syncOverflows++;
+ NG_FREE_DATA(m, meta);
+ return (EMSGSIZE);
+ }
+ sc->stats.syncFrames++;
+ sc->stats.syncOctets += m->m_pkthdr.len;
+
+ /* Initialize async encoded version of input mbuf */
+ alen = 0;
+ fcs = PPP_INITFCS;
+
+ /* Add beginning sync flag if it's been long enough to need one */
+#if SYNC_OPT_TIME
+ {
+ struct timeval time;
+
+ getmicrotime(&time);
+ if (time.tv_sec >= sc->lasttime + SYNC_OPT_TIME) {
+ sc->abuf[alen++] = PPP_FLAG;
+ sc->lasttime = time.tv_sec;
+ }
+ }
+#else
+ sc->abuf[alen++] = PPP_FLAG;
+#endif
+
+ /* Add option address and control fields, then packet payload */
+ if (!sc->cfg.acfcomp || meta) {
+ ADD_BYTE(PPP_ALLSTATIONS);
+ ADD_BYTE(PPP_UI);
+ }
+ while (m) {
+ struct mbuf *n;
+
+ while (m->m_len > 0) {
+ u_char const ch = *mtod(m, u_char *);
+
+ ADD_BYTE(ch);
+ m->m_data++;
+ m->m_len--;
+ }
+ MFREE(m, n);
+ m = n;
+ }
+
+ /* Add checksum and final sync flag */
+ fcs0 = fcs;
+ ADD_BYTE(~fcs0 & 0xff);
+ ADD_BYTE(~fcs0 >> 8);
+ sc->abuf[alen++] = PPP_FLAG;
+
+ /* Put frame in an mbuf and ship it off */
+ NG_FREE_META(meta);
+ if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL)))
+ error = ENOBUFS;
+ else
+ NG_SEND_DATA(error, sc->async, m, meta);
+ return (error);
+}
+
+/*
+ * Receive incoming asynchronous data
+ * XXX technically, we should strip out supposedly escaped characters
+ */
+static int
+nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
+{
+ struct ifnet *const rcvif = m->m_pkthdr.rcvif;
+ int error;
+
+ if (!sc->cfg.enabled) {
+ NG_SEND_DATA(error, sc->sync, m, meta);
+ return (error);
+ }
+ NG_FREE_META(meta);
+ while (m) {
+ struct mbuf *n;
+
+ for (; m->m_len > 0; m->m_data++, m->m_len--) {
+ u_char ch = *mtod(m, u_char *);
+
+ sc->stats.asyncOctets++;
+ if (ch == PPP_FLAG) { /* Flag overrides everything */
+ int skip = 0;
+
+ /* Check for runts */
+ if (sc->slen < 2) {
+ if (sc->slen > 0)
+ sc->stats.asyncRunts++;
+ goto reset;
+ }
+
+ /* Verify CRC */
+ if (sc->fcs != PPP_GOODFCS) {
+ sc->stats.asyncBadCheckSums++;
+ goto reset;
+ }
+ sc->slen -= 2;
+
+ /* Strip address and control fields */
+ if (sc->slen >= 2
+ && sc->sbuf[0] == PPP_ALLSTATIONS
+ && sc->sbuf[1] == PPP_UI)
+ skip = 2;
+
+ /* Check for frame too big */
+ if (sc->slen - skip > sc->cfg.amru) {
+ sc->stats.asyncOverflows++;
+ goto reset;
+ }
+
+ /* OK, ship it out */
+ if ((n = m_devget(sc->sbuf + skip,
+ sc->slen - skip, 0, rcvif, NULL)))
+ NG_SEND_DATA(error, sc->sync, n, meta);
+ sc->stats.asyncFrames++;
+reset:
+ sc->amode = MODE_NORMAL;
+ sc->fcs = PPP_INITFCS;
+ sc->slen = 0;
+ continue;
+ }
+ switch (sc->amode) {
+ case MODE_NORMAL:
+ if (ch == PPP_ESCAPE) {
+ sc->amode = MODE_ESC;
+ continue;
+ }
+ break;
+ case MODE_ESC:
+ ch ^= PPP_TRANS;
+ sc->amode = MODE_NORMAL;
+ break;
+ case MODE_HUNT:
+ default:
+ continue;
+ }
+
+ /* Add byte to frame */
+ if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
+ sc->stats.asyncOverflows++;
+ sc->amode = MODE_HUNT;
+ sc->slen = 0;
+ } else {
+ sc->sbuf[sc->slen++] = ch;
+ sc->fcs = PPP_FCS(sc->fcs, ch);
+ }
+ }
+ MFREE(m, n);
+ m = n;
+ }
+ return (0);
+}
+
+/*
+ * CRC table
+ *
+ * Taken from RFC 1171 Appendix B
+ */
+static const u_int16_t fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
diff --git a/sys/netgraph/ng_async.h b/sys/netgraph/ng_async.h
new file mode 100644
index 0000000..f08290f
--- /dev/null
+++ b/sys/netgraph/ng_async.h
@@ -0,0 +1,89 @@
+
+/*
+ * ng_async.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_async.h,v 1.5 1999/01/25 01:17:14 archie Exp $
+ */
+
+#ifndef _NETGRAPH_ASYNC_H_
+#define _NETGRAPH_ASYNC_H_
+
+/* Type name and cookie */
+#define NG_ASYNC_NODE_TYPE "async"
+#define NGM_ASYNC_COOKIE 886473715
+
+/* Hook names */
+#define NG_ASYNC_HOOK_SYNC "sync" /* Normal encoding */
+#define NG_ASYNC_HOOK_SYNC2 "sync2" /* Full ACCM, no ACF comp. */
+#define NG_ASYNC_HOOK_ASYNC "async" /* Normal decoding */
+
+/* Maximum receive size bounds (for both sync and async sides) */
+#define NG_ASYNC_MIN_MRU 1
+#define NG_ASYNC_MAX_MRU 8192
+#define NG_ASYNC_DEFAULT_MRU 1600
+
+/* Frame statistics */
+struct ng_async_stat {
+ u_int32_t syncOctets;
+ u_int32_t syncFrames;
+ u_int32_t syncOverflows;
+ u_int32_t asyncOctets;
+ u_int32_t asyncFrames;
+ u_int32_t asyncRunts;
+ u_int32_t asyncOverflows;
+ u_int32_t asyncBadCheckSums;
+};
+
+/* Configuration for this node */
+struct ng_async_cfg {
+ u_char enabled; /* Turn encoding on/off */
+ u_char acfcomp; /* Address/control field compression */
+ u_int16_t amru; /* Max receive async frame length */
+ u_int16_t smru; /* Max receive sync frame length */
+ u_int32_t accm; /* ACCM encoding */
+};
+
+/* Commands */
+enum {
+ NGM_ASYNC_CMD_GET_STATS = 1, /* returns struct ng_async_stat */
+ NGM_ASYNC_CMD_CLR_STATS,
+ NGM_ASYNC_CMD_SET_CONFIG, /* takes struct ng_async_cfg */
+ NGM_ASYNC_CMD_GET_CONFIG, /* returns struct ng_async_cfg */
+};
+
+#endif /* _NETGRAPH_ASYNC_H_ */
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
new file mode 100644
index 0000000..4234355
--- /dev/null
+++ b/sys/netgraph/ng_base.c
@@ -0,0 +1,1633 @@
+
+/*
+ * ng_base.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Authors: Julian Elischer <julian@whistle.com>
+ * Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_base.c,v 1.39 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * This file implements the base netgraph code.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include <sys/linker.h>
+#include <sys/queue.h>
+#include <sys/mbuf.h>
+#include <sys/socketvar.h>
+
+#include <net/netisr.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+
+/* List of all nodes */
+static LIST_HEAD(, ng_node) nodelist;
+
+/* List of installed types */
+static LIST_HEAD(, ng_type) typelist;
+
+/* Internal functions */
+static int ng_add_hook(node_p node, const char *name, hook_p * hookp);
+static int ng_connect(hook_p hook1, hook_p hook2);
+static void ng_disconnect_hook(hook_p hook);
+static int ng_generic_msg(node_p here, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg ** resp);
+static node_p ng_decodeidname(const char *name);
+static int ngb_mod_event(module_t mod, int event, void *data);
+static void ngintr(void);
+
+/* Our own netgraph malloc type */
+MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
+
+/* Set this to Debugger("X") to catch all errors as they occur */
+#ifndef TRAP_ERROR
+#define TRAP_ERROR
+#endif
+
+/************************************************************************
+ Node routines
+************************************************************************/
+
+/*
+ * Instantiate a node of the requested type
+ */
+int
+ng_make_node(const char *typename, node_p *nodepp)
+{
+ struct ng_type *type;
+
+ /* Check that the type makes sense */
+ if (typename == NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Locate the node type */
+ if ((type = ng_findtype(typename)) == NULL) {
+ char *path, filename[NG_TYPELEN + 4];
+ linker_file_t lf;
+ int error;
+
+ /* Not found, try to load it as a loadable module */
+ snprintf(filename, sizeof(filename), "ng_%s.ko", typename);
+ if ((path = linker_search_path(filename)) == NULL)
+ return (ENXIO);
+ error = linker_load_file(path, &lf);
+ FREE(path, M_LINKER);
+ if (error != 0)
+ return (error);
+ lf->userrefs++; /* pretend loaded by the syscall */
+
+ /* Try again, as now the type should have linked itself in */
+ if ((type = ng_findtype(typename)) == NULL)
+ return (ENXIO);
+ }
+
+ /* Call the constructor */
+ if (type->constructor != NULL)
+ return ((*type->constructor)(nodepp));
+ else
+ return (ng_make_node_common(type, nodepp));
+}
+
+/*
+ * Generic node creation. Called by node constructors.
+ * The returned node has a reference count of 1.
+ */
+int
+ng_make_node_common(struct ng_type *type, node_p *nodepp)
+{
+ node_p node;
+
+ /* Require the node type to have been already installed */
+ if (ng_findtype(type->name) == NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Make a node and try attach it to the type */
+ MALLOC(node, node_p, sizeof(*node), M_NETGRAPH, M_WAITOK);
+ if (node == NULL) {
+ TRAP_ERROR;
+ return (ENOMEM);
+ }
+ bzero(node, sizeof(*node));
+ node->type = type;
+ node->refs++; /* note reference */
+ type->refs++;
+
+ /* Link us into the node linked list */
+ LIST_INSERT_HEAD(&nodelist, node, nodes);
+
+ /* Initialize hook list for new node */
+ LIST_INIT(&node->hooks);
+
+ /* Done */
+ *nodepp = node;
+ return (0);
+}
+
+/*
+ * Forceably start the shutdown process on a node. Either call
+ * it's shutdown method, or do the default shutdown if there is
+ * no type-specific method.
+ *
+ * Persistent nodes must have a type-specific method which
+ * resets the NG_INVALID flag.
+ */
+void
+ng_rmnode(node_p node)
+{
+ /* Check if it's already shutting down */
+ if ((node->flags & NG_INVALID) != 0)
+ return;
+
+ /* Add an extra reference so it doesn't go away during this */
+ node->refs++;
+
+ /* Mark it invalid so any newcomers know not to try use it */
+ node->flags |= NG_INVALID;
+
+ /* Ask the type if it has anything to do in this case */
+ if (node->type && node->type->shutdown)
+ (*node->type->shutdown)(node);
+ else { /* do the default thing */
+ ng_unname(node);
+ ng_cutlinks(node);
+ ng_unref(node);
+ }
+
+ /* Remove extra reference, possibly the last */
+ ng_unref(node);
+}
+
+/*
+ * Called by the destructor to remove any STANDARD external references
+ */
+void
+ng_cutlinks(node_p node)
+{
+ hook_p hook;
+
+ /* Make sure that this is set to stop infinite loops */
+ node->flags |= NG_INVALID;
+
+ /* If we have sleepers, wake them up; they'll see NG_INVALID */
+ if (node->sleepers)
+ wakeup(node);
+
+ /* Notify all remaining connected nodes to disconnect */
+ while ((hook = LIST_FIRST(&node->hooks)) != NULL)
+ ng_destroy_hook(hook);
+}
+
+/*
+ * Remove a reference to the node, possibly the last
+ */
+void
+ng_unref(node_p node)
+{
+ if (--node->refs <= 0) {
+ node->type->refs--;
+ LIST_REMOVE(node, nodes);
+ FREE(node, M_NETGRAPH);
+ }
+}
+
+/*
+ * Wait for a node to come ready. Returns a node with a reference count;
+ * don't forget to drop it when we are done with it using ng_release_node().
+ */
+int
+ng_wait_node(node_p node, char *msg)
+{
+ int s, error = 0;
+
+ if (msg == NULL)
+ msg = "netgraph";
+ s = splnet();
+ node->sleepers++;
+ node->refs++; /* the sleeping process counts as a reference */
+ while ((node->flags & (NG_BUSY | NG_INVALID)) == NG_BUSY)
+ error = tsleep(node, (PZERO + 1) | PCATCH, msg, 0);
+ node->sleepers--;
+ if (node->flags & NG_INVALID) {
+ TRAP_ERROR;
+ error = ENXIO;
+ } else {
+#ifdef DIAGNOSTIC
+ if (node->refs == 1) {
+ panic(__FUNCTION__);
+ error = ENXIO;
+ }
+#endif
+ node->flags |= NG_BUSY;
+ }
+ splx(s);
+
+ /* Release the reference we had on it */
+ if (error != 0)
+ ng_unref(node);
+ return error;
+}
+
+/*
+ * Release a node acquired via ng_wait_node()
+ */
+void
+ng_release_node(node_p node)
+{
+ /* Declare that we don't want it */
+ node->flags &= ~NG_BUSY;
+
+ /* If we have sleepers, then wake them up */
+ if (node->sleepers)
+ wakeup(node);
+
+ /* We also have a reference.. drop it too */
+ ng_unref(node);
+}
+
+/************************************************************************
+ Node name handling
+************************************************************************/
+
+/*
+ * Assign a node a name. Once assigned, the name cannot be changed.
+ */
+int
+ng_name_node(node_p node, const char *name)
+{
+ int i;
+
+ /* Check the name is valid */
+ for (i = 0; i < NG_NODELEN + 1; i++) {
+ if (name[i] == '\0' || name[i] == '.' || name[i] == ':')
+ break;
+ }
+ if (i == 0 || name[i] != '\0') {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ if (ng_decodeidname(name) != NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Check the node isn't already named */
+ if (node->name != NULL) {
+ TRAP_ERROR;
+ return (EISCONN);
+ }
+
+ /* Check the name isn't already being used */
+ if (ng_findname(node, name) != NULL) {
+ TRAP_ERROR;
+ return (EADDRINUSE);
+ }
+
+ /* Allocate space and copy it */
+ MALLOC(node->name, char *, strlen(name) + 1, M_NETGRAPH, M_WAITOK);
+ if (node->name == NULL) {
+ TRAP_ERROR;
+ return (ENOMEM);
+ }
+ strcpy(node->name, name);
+
+ /* The name counts as a reference */
+ node->refs++;
+ return (0);
+}
+
+/*
+ * Find a node by absolute name. The name should NOT end with ':'
+ * The name "." means "this node" and "[xxx]" means "the node
+ * with ID (ie, at address) xxx".
+ *
+ * Returns the node if found, else NULL.
+ */
+node_p
+ng_findname(node_p this, const char *name)
+{
+ node_p node, temp;
+
+ /* "." means "this node" */
+ if (strcmp(name, ".") == 0)
+ return(this);
+
+ /* Check for name-by-ID */
+ if ((temp = ng_decodeidname(name)) != NULL) {
+
+ /* Make sure the ID really points to a node */
+ LIST_FOREACH(node, &nodelist, nodes) {
+ if (node == temp)
+ break;
+ }
+ return (node);
+ }
+
+ /* Find node by name */
+ LIST_FOREACH(node, &nodelist, nodes) {
+ if (node->name != NULL && strcmp(node->name, name) == 0)
+ break;
+ }
+ return (node);
+}
+
+/*
+ * Decode a ID name, eg. "[f03034de]". Returns NULL if the
+ * string is not valid, otherwise returns the ID cast to a
+ * node pointer.
+ *
+ * NOTE: the returned pointer is not necessarily valid!
+ */
+static node_p
+ng_decodeidname(const char *name)
+{
+ u_int32_t val;
+ int k, len;
+
+ /* Basic checks */
+ for (len = 0; name[len] != '\0'; len++) {
+ const char ch = name[len];
+
+ if (len == 0) {
+ if (ch != '[')
+ return (NULL);
+ } else if (name[len + 1] == '\0') {
+ if (ch != ']')
+ return (NULL);
+ } else if (!((ch >= '0' && ch <= '9')
+ || (ch >= 'a' && ch <= 'f')
+ || (ch >= 'A' && ch <= 'F')))
+ return (NULL);
+ }
+ if (len < 3 || len > (sizeof(val) * 2) + 2 || name[1] == '0')
+ return (NULL);
+
+ /* Convert number to binary */
+ for (val = 0, k = 1; k < len - 1; k++) {
+ const char ch = name[k];
+
+ if (ch <= '9')
+ val = (val << 4) | ((ch - '0') & 0xf);
+ else
+ val = (val << 4) | (((ch & 0xdf) - 'A' + 10) & 0xf);
+ }
+ return ((node_p) val);
+}
+
+/*
+ * Remove a name from a node. This should only be called
+ * when shutting down and removing the node.
+ */
+void
+ng_unname(node_p node)
+{
+ if (node->name) {
+ FREE(node->name, M_NETGRAPH);
+ node->name = NULL;
+ ng_unref(node);
+ }
+}
+
+/************************************************************************
+ Hook routines
+
+ Names are not optional. Hooks are always connected, except for a
+ brief moment within these routines.
+
+************************************************************************/
+
+/*
+ * Remove a hook reference
+ */
+static void
+ng_unref_hook(hook_p hook)
+{
+ if (--hook->refs == 0)
+ FREE(hook, M_NETGRAPH);
+}
+
+/*
+ * Add an unconnected hook to a node. Only used internally.
+ */
+static int
+ng_add_hook(node_p node, const char *name, hook_p *hookp)
+{
+ hook_p hook;
+ int error = 0;
+
+ /* Check that the given name is good */
+ if (name == NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ if (strcmp(hook->name, name) == 0) {
+ TRAP_ERROR;
+ return (EEXIST);
+ }
+ }
+
+ /* Allocate the hook and link it up */
+ MALLOC(hook, hook_p, sizeof(*hook), M_NETGRAPH, M_WAITOK);
+ if (hook == NULL) {
+ TRAP_ERROR;
+ return (ENOMEM);
+ }
+ bzero(hook, sizeof(*hook));
+ hook->refs = 1;
+ hook->flags = HK_INVALID;
+ hook->node = node;
+ node->refs++; /* each hook counts as a reference */
+
+ /* Check if the node type code has something to say about it */
+ if (node->type->newhook != NULL)
+ if ((error = (*node->type->newhook)(node, hook, name)) != 0)
+ goto fail;
+
+ /*
+ * The 'type' agrees so far, so go ahead and link it in.
+ * We'll ask again later when we actually connect the hooks.
+ */
+ LIST_INSERT_HEAD(&node->hooks, hook, hooks);
+ node->numhooks++;
+
+ /* Set hook name */
+ MALLOC(hook->name, char *, strlen(name) + 1, M_NETGRAPH, M_WAITOK);
+ if (hook->name == NULL) {
+ error = ENOMEM;
+ LIST_REMOVE(hook, hooks);
+ node->numhooks--;
+fail:
+ hook->node = NULL;
+ ng_unref(node);
+ ng_unref_hook(hook); /* this frees the hook */
+ return (error);
+ }
+ strcpy(hook->name, name);
+ if (hookp)
+ *hookp = hook;
+ return (error);
+}
+
+/*
+ * Connect a pair of hooks. Only used internally.
+ */
+static int
+ng_connect(hook_p hook1, hook_p hook2)
+{
+ int error;
+
+ hook1->peer = hook2;
+ hook2->peer = hook1;
+
+ /* Give each node the opportunity to veto the impending connection */
+ if (hook1->node->type->connect) {
+ if ((error = (*hook1->node->type->connect) (hook1))) {
+ ng_destroy_hook(hook1); /* also zaps hook2 */
+ return (error);
+ }
+ }
+ if (hook2->node->type->connect) {
+ if ((error = (*hook2->node->type->connect) (hook2))) {
+ ng_destroy_hook(hook2); /* also zaps hook1 */
+ return (error);
+ }
+ }
+ hook1->flags &= ~HK_INVALID;
+ hook2->flags &= ~HK_INVALID;
+ return (0);
+}
+
+/*
+ * Destroy a hook
+ *
+ * As hooks are always attached, this really destroys two hooks.
+ * The one given, and the one attached to it. Disconnect the hooks
+ * from each other first.
+ */
+void
+ng_destroy_hook(hook_p hook)
+{
+ hook_p peer = hook->peer;
+
+ hook->flags |= HK_INVALID; /* as soon as possible */
+ if (peer) {
+ peer->flags |= HK_INVALID; /* as soon as possible */
+ hook->peer = NULL;
+ peer->peer = NULL;
+ ng_disconnect_hook(peer);
+ }
+ ng_disconnect_hook(hook);
+}
+
+/*
+ * Notify the node of the hook's demise. This may result in more actions
+ * (e.g. shutdown) but we don't do that ourselves and don't know what
+ * happens there. If there is no appropriate handler, then just remove it
+ * (and decrement the reference count of it's node which in turn might
+ * make something happen).
+ */
+static void
+ng_disconnect_hook(hook_p hook)
+{
+ node_p node = hook->node;
+
+ /*
+ * Remove the hook from the node's list to avoid possible recursion
+ * in case the disconnection results in node shutdown.
+ */
+ LIST_REMOVE(hook, hooks);
+ node->numhooks--;
+ if (node->type->disconnect) {
+ /*
+ * The type handler may elect to destroy the peer so don't
+ * trust its existance after this point.
+ */
+ (*node->type->disconnect) (hook);
+ }
+ ng_unref(node); /* might be the last reference */
+ if (hook->name)
+ FREE(hook->name, M_NETGRAPH);
+ hook->node = NULL; /* may still be referenced elsewhere */
+ ng_unref_hook(hook);
+}
+
+/*
+ * Take two hooks on a node and merge the connection so that the given node
+ * is effectively bypassed.
+ */
+int
+ng_bypass(hook_p hook1, hook_p hook2)
+{
+ if (hook1->node != hook2->node)
+ return (EINVAL);
+ hook1->peer->peer = hook2->peer;
+ hook2->peer->peer = hook1->peer;
+
+ /* XXX If we ever cache methods on hooks update them as well */
+ hook1->peer = NULL;
+ hook2->peer = NULL;
+ ng_destroy_hook(hook1);
+ ng_destroy_hook(hook2);
+ return (0);
+}
+
+/*
+ * Install a new netgraph type
+ */
+int
+ng_newtype(struct ng_type *tp)
+{
+ const size_t namelen = strlen(tp->name);
+
+ /* Check version and type name fields */
+ if (tp->version != NG_VERSION || namelen == 0 || namelen > NG_TYPELEN) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Check for name collision */
+ if (ng_findtype(tp->name) != NULL) {
+ TRAP_ERROR;
+ return (EEXIST);
+ }
+
+ /* Link in new type */
+ LIST_INSERT_HEAD(&typelist, tp, types);
+ tp->refs = 0;
+ return (0);
+}
+
+/*
+ * Look for a type of the name given
+ */
+struct ng_type *
+ng_findtype(const char *typename)
+{
+ struct ng_type *type;
+
+ LIST_FOREACH(type, &typelist, types) {
+ if (strcmp(type->name, typename) == 0)
+ break;
+ }
+ return (type);
+}
+
+
+/************************************************************************
+ Composite routines
+************************************************************************/
+
+/*
+ * Make a peer and connect. The order is arranged to minimise
+ * the work needed to back out in case of error.
+ */
+int
+ng_mkpeer(node_p node, const char *name, const char *name2, char *type)
+{
+ node_p node2;
+ hook_p hook;
+ hook_p hook2;
+ int error;
+
+ if ((error = ng_add_hook(node, name, &hook)))
+ return (error);
+ if ((error = ng_make_node(type, &node2))) {
+ ng_destroy_hook(hook);
+ return (error);
+ }
+ if ((error = ng_add_hook(node2, name2, &hook2))) {
+ ng_rmnode(node2);
+ ng_destroy_hook(hook);
+ return (error);
+ }
+
+ /*
+ * Actually link the two hooks together.. on failure they are
+ * destroyed so we don't have to do that here.
+ */
+ if ((error = ng_connect(hook, hook2)))
+ ng_rmnode(node2);
+ return (error);
+}
+
+/*
+ * Connect two nodes using the specified hooks
+ */
+int
+ng_con_nodes(node_p node, const char *name, node_p node2, const char *name2)
+{
+ int error;
+ hook_p hook;
+ hook_p hook2;
+
+ if ((error = ng_add_hook(node, name, &hook)))
+ return (error);
+ if ((error = ng_add_hook(node2, name2, &hook2))) {
+ ng_destroy_hook(hook);
+ return (error);
+ }
+ return (ng_connect(hook, hook2));
+}
+
+/*
+ * Parse and verify a string of the form: <NODE:><PATH>
+ *
+ * Such a string can refer to a specific node or a specific hook
+ * on a specific node, depending on how you look at it. In the
+ * latter case, the PATH component must not end in a dot.
+ *
+ * Both <NODE:> and <PATH> are optional. The <PATH> is a string
+ * of hook names separated by dots. This breaks out the original
+ * string, setting *nodep to "NODE" (or NULL if none) and *pathp
+ * to "PATH" (or NULL if degenerate). Also, *hookp will point to
+ * the final hook component of <PATH>, if any, otherwise NULL.
+ *
+ * This returns -1 if the path is malformed. The char ** are optional.
+ */
+
+int
+ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp)
+{
+ char *node, *path, *hook;
+ int k;
+
+ /*
+ * Extract absolute NODE, if any
+ */
+ for (path = addr; *path && *path != ':'; path++);
+ if (*path) {
+ node = addr; /* Here's the NODE */
+ *path++ = '\0'; /* Here's the PATH */
+
+ /* Node name must not be empty */
+ if (!*node)
+ return -1;
+
+ /* A name of "." is OK; otherwise '.' not allowed */
+ if (strcmp(node, ".") != 0) {
+ for (k = 0; node[k]; k++)
+ if (node[k] == '.')
+ return -1;
+ }
+ } else {
+ node = NULL; /* No absolute NODE */
+ path = addr; /* Here's the PATH */
+ }
+
+ /* Snoop for illegal characters in PATH */
+ for (k = 0; path[k]; k++)
+ if (path[k] == ':')
+ return -1;
+
+ /* Check for no repeated dots in PATH */
+ for (k = 0; path[k]; k++)
+ if (path[k] == '.' && path[k + 1] == '.')
+ return -1;
+
+ /* Remove extra (degenerate) dots from beginning or end of PATH */
+ if (path[0] == '.')
+ path++;
+ if (*path && path[strlen(path) - 1] == '.')
+ path[strlen(path) - 1] = 0;
+
+ /* If PATH has a dot, then we're not talking about a hook */
+ if (*path) {
+ for (hook = path, k = 0; path[k]; k++)
+ if (path[k] == '.') {
+ hook = NULL;
+ break;
+ }
+ } else
+ path = hook = NULL;
+
+ /* Done */
+ if (nodep)
+ *nodep = node;
+ if (pathp)
+ *pathp = path;
+ if (hookp)
+ *hookp = hook;
+ return (0);
+}
+
+/*
+ * Given a path, which may be absolute or relative, and a starting node,
+ * return the destination node. Compute the "return address" if desired.
+ */
+int
+ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
+{
+ const node_p start = here;
+ char fullpath[NG_PATHLEN + 1];
+ char *nodename, *path, pbuf[2];
+ node_p node;
+ char *cp;
+
+ /* Initialize */
+ if (rtnp)
+ *rtnp = NULL;
+ if (destp == NULL)
+ return EINVAL;
+ *destp = NULL;
+
+ /* Make a writable copy of address for ng_path_parse() */
+ strncpy(fullpath, address, sizeof(fullpath) - 1);
+ fullpath[sizeof(fullpath) - 1] = '\0';
+
+ /* Parse out node and sequence of hooks */
+ if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) {
+ TRAP_ERROR;
+ return EINVAL;
+ }
+ if (path == NULL) {
+ pbuf[0] = '.'; /* Needs to be writable */
+ pbuf[1] = '\0';
+ path = pbuf;
+ }
+
+ /* For an absolute address, jump to the starting node */
+ if (nodename) {
+ node = ng_findname(here, nodename);
+ if (node == NULL) {
+ TRAP_ERROR;
+ return (ENOENT);
+ }
+ } else
+ node = here;
+
+ /* Now follow the sequence of hooks */
+ for (cp = path; node != NULL && *cp != '\0'; ) {
+ hook_p hook;
+ char *segment;
+
+ /*
+ * Break out the next path segment. Replace the dot we just
+ * found with a NUL; "cp" points to the next segment (or the
+ * NUL at the end).
+ */
+ for (segment = cp; *cp != '\0'; cp++) {
+ if (*cp == '.') {
+ *cp++ = '\0';
+ break;
+ }
+ }
+
+ /* Empty segment */
+ if (*segment == '\0')
+ continue;
+
+ /* We have a segment, so look for a hook by that name */
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ if (hook->name && strcmp(hook->name, segment) == 0)
+ break;
+ }
+
+ /* Can't get there from here... */
+ if (hook == NULL
+ || hook->peer == NULL
+ || (hook->flags & HK_INVALID) != 0) {
+ TRAP_ERROR;
+ return (ENOENT);
+ }
+
+ /* Hop on over to the next node */
+ node = hook->peer->node;
+ }
+
+ /* If node somehow missing, fail here (probably this is not needed) */
+ if (node == NULL) {
+ TRAP_ERROR;
+ return (ENXIO);
+ }
+
+ /* Now compute return address, i.e., the path to the sender */
+ if (rtnp != NULL) {
+ MALLOC(*rtnp, char *, NG_NODELEN + 2, M_NETGRAPH, M_WAITOK);
+ if (*rtnp == NULL) {
+ TRAP_ERROR;
+ return (ENOMEM);
+ }
+ if (start->name != NULL)
+ sprintf(*rtnp, "%s:", start->name);
+ else
+ sprintf(*rtnp, "[%lx]:", (u_long) start);
+ }
+
+ /* Done */
+ *destp = node;
+ return (0);
+}
+
+/*
+ * Call the appropriate message handler for the object.
+ * It is up to the message handler to free the message.
+ * If it's a generic message, handle it generically, otherwise
+ * call the type's message handler (if it exists)
+ */
+
+#define CALL_MSG_HANDLER(error, node, msg, retaddr, resp) \
+do { \
+ if((msg)->header.typecookie == NGM_GENERIC_COOKIE) { \
+ (error) = ng_generic_msg((node), (msg), \
+ (retaddr), (resp)); \
+ } else { \
+ if ((node)->type->rcvmsg != NULL) { \
+ (error) = (*(node)->type->rcvmsg)((node), \
+ (msg), (retaddr), (resp)); \
+ } else { \
+ TRAP_ERROR; \
+ FREE((msg), M_NETGRAPH); \
+ (error) = EINVAL; \
+ } \
+ } \
+} while (0)
+
+
+/*
+ * Send a control message to a node
+ */
+int
+ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
+ struct ng_mesg **rptr)
+{
+ node_p dest = NULL;
+ char *retaddr = NULL;
+ int error;
+
+ /* Find the target node */
+ error = ng_path2node(here, address, &dest, &retaddr);
+ if (error) {
+ FREE(msg, M_NETGRAPH);
+ return error;
+ }
+
+ /* Make sure the resp field is null before we start */
+ if (rptr != NULL)
+ *rptr = NULL;
+
+ CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr);
+
+ /* Make sure that if there is a response, it has the RESP bit set */
+ if ((error == 0) && rptr && *rptr)
+ (*rptr)->header.flags |= NGF_RESP;
+
+ /*
+ * If we had a return address it is up to us to free it. They should
+ * have taken a copy if they needed to make a delayed response.
+ */
+ if (retaddr)
+ FREE(retaddr, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Implement the 'generic' control messages
+ */
+static int
+ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **resp)
+{
+ int error = 0;
+
+ if (msg->header.typecookie != NGM_GENERIC_COOKIE) {
+ TRAP_ERROR;
+ FREE(msg, M_NETGRAPH);
+ return (EINVAL);
+ }
+ switch (msg->header.cmd) {
+ case NGM_SHUTDOWN:
+ ng_rmnode(here);
+ break;
+ case NGM_MKPEER:
+ {
+ struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
+
+ if (msg->header.arglen != sizeof(*mkp)) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ mkp->type[sizeof(mkp->type) - 1] = '\0';
+ mkp->ourhook[sizeof(mkp->ourhook) - 1] = '\0';
+ mkp->peerhook[sizeof(mkp->peerhook) - 1] = '\0';
+ error = ng_mkpeer(here, mkp->ourhook, mkp->peerhook, mkp->type);
+ break;
+ }
+ case NGM_CONNECT:
+ {
+ struct ngm_connect *const con =
+ (struct ngm_connect *) msg->data;
+ node_p node2;
+
+ if (msg->header.arglen != sizeof(*con)) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ con->path[sizeof(con->path) - 1] = '\0';
+ con->ourhook[sizeof(con->ourhook) - 1] = '\0';
+ con->peerhook[sizeof(con->peerhook) - 1] = '\0';
+ error = ng_path2node(here, con->path, &node2, NULL);
+ if (error)
+ break;
+ error = ng_con_nodes(here, con->ourhook, node2, con->peerhook);
+ break;
+ }
+ case NGM_NAME:
+ {
+ struct ngm_name *const nam = (struct ngm_name *) msg->data;
+
+ if (msg->header.arglen != sizeof(*nam)) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ nam->name[sizeof(nam->name) - 1] = '\0';
+ error = ng_name_node(here, nam->name);
+ break;
+ }
+ case NGM_RMHOOK:
+ {
+ struct ngm_rmhook *const rmh = (struct ngm_rmhook *) msg->data;
+ hook_p hook;
+
+ if (msg->header.arglen != sizeof(*rmh)) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ rmh->ourhook[sizeof(rmh->ourhook) - 1] = '\0';
+ LIST_FOREACH(hook, &here->hooks, hooks) {
+ if (hook->name && strcmp(hook->name, rmh->ourhook) == 0)
+ break;
+ }
+ if (hook)
+ ng_destroy_hook(hook);
+ break;
+ }
+ case NGM_NODEINFO:
+ {
+ struct nodeinfo *ni;
+ struct ng_mesg *rp;
+
+ /* Get response struct */
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(rp, msg, sizeof(*ni), M_NOWAIT);
+ if (rp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+
+ /* Fill in node info */
+ ni = (struct nodeinfo *) rp->data;
+ if (here->name != NULL)
+ strncpy(ni->name, here->name, NG_NODELEN);
+ strncpy(ni->type, here->type->name, NG_TYPELEN);
+ ni->id = (u_int32_t) here;
+ ni->hooks = here->numhooks;
+ *resp = rp;
+ break;
+ }
+ case NGM_LISTHOOKS:
+ {
+ const int nhooks = here->numhooks;
+ struct hooklist *hl;
+ struct nodeinfo *ni;
+ struct ng_mesg *rp;
+ hook_p hook;
+
+ /* Get response struct */
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(rp, msg, sizeof(*hl)
+ + (nhooks * sizeof(struct linkinfo)), M_NOWAIT);
+ if (rp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ hl = (struct hooklist *) rp->data;
+ ni = &hl->nodeinfo;
+
+ /* Fill in node info */
+ if (here->name)
+ strncpy(ni->name, here->name, NG_NODELEN);
+ strncpy(ni->type, here->type->name, NG_TYPELEN);
+ ni->id = (u_int32_t) here;
+
+ /* Cycle through the linked list of hooks */
+ ni->hooks = 0;
+ LIST_FOREACH(hook, &here->hooks, hooks) {
+ struct linkinfo *const link = &hl->link[ni->hooks];
+
+ if (ni->hooks >= nhooks) {
+ log(LOG_ERR, "%s: number of %s changed\n",
+ __FUNCTION__, "hooks");
+ break;
+ }
+ if ((hook->flags & HK_INVALID) != 0)
+ continue;
+ strncpy(link->ourhook, hook->name, NG_HOOKLEN);
+ strncpy(link->peerhook, hook->peer->name, NG_HOOKLEN);
+ if (hook->peer->node->name != NULL)
+ strncpy(link->nodeinfo.name,
+ hook->peer->node->name, NG_NODELEN);
+ strncpy(link->nodeinfo.type,
+ hook->peer->node->type->name, NG_TYPELEN);
+ link->nodeinfo.id = (u_int32_t) hook->peer->node;
+ link->nodeinfo.hooks = hook->peer->node->numhooks;
+ ni->hooks++;
+ }
+ *resp = rp;
+ break;
+ }
+
+ case NGM_LISTNAMES:
+ case NGM_LISTNODES:
+ {
+ const int unnamed = (msg->header.cmd == NGM_LISTNODES);
+ struct namelist *nl;
+ struct ng_mesg *rp;
+ node_p node;
+ int num = 0;
+
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+
+ /* Count number of nodes */
+ LIST_FOREACH(node, &nodelist, nodes) {
+ if (unnamed || node->name != NULL)
+ num++;
+ }
+
+ /* Get response struct */
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(rp, msg, sizeof(*nl)
+ + (num * sizeof(struct nodeinfo)), M_NOWAIT);
+ if (rp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ nl = (struct namelist *) rp->data;
+
+ /* Cycle through the linked list of nodes */
+ nl->numnames = 0;
+ LIST_FOREACH(node, &nodelist, nodes) {
+ struct nodeinfo *const np = &nl->nodeinfo[nl->numnames];
+
+ if (nl->numnames >= num) {
+ log(LOG_ERR, "%s: number of %s changed\n",
+ __FUNCTION__, "nodes");
+ break;
+ }
+ if ((node->flags & NG_INVALID) != 0)
+ continue;
+ if (!unnamed && node->name == NULL)
+ continue;
+ if (node->name != NULL)
+ strncpy(np->name, node->name, NG_NODELEN);
+ strncpy(np->type, node->type->name, NG_TYPELEN);
+ np->id = (u_int32_t) node;
+ np->hooks = node->numhooks;
+ nl->numnames++;
+ }
+ *resp = rp;
+ break;
+ }
+
+ case NGM_LISTTYPES:
+ {
+ struct typelist *tl;
+ struct ng_mesg *rp;
+ struct ng_type *type;
+ int num = 0;
+
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+
+ /* Count number of types */
+ LIST_FOREACH(type, &typelist, types)
+ num++;
+
+ /* Get response struct */
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+ NG_MKRESPONSE(rp, msg, sizeof(*tl)
+ + (num * sizeof(struct typeinfo)), M_NOWAIT);
+ if (rp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ tl = (struct typelist *) rp->data;
+
+ /* Cycle through the linked list of types */
+ tl->numtypes = 0;
+ LIST_FOREACH(type, &typelist, types) {
+ struct typeinfo *const tp = &tl->typeinfo[tl->numtypes];
+
+ if (tl->numtypes >= num) {
+ log(LOG_ERR, "%s: number of %s changed\n",
+ __FUNCTION__, "types");
+ break;
+ }
+ strncpy(tp->typename, type->name, NG_TYPELEN);
+ tp->numnodes = type->refs;
+ tl->numtypes++;
+ }
+ *resp = rp;
+ break;
+ }
+
+ case NGM_TEXT_STATUS:
+ /*
+ * This one is tricky as it passes the command down to the
+ * actual node, even though it is a generic type command.
+ * This means we must assume that the msg is already freed
+ * when control passes back to us.
+ */
+ if (resp == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (here->type->rcvmsg != NULL)
+ return((*here->type->rcvmsg)(here, msg, retaddr, resp));
+ /* Fall through if rcvmsg not supported */
+ default:
+ TRAP_ERROR;
+ error = EINVAL;
+ }
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Send a data packet to a node. If the recipient has no
+ * 'receive data' method, then silently discard the packet.
+ */
+int
+ng_send_data(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int (*rcvdata)(hook_p, struct mbuf *, meta_p);
+ int error;
+
+#ifdef DIAGNOSTIC
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic(__FUNCTION__);
+#endif
+ if (hook && (hook->flags & HK_INVALID) == 0) {
+ rcvdata = hook->peer->node->type->rcvdata;
+ if (rcvdata != NULL)
+ error = (*rcvdata)(hook->peer, m, meta);
+ else {
+ error = 0;
+ NG_FREE_DATA(m, meta);
+ }
+ } else {
+ TRAP_ERROR;
+ error = ENOTCONN;
+ NG_FREE_DATA(m, meta);
+ }
+ return (error);
+}
+
+/*
+ * Send a queued data packet to a node. If the recipient has no
+ * 'receive queued data' method, then try the 'receive data' method above.
+ */
+int
+ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int (*rcvdataq)(hook_p, struct mbuf *, meta_p);
+ int error;
+
+#ifdef DIAGNOSTIC
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic(__FUNCTION__);
+#endif
+ if (hook && (hook->flags & HK_INVALID) == 0) {
+ rcvdataq = hook->peer->node->type->rcvdataq;
+ if (rcvdataq != NULL)
+ error = (*rcvdataq)(hook->peer, m, meta);
+ else {
+ error = ng_send_data(hook, m, meta);
+ }
+ } else {
+ TRAP_ERROR;
+ error = ENOTCONN;
+ NG_FREE_DATA(m, meta);
+ }
+ return (error);
+}
+
+/************************************************************************
+ Module routines
+************************************************************************/
+
+/*
+ * Handle the loading/unloading of a netgraph node type module
+ */
+int
+ng_mod_event(module_t mod, int event, void *data)
+{
+ struct ng_type *const type = data;
+ int s, error = 0;
+
+ switch (event) {
+ case MOD_LOAD:
+
+ /* Register new netgraph node type */
+ s = splnet();
+ if ((error = ng_newtype(type)) != 0) {
+ splx(s);
+ break;
+ }
+
+ /* Call type specific code */
+ if (type->mod_event != NULL)
+ if ((error = (*type->mod_event)(mod, event, data)) != 0)
+ LIST_REMOVE(type, types);
+ splx(s);
+ break;
+
+ case MOD_UNLOAD:
+ s = splnet();
+ if (type->refs != 0) /* make sure no nodes exist! */
+ error = EBUSY;
+ else {
+ if (type->mod_event != NULL) { /* check with type */
+ error = (*type->mod_event)(mod, event, data);
+ if (error != 0) { /* type refuses.. */
+ splx(s);
+ break;
+ }
+ }
+ LIST_REMOVE(type, types);
+ }
+ splx(s);
+ break;
+
+ default:
+ if (type->mod_event != NULL)
+ error = (*type->mod_event)(mod, event, data);
+ else
+ error = 0; /* XXX ? */
+ break;
+ }
+ return (error);
+}
+
+/*
+ * Handle loading and unloading for this code.
+ * The only thing we need to link into is the NETISR strucure.
+ */
+static int
+ngb_mod_event(module_t mod, int event, void *data)
+{
+ int s, error = 0;
+
+ switch (event) {
+ case MOD_LOAD:
+ /* Register line discipline */
+ s = splimp();
+ error = register_netisr(NETISR_NETGRAPH, ngintr);
+ splx(s);
+ break;
+ case MOD_UNLOAD:
+ /* You cant unload it because an interface may be using it. */
+ error = EBUSY;
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
+
+static moduledata_t netgraph_mod = {
+ "netgraph",
+ ngb_mod_event,
+ (NULL)
+};
+DECLARE_MODULE(netgraph, netgraph_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
+
+/************************************************************************
+ Queueing routines
+************************************************************************/
+
+/* The structure for queueing across ISR switches */
+struct ng_queue_entry {
+ u_long flags;
+ struct ng_queue_entry *next;
+ union {
+ struct {
+ hook_p da_hook; /* target hook */
+ struct mbuf *da_m;
+ meta_p da_meta;
+ } data;
+ struct {
+ struct ng_mesg *msg_msg;
+ node_p msg_node;
+ void *msg_retaddr;
+ } msg;
+ } body;
+};
+#define NGQF_DATA 0x01 /* the queue element is data */
+#define NGQF_MESG 0x02 /* the queue element is a message */
+
+static struct ng_queue_entry *ngqbase; /* items to be unqueued */
+static struct ng_queue_entry *ngqlast; /* last item queued */
+static const int ngqroom = 64; /* max items to queue */
+static int ngqsize; /* number of items in queue */
+
+static struct ng_queue_entry *ngqfree; /* free ones */
+static const int ngqfreemax = 16;/* cache at most this many */
+static int ngqfreesize; /* number of cached entries */
+
+/*
+ * Get a queue entry
+ */
+static struct ng_queue_entry *
+ng_getqblk(void)
+{
+ register struct ng_queue_entry *q;
+ int s;
+
+ /* Could be guarding against tty ints or whatever */
+ s = splhigh();
+
+ /* Try get a cached queue block, or else allocate a new one */
+ if ((q = ngqfree) == NULL) {
+ splx(s);
+ if (ngqsize < ngqroom) { /* don't worry about races */
+ MALLOC(q, struct ng_queue_entry *,
+ sizeof(*q), M_NETGRAPH, M_NOWAIT);
+ }
+ } else {
+ ngqfree = q->next;
+ ngqfreesize--;
+ splx(s);
+ }
+ return (q);
+}
+
+/*
+ * Release a queue entry
+ */
+#define RETURN_QBLK(q) \
+do { \
+ int s; \
+ if (ngqfreesize < ngqfreemax) { /* don't worry about races */ \
+ s = splhigh(); \
+ (q)->next = ngqfree; \
+ ngqfree = (q); \
+ ngqfreesize++; \
+ splx(s); \
+ } else { \
+ FREE((q), M_NETGRAPH); \
+ } \
+} while (0)
+
+/*
+ * Running at a raised (but we don't know which) processor priority level,
+ * put the data onto a queue to be picked up by another PPL (probably splnet)
+ */
+int
+ng_queue_data(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ struct ng_queue_entry *q;
+ int s;
+
+ if (hook == NULL) {
+ NG_FREE_DATA(m, meta);
+ return (0);
+ }
+ if ((q = ng_getqblk()) == NULL) {
+ NG_FREE_DATA(m, meta);
+ return (ENOBUFS);
+ }
+
+ /* Fill out the contents */
+ q->flags = NGQF_DATA;
+ q->next = NULL;
+ q->body.data.da_hook = hook;
+ q->body.data.da_m = m;
+ q->body.data.da_meta = meta;
+ hook->refs++; /* don't let it go away while on the queue */
+
+ /* Put it on the queue */
+ s = splhigh();
+ if (ngqbase) {
+ ngqlast->next = q;
+ } else {
+ ngqbase = q;
+ }
+ ngqlast = q;
+ ngqsize++;
+ splx(s);
+
+ /* Schedule software interrupt to handle it later */
+ schednetisr(NETISR_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Running at a raised (but we don't know which) processor priority level,
+ * put the msg onto a queue to be picked up by another PPL (probably splnet)
+ */
+int
+ng_queue_msg(node_p here, struct ng_mesg * msg, int len, const char *address)
+{
+ register struct ng_queue_entry *q;
+ int s;
+ node_p dest = NULL;
+ char *retaddr = NULL;
+ int error;
+
+ /* Find the target node. Note that this trashes address */
+ error = ng_path2node(here, address, &dest, &retaddr);
+ if (error) {
+ FREE(msg, M_NETGRAPH);
+ return (error);
+ }
+ if ((q = ng_getqblk()) == NULL) {
+ FREE(msg, M_NETGRAPH);
+ if (retaddr)
+ FREE(retaddr, M_NETGRAPH);
+ return (ENOBUFS);
+ }
+
+ /* Fill out the contents */
+ q->flags = NGQF_MESG;
+ q->next = NULL;
+ q->body.msg.msg_node = dest;
+ q->body.msg.msg_msg = msg;
+ q->body.msg.msg_retaddr = retaddr;
+ dest->refs++; /* don't let it go away while on the queue */
+
+ /* Put it on the queue */
+ s = splhigh();
+ if (ngqbase) {
+ ngqlast->next = q;
+ } else {
+ ngqbase = q;
+ }
+ ngqlast = q;
+ ngqsize++;
+ splx(s);
+
+ /* Schedule software interrupt to handle it later */
+ schednetisr(NETISR_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Pick an item off the queue, process it, and dispose of the queue entry.
+ * Should be running at splnet.
+ */
+static void
+ngintr(void)
+{
+ hook_p hook;
+ struct ng_queue_entry *ngq;
+ struct mbuf *m;
+ meta_p meta;
+ void *retaddr;
+ struct ng_mesg *msg;
+ node_p node;
+ int error = 0;
+ int s;
+
+ while (1) {
+ s = splhigh();
+ if ((ngq = ngqbase)) {
+ ngqbase = ngq->next;
+ ngqsize--;
+ }
+ splx(s);
+ if (ngq == NULL)
+ return;
+ switch (ngq->flags) {
+ case NGQF_DATA:
+ hook = ngq->body.data.da_hook;
+ m = ngq->body.data.da_m;
+ meta = ngq->body.data.da_meta;
+ RETURN_QBLK(ngq);
+ NG_SEND_DATAQ(error, hook, m, meta);
+ ng_unref_hook(hook);
+ break;
+ case NGQF_MESG:
+ node = ngq->body.msg.msg_node;
+ msg = ngq->body.msg.msg_msg;
+ retaddr = ngq->body.msg.msg_retaddr;
+ RETURN_QBLK(ngq);
+ if (node->flags & NG_INVALID) {
+ FREE(msg, M_NETGRAPH);
+ } else {
+ CALL_MSG_HANDLER(error, node, msg,
+ retaddr, NULL);
+ }
+ ng_unref(node);
+ if (retaddr)
+ FREE(retaddr, M_NETGRAPH);
+ break;
+ default:
+ RETURN_QBLK(ngq);
+ }
+ }
+}
+
+
diff --git a/sys/netgraph/ng_cisco.c b/sys/netgraph/ng_cisco.c
new file mode 100644
index 0000000..1d8ad13
--- /dev/null
+++ b/sys/netgraph/ng_cisco.c
@@ -0,0 +1,557 @@
+
+/*
+ * ng_cisco.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_cisco.c,v 1.23 1999/01/28 23:54:53 julian Exp $
+ */
+
+#include "opt_inet.h"
+#include "opt_atalk.h"
+#include "opt_ipx.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#include <netatalk/at_extern.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_cisco.h>
+
+#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
+#define CISCO_UNICAST 0x0f /* Cisco unicast address */
+#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
+#define CISCO_ADDR_REQ 0 /* Cisco address request */
+#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+
+#define KEEPALIVE_SECS 10
+
+struct cisco_header {
+ u_char address;
+ u_char control;
+ u_short protocol;
+};
+
+#define CISCO_HEADER_LEN sizeof (struct cisco_header)
+
+struct cisco_packet {
+ u_long type;
+ u_long par1;
+ u_long par2;
+ u_short rel;
+ u_short time0;
+ u_short time1;
+};
+
+#define CISCO_PACKET_LEN (sizeof(struct cisco_packet))
+
+struct protoent {
+ hook_p hook; /* the hook for this proto */
+ u_short af; /* address family, -1 = downstream */
+};
+
+struct cisco_priv {
+ u_long local_seq;
+ u_long remote_seq;
+ u_long seq_retries; /* how many times we've been here throwing out
+ * the same sequence number without ack */
+ node_p node;
+ struct callout_handle handle;
+ struct protoent downstream;
+ struct protoent inet; /* IP information */
+ struct in_addr localip;
+ struct in_addr localmask;
+ struct protoent atalk; /* AppleTalk information */
+ struct protoent ipx; /* IPX information */
+};
+typedef struct cisco_priv *sc_p;
+
+/* Netgraph methods */
+static int cisco_constructor(node_p *node);
+static int cisco_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int cisco_rmnode(node_p node);
+static int cisco_newhook(node_p node, hook_p hook, const char *name);
+
+static int cisco_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int cisco_disconnect(hook_p hook);
+
+/* Other functions */
+static int cisco_input(sc_p sc, struct mbuf *m, meta_p meta);
+static void cisco_keepalive(void *arg);
+static int cisco_send(sc_p sc, int type, long par1, long par2);
+
+/* Node type */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_CISCO_NODE_TYPE,
+ NULL,
+ cisco_constructor,
+ cisco_rcvmsg,
+ cisco_rmnode,
+ cisco_newhook,
+ NULL,
+ NULL,
+ cisco_rcvdata,
+ cisco_rcvdata,
+ cisco_disconnect
+};
+NETGRAPH_INIT(cisco, &typestruct);
+
+/*
+ * Node constructor
+ */
+static int
+cisco_constructor(node_p *nodep)
+{
+ sc_p sc;
+ int error = 0;
+
+ MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
+ if (sc == NULL)
+ return (ENOMEM);
+ bzero(sc, sizeof(struct cisco_priv));
+
+ callout_handle_init(&sc->handle);
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(sc, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = sc;
+ sc->node = *nodep;
+
+ /* Initialise the varous protocol hook holders */
+ sc->downstream.af = 0xffff;
+ sc->inet.af = AF_INET;
+ sc->atalk.af = AF_APPLETALK;
+ sc->ipx.af = AF_IPX;
+ return (0);
+}
+
+/*
+ * Check new hook
+ */
+static int
+cisco_newhook(node_p node, hook_p hook, const char *name)
+{
+ const sc_p sc = node->private;
+
+ if (strcmp(name, NG_CISCO_HOOK_DOWNSTREAM) == 0) {
+ sc->downstream.hook = hook;
+ hook->private = &sc->downstream;
+
+ /* Start keepalives */
+ sc->handle = timeout(cisco_keepalive, sc, hz * KEEPALIVE_SECS);
+ } else if (strcmp(name, NG_CISCO_HOOK_INET) == 0) {
+ sc->inet.hook = hook;
+ hook->private = &sc->inet;
+ } else if (strcmp(name, NG_CISCO_HOOK_APPLETALK) == 0) {
+ sc->atalk.hook = hook;
+ hook->private = &sc->atalk;
+ } else if (strcmp(name, NG_CISCO_HOOK_IPX) == 0) {
+ sc->ipx.hook = hook;
+ hook->private = &sc->ipx;
+ } else if (strcmp(name, NG_CISCO_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* unimplemented */
+ } else
+ return (EINVAL);
+ return 0;
+}
+
+/*
+ * Receive control message.
+ */
+static int
+cisco_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **rptr)
+{
+ const sc_p sc = node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ switch (msg->header.typecookie) {
+ case NGM_GENERIC_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_TEXT_STATUS:
+ {
+ char *arg;
+ int pos;
+
+ NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg)
+ + NG_TEXTRESPONSE, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ arg = (char *) resp->data;
+ pos = sprintf(arg,
+ "keepalive period: %d sec; ", KEEPALIVE_SECS);
+ pos += sprintf(arg + pos,
+ "unacknowledged keepalives: %ld", sc->seq_retries);
+ resp->header.arglen = pos + 1;
+ break;
+ }
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case NGM_CISCO_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_CISCO_GET_IPADDR: /* could be a late reply! */
+ if ((msg->header.flags & NGF_RESP) == 0) {
+ struct in_addr *ips;
+
+ NG_MKRESPONSE(resp, msg,
+ 2 * sizeof(*ips), M_NOWAIT);
+ if (!resp) {
+ error = ENOMEM;
+ break;
+ }
+ ips = (struct in_addr *) resp->data;
+ ips[0] = sc->localip;
+ ips[1] = sc->localmask;
+ break;
+ }
+ /* FALLTHROUGH */ /* ...if it's a reply */
+ case NGM_CISCO_SET_IPADDR:
+ {
+ struct in_addr *const ips = (struct in_addr *)msg->data;
+
+ if (msg->header.arglen < 2 * sizeof(*ips)) {
+ error = EINVAL;
+ break;
+ }
+ sc->localip = ips[0];
+ sc->localmask = ips[1];
+ break;
+ }
+ case NGM_CISCO_GET_STATUS:
+ {
+ struct ngciscostat *stat;
+
+ NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT);
+ if (!resp) {
+ error = ENOMEM;
+ break;
+ }
+ stat = (struct ngciscostat *) resp->data;
+ stat->seq_retries = sc->seq_retries;
+ stat->keepalive_period = KEEPALIVE_SECS;
+ break;
+ }
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Receive data
+ */
+static int
+cisco_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const sc_p sc = hook->node->private;
+ struct protoent *pep;
+ struct cisco_header *h;
+ int error = 0;
+
+ if ((pep = hook->private) == NULL)
+ goto out;
+
+ /* If it came from our downlink, deal with it separately */
+ if (pep->af == 0xffff)
+ return (cisco_input(sc, m, meta));
+
+ /* OK so it came from a protocol, heading out. Prepend general data
+ packet header. For now, IP,IPX only */
+ M_PREPEND(m, CISCO_HEADER_LEN, M_DONTWAIT);
+ if (!m) {
+ error = ENOBUFS;
+ goto out;
+ }
+ h = mtod(m, struct cisco_header *);
+ h->address = CISCO_MULTICAST; /* broadcast address */
+ h->control = 0;
+
+ switch (pep->af) {
+ case AF_INET: /* Internet Protocol */
+ h->protocol = htons(ETHERTYPE_IP);
+ break;
+ case AF_APPLETALK: /* AppleTalk Protocol */
+ h->protocol = htons(ETHERTYPE_AT);
+ break;
+ case AF_IPX: /* Novell IPX Protocol */
+ h->protocol = htons(ETHERTYPE_IPX);
+ break;
+ default:
+ error = EAFNOSUPPORT;
+ goto out;
+ }
+
+ /* Send it */
+ NG_SEND_DATA(error, sc->downstream.hook, m, meta);
+ return (error);
+
+out:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * Shutdown node
+ */
+static int
+cisco_rmnode(node_p node)
+{
+ const sc_p sc = node->private;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ node->private = NULL;
+ ng_unref(sc->node);
+ FREE(sc, M_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Disconnection of a hook
+ *
+ * For this type, removal of the last link destroys the node
+ */
+static int
+cisco_disconnect(hook_p hook)
+{
+ const sc_p sc = hook->node->private;
+ struct protoent *pep;
+
+ /* Check it's not the debug hook */
+ if ((pep = hook->private)) {
+ pep->hook = NULL;
+ if (pep->af == 0xffff) {
+ /* If it is the downstream hook, stop the timers */
+ untimeout(cisco_keepalive, sc, sc->handle);
+ }
+ }
+
+ /* If no more hooks, remove the node */
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
+/*
+ * Receive data
+ */
+static int
+cisco_input(sc_p sc, struct mbuf *m, meta_p meta)
+{
+ struct cisco_header *h;
+ struct cisco_packet *p;
+ struct protoent *pep;
+ int error = 0;
+
+ if (m->m_pkthdr.len <= CISCO_HEADER_LEN)
+ goto drop;
+
+ /* Strip off cisco header */
+ h = mtod(m, struct cisco_header *);
+ m_adj(m, CISCO_HEADER_LEN);
+
+ switch (h->address) {
+ default: /* Invalid Cisco packet. */
+ goto drop;
+ case CISCO_UNICAST:
+ case CISCO_MULTICAST:
+ /* Don't check the control field here (RFC 1547). */
+ switch (ntohs(h->protocol)) {
+ default:
+ goto drop;
+ case CISCO_KEEPALIVE:
+ p = mtod(m, struct cisco_packet *);
+ switch (ntohl(p->type)) {
+ default:
+ log(LOG_WARNING,
+ "cisco: unknown cisco packet type: 0x%lx\n",
+ ntohl(p->type));
+ break;
+ case CISCO_ADDR_REPLY:
+ /* Reply on address request, ignore */
+ break;
+ case CISCO_KEEPALIVE_REQ:
+ sc->remote_seq = ntohl(p->par1);
+ if (sc->local_seq == ntohl(p->par2)) {
+ sc->local_seq++;
+ sc->seq_retries = 0;
+ }
+ break;
+ case CISCO_ADDR_REQ:
+ {
+ struct ng_mesg *msg, *resp;
+
+ /* Ask inet peer for IP address information */
+ if (sc->inet.hook == NULL)
+ goto nomsg;
+ NG_MKMESSAGE(msg, NGM_CISCO_COOKIE,
+ NGM_CISCO_GET_IPADDR, 0, M_NOWAIT);
+ if (msg == NULL)
+ goto nomsg;
+ ng_send_msg(sc->node, msg,
+ NG_CISCO_HOOK_INET, &resp);
+ if (resp != NULL)
+ cisco_rcvmsg(sc->node, resp, ".", NULL);
+
+ nomsg:
+ /* Send reply to peer device */
+ error = cisco_send(sc, CISCO_ADDR_REPLY,
+ ntohl(sc->localip.s_addr),
+ ntohl(sc->localmask.s_addr));
+ break;
+ }
+ }
+ goto drop;
+ case ETHERTYPE_IP:
+ pep = &sc->inet;
+ break;
+ case ETHERTYPE_AT:
+ pep = &sc->atalk;
+ break;
+ case ETHERTYPE_IPX:
+ pep = &sc->ipx;
+ break;
+ }
+ break;
+ }
+
+ /* Send it on */
+ if (pep->hook == NULL)
+ goto drop;
+ NG_SEND_DATA(error, pep->hook, m, meta);
+ return (error);
+
+drop:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+
+/*
+ * Send keepalive packets, every 10 seconds.
+ */
+static void
+cisco_keepalive(void *arg)
+{
+ const sc_p sc = arg;
+ int s = splimp();
+
+ cisco_send(sc, CISCO_KEEPALIVE_REQ, sc->local_seq, sc->remote_seq);
+ sc->seq_retries++;
+ splx(s);
+ sc->handle = timeout(cisco_keepalive, sc, hz * KEEPALIVE_SECS);
+}
+
+/*
+ * Send Cisco keepalive packet.
+ */
+static int
+cisco_send(sc_p sc, int type, long par1, long par2)
+{
+ struct cisco_header *h;
+ struct cisco_packet *ch;
+ struct mbuf *m;
+ u_long t;
+ int error = 0;
+ meta_p meta = NULL;
+ struct timeval time;
+
+ getmicrotime(&time);
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (!m)
+ return (ENOBUFS);
+
+ t = (time.tv_sec - boottime.tv_sec) * 1000;
+ m->m_pkthdr.len = m->m_len = CISCO_HEADER_LEN + CISCO_PACKET_LEN;
+ m->m_pkthdr.rcvif = 0;
+
+ h = mtod(m, struct cisco_header *);
+ h->address = CISCO_MULTICAST;
+ h->control = 0;
+ h->protocol = htons(CISCO_KEEPALIVE);
+
+ ch = (struct cisco_packet *) (h + 1);
+ ch->type = htonl(type);
+ ch->par1 = htonl(par1);
+ ch->par2 = htonl(par2);
+ ch->rel = -1;
+ ch->time0 = htons((u_short) (t >> 16));
+ ch->time1 = htons((u_short) t);
+
+ NG_SEND_DATA(error, sc->downstream.hook, m, meta);
+ return (error);
+}
diff --git a/sys/netgraph/ng_cisco.h b/sys/netgraph/ng_cisco.h
new file mode 100644
index 0000000..559cc14
--- /dev/null
+++ b/sys/netgraph/ng_cisco.h
@@ -0,0 +1,76 @@
+
+/*
+ * ng_cisco.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_cisco.h,v 1.6 1999/01/25 01:21:48 archie Exp $
+ */
+
+#ifndef _NETGRAPH_CISCO_H_
+#define _NETGRAPH_CISCO_H_
+
+/* Node type name and magic cookie */
+#define NG_CISCO_NODE_TYPE "cisco"
+#define NGM_CISCO_COOKIE 860707227
+
+/* Hook names */
+#define NG_CISCO_HOOK_DOWNSTREAM "downstream"
+#define NG_CISCO_HOOK_INET "inet"
+#define NG_CISCO_HOOK_APPLETALK "atalk"
+#define NG_CISCO_HOOK_IPX "ipx"
+#define NG_CISCO_HOOK_DEBUG "debug"
+
+/* Netgraph commands */
+enum {
+ /* This takes two struct in_addr's: the IP address and netmask */
+ NGM_CISCO_SET_IPADDR = 1,
+
+ /* This is both received and *sent* by this node (to the "inet"
+ peer). The reply contains the same info as NGM_CISCO_SET_IPADDR. */
+ NGM_CISCO_GET_IPADDR,
+
+ /* This returns a struct ngciscostat (see below) */
+ NGM_CISCO_GET_STATUS,
+};
+
+struct ngciscostat {
+ u_int32_t seq_retries; /* # unack'd retries */
+ u_int32_t keepalive_period; /* in seconds */
+};
+
+#endif /* _NETGRAPH_CISCO_H_ */
+
diff --git a/sys/netgraph/ng_echo.c b/sys/netgraph/ng_echo.c
new file mode 100644
index 0000000..ed69f9c
--- /dev/null
+++ b/sys/netgraph/ng_echo.c
@@ -0,0 +1,121 @@
+
+/*
+ * ng_echo.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elisher <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_echo.c,v 1.11 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * Netgraph "echo" node
+ *
+ * This node simply bounces data and messages back to whence they came.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_echo.h>
+
+/* Netgraph methods */
+static int nge_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg ** resp);
+static int nge_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int nge_disconnect(hook_p hook);
+
+/* Netgraph type */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_ECHO_NODE_TYPE,
+ NULL,
+ NULL,
+ nge_rcvmsg,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ nge_rcvdata,
+ nge_rcvdata,
+ nge_disconnect
+};
+NETGRAPH_INIT(echo, &typestruct);
+
+/*
+ * Receive control message. We just bounce it back as a reply.
+ */
+static int
+nge_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **rptr)
+{
+ if (rptr) {
+ msg->header.flags |= NGF_RESP;
+ *rptr = msg;
+ } else {
+ FREE(msg, M_NETGRAPH);
+ }
+ return (0);
+}
+
+/*
+ * Receive data
+ */
+static int
+nge_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int error = 0;
+
+ NG_SEND_DATA(error, hook, m, meta);
+ return (error);
+}
+
+/*
+ * Removal of the last link destroys the nodeo
+ */
+static int
+nge_disconnect(hook_p hook)
+{
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_echo.h b/sys/netgraph/ng_echo.h
new file mode 100644
index 0000000..ca8663f
--- /dev/null
+++ b/sys/netgraph/ng_echo.h
@@ -0,0 +1,50 @@
+
+/*
+ * ng_echo.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_echo.h,v 1.3 1999/01/20 00:22:12 archie Exp $
+ */
+
+#ifndef _NETGRAPH_ECHO_H_
+#define _NETGRAPH_ECHO_H_
+
+/* Node type name and magic cookie */
+#define NG_ECHO_NODE_TYPE "echo"
+#define NGM_ECHO_COOKIE 884298942
+
+#endif /* _NETGRAPH_ECHO_H_ */
diff --git a/sys/netgraph/ng_ether.h b/sys/netgraph/ng_ether.h
new file mode 100644
index 0000000..45625e4
--- /dev/null
+++ b/sys/netgraph/ng_ether.h
@@ -0,0 +1,55 @@
+
+/*
+ * ng_ether.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_ether.h,v 1.1 1999/02/02 03:17:22 julian Exp $
+ */
+
+#ifndef _NETGRAPH_NG_ETHER_H_
+#define _NETGRAPH_NG_ETHER_H_
+
+/* Node type name and magic cookie */
+#define NG_ETHER_NODE_TYPE "ether"
+#define NGM_ETHER_COOKIE 917786904
+
+/* Hook names */
+#define NG_ETHER_HOOK_ORPHAN "orphans"
+#define NG_ETHER_HOOK_DIVERT "divert"
+
+#endif /* _NETGRAPH_NG_ETHER_H_ */
+
diff --git a/sys/netgraph/ng_frame_relay.c b/sys/netgraph/ng_frame_relay.c
new file mode 100644
index 0000000..995b769
--- /dev/null
+++ b/sys/netgraph/ng_frame_relay.c
@@ -0,0 +1,526 @@
+
+/*
+ * ng_frame_relay.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elisher <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_frame_relay.c,v 1.16 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * This node implements the frame relay protocol, not including
+ * the LMI line management. This means basically keeping track
+ * of which DLCI's are active, doing frame (de)multiplexing, etc.
+ *
+ * It has a 'downstream' hook that goes to the line, and a
+ * hook for each DLCI (eg, 'dlci16').
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <machine/clock.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_frame_relay.h>
+
+/*
+ * Line info, and status per channel.
+ */
+struct ctxinfo { /* one per active hook */
+ u_int flags;
+#define CHAN_VALID 0x01 /* assigned to a channel */
+#define CHAN_ACTIVE 0x02 /* bottom level active */
+ int dlci; /* the dlci assigned to this context */
+ hook_p hook; /* if there's a hook assigned.. */
+};
+
+#define MAX_CT 16 /* # of dlci's active at a time (POWER OF 2!) */
+struct frmrel_softc {
+ int unit; /* which card are we? */
+ char nodename[NG_NODELEN + 1]; /* store our node name */
+ int datahooks; /* number of data hooks attached */
+ node_p node; /* netgraph node */
+ int addrlen; /* address header length */
+ int flags; /* state */
+ int mtu; /* guess */
+ u_char remote_seq; /* sequence number the remote sent */
+ u_char local_seq; /* sequence number the remote rcvd */
+ u_short ALT[1024]; /* map DLCIs to CTX */
+#define CTX_VALID 0x8000 /* this bit means it's a valid CTX */
+#define CTX_VALUE (MAX_CT - 1) /* mask for context part */
+ struct ctxinfo channel[MAX_CT];
+ struct ctxinfo downstream;
+};
+typedef struct frmrel_softc *sc_p;
+
+#define BYTEX_EA 0x01 /* End Address. Always 0 on byte1 */
+#define BYTE1_C_R 0x02
+#define BYTE2_FECN 0x08 /* forwards congestion notification */
+#define BYTE2_BECN 0x04 /* Backward congestion notification */
+#define BYTE2_DE 0x02 /* Discard elligability */
+#define LASTBYTE_D_C 0x02 /* last byte is dl_core or dlci info */
+
+/* Used to do headers */
+static struct segment {
+ u_char mask;
+ u_char shift;
+ u_char width;
+} makeup[] = {
+ { 0xfc, 2, 6 },
+ { 0xf0, 4, 4 },
+ { 0xfe, 1, 7 },
+ { 0xfc, 2, 6 }
+};
+
+#define SHIFTIN(segment, byte, dlci) \
+ { \
+ (dlci) <<= (segment)->width; \
+ (dlci) |= \
+ (((byte) & (segment)->mask) >> (segment)->shift); \
+ }
+
+#define SHIFTOUT(segment, byte, dlci) \
+ { \
+ (byte) |= (((dlci) << (segment)->shift) & (segment)->mask); \
+ (dlci) >>= (segment)->width; \
+ }
+
+/* Netgraph methods */
+static int ngfrm_constructor(node_p *nodep);
+static int ngfrm_rmnode(node_p node);
+static int ngfrm_newhook(node_p node, hook_p hook, const char *name);
+static int ngfrm_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngfrm_disconnect(hook_p hook);
+
+/* Other internal functions */
+static int ngfrm_decode(node_p node, struct mbuf * m, meta_p meta);
+static int ngfrm_addrlen(char *hdr);
+static int ngfrm_allocate_CTX(sc_p sc, int dlci);
+
+/* Netgraph type */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_FRAMERELAY_NODE_TYPE,
+ NULL,
+ ngfrm_constructor,
+ NULL,
+ ngfrm_rmnode,
+ ngfrm_newhook,
+ NULL,
+ NULL,
+ ngfrm_rcvdata,
+ ngfrm_rcvdata,
+ ngfrm_disconnect
+};
+NETGRAPH_INIT(framerelay, &typestruct);
+
+/*
+ * Given a DLCI, return the index of the context table entry for it,
+ * Allocating a new one if needs be, or -1 if none available.
+ */
+static int
+ngfrm_allocate_CTX(sc_p sc, int dlci)
+{
+ u_int ctxnum = -1; /* what ctx number we are using */
+ volatile struct ctxinfo *CTXp = NULL;
+
+ /* Sanity check the dlci value */
+ if (dlci > 1023)
+ return (-1);
+
+ /* Check to see if we already have an entry for this DLCI */
+ if (sc->ALT[dlci]) {
+ if ((ctxnum = sc->ALT[dlci] & CTX_VALUE) < MAX_CT) {
+ CTXp = sc->channel + ctxnum;
+ } else {
+ ctxnum = -1;
+ sc->ALT[dlci] = 0; /* paranoid but... */
+ }
+ }
+
+ /*
+ * If the index has no valid entry yet, then we need to allocate a
+ * CTX number to it
+ */
+ if (CTXp == NULL) {
+ for (ctxnum = 0; ctxnum < MAX_CT; ctxnum++) {
+ /*
+ * If the VALID flag is empty it is unused
+ */
+ if ((sc->channel[ctxnum].flags & CHAN_VALID) == 0) {
+ bzero(sc->channel + ctxnum,
+ sizeof(struct ctxinfo));
+ CTXp = sc->channel + ctxnum;
+ sc->ALT[dlci] = ctxnum | CTX_VALID;
+ sc->channel[ctxnum].dlci = dlci;
+ sc->channel[ctxnum].flags = CHAN_VALID;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If we still don't have a CTX pointer, then we never found a free
+ * spot so give up now..
+ */
+ if (!CTXp) {
+ log(LOG_ERR, "No CTX available for dlci %d\n", dlci);
+ return (-1);
+ }
+ return (ctxnum);
+}
+
+/*
+ * Node constructor
+ */
+static int
+ngfrm_constructor(node_p *nodep)
+{
+ sc_p sc;
+ int error = 0;
+
+ MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT);
+ if (!sc)
+ return (ENOMEM);
+ bzero(sc, sizeof(*sc));
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(sc, M_NETGRAPH);
+ return (error);
+ }
+ sc->addrlen = 2; /* default */
+
+ /* Link the node and our private info */
+ (*nodep)->private = sc;
+ sc->node = *nodep;
+ return (0);
+}
+
+/*
+ * Add a new hook
+ *
+ * We allow hooks called "debug", "downstream" and dlci[0-1023]
+ * The hook's private info points to our stash of info about that
+ * channel. A NULL pointer is debug and a DLCI of -1 means downstream.
+ */
+static int
+ngfrm_newhook(node_p node, hook_p hook, const char *name)
+{
+ const sc_p sc = node->private;
+ const char *cp;
+ char c = '\0';
+ int digits = 0;
+ int dlci = 0;
+ int ctxnum;
+
+ /* Check if it's our friend the control hook */
+ if (strcmp(name, NG_FRAMERELAY_HOOK_DEBUG) == 0) {
+ hook->private = NULL; /* paranoid */
+ return (0);
+ }
+
+ /*
+ * All other hooks either start with 'dlci' and have a decimal
+ * trailing channel number up to 4 digits, or are the downstream
+ * hook.
+ */
+ if (strncmp(name, NG_FRAMERELAY_HOOK_DLCI,
+ strlen(NG_FRAMERELAY_HOOK_DLCI)) != 0) {
+
+ /* It must be the downstream connection */
+ if (strcmp(name, NG_FRAMERELAY_HOOK_DOWNSTREAM) != 0)
+ return EINVAL;
+
+ /* Make sure we haven't already got one (paranoid) */
+ if (sc->downstream.hook)
+ return (EADDRINUSE);
+
+ /* OK add it */
+ hook->private = &sc->downstream;
+ sc->downstream.hook = hook;
+ sc->downstream.dlci = -1;
+ sc->downstream.flags |= CHAN_ACTIVE;
+ sc->datahooks++;
+ return (0);
+ }
+
+ /* Must be a dlci hook at this point */
+ cp = name + strlen(NG_FRAMERELAY_HOOK_DLCI);
+ while ((digits < 5) && ((c = *cp++) >= '0') && (c <= '9')) {
+ dlci *= 10;
+ dlci += c - '0';
+ digits++;
+ }
+ if ((c != 0) || (digits == 5) || (dlci < 0) || (dlci > 1023))
+ return (EINVAL);
+ /*
+ * We have a dlci, now either find it, or allocate it. It's possible
+ * that we might have seen packets for it already and made an entry
+ * for it.
+ */
+ ctxnum = ngfrm_allocate_CTX(sc, dlci);
+ if (ctxnum == -1)
+ return (ENOBUFS);
+
+ /*
+ * Be paranoid: if it's got a hook already, that dlci is in use .
+ * Generic code can not catch all the synonyms (e.g. dlci016 vs
+ * dlci16)
+ */
+ if (sc->channel[ctxnum].hook != NULL)
+ return (EADDRINUSE);
+
+ /*
+ * Put our hooks into it (pun not intended)
+ */
+ sc->channel[ctxnum].flags |= CHAN_ACTIVE;
+ hook->private = sc->channel + ctxnum;
+ sc->channel[ctxnum].hook = hook;
+ sc->datahooks++;
+ return (0);
+}
+
+/*
+ * Count up the size of the address header if we don't already know
+ */
+int
+ngfrm_addrlen(char *hdr)
+{
+ if (hdr[0] & BYTEX_EA)
+ return 0;
+ if (hdr[1] & BYTEX_EA)
+ return 2;
+ if (hdr[2] & BYTEX_EA)
+ return 3;
+ if (hdr[3] & BYTEX_EA)
+ return 4;
+ return 0;
+}
+
+/*
+ * Receive data packet
+ */
+static int
+ngfrm_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ struct ctxinfo *const ctxp = hook->private;
+ int error = 0;
+ int dlci;
+ sc_p sc;
+ int alen;
+ char *data;
+
+ /* Data doesn't come in from just anywhere (e.g debug hook) */
+ if (ctxp == NULL) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /* If coming from downstream, decode it to a channel */
+ dlci = ctxp->dlci;
+ if (dlci == -1)
+ return (ngfrm_decode(hook->node, m, meta));
+
+ /* Derive the softc we will need */
+ sc = hook->node->private;
+
+ /* If there is no live channel, throw it away */
+ if ((sc->downstream.hook == NULL)
+ || ((ctxp->flags & CHAN_ACTIVE) == 0)) {
+ error = ENETDOWN;
+ goto bad;
+ }
+
+ /* Store the DLCI on the front of the packet */
+ alen = sc->addrlen;
+ if (alen == 0)
+ alen = 2; /* default value for transmit */
+ M_PREPEND(m, alen, M_DONTWAIT);
+ if (m == NULL) {
+ error = ENOBUFS;
+ goto bad;
+ }
+ data = mtod(m, char *);
+
+ /*
+ * Shift the lowest bits into the address field untill we are done.
+ * First byte is MSBits of addr so work backwards.
+ */
+ switch (alen) {
+ case 2:
+ data[0] = data[1] = '\0';
+ SHIFTOUT(makeup + 1, data[1], dlci);
+ SHIFTOUT(makeup + 0, data[0], dlci);
+ data[1] |= BYTEX_EA;
+ break;
+ case 3:
+ data[0] = data[1] = data[2] = '\0';
+ SHIFTOUT(makeup + 3, data[2], dlci); /* 3 and 2 is correct */
+ SHIFTOUT(makeup + 1, data[1], dlci);
+ SHIFTOUT(makeup + 0, data[0], dlci);
+ data[2] |= BYTEX_EA;
+ break;
+ case 4:
+ data[0] = data[1] = data[2] = data[3] = '\0';
+ SHIFTOUT(makeup + 3, data[3], dlci);
+ SHIFTOUT(makeup + 2, data[2], dlci);
+ SHIFTOUT(makeup + 1, data[1], dlci);
+ SHIFTOUT(makeup + 0, data[0], dlci);
+ data[3] |= BYTEX_EA;
+ break;
+ default:
+ panic(__FUNCTION__);
+ }
+
+ /* Send it */
+ NG_SEND_DATA(error, sc->downstream.hook, m, meta);
+ return (error);
+
+bad:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * Decode an incoming frame coming from the switch
+ */
+static int
+ngfrm_decode(node_p node, struct mbuf *m, meta_p meta)
+{
+ const sc_p sc = node->private;
+ char *data;
+ int alen;
+ u_int dlci = 0;
+ int error = 0;
+ int ctxnum;
+
+ if ((m = m_pullup(m, 4)) == NULL) {
+ error = ENOBUFS;
+ goto out;
+ }
+ data = mtod(m, char *);
+ if ((alen = sc->addrlen) == 0) {
+ sc->addrlen = alen = ngfrm_addrlen(data);
+ }
+ switch (alen) {
+ case 2:
+ SHIFTIN(makeup + 0, data[0], dlci);
+ SHIFTIN(makeup + 1, data[1], dlci);
+ break;
+ case 3:
+ SHIFTIN(makeup + 0, data[0], dlci);
+ SHIFTIN(makeup + 1, data[1], dlci);
+ SHIFTIN(makeup + 3, data[2], dlci); /* 3 and 2 is correct */
+ break;
+ case 4:
+ SHIFTIN(makeup + 0, data[0], dlci);
+ SHIFTIN(makeup + 1, data[1], dlci);
+ SHIFTIN(makeup + 2, data[2], dlci);
+ SHIFTIN(makeup + 3, data[3], dlci);
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ if (dlci > 1023) {
+ error = EINVAL;
+ goto out;
+ }
+ ctxnum = sc->ALT[dlci];
+ if ((ctxnum & CTX_VALID) && sc->channel[ctxnum &= CTX_VALUE].hook) {
+ /* Send it */
+ m_adj(m, alen);
+ NG_SEND_DATA(error, sc->channel[ctxnum].hook, m, meta);
+ return (error);
+ } else {
+ error = ENETDOWN;
+ }
+out:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * Shutdown node
+ */
+static int
+ngfrm_rmnode(node_p node)
+{
+ const sc_p sc = node->private;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ node->private = NULL;
+ FREE(sc, M_NETGRAPH);
+ ng_unref(sc->node);
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ *
+ * Invalidate the private data associated with this dlci.
+ * For this type, removal of the last link resets tries to destroy the node.
+ */
+static int
+ngfrm_disconnect(hook_p hook)
+{
+ const sc_p sc = hook->node->private;
+ struct ctxinfo *const cp = hook->private;
+ int dlci;
+
+ /* If it's a regular dlci hook, then free resources etc.. */
+ if (cp != NULL) {
+ cp->hook = NULL;
+ dlci = cp->dlci;
+ if (dlci != -1)
+ sc->ALT[dlci] = 0;
+ cp->flags = 0;
+ sc->datahooks--;
+ }
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
diff --git a/sys/netgraph/ng_frame_relay.h b/sys/netgraph/ng_frame_relay.h
new file mode 100644
index 0000000..5c76421
--- /dev/null
+++ b/sys/netgraph/ng_frame_relay.h
@@ -0,0 +1,55 @@
+
+/*
+ * ng_frame_relay.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_frame_relay.h,v 1.7 1999/01/20 00:22:13 archie Exp $
+ */
+
+#ifndef _NETGRAPH_FRAME_RELAY_H_
+#define _NETGRAPH_FRAME_RELAY_H_
+
+/* Node type name and magic cookie */
+#define NG_FRAMERELAY_NODE_TYPE "frame_relay"
+#define NGM_FRAMERELAY_COOKIE 872148478
+
+/* Hook names */
+#define NG_FRAMERELAY_HOOK_DEBUG "debug"
+#define NG_FRAMERELAY_HOOK_DOWNSTREAM "downstream"
+#define NG_FRAMERELAY_HOOK_DLCI "dlci" /* really just the prefix */
+
+#endif /* _NETGRAPH_FRAME_RELAY_H_ */
diff --git a/sys/netgraph/ng_hole.c b/sys/netgraph/ng_hole.c
new file mode 100644
index 0000000..7baf91d
--- /dev/null
+++ b/sys/netgraph/ng_hole.c
@@ -0,0 +1,97 @@
+
+/*
+ * ng_hole.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elisher <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_hole.c,v 1.8 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * This node is a 'black hole' that simply discards everything it receives
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_hole.h>
+
+/* Netgraph methods */
+static int ngh_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngh_disconnect(hook_p hook);
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_HOLE_NODE_TYPE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ngh_rcvdata,
+ ngh_rcvdata,
+ ngh_disconnect
+};
+NETGRAPH_INIT(hole, &typestruct);
+
+/*
+ * Receive data
+ */
+static int
+ngh_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ NG_FREE_DATA(m, meta);
+ return 0;
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ngh_disconnect(hook_p hook)
+{
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
diff --git a/sys/netgraph/ng_hole.h b/sys/netgraph/ng_hole.h
new file mode 100644
index 0000000..ec12f3f
--- /dev/null
+++ b/sys/netgraph/ng_hole.h
@@ -0,0 +1,50 @@
+
+/*
+ * ng_hole.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_hole.h,v 1.3 1999/01/20 00:22:13 archie Exp $
+ */
+
+#ifndef _NETGRAPH_HOLE_H_
+#define _NETGRAPH_HOLE_H_
+
+/* Node type name and magic cookie */
+#define NG_HOLE_NODE_TYPE "hole"
+#define NGM_HOLE_COOKIE 915433206
+
+#endif /* _NETGRAPH_HOLE_H_ */
diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c
new file mode 100644
index 0000000..d487749
--- /dev/null
+++ b/sys/netgraph/ng_iface.c
@@ -0,0 +1,778 @@
+
+/*
+ * ng_iface.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_iface.c,v 1.31 1999/02/02 22:27:28 archie Exp $
+ */
+
+/*
+ * This node is also a system networking interface. It has
+ * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
+ * are simply relayed between the interface and the hooks.
+ *
+ * Interfaces are named ng0, ng1, .... FreeBSD does not support
+ * the removal of interfaces, so iface nodes are persistent.
+ *
+ * This node also includes Berkeley packet filter support.
+ */
+
+#include "opt_inet.h"
+#include "opt_atalk.h"
+#include "opt_ipx.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_iface.h>
+#include <netgraph/ng_cisco.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_var.h>
+#endif
+
+#ifdef NETATALK
+#include <netatalk/at.h>
+#include <netatalk/at_var.h>
+#include <netatalk/at_extern.h>
+#endif
+
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include "bpfilter.h"
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+/* This struct describes one address family */
+struct iffam {
+ char *hookname; /* Name for hook */
+ u_char af; /* Family number */
+ u_char netisr; /* or NETISR_NONE */
+ union {
+ void *_dummy; /* avoid warning */
+ struct ifqueue *inq; /* if netisr */
+ void (*input)(struct mbuf *m); /* if direct input */
+ } u;
+};
+typedef const struct iffam *iffam_p;
+
+#define NETISR_NONE 0xff
+
+/* List of address families supported by our interface. Each address
+ family has a way to input packets to it, either by calling a function
+ directly (such as ip_input()) or by adding the packet to a queue and
+ setting a NETISR bit. */
+const static struct iffam gFamilies[] = {
+#ifdef INET
+ {
+ NG_IFACE_HOOK_INET,
+ AF_INET,
+ NETISR_NONE,
+ ip_input
+ },
+#endif
+#ifdef NETATALK
+ {
+ NG_IFACE_HOOK_ATALK,
+ AF_APPLETALK,
+ NETISR_ATALK,
+ &atintrq2
+ },
+#endif
+#ifdef IPX
+ {
+ NG_IFACE_HOOK_IPX,
+ AF_IPX,
+ NETISR_IPX,
+ &ipxintrq
+ },
+#endif
+#ifdef NS
+ {
+ NG_IFACE_HOOK_NS,
+ AF_NS,
+ NETISR_NS,
+ &nsintrq
+ },
+#endif
+};
+#define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies))
+
+/* Node private data */
+struct private {
+ struct ifnet *ifp; /* This interface */
+ node_p node; /* Our netgraph node */
+ hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */
+ struct private *next; /* When hung on the free list */
+};
+typedef struct private *priv_p;
+
+/* Interface methods */
+static void ng_iface_start(struct ifnet *ifp);
+static int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
+static int ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
+ struct sockaddr *dst, struct rtentry *rt0);
+#if NBPFILTER > 0
+static void ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af);
+#endif
+#ifdef DEBUG
+static void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
+#endif
+
+/* Netgraph methods */
+static int ng_iface_constructor(node_p *nodep);
+static int ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_iface_rmnode(node_p node);
+static int ng_iface_newhook(node_p node, hook_p hook, const char *name);
+static int ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_iface_disconnect(hook_p hook);
+
+/* Helper stuff */
+static iffam_p get_iffam_from_af(int af);
+static iffam_p get_iffam_from_hook(priv_p priv, hook_p hook);
+static iffam_p get_iffam_from_name(const char *name);
+static hook_p *get_hook_from_iffam(priv_p priv, iffam_p iffam);
+
+/* Node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_IFACE_NODE_TYPE,
+ NULL,
+ ng_iface_constructor,
+ ng_iface_rcvmsg,
+ ng_iface_rmnode,
+ ng_iface_newhook,
+ NULL,
+ NULL,
+ ng_iface_rcvdata,
+ ng_iface_rcvdata,
+ ng_iface_disconnect
+};
+NETGRAPH_INIT(iface, &typestruct);
+
+static char ng_iface_ifname[] = NG_IFACE_IFACE_NAME;
+static int ng_iface_next_unit;
+
+/************************************************************************
+ HELPER STUFF
+ ************************************************************************/
+
+/*
+ * Get the family descriptor from the family ID
+ */
+static __inline__ iffam_p
+get_iffam_from_af(int af)
+{
+ iffam_p iffam;
+ int k;
+
+ for (k = 0; k < NUM_FAMILIES; k++) {
+ iffam = &gFamilies[k];
+ if (iffam->af == af)
+ return (iffam);
+ }
+ return (NULL);
+}
+
+/*
+ * Get the family descriptor from the hook
+ */
+static __inline__ iffam_p
+get_iffam_from_hook(priv_p priv, hook_p hook)
+{
+ int k;
+
+ for (k = 0; k < NUM_FAMILIES; k++)
+ if (priv->hooks[k] == hook)
+ return (&gFamilies[k]);
+ return (NULL);
+}
+
+/*
+ * Get the hook from the iffam descriptor
+ */
+
+static __inline__ hook_p *
+get_hook_from_iffam(priv_p priv, iffam_p iffam)
+{
+ return (&priv->hooks[iffam - gFamilies]);
+}
+
+/*
+ * Get the iffam descriptor from the name
+ */
+static __inline__ iffam_p
+get_iffam_from_name(const char *name)
+{
+ iffam_p iffam;
+ int k;
+
+ for (k = 0; k < NUM_FAMILIES; k++) {
+ iffam = &gFamilies[k];
+ if (!strcmp(iffam->hookname, name))
+ return (iffam);
+ }
+ return (NULL);
+}
+
+/************************************************************************
+ INTERFACE STUFF
+ ************************************************************************/
+
+/*
+ * Process an ioctl for the virtual interface
+ */
+static int
+ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct ifreq *const ifr = (struct ifreq *) data;
+ int s, error = 0;
+
+#ifdef DEBUG
+ ng_iface_print_ioctl(ifp, command, data);
+#endif
+ s = splimp();
+ switch (command) {
+
+ /* These two are mostly handled at a higher layer */
+ case SIOCSIFADDR:
+ ifp->if_flags |= (IFF_UP | IFF_RUNNING);
+ ifp->if_flags &= ~(IFF_OACTIVE);
+ break;
+ case SIOCGIFADDR:
+ break;
+
+ /* Set flags */
+ case SIOCSIFFLAGS:
+ /*
+ * If the interface is marked up and stopped, then start it.
+ * If it is marked down and running, then stop it.
+ */
+ if (ifr->ifr_flags & IFF_UP) {
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags &= ~(IFF_OACTIVE);
+ ifp->if_flags |= IFF_RUNNING;
+ }
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ }
+ break;
+
+ /* Set the interface MTU */
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
+ || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+ /* Stuff that's not supported */
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ case SIOCSIFPHYS:
+ error = EOPNOTSUPP;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/*
+ * This routine is called to deliver a packet out the interface.
+ * We simply look at the address family and relay the packet to
+ * the corresponding hook, if it exists and is connected.
+ */
+
+static int
+ng_iface_output(struct ifnet *ifp, struct mbuf *m,
+ struct sockaddr *dst, struct rtentry *rt0)
+{
+ const priv_p priv = (priv_p) ifp->if_softc;
+ const iffam_p iffam = get_iffam_from_af(dst->sa_family);
+ meta_p meta = NULL;
+ int len, error = 0;
+
+ /* Check interface flags */
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ m_freem(m);
+ return (ENETDOWN);
+ }
+
+ /* Berkeley packet filter */
+#if NBPFILTER > 0
+ ng_iface_bpftap(ifp, m, dst->sa_family);
+#endif
+
+ /* Check address family to determine hook (if known) */
+ if (iffam == NULL) {
+ m_freem(m);
+ log(LOG_WARNING, "%s%d: can't handle af%d\n",
+ ifp->if_name, ifp->if_unit, dst->sa_family);
+ return (EAFNOSUPPORT);
+ }
+
+ /* Copy length before the mbuf gets invalidated */
+ len = m->m_pkthdr.len;
+
+ /* Send packet; if hook is not connected, mbuf will get freed. */
+ NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta);
+
+ /* Update stats */
+ if (error == 0) {
+ ifp->if_obytes += len;
+ ifp->if_opackets++;
+ }
+ return (error);
+}
+
+/*
+ * This routine should never be called
+ */
+
+static void
+ng_iface_start(struct ifnet *ifp)
+{
+ printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__);
+}
+
+#if NBPFILTER > 0
+/*
+ * Flash a packet by the BPF (requires prepending 4 byte AF header)
+ * Note the phoney mbuf; this is OK because BPF treats it read-only.
+ */
+static void
+ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af)
+{
+ struct mbuf m2;
+
+ if (af == AF_UNSPEC) {
+ af = *(mtod(m, int *));
+ m->m_len -= sizeof(int);
+ m->m_pkthdr.len -= sizeof(int);
+ m->m_data += sizeof(int);
+ }
+ if (!ifp->if_bpf)
+ return;
+ m2.m_next = m;
+ m2.m_len = 4;
+ m2.m_data = (char *) &af;
+ bpf_mtap(ifp, &m2);
+}
+#endif /* NBPFILTER > 0 */
+
+#ifdef DEBUG
+/*
+ * Display an ioctl to the virtual interface
+ */
+
+static void
+ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
+{
+ char *str;
+
+ switch (command & IOC_DIRMASK) {
+ case IOC_VOID:
+ str = "IO";
+ break;
+ case IOC_OUT:
+ str = "IOR";
+ break;
+ case IOC_IN:
+ str = "IOW";
+ break;
+ case IOC_INOUT:
+ str = "IORW";
+ break;
+ default:
+ str = "IO??";
+ }
+ log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n",
+ ifp->if_name, ifp->if_unit,
+ str,
+ IOCGROUP(command),
+ command & 0xff,
+ IOCPARM_LEN(command));
+}
+#endif /* DEBUG */
+
+/************************************************************************
+ NETGRAPH NODE STUFF
+ ************************************************************************/
+
+/*
+ * Constructor for a node
+ */
+static int
+ng_iface_constructor(node_p *nodep)
+{
+ char ifname[NG_IFACE_IFACE_NAME_MAX + 1];
+ struct ifnet *ifp;
+ node_p node;
+ priv_p priv;
+ int error = 0;
+
+ /* Allocate node and interface private structures */
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
+ if (priv == NULL)
+ return (ENOMEM);
+ bzero(priv, sizeof(*priv));
+ MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_WAITOK);
+ if (ifp == NULL) {
+ FREE(priv, M_NETGRAPH);
+ return (ENOMEM);
+ }
+ bzero(ifp, sizeof(*ifp));
+
+ /* Link them together */
+ ifp->if_softc = priv;
+ priv->ifp = ifp;
+
+ /* Call generic node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(priv, M_NETGRAPH);
+ FREE(ifp, M_NETGRAPH);
+ return (error);
+ }
+ node = *nodep;
+
+ /* Link together node and private info */
+ node->private = priv;
+ priv->node = node;
+
+ /* Initialize interface structure */
+ ifp->if_name = ng_iface_ifname;
+ ifp->if_unit = ng_iface_next_unit++;
+ ifp->if_output = ng_iface_output;
+ ifp->if_start = ng_iface_start;
+ ifp->if_ioctl = ng_iface_ioctl;
+ ifp->if_watchdog = NULL;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
+ ifp->if_flags = (IFF_SIMPLEX | IFF_POINTOPOINT | IFF_NOARP);
+ ifp->if_type = IFT_PROPVIRTUAL; /* XXX */
+ ifp->if_addrlen = 0; /* XXX */
+ ifp->if_hdrlen = 0; /* XXX */
+ ifp->if_baudrate = 64000; /* XXX */
+ TAILQ_INIT(&ifp->if_addrhead);
+
+ /* Give this node the same name as the interface (if possible) */
+ bzero(ifname, sizeof(ifname));
+ sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
+ (void) ng_name_node(node, ifname);
+
+ /* Attach the interface */
+ if_attach(ifp);
+#if NBPFILTER > 0
+ bpfattach(ifp, DLT_NULL, sizeof(u_int));
+#endif
+
+ /* Done */
+ return (0);
+}
+
+/*
+ * Give our ok for a hook to be added
+ */
+static int
+ng_iface_newhook(node_p node, hook_p hook, const char *name)
+{
+ const iffam_p iffam = get_iffam_from_name(name);
+ hook_p *hookptr;
+
+ if (iffam == NULL)
+ return (EPFNOSUPPORT);
+ hookptr = get_hook_from_iffam((priv_p) node->private, iffam);
+ if (*hookptr != NULL)
+ return (EISCONN);
+ *hookptr = hook;
+ return (0);
+}
+
+/*
+ * Receive a control message
+ */
+static int
+ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **rptr)
+{
+ const priv_p priv = node->private;
+ struct ifnet *const ifp = priv->ifp;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ switch (msg->header.typecookie) {
+ case NGM_IFACE_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_IFACE_GET_IFNAME:
+ {
+ struct ng_iface_ifname *arg;
+
+ NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ arg = (struct ng_iface_ifname *) resp->data;
+ sprintf(arg->ngif_name,
+ "%s%d", ifp->if_name, ifp->if_unit);
+ break;
+ }
+
+ case NGM_IFACE_GET_IFADDRS:
+ {
+ struct ifaddr *ifa;
+ caddr_t ptr;
+ int buflen;
+
+#define SA_SIZE(s) ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len)
+
+ /* Determine size of response and allocate it */
+ buflen = 0;
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
+ buflen += SA_SIZE(ifa->ifa_addr);
+ NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+
+ /* Add addresses */
+ ptr = resp->data;
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ const int len = SA_SIZE(ifa->ifa_addr);
+
+ if (buflen < len) {
+ log(LOG_ERR, "%s%d: len changed?\n",
+ ifp->if_name, ifp->if_unit);
+ break;
+ }
+ bcopy(ifa->ifa_addr, ptr, len);
+ ptr += len;
+ buflen -= len;
+ }
+ break;
+#undef SA_SIZE
+ }
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case NGM_CISCO_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_CISCO_GET_IPADDR: /* we understand this too */
+ {
+ struct ifaddr *ifa;
+
+ /* Return the first configured IP address */
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ struct in_addr *ips;
+
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ NG_MKRESPONSE(resp, msg,
+ 2 * sizeof(*ips), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ ips = (struct in_addr *) resp->data;
+ ips[0] = ((struct sockaddr_in *)
+ ifa->ifa_addr)->sin_addr;
+ ips[1] = ((struct sockaddr_in *)
+ ifa->ifa_netmask)->sin_addr;
+ break;
+ }
+
+ /* No IP addresses on this interface? */
+ if (ifa == NULL)
+ error = EADDRNOTAVAIL;
+ break;
+ }
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Recive data from a hook. Pass the packet to the correct input routine.
+ */
+static int
+ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const priv_p priv = hook->node->private;
+ const iffam_p iffam = get_iffam_from_hook(priv, hook);
+ struct ifnet *const ifp = priv->ifp;
+ int s, error = 0;
+
+ /* Sanity checks */
+#ifdef DIAGNOSTIC
+ if (iffam == NULL)
+ panic(__FUNCTION__);
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic(__FUNCTION__);
+#endif
+ if (m == NULL)
+ return (EINVAL);
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ NG_FREE_DATA(m, meta);
+ return (ENETDOWN);
+ }
+
+ /* Update interface stats */
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+
+ /* Note receiving interface */
+ m->m_pkthdr.rcvif = ifp;
+
+#if NBPFILTER > 0
+ /* Berkeley packet filter */
+ ng_iface_bpftap(ifp, m, iffam->af);
+#endif
+
+ /* Ignore any meta-data */
+ NG_FREE_META(meta);
+
+ /* Send packet, either by NETISR or use a direct input function */
+ switch (iffam->netisr) {
+ case NETISR_NONE:
+ (*iffam->u.input)(m);
+ break;
+ default:
+ s = splimp();
+ schednetisr(iffam->netisr);
+ if (IF_QFULL(iffam->u.inq)) {
+ IF_DROP(iffam->u.inq);
+ m_freem(m);
+ error = ENOBUFS;
+ } else
+ IF_ENQUEUE(iffam->u.inq, m);
+ splx(s);
+ break;
+ }
+
+ /* Done */
+ return (error);
+}
+
+/*
+ * Because the BSD networking code doesn't support the removal of
+ * networking interfaces, iface nodes (once created) are persistent.
+ * So this method breaks all connections and marks the interface
+ * down, but does not remove the node.
+ */
+static int
+ng_iface_rmnode(node_p node)
+{
+ const priv_p priv = node->private;
+ struct ifnet *const ifp = priv->ifp;
+
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID;
+ ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_OACTIVE);
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ng_iface_disconnect(hook_p hook)
+{
+ const priv_p priv = hook->node->private;
+ const iffam_p iffam = get_iffam_from_hook(priv, hook);
+
+ if (iffam == NULL)
+ panic(__FUNCTION__);
+ *get_hook_from_iffam(priv, iffam) = NULL;
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_iface.h b/sys/netgraph/ng_iface.h
new file mode 100644
index 0000000..946f06e
--- /dev/null
+++ b/sys/netgraph/ng_iface.h
@@ -0,0 +1,75 @@
+
+/*
+ * ng_iface.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_iface.h,v 1.5 1999/01/20 00:22:13 archie Exp $
+ */
+
+#ifndef _NETGRAPH_IFACE_H_
+#define _NETGRAPH_IFACE_H_
+
+/* Node type name and magic cookie */
+#define NG_IFACE_NODE_TYPE "iface"
+#define NGM_IFACE_COOKIE 858821772
+
+/* Interface base name */
+#define NG_IFACE_IFACE_NAME "ng"
+#define NG_IFACE_IFACE_NAME_MAX 15
+
+/* My hook names */
+#define NG_IFACE_HOOK_INET "inet"
+#define NG_IFACE_HOOK_ATALK "atalk" /* AppleTalk phase 2 */
+#define NG_IFACE_HOOK_IPX "ipx"
+#define NG_IFACE_HOOK_NS "ns"
+
+/* MTU bounds */
+#define NG_IFACE_MTU_MIN 72
+#define NG_IFACE_MTU_MAX 65535
+#define NG_IFACE_MTU_DEFAULT 1500
+
+/* Netgraph commands */
+enum {
+ NGM_IFACE_GET_IFNAME = 1, /* returns struct ng_iface_ifname */
+ NGM_IFACE_GET_IFADDRS, /* returns list of addresses */
+};
+
+struct ng_iface_ifname {
+ char ngif_name[NG_IFACE_IFACE_NAME_MAX + 1];
+};
+
+#endif /* _NETGRAPH_IFACE_H_ */
diff --git a/sys/netgraph/ng_lmi.c b/sys/netgraph/ng_lmi.c
new file mode 100644
index 0000000..a404998
--- /dev/null
+++ b/sys/netgraph/ng_lmi.c
@@ -0,0 +1,1090 @@
+
+/*
+ * ng_lmi.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_lmi.c,v 1.35 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * This node performs the frame relay LMI protocol. It knows how
+ * to do ITU Annex A, ANSI Annex D, and "Group-of-Four" variants
+ * of the protocol.
+ *
+ * A specific protocol can be forced by connecting the corresponding
+ * hook to DLCI 0 or 1023 (as appropriate) of a frame relay link.
+ *
+ * Alternately, this node can do auto-detection of the LMI protocol
+ * by connecting hook "auto0" to DLCI 0 and "auto1023" to DLCI 1023.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_lmi.h>
+
+/*
+ * Human readable names for LMI
+ */
+#define NAME_ANNEXA NG_LMI_HOOK_ANNEXA
+#define NAME_ANNEXD NG_LMI_HOOK_ANNEXD
+#define NAME_GROUP4 NG_LMI_HOOK_GROUPOF4
+#define NAME_NONE "None"
+
+#define MAX_DLCIS 128
+#define MAXDLCI 1023
+
+/*
+ * DLCI states
+ */
+#define DLCI_NULL 0
+#define DLCI_UP 1
+#define DLCI_DOWN 2
+
+/*
+ * Any received LMI frame should be at least this long
+ */
+#define LMI_MIN_LENGTH 8 /* XXX verify */
+
+/*
+ * Netgraph node methods and type descriptor
+ */
+static int nglmi_constructor(node_p *node);
+static int nglmi_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int nglmi_rmnode(node_p node);
+static int nglmi_newhook(node_p node, hook_p hook, const char *name);
+static int nglmi_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int nglmi_disconnect(hook_p hook); /* notify on disconnect */
+static int nglmi_checkdata(hook_p hook, struct mbuf *m, meta_p meta);
+
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_LMI_NODE_TYPE,
+ NULL,
+ nglmi_constructor,
+ nglmi_rcvmsg,
+ nglmi_rmnode,
+ nglmi_newhook,
+ NULL,
+ NULL,
+ nglmi_rcvdata,
+ nglmi_rcvdata,
+ nglmi_disconnect
+};
+NETGRAPH_INIT(lmi, &typestruct);
+
+/*
+ * Info and status per node
+ */
+struct nglmi_softc {
+ node_p node; /* netgraph node */
+ int flags; /* state */
+ int poll_count; /* the count of times for autolmi */
+ int poll_state; /* state of auto detect machine */
+ u_char remote_seq; /* sequence number the remote sent */
+ u_char local_seq; /* last sequence number we sent */
+ u_char protoID; /* 9 for group of 4, 8 otherwise */
+ u_long seq_retries; /* sent this how many time so far */
+ struct callout_handle handle; /* see timeout(9) */
+ int liv_per_full;
+ int liv_rate;
+ int livs;
+ int need_full;
+ hook_p lmi_channel; /* whatever we ended up using */
+ hook_p lmi_annexA;
+ hook_p lmi_annexD;
+ hook_p lmi_group4;
+ hook_p lmi_channel0; /* auto-detect on DLCI 0 */
+ hook_p lmi_channel1023;/* auto-detect on DLCI 1023 */
+ char *protoname; /* cache protocol name */
+ u_char dlci_state[MAXDLCI + 1];
+ int invalidx; /* next dlci's to invalidate */
+};
+typedef struct nglmi_softc *sc_p;
+
+/*
+ * Other internal functions
+ */
+static void LMI_ticker(void *arg);
+static void nglmi_startup_fixed(sc_p sc, hook_p hook);
+static void nglmi_startup_auto(sc_p sc);
+static void nglmi_startup(sc_p sc);
+static void nglmi_inquire(sc_p sc, int full);
+static void ngauto_state_machine(sc_p sc);
+
+/*
+ * Values for 'flags' field
+ * NB: the SCF_CONNECTED flag is set if and only if the timer is running.
+ */
+#define SCF_CONNECTED 0x01 /* connected to something */
+#define SCF_AUTO 0x02 /* we are auto-detecting */
+#define SCF_FIXED 0x04 /* we are fixed from the start */
+
+#define SCF_LMITYPE 0x18 /* mask for determining Annex mode */
+#define SCF_NOLMI 0x00 /* no LMI type selected yet */
+#define SCF_ANNEX_A 0x08 /* running annex A mode */
+#define SCF_ANNEX_D 0x10 /* running annex D mode */
+#define SCF_GROUP4 0x18 /* running group of 4 */
+
+#define SETLMITYPE(sc, annex) \
+do { \
+ (sc)->flags &= ~SCF_LMITYPE; \
+ (sc)->flags |= (annex); \
+} while (0)
+
+#define NOPROTO(sc) (((sc)->flags & SCF_LMITYPE) == SCF_NOLMI)
+#define ANNEXA(sc) (((sc)->flags & SCF_LMITYPE) == SCF_ANNEX_A)
+#define ANNEXD(sc) (((sc)->flags & SCF_LMITYPE) == SCF_ANNEX_D)
+#define GROUP4(sc) (((sc)->flags & SCF_LMITYPE) == SCF_GROUP4)
+
+#define LMIPOLLSIZE 3
+#define LMI_PATIENCE 8 /* declare all DLCI DOWN after N LMI failures */
+
+/*
+ * Node constructor
+ */
+static int
+nglmi_constructor(node_p *nodep)
+{
+ sc_p sc;
+ int error = 0;
+
+ MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
+ if (sc == NULL)
+ return (ENOMEM);
+ bzero(sc, sizeof(*sc));
+
+ callout_handle_init(&sc->handle);
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(sc, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = sc;
+ sc->protoname = NAME_NONE;
+ sc->node = *nodep;
+ sc->liv_per_full = NG_LMI_SEQ_PER_FULL; /* make this dynamic */
+ sc->liv_rate = NG_LMI_KEEPALIVE_RATE;
+ return (0);
+}
+
+/*
+ * The LMI channel has a private pointer which is the same as the
+ * node private pointer. The debug channel has a NULL private pointer.
+ */
+static int
+nglmi_newhook(node_p node, hook_p hook, const char *name)
+{
+ sc_p sc = node->private;
+
+ if (strcmp(name, NG_LMI_HOOK_DEBUG) == 0) {
+ hook->private = NULL;
+ return (0);
+ }
+ if (sc->flags & SCF_CONNECTED) {
+ /* already connected, return an error */
+ return (EINVAL);
+ }
+ if (strcmp(name, NG_LMI_HOOK_ANNEXA) == 0) {
+ sc->lmi_annexA = hook;
+ hook->private = node->private;
+ sc->protoID = 8;
+ SETLMITYPE(sc, SCF_ANNEX_A);
+ sc->protoname = NAME_ANNEXA;
+ nglmi_startup_fixed(sc, hook);
+ } else if (strcmp(name, NG_LMI_HOOK_ANNEXD) == 0) {
+ sc->lmi_annexD = hook;
+ hook->private = node->private;
+ sc->protoID = 8;
+ SETLMITYPE(sc, SCF_ANNEX_D);
+ sc->protoname = NAME_ANNEXD;
+ nglmi_startup_fixed(sc, hook);
+ } else if (strcmp(name, NG_LMI_HOOK_GROUPOF4) == 0) {
+ sc->lmi_group4 = hook;
+ hook->private = node->private;
+ sc->protoID = 9;
+ SETLMITYPE(sc, SCF_GROUP4);
+ sc->protoname = NAME_GROUP4;
+ nglmi_startup_fixed(sc, hook);
+ } else if (strcmp(name, NG_LMI_HOOK_AUTO0) == 0) {
+ /* Note this, and if B is already installed, we're complete */
+ sc->lmi_channel0 = hook;
+ sc->protoname = NAME_NONE;
+ hook->private = node->private;
+ if (sc->lmi_channel1023)
+ nglmi_startup_auto(sc);
+ } else if (strcmp(name, NG_LMI_HOOK_AUTO1023) == 0) {
+ /* Note this, and if A is already installed, we're complete */
+ sc->lmi_channel1023 = hook;
+ sc->protoname = NAME_NONE;
+ hook->private = node->private;
+ if (sc->lmi_channel0)
+ nglmi_startup_auto(sc);
+ } else
+ return (EINVAL); /* unknown hook */
+ return (0);
+}
+
+/*
+ * We have just attached to a live (we hope) node.
+ * Fire out a LMI inquiry, and then start up the timers.
+ */
+static void
+LMI_ticker(void *arg)
+{
+ sc_p sc = arg;
+ int s = splnet();
+
+ if (sc->flags & SCF_AUTO) {
+ ngauto_state_machine(sc);
+ sc->handle = timeout(LMI_ticker, sc, NG_LMI_POLL_RATE * hz);
+ } else {
+ if (sc->livs++ >= sc->liv_per_full) {
+ nglmi_inquire(sc, 1);
+ /* sc->livs = 0; *//* do this when we get the answer! */
+ } else {
+ nglmi_inquire(sc, 0);
+ }
+ sc->handle = timeout(LMI_ticker, sc, sc->liv_rate * hz);
+ }
+ splx(s);
+}
+
+static void
+nglmi_startup_fixed(sc_p sc, hook_p hook)
+{
+ sc->flags |= (SCF_FIXED | SCF_CONNECTED);
+ sc->lmi_channel = hook;
+ nglmi_startup(sc);
+}
+
+static void
+nglmi_startup_auto(sc_p sc)
+{
+ sc->flags |= (SCF_AUTO | SCF_CONNECTED);
+ sc->poll_state = 0; /* reset state machine */
+ sc->poll_count = 0;
+ nglmi_startup(sc);
+}
+
+static void
+nglmi_startup(sc_p sc)
+{
+ sc->remote_seq = 0;
+ sc->local_seq = 1;
+ sc->seq_retries = 0;
+ sc->livs = sc->liv_per_full - 1;
+ /* start off the ticker in 1 sec */
+ sc->handle = timeout(LMI_ticker, sc, hz);
+}
+
+#define META_PAD 16
+static void
+nglmi_inquire(sc_p sc, int full)
+{
+ struct mbuf *m;
+ char *cptr, *start;
+ int error;
+ meta_p meta = NULL;
+
+ if (sc->lmi_channel == NULL)
+ return;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ log(LOG_ERR, "nglmi: unable to start up LMI processing\n");
+ return;
+ }
+ /* Allocate a meta struct (and leave some slop for options to be
+ * added by other modules). */
+ /* MALLOC(meta, meta_p, sizeof( struct ng_meta) + META_PAD,
+ * M_NETGRAPH, M_NOWAIT); */
+ MALLOC(meta, meta_p, sizeof(*meta) + META_PAD, M_NETGRAPH, M_NOWAIT);
+ if (meta != NULL) { /* if it failed, well, it was optional anyhow */
+ meta->used_len = (u_short) sizeof(struct ng_meta);
+ meta->allocated_len
+ = (u_short) sizeof(struct ng_meta) + META_PAD;
+ meta->flags = 0;
+ meta->priority = NG_LMI_LMI_PRIORITY;
+ meta->discardability = -1;
+ }
+ m->m_data += 4; /* leave some room for a header */
+ cptr = start = mtod(m, char *);
+ /* add in the header for an LMI inquiry. */
+ *cptr++ = 0x03; /* UI frame */
+ if (GROUP4(sc))
+ *cptr++ = 0x09; /* proto discriminator */
+ else
+ *cptr++ = 0x08; /* proto discriminator */
+ *cptr++ = 0x00; /* call reference */
+ *cptr++ = 0x75; /* inquiry */
+
+ /* If we are Annex-D, there is this extra thing.. */
+ if (ANNEXD(sc))
+ *cptr++ = 0x95; /* ??? */
+ /* Add a request type */
+ if (ANNEXA(sc))
+ *cptr++ = 0x51; /* report type */
+ else
+ *cptr++ = 0x01; /* report type */
+ *cptr++ = 0x01; /* size = 1 */
+ if (full)
+ *cptr++ = 0x00; /* full */
+ else
+ *cptr++ = 0x01; /* partial */
+
+ /* Add a link verification IE */
+ if (ANNEXA(sc))
+ *cptr++ = 0x53; /* verification IE */
+ else
+ *cptr++ = 0x03; /* verification IE */
+ *cptr++ = 0x02; /* 2 extra bytes */
+ *cptr++ = sc->local_seq;
+ *cptr++ = sc->remote_seq;
+ sc->seq_retries++;
+
+ /* Send it */
+ m->m_len = m->m_pkthdr.len = cptr - start;
+ NG_SEND_DATA(error, sc->lmi_channel, m, meta);
+
+ /* If we've been sending requests for long enough, and there has
+ * been no response, then mark as DOWN, any DLCIs that are UP. */
+ if (sc->seq_retries == LMI_PATIENCE) {
+ int count;
+
+ for (count = 0; count < MAXDLCI; count++)
+ if (sc->dlci_state[count] == DLCI_UP)
+ sc->dlci_state[count] = DLCI_DOWN;
+ }
+}
+
+/*
+ * State machine for LMI auto-detect. The transitions are ordered
+ * to try the more likely possibilities first.
+ */
+static void
+ngauto_state_machine(sc_p sc)
+{
+ if ((sc->poll_count <= 0) || (sc->poll_count > LMIPOLLSIZE)) {
+ /* time to change states in the auto probe machine */
+ /* capture wild values of poll_count while we are at it */
+ sc->poll_count = LMIPOLLSIZE;
+ sc->poll_state++;
+ }
+ switch (sc->poll_state) {
+ case 7:
+ log(LOG_WARNING, "nglmi: no response from exchange\n");
+ default: /* capture bad states */
+ sc->poll_state = 1;
+ case 1:
+ sc->lmi_channel = sc->lmi_channel0;
+ SETLMITYPE(sc, SCF_ANNEX_D);
+ break;
+ case 2:
+ sc->lmi_channel = sc->lmi_channel1023;
+ SETLMITYPE(sc, SCF_ANNEX_D);
+ break;
+ case 3:
+ sc->lmi_channel = sc->lmi_channel0;
+ SETLMITYPE(sc, SCF_ANNEX_A);
+ break;
+ case 4:
+ sc->lmi_channel = sc->lmi_channel1023;
+ SETLMITYPE(sc, SCF_GROUP4);
+ break;
+ case 5:
+ sc->lmi_channel = sc->lmi_channel1023;
+ SETLMITYPE(sc, SCF_ANNEX_A);
+ break;
+ case 6:
+ sc->lmi_channel = sc->lmi_channel0;
+ SETLMITYPE(sc, SCF_GROUP4);
+ break;
+ }
+
+ /* send an inquirey encoded appropriatly */
+ nglmi_inquire(sc, 0);
+ sc->poll_count--;
+}
+
+/*
+ * Receive a netgraph control message.
+ */
+static int
+nglmi_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **resp)
+{
+ int error = 0;
+ sc_p sc = node->private;
+
+ switch (msg->header.typecookie) {
+ case NGM_GENERIC_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_TEXT_STATUS:
+ {
+ char *arg;
+ int pos, count;
+
+ NG_MKRESPONSE(*resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
+ if (*resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ arg = (*resp)->data;
+ pos = sprintf(arg, "protocol %s ", sc->protoname);
+ if (sc->flags & SCF_FIXED)
+ pos += sprintf(arg + pos, "fixed\n");
+ else if (sc->flags & SCF_AUTO)
+ pos += sprintf(arg + pos, "auto-detecting\n");
+ else
+ pos += sprintf(arg + pos, "auto on dlci %d\n",
+ (sc->lmi_channel == sc->lmi_channel0) ?
+ 0 : 1023);
+ pos += sprintf(arg + pos,
+ "keepalive period: %d seconds\n", sc->liv_rate);
+ pos += sprintf(arg + pos,
+ "unacknowledged keepalives: %ld\n",
+ sc->seq_retries);
+ for (count = 0;
+ ((count <= MAXDLCI)
+ && (pos < (NG_TEXTRESPONSE - 20)));
+ count++) {
+ if (sc->dlci_state[count]) {
+ pos += sprintf(arg + pos,
+ "dlci %d %s\n", count,
+ (sc->dlci_state[count]
+ == DLCI_UP) ? "up" : "down");
+ }
+ }
+ (*resp)->header.arglen = pos + 1;
+ break;
+ }
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case NGM_LMI_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_LMI_GET_STATUS:
+ {
+ struct nglmistat *stat;
+ int k;
+
+ NG_MKRESPONSE(*resp, msg, sizeof(*stat), M_NOWAIT);
+ if (!*resp) {
+ error = ENOMEM;
+ break;
+ }
+ stat = (struct nglmistat *) (*resp)->data;
+ strncpy(stat->proto,
+ sc->protoname, sizeof(stat->proto) - 1);
+ strncpy(stat->hook,
+ sc->protoname, sizeof(stat->hook) - 1);
+ stat->autod = !!(sc->flags & SCF_AUTO);
+ stat->fixed = !!(sc->flags & SCF_FIXED);
+ for (k = 0; k <= MAXDLCI; k++) {
+ switch (sc->dlci_state[k]) {
+ case DLCI_UP:
+ stat->up[k / 8] |= (1 << (k % 8));
+ /* fall through */
+ case DLCI_DOWN:
+ stat->seen[k / 8] |= (1 << (k % 8));
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+#define STEPBY(stepsize) \
+ do { \
+ packetlen -= (stepsize); \
+ data += (stepsize); \
+ } while (0)
+
+/*
+ * receive data, and use it to update our status.
+ * Anything coming in on the debug port is discarded.
+ */
+static int
+nglmi_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ sc_p sc = hook->node->private;
+ u_char *data;
+ unsigned short dlci;
+ u_short packetlen;
+ int resptype_seen = 0;
+ int seq_seen = 0;
+
+ if (hook->private == NULL) {
+ goto drop;
+ }
+ packetlen = m->m_hdr.mh_len;
+
+ /* XXX what if it's more than 1 mbuf? */
+ if ((packetlen > MHLEN) && !(m->m_flags & M_EXT)) {
+ log(LOG_WARNING, "nglmi: packetlen (%d) too big\n", packetlen);
+ goto drop;
+ }
+ if ((m = m_pullup(m, packetlen)) == NULL) {
+ log(LOG_WARNING, "nglmi: m_pullup failed for %d bytes\n", packetlen);
+ NG_FREE_META(meta);
+ return (0);
+ }
+ if (nglmi_checkdata(hook, m, meta) == 0)
+ return (0);
+
+ /* pass the first 4 bytes (already checked in the nglmi_checkdata()) */
+ data = mtod(m, u_char *);
+ STEPBY(4);
+
+ /* Now check if there is a 'locking shift'. This is only seen in
+ * Annex D frames. don't bother checking, we already did that. Don't
+ * increment immediatly as it might not be there. */
+ if (ANNEXD(sc))
+ STEPBY(1);
+
+ /* If we get this far we should consider that it is a legitimate
+ * frame and we know what it is. */
+ if (sc->flags & SCF_AUTO) {
+ /* note the hook that this valid channel came from and drop
+ * out of auto probe mode. */
+ if (ANNEXA(sc))
+ sc->protoname = NAME_ANNEXA;
+ else if (ANNEXD(sc))
+ sc->protoname = NAME_ANNEXD;
+ else if (GROUP4(sc))
+ sc->protoname = NAME_GROUP4;
+ else {
+ log(LOG_ERR, "nglmi: No known type\n");
+ goto drop;
+ }
+ sc->lmi_channel = hook;
+ sc->flags &= ~SCF_AUTO;
+ log(LOG_INFO, "nglmi: auto-detected %s LMI on DLCI %d\n",
+ sc->protoname, hook == sc->lmi_channel0 ? 0 : 1023);
+ }
+
+ /* While there is more data in the status packet, keep processing
+ * status items. First make sure there is enough data for the
+ * segment descriptor's length field. */
+ while (packetlen >= 2) {
+ u_int segtype = data[0];
+ u_int segsize = data[1];
+
+ /* Now that we know how long it claims to be, make sure
+ * there is enough data for the next seg. */
+ if (packetlen < segsize + 2)
+ break;
+ switch (segtype) {
+ case 0x01:
+ case 0x51:
+ if (resptype_seen) {
+ log(LOG_WARNING, "nglmi: dup MSGTYPE\n");
+ goto nextIE;
+ }
+ resptype_seen++;
+ /* The remote end tells us what kind of response
+ * this is. Only expect a type 0 or 1. if we are a
+ * full status, invalidate a few DLCIs just to see
+ * that they are still ok. */
+ if (segsize != 1)
+ goto nextIE;
+ switch (data[2]) {
+ case 1:
+ /* partial status, do no extra processing */
+ break;
+ case 0:
+ {
+ int count = 0;
+ int idx = sc->invalidx;
+
+ for (count = 0; count < 10; count++) {
+ if (idx > MAXDLCI)
+ idx = 0;
+ if (sc->dlci_state[idx] == DLCI_UP)
+ sc->dlci_state[idx] = DLCI_DOWN;
+ idx++;
+ }
+ sc->invalidx = idx;
+ /* we got and we wanted one. relax
+ * now.. but don't reset to 0 if it
+ * was unrequested. */
+ if (sc->livs > sc->liv_per_full)
+ sc->livs = 0;
+ break;
+ }
+ }
+ break;
+ case 0x03:
+ case 0x53:
+ /* The remote tells us what it thinks the sequence
+ * numbers are. If it's not size 2, it must be a
+ * duplicate to have gotten this far, skip it. */
+ if (seq_seen != 0) /* already seen seq numbers */
+ goto nextIE;
+ if (segsize != 2)
+ goto nextIE;
+ sc->remote_seq = data[2];
+ if (sc->local_seq == data[3]) {
+ sc->local_seq++;
+ sc->seq_retries = 0;
+ /* Note that all 3 Frame protocols seem to
+ * not like 0 as a sequence number. */
+ if (sc->local_seq == 0)
+ sc->local_seq = 1;
+ }
+ break;
+ case 0x07:
+ case 0x57:
+ /* The remote tells us about a DLCI that it knows
+ * about. There may be many of these in a single
+ * status response */
+ switch (segsize) {
+ case 6:/* only on 'group of 4' */
+ dlci = ((u_short) data[2] & 0xff) << 8;
+ dlci |= (data[3] & 0xff);
+ if ((dlci < 1024) && (dlci > 0)) {
+ /* XXX */
+ }
+ break;
+ case 3:
+ dlci = ((u_short) data[2] & 0x3f) << 4;
+ dlci |= ((data[3] & 0x78) >> 3);
+ if ((dlci < 1024) && (dlci > 0)) {
+ /* set up the bottom half of the
+ * support for that dlci if it's not
+ * already been done */
+ /* store this information somewhere */
+ }
+ break;
+ default:
+ goto nextIE;
+ }
+ if (sc->dlci_state[dlci] != DLCI_UP) {
+ /* bring new DLCI to life */
+ /* may do more here some day */
+ if (sc->dlci_state[dlci] != DLCI_DOWN)
+ log(LOG_INFO,
+ "nglmi: DLCI %d became active\n",
+ dlci);
+ sc->dlci_state[dlci] = DLCI_UP;
+ }
+ break;
+ }
+nextIE:
+ STEPBY(segsize + 2);
+ }
+ NG_FREE_DATA(m, meta);
+ return (0);
+
+drop:
+ NG_FREE_DATA(m, meta);
+ return (EINVAL);
+}
+
+/*
+ * Check that a packet is entirely kosha.
+ * return 1 of ok, and 0 if not.
+ * All data is discarded if a 0 is returned.
+ */
+static int
+nglmi_checkdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ sc_p sc = hook->node->private;
+ u_char *data;
+ u_short packetlen;
+ unsigned short dlci;
+ u_char type;
+ u_char nextbyte;
+ int seq_seen = 0;
+ int resptype_seen = 0; /* 0 , 1 (partial) or 2 (full) */
+ int highest_dlci = 0;
+
+ packetlen = m->m_hdr.mh_len;
+ data = mtod(m, u_char *);
+ if (*data != 0x03) {
+ log(LOG_WARNING, "nglmi: unexpected value in LMI(%d)\n", 1);
+ goto reject;
+ }
+ STEPBY(1);
+
+ /* look at the protocol ID */
+ nextbyte = *data;
+ if (sc->flags & SCF_AUTO) {
+ SETLMITYPE(sc, SCF_NOLMI); /* start with a clean slate */
+ switch (nextbyte) {
+ case 0x8:
+ sc->protoID = 8;
+ break;
+ case 0x9:
+ SETLMITYPE(sc, SCF_GROUP4);
+ sc->protoID = 9;
+ break;
+ default:
+ log(LOG_WARNING, "nglmi: bad Protocol ID(%d)\n",
+ (int) nextbyte);
+ goto reject;
+ }
+ } else {
+ if (nextbyte != sc->protoID) {
+ log(LOG_WARNING, "nglmi: unexpected Protocol ID(%d)\n",
+ (int) nextbyte);
+ goto reject;
+ }
+ }
+ STEPBY(1);
+
+ /* check call reference (always null in non ISDN frame relay) */
+ if (*data != 0x00) {
+ log(LOG_WARNING, "nglmi: unexpected Call Reference (0x%x)\n",
+ data[-1]);
+ goto reject;
+ }
+ STEPBY(1);
+
+ /* check message type */
+ switch ((type = *data)) {
+ case 0x75: /* Status enquiry */
+ log(LOG_WARNING, "nglmi: unexpected message type(0x%x)\n",
+ data[-1]);
+ goto reject;
+ case 0x7D: /* Status message */
+ break;
+ default:
+ log(LOG_WARNING,
+ "nglmi: unexpected msg type(0x%x) \n", (int) type);
+ goto reject;
+ }
+ STEPBY(1);
+
+ /* Now check if there is a 'locking shift'. This is only seen in
+ * Annex D frames. Don't increment immediately as it might not be
+ * there. */
+ nextbyte = *data;
+ if (sc->flags & SCF_AUTO) {
+ if (!(GROUP4(sc))) {
+ if (nextbyte == 0x95) {
+ SETLMITYPE(sc, SCF_ANNEX_D);
+ STEPBY(1);
+ } else
+ SETLMITYPE(sc, SCF_ANNEX_A);
+ } else if (nextbyte == 0x95) {
+ log(LOG_WARNING, "nglmi: locking shift seen in G4\n");
+ goto reject;
+ }
+ } else {
+ if (ANNEXD(sc)) {
+ if (*data == 0x95)
+ STEPBY(1);
+ else {
+ log(LOG_WARNING,
+ "nglmi: locking shift missing\n");
+ goto reject;
+ }
+ } else if (*data == 0x95) {
+ log(LOG_WARNING, "nglmi: locking shift seen\n");
+ goto reject;
+ }
+ }
+
+ /* While there is more data in the status packet, keep processing
+ * status items. First make sure there is enough data for the
+ * segment descriptor's length field. */
+ while (packetlen >= 2) {
+ u_int segtype = data[0];
+ u_int segsize = data[1];
+
+ /* Now that we know how long it claims to be, make sure
+ * there is enough data for the next seg. */
+ if (packetlen < (segsize + 2)) {
+ log(LOG_WARNING, "nglmi: IE longer than packet\n");
+ break;
+ }
+ switch (segtype) {
+ case 0x01:
+ case 0x51:
+ /* According to MCI's HP analyser, we should just
+ * ignore if there is mor ethan one of these (?). */
+ if (resptype_seen) {
+ log(LOG_WARNING, "nglmi: dup MSGTYPE\n");
+ goto nextIE;
+ }
+ if (segsize != 1) {
+ log(LOG_WARNING, "nglmi: MSGTYPE wrong size\n");
+ goto reject;
+ }
+ /* The remote end tells us what kind of response
+ * this is. Only expect a type 0 or 1. if it was a
+ * full (type 0) check we just asked for a type
+ * full. */
+ switch (data[2]) {
+ case 1:/* partial */
+ if (sc->livs > sc->liv_per_full) {
+ log(LOG_WARNING,
+ "nglmi: LIV when FULL expected\n");
+ goto reject; /* need full */
+ }
+ resptype_seen = 1;
+ break;
+ case 0:/* full */
+ /* Full response is always acceptable */
+ resptype_seen = 2;
+ break;
+ default:
+ log(LOG_WARNING,
+ "nglmi: Unknown report type %d\n", data[2]);
+ goto reject;
+ }
+ break;
+ case 0x03:
+ case 0x53:
+ /* The remote tells us what it thinks the sequence
+ * numbers are. I would have thought that there
+ * needs to be one and only one of these, but MCI
+ * want us to just ignore extras. (?) */
+ if (resptype_seen == 0) {
+ log(LOG_WARNING, "nglmi: no TYPE before SEQ\n");
+ goto reject;
+ }
+ if (seq_seen != 0) /* already seen seq numbers */
+ goto nextIE;
+ if (segsize != 2) {
+ log(LOG_WARNING, "nglmi: bad SEQ sts size\n");
+ goto reject;
+ }
+ if (sc->local_seq != data[3]) {
+ log(LOG_WARNING, "nglmi: unexpected SEQ\n");
+ goto reject;
+ }
+ seq_seen = 1;
+ break;
+ case 0x07:
+ case 0x57:
+ /* The remote tells us about a DLCI that it knows
+ * about. There may be many of these in a single
+ * status response */
+ if (seq_seen != 1) { /* already seen seq numbers? */
+ log(LOG_WARNING,
+ "nglmi: No sequence before DLCI\n");
+ goto reject;
+ }
+ if (resptype_seen != 2) { /* must be full */
+ log(LOG_WARNING,
+ "nglmi: No resp type before DLCI\n");
+ goto reject;
+ }
+ if (GROUP4(sc)) {
+ if (segsize != 6) {
+ log(LOG_WARNING,
+ "nglmi: wrong IE segsize\n");
+ goto reject;
+ }
+ dlci = ((u_short) data[2] & 0xff) << 8;
+ dlci |= (data[3] & 0xff);
+ } else {
+ if (segsize != 3) {
+ log(LOG_WARNING,
+ "nglmi: DLCI headersize of %d"
+ " not supported\n", segsize - 1);
+ goto reject;
+ }
+ dlci = ((u_short) data[2] & 0x3f) << 4;
+ dlci |= ((data[3] & 0x78) >> 3);
+ }
+ /* async can only have one of these */
+#if 0 /* async not yet accepted */
+ if (async && highest_dlci) {
+ log(LOG_WARNING,
+ "nglmi: Async with > 1 DLCI\n");
+ goto reject;
+ }
+#endif
+ /* Annex D says these will always be Ascending, but
+ * the HP test for G4 says we should accept
+ * duplicates, so for now allow that. ( <= vs. < ) */
+#if 0
+ /* MCI tests want us to accept out of order for AnxD */
+ if ((!GROUP4(sc)) && (dlci < highest_dlci)) {
+ /* duplicate or mis-ordered dlci */
+ /* (spec says they will increase in number) */
+ log(LOG_WARNING, "nglmi: DLCI out of order\n");
+ goto reject;
+ }
+#endif
+ if (dlci > 1023) {
+ log(LOG_WARNING, "nglmi: DLCI out of range\n");
+ goto reject;
+ }
+ highest_dlci = dlci;
+ break;
+ default:
+ log(LOG_WARNING,
+ "nglmi: unknown LMI segment type %d\n", segtype);
+ }
+nextIE:
+ STEPBY(segsize + 2);
+ }
+ if (packetlen != 0) { /* partial junk at end? */
+ log(LOG_WARNING,
+ "nglmi: %d bytes extra at end of packet\n", packetlen);
+ goto print;
+ }
+ if (resptype_seen == 0) {
+ log(LOG_WARNING, "nglmi: No response type seen\n");
+ goto reject; /* had no response type */
+ }
+ if (seq_seen == 0) {
+ log(LOG_WARNING, "nglmi: No sequence numbers seen\n");
+ goto reject; /* had no sequence numbers */
+ }
+ return (1);
+
+print:
+ {
+ int i, j, k, pos;
+ char buf[100];
+ int loc;
+ u_char *bp = mtod(m, u_char *);
+
+ k = i = 0;
+ loc = (m->m_hdr.mh_len - packetlen);
+ log(LOG_WARNING, "nglmi: error at location %d\n", loc);
+ while (k < m->m_hdr.mh_len) {
+ pos = 0;
+ j = 0;
+ while ((j++ < 16) && k < m->m_hdr.mh_len) {
+ pos += sprintf(buf + pos, "%c%02x",
+ ((loc == k) ? '>' : ' '),
+ bp[k]);
+ k++;
+ }
+ if (i == 0)
+ log(LOG_WARNING, "nglmi: packet data:%s\n", buf);
+ else
+ log(LOG_WARNING, "%04d :%s\n", k, buf);
+ i++;
+ }
+ }
+ return (1);
+reject:
+ {
+ int i, j, k, pos;
+ char buf[100];
+ int loc;
+ u_char *bp = mtod(m, u_char *);
+
+ k = i = 0;
+ loc = (m->m_hdr.mh_len - packetlen);
+ log(LOG_WARNING, "nglmi: error at location %d\n", loc);
+ while (k < m->m_hdr.mh_len) {
+ pos = 0;
+ j = 0;
+ while ((j++ < 16) && k < m->m_hdr.mh_len) {
+ pos += sprintf(buf + pos, "%c%02x",
+ ((loc == k) ? '>' : ' '),
+ bp[k]);
+ k++;
+ }
+ if (i == 0)
+ log(LOG_WARNING, "nglmi: packet data:%s\n", buf);
+ else
+ log(LOG_WARNING, "%04d :%s\n", k, buf);
+ i++;
+ }
+ }
+ NG_FREE_DATA(m, meta);
+ return (0);
+}
+
+/*
+ * Do local shutdown processing..
+ * Cut any remaining links and free our local resources.
+ */
+static int
+nglmi_rmnode(node_p node)
+{
+ const sc_p sc = node->private;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ node->private = NULL;
+ ng_unref(sc->node);
+ FREE(sc, M_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ * For this type, removal of any link except "debug" destroys the node.
+ */
+static int
+nglmi_disconnect(hook_p hook)
+{
+ const sc_p sc = hook->node->private;
+
+ /* OK to remove debug hook(s) */
+ if (hook->private == NULL)
+ return (0);
+
+ /* Stop timer if it's currently active */
+ if (sc->flags & SCF_CONNECTED)
+ untimeout(LMI_ticker, sc, sc->handle);
+
+ /* Self-destruct */
+ ng_rmnode(hook->node);
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_lmi.h b/sys/netgraph/ng_lmi.h
new file mode 100644
index 0000000..16f2b5b
--- /dev/null
+++ b/sys/netgraph/ng_lmi.h
@@ -0,0 +1,80 @@
+
+/*
+ * ng_lmi.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_lmi.h,v 1.9 1999/01/20 00:22:13 archie Exp $
+ */
+
+#ifndef _NETGRAPH_LMI_H_
+#define _NETGRAPH_LMI_H_
+
+/* Node type name and magic cookie */
+#define NG_LMI_NODE_TYPE "lmi"
+#define NGM_LMI_COOKIE 867184133
+
+/* My hook names */
+#define NG_LMI_HOOK_DEBUG "debug"
+#define NG_LMI_HOOK_ANNEXA "annexA"
+#define NG_LMI_HOOK_ANNEXD "annexD"
+#define NG_LMI_HOOK_GROUPOF4 "group4"
+#define NG_LMI_HOOK_AUTO0 "auto0"
+#define NG_LMI_HOOK_AUTO1023 "auto1023"
+
+/* Netgraph commands */
+enum {
+ NGM_LMI_GET_STATUS = 1,
+};
+
+#define NGM_LMI_STAT_ARYSIZE (1024/8)
+
+struct nglmistat {
+ u_char proto[12]; /* Active proto (same as hook name) */
+ u_char hook[12]; /* Active hook */
+ u_char fixed; /* Set to fixed LMI mode */
+ u_char autod; /* Currently auto-detecting */
+ u_char seen[NGM_LMI_STAT_ARYSIZE]; /* DLCIs ever seen */
+ u_char up[NGM_LMI_STAT_ARYSIZE]; /* DLCIs currently up */
+};
+
+/* Some default values */
+#define NG_LMI_KEEPALIVE_RATE 10 /* seconds per keepalive */
+#define NG_LMI_POLL_RATE 3 /* faster when AUTO polling */
+#define NG_LMI_SEQ_PER_FULL 5 /* keepalives per full status */
+#define NG_LMI_LMI_PRIORITY 64 /* priority for LMI data */
+
+#endif /* _NETGRAPH_LMI_H_ */
diff --git a/sys/netgraph/ng_message.h b/sys/netgraph/ng_message.h
new file mode 100644
index 0000000..8ff46b2
--- /dev/null
+++ b/sys/netgraph/ng_message.h
@@ -0,0 +1,209 @@
+
+/*
+ * ng_message.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_message.h,v 1.12 1999/01/25 01:17:44 archie Exp $
+ */
+
+#ifndef _NETGRAPH_NG_MESSAGE_H_
+#define _NETGRAPH_NG_MESSAGE_H_ 1
+
+/* ASCII string size limits */
+#define NG_TYPELEN 15 /* max type name len (16 with null) */
+#define NG_HOOKLEN 15 /* max hook name len (16 with null) */
+#define NG_NODELEN 15 /* max node name len (16 with null) */
+#define NG_PATHLEN 511 /* max path len (512 with null) */
+#define NG_CMDSTRLEN 15 /* max command string (16 with null) */
+#define NG_TEXTRESPONSE 1024 /* allow this length for a text response */
+
+/* A netgraph message */
+struct ng_mesg {
+ struct ng_msghdr {
+ u_char version; /* must == NG_VERSION */
+ u_char spare; /* pad to 2 bytes */
+ u_int16_t arglen; /* length of data */
+ u_int32_t flags; /* message status */
+ u_int32_t token; /* match with reply */
+ u_int32_t typecookie; /* node's type cookie */
+ u_int32_t cmd; /* command identifier */
+ u_char cmdstr[NG_CMDSTRLEN+1]; /* cmd string + \0 */
+ } header;
+ char data[0]; /* placeholder for actual data */
+};
+#define NG_VERSION 1
+#define NGF_ORIG 0x0000 /* the msg is the original request */
+#define NGF_RESP 0x0001 /* the message is a response */
+
+/*
+ * Here we describe the "generic" messages that all nodes inherently
+ * understand. With the exception of NGM_TEXT_STATUS, these are handled
+ * automatically by the base netgraph code.
+ */
+
+/* Generic message type cookie */
+#define NGM_GENERIC_COOKIE 851672668
+
+/* Generic messages defined for this type cookie */
+#define NGM_SHUTDOWN 0x0001 /* no args */
+#define NGM_MKPEER 0x0002
+#define NGM_CONNECT 0x0003
+#define NGM_NAME 0x0004
+#define NGM_RMHOOK 0x0005
+#define NGM_NODEINFO 0x0006 /* get nodeinfo for the target */
+#define NGM_LISTHOOKS 0x0007 /* get nodeinfo for the target + hook info */
+#define NGM_LISTNAMES 0x0008 /* list all globally named nodes */
+#define NGM_LISTNODES 0x0009 /* list all nodes, named and unnamed */
+#define NGM_LISTTYPES 0x000a /* list all installed node types */
+#define NGM_TEXT_STATUS 0x000b /* (optional) returns human readable status */
+
+/*
+ * Args sections for generic NG commands. All strings are NUL-terminated.
+ */
+struct ngm_mkpeer {
+ char type[NG_TYPELEN + 1]; /* peer type */
+ char ourhook[NG_HOOKLEN + 1]; /* hook name */
+ char peerhook[NG_HOOKLEN + 1]; /* peer hook name */
+};
+
+struct ngm_connect {
+ char path[NG_PATHLEN + 1]; /* peer path */
+ char ourhook[NG_HOOKLEN + 1]; /* hook name */
+ char peerhook[NG_HOOKLEN + 1]; /* peer hook name */
+};
+
+struct ngm_name {
+ char name[NG_NODELEN + 1]; /* node name */
+};
+
+struct ngm_rmhook {
+ char ourhook[NG_HOOKLEN + 1]; /* hook name */
+};
+
+/* Structures used in response to NGM_NODEINFO and NGM_LISTHOOKS */
+struct nodeinfo {
+ char name[NG_NODELEN + 1]; /* node name (if any) */
+ char type[NG_TYPELEN + 1]; /* peer type */
+ u_int32_t id; /* unique identifier */
+ u_int32_t hooks; /* number of active hooks */
+};
+
+struct linkinfo {
+ char ourhook[NG_HOOKLEN + 1]; /* hook name */
+ char peerhook[NG_HOOKLEN + 1]; /* peer hook */
+ struct nodeinfo nodeinfo;
+};
+
+struct hooklist {
+ struct nodeinfo nodeinfo; /* node information */
+ struct linkinfo link[0]; /* info about each hook */
+};
+
+/* Structure used for NGM_LISTNAMES/NGM_LISTNODES (not node specific) */
+struct namelist {
+ u_int32_t numnames;
+ struct nodeinfo nodeinfo[0];
+};
+
+/* Structures used for NGM_LISTTYPES (not node specific) */
+struct typeinfo {
+ char typename[NG_TYPELEN + 1]; /* name of type */
+ u_int32_t numnodes; /* number alive */
+};
+
+struct typelist {
+ u_int32_t numtypes;
+ struct typeinfo typeinfo[0];
+};
+
+/*
+ * For netgraph nodes that are somehow associated with file descriptors
+ * (e.g., a device that has a /dev entry and is also a netgraph node),
+ * we define a generic ioctl for requesting the corresponding nodeinfo
+ * structure and for assigning a name (if there isn't one already).
+ *
+ * For these to you need to also #include <sys/ioccom.h>.
+ */
+
+#define NGIOCGINFO _IOR('N', 40, struct nodeinfo) /* get node info */
+#define NGIOCSETNAME _IOW('N', 41, struct ngm_name) /* set node name */
+
+#ifdef KERNEL
+/*
+ * Allocate and initialize a netgraph message "msg" with "len"
+ * extra bytes of argument. Sets "msg" to NULL if fails.
+ * Does not initialize token.
+ */
+#define NG_MKMESSAGE(msg, cookie, cmdid, len, how) \
+ do { \
+ MALLOC((msg), struct ng_mesg *, sizeof(struct ng_mesg) \
+ + (len), M_NETGRAPH, (how)); \
+ if ((msg) == NULL) \
+ break; \
+ bzero((msg), sizeof(struct ng_mesg) + (len)); \
+ (msg)->header.version = NG_VERSION; \
+ (msg)->header.typecookie = (cookie); \
+ (msg)->header.cmd = (cmdid); \
+ (msg)->header.arglen = (len); \
+ strncpy((msg)->header.cmdstr, #cmdid, \
+ sizeof((msg)->header.cmdstr) - 1); \
+ } while (0)
+
+/*
+ * Allocate and initialize a response "rsp" to a message "msg"
+ * with "len" extra bytes of argument. Sets "rsp" to NULL if fails.
+ */
+#define NG_MKRESPONSE(rsp, msg, len, how) \
+ do { \
+ MALLOC((rsp), struct ng_mesg *, sizeof(struct ng_mesg) \
+ + (len), M_NETGRAPH, (how)); \
+ if ((rsp) == NULL) \
+ break; \
+ bzero((rsp), sizeof(struct ng_mesg) + (len)); \
+ (rsp)->header.version = NG_VERSION; \
+ (rsp)->header.arglen = (len); \
+ (rsp)->header.token = (msg)->header.token; \
+ (rsp)->header.typecookie = (msg)->header.typecookie; \
+ (rsp)->header.cmd = (msg)->header.cmd; \
+ bcopy((msg)->header.cmdstr, (rsp)->header.cmdstr, \
+ sizeof((rsp)->header.cmdstr)); \
+ (rsp)->header.flags |= NGF_RESP; \
+ } while (0)
+#endif /* KERNEL */
+
+#endif /* _NETGRAPH_NG_MESSAGE_H_ */
+
diff --git a/sys/netgraph/ng_ppp.c b/sys/netgraph/ng_ppp.c
new file mode 100644
index 0000000..3377a80
--- /dev/null
+++ b/sys/netgraph/ng_ppp.c
@@ -0,0 +1,406 @@
+
+/*
+ * ng_ppp.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_ppp.c,v 1.22 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * This node does PPP protocol multiplexing based on PPP protocol
+ * ID numbers. This node does not add address and control fields,
+ * as that is considered a ``device layer'' issue.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_ppp.h>
+
+/* Protocol stuff */
+#define PROT_DOWNLINK 0xffff
+#define PROT_BYPASS 0x0000
+
+#define PROT_VALID(p) (((p) & 0x0101) == 0x0001)
+#define PROT_COMPRESSIBLE(p) (((p) & 0xFF00) == 0x0000)
+
+/* Extract protocol from hook private pointer */
+#define HOOK_PROTO(hook) (*((u_int16_t *) &hook->private))
+
+/* Node private data */
+struct private {
+ struct ng_ppp_stat stats;
+ u_int protocomp:1;
+};
+typedef struct private *priv_p;
+
+/* Protocol aliases */
+struct protoalias {
+ char *name;
+ u_int16_t proto;
+};
+
+/* Netgraph node methods */
+static int ng_ppp_constructor(node_p *nodep);
+static int ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_ppp_rmnode(node_p node);
+static int ng_ppp_newhook(node_p node, hook_p hook, const char *name);
+static int ng_ppp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_ppp_disconnect(hook_p hook);
+
+/* Helper stuff */
+static int ng_ppp_decodehookname(const char *name);
+static hook_p ng_ppp_findhook(node_p node, int proto);
+
+/* Node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_PPP_NODE_TYPE,
+ NULL,
+ ng_ppp_constructor,
+ ng_ppp_rcvmsg,
+ ng_ppp_rmnode,
+ ng_ppp_newhook,
+ NULL,
+ NULL,
+ ng_ppp_rcvdata,
+ ng_ppp_rcvdata,
+ ng_ppp_disconnect
+};
+NETGRAPH_INIT(ppp, &typestruct);
+
+/* Protocol aliases */
+static const struct protoalias gAliases[] =
+{
+ { NG_PPP_HOOK_DOWNLINK, PROT_DOWNLINK },
+ { NG_PPP_HOOK_BYPASS, PROT_BYPASS },
+ { NG_PPP_HOOK_LCP, 0xc021 },
+ { NG_PPP_HOOK_IPCP, 0x8021 },
+ { NG_PPP_HOOK_ATCP, 0x8029 },
+ { NG_PPP_HOOK_CCP, 0x80fd },
+ { NG_PPP_HOOK_ECP, 0x8053 },
+ { NG_PPP_HOOK_IP, 0x0021 },
+ { NG_PPP_HOOK_VJCOMP, 0x002d },
+ { NG_PPP_HOOK_VJUNCOMP, 0x002f },
+ { NG_PPP_HOOK_MP, 0x003d },
+ { NG_PPP_HOOK_COMPD, 0x00fd },
+ { NG_PPP_HOOK_CRYPTD, 0x0053 },
+ { NG_PPP_HOOK_PAP, 0xc023 },
+ { NG_PPP_HOOK_CHAP, 0xc223 },
+ { NG_PPP_HOOK_LQR, 0xc025 },
+ { NULL, 0 }
+};
+
+#define ERROUT(x) do { error = (x); goto done; } while (0)
+
+/************************************************************************
+ NETGRAPH NODE STUFF
+ ************************************************************************/
+
+/*
+ * Node constructor
+ */
+static int
+ng_ppp_constructor(node_p *nodep)
+{
+ priv_p priv;
+ int error;
+
+ /* Allocate private structure */
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
+ if (priv == NULL)
+ return (ENOMEM);
+ bzero(priv, sizeof(*priv));
+
+ /* Call generic node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(priv, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = priv;
+
+ /* Done */
+ return (0);
+}
+
+/*
+ * Give our OK for a hook to be added
+ */
+static int
+ng_ppp_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p priv = node->private;
+ int proto;
+
+ /* Decode protocol number */
+ if ((proto = ng_ppp_decodehookname(name)) < 0)
+ return (EINVAL);
+
+ /* See if already connected */
+ if (ng_ppp_findhook(node, proto) != NULL)
+ return (EISCONN);
+
+ /* Clear stats when downstream hook reconnected */
+ if (proto == PROT_DOWNLINK)
+ bzero(&priv->stats, sizeof(priv->stats));
+
+ /* OK */
+ HOOK_PROTO(hook) = proto;
+ return (0);
+}
+
+/*
+ * Receive a control message
+ */
+static int
+ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *raddr, struct ng_mesg **rptr)
+{
+ const priv_p priv = node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ switch (msg->header.typecookie) {
+ case NGM_PPP_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_PPP_SET_PROTOCOMP:
+ if (msg->header.arglen < sizeof(int))
+ ERROUT(EINVAL);
+ priv->protocomp = !!*((int *) msg->data);
+ break;
+ case NGM_PPP_GET_STATS:
+ NG_MKRESPONSE(resp, msg, sizeof(priv->stats), M_NOWAIT);
+ if (resp == NULL)
+ ERROUT(ENOMEM);
+ *((struct ng_ppp_stat *) resp->data) = priv->stats;
+ break;
+ case NGM_PPP_CLR_STATS:
+ bzero(&priv->stats, sizeof(priv->stats));
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+done:
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Receive data on a hook
+ */
+static int
+ng_ppp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const node_p node = hook->node;
+ const priv_p priv = node->private;
+ u_int16_t proto = HOOK_PROTO(hook);
+ int error = 0;
+
+ switch (proto) {
+
+ /* Prepend the (possibly compressed) protocol number */
+ default:
+ {
+ int psize = (priv->protocomp
+ && PROT_COMPRESSIBLE(proto)) ? 1 : 2;
+
+ M_PREPEND(m, psize, M_NOWAIT);
+ if (!m || !(m = m_pullup(m, psize)))
+ ERROUT(ENOBUFS);
+ if (psize == 1)
+ *mtod(m, u_char *) = proto;
+ else
+ *mtod(m, u_short *) = htons(proto);
+ hook = ng_ppp_findhook(node, PROT_DOWNLINK);
+ break;
+ }
+
+ /* Extract the protocol number and direct to the corresponding hook */
+ case PROT_DOWNLINK:
+ {
+ /* Stats */
+ priv->stats.recvFrames++;
+ priv->stats.recvOctets += m->m_pkthdr.len;
+
+ /* Extract protocol number */
+ for (proto = 0;
+ !PROT_VALID(proto);
+ proto = (proto << 8) + *mtod(m, u_char *), m_adj(m, 1)) {
+ if (m == NULL) {
+ priv->stats.badProto++;
+ ERROUT(EINVAL);
+ }
+ if ((m = m_pullup(m, 1)) == NULL)
+ ERROUT(ENOBUFS);
+ }
+
+ /* Find corresponding hook; if none, use the "unhooked"
+ hook and leave the two-byte protocol prepended */
+ if ((hook = ng_ppp_findhook(node, proto)) == NULL) {
+ priv->stats.unknownProto++;
+ hook = ng_ppp_findhook(node, PROT_BYPASS);
+ M_PREPEND(m, 2, M_NOWAIT);
+ if (m == NULL || (m = m_pullup(m, 2)) == NULL)
+ ERROUT(ENOBUFS);
+ *mtod(m, u_short *) = htons(proto);
+ }
+ break;
+ }
+
+ /* Send raw data from "unhooked" hook as-is; we assume the
+ protocol is already prepended */
+ case PROT_BYPASS:
+ hook = ng_ppp_findhook(node, PROT_DOWNLINK);
+ break;
+ }
+
+ /* Stats */
+ if (m != NULL && hook != NULL && HOOK_PROTO(hook) == PROT_DOWNLINK) {
+ priv->stats.xmitFrames++;
+ priv->stats.xmitOctets += m->m_pkthdr.len;
+ }
+
+ /* Forward packet on hook */
+ NG_SEND_DATA(error, hook, m, meta);
+ return (error);
+
+done:
+ /* Something went wrong */
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * Destroy node
+ */
+static int
+ng_ppp_rmnode(node_p node)
+{
+ const priv_p priv = node->private;
+
+ /* Take down netgraph node */
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ bzero(priv, sizeof(*priv));
+ FREE(priv, M_NETGRAPH);
+ node->private = NULL;
+ ng_unref(node); /* let the node escape */
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ng_ppp_disconnect(hook_p hook)
+{
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
+/************************************************************************
+ HELPER STUFF
+ ************************************************************************/
+
+/*
+ * Decode ASCII protocol name
+ */
+static int
+ng_ppp_decodehookname(const char *name)
+{
+ int k, proto;
+
+ for (k = 0; gAliases[k].name; k++)
+ if (!strcmp(gAliases[k].name, name))
+ return (gAliases[k].proto);
+ if (strlen(name) != 6 || name[0] != '0' || name[1] != 'x')
+ return (-1);
+ for (proto = k = 2; k < 6; k++) {
+ const u_char ch = name[k] | 0x20;
+ int dig;
+
+ if (ch >= '0' && ch <= '9')
+ dig = ch - '0';
+ else if (ch >= 'a' && ch <= 'f')
+ dig = ch - 'a' + 10;
+ else
+ return (-1);
+ proto = (proto << 4) + dig;
+ }
+ if (!PROT_VALID(proto))
+ return(-1);
+ return (proto);
+}
+
+/*
+ * Find a hook by protocol number
+ */
+static hook_p
+ng_ppp_findhook(node_p node, int proto)
+{
+ hook_p hook;
+
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ if (HOOK_PROTO(hook) == proto)
+ return (hook);
+ }
+ return (NULL);
+}
+
diff --git a/sys/netgraph/ng_ppp.h b/sys/netgraph/ng_ppp.h
new file mode 100644
index 0000000..06a6ddd
--- /dev/null
+++ b/sys/netgraph/ng_ppp.h
@@ -0,0 +1,91 @@
+
+/*
+ * ng_ppp.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_ppp.h,v 1.8 1999/01/25 02:40:02 archie Exp $
+ */
+
+#ifndef _NETGRAPH_PPP_H_
+#define _NETGRAPH_PPP_H_
+
+/* Node type name and magic cookie */
+#define NG_PPP_NODE_TYPE "ppp"
+#define NGM_PPP_COOKIE 860635544
+
+/* Hook names */
+#define NG_PPP_HOOK_DOWNLINK "downlink" /* downstream hook */
+#define NG_PPP_HOOK_BYPASS "bypass" /* any unhooked protocol */
+
+/* Netgraph commands */
+enum {
+ NGM_PPP_SET_PROTOCOMP = 1, /* takes an integer 0 or 1 */
+ NGM_PPP_GET_STATS, /* returns struct ng_ppp_stat */
+ NGM_PPP_CLR_STATS, /* clear stats */
+};
+
+/* Statistics struct */
+struct ng_ppp_stat {
+ u_int32_t xmitFrames; /* xmit frames on "downstream" */
+ u_int32_t xmitOctets; /* xmit octets on "downstream" */
+ u_int32_t recvFrames; /* recv frames on "downstream" */
+ u_int32_t recvOctets; /* recv octets on "downstream" */
+ u_int32_t badProto; /* frames with invalid protocol */
+ u_int32_t unknownProto; /* frames sent to "unhooked" */
+};
+
+/*
+ * We recognize these hook names for some various PPP protocols. But we
+ * always recognize the hook name "0xNNNN" for any protocol, including these.
+ * So these are really just alias hook names.
+ */
+#define NG_PPP_HOOK_LCP "lcp" /* 0xc021 */
+#define NG_PPP_HOOK_IPCP "ipcp" /* 0x8021 */
+#define NG_PPP_HOOK_ATCP "atcp" /* 0x8029 */
+#define NG_PPP_HOOK_CCP "ccp" /* 0x80fd */
+#define NG_PPP_HOOK_ECP "ecp" /* 0x8053 */
+#define NG_PPP_HOOK_IP "ip" /* 0x0021 */
+#define NG_PPP_HOOK_VJCOMP "vjcomp" /* 0x002d */
+#define NG_PPP_HOOK_VJUNCOMP "vjuncomp" /* 0x002f */
+#define NG_PPP_HOOK_MP "mp" /* 0x003d */
+#define NG_PPP_HOOK_COMPD "compd" /* 0x00fd */
+#define NG_PPP_HOOK_CRYPTD "cryptd" /* 0x0053 */
+#define NG_PPP_HOOK_PAP "pap" /* 0xc023 */
+#define NG_PPP_HOOK_CHAP "chap" /* 0xc223 */
+#define NG_PPP_HOOK_LQR "lqr" /* 0xc025 */
+
+#endif /* _NETGRAPH_PPP_H_ */
diff --git a/sys/netgraph/ng_pppoe.c b/sys/netgraph/ng_pppoe.c
new file mode 100644
index 0000000..b59dbb3
--- /dev/null
+++ b/sys/netgraph/ng_pppoe.c
@@ -0,0 +1,1343 @@
+
+/*
+ * ng_pppoe.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_pppoe.c,v 1.7 1999/10/16 10:16:43 julian Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <net/ethernet.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_pppoe.h>
+
+/*
+ * This section contains the netgraph method declarations for the
+ * sample node. These methods define the netgraph 'type'.
+ */
+
+static int ng_PPPoE_constructor(node_p *node);
+static int ng_PPPoE_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_PPPoE_rmnode(node_p node);
+static int ng_PPPoE_newhook(node_p node, hook_p hook, const char *name);
+static int ng_PPPoE_connect(hook_p hook);
+static int ng_PPPoE_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_PPPoE_disconnect(hook_p hook);
+
+/* Netgraph node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_PPPOE_NODE_TYPE,
+ NULL,
+ ng_PPPoE_constructor,
+ ng_PPPoE_rcvmsg,
+ ng_PPPoE_rmnode,
+ ng_PPPoE_newhook,
+ NULL,
+ ng_PPPoE_connect,
+ ng_PPPoE_rcvdata,
+ ng_PPPoE_rcvdata,
+ ng_PPPoE_disconnect
+};
+NETGRAPH_INIT(PPPoE, &typestruct);
+
+/*
+ * States for the session state machine.
+ * These have no meaning if there is no hook attached yet.
+ */
+enum state {
+ PPPOE_SNONE=0, /* [both] Initial state */
+ PPPOE_SINIT, /* [Client] Sent discovery initiation */
+ PPPOE_PRIMED, /* [Server] Sent offer message */
+ PPPOE_SOFFER, /* [Server] Sent offer message */
+ PPPOE_SREQ, /* [Client] Sent a Request */
+ PPPOE_LISTENING, /* [Server] Listening for discover initiation msg */
+ PPPOE_NEWCONNECTED, /* [Both] Connection established, No data received */
+ PPPOE_CONNECTED, /* [Both] Connection established, Data received */
+ PPPOE_DEAD /* [Both] */
+};
+/*
+ * Events for the state machine
+ */
+enum event {
+ PPPOE_TIMEOUT, /* It's time to do something */
+ PPPOE_PACKET, /* a packet has been received. */
+ PPPOE_CLOSE /* start shutdown processing */
+};
+
+#define NUMTAGS 20 /* number of tags we are set up to work with */
+
+/*
+ * Information we store for each hook on each node for negotiating the
+ * session. The mbuf and cluster are freed once negotiation has completed.
+ * The whole negotiation block is then discarded.
+ */
+
+struct sess_neg {
+ struct mbuf *m; /* holds cluster with last sent packet */
+ union packet *pkt; /* points within the above cluster */
+ struct callout_handle timeout_handle; /* see timeout(9) */
+ u_int timeout; /* 0,1,2,4,8,16 etc. seconds */
+ u_int numtags;
+ struct pppoe_tag *tags[NUMTAGS];
+ u_int service_len;
+ u_int ac_name_len;
+
+ struct datatag service;
+ struct datatag ac_name;
+};
+typedef struct sess_neg *negp;
+
+/*
+ * Session information that is needed after connection.
+ */
+struct session {
+ hook_p hook;
+ u_int16_t Session_ID;
+ struct session *hash_next; /* not yet uesed */
+ enum state state;
+ char creator[NG_NODELEN + 1]; /* who to notify */
+ struct pppoe_full_hdr pkt_hdr; /* used when connected */
+ negp neg; /* used when negotiating */
+};
+typedef struct session *sessp;
+
+/*
+ * Information we store for each node
+ */
+struct PPPOE {
+ node_p node; /* back pointer to node */
+ hook_p ethernet_hook;
+ hook_p debug_hook;
+ u_int packets_in; /* packets in from ethernet */
+ u_int packets_out; /* packets out towards ethernet */
+ u_int32_t flags;
+ /*struct session *buckets[HASH_SIZE];*/ /* not yet used */
+};
+typedef struct PPPOE *priv_p;
+
+const struct ether_header eh_prototype =
+ {{0xff,0xff,0xff,0xff,0xff,0xff},
+ {0x00,0x00,0x00,0x00,0x00,0x00},
+ ETHERTYPE_PPPOE_DISC};
+
+union uniq {
+ char bytes[sizeof(void *)];
+ void * pointer;
+ };
+
+#define LEAVE(x) do { error = x; goto quit; } while(0)
+static void pppoe_start(sessp sp);
+static void sendpacket(sessp sp);
+static void pppoe_ticker(void *arg);
+static struct pppoe_tag* scan_tags(sessp sp, struct pppoe_hdr* ph);
+
+/*************************************************************************
+ * Some basic utilities from the Linux version with author's permission.*
+ * Author: Michal Ostrowski <mostrows@styx.uwaterloo.ca> *
+ ************************************************************************/
+
+/*
+ * Generate a new session id
+ * XXX find out the freeBSD locking scheme.
+ */
+static u_int16_t
+get_new_sid(node_p node)
+{
+ static int pppoe_sid = 10;
+ sessp sp;
+ hook_p hook;
+ u_int16_t val;
+ priv_p privp = node->private;
+
+restart:
+ val = pppoe_sid++;
+ /*
+ * Spec says 0xFFFF is reserved.
+ * Also don't use 0x0000
+ */
+ if (val == 0xffff) {
+ pppoe_sid = 20;
+ goto restart;
+ }
+
+ /* Check it isn't already in use */
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ /* don't check special hooks */
+ if ((hook->private == &privp->debug_hook)
+ || (hook->private == &privp->ethernet_hook))
+ continue;
+ sp = hook->private;
+ if (sp->Session_ID == val)
+ goto restart;
+ }
+
+ return val;
+}
+
+
+/*
+ * Return the location where the next tag can be put
+ */
+static __inline struct pppoe_tag*
+next_tag(struct pppoe_hdr* ph)
+{
+ return (struct pppoe_tag*)(((char*)&ph->tag[0]) + ntohs(ph->length));
+}
+
+/*
+ * Look for a tag of a specific type
+ * Don't trust any length the other end says.
+ * but assume we already sanity checked ph->length.
+ */
+static struct pppoe_tag*
+get_tag(struct pppoe_hdr* ph, u_int16_t idx)
+{
+ char *end = (char *)next_tag(ph);
+ char *ptn;
+ struct pppoe_tag *pt = &ph->tag[0];
+ /*
+ * Keep processing tags while a tag header will still fit.
+ */
+ while((char*)(pt + 1) <= end) {
+ /*
+ * If the tag data would go past the end of the packet, abort.
+ */
+ ptn = (((char *)(pt + 1)) + ntohs(pt->tag_len));
+ if(ptn > end)
+ return NULL;
+
+ if(pt->tag_type == idx)
+ return pt;
+
+ pt = (struct pppoe_tag*)ptn;
+ }
+ return NULL;
+}
+
+/**************************************************************************
+ * inlines to initialise or add tags to a session's tag list,
+ **************************************************************************/
+/*
+ * Initialise the session's tag list
+ */
+static void
+init_tags(sessp sp)
+{
+ if(sp->neg == NULL) {
+ printf("pppoe: asked to init NULL neg pointer\n");
+ return;
+ }
+ sp->neg->numtags = 0;
+}
+
+static void
+insert_tag(sessp sp, struct pppoe_tag *tp)
+{
+ int i;
+ negp neg;
+
+ if((neg = sp->neg) == NULL) {
+ printf("pppoe: asked to use NULL neg pointer\n");
+ return;
+ }
+ if ((i = neg->numtags++) < NUMTAGS) {
+ neg->tags[i] = tp;
+ } else {
+ printf("pppoe: asked to add too many tags to packet\n");
+ }
+}
+
+/*
+ * Make up a packet, using the tags filled out for the session.
+ *
+ * Assume that the actual pppoe header and ethernet header
+ * are filled out externally to this routine.
+ * Also assume that neg->wh points to the correct
+ * location at the front of the buffer space.
+ */
+static void
+make_packet(sessp sp) {
+ struct pppoe_full_hdr *wh = &sp->neg->pkt->pkt_header;
+ struct pppoe_tag **tag;
+ char *dp;
+ int count;
+ int tlen;
+ u_int16_t length = 0;
+
+ if ((sp->neg == NULL) || (sp->neg->m = NULL)) {
+ printf("pppoe: make_packet called from wrong state\n");
+ }
+ dp = (char *)wh->ph.tag;
+ for (count = 0, tag = sp->neg->tags;
+ ((count < sp->neg->numtags) && (count < NUMTAGS));
+ tag++, count++) {
+ tlen = ntohs((*tag)->tag_len) + sizeof(**tag);
+ if ((length + tlen) > (ETHER_MAX_LEN - 4 - sizeof(*wh))) {
+ printf("pppoe: tags too long\n");
+ sp->neg->numtags = count;
+ break; /* XXX chop off what's too long */
+ }
+ bcopy((char *)*tag, (char *)dp, tlen);
+ length += tlen;
+ dp += tlen;
+ }
+ wh->ph.length = htons(length);
+ sp->neg->m->m_len = length + sizeof(*wh);
+ sp->neg->m->m_pkthdr.len = length + sizeof(*wh);
+}
+
+/**************************************************************************
+ * Routine to match a service offered *
+ **************************************************************************/
+/*
+ * Find a hook that has a service string that matches that
+ * we are seeking. for now use a simple string.
+ * In the future we may need something like regexp().
+ * for testing allow a null string to match 1st found and a null service
+ * to match all requests. Also make '*' do the same.
+ */
+static hook_p
+pppoe_match_svc(node_p node, char *svc_name, int svc_len)
+{
+ sessp sp = NULL;
+ negp neg = NULL;
+ priv_p privp = node->private;
+ hook_p hook;
+
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+
+ /* skip any hook that is debug or ethernet */
+ if ((hook->private == &privp->debug_hook)
+ || (hook->private == &privp->ethernet_hook))
+ continue;
+ sp = hook->private;
+
+ /* Skip any sessions which are not in LISTEN mode. */
+ if ( sp->state != PPPOE_LISTENING)
+ continue;
+
+ neg = sp->neg;
+ /* XXX check validity of this */
+ /* special case, NULL request. match 1st found. */
+ if (svc_len == 0)
+ break;
+
+ /* XXX check validity of this */
+ /* Special case for a blank or "*" service name (wildcard) */
+ if ((neg->service_len == 0)
+ || ((neg->service_len == 1)
+ && (neg->service.data[0] == '*'))) {
+ break;
+ }
+
+ /* If the lengths don't match, that aint it. */
+ if (neg->service_len != svc_len)
+ continue;
+
+ /* An exact match? */
+ if (strncmp(svc_name, neg->service.data, svc_len) == 0)
+ break;
+ }
+ return (hook);
+}
+/**************************************************************************
+ * Routine to find a particular session that matches an incoming packet *
+ **************************************************************************/
+static hook_p
+pppoe_findsession(node_p node, struct pppoe_full_hdr *wh)
+{
+ sessp sp = NULL;
+ hook_p hook = NULL;
+ priv_p privp = node->private;
+ u_int16_t session = wh->ph.sid;
+
+ /*
+ * find matching peer/session combination.
+ */
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ /* don't check special hooks */
+ if ((hook->private == &privp->debug_hook)
+ || (hook->private == &privp->ethernet_hook)) {
+ continue;
+ }
+ sp = hook->private;
+ if ( ( (sp->state == PPPOE_CONNECTED)
+ || (sp->state == PPPOE_NEWCONNECTED) )
+ && (sp->Session_ID == session)
+ && (bcmp(sp->pkt_hdr.eh.ether_dhost,
+ wh->eh.ether_shost,
+ ETHER_ADDR_LEN)) == 0) {
+ break;
+ }
+ }
+ return (hook);
+}
+
+static hook_p
+pppoe_finduniq(node_p node, struct pppoe_tag *tag)
+{
+ hook_p hook = NULL;
+ priv_p privp = node->private;
+ union uniq uniq;
+
+ bcopy(tag->tag_data, uniq.bytes, sizeof(void *));
+ /* cycle through all known hooks */
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ /* don't check special hooks */
+ if ((hook->private == &privp->debug_hook)
+ || (hook->private == &privp->ethernet_hook))
+ continue;
+ if (uniq.pointer == hook->private)
+ break;
+ }
+ return (hook);
+}
+
+/**************************************************************************
+ * start of Netgraph entrypoints *
+ **************************************************************************/
+
+/*
+ * Allocate the private data structure and the generic node
+ * and link them together.
+ *
+ * ng_make_node_common() returns with a generic node struct
+ * with a single reference for us.. we transfer it to the
+ * private structure.. when we free the private struct we must
+ * unref the node so it gets freed too.
+ *
+ * If this were a device node than this work would be done in the attach()
+ * routine and the constructor would return EINVAL as you should not be able
+ * to creatednodes that depend on hardware (unless you can add the hardware :)
+ */
+static int
+ng_PPPoE_constructor(node_p *nodep)
+{
+ priv_p privdata;
+ int error;
+
+ /* Initialize private descriptor */
+ MALLOC(privdata, priv_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK);
+ if (privdata == NULL)
+ return (ENOMEM);
+ bzero(privdata, sizeof(*privdata));
+
+ /* Call the 'generic' (ie, superclass) node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(privdata, M_NETGRAPH);
+ return (error);
+ }
+
+ /* Link structs together; this counts as our one reference to *nodep */
+ (*nodep)->private = privdata;
+ privdata->node = *nodep;
+ return (0);
+}
+
+/*
+ * Give our ok for a hook to be added...
+ * point the hook's private info to the hook structure.
+ *
+ * The following hook names are special:
+ * Ethernet: the hook that should be connected to a NIC.
+ * debug: copies of data sent out here (when I write the code).
+ */
+static int
+ng_PPPoE_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p privp = node->private;
+ sessp sp;
+
+ if (strcmp(name, NG_PPPOE_HOOK_ETHERNET) == 0) {
+ privp->ethernet_hook = hook;
+ hook->private = &privp->ethernet_hook;
+ } else if (strcmp(name, NG_PPPOE_HOOK_DEBUG) == 0) {
+ privp->debug_hook = hook;
+ hook->private = &privp->debug_hook;
+ } else {
+ /*
+ * Any other unique name is OK.
+ * The infrastructure has already checked that it's unique,
+ * so just allocate it and hook it in.
+ */
+ MALLOC(sp, sessp, sizeof(*sp), M_NETGRAPH, M_WAITOK);
+ if (sp == NULL) {
+ return (ENOMEM);
+ }
+ bzero(sp, sizeof(*sp));
+
+ hook->private = sp;
+ sp->hook = hook;
+ callout_handle_init( &sp->neg->timeout_handle);
+ }
+ return(0);
+}
+
+/*
+ * Get a netgraph control message.
+ * Check it is one we understand. If needed, send a response.
+ * We sometimes save the address for an async action later.
+ * Always free the message.
+ */
+static int
+ng_PPPoE_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr)
+{
+ priv_p privp = node->private;
+ struct ngPPPoE_init_data *ourmsg = NULL;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+ hook_p hook = NULL;
+ sessp sp = NULL;
+ negp neg = NULL;
+
+ /* Deal with message according to cookie and command */
+ switch (msg->header.typecookie) {
+ case NGM_PPPOE_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_PPPOE_CONNECT:
+ case NGM_PPPOE_LISTEN:
+ case NGM_PPPOE_OFFER:
+ ourmsg = (struct ngPPPoE_init_data *)msg->data;
+ if (( sizeof(*ourmsg) > msg->header.arglen)
+ || ((sizeof(*ourmsg) + ourmsg->data_len)
+ > msg->header.arglen)) {
+ printf("PPPoE_rcvmsg: bad arg size");
+ LEAVE(EMSGSIZE);
+ }
+ if (ourmsg->data_len > PPPOE_SERVICE_NAME_SIZE) {
+ printf("pppoe: init data too long (%d)\n",
+ ourmsg->data_len);
+ LEAVE(EMSGSIZE);
+ }
+ /* make sure strcmp will terminate safely */
+ ourmsg->hook[sizeof(ourmsg->hook) - 1] = '\0';
+
+ /* cycle through all known hooks */
+ LIST_FOREACH(hook, &node->hooks, hooks) {
+ if (hook->name
+ && strcmp(hook->name, ourmsg->hook) == 0)
+ break;
+ }
+ if (hook == NULL) {
+ LEAVE(ENOENT);
+ }
+ if ((hook->private == &privp->debug_hook)
+ || (hook->private == &privp->ethernet_hook)) {
+ LEAVE(EINVAL);
+ }
+ sp = hook->private;
+ if (sp->state |= PPPOE_SNONE) {
+ printf("pppoe: Session already active\n");
+ LEAVE(EISCONN);
+ }
+ /*
+ * set up prototype header
+ */
+
+ MALLOC(neg, negp, sizeof(*neg), M_NETGRAPH, M_WAITOK);
+
+ if (neg == NULL) {
+ printf("pppoe: Session out of memory\n");
+ LEAVE(ENOMEM);
+ }
+ bzero(neg, sizeof(*neg));
+ MGETHDR(neg->m, M_DONTWAIT, MT_DATA);
+ if(neg->m == NULL) {
+ FREE(neg, M_NETGRAPH);
+ LEAVE(ENOBUFS);
+ }
+ neg->m->m_pkthdr.rcvif = NULL;
+ MCLGET(neg->m, M_DONTWAIT);
+ if ((neg->m->m_flags & M_EXT) == 0) {
+ m_freem(neg->m);
+ FREE(neg, M_NETGRAPH);
+ LEAVE(ENOBUFS);
+ }
+ sp->neg = neg;
+ neg->m->m_len = sizeof(struct pppoe_full_hdr);
+ neg->pkt = mtod(neg->m, union packet*);
+ neg->pkt->pkt_header.eh = eh_prototype;
+ neg->pkt->pkt_header.ph.ver = 0x1;
+ neg->pkt->pkt_header.ph.type = 0x1;
+ neg->pkt->pkt_header.ph.sid = 0x0000;
+ neg->timeout = 0;
+
+ strncpy(sp->creator, retaddr, NG_NODELEN);
+ sp->creator[NG_NODELEN] = '\0';
+ }
+ switch (msg->header.cmd) {
+ case NGM_PPPOE_GET_STATUS:
+ {
+ struct ngPPPoEstat *stats;
+
+ NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
+ if (!resp) {
+ LEAVE(ENOMEM);
+ }
+ stats = (struct ngPPPoEstat *) resp->data;
+ stats->packets_in = privp->packets_in;
+ stats->packets_out = privp->packets_out;
+ break;
+ }
+ case NGM_PPPOE_CONNECT:
+ /*
+ * Check the hook exists and is Uninitialised.
+ * Send a PADI request, and start the timeout logic.
+ * Store the originator of this message so we can send
+ * a success of fail message to them later.
+ * Move the session to SINIT
+ * Set up the session to the correct state and
+ * start it.
+ */
+ neg->service.hdr.tag_type = PTT_SRV_NAME;
+ neg->service.hdr.tag_len =
+ htons((u_int16_t)ourmsg->data_len);
+ bcopy(ourmsg->data,
+ neg->service.data, ourmsg->data_len);
+ neg->service_len = ourmsg->data_len;
+ neg->pkt->pkt_header.ph.code = PADI_CODE;
+ pppoe_start(sp);
+ break;
+ case NGM_PPPOE_LISTEN:
+ /*
+ * Check the hook exists and is Uninitialised.
+ * Install the service matching string.
+ * Store the originator of this message so we can send
+ * a success of fail message to them later.
+ * Move the hook to 'LISTENING'
+ */
+ neg->service.hdr.tag_type = PTT_SRV_NAME;
+ neg->service.hdr.tag_len =
+ htons((u_int16_t)ourmsg->data_len);
+ bcopy(ourmsg->data,
+ neg->service.data, ourmsg->data_len);
+ neg->service_len = ourmsg->data_len;
+ neg->pkt->pkt_header.ph.code = PADT_CODE;
+ /*
+ * wait for PADI packet coming from ethernet
+ */
+ sp->state = PPPOE_LISTENING;
+ break;
+ case NGM_PPPOE_OFFER:
+ /*
+ * Check the hook exists and is Uninitialised.
+ * Store the originator of this message so we can send
+ * a success of fail message to them later.
+ * Store the AC-Name given and go to PRIMED.
+ */
+ neg->ac_name.hdr.tag_type = PTT_AC_NAME;
+ neg->ac_name.hdr.tag_len =
+ htons((u_int16_t)ourmsg->data_len);
+ bcopy(ourmsg->data,
+ neg->ac_name.data, ourmsg->data_len);
+ neg->ac_name_len = ourmsg->data_len;
+ neg->pkt->pkt_header.ph.code = PADO_CODE;
+ /*
+ * Wait for PADI packet coming from hook
+ */
+ sp->state = PPPOE_PRIMED;
+ break;
+ default:
+ LEAVE(EINVAL);
+ }
+ break;
+ default:
+ LEAVE(EINVAL);
+ }
+
+ /* Take care of synchronous response, if any */
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+ /* Free the message and return */
+quit:
+ FREE(msg, M_NETGRAPH);
+ return(error);
+}
+
+static void
+pppoe_start(sessp sp)
+{
+ struct {
+ struct pppoe_tag hdr;
+ union uniq data;
+ } uniqtag;
+
+ /*
+ * kick the state machine into starting up
+ */
+ sp->state = PPPOE_SINIT;
+ uniqtag.hdr.tag_type = PTT_HOST_UNIQ;
+ uniqtag.hdr.tag_len = htons((u_int16_t)sizeof(uniqtag.data));
+ uniqtag.data.pointer = sp;
+ init_tags(sp);
+ insert_tag(sp, &uniqtag.hdr);
+ insert_tag(sp, &sp->neg->service.hdr);
+ make_packet(sp);
+ sendpacket(sp);
+}
+
+/*
+ * Receive data, and do something with it.
+ * The caller will never free m or meta, so
+ * if we use up this data or abort we must free BOTH of these.
+ */
+static int
+ng_PPPoE_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ node_p node = hook->node;
+ const priv_p privp = node->private;
+ sessp sp = hook->private;
+ struct pppoe_full_hdr *wh;
+ struct pppoe_hdr *ph;
+ int error = 0;
+ u_int16_t session;
+ u_int16_t length;
+ u_int8_t code;
+ struct pppoe_tag *tag = NULL;
+ hook_p sendhook;
+ struct {
+ struct pppoe_tag hdr;
+ union uniq data;
+ } uniqtag;
+ negp neg = NULL;
+
+ if (hook->private == &privp->debug_hook) {
+ /*
+ * Data from the debug hook gets sent without modification
+ * straight to the ethernet.
+ */
+ NG_SEND_DATA( error, privp->ethernet_hook, m, meta);
+ privp->packets_out++;
+ } else if (hook->private == &privp->ethernet_hook) {
+ /*
+ * Incoming data.
+ * Dig out various fields from the packet.
+ * use them to decide where to send it.
+ */
+
+ privp->packets_in++;
+ m_pullup(m, sizeof(*wh)); /* Checks length */
+ if (m == NULL) {
+ LEAVE(ENOBUFS);
+ }
+ wh = mtod(m, struct pppoe_full_hdr *);
+ ph = &wh->ph;
+ session = ntohs(wh->ph.sid);
+ length = ntohs(wh->ph.length);
+ code = wh->ph.code;
+ switch(ntohs(wh->eh.ether_type)) {
+ case ETHERTYPE_PPPOE_DISC:
+ /*
+ * We need to try make sure that the tag area
+ * is contiguous, or we could wander of the end
+ * of a buffer and make a mess.
+ * (Linux wouldn't have this problem).
+ */
+ if (m->m_len != m->m_pkthdr.len) {
+ /*
+ * It's not all in one piece.
+ * We need to do extra work.
+ */
+ printf("packet fragmented\n");
+ }
+
+ switch(code) {
+ case PADI_CODE:
+ /*
+ * We are a server:
+ * Look for a hook with the required service
+ * and send the ENTIRE packet up there.
+ * It should come back to a new hook in
+ * PRIMED state. Look there for further
+ * processing.
+ */
+ tag = get_tag(ph, PTT_SRV_NAME);
+ if (tag == NULL) {
+ LEAVE(ENETUNREACH);
+ }
+ sendhook = pppoe_match_svc(hook->node,
+ tag->tag_data, ntohs(tag->tag_len));
+ if (sendhook) {
+ NG_SEND_DATA(error, sendhook, m, meta);
+ } else {
+ LEAVE(ENETUNREACH);
+ }
+ break;
+ case PADO_CODE:
+ /*
+ * We are a client:
+ * Use the host_uniq tag to find the
+ * hook this is in response to.
+ *
+ * For now simply accept the first we receive.
+ */
+ tag = get_tag(ph, PTT_HOST_UNIQ);
+ if ((tag == NULL)
+ || (ntohs(tag->tag_len) != sizeof(sp))) {
+ LEAVE(ENETUNREACH);
+ }
+
+ sendhook = pppoe_finduniq(node, tag);
+ if (sendhook == NULL) {
+ LEAVE(ENETUNREACH);
+ }
+
+ /*
+ * Check the session is in the right state.
+ * It needs to be in PPPOE_SINIT.
+ */
+ sp = sendhook->private;
+ if (sp->state != PPPOE_SINIT) {
+ LEAVE(ENETUNREACH);
+ }
+ neg = sp->neg;
+ untimeout(pppoe_ticker, sendhook,
+ neg->timeout_handle);
+
+ /*
+ * This is the first time we hear
+ * from the server, so note it's
+ * unicast address, replacing the
+ * broadcast address .
+ */
+ bcopy(wh->eh.ether_shost,
+ neg->pkt->pkt_header.eh.ether_dhost,
+ ETHER_ADDR_LEN);
+ neg->timeout = 0;
+ neg->pkt->pkt_header.ph.code = PADR_CODE;
+ init_tags(sp);
+ insert_tag(sp,&neg->service.hdr); /* Service */
+ insert_tag(sp, tag); /* Host Unique */
+ tag = get_tag(ph, PTT_AC_COOKIE);
+ insert_tag(sp, tag); /* returned cookie */
+ scan_tags(sp, ph);
+ make_packet(sp);
+ sp->state = PPPOE_SREQ;
+ sendpacket(sp);
+ break;
+ case PADR_CODE:
+
+ /*
+ * We are a server:
+ * Use the ac_cookie tag to find the
+ * hook this is in response to.
+ */
+ tag = get_tag(ph, PTT_AC_COOKIE);
+ if ((tag == NULL)
+ || (ntohs(tag->tag_len) != sizeof(sp))) {
+ LEAVE(ENETUNREACH);
+ }
+
+ sendhook = pppoe_finduniq(node, tag);
+ if (sendhook == NULL) {
+ LEAVE(ENETUNREACH);
+ }
+
+ /*
+ * Check the session is in the right state.
+ * It needs to be in PPPOE_SOFFER
+ * or PPPOE_NEWCONNECTED. If the latter,
+ * then this is a retry by the client.
+ * so be nice, and resend.
+ */
+ sp = sendhook->private;
+ if (sp->state == PPPOE_NEWCONNECTED) {
+ /*
+ * Whoa! drop back to resend that
+ * PADS packet.
+ * We should still have a copy of it.
+ */
+ sp->state = PPPOE_SOFFER;
+ }
+ if (sp->state != PPPOE_SOFFER) {
+ LEAVE (ENETUNREACH);
+ break;
+ }
+ neg = sp->neg;
+ untimeout(pppoe_ticker, sendhook,
+ neg->timeout_handle);
+ neg->pkt->pkt_header.ph.code = PADS_CODE;
+ if (sp->Session_ID == 0)
+ neg->pkt->pkt_header.ph.sid =
+ sp->Session_ID = get_new_sid(node);
+ neg->timeout = 0;
+ /*
+ * start working out the tags to respond with.
+ */
+ init_tags(sp);
+ insert_tag(sp, &neg->ac_name.hdr); /* AC_NAME */
+ insert_tag(sp, tag); /* ac_cookie */
+ tag = get_tag(ph, PTT_SRV_NAME);
+ insert_tag(sp, tag); /* returned service */
+ tag = get_tag(ph, PTT_HOST_UNIQ);
+ insert_tag(sp, tag); /* returned hostuniq */
+ scan_tags(sp, ph);
+ make_packet(sp);
+ sp->state = PPPOE_NEWCONNECTED;
+ sendpacket(sp);
+ /*
+ * Having sent the last Negotiation header,
+ * Set up the stored packet header to
+ * be correct for the actual session.
+ * But keep the negotialtion stuff
+ * around in case we need to resend this last
+ * packet. We'll discard it when we move
+ * from NEWCONNECTED to CONNECTED
+ */
+ sp->pkt_hdr = neg->pkt->pkt_header;
+ sp->pkt_hdr.eh.ether_type
+ = ETHERTYPE_PPPOE_SESS;
+ sp->pkt_hdr.ph.code = 0;
+ break;
+ case PADS_CODE:
+ /*
+ * We are a client:
+ * Use the host_uniq tag to find the
+ * hook this is in response to.
+ * take the session ID and store it away.
+ * Also make sure the pre-made header is
+ * correct and set us into Session mode.
+ */
+ tag = get_tag(ph, PTT_HOST_UNIQ);
+ if ((tag == NULL)
+ || (ntohs(tag->tag_len) != sizeof(sp))) {
+ LEAVE (ENETUNREACH);
+ break;
+ }
+
+ sendhook = pppoe_finduniq(node, tag);
+ if (sendhook == NULL) {
+ LEAVE(ENETUNREACH);
+ }
+
+ /*
+ * Check the session is in the right state.
+ * It needs to be in PPPOE_SREQ.
+ */
+ sp = sendhook->private;
+ if (sp->state != PPPOE_SREQ) {
+ LEAVE(ENETUNREACH);
+ }
+ neg = sp->neg;
+ untimeout(pppoe_ticker, sendhook,
+ neg->timeout_handle);
+ sp->Session_ID = wh->ph.sid;
+ neg->timeout = 0;
+ sp->state = PPPOE_CONNECTED;
+ sendpacket(sp);
+ /*
+ * Now we have gone to Connected mode,
+ * Free all resources needed for
+ * negotiation.
+ * Keep a copy of the header we will be using.
+ */
+ sp->pkt_hdr = neg->pkt->pkt_header;
+ sp->pkt_hdr.eh.ether_type
+ = ETHERTYPE_PPPOE_SESS;
+ sp->pkt_hdr.ph.code = 0;
+ m_freem(neg->m);
+ FREE(sp->neg, M_NETGRAPH);
+ sp->neg = NULL;
+ break;
+ case PADT_CODE:
+ /*
+ * Send a 'close' message to the controlling
+ * process (the one that set us up);
+ * And then tear everything down.
+ *
+ * Find matching peer/session combination.
+ */
+ sendhook = pppoe_findsession(node, wh);
+ NG_FREE_DATA(m, meta); /* no longer needed */
+ if (sendhook == NULL) {
+ LEAVE(ENETUNREACH);
+ }
+ /* send message to creator */
+ /* close hook */
+ ng_destroy_hook(sendhook);
+ break;
+ default:
+ LEAVE(EPFNOSUPPORT);
+ }
+ break;
+ case ETHERTYPE_PPPOE_SESS:
+ /*
+ * find matching peer/session combination.
+ */
+ sendhook = pppoe_findsession(node, wh);
+ if (sendhook == NULL) {
+ LEAVE (ENETUNREACH);
+ break;
+ }
+ m_adj(m, sizeof(*wh));
+ if (m->m_pkthdr.len < length) {
+ /* Packet too short, dump it */
+ LEAVE(EMSGSIZE);
+ }
+ /* XXX also need to trim excess at end I should think */
+ if ( sp->state != PPPOE_CONNECTED) {
+ if (sp->state == PPPOE_NEWCONNECTED) {
+ sp->state = PPPOE_CONNECTED;
+ /*
+ * Now we have gone to Connected mode,
+ * Free all resources needed for
+ * negotiation.
+ */
+ m_freem(sp->neg->m);
+ FREE(sp->neg, M_NETGRAPH);
+ sp->neg = NULL;
+ } else {
+ LEAVE (ENETUNREACH);
+ break;
+ }
+ }
+ NG_SEND_DATA( error, sendhook, m, meta);
+ break;
+ default:
+ LEAVE(EPFNOSUPPORT);
+ }
+ } else {
+ /*
+ * Not ethernet or debug hook..
+ *
+ * The packet has come in on a normal hook.
+ * We need to find out what kind of hook,
+ * So we can decide how to handle it.
+ * Check the hook's state.
+ */
+ sp = hook->private;
+ switch (sp->state) {
+ case PPPOE_NEWCONNECTED:
+ case PPPOE_CONNECTED: {
+ struct pppoe_full_hdr *wh;
+ /*
+ * Bang in a pre-made header, and set the length up
+ * to be correct. Then send it to the ethernet driver.
+ */
+ M_PREPEND(m, sizeof(*wh), M_DONTWAIT);
+ if (m == NULL) {
+ LEAVE(ENOBUFS);
+ }
+ wh = mtod(m, struct pppoe_full_hdr *);
+ bcopy(&sp->pkt_hdr, wh, sizeof(*wh));
+ wh->ph.length = htons((short)(m->m_pkthdr.len));
+ NG_SEND_DATA( error, privp->ethernet_hook, m, meta);
+ privp->packets_out++;
+ break;
+ }
+ case PPPOE_PRIMED:
+ /*
+ * A PADI packet is being returned by the application
+ * that has set up this hook. This indicates that it
+ * wants us to offer service.
+ */
+ neg = sp->neg;
+ m_pullup(m, sizeof(*wh)); /* Checks length */
+ if (m == NULL) {
+ LEAVE(ENOBUFS);
+ }
+ wh = mtod(m, struct pppoe_full_hdr *);
+ ph = &wh->ph;
+ session = ntohs(wh->ph.sid);
+ length = ntohs(wh->ph.length);
+ code = wh->ph.code;
+
+ /*
+ * This is the first time we hear
+ * from the client, so note it's
+ * unicast address, replacing the
+ * broadcast address .
+ */
+ bcopy(wh->eh.ether_shost,
+ neg->pkt->pkt_header.eh.ether_dhost,
+ ETHER_ADDR_LEN);
+ sp->state = PPPOE_SOFFER;
+ neg->timeout = 0;
+ neg->pkt->pkt_header.ph.code = PADO_CODE;
+
+ /*
+ * start working out the tags to respond with.
+ */
+ uniqtag.hdr.tag_type = PTT_AC_COOKIE;
+ uniqtag.hdr.tag_len = htons((u_int16_t)sizeof(sp));
+ uniqtag.data.pointer = sp;
+ init_tags(sp);
+ insert_tag(sp, &neg->ac_name.hdr); /* AC_NAME */
+ insert_tag(sp, tag); /* returned hostunique */
+ insert_tag(sp, &uniqtag.hdr); /* AC cookie */
+ tag = get_tag(ph, PTT_SRV_NAME);
+ insert_tag(sp, tag); /* returned service */
+ /* XXX maybe put the tag in the session store */
+ scan_tags(sp, ph);
+ make_packet(sp);
+ sendpacket(sp);
+ break;
+
+ /*
+ * Packets coming from the hook make no sense
+ * to sessions in these states. Throw them away.
+ */
+ case PPPOE_SINIT:
+ case PPPOE_SREQ:
+ case PPPOE_SOFFER:
+ case PPPOE_SNONE:
+ case PPPOE_LISTENING:
+ case PPPOE_DEAD:
+ default:
+ LEAVE(ENETUNREACH);
+ }
+ }
+quit:
+ NG_FREE_DATA(m, meta);
+ return error;
+}
+
+/*
+ * Do local shutdown processing..
+ * If we are a persistant device, we might refuse to go away, and
+ * we'd only remove our links and reset ourself.
+ */
+static int
+ng_PPPoE_rmnode(node_p node)
+{
+ const priv_p privdata = node->private;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ node->private = NULL;
+ ng_unref(privdata->node);
+ FREE(privdata, M_NETGRAPH);
+ return (0);
+}
+
+/*
+ * This is called once we've already connected a new hook to the other node.
+ * It gives us a chance to balk at the last minute.
+ */
+static int
+ng_PPPoE_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ *
+ * Clean up all dangling links and infirmation about the session/hook.
+ * For this type, removal of the last link destroys the node
+ */
+static int
+ng_PPPoE_disconnect(hook_p hook)
+{
+ node_p node = hook->node;
+ priv_p privp = node->private;
+ sessp sp;
+
+ if (hook->private == &privp->debug_hook) {
+ privp->debug_hook = NULL;
+ } else if (hook->private == &privp->ethernet_hook) {
+ privp->ethernet_hook = NULL;
+ } else {
+ sp = hook->private;
+ untimeout(pppoe_ticker, hook, sp->neg->timeout_handle);
+ FREE(sp, M_NETGRAPH);
+ }
+ if (node->numhooks == 0)
+ ng_rmnode(node);
+ return (0);
+}
+
+/*
+ * timeouts come here.
+ */
+static void
+pppoe_ticker(void *arg)
+{
+ int s = splnet();
+ hook_p hook = arg;
+ sessp sp = hook->private;
+ negp neg = sp->neg;
+ int error = 0;
+ struct mbuf *m0 = NULL;
+ priv_p privp = hook->node->private;
+ meta_p dummy = NULL;
+
+ switch(sp->state) {
+ /*
+ * resend the last packet, using an exponential backoff.
+ * After a period of time, stop growing the backoff,
+ * and either leave it, or reverst to the start.
+ */
+ case PPPOE_SINIT:
+ case PPPOE_SREQ:
+ /* timeouts on these produce resends */
+ m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
+ NG_SEND_DATA( error, privp->ethernet_hook, m0, dummy);
+ neg->timeout_handle = timeout(pppoe_ticker,
+ hook, neg->timeout * hz);
+ if ((neg->timeout <<= 1) > PPPOE_TIMEOUT_LIMIT) {
+ if (sp->state == PPPOE_SREQ) {
+ /* revert to SINIT mode */
+ } else {
+ neg->timeout = PPPOE_TIMEOUT_LIMIT;
+ }
+ }
+ break;
+ case PPPOE_PRIMED:
+ case PPPOE_SOFFER:
+ /* a timeout on these says "give up" */
+ /* XXX should notify creator */
+ ng_destroy_hook(hook);
+ break;
+ default:
+ /* timeouts have no meaning in other states */
+ printf("pppoe: unexpected timeout\n");
+ }
+ splx(s);
+}
+
+
+static void
+sendpacket(sessp sp)
+{
+ int error = 0;
+ struct mbuf *m0 = NULL;
+ hook_p hook = sp->hook;
+ negp neg = sp->neg;
+ priv_p privp = hook->node->private;
+ meta_p dummy = NULL;
+
+ switch(sp->state) {
+ case PPPOE_LISTENING:
+ case PPPOE_DEAD:
+ case PPPOE_SNONE:
+ case PPPOE_NEWCONNECTED:
+ case PPPOE_CONNECTED:
+ printf("pppoe: timeout: unexpected state\n");
+ break;
+
+ case PPPOE_PRIMED:
+ /* No packet to send, but set up the timeout */
+ neg->timeout_handle = timeout(pppoe_ticker,
+ hook, PPPOE_OFFER_TIMEOUT * hz);
+ break;
+
+ case PPPOE_SOFFER:
+ /*
+ * send the offer but if they don't respond
+ * in PPPOE_OFFER_TIMEOUT seconds, forget about it.
+ */
+ m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
+ NG_SEND_DATA( error, privp->ethernet_hook, m0, dummy);
+ neg->timeout_handle = timeout(pppoe_ticker,
+ hook, PPPOE_OFFER_TIMEOUT * hz);
+ break;
+
+ case PPPOE_SINIT:
+ case PPPOE_SREQ:
+ m0 = m_copypacket(sp->neg->m, M_DONTWAIT);
+ NG_SEND_DATA( error, sp->hook, m0, dummy);
+ neg->timeout_handle = timeout(pppoe_ticker, hook, hz);
+ neg->timeout = 2;
+ break;
+
+ default:
+ error = EINVAL;
+ printf("pppoe: timeout: bad state\n");
+ }
+ /* return (error); */
+}
+
+/*
+ * Parse an incoming packet to see if any tags should be copied to the
+ * output packet. DOon't do any tags that are likely to have been
+ * handles a the main state machine.
+ */
+static struct pppoe_tag*
+scan_tags(sessp sp, struct pppoe_hdr* ph)
+{
+ char *end = (char *)next_tag(ph);
+ char *ptn;
+ struct pppoe_tag *pt = &ph->tag[0];
+ /*
+ * Keep processing tags while a tag header will still fit.
+ */
+ while((char*)(pt + 1) <= end) {
+ /*
+ * If the tag data would go past the end of the packet, abort.
+ */
+ ptn = (((char *)(pt + 1)) + ntohs(pt->tag_len));
+ if(ptn > end)
+ return NULL;
+
+ switch (pt->tag_type) {
+ case PTT_RELAY_SID:
+ insert_tag(sp, pt);
+ break;
+ case PTT_EOL:
+ return NULL;
+ case PTT_SRV_NAME:
+ case PTT_AC_NAME:
+ case PTT_HOST_UNIQ:
+ case PTT_AC_COOKIE:
+ case PTT_VENDOR:
+ case PTT_SRV_ERR:
+ case PTT_SYS_ERR:
+ case PTT_GEN_ERR:
+ break;
+ }
+ pt = (struct pppoe_tag*)ptn;
+ }
+ return NULL;
+}
+
diff --git a/sys/netgraph/ng_pppoe.h b/sys/netgraph/ng_pppoe.h
new file mode 100644
index 0000000..5ee3e7d
--- /dev/null
+++ b/sys/netgraph/ng_pppoe.h
@@ -0,0 +1,224 @@
+
+/*
+ * ng_pppoe.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_pppoe.h,v 1.7 1999/10/16 10:16:43 julian Exp $
+ */
+
+#ifndef _NETGRAPH_PPPOE_H_
+#define _NETGRAPH_PPPOE_H_
+
+/********************************************************************
+ * Netgraph hook constants etc.
+ ********************************************************************/
+/* Node type name. This should be unique among all netgraph node types */
+#define NG_PPPOE_NODE_TYPE "PPPoE"
+
+#define NGM_PPPOE_COOKIE 939032003
+
+/* Number of active sessions we can handle */
+#define PPPOE_NUM_SESSIONS 16 /* for now */
+#define PPPOE_SERVICE_NAME_SIZE 64 /* for now */
+
+/* Hook names */
+#define NG_PPPOE_HOOK_ETHERNET "ethernet"
+#define NG_PPPOE_HOOK_PADI "PADI" /* default PADI requests come here */
+#define NG_PPPOE_HOOK_S_LEADIN "service" /* PADO responses from PADI */
+#define NG_PPPOE_HOOK_C_LEADIN "client" /* Connect message starts this */
+#define NG_PPPOE_HOOK_DEBUG "debug"
+
+/**********************************************************************
+ * Netgraph commands understood by this node type.
+ * FAIL, SUCCESS and CLOSE are sent by the node rather than received.
+ ********************************************************************/
+enum {
+ NGM_PPPOE_SET_FLAG = 1,
+ NGM_PPPOE_CONNECT = 2, /* Client, Try find this service */
+ NGM_PPPOE_LISTEN = 3, /* Server, Await a request for this service */
+ NGM_PPPOE_OFFER = 4, /* Server, hook X should respond (*) */
+ NGM_PPPOE_SUCCESS = 5, /* State machine connected */
+ NGM_PPPOE_FAIL = 6, /* State machine could not connect */
+ NGM_PPPOE_CLOSE = 7, /* Session closed down */
+ NGM_PPPOE_GET_STATUS
+};
+
+/***********************
+ * Structures passed in the various netgraph command messages.
+ ***********************/
+/* This structure is returned by the NGM_PPPOE_GET_STATUS command */
+struct ngPPPoEstat {
+ u_int packets_in; /* packets in from downstream */
+ u_int packets_out; /* packets out towards downstream */
+};
+
+/*
+ * When this structure is accepted by the NGM_PPPOE_CONNECT command :
+ * The data field is MANDATORY.
+ * The session sends out a PADI request for the named service.
+ *
+ *
+ * When this structure is accepted by the NGM_PPPOE_WAIT command.
+ * If no service is given this is assumed to accept ALL PADI requests.
+ * This may at some time take a regexp exporession, but not yet.
+ * Matching PADI requests will be passed up the named hook.
+ *
+ *
+ * When this structure is accepted by the NGM_PPPOE_OFFER command:
+ * The AC-NAme field is set from that given and a PADI
+ * packet is expected to arrive from the session control daemon, on the
+ * named hook. The session will then issue the appropriate PADO
+ * and begin negotiation.
+ */
+struct ngPPPoE_init_data {
+ char hook[NG_HOOKLEN + 1]; /* hook to monitor on */
+ u_int16_t data_len; /* Length of the service name */
+ char data[0]; /* init data goes here */
+};
+
+/*
+ * This structure is used by the asychronous success and failure messages.
+ * (to report which hook has failed or connected). The message is sent
+ * to whoever requested the connection. (close may use this too).
+ */
+struct ngPPPoE_req {
+ char hook[NG_HOOKLEN + 1]; /* hook associated with event session */
+};
+
+
+/********************************************************************
+ * Constants and definitions specific to PPPoE
+ ********************************************************************/
+
+#define PPPOE_TIMEOUT_LIMIT 64
+#define PPPOE_OFFER_TIMEOUT 16
+
+/* Codes to identify message types */
+#define PADI_CODE 0x09
+#define PADO_CODE 0x07
+#define PADR_CODE 0x19
+#define PADS_CODE 0x65
+#define PADT_CODE 0xa7
+
+/* Tag identifiers */
+#if BYTE_ORDER == BIG_ENDIAN
+#define PTT_EOL (0x0000)
+#define PTT_SRV_NAME (0x0101)
+#define PTT_AC_NAME (0x0102)
+#define PTT_HOST_UNIQ (0x0103)
+#define PTT_AC_COOKIE (0x0104)
+#define PTT_VENDOR (0x0105)
+#define PTT_RELAY_SID (0x0106)
+#define PTT_SRV_ERR (0x0201)
+#define PTT_SYS_ERR (0x0202)
+#define PTT_GEN_ERR (0x0203)
+
+#define ETHERTYPE_PPPOE_DISC 0x8863 /* PPPoE discovery packets */
+#define ETHERTYPE_PPPOE_SESS 0x8864 /* PPPoE session packets */
+#else
+#define PTT_EOL (0x0000)
+#define PTT_SRV_NAME (0x0101)
+#define PTT_AC_NAME (0x0201)
+#define PTT_HOST_UNIQ (0x0301)
+#define PTT_AC_COOKIE (0x0401)
+#define PTT_VENDOR (0x0501)
+#define PTT_RELAY_SID (0x0601)
+#define PTT_SRV_ERR (0x0102)
+#define PTT_SYS_ERR (0x0202)
+#define PTT_GEN_ERR (0x0302)
+
+#define ETHERTYPE_PPPOE_DISC 0x6388 /* PPPoE discovery packets */
+#define ETHERTYPE_PPPOE_SESS 0x6488 /* PPPoE session packets */
+#endif
+
+struct pppoe_tag {
+ u_int16_t tag_type;
+ u_int16_t tag_len;
+ char tag_data[0];
+}__attribute ((packed));
+
+struct pppoe_hdr{
+ u_int8_t ver:4;
+ u_int8_t type:4;
+ u_int8_t code;
+ u_int16_t sid;
+ u_int16_t length;
+ struct pppoe_tag tag[0];
+}__attribute__ ((packed));
+
+
+struct pppoe_full_hdr {
+ struct ether_header eh;
+ struct pppoe_hdr ph;
+}__attribute__ ((packed));
+
+union packet {
+ struct pppoe_full_hdr pkt_header;
+ u_int8_t bytes[2048];
+};
+
+struct datatag {
+ struct pppoe_tag hdr;
+ u_int8_t data[PPPOE_SERVICE_NAME_SIZE];
+};
+
+
+/*
+ * Define the order in which we will place tags in packets
+ * this may be ignored
+ */
+/* for PADI */
+#define TAGI_SVC 0
+#define TAGI_HUNIQ 1
+/* for PADO */
+#define TAGO_ACNAME 0
+#define TAGO_SVC 1
+#define TAGO_COOKIE 2
+#define TAGO_HUNIQ 3
+/* for PADR */
+#define TAGR_SVC 0
+#define TAGR_HUNIQ 1
+#define TAGR_COOKIE 2
+/* for PADS */
+#define TAGS_ACNAME 0
+#define TAGS_SVC 1
+#define TAGS_COOKIE 2
+#define TAGS_HUNIQ 3
+/* for PADT */
+
+#endif /* _NETGRAPH_PPPOE_H_ */
+
diff --git a/sys/netgraph/ng_rfc1490.c b/sys/netgraph/ng_rfc1490.c
new file mode 100644
index 0000000..3649476
--- /dev/null
+++ b/sys/netgraph/ng_rfc1490.c
@@ -0,0 +1,347 @@
+
+/*
+ * ng_rfc1490.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_rfc1490.c,v 1.19 1999/01/28 23:54:53 julian Exp $
+ */
+
+/*
+ * This node does RFC 1490 multiplexing.
+ *
+ * NOTE: RFC 1490 is updated by RFC 2427.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_rfc1490.h>
+
+/*
+ * DEFINITIONS
+ */
+
+/* Q.922 stuff -- see RFC 1490 */
+#define HDLC_UI 0x03
+
+#define NLPID_IP 0xCC
+#define NLPID_PPP 0xCF
+#define NLPID_SNAP 0x80
+#define NLPID_Q933 0x08
+#define NLPID_CLNP 0x81
+#define NLPID_ESIS 0x82
+#define NLPID_ISIS 0x83
+
+/* Node private data */
+struct private {
+ hook_p downlink;
+ hook_p ppp;
+ hook_p inet;
+};
+typedef struct private *priv_p;
+
+/* Netgraph node methods */
+static int ng_rfc1490_constructor(node_p * nodep);
+static int ng_rfc1490_rcvmsg(node_p node, struct ng_mesg * msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_rfc1490_rmnode(node_p node);
+static int ng_rfc1490_newhook(node_p node, hook_p hook, const char *name);
+static int ng_rfc1490_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_rfc1490_disconnect(hook_p hook);
+
+/* Node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_RFC1490_NODE_TYPE,
+ NULL,
+ ng_rfc1490_constructor,
+ ng_rfc1490_rcvmsg,
+ ng_rfc1490_rmnode,
+ ng_rfc1490_newhook,
+ NULL,
+ NULL,
+ ng_rfc1490_rcvdata,
+ ng_rfc1490_rcvdata,
+ ng_rfc1490_disconnect
+};
+NETGRAPH_INIT(rfc1490, &typestruct);
+
+/************************************************************************
+ NETGRAPH NODE STUFF
+ ************************************************************************/
+
+/*
+ * Node constructor
+ */
+static int
+ng_rfc1490_constructor(node_p *nodep)
+{
+ priv_p priv;
+ int error;
+
+ /* Allocate private structure */
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
+ if (priv == NULL)
+ return (ENOMEM);
+ bzero(priv, sizeof(*priv));
+
+ /* Call generic node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(priv, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = priv;
+
+ /* Done */
+ return (0);
+}
+
+/*
+ * Give our ok for a hook to be added
+ */
+static int
+ng_rfc1490_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p priv = node->private;
+
+ if (!strcmp(name, NG_RFC1490_HOOK_DOWNSTREAM)) {
+ if (priv->downlink)
+ return (EISCONN);
+ priv->downlink = hook;
+ } else if (!strcmp(name, NG_RFC1490_HOOK_PPP)) {
+ if (priv->ppp)
+ return (EISCONN);
+ priv->ppp = hook;
+ } else if (!strcmp(name, NG_RFC1490_HOOK_INET)) {
+ if (priv->inet)
+ return (EISCONN);
+ priv->inet = hook;
+ } else
+ return (EINVAL);
+ return (0);
+}
+
+/*
+ * Receive a control message. We don't support any special ones.
+ */
+static int
+ng_rfc1490_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *raddr, struct ng_mesg **rp)
+{
+ FREE(msg, M_NETGRAPH);
+ return (EINVAL);
+}
+
+/*
+ * Receive data on a hook and encapsulate according to RFC 1490.
+ * Only those nodes marked (*) are supported by this routine so far.
+ *
+ * Q.922 control
+ * |
+ * |
+ * --------------------------------------------
+ * | 0x03 |
+ * UI I Frame
+ * | |
+ * --------------------------------- --------------
+ * | 0x08 | 0x81 |0xCC |0xCF | 0x00 |..01.... |..10....
+ * | | | | | 0x80 | |
+ * Q.933 CLNP IP(*) PPP(*) SNAP ISO 8208 ISO 8208
+ * | (rfc1973) | Modulo 8 Modulo 128
+ * | |
+ * -------------------- OUI
+ * | | |
+ * L2 ID L3 ID -------------------------
+ * | User |00-80-C2 |00-00-00
+ * | specified | |
+ * | 0x70 PID Ethertype
+ * | | |
+ * ------------------- --------------... ----------
+ * |0x51 |0x4E | |0x4C |0x1 |0xB | |0x806 |
+ * | | | | | | | | |
+ * 7776 Q.922 Others 802.2 802.3 802.6 Others ARP(*) Others
+ *
+ *
+ */
+
+#define MAX_ENCAPS_HDR 8
+#define ERROUT(x) do { error = (x); goto done; } while (0)
+#define OUICMP(P,A,B,C) ((P)[0]==(A) && (P)[1]==(B) && (P)[2]==(C))
+
+static int
+ng_rfc1490_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const node_p node = hook->node;
+ const priv_p priv = node->private;
+ int error = 0;
+
+ if (hook == priv->downlink) {
+ u_char *start, *ptr;
+
+ if (!m || !(m = m_pullup(m, MAX_ENCAPS_HDR)))
+ ERROUT(ENOBUFS);
+ ptr = start = mtod(m, u_char *);
+
+ /* Must be UI frame */
+ if (*ptr++ != HDLC_UI)
+ ERROUT(0);
+
+ /* Eat optional zero pad byte */
+ if (*ptr == 0x00)
+ ptr++;
+
+ /* Multiplex on NLPID */
+ switch (*ptr++) {
+ case NLPID_SNAP:
+ if (OUICMP(ptr, 0, 0, 0)) { /* It's an ethertype */
+ u_int16_t etype;
+
+ ptr += 3;
+ etype = ntohs(*((u_int16_t *) ptr));
+ ptr += 2;
+ m_adj(m, ptr - start);
+ switch (etype) {
+ case ETHERTYPE_IP:
+ NG_SEND_DATA(error,
+ priv->inet, m, meta);
+ break;
+ case ETHERTYPE_ARP:
+ case ETHERTYPE_REVARP:
+ default:
+ ERROUT(0);
+ }
+ } else if (OUICMP(ptr, 0x00, 0x80, 0xc2)) /* 802.1 bridging */
+ ERROUT(0);
+ else /* Other weird stuff... */
+ ERROUT(0);
+ break;
+ case NLPID_IP:
+ m_adj(m, ptr - start);
+ NG_SEND_DATA(error, priv->inet, m, meta);
+ break;
+ case NLPID_PPP:
+ m_adj(m, ptr - start);
+ NG_SEND_DATA(error, priv->ppp, m, meta);
+ break;
+ case NLPID_Q933:
+ case NLPID_CLNP:
+ case NLPID_ESIS:
+ case NLPID_ISIS:
+ ERROUT(0);
+ default: /* Try PPP (see RFC 1973) */
+ ptr--; /* NLPID becomes PPP proto */
+ if ((*ptr & 0x01) == 0x01)
+ ERROUT(0);
+ m_adj(m, ptr - start);
+ NG_SEND_DATA(error, priv->ppp, m, meta);
+ break;
+ }
+ } else if (hook == priv->ppp) {
+ M_PREPEND(m, 2, M_DONTWAIT); /* Prepend PPP NLPID */
+ if (!m)
+ ERROUT(ENOBUFS);
+ mtod(m, u_char *)[0] = HDLC_UI;
+ mtod(m, u_char *)[1] = NLPID_PPP;
+ NG_SEND_DATA(error, priv->downlink, m, meta);
+ } else if (hook == priv->inet) {
+ M_PREPEND(m, 2, M_DONTWAIT); /* Prepend IP NLPID */
+ if (!m)
+ ERROUT(ENOBUFS);
+ mtod(m, u_char *)[0] = HDLC_UI;
+ mtod(m, u_char *)[1] = NLPID_IP;
+ NG_SEND_DATA(error, priv->downlink, m, meta);
+ } else
+ panic(__FUNCTION__);
+
+done:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * Nuke node
+ */
+static int
+ng_rfc1490_rmnode(node_p node)
+{
+ const priv_p priv = node->private;
+
+ /* Take down netgraph node */
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ bzero(priv, sizeof(*priv));
+ node->private = NULL;
+ ng_unref(node); /* let the node escape */
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ng_rfc1490_disconnect(hook_p hook)
+{
+ const priv_p priv = hook->node->private;
+
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ else if (hook == priv->downlink)
+ priv->downlink = NULL;
+ else if (hook == priv->inet)
+ priv->inet = NULL;
+ else if (hook == priv->ppp)
+ priv->ppp = NULL;
+ else
+ panic(__FUNCTION__);
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_rfc1490.h b/sys/netgraph/ng_rfc1490.h
new file mode 100644
index 0000000..98cdf63
--- /dev/null
+++ b/sys/netgraph/ng_rfc1490.h
@@ -0,0 +1,55 @@
+
+/*
+ * ng_rfc1490.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_rfc1490.h,v 1.7 1999/01/20 00:54:15 archie Exp $
+ */
+
+#ifndef _NETGRAPH_RFC1490_H_
+#define _NETGRAPH_RFC1490_H_
+
+/* Node type name */
+#define NG_RFC1490_NODE_TYPE "rfc1490"
+#define NGM_RFC1490_NODE_COOKIE 861060632
+
+/* Hook names */
+#define NG_RFC1490_HOOK_DOWNSTREAM "downstream"
+#define NG_RFC1490_HOOK_INET "inet"
+#define NG_RFC1490_HOOK_PPP "ppp"
+
+#endif /* _NETGRAPH_RFC1490_H_ */
diff --git a/sys/netgraph/ng_sample.c b/sys/netgraph/ng_sample.c
new file mode 100644
index 0000000..cef1977
--- /dev/null
+++ b/sys/netgraph/ng_sample.c
@@ -0,0 +1,441 @@
+
+/*
+ * ng_sample.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_sample.c,v 1.11 1999/01/28 23:54:54 julian Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_sample.h>
+#include <netgraph/netgraph.h>
+
+/*
+ * This section contains the netgraph method declarations for the
+ * sample node. These methods define the netgraph 'type'.
+ */
+
+static int ng_xxx_constructor(node_p *node);
+static int ng_xxx_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_xxx_rmnode(node_p node);
+static int ng_xxx_newhook(node_p node, hook_p hook, const char *name);
+static int ng_xxx_connect(hook_p hook);
+static int ng_xxx_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_xxx_rcvdataq(hook_p hook, struct mbuf *m, meta_p meta);
+static int ng_xxx_disconnect(hook_p hook);
+
+/* Netgraph node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_XXX_NODE_TYPE,
+ NULL,
+ ng_xxx_constructor,
+ ng_xxx_rcvmsg,
+ ng_xxx_rmnode,
+ ng_xxx_newhook,
+ NULL,
+ ng_xxx_connect,
+ ng_xxx_rcvdata,
+ ng_xxx_rcvdataq,
+ ng_xxx_disconnect
+};
+NETGRAPH_INIT(xxx, &typestruct);
+
+/* Information we store for each hook on each node */
+struct XXX_hookinfo {
+ int dlci; /* The DLCI it represents, -1 == downstream */
+ int channel; /* The channel representing this DLCI */
+ hook_p hook;
+};
+
+/* Information we store for each node */
+struct XXX {
+ struct XXX_hookinfo channel[XXX_NUM_DLCIS];
+ struct XXX_hookinfo downstream_hook;
+ node_p node; /* back pointer to node */
+ hook_p debughook;
+ u_int packets_in; /* packets in from downstream */
+ u_int packets_out; /* packets out towards downstream */
+ u_int32_t flags;
+};
+typedef struct XXX *xxx_p;
+
+/*
+ * Allocate the private data structure and the generic node
+ * and link them together.
+ *
+ * ng_make_node_common() returns with a generic node struct
+ * with a single reference for us.. we transfer it to the
+ * private structure.. when we free the private struct we must
+ * unref the node so it gets freed too.
+ *
+ * If this were a device node than this work would be done in the attach()
+ * routine and the constructor would return EINVAL as you should not be able
+ * to creatednodes that depend on hardware (unless you can add the hardware :)
+ */
+static int
+ng_xxx_constructor(node_p *nodep)
+{
+ xxx_p privdata;
+ int i, error;
+
+ /* Initialize private descriptor */
+ MALLOC(privdata, xxx_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK);
+ if (privdata == NULL)
+ return (ENOMEM);
+ bzero(privdata, sizeof(struct XXX));
+ for (i = 0; i < XXX_NUM_DLCIS; i++) {
+ privdata->channel[i].dlci = -2;
+ privdata->channel[i].channel = i;
+ }
+
+ /* Call the 'generic' (ie, superclass) node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(privdata, M_NETGRAPH);
+ return (error);
+ }
+
+ /* Link structs together; this counts as our one reference to *nodep */
+ (*nodep)->private = privdata;
+ privdata->node = *nodep;
+ return (0);
+}
+
+/*
+ * Give our ok for a hook to be added...
+ * If we are not running this might kick a device into life.
+ * Possibly decode information out of the hook name.
+ * Add the hook's private info to the hook structure.
+ * (if we had some). In this example, we assume that there is a
+ * an array of structs, called 'channel' in the private info,
+ * one for each active channel. The private
+ * pointer of each hook points to the appropriate XXX_hookinfo struct
+ * so that the source of an input packet is easily identified.
+ * (a dlci is a frame relay channel)
+ */
+static int
+ng_xxx_newhook(node_p node, hook_p hook, const char *name)
+{
+ const xxx_p xxxp = node->private;
+ const char *cp;
+ char c = '\0';
+ int digits = 0;
+ int dlci = 0;
+ int chan;
+
+#if 0
+ /* Possibly start up the device if it's not already going */
+ if ((xxxp->flags & SCF_RUNNING) == 0) {
+ ng_xxx_start_hardware(xxxp);
+ }
+#endif
+
+ /* Example of how one might use hooks with embedded numbers: All
+ * hooks start with 'dlci' and have a decimal trailing channel
+ * number up to 4 digits Use the leadin defined int he associated .h
+ * file. */
+ if (strncmp(name, NG_XXX_HOOK_DLCI_LEADIN, 4) == 0) {
+ cp = name + sizeof(NG_XXX_HOOK_DLCI_LEADIN);
+ while ((digits < 5)
+ && ((c = *cp++) > '0') && (c < '9')) {
+ dlci *= 10;
+ dlci += c - '0';
+ digits++;
+ }
+ if ((c != 0) || (digits == 5)
+ || (dlci <= 0) || (dlci > 1023))
+ return (EINVAL);
+ /* We have a dlci, now either find it, or allocate it */
+ for (chan = 0; chan < XXX_NUM_DLCIS; chan++)
+ if (xxxp->channel[chan].dlci == dlci)
+ break;
+ if (chan == XXX_NUM_DLCIS) {
+ for (chan = 0; chan < XXX_NUM_DLCIS; chan++)
+ if (xxxp->channel[chan].dlci != -2)
+ continue;
+ if (chan == XXX_NUM_DLCIS)
+ return (ENOBUFS);
+ }
+ if (xxxp->channel[chan].hook != NULL)
+ return (EADDRINUSE);
+ hook->private = xxxp->channel + chan;
+ xxxp->channel[chan].hook = hook;
+ return (0);
+ } else if (strcmp(name, NG_XXX_HOOK_DOWNSTREAM) == 0) {
+ /* Example of simple predefined hooks. */
+ /* do something specific to the downstream connection */
+ xxxp->downstream_hook.hook = hook;
+ hook->private = &xxxp->downstream_hook;
+ } else if (strcmp(name, NG_XXX_HOOK_DEBUG) == 0) {
+ /* do something specific to a debug connection */
+ xxxp->debughook = hook;
+ hook->private = NULL;
+ } else
+ return (EINVAL); /* not a hook we know about */
+ return(0);
+}
+
+/*
+ * Get a netgraph control message.
+ * Check it is one we understand. If needed, send a response.
+ * We could save the address for an async action later, but don't here.
+ * Always free the message.
+ * The response should be in a malloc'd region that the caller can 'free'.
+ * A response is not required.
+ * Theoretically you could respond defferently to old message types if
+ * the cookie in the header didn't match what we consider to be current
+ * (so that old userland programs could continue to work).
+ */
+static int
+ng_xxx_rcvmsg(node_p node,
+ struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr)
+{
+ const xxx_p xxxp = node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ /* Deal with message according to cookie and command */
+ switch (msg->header.typecookie) {
+ case NGM_XXX_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_XXX_GET_STATUS:
+ {
+ struct ngxxxstat *stats;
+
+ NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT);
+ if (!resp) {
+ error = ENOMEM;
+ break;
+ }
+ stats = (struct ngxxxstat *) resp->data;
+ stats->packets_in = xxxp->packets_in;
+ stats->packets_out = xxxp->packets_out;
+ break;
+ }
+ case NGM_XXX_SET_FLAG:
+ if (msg->header.arglen != sizeof(u_int32_t)) {
+ error = EINVAL;
+ break;
+ }
+ xxxp->flags = *((u_int32_t *) msg->data);
+ break;
+ default:
+ error = EINVAL; /* unknown command */
+ break;
+ }
+ break;
+ default:
+ error = EINVAL; /* unknown cookie type */
+ break;
+ }
+
+ /* Take care of synchronous response, if any */
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+ /* Free the message and return */
+ FREE(msg, M_NETGRAPH);
+ return(error);
+}
+
+/*
+ * Receive data, and do something with it.
+ * Possibly send it out on another link after processing.
+ * Possibly do something different if it comes from different
+ * hooks. the caller will never free m or meta, so
+ * if we use up this data or abort we must free BOTH of these.
+ *
+ * If we want, we may decide to force this data to be queued and reprocessed
+ * at the netgraph NETISR time. (at which time it will be entered using ng_xxx_rcvdataq().
+ */
+static int
+ng_xxx_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ int dlci = -2;
+ int error;
+
+ if (hook->private) {
+ /*
+ * If it's dlci 1023, requeue it so that it's handled at a lower priority.
+ * This is how a node decides to defer a data message.
+ */
+ dlci = ((struct XXX_hookinfo *) hook->private)->dlci;
+ if (dlci == 1023) {
+ ng_queue_data(hook->peer, m, meta);
+ }
+ }
+ ng_xxx_rcvdataq(hook, m, meta);
+}
+
+/*
+ * Always accept the data. This version of rcvdata is called from the dequeueing routine.
+ */
+static int
+ng_xxx_rcvdataq(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const xxx_p xxxp = hook->node->private;
+ int chan = -2;
+ int dlci = -2;
+ int error;
+
+ if (hook->private) {
+ dlci = ((struct XXX_hookinfo *) hook->private)->dlci;
+ chan = ((struct XXX_hookinfo *) hook->private)->channel;
+ if (dlci != -1) {
+ /* If received on a DLCI hook process for this
+ * channel and pass it to the downstream module.
+ * Normally one would add a multiplexing header at
+ * the front here */
+ /* M_PREPEND(....) ; */
+ /* mtod(m, xxxxxx)->dlci = dlci; */
+ error = ng_send_data(xxxp->downstream_hook.hook,
+ m, meta);
+ xxxp->packets_out++;
+ } else {
+ /* data came from the multiplexed link */
+ dlci = 1; /* get dlci from header */
+ /* madjust(....) *//* chop off header */
+ for (chan = 0; chan < XXX_NUM_DLCIS; chan++)
+ if (xxxp->channel[chan].dlci == dlci)
+ break;
+ if (chan == XXX_NUM_DLCIS) {
+ NG_FREE_DATA(m, meta);
+ return (ENETUNREACH);
+ }
+ /* If we were called at splnet, use the following:
+ * NG_SEND_DATA(error, otherhook, m, meta); if this
+ * node is running at some SPL other than SPLNET
+ * then you should use instead: error =
+ * ng_queueit(otherhook, m, meta); m = NULL: meta =
+ * NULL; this queues the data using the standard
+ * NETISR system and schedules the data to be picked
+ * up again once the system has moved to SPLNET and
+ * the processing of the data can continue. after
+ * these are run 'm' and 'meta' should be considered
+ * as invalid and NG_SEND_DATA actually zaps them. */
+ NG_SEND_DATA(error, xxxp->channel[chan].hook, m, meta);
+ xxxp->packets_in++;
+ }
+ } else {
+ /* It's the debug hook, throw it away.. */
+ if (hook == xxxp->downstream_hook.hook)
+ NG_FREE_DATA(m, meta);
+ }
+ return 0;
+}
+
+#if 0
+/*
+ * If this were a device node, the data may have been received in response
+ * to some interrupt.
+ * in which case it would probably look as follows:
+ */
+devintr()
+{
+ meta_p meta = NULL; /* whatever metadata we might imagine goes
+ * here */
+
+ /* get packet from device and send on */
+ m = MGET(blah blah)
+ error = ng_queueit(upstream, m, meta); /* see note above in
+ * xxx_rcvdata() */
+}
+
+#endif /* 0 */
+
+/*
+ * Do local shutdown processing..
+ * If we are a persistant device, we might refuse to go away, and
+ * we'd only remove our links and reset ourself.
+ */
+static int
+ng_xxx_rmnode(node_p node)
+{
+ const xxx_p privdata = node->private;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+#ifndef PERSISTANT_NODE
+ ng_unname(node);
+ node->private = NULL;
+ ng_unref(privdata->node);
+ FREE(privdata, M_NETGRAPH);
+#else
+ privdata->packets_in = 0; /* reset stats */
+ privdata->packets_out = 0;
+ node->flags &= ~NG_INVALID; /* reset invalid flag */
+#endif /* PERSISTANT_NODE */
+ return (0);
+}
+
+/*
+ * This is called once we've already connected a new hook to the other node.
+ * It gives us a chance to balk at the last minute.
+ */
+static int
+ng_xxx_connect(hook_p hook)
+{
+ /* be really amiable and just say "YUP that's OK by me! " */
+ return (0);
+}
+
+/*
+ * Dook disconnection
+ *
+ * For this type, removal of the last link destroys the node
+ */
+static int
+ng_xxx_disconnect(hook_p hook)
+{
+ if (hook->private)
+ ((struct XXX_hookinfo *) (hook->private))->hook == NULL;
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_sample.h b/sys/netgraph/ng_sample.h
new file mode 100644
index 0000000..5d2df45
--- /dev/null
+++ b/sys/netgraph/ng_sample.h
@@ -0,0 +1,75 @@
+
+/*
+ * ng_sample.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_sample.h,v 1.3 1999/01/20 00:22:14 archie Exp $
+ */
+
+#ifndef _NETGRAPH_SAMPLE_H_
+#define _NETGRAPH_SAMPLE_H_
+
+/* Node type name. This should be unique among all netgraph node types */
+#define NG_XXX_NODE_TYPE "sample"
+
+/* Node type cookie. Should also be unique. This value MUST change whenever
+ an incompatible change is made to this header file, to insure consistency.
+ The de facto method for generating cookies is to take the output of the
+ date command: date -u +'%s' */
+#define NGM_XXX_COOKIE 915491374
+
+/* Number of active DLCI's we can handle */
+#define XXX_NUM_DLCIS 16
+
+/* Hook names */
+#define NG_XXX_HOOK_DLCI_LEADIN "dlci"
+#define NG_XXX_HOOK_DOWNSTREAM "downstream"
+#define NG_XXX_HOOK_DEBUG "debug"
+
+/* Netgraph commands understood by this node type */
+enum {
+ NGM_XXX_SET_FLAG = 1,
+ NGM_XXX_GET_STATUS,
+};
+
+/* This structure is returned by the NGM_XXX_GET_STATUS command */
+struct ngxxxstat {
+ u_int packets_in; /* packets in from downstream */
+ u_int packets_out; /* packets out towards downstream */
+};
+
+#endif /* _NETGRAPH_SAMPLE_H_ */
diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c
new file mode 100644
index 0000000..b8ba80b
--- /dev/null
+++ b/sys/netgraph/ng_socket.c
@@ -0,0 +1,957 @@
+
+/*
+ * ng_socket.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_socket.c,v 1.25 1999/01/28 23:54:54 julian Exp $
+ */
+
+/*
+ * Netgraph socket nodes
+ *
+ * There are two types of netgraph sockets, control and data.
+ * Control sockets have a netgraph node, but data sockets are
+ * parasitic on control sockets, and have no node of their own.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/domain.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#ifdef NOTYET
+#include <sys/vnode.h>
+#endif
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_socket.h>
+#include <netgraph/ng_socketvar.h>
+
+/*
+ * It's Ascii-art time!
+ * +-------------+ +-------------+
+ * |socket (ctl)| |socket (data)|
+ * +-------------+ +-------------+
+ * ^ ^
+ * | |
+ * v v
+ * +-----------+ +-----------+
+ * |pcb (ctl)| |pcb (data)|
+ * +-----------+ +-----------+
+ * ^ ^
+ * | |
+ * v v
+ * +--------------------------+
+ * | Socket type private |
+ * | data |
+ * +--------------------------+
+ * ^
+ * |
+ * v
+ * +----------------+
+ * | struct ng_node |
+ * +----------------+
+ */
+
+/* Netgraph node methods */
+static int ngs_constructor(node_p *nodep);
+static int ngs_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngs_rmnode(node_p node);
+static int ngs_newhook(node_p node, hook_p hook, const char *name);
+static int ngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+
+/* Internal methods */
+static int ng_attach_data(struct socket *so);
+static int ng_attach_cntl(struct socket *so);
+static int ng_attach_common(struct socket *so, int type);
+static void ng_detach_common(struct ngpcb *pcbp, int type);
+/*static int ng_internalize(struct mbuf *m, struct proc *p); */
+
+static int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
+static int ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp);
+static int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
+
+static int ngs_mod_event(module_t mod, int event, void *data);
+static int ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg,
+ struct sockaddr_ng *addr);
+
+/* Netgraph type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_SOCKET_NODE_TYPE,
+ ngs_mod_event,
+ ngs_constructor,
+ ngs_rcvmsg,
+ ngs_rmnode,
+ ngs_newhook,
+ NULL,
+ NULL,
+ ngs_rcvdata,
+ ngs_rcvdata,
+ NULL,
+};
+NETGRAPH_INIT(socket, &typestruct);
+
+/* Buffer space */
+static u_long ngpdg_sendspace = 2 * 1024; /* really max datagram size */
+static u_long ngpdg_recvspace = 20 * 1024;
+
+/* List of all sockets */
+LIST_HEAD(, ngpcb) ngsocklist;
+
+#define sotongpcb(so) ((struct ngpcb *)so->so_pcb)
+
+/* If getting unexplained errors returned, set this to "Debugger("X"); */
+#ifndef TRAP_ERROR
+#define TRAP_ERROR
+#endif
+
+/***************************************************************
+ Control sockets
+***************************************************************/
+
+static int
+ngc_attach(struct socket *so, int proto, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp != NULL)
+ return (EISCONN);
+ return (ng_attach_cntl(so));
+}
+
+static int
+ngc_detach(struct socket *so)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp == NULL)
+ return (EINVAL);
+ ng_detach_common(pcbp, NG_CONTROL);
+ return (0);
+}
+
+static int
+ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
+ struct mbuf *control, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+ struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
+ struct ng_mesg *resp;
+ struct mbuf *m0;
+ char *msg, *path = NULL;
+ int len, error = 0;
+
+ if (pcbp == NULL) {
+ error = EINVAL;
+ goto release;
+ }
+#ifdef NOTYET
+ if (control && (error = ng_internalize(control, p))) {
+ if (pcbp->sockdata == NULL) {
+ error = ENOTCONN;
+ goto release;
+ }
+ }
+#else /* NOTYET */
+ if (control) {
+ error = EINVAL;
+ goto release;
+ }
+#endif /* NOTYET */
+
+ /* Require destination as there may be >= 1 hooks on this node */
+ if (addr == NULL) {
+ error = EDESTADDRREQ;
+ goto release;
+ }
+
+ /* Allocate an expendable buffer for the path, chop off
+ * the sockaddr header, and make sure it's NUL terminated */
+ len = sap->sg_len - 2;
+ MALLOC(path, char *, len + 1, M_NETGRAPH, M_WAITOK);
+ if (path == NULL) {
+ error = ENOMEM;
+ goto release;
+ }
+ bcopy(sap->sg_data, path, len);
+ path[len] = '\0';
+
+ /* Move the actual message out of mbufs into a linear buffer.
+ * Start by adding up the size of the data. (could use mh_len?) */
+ for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next)
+ len += m0->m_len;
+
+ /* Move the data into a linear buffer as well. Messages are not
+ * delivered in mbufs. */
+ MALLOC(msg, char *, len + 1, M_NETGRAPH, M_WAITOK);
+ if (msg == NULL) {
+ error = ENOMEM;
+ goto release;
+ }
+ m_copydata(m, 0, len, msg);
+
+ /* The callee will free the msg when done. The addr is our business. */
+ error = ng_send_msg(pcbp->sockdata->node,
+ (struct ng_mesg *) msg, path, &resp);
+
+ /* If the callee responded with a synchronous response, then put it
+ * back on the receive side of the socket; sap is source address. */
+ if (error == 0 && resp != NULL)
+ error = ship_msg(pcbp, resp, sap);
+
+release:
+ if (path != NULL)
+ FREE(path, M_NETGRAPH);
+ if (control != NULL)
+ m_freem(control);
+ if (m != NULL)
+ m_freem(m);
+ return (error);
+}
+
+static int
+ngc_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp == 0)
+ return (EINVAL);
+ return (ng_bind(nam, pcbp));
+}
+
+static int
+ngc_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp == 0)
+ return (EINVAL);
+ return (ng_connect_cntl(nam, pcbp));
+}
+
+/***************************************************************
+ Data sockets
+***************************************************************/
+
+static int
+ngd_attach(struct socket *so, int proto, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp != NULL)
+ return (EISCONN);
+ return (ng_attach_data(so));
+}
+
+static int
+ngd_detach(struct socket *so)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp == NULL)
+ return (EINVAL);
+ ng_detach_common(pcbp, NG_DATA);
+ return (0);
+}
+
+static int
+ngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
+ struct mbuf *control, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+ struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr;
+ char *hookname = NULL;
+ meta_p mp = NULL;
+ int len, error;
+ hook_p hook;
+
+ if ((pcbp == NULL) || (control != NULL)) {
+ error = EINVAL;
+ goto release;
+ }
+ if (pcbp->sockdata == NULL) {
+ error = ENOTCONN;
+ goto release;
+ }
+ if (addr == NULL) {
+ error = EDESTADDRREQ;
+ goto release;
+ }
+
+ /* Allocate an expendable buffer for the hook name, chop off
+ * the sockaddr header, and make sure it's NUL terminated */
+ len = sap->sg_len - 2;
+ MALLOC(hookname, char *, len + 1, M_NETGRAPH, M_WAITOK);
+ if (hookname == NULL) {
+ error = ENOMEM;
+ goto release;
+ }
+ bcopy(sap->sg_data, hookname, len);
+ hookname[len] = '\0';
+
+ /* Find the correct hook from 'hookname' */
+ LIST_FOREACH(hook, &pcbp->sockdata->node->hooks, hooks) {
+ if (strcmp(hookname, hook->name) == 0)
+ break;
+ }
+
+ /* Send data (OK if hook is NULL) */
+ NG_SEND_DATA(error, hook, m, mp); /* makes m NULL */
+
+release:
+ if (hookname != NULL)
+ FREE(hookname, M_NETGRAPH);
+ if (control != NULL)
+ m_freem(control);
+ if (m != NULL)
+ m_freem(m);
+ return (error);
+}
+
+static int
+ngd_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+
+ if (pcbp == 0)
+ return (EINVAL);
+ return (ng_connect_data(nam, pcbp));
+}
+
+/*
+ * Used for both data and control sockets
+ */
+static int
+ng_setsockaddr(struct socket *so, struct sockaddr **addr)
+{
+ struct ngpcb *const pcbp = sotongpcb(so);
+ struct sockaddr *sa;
+ int namelen;
+
+ if (pcbp == 0)
+ return (EINVAL);
+ if (pcbp->sockdata->node->name != NULL) {
+ namelen = strlen(pcbp->sockdata->node->name) + 3;
+ MALLOC(sa, struct sockaddr *, namelen, M_SONAME, M_WAITOK);
+ if (sa == NULL)
+ return (ENOMEM);
+ sa->sa_family = AF_NETGRAPH;
+ sa->sa_len = namelen;
+ strcpy(sa->sa_data, pcbp->sockdata->node->name);
+ *addr = sa;
+ } else
+ *addr = NULL; /* XXX check this makes sense */
+ return (0);
+}
+
+/*
+ * Attach a socket to it's protocol specific partner.
+ * For a control socket, actually create a netgraph node and attach
+ * to it as well.
+ */
+
+static int
+ng_attach_cntl(struct socket *so)
+{
+ struct ngsock *privdata;
+ struct ngpcb *pcbp;
+ int error;
+
+ /* Setup protocol control block */
+ if ((error = ng_attach_common(so, NG_CONTROL)) != 0)
+ return (error);
+ pcbp = (struct ngpcb *) so->so_pcb;
+
+ /* Allocate node private info */
+ MALLOC(privdata, struct ngsock *,
+ sizeof(*privdata), M_NETGRAPH, M_WAITOK);
+ if (privdata == NULL) {
+ ng_detach_common(pcbp, NG_CONTROL);
+ return (ENOMEM);
+ }
+ bzero(privdata, sizeof(*privdata));
+
+ /* Make the generic node components */
+ if ((error = ng_make_node_common(&typestruct, &privdata->node)) != 0) {
+ FREE(privdata, M_NETGRAPH);
+ ng_detach_common(pcbp, NG_CONTROL);
+ return (error);
+ }
+ privdata->node->private = privdata;
+
+ /* Link the pcb and the node private data */
+ privdata->ctlsock = pcbp;
+ pcbp->sockdata = privdata;
+ privdata->refs++;
+ return (0);
+}
+
+static int
+ng_attach_data(struct socket *so)
+{
+ return(ng_attach_common(so, NG_DATA));
+}
+
+/*
+ * Set up a socket protocol control block.
+ * This code is shared between control and data sockets.
+ */
+static int
+ng_attach_common(struct socket *so, int type)
+{
+ struct ngpcb *pcbp;
+ int error;
+
+ /* Standard socket setup stuff */
+ error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace);
+ if (error)
+ return (error);
+
+ /* Allocate the pcb */
+ MALLOC(pcbp, struct ngpcb *, sizeof(*pcbp), M_PCB, M_WAITOK);
+ if (pcbp == NULL)
+ return (ENOMEM);
+ bzero(pcbp, sizeof(*pcbp));
+ pcbp->type = type;
+
+ /* Link the pcb and the socket */
+ so->so_pcb = (caddr_t) pcbp;
+ pcbp->ng_socket = so;
+
+ /* Add the socket to linked list */
+ LIST_INSERT_HEAD(&ngsocklist, pcbp, socks);
+ return (0);
+}
+
+/*
+ * Disassociate the socket from it's protocol specific
+ * partner. If it's attached to a node's private data structure,
+ * then unlink from that too. If we were the last socket attached to it,
+ * then shut down the entire node. Shared code for control and data sockets.
+ */
+static void
+ng_detach_common(struct ngpcb *pcbp, int which)
+{
+ struct ngsock *sockdata;
+
+ if (pcbp->sockdata) {
+ sockdata = pcbp->sockdata;
+ pcbp->sockdata = NULL;
+ switch (which) {
+ case NG_CONTROL:
+ sockdata->ctlsock = NULL;
+ break;
+ case NG_DATA:
+ sockdata->datasock = NULL;
+ break;
+ default:
+ panic(__FUNCTION__);
+ }
+ if ((--sockdata->refs == 0) && (sockdata->node != NULL))
+ ng_rmnode(sockdata->node);
+ }
+ pcbp->ng_socket->so_pcb = NULL;
+ pcbp->ng_socket = NULL;
+ LIST_REMOVE(pcbp, socks);
+ FREE(pcbp, M_PCB);
+}
+
+#ifdef NOTYET
+/*
+ * File descriptors can be passed into a AF_NETGRAPH socket.
+ * Note, that file descriptors cannot be passed OUT.
+ * Only character device descriptors are accepted.
+ * Character devices are useful to connect a graph to a device,
+ * which after all is the purpose of this whole system.
+ */
+static int
+ng_internalize(struct mbuf *control, struct proc *p)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct cmsghdr *cm = mtod(control, struct cmsghdr *);
+ struct file *fp;
+ struct vnode *vn;
+ int oldfds;
+ int fd;
+
+ if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
+ cm->cmsg_len != control->m_len) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Check there is only one FD. XXX what would more than one signify? */
+ oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
+ if (oldfds != 1) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Check that the FD given is legit. and change it to a pointer to a
+ * struct file. */
+ fd = *(int *) (cm + 1);
+ if ((unsigned) fd >= fdp->fd_nfiles
+ || (fp = fdp->fd_ofiles[fd]) == NULL) {
+ return (EBADF);
+ }
+
+ /* Depending on what kind of resource it is, act differently. For
+ * devices, we treat it as a file. For a AF_NETGRAPH socket,
+ * shortcut straight to the node. */
+ switch (fp->f_type) {
+ case DTYPE_VNODE:
+ vn = (struct vnode *) fp->f_data;
+ if (vn && (vn->v_type == VCHR)) {
+ /* for a VCHR, actually reference the FILE */
+ fp->f_count++;
+ /* XXX then what :) */
+ /* how to pass on to other modules? */
+ } else {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ break;
+ default:
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ return (0);
+}
+#endif /* NOTYET */
+
+/*
+ * Connect the data socket to a named control socket node.
+ */
+static int
+ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp)
+{
+ struct sockaddr_ng *sap;
+ node_p farnode;
+ struct ngsock *sockdata;
+ int error;
+
+ /* If we are already connected, don't do it again */
+ if (pcbp->sockdata != NULL)
+ return (EISCONN);
+
+ /* Find the target (victim) and check it doesn't already have a data
+ * socket. Also check it is a 'socket' type node. */
+ sap = (struct sockaddr_ng *) nam;
+ if ((error = ng_path2node(NULL, sap->sg_data, &farnode, NULL)))
+ return (error);
+
+ if (strcmp(farnode->type->name, NG_SOCKET_NODE_TYPE) != 0)
+ return (EINVAL);
+ sockdata = farnode->private;
+ if (sockdata->datasock != NULL)
+ return (EADDRINUSE);
+
+ /* Link the PCB and the private data struct. and note the extra
+ * reference */
+ sockdata->datasock = pcbp;
+ pcbp->sockdata = sockdata;
+ sockdata->refs++;
+ return (0);
+}
+
+/*
+ * Connect the existing control socket node to a named node:hook.
+ * The hook we use on this end is the same name as the remote node name.
+ */
+static int
+ng_connect_cntl(struct sockaddr *nam, struct ngpcb *pcbp)
+{
+ struct ngsock *const sockdata = pcbp->sockdata;
+ struct sockaddr_ng *sap;
+ char *node, *hook;
+ node_p farnode;
+ int rtn, error;
+
+ sap = (struct sockaddr_ng *) nam;
+ rtn = ng_path_parse(sap->sg_data, &node, NULL, &hook);
+ if (rtn < 0 || node == NULL || hook == NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ farnode = ng_findname(sockdata->node, node);
+ if (farnode == NULL) {
+ TRAP_ERROR;
+ return (EADDRNOTAVAIL);
+ }
+
+ /* Connect, using a hook name the same as the far node name. */
+ error = ng_con_nodes(sockdata->node, node, farnode, hook);
+ return error;
+}
+
+/*
+ * Binding a socket means giving the corresponding node a name
+ */
+static int
+ng_bind(struct sockaddr *nam, struct ngpcb *pcbp)
+{
+ struct ngsock *const sockdata = pcbp->sockdata;
+ struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam;
+
+ if (sockdata == NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ if (sap->sg_len < 3 || sap->sg_data[sap->sg_len - 3] != '\0') {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+ return (ng_name_node(sockdata->node, sap->sg_data));
+}
+
+/*
+ * Take a message and pass it up to the control socket associated
+ * with the node.
+ */
+static int
+ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr)
+{
+ struct socket *const so = pcbp->ng_socket;
+ struct mbuf *mdata;
+ int msglen;
+
+ /* Copy the message itself into an mbuf chain */
+ msglen = sizeof(struct ng_mesg) + msg->header.arglen;
+ mdata = m_devget((caddr_t) msg, msglen, 0, NULL, NULL);
+
+ /* Here we free the message, as we are the end of the line.
+ * We need to do that regardless of whether we got mbufs. */
+ FREE(msg, M_NETGRAPH);
+
+ if (mdata == NULL) {
+ TRAP_ERROR;
+ return (ENOBUFS);
+ }
+
+ /* Send it up to the socket */
+ if (sbappendaddr(&so->so_rcv,
+ (struct sockaddr *) addr, mdata, NULL) == 0) {
+ TRAP_ERROR;
+ m_freem(mdata);
+ return (ENOBUFS);
+ }
+ sorwakeup(so);
+ return (0);
+}
+
+/*
+ * You can only create new nodes from the socket end of things.
+ */
+static int
+ngs_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * We allow any hook to be connected to the node.
+ * There is no per-hook private information though.
+ */
+static int
+ngs_newhook(node_p node, hook_p hook, const char *name)
+{
+ hook->private = node->private;
+ return (0);
+}
+
+/*
+ * Incoming messages get passed up to the control socket.
+ */
+static int
+ngs_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **resp)
+{
+ struct ngsock *const sockdata = node->private;
+ struct ngpcb *const pcbp = sockdata->ctlsock;
+ struct sockaddr_ng *addr;
+ int addrlen;
+ int error = 0;
+
+ /* Only allow mesgs to be passed if we have the control socket.
+ * Data sockets can only support the generic messages. */
+ if (pcbp == NULL) {
+ TRAP_ERROR;
+ return (EINVAL);
+ }
+
+ /* Get the return address into a sockaddr */
+ if ((retaddr == NULL) || (*retaddr == '\0'))
+ retaddr = "";
+ addrlen = strlen(retaddr);
+ MALLOC(addr, struct sockaddr_ng *, addrlen + 4, M_NETGRAPH, M_NOWAIT);
+ if (addr == NULL) {
+ TRAP_ERROR;
+ return (ENOMEM);
+ }
+ addr->sg_len = addrlen + 3;
+ addr->sg_family = AF_NETGRAPH;
+ bcopy(retaddr, addr->sg_data, addrlen);
+ addr->sg_data[addrlen] = '\0';
+
+ /* Send it up */
+ error = ship_msg(pcbp, msg, addr);
+ FREE(addr, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Receive data on a hook
+ */
+static int
+ngs_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ struct ngsock *const sockdata = hook->node->private;
+ struct ngpcb *const pcbp = sockdata->datasock;
+ struct socket *so;
+ struct sockaddr_ng *addr;
+ char *addrbuf[NG_HOOKLEN + 1 + 4];
+ int addrlen;
+
+ /* If there is no data socket, black-hole it */
+ if (pcbp == NULL) {
+ NG_FREE_DATA(m, meta);
+ return (0);
+ }
+ so = pcbp->ng_socket;
+
+ /* Get the return address into a sockaddr. */
+ addrlen = strlen(hook->name); /* <= NG_HOOKLEN */
+ addr = (struct sockaddr_ng *) addrbuf;
+ addr->sg_len = addrlen + 3;
+ addr->sg_family = AF_NETGRAPH;
+ bcopy(hook->name, addr->sg_data, addrlen);
+ addr->sg_data[addrlen] = '\0';
+
+ /* We have no use for the meta data, free/clear it now. */
+ NG_FREE_META(meta);
+
+ /* Try to tell the socket which hook it came in on */
+ if (sbappendaddr(&so->so_rcv, (struct sockaddr *) addr, m, NULL) == 0) {
+ m_freem(m);
+ TRAP_ERROR;
+ return (ENOBUFS);
+ }
+ sorwakeup(so);
+ return (0);
+}
+
+/*
+ * Do local shutdown processing.
+ * In this case, that involves making sure the socket
+ * knows we should be shutting down.
+ */
+static int
+ngs_rmnode(node_p node)
+{
+ struct ngsock *const sockdata = node->private;
+ struct ngpcb *const dpcbp = sockdata->datasock;
+ struct ngpcb *const pcbp = sockdata->ctlsock;
+
+ ng_cutlinks(node);
+ ng_unname(node);
+
+ if (dpcbp != NULL) {
+ soisdisconnected(dpcbp->ng_socket);
+ dpcbp->sockdata = NULL;
+ sockdata->datasock = NULL;
+ sockdata->refs--;
+ }
+ if (pcbp != NULL) {
+ soisdisconnected(pcbp->ng_socket);
+ pcbp->sockdata = NULL;
+ sockdata->ctlsock = NULL;
+ sockdata->refs--;
+ }
+ node->private = NULL;
+ ng_unref(node);
+ FREE(sockdata, M_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Control and data socket type descriptors
+ */
+
+static struct pr_usrreqs ngc_usrreqs = {
+ NULL, /* abort */
+ pru_accept_notsupp,
+ ngc_attach,
+ ngc_bind,
+ ngc_connect,
+ pru_connect2_notsupp,
+ pru_control_notsupp,
+ ngc_detach,
+ NULL, /* disconnect */
+ pru_listen_notsupp,
+ NULL, /* setpeeraddr */
+ pru_rcvd_notsupp,
+ pru_rcvoob_notsupp,
+ ngc_send,
+ pru_sense_null,
+ NULL, /* shutdown */
+ ng_setsockaddr,
+ sosend,
+ soreceive,
+ sopoll
+};
+
+static struct pr_usrreqs ngd_usrreqs = {
+ NULL, /* abort */
+ pru_accept_notsupp,
+ ngd_attach,
+ NULL, /* bind */
+ ngd_connect,
+ pru_connect2_notsupp,
+ pru_control_notsupp,
+ ngd_detach,
+ NULL, /* disconnect */
+ pru_listen_notsupp,
+ NULL, /* setpeeraddr */
+ pru_rcvd_notsupp,
+ pru_rcvoob_notsupp,
+ ngd_send,
+ pru_sense_null,
+ NULL, /* shutdown */
+ ng_setsockaddr,
+ sosend,
+ soreceive,
+ sopoll
+};
+
+/*
+ * Definitions of protocols supported in the NETGRAPH domain.
+ */
+
+extern struct domain ngdomain; /* stop compiler warnings */
+
+static struct protosw ngsw[] = {
+ {
+ SOCK_DGRAM,
+ &ngdomain,
+ NG_CONTROL,
+ PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */,
+ 0, 0, 0, 0,
+ NULL,
+ 0, 0, 0, 0,
+ &ngc_usrreqs
+ },
+ {
+ SOCK_DGRAM,
+ &ngdomain,
+ NG_DATA,
+ PR_ATOMIC | PR_ADDR,
+ 0, 0, 0, 0,
+ NULL,
+ 0, 0, 0, 0,
+ &ngd_usrreqs
+ }
+};
+
+struct domain ngdomain = {
+ AF_NETGRAPH,
+ "netgraph",
+ 0,
+ NULL,
+ NULL,
+ ngsw,
+ &ngsw[sizeof(ngsw) / sizeof(ngsw[0])],
+ 0,
+ NULL,
+ 0,
+ 0
+};
+
+/*
+ * Handle loading and unloading for this node type
+ * This is to handle auxiliary linkages (e.g protocol domain addition).
+ */
+static int
+ngs_mod_event(module_t mod, int event, void *data)
+{
+ int error = 0;
+
+ switch (event) {
+ case MOD_LOAD:
+ /* Register protocol domain */
+ net_add_domain(&ngdomain);
+ break;
+ case MOD_UNLOAD:
+ /* Insure there are no open netgraph sockets */
+ if (!LIST_EMPTY(&ngsocklist)) {
+ error = EBUSY;
+ break;
+ }
+
+#ifdef NOTYET
+ /* Unregister protocol domain XXX can't do this yet.. */
+ if ((error = net_rm_domain(&ngdomain)) != 0)
+ break;
+#else
+ error = EBUSY;
+#endif
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
+
+SYSCTL_NODE(_net, AF_NETGRAPH, graph, CTLFLAG_RW, 0, "netgraph Family");
+SYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, "");
+SYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA");
+SYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, "");
+SYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL");
+SYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, "");
+
diff --git a/sys/netgraph/ng_socket.h b/sys/netgraph/ng_socket.h
new file mode 100644
index 0000000..a84d12a
--- /dev/null
+++ b/sys/netgraph/ng_socket.h
@@ -0,0 +1,62 @@
+
+/*
+ * ng_socket.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_socket.h,v 1.5 1999/01/20 00:22:14 archie Exp $
+ */
+
+#ifndef _NETGRAPH_NG_SOCKET_H_
+#define _NETGRAPH_NG_SOCKET_H_ 1
+
+/* Netgraph node type name and cookie */
+#define NG_SOCKET_NODE_TYPE "socket"
+#define NGM_SOCKET_COOKIE 851601233
+
+/* Netgraph socket(2) constants */
+#define NG_DATA 1
+#define NG_CONTROL 2
+
+/* Netgraph version of struct sockaddr */
+struct sockaddr_ng {
+ u_char sg_len; /* total length */
+ u_char sg_family; /* address family */
+ char sg_data[14]; /* actually longer; address value */
+};
+
+#endif /* _NETGRAPH_NG_SOCKET_H_ */
+
diff --git a/sys/netgraph/ng_socketvar.h b/sys/netgraph/ng_socketvar.h
new file mode 100644
index 0000000..5451524
--- /dev/null
+++ b/sys/netgraph/ng_socketvar.h
@@ -0,0 +1,63 @@
+
+/*
+ * netgraph.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_socketvar.h,v 1.1 1999/01/20 21:35:39 archie Exp $
+ */
+
+#ifndef _NETGRAPH_NG_SOCKETVAR_H_
+#define _NETGRAPH_NG_SOCKETVAR_H_ 1
+
+/* Netgraph protocol control block for each socket */
+struct ngpcb {
+ struct socket *ng_socket; /* the socket */
+ struct ngsock *sockdata; /* netgraph info */
+ LIST_ENTRY(ngpcb) socks; /* linked list of sockets */
+ int type; /* NG_CONTROL or NG_DATA */
+};
+
+/* Per-node private data */
+struct ngsock {
+ struct ng_node *node; /* the associated netgraph node */
+ struct ngpcb *datasock; /* optional data socket */
+ struct ngpcb *ctlsock; /* optional control socket */
+ int refs;
+};
+
+#endif /* _NETGRAPH_NG_SOCKETVAR_H_ */
+
diff --git a/sys/netgraph/ng_tee.c b/sys/netgraph/ng_tee.c
new file mode 100644
index 0000000..476913c
--- /dev/null
+++ b/sys/netgraph/ng_tee.c
@@ -0,0 +1,268 @@
+
+/*
+ * ng_tee.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Julian Elischer <julian@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_tee.c,v 1.16 1999/01/28 23:54:54 julian Exp $
+ */
+
+/*
+ * This node is like the tee(1) command and is useful for ``snooping.''
+ * It has 4 hooks: left, right, left2right, and right2left. Data
+ * entering from the right is passed to the left and duplicated on
+ * right2left, and data entering from the left is passed to the right
+ * and duplicated on left2right. Data entering from left2right is
+ * sent to right, and data from right2left to left.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_tee.h>
+
+/* Per hook info */
+struct hookinfo {
+ hook_p hook;
+ int bytes;
+ int packets;
+ int flags;
+};
+
+/* Per node info */
+struct privdata {
+ node_p node;
+ int flags;
+ struct hookinfo left;
+ struct hookinfo right;
+ struct hookinfo left2right;
+ struct hookinfo right2left;
+};
+typedef struct privdata *sc_p;
+
+/* Netgraph methods */
+static int ngt_constructor(node_p *node);
+static int ngt_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngt_rmnode(node_p node);
+static int ngt_newhook(node_p node, hook_p hook, const char *name);
+static int ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngt_disconnect(hook_p hook);
+
+/* Netgraph type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_TEE_NODE_TYPE,
+ NULL,
+ ngt_constructor,
+ ngt_rcvmsg,
+ ngt_rmnode,
+ ngt_newhook,
+ NULL,
+ NULL,
+ ngt_rcvdata,
+ ngt_rcvdata,
+ ngt_disconnect
+};
+NETGRAPH_INIT(tee, &typestruct);
+
+/*
+ * Node constructor
+ */
+static int
+ngt_constructor(node_p *nodep)
+{
+ sc_p privdata;
+ int error = 0;
+
+ MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK);
+ if (privdata == NULL)
+ return (ENOMEM);
+ bzero(privdata, sizeof(*privdata));
+
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(privdata, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = privdata;
+ privdata->node = *nodep;
+ return (0);
+}
+
+/*
+ * Add a hook
+ */
+static int
+ngt_newhook(node_p node, hook_p hook, const char *name)
+{
+ const sc_p sc = node->private;
+
+ if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) {
+ sc->right.hook = hook;
+ sc->right.bytes = 0;
+ sc->right.packets = 0;
+ hook->private = &sc->right;
+ } else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) {
+ sc->left.hook = hook;
+ sc->left.bytes = 0;
+ sc->left.packets = 0;
+ hook->private = &sc->left;
+ } else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) {
+ sc->right2left.hook = hook;
+ sc->right2left.bytes = 0;
+ sc->right2left.packets = 0;
+ hook->private = &sc->right2left;
+ } else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) {
+ sc->left2right.hook = hook;
+ sc->left2right.bytes = 0;
+ sc->left2right.packets = 0;
+ hook->private = &sc->left2right;
+ } else
+ return (EINVAL);
+ return (0);
+}
+
+/*
+ * We don't support any type-specific messages
+ */
+static int
+ngt_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **resp)
+{
+ FREE(msg, M_NETGRAPH);
+ return (EINVAL);
+}
+
+/*
+ * Receive data on a hook
+ *
+ * If data comes in the right link send a copy out right2left, and then
+ * send the original onwards out through the left link.
+ * Do the opposite for data coming in from the left link.
+ * Data coming in right2left or left2right is forwarded
+ * on through the appropriate destination hook as if it had come
+ * from the other side.
+ */
+static int
+ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const sc_p sc = hook->node->private;
+ struct hookinfo *hi;
+ struct hookinfo *dest;
+ struct hookinfo *dup;
+ struct mbuf *mdup;
+ int error = 0;
+
+ if ((hi = hook->private) != NULL) {
+ if (hi == &sc->left) {
+ dup = &sc->left2right;
+ dest = &sc->right;
+ } else if (hi == &sc->right) {
+ dup = &sc->right2left;
+ dest = &sc->left;
+ } else if (hi == &sc->right2left) {
+ dup = NULL;
+ dest = &sc->left;
+ } else if (hi == &sc->left2right) {
+ dup = NULL;
+ dest = &sc->right;
+ } else
+ goto out;
+ if (dup) {
+ mdup = m_copypacket(m, M_NOWAIT);
+ if (mdup) {
+ /* XXX should we duplicate meta? */
+ /* for now no. */
+ void *x = NULL;
+
+ NG_SEND_DATA(error, dup->hook, mdup, x);
+ }
+ }
+ NG_SEND_DATA(error, dest->hook, m, meta);
+ }
+
+out:
+ NG_FREE_DATA(m, meta);
+ return (error);
+}
+
+/*
+ * Shutdown processing
+ *
+ * This is tricky. If we have both a left and right hook, then we
+ * probably want to extricate ourselves and leave the two peers
+ * still linked to each other. Otherwise we should just shut down as
+ * a normal node would.
+ *
+ * To keep the scope of info correct the routine to "extract" a node
+ * from two links is in ng_base.c.
+ */
+static int
+ngt_rmnode(node_p node)
+{
+ const sc_p privdata = node->private;
+
+ node->flags |= NG_INVALID;
+ if (privdata->left.hook && privdata->right.hook)
+ ng_bypass(privdata->left.hook, privdata->right.hook);
+ ng_cutlinks(node);
+ ng_unname(node);
+ node->private = NULL;
+ ng_unref(privdata->node);
+ FREE(privdata, M_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ngt_disconnect(hook_p hook)
+{
+ struct hookinfo *hi;
+
+ if ((hi = hook->private) != NULL)
+ hi->hook = NULL;
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
diff --git a/sys/netgraph/ng_tee.h b/sys/netgraph/ng_tee.h
new file mode 100644
index 0000000..96f2380
--- /dev/null
+++ b/sys/netgraph/ng_tee.h
@@ -0,0 +1,56 @@
+
+/*
+ * ng_tee.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_tee.h,v 1.2 1999/01/20 00:22:14 archie Exp $
+ */
+
+#ifndef _NETGRAPH_TEE_H_
+#define _NETGRAPH_TEE_H_
+
+/* Node type name and magic cookie */
+#define NG_TEE_NODE_TYPE "tee"
+#define NGM_TEE_COOKIE 916107047
+
+/* Hook names */
+#define NG_TEE_HOOK_RIGHT "right"
+#define NG_TEE_HOOK_LEFT "left"
+#define NG_TEE_HOOK_RIGHT2LEFT "right2left"
+#define NG_TEE_HOOK_LEFT2RIGHT "left2right"
+
+#endif /* _NETGRAPH_TEE_H_ */
diff --git a/sys/netgraph/ng_tty.c b/sys/netgraph/ng_tty.c
new file mode 100644
index 0000000..4ec7bf9
--- /dev/null
+++ b/sys/netgraph/ng_tty.c
@@ -0,0 +1,706 @@
+
+/*
+ * ng_tty.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_tty.c,v 1.18 1999/01/28 23:54:54 julian Exp $
+ */
+
+/*
+ * This file implements a terminal line discipline that is also a
+ * netgraph node. Installing this line discipline on a terminal device
+ * instantiates a new netgraph node of this type, which allows access
+ * to the device via the "hook" hook of the node.
+ *
+ * Once the line discipline is installed, you can find out the name
+ * of the corresponding netgraph node via a NGIOCGINFO ioctl().
+ *
+ * Incoming characters are delievered to the hook one at a time, each
+ * in its own mbuf. You may optionally define a ``hotchar,'' which causes
+ * incoming characters to be buffered up until either the hotchar is
+ * seen or the mbuf is full (MHLEN bytes). Then all buffered characters
+ * are immediately delivered.
+ *
+ * NOTE: This node operates at spltty().
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/tty.h>
+#include <sys/syslog.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_tty.h>
+
+#ifdef __i386__ /* fiddle with the spl locking */
+#include <machine/ipl.h>
+#include <i386/isa/intr_machdep.h>
+#endif
+
+/* Misc defs */
+#define MAX_MBUFQ 3 /* Max number of queued mbufs */
+#define NGT_HIWATER 400 /* High water mark on output */
+
+/* Per-node private info */
+struct ngt_sc {
+ struct tty *tp; /* Terminal device */
+ node_p node; /* Netgraph node */
+ hook_p hook; /* Netgraph hook */
+ struct mbuf *m; /* Incoming data buffer */
+ struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */
+ short qlen; /* Length of queue */
+ short hotchar; /* Hotchar, or -1 if none */
+ u_int flags; /* Flags */
+ struct callout_handle chand; /* See man timeout(9) */
+};
+typedef struct ngt_sc *sc_p;
+
+/* Flags */
+#define FLG_TIMEOUT 0x0001 /* A timeout is pending */
+#define FLG_DEBUG 0x0002
+
+/* Debugging */
+#ifdef DIAGNOSTICS
+#define QUEUECHECK(sc) \
+ do { \
+ struct mbuf **mp; \
+ int k; \
+ \
+ for (k = 0, mp = &sc->qhead; \
+ k <= MAX_MBUFQ && *mp; \
+ k++, mp = &(*mp)->m_nextpkt); \
+ if (k != sc->qlen || k > MAX_MBUFQ || *mp || mp != sc->qtail) \
+ panic(__FUNCTION__ ": queue"); \
+ } while (0)
+#else
+#define QUEUECHECK(sc) do {} while (0)
+#endif
+
+/* Line discipline methods */
+static int ngt_open(dev_t dev, struct tty *tp);
+static int ngt_close(struct tty *tp, int flag);
+static int ngt_read(struct tty *tp, struct uio *uio, int flag);
+static int ngt_write(struct tty *tp, struct uio *uio, int flag);
+static int ngt_tioctl(struct tty *tp,
+ u_long cmd, caddr_t data, int flag, struct proc *);
+static int ngt_input(int c, struct tty *tp);
+static int ngt_start(struct tty *tp);
+
+/* Netgraph methods */
+static int ngt_constructor(node_p *node);
+static int ngt_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ngt_shutdown(node_p node);
+static int ngt_newhook(node_p node, hook_p hook, const char *name);
+static int ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
+static int ngt_disconnect(hook_p hook);
+static int ngt_mod_event(module_t mod, int event, void *data);
+
+/* Other stuff */
+static void ngt_timeout(void *arg);
+
+#define ERROUT(x) do { error = (x); goto done; } while (0)
+
+/* Line discipline descriptor */
+static struct linesw ngt_disc = {
+ ngt_open,
+ ngt_close,
+ ngt_read,
+ ngt_write,
+ ngt_tioctl,
+ ngt_input,
+ ngt_start,
+ ttymodem,
+ NG_TTY_DFL_HOTCHAR /* XXX can't change this in serial driver */
+};
+static int ngt_ldisc = -1;
+
+/* Netgraph node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_TTY_NODE_TYPE,
+ ngt_mod_event,
+ ngt_constructor,
+ ngt_rcvmsg,
+ ngt_shutdown,
+ ngt_newhook,
+ NULL,
+ NULL,
+ ngt_rcvdata,
+ ngt_rcvdata,
+ ngt_disconnect,
+};
+NETGRAPH_INIT(tty, &typestruct);
+
+static int ngt_unit;
+static int ngt_nodeop_ok; /* OK to create/remove node */
+
+/******************************************************************
+ LINE DISCIPLINE METHODS
+******************************************************************/
+
+/*
+ * Set our line discipline on the tty.
+ * Called from device open routine or ttioctl() at >= splsofttty()
+ */
+static int
+ngt_open(dev_t dev, struct tty *tp)
+{
+ struct proc *const p = curproc; /* XXX */
+ char name[sizeof(NG_TTY_NODE_TYPE) + 8];
+ sc_p sc;
+ int s, error;
+
+ /* Super-user only */
+ if ((error = suser(p)))
+ return (error);
+ s = splnet();
+ (void) spltty(); /* XXX is this necessary? */
+
+ /* Already installed? */
+ if (tp->t_line == ngt_ldisc) {
+ sc = (sc_p) tp->t_sc;
+ if (sc != NULL && sc->tp == tp)
+ goto done;
+ }
+
+ /* Initialize private struct */
+ MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK);
+ if (sc == NULL) {
+ error = ENOMEM;
+ goto done;
+ }
+ bzero(sc, sizeof(*sc));
+ sc->tp = tp;
+ sc->hotchar = NG_TTY_DFL_HOTCHAR;
+ sc->qtail = &sc->qhead;
+ QUEUECHECK(sc);
+ callout_handle_init(&sc->chand);
+
+ /* Setup netgraph node */
+ ngt_nodeop_ok = 1;
+ error = ng_make_node_common(&typestruct, &sc->node);
+ ngt_nodeop_ok = 0;
+ if (error) {
+ FREE(sc, M_NETGRAPH);
+ goto done;
+ }
+ sprintf(name, "%s%d", typestruct.name, ngt_unit++);
+
+ /* Set back pointers */
+ sc->node->private = sc;
+ tp->t_sc = (caddr_t) sc;
+
+ /* Assign node its name */
+ if ((error = ng_name_node(sc->node, name))) {
+ log(LOG_ERR, "%s: node name exists?\n", name);
+ ngt_nodeop_ok = 1;
+ ng_rmnode(sc->node);
+ ngt_nodeop_ok = 0;
+ goto done;
+ }
+
+ /*
+ * Pre-allocate cblocks to the an appropriate amount.
+ * I'm not sure what is appropriate.
+ */
+ ttyflush(tp, FREAD | FWRITE);
+ clist_alloc_cblocks(&tp->t_canq, 0, 0);
+ clist_alloc_cblocks(&tp->t_rawq, 0, 0);
+ clist_alloc_cblocks(&tp->t_outq,
+ MLEN + NGT_HIWATER, MLEN + NGT_HIWATER);
+
+done:
+ /* Done */
+ splx(s);
+ return (error);
+}
+
+/*
+ * Line specific close routine, called from device close routine
+ * and from ttioctl at >= splsofttty(). This causes the node to
+ * be destroyed as well.
+ */
+static int
+ngt_close(struct tty *tp, int flag)
+{
+ const sc_p sc = (sc_p) tp->t_sc;
+ int s;
+
+ s = spltty();
+ ttyflush(tp, FREAD | FWRITE);
+ clist_free_cblocks(&tp->t_outq);
+ tp->t_line = 0;
+ if (sc != NULL) {
+ if (sc->flags & FLG_TIMEOUT) {
+ untimeout(ngt_timeout, sc, sc->chand);
+ sc->flags &= ~FLG_TIMEOUT;
+ }
+ ngt_nodeop_ok = 1;
+ ng_rmnode(sc->node);
+ ngt_nodeop_ok = 0;
+ tp->t_sc = NULL;
+ }
+ splx(s);
+ return (0);
+}
+
+/*
+ * Once the device has been turned into a node, we don't allow reading.
+ */
+static int
+ngt_read(struct tty *tp, struct uio *uio, int flag)
+{
+ return (EIO);
+}
+
+/*
+ * Once the device has been turned into a node, we don't allow writing.
+ */
+static int
+ngt_write(struct tty *tp, struct uio *uio, int flag)
+{
+ return (EIO);
+}
+
+/*
+ * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
+ */
+static int
+ngt_tioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ const sc_p sc = (sc_p) tp->t_sc;
+ int s, error = 0;
+
+ s = spltty();
+ switch (cmd) {
+ case NGIOCGINFO:
+ {
+ struct nodeinfo *const ni = (struct nodeinfo *) data;
+ const node_p node = sc->node;
+
+ bzero(ni, sizeof(*ni));
+ if (node->name)
+ strncpy(ni->name, node->name, sizeof(ni->name) - 1);
+ strncpy(ni->type, node->type->name, sizeof(ni->type) - 1);
+ ni->id = (u_int32_t) node;
+ ni->hooks = node->numhooks;
+ break;
+ }
+ default:
+ ERROUT(ENOIOCTL);
+ }
+done:
+ splx(s);
+ return (error);
+}
+
+/*
+ * Receive data coming from the device. We get one character at
+ * a time, which is kindof silly.
+ * Only guaranteed to be at splsofttty() or spltty().
+ */
+static int
+ngt_input(int c, struct tty *tp)
+{
+ const sc_p sc = (sc_p) tp->t_sc;
+ const node_p node = sc->node;
+ struct mbuf *m;
+ int s, error = 0;
+
+ if (!sc || tp != sc->tp)
+ return (0);
+ s = spltty();
+ if (!sc->hook)
+ ERROUT(0);
+
+ /* Check for error conditions */
+ if ((tp->t_state & TS_CONNECTED) == 0) {
+ if (sc->flags & FLG_DEBUG)
+ log(LOG_DEBUG, "%s: no carrier\n", node->name);
+ ERROUT(0);
+ }
+ if (c & TTY_ERRORMASK) {
+ /* framing error or overrun on this char */
+ if (sc->flags & FLG_DEBUG)
+ log(LOG_DEBUG, "%s: line error %x\n",
+ node->name, c & TTY_ERRORMASK);
+ ERROUT(0);
+ }
+ c &= TTY_CHARMASK;
+
+ /* Get a new header mbuf if we need one */
+ if (!(m = sc->m)) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (!m) {
+ if (sc->flags & FLG_DEBUG)
+ log(LOG_ERR,
+ "%s: can't get mbuf\n", node->name);
+ ERROUT(ENOBUFS);
+ }
+ m->m_len = 0;
+ m->m_pkthdr.len = 0;
+ sc->m = m;
+ }
+
+ /* Add char to mbuf */
+ *mtod(m, u_char *) = c;
+ m->m_data++;
+ m->m_len++;
+ m->m_pkthdr.len++;
+
+ /* Ship off mbuf if it's time */
+ if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) {
+ m->m_data = m->m_pktdat;
+ error = ng_queue_data(sc->hook, m, NULL);
+ sc->m = NULL;
+ }
+done:
+ splx(s);
+ return (error);
+}
+
+/*
+ * This is called when the device driver is ready for more output.
+ * Called from tty system at splsofttty() or spltty().
+ * Also call from ngt_rcv_data() when a new mbuf is available for output.
+ */
+static int
+ngt_start(struct tty *tp)
+{
+ const sc_p sc = (sc_p) tp->t_sc;
+ int s;
+
+ s = spltty();
+ while (tp->t_outq.c_cc < NGT_HIWATER) { /* XXX 2.2 specific ? */
+ struct mbuf *m = sc->qhead;
+
+ /* Remove first mbuf from queue */
+ if (!m)
+ break;
+ if ((sc->qhead = m->m_nextpkt) == NULL)
+ sc->qtail = &sc->qhead;
+ sc->qlen--;
+ QUEUECHECK(sc);
+
+ /* Send as much of it as possible */
+ while (m) {
+ struct mbuf *m2;
+ int sent;
+
+ sent = m->m_len
+ - b_to_q(mtod(m, u_char *), m->m_len, &tp->t_outq);
+ m->m_data += sent;
+ m->m_len -= sent;
+ if (m->m_len > 0)
+ break; /* device can't take no more */
+ MFREE(m, m2);
+ m = m2;
+ }
+
+ /* Put remainder of mbuf chain (if any) back on queue */
+ if (m) {
+ m->m_nextpkt = sc->qhead;
+ sc->qhead = m;
+ if (sc->qtail == &sc->qhead)
+ sc->qtail = &m->m_nextpkt;
+ sc->qlen++;
+ QUEUECHECK(sc);
+ break;
+ }
+ }
+
+ /* Call output process whether or not there is any output. We are
+ * being called in lieu of ttstart and must do what it would. */
+ if (tp->t_oproc != NULL)
+ (*tp->t_oproc) (tp);
+
+ /* This timeout is needed for operation on a pseudo-tty, because the
+ * pty code doesn't call pppstart after it has drained the t_outq. */
+ if (sc->qhead && (sc->flags & FLG_TIMEOUT) == 0) {
+ sc->chand = timeout(ngt_timeout, sc, 1);
+ sc->flags |= FLG_TIMEOUT;
+ }
+ splx(s);
+ return (0);
+}
+
+/*
+ * We still have data to output to the device, so try sending more.
+ */
+static void
+ngt_timeout(void *arg)
+{
+ const sc_p sc = (sc_p) arg;
+ int s;
+
+ s = spltty();
+ sc->flags &= ~FLG_TIMEOUT;
+ ngt_start(sc->tp);
+ splx(s);
+}
+
+/******************************************************************
+ NETGRAPH NODE METHODS
+******************************************************************/
+
+/*
+ * Initialize a new node of this type.
+ *
+ * We only allow nodes to be created as a result of setting
+ * the line discipline on a tty, so always return an error if not.
+ */
+static int
+ngt_constructor(node_p *nodep)
+{
+ if (!ngt_nodeop_ok)
+ return (EOPNOTSUPP);
+ return (ng_make_node_common(&typestruct, nodep));
+}
+
+/*
+ * Add a new hook. There can only be one.
+ */
+static int
+ngt_newhook(node_p node, hook_p hook, const char *name)
+{
+ const sc_p sc = node->private;
+ int s, error = 0;
+
+ if (strcmp(name, NG_TTY_HOOK))
+ return (EINVAL);
+ s = spltty();
+ if (sc->hook)
+ ERROUT(EISCONN);
+ sc->hook = hook;
+done:
+ splx(s);
+ return (error);
+}
+
+/*
+ * Disconnect the hook
+ */
+static int
+ngt_disconnect(hook_p hook)
+{
+ const sc_p sc = hook->node->private;
+ int s;
+
+ s = spltty();
+ if (hook != sc->hook)
+ panic(__FUNCTION__);
+ sc->hook = NULL;
+ m_freem(sc->m);
+ sc->m = NULL;
+ splx(s);
+ return (0);
+}
+
+/*
+ * Remove this node. The does the netgraph portion of the shutdown.
+ * This should only be called indirectly from ngt_close().
+ */
+static int
+ngt_shutdown(node_p node)
+{
+ const sc_p sc = node->private;
+
+ if (!ngt_nodeop_ok)
+ return (EOPNOTSUPP);
+ ng_unname(node);
+ ng_cutlinks(node);
+ node->private = NULL;
+ ng_unref(sc->node);
+ m_freem(sc->qhead);
+ m_freem(sc->m);
+ bzero(sc, sizeof(*sc));
+ FREE(sc, M_NETGRAPH);
+ return (0);
+}
+
+/*
+ * Receive incoming data from netgraph system. Put it on our
+ * output queue and start output if necessary.
+ */
+static int
+ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const sc_p sc = hook->node->private;
+ int s, error = 0;
+
+ if (hook != sc->hook)
+ panic(__FUNCTION__);
+ NG_FREE_META(meta);
+ s = spltty();
+ if (sc->qlen >= MAX_MBUFQ)
+ ERROUT(ENOBUFS);
+ m->m_nextpkt = NULL;
+ *sc->qtail = m;
+ sc->qtail = &m->m_nextpkt;
+ sc->qlen++;
+ QUEUECHECK(sc);
+ m = NULL;
+ if (sc->qlen == 1)
+ ngt_start(sc->tp);
+done:
+ splx(s);
+ if (m)
+ m_freem(m);
+ return (error);
+}
+
+/*
+ * Receive control message
+ */
+static int
+ngt_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **rptr)
+{
+ const sc_p sc = (sc_p) node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ switch (msg->header.typecookie) {
+ case NGM_TTY_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_TTY_SET_HOTCHAR:
+ {
+ int hotchar;
+
+ if (msg->header.arglen != sizeof(int))
+ ERROUT(EINVAL);
+ hotchar = *((int *) msg->data);
+ if (hotchar != (u_char) hotchar && hotchar != -1)
+ ERROUT(EINVAL);
+ sc->hotchar = hotchar; /* race condition is OK */
+ break;
+ }
+ case NGM_TTY_GET_HOTCHAR:
+ NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT);
+ if (!resp)
+ ERROUT(ENOMEM);
+ /* Race condition here is OK */
+ *((int *) resp->data) = sc->hotchar;
+ break;
+ default:
+ ERROUT(EINVAL);
+ }
+ break;
+ default:
+ ERROUT(EINVAL);
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+done:
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/******************************************************************
+ INITIALIZATION
+******************************************************************/
+
+/*
+ * Handle loading and unloading for this node type
+ */
+static int
+ngt_mod_event(module_t mod, int event, void *data)
+{
+ struct ng_type *const type = data;
+ int s, error = 0;
+
+ switch (event) {
+ case MOD_LOAD:
+#ifdef __i386__
+ /* Insure the soft net "engine" can't run during spltty code */
+ s = splhigh();
+ tty_imask |= softnet_imask; /* spltty() block spl[soft]net() */
+ net_imask |= softtty_imask; /* splimp() block splsofttty() */
+ net_imask |= tty_imask; /* splimp() block spltty() */
+ update_intr_masks();
+ splx(s);
+
+ if (bootverbose)
+ log(LOG_DEBUG, "new masks: bio %x, tty %x, net %x\n",
+ bio_imask, tty_imask, net_imask);
+#endif
+
+ /* Register line discipline */
+ s = spltty();
+ if ((ngt_ldisc = ldisc_register(LDISC_LOAD, &ngt_disc)) < 0) {
+ splx(s);
+ log(LOG_ERR, "%s: can't register line discipline",
+ __FUNCTION__);
+ return (EIO);
+ }
+ splx(s);
+
+ /* OK */
+ log(LOG_INFO, "line discipline #%d registered to"
+ " netgraph node type \"%s\"\n", ngt_ldisc, type->name);
+ break;
+
+ case MOD_UNLOAD:
+
+ /* Unregister line discipline */
+ s = spltty();
+ ldisc_deregister(ngt_ldisc);
+ splx(s);
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
+
diff --git a/sys/netgraph/ng_tty.h b/sys/netgraph/ng_tty.h
new file mode 100644
index 0000000..ad7dc4e
--- /dev/null
+++ b/sys/netgraph/ng_tty.h
@@ -0,0 +1,62 @@
+
+/*
+ * ng_tty.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_tty.h,v 1.7 1999/01/20 00:22:15 archie Exp $
+ */
+
+#ifndef _NETGRAPH_TTY_H_
+#define _NETGRAPH_TTY_H_
+
+/* Node type name and magic cookie */
+#define NG_TTY_NODE_TYPE "tty"
+#define NGM_TTY_COOKIE 886279262
+
+/* Default hot char */
+#define NG_TTY_DFL_HOTCHAR 0x7e /* PPP flag byte */
+
+/* Hook names */
+#define NG_TTY_HOOK "hook"
+
+/* Netgraph commands */
+enum {
+ NGM_TTY_GET_HOTCHAR = 1,
+ NGM_TTY_SET_HOTCHAR,
+};
+
+#endif /* _NETGRAPH_TTY_H_ */
diff --git a/sys/netgraph/ng_vjc.c b/sys/netgraph/ng_vjc.c
new file mode 100644
index 0000000..9755bd4
--- /dev/null
+++ b/sys/netgraph/ng_vjc.c
@@ -0,0 +1,439 @@
+
+/*
+ * ng_vjc.c
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_vjc.c,v 1.14 1999/01/28 23:54:54 julian Exp $
+ */
+
+/*
+ * This node performs Van Jacobsen IP header (de)compression.
+ * You must have included net/slcompress.c in your kernel compilation.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_vjc.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <net/slcompress.h>
+
+/* Check agreement with slcompress.c */
+#if MAX_STATES != NG_VJC_MAX_CHANNELS
+#error NG_VJC_MAX_CHANNELS must be the same as MAX_STATES
+#endif
+
+#define MAX_VJHEADER 16
+
+/* Node private data */
+struct private {
+ struct ngm_vjc_config conf;
+ struct slcompress slc;
+ hook_p ip;
+ hook_p vjcomp;
+ hook_p vjuncomp;
+ hook_p vjip;
+};
+typedef struct private *priv_p;
+
+#define ERROUT(x) do { error = (x); goto done; } while (0)
+
+/* Netgraph node methods */
+static int ng_vjc_constructor(node_p *nodep);
+static int ng_vjc_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *retaddr, struct ng_mesg **resp);
+static int ng_vjc_rmnode(node_p node);
+static int ng_vjc_newhook(node_p node, hook_p hook, const char *name);
+static int ng_vjc_rcvdata(hook_p hook, struct mbuf *m, meta_p t);
+static int ng_vjc_disconnect(hook_p hook);
+
+/* Helper stuff */
+static struct mbuf *pulluphdrs(struct mbuf *m);
+
+/* Node type descriptor */
+static struct ng_type typestruct = {
+ NG_VERSION,
+ NG_VJC_NODE_TYPE,
+ NULL,
+ ng_vjc_constructor,
+ ng_vjc_rcvmsg,
+ ng_vjc_rmnode,
+ ng_vjc_newhook,
+ NULL,
+ NULL,
+ ng_vjc_rcvdata,
+ ng_vjc_rcvdata,
+ ng_vjc_disconnect
+};
+NETGRAPH_INIT(vjc, &typestruct);
+
+/************************************************************************
+ NETGRAPH NODE METHODS
+ ************************************************************************/
+
+/*
+ * Create a new node
+ */
+static int
+ng_vjc_constructor(node_p *nodep)
+{
+ priv_p priv;
+ int error;
+
+ /* Allocate private structure */
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
+ if (priv == NULL)
+ return (ENOMEM);
+ bzero(priv, sizeof(*priv));
+
+ /* Call generic node constructor */
+ if ((error = ng_make_node_common(&typestruct, nodep))) {
+ FREE(priv, M_NETGRAPH);
+ return (error);
+ }
+ (*nodep)->private = priv;
+
+ /* Done */
+ return (0);
+}
+
+/*
+ * Add a new hook
+ */
+static int
+ng_vjc_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p priv = (priv_p) node->private;
+ hook_p *hookp;
+
+ /* Get hook */
+ if (!strcmp(name, NG_VJC_HOOK_IP))
+ hookp = &priv->ip;
+ else if (!strcmp(name, NG_VJC_HOOK_VJCOMP))
+ hookp = &priv->vjcomp;
+ else if (!strcmp(name, NG_VJC_HOOK_VJUNCOMP))
+ hookp = &priv->vjuncomp;
+ else if (!strcmp(name, NG_VJC_HOOK_VJIP))
+ hookp = &priv->vjip;
+ else
+ return (EINVAL);
+
+ /* See if already connected */
+ if (*hookp)
+ return (EISCONN);
+
+ /* OK */
+ *hookp = hook;
+ return (0);
+}
+
+/*
+ * Receive a control message
+ */
+static int
+ng_vjc_rcvmsg(node_p node, struct ng_mesg *msg,
+ const char *raddr, struct ng_mesg **rptr)
+{
+ const priv_p priv = (priv_p) node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ /* Check type cookie */
+ switch (msg->header.typecookie) {
+ case NGM_VJC_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_VJC_CONFIG:
+ {
+ struct ngm_vjc_config *const c =
+ (struct ngm_vjc_config *) msg->data;
+
+ if (msg->header.arglen != sizeof(*c)
+ || c->numChannels > NG_VJC_MAX_CHANNELS
+ || c->numChannels < NG_VJC_MIN_CHANNELS)
+ ERROUT(EINVAL);
+ if (priv->conf.enabled && c->enabled)
+ ERROUT(EALREADY);
+ if (c->enabled != 0) {
+ bzero(&priv->slc, sizeof(priv->slc));
+ sl_compress_init(&priv->slc, c->numChannels);
+ }
+ priv->conf = *c;
+ break;
+ }
+ case NGM_VJC_GET_STATE:
+ NG_MKRESPONSE(resp, msg, sizeof(priv->slc), M_NOWAIT);
+ if (resp == NULL)
+ ERROUT(ENOMEM);
+ *((struct slcompress *) resp->data) = priv->slc;
+ break;
+ case NGM_VJC_CLR_STATS:
+ priv->slc.sls_packets = 0;
+ priv->slc.sls_compressed = 0;
+ priv->slc.sls_searches = 0;
+ priv->slc.sls_misses = 0;
+ priv->slc.sls_uncompressedin = 0;
+ priv->slc.sls_compressedin = 0;
+ priv->slc.sls_errorin = 0;
+ priv->slc.sls_tossed = 0;
+ break;
+ case NGM_VJC_RECV_ERROR:
+ priv->slc.flags |= SLF_TOSS;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp)
+ FREE(resp, M_NETGRAPH);
+
+done:
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Receive data
+ */
+static int
+ng_vjc_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
+{
+ const node_p node = hook->node;
+ const priv_p priv = (priv_p) node->private;
+ int error = 0;
+
+ if (hook == priv->ip) { /* outgoing packet */
+ u_int type;
+
+ if (!priv->conf.enabled) /* compression not enabled */
+ type = TYPE_IP;
+ else {
+ struct ip *ip;
+
+ if ((m = pulluphdrs(m)) == NULL)
+ ERROUT(ENOBUFS);
+ ip = mtod(m, struct ip *);
+ type = (ip->ip_p == IPPROTO_TCP) ?
+ sl_compress_tcp(m, ip,
+ &priv->slc, priv->conf.compressCID) : TYPE_IP;
+ }
+ switch (type) {
+ case TYPE_IP:
+ hook = priv->vjip;
+ break;
+ case TYPE_UNCOMPRESSED_TCP:
+ hook = priv->vjuncomp;
+ break;
+ case TYPE_COMPRESSED_TCP:
+ hook = priv->vjcomp;
+ break;
+ default:
+ panic(__FUNCTION__);
+ }
+ } else if (hook == priv->vjcomp) { /* incoming compressed packet */
+ int vjlen;
+ u_int hlen;
+ u_char *hdr;
+ struct mbuf *mp;
+
+ /* Are we initialized? */
+ if (!priv->conf.enabled) {
+ m_freem(m);
+ m = NULL;
+ ERROUT(ENETDOWN);
+ }
+
+ /* Uncompress packet to reconstruct TCP/IP header */
+ if (!(m = m_pullup(m, MAX_VJHEADER)))
+ ERROUT(ENOBUFS);
+ vjlen = sl_uncompress_tcp_core(mtod(m, u_char *),
+ m->m_len, m->m_pkthdr.len, TYPE_COMPRESSED_TCP,
+ &priv->slc, &hdr, &hlen);
+ if (vjlen <= 0) {
+ m_freem(m);
+ m = NULL;
+ ERROUT(EINVAL);
+ }
+
+ /* Copy the reconstructed TCP/IP headers into a new mbuf */
+ MGETHDR(mp, M_DONTWAIT, MT_DATA);
+ if (!mp)
+ goto compfailmem;
+ mp->m_len = 0;
+ mp->m_next = NULL;
+ if (hlen > MHLEN) {
+ MCLGET(mp, M_DONTWAIT);
+ if (M_TRAILINGSPACE(mp) < hlen) {
+ m_freem(mp); /* can't get a cluster, drop */
+compfailmem:
+ m_freem(m);
+ m = NULL;
+ ERROUT(ENOBUFS);
+ }
+ }
+ bcopy(hdr, mtod(mp, u_char *), hlen);
+ mp->m_len = hlen;
+
+ /* Stick header and rest of packet together */
+ m->m_data += vjlen;
+ m->m_len -= vjlen;
+ if (m->m_len <= M_TRAILINGSPACE(mp)) {
+ bcopy(mtod(m, u_char *),
+ mtod(mp, u_char *) + mp->m_len, m->m_len);
+ mp->m_len += m->m_len;
+ MFREE(m, mp->m_next);
+ } else
+ mp->m_next = m;
+ m = mp;
+ hook = priv->ip;
+ } else if (hook == priv->vjuncomp) { /* incoming uncompressed pkt */
+ u_int hlen;
+ u_char *hdr;
+
+ /* Are we initialized? */
+ if (!priv->conf.enabled) {
+ m_freem(m);
+ m = NULL;
+ ERROUT(ENETDOWN);
+ }
+
+ /* Run packet through uncompressor */
+ if ((m = pulluphdrs(m)) == NULL)
+ ERROUT(ENOBUFS);
+ if (sl_uncompress_tcp_core(mtod(m, u_char *),
+ m->m_len, m->m_pkthdr.len, TYPE_UNCOMPRESSED_TCP,
+ &priv->slc, &hdr, &hlen) < 0) {
+ m_freem(m);
+ m = NULL;
+ ERROUT(EINVAL);
+ }
+ hook = priv->ip;
+ } else if (hook == priv->vjip) /* incoming regular packet (bypass) */
+ hook = priv->ip;
+ else
+ panic(__FUNCTION__);
+
+done:
+ if (m)
+ NG_SEND_DATA(error, hook, m, meta);
+ else
+ NG_FREE_META(meta);
+ return (error);
+}
+
+/*
+ * Shutdown node
+ */
+static int
+ng_vjc_rmnode(node_p node)
+{
+ const priv_p priv = (priv_p) node->private;
+
+ node->flags |= NG_INVALID;
+ ng_cutlinks(node);
+ ng_unname(node);
+ bzero(priv, sizeof(*priv));
+ FREE(priv, M_NETGRAPH);
+ node->private = NULL;
+ ng_unref(node);
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ng_vjc_disconnect(hook_p hook)
+{
+ if (hook->node->numhooks == 0)
+ ng_rmnode(hook->node);
+ return (0);
+}
+
+/************************************************************************
+ HELPER STUFF
+ ************************************************************************/
+
+/*
+ * Pull up the full IP and TCP headers of a packet. This is optimized
+ * for the common case of standard length headers. If packet is not
+ * a TCP packet, just pull up the IP header.
+ */
+static struct mbuf *
+pulluphdrs(struct mbuf *m)
+{
+ struct ip *ip;
+ struct tcphdr *tcp;
+ int ihlen, thlen;
+
+ if ((m = m_pullup(m, sizeof(*ip) + sizeof(*tcp))) == NULL)
+ return (NULL);
+ ip = mtod(m, struct ip *);
+ if (ip->ip_p != IPPROTO_TCP)
+ return (m);
+ if ((ihlen = (ip->ip_hl << 2)) != sizeof(*ip)) {
+ if (!(m = m_pullup(m, ihlen + sizeof(*tcp))))
+ return (NULL);
+ ip = mtod(m, struct ip *);
+ }
+ tcp = (struct tcphdr *) ((u_char *) ip + ihlen);
+ if ((thlen = (tcp->th_off << 2)) != sizeof(*tcp))
+ m = m_pullup(m, ihlen + thlen);
+ return (m);
+}
+
diff --git a/sys/netgraph/ng_vjc.h b/sys/netgraph/ng_vjc.h
new file mode 100644
index 0000000..5067f6a
--- /dev/null
+++ b/sys/netgraph/ng_vjc.h
@@ -0,0 +1,75 @@
+
+/*
+ * ng_vjc.h
+ *
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Archie Cobbs <archie@whistle.com>
+ *
+ * $FreeBSD$
+ * $Whistle: ng_vjc.h,v 1.6 1999/01/25 02:40:22 archie Exp $
+ */
+
+#ifndef _NETGRAPH_VJC_H_
+#define _NETGRAPH_VJC_H_
+
+ /* Node type name and magic cookie */
+#define NG_VJC_NODE_TYPE "vjc"
+#define NGM_VJC_COOKIE 868219207
+
+ /* Hook names */
+#define NG_VJC_HOOK_IP "ip" /* normal IP traffic */
+#define NG_VJC_HOOK_VJCOMP "vjcomp" /* compressed TCP */
+#define NG_VJC_HOOK_VJUNCOMP "vjuncomp" /* uncompressed TCP */
+#define NG_VJC_HOOK_VJIP "vjip" /* uncompressed IP */
+
+ /* Minimum and maximum number of channels */
+#define NG_VJC_MIN_CHANNELS 4
+#define NG_VJC_MAX_CHANNELS 16
+
+ /* Configure struct */
+struct ngm_vjc_config {
+ u_char enabled; /* Enable compression/decompression */
+ u_char numChannels; /* Number of outgoing channels */
+ u_char compressCID; /* OK to compress outgoing CID's */
+};
+
+ /* Netgraph commands */
+enum {
+ NGM_VJC_CONFIG, /* Supply a struct ngm_vjc_config */
+ NGM_VJC_GET_STATE, /* Returns current struct slcompress */
+ NGM_VJC_CLR_STATS, /* Clears statistics counters */
+ NGM_VJC_RECV_ERROR, /* Indicate loss of incoming frame */
+};
+
+#endif /* _NETGRAPH_VJC_H_ */
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index b161718..ad0ed65 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -355,7 +355,7 @@ struct vfsops {
#include <net/radix.h>
-#define AF_MAX 32 /* XXX */
+#define AF_MAX 33 /* XXX */
/*
* Network address lookup element
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index 4303945..d7d0f08 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -129,6 +129,7 @@ struct linger {
#define AF_NATM 29 /* native ATM access */
#define AF_ATM 30 /* ATM */
#define pseudo_AF_HDRCMPLT 31 /* Used by BPF to not rewrite headers
+#define AF_NETGRAPH 32 /* Netgraph sockets */
* in interface output routine
*/
@@ -190,6 +191,7 @@ struct sockproto {
#define PF_INET6 AF_INET6
#define PF_NATM AF_NATM
#define PF_ATM AF_ATM
+#define PF_NETGRAPH AF_NETGRAPH
#define PF_MAX AF_MAX
@@ -234,6 +236,7 @@ struct sockproto {
{ "key", CTLTYPE_NODE }, \
{ "inet6", CTLTYPE_NODE }, \
{ "natm", CTLTYPE_NODE }, \
+ { "netgraph", CTLTYPE_NODE }, \
}
/*
OpenPOWER on IntegriCloud