|
|
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_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */ ! 28: /* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */ ! 29: /* @(#)clnp_output.c 7.8 (Berkeley) 6/4/90 */ ! 30: ! 31: #ifndef lint ! 32: static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $"; ! 33: #endif lint ! 34: ! 35: #include "param.h" ! 36: #include "mbuf.h" ! 37: #include "domain.h" ! 38: #include "protosw.h" ! 39: #include "socket.h" ! 40: #include "socketvar.h" ! 41: #include "errno.h" ! 42: #include "time.h" ! 43: ! 44: #include "../net/if.h" ! 45: #include "../net/route.h" ! 46: ! 47: #include "iso.h" ! 48: #include "iso_var.h" ! 49: #include "iso_pcb.h" ! 50: #include "clnp.h" ! 51: #include "clnp_stat.h" ! 52: #include "argo_debug.h" ! 53: ! 54: static struct clnp_fixed dt_template = { ! 55: ISO8473_CLNP, /* network identifier */ ! 56: 0, /* length */ ! 57: ISO8473_V1, /* version */ ! 58: CLNP_TTL, /* ttl */ ! 59: CLNP_DT|CNF_SEG_OK|CNF_ERR_OK, /* type */ ! 60: 0, /* segment length */ ! 61: 0 /* checksum */ ! 62: }; ! 63: ! 64: static struct clnp_fixed raw_template = { ! 65: ISO8473_CLNP, /* network identifier */ ! 66: 0, /* length */ ! 67: ISO8473_V1, /* version */ ! 68: CLNP_TTL, /* ttl */ ! 69: CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK, /* type */ ! 70: 0, /* segment length */ ! 71: 0 /* checksum */ ! 72: }; ! 73: ! 74: static struct clnp_fixed echo_template = { ! 75: ISO8473_CLNP, /* network identifier */ ! 76: 0, /* length */ ! 77: ISO8473_V1, /* version */ ! 78: CLNP_TTL, /* ttl */ ! 79: CLNP_EC|CNF_SEG_OK|CNF_ERR_OK, /* type */ ! 80: 0, /* segment length */ ! 81: 0 /* checksum */ ! 82: }; ! 83: ! 84: #ifdef DECBIT ! 85: u_char qos_option[] = {CLNPOVAL_QOS, 1, ! 86: CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY}; ! 87: #endif DECBIT ! 88: ! 89: int clnp_id = 0; /* id for segmented dgrams */ ! 90: ! 91: /* ! 92: * FUNCTION: clnp_output ! 93: * ! 94: * PURPOSE: output the data in the mbuf as a clnp datagram ! 95: * ! 96: * The data specified by m0 is sent as a clnp datagram. ! 97: * The mbuf chain m0 will be freed when this routine has ! 98: * returned. ! 99: * ! 100: * If options is non-null, it points to an mbuf which contains ! 101: * options to be sent with the datagram. The options must ! 102: * be formatted in the mbuf according to clnp rules. Options ! 103: * will not be freed. ! 104: * ! 105: * Datalen specifies the length of the data in m0. ! 106: * ! 107: * Src and dst are the addresses for the packet. ! 108: * ! 109: * If route is non-null, it is used as the route for ! 110: * the packet. ! 111: * ! 112: * By default, a DT is sent. However, if flags & CNLP_SEND_ER ! 113: * then an ER will be sent. If flags & CLNP_SEND_RAW, then ! 114: * the packet will be send as raw clnp. ! 115: * ! 116: * RETURNS: 0 success ! 117: * appropriate error code ! 118: * ! 119: * SIDE EFFECTS: none ! 120: * ! 121: * NOTES: ! 122: * Flags are interpretated as follows: ! 123: * CLNP_NO_SEG - do not allow this pkt to be segmented. ! 124: * CLNP_NO_ER - have pkt request ER suppression. ! 125: * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT ! 126: * CLNP_NO_CKSUM - don't compute clnp checksum ! 127: * CLNP_ECHO - send as ECHO packet ! 128: * ! 129: * When checking for a cached packet, clnp checks ! 130: * that the route taken is still up. It does not ! 131: * check that the route is still to the same destination. ! 132: * This means that any entity that alters an existing ! 133: * route for an isopcb (such as when a redirect arrives) ! 134: * must invalidate the clnp cache. It might be perferable ! 135: * to have clnp check that the route has the same dest, but ! 136: * by avoiding this check, we save a call to iso_addrmatch1. ! 137: */ ! 138: clnp_output(m0, isop, datalen, flags) ! 139: struct mbuf *m0; /* data for the packet */ ! 140: struct isopcb *isop; /* iso pcb */ ! 141: int datalen; /* number of bytes of data in m0 */ ! 142: int flags; /* flags */ ! 143: { ! 144: int error = 0; /* return value of function */ ! 145: register struct mbuf *m = m0; /* mbuf for clnp header chain */ ! 146: register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */ ! 147: register caddr_t hoff; /* offset into header */ ! 148: int total_len; /* total length of packet */ ! 149: struct iso_addr *src; /* ptr to source address */ ! 150: struct iso_addr *dst; /* ptr to destination address */ ! 151: struct clnp_cache clc; /* storage for cache information */ ! 152: struct clnp_cache *clcp = NULL; /* ptr to clc */ ! 153: int hdrlen = 0; ! 154: ! 155: dst = &isop->isop_faddr->siso_addr; ! 156: if (isop->isop_laddr == 0) { ! 157: struct iso_ifaddr *ia = 0; ! 158: clnp_route(dst, &isop->isop_route, flags, 0, &ia); ! 159: if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO) ! 160: return (ENETUNREACH); ! 161: src = &ia->ia_addr.siso_addr; ! 162: } else ! 163: src = &isop->isop_laddr->siso_addr; ! 164: ! 165: IFDEBUG(D_OUTPUT) ! 166: printf("clnp_output: to %s", clnp_iso_addrp(dst)); ! 167: printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen); ! 168: printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", ! 169: isop->isop_options, flags, isop->isop_clnpcache); ! 170: ENDDEBUG ! 171: ! 172: if (isop->isop_clnpcache != NULL) { ! 173: clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); ! 174: } ! 175: ! 176: /* ! 177: * Check if cache is valid ... ! 178: */ ! 179: IFDEBUG(D_OUTPUT) ! 180: printf("clnp_output: ck cache: clcp %x\n", clcp); ! 181: if (clcp != NULL) { ! 182: printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst)); ! 183: printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options, ! 184: clcp->clc_options); ! 185: if (isop->isop_route.ro_rt) ! 186: printf("\tro_rt x%x, rt_flags x%x\n", ! 187: isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags); ! 188: printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags); ! 189: printf("\tclc_hdr x%x\n", clcp->clc_hdr); ! 190: } ! 191: ENDDEBUG ! 192: if ((clcp != NULL) && /* cache exists */ ! 193: (isop->isop_options == clcp->clc_options) && /* same options */ ! 194: (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */ ! 195: (isop->isop_route.ro_rt != NULL) && /* route exists */ ! 196: (isop->isop_route.ro_rt == clcp->clc_rt) && /* and is cached */ ! 197: (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */ ! 198: (flags == clcp->clc_flags) && /* same flags */ ! 199: (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */ ! 200: /* ! 201: * The cache is valid ! 202: */ ! 203: ! 204: IFDEBUG(D_OUTPUT) ! 205: printf("clnp_output: using cache\n"); ! 206: ENDDEBUG ! 207: ! 208: m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL); ! 209: if (m == NULL) { ! 210: /* ! 211: * No buffers left to copy cached packet header. Use ! 212: * the cached packet header this time, and ! 213: * mark the hdr as vacant ! 214: */ ! 215: m = clcp->clc_hdr; ! 216: clcp->clc_hdr = NULL; ! 217: } ! 218: m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */ ! 219: clnp = mtod(m, struct clnp_fixed *); ! 220: } else { ! 221: struct clnp_optidx *oidx = NULL; /* index to clnp options */ ! 222: ! 223: /* ! 224: * The cache is not valid. Allocate an mbuf (if necessary) ! 225: * to hold cached info. If one is not available, then ! 226: * don't bother with the cache ! 227: */ ! 228: INCSTAT(cns_cachemiss); ! 229: if (flags & CLNP_NOCACHE) { ! 230: clcp = &clc; ! 231: } else { ! 232: if (isop->isop_clnpcache == NULL) { ! 233: /* ! 234: * There is no clnpcache. Allocate an mbuf to hold one ! 235: */ ! 236: if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER)) ! 237: == NULL) { ! 238: /* ! 239: * No mbufs available. Pretend that we don't want ! 240: * caching this time. ! 241: */ ! 242: IFDEBUG(D_OUTPUT) ! 243: printf("clnp_output: no mbufs to allocate to cache\n"); ! 244: ENDDEBUG ! 245: flags |= CLNP_NOCACHE; ! 246: clcp = &clc; ! 247: } else { ! 248: clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); ! 249: } ! 250: } else { ! 251: /* ! 252: * A clnpcache mbuf exists. If the clc_hdr is not null, ! 253: * we must free it, as a new one is about to be created. ! 254: */ ! 255: clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); ! 256: if (clcp->clc_hdr != NULL) { ! 257: /* ! 258: * The clc_hdr is not null but a clnpcache mbuf exists. ! 259: * This means that there was a cache, but the existing ! 260: * copy of the hdr is no longer valid. Free it now ! 261: * before we lose the pointer to it. ! 262: */ ! 263: IFDEBUG(D_OUTPUT) ! 264: printf("clnp_output: freeing old clc_hdr 0x%x\n", ! 265: clcp->clc_hdr); ! 266: ENDDEBUG ! 267: m_free(clcp->clc_hdr); ! 268: IFDEBUG(D_OUTPUT) ! 269: printf("clnp_output: freed old clc_hdr (done)\n"); ! 270: ENDDEBUG ! 271: } ! 272: } ! 273: } ! 274: IFDEBUG(D_OUTPUT) ! 275: printf("clnp_output: NEW clcp x%x\n",clcp); ! 276: ENDDEBUG ! 277: bzero((caddr_t)clcp, sizeof(struct clnp_cache)); ! 278: ! 279: if (isop->isop_optindex) ! 280: oidx = mtod(isop->isop_optindex, struct clnp_optidx *); ! 281: ! 282: /* ! 283: * Don't allow packets with security, quality of service, ! 284: * priority, or error report options to be sent. ! 285: */ ! 286: if ((isop->isop_options) && (oidx)) { ! 287: if ((oidx->cni_securep) || ! 288: (oidx->cni_priorp) || ! 289: (oidx->cni_qos_formatp) || ! 290: (oidx->cni_er_reason != ER_INVALREAS)) { ! 291: IFDEBUG(D_OUTPUT) ! 292: printf("clnp_output: pkt dropped - option unsupported\n"); ! 293: ENDDEBUG ! 294: m_freem(m0); ! 295: return(EINVAL); ! 296: } ! 297: } ! 298: ! 299: /* ! 300: * Don't allow any invalid flags to be set ! 301: */ ! 302: if ((flags & (CLNP_VFLAGS)) != flags) { ! 303: IFDEBUG(D_OUTPUT) ! 304: printf("clnp_output: packet dropped - flags unsupported\n"); ! 305: ENDDEBUG ! 306: INCSTAT(cns_odropped); ! 307: m_freem(m0); ! 308: return(EINVAL); ! 309: } ! 310: ! 311: /* ! 312: * Don't allow funny lengths on dst; src may be zero in which ! 313: * case we insert the source address based upon the interface ! 314: */ ! 315: if ((src->isoa_len > sizeof(struct iso_addr)) || ! 316: (dst->isoa_len == 0) || ! 317: (dst->isoa_len > sizeof(struct iso_addr))) { ! 318: m_freem(m0); ! 319: INCSTAT(cns_odropped); ! 320: return(ENAMETOOLONG); ! 321: } ! 322: ! 323: /* ! 324: * Grab mbuf to contain header ! 325: */ ! 326: MGETHDR(m, M_DONTWAIT, MT_HEADER); ! 327: if (m == 0) { ! 328: m_freem(m0); ! 329: INCSTAT(cns_odropped); ! 330: return(ENOBUFS); ! 331: } ! 332: INCSTAT(cns_sent); ! 333: m->m_next = m0; ! 334: clnp = mtod(m, struct clnp_fixed *); ! 335: clcp->clc_segoff = 0; ! 336: ! 337: /* ! 338: * Fill in all of fixed hdr except lengths and checksum ! 339: */ ! 340: if (flags & CLNP_SEND_RAW) { ! 341: *clnp = raw_template; ! 342: } else if (flags & CLNP_ECHO) { ! 343: *clnp = echo_template; ! 344: } else { ! 345: *clnp = dt_template; ! 346: } ! 347: if (flags & CLNP_NO_SEG) ! 348: clnp->cnf_type &= ~CNF_SEG_OK; ! 349: if (flags & CLNP_NO_ER) ! 350: clnp->cnf_type &= ~CNF_ERR_OK; ! 351: ! 352: /* ! 353: * Route packet; special case for source rt ! 354: */ ! 355: if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) { ! 356: IFDEBUG(D_OUTPUT) ! 357: printf("clnp_output: calling clnp_srcroute\n"); ! 358: ENDDEBUG ! 359: error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route, ! 360: &clcp->clc_firsthop, &clcp->clc_ifa, dst); ! 361: } else { ! 362: IFDEBUG(D_OUTPUT) ! 363: ENDDEBUG ! 364: error = clnp_route(dst, &isop->isop_route, flags, ! 365: &clcp->clc_firsthop, &clcp->clc_ifa); ! 366: } ! 367: if (error || (clcp->clc_ifa == 0)) { ! 368: IFDEBUG(D_OUTPUT) ! 369: printf("clnp_output: route failed, errno %d\n", error); ! 370: printf("@clcp:\n"); ! 371: dump_buf(clcp, sizeof (struct clnp_cache)); ! 372: ENDDEBUG ! 373: goto bad; ! 374: } ! 375: clcp->clc_rt = isop->isop_route.ro_rt; /* XXX */ ! 376: ! 377: IFDEBUG(D_OUTPUT) ! 378: printf("clnp_output: packet routed to %s\n", ! 379: clnp_iso_addrp( ! 380: &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr)); ! 381: ENDDEBUG ! 382: ! 383: /* ! 384: * If src address is not yet specified, use address of ! 385: * interface. NOTE: this will now update the laddr field in ! 386: * the isopcb. Is this desirable? RAH? ! 387: */ ! 388: if (src->isoa_len == 0) { ! 389: src = &(clcp->clc_ifa->ia_addr.siso_addr); ! 390: IFDEBUG(D_OUTPUT) ! 391: printf("clnp_output: new src %s\n", clnp_iso_addrp(src)); ! 392: ENDDEBUG ! 393: } ! 394: ! 395: /* ! 396: * Insert the source and destination address, ! 397: */ ! 398: hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); ! 399: CLNP_INSERT_ADDR(hoff, *dst); ! 400: CLNP_INSERT_ADDR(hoff, *src); ! 401: ! 402: /* ! 403: * Leave room for the segment part, if segmenting is selected ! 404: */ ! 405: if (clnp->cnf_type & CNF_SEG_OK) { ! 406: clcp->clc_segoff = hoff - (caddr_t)clnp; ! 407: hoff += sizeof(struct clnp_segment); ! 408: } ! 409: ! 410: clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp); ! 411: hdrlen = clnp->cnf_hdr_len; ! 412: ! 413: #ifdef DECBIT ! 414: /* ! 415: * Add the globally unique QOS (with room for congestion experienced ! 416: * bit). I can safely assume that this option is not in the options ! 417: * mbuf below because I checked that the option was not specified ! 418: * previously ! 419: */ ! 420: if ((m->m_len + sizeof(qos_option)) < MLEN) { ! 421: bcopy((caddr_t)qos_option, hoff, sizeof(qos_option)); ! 422: clnp->cnf_hdr_len += sizeof(qos_option); ! 423: hdrlen += sizeof(qos_option); ! 424: m->m_len += sizeof(qos_option); ! 425: } ! 426: #endif DECBIT ! 427: ! 428: /* ! 429: * If an options mbuf is present, concatenate a copy to the hdr mbuf. ! 430: */ ! 431: if (isop->isop_options) { ! 432: struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL); ! 433: if (opt_copy == NULL) { ! 434: error = ENOBUFS; ! 435: goto bad; ! 436: } ! 437: /* Link in place */ ! 438: opt_copy->m_next = m->m_next; ! 439: m->m_next = opt_copy; ! 440: ! 441: /* update size of header */ ! 442: clnp->cnf_hdr_len += opt_copy->m_len; ! 443: hdrlen += opt_copy->m_len; ! 444: } ! 445: ! 446: if (hdrlen > CLNP_HDR_MAX) { ! 447: error = EMSGSIZE; ! 448: goto bad; ! 449: } ! 450: ! 451: /* ! 452: * Now set up the cache entry in the pcb ! 453: */ ! 454: if ((flags & CLNP_NOCACHE) == 0) { ! 455: if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) { ! 456: clcp->clc_dst = *dst; ! 457: clcp->clc_flags = flags; ! 458: clcp->clc_options = isop->isop_options; ! 459: } ! 460: } ! 461: } ! 462: /* ! 463: * If small enough for interface, send directly ! 464: * Fill in segmentation part of hdr if using the full protocol ! 465: */ ! 466: total_len = clnp->cnf_hdr_len + datalen; ! 467: if (clnp->cnf_type & CNF_SEG_OK) { ! 468: struct clnp_segment seg_part; /* segment part of hdr */ ! 469: seg_part.cng_id = htons(clnp_id++); ! 470: seg_part.cng_off = htons(0); ! 471: seg_part.cng_tot_len = htons(total_len); ! 472: (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, ! 473: sizeof(seg_part)); ! 474: } ! 475: if (total_len <= SN_MTU(clcp->clc_ifa->ia_ifp)) { ! 476: HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len); ! 477: m->m_pkthdr.len = total_len; ! 478: /* ! 479: * Compute clnp checksum (on header only) ! 480: */ ! 481: if (flags & CLNP_NO_CKSUM) { ! 482: HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); ! 483: } else { ! 484: iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); ! 485: } ! 486: ! 487: IFDEBUG(D_DUMPOUT) ! 488: struct mbuf *mdump = m; ! 489: printf("clnp_output: sending dg:\n"); ! 490: while (mdump != NULL) { ! 491: dump_buf(mtod(mdump, caddr_t), mdump->m_len); ! 492: mdump = mdump->m_next; ! 493: } ! 494: ENDDEBUG ! 495: ! 496: error = SN_OUTPUT(clcp, m); ! 497: goto done; ! 498: } else { ! 499: /* ! 500: * Too large for interface; fragment if possible. ! 501: */ ! 502: error = clnp_fragment(clcp->clc_ifa->ia_ifp, m, clcp->clc_firsthop, ! 503: total_len, clcp->clc_segoff, flags, clcp->clc_rt); ! 504: goto done; ! 505: } ! 506: bad: ! 507: m_freem(m); ! 508: done: ! 509: if (error) { ! 510: clnp_stat.cns_sent--; ! 511: clnp_stat.cns_odropped++; ! 512: } ! 513: return (error); ! 514: } ! 515: ! 516: int clnp_ctloutput() ! 517: { ! 518: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.