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