1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)clnp_subr.c 7.14 (Berkeley) 02/14/92 8 */ 9 10 /*********************************************************** 11 Copyright IBM Corporation 1987 12 13 All Rights Reserved 14 15 Permission to use, copy, modify, and distribute this software and its 16 documentation for any purpose and without fee is hereby granted, 17 provided that the above copyright notice appear in all copies and that 18 both that copyright notice and this permission notice appear in 19 supporting documentation, and that the name of IBM not be 20 used in advertising or publicity pertaining to distribution of the 21 software without specific, written prior permission. 22 23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 29 SOFTWARE. 30 31 ******************************************************************/ 32 33 /* 34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 35 */ 36 /* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */ 37 /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */ 38 39 #ifdef ISO 40 41 #include "types.h" 42 #include "param.h" 43 #include "mbuf.h" 44 #include "domain.h" 45 #include "protosw.h" 46 #include "socket.h" 47 #include "socketvar.h" 48 #include "errno.h" 49 #include "time.h" 50 51 #include "../net/if.h" 52 #include "../net/route.h" 53 #include "../net/if_dl.h" 54 55 #include "iso.h" 56 #include "iso_var.h" 57 #include "iso_pcb.h" 58 #include "iso_snpac.h" 59 #include "clnp.h" 60 #include "clnp_stat.h" 61 #include "argo_debug.h" 62 63 /* 64 * FUNCTION: clnp_data_ck 65 * 66 * PURPOSE: Check that the amount of data in the mbuf chain is 67 * at least as much as the clnp header would have us 68 * expect. Trim mbufs if longer than expected, drop 69 * packet if shorter than expected. 70 * 71 * RETURNS: success - ptr to mbuf chain 72 * failure - 0 73 * 74 * SIDE EFFECTS: 75 * 76 * NOTES: 77 */ 78 struct mbuf * 79 clnp_data_ck(m, length) 80 register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */ 81 int length; /* length (in bytes) of packet */ 82 { 83 register int len; /* length of data */ 84 register struct mbuf *mhead; /* ptr to head of chain */ 85 86 len = -length; 87 mhead = m; 88 for (;;) { 89 len += m->m_len; 90 if (m->m_next == 0) 91 break; 92 m = m->m_next; 93 } 94 if (len != 0) { 95 if (len < 0) { 96 INCSTAT(cns_toosmall); 97 clnp_discard(mhead, GEN_INCOMPLETE); 98 return 0; 99 } 100 if (len <= m->m_len) 101 m->m_len -= len; 102 else 103 m_adj(mhead, -len); 104 } 105 return mhead; 106 } 107 108 #ifdef notdef 109 /* 110 * FUNCTION: clnp_extract_addr 111 * 112 * PURPOSE: Extract the source and destination address from the 113 * supplied buffer. Place them in the supplied address buffers. 114 * If insufficient data is supplied, then fail. 115 * 116 * RETURNS: success - Address of first byte in the packet past 117 * the address part. 118 * failure - 0 119 * 120 * SIDE EFFECTS: 121 * 122 * NOTES: 123 */ 124 caddr_t 125 clnp_extract_addr(bufp, buflen, srcp, destp) 126 caddr_t bufp; /* ptr to buffer containing addresses */ 127 int buflen; /* length of buffer */ 128 register struct iso_addr *srcp; /* ptr to source address buffer */ 129 register struct iso_addr *destp; /* ptr to destination address buffer */ 130 { 131 int len; /* argument to bcopy */ 132 133 /* 134 * check that we have enough data. Plus1 is for length octet 135 */ 136 if ((u_char)*bufp + 1 > buflen) { 137 return((caddr_t)0); 138 } 139 len = destp->isoa_len = (u_char)*bufp++; 140 (void) bcopy(bufp, (caddr_t)destp, len); 141 buflen -= len; 142 bufp += len; 143 144 /* 145 * check that we have enough data. Plus1 is for length octet 146 */ 147 if ((u_char)*bufp + 1 > buflen) { 148 return((caddr_t)0); 149 } 150 len = srcp->isoa_len = (u_char)* bufp++; 151 (void) bcopy(bufp, (caddr_t)srcp, len); 152 bufp += len; 153 154 /* 155 * Insure that the addresses make sense 156 */ 157 if (iso_ck_addr(srcp) && iso_ck_addr(destp)) 158 return bufp; 159 else 160 return (caddr_t) 0; 161 } 162 #endif notdef 163 164 /* 165 * FUNCTION: clnp_ours 166 * 167 * PURPOSE: Decide whether the supplied packet is destined for 168 * us, or that it should be forwarded on. 169 * 170 * RETURNS: packet is for us - 1 171 * packet is not for us - 0 172 * 173 * SIDE EFFECTS: 174 * 175 * NOTES: 176 */ 177 clnp_ours(dst) 178 register struct iso_addr *dst; /* ptr to destination address */ 179 { 180 register struct iso_ifaddr *ia; /* scan through interface addresses */ 181 182 for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 183 IFDEBUG(D_ROUTE) 184 printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr, 185 dst); 186 ENDDEBUG 187 /* 188 * XXX Warning: 189 * We are overloading siso_tlen in the if's address, as an nsel length. 190 */ 191 if (dst->isoa_len == ia->ia_addr.siso_nlen && 192 bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr, 193 (caddr_t)dst->isoa_genaddr, 194 ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0) 195 return 1; 196 } 197 return 0; 198 } 199 200 /* Dec bit set if ifp qlen is greater than congest_threshold */ 201 int congest_threshold = 0; 202 203 /* 204 * FUNCTION: clnp_forward 205 * 206 * PURPOSE: Forward the datagram passed 207 * clnpintr guarantees that the header will be 208 * contigious (a cluster mbuf will be used if necessary). 209 * 210 * If oidx is NULL, no options are present. 211 * 212 * RETURNS: nothing 213 * 214 * SIDE EFFECTS: 215 * 216 * NOTES: 217 */ 218 clnp_forward(m, len, dst, oidx, seg_off, inbound_shp) 219 struct mbuf *m; /* pkt to forward */ 220 int len; /* length of pkt */ 221 struct iso_addr *dst; /* destination address */ 222 struct clnp_optidx *oidx; /* option index */ 223 int seg_off;/* offset of segmentation part */ 224 struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */ 225 { 226 struct clnp_fixed *clnp; /* ptr to fixed part of header */ 227 int error; /* return value of route function */ 228 struct sockaddr *next_hop; /* next hop for dgram */ 229 struct ifnet *ifp; /* ptr to outgoing interface */ 230 struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */ 231 struct route_iso route; /* filled in by clnp_route */ 232 extern int iso_systype; 233 234 clnp = mtod(m, struct clnp_fixed *); 235 bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */ 236 237 /* 238 * Don't forward multicast or broadcast packets 239 */ 240 if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { 241 IFDEBUG(D_FORWARD) 242 printf("clnp_forward: dropping multicast packet\n"); 243 ENDDEBUG 244 clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */ 245 clnp_discard(m, 0); 246 INCSTAT(cns_cantforward); 247 goto done; 248 } 249 250 IFDEBUG(D_FORWARD) 251 printf("clnp_forward: %d bytes, to %s, options x%x\n", len, 252 clnp_iso_addrp(dst), oidx); 253 ENDDEBUG 254 255 /* 256 * Decrement ttl, and if zero drop datagram 257 * Can't compare ttl as less than zero 'cause its a unsigned 258 */ 259 if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { 260 IFDEBUG(D_FORWARD) 261 printf("clnp_forward: discarding datagram because ttl is zero\n"); 262 ENDDEBUG 263 INCSTAT(cns_ttlexpired); 264 clnp_discard(m, TTL_EXPTRANSIT); 265 goto done; 266 } 267 /* 268 * Route packet; special case for source rt 269 */ 270 if CLNPSRCRT_VALID(oidx) { 271 /* 272 * Update src route first 273 */ 274 clnp_update_srcrt(m, oidx); 275 error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst); 276 } else { 277 error = clnp_route(dst, &route, 0, &next_hop, &ia); 278 } 279 if (error || ia == 0) { 280 IFDEBUG(D_FORWARD) 281 printf("clnp_forward: can't route packet (errno %d)\n", error); 282 ENDDEBUG 283 clnp_discard(m, ADDR_DESTUNREACH); 284 INCSTAT(cns_cantforward); 285 goto done; 286 } 287 ifp = ia->ia_ifp; 288 289 IFDEBUG(D_FORWARD) 290 printf("clnp_forward: packet routed to %s\n", 291 clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr)); 292 ENDDEBUG 293 294 INCSTAT(cns_forward); 295 296 /* 297 * If we are an intermediate system and 298 * we are routing outbound on the same ifp that the packet 299 * arrived upon, and we know the next hop snpa, 300 * then generate a redirect request 301 */ 302 if ((iso_systype & SNPA_IS) && (inbound_shp) && 303 (ifp == inbound_shp->snh_ifp)) 304 esis_rdoutput(inbound_shp, m, oidx, dst, route.ro_rt); 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, route.ro_rt)) { 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 notdef 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 notdef 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, ro, first_hop, ifa, final_dst) 508 struct mbuf *options; /* ptr to options */ 509 struct clnp_optidx *oidx; /* index to options */ 510 struct route_iso *ro; /* 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, ro, 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_echoreply 556 * 557 * PURPOSE: generate an echo reply packet and transmit 558 * 559 * RETURNS: result of clnp_output 560 * 561 * SIDE EFFECTS: 562 */ 563 clnp_echoreply(ec_m, ec_len, ec_src, ec_dst, ec_oidxp) 564 struct mbuf *ec_m; /* echo request */ 565 int ec_len; /* length of ec */ 566 struct sockaddr_iso *ec_src; /* src of ec */ 567 struct sockaddr_iso *ec_dst; /* destination of ec (i.e., us) */ 568 struct clnp_optidx *ec_oidxp; /* options index to ec packet */ 569 { 570 struct isopcb isopcb; 571 int flags = CLNP_NOCACHE|CLNP_ECHOR; 572 int ret; 573 574 /* fill in fake isopcb to pass to output function */ 575 bzero(&isopcb, sizeof(isopcb)); 576 isopcb.isop_laddr = ec_dst; 577 isopcb.isop_faddr = ec_src; 578 579 /* forget copying the options for now. If implemented, need only 580 * copy record route option, but it must be reset to zero length */ 581 582 ret = clnp_output(ec_m, &isopcb, ec_len, flags); 583 584 IFDEBUG(D_OUTPUT) 585 printf("clnp_echoreply: output returns %d\n", ret); 586 ENDDEBUG 587 return ret; 588 } 589 590 /* 591 * FUNCTION: clnp_badmtu 592 * 593 * PURPOSE: print notice of route with mtu not initialized. 594 * 595 * RETURNS: mtu of ifp. 596 * 597 * SIDE EFFECTS: prints notice, slows down system. 598 */ 599 clnp_badmtu(ifp, rt, line, file) 600 struct ifnet *ifp; /* outgoing interface */ 601 struct rtentry *rt; /* dst route */ 602 int line; /* where the dirty deed occured */ 603 char *file; /* where the dirty deed occured */ 604 { 605 printf("sending on route %x with no mtu, line %s of file %s\n", 606 rt, line, file); 607 #ifdef ARGO_DEBUG 608 printf("route dst is"); 609 dump_isoaddr(rt_key(rt)); 610 #endif 611 return ifp->if_mtu; 612 } 613 614 /* 615 * FUNCTION: clnp_ypocb - backwards bcopy 616 * 617 * PURPOSE: bcopy starting at end of src rather than beginning. 618 * 619 * RETURNS: none 620 * 621 * SIDE EFFECTS: 622 * 623 * NOTES: No attempt has been made to make this efficient 624 */ 625 clnp_ypocb(from, to, len) 626 caddr_t from; /* src buffer */ 627 caddr_t to; /* dst buffer */ 628 u_int len; /* number of bytes */ 629 { 630 while (len--) 631 *(to + len) = *(from + len); 632 } 633 #endif ISO 634