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