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