1 /* $NetBSD: ddp_usrreq.c,v 1.63 2014/08/09 05:33:01 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.63 2014/08/09 05:33:01 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 mbuf *); 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 mbuf *addr) 146 { 147 struct sockaddr_at lsat, *sat; 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 (addr != 0) { /* validate passed address */ 155 sat = mtod(addr, struct sockaddr_at *); 156 if (addr->m_len != sizeof(*sat)) 157 return (EINVAL); 158 159 if (sat->sat_family != AF_APPLETALK) 160 return (EAFNOSUPPORT); 161 162 if (sat->sat_addr.s_node != ATADDR_ANYNODE || 163 sat->sat_addr.s_net != ATADDR_ANYNET) { 164 TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 165 if ((sat->sat_addr.s_net == 166 AA_SAT(aa)->sat_addr.s_net) && 167 (sat->sat_addr.s_node == 168 AA_SAT(aa)->sat_addr.s_node)) 169 break; 170 } 171 if (!aa) 172 return (EADDRNOTAVAIL); 173 } 174 if (sat->sat_port != ATADDR_ANYPORT) { 175 int error; 176 177 if (sat->sat_port < ATPORT_FIRST || 178 sat->sat_port >= ATPORT_LAST) 179 return (EINVAL); 180 181 if (sat->sat_port < ATPORT_RESERVED && 182 (error = kauth_authorize_network(curlwp->l_cred, 183 KAUTH_NETWORK_BIND, KAUTH_REQ_NETWORK_BIND_PRIVPORT, 184 ddpcb->ddp_socket, sat, NULL)) != 0) 185 return (error); 186 } 187 } else { 188 memset((void *) & lsat, 0, sizeof(struct sockaddr_at)); 189 lsat.sat_len = sizeof(struct sockaddr_at); 190 lsat.sat_addr.s_node = ATADDR_ANYNODE; 191 lsat.sat_addr.s_net = ATADDR_ANYNET; 192 lsat.sat_family = AF_APPLETALK; 193 sat = &lsat; 194 } 195 196 if (sat->sat_addr.s_node == ATADDR_ANYNODE && 197 sat->sat_addr.s_net == ATADDR_ANYNET) { 198 if (TAILQ_EMPTY(&at_ifaddr)) 199 return EADDRNOTAVAIL; 200 sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddr))->sat_addr; 201 } 202 ddp->ddp_lsat = *sat; 203 204 /* 205 * Choose port. 206 */ 207 if (sat->sat_port == ATADDR_ANYPORT) { 208 for (sat->sat_port = ATPORT_RESERVED; 209 sat->sat_port < ATPORT_LAST; sat->sat_port++) { 210 if (ddp_ports[sat->sat_port - 1] == 0) 211 break; 212 } 213 if (sat->sat_port == ATPORT_LAST) { 214 return (EADDRNOTAVAIL); 215 } 216 ddp->ddp_lsat.sat_port = sat->sat_port; 217 ddp_ports[sat->sat_port - 1] = ddp; 218 } else { 219 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 220 ddpp = ddpp->ddp_pnext) { 221 if (ddpp->ddp_lsat.sat_addr.s_net == 222 sat->sat_addr.s_net && 223 ddpp->ddp_lsat.sat_addr.s_node == 224 sat->sat_addr.s_node) 225 break; 226 } 227 if (ddpp != NULL) 228 return (EADDRINUSE); 229 230 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 231 ddp_ports[sat->sat_port - 1] = ddp; 232 if (ddp->ddp_pnext) 233 ddp->ddp_pnext->ddp_pprev = ddp; 234 } 235 236 return 0; 237 } 238 239 static int 240 at_pcbconnect(struct ddpcb *ddp, struct mbuf *addr) 241 { 242 struct rtentry *rt; 243 const struct sockaddr_at *cdst; 244 struct sockaddr_at *sat = mtod(addr, struct sockaddr_at *); 245 struct route *ro; 246 struct at_ifaddr *aa; 247 struct ifnet *ifp; 248 u_short hintnet = 0, net; 249 250 if (addr->m_len != sizeof(*sat)) 251 return EINVAL; 252 if (sat->sat_family != AF_APPLETALK) { 253 return EAFNOSUPPORT; 254 } 255 /* 256 * Under phase 2, network 0 means "the network". We take "the 257 * network" to mean the network the control block is bound to. 258 * If the control block is not bound, there is an error. 259 */ 260 if (sat->sat_addr.s_net == ATADDR_ANYNET 261 && sat->sat_addr.s_node != ATADDR_ANYNODE) { 262 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) { 263 return EADDRNOTAVAIL; 264 } 265 hintnet = ddp->ddp_lsat.sat_addr.s_net; 266 } 267 ro = &ddp->ddp_route; 268 /* 269 * If we've got an old route for this pcb, check that it is valid. 270 * If we've changed our address, we may have an old "good looking" 271 * route here. Attempt to detect it. 272 */ 273 if ((rt = rtcache_validate(ro)) != NULL || 274 (rt = rtcache_update(ro, 1)) != NULL) { 275 if (hintnet) { 276 net = hintnet; 277 } else { 278 net = sat->sat_addr.s_net; 279 } 280 if ((ifp = rt->rt_ifp) != NULL) { 281 TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 282 if (aa->aa_ifp == ifp && 283 ntohs(net) >= ntohs(aa->aa_firstnet) && 284 ntohs(net) <= ntohs(aa->aa_lastnet)) { 285 break; 286 } 287 } 288 } else 289 aa = NULL; 290 cdst = satocsat(rtcache_getdst(ro)); 291 if (aa == NULL || (cdst->sat_addr.s_net != 292 (hintnet ? hintnet : sat->sat_addr.s_net) || 293 cdst->sat_addr.s_node != sat->sat_addr.s_node)) { 294 rtcache_free(ro); 295 rt = NULL; 296 } 297 } 298 /* 299 * If we've got no route for this interface, try to find one. 300 */ 301 if (rt == NULL) { 302 union { 303 struct sockaddr dst; 304 struct sockaddr_at dsta; 305 } u; 306 307 sockaddr_at_init(&u.dsta, &sat->sat_addr, 0); 308 if (hintnet) 309 u.dsta.sat_addr.s_net = hintnet; 310 rt = rtcache_lookup(ro, &u.dst); 311 } 312 /* 313 * Make sure any route that we have has a valid interface. 314 */ 315 if (rt != NULL && (ifp = rt->rt_ifp) != NULL) { 316 TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 317 if (aa->aa_ifp == ifp) 318 break; 319 } 320 } else 321 aa = NULL; 322 if (aa == NULL) 323 return ENETUNREACH; 324 ddp->ddp_fsat = *sat; 325 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 326 return at_pcbsetaddr(ddp, NULL); 327 return 0; 328 } 329 330 static void 331 at_pcbdisconnect(struct ddpcb *ddp) 332 { 333 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 334 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 335 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 336 } 337 338 static int 339 ddp_attach(struct socket *so, int proto) 340 { 341 struct ddpcb *ddp; 342 int error; 343 344 KASSERT(sotoddpcb(so) == NULL); 345 sosetlock(so); 346 #ifdef MBUFTRACE 347 so->so_rcv.sb_mowner = &atalk_rx_mowner; 348 so->so_snd.sb_mowner = &atalk_tx_mowner; 349 #endif 350 error = soreserve(so, ddp_sendspace, ddp_recvspace); 351 if (error) { 352 return error; 353 } 354 355 ddp = kmem_zalloc(sizeof(*ddp), KM_SLEEP); 356 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 357 358 ddp->ddp_next = ddpcb; 359 ddp->ddp_prev = NULL; 360 ddp->ddp_pprev = NULL; 361 ddp->ddp_pnext = NULL; 362 if (ddpcb) { 363 ddpcb->ddp_prev = ddp; 364 } 365 ddpcb = ddp; 366 367 ddp->ddp_socket = so; 368 so->so_pcb = ddp; 369 return 0; 370 } 371 372 static void 373 ddp_detach(struct socket *so) 374 { 375 struct ddpcb *ddp = sotoddpcb(so); 376 377 soisdisconnected(so); 378 so->so_pcb = NULL; 379 /* sofree drops the lock */ 380 sofree(so); 381 mutex_enter(softnet_lock); 382 383 /* remove ddp from ddp_ports list */ 384 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 385 ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 386 if (ddp->ddp_pprev != NULL) { 387 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 388 } else { 389 ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 390 } 391 if (ddp->ddp_pnext != NULL) { 392 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 393 } 394 } 395 rtcache_free(&ddp->ddp_route); 396 if (ddp->ddp_prev) { 397 ddp->ddp_prev->ddp_next = ddp->ddp_next; 398 } else { 399 ddpcb = ddp->ddp_next; 400 } 401 if (ddp->ddp_next) { 402 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 403 } 404 kmem_free(ddp, sizeof(*ddp)); 405 } 406 407 static int 408 ddp_accept(struct socket *so, struct mbuf *nam) 409 { 410 KASSERT(solocked(so)); 411 412 return EOPNOTSUPP; 413 } 414 415 static int 416 ddp_bind(struct socket *so, struct mbuf *nam, struct lwp *l) 417 { 418 KASSERT(solocked(so)); 419 KASSERT(sotoddpcb(so) != NULL); 420 421 return at_pcbsetaddr(sotoddpcb(so), nam); 422 } 423 424 static int 425 ddp_listen(struct socket *so, struct lwp *l) 426 { 427 KASSERT(solocked(so)); 428 429 return EOPNOTSUPP; 430 } 431 432 static int 433 ddp_connect(struct socket *so, struct mbuf *nam, struct lwp *l) 434 { 435 struct ddpcb *ddp = sotoddpcb(so); 436 int error = 0; 437 438 KASSERT(solocked(so)); 439 KASSERT(ddp != NULL); 440 KASSERT(nam != NULL); 441 442 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) 443 return EISCONN; 444 error = at_pcbconnect(ddp, nam); 445 if (error == 0) 446 soisconnected(so); 447 448 return error; 449 } 450 451 static int 452 ddp_connect2(struct socket *so, struct socket *so2) 453 { 454 KASSERT(solocked(so)); 455 456 return EOPNOTSUPP; 457 } 458 459 static int 460 ddp_disconnect(struct socket *so) 461 { 462 struct ddpcb *ddp = sotoddpcb(so); 463 464 KASSERT(solocked(so)); 465 KASSERT(ddp != NULL); 466 467 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) 468 return ENOTCONN; 469 470 at_pcbdisconnect(ddp); 471 soisdisconnected(so); 472 return 0; 473 } 474 475 static int 476 ddp_shutdown(struct socket *so) 477 { 478 KASSERT(solocked(so)); 479 480 socantsendmore(so); 481 return 0; 482 } 483 484 static int 485 ddp_abort(struct socket *so) 486 { 487 KASSERT(solocked(so)); 488 489 soisdisconnected(so); 490 ddp_detach(so); 491 return 0; 492 } 493 494 static int 495 ddp_ioctl(struct socket *so, u_long cmd, void *addr, struct ifnet *ifp) 496 { 497 return at_control(cmd, addr, ifp); 498 } 499 500 static int 501 ddp_stat(struct socket *so, struct stat *ub) 502 { 503 KASSERT(solocked(so)); 504 505 /* stat: don't bother with a blocksize. */ 506 return 0; 507 } 508 509 static int 510 ddp_peeraddr(struct socket *so, struct mbuf *nam) 511 { 512 KASSERT(solocked(so)); 513 514 return EOPNOTSUPP; 515 } 516 517 static int 518 ddp_sockaddr(struct socket *so, struct mbuf *nam) 519 { 520 KASSERT(solocked(so)); 521 KASSERT(sotoddpcb(so) != NULL); 522 KASSERT(nam != NULL); 523 524 at_sockaddr(sotoddpcb(so), nam); 525 return 0; 526 } 527 528 static int 529 ddp_rcvd(struct socket *so, int flags, struct lwp *l) 530 { 531 KASSERT(solocked(so)); 532 533 return EOPNOTSUPP; 534 } 535 536 static int 537 ddp_recvoob(struct socket *so, struct mbuf *m, int flags) 538 { 539 KASSERT(solocked(so)); 540 541 return EOPNOTSUPP; 542 } 543 544 static int 545 ddp_send(struct socket *so, struct mbuf *m, struct mbuf *nam, 546 struct mbuf *control, struct lwp *l) 547 { 548 struct ddpcb *ddp = sotoddpcb(so); 549 int error = 0; 550 int s = 0; /* XXX gcc 4.8 warns on sgimips */ 551 552 KASSERT(solocked(so)); 553 KASSERT(ddp != NULL); 554 555 if (nam) { 556 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) 557 return EISCONN; 558 s = splnet(); 559 error = at_pcbconnect(ddp, nam); 560 if (error) { 561 splx(s); 562 return error; 563 } 564 } else { 565 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 566 return ENOTCONN; 567 } 568 569 error = ddp_output(m, ddp); 570 m = NULL; 571 if (nam) { 572 at_pcbdisconnect(ddp); 573 splx(s); 574 } 575 576 return error; 577 } 578 579 static int 580 ddp_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 581 { 582 KASSERT(solocked(so)); 583 584 if (m) 585 m_freem(m); 586 587 return EOPNOTSUPP; 588 } 589 590 static int 591 ddp_purgeif(struct socket *so, struct ifnet *ifp) 592 { 593 594 mutex_enter(softnet_lock); 595 at_purgeif(ifp); 596 mutex_exit(softnet_lock); 597 598 return 0; 599 } 600 601 /* 602 * For the moment, this just find the pcb with the correct local address. 603 * In the future, this will actually do some real searching, so we can use 604 * the sender's address to do de-multiplexing on a single port to many 605 * sockets (pcbs). 606 */ 607 struct ddpcb * 608 ddp_search( 609 struct sockaddr_at *from, 610 struct sockaddr_at *to, 611 struct at_ifaddr *aa) 612 { 613 struct ddpcb *ddp; 614 615 /* 616 * Check for bad ports. 617 */ 618 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 619 return NULL; 620 621 /* 622 * Make sure the local address matches the sent address. What about 623 * the interface? 624 */ 625 for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 626 /* XXX should we handle 0.YY? */ 627 628 /* XXXX.YY to socket on destination interface */ 629 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 630 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 631 break; 632 } 633 /* 0.255 to socket on receiving interface */ 634 if (to->sat_addr.s_node == ATADDR_BCAST && 635 (to->sat_addr.s_net == 0 || 636 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 637 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) { 638 break; 639 } 640 /* XXXX.0 to socket on destination interface */ 641 if (to->sat_addr.s_net == aa->aa_firstnet && 642 to->sat_addr.s_node == 0 && 643 ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 644 ntohs(aa->aa_firstnet) && 645 ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 646 ntohs(aa->aa_lastnet)) { 647 break; 648 } 649 } 650 return (ddp); 651 } 652 653 /* 654 * Initialize all the ddp & appletalk stuff 655 */ 656 void 657 ddp_init(void) 658 { 659 660 ddpstat_percpu = percpu_alloc(sizeof(uint64_t) * DDP_NSTATS); 661 662 TAILQ_INIT(&at_ifaddr); 663 atintrq1.ifq_maxlen = IFQ_MAXLEN; 664 atintrq2.ifq_maxlen = IFQ_MAXLEN; 665 666 MOWNER_ATTACH(&atalk_tx_mowner); 667 MOWNER_ATTACH(&atalk_rx_mowner); 668 MOWNER_ATTACH(&aarp_mowner); 669 } 670 671 PR_WRAP_USRREQS(ddp) 672 #define ddp_attach ddp_attach_wrapper 673 #define ddp_detach ddp_detach_wrapper 674 #define ddp_accept ddp_accept_wrapper 675 #define ddp_bind ddp_bind_wrapper 676 #define ddp_listen ddp_listen_wrapper 677 #define ddp_connect ddp_connect_wrapper 678 #define ddp_connect2 ddp_connect2_wrapper 679 #define ddp_disconnect ddp_disconnect_wrapper 680 #define ddp_shutdown ddp_shutdown_wrapper 681 #define ddp_abort ddp_abort_wrapper 682 #define ddp_ioctl ddp_ioctl_wrapper 683 #define ddp_stat ddp_stat_wrapper 684 #define ddp_peeraddr ddp_peeraddr_wrapper 685 #define ddp_sockaddr ddp_sockaddr_wrapper 686 #define ddp_rcvd ddp_rcvd_wrapper 687 #define ddp_recvoob ddp_recvoob_wrapper 688 #define ddp_send ddp_send_wrapper 689 #define ddp_sendoob ddp_sendoob_wrapper 690 #define ddp_purgeif ddp_purgeif_wrapper 691 #define ddp_usrreq ddp_usrreq_wrapper 692 693 const struct pr_usrreqs ddp_usrreqs = { 694 .pr_attach = ddp_attach, 695 .pr_detach = ddp_detach, 696 .pr_accept = ddp_accept, 697 .pr_bind = ddp_bind, 698 .pr_listen = ddp_listen, 699 .pr_connect = ddp_connect, 700 .pr_connect2 = ddp_connect2, 701 .pr_disconnect = ddp_disconnect, 702 .pr_shutdown = ddp_shutdown, 703 .pr_abort = ddp_abort, 704 .pr_ioctl = ddp_ioctl, 705 .pr_stat = ddp_stat, 706 .pr_peeraddr = ddp_peeraddr, 707 .pr_sockaddr = ddp_sockaddr, 708 .pr_rcvd = ddp_rcvd, 709 .pr_recvoob = ddp_recvoob, 710 .pr_send = ddp_send, 711 .pr_sendoob = ddp_sendoob, 712 .pr_purgeif = ddp_purgeif, 713 .pr_generic = ddp_usrreq, 714 }; 715 716 static int 717 sysctl_net_atalk_ddp_stats(SYSCTLFN_ARGS) 718 { 719 720 return (NETSTAT_SYSCTL(ddpstat_percpu, DDP_NSTATS)); 721 } 722 723 /* 724 * Sysctl for DDP variables. 725 */ 726 SYSCTL_SETUP(sysctl_net_atalk_ddp_setup, "sysctl net.atalk.ddp subtree setup") 727 { 728 729 sysctl_createv(clog, 0, NULL, NULL, 730 CTLFLAG_PERMANENT, 731 CTLTYPE_NODE, "atalk", NULL, 732 NULL, 0, NULL, 0, 733 CTL_NET, PF_APPLETALK, CTL_EOL); 734 sysctl_createv(clog, 0, NULL, NULL, 735 CTLFLAG_PERMANENT, 736 CTLTYPE_NODE, "ddp", 737 SYSCTL_DESCR("DDP related settings"), 738 NULL, 0, NULL, 0, 739 CTL_NET, PF_APPLETALK, ATPROTO_DDP, CTL_EOL); 740 741 sysctl_createv(clog, 0, NULL, NULL, 742 CTLFLAG_PERMANENT, 743 CTLTYPE_STRUCT, "stats", 744 SYSCTL_DESCR("DDP statistics"), 745 sysctl_net_atalk_ddp_stats, 0, NULL, 0, 746 CTL_NET, PF_APPLETALK, ATPROTO_DDP, CTL_CREATE, 747 CTL_EOL); 748 } 749