149267Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449267Sbostic *
549267Sbostic * %sccs.include.redist.c%
649267Sbostic *
7*63222Sbostic * @(#)clnp_subr.c 8.1 (Berkeley) 06/10/93
849267Sbostic */
949267Sbostic
1036375Ssklower /***********************************************************
1136375Ssklower Copyright IBM Corporation 1987
1236375Ssklower
1336375Ssklower All Rights Reserved
1436375Ssklower
1536375Ssklower Permission to use, copy, modify, and distribute this software and its
1636375Ssklower documentation for any purpose and without fee is hereby granted,
1736375Ssklower provided that the above copyright notice appear in all copies and that
1836375Ssklower both that copyright notice and this permission notice appear in
1936375Ssklower supporting documentation, and that the name of IBM not be
2036375Ssklower used in advertising or publicity pertaining to distribution of the
2136375Ssklower software without specific, written prior permission.
2236375Ssklower
2336375Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436375Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536375Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636375Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736375Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836375Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936375Ssklower SOFTWARE.
3036375Ssklower
3136375Ssklower ******************************************************************/
3236375Ssklower
3336375Ssklower /*
3436375Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536375Ssklower */
3636770Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */
3736770Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */
3836375Ssklower
3936375Ssklower #ifdef ISO
4036375Ssklower
4156533Sbostic #include <sys/param.h>
4256533Sbostic #include <sys/mbuf.h>
4356533Sbostic #include <sys/domain.h>
4456533Sbostic #include <sys/protosw.h>
4556533Sbostic #include <sys/socket.h>
4656533Sbostic #include <sys/socketvar.h>
4756533Sbostic #include <sys/errno.h>
4856533Sbostic #include <sys/time.h>
4936375Ssklower
5056533Sbostic #include <net/if.h>
5156533Sbostic #include <net/route.h>
5256533Sbostic #include <net/if_dl.h>
5336375Ssklower
5456533Sbostic #include <netiso/iso.h>
5556533Sbostic #include <netiso/iso_var.h>
5656533Sbostic #include <netiso/iso_pcb.h>
5756533Sbostic #include <netiso/iso_snpac.h>
5856533Sbostic #include <netiso/clnp.h>
5956533Sbostic #include <netiso/clnp_stat.h>
6056533Sbostic #include <netiso/argo_debug.h>
6136375Ssklower
6236375Ssklower /*
6336375Ssklower * FUNCTION: clnp_data_ck
6436375Ssklower *
6536375Ssklower * PURPOSE: Check that the amount of data in the mbuf chain is
6636375Ssklower * at least as much as the clnp header would have us
6736375Ssklower * expect. Trim mbufs if longer than expected, drop
6836375Ssklower * packet if shorter than expected.
6936375Ssklower *
7036375Ssklower * RETURNS: success - ptr to mbuf chain
7136375Ssklower * failure - 0
7236375Ssklower *
7336375Ssklower * SIDE EFFECTS:
7436375Ssklower *
7536375Ssklower * NOTES:
7636375Ssklower */
7736375Ssklower struct mbuf *
clnp_data_ck(m,length)7836375Ssklower clnp_data_ck(m, length)
7936375Ssklower register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */
8036375Ssklower int length; /* length (in bytes) of packet */
8136375Ssklower {
8236375Ssklower register int len; /* length of data */
8336375Ssklower register struct mbuf *mhead; /* ptr to head of chain */
8436375Ssklower
8536375Ssklower len = -length;
8636375Ssklower mhead = m;
8736375Ssklower for (;;) {
8836375Ssklower len += m->m_len;
8936375Ssklower if (m->m_next == 0)
9036375Ssklower break;
9136375Ssklower m = m->m_next;
9236375Ssklower }
9336375Ssklower if (len != 0) {
9436375Ssklower if (len < 0) {
9536375Ssklower INCSTAT(cns_toosmall);
9636375Ssklower clnp_discard(mhead, GEN_INCOMPLETE);
9736375Ssklower return 0;
9836375Ssklower }
9936375Ssklower if (len <= m->m_len)
10036375Ssklower m->m_len -= len;
10136375Ssklower else
10236375Ssklower m_adj(mhead, -len);
10336375Ssklower }
10436375Ssklower return mhead;
10536375Ssklower }
10636375Ssklower
10748740Ssklower #ifdef notdef
10836375Ssklower /*
10936375Ssklower * FUNCTION: clnp_extract_addr
11036375Ssklower *
11136375Ssklower * PURPOSE: Extract the source and destination address from the
11236375Ssklower * supplied buffer. Place them in the supplied address buffers.
11336375Ssklower * If insufficient data is supplied, then fail.
11436375Ssklower *
11536375Ssklower * RETURNS: success - Address of first byte in the packet past
11636375Ssklower * the address part.
11736375Ssklower * failure - 0
11836375Ssklower *
11936375Ssklower * SIDE EFFECTS:
12036375Ssklower *
12136375Ssklower * NOTES:
12236375Ssklower */
12336375Ssklower caddr_t
clnp_extract_addr(bufp,buflen,srcp,destp)12436375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp)
12536375Ssklower caddr_t bufp; /* ptr to buffer containing addresses */
12636375Ssklower int buflen; /* length of buffer */
12736375Ssklower register struct iso_addr *srcp; /* ptr to source address buffer */
12836375Ssklower register struct iso_addr *destp; /* ptr to destination address buffer */
12936375Ssklower {
13036375Ssklower int len; /* argument to bcopy */
13136375Ssklower
13236375Ssklower /*
13336375Ssklower * check that we have enough data. Plus1 is for length octet
13436375Ssklower */
13536375Ssklower if ((u_char)*bufp + 1 > buflen) {
13636375Ssklower return((caddr_t)0);
13736375Ssklower }
13836375Ssklower len = destp->isoa_len = (u_char)*bufp++;
13936375Ssklower (void) bcopy(bufp, (caddr_t)destp, len);
14036375Ssklower buflen -= len;
14136375Ssklower bufp += len;
14236375Ssklower
14336375Ssklower /*
14436375Ssklower * check that we have enough data. Plus1 is for length octet
14536375Ssklower */
14636375Ssklower if ((u_char)*bufp + 1 > buflen) {
14736375Ssklower return((caddr_t)0);
14836375Ssklower }
14936375Ssklower len = srcp->isoa_len = (u_char)* bufp++;
15036375Ssklower (void) bcopy(bufp, (caddr_t)srcp, len);
15136375Ssklower bufp += len;
15236375Ssklower
15336375Ssklower /*
15436375Ssklower * Insure that the addresses make sense
15536375Ssklower */
15636375Ssklower if (iso_ck_addr(srcp) && iso_ck_addr(destp))
15736375Ssklower return bufp;
15836375Ssklower else
15936375Ssklower return (caddr_t) 0;
16036375Ssklower }
16161290Ssklower #endif /* notdef */
16236375Ssklower
16336375Ssklower /*
16436375Ssklower * FUNCTION: clnp_ours
16536375Ssklower *
16636375Ssklower * PURPOSE: Decide whether the supplied packet is destined for
16736375Ssklower * us, or that it should be forwarded on.
16836375Ssklower *
16936375Ssklower * RETURNS: packet is for us - 1
17036375Ssklower * packet is not for us - 0
17136375Ssklower *
17236375Ssklower * SIDE EFFECTS:
17336375Ssklower *
17436375Ssklower * NOTES:
17536375Ssklower */
clnp_ours(dst)17636375Ssklower clnp_ours(dst)
17736375Ssklower register struct iso_addr *dst; /* ptr to destination address */
17836375Ssklower {
17936375Ssklower register struct iso_ifaddr *ia; /* scan through interface addresses */
18036375Ssklower
18136375Ssklower for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
18236375Ssklower IFDEBUG(D_ROUTE)
18342949Ssklower printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr,
18436375Ssklower dst);
18536375Ssklower ENDDEBUG
18642949Ssklower /*
18742949Ssklower * XXX Warning:
18842949Ssklower * We are overloading siso_tlen in the if's address, as an nsel length.
18942949Ssklower */
19043332Ssklower if (dst->isoa_len == ia->ia_addr.siso_nlen &&
19142949Ssklower bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr,
19243332Ssklower (caddr_t)dst->isoa_genaddr,
19343332Ssklower ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0)
19442949Ssklower return 1;
19536375Ssklower }
19636375Ssklower return 0;
19736375Ssklower }
19836375Ssklower
19936770Ssklower /* Dec bit set if ifp qlen is greater than congest_threshold */
20036770Ssklower int congest_threshold = 0;
20136770Ssklower
20236375Ssklower /*
20336375Ssklower * FUNCTION: clnp_forward
20436375Ssklower *
20536375Ssklower * PURPOSE: Forward the datagram passed
20636375Ssklower * clnpintr guarantees that the header will be
20736375Ssklower * contigious (a cluster mbuf will be used if necessary).
20836375Ssklower *
20936375Ssklower * If oidx is NULL, no options are present.
21036375Ssklower *
21136375Ssklower * RETURNS: nothing
21236375Ssklower *
21336375Ssklower * SIDE EFFECTS:
21436375Ssklower *
21536375Ssklower * NOTES:
21636375Ssklower */
21736375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
21836375Ssklower struct mbuf *m; /* pkt to forward */
21936375Ssklower int len; /* length of pkt */
22036375Ssklower struct iso_addr *dst; /* destination address */
22136375Ssklower struct clnp_optidx *oidx; /* option index */
22236375Ssklower int seg_off;/* offset of segmentation part */
22336375Ssklower struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */
22436375Ssklower {
22536375Ssklower struct clnp_fixed *clnp; /* ptr to fixed part of header */
22636375Ssklower int error; /* return value of route function */
22736375Ssklower struct sockaddr *next_hop; /* next hop for dgram */
22836375Ssklower struct ifnet *ifp; /* ptr to outgoing interface */
22937469Ssklower struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */
23036769Ssklower struct route_iso route; /* filled in by clnp_route */
23136375Ssklower extern int iso_systype;
23236375Ssklower
23336375Ssklower clnp = mtod(m, struct clnp_fixed *);
23436375Ssklower bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
23536375Ssklower
23636375Ssklower /*
23736375Ssklower * Don't forward multicast or broadcast packets
23836375Ssklower */
23936375Ssklower if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
24036375Ssklower IFDEBUG(D_FORWARD)
24136375Ssklower printf("clnp_forward: dropping multicast packet\n");
24236375Ssklower ENDDEBUG
24337469Ssklower clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
24436375Ssklower clnp_discard(m, 0);
24539198Ssklower INCSTAT(cns_cantforward);
24636375Ssklower goto done;
24736375Ssklower }
24836375Ssklower
24936375Ssklower IFDEBUG(D_FORWARD)
25036375Ssklower printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
25136375Ssklower clnp_iso_addrp(dst), oidx);
25236375Ssklower ENDDEBUG
25336375Ssklower
25436375Ssklower /*
25536375Ssklower * Decrement ttl, and if zero drop datagram
25636375Ssklower * Can't compare ttl as less than zero 'cause its a unsigned
25736375Ssklower */
25836375Ssklower if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
25936375Ssklower IFDEBUG(D_FORWARD)
26036375Ssklower printf("clnp_forward: discarding datagram because ttl is zero\n");
26136375Ssklower ENDDEBUG
26236375Ssklower INCSTAT(cns_ttlexpired);
26336375Ssklower clnp_discard(m, TTL_EXPTRANSIT);
26436375Ssklower goto done;
26536375Ssklower }
26636375Ssklower /*
26736375Ssklower * Route packet; special case for source rt
26836375Ssklower */
26936375Ssklower if CLNPSRCRT_VALID(oidx) {
27036375Ssklower /*
27136375Ssklower * Update src route first
27236375Ssklower */
27336375Ssklower clnp_update_srcrt(m, oidx);
27437469Ssklower error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
27536375Ssklower } else {
27637469Ssklower error = clnp_route(dst, &route, 0, &next_hop, &ia);
27736375Ssklower }
27837469Ssklower if (error || ia == 0) {
27936375Ssklower IFDEBUG(D_FORWARD)
28036375Ssklower printf("clnp_forward: can't route packet (errno %d)\n", error);
28136375Ssklower ENDDEBUG
28236375Ssklower clnp_discard(m, ADDR_DESTUNREACH);
28339198Ssklower INCSTAT(cns_cantforward);
28436375Ssklower goto done;
28536375Ssklower }
28637469Ssklower ifp = ia->ia_ifp;
28736375Ssklower
28836375Ssklower IFDEBUG(D_FORWARD)
28936375Ssklower printf("clnp_forward: packet routed to %s\n",
29036375Ssklower clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
29136375Ssklower ENDDEBUG
29236375Ssklower
29336375Ssklower INCSTAT(cns_forward);
29436375Ssklower
29536375Ssklower /*
29636375Ssklower * If we are an intermediate system and
29736375Ssklower * we are routing outbound on the same ifp that the packet
29836375Ssklower * arrived upon, and we know the next hop snpa,
29936375Ssklower * then generate a redirect request
30036375Ssklower */
30136375Ssklower if ((iso_systype & SNPA_IS) && (inbound_shp) &&
30243332Ssklower (ifp == inbound_shp->snh_ifp))
30343332Ssklower esis_rdoutput(inbound_shp, m, oidx, dst, route.ro_rt);
30436375Ssklower /*
30536375Ssklower * If options are present, update them
30636375Ssklower */
30736375Ssklower if (oidx) {
30837469Ssklower struct iso_addr *mysrc = &ia->ia_addr.siso_addr;
30936375Ssklower if (mysrc == NULL) {
31036375Ssklower clnp_discard(m, ADDR_DESTUNREACH);
31139198Ssklower INCSTAT(cns_cantforward);
31239198Ssklower clnp_stat.cns_forward--;
31336375Ssklower goto done;
31436375Ssklower } else {
31536770Ssklower (void) clnp_dooptions(m, oidx, ifp, mysrc);
31636375Ssklower }
31736375Ssklower }
31836770Ssklower
31936770Ssklower #ifdef DECBIT
32036770Ssklower if (ifp->if_snd.ifq_len > congest_threshold) {
32136770Ssklower /*
32236770Ssklower * Congestion! Set the Dec Bit and thank Dave Oran
32336770Ssklower */
32436770Ssklower IFDEBUG(D_FORWARD)
32536770Ssklower printf("clnp_forward: congestion experienced\n");
32636770Ssklower ENDDEBUG
32736770Ssklower if ((oidx) && (oidx->cni_qos_formatp)) {
32836770Ssklower caddr_t qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
32936770Ssklower u_char qos = *qosp;
33036770Ssklower IFDEBUG(D_FORWARD)
33136770Ssklower printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
33236770Ssklower ENDDEBUG
33336770Ssklower if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
33436770Ssklower qos |= CLNPOVAL_CONGESTED;
33536770Ssklower INCSTAT(cns_congest_set);
33636770Ssklower *qosp = qos;
33736770Ssklower }
33836770Ssklower }
33936770Ssklower }
34061290Ssklower #endif /* DECBIT */
34136375Ssklower
34236375Ssklower /*
34336375Ssklower * Dispatch the datagram if it is small enough, otherwise fragment
34436375Ssklower */
34548740Ssklower if (len <= SN_MTU(ifp, route.ro_rt)) {
34636375Ssklower iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
34740776Ssklower (void) (*ifp->if_output)(ifp, m, next_hop, route.ro_rt);
34836375Ssklower } else {
34940776Ssklower (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0, route.ro_rt);
35036375Ssklower }
35136375Ssklower
35236375Ssklower done:
35336375Ssklower /*
35436375Ssklower * Free route
35536375Ssklower */
35636375Ssklower if (route.ro_rt != NULL) {
35736375Ssklower RTFREE(route.ro_rt);
35836375Ssklower }
35936375Ssklower }
36036375Ssklower
36148740Ssklower #ifdef notdef
36236375Ssklower /*
36336375Ssklower * FUNCTION: clnp_insert_addr
36436375Ssklower *
36536375Ssklower * PURPOSE: Insert the address part into a clnp datagram.
36636375Ssklower *
36736375Ssklower * RETURNS: Address of first byte after address part in datagram.
36836375Ssklower *
36936375Ssklower * SIDE EFFECTS:
37036375Ssklower *
37136375Ssklower * NOTES: Assume that there is enough space for the address part.
37236375Ssklower */
37336375Ssklower caddr_t
clnp_insert_addr(bufp,srcp,dstp)37436375Ssklower clnp_insert_addr(bufp, srcp, dstp)
37536375Ssklower caddr_t bufp; /* address of where addr part goes */
37636375Ssklower register struct iso_addr *srcp; /* ptr to src addr */
37736375Ssklower register struct iso_addr *dstp; /* ptr to dst addr */
37836375Ssklower {
37936375Ssklower *bufp++ = dstp->isoa_len;
38036375Ssklower (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
38136375Ssklower bufp += dstp->isoa_len;
38236375Ssklower
38336375Ssklower *bufp++ = srcp->isoa_len;
38436375Ssklower (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
38536375Ssklower bufp += srcp->isoa_len;
38636375Ssklower
38736375Ssklower return bufp;
38836375Ssklower }
38936375Ssklower
39061290Ssklower #endif /* notdef */
39136375Ssklower
39236375Ssklower /*
39336375Ssklower * FUNCTION: clnp_route
39436375Ssklower *
39536375Ssklower * PURPOSE: Route a clnp datagram to the first hop toward its
39636375Ssklower * destination. In many cases, the first hop will be
39736375Ssklower * the destination. The address of a route
39836375Ssklower * is specified. If a routing entry is present in
39936375Ssklower * that route, and it is still up to the same destination,
40036375Ssklower * then no further action is necessary. Otherwise, a
40136375Ssklower * new routing entry will be allocated.
40236375Ssklower *
40336375Ssklower * RETURNS: route found - 0
40436375Ssklower * unix error code
40536375Ssklower *
40636375Ssklower * SIDE EFFECTS:
40736375Ssklower *
40836375Ssklower * NOTES: It is up to the caller to free the routing entry
40936375Ssklower * allocated in route.
41036375Ssklower */
41137469Ssklower clnp_route(dst, ro, flags, first_hop, ifa)
41237469Ssklower struct iso_addr *dst; /* ptr to datagram destination */
41337469Ssklower register struct route_iso *ro; /* existing route structure */
41437469Ssklower int flags; /* flags for routing */
41537469Ssklower struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */
41637469Ssklower struct iso_ifaddr **ifa; /* result: fill in with ptr to interface */
41736375Ssklower {
41837469Ssklower if (flags & SO_DONTROUTE) {
41937469Ssklower struct iso_ifaddr *ia;
42036375Ssklower
42138476Ssklower if (ro->ro_rt) {
42238476Ssklower RTFREE(ro->ro_rt);
42338476Ssklower ro->ro_rt = 0;
42438476Ssklower }
42538476Ssklower bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
42638476Ssklower bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr,
42737469Ssklower 1 + (unsigned)dst->isoa_len);
42838476Ssklower ro->ro_dst.siso_family = AF_ISO;
42938476Ssklower ro->ro_dst.siso_len = sizeof(ro->ro_dst);
43038476Ssklower ia = iso_localifa(&ro->ro_dst);
43137469Ssklower if (ia == 0)
43237469Ssklower return EADDRNOTAVAIL;
43337469Ssklower if (ifa)
43438476Ssklower *ifa = ia;
43538476Ssklower if (first_hop)
43638476Ssklower *first_hop = (struct sockaddr *)&ro->ro_dst;
43737469Ssklower return 0;
43837469Ssklower }
43936375Ssklower /*
44036375Ssklower * If there is a cached route, check that it is still up and to
44136375Ssklower * the same destination. If not, free it and try again.
44236375Ssklower */
44336375Ssklower if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
44437469Ssklower (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
44536375Ssklower IFDEBUG(D_ROUTE)
44636375Ssklower printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
44736375Ssklower ro->ro_rt);
44836375Ssklower printf("clnp_route: old route refcnt: 0x%x\n",
44936375Ssklower ro->ro_rt->rt_refcnt);
45036375Ssklower ENDDEBUG
45136375Ssklower
45236375Ssklower /* free old route entry */
45336375Ssklower RTFREE(ro->ro_rt);
45436375Ssklower ro->ro_rt = (struct rtentry *)0;
45536375Ssklower } else {
45636375Ssklower IFDEBUG(D_ROUTE)
45736375Ssklower printf("clnp_route: OK route exists\n");
45836375Ssklower ENDDEBUG
45936375Ssklower }
46036375Ssklower
46136375Ssklower if (ro->ro_rt == 0) {
46236375Ssklower /* set up new route structure */
46337469Ssklower bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
46437469Ssklower ro->ro_dst.siso_len = sizeof(ro->ro_dst);
46537469Ssklower ro->ro_dst.siso_family = AF_ISO;
46637469Ssklower Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
46736375Ssklower /* allocate new route */
46836375Ssklower IFDEBUG(D_ROUTE)
46936375Ssklower printf("clnp_route: allocating new route to %s\n",
47036375Ssklower clnp_iso_addrp(dst));
47136375Ssklower ENDDEBUG
47237469Ssklower rtalloc((struct route *)ro);
47336375Ssklower }
47437469Ssklower if (ro->ro_rt == 0)
47536375Ssklower return(ENETUNREACH); /* rtalloc failed */
47637469Ssklower ro->ro_rt->rt_use++;
47737469Ssklower if (ifa)
47837469Ssklower if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
47937469Ssklower panic("clnp_route");
48037469Ssklower if (first_hop) {
48140776Ssklower if (ro->ro_rt->rt_flags & RTF_GATEWAY)
48237469Ssklower *first_hop = ro->ro_rt->rt_gateway;
48337469Ssklower else
48437469Ssklower *first_hop = (struct sockaddr *)&ro->ro_dst;
48536375Ssklower }
48636375Ssklower return(0);
48736375Ssklower }
48836375Ssklower
48936375Ssklower /*
49036375Ssklower * FUNCTION: clnp_srcroute
49136375Ssklower *
49236375Ssklower * PURPOSE: Source route the datagram. If complete source
49336375Ssklower * routing is specified but not possible, then
49436375Ssklower * return an error. If src routing is terminated, then
49536375Ssklower * try routing on destination.
49636375Ssklower * Usage of first_hop,
49736375Ssklower * ifp, and error return is identical to clnp_route.
49836375Ssklower *
49936375Ssklower * RETURNS: 0 or unix error code
50036375Ssklower *
50136375Ssklower * SIDE EFFECTS:
50236375Ssklower *
50336375Ssklower * NOTES: Remember that option index pointers are really
50436375Ssklower * offsets from the beginning of the mbuf.
50536375Ssklower */
50643332Ssklower clnp_srcroute(options, oidx, ro, first_hop, ifa, final_dst)
50736375Ssklower struct mbuf *options; /* ptr to options */
50836375Ssklower struct clnp_optidx *oidx; /* index to options */
50943332Ssklower struct route_iso *ro; /* route structure */
51036375Ssklower struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */
51137469Ssklower struct iso_ifaddr **ifa; /* RETURN: fill in with ptr to interface */
51236375Ssklower struct iso_addr *final_dst; /* final destination */
51336375Ssklower {
51436375Ssklower struct iso_addr dst; /* first hop specified by src rt */
51536375Ssklower int error = 0; /* return code */
51636375Ssklower
51736375Ssklower /*
51836375Ssklower * Check if we have run out of routes
51936375Ssklower * If so, then try to route on destination.
52036375Ssklower */
52136375Ssklower if CLNPSRCRT_TERM(oidx, options) {
52236375Ssklower dst.isoa_len = final_dst->isoa_len;
52337469Ssklower bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
52436375Ssklower } else {
52536375Ssklower /*
52636375Ssklower * setup dst based on src rt specified
52736375Ssklower */
52836375Ssklower dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
52937469Ssklower bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
53036375Ssklower }
53136375Ssklower
53236375Ssklower /*
53336375Ssklower * try to route it
53436375Ssklower */
53543332Ssklower error = clnp_route(&dst, ro, 0, first_hop, ifa);
53636375Ssklower if (error != 0)
53736375Ssklower return error;
53836375Ssklower
53936375Ssklower /*
54036375Ssklower * If complete src rt, first hop must be equal to dst
54136375Ssklower */
54236375Ssklower if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
54336375Ssklower (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
54436375Ssklower IFDEBUG(D_OPTIONS)
54536375Ssklower printf("clnp_srcroute: complete src route failed\n");
54636375Ssklower ENDDEBUG
54736375Ssklower return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
54836375Ssklower }
54936375Ssklower
55036375Ssklower return error;
55136375Ssklower }
55236375Ssklower
55336375Ssklower /*
55452487Ssklower * FUNCTION: clnp_echoreply
55552487Ssklower *
55652487Ssklower * PURPOSE: generate an echo reply packet and transmit
55752487Ssklower *
55852487Ssklower * RETURNS: result of clnp_output
55952487Ssklower *
56052487Ssklower * SIDE EFFECTS:
56152487Ssklower */
56252487Ssklower clnp_echoreply(ec_m, ec_len, ec_src, ec_dst, ec_oidxp)
56352487Ssklower struct mbuf *ec_m; /* echo request */
56452487Ssklower int ec_len; /* length of ec */
56552487Ssklower struct sockaddr_iso *ec_src; /* src of ec */
56652487Ssklower struct sockaddr_iso *ec_dst; /* destination of ec (i.e., us) */
56752487Ssklower struct clnp_optidx *ec_oidxp; /* options index to ec packet */
56852487Ssklower {
56952487Ssklower struct isopcb isopcb;
57052487Ssklower int flags = CLNP_NOCACHE|CLNP_ECHOR;
57152487Ssklower int ret;
57252487Ssklower
57352487Ssklower /* fill in fake isopcb to pass to output function */
57452487Ssklower bzero(&isopcb, sizeof(isopcb));
57552487Ssklower isopcb.isop_laddr = ec_dst;
57652487Ssklower isopcb.isop_faddr = ec_src;
57752487Ssklower
57852487Ssklower /* forget copying the options for now. If implemented, need only
57952487Ssklower * copy record route option, but it must be reset to zero length */
58052487Ssklower
58152487Ssklower ret = clnp_output(ec_m, &isopcb, ec_len, flags);
58252487Ssklower
58352487Ssklower IFDEBUG(D_OUTPUT)
58452487Ssklower printf("clnp_echoreply: output returns %d\n", ret);
58552487Ssklower ENDDEBUG
58652487Ssklower return ret;
58752487Ssklower }
58852487Ssklower
58952487Ssklower /*
59048740Ssklower * FUNCTION: clnp_badmtu
59148740Ssklower *
59248740Ssklower * PURPOSE: print notice of route with mtu not initialized.
59348740Ssklower *
59448740Ssklower * RETURNS: mtu of ifp.
59548740Ssklower *
59648740Ssklower * SIDE EFFECTS: prints notice, slows down system.
59748740Ssklower */
59848740Ssklower clnp_badmtu(ifp, rt, line, file)
59948740Ssklower struct ifnet *ifp; /* outgoing interface */
60048740Ssklower struct rtentry *rt; /* dst route */
60148740Ssklower int line; /* where the dirty deed occured */
60248740Ssklower char *file; /* where the dirty deed occured */
60348740Ssklower {
60457951Ssklower printf("sending on route 0x%x with no mtu, line %d of file %s\n",
60548740Ssklower rt, line, file);
60648740Ssklower #ifdef ARGO_DEBUG
60757951Ssklower printf("route dst is ");
60848740Ssklower dump_isoaddr(rt_key(rt));
60948740Ssklower #endif
61048740Ssklower return ifp->if_mtu;
61148740Ssklower }
61248740Ssklower
61348740Ssklower /*
61436375Ssklower * FUNCTION: clnp_ypocb - backwards bcopy
61536375Ssklower *
61636375Ssklower * PURPOSE: bcopy starting at end of src rather than beginning.
61736375Ssklower *
61836375Ssklower * RETURNS: none
61936375Ssklower *
62036375Ssklower * SIDE EFFECTS:
62136375Ssklower *
62236375Ssklower * NOTES: No attempt has been made to make this efficient
62336375Ssklower */
clnp_ypocb(from,to,len)62436375Ssklower clnp_ypocb(from, to, len)
62536375Ssklower caddr_t from; /* src buffer */
62636375Ssklower caddr_t to; /* dst buffer */
62736375Ssklower u_int len; /* number of bytes */
62836375Ssklower {
62936375Ssklower while (len--)
63036375Ssklower *(to + len) = *(from + len);
63136375Ssklower }
63261290Ssklower #endif /* ISO */
633