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