1/* $NetBSD: clnp_subr.c,v 1.32 2009/03/18 15:14:32 cegger Exp $ */ 2 3/*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)clnp_subr.c 8.1 (Berkeley) 6/10/93 32 */ 33 34/*********************************************************** 35 Copyright IBM Corporation 1987 36 37 All Rights Reserved 38 39Permission to use, copy, modify, and distribute this software and its 40documentation for any purpose and without fee is hereby granted, 41provided that the above copyright notice appear in all copies and that 42both that copyright notice and this permission notice appear in 43supporting documentation, and that the name of IBM not be 44used in advertising or publicity pertaining to distribution of the 45software without specific, written prior permission. 46 47IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 48ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 49IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 50ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 51WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 52ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 53SOFTWARE. 54 55******************************************************************/ 56 57/* 58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 59 */ 60 61#include <sys/cdefs.h> 62__KERNEL_RCSID(0, "$NetBSD: clnp_subr.c,v 1.32 2009/03/18 15:14:32 cegger Exp $"); 63 64#include "opt_iso.h" 65 66#ifdef ISO 67 68#include <sys/param.h> 69#include <sys/mbuf.h> 70#include <sys/domain.h> 71#include <sys/protosw.h> 72#include <sys/socket.h> 73#include <sys/socketvar.h> 74#include <sys/errno.h> 75#include <sys/time.h> 76#include <sys/systm.h> 77 78#include <net/if.h> 79#include <net/route.h> 80#include <net/if_dl.h> 81 82#include <netiso/iso.h> 83#include <netiso/iso_var.h> 84#include <netiso/iso_pcb.h> 85#include <netiso/iso_snpac.h> 86#include <netiso/clnp.h> 87#include <netiso/clnp_stat.h> 88#include <netiso/argo_debug.h> 89#include <netiso/esis.h> 90 91/* 92 * FUNCTION: clnp_data_ck 93 * 94 * PURPOSE: Check that the amount of data in the mbuf chain is 95 * at least as much as the clnp header would have us 96 * expect. Trim mbufs if longer than expected, drop 97 * packet if shorter than expected. 98 * 99 * RETURNS: success - ptr to mbuf chain 100 * failure - 0 101 * 102 * SIDE EFFECTS: 103 * 104 * NOTES: 105 */ 106struct mbuf * 107clnp_data_ck( 108 struct mbuf *m, /* ptr to mbuf chain containing hdr & data */ 109 int length) /* length (in bytes) of packet */ 110{ 111 int len; /* length of data */ 112 struct mbuf *mhead; /* ptr to head of chain */ 113 114 len = -length; 115 mhead = m; 116 for (;;) { 117 len += m->m_len; 118 if (m->m_next == 0) 119 break; 120 m = m->m_next; 121 } 122 if (len != 0) { 123 if (len < 0) { 124 INCSTAT(cns_toosmall); 125 clnp_discard(mhead, GEN_INCOMPLETE); 126 return 0; 127 } 128 if (len <= m->m_len) 129 m->m_len -= len; 130 else 131 m_adj(mhead, -len); 132 } 133 return mhead; 134} 135 136#ifdef notdef 137/* 138 * FUNCTION: clnp_extract_addr 139 * 140 * PURPOSE: Extract the source and destination address from the 141 * supplied buffer. Place them in the supplied address buffers. 142 * If insufficient data is supplied, then fail. 143 * 144 * RETURNS: success - Address of first byte in the packet past 145 * the address part. 146 * failure - 0 147 * 148 * SIDE EFFECTS: 149 * 150 * NOTES: 151 */ 152void * 153clnp_extract_addr( 154 void * bufp, /* ptr to buffer containing addresses */ 155 int buflen, /* length of buffer */ 156 struct iso_addr *srcp, /* ptr to source address buffer */ 157 struct iso_addr *destp) /* ptr to destination address 158 * buffer */ 159{ 160 size_t len; /* argument to memcpy */ 161 162 /* 163 * check that we have enough data. Plus1 is for length octet 164 */ 165 len = (u_char)*bufp++; 166 if (len > buflen) 167 return NULL; 168 destp->isoa_len = len; 169 (void)memcpy(destp, bufp, len); 170 buflen -= len; 171 bufp += len; 172 173 /* 174 * check that we have enough data. Plus1 is for length octet 175 */ 176 len = (u_char)*bufp++; 177 if (len > buflen) 178 return NULL; 179 srcp->isoa_len = len; 180 (void)memcpy(srcp, bufp, len); 181 bufp += len; 182 183 /* 184 * Insure that the addresses make sense 185 */ 186 if (iso_ck_addr(srcp) && iso_ck_addr(destp)) 187 return bufp; 188 else 189 return NULL; 190} 191#endif /* notdef */ 192 193/* 194 * FUNCTION: clnp_ours 195 * 196 * PURPOSE: Decide whether the supplied packet is destined for 197 * us, or that it should be forwarded on. 198 * 199 * RETURNS: packet is for us - 1 200 * packet is not for us - 0 201 * 202 * SIDE EFFECTS: 203 * 204 * NOTES: 205 */ 206int 207clnp_ours( 208 struct iso_addr *dst) /* ptr to destination address */ 209{ 210 struct iso_ifaddr *ia; /* scan through interface addresses */ 211 212 for (ia = iso_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next) { 213#ifdef ARGO_DEBUG 214 if (argo_debug[D_ROUTE]) { 215 printf("clnp_ours: ia_sis %p, dst %p\n", 216 &ia->ia_addr, dst); 217 } 218#endif 219 /* 220 * XXX Warning: 221 * We are overloading siso_tlen in the if's address, as an nsel length. 222 */ 223 if (dst->isoa_len == ia->ia_addr.siso_nlen && 224 memcmp((void *) ia->ia_addr.siso_addr.isoa_genaddr, 225 (void *) dst->isoa_genaddr, 226 ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0) 227 return 1; 228 } 229 return 0; 230} 231 232/* Dec bit set if ifp qlen is greater than congest_threshold */ 233int congest_threshold = 0; 234 235/* 236 * FUNCTION: clnp_forward 237 * 238 * PURPOSE: Forward the datagram passed 239 * clnpintr guarantees that the header will be 240 * contigious (a cluster mbuf will be used if necessary). 241 * 242 * If oidx is NULL, no options are present. 243 * 244 * RETURNS: nothing 245 * 246 * SIDE EFFECTS: 247 * 248 * NOTES: 249 */ 250void 251clnp_forward( 252 struct mbuf *m, /* pkt to forward */ 253 int len, /* length of pkt */ 254 struct iso_addr *dst, /* destination address */ 255 struct clnp_optidx *oidx, /* option index */ 256 int seg_off, /* offset of segmentation part */ 257 struct snpa_hdr *inbound_shp) /* subnetwork header of inbound 258 * packet */ 259{ 260 struct clnp_fixed *clnp; /* ptr to fixed part of header */ 261 int error; /* return value of route function */ 262 const struct sockaddr *next_hop; /* next hop for dgram */ 263 struct ifnet *ifp; /* ptr to outgoing interface */ 264 struct iso_ifaddr *ia = 0; /* ptr to iso name for ifp */ 265 struct route route; /* filled in by clnp_route */ 266 struct rtentry *rt; 267 extern int iso_systype; 268 269 clnp = mtod(m, struct clnp_fixed *); 270 memset((void *) & route, 0, sizeof(route)); /* MUST be done before 271 * "bad:" */ 272 273 /* 274 * Don't forward multicast or broadcast packets 275 */ 276 if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { 277#ifdef ARGO_DEBUG 278 if (argo_debug[D_FORWARD]) { 279 printf("clnp_forward: dropping multicast packet\n"); 280 } 281#endif 282 clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */ 283 clnp_discard(m, 0); 284 INCSTAT(cns_cantforward); 285 goto done; 286 } 287#ifdef ARGO_DEBUG 288 if (argo_debug[D_FORWARD]) { 289 printf("clnp_forward: %d bytes, to %s, options %p\n", len, 290 clnp_iso_addrp(dst), oidx); 291 } 292#endif 293 294 /* 295 * Decrement ttl, and if zero drop datagram 296 * Can't compare ttl as less than zero 'cause its a unsigned 297 */ 298 if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { 299#ifdef ARGO_DEBUG 300 if (argo_debug[D_FORWARD]) { 301 printf("clnp_forward: discarding datagram because ttl is zero\n"); 302 } 303#endif 304 INCSTAT(cns_ttlexpired); 305 clnp_discard(m, TTL_EXPTRANSIT); 306 goto done; 307 } 308 /* 309 * Route packet; special case for source rt 310 */ 311 if CLNPSRCRT_VALID 312 (oidx) { 313 /* 314 * Update src route first 315 */ 316 clnp_update_srcrt(m, oidx); 317 error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst); 318 } else { 319 error = clnp_route(dst, &route, 0, &next_hop, &ia); 320 } 321 if (error || ia == 0) { 322#ifdef ARGO_DEBUG 323 if (argo_debug[D_FORWARD]) { 324 printf("clnp_forward: can't route packet (errno %d)\n", error); 325 } 326#endif 327 clnp_discard(m, ADDR_DESTUNREACH); 328 INCSTAT(cns_cantforward); 329 goto done; 330 } 331 ifp = ia->ia_ifp; 332 333#ifdef ARGO_DEBUG 334 if (argo_debug[D_FORWARD]) { 335 printf("clnp_forward: packet routed to %s\n", 336 clnp_iso_addrp(&satocsiso(next_hop)->siso_addr)); 337 } 338#endif 339 340 INCSTAT(cns_forward); 341 342 /* 343 * If we are an intermediate system and 344 * we are routing outbound on the same ifp that the packet 345 * arrived upon, and we know the next hop snpa, 346 * then generate a redirect request 347 */ 348 if ((iso_systype & SNPA_IS) && (inbound_shp) && 349 (ifp == inbound_shp->snh_ifp)) 350 esis_rdoutput(inbound_shp, m, oidx, dst, rtcache_validate(&route)); 351 /* 352 * If options are present, update them 353 */ 354 if (oidx) { 355 struct iso_addr *mysrc = &ia->ia_addr.siso_addr; 356 if (mysrc == NULL) { 357 clnp_discard(m, ADDR_DESTUNREACH); 358 INCSTAT(cns_cantforward); 359 clnp_stat.cns_forward--; 360 goto done; 361 } else { 362 (void) clnp_dooptions(m, oidx, ifp, mysrc); 363 } 364 } 365#ifdef DECBIT 366 if (ifp->if_snd.ifq_len > congest_threshold) { 367 /* 368 * Congestion! Set the Dec Bit and thank Dave Oran 369 */ 370#ifdef ARGO_DEBUG 371 if (argo_debug[D_FORWARD]) { 372 printf("clnp_forward: congestion experienced\n"); 373 } 374#endif 375 if ((oidx) && (oidx->cni_qos_formatp)) { 376 char * qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp); 377 u_char qos = *qosp; 378#ifdef ARGO_DEBUG 379 if (argo_debug[D_FORWARD]) { 380 printf("clnp_forward: setting congestion bit (qos x%x)\n", qos); 381 } 382#endif 383 if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) { 384 qos |= CLNPOVAL_CONGESTED; 385 INCSTAT(cns_congest_set); 386 *qosp = qos; 387 } 388 } 389 } 390#endif /* DECBIT */ 391 392 /* 393 * Dispatch the datagram if it is small enough, otherwise fragment 394 */ 395 if ((rt = rtcache_validate(&route)) == NULL) 396 ; 397 else if (len <= SN_MTU(ifp, rt)) { 398 iso_gen_csum(m, CLNP_CKSUM_OFF, (int) clnp->cnf_hdr_len); 399 (void) (*ifp->if_output) (ifp, m, next_hop, rt); 400 } else { 401 (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */ 0, rt); 402 } 403 404done: 405 /* 406 * Free route 407 */ 408 rtcache_free(&route); 409} 410 411#ifdef notdef 412/* 413 * FUNCTION: clnp_insert_addr 414 * 415 * PURPOSE: Insert the address part into a clnp datagram. 416 * 417 * RETURNS: Address of first byte after address part in datagram. 418 * 419 * SIDE EFFECTS: 420 * 421 * NOTES: Assume that there is enough space for the address part. 422 */ 423void * 424clnp_insert_addr( 425 void * bufp, /* address of where addr part goes */ 426 struct iso_addr *srcp, /* ptr to src addr */ 427 struct iso_addr *dstp) /* ptr to dst addr */ 428{ 429 *bufp++ = dstp->isoa_len; 430 (void)memcpy(bufp, dstp, dstp->isoa_len); 431 bufp += dstp->isoa_len; 432 433 *bufp++ = srcp->isoa_len; 434 (void)memcpy(bufp, srcp, srcp->isoa_len); 435 bufp += srcp->isoa_len; 436 437 return bufp; 438} 439 440#endif /* notdef */ 441 442/* 443 * FUNCTION: clnp_route 444 * 445 * PURPOSE: Route a clnp datagram to the first hop toward its 446 * destination. In many cases, the first hop will be 447 * the destination. The address of a route 448 * is specified. If a routing entry is present in 449 * that route, and it is still up to the same destination, 450 * then no further action is necessary. Otherwise, a 451 * new routing entry will be allocated. 452 * 453 * RETURNS: route found - 0 454 * unix error code 455 * 456 * SIDE EFFECTS: 457 * 458 * NOTES: It is up to the caller to free the routing entry 459 * allocated in route. 460 */ 461int 462clnp_route( 463 struct iso_addr *dst, /* ptr to datagram destination */ 464 struct route *ro, /* existing route structure */ 465 int flags, /* flags for routing */ 466 const struct sockaddr **first_hop, /* result: fill in with ptr to 467 * firsthop */ 468 struct iso_ifaddr **ifa) /* result: fill in with ptr to ifa */ 469{ 470 struct rtentry *rt; 471 int rc; 472 union { 473 struct sockaddr dst; 474 struct sockaddr_iso dsti; 475 } u; 476 477 if (flags & SO_DONTROUTE) { 478 struct iso_ifaddr *ia; 479 480 if ((rc = sockaddr_iso_init(&u.dsti, dst)) != 0) 481 return rc; 482 rtcache_setdst(ro, &u.dst); 483 484 if (rtcache_getdst(ro) == NULL) 485 return EADDRNOTAVAIL; 486 ia = iso_localifa(satocsiso(rtcache_getdst(ro))); 487 if (ia == NULL) 488 return EADDRNOTAVAIL; 489 if (ifa != NULL) 490 *ifa = ia; 491 if (first_hop != NULL) 492 *first_hop = rtcache_getdst(ro); 493 return 0; 494 } 495 496 /* set up new route structure */ 497 if ((rc = sockaddr_iso_init(&u.dsti, dst)) != 0) 498 return rc; 499 if ((rt = rtcache_lookup(ro, &u.dst)) == NULL) { 500 rtcache_free(ro); 501 return ENETUNREACH; 502 } 503 rt->rt_use++; 504 if (ifa != NULL) 505 if ((*ifa = (struct iso_ifaddr *)rt->rt_ifa) == NULL) 506 panic("clnp_route"); 507 if (first_hop != NULL) { 508 if (rt->rt_flags & RTF_GATEWAY) 509 *first_hop = rt->rt_gateway; 510 else 511 *first_hop = rtcache_getdst(ro); 512 } 513 return 0; 514} 515 516/* 517 * FUNCTION: clnp_srcroute 518 * 519 * PURPOSE: Source route the datagram. If complete source 520 * routing is specified but not possible, then 521 * return an error. If src routing is terminated, then 522 * try routing on destination. 523 * Usage of first_hop, 524 * ifp, and error return is identical to clnp_route. 525 * 526 * RETURNS: 0 or unix error code 527 * 528 * SIDE EFFECTS: 529 * 530 * NOTES: Remember that option index pointers are really 531 * offsets from the beginning of the mbuf. 532 */ 533int 534clnp_srcroute( 535 struct mbuf *options, /* ptr to options */ 536 struct clnp_optidx *oidx, /* index to options */ 537 struct route *ro, /* route structure */ 538 const struct sockaddr **first_hop, /* RETURN: fill in with ptr to 539 * firsthop */ 540 struct iso_ifaddr **ifa, /* RETURN: fill in with ptr to ifa */ 541 struct iso_addr *final_dst) /* final destination */ 542{ 543 struct iso_addr dst; /* first hop specified by src rt */ 544 int error = 0; /* return code */ 545 546 /* 547 * Check if we have run out of routes 548 * If so, then try to route on destination. 549 */ 550 if CLNPSRCRT_TERM 551 (oidx, options) { 552 dst.isoa_len = final_dst->isoa_len; 553 if (sizeof(dst.isoa_genaddr) < (size_t)dst.isoa_len) 554 return EINVAL; 555 (void)memcpy(dst.isoa_genaddr, final_dst->isoa_genaddr, 556 (size_t)dst.isoa_len); 557 } else { 558 /* 559 * setup dst based on src rt specified 560 */ 561 dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); 562 if (sizeof(dst.isoa_genaddr) < (unsigned)dst.isoa_len) 563 return EINVAL; 564 (void)memcpy(dst.isoa_genaddr, CLNPSRCRT_CADDR(oidx, options), 565 (size_t)dst.isoa_len); 566 } 567 568 /* 569 * try to route it 570 */ 571 error = clnp_route(&dst, ro, 0, first_hop, ifa); 572 if (error != 0) 573 return error; 574 575 /* 576 * If complete src rt, first hop must be equal to dst 577 */ 578 if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) && 579 (!iso_addrmatch1(&satocsiso(*first_hop)->siso_addr, &dst))) { 580#ifdef ARGO_DEBUG 581 if (argo_debug[D_OPTIONS]) { 582 printf("clnp_srcroute: complete src route failed\n"); 583 } 584#endif 585 return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */ 586 } 587 return error; 588} 589 590/* 591 * FUNCTION: clnp_echoreply 592 * 593 * PURPOSE: generate an echo reply packet and transmit 594 * 595 * RETURNS: result of clnp_output 596 * 597 * SIDE EFFECTS: 598 */ 599int 600clnp_echoreply( 601 struct mbuf *ec_m, /* echo request */ 602 int ec_len, /* length of ec */ 603 struct sockaddr_iso *ec_src, /* src of ec */ 604 struct sockaddr_iso *ec_dst, /* destination of ec (i.e., us) */ 605 struct clnp_optidx *ec_oidxp) /* options index to ec packet */ 606{ 607 struct isopcb isopcb; 608 int flags = CLNP_NOCACHE | CLNP_ECHOR; 609 int ret; 610 611 /* fill in fake isopcb to pass to output function */ 612 memset(&isopcb, 0, sizeof(isopcb)); 613 isopcb.isop_laddr = ec_dst; 614 isopcb.isop_faddr = ec_src; 615 616 /* 617 * forget copying the options for now. If implemented, need only copy 618 * record route option, but it must be reset to zero length 619 */ 620 621 ret = clnp_output(ec_m, &isopcb, ec_len, flags); 622 623#ifdef ARGO_DEBUG 624 if (argo_debug[D_OUTPUT]) { 625 printf("clnp_echoreply: output returns %d\n", ret); 626 } 627#endif 628 return ret; 629} 630 631/* 632 * FUNCTION: clnp_badmtu 633 * 634 * PURPOSE: print notice of route with mtu not initialized. 635 * 636 * RETURNS: mtu of ifp. 637 * 638 * SIDE EFFECTS: prints notice, slows down system. 639 */ 640int 641clnp_badmtu( 642 struct ifnet *ifp, /* outgoing interface */ 643 struct rtentry *rt, /* dst route */ 644 int line, /* where the dirty deed occurred */ 645 const char *file) /* where the dirty deed occurred */ 646{ 647 printf("sending on route %p with no mtu, line %d of file %s\n", 648 rt, line, file); 649#ifdef ARGO_DEBUG 650 printf("route dst is "); 651 dump_isoaddr(satocsiso(rt_getkey(rt))); 652#endif 653 return ifp->if_mtu; 654} 655 656/* 657 * FUNCTION: clnp_ypocb - backwards bcopy 658 * 659 * PURPOSE: bcopy starting at end of src rather than beginning. 660 * 661 * RETURNS: none 662 * 663 * SIDE EFFECTS: 664 * 665 * NOTES: No attempt has been made to make this efficient 666 */ 667void 668clnp_ypocb( 669 void * from, /* src buffer */ 670 void * to, /* dst buffer */ 671 u_int len) /* number of bytes */ 672{ 673 while (len--) 674 *((char *)to + len) = *((char *)from + len); 675} 676#endif /* ISO */ 677