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