if_atmsubr.c revision 32350
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" 4032350Seivind 4125603Skjc#include <sys/param.h> 4225603Skjc#include <sys/systm.h> 4325603Skjc#include <sys/mbuf.h> 4425603Skjc#include <sys/socket.h> 4525603Skjc 4625603Skjc#include <net/if.h> 4725603Skjc#include <net/netisr.h> 4825603Skjc#include <net/route.h> 4925603Skjc#include <net/if_dl.h> 5025603Skjc#include <net/if_types.h> 5125603Skjc#include <net/if_atm.h> 5225603Skjc 5325603Skjc#include <netinet/in.h> 5425603Skjc#include <netinet/if_atm.h> 5525603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 5625603Skjc#ifdef INET 5725603Skjc#include <netinet/in_var.h> 5825603Skjc#endif 5925603Skjc#ifdef NATM 6025603Skjc#include <netnatm/natm.h> 6125603Skjc#endif 6225603Skjc 6325603Skjc#include "bpfilter.h" 6425603Skjc#if NBPFILTER > 0 6525603Skjc/* 6625603Skjc * bpf support. 6725603Skjc * the code is derived from if_loop.c. 6825603Skjc * bpf support should belong to the driver but it's easier to implement 6925603Skjc * it here since we can call bpf_mtap before atm_output adds a pseudo 7025603Skjc * header to the mbuf. 7125603Skjc * --kjc 7225603Skjc */ 7325603Skjc#include <net/bpf.h> 7425603Skjc#endif /* NBPFILTER > 0 */ 7525603Skjc 7625603Skjc#define senderr(e) { error = (e); goto bad;} 7725603Skjc 7825603Skjc/* 7925603Skjc * atm_output: ATM output routine 8025603Skjc * inputs: 8125603Skjc * "ifp" = ATM interface to output to 8225603Skjc * "m0" = the packet to output 8325603Skjc * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 8425603Skjc * "rt0" = the route to use 8525603Skjc * returns: error code [0 == ok] 8625603Skjc * 8725603Skjc * note: special semantic: if (dst == NULL) then we assume "m" already 8825603Skjc * has an atm_pseudohdr on it and just send it directly. 8925603Skjc * [for native mode ATM output] if dst is null, then 9025603Skjc * rt0 must also be NULL. 9125603Skjc */ 9225603Skjc 9325603Skjcint 9425603Skjcatm_output(ifp, m0, dst, rt0) 9525603Skjc register struct ifnet *ifp; 9625603Skjc struct mbuf *m0; 9725603Skjc struct sockaddr *dst; 9825603Skjc struct rtentry *rt0; 9925603Skjc{ 10025603Skjc u_int16_t etype = 0; /* if using LLC/SNAP */ 10125603Skjc int s, error = 0, sz; 10225603Skjc struct atm_pseudohdr atmdst, *ad; 10325603Skjc register struct mbuf *m = m0; 10425603Skjc register struct rtentry *rt; 10525603Skjc struct atmllc *atmllc; 10625603Skjc u_int32_t atm_flags; 10725603Skjc 10825603Skjc if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 10925603Skjc senderr(ENETDOWN); 11031264Sbde gettime(&ifp->if_lastchange); 11125603Skjc 11225603Skjc /* 11325603Skjc * check route 11425603Skjc */ 11525603Skjc if ((rt = rt0) != NULL) { 11625603Skjc 11725603Skjc if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ 11825603Skjc if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL) 11925603Skjc rt->rt_refcnt--; 12025603Skjc else 12125603Skjc senderr(EHOSTUNREACH); 12225603Skjc } 12325603Skjc 12425603Skjc if (rt->rt_flags & RTF_GATEWAY) { 12525603Skjc if (rt->rt_gwroute == 0) 12625603Skjc goto lookup; 12725603Skjc if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 12825603Skjc rtfree(rt); rt = rt0; 12925603Skjc lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0); 13025603Skjc if ((rt = rt->rt_gwroute) == 0) 13125603Skjc senderr(EHOSTUNREACH); 13225603Skjc } 13325603Skjc } 13425603Skjc 13525603Skjc /* XXX: put RTF_REJECT code here if doing ATMARP */ 13625603Skjc 13725603Skjc } 13825603Skjc 13925603Skjc /* 14025603Skjc * check for non-native ATM traffic (dst != NULL) 14125603Skjc */ 14225603Skjc if (dst) { 14325603Skjc switch (dst->sa_family) { 14425603Skjc#ifdef INET 14525603Skjc case AF_INET: 14625603Skjc if (!atmresolve(rt, m, dst, &atmdst)) { 14725603Skjc m = NULL; 14825603Skjc /* XXX: atmresolve already free'd it */ 14925603Skjc senderr(EHOSTUNREACH); 15025603Skjc /* XXX: put ATMARP stuff here */ 15125603Skjc /* XXX: watch who frees m on failure */ 15225603Skjc } 15325603Skjc etype = htons(ETHERTYPE_IP); 15425603Skjc break; 15525603Skjc#endif 15625603Skjc 15725603Skjc default: 15825603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 15925603Skjc printf("%s: can't handle af%d\n", ifp->if_xname, 16025603Skjc dst->sa_family); 16125603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 16225603Skjc printf("%s%d: can't handle af%d\n", ifp->if_name, 16325603Skjc ifp->if_unit, dst->sa_family); 16425603Skjc#endif 16525603Skjc senderr(EAFNOSUPPORT); 16625603Skjc } 16725603Skjc 16825603Skjc#if NBPFILTER > 0 16925603Skjc /* BPF write needs to be handled specially */ 17025603Skjc if (dst && dst->sa_family == AF_UNSPEC) { 17125603Skjc dst->sa_family = *(mtod(m, int *)); 17225603Skjc m->m_len -= sizeof(int); 17325603Skjc m->m_pkthdr.len -= sizeof(int); 17425603Skjc m->m_data += sizeof(int); 17525603Skjc } 17625603Skjc 17725603Skjc if (ifp->if_bpf) { 17825603Skjc /* 17925603Skjc * We need to prepend the address family as 18025603Skjc * a four byte field. Cons up a dummy header 18125603Skjc * to pacify bpf. This is safe because bpf 18225603Skjc * will only read from the mbuf (i.e., it won't 18325603Skjc * try to free it or keep a pointer a to it). 18425603Skjc */ 18525603Skjc struct mbuf m1; 18625603Skjc u_int af = dst->sa_family; 18725603Skjc 18825603Skjc m1.m_next = m; 18925603Skjc m1.m_len = 4; 19025603Skjc m1.m_data = (char *)⁡ 19125603Skjc 19225603Skjc s = splimp(); 19325603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 19425603Skjc bpf_mtap(&ifp->if_bpf, &m0); 19525603Skjc#elif defined(__FreeBSD__) 19625603Skjc bpf_mtap(ifp, &m1); 19725603Skjc#endif 19825603Skjc splx(s); 19925603Skjc } 20025603Skjc#endif /* NBPFILTER > 0 */ 20125603Skjc 20225603Skjc /* 20325603Skjc * must add atm_pseudohdr to data 20425603Skjc */ 20525603Skjc sz = sizeof(atmdst); 20625603Skjc atm_flags = ATM_PH_FLAGS(&atmdst); 20725603Skjc if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */ 20825603Skjc M_PREPEND(m, sz, M_DONTWAIT); 20925603Skjc if (m == 0) 21025603Skjc senderr(ENOBUFS); 21125603Skjc ad = mtod(m, struct atm_pseudohdr *); 21225603Skjc *ad = atmdst; 21325603Skjc if (atm_flags & ATM_PH_LLCSNAP) { 21425603Skjc atmllc = (struct atmllc *)(ad + 1); 21525603Skjc bcopy(ATMLLC_HDR, atmllc->llchdr, 21625603Skjc sizeof(atmllc->llchdr)); 21725603Skjc ATM_LLC_SETTYPE(atmllc, etype); 21825603Skjc /* note: already in network order */ 21925603Skjc } 22025603Skjc } 22125603Skjc 22225603Skjc /* 22325603Skjc * Queue message on interface, and start output if interface 22425603Skjc * not yet active. 22525603Skjc */ 22625603Skjc 22725603Skjc s = splimp(); 22825603Skjc if (IF_QFULL(&ifp->if_snd)) { 22925603Skjc IF_DROP(&ifp->if_snd); 23025603Skjc splx(s); 23125603Skjc senderr(ENOBUFS); 23225603Skjc } 23325603Skjc ifp->if_obytes += m->m_pkthdr.len; 23425603Skjc IF_ENQUEUE(&ifp->if_snd, m); 23525603Skjc if ((ifp->if_flags & IFF_OACTIVE) == 0) 23625603Skjc (*ifp->if_start)(ifp); 23725603Skjc splx(s); 23825603Skjc return (error); 23925603Skjc 24025603Skjcbad: 24125603Skjc if (m) 24225603Skjc m_freem(m); 24325603Skjc return (error); 24425603Skjc} 24525603Skjc 24625603Skjc/* 24725603Skjc * Process a received ATM packet; 24825603Skjc * the packet is in the mbuf chain m. 24925603Skjc */ 25025603Skjcvoid 25125603Skjcatm_input(ifp, ah, m, rxhand) 25225603Skjc struct ifnet *ifp; 25325603Skjc register struct atm_pseudohdr *ah; 25425603Skjc struct mbuf *m; 25525603Skjc void *rxhand; 25625603Skjc{ 25725603Skjc register struct ifqueue *inq; 25825603Skjc u_int16_t etype = ETHERTYPE_IP; /* default */ 25925603Skjc int s; 26025603Skjc 26125603Skjc if ((ifp->if_flags & IFF_UP) == 0) { 26225603Skjc m_freem(m); 26325603Skjc return; 26425603Skjc } 26531264Sbde gettime(&ifp->if_lastchange); 26625603Skjc ifp->if_ibytes += m->m_pkthdr.len; 26725603Skjc 26825603Skjc#if NBPFILTER > 0 26925603Skjc if (ifp->if_bpf) { 27025603Skjc /* 27125603Skjc * We need to prepend the address family as 27225603Skjc * a four byte field. Cons up a dummy header 27325603Skjc * to pacify bpf. This is safe because bpf 27425603Skjc * will only read from the mbuf (i.e., it won't 27525603Skjc * try to free it or keep a pointer to it). 27625603Skjc */ 27725603Skjc struct mbuf m0; 27825603Skjc u_int af = AF_INET; 27925603Skjc 28025603Skjc m0.m_next = m; 28125603Skjc m0.m_len = 4; 28225603Skjc m0.m_data = (char *)⁡ 28325603Skjc 28425603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 28525603Skjc bpf_mtap(&ifp->if_bpf, &m0); 28625603Skjc#elif defined(__FreeBSD__) 28725603Skjc bpf_mtap(ifp, &m0); 28825603Skjc#endif 28925603Skjc } 29025603Skjc#endif /* NBPFILTER > 0 */ 29125603Skjc 29225603Skjc if (rxhand) { 29325603Skjc#ifdef NATM 29425603Skjc struct natmpcb *npcb = rxhand; 29525603Skjc s = splimp(); /* in case 2 atm cards @ diff lvls */ 29625603Skjc npcb->npcb_inq++; /* count # in queue */ 29725603Skjc splx(s); 29825603Skjc schednetisr(NETISR_NATM); 29925603Skjc inq = &natmintrq; 30025603Skjc m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 30125603Skjc#else 30225603Skjc printf("atm_input: NATM detected but not configured in kernel\n"); 30325603Skjc m_freem(m); 30425603Skjc return; 30525603Skjc#endif 30625603Skjc } else { 30725603Skjc /* 30825603Skjc * handle LLC/SNAP header, if present 30925603Skjc */ 31025603Skjc if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 31125603Skjc struct atmllc *alc; 31225603Skjc if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0) 31325603Skjc return; /* failed */ 31425603Skjc alc = mtod(m, struct atmllc *); 31525603Skjc if (bcmp(alc, ATMLLC_HDR, 6)) { 31625603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 31725603Skjc printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", 31825603Skjc ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 31925603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 32025603Skjc printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", 32125603Skjc ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 32225603Skjc#endif 32325603Skjc m_freem(m); 32425603Skjc return; 32525603Skjc } 32625603Skjc etype = ATM_LLC_TYPE(alc); 32725603Skjc m_adj(m, sizeof(*alc)); 32825603Skjc } 32925603Skjc 33025603Skjc switch (etype) { 33125603Skjc#ifdef INET 33225603Skjc case ETHERTYPE_IP: 33325603Skjc schednetisr(NETISR_IP); 33425603Skjc inq = &ipintrq; 33525603Skjc break; 33625603Skjc#endif 33725603Skjc default: 33825603Skjc m_freem(m); 33925603Skjc return; 34025603Skjc } 34125603Skjc } 34225603Skjc 34325603Skjc s = splimp(); 34425603Skjc if (IF_QFULL(inq)) { 34525603Skjc IF_DROP(inq); 34625603Skjc m_freem(m); 34725603Skjc } else 34825603Skjc IF_ENQUEUE(inq, m); 34925603Skjc splx(s); 35025603Skjc} 35125603Skjc 35225603Skjc/* 35325603Skjc * Perform common duties while attaching to interface list 35425603Skjc */ 35525603Skjcvoid 35625603Skjcatm_ifattach(ifp) 35725603Skjc register struct ifnet *ifp; 35825603Skjc{ 35925603Skjc register struct ifaddr *ifa; 36025603Skjc register struct sockaddr_dl *sdl; 36125603Skjc 36225603Skjc ifp->if_type = IFT_ATM; 36325603Skjc ifp->if_addrlen = 0; 36425603Skjc ifp->if_hdrlen = 0; 36525603Skjc ifp->if_mtu = ATMMTU; 36625603Skjc ifp->if_output = atm_output; 36725603Skjc 36825603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 36925603Skjc for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; 37025603Skjc ifa = ifa->ifa_list.tqe_next) 37125603Skjc#elif defined(__FreeBSD__) && ((__FreeBSD__ > 2) || defined(_NET_IF_VAR_H_)) 37225603Skjc/* 37325603Skjc * for FreeBSD-3.0. 3.0-SNAP-970124 still sets -D__FreeBSD__=2! 37425603Skjc * XXX -- for now, use newly-introduced "net/if_var.h" as an identifier. 37525603Skjc * need a better way to identify 3.0. -- kjc 37625603Skjc */ 37725603Skjc for (ifa = ifp->if_addrhead.tqh_first; ifa; 37825603Skjc ifa = ifa->ifa_link.tqe_next) 37925603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__) 38025603Skjc for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 38125603Skjc#endif 38225603Skjc 38325603Skjc if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 38425603Skjc sdl->sdl_family == AF_LINK) { 38525603Skjc sdl->sdl_type = IFT_ATM; 38625603Skjc sdl->sdl_alen = ifp->if_addrlen; 38725603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 38825603Skjc bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 38925603Skjc#endif 39025603Skjc break; 39125603Skjc } 39225603Skjc#if NBPFILTER > 0 39325603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 39425603Skjc bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); 39525603Skjc#elif defined(__FreeBSD__) 39625603Skjc bpfattach(ifp, DLT_NULL, sizeof(u_int)); 39725603Skjc#endif 39825603Skjc#endif /* NBPFILTER > 0 */ 39925603Skjc} 400