if_atmsubr.c revision 148125
1187498Simp/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ 2187498Simp 3187498Simp/*- 4187498Simp * 5187498Simp * Copyright (c) 1996 Charles D. Cranor and Washington University. 6187498Simp * All rights reserved. 7215270Simp * 8187498Simp * Redistribution and use in source and binary forms, with or without 9187498Simp * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles D. Cranor and 19 * Washington University. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * if_atmsubr.c 35 */ 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: head/sys/net/if_atmsubr.c 148125 2005-07-18 16:55:46Z rwatson $"); 39 40#include "opt_inet.h" 41#include "opt_inet6.h" 42#include "opt_mac.h" 43#include "opt_natm.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/module.h> 49#include <sys/mac.h> 50#include <sys/mbuf.h> 51#include <sys/socket.h> 52#include <sys/sockio.h> 53#include <sys/errno.h> 54#include <sys/sysctl.h> 55#include <sys/malloc.h> 56 57#include <net/if.h> 58#include <net/netisr.h> 59#include <net/route.h> 60#include <net/if_dl.h> 61#include <net/if_types.h> 62#include <net/if_atm.h> 63 64#include <netinet/in.h> 65#include <netinet/if_atm.h> 66#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 67#if defined(INET) || defined(INET6) 68#include <netinet/in_var.h> 69#endif 70#ifdef NATM 71#include <netnatm/natm.h> 72#endif 73 74/* 75 * Netgraph interface functions. 76 * These need not be protected by a lock, because ng_atm nodes are persitent. 77 * The ng_atm module can be unloaded only if all ATM interfaces have been 78 * unloaded, so nobody should be in the code paths accessing these function 79 * pointers. 80 */ 81void (*ng_atm_attach_p)(struct ifnet *); 82void (*ng_atm_detach_p)(struct ifnet *); 83int (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 84void (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 85 struct atm_pseudohdr *, void *); 86void (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 87 struct atm_pseudohdr *, void *); 88void (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 89 90/* 91 * Harp pseudo interface hooks 92 */ 93void (*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m, 94 struct atm_pseudohdr *ah, void *rxhand); 95void (*atm_harp_attach_p)(struct ifnet *); 96void (*atm_harp_detach_p)(struct ifnet *); 97void (*atm_harp_event_p)(struct ifnet *, uint32_t, void *); 98 99SYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware"); 100 101MALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals"); 102 103#ifndef ETHERTYPE_IPV6 104#define ETHERTYPE_IPV6 0x86dd 105#endif 106 107#define senderr(e) do { error = (e); goto bad; } while (0) 108 109/* 110 * atm_output: ATM output routine 111 * inputs: 112 * "ifp" = ATM interface to output to 113 * "m0" = the packet to output 114 * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 115 * "rt0" = the route to use 116 * returns: error code [0 == ok] 117 * 118 * note: special semantic: if (dst == NULL) then we assume "m" already 119 * has an atm_pseudohdr on it and just send it directly. 120 * [for native mode ATM output] if dst is null, then 121 * rt0 must also be NULL. 122 */ 123int 124atm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, 125 struct rtentry *rt0) 126{ 127 u_int16_t etype = 0; /* if using LLC/SNAP */ 128 int error = 0, sz; 129 struct atm_pseudohdr atmdst, *ad; 130 struct mbuf *m = m0; 131 struct atmllc *atmllc; 132 struct atmllc *llc_hdr = NULL; 133 u_int32_t atm_flags; 134 135#ifdef MAC 136 error = mac_check_ifnet_transmit(ifp, m); 137 if (error) 138 senderr(error); 139#endif 140 141 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) 142 senderr(ENETDOWN); 143 144 /* 145 * check for non-native ATM traffic (dst != NULL) 146 */ 147 if (dst) { 148 switch (dst->sa_family) { 149 150#if defined(INET) || defined(INET6) 151 case AF_INET: 152 case AF_INET6: 153 { 154 struct rtentry *rt; 155 /* 156 * check route 157 */ 158 error = rt_check(&rt, &rt0, dst); 159 if (error) 160 goto bad; 161 162 if (dst->sa_family == AF_INET6) 163 etype = ETHERTYPE_IPV6; 164 else 165 etype = ETHERTYPE_IP; 166 if (!atmresolve(rt, m, dst, &atmdst)) { 167 m = NULL; 168 /* XXX: atmresolve already free'd it */ 169 senderr(EHOSTUNREACH); 170 /* XXX: put ATMARP stuff here */ 171 /* XXX: watch who frees m on failure */ 172 } 173 } 174 break; 175#endif /* INET || INET6 */ 176 177 case AF_UNSPEC: 178 /* 179 * XXX: bpfwrite. assuming dst contains 12 bytes 180 * (atm pseudo header (4) + LLC/SNAP (8)) 181 */ 182 bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 183 llc_hdr = (struct atmllc *)(dst->sa_data + 184 sizeof(atmdst)); 185 break; 186 187 default: 188#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \ 189 defined(__NetBSD__) || defined(__OpenBSD__) 190 printf("%s: can't handle af%d\n", ifp->if_xname, 191 dst->sa_family); 192#elif defined(__FreeBSD__) || defined(__bsdi__) 193 printf("%s%d: can't handle af%d\n", ifp->if_name, 194 ifp->if_unit, dst->sa_family); 195#endif 196 senderr(EAFNOSUPPORT); 197 } 198 199 /* 200 * must add atm_pseudohdr to data 201 */ 202 sz = sizeof(atmdst); 203 atm_flags = ATM_PH_FLAGS(&atmdst); 204 if (atm_flags & ATM_PH_LLCSNAP) 205 sz += 8; /* sizeof snap == 8 */ 206 M_PREPEND(m, sz, M_DONTWAIT); 207 if (m == 0) 208 senderr(ENOBUFS); 209 ad = mtod(m, struct atm_pseudohdr *); 210 *ad = atmdst; 211 if (atm_flags & ATM_PH_LLCSNAP) { 212 atmllc = (struct atmllc *)(ad + 1); 213 if (llc_hdr == NULL) { 214 bcopy(ATMLLC_HDR, atmllc->llchdr, 215 sizeof(atmllc->llchdr)); 216 /* note: in host order */ 217 ATM_LLC_SETTYPE(atmllc, etype); 218 } 219 else 220 bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 221 } 222 } 223 224 if (ng_atm_output_p != NULL) { 225 if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) { 226 if (m != NULL) 227 m_freem(m); 228 return (error); 229 } 230 if (m == NULL) 231 return (0); 232 } 233 234 /* 235 * Queue message on interface, and start output if interface 236 * not yet active. 237 */ 238 if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, 239 -(int)sizeof(struct atm_pseudohdr))) 240 return (ENOBUFS); 241 return (error); 242 243bad: 244 if (m) 245 m_freem(m); 246 return (error); 247} 248 249/* 250 * Process a received ATM packet; 251 * the packet is in the mbuf chain m. 252 */ 253void 254atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 255 void *rxhand) 256{ 257 int isr; 258 u_int16_t etype = ETHERTYPE_IP; /* default */ 259 260 if ((ifp->if_flags & IFF_UP) == 0) { 261 m_freem(m); 262 return; 263 } 264#ifdef MAC 265 mac_create_mbuf_from_ifnet(ifp, m); 266#endif 267 ifp->if_ibytes += m->m_pkthdr.len; 268 269 if (ng_atm_input_p != NULL) { 270 (*ng_atm_input_p)(ifp, &m, ah, rxhand); 271 if (m == NULL) 272 return; 273 } 274 275 /* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */ 276 if (atm_harp_input_p != NULL) { 277 (*atm_harp_input_p)(ifp, &m, ah, rxhand); 278 if (m == NULL) 279 return; 280 } 281 282 if (rxhand) { 283#ifdef NATM 284 struct natmpcb *npcb; 285 286 /* 287 * XXXRW: this use of 'rxhand' is not a very good idea, and 288 * was subject to races even before SMPng due to the release 289 * of spl here. 290 */ 291 NATM_LOCK(); 292 npcb = rxhand; 293 npcb->npcb_inq++; /* count # in queue */ 294 isr = NETISR_NATM; 295 m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 296 NATM_UNLOCK(); 297#else 298 printf("atm_input: NATM detected but not " 299 "configured in kernel\n"); 300 goto dropit; 301#endif 302 } else { 303 /* 304 * handle LLC/SNAP header, if present 305 */ 306 if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 307 struct atmllc *alc; 308 309 if (m->m_len < sizeof(*alc) && 310 (m = m_pullup(m, sizeof(*alc))) == 0) 311 return; /* failed */ 312 alc = mtod(m, struct atmllc *); 313 if (bcmp(alc, ATMLLC_HDR, 6)) { 314#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \ 315 defined(__NetBSD__) || defined(__OpenBSD__) 316 printf("%s: recv'd invalid LLC/SNAP frame " 317 "[vp=%d,vc=%d]\n", ifp->if_xname, 318 ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 319#elif defined(__FreeBSD__) || defined(__bsdi__) 320 printf("%s%d: recv'd invalid LLC/SNAP frame " 321 "[vp=%d,vc=%d]\n", ifp->if_name, 322 ifp->if_unit, ATM_PH_VPI(ah), 323 ATM_PH_VCI(ah)); 324#endif 325 m_freem(m); 326 return; 327 } 328 etype = ATM_LLC_TYPE(alc); 329 m_adj(m, sizeof(*alc)); 330 } 331 332 switch (etype) { 333 334#ifdef INET 335 case ETHERTYPE_IP: 336 isr = NETISR_IP; 337 break; 338#endif 339 340#ifdef INET6 341 case ETHERTYPE_IPV6: 342 isr = NETISR_IPV6; 343 break; 344#endif 345 default: 346#ifndef NATM 347 dropit: 348#endif 349 if (ng_atm_input_orphan_p != NULL) 350 (*ng_atm_input_orphan_p)(ifp, m, ah, rxhand); 351 else 352 m_freem(m); 353 return; 354 } 355 } 356 netisr_dispatch(isr, m); 357} 358 359/* 360 * Perform common duties while attaching to interface list. 361 */ 362void 363atm_ifattach(struct ifnet *ifp) 364{ 365 struct ifaddr *ifa; 366 struct sockaddr_dl *sdl; 367 struct ifatm *ifatm = ifp->if_l2com; 368 369 ifp->if_addrlen = 0; 370 ifp->if_hdrlen = 0; 371 if_attach(ifp); 372 ifp->if_mtu = ATMMTU; 373 ifp->if_output = atm_output; 374#if 0 375 ifp->if_input = atm_input; 376#endif 377 ifp->if_snd.ifq_maxlen = 50; /* dummy */ 378 379#if defined(__NetBSD__) || defined(__OpenBSD__) 380 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 381#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) 382 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 383 ifa = TAILQ_NEXT(ifa, ifa_link)) 384#elif defined(__FreeBSD__) || defined(__bsdi__) 385 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 386#endif 387 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 388 sdl->sdl_family == AF_LINK) { 389 sdl->sdl_type = IFT_ATM; 390 sdl->sdl_alen = ifp->if_addrlen; 391#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 392 bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 393#endif 394 break; 395 } 396 397 ifp->if_linkmib = &ifatm->mib; 398 ifp->if_linkmiblen = sizeof(ifatm->mib); 399 400 if(ng_atm_attach_p) 401 (*ng_atm_attach_p)(ifp); 402 if (atm_harp_attach_p) 403 (*atm_harp_attach_p)(ifp); 404} 405 406/* 407 * Common stuff for detaching an ATM interface 408 */ 409void 410atm_ifdetach(struct ifnet *ifp) 411{ 412 if (atm_harp_detach_p) 413 (*atm_harp_detach_p)(ifp); 414 if(ng_atm_detach_p) 415 (*ng_atm_detach_p)(ifp); 416 if_detach(ifp); 417} 418 419/* 420 * Support routine for the SIOCATMGVCCS ioctl(). 421 * 422 * This routine assumes, that the private VCC structures used by the driver 423 * begin with a struct atmio_vcc. 424 * 425 * Return a table of VCCs in a freshly allocated memory area. 426 * Here we have a problem: we first count, how many vccs we need 427 * to return. The we allocate the memory and finally fill it in. 428 * Because we cannot lock while calling malloc, the number of active 429 * vccs may change while we're in malloc. So we allocate a couple of 430 * vccs more and if space anyway is not enough re-iterate. 431 * 432 * We could use an sx lock for the vcc tables. 433 */ 434struct atmio_vcctable * 435atm_getvccs(struct atmio_vcc **table, u_int size, u_int start, 436 struct mtx *lock, int waitok) 437{ 438 u_int cid, alloc; 439 size_t len; 440 struct atmio_vcctable *vccs; 441 struct atmio_vcc *v; 442 443 alloc = start + 10; 444 vccs = NULL; 445 446 for (;;) { 447 len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]); 448 vccs = reallocf(vccs, len, M_TEMP, 449 waitok ? M_WAITOK : M_NOWAIT); 450 if (vccs == NULL) 451 return (NULL); 452 bzero(vccs, len); 453 454 vccs->count = 0; 455 v = vccs->vccs; 456 457 mtx_lock(lock); 458 for (cid = 0; cid < size; cid++) 459 if (table[cid] != NULL) { 460 if (++vccs->count == alloc) 461 /* too many - try again */ 462 break; 463 *v++ = *table[cid]; 464 } 465 mtx_unlock(lock); 466 467 if (cid == size) 468 break; 469 470 alloc *= 2; 471 } 472 return (vccs); 473} 474 475/* 476 * Driver or channel state has changed. Inform whoever is interested 477 * in these events. 478 */ 479void 480atm_event(struct ifnet *ifp, u_int event, void *arg) 481{ 482 if (ng_atm_event_p != NULL) 483 (*ng_atm_event_p)(ifp, event, arg); 484 if (atm_harp_event_p != NULL) 485 (*atm_harp_event_p)(ifp, event, arg); 486} 487 488static void * 489atm_alloc(u_char type, struct ifnet *ifp) 490{ 491 struct ifatm *ifatm; 492 493 ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO); 494 ifatm->ifp = ifp; 495 496 return (ifatm); 497} 498 499static void 500atm_free(void *com, u_char type) 501{ 502 503 free(com, M_IFATM); 504} 505 506static int 507atm_modevent(module_t mod, int type, void *data) 508{ 509 switch (type) { 510 case MOD_LOAD: 511 if_register_com_alloc(IFT_ATM, atm_alloc, atm_free); 512 break; 513 case MOD_UNLOAD: 514 if_deregister_com_alloc(IFT_ATM); 515 break; 516 default: 517 return (EOPNOTSUPP); 518 } 519 520 return (0); 521} 522 523static moduledata_t atm_mod = { 524 "atm", 525 atm_modevent, 526 0 527}; 528 529DECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 530MODULE_VERSION(atm, 1); 531