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