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