1 /* $NetBSD: ddp_usrreq.c,v 1.20 2006/11/16 01:33:44 christos 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.20 2006/11/16 01:33:44 christos 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/proc.h> 38 #include <sys/mbuf.h> 39 #include <sys/ioctl.h> 40 #include <sys/socket.h> 41 #include <sys/socketvar.h> 42 #include <sys/protosw.h> 43 #include <sys/kauth.h> 44 #include <net/if.h> 45 #include <net/route.h> 46 #include <net/if_ether.h> 47 #include <netinet/in.h> 48 49 #include <netatalk/at.h> 50 #include <netatalk/at_var.h> 51 #include <netatalk/ddp_var.h> 52 #include <netatalk/aarp.h> 53 #include <netatalk/at_extern.h> 54 55 static void at_pcbdisconnect __P((struct ddpcb *)); 56 static void at_sockaddr __P((struct ddpcb *, struct mbuf *)); 57 static int at_pcbsetaddr __P((struct ddpcb *, struct mbuf *, struct lwp *)); 58 static int at_pcbconnect __P((struct ddpcb *, struct mbuf *, struct lwp *)); 59 static void at_pcbdetach __P((struct socket *, struct ddpcb *)); 60 static int at_pcballoc __P((struct socket *)); 61 62 struct ifqueue atintrq1, atintrq2; 63 struct ddpcb *ddp_ports[ATPORT_LAST]; 64 struct ddpcb *ddpcb = NULL; 65 struct ddpstat ddpstat; 66 struct at_ifaddrhead at_ifaddr; /* Here as inited in this file */ 67 u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ 68 u_long ddp_recvspace = 25 * (587 + sizeof(struct sockaddr_at)); 69 70 #ifdef MBUFTRACE 71 struct mowner atalk_rx_mowner = MOWNER_INIT("atalk", "rx"); 72 struct mowner atalk_tx_mowner = MOWNER_INIT("atalk", "tx"); 73 #endif 74 75 /* ARGSUSED */ 76 int 77 ddp_usrreq(so, req, m, addr, rights, l) 78 struct socket *so; 79 int req; 80 struct mbuf *m; 81 struct mbuf *addr; 82 struct mbuf *rights; 83 struct lwp *l; 84 { 85 struct ddpcb *ddp; 86 int error = 0; 87 88 ddp = sotoddpcb(so); 89 90 if (req == PRU_CONTROL) { 91 return (at_control((long) m, (caddr_t) addr, 92 (struct ifnet *) rights, l)); 93 } 94 if (req == PRU_PURGEIF) { 95 at_purgeif((struct ifnet *) rights); 96 return (0); 97 } 98 if (rights && rights->m_len) { 99 error = EINVAL; 100 goto release; 101 } 102 if (ddp == NULL && req != PRU_ATTACH) { 103 error = EINVAL; 104 goto release; 105 } 106 switch (req) { 107 case PRU_ATTACH: 108 if (ddp != NULL) { 109 error = EINVAL; 110 break; 111 } 112 if ((error = at_pcballoc(so)) != 0) { 113 break; 114 } 115 error = soreserve(so, ddp_sendspace, ddp_recvspace); 116 break; 117 118 case PRU_DETACH: 119 at_pcbdetach(so, ddp); 120 break; 121 122 case PRU_BIND: 123 error = at_pcbsetaddr(ddp, addr, l); 124 break; 125 126 case PRU_SOCKADDR: 127 at_sockaddr(ddp, addr); 128 break; 129 130 case PRU_CONNECT: 131 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 132 error = EISCONN; 133 break; 134 } 135 error = at_pcbconnect(ddp, addr, l); 136 if (error == 0) 137 soisconnected(so); 138 break; 139 140 case PRU_DISCONNECT: 141 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { 142 error = ENOTCONN; 143 break; 144 } 145 at_pcbdisconnect(ddp); 146 soisdisconnected(so); 147 break; 148 149 case PRU_SHUTDOWN: 150 socantsendmore(so); 151 break; 152 153 case PRU_SEND:{ 154 int s = 0; 155 156 if (addr) { 157 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 158 error = EISCONN; 159 break; 160 } 161 s = splnet(); 162 error = at_pcbconnect(ddp, addr, l); 163 if (error) { 164 splx(s); 165 break; 166 } 167 } else { 168 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) { 169 error = ENOTCONN; 170 break; 171 } 172 } 173 174 error = ddp_output(m, ddp); 175 m = NULL; 176 if (addr) { 177 at_pcbdisconnect(ddp); 178 splx(s); 179 } 180 } 181 break; 182 183 case PRU_ABORT: 184 soisdisconnected(so); 185 at_pcbdetach(so, ddp); 186 break; 187 188 case PRU_LISTEN: 189 case PRU_CONNECT2: 190 case PRU_ACCEPT: 191 case PRU_SENDOOB: 192 case PRU_FASTTIMO: 193 case PRU_SLOWTIMO: 194 case PRU_PROTORCV: 195 case PRU_PROTOSEND: 196 error = EOPNOTSUPP; 197 break; 198 199 case PRU_RCVD: 200 case PRU_RCVOOB: 201 /* 202 * Don't mfree. Good architecture... 203 */ 204 return (EOPNOTSUPP); 205 206 case PRU_SENSE: 207 /* 208 * 1. Don't return block size. 209 * 2. Don't mfree. 210 */ 211 return (0); 212 213 default: 214 error = EOPNOTSUPP; 215 } 216 217 release: 218 if (m != NULL) { 219 m_freem(m); 220 } 221 return (error); 222 } 223 224 static void 225 at_sockaddr(ddp, addr) 226 struct ddpcb *ddp; 227 struct mbuf *addr; 228 { 229 struct sockaddr_at *sat; 230 231 addr->m_len = sizeof(struct sockaddr_at); 232 sat = mtod(addr, struct sockaddr_at *); 233 *sat = ddp->ddp_lsat; 234 } 235 236 static int 237 at_pcbsetaddr(ddp, addr, l) 238 struct ddpcb *ddp; 239 struct mbuf *addr; 240 struct lwp *l; 241 { 242 struct sockaddr_at lsat, *sat; 243 struct at_ifaddr *aa; 244 struct ddpcb *ddpp; 245 246 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) { /* shouldn't be bound */ 247 return (EINVAL); 248 } 249 if (addr != 0) { /* validate passed address */ 250 sat = mtod(addr, struct sockaddr_at *); 251 if (addr->m_len != sizeof(*sat)) 252 return (EINVAL); 253 254 if (sat->sat_family != AF_APPLETALK) 255 return (EAFNOSUPPORT); 256 257 if (sat->sat_addr.s_node != ATADDR_ANYNODE || 258 sat->sat_addr.s_net != ATADDR_ANYNET) { 259 for (aa = at_ifaddr.tqh_first; aa; 260 aa = aa->aa_list.tqe_next) { 261 if ((sat->sat_addr.s_net == 262 AA_SAT(aa)->sat_addr.s_net) && 263 (sat->sat_addr.s_node == 264 AA_SAT(aa)->sat_addr.s_node)) 265 break; 266 } 267 if (!aa) 268 return (EADDRNOTAVAIL); 269 } 270 if (sat->sat_port != ATADDR_ANYPORT) { 271 if (sat->sat_port < ATPORT_FIRST || 272 sat->sat_port >= ATPORT_LAST) 273 return (EINVAL); 274 275 if (sat->sat_port < ATPORT_RESERVED && l && 276 kauth_authorize_generic(l->l_cred, 277 KAUTH_GENERIC_ISSUSER, 278 &l->l_acflag)) 279 return (EACCES); 280 } 281 } else { 282 bzero((caddr_t) & lsat, sizeof(struct sockaddr_at)); 283 lsat.sat_len = sizeof(struct sockaddr_at); 284 lsat.sat_addr.s_node = ATADDR_ANYNODE; 285 lsat.sat_addr.s_net = ATADDR_ANYNET; 286 lsat.sat_family = AF_APPLETALK; 287 sat = &lsat; 288 } 289 290 if (sat->sat_addr.s_node == ATADDR_ANYNODE && 291 sat->sat_addr.s_net == ATADDR_ANYNET) { 292 if (at_ifaddr.tqh_first == NULL) 293 return (EADDRNOTAVAIL); 294 sat->sat_addr = AA_SAT(at_ifaddr.tqh_first)->sat_addr; 295 } 296 ddp->ddp_lsat = *sat; 297 298 /* 299 * Choose port. 300 */ 301 if (sat->sat_port == ATADDR_ANYPORT) { 302 for (sat->sat_port = ATPORT_RESERVED; 303 sat->sat_port < ATPORT_LAST; sat->sat_port++) { 304 if (ddp_ports[sat->sat_port - 1] == 0) 305 break; 306 } 307 if (sat->sat_port == ATPORT_LAST) { 308 return (EADDRNOTAVAIL); 309 } 310 ddp->ddp_lsat.sat_port = sat->sat_port; 311 ddp_ports[sat->sat_port - 1] = ddp; 312 } else { 313 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 314 ddpp = ddpp->ddp_pnext) { 315 if (ddpp->ddp_lsat.sat_addr.s_net == 316 sat->sat_addr.s_net && 317 ddpp->ddp_lsat.sat_addr.s_node == 318 sat->sat_addr.s_node) 319 break; 320 } 321 if (ddpp != NULL) 322 return (EADDRINUSE); 323 324 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 325 ddp_ports[sat->sat_port - 1] = ddp; 326 if (ddp->ddp_pnext) 327 ddp->ddp_pnext->ddp_pprev = ddp; 328 } 329 330 return 0; 331 } 332 333 static int 334 at_pcbconnect(ddp, addr, l) 335 struct ddpcb *ddp; 336 struct mbuf *addr; 337 struct lwp *l; 338 { 339 struct sockaddr_at *sat = mtod(addr, struct sockaddr_at *); 340 struct route *ro; 341 struct at_ifaddr *aa = 0; 342 struct ifnet *ifp; 343 u_short hintnet = 0, net; 344 345 if (addr->m_len != sizeof(*sat)) 346 return (EINVAL); 347 if (sat->sat_family != AF_APPLETALK) { 348 return (EAFNOSUPPORT); 349 } 350 /* 351 * Under phase 2, network 0 means "the network". We take "the 352 * network" to mean the network the control block is bound to. 353 * If the control block is not bound, there is an error. 354 */ 355 if (sat->sat_addr.s_net == ATADDR_ANYNET 356 && sat->sat_addr.s_node != ATADDR_ANYNODE) { 357 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) { 358 return (EADDRNOTAVAIL); 359 } 360 hintnet = ddp->ddp_lsat.sat_addr.s_net; 361 } 362 ro = &ddp->ddp_route; 363 /* 364 * If we've got an old route for this pcb, check that it is valid. 365 * If we've changed our address, we may have an old "good looking" 366 * route here. Attempt to detect it. 367 */ 368 if (ro->ro_rt) { 369 if (hintnet) { 370 net = hintnet; 371 } else { 372 net = sat->sat_addr.s_net; 373 } 374 aa = 0; 375 if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 376 for (aa = at_ifaddr.tqh_first; aa; 377 aa = aa->aa_list.tqe_next) { 378 if (aa->aa_ifp == ifp && 379 ntohs(net) >= ntohs(aa->aa_firstnet) && 380 ntohs(net) <= ntohs(aa->aa_lastnet)) { 381 break; 382 } 383 } 384 } 385 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 386 (hintnet ? hintnet : sat->sat_addr.s_net) || 387 satosat(&ro->ro_dst)->sat_addr.s_node != 388 sat->sat_addr.s_node)) { 389 RTFREE(ro->ro_rt); 390 ro->ro_rt = (struct rtentry *) 0; 391 } 392 } 393 /* 394 * If we've got no route for this interface, try to find one. 395 */ 396 if (ro->ro_rt == (struct rtentry *) 0 || 397 ro->ro_rt->rt_ifp == (struct ifnet *) 0) { 398 bzero(&ro->ro_dst, sizeof(struct sockaddr_at)); 399 ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 400 ro->ro_dst.sa_family = AF_APPLETALK; 401 if (hintnet) { 402 satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 403 } else { 404 satosat(&ro->ro_dst)->sat_addr.s_net = 405 sat->sat_addr.s_net; 406 } 407 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 408 rtalloc(ro); 409 } 410 /* 411 * Make sure any route that we have has a valid interface. 412 */ 413 aa = 0; 414 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 415 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 416 if (aa->aa_ifp == ifp) { 417 break; 418 } 419 } 420 } 421 if (aa == 0) { 422 return (ENETUNREACH); 423 } 424 ddp->ddp_fsat = *sat; 425 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) { 426 return (at_pcbsetaddr(ddp, (struct mbuf *) 0, l)); 427 } 428 return (0); 429 } 430 431 static void 432 at_pcbdisconnect(ddp) 433 struct ddpcb *ddp; 434 { 435 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 436 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 437 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 438 } 439 440 static int 441 at_pcballoc(so) 442 struct socket *so; 443 { 444 struct ddpcb *ddp; 445 446 MALLOC(ddp, struct ddpcb *, sizeof(*ddp), M_PCB, M_WAITOK|M_ZERO); 447 if (!ddp) 448 panic("at_pcballoc"); 449 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 450 451 ddp->ddp_next = ddpcb; 452 ddp->ddp_prev = NULL; 453 ddp->ddp_pprev = NULL; 454 ddp->ddp_pnext = NULL; 455 if (ddpcb) { 456 ddpcb->ddp_prev = ddp; 457 } 458 ddpcb = ddp; 459 460 ddp->ddp_socket = so; 461 so->so_pcb = (caddr_t) ddp; 462 #ifdef MBUFTRACE 463 so->so_rcv.sb_mowner = &atalk_rx_mowner; 464 so->so_snd.sb_mowner = &atalk_tx_mowner; 465 #endif 466 return (0); 467 } 468 469 static void 470 at_pcbdetach(so, ddp) 471 struct socket *so; 472 struct ddpcb *ddp; 473 { 474 soisdisconnected(so); 475 so->so_pcb = 0; 476 sofree(so); 477 478 /* remove ddp from ddp_ports list */ 479 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 480 ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 481 if (ddp->ddp_pprev != NULL) { 482 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 483 } else { 484 ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 485 } 486 if (ddp->ddp_pnext != NULL) { 487 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 488 } 489 } 490 if (ddp->ddp_route.ro_rt) { 491 rtfree(ddp->ddp_route.ro_rt); 492 } 493 if (ddp->ddp_prev) { 494 ddp->ddp_prev->ddp_next = ddp->ddp_next; 495 } else { 496 ddpcb = ddp->ddp_next; 497 } 498 if (ddp->ddp_next) { 499 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 500 } 501 free(ddp, M_PCB); 502 } 503 504 /* 505 * For the moment, this just find the pcb with the correct local address. 506 * In the future, this will actually do some real searching, so we can use 507 * the sender's address to do de-multiplexing on a single port to many 508 * sockets (pcbs). 509 */ 510 struct ddpcb * 511 ddp_search( 512 struct sockaddr_at *from, 513 struct sockaddr_at *to, 514 struct at_ifaddr *aa) 515 { 516 struct ddpcb *ddp; 517 518 /* 519 * Check for bad ports. 520 */ 521 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) { 522 return (NULL); 523 } 524 /* 525 * Make sure the local address matches the sent address. What about 526 * the interface? 527 */ 528 for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 529 /* XXX should we handle 0.YY? */ 530 531 /* XXXX.YY to socket on destination interface */ 532 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 533 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 534 break; 535 } 536 /* 0.255 to socket on receiving interface */ 537 if (to->sat_addr.s_node == ATADDR_BCAST && 538 (to->sat_addr.s_net == 0 || 539 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 540 ddp->ddp_lsat.sat_addr.s_net == AA_SAT(aa)->sat_addr.s_net) { 541 break; 542 } 543 /* XXXX.0 to socket on destination interface */ 544 if (to->sat_addr.s_net == aa->aa_firstnet && 545 to->sat_addr.s_node == 0 && 546 ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 547 ntohs(aa->aa_firstnet) && 548 ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 549 ntohs(aa->aa_lastnet)) { 550 break; 551 } 552 } 553 return (ddp); 554 } 555 556 /* 557 * Initialize all the ddp & appletalk stuff 558 */ 559 void 560 ddp_init() 561 { 562 TAILQ_INIT(&at_ifaddr); 563 atintrq1.ifq_maxlen = IFQ_MAXLEN; 564 atintrq2.ifq_maxlen = IFQ_MAXLEN; 565 566 MOWNER_ATTACH(&atalk_tx_mowner); 567 MOWNER_ATTACH(&atalk_rx_mowner); 568 } 569 570 #if 0 571 static void 572 ddp_clean() 573 { 574 struct ddpcb *ddp; 575 576 for (ddp = ddpcb; ddp; ddp = ddp->ddp_next) 577 at_pcbdetach(ddp->ddp_socket, ddp); 578 } 579 #endif 580