if_atmsubr.c revision 124283
1/* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */ 2 3/* 4 * 5 * Copyright (c) 1996 Charles D. Cranor and Washington University. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * 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 124283 2004-01-09 11:25:14Z harti $"); 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 101#ifndef ETHERTYPE_IPV6 102#define ETHERTYPE_IPV6 0x86dd 103#endif 104 105#define senderr(e) do { error = (e); goto bad; } while (0) 106 107/* 108 * atm_output: ATM output routine 109 * inputs: 110 * "ifp" = ATM interface to output to 111 * "m0" = the packet to output 112 * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 113 * "rt0" = the route to use 114 * returns: error code [0 == ok] 115 * 116 * note: special semantic: if (dst == NULL) then we assume "m" already 117 * has an atm_pseudohdr on it and just send it directly. 118 * [for native mode ATM output] if dst is null, then 119 * rt0 must also be NULL. 120 */ 121int 122atm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, 123 struct rtentry *rt0) 124{ 125 u_int16_t etype = 0; /* if using LLC/SNAP */ 126 int error = 0, sz; 127 struct atm_pseudohdr atmdst, *ad; 128 struct mbuf *m = m0; 129 struct rtentry *rt; 130 struct atmllc *atmllc; 131 struct atmllc *llc_hdr = NULL; 132 u_int32_t atm_flags; 133 134#ifdef MAC 135 error = mac_check_ifnet_transmit(ifp, m); 136 if (error) 137 senderr(error); 138#endif 139 140 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) 141 senderr(ENETDOWN); 142 143 /* 144 * check route 145 */ 146 error = rt_check(&rt, &rt0, dst); 147 if (error) 148 goto bad; 149 150 /* 151 * check for non-native ATM traffic (dst != NULL) 152 */ 153 if (dst) { 154 switch (dst->sa_family) { 155 156#if defined(INET) || defined(INET6) 157 case AF_INET: 158 case AF_INET6: 159 if (dst->sa_family == AF_INET6) 160 etype = ETHERTYPE_IPV6; 161 else 162 etype = ETHERTYPE_IP; 163 if (!atmresolve(rt, m, dst, &atmdst)) { 164 m = NULL; 165 /* XXX: atmresolve already free'd it */ 166 senderr(EHOSTUNREACH); 167 /* XXX: put ATMARP stuff here */ 168 /* XXX: watch who frees m on failure */ 169 } 170 break; 171#endif /* INET || INET6 */ 172 173 case AF_UNSPEC: 174 /* 175 * XXX: bpfwrite. assuming dst contains 12 bytes 176 * (atm pseudo header (4) + LLC/SNAP (8)) 177 */ 178 bcopy(dst->sa_data, &atmdst, sizeof(atmdst)); 179 llc_hdr = (struct atmllc *)(dst->sa_data + 180 sizeof(atmdst)); 181 break; 182 183 default: 184#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \ 185 defined(__NetBSD__) || defined(__OpenBSD__) 186 printf("%s: can't handle af%d\n", ifp->if_xname, 187 dst->sa_family); 188#elif defined(__FreeBSD__) || defined(__bsdi__) 189 printf("%s%d: can't handle af%d\n", ifp->if_name, 190 ifp->if_unit, dst->sa_family); 191#endif 192 senderr(EAFNOSUPPORT); 193 } 194 195 /* 196 * must add atm_pseudohdr to data 197 */ 198 sz = sizeof(atmdst); 199 atm_flags = ATM_PH_FLAGS(&atmdst); 200 if (atm_flags & ATM_PH_LLCSNAP) 201 sz += 8; /* sizeof snap == 8 */ 202 M_PREPEND(m, sz, M_DONTWAIT); 203 if (m == 0) 204 senderr(ENOBUFS); 205 ad = mtod(m, struct atm_pseudohdr *); 206 *ad = atmdst; 207 if (atm_flags & ATM_PH_LLCSNAP) { 208 atmllc = (struct atmllc *)(ad + 1); 209 if (llc_hdr == NULL) { 210 bcopy(ATMLLC_HDR, atmllc->llchdr, 211 sizeof(atmllc->llchdr)); 212 /* note: in host order */ 213 ATM_LLC_SETTYPE(atmllc, etype); 214 } 215 else 216 bcopy(llc_hdr, atmllc, sizeof(struct atmllc)); 217 } 218 } 219 220 if (ng_atm_output_p != NULL) { 221 if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) { 222 if (m != NULL) 223 m_freem(m); 224 return (error); 225 } 226 if (m == NULL) 227 return (0); 228 } 229 230 /* 231 * Queue message on interface, and start output if interface 232 * not yet active. 233 */ 234 if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, 235 -(int)sizeof(struct atm_pseudohdr))) 236 return (ENOBUFS); 237 return (error); 238 239bad: 240 if (m) 241 m_freem(m); 242 return (error); 243} 244 245/* 246 * Process a received ATM packet; 247 * the packet is in the mbuf chain m. 248 */ 249void 250atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 251 void *rxhand) 252{ 253 int isr; 254 u_int16_t etype = ETHERTYPE_IP; /* default */ 255#ifdef NATM 256 int s; 257#endif 258 259 if ((ifp->if_flags & IFF_UP) == 0) { 260 m_freem(m); 261 return; 262 } 263#ifdef MAC 264 mac_create_mbuf_from_ifnet(ifp, m); 265#endif 266 ifp->if_ibytes += m->m_pkthdr.len; 267 268 if (ng_atm_input_p != NULL) { 269 (*ng_atm_input_p)(ifp, &m, ah, rxhand); 270 if (m == NULL) 271 return; 272 } 273 274 /* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */ 275 if (atm_harp_input_p != NULL) { 276 (*atm_harp_input_p)(ifp, &m, ah, rxhand); 277 if (m == NULL) 278 return; 279 } 280 281 if (rxhand) { 282#ifdef NATM 283 struct natmpcb *npcb = rxhand; 284 285 s = splimp(); /* in case 2 atm cards @ diff lvls */ 286 npcb->npcb_inq++; /* count # in queue */ 287 splx(s); 288 isr = NETISR_NATM; 289 m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 290#else 291 printf("atm_input: NATM detected but not " 292 "configured in kernel\n"); 293 goto dropit; 294#endif 295 } else { 296 /* 297 * handle LLC/SNAP header, if present 298 */ 299 if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 300 struct atmllc *alc; 301 302 if (m->m_len < sizeof(*alc) && 303 (m = m_pullup(m, sizeof(*alc))) == 0) 304 return; /* failed */ 305 alc = mtod(m, struct atmllc *); 306 if (bcmp(alc, ATMLLC_HDR, 6)) { 307#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \ 308 defined(__NetBSD__) || defined(__OpenBSD__) 309 printf("%s: recv'd invalid LLC/SNAP frame " 310 "[vp=%d,vc=%d]\n", ifp->if_xname, 311 ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 312#elif defined(__FreeBSD__) || defined(__bsdi__) 313 printf("%s%d: recv'd invalid LLC/SNAP frame " 314 "[vp=%d,vc=%d]\n", ifp->if_name, 315 ifp->if_unit, ATM_PH_VPI(ah), 316 ATM_PH_VCI(ah)); 317#endif 318 m_freem(m); 319 return; 320 } 321 etype = ATM_LLC_TYPE(alc); 322 m_adj(m, sizeof(*alc)); 323 } 324 325 switch (etype) { 326 327#ifdef INET 328 case ETHERTYPE_IP: 329 isr = NETISR_IP; 330 break; 331#endif 332 333#ifdef INET6 334 case ETHERTYPE_IPV6: 335 isr = NETISR_IPV6; 336 break; 337#endif 338 default: 339#ifndef NATM 340 dropit: 341#endif 342 if (ng_atm_input_orphan_p != NULL) 343 (*ng_atm_input_orphan_p)(ifp, m, ah, rxhand); 344 else 345 m_freem(m); 346 return; 347 } 348 } 349 netisr_dispatch(isr, m); 350} 351 352/* 353 * Perform common duties while attaching to interface list. 354 */ 355void 356atm_ifattach(struct ifnet *ifp) 357{ 358 struct ifaddr *ifa; 359 struct sockaddr_dl *sdl; 360 struct ifatm *ifatm = ifp->if_softc; 361 362 ifp->if_type = IFT_ATM; 363 ifp->if_addrlen = 0; 364 ifp->if_hdrlen = 0; 365 if_attach(ifp); 366 ifp->if_mtu = ATMMTU; 367 ifp->if_output = atm_output; 368#if 0 369 ifp->if_input = atm_input; 370#endif 371 ifp->if_snd.ifq_maxlen = 50; /* dummy */ 372 373#if defined(__NetBSD__) || defined(__OpenBSD__) 374 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 375#elif defined(__FreeBSD__) && (__FreeBSD__ > 2) 376 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 377 ifa = TAILQ_NEXT(ifa, ifa_link)) 378#elif defined(__FreeBSD__) || defined(__bsdi__) 379 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 380#endif 381 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 382 sdl->sdl_family == AF_LINK) { 383 sdl->sdl_type = IFT_ATM; 384 sdl->sdl_alen = ifp->if_addrlen; 385#ifdef notyet /* if using ATMARP, store hardware address using the next line */ 386 bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen); 387#endif 388 break; 389 } 390 391 ifp->if_linkmib = &ifatm->mib; 392 ifp->if_linkmiblen = sizeof(ifatm->mib); 393 394 if(ng_atm_attach_p) 395 (*ng_atm_attach_p)(ifp); 396 if (atm_harp_attach_p) 397 (*atm_harp_attach_p)(ifp); 398} 399 400/* 401 * Common stuff for detaching an ATM interface 402 */ 403void 404atm_ifdetach(struct ifnet *ifp) 405{ 406 if (atm_harp_detach_p) 407 (*atm_harp_detach_p)(ifp); 408 if(ng_atm_detach_p) 409 (*ng_atm_detach_p)(ifp); 410 if_detach(ifp); 411} 412 413/* 414 * Support routine for the SIOCATMGVCCS ioctl(). 415 * 416 * This routine assumes, that the private VCC structures used by the driver 417 * begin with a struct atmio_vcc. 418 * 419 * Return a table of VCCs in a freshly allocated memory area. 420 * Here we have a problem: we first count, how many vccs we need 421 * to return. The we allocate the memory and finally fill it in. 422 * Because we cannot lock while calling malloc, the number of active 423 * vccs may change while we're in malloc. So we allocate a couple of 424 * vccs more and if space anyway is not enough re-iterate. 425 * 426 * We could use an sx lock for the vcc tables. 427 */ 428struct atmio_vcctable * 429atm_getvccs(struct atmio_vcc **table, u_int size, u_int start, 430 struct mtx *lock, int waitok) 431{ 432 u_int cid, alloc; 433 size_t len; 434 struct atmio_vcctable *vccs; 435 struct atmio_vcc *v; 436 437 alloc = start + 10; 438 vccs = NULL; 439 440 for (;;) { 441 len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]); 442 vccs = reallocf(vccs, len, M_TEMP, 443 waitok ? M_WAITOK : M_NOWAIT); 444 if (vccs == NULL) 445 return (NULL); 446 bzero(vccs, len); 447 448 vccs->count = 0; 449 v = vccs->vccs; 450 451 mtx_lock(lock); 452 for (cid = 0; cid < size; cid++) 453 if (table[cid] != NULL) { 454 if (++vccs->count == alloc) 455 /* too many - try again */ 456 break; 457 *v++ = *table[cid]; 458 } 459 mtx_unlock(lock); 460 461 if (cid == size) 462 break; 463 464 alloc *= 2; 465 } 466 return (vccs); 467} 468 469/* 470 * Driver or channel state has changed. Inform whoever is interested 471 * in these events. 472 */ 473void 474atm_event(struct ifnet *ifp, u_int event, void *arg) 475{ 476 if (ng_atm_event_p != NULL) 477 (*ng_atm_event_p)(ifp, event, arg); 478 if (atm_harp_event_p != NULL) 479 (*atm_harp_event_p)(ifp, event, arg); 480} 481 482static moduledata_t atm_mod = { 483 "atm", 484 NULL, 485 0 486}; 487 488DECLARE_MODULE(atm, atm_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 489MODULE_VERSION(atm, 1); 490