summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkjc <kjc@FreeBSD.org>1998-07-29 05:35:16 +0000
committerkjc <kjc@FreeBSD.org>1998-07-29 05:35:16 +0000
commitbd9e5f5f5b5ac9cb1bcfd4be4ac99ce4fd518e15 (patch)
tree62f7c8492d4fd7faf52a9a0f3a13e97ae83bed96 /sys
parent50f3429a4832d3eeb70ad7d19a88c51c7021c04c (diff)
downloadFreeBSD-src-bd9e5f5f5b5ac9cb1bcfd4be4ac99ce4fd518e15.zip
FreeBSD-src-bd9e5f5f5b5ac9cb1bcfd4be4ac99ce4fd518e15.tar.gz
update ATM driver. (base version: midway.c 1.67 --> 1.68)
several new features are added: - support vc/vp shaping - support pvc shadow interface code cleanup: - remove WMAYBE related code. ENI WMAYBE DMA doen't work. - 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.) the code has been used for months in ALTQ and KAME IPv6. OKed by phk long time ago.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/en/midway.c780
-rw-r--r--sys/dev/en/midwayreg.h1
-rw-r--r--sys/dev/en/midwayvar.h3
-rw-r--r--sys/net/bpf.c14
-rw-r--r--sys/net/if_atm.h42
-rw-r--r--sys/net/if_atmsubr.c483
-rw-r--r--sys/netinet/if_atm.c3
7 files changed, 1053 insertions, 273 deletions
diff --git a/sys/dev/en/midway.c b/sys/dev/en/midway.c
index 91c1061..9e3b2d0 100644
--- a/sys/dev/en/midway.c
+++ b/sys/dev/en/midway.c
@@ -1,5 +1,5 @@
-/* $NetBSD: midway.c,v 1.25 1997/03/20 21:34:42 chuck Exp $ */
-/* (sync'd to midway.c 1.67) */
+/* $NetBSD: midway.c,v 1.30 1997/09/29 17:40:38 chuck Exp $ */
+/* (sync'd to midway.c 1.68) */
/*
*
@@ -46,7 +46,32 @@
* 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? */
@@ -58,16 +83,35 @@
#endif
#define EN_NOTXDMA 0 /* hook to disable tx dma only */
#define EN_NORXDMA 0 /* hook to disable rx dma only */
-#define EN_NOWMAYBE 1 /* hook to disable word maybe DMA */
- /* XXX: WMAYBE doesn't work, needs debugging */
#define EN_DDBHOOK 1 /* compile in ddb functions */
-#ifdef __FreeBSD__
-/* somehow, misaligned DMA doesn't work on FreeBSD with ENI card.
- * not sure if this is specific to FreeBSD.
- * anyway, always fix unaligned or word fragmented mbufs. --kjc */
-#define EN_FIXMBUF
+#if defined(MIDWAY_ADPONLY)
+#define EN_ENIDMAFIX 0 /* no ENI cards to worry about */
+#else
+#define EN_ENIDMAFIX 1 /* avoid byte DMA on the ENI card (see below) */
#endif
+/*
+ * note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card
+ * appears to be broken. it works just fine if there is no load... however
+ * when the card is loaded the data get corrupted. to see this, one only
+ * has to use "telnet" over ATM. do the following command in "telnet":
+ * cat /usr/share/misc/termcap
+ * "telnet" seems to generate lots of 1023 byte mbufs (which make great
+ * use of the byte aligner). watch "netstat -s" for checksum errors.
+ *
+ * I further tested this by adding a function that compared the transmit
+ * data on the card's SRAM with the data in the mbuf chain _after_ the
+ * "transmit DMA complete" interrupt. using the "telnet" test I got data
+ * mismatches where the byte-aligned data should have been. using ddb
+ * and en_dumpmem() I verified that the DTQs fed into the card were
+ * absolutely correct. thus, we are forced to concluded that the ENI
+ * hardware is buggy. note that the Adaptec version of the card works
+ * just fine with byte DMA.
+ *
+ * bottom line: we set EN_ENIDMAFIX to 1 to avoid byte DMAs on the ENI
+ * card.
+ */
+
#if defined(DIAGNOSTIC) && !defined(EN_DIAG)
#define EN_DIAG /* link in with master DIAG option */
#endif
@@ -97,28 +141,29 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/queue.h>
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
#include <sys/device.h>
#endif
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/proc.h>
#include <net/if.h>
#include <net/if_atm.h>
#include <vm/vm.h>
-#ifdef INET
+#if defined(INET) || defined(INET6)
+#include <netinet/in.h>
#include <netinet/if_atm.h>
#endif
#ifdef NATM
-#include <netinet/in.h>
#include <netnatm/natm.h>
#endif
-
#if !defined(sparc) && !defined(__FreeBSD__)
#include <machine/bus.h>
#endif
@@ -137,18 +182,24 @@
#include <dev/en/midwayvar.h>
#include <vm/pmap.h> /* for vtophys proto */
-/*
- * 2.1.x does not have if_softc. detect this by seeing if IFF_NOTRAILERS
- * is defined, as per kjc.
- */
-#ifdef IFF_NOTRAILERS
-#define MISSING_IF_SOFTC
-#else
+#ifndef IFF_NOTRAILERS
#define IFF_NOTRAILERS 0
#endif
#endif /* __FreeBSD__ */
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#ifdef __FreeBSD__
+#define BPFATTACH(ifp, dlt, hlen) bpfattach((ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m) bpf_mtap((ifp), (m))
+#else
+#define BPFATTACH(ifp, dlt, hlen) bpfattach(&(ifp)->if_bpf, (ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
+#endif
+#endif /* NBPFILTER > 0 */
+
/*
* params
*/
@@ -206,7 +257,7 @@ struct en_launch {
/*
* dma table (index by # of words)
*
- * plan A: use WMAYBE
+ * plan A: use WMAYBE (obsolete)
* plan B: avoid WMAYBE
*/
@@ -215,18 +266,6 @@ struct en_dmatab {
u_int8_t divshift; /* byte divisor */
};
-static struct en_dmatab en_dma_planA[] = {
- { 0, 0 }, /* 0 */ { MIDDMA_WORD, 2 }, /* 1 */
- { MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_4WMAYBE, 2}, /* 3 */
- { MIDDMA_4WORD, 4}, /* 4 */ { MIDDMA_8WMAYBE, 2}, /* 5 */
- { MIDDMA_8WMAYBE, 2}, /* 6 */ { MIDDMA_8WMAYBE, 2}, /* 7 */
- { MIDDMA_8WORD, 5}, /* 8 */ { MIDDMA_16WMAYBE, 2}, /* 9 */
- { MIDDMA_16WMAYBE,2}, /* 10 */ { MIDDMA_16WMAYBE, 2}, /* 11 */
- { MIDDMA_16WMAYBE,2}, /* 12 */ { MIDDMA_16WMAYBE, 2}, /* 13 */
- { MIDDMA_16WMAYBE,2}, /* 14 */ { MIDDMA_16WMAYBE, 2}, /* 15 */
- { MIDDMA_16WORD, 6}, /* 16 */
-};
-
static struct en_dmatab en_dma_planB[] = {
{ 0, 0 }, /* 0 */ { MIDDMA_WORD, 2}, /* 1 */
{ MIDDMA_2WORD, 3}, /* 2 */ { MIDDMA_WORD, 2}, /* 3 */
@@ -239,35 +278,50 @@ static struct en_dmatab en_dma_planB[] = {
{ MIDDMA_16WORD, 6}, /* 16 */
};
-static struct en_dmatab *en_dmaplan = en_dma_planA;
-
+static struct en_dmatab *en_dmaplan = en_dma_planB;
+
/*
* prototypes
*/
-STATIC int en_b2sz __P((int));
+STATIC INLINE int en_b2sz __P((int)) __attribute__ ((unused));
#ifdef EN_DDBHOOK
-int en_dump __P((int,int));
-int en_dumpmem __P((int,int,int));
-#endif
-STATIC void en_dmaprobe __P((struct en_softc *));
-STATIC int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *,
- u_int8_t *, int));
-STATIC int en_dqneed __P((struct en_softc *, caddr_t, u_int, u_int));
-STATIC void en_init __P((struct en_softc *));
-STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
-STATIC int en_k2sz __P((int));
-STATIC void en_loadvc __P((struct en_softc *, int));
-STATIC int en_mfix __P((struct en_softc *, struct mbuf **, struct mbuf *));
-STATIC struct mbuf *en_mget __P((struct en_softc *, u_int, u_int *));
-STATIC u_int32_t en_read __P((struct en_softc *, u_int32_t));
-STATIC int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *, int));
-STATIC void en_txdma __P((struct en_softc *, int));
-STATIC void en_txlaunch __P((struct en_softc *, int, struct en_launch *));
-STATIC void en_service __P((struct en_softc *));
-STATIC void en_start __P((struct ifnet *));
-STATIC int en_sz2b __P((int));
-STATIC void en_write __P((struct en_softc *, u_int32_t, u_int32_t));
+ int en_dump __P((int,int));
+ int en_dumpmem __P((int,int,int));
+#endif
+STATIC void en_dmaprobe __P((struct en_softc *));
+STATIC int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *,
+ u_int8_t *, int));
+STATIC INLINE int en_dqneed __P((struct en_softc *, caddr_t, u_int,
+ u_int)) __attribute__ ((unused));
+STATIC void en_init __P((struct en_softc *));
+STATIC int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));
+STATIC INLINE int en_k2sz __P((int)) __attribute__ ((unused));
+STATIC void en_loadvc __P((struct en_softc *, int));
+STATIC int en_mfix __P((struct en_softc *, struct mbuf **,
+ struct mbuf *));
+STATIC INLINE struct mbuf *en_mget __P((struct en_softc *, u_int,
+ u_int *)) __attribute__ ((unused));
+STATIC INLINE u_int32_t en_read __P((struct en_softc *,
+ u_int32_t)) __attribute__ ((unused));
+STATIC int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *,
+ int));
+STATIC void en_txdma __P((struct en_softc *, int));
+STATIC void en_txlaunch __P((struct en_softc *, int,
+ struct en_launch *));
+STATIC void en_service __P((struct en_softc *));
+STATIC void en_start __P((struct ifnet *));
+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
@@ -596,10 +650,14 @@ u_int totlen, *drqneed;
}
m->m_len = MLEN;
}
- if (top && totlen >= MINCLSIZE) {
+ if (totlen >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
- if (m->m_flags & M_EXT)
- m->m_len = MCLBYTES;
+ if ((m->m_flags & M_EXT) == 0) {
+ m_free(m);
+ m_freem(top);
+ return(NULL); /* out of mbuf clusters */
+ }
+ m->m_len = MCLBYTES;
}
m->m_len = min(totlen, m->m_len);
totlen -= m->m_len;
@@ -687,12 +745,6 @@ done_probe:
sc->bestburstlen, (sc->alburst) ? " (must align)" : "");
}
-#if 0 /* WMAYBE doesn't work, don't complain about it */
- /* check if en_dmaprobe disabled wmaybe */
- if (en_dmaplan == en_dma_planB)
- printf("%s: note: WMAYBE DMA has been disabled\n", sc->sc_dev.dv_xname);
-#endif
-
/*
* link into network subsystem and prepare card
*/
@@ -700,9 +752,7 @@ done_probe:
#if defined(__NetBSD__) || defined(__OpenBSD__)
bcopy(sc->sc_dev.dv_xname, sc->enif.if_xname, IFNAMSIZ);
#endif
-#if !defined(MISSING_IF_SOFTC)
sc->enif.if_softc = sc;
-#endif
ifp->if_flags = IFF_SIMPLEX|IFF_NOTRAILERS;
ifp->if_ioctl = en_ioctl;
ifp->if_output = atm_output;
@@ -749,11 +799,14 @@ done_probe:
printf("%s: EN_NTX/EN_TXSZ/EN_RXSZ too big\n", sc->sc_dev.dv_xname);
return;
}
-#if 1
- /* leave one entry in the ringbuf unused to avoid wraparound */
+
+ /*
+ * ensure that there is always one VC slot on the service list free
+ * so that we can tell the difference between a full and empty list.
+ */
if (sc->en_nrx >= MID_N_VC)
- sc->en_nrx = MID_N_VC - 1;
-#endif
+ sc->en_nrx = MID_N_VC - 1;
+
for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) {
sc->rxslot[lcv].rxhand = NULL;
sc->rxslot[lcv].oth_flags = ENOTHER_FREE;
@@ -788,6 +841,9 @@ done_probe:
printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n",
sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
+ printf("%s: End Station Identifier (mac address) %6D\n",
+ sc->sc_dev.dv_xname, sc->macaddr, ":");
+
/*
* final commit
*/
@@ -795,6 +851,9 @@ done_probe:
if_attach(ifp);
atm_ifattach(ifp);
+#if NBPFILTER > 0
+ BPFATTACH(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
+#endif
}
@@ -812,30 +871,67 @@ done_probe:
* p166: bestburstlen=64, alburst=0
*/
+#if 1 /* __FreeBSD__ */
+#define NBURSTS 3 /* number of bursts to use for dmaprobe */
+#define BOUNDARY 1024 /* test misaligned dma crossing the bounday.
+ should be n * 64. at least 64*(NBURSTS+1).
+ dell P6 with EDO DRAM has 1K bounday problem */
+#endif
+
STATIC void en_dmaprobe(sc)
struct en_softc *sc;
{
+#ifdef NBURSTS
+ /* be careful. kernel stack is only 8K */
+ u_int8_t buffer[BOUNDARY * 2 + 64 * (NBURSTS + 1)];
+#else
u_int32_t srcbuf[64], dstbuf[64];
+#endif
u_int8_t *sp, *dp;
- int bestalgn, bestnotalgn, lcv, try, fail;
+ int bestalgn, bestnotalgn, lcv, try;
sc->alburst = 0;
+#ifdef NBURSTS
+ /* setup src and dst buf at the end of the boundary */
+ sp = (u_int8_t *)roundup((unsigned long)buffer, 64);
+ while (((unsigned long)sp & (BOUNDARY - 1)) != (BOUNDARY - 64))
+ sp += 64;
+ dp = sp + BOUNDARY;
+
+ /*
+ * we can't dma across page boundary so that, if buf is at a page
+ * boundary, move it to the next page. but still either src or dst
+ * will be at the boundary, which should be ok.
+ */
+ if ((((unsigned long)sp + 64) & PAGE_MASK) == 0)
+ sp += 64;
+ if ((((unsigned long)dp + 64) & PAGE_MASK) == 0)
+ dp += 64;
+#else /* !NBURSTS */
sp = (u_int8_t *) srcbuf;
while ((((unsigned long) sp) % MIDDMA_MAXBURST) != 0)
sp += 4;
dp = (u_int8_t *) dstbuf;
while ((((unsigned long) dp) % MIDDMA_MAXBURST) != 0)
dp += 4;
+#endif /* !NBURSTS */
bestalgn = bestnotalgn = en_dmaprobe_doit(sc, sp, dp, 0);
for (lcv = 4 ; lcv < MIDDMA_MAXBURST ; lcv += 4) {
try = en_dmaprobe_doit(sc, sp+lcv, dp+lcv, 0);
+#ifdef NBURSTS
+ if (try < bestnotalgn) {
+ bestnotalgn = try;
+ break;
+ }
+#else
if (try < bestnotalgn)
bestnotalgn = try;
+#endif
}
if (bestalgn != bestnotalgn) /* need bursts aligned */
@@ -846,39 +942,21 @@ struct en_softc *sc;
sc->bestburstmask = sc->bestburstlen - 1; /* must be power of 2 */
sc->bestburstcode = en_sz2b(bestalgn);
- if (sc->bestburstlen <= 2*sizeof(u_int32_t))
- return; /* won't be using WMAYBE */
-
+#if 1 /* __FreeBSD__ */
/*
- * adaptec does not have (or need) wmaybe. do not bother testing
- * for it.
+ * correct pci chipsets should be able to handle misaligned-64-byte DMA.
+ * but there are too many broken chipsets around. we try to work around
+ * by finding the best workable dma size, but still some broken machines
+ * exhibit the problem later. so warn it here.
*/
- if (sc->is_adaptec) {
- /* XXX, actually don't need a DMA plan: adaptec is smarter than that */
- en_dmaplan = en_dma_planB;
- return;
- }
-
- /*
- * test that WMAYBE dma works like we think it should
- * (i.e. no alignment restrictions on host address other than alburst)
- */
-
- try = sc->bestburstlen - 4;
- fail = 0;
- fail += en_dmaprobe_doit(sc, sp, dp, try);
- for (lcv = 4 ; lcv < sc->bestburstlen ; lcv += 4) {
- fail += en_dmaprobe_doit(sc, sp+lcv, dp+lcv, try);
- if (sc->alburst)
- try -= 4;
- }
- if (EN_NOWMAYBE || fail) {
- if (fail)
- printf("%s: WARNING: WMAYBE DMA test failed %d time(s)\n",
- sc->sc_dev.dv_xname, fail);
- en_dmaplan = en_dma_planB; /* fall back to plan B */
+ if (bestalgn != 64 || sc->alburst != 0) {
+ printf("%s: WARNING: DMA test detects a broken PCI chipset!\n",
+ sc->sc_dev.dv_xname);
+ printf(" trying to work around the problem... but if this doesn't\n");
+ printf(" work for you, you'd better switch to a newer motherboard.\n");
}
-
+#endif /* 1 */
+ return;
}
@@ -912,7 +990,11 @@ int wmtry;
EN_WRITE(sc, MID_DST_RP(0), 0);
EN_WRITE(sc, MID_WP_ST_CNT(0), 0);
+#ifdef NBURSTS
+ for (lcv = 0 ; lcv < 64*NBURSTS; lcv++) /* set up sample data */
+#else
for (lcv = 0 ; lcv < 68 ; lcv++) /* set up sample data */
+#endif
sp[lcv] = lcv+1;
EN_WRITE(sc, MID_MAST_CSR, MID_MCSR_ENDMA); /* enable DMA (only) */
@@ -934,10 +1016,19 @@ int wmtry;
for (lcv = 8 ; lcv <= MIDDMA_MAXBURST ; lcv = lcv * 2) {
+#ifdef EN_DEBUG
+ printf("DMA test lcv=%d, sp=0x%x, dp=0x%x, wmtry=%d\n",
+ lcv, sp, dp, wmtry);
+#endif
+
/* zero SRAM and dest buffer */
for (cnt = 0 ; cnt < 1024; cnt += 4)
EN_WRITE(sc, MID_BUFOFF+cnt, 0); /* zero memory */
+#ifdef NBURSTS
+ for (cnt = 0 ; cnt < 64*NBURSTS; cnt++)
+#else
for (cnt = 0 ; cnt < 68 ; cnt++)
+#endif
dp[cnt] = 0;
if (wmtry) {
@@ -948,6 +1039,29 @@ int wmtry;
bcode = en_sz2b(lcv);
count = 1;
}
+#ifdef NBURSTS
+ /* build lcv-byte-DMA x NBURSTS */
+ if (sc->is_adaptec)
+ EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv*NBURSTS, 0, MID_DMA_END, 0));
+ else
+ EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ENI(count*NBURSTS, 0, MID_DMA_END, bcode));
+ EN_WRITE(sc, sc->dtq_chip+4, vtophys(sp));
+ EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
+ EN_WRITE(sc, MID_DMA_WRTX, MID_DTQ_A2REG(sc->dtq_chip));
+ cnt = 1000;
+ while (EN_READ(sc, MID_DMA_RDTX) != MID_DTQ_A2REG(sc->dtq_chip)) {
+ DELAY(1);
+ cnt--;
+ if (cnt == 0) {
+ printf("%s: unexpected timeout in tx DMA test\n", sc->sc_dev.dv_xname);
+/*
+ printf(" alignment=0x%x, burst size=%d, dma addr reg=0x%x\n",
+ (u_long)sp & 63, lcv, EN_READ(sc, MID_DMA_ADDR));
+*/
+ return(retval); /* timeout, give up */
+ }
+ }
+#else /* !NBURSTS */
if (sc->is_adaptec)
EN_WRITE(sc, sc->dtq_chip, MID_MK_TXQ_ADP(lcv, 0, MID_DMA_END, 0));
else
@@ -964,6 +1078,7 @@ int wmtry;
}
}
EN_WRAPADD(MID_DTQOFF, MID_DTQEND, sc->dtq_chip, 8);
+#endif /* !NBURSTS */
reg = EN_READ(sc, MID_INTACK);
if ((reg & MID_INT_DMA_TX) != MID_INT_DMA_TX) {
printf("%s: unexpected status in tx DMA test: 0x%x\n",
@@ -974,6 +1089,25 @@ int wmtry;
/* "return to sender..." address is known ... */
+#ifdef NBURSTS
+ /* build lcv-byte-DMA x NBURSTS */
+ if (sc->is_adaptec)
+ EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv*NBURSTS, 0, MID_DMA_END, 0));
+ else
+ EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ENI(count*NBURSTS, 0, MID_DMA_END, bcode));
+ EN_WRITE(sc, sc->drq_chip+4, vtophys(dp));
+ EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
+ EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
+ cnt = 1000;
+ while (EN_READ(sc, MID_DMA_RDRX) != MID_DRQ_A2REG(sc->drq_chip)) {
+ DELAY(1);
+ cnt--;
+ if (cnt == 0) {
+ printf("%s: unexpected timeout in rx DMA test\n", sc->sc_dev.dv_xname);
+ return(retval); /* timeout, give up */
+ }
+ }
+#else /* !NBURSTS */
if (sc->is_adaptec)
EN_WRITE(sc, sc->drq_chip, MID_MK_RXQ_ADP(lcv, 0, MID_DMA_END, 0));
else
@@ -990,6 +1124,7 @@ int wmtry;
}
}
EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_chip, 8);
+#endif /* !NBURSTS */
reg = EN_READ(sc, MID_INTACK);
if ((reg & MID_INT_DMA_RX) != MID_INT_DMA_RX) {
printf("%s: unexpected status in rx DMA test: 0x%x\n",
@@ -1002,8 +1137,15 @@ int wmtry;
return(bcmp(sp, dp, wmtry)); /* wmtry always exits here, no looping */
}
+#ifdef NBURSTS
+ if (bcmp(sp, dp, lcv * NBURSTS)) {
+/* printf("DMA test failed! lcv=%d, sp=0x%x, dp=0x%x\n", lcv, sp, dp); */
+ return(retval); /* failed, use last value */
+ }
+#else
if (bcmp(sp, dp, lcv))
return(retval); /* failed, use last value */
+#endif
retval = lcv;
@@ -1030,11 +1172,7 @@ EN_IOCTL_CMDT cmd;
caddr_t data;
{
-#ifdef MISSING_IF_SOFTC
- struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
-#else
struct en_softc *sc = (struct en_softc *) ifp->if_softc;
-#endif
struct ifaddr *ifa = (struct ifaddr *) data;
struct ifreq *ifr = (struct ifreq *) data;
struct atm_pseudoioctl *api = (struct atm_pseudoioctl *)data;
@@ -1079,8 +1217,9 @@ caddr_t data;
#endif
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
-#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET) {
+#if defined(INET) || defined(INET6)
+ if (ifa->ifa_addr->sa_family == AF_INET
+ || ifa->ifa_addr->sa_family == AF_INET6) {
en_reset(sc);
en_init(sc);
ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
@@ -1121,6 +1260,34 @@ caddr_t data;
break;
#endif /* SIOCSIFMTU */
+#ifdef ATM_PVCEXT
+ case SIOCSPVCTX:
+ if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) == 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->p_ucred, &curproc->p_acflag))
+ break;
+
+ if ((shadow = pvc_attach(ifp)) != NULL) {
+ sprintf(ifr->ifr_name, "%s%d",
+ shadow->if_name, shadow->if_unit);
+ }
+ else
+ error = ENOBUFS;
+ } while (0);
+ break;
+
+#endif /* ATM_PVCEXT */
+
default:
error = EINVAL;
break;
@@ -1296,6 +1463,7 @@ struct en_softc *sc;
break; /* >>> exit 'while(1)' here <<< */
m_freem(m);
}
+
sc->txslot[lcv].mbsize = 0;
}
@@ -1335,30 +1503,30 @@ struct en_softc *sc;
/*
* init obmem data structures: vc tab, dma q's, slist.
+ *
+ * note that we set drq_free/dtq_free to one less than the total number
+ * of DTQ/DRQs present. we do this because the card uses the condition
+ * (drq_chip == drq_us) to mean "list is empty"... but if you allow the
+ * circular list to be completely full then (drq_chip == drq_us) [i.e.
+ * the drq_us pointer will wrap all the way around]. by restricting
+ * the number of active requests to (N - 1) we prevent the list from
+ * becoming completely full. note that the card will sometimes give
+ * us an interrupt for a DTQ/DRQ we have already processes... this helps
+ * keep that interrupt from messing us up.
*/
for (vc = 0 ; vc < MID_N_VC ; vc++)
en_loadvc(sc, vc);
bzero(&sc->drq, sizeof(sc->drq));
-#if 1
- /* leave one entry in the ringbuf unused to avoid wraparound */
- sc->drq_free = MID_DRQ_N - 1;
-#else
- sc->drq_free = MID_DRQ_N;
-#endif
+ sc->drq_free = MID_DRQ_N - 1; /* N - 1 */
sc->drq_chip = MID_DRQ_REG2A(EN_READ(sc, MID_DMA_RDRX));
EN_WRITE(sc, MID_DMA_WRRX, MID_DRQ_A2REG(sc->drq_chip));
/* ensure zero queue */
sc->drq_us = sc->drq_chip;
bzero(&sc->dtq, sizeof(sc->dtq));
-#if 1
- /* leave one entry in the ringbuf unused to avoid wraparound */
- sc->dtq_free = MID_DTQ_N - 1;
-#else
- sc->dtq_free = MID_DTQ_N;
-#endif
+ sc->dtq_free = MID_DTQ_N - 1; /* N - 1 */
sc->dtq_chip = MID_DTQ_REG2A(EN_READ(sc, MID_DMA_RDTX));
EN_WRITE(sc, MID_DMA_WRTX, MID_DRQ_A2REG(sc->dtq_chip));
/* ensure zero queue */
@@ -1443,11 +1611,7 @@ STATIC void en_start(ifp)
struct ifnet *ifp;
{
-#ifdef MISSING_IF_SOFTC
- struct en_softc *sc = (struct en_softc *) en_cd.cd_devs[ifp->if_unit];
-#else
struct en_softc *sc = (struct en_softc *) ifp->if_softc;
-#endif
struct ifqueue *ifq = &ifp->if_snd; /* if INPUT QUEUE */
struct mbuf *m, *lastm, *prev;
struct atm_pseudohdr *ap, *new_ap;
@@ -1483,12 +1647,8 @@ struct ifnet *ifp;
mlen = 0;
prev = NULL;
while (1) {
-#ifdef EN_FIXMBUF
- /* if eni, always fix misaligned mbuf */
- if (!sc->is_adaptec || EN_NOTXDMA || !en_dma) {
-#else
- if (EN_NOTXDMA || !en_dma) { /* no DMA? */
-#endif
+ /* no DMA? */
+ if ((!sc->is_adaptec && EN_ENIDMAFIX) || EN_NOTXDMA || !en_dma) {
if ( (mtod(lastm, unsigned long) % sizeof(u_int32_t)) != 0 ||
((lastm->m_len % sizeof(u_int32_t)) != 0 && lastm->m_next)) {
first = (lastm == m);
@@ -1502,6 +1662,7 @@ struct ifnet *ifp;
}
prev = lastm;
}
+
mlen += lastm->m_len;
if (lastm->m_next == NULL)
break;
@@ -1624,6 +1785,7 @@ struct ifnet *ifp;
#endif
IF_ENQUEUE(&sc->txslot[txchan].q, m);
+
en_txdma(sc, txchan);
}
@@ -1634,6 +1796,85 @@ struct ifnet *ifp;
/*
* en_mfix: fix a stupid mbuf
*/
+
+#ifndef __FreeBSD__
+
+STATIC int en_mfix(sc, mm, prev)
+
+struct en_softc *sc;
+struct mbuf **mm, *prev;
+
+{
+ struct mbuf *m, *new;
+ u_char *d, *cp;
+ int off;
+ struct mbuf *nxt;
+
+ m = *mm;
+
+ EN_COUNT(sc->mfix); /* count # of calls */
+#ifdef EN_DEBUG
+ printf("%s: mfix mbuf m_data=%p, m_len=%d\n", sc->sc_dev.dv_xname,
+ m->m_data, m->m_len);
+#endif
+
+ d = mtod(m, u_char *);
+ off = ((unsigned long) d) % sizeof(u_int32_t);
+
+ if (off) {
+ if ((m->m_flags & M_EXT) == 0) {
+ bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */
+ d -= off;
+ m->m_data = (caddr_t)d;
+ } else {
+ /* can't write to an M_EXT mbuf since it may be shared */
+ MGET(new, M_DONTWAIT, MT_DATA);
+ if (!new) {
+ EN_COUNT(sc->mfixfail);
+ return(0);
+ }
+ MCLGET(new, M_DONTWAIT);
+ if ((new->m_flags & M_EXT) == 0) {
+ m_free(new);
+ EN_COUNT(sc->mfixfail);
+ return(0);
+ }
+ bcopy(d, new->m_data, m->m_len); /* ALIGN! (with costly data copy...) */
+ new->m_len = m->m_len;
+ new->m_next = m->m_next;
+ if (prev)
+ prev->m_next = new;
+ m_free(m);
+ *mm = m = new; /* note: 'd' now invalid */
+ }
+ }
+
+ off = m->m_len % sizeof(u_int32_t);
+ if (off == 0)
+ return(1);
+
+ d = mtod(m, u_char *) + m->m_len;
+ off = sizeof(u_int32_t) - off;
+
+ nxt = m->m_next;
+ while (off--) {
+ for ( ; nxt != NULL && nxt->m_len == 0 ; nxt = nxt->m_next)
+ /*null*/;
+ if (nxt == NULL) { /* out of data, zero fill */
+ *d++ = 0;
+ continue; /* next "off" */
+ }
+ cp = mtod(nxt, u_char *);
+ *d++ = *cp++;
+ m->m_len++;
+ nxt->m_len--;
+ nxt->m_data = (caddr_t)cp;
+ }
+ return(1);
+}
+
+#else /* __FreeBSD__ */
+
STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *);
STATIC int en_makeexclusive(sc, mm, prev)
@@ -1761,6 +2002,7 @@ struct mbuf **mm, *prev;
return(1);
}
+#endif /* __FreeBSD__ */
/*
* en_txdma: start trasmit DMA, if possible
@@ -1929,7 +2171,27 @@ again:
}
en_txlaunch(sc, chan, &launch);
-
+
+#if NBPFILTER > 0
+ if (sc->enif.if_bpf) {
+ /*
+ * adjust the top of the mbuf to skip the pseudo atm header
+ * (and TBD, if present) before passing the packet to bpf,
+ * restore it afterwards.
+ */
+ int size = sizeof(struct atm_pseudohdr);
+ if (launch.atm_flags & EN_OBHDR)
+ size += MID_TBD_SIZE;
+
+ launch.t->m_data += size;
+ launch.t->m_len -= size;
+
+ BPF_MTAP(&sc->enif, launch.t);
+
+ launch.t->m_data -= size;
+ launch.t->m_len += size;
+ }
+#endif /* NBPFILTER > 0 */
/*
* do some housekeeping and get the next packet
*/
@@ -2418,7 +2680,7 @@ void *arg;
m_freem(m);
}
EN_WRAPADD(0, MID_DTQ_N, idx, 1);
- }
+ };
sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */
}
@@ -2490,6 +2752,11 @@ 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++;
atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand);
@@ -2497,7 +2764,7 @@ void *arg;
}
EN_WRAPADD(0, MID_DRQ_N, idx, 1);
- }
+ };
sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */
if (sc->need_drqs) { /* true if we had a DRQ shortage */
@@ -2549,7 +2816,7 @@ void *arg;
printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci);
#endif
}
- }
+ };
}
/*
@@ -2688,6 +2955,9 @@ defer: /* defer processing */
mlen = 0; /* we've got trash */
fill = MID_RBD_SIZE;
EN_COUNT(sc->ttrash);
+#ifdef EN_DEBUG
+ printf("RX overflow lost %d cells!\n", MID_RBD_CNT(rbd));
+#endif
} else if (!aal5) {
mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */
fill = 0;
@@ -2699,11 +2969,11 @@ 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: invalid AAL5 PDU length or CRC detected, dropping frame\n",
- sc->sc_dev.dv_xname);
- printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x) CRCERR=%d\n",
- sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE,
- MID_PDU_LEN(pdu), pdu, (rbd & MID_RBD_CRCERR)?1: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);
fill = tlen;
}
mlen = tlen - fill;
@@ -3162,7 +3432,6 @@ int unit, level;
printf("0x%x ", sc->swslist[cnt]);
printf("\n");
}
-
}
return(0);
}
@@ -3199,5 +3468,234 @@ 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);
+ }
+ sprintf(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/dev/en/midwayreg.h b/sys/dev/en/midwayreg.h
index 3951ade..8f5891f 100644
--- a/sys/dev/en/midwayreg.h
+++ b/sys/dev/en/midwayreg.h
@@ -68,6 +68,7 @@ typedef caddr_t bus_addr_t;
/*
* prom & phy: not defined here
*/
+#define MID_ADPMACOFF 0xffc0 /* mac address offset (adaptec only) */
/*
* midway regs (byte offsets from en_base)
diff --git a/sys/dev/en/midwayvar.h b/sys/dev/en/midwayvar.h
index b9f41da..62d05bf 100644
--- a/sys/dev/en/midwayvar.h
+++ b/sys/dev/en/midwayvar.h
@@ -90,7 +90,6 @@ struct cfdriver {
#endif
-
/*
* softc
*/
@@ -162,6 +161,8 @@ struct en_softc {
struct ifqueue q; /* mbufs waiting for dma now */
} rxslot[EN_MAXNRX]; /* recv info */
+ u_int8_t macaddr[6]; /* card unique mac address */
+
/* stats */
u_int32_t vtrash; /* sw copy of counter */
u_int32_t otrash; /* sw copy of counter */
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 136edf0..c65bbff 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -37,7 +37,7 @@
*
* @(#)bpf.c 8.2 (Berkeley) 3/28/94
*
- * $Id: bpf.c,v 1.38 1998/02/20 13:46:57 bde Exp $
+ * $Id: bpf.c,v 1.39 1998/06/07 17:12:01 dfr Exp $
*/
#include "bpfilter.h"
@@ -197,6 +197,18 @@ bpf_movein(uio, linktype, mp, sockp, datlen)
hlen = 0;
break;
+#ifdef __FreeBSD__
+ case DLT_ATM_RFC1483:
+ /*
+ * en atm driver requires 4-byte atm pseudo header.
+ * though it isn't standard, vpi:vci needs to be
+ * specified anyway.
+ */
+ sockp->sa_family = AF_UNSPEC;
+ hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */
+ break;
+#endif
+
default:
return (EIO);
}
diff --git a/sys/net/if_atm.h b/sys/net/if_atm.h
index 1d7cd8e..f1e2d8b 100644
--- a/sys/net/if_atm.h
+++ b/sys/net/if_atm.h
@@ -42,6 +42,14 @@
#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__)
@@ -51,7 +59,6 @@
/*
* pseudo header for packet transmission
*/
-
struct atm_pseudohdr {
u_int8_t atm_ph[4]; /* flags+VPI+VCI1(msb)+VCI2(lsb) */
};
@@ -67,6 +74,9 @@ 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 */
@@ -85,6 +95,29 @@ 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
*/
@@ -109,3 +142,10 @@ 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 7df2626..a41bfaf 100644
--- a/sys/net/if_atmsubr.c
+++ b/sys/net/if_atmsubr.c
@@ -43,6 +43,9 @@
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
#include <net/if.h>
#include <net/netisr.h>
@@ -54,25 +57,16 @@
#include <netinet/in.h>
#include <netinet/if_atm.h>
#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
-#ifdef INET
+#if defined(INET) || defined(INET6)
#include <netinet/in_var.h>
#endif
#ifdef NATM
#include <netnatm/natm.h>
#endif
-#include "bpfilter.h"
-#if NBPFILTER > 0
-/*
- * bpf support.
- * the code is derived from if_loop.c.
- * bpf support should belong to the driver but it's easier to implement
- * it here since we can call bpf_mtap before atm_output adds a pseudo
- * header to the mbuf.
- * --kjc
- */
-#include <net/bpf.h>
-#endif /* NBPFILTER > 0 */
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6 0x86dd
+#endif
#define senderr(e) { error = (e); goto bad;}
@@ -104,11 +98,11 @@ atm_output(ifp, m0, dst, rt0)
register struct mbuf *m = m0;
register struct rtentry *rt;
struct atmllc *atmllc;
+ struct atmllc *llc_hdr = NULL;
u_int32_t atm_flags;
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
senderr(ENETDOWN);
- getmicrotime(&ifp->if_lastchange);
/*
* check route
@@ -142,8 +136,9 @@ atm_output(ifp, m0, dst, rt0)
*/
if (dst) {
switch (dst->sa_family) {
-#ifdef INET
+#if defined(INET) || defined(INET6)
case AF_INET:
+ case AF_INET6:
if (!atmresolve(rt, m, dst, &atmdst)) {
m = NULL;
/* XXX: atmresolve already free'd it */
@@ -151,10 +146,23 @@ atm_output(ifp, m0, dst, rt0)
/* XXX: put ATMARP stuff here */
/* XXX: watch who frees m on failure */
}
- etype = htons(ETHERTYPE_IP);
+ if (dst->sa_family == AF_INET6)
+ etype = htons(ETHERTYPE_IPV6);
+ else
+ etype = htons(ETHERTYPE_IP);
break;
-#endif
-
+#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))
+ */
+ bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
+ llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
+ break;
+
default:
#if defined(__NetBSD__) || defined(__OpenBSD__)
printf("%s: can't handle af%d\n", ifp->if_xname,
@@ -166,40 +174,6 @@ atm_output(ifp, m0, dst, rt0)
senderr(EAFNOSUPPORT);
}
-#if NBPFILTER > 0
- /* BPF write needs to be handled specially */
- if (dst && dst->sa_family == AF_UNSPEC) {
- dst->sa_family = *(mtod(m, int *));
- m->m_len -= sizeof(int);
- m->m_pkthdr.len -= sizeof(int);
- m->m_data += sizeof(int);
- }
-
- if (ifp->if_bpf) {
- /*
- * We need to prepend the address family as
- * a four byte field. Cons up a dummy header
- * to pacify bpf. This is safe because bpf
- * will only read from the mbuf (i.e., it won't
- * try to free it or keep a pointer a to it).
- */
- struct mbuf m1;
- u_int af = dst->sa_family;
-
- m1.m_next = m;
- m1.m_len = 4;
- m1.m_data = (char *)&af;
-
- s = splimp();
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- bpf_mtap(&ifp->if_bpf, &m0);
-#elif defined(__FreeBSD__)
- bpf_mtap(ifp, &m1);
-#endif
- splx(s);
- }
-#endif /* NBPFILTER > 0 */
-
/*
* must add atm_pseudohdr to data
*/
@@ -213,10 +187,14 @@ atm_output(ifp, m0, dst, rt0)
*ad = atmdst;
if (atm_flags & ATM_PH_LLCSNAP) {
atmllc = (struct atmllc *)(ad + 1);
- bcopy(ATMLLC_HDR, atmllc->llchdr,
- sizeof(atmllc->llchdr));
- ATM_LLC_SETTYPE(atmllc, etype);
+ if (llc_hdr == NULL) {
+ bcopy(ATMLLC_HDR, atmllc->llchdr,
+ sizeof(atmllc->llchdr));
+ ATM_LLC_SETTYPE(atmllc, etype);
/* note: already in network order */
+ }
+ else
+ bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
}
}
@@ -224,7 +202,6 @@ atm_output(ifp, m0, dst, rt0)
* Queue message on interface, and start output if interface
* not yet active.
*/
-
s = splimp();
if (IF_QFULL(&ifp->if_snd)) {
IF_DROP(&ifp->if_snd);
@@ -263,82 +240,76 @@ atm_input(ifp, ah, m, rxhand)
m_freem(m);
return;
}
- getmicrotime(&ifp->if_lastchange);
ifp->if_ibytes += m->m_pkthdr.len;
-#if NBPFILTER > 0
- if (ifp->if_bpf) {
+#ifdef ATM_PVCEXT
+ if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) {
/*
- * We need to prepend the address family as
- * a four byte field. Cons up a dummy header
- * to pacify bpf. This is safe because bpf
- * will only read from the mbuf (i.e., it won't
- * try to free it or keep a pointer to it).
+ * when PVC shadow interface is used, pointer to
+ * the shadow interface is passed as rxhand.
+ * override the receive interface of the packet.
*/
- struct mbuf m0;
- u_int af = AF_INET;
-
- m0.m_next = m;
- m0.m_len = 4;
- m0.m_data = (char *)&af;
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- bpf_mtap(&ifp->if_bpf, &m0);
-#elif defined(__FreeBSD__)
- bpf_mtap(ifp, &m0);
-#endif
+ m->m_pkthdr.rcvif = (struct ifnet *)rxhand;
+ rxhand = NULL;
}
-#endif /* NBPFILTER > 0 */
+#endif /* ATM_PVCEXT */
if (rxhand) {
#ifdef NATM
- struct natmpcb *npcb = rxhand;
- s = splimp(); /* in case 2 atm cards @ diff lvls */
- npcb->npcb_inq++; /* count # in queue */
- splx(s);
- schednetisr(NETISR_NATM);
- inq = &natmintrq;
- m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
+ struct natmpcb *npcb = rxhand;
+ s = splimp(); /* in case 2 atm cards @ diff lvls */
+ npcb->npcb_inq++; /* count # in queue */
+ splx(s);
+ schednetisr(NETISR_NATM);
+ inq = &natmintrq;
+ m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
#else
- printf("atm_input: NATM detected but not configured in kernel\n");
- m_freem(m);
- return;
+ printf("atm_input: NATM detected but not configured in kernel\n");
+ m_freem(m);
+ return;
#endif
} else {
- /*
- * handle LLC/SNAP header, if present
- */
- if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
- struct atmllc *alc;
- if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0)
- return; /* failed */
- alc = mtod(m, struct atmllc *);
- if (bcmp(alc, ATMLLC_HDR, 6)) {
+ /*
+ * handle LLC/SNAP header, if present
+ */
+ if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
+ struct atmllc *alc;
+ if (m->m_len < sizeof(*alc) &&
+ (m = m_pullup(m, sizeof(*alc))) == 0)
+ return; /* failed */
+ alc = mtod(m, struct atmllc *);
+ if (bcmp(alc, ATMLLC_HDR, 6)) {
#if defined(__NetBSD__) || defined(__OpenBSD__)
- printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
- ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
+ printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
+ ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
#elif defined(__FreeBSD__) || defined(__bsdi__)
- printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
- ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
+ printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
+ ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
#endif
- m_freem(m);
- return;
- }
- etype = ATM_LLC_TYPE(alc);
- m_adj(m, sizeof(*alc));
- }
-
- switch (etype) {
+ m_freem(m);
+ return;
+ }
+ etype = ATM_LLC_TYPE(alc);
+ m_adj(m, sizeof(*alc));
+ }
+
+ switch (etype) {
#ifdef INET
- case ETHERTYPE_IP:
- schednetisr(NETISR_IP);
- inq = &ipintrq;
- break;
+ case ETHERTYPE_IP:
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+#endif
+#ifdef INET6
+ case ETHERTYPE_IPV6:
+ schednetisr(NETISR_IPV6);
+ inq = &ip6intrq;
+ break;
#endif
- default:
- m_freem(m);
- return;
- }
+ default:
+ m_freem(m);
+ return;
+ }
}
s = splimp();
@@ -369,18 +340,12 @@ atm_ifattach(ifp)
#if defined(__NetBSD__) || defined(__OpenBSD__)
for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
ifa = ifa->ifa_list.tqe_next)
-#elif defined(__FreeBSD__) && ((__FreeBSD__ > 2) || defined(_NET_IF_VAR_H_))
-/*
- * for FreeBSD-3.0. 3.0-SNAP-970124 still sets -D__FreeBSD__=2!
- * XXX -- for now, use newly-introduced "net/if_var.h" as an identifier.
- * need a better way to identify 3.0. -- kjc
- */
+#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
for (ifa = ifp->if_addrhead.tqh_first; ifa;
ifa = ifa->ifa_link.tqe_next)
#elif defined(__FreeBSD__) || defined(__bsdi__)
for (ifa = ifp->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;
@@ -390,11 +355,273 @@ atm_ifattach(ifp)
#endif
break;
}
-#if NBPFILTER > 0
+
+}
+
+#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__)
- bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
-#elif defined(__FreeBSD__)
- bpfattach(ifp, DLT_NULL, sizeof(u_int));
+ 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:
+ sprintf(ifr->ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
+ return (0);
+
+ case SIOCGPVCTX:
+ do {
+ struct pvctxreq *pvcreq = (struct pvctxreq *)data;
+
+ sprintf(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
-#endif /* NBPFILTER > 0 */
+#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 */
diff --git a/sys/netinet/if_atm.c b/sys/netinet/if_atm.c
index 1c60ef0..020e5ac 100644
--- a/sys/netinet/if_atm.c
+++ b/sys/netinet/if_atm.c
@@ -39,10 +39,11 @@
#include "opt_inet.h"
#include "opt_natm.h"
-#ifdef INET
+#if defined(INET) || defined(INET6)
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/queue.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
OpenPOWER on IntegriCloud