|
|
1.1 ! root 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) 6/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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.