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