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