if_atmsubr.c revision 241394
1251881Speter/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ 2251881Speter 3298845Sdim/*- 4251881Speter * 5251881Speter * Copyright (c) 1996 Charles D. Cranor and Washington University. 6251881Speter * All rights reserved. 7251881Speter * 8251881Speter * Redistribution and use in source and binary forms, with or without 9251881Speter * modification, are permitted provided that the following conditions 10251881Speter * are met: 11251881Speter * 1. Redistributions of source code must retain the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer. 13251881Speter * 2. Redistributions in binary form must reproduce the above copyright 14251881Speter * notice, this list of conditions and the following disclaimer in the 15251881Speter * documentation and/or other materials provided with the distribution. 16251881Speter * 3. All advertising materials mentioning features or use of this software 17251881Speter * must display the following acknowledgement: 18251881Speter * This product includes software developed by Charles D. Cranor and 19251881Speter * Washington University. 20251881Speter * 4. The name of the author may not be used to endorse or promote products 21251881Speter * derived from this software without specific prior written permission. 22251881Speter * 23251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24251881Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25251881Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26251881Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27251881Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28251881Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29251881Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30251881Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31251881Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32251881Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33251881Speter * 34251881Speter * if_atmsubr.c 35251881Speter */ 36251881Speter 37251881Speter#include <sys/cdefs.h> 38251881Speter__FBSDID("$FreeBSD: head/sys/net/if_atmsubr.c 241394 2012-10-10 08:36:38Z kevlo $"); 39251881Speter 40251881Speter#include "opt_inet.h" 41251881Speter#include "opt_inet6.h" 42251881Speter#include "opt_natm.h" 43251881Speter 44251881Speter#include <sys/param.h> 45251881Speter#include <sys/systm.h> 46251881Speter#include <sys/kernel.h> 47251881Speter#include <sys/module.h> 48251881Speter#include <sys/mbuf.h> 49251881Speter#include <sys/socket.h> 50251881Speter#include <sys/sockio.h> 51251881Speter#include <sys/errno.h> 52251881Speter#include <sys/sysctl.h> 53251881Speter#include <sys/malloc.h> 54251881Speter 55251881Speter#include <net/if.h> 56251881Speter#include <net/netisr.h> 57251881Speter#include <net/route.h> 58251881Speter#include <net/if_dl.h> 59251881Speter#include <net/if_types.h> 60251881Speter#include <net/if_atm.h> 61251881Speter 62251881Speter#include <netinet/in.h> 63251881Speter#include <netinet/if_atm.h> 64251881Speter#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 65251881Speter#if defined(INET) || defined(INET6) 66251881Speter#include <netinet/in_var.h> 67251881Speter#endif 68251881Speter#ifdef NATM 69251881Speter#include <netnatm/natm.h> 70251881Speter#endif 71251881Speter 72251881Speter#include <security/mac/mac_framework.h> 73251881Speter 74251881Speter/* 75251881Speter * Netgraph interface functions. 76251881Speter * These need not be protected by a lock, because ng_atm nodes are persitent. 77251881Speter * The ng_atm module can be unloaded only if all ATM interfaces have been 78251881Speter * unloaded, so nobody should be in the code paths accessing these function 79251881Speter * pointers. 80251881Speter */ 81251881Spetervoid (*ng_atm_attach_p)(struct ifnet *); 82251881Spetervoid (*ng_atm_detach_p)(struct ifnet *); 83251881Speterint (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 84251881Spetervoid (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 85251881Speter struct atm_pseudohdr *, void *); 86251881Spetervoid (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 87251881Speter struct atm_pseudohdr *, void *); 88251881Spetervoid (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 89251881Speter 90251881Speter/* 91251881Speter * Harp pseudo interface hooks 92251881Speter */ 93251881Spetervoid (*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m, 94251881Speter struct atm_pseudohdr *ah, void *rxhand); 95251881Spetervoid (*atm_harp_attach_p)(struct ifnet *); 96251881Spetervoid (*atm_harp_detach_p)(struct ifnet *); 97251881Spetervoid (*atm_harp_event_p)(struct ifnet *, uint32_t, void *); 98251881Speter 99251881SpeterSYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware"); 100251881Speter 101251881Speterstatic MALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals"); 102251881Speter 103251881Speter#ifndef ETHERTYPE_IPV6 104251881Speter#define ETHERTYPE_IPV6 0x86dd 105251881Speter#endif 106251881Speter 107251881Speter#define senderr(e) do { error = (e); goto bad; } while (0) 108251881Speter 109251881Speter/* 110251881Speter * atm_output: ATM output routine 111251881Speter * inputs: 112251881Speter * "ifp" = ATM interface to output to 113251881Speter * "m0" = the packet to output 114251881Speter * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 115251881Speter * "ro" = the route to use 116251881Speter * returns: error code [0 == ok] 117251881Speter * 118251881Speter * note: special semantic: if (dst == NULL) then we assume "m" already 119251881Speter * has an atm_pseudohdr on it and just send it directly. 120251881Speter * [for native mode ATM output] if dst is null, then 121251881Speter * ro->ro_rt must also be NULL. 122251881Speter */ 123251881Speterint 124251881Speteratm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, 125251881Speter struct route *ro) 126251881Speter{ 127251881Speter u_int16_t etype = 0; /* if using LLC/SNAP */ 128251881Speter int error = 0, sz; 129251881Speter struct atm_pseudohdr atmdst, *ad; 130251881Speter struct mbuf *m = m0; 131251881Speter struct atmllc *atmllc; 132251881Speter struct atmllc *llc_hdr = NULL; 133251881Speter u_int32_t atm_flags; 134251881Speter 135251881Speter#ifdef MAC 136251881Speter error = mac_ifnet_check_transmit(ifp, m); 137251881Speter if (error) 138251881Speter senderr(error); 139251881Speter#endif 140251881Speter 141251881Speter if (!((ifp->if_flags & IFF_UP) && 142251881Speter (ifp->if_drv_flags & IFF_DRV_RUNNING))) 143251881Speter senderr(ENETDOWN); 144251881Speter 145251881Speter /* 146251881Speter * check for non-native ATM traffic (dst != NULL) 147251881Speter */ 148251881Speter if (dst) { 149251881Speter switch (dst->sa_family) { 150251881Speter 151251881Speter#if defined(INET) || defined(INET6) 152251881Speter case AF_INET: 153251881Speter case AF_INET6: 154251881Speter { 155251881Speter if (dst->sa_family == AF_INET6) 156251881Speter etype = ETHERTYPE_IPV6; 157251881Speter else 158251881Speter etype = ETHERTYPE_IP; 159251881Speter if (!atmresolve(ro->ro_rt, m, dst, &atmdst)) { 160251881Speter m = NULL; 161251881Speter /* XXX: atmresolve already free'd it */ 162251881Speter senderr(EHOSTUNREACH); 163251881Speter /* XXX: put ATMARP stuff here */ 164251881Speter /* XXX: watch who frees m on failure */ 165251881Speter } 166251881Speter } 167251881Speter break; 168251881Speter#endif /* INET || INET6 */ 169251881Speter 170251881Speter case AF_UNSPEC: 171251881Speter /* 172251881Speter * XXX: bpfwrite. assuming dst contains 12 bytes 173251881Speter * (atm pseudo header (4) + LLC/SNAP (8)) 174251881Speter */ 175251881Speter bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 176251881Speter llc_hdr = (struct atmllc *)(dst->sa_data + 177251881Speter sizeof(atmdst)); 178251881Speter break; 179251881Speter 180251881Speter default: 181251881Speter printf("%s: can't handle af%d\n", ifp->if_xname, 182251881Speter dst->sa_family); 183251881Speter senderr(EAFNOSUPPORT); 184251881Speter } 185251881Speter 186251881Speter /* 187251881Speter * must add atm_pseudohdr to data 188251881Speter */ 189251881Speter sz = sizeof(atmdst); 190251881Speter atm_flags = ATM_PH_FLAGS(&atmdst); 191251881Speter if (atm_flags & ATM_PH_LLCSNAP) 192251881Speter sz += 8; /* sizeof snap == 8 */ 193251881Speter M_PREPEND(m, sz, M_DONTWAIT); 194251881Speter if (m == 0) 195251881Speter senderr(ENOBUFS); 196251881Speter ad = mtod(m, struct atm_pseudohdr *); 197251881Speter *ad = atmdst; 198251881Speter if (atm_flags & ATM_PH_LLCSNAP) { 199251881Speter atmllc = (struct atmllc *)(ad + 1); 200251881Speter if (llc_hdr == NULL) { 201251881Speter bcopy(ATMLLC_HDR, atmllc->llchdr, 202251881Speter sizeof(atmllc->llchdr)); 203251881Speter /* note: in host order */ 204251881Speter ATM_LLC_SETTYPE(atmllc, etype); 205251881Speter } 206251881Speter else 207251881Speter bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 208251881Speter } 209251881Speter } 210251881Speter 211251881Speter if (ng_atm_output_p != NULL) { 212251881Speter if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) { 213251881Speter if (m != NULL) 214251881Speter m_freem(m); 215251881Speter return (error); 216251881Speter } 217251881Speter if (m == NULL) 218251881Speter return (0); 219251881Speter } 220251881Speter 221251881Speter /* 222251881Speter * Queue message on interface, and start output if interface 223251881Speter * not yet active. 224251881Speter */ 225251881Speter if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, 226251881Speter -(int)sizeof(struct atm_pseudohdr))) 227251881Speter return (ENOBUFS); 228251881Speter return (error); 229251881Speter 230251881Speterbad: 231251881Speter if (m) 232251881Speter m_freem(m); 233251881Speter return (error); 234251881Speter} 235251881Speter 236251881Speter/* 237251881Speter * Process a received ATM packet; 238251881Speter * the packet is in the mbuf chain m. 239251881Speter */ 240251881Spetervoid 241251881Speteratm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 242251881Speter void *rxhand) 243251881Speter{ 244251881Speter int isr; 245251881Speter u_int16_t etype = ETHERTYPE_IP; /* default */ 246251881Speter 247251881Speter if ((ifp->if_flags & IFF_UP) == 0) { 248251881Speter m_freem(m); 249251881Speter return; 250251881Speter } 251251881Speter#ifdef MAC 252251881Speter mac_ifnet_create_mbuf(ifp, m); 253251881Speter#endif 254251881Speter ifp->if_ibytes += m->m_pkthdr.len; 255251881Speter 256251881Speter if (ng_atm_input_p != NULL) { 257251881Speter (*ng_atm_input_p)(ifp, &m, ah, rxhand); 258251881Speter if (m == NULL) 259251881Speter return; 260251881Speter } 261251881Speter 262251881Speter /* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */ 263251881Speter if (atm_harp_input_p != NULL) { 264251881Speter (*atm_harp_input_p)(ifp, &m, ah, rxhand); 265251881Speter if (m == NULL) 266251881Speter return; 267251881Speter } 268251881Speter 269251881Speter if (rxhand) { 270251881Speter#ifdef NATM 271251881Speter struct natmpcb *npcb; 272251881Speter 273251881Speter /* 274251881Speter * XXXRW: this use of 'rxhand' is not a very good idea, and 275251881Speter * was subject to races even before SMPng due to the release 276251881Speter * of spl here. 277251881Speter */ 278251881Speter NATM_LOCK(); 279251881Speter npcb = rxhand; 280251881Speter npcb->npcb_inq++; /* count # in queue */ 281251881Speter isr = NETISR_NATM; 282251881Speter m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 283251881Speter NATM_UNLOCK(); 284251881Speter#else 285251881Speter printf("atm_input: NATM detected but not " 286251881Speter "configured in kernel\n"); 287251881Speter goto dropit; 288251881Speter#endif 289251881Speter } else { 290251881Speter /* 291251881Speter * handle LLC/SNAP header, if present 292251881Speter */ 293251881Speter if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 294251881Speter struct atmllc *alc; 295251881Speter 296251881Speter if (m->m_len < sizeof(*alc) && 297251881Speter (m = m_pullup(m, sizeof(*alc))) == 0) 298251881Speter return; /* failed */ 299251881Speter alc = mtod(m, struct atmllc *); 300251881Speter if (bcmp(alc, ATMLLC_HDR, 6)) { 301251881Speter printf("%s: recv'd invalid LLC/SNAP frame " 302251881Speter "[vp=%d,vc=%d]\n", ifp->if_xname, 303251881Speter ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 304251881Speter m_freem(m); 305251881Speter return; 306251881Speter } 307251881Speter etype = ATM_LLC_TYPE(alc); 308251881Speter m_adj(m, sizeof(*alc)); 309251881Speter } 310251881Speter 311251881Speter switch (etype) { 312251881Speter 313251881Speter#ifdef INET 314251881Speter case ETHERTYPE_IP: 315251881Speter isr = NETISR_IP; 316251881Speter break; 317251881Speter#endif 318251881Speter 319251881Speter#ifdef INET6 320251881Speter case ETHERTYPE_IPV6: 321251881Speter isr = NETISR_IPV6; 322251881Speter break; 323251881Speter#endif 324251881Speter default: 325251881Speter#ifndef NATM 326251881Speter dropit: 327251881Speter#endif 328251881Speter if (ng_atm_input_orphan_p != NULL) 329251881Speter (*ng_atm_input_orphan_p)(ifp, m, ah, rxhand); 330251881Speter else 331251881Speter m_freem(m); 332251881Speter return; 333251881Speter } 334251881Speter } 335251881Speter M_SETFIB(m, ifp->if_fib); 336251881Speter netisr_dispatch(isr, m); 337251881Speter} 338251881Speter 339251881Speter/* 340251881Speter * Perform common duties while attaching to interface list. 341251881Speter */ 342251881Spetervoid 343251881Speteratm_ifattach(struct ifnet *ifp) 344251881Speter{ 345251881Speter struct ifaddr *ifa; 346251881Speter struct sockaddr_dl *sdl; 347251881Speter struct ifatm *ifatm = ifp->if_l2com; 348251881Speter 349251881Speter ifp->if_addrlen = 0; 350251881Speter ifp->if_hdrlen = 0; 351251881Speter if_attach(ifp); 352251881Speter ifp->if_mtu = ATMMTU; 353251881Speter ifp->if_output = atm_output; 354251881Speter#if 0 355251881Speter ifp->if_input = atm_input; 356251881Speter#endif 357251881Speter ifp->if_snd.ifq_maxlen = 50; /* dummy */ 358251881Speter 359251881Speter TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 360251881Speter if (ifa->ifa_addr->sa_family == AF_LINK) { 361251881Speter sdl = (struct sockaddr_dl *)ifa->ifa_addr; 362251881Speter sdl->sdl_type = IFT_ATM; 363251881Speter sdl->sdl_alen = ifp->if_addrlen; 364251881Speter#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 365251881Speter bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 366251881Speter#endif 367251881Speter break; 368251881Speter } 369251881Speter 370251881Speter ifp->if_linkmib = &ifatm->mib; 371251881Speter ifp->if_linkmiblen = sizeof(ifatm->mib); 372251881Speter 373251881Speter if(ng_atm_attach_p) 374251881Speter (*ng_atm_attach_p)(ifp); 375251881Speter if (atm_harp_attach_p) 376251881Speter (*atm_harp_attach_p)(ifp); 377251881Speter} 378251881Speter 379251881Speter/* 380251881Speter * Common stuff for detaching an ATM interface 381251881Speter */ 382251881Spetervoid 383251881Speteratm_ifdetach(struct ifnet *ifp) 384251881Speter{ 385251881Speter if (atm_harp_detach_p) 386251881Speter (*atm_harp_detach_p)(ifp); 387251881Speter if(ng_atm_detach_p) 388251881Speter (*ng_atm_detach_p)(ifp); 389251881Speter if_detach(ifp); 390251881Speter} 391251881Speter 392251881Speter/* 393251881Speter * Support routine for the SIOCATMGVCCS ioctl(). 394251881Speter * 395251881Speter * This routine assumes, that the private VCC structures used by the driver 396251881Speter * begin with a struct atmio_vcc. 397251881Speter * 398251881Speter * Return a table of VCCs in a freshly allocated memory area. 399251881Speter * Here we have a problem: we first count, how many vccs we need 400251881Speter * to return. The we allocate the memory and finally fill it in. 401251881Speter * Because we cannot lock while calling malloc, the number of active 402251881Speter * vccs may change while we're in malloc. So we allocate a couple of 403251881Speter * vccs more and if space anyway is not enough re-iterate. 404251881Speter * 405251881Speter * We could use an sx lock for the vcc tables. 406251881Speter */ 407251881Speterstruct atmio_vcctable * 408251881Speteratm_getvccs(struct atmio_vcc **table, u_int size, u_int start, 409251881Speter struct mtx *lock, int waitok) 410251881Speter{ 411251881Speter u_int cid, alloc; 412251881Speter size_t len; 413251881Speter struct atmio_vcctable *vccs; 414251881Speter struct atmio_vcc *v; 415251881Speter 416251881Speter alloc = start + 10; 417251881Speter vccs = NULL; 418251881Speter 419251881Speter for (;;) { 420251881Speter len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]); 421251881Speter vccs = reallocf(vccs, len, M_TEMP, 422251881Speter waitok ? M_WAITOK : M_NOWAIT); 423251881Speter if (vccs == NULL) 424251881Speter return (NULL); 425251881Speter bzero(vccs, len); 426251881Speter 427251881Speter vccs->count = 0; 428251881Speter v = vccs->vccs; 429251881Speter 430251881Speter mtx_lock(lock); 431251881Speter for (cid = 0; cid < size; cid++) 432251881Speter if (table[cid] != NULL) { 433251881Speter if (++vccs->count == alloc) 434251881Speter /* too many - try again */ 435251881Speter break; 436251881Speter *v++ = *table[cid]; 437251881Speter } 438251881Speter mtx_unlock(lock); 439251881Speter 440251881Speter if (cid == size) 441251881Speter break; 442251881Speter 443251881Speter alloc *= 2; 444251881Speter } 445251881Speter return (vccs); 446251881Speter} 447251881Speter 448251881Speter/* 449251881Speter * Driver or channel state has changed. Inform whoever is interested 450251881Speter * in these events. 451251881Speter */ 452251881Spetervoid 453251881Speteratm_event(struct ifnet *ifp, u_int event, void *arg) 454251881Speter{ 455251881Speter if (ng_atm_event_p != NULL) 456251881Speter (*ng_atm_event_p)(ifp, event, arg); 457251881Speter if (atm_harp_event_p != NULL) 458251881Speter (*atm_harp_event_p)(ifp, event, arg); 459251881Speter} 460251881Speter 461251881Speterstatic void * 462251881Speteratm_alloc(u_char type, struct ifnet *ifp) 463251881Speter{ 464251881Speter struct ifatm *ifatm; 465251881Speter 466251881Speter ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO); 467251881Speter ifatm->ifp = ifp; 468251881Speter 469251881Speter return (ifatm); 470251881Speter} 471251881Speter 472251881Speterstatic void 473251881Speteratm_free(void *com, u_char type) 474251881Speter{ 475251881Speter 476251881Speter free(com, M_IFATM); 477251881Speter} 478251881Speter 479251881Speterstatic int 480251881Speteratm_modevent(module_t mod, int type, void *data) 481251881Speter{ 482251881Speter switch (type) { 483251881Speter case MOD_LOAD: 484251881Speter if_register_com_alloc(IFT_ATM, atm_alloc, atm_free); 485251881Speter break; 486251881Speter case MOD_UNLOAD: 487251881Speter if_deregister_com_alloc(IFT_ATM); 488251881Speter break; 489251881Speter default: 490251881Speter return (EOPNOTSUPP); 491251881Speter } 492251881Speter 493251881Speter return (0); 494251881Speter} 495251881Speter 496251881Speterstatic moduledata_t atm_mod = { 497251881Speter "atm", 498251881Speter atm_modevent, 499251881Speter 0 500251881Speter}; 501251881Speter 502251881SpeterDECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 503251881SpeterMODULE_VERSION(atm, 1); 504251881Speter