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.
This commit is contained in:
parent
542f2aacfa
commit
4f53e3cc7a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=37939
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 *)⁡
|
||||
|
||||
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 *)⁡
|
||||
|
||||
#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));
|
||||
}
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
etype = ATM_LLC_TYPE(alc);
|
||||
m_adj(m, sizeof(*alc));
|
||||
}
|
||||
|
||||
switch (etype) {
|
||||
switch (etype) {
|
||||
#ifdef INET
|
||||
case ETHERTYPE_IP:
|
||||
schednetisr(NETISR_IP);
|
||||
inq = &ipintrq;
|
||||
break;
|
||||
case ETHERTYPE_IP:
|
||||
schednetisr(NETISR_IP);
|
||||
inq = &ipintrq;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
#ifdef INET6
|
||||
case ETHERTYPE_IPV6:
|
||||
schednetisr(NETISR_IPV6);
|
||||
inq = &ip6intrq;
|
||||
break;
|
||||
#endif
|
||||
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
|
||||
#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));
|
||||
#endif
|
||||
#endif /* 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__)
|
||||
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
|
||||
#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 */
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user