1 /* $NetBSD: ddp_usrreq.c,v 1.64 2015/04/03 20:01:07 rtr Exp $ */ 2 3 /* 4 * Copyright (c) 1990,1991 Regents of The University of Michigan. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby granted, 9 * provided that the above copyright notice appears in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation, and that the name of The University 12 * of Michigan not be used in advertising or publicity pertaining to 13 * distribution of the software without specific, written prior 14 * permission. This software is supplied as is without expressed or 15 * implied warranties of any kind. 16 * 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 20 * Research Systems Unix Group 21 * The University of Michigan 22 * c/o Wesley Craig 23 * 535 W. William Street 24 * Ann Arbor, Michigan 25 * +1-313-764-2278 26 * netatalk@umich.edu 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: ddp_usrreq.c,v 1.64 2015/04/03 20:01:07 rtr Exp $"); 31 32 #include "opt_mbuftrace.h" 33 34 #include <sys/param.h> 35 #include <sys/errno.h> 36 #include <sys/systm.h> 37 #include <sys/mbuf.h> 38 #include <sys/ioctl.h> 39 #include <sys/queue.h> 40 #include <sys/socket.h> 41 #include <sys/socketvar.h> 42 #include <sys/protosw.h> 43 #include <sys/kauth.h> 44 #include <sys/kmem.h> 45 #include <sys/sysctl.h> 46 #include <net/if.h> 47 #include <net/route.h> 48 #include <net/if_ether.h> 49 #include <net/net_stats.h> 50 #include <netinet/in.h> 51 52 #include <netatalk/at.h> 53 #include <netatalk/at_var.h> 54 #include <netatalk/ddp_var.h> 55 #include <netatalk/ddp_private.h> 56 #include <netatalk/aarp.h> 57 #include <netatalk/at_extern.h> 58 59 static void at_pcbdisconnect(struct ddpcb *); 60 static void at_sockaddr(struct ddpcb *, struct mbuf *); 61 static int at_pcbsetaddr(struct ddpcb *, struct sockaddr_at *); 62 static int at_pcbconnect(struct ddpcb *, struct mbuf *); 63 static void ddp_detach(struct socket *); 64 65 struct ifqueue atintrq1, atintrq2; 66 struct ddpcb *ddp_ports[ATPORT_LAST]; 67 struct ddpcb *ddpcb = NULL; 68 percpu_t *ddpstat_percpu; 69 struct at_ifaddrhead at_ifaddr; /* Here as inited in this file */ 70 u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ 71 u_long ddp_recvspace = 25 * (587 + sizeof(struct sockaddr_at)); 72 73 #ifdef MBUFTRACE 74 struct mowner atalk_rx_mowner = MOWNER_INIT("atalk", "rx"); 75 struct mowner atalk_tx_mowner = MOWNER_INIT("atalk", "tx"); 76 #endif 77 78 static int 79 ddp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr, 80 struct mbuf *rights, struct lwp *l) 81 { 82 struct ddpcb *ddp; 83 int error = 0; 84 85 KASSERT(req != PRU_ATTACH); 86 KASSERT(req != PRU_DETACH); 87 KASSERT(req != PRU_ACCEPT); 88 KASSERT(req != PRU_BIND); 89 KASSERT(req != PRU_LISTEN); 90 KASSERT(req != PRU_CONNECT); 91 KASSERT(req != PRU_CONNECT2); 92 KASSERT(req != PRU_DISCONNECT); 93 KASSERT(req != PRU_SHUTDOWN); 94 KASSERT(req != PRU_ABORT); 95 KASSERT(req != PRU_CONTROL); 96 KASSERT(req != PRU_SENSE); 97 KASSERT(req != PRU_PEERADDR); 98 KASSERT(req != PRU_SOCKADDR); 99 KASSERT(req != PRU_RCVD); 100 KASSERT(req != PRU_RCVOOB); 101 KASSERT(req != PRU_SEND); 102 KASSERT(req != PRU_SENDOOB); 103 KASSERT(req != PRU_PURGEIF); 104 105 ddp = sotoddpcb(so); 106 107 if (rights && rights->m_len) { 108 error = EINVAL; 109 goto release; 110 } 111 if (ddp == NULL) { 112 error = EINVAL; 113 goto release; 114 } 115 switch (req) { 116 case PRU_FASTTIMO: 117 case PRU_SLOWTIMO: 118 case PRU_PROTORCV: 119 case PRU_PROTOSEND: 120 error = EOPNOTSUPP; 121 break; 122 123 default: 124 error = EOPNOTSUPP; 125 } 126 127 release: 128 if (m != NULL) { 129 m_freem(m); 130 } 131 return (error); 132 } 133 134 static void 135 at_sockaddr(struct ddpcb *ddp, struct mbuf *addr) 136 { 137 struct sockaddr_at *sat; 138 139 addr->m_len = sizeof(struct sockaddr_at); 140 sat = mtod(addr, struct sockaddr_at *); 141 *sat = ddp->ddp_lsat; 142 } 143 144 static int 145 at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr_at *sat) 146 { 147 struct sockaddr_at lsat; 148 struct at_ifaddr *aa; 149 struct ddpcb *ddpp; 150 151 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */ 152 return (EINVAL); 153 } 154 if (NULL != sat) { /* validate passed address */ 155 156 if (sat->sat_family != AF_APPLETALK) 157 return (EAFNOSUPPORT); 158 159 if (sat->sat_addr.s_node != ATADDR_ANYNODE || 160 sat->sat_addr.s_net != ATADDR_ANYNET) { 161 TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 162 if ((sat->sat_addr.s_net == 163 AA_SAT(aa)->sat_addr.s_net) && 164 (sat->sat_addr.s_node == 165 AA_SAT(aa)->sat_addr.s_node)) 166 break; 167 } 168 if (!aa) 169 return (EADDRNOTAVAIL); 170 } 171 if (sat->sat_port != ATADDR_ANYPORT) { 172 int error; 173 174 if (sat->sat_port < ATPORT_FIRST || 175 sat->sat_port >= ATPORT_LAST) 176 return (EINVAL); 177 178 if (sat->sat_port < ATPORT_RESERVED && 179 (error = kauth_authorize_network(curlwp->l_cred, 180 KAUTH_NETWORK_BIND, KAUTH_REQ_NETWORK_BIND_PRIVPORT, 181 ddpcb->ddp_socket, sat, NULL)) != 0) 182 return (error); 183 } 184 } else { 185 memset((void *) & lsat, 0, sizeof(struct sockaddr_at)); 186 lsat.sat_len = sizeof(struct sockaddr_at); 187 lsat.sat_addr.s_node = ATADDR_ANYNODE; 188 lsat.sat_addr.s_net = ATADDR_ANYNET; 189 lsat.sat_family = AF_APPLETALK; 190 sat = &lsat; 191 } 192 193 if (sat->sat_addr.s_node == ATADDR_ANYNODE && 194 sat->sat_addr.s_net == ATADDR_ANYNET) { 195 if (TAILQ_EMPTY(&at_ifaddr)) 196 return EADDRNOTAVAIL; 197 sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddr))->sat_addr; 198 } 199 ddp->ddp_lsat = *sat; 200 201 /* 202 * Choose port. 203 */ 204 if (sat->sat_port == ATADDR_ANYPORT) { 205 for (sat->sat_port = ATPORT_RESERVED; 206 sat->sat_port < ATPORT_LAST; sat->sat_port++) { 207 if (ddp_ports[sat->sat_port - 1] == 0) 208 break; 209 } 210 if (sat->sat_port == ATPORT_LAST) { 211 return (EADDRNOTAVAIL); 212 } 213 ddp->ddp_lsat.sat_port = sat->sat_port; 214 ddp_ports[sat->sat_port - 1] = ddp; 215 } else { 216 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 217 ddpp = ddpp->ddp_pnext) { 218 if (ddpp->ddp_lsat.sat_addr.s_net == 219 sat->sat_addr.s_net && 220 ddpp->ddp_lsat.sat_addr.s_node == 221 sat->sat_addr.s_node) 222 break; 223 } 224 if (ddpp != NULL) 225 return (EADDRINUSE); 226 227 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 228 ddp_ports[sat->sat_port - 1] = ddp; 229 if (ddp->ddp_pnext) 230 ddp->ddp_pnext->ddp_pprev = ddp; 231 } 232 233 return 0; 234 } 235 236 static int 237 at_pcbconnect(struct ddpcb *ddp, struct mbuf *addr) 238 { 239 struct rtentry *rt; 240 const struct sockaddr_at *cdst; 241 struct sockaddr_at *sat = mtod(addr, struct sockaddr_at *); 242 struct route *ro; 243 struct at_ifaddr *aa; 244 struct ifnet *ifp; 245 u_short hintnet = 0, net; 246 247 if (addr->m_len != sizeof(*sat)) 248 return EINVAL; 249 if (sat->sat_family != AF_APPLETALK) { 250 return EAFNOSUPPORT; 251 } 252 /* 253 * Under phase 2, network 0 means "the network". We take "the 254 * network" to mean the network the control block is bound to. 255 * If the control block is not bound, there is an error. 256 */ 257 if (sat->sat_addr.s_net == ATADDR_ANYNET 258 && sat->sat_addr.s_node != ATADDR_ANYNODE) { 259 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) { 260 return EADDRNOTAVAIL; 261 } 262 hintnet = ddp->ddp_lsat.sat_addr.s_net; 263 } 264 ro = &ddp->ddp_route; 265 /* 266 * If we've got an old route for this pcb, check that it is valid. 267 * If we've changed our address, we may have an old "good looking" 268 * route here. Attempt to detect it. 269 */ 270 if ((rt = rtcache_validate(ro)) != NULL || 271 (rt = rtcache_update(ro, 1)) != NULL) { 272 if (hintnet) { 273 net = hintnet; 274 } else { 275 net = sat->sat_addr.s_net; 276 } 277 if ((ifp = rt->rt_ifp) != NULL) { 278 TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 279 if (aa->aa_ifp == ifp && 280 ntohs(net) >= ntohs(aa->aa_firstnet) && 281 ntohs(net) <= ntohs(aa->aa_lastnet)) { 282 break; 283 } 284 } 285 } else 286 aa = NULL; 287 cdst = satocsat(rtcache_getdst(ro)); 288 if (aa == NULL || (cdst->sat_addr.s_net != 289 (hintnet ? hintnet : sat->sat_addr.s_net) || 290 cdst->sat_addr.s_node != sat->sat_addr.s_node)) { 291 rtcache_free(ro); 292 rt = NULL; 293 } 294 } 295 /* 296 * If we've got no route for this interface, try to find one. 297 */ 298 if (rt == NULL) { 299 union { 300 struct sockaddr dst; 301 struct sockaddr_at dsta; 302 } u; 303 304 sockaddr_at_init(&u.dsta, &sat->sat_addr, 0); 305 if (hintnet) 306 u.dsta.sat_addr.s_net = hintnet; 307 rt = rtcache_lookup(ro, &u.dst); 308 } 309 /* 310 * Make sure any route that we have has a valid interface. 311 */ 312 if (rt != NULL && (ifp = rt->rt_ifp) != NULL) { 313 TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 314 if (aa->aa_ifp == ifp) 315 break; 316 } 317 } else 318 aa = NULL; 319 if (aa == NULL) 320 return ENETUNREACH; 321 ddp->ddp_fsat = *sat; 322 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 323 return at_pcbsetaddr(ddp, NULL); 324 return 0; 325 } 326 327 static void 328 at_pcbdisconnect(struct ddpcb *ddp) 329 { 330 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 331 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 332 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 333 } 334 335 static int 336 ddp_attach(struct socket *so, int proto) 337 { 338 struct ddpcb *ddp; 339 int error; 340 341 KASSERT(sotoddpcb(so) == NULL); 342 sosetlock(so); 343 #ifdef MBUFTRACE 344 so->so_rcv.sb_mowner = &atalk_rx_mowner; 345 so->so_snd.sb_mowner = &atalk_tx_mowner; 346 #endif 347 error = soreserve(so, ddp_sendspace, ddp_recvspace); 348 if (error) { 349 return error; 350 } 351 352 ddp = kmem_zalloc(sizeof(*ddp), KM_SLEEP); 353 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 354 355 ddp->ddp_next = ddpcb; 356 ddp->ddp_prev = NULL; 357 ddp->ddp_pprev = NULL; 358 ddp->ddp_pnext = NULL; 359 if (ddpcb) { 360 ddpcb->ddp_prev = ddp; 361 } 362 ddpcb = ddp; 363 364 ddp->ddp_socket = so; 365 so->so_pcb = ddp; 366 return 0; 367 } 368 369 static void 370 ddp_detach(struct socket *so) 371 { 372 struct ddpcb *ddp = sotoddpcb(so); 373 374 soisdisconnected(so); 375 so->so_pcb = NULL; 376 /* sofree drops the lock */ 377 sofree(so); 378 mutex_enter(softnet_lock); 379 380 /* remove ddp from ddp_ports list */ 381 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 382 ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 383 if (ddp->ddp_pprev != NULL) { 384 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 385 } else { 386 ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 387 } 388 if (ddp->ddp_pnext != NULL) { 389 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 390 } 391 } 392 rtcache_free(&ddp->ddp_route); 393 if (ddp->ddp_prev) { 394 ddp->ddp_prev->ddp_next = ddp->ddp_next; 395 } else { 396 ddpcb = ddp->ddp_next; 397 } 398 if (ddp->ddp_next) { 399 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 400 } 401 kmem_free(ddp, sizeof(*ddp)); 402 } 403 404 static int 405 ddp_accept(struct socket *so, struct mbuf *nam) 406 { 407 KASSERT(solocked(so)); 408 409 return EOPNOTSUPP; 410 } 411 412 static int 413 ddp_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 414 { 415 KASSERT(solocked(so)); 416 KASSERT(sotoddpcb(so) != NULL); 417 418 return at_pcbsetaddr(sotoddpcb(so), (struct sockaddr_at *)nam); 419 } 420 421 static int 422 ddp_listen(struct socket *so, struct lwp *l) 423 { 424 KASSERT(solocked(so)); 425 426 return EOPNOTSUPP; 427 } 428 429 static int 430 ddp_connect(struct socket *so, struct mbuf *nam, struct lwp *l) 431 { 432 struct ddpcb *ddp = sotoddpcb(so); 433 int error = 0; 434 435 KASSERT(solocked(so)); 436 KASSERT(ddp != NULL); 437 KASSERT(nam != NULL); 438 439 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) 440 return EISCONN; 441 error = at_pcbconnect(ddp, nam); 442 if (error == 0) 443 soisconnected(so); 444 445 return error; 446 } 447 448 static int 449 ddp_connect2(struct socket *so, struct socket *so2) 450 { 451 KASSERT(solocked(so)); 452 453 return EOPNOTSUPP; 454 } 455 456 static int 457 ddp_disconnect(struct socket *so) 458 { 459 struct ddpcb *ddp = sotoddpcb(so); 460 461 KASSERT(solocked(so)); 462 KASSERT(ddp != NULL); 463 464 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) 465 return ENOTCONN; 466 467 at_pcbdisconnect(ddp); 468 soisdisconnected(so); 469 return 0; 470 } 471 472 static int 473 ddp_shutdown(struct socket *so) 474 { 475 KASSERT(solocked(so)); 476 477 socantsendmore(so); 478 return 0; 479 } 480 481 static int 482 ddp_abort(struct socket *so) 483 { 484 KASSERT(solocked(so)); 485 486 soisdisconnected(so); 487 ddp_detach(so); 488 return 0; 489 } 490 491 static int 492 ddp_ioctl(struct socket *so, u_long cmd, void *addr, struct ifnet *ifp) 493 { 494 return at_control(cmd, addr, ifp); 495 } 496 497 static int 498 ddp_stat(struct socket *so, struct stat *ub) 499 { 500 KASSERT(solocked(so)); 501 502 /* stat: don't bother with a blocksize. */ 503 return 0; 504 } 505 506 static int 507 ddp_peeraddr(struct socket *so, struct mbuf *nam) 508 { 509 KASSERT(solocked(so)); 510 511 return EOPNOTSUPP; 512 } 513 514 static int 515 ddp_sockaddr(struct socket *so, struct mbuf *nam) 516 { 517 KASSERT(solocked(so)); 518 KASSERT(sotoddpcb(so) != NULL); 519 KASSERT(nam != NULL); 520 521 at_sockaddr(sotoddpcb(so), nam); 522 return 0; 523 } 524 525 static int 526 ddp_rcvd(struct socket *so, int flags, struct lwp *l) 527 { 528 KASSERT(solocked(so)); 529 530 return EOPNOTSUPP; 531 } 532 533 static int 534 ddp_recvoob(struct socket *so, struct mbuf *m, int flags) 535 { 536 KASSERT(solocked(so)); 537 538 return EOPNOTSUPP; 539 } 540 541 static int 542 ddp_send(struct socket *so, struct mbuf *m, struct mbuf *nam, 543 struct mbuf *control, struct lwp *l) 544 { 545 struct ddpcb *ddp = sotoddpcb(so); 546 int error = 0; 547 int s = 0; /* XXX gcc 4.8 warns on sgimips */ 548 549 KASSERT(solocked(so)); 550 KASSERT(ddp != NULL); 551 552 if (nam) { 553 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) 554 return EISCONN; 555 s = splnet(); 556 error = at_pcbconnect(ddp, nam); 557 if (error) { 558 splx(s); 559 return error; 560 } 561 } else { 562 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 563 return ENOTCONN; 564 } 565 566 error = ddp_output(m, ddp); 567 m = NULL; 568 if (nam) { 569 at_pcbdisconnect(ddp); 570 splx(s); 571 } 572 573 return error; 574 } 575 576 static int 577 ddp_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 578 { 579 KASSERT(solocked(so)); 580 581 if (m) 582 m_freem(m); 583 584 return EOPNOTSUPP; 585 } 586 587 static int 588 ddp_purgeif(struct socket *so, struct ifnet *ifp) 589 { 590 591 mutex_enter(softnet_lock); 592 at_purgeif(ifp); 593 mutex_exit(softnet_lock); 594 595 return 0; 596 } 597 598 /* 599 * For the moment, this just find the pcb with the correct local address. 600 * In the future, this will actually do some real searching, so we can use 601 * the sender's address to do de-multiplexing on a single port to many 602 * sockets (pcbs). 603 */ 604 struct ddpcb * 605 ddp_search( 606 struct sockaddr_at *from, 607 struct sockaddr_at *to, 608 struct at_ifaddr *aa) 609 { 610 struct ddpcb *ddp; 611 612 /* 613 * Check for bad ports. 614 */ 615 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 616 return NULL; 617 618 /* 619 * Make sure the local address matches the sent address. What about 620 * the interface? 621 */ 622 for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 623 /* XXX should we handle 0.YY? */ 624 625 /* XXXX.YY to socket on destination interface */ 626 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 627 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 628 break; 629 } 630 /* 0.255 to socket on receiving interface */ 631 if (to->sat_addr.s_node == ATADDR_BCAST && 632 (to->sat_addr.s_net == 0 || 633 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 634 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) { 635 break; 636 } 637 /* XXXX.0 to socket on destination interface */ 638 if (to->sat_addr.s_net == aa->aa_firstnet && 639 to->sat_addr.s_node == 0 && 640 ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 641 ntohs(aa->aa_firstnet) && 642 ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 643 ntohs(aa->aa_lastnet)) { 644 break; 645 } 646 } 647 return (ddp); 648 } 649 650 /* 651 * Initialize all the ddp & appletalk stuff 652 */ 653 void 654 ddp_init(void) 655 { 656 657 ddpstat_percpu = percpu_alloc(sizeof(uint64_t) * DDP_NSTATS); 658 659 TAILQ_INIT(&at_ifaddr); 660 atintrq1.ifq_maxlen = IFQ_MAXLEN; 661 atintrq2.ifq_maxlen = IFQ_MAXLEN; 662 663 MOWNER_ATTACH(&atalk_tx_mowner); 664 MOWNER_ATTACH(&atalk_rx_mowner); 665 MOWNER_ATTACH(&aarp_mowner); 666 } 667 668 PR_WRAP_USRREQS(ddp) 669 #define ddp_attach ddp_attach_wrapper 670 #define ddp_detach ddp_detach_wrapper 671 #define ddp_accept ddp_accept_wrapper 672 #define ddp_bind ddp_bind_wrapper 673 #define ddp_listen ddp_listen_wrapper 674 #define ddp_connect ddp_connect_wrapper 675 #define ddp_connect2 ddp_connect2_wrapper 676 #define ddp_disconnect ddp_disconnect_wrapper 677 #define ddp_shutdown ddp_shutdown_wrapper 678 #define ddp_abort ddp_abort_wrapper 679 #define ddp_ioctl ddp_ioctl_wrapper 680 #define ddp_stat ddp_stat_wrapper 681 #define ddp_peeraddr ddp_peeraddr_wrapper 682 #define ddp_sockaddr ddp_sockaddr_wrapper 683 #define ddp_rcvd ddp_rcvd_wrapper 684 #define ddp_recvoob ddp_recvoob_wrapper 685 #define ddp_send ddp_send_wrapper 686 #define ddp_sendoob ddp_sendoob_wrapper 687 #define ddp_purgeif ddp_purgeif_wrapper 688 #define ddp_usrreq ddp_usrreq_wrapper 689 690 const struct pr_usrreqs ddp_usrreqs = { 691 .pr_attach = ddp_attach, 692 .pr_detach = ddp_detach, 693 .pr_accept = ddp_accept, 694 .pr_bind = ddp_bind, 695 .pr_listen = ddp_listen, 696 .pr_connect = ddp_connect, 697 .pr_connect2 = ddp_connect2, 698 .pr_disconnect = ddp_disconnect, 699 .pr_shutdown = ddp_shutdown, 700 .pr_abort = ddp_abort, 701 .pr_ioctl = ddp_ioctl, 702 .pr_stat = ddp_stat, 703 .pr_peeraddr = ddp_peeraddr, 704 .pr_sockaddr = ddp_sockaddr, 705 .pr_rcvd = ddp_rcvd, 706 .pr_recvoob = ddp_recvoob, 707 .pr_send = ddp_send, 708 .pr_sendoob = ddp_sendoob, 709 .pr_purgeif = ddp_purgeif, 710 .pr_generic = ddp_usrreq, 711 }; 712 713 static int 714 sysctl_net_atalk_ddp_stats(SYSCTLFN_ARGS) 715 { 716 717 return (NETSTAT_SYSCTL(ddpstat_percpu, DDP_NSTATS)); 718 } 719 720 /* 721 * Sysctl for DDP variables. 722 */ 723 SYSCTL_SETUP(sysctl_net_atalk_ddp_setup, "sysctl net.atalk.ddp subtree setup") 724 { 725 726 sysctl_createv(clog, 0, NULL, NULL, 727 CTLFLAG_PERMANENT, 728 CTLTYPE_NODE, "atalk", NULL, 729 NULL, 0, NULL, 0, 730 CTL_NET, PF_APPLETALK, CTL_EOL); 731 sysctl_createv(clog, 0, NULL, NULL, 732 CTLFLAG_PERMANENT, 733 CTLTYPE_NODE, "ddp", 734 SYSCTL_DESCR("DDP related settings"), 735 NULL, 0, NULL, 0, 736 CTL_NET, PF_APPLETALK, ATPROTO_DDP, CTL_EOL); 737 738 sysctl_createv(clog, 0, NULL, NULL, 739 CTLFLAG_PERMANENT, 740 CTLTYPE_STRUCT, "stats", 741 SYSCTL_DESCR("DDP statistics"), 742 sysctl_net_atalk_ddp_stats, 0, NULL, 0, 743 CTL_NET, PF_APPLETALK, ATPROTO_DDP, CTL_CREATE, 744 CTL_EOL); 745 } 746