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