natm.c revision 96972
1/* $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $ */ 2/* $FreeBSD: head/sys/netnatm/natm.c 96972 2002-05-20 05:41:09Z tanimura $ */ 3 4/* 5 * 6 * Copyright (c) 1996 Charles D. Cranor and Washington University. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Charles D. Cranor and 20 * Washington University. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36/* 37 * natm.c: native mode ATM access (both aal0 and aal5). 38 */ 39 40#include <sys/param.h> 41#include <sys/conf.h> 42#include <sys/kernel.h> 43#include <sys/lock.h> 44#include <sys/malloc.h> 45#include <sys/mbuf.h> 46#include <sys/protosw.h> 47#include <sys/signalvar.h> 48#include <sys/socket.h> 49#include <sys/socketvar.h> 50#include <sys/sockio.h> 51#include <sys/sx.h> 52#include <sys/systm.h> 53 54#include <net/if.h> 55#include <net/if_atm.h> 56#include <net/netisr.h> 57 58#include <netinet/in.h> 59 60#include <netnatm/natm.h> 61 62static u_long natm5_sendspace = 16*1024; 63static u_long natm5_recvspace = 16*1024; 64 65static u_long natm0_sendspace = 16*1024; 66static u_long natm0_recvspace = 16*1024; 67 68/* 69 * user requests 70 */ 71#ifdef FREEBSD_USRREQS 72/* 73 * FreeBSD new usrreqs supersedes pr_usrreq. 74 */ 75static int natm_usr_attach(struct socket *, int, d_thread_t *); 76static int natm_usr_detach(struct socket *); 77static int natm_usr_connect(struct socket *, struct sockaddr *, d_thread_t *); 78static int natm_usr_disconnect(struct socket *); 79static int natm_usr_shutdown(struct socket *); 80static int natm_usr_send(struct socket *, int, struct mbuf *, 81 struct sockaddr *, struct mbuf *, d_thread_t *); 82static int natm_usr_peeraddr(struct socket *, struct sockaddr **); 83static int natm_usr_control(struct socket *, u_long, caddr_t, 84 struct ifnet *, d_thread_t *); 85static int natm_usr_abort(struct socket *); 86static int natm_usr_bind(struct socket *, struct sockaddr *, d_thread_t *); 87static int natm_usr_sockaddr(struct socket *, struct sockaddr **); 88 89static int 90natm_usr_attach(struct socket *so, int proto, d_thread_t *p) 91{ 92 struct natmpcb *npcb; 93 int error = 0; 94 int s = SPLSOFTNET(); 95 96 npcb = (struct natmpcb *) so->so_pcb; 97 98 if (npcb) { 99 error = EISCONN; 100 goto out; 101 } 102 103 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 104 if (proto == PROTO_NATMAAL5) 105 error = soreserve(so, natm5_sendspace, natm5_recvspace); 106 else 107 error = soreserve(so, natm0_sendspace, natm0_recvspace); 108 if (error) 109 goto out; 110 } 111 112 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK)); 113 npcb->npcb_socket = so; 114 out: 115 splx(s); 116 return (error); 117} 118 119static int 120natm_usr_detach(struct socket *so) 121{ 122 struct natmpcb *npcb; 123 int error = 0; 124 int s = SPLSOFTNET(); 125 126 npcb = (struct natmpcb *) so->so_pcb; 127 if (npcb == NULL) { 128 error = EINVAL; 129 goto out; 130 } 131 132 /* 133 * we turn on 'drain' *before* we sofree. 134 */ 135 npcb_free(npcb, NPCB_DESTROY); /* drain */ 136 so->so_pcb = NULL; 137 SOCK_LOCK(so); 138 sotryfree(so); 139 out: 140 splx(s); 141 return (error); 142} 143 144static int 145natm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p) 146{ 147 struct natmpcb *npcb; 148 struct sockaddr_natm *snatm; 149 struct atm_pseudoioctl api; 150 struct ifnet *ifp; 151 int error = 0; 152 int s2, s = SPLSOFTNET(); 153 int proto = so->so_proto->pr_protocol; 154 155 npcb = (struct natmpcb *) so->so_pcb; 156 if (npcb == NULL) { 157 error = EINVAL; 158 goto out; 159 } 160 161 /* 162 * validate nam and npcb 163 */ 164 165 snatm = (struct sockaddr_natm *)nam; 166 if (snatm->snatm_len != sizeof(*snatm) || 167 (npcb->npcb_flags & NPCB_FREE) == 0) { 168 error = EINVAL; 169 goto out; 170 } 171 if (snatm->snatm_family != AF_NATM) { 172 error = EAFNOSUPPORT; 173 goto out; 174 } 175 176 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination 177 since ifunit() uses strcmp */ 178 179 /* 180 * convert interface string to ifp, validate. 181 */ 182 183 ifp = ifunit(snatm->snatm_if); 184 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { 185 error = ENXIO; 186 goto out; 187 } 188 if (ifp->if_output != atm_output) { 189 error = EAFNOSUPPORT; 190 goto out; 191 } 192 193 /* 194 * register us with the NATM PCB layer 195 */ 196 197 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { 198 error = EADDRINUSE; 199 goto out; 200 } 201 202 /* 203 * enable rx 204 */ 205 206 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 207 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; 208 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); 209 api.rxhand = npcb; 210 s2 = splimp(); 211 if (ifp->if_ioctl == NULL || 212 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) { 213 splx(s2); 214 npcb_free(npcb, NPCB_REMOVE); 215 error = EIO; 216 goto out; 217 } 218 splx(s2); 219 220 SOCK_LOCK(so); 221 soisconnected(so); 222 SOCK_UNLOCK(so); 223 224 out: 225 splx(s); 226 return (error); 227} 228 229static int 230natm_usr_disconnect(struct socket *so) 231{ 232 struct natmpcb *npcb; 233 struct atm_pseudoioctl api; 234 struct ifnet *ifp; 235 int error = 0; 236 int s2, s = SPLSOFTNET(); 237 238 npcb = (struct natmpcb *) so->so_pcb; 239 if (npcb == NULL) { 240 error = EINVAL; 241 goto out; 242 } 243 244 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { 245 printf("natm: disconnected check\n"); 246 error = EIO; 247 goto out; 248 } 249 ifp = npcb->npcb_ifp; 250 251 /* 252 * disable rx 253 */ 254 255 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5; 256 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; 257 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); 258 api.rxhand = npcb; 259 s2 = splimp(); 260 if (ifp->if_ioctl != NULL) 261 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api); 262 splx(s2); 263 264 npcb_free(npcb, NPCB_REMOVE); 265 SOCK_LOCK(so); 266 soisdisconnected(so); 267 SOCK_UNLOCK(so); 268 269 out: 270 splx(s); 271 return (error); 272} 273 274static int 275natm_usr_shutdown(struct socket *so) 276{ 277 socantsendmore(so); 278 return 0; 279} 280 281static int 282natm_usr_send(struct socket *so, int flags, struct mbuf *m, 283 struct sockaddr *nam, struct mbuf *control, d_thread_t *p) 284{ 285 struct natmpcb *npcb; 286 struct atm_pseudohdr *aph; 287 int error = 0; 288 int s = SPLSOFTNET(); 289 int proto = so->so_proto->pr_protocol; 290 291 npcb = (struct natmpcb *) so->so_pcb; 292 if (npcb == NULL) { 293 error = EINVAL; 294 goto out; 295 } 296 297 if (control && control->m_len) { 298 m_freem(control); 299 m_freem(m); 300 error = EINVAL; 301 goto out; 302 } 303 304 /* 305 * send the data. we must put an atm_pseudohdr on first 306 */ 307 308 M_PREPEND(m, sizeof(*aph), M_TRYWAIT); 309 if (m == NULL) { 310 error = ENOBUFS; 311 goto out; 312 } 313 aph = mtod(m, struct atm_pseudohdr *); 314 ATM_PH_VPI(aph) = npcb->npcb_vpi; 315 ATM_PH_SETVCI(aph, npcb->npcb_vci); 316 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 317 318 error = atm_output(npcb->npcb_ifp, m, NULL, NULL); 319 320 out: 321 splx(s); 322 return (error); 323} 324 325static int 326natm_usr_peeraddr(struct socket *so, struct sockaddr **nam) 327{ 328 struct natmpcb *npcb; 329 struct sockaddr_natm *snatm, ssnatm; 330 int error = 0; 331 int s = SPLSOFTNET(); 332 333 npcb = (struct natmpcb *) so->so_pcb; 334 if (npcb == NULL) { 335 error = EINVAL; 336 goto out; 337 } 338 339 snatm = &ssnatm; 340 bzero(snatm, sizeof(*snatm)); 341 snatm->snatm_len = sizeof(*snatm); 342 snatm->snatm_family = AF_NATM; 343 snprintf(snatm->snatm_if, sizeof(snatm->snatm_if), 344 "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit); 345 snatm->snatm_vci = npcb->npcb_vci; 346 snatm->snatm_vpi = npcb->npcb_vpi; 347 *nam = dup_sockaddr((struct sockaddr *)snatm, 0); 348 349 out: 350 splx(s); 351 return (error); 352} 353 354static int 355natm_usr_control(struct socket *so, u_long cmd, caddr_t arg, 356 struct ifnet *ifp, d_thread_t *p) 357{ 358 struct natmpcb *npcb; 359 struct atm_rawioctl ario; 360 int error = 0; 361 int s = SPLSOFTNET(); 362 363 npcb = (struct natmpcb *) so->so_pcb; 364 if (npcb == NULL) { 365 error = EINVAL; 366 goto out; 367 } 368 369 /* 370 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to 371 * SIOCXRAWATM and pass it to the driver. 372 */ 373 if (cmd == SIOCRAWATM) { 374 if (npcb->npcb_ifp == NULL) { 375 error = ENOTCONN; 376 goto out; 377 } 378 ario.npcb = npcb; 379 ario.rawvalue = *((int *)arg); 380 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, 381 SIOCXRAWATM, (caddr_t) &ario); 382 if (!error) { 383 if (ario.rawvalue) 384 npcb->npcb_flags |= NPCB_RAW; 385 else 386 npcb->npcb_flags &= ~(NPCB_RAW); 387 } 388 } 389 else 390 error = EOPNOTSUPP; 391 392 out: 393 splx(s); 394 return (error); 395} 396 397static int 398natm_usr_abort(struct socket *so) 399{ 400 return natm_usr_shutdown(so); 401} 402 403static int 404natm_usr_bind(struct socket *so, struct sockaddr *nam, d_thread_t *p) 405{ 406 return EOPNOTSUPP; 407} 408 409static int 410natm_usr_sockaddr(struct socket *so, struct sockaddr **nam) 411{ 412 return EOPNOTSUPP; 413} 414 415/* xxx - should be const */ 416struct pr_usrreqs natm_usrreqs = { 417 natm_usr_abort, pru_accept_notsupp, natm_usr_attach, natm_usr_bind, 418 natm_usr_connect, pru_connect2_notsupp, natm_usr_control, 419 natm_usr_detach, natm_usr_disconnect, pru_listen_notsupp, 420 natm_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, 421 natm_usr_send, pru_sense_null, natm_usr_shutdown, 422 natm_usr_sockaddr, sosend, soreceive, sopoll 423}; 424 425#else /* !FREEBSD_USRREQS */ 426 427#if defined(__NetBSD__) || defined(__OpenBSD__) 428int natm_usrreq(so, req, m, nam, control, p) 429#elif defined(__FreeBSD__) 430int natm_usrreq(so, req, m, nam, control) 431#endif 432 433struct socket *so; 434int req; 435struct mbuf *m, *nam, *control; 436#if defined(__NetBSD__) || defined(__OpenBSD__) 437struct proc *p; 438#endif 439 440{ 441 int error = 0, s, s2; 442 struct natmpcb *npcb; 443 struct sockaddr_natm *snatm; 444 struct atm_pseudoioctl api; 445 struct atm_pseudohdr *aph; 446 struct atm_rawioctl ario; 447 struct ifnet *ifp; 448 int proto = so->so_proto->pr_protocol; 449 450 s = SPLSOFTNET(); 451 452 npcb = (struct natmpcb *) so->so_pcb; 453 454 if (npcb == NULL && req != PRU_ATTACH) { 455 error = EINVAL; 456 goto done; 457 } 458 459 460 switch (req) { 461 case PRU_ATTACH: /* attach protocol to up */ 462 463 if (npcb) { 464 error = EISCONN; 465 break; 466 } 467 468 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 469 if (proto == PROTO_NATMAAL5) 470 error = soreserve(so, natm5_sendspace, natm5_recvspace); 471 else 472 error = soreserve(so, natm0_sendspace, natm0_recvspace); 473 if (error) 474 break; 475 } 476 477 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK)); 478 npcb->npcb_socket = so; 479 480 break; 481 482 case PRU_DETACH: /* detach protocol from up */ 483 484 /* 485 * we turn on 'drain' *before* we sofree. 486 */ 487 488 npcb_free(npcb, NPCB_DESTROY); /* drain */ 489 so->so_pcb = NULL; 490 SOCK_LOCK(so); 491 sotryfree(so); 492 493 break; 494 495 case PRU_CONNECT: /* establish connection to peer */ 496 497 /* 498 * validate nam and npcb 499 */ 500 501 if (nam->m_len != sizeof(*snatm)) { 502 error = EINVAL; 503 break; 504 } 505 snatm = mtod(nam, struct sockaddr_natm *); 506 if (snatm->snatm_len != sizeof(*snatm) || 507 (npcb->npcb_flags & NPCB_FREE) == 0) { 508 error = EINVAL; 509 break; 510 } 511 if (snatm->snatm_family != AF_NATM) { 512 error = EAFNOSUPPORT; 513 break; 514 } 515 516 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination 517 since ifunit() uses strcmp */ 518 519 /* 520 * convert interface string to ifp, validate. 521 */ 522 523 ifp = ifunit(snatm->snatm_if); 524 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { 525 error = ENXIO; 526 break; 527 } 528 if (ifp->if_output != atm_output) { 529 error = EAFNOSUPPORT; 530 break; 531 } 532 533 534 /* 535 * register us with the NATM PCB layer 536 */ 537 538 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { 539 error = EADDRINUSE; 540 break; 541 } 542 543 /* 544 * enable rx 545 */ 546 547 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 548 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; 549 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); 550 api.rxhand = npcb; 551 s2 = splimp(); 552 if (ifp->if_ioctl == NULL || 553 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) { 554 splx(s2); 555 npcb_free(npcb, NPCB_REMOVE); 556 error = EIO; 557 break; 558 } 559 splx(s2); 560 561 SOCK_LOCK(so); 562 soisconnected(so); 563 SOCK_UNLOCK(so); 564 565 break; 566 567 case PRU_DISCONNECT: /* disconnect from peer */ 568 569 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { 570 printf("natm: disconnected check\n"); 571 error = EIO; 572 break; 573 } 574 ifp = npcb->npcb_ifp; 575 576 /* 577 * disable rx 578 */ 579 580 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5; 581 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; 582 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); 583 api.rxhand = npcb; 584 s2 = splimp(); 585 if (ifp->if_ioctl != NULL) 586 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api); 587 splx(s2); 588 589 npcb_free(npcb, NPCB_REMOVE); 590 SOCK_LOCK(so); 591 soisdisconnected(so); 592 SOCK_UNLOCK(so); 593 594 break; 595 596 case PRU_SHUTDOWN: /* won't send any more data */ 597 socantsendmore(so); 598 break; 599 600 case PRU_SEND: /* send this data */ 601 if (control && control->m_len) { 602 m_freem(control); 603 m_freem(m); 604 error = EINVAL; 605 break; 606 } 607 608 /* 609 * send the data. we must put an atm_pseudohdr on first 610 */ 611 612 M_PREPEND(m, sizeof(*aph), M_TRYWAIT); 613 if (m == NULL) { 614 error = ENOBUFS; 615 break; 616 } 617 aph = mtod(m, struct atm_pseudohdr *); 618 ATM_PH_VPI(aph) = npcb->npcb_vpi; 619 ATM_PH_SETVCI(aph, npcb->npcb_vci); 620 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 621 622 error = atm_output(npcb->npcb_ifp, m, NULL, NULL); 623 624 break; 625 626 case PRU_SENSE: /* return status into m */ 627 /* return zero? */ 628 break; 629 630 case PRU_PEERADDR: /* fetch peer's address */ 631 snatm = mtod(nam, struct sockaddr_natm *); 632 bzero(snatm, sizeof(*snatm)); 633 nam->m_len = snatm->snatm_len = sizeof(*snatm); 634 snatm->snatm_family = AF_NATM; 635#if defined(__NetBSD__) || defined(__OpenBSD__) 636 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if)); 637#elif defined(__FreeBSD__) 638 snprintf(snatm->snatm_if, sizeof(snatm->snatm_if), 639 "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit); 640#endif 641 snatm->snatm_vci = npcb->npcb_vci; 642 snatm->snatm_vpi = npcb->npcb_vpi; 643 break; 644 645 case PRU_CONTROL: /* control operations on protocol */ 646 /* 647 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to 648 * SIOCXRAWATM and pass it to the driver. 649 */ 650 if ((u_long)m == SIOCRAWATM) { 651 if (npcb->npcb_ifp == NULL) { 652 error = ENOTCONN; 653 break; 654 } 655 ario.npcb = npcb; 656 ario.rawvalue = *((int *)nam); 657 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, 658 SIOCXRAWATM, (caddr_t) &ario); 659 if (!error) { 660 if (ario.rawvalue) 661 npcb->npcb_flags |= NPCB_RAW; 662 else 663 npcb->npcb_flags &= ~(NPCB_RAW); 664 } 665 666 break; 667 } 668 669 error = EOPNOTSUPP; 670 break; 671 672 case PRU_BIND: /* bind socket to address */ 673 case PRU_LISTEN: /* listen for connection */ 674 case PRU_ACCEPT: /* accept connection from peer */ 675 case PRU_CONNECT2: /* connect two sockets */ 676 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */ 677 /* (only happens if LISTEN socket) */ 678 case PRU_RCVD: /* have taken data; more room now */ 679 case PRU_FASTTIMO: /* 200ms timeout */ 680 case PRU_SLOWTIMO: /* 500ms timeout */ 681 case PRU_RCVOOB: /* retrieve out of band data */ 682 case PRU_SENDOOB: /* send out of band data */ 683 case PRU_PROTORCV: /* receive from below */ 684 case PRU_PROTOSEND: /* send to below */ 685 case PRU_SOCKADDR: /* fetch socket's address */ 686#ifdef DIAGNOSTIC 687 printf("natm: PRU #%d unsupported\n", req); 688#endif 689 error = EOPNOTSUPP; 690 break; 691 692 default: panic("natm usrreq"); 693 } 694 695done: 696 splx(s); 697 return(error); 698} 699 700#endif /* !FREEBSD_USRREQS */ 701 702/* 703 * natmintr: splsoftnet interrupt 704 * 705 * note: we expect a socket pointer in rcvif rather than an interface 706 * pointer. we can get the interface pointer from the so's PCB if 707 * we really need it. 708 */ 709 710void 711natmintr() 712 713{ 714 int s; 715 struct mbuf *m; 716 struct socket *so; 717 struct natmpcb *npcb; 718 719next: 720 s = splimp(); 721 IF_DEQUEUE(&natmintrq, m); 722 splx(s); 723 if (m == NULL) 724 return; 725 726#ifdef DIAGNOSTIC 727 if ((m->m_flags & M_PKTHDR) == 0) 728 panic("natmintr no HDR"); 729#endif 730 731 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */ 732 so = npcb->npcb_socket; 733 734 s = splimp(); /* could have atm devs @ different levels */ 735 npcb->npcb_inq--; 736 splx(s); 737 738 if (npcb->npcb_flags & NPCB_DRAIN) { 739 m_freem(m); 740 if (npcb->npcb_inq == 0) 741 FREE(npcb, M_PCB); /* done! */ 742 goto next; 743 } 744 745 if (npcb->npcb_flags & NPCB_FREE) { 746 m_freem(m); /* drop */ 747 goto next; 748 } 749 750#ifdef NEED_TO_RESTORE_IFP 751 m->m_pkthdr.rcvif = npcb->npcb_ifp; 752#else 753#ifdef DIAGNOSTIC 754m->m_pkthdr.rcvif = NULL; /* null it out to be safe */ 755#endif 756#endif 757 758 if (sbspace(&so->so_rcv) > m->m_pkthdr.len || 759 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) { 760#ifdef NATM_STAT 761 natm_sookcnt++; 762 natm_sookbytes += m->m_pkthdr.len; 763#endif 764 sbappendrecord(&so->so_rcv, m); 765 SOCK_LOCK(so); 766 sorwakeup(so); 767 SOCK_UNLOCK(so); 768 } else { 769#ifdef NATM_STAT 770 natm_sodropcnt++; 771 natm_sodropbytes += m->m_pkthdr.len; 772#endif 773 m_freem(m); 774 } 775 776 goto next; 777} 778 779#if defined(__FreeBSD__) 780static void 781netisr_natm_setup(void *dummy __unused) 782{ 783 784 register_netisr(NETISR_NATM, natmintr); 785} 786SYSINIT(natm_setup, SI_SUB_CPU, SI_ORDER_ANY, netisr_natm_setup, NULL); 787#endif 788 789 790/* 791 * natm0_sysctl: not used, but here in case we want to add something 792 * later... 793 */ 794 795int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 796 797int *name; 798u_int namelen; 799void *oldp; 800size_t *oldlenp; 801void *newp; 802size_t newlen; 803 804{ 805 /* All sysctl names at this level are terminal. */ 806 if (namelen != 1) 807 return (ENOTDIR); 808 return (ENOPROTOOPT); 809} 810 811/* 812 * natm5_sysctl: not used, but here in case we want to add something 813 * later... 814 */ 815 816int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 817 818int *name; 819u_int namelen; 820void *oldp; 821size_t *oldlenp; 822void *newp; 823size_t newlen; 824 825{ 826 /* All sysctl names at this level are terminal. */ 827 if (namelen != 1) 828 return (ENOTDIR); 829 return (ENOPROTOOPT); 830} 831