125603Skjc/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ 225603Skjc 3139823Simp/*- 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. 3354263Sshin * 3425603Skjc * if_atmsubr.c 3525603Skjc */ 3625603Skjc 37116720Sharti#include <sys/cdefs.h> 38116720Sharti__FBSDID("$FreeBSD$"); 39116720Sharti 4032350Seivind#include "opt_inet.h" 4154263Sshin#include "opt_inet6.h" 4232925Seivind#include "opt_natm.h" 4332350Seivind 4425603Skjc#include <sys/param.h> 4525603Skjc#include <sys/systm.h> 46114201Sharti#include <sys/kernel.h> 47114201Sharti#include <sys/module.h> 4825603Skjc#include <sys/mbuf.h> 4925603Skjc#include <sys/socket.h> 5037939Skjc#include <sys/sockio.h> 5137939Skjc#include <sys/errno.h> 52114201Sharti#include <sys/sysctl.h> 53117630Sharti#include <sys/malloc.h> 5425603Skjc 5525603Skjc#include <net/if.h> 56257176Sglebius#include <net/if_var.h> 5725603Skjc#include <net/netisr.h> 5825603Skjc#include <net/route.h> 5925603Skjc#include <net/if_dl.h> 6025603Skjc#include <net/if_types.h> 6125603Skjc#include <net/if_atm.h> 6225603Skjc 6325603Skjc#include <netinet/in.h> 6425603Skjc#include <netinet/if_atm.h> 6525603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 6637939Skjc#if defined(INET) || defined(INET6) 6725603Skjc#include <netinet/in_var.h> 6825603Skjc#endif 6925603Skjc#ifdef NATM 7025603Skjc#include <netnatm/natm.h> 7125603Skjc#endif 7225603Skjc 73163606Srwatson#include <security/mac/mac_framework.h> 74163606Srwatson 75116741Sharti/* 76116741Sharti * Netgraph interface functions. 77116741Sharti * These need not be protected by a lock, because ng_atm nodes are persitent. 78116741Sharti * The ng_atm module can be unloaded only if all ATM interfaces have been 79116741Sharti * unloaded, so nobody should be in the code paths accessing these function 80116741Sharti * pointers. 81116741Sharti */ 82116741Shartivoid (*ng_atm_attach_p)(struct ifnet *); 83116741Shartivoid (*ng_atm_detach_p)(struct ifnet *); 84116741Shartiint (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 85116741Shartivoid (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 86116741Sharti struct atm_pseudohdr *, void *); 87116741Shartivoid (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 88116741Sharti struct atm_pseudohdr *, void *); 89118157Shartivoid (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 90116741Sharti 91116741Sharti/* 92116741Sharti * Harp pseudo interface hooks 93116741Sharti */ 94116741Shartivoid (*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m, 95116741Sharti struct atm_pseudohdr *ah, void *rxhand); 96116741Shartivoid (*atm_harp_attach_p)(struct ifnet *); 97116741Shartivoid (*atm_harp_detach_p)(struct ifnet *); 98118157Shartivoid (*atm_harp_event_p)(struct ifnet *, uint32_t, void *); 99116741Sharti 100114201ShartiSYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware"); 101114201Sharti 102227293Sedstatic MALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals"); 103147256Sbrooks 10437939Skjc#ifndef ETHERTYPE_IPV6 105116720Sharti#define ETHERTYPE_IPV6 0x86dd 10637939Skjc#endif 10725603Skjc 108116720Sharti#define senderr(e) do { error = (e); goto bad; } while (0) 10925603Skjc 11025603Skjc/* 11125603Skjc * atm_output: ATM output routine 11225603Skjc * inputs: 11325603Skjc * "ifp" = ATM interface to output to 11425603Skjc * "m0" = the packet to output 11525603Skjc * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 116191148Skmacy * "ro" = the route to use 11725603Skjc * returns: error code [0 == ok] 11825603Skjc * 11925603Skjc * note: special semantic: if (dst == NULL) then we assume "m" already 12025603Skjc * has an atm_pseudohdr on it and just send it directly. 12125603Skjc * [for native mode ATM output] if dst is null, then 122191148Skmacy * ro->ro_rt must also be NULL. 12325603Skjc */ 12425603Skjcint 125249925Sglebiusatm_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, 126191148Skmacy struct route *ro) 12725603Skjc{ 12825603Skjc u_int16_t etype = 0; /* if using LLC/SNAP */ 12978249Speter int error = 0, sz; 13025603Skjc struct atm_pseudohdr atmdst, *ad; 13159633Skjc struct mbuf *m = m0; 13225603Skjc struct atmllc *atmllc; 133249925Sglebius const struct atmllc *llc_hdr = NULL; 13425603Skjc u_int32_t atm_flags; 13525603Skjc 136105576Srwatson#ifdef MAC 137172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 138105576Srwatson if (error) 139105576Srwatson senderr(error); 140105576Srwatson#endif 141105576Srwatson 142148887Srwatson if (!((ifp->if_flags & IFF_UP) && 143148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 14425603Skjc senderr(ENETDOWN); 14525603Skjc 14625603Skjc /* 14725603Skjc * check for non-native ATM traffic (dst != NULL) 14825603Skjc */ 14925603Skjc if (dst) { 15025603Skjc switch (dst->sa_family) { 151116720Sharti 15237939Skjc#if defined(INET) || defined(INET6) 15325603Skjc case AF_INET: 15437939Skjc case AF_INET6: 155128636Sluigi { 15646695Skjc if (dst->sa_family == AF_INET6) 157112193Sharti etype = ETHERTYPE_IPV6; 15846695Skjc else 159112193Sharti etype = ETHERTYPE_IP; 160191148Skmacy if (!atmresolve(ro->ro_rt, m, dst, &atmdst)) { 16125603Skjc m = NULL; 16225603Skjc /* XXX: atmresolve already free'd it */ 16325603Skjc senderr(EHOSTUNREACH); 16425603Skjc /* XXX: put ATMARP stuff here */ 16525603Skjc /* XXX: watch who frees m on failure */ 16625603Skjc } 167128636Sluigi } 16825603Skjc break; 16937939Skjc#endif /* INET || INET6 */ 17025603Skjc 17137939Skjc case AF_UNSPEC: 17237939Skjc /* 17346695Skjc * XXX: bpfwrite. assuming dst contains 12 bytes 17446695Skjc * (atm pseudo header (4) + LLC/SNAP (8)) 17537939Skjc */ 17637939Skjc bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 177249925Sglebius llc_hdr = (const struct atmllc *)(dst->sa_data + 178116720Sharti sizeof(atmdst)); 17937939Skjc break; 18037939Skjc 18125603Skjc default: 18225603Skjc printf("%s: can't handle af%d\n", ifp->if_xname, 18325603Skjc dst->sa_family); 18425603Skjc senderr(EAFNOSUPPORT); 18525603Skjc } 18625603Skjc 18725603Skjc /* 18825603Skjc * must add atm_pseudohdr to data 18925603Skjc */ 19025603Skjc sz = sizeof(atmdst); 19125603Skjc atm_flags = ATM_PH_FLAGS(&atmdst); 192116720Sharti if (atm_flags & ATM_PH_LLCSNAP) 193116720Sharti sz += 8; /* sizeof snap == 8 */ 194243882Sglebius M_PREPEND(m, sz, M_NOWAIT); 195298075Spfg if (m == NULL) 19625603Skjc senderr(ENOBUFS); 19725603Skjc ad = mtod(m, struct atm_pseudohdr *); 19825603Skjc *ad = atmdst; 19925603Skjc if (atm_flags & ATM_PH_LLCSNAP) { 20025603Skjc atmllc = (struct atmllc *)(ad + 1); 20137939Skjc if (llc_hdr == NULL) { 20237939Skjc bcopy(ATMLLC_HDR, atmllc->llchdr, 20337939Skjc sizeof(atmllc->llchdr)); 204116720Sharti /* note: in host order */ 20537939Skjc ATM_LLC_SETTYPE(atmllc, etype); 20637939Skjc } 20737939Skjc else 20837939Skjc bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 20925603Skjc } 21025603Skjc } 21125603Skjc 212116741Sharti if (ng_atm_output_p != NULL) { 213116741Sharti if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) { 214116741Sharti if (m != NULL) 215116741Sharti m_freem(m); 216116741Sharti return (error); 217116741Sharti } 218116741Sharti if (m == NULL) 219116741Sharti return (0); 220116741Sharti } 221116741Sharti 22225603Skjc /* 22325603Skjc * Queue message on interface, and start output if interface 22425603Skjc * not yet active. 22525603Skjc */ 226117629Sharti if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, 227117629Sharti -(int)sizeof(struct atm_pseudohdr))) 22869152Sjlemon return (ENOBUFS); 22925603Skjc return (error); 23025603Skjc 23125603Skjcbad: 23225603Skjc if (m) 23325603Skjc m_freem(m); 23425603Skjc return (error); 23525603Skjc} 23625603Skjc 23725603Skjc/* 23825603Skjc * Process a received ATM packet; 23925603Skjc * the packet is in the mbuf chain m. 24025603Skjc */ 24125603Skjcvoid 242116720Shartiatm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 243116720Sharti void *rxhand) 24425603Skjc{ 245111888Sjlemon int isr; 246116720Sharti u_int16_t etype = ETHERTYPE_IP; /* default */ 24725603Skjc 24825603Skjc if ((ifp->if_flags & IFF_UP) == 0) { 24925603Skjc m_freem(m); 25025603Skjc return; 25125603Skjc } 252105576Srwatson#ifdef MAC 253172930Srwatson mac_ifnet_create_mbuf(ifp, m); 254105576Srwatson#endif 255271867Sglebius if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 25625603Skjc 257116741Sharti if (ng_atm_input_p != NULL) { 258116741Sharti (*ng_atm_input_p)(ifp, &m, ah, rxhand); 259116741Sharti if (m == NULL) 260116741Sharti return; 261116741Sharti } 262116741Sharti 263116741Sharti /* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */ 264116741Sharti if (atm_harp_input_p != NULL) { 265116741Sharti (*atm_harp_input_p)(ifp, &m, ah, rxhand); 266116741Sharti if (m == NULL) 267116741Sharti return; 268116741Sharti } 269116741Sharti 27025603Skjc if (rxhand) { 27125603Skjc#ifdef NATM 272148125Srwatson struct natmpcb *npcb; 273116720Sharti 274148125Srwatson /* 275148125Srwatson * XXXRW: this use of 'rxhand' is not a very good idea, and 276148125Srwatson * was subject to races even before SMPng due to the release 277148125Srwatson * of spl here. 278148125Srwatson */ 279148125Srwatson NATM_LOCK(); 280148125Srwatson npcb = rxhand; 28137939Skjc npcb->npcb_inq++; /* count # in queue */ 282111888Sjlemon isr = NETISR_NATM; 28337939Skjc m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 284148125Srwatson NATM_UNLOCK(); 28525603Skjc#else 286116720Sharti printf("atm_input: NATM detected but not " 287116720Sharti "configured in kernel\n"); 288116741Sharti goto dropit; 28925603Skjc#endif 29025603Skjc } else { 29137939Skjc /* 29237939Skjc * handle LLC/SNAP header, if present 29337939Skjc */ 29437939Skjc if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 29537939Skjc struct atmllc *alc; 296116720Sharti 29737939Skjc if (m->m_len < sizeof(*alc) && 298298075Spfg (m = m_pullup(m, sizeof(*alc))) == NULL) 29937939Skjc return; /* failed */ 30037939Skjc alc = mtod(m, struct atmllc *); 30137939Skjc if (bcmp(alc, ATMLLC_HDR, 6)) { 302116720Sharti printf("%s: recv'd invalid LLC/SNAP frame " 303116720Sharti "[vp=%d,vc=%d]\n", ifp->if_xname, 304116720Sharti ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 30537939Skjc m_freem(m); 30637939Skjc return; 30737939Skjc } 30837939Skjc etype = ATM_LLC_TYPE(alc); 30937939Skjc m_adj(m, sizeof(*alc)); 31037939Skjc } 31125603Skjc 31237939Skjc switch (etype) { 313116720Sharti 31425603Skjc#ifdef INET 31537939Skjc case ETHERTYPE_IP: 316111888Sjlemon isr = NETISR_IP; 31737939Skjc break; 31825603Skjc#endif 319116720Sharti 32037939Skjc#ifdef INET6 32137939Skjc case ETHERTYPE_IPV6: 322111888Sjlemon isr = NETISR_IPV6; 32337939Skjc break; 32437939Skjc#endif 32537939Skjc default: 326116741Sharti#ifndef NATM 327116741Sharti dropit: 328116741Sharti#endif 329116741Sharti if (ng_atm_input_orphan_p != NULL) 330116741Sharti (*ng_atm_input_orphan_p)(ifp, m, ah, rxhand); 331116741Sharti else 332116741Sharti m_freem(m); 33337939Skjc return; 33437939Skjc } 33525603Skjc } 336223741Sbz M_SETFIB(m, ifp->if_fib); 337111888Sjlemon netisr_dispatch(isr, m); 33825603Skjc} 33925603Skjc 34025603Skjc/* 341114201Sharti * Perform common duties while attaching to interface list. 34225603Skjc */ 34325603Skjcvoid 344116720Shartiatm_ifattach(struct ifnet *ifp) 34525603Skjc{ 346111774Smdodd struct ifaddr *ifa; 347111774Smdodd struct sockaddr_dl *sdl; 348147256Sbrooks struct ifatm *ifatm = ifp->if_l2com; 34925603Skjc 35025603Skjc ifp->if_addrlen = 0; 35125603Skjc ifp->if_hdrlen = 0; 352114201Sharti if_attach(ifp); 35325603Skjc ifp->if_mtu = ATMMTU; 35425603Skjc ifp->if_output = atm_output; 355106939Ssam#if 0 356106939Ssam ifp->if_input = atm_input; 357106939Ssam#endif 35846695Skjc ifp->if_snd.ifq_maxlen = 50; /* dummy */ 35925603Skjc 360160035Syar TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 361160038Syar if (ifa->ifa_addr->sa_family == AF_LINK) { 362160038Syar sdl = (struct sockaddr_dl *)ifa->ifa_addr; 36325603Skjc sdl->sdl_type = IFT_ATM; 36425603Skjc sdl->sdl_alen = ifp->if_addrlen; 36525603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 36625603Skjc bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 36725603Skjc#endif 36825603Skjc break; 36925603Skjc } 37037939Skjc 371114739Sharti ifp->if_linkmib = &ifatm->mib; 372114739Sharti ifp->if_linkmiblen = sizeof(ifatm->mib); 373116741Sharti 374116741Sharti if(ng_atm_attach_p) 375116741Sharti (*ng_atm_attach_p)(ifp); 376116741Sharti if (atm_harp_attach_p) 377116741Sharti (*atm_harp_attach_p)(ifp); 37837939Skjc} 379114201Sharti 380114201Sharti/* 381114201Sharti * Common stuff for detaching an ATM interface 382114201Sharti */ 383114201Shartivoid 384114201Shartiatm_ifdetach(struct ifnet *ifp) 385114201Sharti{ 386116741Sharti if (atm_harp_detach_p) 387116741Sharti (*atm_harp_detach_p)(ifp); 388116741Sharti if(ng_atm_detach_p) 389116741Sharti (*ng_atm_detach_p)(ifp); 390114201Sharti if_detach(ifp); 391114201Sharti} 392114201Sharti 393117630Sharti/* 394117630Sharti * Support routine for the SIOCATMGVCCS ioctl(). 395117630Sharti * 396117630Sharti * This routine assumes, that the private VCC structures used by the driver 397117630Sharti * begin with a struct atmio_vcc. 398117630Sharti * 399117630Sharti * Return a table of VCCs in a freshly allocated memory area. 400117630Sharti * Here we have a problem: we first count, how many vccs we need 401117630Sharti * to return. The we allocate the memory and finally fill it in. 402117630Sharti * Because we cannot lock while calling malloc, the number of active 403117630Sharti * vccs may change while we're in malloc. So we allocate a couple of 404117630Sharti * vccs more and if space anyway is not enough re-iterate. 405117630Sharti * 406117630Sharti * We could use an sx lock for the vcc tables. 407117630Sharti */ 408117630Shartistruct atmio_vcctable * 409117630Shartiatm_getvccs(struct atmio_vcc **table, u_int size, u_int start, 410117630Sharti struct mtx *lock, int waitok) 411117630Sharti{ 412117630Sharti u_int cid, alloc; 413117630Sharti size_t len; 414117630Sharti struct atmio_vcctable *vccs; 415117630Sharti struct atmio_vcc *v; 416117630Sharti 417117630Sharti alloc = start + 10; 418117630Sharti vccs = NULL; 419117630Sharti 420117630Sharti for (;;) { 421117630Sharti len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]); 422117630Sharti vccs = reallocf(vccs, len, M_TEMP, 423117630Sharti waitok ? M_WAITOK : M_NOWAIT); 424117630Sharti if (vccs == NULL) 425117630Sharti return (NULL); 426117630Sharti bzero(vccs, len); 427117630Sharti 428117630Sharti vccs->count = 0; 429117630Sharti v = vccs->vccs; 430117630Sharti 431117630Sharti mtx_lock(lock); 432117630Sharti for (cid = 0; cid < size; cid++) 433117630Sharti if (table[cid] != NULL) { 434117630Sharti if (++vccs->count == alloc) 435117630Sharti /* too many - try again */ 436117630Sharti break; 437117630Sharti *v++ = *table[cid]; 438117630Sharti } 439117630Sharti mtx_unlock(lock); 440117630Sharti 441117630Sharti if (cid == size) 442117630Sharti break; 443117630Sharti 444117630Sharti alloc *= 2; 445117630Sharti } 446117630Sharti return (vccs); 447117630Sharti} 448117630Sharti 449118157Sharti/* 450118157Sharti * Driver or channel state has changed. Inform whoever is interested 451118157Sharti * in these events. 452118157Sharti */ 453118157Shartivoid 454118157Shartiatm_event(struct ifnet *ifp, u_int event, void *arg) 455118157Sharti{ 456118157Sharti if (ng_atm_event_p != NULL) 457118157Sharti (*ng_atm_event_p)(ifp, event, arg); 458118157Sharti if (atm_harp_event_p != NULL) 459118157Sharti (*atm_harp_event_p)(ifp, event, arg); 460118157Sharti} 461118157Sharti 462147256Sbrooksstatic void * 463147256Sbrooksatm_alloc(u_char type, struct ifnet *ifp) 464147256Sbrooks{ 465147256Sbrooks struct ifatm *ifatm; 466147256Sbrooks 467147256Sbrooks ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO); 468147256Sbrooks ifatm->ifp = ifp; 469147256Sbrooks 470147256Sbrooks return (ifatm); 471147256Sbrooks} 472147256Sbrooks 473147256Sbrooksstatic void 474147256Sbrooksatm_free(void *com, u_char type) 475147256Sbrooks{ 476147256Sbrooks 477147256Sbrooks free(com, M_IFATM); 478147256Sbrooks} 479147256Sbrooks 480147256Sbrooksstatic int 481147256Sbrooksatm_modevent(module_t mod, int type, void *data) 482147256Sbrooks{ 483147256Sbrooks switch (type) { 484147256Sbrooks case MOD_LOAD: 485147256Sbrooks if_register_com_alloc(IFT_ATM, atm_alloc, atm_free); 486147256Sbrooks break; 487147256Sbrooks case MOD_UNLOAD: 488147256Sbrooks if_deregister_com_alloc(IFT_ATM); 489147256Sbrooks break; 490147256Sbrooks default: 491147256Sbrooks return (EOPNOTSUPP); 492147256Sbrooks } 493147256Sbrooks 494147256Sbrooks return (0); 495147256Sbrooks} 496147256Sbrooks 497114201Shartistatic moduledata_t atm_mod = { 498114201Sharti "atm", 499147256Sbrooks atm_modevent, 500241394Skevlo 0 501114201Sharti}; 502114201Sharti 503147256SbrooksDECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 504114201ShartiMODULE_VERSION(atm, 1); 505