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