136375Ssklower /*********************************************************** 236375Ssklower Copyright IBM Corporation 1987 336375Ssklower 436375Ssklower All Rights Reserved 536375Ssklower 636375Ssklower Permission to use, copy, modify, and distribute this software and its 736375Ssklower documentation for any purpose and without fee is hereby granted, 836375Ssklower provided that the above copyright notice appear in all copies and that 936375Ssklower both that copyright notice and this permission notice appear in 1036375Ssklower supporting documentation, and that the name of IBM not be 1136375Ssklower used in advertising or publicity pertaining to distribution of the 1236375Ssklower software without specific, written prior permission. 1336375Ssklower 1436375Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536375Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636375Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736375Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836375Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936375Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036375Ssklower SOFTWARE. 2136375Ssklower 2236375Ssklower ******************************************************************/ 2336375Ssklower 2436375Ssklower /* 2536375Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636375Ssklower */ 2736770Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */ 2836770Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */ 29*39198Ssklower /* @(#)clnp_subr.c 7.7 (Berkeley) 09/22/89 */ 3036375Ssklower 3136375Ssklower #ifndef lint 3236770Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $"; 3336375Ssklower #endif lint 3436375Ssklower 3536375Ssklower #ifdef ISO 3636375Ssklower 3737469Ssklower #include "types.h" 3837469Ssklower #include "param.h" 3937469Ssklower #include "mbuf.h" 4037469Ssklower #include "domain.h" 4137469Ssklower #include "protosw.h" 4237469Ssklower #include "socket.h" 4337469Ssklower #include "socketvar.h" 4437469Ssklower #include "errno.h" 4537469Ssklower #include "time.h" 4636375Ssklower 4736375Ssklower #include "../net/if.h" 4836375Ssklower #include "../net/route.h" 4936375Ssklower 5037469Ssklower #include "iso.h" 5137469Ssklower #include "iso_var.h" 5237469Ssklower #include "iso_pcb.h" 5337469Ssklower #include "iso_snpac.h" 5437469Ssklower #include "clnp.h" 5537469Ssklower #include "clnp_stat.h" 5637469Ssklower #include "argo_debug.h" 5736375Ssklower 5836375Ssklower /* 5936375Ssklower * FUNCTION: clnp_data_ck 6036375Ssklower * 6136375Ssklower * PURPOSE: Check that the amount of data in the mbuf chain is 6236375Ssklower * at least as much as the clnp header would have us 6336375Ssklower * expect. Trim mbufs if longer than expected, drop 6436375Ssklower * packet if shorter than expected. 6536375Ssklower * 6636375Ssklower * RETURNS: success - ptr to mbuf chain 6736375Ssklower * failure - 0 6836375Ssklower * 6936375Ssklower * SIDE EFFECTS: 7036375Ssklower * 7136375Ssklower * NOTES: 7236375Ssklower */ 7336375Ssklower struct mbuf * 7436375Ssklower clnp_data_ck(m, length) 7536375Ssklower register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */ 7636375Ssklower int length; /* length (in bytes) of packet */ 7736375Ssklower { 7836375Ssklower register int len; /* length of data */ 7936375Ssklower register struct mbuf *mhead; /* ptr to head of chain */ 8036375Ssklower 8136375Ssklower len = -length; 8236375Ssklower mhead = m; 8336375Ssklower for (;;) { 8436375Ssklower len += m->m_len; 8536375Ssklower if (m->m_next == 0) 8636375Ssklower break; 8736375Ssklower m = m->m_next; 8836375Ssklower } 8936375Ssklower if (len != 0) { 9036375Ssklower if (len < 0) { 9136375Ssklower INCSTAT(cns_toosmall); 9236375Ssklower clnp_discard(mhead, GEN_INCOMPLETE); 9336375Ssklower return 0; 9436375Ssklower } 9536375Ssklower if (len <= m->m_len) 9636375Ssklower m->m_len -= len; 9736375Ssklower else 9836375Ssklower m_adj(mhead, -len); 9936375Ssklower } 10036375Ssklower return mhead; 10136375Ssklower } 10236375Ssklower 10336375Ssklower #ifdef ndef 10436375Ssklower /* 10536375Ssklower * FUNCTION: clnp_extract_addr 10636375Ssklower * 10736375Ssklower * PURPOSE: Extract the source and destination address from the 10836375Ssklower * supplied buffer. Place them in the supplied address buffers. 10936375Ssklower * If insufficient data is supplied, then fail. 11036375Ssklower * 11136375Ssklower * RETURNS: success - Address of first byte in the packet past 11236375Ssklower * the address part. 11336375Ssklower * failure - 0 11436375Ssklower * 11536375Ssklower * SIDE EFFECTS: 11636375Ssklower * 11736375Ssklower * NOTES: 11836375Ssklower */ 11936375Ssklower caddr_t 12036375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp) 12136375Ssklower caddr_t bufp; /* ptr to buffer containing addresses */ 12236375Ssklower int buflen; /* length of buffer */ 12336375Ssklower register struct iso_addr *srcp; /* ptr to source address buffer */ 12436375Ssklower register struct iso_addr *destp; /* ptr to destination address buffer */ 12536375Ssklower { 12636375Ssklower int len; /* argument to bcopy */ 12736375Ssklower 12836375Ssklower /* 12936375Ssklower * check that we have enough data. Plus1 is for length octet 13036375Ssklower */ 13136375Ssklower if ((u_char)*bufp + 1 > buflen) { 13236375Ssklower return((caddr_t)0); 13336375Ssklower } 13436375Ssklower len = destp->isoa_len = (u_char)*bufp++; 13536375Ssklower (void) bcopy(bufp, (caddr_t)destp, len); 13636375Ssklower buflen -= len; 13736375Ssklower bufp += len; 13836375Ssklower 13936375Ssklower /* 14036375Ssklower * check that we have enough data. Plus1 is for length octet 14136375Ssklower */ 14236375Ssklower if ((u_char)*bufp + 1 > buflen) { 14336375Ssklower return((caddr_t)0); 14436375Ssklower } 14536375Ssklower len = srcp->isoa_len = (u_char)* bufp++; 14636375Ssklower (void) bcopy(bufp, (caddr_t)srcp, len); 14736375Ssklower bufp += len; 14836375Ssklower 14936375Ssklower /* 15036375Ssklower * Insure that the addresses make sense 15136375Ssklower */ 15236375Ssklower if (iso_ck_addr(srcp) && iso_ck_addr(destp)) 15336375Ssklower return bufp; 15436375Ssklower else 15536375Ssklower return (caddr_t) 0; 15636375Ssklower } 15736375Ssklower #endif ndef 15836375Ssklower 15936375Ssklower /* 16036375Ssklower * FUNCTION: clnp_ours 16136375Ssklower * 16236375Ssklower * PURPOSE: Decide whether the supplied packet is destined for 16336375Ssklower * us, or that it should be forwarded on. 16436375Ssklower * 16536375Ssklower * RETURNS: packet is for us - 1 16636375Ssklower * packet is not for us - 0 16736375Ssklower * 16836375Ssklower * SIDE EFFECTS: 16936375Ssklower * 17036375Ssklower * NOTES: 17136375Ssklower */ 17236375Ssklower clnp_ours(dst) 17336375Ssklower register struct iso_addr *dst; /* ptr to destination address */ 17436375Ssklower { 17536375Ssklower register struct iso_ifaddr *ia; /* scan through interface addresses */ 17636375Ssklower 17736375Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) { 17836375Ssklower IFDEBUG(D_ROUTE) 17936375Ssklower printf("clnp_ours: ia_sis x%x, dst x%x\n", &IA_SIS(ia)->siso_addr, 18036375Ssklower dst); 18136375Ssklower ENDDEBUG 18236375Ssklower /* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */ 18336375Ssklower if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst)) 18436375Ssklower return 1; 18536375Ssklower } 18636375Ssklower return 0; 18736375Ssklower } 18836375Ssklower 18936770Ssklower /* Dec bit set if ifp qlen is greater than congest_threshold */ 19036770Ssklower int congest_threshold = 0; 19136770Ssklower 19236375Ssklower /* 19336375Ssklower * FUNCTION: clnp_forward 19436375Ssklower * 19536375Ssklower * PURPOSE: Forward the datagram passed 19636375Ssklower * clnpintr guarantees that the header will be 19736375Ssklower * contigious (a cluster mbuf will be used if necessary). 19836375Ssklower * 19936375Ssklower * If oidx is NULL, no options are present. 20036375Ssklower * 20136375Ssklower * RETURNS: nothing 20236375Ssklower * 20336375Ssklower * SIDE EFFECTS: 20436375Ssklower * 20536375Ssklower * NOTES: 20636375Ssklower */ 20736375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp) 20836375Ssklower struct mbuf *m; /* pkt to forward */ 20936375Ssklower int len; /* length of pkt */ 21036375Ssklower struct iso_addr *dst; /* destination address */ 21136375Ssklower struct clnp_optidx *oidx; /* option index */ 21236375Ssklower int seg_off;/* offset of segmentation part */ 21336375Ssklower struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */ 21436375Ssklower { 21536375Ssklower struct clnp_fixed *clnp; /* ptr to fixed part of header */ 21636375Ssklower int error; /* return value of route function */ 21736375Ssklower struct sockaddr *next_hop; /* next hop for dgram */ 21836375Ssklower struct ifnet *ifp; /* ptr to outgoing interface */ 21937469Ssklower struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */ 22036769Ssklower struct route_iso route; /* filled in by clnp_route */ 22136375Ssklower extern int iso_systype; 22236375Ssklower 22336375Ssklower clnp = mtod(m, struct clnp_fixed *); 22436375Ssklower bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */ 22536375Ssklower 22636375Ssklower /* 22736375Ssklower * Don't forward multicast or broadcast packets 22836375Ssklower */ 22936375Ssklower if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { 23036375Ssklower IFDEBUG(D_FORWARD) 23136375Ssklower printf("clnp_forward: dropping multicast packet\n"); 23236375Ssklower ENDDEBUG 23337469Ssklower clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */ 23436375Ssklower clnp_discard(m, 0); 235*39198Ssklower INCSTAT(cns_cantforward); 23636375Ssklower goto done; 23736375Ssklower } 23836375Ssklower 23936375Ssklower IFDEBUG(D_FORWARD) 24036375Ssklower printf("clnp_forward: %d bytes, to %s, options x%x\n", len, 24136375Ssklower clnp_iso_addrp(dst), oidx); 24236375Ssklower ENDDEBUG 24336375Ssklower 24436375Ssklower /* 24536375Ssklower * Decrement ttl, and if zero drop datagram 24636375Ssklower * Can't compare ttl as less than zero 'cause its a unsigned 24736375Ssklower */ 24836375Ssklower if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { 24936375Ssklower IFDEBUG(D_FORWARD) 25036375Ssklower printf("clnp_forward: discarding datagram because ttl is zero\n"); 25136375Ssklower ENDDEBUG 25236375Ssklower INCSTAT(cns_ttlexpired); 25336375Ssklower clnp_discard(m, TTL_EXPTRANSIT); 25436375Ssklower goto done; 25536375Ssklower } 25636375Ssklower /* 25736375Ssklower * Route packet; special case for source rt 25836375Ssklower */ 25936375Ssklower if CLNPSRCRT_VALID(oidx) { 26036375Ssklower /* 26136375Ssklower * Update src route first 26236375Ssklower */ 26336375Ssklower clnp_update_srcrt(m, oidx); 26437469Ssklower error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst); 26536375Ssklower } else { 26637469Ssklower error = clnp_route(dst, &route, 0, &next_hop, &ia); 26736375Ssklower } 26837469Ssklower if (error || ia == 0) { 26936375Ssklower IFDEBUG(D_FORWARD) 27036375Ssklower printf("clnp_forward: can't route packet (errno %d)\n", error); 27136375Ssklower ENDDEBUG 27236375Ssklower clnp_discard(m, ADDR_DESTUNREACH); 273*39198Ssklower INCSTAT(cns_cantforward); 27436375Ssklower goto done; 27536375Ssklower } 27637469Ssklower ifp = ia->ia_ifp; 27736375Ssklower 27836375Ssklower IFDEBUG(D_FORWARD) 27936375Ssklower printf("clnp_forward: packet routed to %s\n", 28036375Ssklower clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr)); 28136375Ssklower ENDDEBUG 28236375Ssklower 28336375Ssklower INCSTAT(cns_forward); 28436375Ssklower 28536375Ssklower /* 28636375Ssklower * If we are an intermediate system and 28736375Ssklower * we are routing outbound on the same ifp that the packet 28836375Ssklower * arrived upon, and we know the next hop snpa, 28936375Ssklower * then generate a redirect request 29036375Ssklower */ 29136375Ssklower if ((iso_systype & SNPA_IS) && (inbound_shp) && 29236375Ssklower (ifp == inbound_shp->snh_ifp)) { 29336375Ssklower struct snpa_cache *sc; 29436375Ssklower 29536375Ssklower sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr); 29636375Ssklower if (sc != NULL) { 29736375Ssklower esis_rdoutput(inbound_shp, m, oidx, dst, sc); 29836375Ssklower } 29936375Ssklower } 30036375Ssklower 30136375Ssklower /* 30236375Ssklower * If options are present, update them 30336375Ssklower */ 30436375Ssklower if (oidx) { 30537469Ssklower struct iso_addr *mysrc = &ia->ia_addr.siso_addr; 30636375Ssklower if (mysrc == NULL) { 30736375Ssklower clnp_discard(m, ADDR_DESTUNREACH); 308*39198Ssklower INCSTAT(cns_cantforward); 309*39198Ssklower clnp_stat.cns_forward--; 31036375Ssklower goto done; 31136375Ssklower } else { 31236770Ssklower (void) clnp_dooptions(m, oidx, ifp, mysrc); 31336375Ssklower } 31436375Ssklower } 31536770Ssklower 31636770Ssklower #ifdef DECBIT 31736770Ssklower if (ifp->if_snd.ifq_len > congest_threshold) { 31836770Ssklower /* 31936770Ssklower * Congestion! Set the Dec Bit and thank Dave Oran 32036770Ssklower */ 32136770Ssklower IFDEBUG(D_FORWARD) 32236770Ssklower printf("clnp_forward: congestion experienced\n"); 32336770Ssklower ENDDEBUG 32436770Ssklower if ((oidx) && (oidx->cni_qos_formatp)) { 32536770Ssklower caddr_t qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp); 32636770Ssklower u_char qos = *qosp; 32736770Ssklower IFDEBUG(D_FORWARD) 32836770Ssklower printf("clnp_forward: setting congestion bit (qos x%x)\n", qos); 32936770Ssklower ENDDEBUG 33036770Ssklower if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) { 33136770Ssklower qos |= CLNPOVAL_CONGESTED; 33236770Ssklower INCSTAT(cns_congest_set); 33336770Ssklower *qosp = qos; 33436770Ssklower } 33536770Ssklower } 33636770Ssklower } 33736770Ssklower #endif DECBIT 33836375Ssklower 33936375Ssklower /* 34036375Ssklower * Dispatch the datagram if it is small enough, otherwise fragment 34136375Ssklower */ 34236375Ssklower if (len <= SN_MTU(ifp)) { 34336375Ssklower iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 34436375Ssklower (void) (*ifp->if_output)(ifp, m, next_hop); 34536375Ssklower } else { 34636375Ssklower (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0); 34736375Ssklower } 34836375Ssklower 34936375Ssklower done: 35036375Ssklower /* 35136375Ssklower * Free route 35236375Ssklower */ 35336375Ssklower if (route.ro_rt != NULL) { 35436375Ssklower RTFREE(route.ro_rt); 35536375Ssklower } 35636375Ssklower } 35736375Ssklower 35836375Ssklower #ifdef ndef 35936375Ssklower /* 36036375Ssklower * FUNCTION: clnp_insert_addr 36136375Ssklower * 36236375Ssklower * PURPOSE: Insert the address part into a clnp datagram. 36336375Ssklower * 36436375Ssklower * RETURNS: Address of first byte after address part in datagram. 36536375Ssklower * 36636375Ssklower * SIDE EFFECTS: 36736375Ssklower * 36836375Ssklower * NOTES: Assume that there is enough space for the address part. 36936375Ssklower */ 37036375Ssklower caddr_t 37136375Ssklower clnp_insert_addr(bufp, srcp, dstp) 37236375Ssklower caddr_t bufp; /* address of where addr part goes */ 37336375Ssklower register struct iso_addr *srcp; /* ptr to src addr */ 37436375Ssklower register struct iso_addr *dstp; /* ptr to dst addr */ 37536375Ssklower { 37636375Ssklower *bufp++ = dstp->isoa_len; 37736375Ssklower (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len); 37836375Ssklower bufp += dstp->isoa_len; 37936375Ssklower 38036375Ssklower *bufp++ = srcp->isoa_len; 38136375Ssklower (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len); 38236375Ssklower bufp += srcp->isoa_len; 38336375Ssklower 38436375Ssklower return bufp; 38536375Ssklower } 38636375Ssklower 38736375Ssklower #endif ndef 38836375Ssklower 38936375Ssklower /* 39036375Ssklower * FUNCTION: clnp_route 39136375Ssklower * 39236375Ssklower * PURPOSE: Route a clnp datagram to the first hop toward its 39336375Ssklower * destination. In many cases, the first hop will be 39436375Ssklower * the destination. The address of a route 39536375Ssklower * is specified. If a routing entry is present in 39636375Ssklower * that route, and it is still up to the same destination, 39736375Ssklower * then no further action is necessary. Otherwise, a 39836375Ssklower * new routing entry will be allocated. 39936375Ssklower * 40036375Ssklower * RETURNS: route found - 0 40136375Ssklower * unix error code 40236375Ssklower * 40336375Ssklower * SIDE EFFECTS: 40436375Ssklower * 40536375Ssklower * NOTES: It is up to the caller to free the routing entry 40636375Ssklower * allocated in route. 40736375Ssklower */ 40837469Ssklower clnp_route(dst, ro, flags, first_hop, ifa) 40937469Ssklower struct iso_addr *dst; /* ptr to datagram destination */ 41037469Ssklower register struct route_iso *ro; /* existing route structure */ 41137469Ssklower int flags; /* flags for routing */ 41237469Ssklower struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */ 41337469Ssklower struct iso_ifaddr **ifa; /* result: fill in with ptr to interface */ 41436375Ssklower { 41537469Ssklower if (flags & SO_DONTROUTE) { 41637469Ssklower struct iso_ifaddr *ia; 41736375Ssklower 41838476Ssklower if (ro->ro_rt) { 41938476Ssklower RTFREE(ro->ro_rt); 42038476Ssklower ro->ro_rt = 0; 42138476Ssklower } 42238476Ssklower bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); 42338476Ssklower bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr, 42437469Ssklower 1 + (unsigned)dst->isoa_len); 42538476Ssklower ro->ro_dst.siso_family = AF_ISO; 42638476Ssklower ro->ro_dst.siso_len = sizeof(ro->ro_dst); 42738476Ssklower ia = iso_localifa(&ro->ro_dst); 42837469Ssklower if (ia == 0) 42937469Ssklower return EADDRNOTAVAIL; 43037469Ssklower if (ifa) 43138476Ssklower *ifa = ia; 43238476Ssklower if (first_hop) 43338476Ssklower *first_hop = (struct sockaddr *)&ro->ro_dst; 43437469Ssklower return 0; 43537469Ssklower } 43636375Ssklower /* 43736375Ssklower * If there is a cached route, check that it is still up and to 43836375Ssklower * the same destination. If not, free it and try again. 43936375Ssklower */ 44036375Ssklower if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 44137469Ssklower (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) { 44236375Ssklower IFDEBUG(D_ROUTE) 44336375Ssklower printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n", 44436375Ssklower ro->ro_rt); 44536375Ssklower printf("clnp_route: old route refcnt: 0x%x\n", 44636375Ssklower ro->ro_rt->rt_refcnt); 44736375Ssklower ENDDEBUG 44836375Ssklower 44936375Ssklower /* free old route entry */ 45036375Ssklower RTFREE(ro->ro_rt); 45136375Ssklower ro->ro_rt = (struct rtentry *)0; 45236375Ssklower } else { 45336375Ssklower IFDEBUG(D_ROUTE) 45436375Ssklower printf("clnp_route: OK route exists\n"); 45536375Ssklower ENDDEBUG 45636375Ssklower } 45736375Ssklower 45836375Ssklower if (ro->ro_rt == 0) { 45936375Ssklower /* set up new route structure */ 46037469Ssklower bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); 46137469Ssklower ro->ro_dst.siso_len = sizeof(ro->ro_dst); 46237469Ssklower ro->ro_dst.siso_family = AF_ISO; 46337469Ssklower Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len); 46436375Ssklower /* allocate new route */ 46536375Ssklower IFDEBUG(D_ROUTE) 46636375Ssklower printf("clnp_route: allocating new route to %s\n", 46736375Ssklower clnp_iso_addrp(dst)); 46836375Ssklower ENDDEBUG 46937469Ssklower rtalloc((struct route *)ro); 47036375Ssklower } 47137469Ssklower if (ro->ro_rt == 0) 47236375Ssklower return(ENETUNREACH); /* rtalloc failed */ 47337469Ssklower ro->ro_rt->rt_use++; 47437469Ssklower if (ifa) 47537469Ssklower if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0) 47637469Ssklower panic("clnp_route"); 47737469Ssklower if (first_hop) { 47837469Ssklower if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) 47937469Ssklower *first_hop = ro->ro_rt->rt_gateway; 48037469Ssklower else 48137469Ssklower *first_hop = (struct sockaddr *)&ro->ro_dst; 48236375Ssklower } 48336375Ssklower return(0); 48436375Ssklower } 48536375Ssklower 48636375Ssklower /* 48736375Ssklower * FUNCTION: clnp_srcroute 48836375Ssklower * 48936375Ssklower * PURPOSE: Source route the datagram. If complete source 49036375Ssklower * routing is specified but not possible, then 49136375Ssklower * return an error. If src routing is terminated, then 49236375Ssklower * try routing on destination. 49336375Ssklower * Usage of first_hop, 49436375Ssklower * ifp, and error return is identical to clnp_route. 49536375Ssklower * 49636375Ssklower * RETURNS: 0 or unix error code 49736375Ssklower * 49836375Ssklower * SIDE EFFECTS: 49936375Ssklower * 50036375Ssklower * NOTES: Remember that option index pointers are really 50136375Ssklower * offsets from the beginning of the mbuf. 50236375Ssklower */ 50337469Ssklower clnp_srcroute(options, oidx, route, first_hop, ifa, final_dst) 50436375Ssklower struct mbuf *options; /* ptr to options */ 50536375Ssklower struct clnp_optidx *oidx; /* index to options */ 50637469Ssklower struct route_iso *route; /* route structure */ 50736375Ssklower struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */ 50837469Ssklower struct iso_ifaddr **ifa; /* RETURN: fill in with ptr to interface */ 50936375Ssklower struct iso_addr *final_dst; /* final destination */ 51036375Ssklower { 51136375Ssklower struct iso_addr dst; /* first hop specified by src rt */ 51236375Ssklower int error = 0; /* return code */ 51336375Ssklower 51436375Ssklower /* 51536375Ssklower * Check if we have run out of routes 51636375Ssklower * If so, then try to route on destination. 51736375Ssklower */ 51836375Ssklower if CLNPSRCRT_TERM(oidx, options) { 51936375Ssklower dst.isoa_len = final_dst->isoa_len; 52037469Ssklower bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len); 52136375Ssklower } else { 52236375Ssklower /* 52336375Ssklower * setup dst based on src rt specified 52436375Ssklower */ 52536375Ssklower dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); 52637469Ssklower bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len); 52736375Ssklower } 52836375Ssklower 52936375Ssklower /* 53036375Ssklower * try to route it 53136375Ssklower */ 53237469Ssklower error = clnp_route(&dst, route, 0, first_hop, ifa); 53336375Ssklower if (error != 0) 53436375Ssklower return error; 53536375Ssklower 53636375Ssklower /* 53736375Ssklower * If complete src rt, first hop must be equal to dst 53836375Ssklower */ 53936375Ssklower if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) && 54036375Ssklower (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){ 54136375Ssklower IFDEBUG(D_OPTIONS) 54236375Ssklower printf("clnp_srcroute: complete src route failed\n"); 54336375Ssklower ENDDEBUG 54436375Ssklower return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */ 54536375Ssklower } 54636375Ssklower 54736375Ssklower return error; 54836375Ssklower } 54936375Ssklower 55036375Ssklower /* 55136375Ssklower * FUNCTION: clnp_ypocb - backwards bcopy 55236375Ssklower * 55336375Ssklower * PURPOSE: bcopy starting at end of src rather than beginning. 55436375Ssklower * 55536375Ssklower * RETURNS: none 55636375Ssklower * 55736375Ssklower * SIDE EFFECTS: 55836375Ssklower * 55936375Ssklower * NOTES: No attempt has been made to make this efficient 56036375Ssklower */ 56136375Ssklower clnp_ypocb(from, to, len) 56236375Ssklower caddr_t from; /* src buffer */ 56336375Ssklower caddr_t to; /* dst buffer */ 56436375Ssklower u_int len; /* number of bytes */ 56536375Ssklower { 56636375Ssklower while (len--) 56736375Ssklower *(to + len) = *(from + len); 56836375Ssklower } 56936375Ssklower 57036375Ssklower /* 57136375Ssklower * FUNCTION: clnp_hdrsize 57236375Ssklower * 57336375Ssklower * PURPOSE: Return the size of a typical clnp hdr. 57436375Ssklower * 57536375Ssklower * RETURNS: Size of hdr in bytes. 57636375Ssklower * 57736375Ssklower * SIDE EFFECTS: 57836375Ssklower * 57936375Ssklower * NOTES: Assumes segmenting subset. If addrlen is 58036375Ssklower * zero, default to largest nsap address size. 58136375Ssklower */ 58236375Ssklower clnp_hdrsize(addrlen) 58336375Ssklower u_char addrlen; /* length of nsap address */ 58436375Ssklower { 58536375Ssklower if (addrlen == 0) 58636375Ssklower addrlen = 20; 58736375Ssklower 58836375Ssklower addrlen++; /* length of address byte */ 58936375Ssklower addrlen *= 2; /* src and dst addresses */ 59036375Ssklower addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment); 59136375Ssklower 59236375Ssklower return(addrlen); 59336375Ssklower } 59436375Ssklower #endif ISO 595