if_atmsubr.c revision 37939
125603Skjc/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ 225603Skjc 325603Skjc/* 425603Skjc * 525603Skjc * Copyright (c) 1996 Charles D. Cranor and Washington University. 625603Skjc * All rights reserved. 725603Skjc * 825603Skjc * Redistribution and use in source and binary forms, with or without 925603Skjc * modification, are permitted provided that the following conditions 1025603Skjc * are met: 1125603Skjc * 1. Redistributions of source code must retain the above copyright 1225603Skjc * notice, this list of conditions and the following disclaimer. 1325603Skjc * 2. Redistributions in binary form must reproduce the above copyright 1425603Skjc * notice, this list of conditions and the following disclaimer in the 1525603Skjc * documentation and/or other materials provided with the distribution. 1625603Skjc * 3. All advertising materials mentioning features or use of this software 1725603Skjc * must display the following acknowledgement: 1825603Skjc * This product includes software developed by Charles D. Cranor and 1925603Skjc * Washington University. 2025603Skjc * 4. The name of the author may not be used to endorse or promote products 2125603Skjc * derived from this software without specific prior written permission. 2225603Skjc * 2325603Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2425603Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2525603Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2625603Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2725603Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2825603Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2925603Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3025603Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3125603Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3225603Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3325603Skjc */ 3425603Skjc 3525603Skjc/* 3625603Skjc * if_atmsubr.c 3725603Skjc */ 3825603Skjc 3932350Seivind#include "opt_inet.h" 4032925Seivind#include "opt_natm.h" 4132350Seivind 4225603Skjc#include <sys/param.h> 4325603Skjc#include <sys/systm.h> 4425603Skjc#include <sys/mbuf.h> 4525603Skjc#include <sys/socket.h> 4637939Skjc#include <sys/sockio.h> 4737939Skjc#include <sys/malloc.h> 4837939Skjc#include <sys/errno.h> 4925603Skjc 5025603Skjc#include <net/if.h> 5125603Skjc#include <net/netisr.h> 5225603Skjc#include <net/route.h> 5325603Skjc#include <net/if_dl.h> 5425603Skjc#include <net/if_types.h> 5525603Skjc#include <net/if_atm.h> 5625603Skjc 5725603Skjc#include <netinet/in.h> 5825603Skjc#include <netinet/if_atm.h> 5925603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 6037939Skjc#if defined(INET) || defined(INET6) 6125603Skjc#include <netinet/in_var.h> 6225603Skjc#endif 6325603Skjc#ifdef NATM 6425603Skjc#include <netnatm/natm.h> 6525603Skjc#endif 6625603Skjc 6737939Skjc#ifndef ETHERTYPE_IPV6 6837939Skjc#define ETHERTYPE_IPV6 0x86dd 6937939Skjc#endif 7025603Skjc 7125603Skjc#define senderr(e) { error = (e); goto bad;} 7225603Skjc 7325603Skjc/* 7425603Skjc * atm_output: ATM output routine 7525603Skjc * inputs: 7625603Skjc * "ifp" = ATM interface to output to 7725603Skjc * "m0" = the packet to output 7825603Skjc * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 7925603Skjc * "rt0" = the route to use 8025603Skjc * returns: error code [0 == ok] 8125603Skjc * 8225603Skjc * note: special semantic: if (dst == NULL) then we assume "m" already 8325603Skjc * has an atm_pseudohdr on it and just send it directly. 8425603Skjc * [for native mode ATM output] if dst is null, then 8525603Skjc * rt0 must also be NULL. 8625603Skjc */ 8725603Skjc 8825603Skjcint 8925603Skjcatm_output(ifp, m0, dst, rt0) 9025603Skjc register struct ifnet *ifp; 9125603Skjc struct mbuf *m0; 9225603Skjc struct sockaddr *dst; 9325603Skjc struct rtentry *rt0; 9425603Skjc{ 9525603Skjc u_int16_t etype = 0; /* if using LLC/SNAP */ 9625603Skjc int s, error = 0, sz; 9725603Skjc struct atm_pseudohdr atmdst, *ad; 9825603Skjc register struct mbuf *m = m0; 9925603Skjc register struct rtentry *rt; 10025603Skjc struct atmllc *atmllc; 10137939Skjc struct atmllc *llc_hdr = NULL; 10225603Skjc u_int32_t atm_flags; 10325603Skjc 10425603Skjc if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 10525603Skjc senderr(ENETDOWN); 10625603Skjc 10725603Skjc /* 10825603Skjc * check route 10925603Skjc */ 11025603Skjc if ((rt = rt0) != NULL) { 11125603Skjc 11225603Skjc if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ 11325603Skjc if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL) 11425603Skjc rt->rt_refcnt--; 11525603Skjc else 11625603Skjc senderr(EHOSTUNREACH); 11725603Skjc } 11825603Skjc 11925603Skjc if (rt->rt_flags & RTF_GATEWAY) { 12025603Skjc if (rt->rt_gwroute == 0) 12125603Skjc goto lookup; 12225603Skjc if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 12325603Skjc rtfree(rt); rt = rt0; 12425603Skjc lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0); 12525603Skjc if ((rt = rt->rt_gwroute) == 0) 12625603Skjc senderr(EHOSTUNREACH); 12725603Skjc } 12825603Skjc } 12925603Skjc 13025603Skjc /* XXX: put RTF_REJECT code here if doing ATMARP */ 13125603Skjc 13225603Skjc } 13325603Skjc 13425603Skjc /* 13525603Skjc * check for non-native ATM traffic (dst != NULL) 13625603Skjc */ 13725603Skjc if (dst) { 13825603Skjc switch (dst->sa_family) { 13937939Skjc#if defined(INET) || defined(INET6) 14025603Skjc case AF_INET: 14137939Skjc case AF_INET6: 14225603Skjc if (!atmresolve(rt, m, dst, &atmdst)) { 14325603Skjc m = NULL; 14425603Skjc /* XXX: atmresolve already free'd it */ 14525603Skjc senderr(EHOSTUNREACH); 14625603Skjc /* XXX: put ATMARP stuff here */ 14725603Skjc /* XXX: watch who frees m on failure */ 14825603Skjc } 14937939Skjc if (dst->sa_family == AF_INET6) 15037939Skjc etype = htons(ETHERTYPE_IPV6); 15137939Skjc else 15237939Skjc etype = htons(ETHERTYPE_IP); 15325603Skjc break; 15437939Skjc#endif /* INET || INET6 */ 15525603Skjc 15637939Skjc case AF_UNSPEC: 15737939Skjc /* 15837939Skjc * XXX: bpfwrite or output from a pvc shadow if. 15937939Skjc * assuming dst contains 12 bytes (atm pseudo 16037939Skjc * header (4) + LLC/SNAP (8)) 16137939Skjc */ 16237939Skjc bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 16337939Skjc llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst)); 16437939Skjc break; 16537939Skjc 16625603Skjc default: 16725603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 16825603Skjc printf("%s: can't handle af%d\n", ifp->if_xname, 16925603Skjc dst->sa_family); 17025603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 17125603Skjc printf("%s%d: can't handle af%d\n", ifp->if_name, 17225603Skjc ifp->if_unit, dst->sa_family); 17325603Skjc#endif 17425603Skjc senderr(EAFNOSUPPORT); 17525603Skjc } 17625603Skjc 17725603Skjc /* 17825603Skjc * must add atm_pseudohdr to data 17925603Skjc */ 18025603Skjc sz = sizeof(atmdst); 18125603Skjc atm_flags = ATM_PH_FLAGS(&atmdst); 18225603Skjc if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */ 18325603Skjc M_PREPEND(m, sz, M_DONTWAIT); 18425603Skjc if (m == 0) 18525603Skjc senderr(ENOBUFS); 18625603Skjc ad = mtod(m, struct atm_pseudohdr *); 18725603Skjc *ad = atmdst; 18825603Skjc if (atm_flags & ATM_PH_LLCSNAP) { 18925603Skjc atmllc = (struct atmllc *)(ad + 1); 19037939Skjc if (llc_hdr == NULL) { 19137939Skjc bcopy(ATMLLC_HDR, atmllc->llchdr, 19237939Skjc sizeof(atmllc->llchdr)); 19337939Skjc ATM_LLC_SETTYPE(atmllc, etype); 19425603Skjc /* note: already in network order */ 19537939Skjc } 19637939Skjc else 19737939Skjc bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 19825603Skjc } 19925603Skjc } 20025603Skjc 20125603Skjc /* 20225603Skjc * Queue message on interface, and start output if interface 20325603Skjc * not yet active. 20425603Skjc */ 20525603Skjc s = splimp(); 20625603Skjc if (IF_QFULL(&ifp->if_snd)) { 20725603Skjc IF_DROP(&ifp->if_snd); 20825603Skjc splx(s); 20925603Skjc senderr(ENOBUFS); 21025603Skjc } 21125603Skjc ifp->if_obytes += m->m_pkthdr.len; 21225603Skjc IF_ENQUEUE(&ifp->if_snd, m); 21325603Skjc if ((ifp->if_flags & IFF_OACTIVE) == 0) 21425603Skjc (*ifp->if_start)(ifp); 21525603Skjc splx(s); 21625603Skjc return (error); 21725603Skjc 21825603Skjcbad: 21925603Skjc if (m) 22025603Skjc m_freem(m); 22125603Skjc return (error); 22225603Skjc} 22325603Skjc 22425603Skjc/* 22525603Skjc * Process a received ATM packet; 22625603Skjc * the packet is in the mbuf chain m. 22725603Skjc */ 22825603Skjcvoid 22925603Skjcatm_input(ifp, ah, m, rxhand) 23025603Skjc struct ifnet *ifp; 23125603Skjc register struct atm_pseudohdr *ah; 23225603Skjc struct mbuf *m; 23325603Skjc void *rxhand; 23425603Skjc{ 23525603Skjc register struct ifqueue *inq; 23625603Skjc u_int16_t etype = ETHERTYPE_IP; /* default */ 23725603Skjc int s; 23825603Skjc 23925603Skjc if ((ifp->if_flags & IFF_UP) == 0) { 24025603Skjc m_freem(m); 24125603Skjc return; 24225603Skjc } 24325603Skjc ifp->if_ibytes += m->m_pkthdr.len; 24425603Skjc 24537939Skjc#ifdef ATM_PVCEXT 24637939Skjc if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) { 24725603Skjc /* 24837939Skjc * when PVC shadow interface is used, pointer to 24937939Skjc * the shadow interface is passed as rxhand. 25037939Skjc * override the receive interface of the packet. 25125603Skjc */ 25237939Skjc m->m_pkthdr.rcvif = (struct ifnet *)rxhand; 25337939Skjc rxhand = NULL; 25425603Skjc } 25537939Skjc#endif /* ATM_PVCEXT */ 25625603Skjc 25725603Skjc if (rxhand) { 25825603Skjc#ifdef NATM 25937939Skjc struct natmpcb *npcb = rxhand; 26037939Skjc s = splimp(); /* in case 2 atm cards @ diff lvls */ 26137939Skjc npcb->npcb_inq++; /* count # in queue */ 26237939Skjc splx(s); 26337939Skjc schednetisr(NETISR_NATM); 26437939Skjc inq = &natmintrq; 26537939Skjc m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 26625603Skjc#else 26737939Skjc printf("atm_input: NATM detected but not configured in kernel\n"); 26837939Skjc m_freem(m); 26937939Skjc return; 27025603Skjc#endif 27125603Skjc } else { 27237939Skjc /* 27337939Skjc * handle LLC/SNAP header, if present 27437939Skjc */ 27537939Skjc if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 27637939Skjc struct atmllc *alc; 27737939Skjc if (m->m_len < sizeof(*alc) && 27837939Skjc (m = m_pullup(m, sizeof(*alc))) == 0) 27937939Skjc return; /* failed */ 28037939Skjc alc = mtod(m, struct atmllc *); 28137939Skjc if (bcmp(alc, ATMLLC_HDR, 6)) { 28225603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 28337939Skjc printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", 28437939Skjc ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 28525603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 28637939Skjc printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", 28737939Skjc ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 28825603Skjc#endif 28937939Skjc m_freem(m); 29037939Skjc return; 29137939Skjc } 29237939Skjc etype = ATM_LLC_TYPE(alc); 29337939Skjc m_adj(m, sizeof(*alc)); 29437939Skjc } 29525603Skjc 29637939Skjc switch (etype) { 29725603Skjc#ifdef INET 29837939Skjc case ETHERTYPE_IP: 29937939Skjc schednetisr(NETISR_IP); 30037939Skjc inq = &ipintrq; 30137939Skjc break; 30225603Skjc#endif 30337939Skjc#ifdef INET6 30437939Skjc case ETHERTYPE_IPV6: 30537939Skjc schednetisr(NETISR_IPV6); 30637939Skjc inq = &ip6intrq; 30737939Skjc break; 30837939Skjc#endif 30937939Skjc default: 31037939Skjc m_freem(m); 31137939Skjc return; 31237939Skjc } 31325603Skjc } 31425603Skjc 31525603Skjc s = splimp(); 31625603Skjc if (IF_QFULL(inq)) { 31725603Skjc IF_DROP(inq); 31825603Skjc m_freem(m); 31925603Skjc } else 32025603Skjc IF_ENQUEUE(inq, m); 32125603Skjc splx(s); 32225603Skjc} 32325603Skjc 32425603Skjc/* 32525603Skjc * Perform common duties while attaching to interface list 32625603Skjc */ 32725603Skjcvoid 32825603Skjcatm_ifattach(ifp) 32925603Skjc register struct ifnet *ifp; 33025603Skjc{ 33125603Skjc register struct ifaddr *ifa; 33225603Skjc register struct sockaddr_dl *sdl; 33325603Skjc 33425603Skjc ifp->if_type = IFT_ATM; 33525603Skjc ifp->if_addrlen = 0; 33625603Skjc ifp->if_hdrlen = 0; 33725603Skjc ifp->if_mtu = ATMMTU; 33825603Skjc ifp->if_output = atm_output; 33925603Skjc 34025603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 34125603Skjc for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; 34225603Skjc ifa = ifa->ifa_list.tqe_next) 34337939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) 34425603Skjc for (ifa = ifp->if_addrhead.tqh_first; ifa; 34525603Skjc ifa = ifa->ifa_link.tqe_next) 34625603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 34725603Skjc for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 34825603Skjc#endif 34925603Skjc if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 35025603Skjc sdl->sdl_family == AF_LINK) { 35125603Skjc sdl->sdl_type = IFT_ATM; 35225603Skjc sdl->sdl_alen = ifp->if_addrlen; 35325603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 35425603Skjc bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 35525603Skjc#endif 35625603Skjc break; 35725603Skjc } 35837939Skjc 35937939Skjc} 36037939Skjc 36137939Skjc#ifdef ATM_PVCEXT 36237939Skjc/* 36337939Skjc * ATM PVC shadow interface: a trick to assign a shadow interface 36437939Skjc * to a PVC. 36537939Skjc * with shadow interface, each PVC looks like an individual 36637939Skjc * Point-to-Point interface. 36737939Skjc * as oposed to the NBMA model, a shadow interface is inherently 36837939Skjc * multicast capable (no LANE/MARS required). 36937939Skjc */ 37037939Skjcstruct pvcsif { 37137939Skjc struct ifnet sif_shadow; /* shadow ifnet structure per pvc */ 37237939Skjc struct atm_pseudohdr sif_aph; /* flags + vpi:vci */ 37337939Skjc struct ifnet *sif_ifp; /* pointer to the genuine interface */ 37437939Skjc}; 37537939Skjc 37637939Skjcstatic int pvc_output __P((struct ifnet *, struct mbuf *, 37737939Skjc struct sockaddr *, struct rtentry *)); 37837939Skjcstatic int pvc_ioctl __P((struct ifnet *, u_long, caddr_t)); 37937939Skjc 38037939Skjc/* 38137939Skjc * create and attach per pvc shadow interface 38237939Skjc * (currently detach is not supported) 38337939Skjc */ 38437939Skjcstatic int pvc_number = 0; 38537939Skjc 38637939Skjcstruct ifnet * 38737939Skjcpvc_attach(ifp) 38837939Skjc struct ifnet *ifp; 38937939Skjc{ 39037939Skjc struct pvcsif *pvcsif; 39137939Skjc struct ifnet *shadow; 39237939Skjc struct ifaddr *ifa; 39337939Skjc struct sockaddr_dl *sdl; 39437939Skjc int s; 39537939Skjc 39637939Skjc MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif), 39737939Skjc M_DEVBUF, M_WAITOK); 39837939Skjc bzero(pvcsif, sizeof(struct pvcsif)); 39937939Skjc 40037939Skjc pvcsif->sif_ifp = ifp; 40137939Skjc shadow = &pvcsif->sif_shadow; 40237939Skjc 40337939Skjc shadow->if_name = "pvc"; 40437939Skjc shadow->if_unit = pvc_number++; 40537939Skjc shadow->if_flags = ifp->if_flags | (IFF_POINTOPOINT | IFF_MULTICAST); 40637939Skjc shadow->if_ioctl = pvc_ioctl; 40737939Skjc shadow->if_output = pvc_output; 40837939Skjc shadow->if_start = NULL; 40937939Skjc shadow->if_mtu = ifp->if_mtu; 41037939Skjc shadow->if_type = ifp->if_type; 41137939Skjc shadow->if_addrlen = ifp->if_addrlen; 41237939Skjc shadow->if_hdrlen = ifp->if_hdrlen; 41337939Skjc shadow->if_softc = pvcsif; 41437939Skjc shadow->if_snd.ifq_maxlen = 50; /* dummy */ 41537939Skjc 41637939Skjc s = splimp(); 41737939Skjc if_attach(shadow); 41837939Skjc 41925603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 42037939Skjc for (ifa = shadow->if_addrlist.tqh_first; ifa != 0; 42137939Skjc ifa = ifa->ifa_list.tqe_next) 42237939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) 42337939Skjc for (ifa = shadow->if_addrhead.tqh_first; ifa; 42437939Skjc ifa = ifa->ifa_link.tqe_next) 42537939Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 42637939Skjc for (ifa = shadow->if_addrlist; ifa; ifa = ifa->ifa_next) 42725603Skjc#endif 42837939Skjc if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 42937939Skjc sdl->sdl_family == AF_LINK) { 43037939Skjc sdl->sdl_type = IFT_ATM; 43137939Skjc sdl->sdl_alen = shadow->if_addrlen; 43237939Skjc break; 43337939Skjc } 43437939Skjc splx(s); 43537939Skjc 43637939Skjc return (shadow); 43725603Skjc} 43837939Skjc 43937939Skjc/* 44037939Skjc * pvc_output relays the packet to atm_output along with vpi:vci info. 44137939Skjc */ 44237939Skjcstatic int 44337939Skjcpvc_output(shadow, m, dst, rt) 44437939Skjc struct ifnet *shadow; 44537939Skjc struct mbuf *m; 44637939Skjc struct sockaddr *dst; 44737939Skjc struct rtentry *rt; 44837939Skjc{ 44937939Skjc struct pvcsif *pvcsif; 45037939Skjc struct sockaddr dst_addr; 45137939Skjc struct atmllc *atmllc; 45237939Skjc u_int16_t etype = 0; 45337939Skjc int error = 0; 45437939Skjc 45537939Skjc if ((shadow->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 45637939Skjc senderr(ENETDOWN); 45737939Skjc 45837939Skjc pvcsif = shadow->if_softc; 45937939Skjc if (ATM_PH_VCI(&pvcsif->sif_aph) == 0) 46037939Skjc senderr(ENETDOWN); 46137939Skjc 46237939Skjc /* 46337939Skjc * create a dummy sockaddr: (using bpfwrite interface) 46437939Skjc * put atm pseudo header and llc/snap into sa_data (12 bytes) 46537939Skjc * and mark it as AF_UNSPEC. 46637939Skjc */ 46737939Skjc if (dst) { 46837939Skjc switch (dst->sa_family) { 46937939Skjc#if defined(INET) || defined(INET6) 47037939Skjc case AF_INET: 47137939Skjc case AF_INET6: 47237939Skjc if (dst->sa_family == AF_INET6) 47337939Skjc etype = htons(ETHERTYPE_IPV6); 47437939Skjc else 47537939Skjc etype = htons(ETHERTYPE_IP); 47637939Skjc break; 47737939Skjc#endif 47837939Skjc 47937939Skjc default: 48037939Skjc printf("%s%d: can't handle af%d\n", shadow->if_name, 48137939Skjc shadow->if_unit, dst->sa_family); 48237939Skjc senderr(EAFNOSUPPORT); 48337939Skjc } 48437939Skjc } 48537939Skjc 48637939Skjc dst_addr.sa_family = AF_UNSPEC; 48737939Skjc bcopy(&pvcsif->sif_aph, dst_addr.sa_data, 48837939Skjc sizeof(struct atm_pseudohdr)); 48937939Skjc atmllc = (struct atmllc *) 49037939Skjc (dst_addr.sa_data + sizeof(struct atm_pseudohdr)); 49137939Skjc bcopy(ATMLLC_HDR, atmllc->llchdr, sizeof(atmllc->llchdr)); 49237939Skjc ATM_LLC_SETTYPE(atmllc, etype); /* note: already in network order */ 49337939Skjc 49437939Skjc return atm_output(pvcsif->sif_ifp, m, &dst_addr, rt); 49537939Skjc 49637939Skjcbad: 49737939Skjc if (m) 49837939Skjc m_freem(m); 49937939Skjc return (error); 50037939Skjc} 50137939Skjc 50237939Skjcstatic int 50337939Skjcpvc_ioctl(shadow, cmd, data) 50437939Skjc struct ifnet *shadow; 50537939Skjc u_long cmd; 50637939Skjc caddr_t data; 50737939Skjc{ 50837939Skjc struct ifnet *ifp; 50937939Skjc struct pvcsif *pvcsif; 51037939Skjc struct ifreq *ifr = (struct ifreq *) data; 51137939Skjc void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *) = NULL; 51237939Skjc int error = 0; 51337939Skjc 51437939Skjc pvcsif = (struct pvcsif *)shadow->if_softc; 51537939Skjc ifp = pvcsif->sif_ifp; 51637939Skjc if (ifp == 0 || ifp->if_ioctl == 0) 51737939Skjc return (EOPNOTSUPP); 51837939Skjc 51937939Skjc /* 52037939Skjc * pre process 52137939Skjc */ 52237939Skjc switch (cmd) { 52337939Skjc case SIOCGPVCSIF: 52437939Skjc sprintf(ifr->ifr_name, "%s%d", ifp->if_name, ifp->if_unit); 52537939Skjc return (0); 52637939Skjc 52737939Skjc case SIOCGPVCTX: 52837939Skjc do { 52937939Skjc struct pvctxreq *pvcreq = (struct pvctxreq *)data; 53037939Skjc 53137939Skjc sprintf(pvcreq->pvc_ifname, "%s%d", 53237939Skjc ifp->if_name, ifp->if_unit); 53337939Skjc pvcreq->pvc_aph = pvcsif->sif_aph; 53437939Skjc } while (0); 53537939Skjc break; 53637939Skjc 53737939Skjc case SIOCADDMULTI: 53837939Skjc case SIOCDELMULTI: 53937939Skjc if (ifr == 0) 54037939Skjc return (EAFNOSUPPORT); /* XXX */ 54137939Skjc switch (ifr->ifr_addr.sa_family) { 54237939Skjc#ifdef INET 54337939Skjc case AF_INET: 54437939Skjc return (0); 54537939Skjc#endif 54637939Skjc#ifdef INET6 54737939Skjc case AF_INET6: 54837939Skjc return (0); 54937939Skjc#endif 55037939Skjc default: 55137939Skjc return (EAFNOSUPPORT); 55237939Skjc } 55337939Skjc break; 55437939Skjc case SIOCSIFADDR: 55537939Skjc if (ifp->if_flags & IFF_UP) { 55637939Skjc /* real if is already up */ 55737939Skjc shadow->if_flags = ifp->if_flags | 55837939Skjc (IFF_POINTOPOINT|IFF_MULTICAST); 55937939Skjc return (0); 56037939Skjc } 56137939Skjc /* 56237939Skjc * XXX: save the rtrequest field since the atm driver 56337939Skjc * overwrites this field. 56437939Skjc */ 56537939Skjc ifa_rtrequest = ((struct ifaddr *)data)->ifa_rtrequest; 56637939Skjc break; 56737939Skjc 56837939Skjc case SIOCSIFFLAGS: 56937939Skjc if ((shadow->if_flags & IFF_UP) == 0) { 57037939Skjc /* 57137939Skjc * interface down. don't pass this to 57237939Skjc * the real interface. 57337939Skjc */ 57437939Skjc return (0); 57537939Skjc } 57637939Skjc if (shadow->if_flags & IFF_UP) { 57737939Skjc /* 57837939Skjc * interface up. if the real if is already up, 57937939Skjc * nothing to do. 58037939Skjc */ 58137939Skjc if (ifp->if_flags & IFF_UP) { 58237939Skjc shadow->if_flags = ifp->if_flags | 58337939Skjc (IFF_POINTOPOINT|IFF_MULTICAST); 58437939Skjc return (0); 58537939Skjc } 58637939Skjc } 58737939Skjc break; 58837939Skjc } 58937939Skjc 59037939Skjc /* 59137939Skjc * pass the ioctl to the genuine interface 59237939Skjc */ 59337939Skjc error = (*ifp->if_ioctl)(ifp, cmd, data); 59437939Skjc 59537939Skjc /* 59637939Skjc * post process 59737939Skjc */ 59837939Skjc switch (cmd) { 59937939Skjc case SIOCSIFMTU: 60037939Skjc shadow->if_mtu = ifp->if_mtu; 60137939Skjc break; 60237939Skjc case SIOCSIFADDR: 60337939Skjc /* restore rtrequest */ 60437939Skjc ((struct ifaddr *)data)->ifa_rtrequest = ifa_rtrequest; 60537939Skjc /* fall into... */ 60637939Skjc case SIOCSIFFLAGS: 60737939Skjc /* update if_flags */ 60837939Skjc shadow->if_flags = ifp->if_flags 60937939Skjc | (IFF_POINTOPOINT|IFF_MULTICAST); 61037939Skjc break; 61137939Skjc } 61237939Skjc 61337939Skjc return (error); 61437939Skjc} 61537939Skjc 61637939Skjcint pvc_setaph(shadow, aph) 61737939Skjc struct ifnet *shadow; 61837939Skjc struct atm_pseudohdr *aph; 61937939Skjc{ 62037939Skjc struct pvcsif *pvcsif; 62137939Skjc 62237939Skjc pvcsif = shadow->if_softc; 62337939Skjc bcopy(aph, &pvcsif->sif_aph, sizeof(struct atm_pseudohdr)); 62437939Skjc return (0); 62537939Skjc} 62637939Skjc 62737939Skjc#endif /* ATM_PVCEXT */ 628