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 * @(#)iso_pcb.c 7.4 (Berkeley) 07/19/89 31 * 32 * Iso address family net-layer(s) pcb stuff. NEH 1/29/87 33 */ 34 35 #ifndef lint 36 static char *rcsid = "$Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $"; 37 #endif 38 39 #ifdef ISO 40 41 #include "param.h" 42 #include "systm.h" 43 #include "user.h" 44 #include "mbuf.h" 45 #include "socket.h" 46 #include "socketvar.h" 47 #include "argo_debug.h" 48 #include "iso.h" 49 #include "clnp.h" 50 #include "../netinet/in_systm.h" 51 #include "../net/if.h" 52 #include "../net/route.h" 53 #include "iso_pcb.h" 54 #include "iso_var.h" 55 #include "protosw.h" 56 57 #define PCBNULL (struct isopcb *)0 58 struct iso_addr zeroiso_addr = { 59 0 60 }; 61 62 63 /* 64 * FUNCTION: iso_pcballoc 65 * 66 * PURPOSE: creates an isopcb structure in an mbuf, 67 * with socket (so), and 68 * puts it in the queue with head (head) 69 * 70 * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf 71 */ 72 int 73 iso_pcballoc(so, head) 74 struct socket *so; 75 struct isopcb *head; 76 { 77 register struct isopcb *isop; 78 79 IFDEBUG(D_ISO) 80 printf("iso_pcballoc(so 0x%x)\n", so); 81 ENDDEBUG 82 MALLOC(isop, struct isopcb *, sizeof(*isop), M_PCB, M_NOWAIT); 83 if (isop == NULL) 84 return ENOBUFS; 85 bzero((caddr_t)isop, sizeof(*isop)); 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 #define satosiso(sa) ((struct sockaddr_iso *)(sa)) 111 int 112 iso_pcbbind(isop, nam) 113 register struct isopcb *isop; 114 struct mbuf *nam; 115 { 116 register struct isopcb *head = isop->isop_head; 117 register struct sockaddr_iso *siso; 118 struct iso_ifaddr *ia; 119 union { 120 char data[2]; 121 u_short s; 122 } suf; 123 124 IFDEBUG(D_ISO) 125 printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop, nam); 126 ENDDEBUG 127 suf.s = 0; 128 if (iso_ifaddr == 0) /* any interfaces attached? */ 129 return EADDRNOTAVAIL; 130 if (isop->isop_laddr) /* already bound */ 131 return EADDRINUSE; 132 if(nam == (struct mbuf *)0) { 133 isop->isop_laddr = &isop->isop_sladdr; 134 isop->isop_sladdr.siso_tsuffixlen = 2; 135 isop->isop_sladdr.siso_nlen = 0; 136 isop->isop_sladdr.siso_family = AF_ISO; 137 isop->isop_sladdr.siso_len = sizeof(struct sockaddr_iso); 138 goto noname; 139 } 140 siso = mtod(nam, struct sockaddr_iso *); 141 IFDEBUG(D_ISO) 142 printf("iso_pcbbind(name len 0x%x)\n", nam->m_len); 143 printf("The address is %s\n", clnp_iso_addrp(&siso->siso_addr)); 144 ENDDEBUG 145 /* 146 * We would like sort of length check but since some OSI addrs 147 * do not have fixed length, we can't really do much. 148 * The ONLY thing we can say is that an osi addr has to have 149 * at LEAST an afi and one more byte and had better fit into 150 * a struct iso_addr. 151 * However, in fact the size of the whole thing is a struct 152 * sockaddr_iso, so probably this is what we should check for. 153 */ 154 if( (nam->m_len < 2) || (nam->m_len < siso->siso_len)) { 155 return ENAMETOOLONG; 156 } 157 if (siso->siso_tsuffixlen) { 158 register char *cp = TSEL(siso); 159 suf.data[0] = cp[0]; 160 suf.data[1] = cp[1]; 161 } 162 if (siso->siso_nlen) { 163 /* non-zero net addr- better match one of our interfaces */ 164 IFDEBUG(D_ISO) 165 printf("iso_pcbbind: bind to NOT zeroisoaddr\n"); 166 ENDDEBUG 167 for (ia = iso_ifaddr; ia; ia = ia->ia_next) 168 if (SAME_ISOADDR(siso, &ia->ia_addr)) 169 break; 170 if (ia == 0) 171 return EADDRNOTAVAIL; 172 } 173 if (siso->siso_len <= sizeof (isop->isop_sladdr)) { 174 isop->isop_laddr = &isop->isop_sladdr; 175 } else { 176 if ((nam = m_copy(nam, 0, (int)M_COPYALL)) == 0) 177 return ENOBUFS; 178 isop->isop_laddr = mtod(nam, struct sockaddr_iso *); 179 } 180 bcopy((caddr_t)siso, (caddr_t)isop->isop_laddr, siso->siso_len); 181 if (suf.s) { 182 if((suf.s < ISO_PORT_RESERVED) && (siso->siso_tsuffixlen <= 2) && 183 (u.u_uid != 0)) 184 return EACCES; 185 if ((isop->isop_socket->so_options & SO_REUSEADDR) == 0 && 186 iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr)) 187 return EADDRINUSE; 188 } else { 189 register char *cp; 190 noname: 191 cp = TSEL(isop->isop_laddr); 192 IFDEBUG(D_ISO) 193 printf("iso_pcbbind noname\n"); 194 ENDDEBUG 195 do { 196 if (head->isop_lport++ < ISO_PORT_RESERVED || 197 head->isop_lport > ISO_PORT_USERRESERVED) 198 head->isop_lport = ISO_PORT_RESERVED; 199 suf.s = head->isop_lport; 200 cp[0] = suf.data[0]; 201 cp[1] = suf.data[1]; 202 } while (iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr)); 203 } 204 IFDEBUG(D_ISO) 205 printf("iso_pcbbind returns 0, suf 0x%x\n", suf); 206 ENDDEBUG 207 return 0; 208 } 209 /* 210 * FUNCTION: iso_pcbconnect 211 * 212 * PURPOSE: Make the isopcb (isop) look like it's connected. 213 * In other words, give it the peer address given in 214 * the mbuf * (nam). Make sure such a combination 215 * of local, peer addresses doesn't already exist 216 * for this protocol. Internet mentality prevails here, 217 * wherein a src,dst pair uniquely identifies a connection. 218 * Both net address and port must be specified in argument 219 * (nam). 220 * If we don't have a local address for this socket yet, 221 * we pick one by calling iso_pcbbind(). 222 * 223 * RETURNS: errno E* or 0 if ok. 224 * 225 * SIDE EFFECTS: Looks up a route, which may cause one to be left 226 * in the isopcb. 227 * 228 * NOTES: 229 */ 230 int 231 iso_pcbconnect(isop, nam) 232 register struct isopcb *isop; 233 struct mbuf *nam; 234 { 235 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 236 int local_zero, error = 0; 237 struct iso_ifaddr *ia; 238 239 IFDEBUG(D_ISO) 240 printf("iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x", 241 isop, isop->isop_socket, nam); 242 printf("nam->m_len 0x%x), addr:\n", nam->m_len); 243 dump_isoaddr(siso); 244 ENDDEBUG 245 if (nam->m_len < siso->siso_len) 246 return EINVAL; 247 if (siso->siso_family != AF_ISO) 248 return EAFNOSUPPORT; 249 if (siso->siso_nlen == 0) { 250 if (ia = iso_ifaddr) { 251 int nlen = ia->ia_addr.siso_nlen; 252 ovbcopy(TSEL(siso), nlen + TSEL(siso), 253 siso->siso_tsuffixlen + siso->siso_ssuffixlen); 254 bcopy((caddr_t)&ia->ia_addr.siso_addr, 255 (caddr_t)&siso->siso_addr, nlen + 1); 256 /* includes siso->siso_nlen = nlen; */ 257 } else 258 return EADDRNOTAVAIL; 259 } 260 /* 261 * Local zero means either not bound, or bound to a TSEL, but no 262 * particular local interface. So, if we want to send somebody 263 * we need to choose a return address. 264 */ 265 local_zero = 266 ((isop->isop_laddr == 0) || (isop->isop_laddr->siso_nlen == 0)); 267 if (local_zero) { 268 int flags; 269 270 IFDEBUG(D_ISO) 271 printf("iso_pcbconnect localzero 1\n"); 272 ENDDEBUG 273 /* 274 * If route is known or can be allocated now, 275 * our src addr is taken from the i/f, else punt. 276 */ 277 flags = isop->isop_socket->so_options & SO_DONTROUTE; 278 if (error = clnp_route(&siso->siso_addr, &isop->isop_route, flags, 279 (struct sockaddr **)0, &ia)) 280 return error; 281 IFDEBUG(D_ISO) 282 printf("iso_pcbconnect localzero 2, ro->ro_rt 0x%x", 283 isop->isop_route.ro_rt); 284 printf(" ia 0x%x\n", ia); 285 ENDDEBUG 286 } 287 IFDEBUG(D_ISO) 288 printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n", 289 isop, isop->isop_socket); 290 ENDDEBUG 291 if (local_zero) { 292 int nlen, tlen, totlen; caddr_t oldtsel, newtsel; 293 siso = isop->isop_laddr; 294 if (siso == 0 || siso->siso_tsuffixlen == 0) 295 (void)iso_pcbbind(isop, (struct mbuf *)0); 296 /* 297 * Here we have problem of squezeing in a definite network address 298 * into an existing sockaddr_iso, which in fact may not have room 299 * for it. This gets messy. 300 */ 301 siso = isop->isop_laddr; 302 oldtsel = TSEL(siso); 303 tlen = siso->siso_tsuffixlen; 304 nlen = ia->ia_addr.siso_nlen; 305 totlen = tlen + nlen + _offsetof(struct sockaddr_iso, siso_data[0]); 306 if ((siso == &isop->isop_sladdr) && 307 (totlen > sizeof(isop->isop_sladdr))) { 308 struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT); 309 if (m == 0) 310 return ENOBUFS; 311 m->m_len = totlen; 312 isop->isop_laddr = siso = mtod(m, struct sockaddr_iso *); 313 } 314 siso->siso_nlen = ia->ia_addr.siso_nlen; 315 newtsel = TSEL(siso); 316 ovbcopy(oldtsel, newtsel, tlen); 317 bcopy(ia->ia_addr.siso_data, siso->siso_data, nlen); 318 siso->siso_tsuffixlen = tlen; 319 siso->siso_family = AF_ISO; 320 siso->siso_len = totlen; 321 siso = mtod(nam, struct sockaddr_iso *); 322 } 323 IFDEBUG(D_ISO) 324 printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n", 325 isop, isop->isop_socket); 326 ENDDEBUG 327 /* 328 * If we had to allocate space to a previous big foreign address, 329 * and for some reason we didn't free it, we reuse it knowing 330 * that is going to be big enough, as sockaddrs are delivered in 331 * 128 byte mbufs. 332 * If the foreign address is small enough, we use default space; 333 * otherwise, we grab an mbuf to copy into. 334 */ 335 if (isop->isop_faddr == 0 || isop->isop_faddr == &isop->isop_sfaddr) { 336 if (siso->siso_len <= sizeof(isop->isop_sfaddr)) 337 isop->isop_faddr = &isop->isop_sfaddr; 338 else { 339 struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT); 340 if (m == 0) 341 return ENOBUFS; 342 isop->isop_faddr = mtod(m, struct sockaddr_iso *); 343 } 344 } 345 bcopy((caddr_t)siso, (caddr_t)isop->isop_faddr, siso->siso_len); 346 IFDEBUG(D_ISO) 347 printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n", 348 isop, isop->isop_socket); 349 printf("iso_pcbconnect connected to addr:\n"); 350 dump_isoaddr(isop->isop_faddr); 351 printf("iso_pcbconnect end: src addr:\n"); 352 dump_isoaddr(isop->isop_laddr); 353 ENDDEBUG 354 return 0; 355 } 356 357 /* 358 * FUNCTION: iso_pcbdisconnect() 359 * 360 * PURPOSE: washes away the peer address info so the socket 361 * appears to be disconnected. 362 * If there's no file descriptor associated with the socket 363 * it detaches the pcb. 364 * 365 * RETURNS: Nada. 366 * 367 * SIDE EFFECTS: May detach the pcb. 368 * 369 * NOTES: 370 */ 371 void 372 iso_pcbdisconnect(isop) 373 struct isopcb *isop; 374 { 375 void iso_pcbdetach(); 376 377 IFDEBUG(D_ISO) 378 printf("iso_pcbdisconnect(isop 0x%x)\n", isop); 379 ENDDEBUG 380 /* 381 * Preserver binding infnormation if already bound. 382 */ 383 if (isop->isop_laddr && isop->isop_laddr->siso_nlen) 384 isop->isop_laddr->siso_nlen = 0; 385 if (isop->isop_faddr && isop->isop_faddr != &isop->isop_sfaddr) 386 m_freem(dtom(isop->isop_faddr)); 387 isop->isop_faddr = 0; 388 if (isop->isop_socket->so_state & SS_NOFDREF) 389 iso_pcbdetach(isop); 390 } 391 392 /* 393 * FUNCTION: iso_pcbdetach 394 * 395 * PURPOSE: detach the pcb at *(isop) from it's socket and free 396 * the mbufs associated with the pcb.. 397 * Dequeues (isop) from its head. 398 * 399 * RETURNS: Nada. 400 * 401 * SIDE EFFECTS: 402 * 403 * NOTES: 404 */ 405 void 406 iso_pcbdetach(isop) 407 struct isopcb *isop; 408 { 409 struct socket *so = isop->isop_socket; 410 411 IFDEBUG(D_ISO) 412 printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n", 413 isop, isop->isop_socket, so); 414 ENDDEBUG 415 if (so ) { /* in the x.25 domain, we sometimes have no socket */ 416 so->so_pcb = 0; 417 sofree(so); 418 } 419 IFDEBUG(D_ISO) 420 printf("iso_pcbdetach 2 \n"); 421 ENDDEBUG 422 if (isop->isop_options) 423 (void)m_free(isop->isop_options); 424 IFDEBUG(D_ISO) 425 printf("iso_pcbdetach 3 \n"); 426 ENDDEBUG 427 if (isop->isop_route.ro_rt) 428 rtfree(isop->isop_route.ro_rt); 429 IFDEBUG(D_ISO) 430 printf("iso_pcbdetach 3.1\n"); 431 ENDDEBUG 432 if (isop->isop_clnpcache != NULL) { 433 struct clnp_cache *clcp = 434 mtod(isop->isop_clnpcache, struct clnp_cache *); 435 IFDEBUG(D_ISO) 436 printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n", 437 clcp, clcp->clc_hdr); 438 ENDDEBUG 439 if (clcp->clc_hdr != NULL) 440 m_free(clcp->clc_hdr); 441 IFDEBUG(D_ISO) 442 printf("iso_pcbdetach 3.3: freeing cache x%x\n", 443 isop->isop_clnpcache); 444 ENDDEBUG 445 m_free(isop->isop_clnpcache); 446 } 447 IFDEBUG(D_ISO) 448 printf("iso_pcbdetach 4 \n"); 449 ENDDEBUG 450 remque(isop); 451 IFDEBUG(D_ISO) 452 printf("iso_pcbdetach 5 \n"); 453 ENDDEBUG 454 if (isop->isop_laddr && (isop->isop_laddr != &isop->isop_sladdr)) 455 m_freem(dtom(isop->isop_laddr)); 456 free((caddr_t)isop, M_IFADDR); 457 } 458 459 #ifdef notdef 460 /* NEEDED? */ 461 void 462 iso_setsockaddr(isop, nam) 463 register struct isopcb *isop; 464 struct mbuf *nam; 465 { 466 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 467 468 nam->m_len = sizeof (*siso); 469 siso = mtod(nam, struct sockaddr_iso *); 470 bzero((caddr_t)siso, sizeof (*siso)); 471 siso->siso_family = AF_ISO; 472 siso->siso_tsuffix = isop->isop_lport; 473 siso->siso_addr = isop->isop_laddr.siso_addr; 474 } 475 476 /* NEEDED? */ 477 void 478 iso_setpeeraddr(isop, nam) 479 register struct isopcb *isop; 480 struct mbuf *nam; 481 { 482 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 483 484 nam->m_len = sizeof (*siso); 485 siso = mtod(nam, struct sockaddr_iso *); 486 bzero((caddr_t)siso, sizeof (*siso)); 487 siso->siso_family = AF_ISO; 488 siso->siso_tsuffix = isop->isop_fport; 489 siso->siso_addr = isop->isop_faddr.siso_addr; 490 } 491 #endif notdef 492 493 /* 494 * FUNCTION: iso_pcbnotify 495 * 496 * PURPOSE: notify all connections in this protocol's queue (head) 497 * that have peer address (dst) of the problem (errno) 498 * by calling (notify) on the connections' isopcbs. 499 * 500 * RETURNS: Rien. 501 * 502 * SIDE EFFECTS: 503 * 504 * NOTES: (notify) is called at splimp! 505 */ 506 void 507 iso_pcbnotify(head, dst, errno, notify) 508 struct isopcb *head; 509 register struct iso_addr *dst; 510 int errno, (*notify)(); 511 { 512 register struct isopcb *isop, *oisop; 513 int s = splimp(); 514 515 IFDEBUG(D_ISO) 516 printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head, notify); 517 ENDDEBUG 518 for (isop = head->isop_next; isop != head;) { 519 if (!iso_addrmatch1(&(isop->isop_faddr->siso_addr), dst) || 520 isop->isop_socket == 0) { 521 IFDEBUG(D_ISO) 522 printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" , 523 isop, isop->isop_socket); 524 printf("addrmatch cmp'd with (0x%x):\n", 525 &(isop->isop_faddr->siso_addr)); 526 dump_isoaddr(isop->isop_faddr); 527 ENDDEBUG 528 isop = isop->isop_next; 529 continue; 530 } 531 if (errno) 532 isop->isop_socket->so_error = errno; 533 oisop = isop; 534 isop = isop->isop_next; 535 if (notify) 536 (*notify)(oisop); 537 } 538 splx(s); 539 IFDEBUG(D_ISO) 540 printf("END OF iso_pcbnotify\n" ); 541 ENDDEBUG 542 } 543 544 545 /* 546 * FUNCTION: iso_pcblookup 547 * 548 * PURPOSE: looks for a given combination of (faddr), (fport), 549 * (lport), (laddr) in the queue named by (head). 550 * Argument (flags) is ignored. 551 * 552 * RETURNS: ptr to the isopcb if it finds a connection matching 553 * these arguments, o.w. returns zero. 554 * 555 * SIDE EFFECTS: 556 * 557 * NOTES: 558 */ 559 struct isopcb * 560 iso_pcblookup(head, fportlen, fport, laddr) 561 struct isopcb *head; 562 register struct sockaddr_iso *laddr; 563 caddr_t fport; 564 int fportlen; 565 { 566 register struct isopcb *isop; 567 register caddr_t lp = TSEL(laddr); 568 unsigned int llen = laddr->siso_tsuffixlen; 569 570 IFDEBUG(D_ISO) 571 printf("iso_pcblookup(head 0x%x laddr 0x%x fport 0x%x)\n", 572 head, laddr, fport); 573 ENDDEBUG 574 for (isop = head->isop_next; isop != head; isop = isop->isop_next) { 575 if (isop->isop_laddr == 0 || isop->isop_laddr == laddr) 576 continue; 577 if (isop->isop_laddr->siso_tsuffixlen != llen) 578 continue; 579 if (bcmp(lp, TSEL(isop->isop_laddr), llen)) 580 continue; 581 if (fportlen && isop->isop_faddr && 582 bcmp(fport, TSEL(isop->isop_faddr), (unsigned)fportlen)) 583 continue; 584 /* PHASE2 585 * addrmatch1 should be iso_addrmatch(a, b, mask) 586 * where mask is taken from isop->isop_laddrmask (new field) 587 * isop_lnetmask will also be available in isop 588 if (laddr != &zeroiso_addr && 589 !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr))) 590 continue; 591 */ 592 if (laddr->siso_nlen && (!SAME_ISOADDR(laddr, isop->isop_laddr))) 593 continue; 594 return (isop); 595 } 596 return (struct isopcb *)0; 597 } 598 #endif ISO 599