summaryrefslogtreecommitdiffstats
path: root/sys/net/if_atmsubr.c
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/net/if_atmsubr.c
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/net/if_atmsubr.c')
-rw-r--r--sys/net/if_atmsubr.c483
1 files changed, 355 insertions, 128 deletions
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 */
OpenPOWER on IntegriCloud