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.6 (Berkeley) 08/29/89 */ 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_SIS(ia)->siso_addr, 180 dst); 181 ENDDEBUG 182 /* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */ 183 if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst)) 184 return 1; 185 } 186 return 0; 187 } 188 189 /* Dec bit set if ifp qlen is greater than congest_threshold */ 190 int congest_threshold = 0; 191 192 /* 193 * FUNCTION: clnp_forward 194 * 195 * PURPOSE: Forward the datagram passed 196 * clnpintr guarantees that the header will be 197 * contigious (a cluster mbuf will be used if necessary). 198 * 199 * If oidx is NULL, no options are present. 200 * 201 * RETURNS: nothing 202 * 203 * SIDE EFFECTS: 204 * 205 * NOTES: 206 */ 207 clnp_forward(m, len, dst, oidx, seg_off, inbound_shp) 208 struct mbuf *m; /* pkt to forward */ 209 int len; /* length of pkt */ 210 struct iso_addr *dst; /* destination address */ 211 struct clnp_optidx *oidx; /* option index */ 212 int seg_off;/* offset of segmentation part */ 213 struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */ 214 { 215 struct clnp_fixed *clnp; /* ptr to fixed part of header */ 216 int error; /* return value of route function */ 217 struct sockaddr *next_hop; /* next hop for dgram */ 218 struct ifnet *ifp; /* ptr to outgoing interface */ 219 struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */ 220 struct route_iso route; /* filled in by clnp_route */ 221 extern int iso_systype; 222 223 clnp = mtod(m, struct clnp_fixed *); 224 bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */ 225 226 /* 227 * Don't forward multicast or broadcast packets 228 */ 229 if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { 230 IFDEBUG(D_FORWARD) 231 printf("clnp_forward: dropping multicast packet\n"); 232 ENDDEBUG 233 clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */ 234 clnp_discard(m, 0); 235 goto done; 236 } 237 238 IFDEBUG(D_FORWARD) 239 printf("clnp_forward: %d bytes, to %s, options x%x\n", len, 240 clnp_iso_addrp(dst), oidx); 241 ENDDEBUG 242 243 /* 244 * Decrement ttl, and if zero drop datagram 245 * Can't compare ttl as less than zero 'cause its a unsigned 246 */ 247 if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { 248 IFDEBUG(D_FORWARD) 249 printf("clnp_forward: discarding datagram because ttl is zero\n"); 250 ENDDEBUG 251 INCSTAT(cns_ttlexpired); 252 clnp_discard(m, TTL_EXPTRANSIT); 253 goto done; 254 } 255 /* 256 * Route packet; special case for source rt 257 */ 258 if CLNPSRCRT_VALID(oidx) { 259 /* 260 * Update src route first 261 */ 262 clnp_update_srcrt(m, oidx); 263 error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst); 264 } else { 265 error = clnp_route(dst, &route, 0, &next_hop, &ia); 266 } 267 if (error || ia == 0) { 268 IFDEBUG(D_FORWARD) 269 printf("clnp_forward: can't route packet (errno %d)\n", error); 270 ENDDEBUG 271 clnp_discard(m, ADDR_DESTUNREACH); 272 goto done; 273 } 274 ifp = ia->ia_ifp; 275 276 IFDEBUG(D_FORWARD) 277 printf("clnp_forward: packet routed to %s\n", 278 clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr)); 279 ENDDEBUG 280 281 INCSTAT(cns_forward); 282 283 /* 284 * If we are an intermediate system and 285 * we are routing outbound on the same ifp that the packet 286 * arrived upon, and we know the next hop snpa, 287 * then generate a redirect request 288 */ 289 if ((iso_systype & SNPA_IS) && (inbound_shp) && 290 (ifp == inbound_shp->snh_ifp)) { 291 struct snpa_cache *sc; 292 293 sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr); 294 if (sc != NULL) { 295 esis_rdoutput(inbound_shp, m, oidx, dst, sc); 296 } 297 } 298 299 /* 300 * If options are present, update them 301 */ 302 if (oidx) { 303 struct iso_addr *mysrc = &ia->ia_addr.siso_addr; 304 if (mysrc == NULL) { 305 clnp_discard(m, ADDR_DESTUNREACH); 306 goto done; 307 } else { 308 (void) clnp_dooptions(m, oidx, ifp, mysrc); 309 } 310 } 311 312 #ifdef DECBIT 313 if (ifp->if_snd.ifq_len > congest_threshold) { 314 /* 315 * Congestion! Set the Dec Bit and thank Dave Oran 316 */ 317 IFDEBUG(D_FORWARD) 318 printf("clnp_forward: congestion experienced\n"); 319 ENDDEBUG 320 if ((oidx) && (oidx->cni_qos_formatp)) { 321 caddr_t qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp); 322 u_char qos = *qosp; 323 IFDEBUG(D_FORWARD) 324 printf("clnp_forward: setting congestion bit (qos x%x)\n", qos); 325 ENDDEBUG 326 if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) { 327 qos |= CLNPOVAL_CONGESTED; 328 INCSTAT(cns_congest_set); 329 *qosp = qos; 330 } 331 } 332 } 333 #endif DECBIT 334 335 /* 336 * Dispatch the datagram if it is small enough, otherwise fragment 337 */ 338 if (len <= SN_MTU(ifp)) { 339 iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 340 (void) (*ifp->if_output)(ifp, m, next_hop); 341 } else { 342 (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0); 343 } 344 345 done: 346 /* 347 * Free route 348 */ 349 if (route.ro_rt != NULL) { 350 RTFREE(route.ro_rt); 351 } 352 } 353 354 #ifdef ndef 355 /* 356 * FUNCTION: clnp_insert_addr 357 * 358 * PURPOSE: Insert the address part into a clnp datagram. 359 * 360 * RETURNS: Address of first byte after address part in datagram. 361 * 362 * SIDE EFFECTS: 363 * 364 * NOTES: Assume that there is enough space for the address part. 365 */ 366 caddr_t 367 clnp_insert_addr(bufp, srcp, dstp) 368 caddr_t bufp; /* address of where addr part goes */ 369 register struct iso_addr *srcp; /* ptr to src addr */ 370 register struct iso_addr *dstp; /* ptr to dst addr */ 371 { 372 *bufp++ = dstp->isoa_len; 373 (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len); 374 bufp += dstp->isoa_len; 375 376 *bufp++ = srcp->isoa_len; 377 (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len); 378 bufp += srcp->isoa_len; 379 380 return bufp; 381 } 382 383 #endif ndef 384 385 /* 386 * FUNCTION: clnp_route 387 * 388 * PURPOSE: Route a clnp datagram to the first hop toward its 389 * destination. In many cases, the first hop will be 390 * the destination. The address of a route 391 * is specified. If a routing entry is present in 392 * that route, and it is still up to the same destination, 393 * then no further action is necessary. Otherwise, a 394 * new routing entry will be allocated. 395 * 396 * RETURNS: route found - 0 397 * unix error code 398 * 399 * SIDE EFFECTS: 400 * 401 * NOTES: It is up to the caller to free the routing entry 402 * allocated in route. 403 */ 404 clnp_route(dst, ro, flags, first_hop, ifa) 405 struct iso_addr *dst; /* ptr to datagram destination */ 406 register struct route_iso *ro; /* existing route structure */ 407 int flags; /* flags for routing */ 408 struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */ 409 struct iso_ifaddr **ifa; /* result: fill in with ptr to interface */ 410 { 411 if (flags & SO_DONTROUTE) { 412 struct iso_ifaddr *ia; 413 414 if (ro->ro_rt) { 415 RTFREE(ro->ro_rt); 416 ro->ro_rt = 0; 417 } 418 bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); 419 bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr, 420 1 + (unsigned)dst->isoa_len); 421 ro->ro_dst.siso_family = AF_ISO; 422 ro->ro_dst.siso_len = sizeof(ro->ro_dst); 423 ia = iso_localifa(&ro->ro_dst); 424 if (ia == 0) 425 return EADDRNOTAVAIL; 426 if (ifa) 427 *ifa = ia; 428 if (first_hop) 429 *first_hop = (struct sockaddr *)&ro->ro_dst; 430 return 0; 431 } 432 /* 433 * If there is a cached route, check that it is still up and to 434 * the same destination. If not, free it and try again. 435 */ 436 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 437 (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) { 438 IFDEBUG(D_ROUTE) 439 printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n", 440 ro->ro_rt); 441 printf("clnp_route: old route refcnt: 0x%x\n", 442 ro->ro_rt->rt_refcnt); 443 ENDDEBUG 444 445 /* free old route entry */ 446 RTFREE(ro->ro_rt); 447 ro->ro_rt = (struct rtentry *)0; 448 } else { 449 IFDEBUG(D_ROUTE) 450 printf("clnp_route: OK route exists\n"); 451 ENDDEBUG 452 } 453 454 if (ro->ro_rt == 0) { 455 /* set up new route structure */ 456 bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); 457 ro->ro_dst.siso_len = sizeof(ro->ro_dst); 458 ro->ro_dst.siso_family = AF_ISO; 459 Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len); 460 /* allocate new route */ 461 IFDEBUG(D_ROUTE) 462 printf("clnp_route: allocating new route to %s\n", 463 clnp_iso_addrp(dst)); 464 ENDDEBUG 465 rtalloc((struct route *)ro); 466 } 467 if (ro->ro_rt == 0) 468 return(ENETUNREACH); /* rtalloc failed */ 469 ro->ro_rt->rt_use++; 470 if (ifa) 471 if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0) 472 panic("clnp_route"); 473 if (first_hop) { 474 if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) 475 *first_hop = ro->ro_rt->rt_gateway; 476 else 477 *first_hop = (struct sockaddr *)&ro->ro_dst; 478 } 479 return(0); 480 } 481 482 /* 483 * FUNCTION: clnp_srcroute 484 * 485 * PURPOSE: Source route the datagram. If complete source 486 * routing is specified but not possible, then 487 * return an error. If src routing is terminated, then 488 * try routing on destination. 489 * Usage of first_hop, 490 * ifp, and error return is identical to clnp_route. 491 * 492 * RETURNS: 0 or unix error code 493 * 494 * SIDE EFFECTS: 495 * 496 * NOTES: Remember that option index pointers are really 497 * offsets from the beginning of the mbuf. 498 */ 499 clnp_srcroute(options, oidx, route, first_hop, ifa, final_dst) 500 struct mbuf *options; /* ptr to options */ 501 struct clnp_optidx *oidx; /* index to options */ 502 struct route_iso *route; /* route structure */ 503 struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */ 504 struct iso_ifaddr **ifa; /* RETURN: fill in with ptr to interface */ 505 struct iso_addr *final_dst; /* final destination */ 506 { 507 struct iso_addr dst; /* first hop specified by src rt */ 508 int error = 0; /* return code */ 509 510 /* 511 * Check if we have run out of routes 512 * If so, then try to route on destination. 513 */ 514 if CLNPSRCRT_TERM(oidx, options) { 515 dst.isoa_len = final_dst->isoa_len; 516 bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len); 517 } else { 518 /* 519 * setup dst based on src rt specified 520 */ 521 dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); 522 bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len); 523 } 524 525 /* 526 * try to route it 527 */ 528 error = clnp_route(&dst, route, 0, first_hop, ifa); 529 if (error != 0) 530 return error; 531 532 /* 533 * If complete src rt, first hop must be equal to dst 534 */ 535 if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) && 536 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){ 537 IFDEBUG(D_OPTIONS) 538 printf("clnp_srcroute: complete src route failed\n"); 539 ENDDEBUG 540 return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */ 541 } 542 543 return error; 544 } 545 546 /* 547 * FUNCTION: clnp_ypocb - backwards bcopy 548 * 549 * PURPOSE: bcopy starting at end of src rather than beginning. 550 * 551 * RETURNS: none 552 * 553 * SIDE EFFECTS: 554 * 555 * NOTES: No attempt has been made to make this efficient 556 */ 557 clnp_ypocb(from, to, len) 558 caddr_t from; /* src buffer */ 559 caddr_t to; /* dst buffer */ 560 u_int len; /* number of bytes */ 561 { 562 while (len--) 563 *(to + len) = *(from + len); 564 } 565 566 /* 567 * FUNCTION: clnp_hdrsize 568 * 569 * PURPOSE: Return the size of a typical clnp hdr. 570 * 571 * RETURNS: Size of hdr in bytes. 572 * 573 * SIDE EFFECTS: 574 * 575 * NOTES: Assumes segmenting subset. If addrlen is 576 * zero, default to largest nsap address size. 577 */ 578 clnp_hdrsize(addrlen) 579 u_char addrlen; /* length of nsap address */ 580 { 581 if (addrlen == 0) 582 addrlen = 20; 583 584 addrlen++; /* length of address byte */ 585 addrlen *= 2; /* src and dst addresses */ 586 addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment); 587 588 return(addrlen); 589 } 590 #endif ISO 591