diff options
author | kjc <kjc@FreeBSD.org> | 1999-05-08 14:23:40 +0000 |
---|---|---|
committer | kjc <kjc@FreeBSD.org> | 1999-05-08 14:23:40 +0000 |
commit | 2193f1d43473d72602aedf1ecdcb5552687edc6a (patch) | |
tree | e8d66bc24ca2964d1f748747343b92c17b401f26 /sys | |
parent | dda5cbbda41e442bf1eb739214a5c3ac36555d79 (diff) | |
download | FreeBSD-src-2193f1d43473d72602aedf1ecdcb5552687edc6a.zip FreeBSD-src-2193f1d43473d72602aedf1ecdcb5552687edc6a.tar.gz |
clean up en atm driver
o fix DDB support
- include "opt_ddb.h"
- fix Debugger() arg
pointed out by bde
o back out pvc shadow interface support
- it is currently not used
- to make it easier to merge another implementation
o misc minor cleanup
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/en/midway.c | 373 | ||||
-rw-r--r-- | sys/net/if_atm.h | 41 | ||||
-rw-r--r-- | sys/net/if_atmsubr.c | 296 |
3 files changed, 62 insertions, 648 deletions
diff --git a/sys/dev/en/midway.c b/sys/dev/en/midway.c index 9ce2401..a999ff5 100644 --- a/sys/dev/en/midway.c +++ b/sys/dev/en/midway.c @@ -46,32 +46,6 @@ * I would also like to thank Werner for promptly answering email and being * generally helpful. */ -/* - * 1997/12/02 kjc - * new features added: - * - support vc/vp shaping - * - integrate IPv6 support. - * - support pvc shadow interface - * (initial work on per-pvc-interface for ipv6 was done - * by Katsushi Kobayashi <ikob@cc.uec.ac.jp> of the WIDE Project, - * extensively modified by kjc.) - * code cleanup: - * - remove WMAYBE related code. ENI WMAYBE DMA doen't work. - * - drop support of FreeBSD-2.1.x and FreeBSD-3.0-SNAP-970124. - * - remove updating if_lastchange for every packet. - * - BPF related code is moved to midway.c as it should be. - * (bpfwrite should work if atm_pseudohdr and LLC/SNAP are - * prepended.) - * - BPF link type is changed to DLT_ATM_RFC1483. - * BPF now understands only LLC/SNAP!! (because bpf can't - * handle variable link header length.) - * It is recommended to use LLC/SNAP instead of NULL - * encapsulation for various reasons. (BPF, IPv6, - * interoperability, etc.) - * - altq queue implementation is moved from the driver internal - * queue to if_snd. - * - AFMAP related code cleanup. - */ #undef EN_DEBUG #undef EN_DEBUG_RANGE /* check ranges on en_read/en_write's? */ @@ -135,6 +109,12 @@ #include "en.h" #include "opt_inet.h" #include "opt_natm.h" +#include "opt_ddb.h" +/* enable DDBHOOK when DDB is available */ +#undef EN_DDBHOOK +#ifdef DDB +#define EN_DDBHOOK 1 +#endif #endif #if NEN > 0 || !defined(__FreeBSD__) @@ -146,6 +126,7 @@ #include <sys/device.h> #endif #include <sys/sockio.h> +#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/proc.h> @@ -315,14 +296,6 @@ STATIC INLINE int en_sz2b __P((int)) __attribute__ ((unused)); STATIC INLINE void en_write __P((struct en_softc *, u_int32_t, u_int32_t)) __attribute__ ((unused)); -#ifdef ATM_PVCEXT -static int en_txctl __P((struct en_softc *, int, int, int)); -static int en_pvctx __P((struct en_softc *, struct pvctxreq *)); -static int en_pvctxget __P((struct en_softc *, struct pvctxreq *)); -static int en_pcr2txspeed __P((int)); -static int en_txspeed2pcr __P((int)); -#endif - /* * macros/inline */ @@ -450,10 +423,8 @@ u_int32_t r; { #ifdef EN_DEBUG_RANGE - if (r > MID_MAXOFF || (r % 4)) { - printf("en_read out of range, r=0x%x\n", r); - panic("en_read"); - } + if (r > MID_MAXOFF || (r % 4)) + panic("en_read out of range, r=0x%x", r); #endif return(bus_space_read_4(sc->en_memt, sc->en_base, r)); @@ -471,10 +442,8 @@ u_int32_t r, v; { #ifdef EN_DEBUG_RANGE - if (r > MID_MAXOFF || (r % 4)) { - printf("en_write out of range, r=0x%x\n", r); - panic("en_write"); - } + if (r > MID_MAXOFF || (r % 4)) + panic("en_write out of range, r=0x%x", r); #endif bus_space_write_4(sc->en_memt, sc->en_base, r, v); @@ -1260,34 +1229,6 @@ caddr_t data; break; #endif /* SIOCSIFMTU */ -#ifdef ATM_PVCEXT - case SIOCSPVCTX: - if ((error = suser(curproc)) == 0) - error = en_pvctx(sc, (struct pvctxreq *)data); - break; - - case SIOCGPVCTX: - error = en_pvctxget(sc, (struct pvctxreq *)data); - break; - - case SIOCSPVCSIF: - do { - struct ifnet *shadow; - - if ((error = suser(curproc)) != 0) - break; - - if ((shadow = pvc_attach(ifp)) != NULL) { - snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), - "%s%d", shadow->if_name, shadow->if_unit); - } - else - error = ENOBUFS; - } while (0); - break; - -#endif /* ATM_PVCEXT */ - default: error = EINVAL; break; @@ -2019,6 +1960,7 @@ int chan; struct en_launch launch; int datalen = 0, dtqneed, len, ncells; u_int8_t *cp; + struct ifnet *ifp; #ifdef EN_DEBUG printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan); @@ -2162,7 +2104,9 @@ again: */ EN_COUNT(sc->launch); - sc->enif.if_opackets++; + ifp = &sc->enif; + ifp->if_opackets++; + if ((launch.atm_flags & EN_OBHDR) == 0) { EN_COUNT(sc->lheader); /* store tbd1/tbd2 in host byte order */ @@ -2177,7 +2121,7 @@ again: en_txlaunch(sc, chan, &launch); #if NBPFILTER > 0 - if (sc->enif.if_bpf) { + if (ifp->if_bpf) { /* * adjust the top of the mbuf to skip the pseudo atm header * (and TBD, if present) before passing the packet to bpf, @@ -2190,7 +2134,7 @@ again: launch.t->m_data += size; launch.t->m_len -= size; - BPF_MTAP(&sc->enif, launch.t); + BPF_MTAP(ifp, launch.t); launch.t->m_data -= size; launch.t->m_len += size; @@ -2592,6 +2536,7 @@ void *arg; struct en_softc *sc = (struct en_softc *) arg; struct mbuf *m; struct atm_pseudohdr ah; + struct ifnet *ifp; u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq; int lcv, idx, need_softserv = 0; @@ -2613,7 +2558,11 @@ void *arg; sc->sc_dev.dv_xname, reg, MID_INTBITS); #ifdef EN_DEBUG #ifdef DDB +#ifdef __FreeBSD__ + Debugger("en: unexpected error"); +#else Debugger(); +#endif #endif /* DDB */ sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */ #else @@ -2726,10 +2675,9 @@ void *arg; m = NULL; } else { IF_DEQUEUE(&sc->rxslot[slot].indma, m); - if (!m) { - printf("%s: lost mbuf in slot %d!\n", sc->sc_dev.dv_xname, slot); - panic("enintr: drqsync"); - } + if (!m) + panic("enintr: drqsync: %s: lost mbuf in slot %d!", + sc->sc_dev.dv_xname, slot); } /* do something with this mbuf */ if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { /* drain? */ @@ -2757,14 +2705,16 @@ void *arg; sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m, EN_DQ_LEN(drq), sc->rxslot[slot].rxhand); #endif -#if NBPFILTER > 0 - if (sc->enif.if_bpf) - BPF_MTAP(&sc->enif, m); -#endif /* NBPFILTER > 0 */ - sc->enif.if_ipackets++; + ifp = &sc->enif; + ifp->if_ipackets++; + +#if NBPFILTER > 0 + if (ifp->if_bpf) + BPF_MTAP(ifp, m); +#endif - atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand); + atm_input(ifp, &ah, m, sc->rxslot[slot].rxhand); } } @@ -2954,7 +2904,7 @@ defer: /* defer processing */ llc = (aal5 && (sc->rxslot[slot].atm_flags & ATM_PH_LLCSNAP)) ? 1 : 0; rbd = EN_READ(sc, cur); if (MID_RBD_ID(rbd) != MID_RBD_STDID) - panic("en_service: id mismatch\n"); + panic("en_service: id mismatch"); if (rbd & MID_RBD_T) { mlen = 0; /* we've got trash */ @@ -2967,6 +2917,8 @@ defer: /* defer processing */ mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */ fill = 0; } else { + struct ifnet *ifp; + tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE; pdu = cur + tlen - MID_PDU_SIZE; if (pdu >= stop) @@ -2974,12 +2926,25 @@ defer: /* defer processing */ pdu = EN_READ(sc, pdu); /* get PDU in correct byte order */ fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu); if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) { - printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname, - (rbd & MID_RBD_CRCERR) ? "CRC error" : "invalid AAL5 PDU length"); - printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n", - sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE, - MID_PDU_LEN(pdu), pdu); + static int first = 1; + + if (first) { + printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname, + (rbd & MID_RBD_CRCERR) ? + "CRC error" : "invalid AAL5 PDU length"); + printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n", + sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), + tlen - MID_RBD_SIZE, MID_PDU_LEN(pdu), pdu); +#ifndef EN_DEBUG + printf("CRC error report disabled from now on!\n"); + first = 0; +#endif + } fill = tlen; + + ifp = &sc->enif; + ifp->if_ierrors++; + } mlen = tlen - fill; } @@ -3481,234 +3446,4 @@ int unit, addr, len; } #endif -#ifdef ATM_PVCEXT -/* - * ATM PVC extention: shaper control and pvc shadow interfaces - */ - -/* txspeed conversion derived from linux drivers/atm/eni.c - by Werner Almesberger, EPFL LRC */ -static const int pre_div[] = { 4,16,128,2048 }; - -static int en_pcr2txspeed(pcr) - int pcr; -{ - int pre, res, div; - - if (pcr == 0 || pcr > 347222) - pre = res = 0; /* max rate */ - else { - for (pre = 0; pre < 3; pre++) - if (25000000/pre_div[pre]/64 <= pcr) - break; - div = pre_div[pre]*(pcr); -#if 1 - /* - * the shaper value should be rounded down, - * instead of rounded up. - * (which means "res" should be rounded up.) - */ - res = (25000000 + div -1)/div - 1; -#else - res = 25000000/div-1; -#endif - if (res < 0) - res = 0; - if (res > 63) - res = 63; - } - return ((pre << 6) + res); -} - -static int en_txspeed2pcr(txspeed) - int txspeed; -{ - int pre, res, pcr; - - pre = (txspeed >> 6) & 0x3; - res = txspeed & 0x3f; - pcr = 25000000 / pre_div[pre] / (res+1); - return (pcr); -} - -/* - * en_txctl selects a hardware transmit channel and sets the shaper value. - * en_txctl should be called after enabling the vc by en_rxctl - * since it assumes a transmit channel is already assigned by en_rxctl - * to the vc. - */ -static int en_txctl(sc, vci, joint_vci, pcr) - struct en_softc *sc; - int vci; - int joint_vci; - int pcr; -{ - int txspeed, txchan, c, s; - - if (pcr) - txspeed = en_pcr2txspeed(pcr); - else - txspeed = 0; - - s = splimp(); - txchan = sc->txvc2slot[vci]; - sc->txslot[txchan].nref--; - - /* select a slot */ - if (joint_vci != 0) - /* use the same channel */ - txchan = sc->txvc2slot[joint_vci]; - if (pcr == 0) - txchan = 0; - else { - for (c = 1, txchan = 1; c < EN_NTX; c++) { - if (sc->txslot[c].nref < sc->txslot[txchan].nref) - txchan = c; - if (sc->txslot[txchan].nref == 0) - break; - } - } - sc->txvc2slot[vci] = txchan; - sc->txslot[txchan].nref++; - - /* set the shaper parameter */ - sc->txspeed[vci] = (u_int8_t)txspeed; - - splx(s); -#ifdef EN_DEBUG - printf("VCI:%d PCR set to %d, tx channel %d\n", vci, pcr, txchan); - if (joint_vci != 0) - printf(" slot shared with VCI:%d\n", joint_vci); -#endif - return (0); -} - -static int en_pvctx(sc, pvcreq) - struct en_softc *sc; - struct pvctxreq *pvcreq; -{ - struct ifnet *ifp; - struct atm_pseudoioctl api; - struct atm_pseudohdr *pvc_aph, *pvc_joint; - int vci, joint_vci, pcr; - int error = 0; - - /* check vpi:vci values */ - pvc_aph = &pvcreq->pvc_aph; - pvc_joint = &pvcreq->pvc_joint; - - vci = ATM_PH_VCI(pvc_aph); - joint_vci = ATM_PH_VCI(pvc_joint); - pcr = pvcreq->pvc_pcr; - - if (ATM_PH_VPI(pvc_aph) != 0 || vci >= MID_N_VC || - ATM_PH_VPI(pvc_joint) != 0 || joint_vci >= MID_N_VC) - return (EADDRNOTAVAIL); - - if ((ifp = ifunit(pvcreq->pvc_ifname)) == NULL) - return (ENXIO); - - if (pcr < 0) { - /* negative pcr means disable the vc. */ - if (sc->rxvc2slot[vci] == RX_NONE) - /* already disabled */ - return 0; - - ATM_PH_FLAGS(&api.aph) = 0; - ATM_PH_VPI(&api.aph) = 0; - ATM_PH_SETVCI(&api.aph, vci); - api.rxhand = NULL; - - error = en_rxctl(sc, &api, 0); - - if (error == 0 && &sc->enif != ifp) { - /* clear vc info of shadow interface */ - ATM_PH_SETVCI(&api.aph, 0); - pvc_setaph(ifp, &api.aph); - } - return (error); - } - - if (&sc->enif == ifp) { - /* called for an en interface */ - if (sc->rxvc2slot[vci] == RX_NONE) { - /* vc is not active */ - printf("%s%d: en_pvctx: rx not active! vci=%d\n", - ifp->if_name, ifp->if_unit, vci); - return (EINVAL); - } - } - else { - /* called for a shadow interface */ - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { - printf("en_pvctx: if %s is not point-to-point!\n", - pvcreq->pvc_ifname); - return (EINVAL); - } - snprintf(pvcreq->pvc_ifname, sizeof(pvcreq->pvc_ifname), - "%s%d", sc->enif.if_name, sc->enif.if_unit); - - ATM_PH_FLAGS(&api.aph) = ATM_PH_PVCSIF | - (ATM_PH_FLAGS(pvc_aph) & (ATM_PH_AAL5|ATM_PH_LLCSNAP)); - ATM_PH_VPI(&api.aph) = 0; - ATM_PH_SETVCI(&api.aph, vci); - api.rxhand = ifp; - pvc_setaph(ifp, &api.aph); - - if (sc->rxvc2slot[vci] == RX_NONE) { - /* vc is not active, enable rx */ - error = en_rxctl(sc, &api, 1); - if (error) - return error; - } - else { - /* vc is already active, update aph in softc */ - sc->rxslot[sc->rxvc2slot[vci]].atm_flags = - ATM_PH_FLAGS(&api.aph); - } - - } - - error = en_txctl(sc, vci, joint_vci, pcr); - - if (error == 0) { - if (sc->txspeed[vci] != 0) - pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]); - else - pvcreq->pvc_pcr = 0; - } - - return error; -} - -static int en_pvctxget(sc, pvcreq) - struct en_softc *sc; - struct pvctxreq *pvcreq; -{ - struct atm_pseudohdr *pvc_aph; - int vci, slot; - - pvc_aph = &pvcreq->pvc_aph; - vci = ATM_PH_VCI(pvc_aph); - - if ((slot = sc->rxvc2slot[vci]) == RX_NONE) { - /* vc is not active */ - ATM_PH_FLAGS(pvc_aph) = 0; - pvcreq->pvc_pcr = -1; - } - else { - ATM_PH_FLAGS(pvc_aph) = sc->rxslot[slot].atm_flags; - ATM_PH_VPI(pvc_aph) = 0; - ATM_PH_SETVCI(pvc_aph, vci); - if (sc->txspeed[vci]) - pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]); - else - pvcreq->pvc_pcr = 0; - } - - return (0); -} - -#endif /* ATM_PVCEXT */ - #endif /* NEN > 0 || !defined(__FreeBSD__) */ diff --git a/sys/net/if_atm.h b/sys/net/if_atm.h index f1e2d8b..16b32a6 100644 --- a/sys/net/if_atm.h +++ b/sys/net/if_atm.h @@ -42,14 +42,6 @@ #endif #endif /* freebsd doesn't define _KERNEL */ -#ifndef NO_ATM_PVCEXT -/* - * ATM_PVCEXT enables PVC extention: VP/VC shaping - * and PVC shadow interfaces. - */ -#define ATM_PVCEXT /* enable pvc extention */ -#endif - #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) #define RTALLOC1(A,B) rtalloc1((A),(B)) #elif defined(__FreeBSD__) @@ -74,9 +66,6 @@ struct atm_pseudohdr { #define ATM_PH_AAL5 0x01 /* use AAL5? (0 == aal0) */ #define ATM_PH_LLCSNAP 0x02 /* use the LLC SNAP encoding (iff aal5) */ -#ifdef ATM_PVCEXT -#define ATM_PH_INERNAL 0x20 /* reserve for kernel internal use */ -#endif #define ATM_PH_DRIVER7 0x40 /* reserve for driver's use */ #define ATM_PH_DRIVER8 0x80 /* reserve for driver's use */ @@ -95,28 +84,6 @@ struct atm_pseudoioctl { #define SIOCATMENA _IOWR('a', 123, struct atm_pseudoioctl) /* enable */ #define SIOCATMDIS _IOWR('a', 124, struct atm_pseudoioctl) /* disable */ -#ifdef ATM_PVCEXT - -/* structure to control PVC transmitter */ -struct pvctxreq { - /* first entry must be compatible with struct ifreq */ - char pvc_ifname[IFNAMSIZ]; /* if name, e.g. "en0" */ - struct atm_pseudohdr pvc_aph; /* (flags) + vpi:vci */ - struct atm_pseudohdr pvc_joint; /* for vp shaping: another vc - to share the shaper */ - int pvc_pcr; /* peak cell rate (shaper value) */ -}; - -/* use ifioctl for now */ -#define SIOCSPVCTX _IOWR('i', 95, struct pvctxreq) -#define SIOCGPVCTX _IOWR('i', 96, struct pvctxreq) -#define SIOCSPVCSIF _IOWR('i', 97, struct ifreq) -#define SIOCGPVCSIF _IOWR('i', 98, struct ifreq) - -#ifdef _KERNEL -#define ATM_PH_PVCSIF ATM_PH_INERNAL /* pvc shadow interface */ -#endif -#endif /* ATM_PVCEXT */ /* * XXX forget all the garbage in if_llc.h and do it the easy way @@ -142,10 +109,4 @@ void atm_input __P((struct ifnet *, struct atm_pseudohdr *, int atm_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); #endif -#ifdef ATM_PVCEXT -char *shadow2if __P((char *)); -#ifdef _KERNEL -struct ifnet *pvc_attach __P((struct ifnet *)); -int pvc_setaph __P((struct ifnet *, struct atm_pseudohdr *)); -#endif -#endif + diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c index 9f56a9b..66cd09d 100644 --- a/sys/net/if_atmsubr.c +++ b/sys/net/if_atmsubr.c @@ -139,6 +139,10 @@ atm_output(ifp, m0, dst, rt0) #if defined(INET) || defined(INET6) case AF_INET: case AF_INET6: + if (dst->sa_family == AF_INET6) + etype = htons(ETHERTYPE_IPV6); + else + etype = htons(ETHERTYPE_IP); if (!atmresolve(rt, m, dst, &atmdst)) { m = NULL; /* XXX: atmresolve already free'd it */ @@ -146,18 +150,13 @@ atm_output(ifp, m0, dst, rt0) /* XXX: put ATMARP stuff here */ /* XXX: watch who frees m on failure */ } - if (dst->sa_family == AF_INET6) - etype = htons(ETHERTYPE_IPV6); - else - etype = htons(ETHERTYPE_IP); break; #endif /* INET || INET6 */ case AF_UNSPEC: /* - * XXX: bpfwrite or output from a pvc shadow if. - * assuming dst contains 12 bytes (atm pseudo - * header (4) + LLC/SNAP (8)) + * XXX: bpfwrite. assuming dst contains 12 bytes + * (atm pseudo header (4) + LLC/SNAP (8)) */ bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst)); @@ -242,18 +241,6 @@ atm_input(ifp, ah, m, rxhand) } ifp->if_ibytes += m->m_pkthdr.len; -#ifdef ATM_PVCEXT - if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) { - /* - * when PVC shadow interface is used, pointer to - * the shadow interface is passed as rxhand. - * override the receive interface of the packet. - */ - m->m_pkthdr.rcvif = (struct ifnet *)rxhand; - rxhand = NULL; - } -#endif /* ATM_PVCEXT */ - if (rxhand) { #ifdef NATM struct natmpcb *npcb = rxhand; @@ -336,6 +323,7 @@ atm_ifattach(ifp) ifp->if_hdrlen = 0; ifp->if_mtu = ATMMTU; ifp->if_output = atm_output; + ifp->if_snd.ifq_maxlen = 50; /* dummy */ #if defined(__NetBSD__) || defined(__OpenBSD__) for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; @@ -357,273 +345,3 @@ atm_ifattach(ifp) } } - -#ifdef ATM_PVCEXT -/* - * ATM PVC shadow interface: a trick to assign a shadow interface - * to a PVC. - * with shadow interface, each PVC looks like an individual - * Point-to-Point interface. - * as oposed to the NBMA model, a shadow interface is inherently - * multicast capable (no LANE/MARS required). - */ -struct pvcsif { - struct ifnet sif_shadow; /* shadow ifnet structure per pvc */ - struct atm_pseudohdr sif_aph; /* flags + vpi:vci */ - struct ifnet *sif_ifp; /* pointer to the genuine interface */ -}; - -static int pvc_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -static int pvc_ioctl __P((struct ifnet *, u_long, caddr_t)); - -/* - * create and attach per pvc shadow interface - * (currently detach is not supported) - */ -static int pvc_number = 0; - -struct ifnet * -pvc_attach(ifp) - struct ifnet *ifp; -{ - struct pvcsif *pvcsif; - struct ifnet *shadow; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - int s; - - MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif), - M_DEVBUF, M_WAITOK); - bzero(pvcsif, sizeof(struct pvcsif)); - - pvcsif->sif_ifp = ifp; - shadow = &pvcsif->sif_shadow; - - shadow->if_name = "pvc"; - shadow->if_unit = pvc_number++; - shadow->if_flags = ifp->if_flags | (IFF_POINTOPOINT | IFF_MULTICAST); - shadow->if_ioctl = pvc_ioctl; - shadow->if_output = pvc_output; - shadow->if_start = NULL; - shadow->if_mtu = ifp->if_mtu; - shadow->if_type = ifp->if_type; - shadow->if_addrlen = ifp->if_addrlen; - shadow->if_hdrlen = ifp->if_hdrlen; - shadow->if_softc = pvcsif; - shadow->if_snd.ifq_maxlen = 50; /* dummy */ - - s = splimp(); - if_attach(shadow); - -#if defined(__NetBSD__) || defined(__OpenBSD__) - for (ifa = shadow->if_addrlist.tqh_first; ifa != 0; - ifa = ifa->ifa_list.tqe_next) -#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) - for (ifa = shadow->if_addrhead.tqh_first; ifa; - ifa = ifa->ifa_link.tqe_next) -#elif defined(__FreeBSD__) || defined(__bsdi__) - for (ifa = shadow->if_addrlist; ifa; ifa = ifa->ifa_next) -#endif - if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_type = IFT_ATM; - sdl->sdl_alen = shadow->if_addrlen; - break; - } - splx(s); - - return (shadow); -} - -/* - * pvc_output relays the packet to atm_output along with vpi:vci info. - */ -static int -pvc_output(shadow, m, dst, rt) - struct ifnet *shadow; - struct mbuf *m; - struct sockaddr *dst; - struct rtentry *rt; -{ - struct pvcsif *pvcsif; - struct sockaddr dst_addr; - struct atmllc *atmllc; - u_int16_t etype = 0; - int error = 0; - - if ((shadow->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - senderr(ENETDOWN); - - pvcsif = shadow->if_softc; - if (ATM_PH_VCI(&pvcsif->sif_aph) == 0) - senderr(ENETDOWN); - - /* - * create a dummy sockaddr: (using bpfwrite interface) - * put atm pseudo header and llc/snap into sa_data (12 bytes) - * and mark it as AF_UNSPEC. - */ - if (dst) { - switch (dst->sa_family) { -#if defined(INET) || defined(INET6) - case AF_INET: - case AF_INET6: - if (dst->sa_family == AF_INET6) - etype = htons(ETHERTYPE_IPV6); - else - etype = htons(ETHERTYPE_IP); - break; -#endif - - default: - printf("%s%d: can't handle af%d\n", shadow->if_name, - shadow->if_unit, dst->sa_family); - senderr(EAFNOSUPPORT); - } - } - - dst_addr.sa_family = AF_UNSPEC; - bcopy(&pvcsif->sif_aph, dst_addr.sa_data, - sizeof(struct atm_pseudohdr)); - atmllc = (struct atmllc *) - (dst_addr.sa_data + sizeof(struct atm_pseudohdr)); - bcopy(ATMLLC_HDR, atmllc->llchdr, sizeof(atmllc->llchdr)); - ATM_LLC_SETTYPE(atmllc, etype); /* note: already in network order */ - - return atm_output(pvcsif->sif_ifp, m, &dst_addr, rt); - -bad: - if (m) - m_freem(m); - return (error); -} - -static int -pvc_ioctl(shadow, cmd, data) - struct ifnet *shadow; - u_long cmd; - caddr_t data; -{ - struct ifnet *ifp; - struct pvcsif *pvcsif; - struct ifreq *ifr = (struct ifreq *) data; - void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *) = NULL; - int error = 0; - - pvcsif = (struct pvcsif *)shadow->if_softc; - ifp = pvcsif->sif_ifp; - if (ifp == 0 || ifp->if_ioctl == 0) - return (EOPNOTSUPP); - - /* - * pre process - */ - switch (cmd) { - case SIOCGPVCSIF: - snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), - "%s%d", ifp->if_name, ifp->if_unit); - return (0); - - case SIOCGPVCTX: - do { - struct pvctxreq *pvcreq = (struct pvctxreq *)data; - - snprintf(pvcreq->pvc_ifname, - sizeof(pvcreq->pvc_ifname), "%s%d", - ifp->if_name, ifp->if_unit); - pvcreq->pvc_aph = pvcsif->sif_aph; - } while (0); - break; - - case SIOCADDMULTI: - case SIOCDELMULTI: - if (ifr == 0) - return (EAFNOSUPPORT); /* XXX */ - switch (ifr->ifr_addr.sa_family) { -#ifdef INET - case AF_INET: - return (0); -#endif -#ifdef INET6 - case AF_INET6: - return (0); -#endif - default: - return (EAFNOSUPPORT); - } - break; - case SIOCSIFADDR: - if (ifp->if_flags & IFF_UP) { - /* real if is already up */ - shadow->if_flags = ifp->if_flags | - (IFF_POINTOPOINT|IFF_MULTICAST); - return (0); - } - /* - * XXX: save the rtrequest field since the atm driver - * overwrites this field. - */ - ifa_rtrequest = ((struct ifaddr *)data)->ifa_rtrequest; - break; - - case SIOCSIFFLAGS: - if ((shadow->if_flags & IFF_UP) == 0) { - /* - * interface down. don't pass this to - * the real interface. - */ - return (0); - } - if (shadow->if_flags & IFF_UP) { - /* - * interface up. if the real if is already up, - * nothing to do. - */ - if (ifp->if_flags & IFF_UP) { - shadow->if_flags = ifp->if_flags | - (IFF_POINTOPOINT|IFF_MULTICAST); - return (0); - } - } - break; - } - - /* - * pass the ioctl to the genuine interface - */ - error = (*ifp->if_ioctl)(ifp, cmd, data); - - /* - * post process - */ - switch (cmd) { - case SIOCSIFMTU: - shadow->if_mtu = ifp->if_mtu; - break; - case SIOCSIFADDR: - /* restore rtrequest */ - ((struct ifaddr *)data)->ifa_rtrequest = ifa_rtrequest; - /* fall into... */ - case SIOCSIFFLAGS: - /* update if_flags */ - shadow->if_flags = ifp->if_flags - | (IFF_POINTOPOINT|IFF_MULTICAST); - break; - } - - return (error); -} - -int pvc_setaph(shadow, aph) - struct ifnet *shadow; - struct atm_pseudohdr *aph; -{ - struct pvcsif *pvcsif; - - pvcsif = shadow->if_softc; - bcopy(aph, &pvcsif->sif_aph, sizeof(struct atm_pseudohdr)); - return (0); -} - -#endif /* ATM_PVCEXT */ |