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