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