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