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