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