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