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