diff options
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/bpf.c | 14 | ||||
-rw-r--r-- | sys/net/if_atm.h | 42 | ||||
-rw-r--r-- | sys/net/if_atmsubr.c | 483 |
3 files changed, 409 insertions, 130 deletions
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 *)⁡ - - 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)); - } - - 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 */ |