1 /*********************************************************** 2 Copyright IBM Corporation 1987 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, 8 provided that the above copyright notice appear in all copies and that 9 both that copyright notice and this permission notice appear in 10 supporting documentation, and that the name of IBM not be 11 used in advertising or publicity pertaining to distribution of the 12 software without specific, written prior permission. 13 14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 22 ******************************************************************/ 23 24 /* 25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26 */ 27 /* 28 * $Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $ 29 * $Source: /usr/argo/sys/netiso/RCS/iso_pcb.c,v $ 30 * 31 * Iso address family net-layer(s) pcb stuff. NEH 1/29/87 32 */ 33 #ifndef lint 34 static char *rcsid = "$Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $"; 35 #endif 36 37 #ifdef ISO 38 39 #include "param.h" 40 #include "systm.h" 41 #include "dir.h" 42 #include "user.h" 43 #include "mbuf.h" 44 #include "../h/socket.h" 45 #include "../h/socketvar.h" 46 #include "../netiso/argo_debug.h" 47 #include "../netiso/iso.h" 48 #include "../netiso/clnp.h" 49 #include "../netinet/in_systm.h" 50 #include "../net/if.h" 51 #include "../net/route.h" 52 #include "../netiso/iso_pcb.h" 53 #include "../netiso/iso_var.h" 54 #include "protosw.h" 55 56 #define PCBNULL (struct isopcb *)0 57 struct iso_addr zeroiso_addr = { 58 0 59 }; 60 61 62 /* 63 * FUNCTION: iso_pcballoc 64 * 65 * PURPOSE: creates an isopcb structure in an mbuf, 66 * with socket (so), and 67 * puts it in the queue with head (head) 68 * 69 * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf 70 */ 71 int 72 iso_pcballoc(so, head) 73 struct socket *so; 74 struct isopcb *head; 75 { 76 struct mbuf *m; 77 register struct isopcb *isop; 78 79 IFDEBUG(D_ISO) 80 printf("iso_pcballoc(so 0x%x)\n", so); 81 ENDDEBUG 82 m = m_getclr(M_DONTWAIT, MT_PCB); 83 if (m == NULL) 84 return ENOBUFS; 85 isop = mtod(m, struct isopcb *); 86 isop->isop_head = head; 87 isop->isop_socket = so; 88 insque(isop, head); 89 so->so_pcb = (caddr_t)isop; 90 return 0; 91 } 92 93 /* 94 * FUNCTION: iso_pcbbind 95 * 96 * PURPOSE: binds the address given in *(nam) to the socket 97 * specified by the isopcb in *(isop) 98 * If the given address is zero, it makes sure the 99 * address isn't already in use and if it's got a network 100 * portion, we look for an interface with that network 101 * address. If the address given is zero, we allocate 102 * a port and stuff it in the (nam) structure. 103 * 104 * RETURNS: errno E* or 0 if ok. 105 * 106 * SIDE EFFECTS: increments head->isop_lport if it allocates a port # 107 * 108 * NOTES: 109 */ 110 int 111 iso_pcbbind(isop, nam) 112 register struct isopcb *isop; 113 struct mbuf *nam; 114 { 115 register struct isopcb *head = isop->isop_head; 116 register struct sockaddr_iso *siso; 117 struct ifaddr *ia; 118 u_short suf = 0; 119 120 IFDEBUG(D_ISO) 121 printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop, nam); 122 ENDDEBUG 123 if (iso_ifaddr == 0) /* any interfaces attached? */ 124 return EADDRNOTAVAIL; 125 if (isop->isop_lport) /* already bound */ 126 return EADDRINUSE; 127 if(nam == (struct mbuf *)0) 128 goto noname; 129 siso = mtod(nam, struct sockaddr_iso *); 130 IFDEBUG(D_ISO) 131 printf("iso_pcbbind(name len 0x%x)\n", nam->m_len); 132 printf("The address is %s\n", clnp_iso_addrp(&siso->siso_addr)); 133 ENDDEBUG 134 /* 135 * We would like sort of length check but since some OSI addrs 136 * do not have fixed length, we can't really do much. 137 * The ONLY thing we can say is that an osi addr has to have 138 * at LEAST an afi and one more byte and had better fit into 139 * a struct iso_addr. 140 * However, in fact the size of the whole thing is a struct 141 * sockaddr_iso, so probably this is what we should check for. 142 */ 143 if( (nam->m_len < 2) || (nam->m_len > sizeof(struct sockaddr_iso))) { 144 return ENAMETOOLONG; 145 } 146 suf = siso->siso_tsuffix; 147 148 if (bcmp(&siso->siso_addr,&zeroiso_addr, 1)) { 149 /* non-zero net addr- better match one of our interfaces */ 150 IFDEBUG(D_ISO) 151 printf("iso_pcbbind: bind to NOT zeroisoaddr\n"); 152 ENDDEBUG 153 siso->siso_tsuffix = 0; /* yech... */ 154 /* PHASE 2: this call is ok */ 155 if ((ia = ifa_ifwithaddr((struct sockaddr *)siso)) 156 == (struct ifaddr *)0) 157 return EADDRNOTAVAIL; 158 /* copy to the inpcb */ 159 bcopy( (caddr_t)&((struct sockaddr_iso *)&(ia->ifa_addr))->siso_addr, 160 (caddr_t)&(isop->isop_laddr.siso_addr), 161 sizeof(struct sockaddr_iso) ); 162 isop->isop_laddr.siso_tsuffix = suf; 163 /* copy also to the nam parameter */ 164 bcopy( (caddr_t)&(isop->isop_laddr.siso_addr), 165 (caddr_t)&(siso->siso_addr), sizeof(struct sockaddr_iso)); 166 siso->siso_tsuffix = suf; 167 } 168 if (suf) { 169 if((suf < ISO_PORT_RESERVED) && (u.u_uid != 0)) 170 return EACCES; 171 if ((isop->isop_socket->so_options & SO_REUSEADDR) == 0 && 172 iso_pcblookup(head, 0, &(isop->isop_laddr.siso_addr), suf, 0) ) 173 return EADDRINUSE; 174 } 175 /* copy the if addr to the result (siso) and to the isopcb */ 176 noname: 177 IFDEBUG(D_ISO) 178 printf("iso_pcbbind noname\n"); 179 ENDDEBUG 180 if (suf == 0) 181 do { 182 if (head->isop_lport++ < ISO_PORT_RESERVED || 183 head->isop_lport > ISO_PORT_USERRESERVED) 184 head->isop_lport = ISO_PORT_RESERVED; 185 suf = head->isop_lport; 186 } while (iso_pcblookup(head, 0, &(isop->isop_laddr.siso_addr), suf, 0)); 187 isop->isop_lport = suf; 188 IFDEBUG(D_ISO) 189 printf("iso_pcbbind returns 0, suf 0x%x\n", suf); 190 ENDDEBUG 191 return 0; 192 } 193 194 /* 195 * FUNCTION: iso_pcbconnect 196 * 197 * PURPOSE: Make the isopcb (isop) look like it's connected. 198 * In other words, give it the peer address given in 199 * the mbuf * (nam). Make sure such a combination 200 * of local, peer addresses doesn't already exist 201 * for this protocol. Internet mentality prevails here, 202 * wherein a src,dst pair uniquely identifies a connection. 203 * Both net address and port must be specified in argument 204 * (nam). 205 * If we don't have a local address for this socket yet, 206 * we pick one by calling iso_pcbbind(). 207 * 208 * RETURNS: errno E* or 0 if ok. 209 * 210 * SIDE EFFECTS: Looks up a route, which may cause one to be left 211 * in the isopcb. 212 * 213 * NOTES: 214 */ 215 #define satosiso(sa) ((struct sockaddr_iso *)(sa)) 216 217 int 218 iso_pcbconnect(isop, nam) 219 struct isopcb *isop; 220 struct mbuf *nam; 221 { 222 struct ifnet *ifp = (struct ifnet *)0; 223 struct sockaddr_iso ifaddr; 224 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 225 int local_zero = 0; 226 227 IFDEBUG(D_ISO) 228 printf( 229 "iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x nam->m_len 0x%x), addr:\n", 230 isop, isop->isop_socket, nam, nam->m_len); 231 dump_isoaddr(siso); 232 ENDDEBUG 233 if (nam->m_len > sizeof (*siso)) 234 return ENAMETOOLONG; /* not great but better than EINVAL! */ 235 if (siso->siso_family != AF_ISO) 236 return EAFNOSUPPORT; 237 #ifdef notdef 238 /* removed for the sake of extended tsels - 239 * user may setsockopt for extended tsel (foreign) and then 240 * connect to nsap w/ tsuffix zero 241 */ 242 if (siso->siso_tsuffix == 0) 243 return EADDRNOTAVAIL; 244 local_zero = iso_addrmatch1(&(isop->isop_laddr.siso_addr), &zeroiso_addr); 245 #endif notdef 246 local_zero = !bcmp(&(isop->isop_laddr.siso_addr), &zeroiso_addr, 1); 247 248 #ifdef PHASEONE 249 if (local_zero) { 250 /* 251 * We need to get the local nsap address. 252 * First, route to the destination. This will provide us with 253 * an ifp. Second, determine which local address linked on 254 * that ifp is appropriate 255 */ 256 struct sockaddr_iso *first_hop; /* filled by clnp_route */ 257 struct ifnet *ifp; /* filled by clnp_route */ 258 int err; 259 struct iso_addr *localaddr; 260 261 if (err = clnp_route(&siso->siso_addr, &isop->isop_route, /* flags */0, 262 &first_hop, &ifp)) 263 return(err); 264 265 /* determine local address based upon ifp */ 266 if ((localaddr = clnp_srcaddr(ifp, &first_hop->siso_addr)) == NULL) 267 return(ENETUNREACH); 268 269 ifaddr.siso_family = AF_ISO; 270 ifaddr.siso_addr = *localaddr; 271 272 if (isop->isop_lport == 0) 273 (void)iso_pcbbind(isop, (struct mbuf *)0); 274 isop->isop_laddr = ifaddr; 275 } 276 #else 277 if (local_zero) { 278 struct iso_ifaddr *ia; 279 register struct route *ro; 280 281 IFDEBUG(D_ISO) 282 printf("iso_pcbconnect localzero 1\n"); 283 ENDDEBUG 284 ia = (struct iso_ifaddr *)0; 285 /* 286 * If route is known or can be allocated now, 287 * our src addr is taken from the i/f, else punt. 288 */ 289 ro = &isop->isop_route; 290 IFDEBUG(D_ISO) 291 printf("iso_pcbconnect rtalloc 1.1, ro->ro_rt 0x%x\n", 292 ro->ro_rt); 293 ENDDEBUG 294 if (ro->ro_rt && ! iso_addrmatch1( &(satosiso(&ro->ro_dst)->siso_addr), 295 &siso->siso_addr)) { 296 RTFREE(ro->ro_rt); 297 ro->ro_rt = (struct rtentry *)0; 298 } 299 /* 300 * TODO: it seems this code has a lot in common with clnp_route. 301 * Maybe they could be combined? (RAH) 302 */ 303 if ((isop->isop_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 304 (ro->ro_rt == (struct rtentry *)0 || 305 (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0)) { 306 /* No route yet, so try to acquire one */ 307 ro->ro_dst.sa_family = AF_ISO; 308 ((struct sockaddr_iso *) &ro->ro_dst)->siso_addr = 309 siso->siso_addr; 310 rtalloc(ro); 311 IFDEBUG(D_ISO) 312 printf("iso_pcbconnect rtalloc 1.5, ro->ro_rt 0x%x\n", 313 ro->ro_rt); 314 if (ro->ro_rt != NULL) { 315 printf("ro->ro_rt->rt_refcnt %d\n", 316 ro->ro_rt->rt_refcnt); 317 printf("rt entry rt_gateway (as sockaddr):\n"); 318 dump_buf(&ro->ro_rt->rt_gateway, 319 sizeof (struct sockaddr)); 320 } 321 ENDDEBUG 322 /* 323 * If we found a route, use the address 324 * corresponding to the outgoing interface 325 * unless it is the loopback (in case a route 326 * to our address on another net goes to loopback). 327 * 328 * We must check to use the address that is of the 329 * same type (in the case where the interface has more 330 * than one type associated with it). (ie ecn0 has 331 * both t37 and osinet addresses. 332 */ 333 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 334 (ifp->if_flags & IFF_LOOPBACK) == 0) 335 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 336 struct iso_addr *isoap = &IA_SIS(ia)->siso_addr; 337 338 IFDEBUG(D_ISO) 339 printf("iso_pcbconnect: ia x%x yields: %s\n", 340 ia, clnp_iso_addrp(isoap)); 341 ENDDEBUG 342 343 if ((ia->ia_ifp == ifp) && 344 (iso_eqtype(&siso->siso_addr, isoap))) 345 break; 346 } 347 } 348 IFDEBUG(D_ISO) 349 printf("iso_pcbconnect localzero 2: ia x%x\n", ia); 350 ENDDEBUG 351 if (ia == 0) { 352 ia = (struct iso_ifaddr *) 353 ifa_ifwithdstaddr((struct sockaddr *)siso); 354 if (ia == 0) 355 ia = iso_iaonnetof(siso); 356 if (ia == 0) 357 return EADDRNOTAVAIL; 358 } 359 ifaddr = *(struct sockaddr_iso *)&ia->ia_addr; 360 } 361 IFDEBUG(D_ISO) 362 printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n", 363 isop, isop->isop_socket); 364 ENDDEBUG 365 if (local_zero) { 366 if (isop->isop_lport == 0) 367 (void)iso_pcbbind(isop, (struct mbuf *)0); 368 isop->isop_laddr.siso_addr = ifaddr.siso_addr; 369 isop->isop_laddr.siso_family = AF_ISO; 370 } 371 #endif PHASEONE 372 IFDEBUG(D_ISO) 373 printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n", 374 isop, isop->isop_socket); 375 ENDDEBUG 376 bcopy((caddr_t) &(siso->siso_addr), (caddr_t) &(isop->isop_faddr.siso_addr), 377 sizeof(struct iso_addr)); 378 IFDEBUG(D_ISO) 379 printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n", 380 isop, isop->isop_socket); 381 ENDDEBUG 382 isop->isop_faddr.siso_family = AF_ISO; 383 isop->isop_fport = siso->siso_tsuffix; 384 IFDEBUG(D_ISO) 385 printf("in iso_pcbconnect end isop 0x%x isop->sock 0x%x\n", 386 isop, isop->isop_socket); 387 printf("iso_pcbconnect connected to addr:\n"); 388 dump_isoaddr(&isop->isop_faddr); 389 printf("iso_pcbconnect end: src addr:\n"); 390 dump_isoaddr(&isop->isop_laddr); 391 ENDDEBUG 392 return 0; 393 } 394 395 /* 396 * FUNCTION: iso_pcbdisconnect() 397 * 398 * PURPOSE: washes away the peer address info so the socket 399 * appears to be disconnected. 400 * If there's no file descriptor associated with the socket 401 * it detaches the pcb. 402 * 403 * RETURNS: Nada. 404 * 405 * SIDE EFFECTS: May detach the pcb. 406 * 407 * NOTES: 408 */ 409 void 410 iso_pcbdisconnect(isop) 411 struct isopcb *isop; 412 { 413 void iso_pcbdetach(); 414 415 IFDEBUG(D_ISO) 416 printf("iso_pcbdisconnect(isop 0x%x)\n", isop); 417 ENDDEBUG 418 isop->isop_laddr.siso_addr = zeroiso_addr; 419 isop->isop_fport = 0; 420 if (isop->isop_socket->so_state & SS_NOFDREF) 421 iso_pcbdetach(isop); 422 } 423 424 /* 425 * FUNCTION: iso_pcbdetach 426 * 427 * PURPOSE: detach the pcb at *(isop) from it's socket and free 428 * the mbufs associated with the pcb.. 429 * Dequeues (isop) from its head. 430 * 431 * RETURNS: Nada. 432 * 433 * SIDE EFFECTS: 434 * 435 * NOTES: 436 */ 437 void 438 iso_pcbdetach(isop) 439 struct isopcb *isop; 440 { 441 struct socket *so = isop->isop_socket; 442 443 IFDEBUG(D_ISO) 444 printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n", 445 isop, isop->isop_socket, so); 446 ENDDEBUG 447 if (so ) { /* in the x.25 domain, we sometimes have no socket */ 448 so->so_pcb = 0; 449 sofree(so); 450 } 451 IFDEBUG(D_ISO) 452 printf("iso_pcbdetach 2 \n"); 453 ENDDEBUG 454 if (isop->isop_options) 455 (void)m_free(isop->isop_options); 456 IFDEBUG(D_ISO) 457 printf("iso_pcbdetach 3 \n"); 458 ENDDEBUG 459 if (isop->isop_route.ro_rt) 460 rtfree(isop->isop_route.ro_rt); 461 IFDEBUG(D_ISO) 462 printf("iso_pcbdetach 3.1\n"); 463 ENDDEBUG 464 if (isop->isop_clnpcache != NULL) { 465 struct clnp_cache *clcp = 466 mtod(isop->isop_clnpcache, struct clnp_cache *); 467 IFDEBUG(D_ISO) 468 printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n", 469 clcp, clcp->clc_hdr); 470 ENDDEBUG 471 if (clcp->clc_hdr != NULL) 472 m_free(clcp->clc_hdr); 473 IFDEBUG(D_ISO) 474 printf("iso_pcbdetach 3.3: freeing cache x%x\n", 475 isop->isop_clnpcache); 476 ENDDEBUG 477 m_free(isop->isop_clnpcache); 478 } 479 IFDEBUG(D_ISO) 480 printf("iso_pcbdetach 4 \n"); 481 ENDDEBUG 482 remque(isop); 483 IFDEBUG(D_ISO) 484 printf("iso_pcbdetach 5 \n"); 485 ENDDEBUG 486 (void) m_free(dtom(isop)); 487 } 488 489 #ifdef notdef 490 /* NEEDED? */ 491 void 492 iso_setsockaddr(isop, nam) 493 register struct isopcb *isop; 494 struct mbuf *nam; 495 { 496 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 497 498 nam->m_len = sizeof (*siso); 499 siso = mtod(nam, struct sockaddr_iso *); 500 bzero((caddr_t)siso, sizeof (*siso)); 501 siso->siso_family = AF_ISO; 502 siso->siso_tsuffix = isop->isop_lport; 503 siso->siso_addr = isop->isop_laddr.siso_addr; 504 } 505 506 /* NEEDED? */ 507 void 508 iso_setpeeraddr(isop, nam) 509 register struct isopcb *isop; 510 struct mbuf *nam; 511 { 512 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 513 514 nam->m_len = sizeof (*siso); 515 siso = mtod(nam, struct sockaddr_iso *); 516 bzero((caddr_t)siso, sizeof (*siso)); 517 siso->siso_family = AF_ISO; 518 siso->siso_tsuffix = isop->isop_fport; 519 siso->siso_addr = isop->isop_faddr.siso_addr; 520 } 521 #endif notdef 522 523 /* 524 * FUNCTION: iso_pcbnotify 525 * 526 * PURPOSE: notify all connections in this protocol's queue (head) 527 * that have peer address (dst) of the problem (errno) 528 * by calling (notify) on the connections' isopcbs. 529 * 530 * RETURNS: Rien. 531 * 532 * SIDE EFFECTS: 533 * 534 * NOTES: (notify) is called at splimp! 535 */ 536 void 537 iso_pcbnotify(head, dst, errno, notify) 538 struct isopcb *head; 539 register struct iso_addr *dst; 540 int errno, (*notify)(); 541 { 542 register struct isopcb *isop, *oisop; 543 int s = splimp(); 544 545 IFDEBUG(D_ISO) 546 printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head, notify); 547 ENDDEBUG 548 for (isop = head->isop_next; isop != head;) { 549 if (!iso_addrmatch1(&(isop->isop_faddr.siso_addr), dst) || 550 isop->isop_socket == 0) { 551 IFDEBUG(D_ISO) 552 printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" , 553 isop, isop->isop_socket); 554 printf("addrmatch cmp'd with (0x%x):\n", 555 &(isop->isop_faddr.siso_addr)); 556 dump_isoaddr(&isop->isop_faddr); 557 ENDDEBUG 558 isop = isop->isop_next; 559 continue; 560 } 561 if (errno) 562 isop->isop_socket->so_error = errno; 563 oisop = isop; 564 isop = isop->isop_next; 565 if (notify) 566 (*notify)(oisop); 567 } 568 splx(s); 569 IFDEBUG(D_ISO) 570 printf("END OF iso_pcbnotify\n" ); 571 ENDDEBUG 572 } 573 574 575 /* 576 * FUNCTION: iso_pcblookup 577 * 578 * PURPOSE: looks for a given combination of (faddr), (fport), 579 * (lport), (laddr) in the queue named by (head). 580 * Argument (flags) is ignored. 581 * 582 * RETURNS: ptr to the isopcb if it finds a connection matching 583 * these arguments, o.w. returns zero. 584 * 585 * SIDE EFFECTS: 586 * 587 * NOTES: 588 */ 589 struct isopcb * 590 iso_pcblookup(head, fport, laddr, lport, flags) 591 struct isopcb *head; 592 struct iso_addr *laddr; 593 u_short fport, lport; 594 int flags; 595 { 596 register struct isopcb *isop; 597 598 IFDEBUG(D_ISO) 599 printf("iso_pcblookup(head 0x%x lport 0x%x fport 0x%x)\n", 600 head, lport, fport); 601 ENDDEBUG 602 for (isop = head->isop_next; isop != head; isop = isop->isop_next) { 603 #ifdef notdef 604 /* 605 * This should be changed to do bcmp on lsuffix in the tpcb instead 606 * since we should be ignoring the lport concept. 607 */ 608 #endif notdef 609 if (isop->isop_lport != lport) 610 continue; 611 if (isop->isop_fport != fport) 612 continue; 613 /* PHASE2 614 * addrmatch1 should be iso_addrmatch(a, b, mask) 615 * where mask is taken from isop->isop_laddrmask (new field) 616 * isop_lnetmask will also be available in isop 617 */ 618 if (laddr != &zeroiso_addr && 619 !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr))) 620 continue; 621 return (isop); 622 } 623 return (struct isopcb *)0; 624 } 625 #endif ISO 626