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