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 /* $Header: clnp_subr.c,v 4.10 88/09/14 11:31:33 hagens Exp $ */ 28 /* $Source: /usr/argo/sys/netiso/RCS/clnp_subr.c,v $ */ 29 30 #ifndef lint 31 static char *rcsid = "$Header: clnp_subr.c,v 4.10 88/09/14 11:31:33 hagens Exp $"; 32 #endif lint 33 34 #ifdef ISO 35 36 #include "../h/types.h" 37 #include "../h/param.h" 38 #include "../h/mbuf.h" 39 #include "../h/domain.h" 40 #include "../h/protosw.h" 41 #include "../h/socket.h" 42 #include "../h/socketvar.h" 43 #include "../h/errno.h" 44 #include "../h/time.h" 45 46 #include "../net/if.h" 47 #include "../net/route.h" 48 49 #include "../netiso/iso.h" 50 #include "../netiso/iso_var.h" 51 #include "../netiso/clnp.h" 52 #include "../netiso/clnp_stat.h" 53 #include "../netiso/argo_debug.h" 54 #include "../netiso/iso_snpac.h" 55 56 /* 57 * FUNCTION: clnp_data_ck 58 * 59 * PURPOSE: Check that the amount of data in the mbuf chain is 60 * at least as much as the clnp header would have us 61 * expect. Trim mbufs if longer than expected, drop 62 * packet if shorter than expected. 63 * 64 * RETURNS: success - ptr to mbuf chain 65 * failure - 0 66 * 67 * SIDE EFFECTS: 68 * 69 * NOTES: 70 */ 71 struct mbuf * 72 clnp_data_ck(m, length) 73 register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */ 74 int length; /* length (in bytes) of packet */ 75 { 76 register int len; /* length of data */ 77 register struct mbuf *mhead; /* ptr to head of chain */ 78 79 len = -length; 80 mhead = m; 81 for (;;) { 82 len += m->m_len; 83 if (m->m_next == 0) 84 break; 85 m = m->m_next; 86 } 87 if (len != 0) { 88 if (len < 0) { 89 INCSTAT(cns_toosmall); 90 clnp_discard(mhead, GEN_INCOMPLETE); 91 return 0; 92 } 93 if (len <= m->m_len) 94 m->m_len -= len; 95 else 96 m_adj(mhead, -len); 97 } 98 return mhead; 99 } 100 101 #ifdef ndef 102 /* 103 * FUNCTION: clnp_extract_addr 104 * 105 * PURPOSE: Extract the source and destination address from the 106 * supplied buffer. Place them in the supplied address buffers. 107 * If insufficient data is supplied, then fail. 108 * 109 * RETURNS: success - Address of first byte in the packet past 110 * the address part. 111 * failure - 0 112 * 113 * SIDE EFFECTS: 114 * 115 * NOTES: 116 */ 117 caddr_t 118 clnp_extract_addr(bufp, buflen, srcp, destp) 119 caddr_t bufp; /* ptr to buffer containing addresses */ 120 int buflen; /* length of buffer */ 121 register struct iso_addr *srcp; /* ptr to source address buffer */ 122 register struct iso_addr *destp; /* ptr to destination address buffer */ 123 { 124 int len; /* argument to bcopy */ 125 126 /* 127 * check that we have enough data. Plus1 is for length octet 128 */ 129 if ((u_char)*bufp + 1 > buflen) { 130 return((caddr_t)0); 131 } 132 len = destp->isoa_len = (u_char)*bufp++; 133 (void) bcopy(bufp, (caddr_t)destp, len); 134 buflen -= len; 135 bufp += len; 136 137 /* 138 * check that we have enough data. Plus1 is for length octet 139 */ 140 if ((u_char)*bufp + 1 > buflen) { 141 return((caddr_t)0); 142 } 143 len = srcp->isoa_len = (u_char)* bufp++; 144 (void) bcopy(bufp, (caddr_t)srcp, len); 145 bufp += len; 146 147 /* 148 * Insure that the addresses make sense 149 */ 150 if (iso_ck_addr(srcp) && iso_ck_addr(destp)) 151 return bufp; 152 else 153 return (caddr_t) 0; 154 } 155 #endif ndef 156 157 /* 158 * FUNCTION: clnp_ours 159 * 160 * PURPOSE: Decide whether the supplied packet is destined for 161 * us, or that it should be forwarded on. 162 * 163 * RETURNS: packet is for us - 1 164 * packet is not for us - 0 165 * 166 * SIDE EFFECTS: 167 * 168 * NOTES: 169 */ 170 clnp_ours(dst) 171 register struct iso_addr *dst; /* ptr to destination address */ 172 { 173 register struct iso_ifaddr *ia; /* scan through interface addresses */ 174 175 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 176 IFDEBUG(D_ROUTE) 177 printf("clnp_ours: ia_sis x%x, dst x%x\n", &IA_SIS(ia)->siso_addr, 178 dst); 179 ENDDEBUG 180 /* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */ 181 if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst)) 182 return 1; 183 } 184 return 0; 185 } 186 187 /* 188 * FUNCTION: clnp_forward 189 * 190 * PURPOSE: Forward the datagram passed 191 * clnpintr guarantees that the header will be 192 * contigious (a cluster mbuf will be used if necessary). 193 * 194 * If oidx is NULL, no options are present. 195 * 196 * RETURNS: nothing 197 * 198 * SIDE EFFECTS: 199 * 200 * NOTES: 201 */ 202 clnp_forward(m, len, dst, oidx, seg_off, inbound_shp) 203 struct mbuf *m; /* pkt to forward */ 204 int len; /* length of pkt */ 205 struct iso_addr *dst; /* destination address */ 206 struct clnp_optidx *oidx; /* option index */ 207 int seg_off;/* offset of segmentation part */ 208 struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */ 209 { 210 struct clnp_fixed *clnp; /* ptr to fixed part of header */ 211 int error; /* return value of route function */ 212 struct sockaddr *next_hop; /* next hop for dgram */ 213 struct ifnet *ifp; /* ptr to outgoing interface */ 214 struct route_iso route; /* filled in by clnp_route */ 215 extern int iso_systype; 216 217 clnp = mtod(m, struct clnp_fixed *); 218 bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */ 219 220 /* 221 * Don't forward multicast or broadcast packets 222 */ 223 if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { 224 IFDEBUG(D_FORWARD) 225 printf("clnp_forward: dropping multicast packet\n"); 226 ENDDEBUG 227 clnp->cnf_err_ok = 0; /* so we don't generate an ER */ 228 clnp_discard(m, 0); 229 goto done; 230 } 231 232 IFDEBUG(D_FORWARD) 233 printf("clnp_forward: %d bytes, to %s, options x%x\n", len, 234 clnp_iso_addrp(dst), oidx); 235 ENDDEBUG 236 237 /* 238 * Decrement ttl, and if zero drop datagram 239 * Can't compare ttl as less than zero 'cause its a unsigned 240 */ 241 if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { 242 IFDEBUG(D_FORWARD) 243 printf("clnp_forward: discarding datagram because ttl is zero\n"); 244 ENDDEBUG 245 INCSTAT(cns_ttlexpired); 246 clnp_discard(m, TTL_EXPTRANSIT); 247 goto done; 248 } 249 250 /* 251 * Route packet; special case for source rt 252 */ 253 if CLNPSRCRT_VALID(oidx) { 254 /* 255 * Update src route first 256 */ 257 clnp_update_srcrt(m, oidx); 258 error = clnp_srcroute(m, oidx, &route, &next_hop, &ifp, dst); 259 } else { 260 error = clnp_route(dst, &route, 0, &next_hop, &ifp); 261 } 262 if (error) { 263 IFDEBUG(D_FORWARD) 264 printf("clnp_forward: can't route packet (errno %d)\n", error); 265 ENDDEBUG 266 clnp_discard(m, ADDR_DESTUNREACH); 267 goto done; 268 } 269 270 IFDEBUG(D_FORWARD) 271 printf("clnp_forward: packet routed to %s\n", 272 clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr)); 273 ENDDEBUG 274 275 INCSTAT(cns_forward); 276 277 /* 278 * If we are an intermediate system and 279 * we are routing outbound on the same ifp that the packet 280 * arrived upon, and we know the next hop snpa, 281 * then generate a redirect request 282 */ 283 if ((iso_systype & SNPA_IS) && (inbound_shp) && 284 (ifp == inbound_shp->snh_ifp)) { 285 struct snpa_cache *sc; 286 287 sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr); 288 if (sc != NULL) { 289 esis_rdoutput(inbound_shp, m, oidx, dst, sc); 290 } 291 } 292 293 /* 294 * If options are present, update them 295 */ 296 if (oidx) { 297 struct iso_addr *mysrc = 298 clnp_srcaddr(ifp, &((struct sockaddr_iso *)next_hop)->siso_addr); 299 if (mysrc == NULL) { 300 clnp_discard(m, ADDR_DESTUNREACH); 301 goto done; 302 } else { 303 (void) clnp_dooptions(m, oidx, ifp, mysrc); 304 } 305 } 306 307 /* 308 * Dispatch the datagram if it is small enough, otherwise fragment 309 */ 310 if (len <= SN_MTU(ifp)) { 311 iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 312 (void) (*ifp->if_output)(ifp, m, next_hop); 313 } else { 314 (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0); 315 } 316 317 done: 318 /* 319 * Free route 320 */ 321 if (route.ro_rt != NULL) { 322 RTFREE(route.ro_rt); 323 } 324 } 325 326 #ifdef ndef 327 /* 328 * FUNCTION: clnp_insert_addr 329 * 330 * PURPOSE: Insert the address part into a clnp datagram. 331 * 332 * RETURNS: Address of first byte after address part in datagram. 333 * 334 * SIDE EFFECTS: 335 * 336 * NOTES: Assume that there is enough space for the address part. 337 */ 338 caddr_t 339 clnp_insert_addr(bufp, srcp, dstp) 340 caddr_t bufp; /* address of where addr part goes */ 341 register struct iso_addr *srcp; /* ptr to src addr */ 342 register struct iso_addr *dstp; /* ptr to dst addr */ 343 { 344 *bufp++ = dstp->isoa_len; 345 (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len); 346 bufp += dstp->isoa_len; 347 348 *bufp++ = srcp->isoa_len; 349 (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len); 350 bufp += srcp->isoa_len; 351 352 return bufp; 353 } 354 355 #endif ndef 356 357 /* 358 * FUNCTION: clnp_route 359 * 360 * PURPOSE: Route a clnp datagram to the first hop toward its 361 * destination. In many cases, the first hop will be 362 * the destination. The address of a route 363 * is specified. If a routing entry is present in 364 * that route, and it is still up to the same destination, 365 * then no further action is necessary. Otherwise, a 366 * new routing entry will be allocated. 367 * 368 * RETURNS: route found - 0 369 * unix error code 370 * 371 * SIDE EFFECTS: 372 * 373 * NOTES: It is up to the caller to free the routing entry 374 * allocated in route. 375 */ 376 clnp_route(dst, ro, flags, first_hop, ifp) 377 struct iso_addr *dst; /* ptr to datagram destination */ 378 struct route_iso *ro; /* existing route structure */ 379 int flags; /* flags for routing */ 380 struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */ 381 struct ifnet **ifp; /* result: fill in with ptr to interface */ 382 { 383 register struct sockaddr_iso *ro_dst; /* ptr to route's destination */ 384 385 ro_dst = (struct sockaddr_iso *)&ro->ro_dst; 386 387 /* 388 * If there is a cached route, check that it is still up and to 389 * the same destination. If not, free it and try again. 390 */ 391 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 392 (!iso_addrmatch1(&ro_dst->siso_addr, dst)))) { 393 IFDEBUG(D_ROUTE) 394 printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n", 395 ro->ro_rt); 396 printf("clnp_route: old route refcnt: 0x%x\n", 397 ro->ro_rt->rt_refcnt); 398 ENDDEBUG 399 400 /* free old route entry */ 401 RTFREE(ro->ro_rt); 402 ro->ro_rt = (struct rtentry *)0; 403 } else { 404 IFDEBUG(D_ROUTE) 405 printf("clnp_route: OK route exists\n"); 406 ENDDEBUG 407 } 408 409 if (ro->ro_rt == 0) { 410 /* set up new route structure */ 411 ro_dst->siso_family = AF_ISO; 412 ro_dst->siso_addr = *dst; 413 414 /* allocate new route */ 415 IFDEBUG(D_ROUTE) 416 printf("clnp_route: allocating new route to %s\n", 417 clnp_iso_addrp(dst)); 418 ENDDEBUG 419 rtalloc(ro); 420 } 421 422 if ((ro->ro_rt == 0) || ((*ifp = ro->ro_rt->rt_ifp) == 0)) { 423 return(ENETUNREACH); /* rtalloc failed */ 424 } 425 426 ro->ro_rt->rt_use++; 427 if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) 428 *first_hop = &ro->ro_rt->rt_gateway; 429 else 430 *first_hop = (struct sockaddr *)ro_dst; 431 432 return(0); 433 } 434 435 /* 436 * FUNCTION: clnp_srcroute 437 * 438 * PURPOSE: Source route the datagram. If complete source 439 * routing is specified but not possible, then 440 * return an error. If src routing is terminated, then 441 * try routing on destination. 442 * Usage of first_hop, 443 * ifp, and error return is identical to clnp_route. 444 * 445 * RETURNS: 0 or unix error code 446 * 447 * SIDE EFFECTS: 448 * 449 * NOTES: Remember that option index pointers are really 450 * offsets from the beginning of the mbuf. 451 */ 452 clnp_srcroute(options, oidx, route, first_hop, ifp, final_dst) 453 struct mbuf *options; /* ptr to options */ 454 struct clnp_optidx *oidx; /* index to options */ 455 struct route *route; /* route structure */ 456 struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */ 457 struct ifnet **ifp; /* RETURN: fill in with ptr to interface */ 458 struct iso_addr *final_dst; /* final destination */ 459 { 460 struct iso_addr dst; /* first hop specified by src rt */ 461 int error = 0; /* return code */ 462 463 /* 464 * Check if we have run out of routes 465 * If so, then try to route on destination. 466 */ 467 if CLNPSRCRT_TERM(oidx, options) { 468 dst.isoa_len = final_dst->isoa_len; 469 bcopy((caddr_t)final_dst, (caddr_t)&dst, dst.isoa_len); 470 } else { 471 /* 472 * setup dst based on src rt specified 473 */ 474 dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); 475 bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&dst, dst.isoa_len); 476 } 477 478 /* 479 * try to route it 480 */ 481 error = clnp_route(&dst, route, 0, first_hop, ifp); 482 if (error != 0) 483 return error; 484 485 /* 486 * If complete src rt, first hop must be equal to dst 487 */ 488 if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) && 489 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){ 490 IFDEBUG(D_OPTIONS) 491 printf("clnp_srcroute: complete src route failed\n"); 492 ENDDEBUG 493 return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */ 494 } 495 496 return error; 497 } 498 499 /* 500 * FUNCTION: clnp_srcaddr 501 * 502 * PURPOSE: Build the correct source address for a datagram based on the 503 * outgoing interface and firsthop. The firsthop information 504 * is needed inorder to decide which addr to use if 505 * >1 ISO addr is present for an ifp. 506 * 507 * RETURNS: a ptr to a static copy of the source address. 508 * or NULL 509 * 510 * SIDE EFFECTS: 511 * 512 * NOTES: The ifp must be valid, or we will return NULL 513 */ 514 static struct iso_addr mysrc; 515 struct iso_addr * 516 clnp_srcaddr(ifp, firsthop) 517 struct ifnet *ifp; /* ptr to interface to send packet on */ 518 struct iso_addr *firsthop; /* ptr to first hop for packet */ 519 { 520 register struct iso_ifaddr *ia; /* scan through interface addresses */ 521 struct iso_addr *maybe = NULL; 522 523 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 524 if (ia->ia_ifp == ifp) { 525 struct iso_addr *isoa = &IA_SIS(ia)->siso_addr; 526 527 IFDEBUG(D_ROUTE) 528 printf("clnp_srcaddr: isoa is %s\n", clnp_iso_addrp(isoa)); 529 ENDDEBUG 530 531 if (iso_eqtype(isoa, firsthop)) { 532 mysrc.isoa_len = isoa->isoa_len; 533 bcopy((caddr_t)isoa, (caddr_t)&mysrc, mysrc.isoa_len); 534 return(&mysrc); 535 } else 536 maybe = isoa; 537 } 538 } 539 540 if (maybe != NULL) { 541 mysrc.isoa_len = maybe->isoa_len; 542 bcopy((caddr_t)maybe, (caddr_t)&mysrc, mysrc.isoa_len); 543 return(&mysrc); 544 } else { 545 /* 546 * This will only happen if there are routes involving 547 * an interface that has just had all iso addresses deleted 548 * from it. This will happen if esisd has added a default 549 * route to an interface, and then the interface was 550 * marked down. As soon as esisd tries to send a pdu on that 551 * interface, it will discover it is down, and remove the 552 * route. Nonetheless, there is a window for this discrepancy, 553 * so we will return null here rather than panicing. 554 */ 555 return(NULL); 556 } 557 } 558 559 /* 560 * FUNCTION: clnp_ypocb - backwards bcopy 561 * 562 * PURPOSE: bcopy starting at end of src rather than beginning. 563 * 564 * RETURNS: none 565 * 566 * SIDE EFFECTS: 567 * 568 * NOTES: No attempt has been made to make this efficient 569 */ 570 clnp_ypocb(from, to, len) 571 caddr_t from; /* src buffer */ 572 caddr_t to; /* dst buffer */ 573 u_int len; /* number of bytes */ 574 { 575 while (len--) 576 *(to + len) = *(from + len); 577 } 578 579 /* 580 * FUNCTION: clnp_hdrsize 581 * 582 * PURPOSE: Return the size of a typical clnp hdr. 583 * 584 * RETURNS: Size of hdr in bytes. 585 * 586 * SIDE EFFECTS: 587 * 588 * NOTES: Assumes segmenting subset. If addrlen is 589 * zero, default to largest nsap address size. 590 */ 591 clnp_hdrsize(addrlen) 592 u_char addrlen; /* length of nsap address */ 593 { 594 if (addrlen == 0) 595 addrlen = 20; 596 597 addrlen++; /* length of address byte */ 598 addrlen *= 2; /* src and dst addresses */ 599 addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment); 600 601 return(addrlen); 602 } 603 #endif ISO 604