summaryrefslogtreecommitdiffstats
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
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.
-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