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> 5625603Skjc#include <net/netisr.h> 5725603Skjc#include <net/route.h> 5825603Skjc#include <net/if_dl.h> 5925603Skjc#include <net/if_types.h> 6025603Skjc#include <net/if_atm.h> 6125603Skjc 6225603Skjc#include <netinet/in.h> 6325603Skjc#include <netinet/if_atm.h> 6425603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 6537939Skjc#if defined(INET) || defined(INET6) 6625603Skjc#include <netinet/in_var.h> 6725603Skjc#endif 6825603Skjc#ifdef NATM 6925603Skjc#include <netnatm/natm.h> 7025603Skjc#endif 7125603Skjc 72163606Srwatson#include <security/mac/mac_framework.h> 73163606Srwatson 74116741Sharti/* 75116741Sharti * Netgraph interface functions. 76116741Sharti * These need not be protected by a lock, because ng_atm nodes are persitent. 77116741Sharti * The ng_atm module can be unloaded only if all ATM interfaces have been 78116741Sharti * unloaded, so nobody should be in the code paths accessing these function 79116741Sharti * pointers. 80116741Sharti */ 81116741Shartivoid (*ng_atm_attach_p)(struct ifnet *); 82116741Shartivoid (*ng_atm_detach_p)(struct ifnet *); 83116741Shartiint (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 84116741Shartivoid (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 85116741Sharti struct atm_pseudohdr *, void *); 86116741Shartivoid (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 87116741Sharti struct atm_pseudohdr *, void *); 88118157Shartivoid (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 89116741Sharti 90116741Sharti/* 91116741Sharti * Harp pseudo interface hooks 92116741Sharti */ 93116741Shartivoid (*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m, 94116741Sharti struct atm_pseudohdr *ah, void *rxhand); 95116741Shartivoid (*atm_harp_attach_p)(struct ifnet *); 96116741Shartivoid (*atm_harp_detach_p)(struct ifnet *); 97118157Shartivoid (*atm_harp_event_p)(struct ifnet *, uint32_t, void *); 98116741Sharti 99114201ShartiSYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware"); 100114201Sharti 101249132Smavstatic MALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals"); 102147256Sbrooks 10337939Skjc#ifndef ETHERTYPE_IPV6 104116720Sharti#define ETHERTYPE_IPV6 0x86dd 10537939Skjc#endif 10625603Skjc 107116720Sharti#define senderr(e) do { error = (e); goto bad; } while (0) 10825603Skjc 10925603Skjc/* 11025603Skjc * atm_output: ATM output routine 11125603Skjc * inputs: 11225603Skjc * "ifp" = ATM interface to output to 11325603Skjc * "m0" = the packet to output 11425603Skjc * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 115191148Skmacy * "ro" = the route to use 11625603Skjc * returns: error code [0 == ok] 11725603Skjc * 11825603Skjc * note: special semantic: if (dst == NULL) then we assume "m" already 11925603Skjc * has an atm_pseudohdr on it and just send it directly. 12025603Skjc * [for native mode ATM output] if dst is null, then 121191148Skmacy * ro->ro_rt must also be NULL. 12225603Skjc */ 12325603Skjcint 124116720Shartiatm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, 125191148Skmacy struct route *ro) 12625603Skjc{ 12725603Skjc u_int16_t etype = 0; /* if using LLC/SNAP */ 12878249Speter int error = 0, sz; 12925603Skjc struct atm_pseudohdr atmdst, *ad; 13059633Skjc struct mbuf *m = m0; 13125603Skjc struct atmllc *atmllc; 13237939Skjc struct atmllc *llc_hdr = NULL; 13325603Skjc u_int32_t atm_flags; 13425603Skjc 135105576Srwatson#ifdef MAC 136172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 137105576Srwatson if (error) 138105576Srwatson senderr(error); 139105576Srwatson#endif 140105576Srwatson 141148887Srwatson if (!((ifp->if_flags & IFF_UP) && 142148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 14325603Skjc senderr(ENETDOWN); 14425603Skjc 14525603Skjc /* 14625603Skjc * check for non-native ATM traffic (dst != NULL) 14725603Skjc */ 14825603Skjc if (dst) { 14925603Skjc switch (dst->sa_family) { 150116720Sharti 15137939Skjc#if defined(INET) || defined(INET6) 15225603Skjc case AF_INET: 15337939Skjc case AF_INET6: 154128636Sluigi { 15546695Skjc if (dst->sa_family == AF_INET6) 156112193Sharti etype = ETHERTYPE_IPV6; 15746695Skjc else 158112193Sharti etype = ETHERTYPE_IP; 159191148Skmacy if (!atmresolve(ro->ro_rt, m, dst, &atmdst)) { 16025603Skjc m = NULL; 16125603Skjc /* XXX: atmresolve already free'd it */ 16225603Skjc senderr(EHOSTUNREACH); 16325603Skjc /* XXX: put ATMARP stuff here */ 16425603Skjc /* XXX: watch who frees m on failure */ 16525603Skjc } 166128636Sluigi } 16725603Skjc break; 16837939Skjc#endif /* INET || INET6 */ 16925603Skjc 17037939Skjc case AF_UNSPEC: 17137939Skjc /* 17246695Skjc * XXX: bpfwrite. assuming dst contains 12 bytes 17346695Skjc * (atm pseudo header (4) + LLC/SNAP (8)) 17437939Skjc */ 17537939Skjc bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 176116720Sharti llc_hdr = (struct atmllc *)(dst->sa_data + 177116720Sharti sizeof(atmdst)); 17837939Skjc break; 17937939Skjc 18025603Skjc default: 18125603Skjc printf("%s: can't handle af%d\n", ifp->if_xname, 18225603Skjc dst->sa_family); 18325603Skjc senderr(EAFNOSUPPORT); 18425603Skjc } 18525603Skjc 18625603Skjc /* 18725603Skjc * must add atm_pseudohdr to data 18825603Skjc */ 18925603Skjc sz = sizeof(atmdst); 19025603Skjc atm_flags = ATM_PH_FLAGS(&atmdst); 191116720Sharti if (atm_flags & ATM_PH_LLCSNAP) 192116720Sharti sz += 8; /* sizeof snap == 8 */ 193111119Simp M_PREPEND(m, sz, M_DONTWAIT); 19425603Skjc if (m == 0) 19525603Skjc senderr(ENOBUFS); 19625603Skjc ad = mtod(m, struct atm_pseudohdr *); 19725603Skjc *ad = atmdst; 19825603Skjc if (atm_flags & ATM_PH_LLCSNAP) { 19925603Skjc atmllc = (struct atmllc *)(ad + 1); 20037939Skjc if (llc_hdr == NULL) { 20137939Skjc bcopy(ATMLLC_HDR, atmllc->llchdr, 20237939Skjc sizeof(atmllc->llchdr)); 203116720Sharti /* note: in host order */ 20437939Skjc ATM_LLC_SETTYPE(atmllc, etype); 20537939Skjc } 20637939Skjc else 20737939Skjc bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 20825603Skjc } 20925603Skjc } 21025603Skjc 211116741Sharti if (ng_atm_output_p != NULL) { 212116741Sharti if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) { 213116741Sharti if (m != NULL) 214116741Sharti m_freem(m); 215116741Sharti return (error); 216116741Sharti } 217116741Sharti if (m == NULL) 218116741Sharti return (0); 219116741Sharti } 220116741Sharti 22125603Skjc /* 22225603Skjc * Queue message on interface, and start output if interface 22325603Skjc * not yet active. 22425603Skjc */ 225117629Sharti if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, 226117629Sharti -(int)sizeof(struct atm_pseudohdr))) 22769152Sjlemon return (ENOBUFS); 22825603Skjc return (error); 22925603Skjc 23025603Skjcbad: 23125603Skjc if (m) 23225603Skjc m_freem(m); 23325603Skjc return (error); 23425603Skjc} 23525603Skjc 23625603Skjc/* 23725603Skjc * Process a received ATM packet; 23825603Skjc * the packet is in the mbuf chain m. 23925603Skjc */ 24025603Skjcvoid 241116720Shartiatm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 242116720Sharti void *rxhand) 24325603Skjc{ 244111888Sjlemon int isr; 245116720Sharti u_int16_t etype = ETHERTYPE_IP; /* default */ 24625603Skjc 24725603Skjc if ((ifp->if_flags & IFF_UP) == 0) { 24825603Skjc m_freem(m); 24925603Skjc return; 25025603Skjc } 251105576Srwatson#ifdef MAC 252172930Srwatson mac_ifnet_create_mbuf(ifp, m); 253105576Srwatson#endif 25425603Skjc ifp->if_ibytes += m->m_pkthdr.len; 25525603Skjc 256116741Sharti if (ng_atm_input_p != NULL) { 257116741Sharti (*ng_atm_input_p)(ifp, &m, ah, rxhand); 258116741Sharti if (m == NULL) 259116741Sharti return; 260116741Sharti } 261116741Sharti 262116741Sharti /* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */ 263116741Sharti if (atm_harp_input_p != NULL) { 264116741Sharti (*atm_harp_input_p)(ifp, &m, ah, rxhand); 265116741Sharti if (m == NULL) 266116741Sharti return; 267116741Sharti } 268116741Sharti 26925603Skjc if (rxhand) { 27025603Skjc#ifdef NATM 271148125Srwatson struct natmpcb *npcb; 272116720Sharti 273148125Srwatson /* 274148125Srwatson * XXXRW: this use of 'rxhand' is not a very good idea, and 275148125Srwatson * was subject to races even before SMPng due to the release 276148125Srwatson * of spl here. 277148125Srwatson */ 278148125Srwatson NATM_LOCK(); 279148125Srwatson npcb = rxhand; 28037939Skjc npcb->npcb_inq++; /* count # in queue */ 281111888Sjlemon isr = NETISR_NATM; 28237939Skjc m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 283148125Srwatson NATM_UNLOCK(); 28425603Skjc#else 285116720Sharti printf("atm_input: NATM detected but not " 286116720Sharti "configured in kernel\n"); 287116741Sharti goto dropit; 28825603Skjc#endif 28925603Skjc } else { 29037939Skjc /* 29137939Skjc * handle LLC/SNAP header, if present 29237939Skjc */ 29337939Skjc if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 29437939Skjc struct atmllc *alc; 295116720Sharti 29637939Skjc if (m->m_len < sizeof(*alc) && 29737939Skjc (m = m_pullup(m, sizeof(*alc))) == 0) 29837939Skjc return; /* failed */ 29937939Skjc alc = mtod(m, struct atmllc *); 30037939Skjc if (bcmp(alc, ATMLLC_HDR, 6)) { 301116720Sharti printf("%s: recv'd invalid LLC/SNAP frame " 302116720Sharti "[vp=%d,vc=%d]\n", ifp->if_xname, 303116720Sharti ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 30437939Skjc m_freem(m); 30537939Skjc return; 30637939Skjc } 30737939Skjc etype = ATM_LLC_TYPE(alc); 30837939Skjc m_adj(m, sizeof(*alc)); 30937939Skjc } 31025603Skjc 31137939Skjc switch (etype) { 312116720Sharti 31325603Skjc#ifdef INET 31437939Skjc case ETHERTYPE_IP: 315111888Sjlemon isr = NETISR_IP; 31637939Skjc break; 31725603Skjc#endif 318116720Sharti 31937939Skjc#ifdef INET6 32037939Skjc case ETHERTYPE_IPV6: 321111888Sjlemon isr = NETISR_IPV6; 32237939Skjc break; 32337939Skjc#endif 32437939Skjc default: 325116741Sharti#ifndef NATM 326116741Sharti dropit: 327116741Sharti#endif 328116741Sharti if (ng_atm_input_orphan_p != NULL) 329116741Sharti (*ng_atm_input_orphan_p)(ifp, m, ah, rxhand); 330116741Sharti else 331116741Sharti m_freem(m); 33237939Skjc return; 33337939Skjc } 33425603Skjc } 335223741Sbz M_SETFIB(m, ifp->if_fib); 336111888Sjlemon netisr_dispatch(isr, m); 33725603Skjc} 33825603Skjc 33925603Skjc/* 340114201Sharti * Perform common duties while attaching to interface list. 34125603Skjc */ 34225603Skjcvoid 343116720Shartiatm_ifattach(struct ifnet *ifp) 34425603Skjc{ 345111774Smdodd struct ifaddr *ifa; 346111774Smdodd struct sockaddr_dl *sdl; 347147256Sbrooks struct ifatm *ifatm = ifp->if_l2com; 34825603Skjc 34925603Skjc ifp->if_addrlen = 0; 35025603Skjc ifp->if_hdrlen = 0; 351114201Sharti if_attach(ifp); 35225603Skjc ifp->if_mtu = ATMMTU; 35325603Skjc ifp->if_output = atm_output; 354106939Ssam#if 0 355106939Ssam ifp->if_input = atm_input; 356106939Ssam#endif 35746695Skjc ifp->if_snd.ifq_maxlen = 50; /* dummy */ 35825603Skjc 359160035Syar TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 360160038Syar if (ifa->ifa_addr->sa_family == AF_LINK) { 361160038Syar sdl = (struct sockaddr_dl *)ifa->ifa_addr; 36225603Skjc sdl->sdl_type = IFT_ATM; 36325603Skjc sdl->sdl_alen = ifp->if_addrlen; 36425603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 36525603Skjc bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 36625603Skjc#endif 36725603Skjc break; 36825603Skjc } 36937939Skjc 370114739Sharti ifp->if_linkmib = &ifatm->mib; 371114739Sharti ifp->if_linkmiblen = sizeof(ifatm->mib); 372116741Sharti 373116741Sharti if(ng_atm_attach_p) 374116741Sharti (*ng_atm_attach_p)(ifp); 375116741Sharti if (atm_harp_attach_p) 376116741Sharti (*atm_harp_attach_p)(ifp); 37737939Skjc} 378114201Sharti 379114201Sharti/* 380114201Sharti * Common stuff for detaching an ATM interface 381114201Sharti */ 382114201Shartivoid 383114201Shartiatm_ifdetach(struct ifnet *ifp) 384114201Sharti{ 385116741Sharti if (atm_harp_detach_p) 386116741Sharti (*atm_harp_detach_p)(ifp); 387116741Sharti if(ng_atm_detach_p) 388116741Sharti (*ng_atm_detach_p)(ifp); 389114201Sharti if_detach(ifp); 390114201Sharti} 391114201Sharti 392117630Sharti/* 393117630Sharti * Support routine for the SIOCATMGVCCS ioctl(). 394117630Sharti * 395117630Sharti * This routine assumes, that the private VCC structures used by the driver 396117630Sharti * begin with a struct atmio_vcc. 397117630Sharti * 398117630Sharti * Return a table of VCCs in a freshly allocated memory area. 399117630Sharti * Here we have a problem: we first count, how many vccs we need 400117630Sharti * to return. The we allocate the memory and finally fill it in. 401117630Sharti * Because we cannot lock while calling malloc, the number of active 402117630Sharti * vccs may change while we're in malloc. So we allocate a couple of 403117630Sharti * vccs more and if space anyway is not enough re-iterate. 404117630Sharti * 405117630Sharti * We could use an sx lock for the vcc tables. 406117630Sharti */ 407117630Shartistruct atmio_vcctable * 408117630Shartiatm_getvccs(struct atmio_vcc **table, u_int size, u_int start, 409117630Sharti struct mtx *lock, int waitok) 410117630Sharti{ 411117630Sharti u_int cid, alloc; 412117630Sharti size_t len; 413117630Sharti struct atmio_vcctable *vccs; 414117630Sharti struct atmio_vcc *v; 415117630Sharti 416117630Sharti alloc = start + 10; 417117630Sharti vccs = NULL; 418117630Sharti 419117630Sharti for (;;) { 420117630Sharti len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]); 421117630Sharti vccs = reallocf(vccs, len, M_TEMP, 422117630Sharti waitok ? M_WAITOK : M_NOWAIT); 423117630Sharti if (vccs == NULL) 424117630Sharti return (NULL); 425117630Sharti bzero(vccs, len); 426117630Sharti 427117630Sharti vccs->count = 0; 428117630Sharti v = vccs->vccs; 429117630Sharti 430117630Sharti mtx_lock(lock); 431117630Sharti for (cid = 0; cid < size; cid++) 432117630Sharti if (table[cid] != NULL) { 433117630Sharti if (++vccs->count == alloc) 434117630Sharti /* too many - try again */ 435117630Sharti break; 436117630Sharti *v++ = *table[cid]; 437117630Sharti } 438117630Sharti mtx_unlock(lock); 439117630Sharti 440117630Sharti if (cid == size) 441117630Sharti break; 442117630Sharti 443117630Sharti alloc *= 2; 444117630Sharti } 445117630Sharti return (vccs); 446117630Sharti} 447117630Sharti 448118157Sharti/* 449118157Sharti * Driver or channel state has changed. Inform whoever is interested 450118157Sharti * in these events. 451118157Sharti */ 452118157Shartivoid 453118157Shartiatm_event(struct ifnet *ifp, u_int event, void *arg) 454118157Sharti{ 455118157Sharti if (ng_atm_event_p != NULL) 456118157Sharti (*ng_atm_event_p)(ifp, event, arg); 457118157Sharti if (atm_harp_event_p != NULL) 458118157Sharti (*atm_harp_event_p)(ifp, event, arg); 459118157Sharti} 460118157Sharti 461147256Sbrooksstatic void * 462147256Sbrooksatm_alloc(u_char type, struct ifnet *ifp) 463147256Sbrooks{ 464147256Sbrooks struct ifatm *ifatm; 465147256Sbrooks 466147256Sbrooks ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO); 467147256Sbrooks ifatm->ifp = ifp; 468147256Sbrooks 469147256Sbrooks return (ifatm); 470147256Sbrooks} 471147256Sbrooks 472147256Sbrooksstatic void 473147256Sbrooksatm_free(void *com, u_char type) 474147256Sbrooks{ 475147256Sbrooks 476147256Sbrooks free(com, M_IFATM); 477147256Sbrooks} 478147256Sbrooks 479147256Sbrooksstatic int 480147256Sbrooksatm_modevent(module_t mod, int type, void *data) 481147256Sbrooks{ 482147256Sbrooks switch (type) { 483147256Sbrooks case MOD_LOAD: 484147256Sbrooks if_register_com_alloc(IFT_ATM, atm_alloc, atm_free); 485147256Sbrooks break; 486147256Sbrooks case MOD_UNLOAD: 487147256Sbrooks if_deregister_com_alloc(IFT_ATM); 488147256Sbrooks break; 489147256Sbrooks default: 490147256Sbrooks return (EOPNOTSUPP); 491147256Sbrooks } 492147256Sbrooks 493147256Sbrooks return (0); 494147256Sbrooks} 495147256Sbrooks 496114201Shartistatic moduledata_t atm_mod = { 497114201Sharti "atm", 498147256Sbrooks atm_modevent, 499114201Sharti 0 500114201Sharti}; 501114201Sharti 502147256SbrooksDECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 503114201ShartiMODULE_VERSION(atm, 1); 504