diff options
Diffstat (limited to 'sys')
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 *) ⁡ + 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 }, \ } /* |