if_atmsubr.c revision 148954
120253Sjoerg/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ 220302Sjoerg 320302Sjoerg/*- 420253Sjoerg * 520253Sjoerg * Copyright (c) 1996 Charles D. Cranor and Washington University. 620253Sjoerg * All rights reserved. 720253Sjoerg * 820253Sjoerg * Redistribution and use in source and binary forms, with or without 920302Sjoerg * modification, are permitted provided that the following conditions 1020253Sjoerg * are met: 1120253Sjoerg * 1. Redistributions of source code must retain the above copyright 1220253Sjoerg * notice, this list of conditions and the following disclaimer. 1320253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1420302Sjoerg * notice, this list of conditions and the following disclaimer in the 1520253Sjoerg * documentation and/or other materials provided with the distribution. 1620253Sjoerg * 3. All advertising materials mentioning features or use of this software 1720302Sjoerg * must display the following acknowledgement: 1820253Sjoerg * This product includes software developed by Charles D. Cranor and 1920253Sjoerg * Washington University. 2020253Sjoerg * 4. The name of the author may not be used to endorse or promote products 2120253Sjoerg * derived from this software without specific prior written permission. 2220253Sjoerg * 2320253Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2420253Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2520253Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2620253Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2730259Scharnier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2830259Scharnier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2950479Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3030259Scharnier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3130259Scharnier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3220253Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3320253Sjoerg * 3420253Sjoerg * if_atmsubr.c 3520253Sjoerg */ 3620253Sjoerg 3720253Sjoerg#include <sys/cdefs.h> 3820253Sjoerg__FBSDID("$FreeBSD: head/sys/net/if_atmsubr.c 148954 2005-08-11 08:14:53Z glebius $"); 3944229Sdavidn 4020253Sjoerg#include "opt_inet.h" 4120253Sjoerg#include "opt_inet6.h" 4220253Sjoerg#include "opt_mac.h" 4344229Sdavidn#include "opt_natm.h" 4444229Sdavidn 4520253Sjoerg#include <sys/param.h> 4644229Sdavidn#include <sys/systm.h> 4744229Sdavidn#include <sys/kernel.h> 4844229Sdavidn#include <sys/module.h> 4944229Sdavidn#include <sys/mac.h> 5044229Sdavidn#include <sys/mbuf.h> 5144229Sdavidn#include <sys/socket.h> 5244229Sdavidn#include <sys/sockio.h> 5344229Sdavidn#include <sys/errno.h> 5444229Sdavidn#include <sys/sysctl.h> 5544229Sdavidn#include <sys/malloc.h> 5644229Sdavidn 5744229Sdavidn#include <net/if.h> 5844229Sdavidn#include <net/netisr.h> 5944229Sdavidn#include <net/route.h> 6044229Sdavidn#include <net/if_dl.h> 6144229Sdavidn#include <net/if_types.h> 6244229Sdavidn#include <net/if_atm.h> 6344229Sdavidn 6444229Sdavidn#include <netinet/in.h> 6544229Sdavidn#include <netinet/if_atm.h> 6644229Sdavidn#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */ 6744229Sdavidn#if defined(INET) || defined(INET6) 6844229Sdavidn#include <netinet/in_var.h> 6944229Sdavidn#endif 7044229Sdavidn#ifdef NATM 7144229Sdavidn#include <netnatm/natm.h> 7244229Sdavidn#endif 7344229Sdavidn 7444229Sdavidn/* 7544229Sdavidn * Netgraph interface functions. 7644229Sdavidn * These need not be protected by a lock, because ng_atm nodes are persitent. 7744229Sdavidn * The ng_atm module can be unloaded only if all ATM interfaces have been 7844229Sdavidn * unloaded, so nobody should be in the code paths accessing these function 7944229Sdavidn * pointers. 8020747Sdavidn */ 8120253Sjoergvoid (*ng_atm_attach_p)(struct ifnet *); 8220253Sjoergvoid (*ng_atm_detach_p)(struct ifnet *); 8320253Sjoergint (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 8420253Sjoergvoid (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 8520747Sdavidn struct atm_pseudohdr *, void *); 8620747Sdavidnvoid (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 8720747Sdavidn struct atm_pseudohdr *, void *); 8820253Sjoergvoid (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 8920747Sdavidn 9020747Sdavidn/* 9120747Sdavidn * Harp pseudo interface hooks 9220747Sdavidn */ 9320747Sdavidnvoid (*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m, 9420747Sdavidn struct atm_pseudohdr *ah, void *rxhand); 9520747Sdavidnvoid (*atm_harp_attach_p)(struct ifnet *); 9620747Sdavidnvoid (*atm_harp_detach_p)(struct ifnet *); 9720747Sdavidnvoid (*atm_harp_event_p)(struct ifnet *, uint32_t, void *); 9820747Sdavidn 9920747SdavidnSYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware"); 10020747Sdavidn 10120747SdavidnMALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals"); 10220747Sdavidn 10320747Sdavidn#ifndef ETHERTYPE_IPV6 10420747Sdavidn#define ETHERTYPE_IPV6 0x86dd 10520747Sdavidn#endif 10620747Sdavidn 10720747Sdavidn#define senderr(e) do { error = (e); goto bad; } while (0) 10820747Sdavidn 10920747Sdavidn/* 11020747Sdavidn * atm_output: ATM output routine 11120747Sdavidn * inputs: 11220747Sdavidn * "ifp" = ATM interface to output to 11320747Sdavidn * "m0" = the packet to output 11420747Sdavidn * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 11520747Sdavidn * "rt0" = the route to use 11620747Sdavidn * returns: error code [0 == ok] 11720253Sjoerg * 11820253Sjoerg * note: special semantic: if (dst == NULL) then we assume "m" already 11920253Sjoerg * has an atm_pseudohdr on it and just send it directly. 12020253Sjoerg * [for native mode ATM output] if dst is null, then 12120253Sjoerg * rt0 must also be NULL. 12220747Sdavidn */ 12320253Sjoergint 12420747Sdavidnatm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, 12520253Sjoerg struct rtentry *rt0) 12620253Sjoerg{ 12720253Sjoerg u_int16_t etype = 0; /* if using LLC/SNAP */ 12820253Sjoerg int error = 0, sz; 12920253Sjoerg struct atm_pseudohdr atmdst, *ad; 13020253Sjoerg struct mbuf *m = m0; 13120253Sjoerg struct atmllc *atmllc; 13220747Sdavidn struct atmllc *llc_hdr = NULL; 13320747Sdavidn u_int32_t atm_flags; 13420747Sdavidn 13520253Sjoerg#ifdef MAC 13644229Sdavidn error = mac_check_ifnet_transmit(ifp, m); 13720747Sdavidn if (error) 13820253Sjoerg senderr(error); 13920253Sjoerg#endif 14020253Sjoerg 14120253Sjoerg if (!((ifp->if_flags & IFF_UP) && 14220747Sdavidn (ifp->if_drv_flags & IFF_DRV_RUNNING))) 14320747Sdavidn senderr(ENETDOWN); 14444229Sdavidn 14544229Sdavidn /* 14644229Sdavidn * check for non-native ATM traffic (dst != NULL) 14744229Sdavidn */ 14820747Sdavidn if (dst) { 14920747Sdavidn switch (dst->sa_family) { 15020747Sdavidn 15120253Sjoerg#if defined(INET) || defined(INET6) 15220253Sjoerg case AF_INET: 15320253Sjoerg case AF_INET6: 15420253Sjoerg { 15520253Sjoerg struct rtentry *rt = NULL; 15620253Sjoerg /* 15720253Sjoerg * check route 15820253Sjoerg */ 15920253Sjoerg if (rt0 != NULL) { 16020253Sjoerg error = rt_check(&rt, &rt0, dst); 16120253Sjoerg if (error) 16220253Sjoerg goto bad; 16320253Sjoerg RT_UNLOCK(rt); 16420253Sjoerg } 16520253Sjoerg 16620253Sjoerg if (dst->sa_family == AF_INET6) 16720253Sjoerg etype = ETHERTYPE_IPV6; 16820253Sjoerg else 16920253Sjoerg etype = ETHERTYPE_IP; 17020253Sjoerg if (!atmresolve(rt, m, dst, &atmdst)) { 171 m = NULL; 172 /* XXX: atmresolve already free'd it */ 173 senderr(EHOSTUNREACH); 174 /* XXX: put ATMARP stuff here */ 175 /* XXX: watch who frees m on failure */ 176 } 177 } 178 break; 179#endif /* INET || INET6 */ 180 181 case AF_UNSPEC: 182 /* 183 * XXX: bpfwrite. assuming dst contains 12 bytes 184 * (atm pseudo header (4) + LLC/SNAP (8)) 185 */ 186 bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 187 llc_hdr = (struct atmllc *)(dst->sa_data + 188 sizeof(atmdst)); 189 break; 190 191 default: 192#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \ 193 defined(__NetBSD__) || defined(__OpenBSD__) 194 printf("%s: can't handle af%d\n", ifp->if_xname, 195 dst->sa_family); 196#elif defined(__FreeBSD__) || defined(__bsdi__) 197 printf("%s%d: can't handle af%d\n", ifp->if_name, 198 ifp->if_unit, dst->sa_family); 199#endif 200 senderr(EAFNOSUPPORT); 201 } 202 203 /* 204 * must add atm_pseudohdr to data 205 */ 206 sz = sizeof(atmdst); 207 atm_flags = ATM_PH_FLAGS(&atmdst); 208 if (atm_flags & ATM_PH_LLCSNAP) 209 sz += 8; /* sizeof snap == 8 */ 210 M_PREPEND(m, sz, M_DONTWAIT); 211 if (m == 0) 212 senderr(ENOBUFS); 213 ad = mtod(m, struct atm_pseudohdr *); 214 *ad = atmdst; 215 if (atm_flags & ATM_PH_LLCSNAP) { 216 atmllc = (struct atmllc *)(ad + 1); 217 if (llc_hdr == NULL) { 218 bcopy(ATMLLC_HDR, atmllc->llchdr, 219 sizeof(atmllc->llchdr)); 220 /* note: in host order */ 221 ATM_LLC_SETTYPE(atmllc, etype); 222 } 223 else 224 bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 225 } 226 } 227 228 if (ng_atm_output_p != NULL) { 229 if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) { 230 if (m != NULL) 231 m_freem(m); 232 return (error); 233 } 234 if (m == NULL) 235 return (0); 236 } 237 238 /* 239 * Queue message on interface, and start output if interface 240 * not yet active. 241 */ 242 if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, 243 -(int)sizeof(struct atm_pseudohdr))) 244 return (ENOBUFS); 245 return (error); 246 247bad: 248 if (m) 249 m_freem(m); 250 return (error); 251} 252 253/* 254 * Process a received ATM packet; 255 * the packet is in the mbuf chain m. 256 */ 257void 258atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 259 void *rxhand) 260{ 261 int isr; 262 u_int16_t etype = ETHERTYPE_IP; /* default */ 263 264 if ((ifp->if_flags & IFF_UP) == 0) { 265 m_freem(m); 266 return; 267 } 268#ifdef MAC 269 mac_create_mbuf_from_ifnet(ifp, m); 270#endif 271 ifp->if_ibytes += m->m_pkthdr.len; 272 273 if (ng_atm_input_p != NULL) { 274 (*ng_atm_input_p)(ifp, &m, ah, rxhand); 275 if (m == NULL) 276 return; 277 } 278 279 /* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */ 280 if (atm_harp_input_p != NULL) { 281 (*atm_harp_input_p)(ifp, &m, ah, rxhand); 282 if (m == NULL) 283 return; 284 } 285 286 if (rxhand) { 287#ifdef NATM 288 struct natmpcb *npcb; 289 290 /* 291 * XXXRW: this use of 'rxhand' is not a very good idea, and 292 * was subject to races even before SMPng due to the release 293 * of spl here. 294 */ 295 NATM_LOCK(); 296 npcb = rxhand; 297 npcb->npcb_inq++; /* count # in queue */ 298 isr = NETISR_NATM; 299 m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 300 NATM_UNLOCK(); 301#else 302 printf("atm_input: NATM detected but not " 303 "configured in kernel\n"); 304 goto dropit; 305#endif 306 } else { 307 /* 308 * handle LLC/SNAP header, if present 309 */ 310 if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 311 struct atmllc *alc; 312 313 if (m->m_len < sizeof(*alc) && 314 (m = m_pullup(m, sizeof(*alc))) == 0) 315 return; /* failed */ 316 alc = mtod(m, struct atmllc *); 317 if (bcmp(alc, ATMLLC_HDR, 6)) { 318#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \ 319 defined(__NetBSD__) || defined(__OpenBSD__) 320 printf("%s: recv'd invalid LLC/SNAP frame " 321 "[vp=%d,vc=%d]\n", ifp->if_xname, 322 ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 323#elif defined(__FreeBSD__) || defined(__bsdi__) 324 printf("%s%d: recv'd invalid LLC/SNAP frame " 325 "[vp=%d,vc=%d]\n", ifp->if_name, 326 ifp->if_unit, ATM_PH_VPI(ah), 327 ATM_PH_VCI(ah)); 328#endif 329 m_freem(m); 330 return; 331 } 332 etype = ATM_LLC_TYPE(alc); 333 m_adj(m, sizeof(*alc)); 334 } 335 336 switch (etype) { 337 338#ifdef INET 339 case ETHERTYPE_IP: 340 isr = NETISR_IP; 341 break; 342#endif 343 344#ifdef INET6 345 case ETHERTYPE_IPV6: 346 isr = NETISR_IPV6; 347 break; 348#endif 349 default: 350#ifndef NATM 351 dropit: 352#endif 353 if (ng_atm_input_orphan_p != NULL) 354 (*ng_atm_input_orphan_p)(ifp, m, ah, rxhand); 355 else 356 m_freem(m); 357 return; 358 } 359 } 360 netisr_dispatch(isr, m); 361} 362 363/* 364 * Perform common duties while attaching to interface list. 365 */ 366void 367atm_ifattach(struct ifnet *ifp) 368{ 369 struct ifaddr *ifa; 370 struct sockaddr_dl *sdl; 371 struct ifatm *ifatm = ifp->if_l2com; 372 373 ifp->if_addrlen = 0; 374 ifp->if_hdrlen = 0; 375 if_attach(ifp); 376 ifp->if_mtu = ATMMTU; 377 ifp->if_output = atm_output; 378#if 0 379 ifp->if_input = atm_input; 380#endif 381 ifp->if_snd.ifq_maxlen = 50; /* dummy */ 382 383#if defined(__NetBSD__) || defined(__OpenBSD__) 384 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 385#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) 386 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 387 ifa = TAILQ_NEXT(ifa, ifa_link)) 388#elif defined(__FreeBSD__) || defined(__bsdi__) 389 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 390#endif 391 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 392 sdl->sdl_family == AF_LINK) { 393 sdl->sdl_type = IFT_ATM; 394 sdl->sdl_alen = ifp->if_addrlen; 395#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 396 bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 397#endif 398 break; 399 } 400 401 ifp->if_linkmib = &ifatm->mib; 402 ifp->if_linkmiblen = sizeof(ifatm->mib); 403 404 if(ng_atm_attach_p) 405 (*ng_atm_attach_p)(ifp); 406 if (atm_harp_attach_p) 407 (*atm_harp_attach_p)(ifp); 408} 409 410/* 411 * Common stuff for detaching an ATM interface 412 */ 413void 414atm_ifdetach(struct ifnet *ifp) 415{ 416 if (atm_harp_detach_p) 417 (*atm_harp_detach_p)(ifp); 418 if(ng_atm_detach_p) 419 (*ng_atm_detach_p)(ifp); 420 if_detach(ifp); 421} 422 423/* 424 * Support routine for the SIOCATMGVCCS ioctl(). 425 * 426 * This routine assumes, that the private VCC structures used by the driver 427 * begin with a struct atmio_vcc. 428 * 429 * Return a table of VCCs in a freshly allocated memory area. 430 * Here we have a problem: we first count, how many vccs we need 431 * to return. The we allocate the memory and finally fill it in. 432 * Because we cannot lock while calling malloc, the number of active 433 * vccs may change while we're in malloc. So we allocate a couple of 434 * vccs more and if space anyway is not enough re-iterate. 435 * 436 * We could use an sx lock for the vcc tables. 437 */ 438struct atmio_vcctable * 439atm_getvccs(struct atmio_vcc **table, u_int size, u_int start, 440 struct mtx *lock, int waitok) 441{ 442 u_int cid, alloc; 443 size_t len; 444 struct atmio_vcctable *vccs; 445 struct atmio_vcc *v; 446 447 alloc = start + 10; 448 vccs = NULL; 449 450 for (;;) { 451 len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]); 452 vccs = reallocf(vccs, len, M_TEMP, 453 waitok ? M_WAITOK : M_NOWAIT); 454 if (vccs == NULL) 455 return (NULL); 456 bzero(vccs, len); 457 458 vccs->count = 0; 459 v = vccs->vccs; 460 461 mtx_lock(lock); 462 for (cid = 0; cid < size; cid++) 463 if (table[cid] != NULL) { 464 if (++vccs->count == alloc) 465 /* too many - try again */ 466 break; 467 *v++ = *table[cid]; 468 } 469 mtx_unlock(lock); 470 471 if (cid == size) 472 break; 473 474 alloc *= 2; 475 } 476 return (vccs); 477} 478 479/* 480 * Driver or channel state has changed. Inform whoever is interested 481 * in these events. 482 */ 483void 484atm_event(struct ifnet *ifp, u_int event, void *arg) 485{ 486 if (ng_atm_event_p != NULL) 487 (*ng_atm_event_p)(ifp, event, arg); 488 if (atm_harp_event_p != NULL) 489 (*atm_harp_event_p)(ifp, event, arg); 490} 491 492static void * 493atm_alloc(u_char type, struct ifnet *ifp) 494{ 495 struct ifatm *ifatm; 496 497 ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO); 498 ifatm->ifp = ifp; 499 500 return (ifatm); 501} 502 503static void 504atm_free(void *com, u_char type) 505{ 506 507 free(com, M_IFATM); 508} 509 510static int 511atm_modevent(module_t mod, int type, void *data) 512{ 513 switch (type) { 514 case MOD_LOAD: 515 if_register_com_alloc(IFT_ATM, atm_alloc, atm_free); 516 break; 517 case MOD_UNLOAD: 518 if_deregister_com_alloc(IFT_ATM); 519 break; 520 default: 521 return (EOPNOTSUPP); 522 } 523 524 return (0); 525} 526 527static moduledata_t atm_mod = { 528 "atm", 529 atm_modevent, 530 0 531}; 532 533DECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 534MODULE_VERSION(atm, 1); 535