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
This commit is contained in:
Kenjiro Cho 1999-05-08 14:23:40 +00:00
parent 4173e42044
commit 0ce8bd9571
3 changed files with 62 additions and 648 deletions

View File

@ -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
ifp = &sc->enif;
ifp->if_ipackets++;
#if NBPFILTER > 0
if (sc->enif.if_bpf)
BPF_MTAP(&sc->enif, m);
#endif /* NBPFILTER > 0 */
if (ifp->if_bpf)
BPF_MTAP(ifp, m);
#endif
sc->enif.if_ipackets++;
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__) */

View File

@ -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

View File

@ -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 */