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