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