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_er.c 8.1 (Berkeley) 06/10/93
849267Sbostic */
949267Sbostic
1036368Ssklower /***********************************************************
1136368Ssklower Copyright IBM Corporation 1987
1236368Ssklower
1336368Ssklower All Rights Reserved
1436368Ssklower
1536368Ssklower Permission to use, copy, modify, and distribute this software and its
1636368Ssklower documentation for any purpose and without fee is hereby granted,
1736368Ssklower provided that the above copyright notice appear in all copies and that
1836368Ssklower both that copyright notice and this permission notice appear in
1936368Ssklower supporting documentation, and that the name of IBM not be
2036368Ssklower used in advertising or publicity pertaining to distribution of the
2136368Ssklower software without specific, written prior permission.
2236368Ssklower
2336368Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436368Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536368Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636368Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736368Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836368Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936368Ssklower SOFTWARE.
3036368Ssklower
3136368Ssklower ******************************************************************/
3236368Ssklower
3336368Ssklower /*
3436368Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536368Ssklower */
3636763Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $ */
3736763Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_er.c,v $ */
3836368Ssklower
3956533Sbostic #include <sys/param.h>
4056533Sbostic #include <sys/mbuf.h>
4156533Sbostic #include <sys/domain.h>
4256533Sbostic #include <sys/protosw.h>
4356533Sbostic #include <sys/socket.h>
4456533Sbostic #include <sys/socketvar.h>
4556533Sbostic #include <sys/errno.h>
4636368Ssklower
4756533Sbostic #include <net/if.h>
4856533Sbostic #include <net/route.h>
4936368Ssklower
5056533Sbostic #include <netiso/iso.h>
5156533Sbostic #include <netiso/iso_var.h>
5256533Sbostic #include <netiso/iso_pcb.h>
5339194Ssklower #define CLNP_ER_CODES
5456533Sbostic #include <netiso/clnp.h>
5556533Sbostic #include <netiso/clnp_stat.h>
5656533Sbostic #include <netiso/argo_debug.h>
5736368Ssklower
5836368Ssklower static struct clnp_fixed er_template = {
5936368Ssklower ISO8473_CLNP, /* network identifier */
6036368Ssklower 0, /* length */
6136368Ssklower ISO8473_V1, /* version */
6236368Ssklower CLNP_TTL, /* ttl */
6336368Ssklower CLNP_ER, /* type */
6436368Ssklower 0, /* segment length */
6536368Ssklower 0 /* checksum */
6636368Ssklower };
6736368Ssklower
6836368Ssklower /*
6936368Ssklower * FUNCTION: clnp_er_input
7036368Ssklower *
7136368Ssklower * PURPOSE: Process an ER pdu.
7236368Ssklower *
7336368Ssklower * RETURNS:
7436368Ssklower *
7536368Ssklower * SIDE EFFECTS:
7636368Ssklower *
7736368Ssklower * NOTES:
7836368Ssklower */
7936368Ssklower clnp_er_input(m, src, reason)
8036368Ssklower struct mbuf *m; /* ptr to packet itself */
8136368Ssklower struct iso_addr *src; /* ptr to src of er */
8237469Ssklower u_char reason; /* reason code of er */
8336368Ssklower {
8436368Ssklower int cmd = -1;
8536368Ssklower extern u_char clnp_protox[];
8636368Ssklower
8736368Ssklower IFDEBUG(D_CTLINPUT)
8836368Ssklower printf("clnp_er_input: m x%x, src %s, reason x%x\n", m,
8936368Ssklower clnp_iso_addrp(src), reason);
9036368Ssklower ENDDEBUG
9136368Ssklower
9239194Ssklower INCSTAT(cns_er_inhist[clnp_er_index(reason)]);
9336368Ssklower switch (reason) {
9436368Ssklower case GEN_NOREAS:
9536368Ssklower case GEN_PROTOERR:
9636368Ssklower break;
9736368Ssklower case GEN_BADCSUM:
9836368Ssklower cmd = PRC_PARAMPROB;
9936368Ssklower break;
10036368Ssklower case GEN_CONGEST:
10136368Ssklower cmd = PRC_QUENCH;
10236368Ssklower break;
10336368Ssklower case GEN_HDRSYNTAX:
10436368Ssklower cmd = PRC_PARAMPROB;
10536368Ssklower break;
10636368Ssklower case GEN_SEGNEEDED:
10740774Ssklower cmd = PRC_MSGSIZE;
10836368Ssklower break;
10936368Ssklower case GEN_INCOMPLETE:
11036368Ssklower cmd = PRC_PARAMPROB;
11136368Ssklower break;
11236368Ssklower case GEN_DUPOPT:
11336368Ssklower cmd = PRC_PARAMPROB;
11436368Ssklower break;
11536368Ssklower case ADDR_DESTUNREACH:
11636368Ssklower cmd = PRC_UNREACH_HOST;
11736368Ssklower break;
11836368Ssklower case ADDR_DESTUNKNOWN:
11936368Ssklower cmd = PRC_UNREACH_PROTOCOL;
12036368Ssklower break;
12136368Ssklower case SRCRT_UNSPECERR:
12236368Ssklower case SRCRT_SYNTAX:
12336368Ssklower case SRCRT_UNKNOWNADDR:
12436368Ssklower case SRCRT_BADPATH:
12536368Ssklower cmd = PRC_UNREACH_SRCFAIL;
12636368Ssklower break;
12736368Ssklower case TTL_EXPTRANSIT:
12836368Ssklower cmd = PRC_TIMXCEED_INTRANS;
12936368Ssklower break;
13036368Ssklower case TTL_EXPREASS:
13136368Ssklower cmd = PRC_TIMXCEED_REASS;
13236368Ssklower break;
13336368Ssklower case DISC_UNSUPPOPT:
13436368Ssklower case DISC_UNSUPPVERS:
13536368Ssklower case DISC_UNSUPPSECURE:
13636368Ssklower case DISC_UNSUPPSRCRT:
13736368Ssklower case DISC_UNSUPPRECRT:
13836368Ssklower cmd = PRC_PARAMPROB;
13936368Ssklower break;
14036368Ssklower case REASS_INTERFERE:
14136368Ssklower cmd = PRC_TIMXCEED_REASS;
14236368Ssklower break;
14336368Ssklower }
14436368Ssklower
14536763Ssklower /*
14636763Ssklower * tpclnp_ctlinput1 is called directly so that we don't
14736763Ssklower * have to build an iso_sockaddr out of src.
14836763Ssklower */
14936368Ssklower if (cmd >= 0)
15036763Ssklower tpclnp_ctlinput1(cmd, src);
15136368Ssklower
15236368Ssklower m_freem(m);
15336368Ssklower }
15436368Ssklower
15536368Ssklower /*
15636368Ssklower * FUNCTION: clnp_discard
15736368Ssklower *
15836368Ssklower * PURPOSE: Discard a clnp datagram
15936368Ssklower *
16036368Ssklower * RETURNS: nothing
16136368Ssklower *
16236368Ssklower * SIDE EFFECTS: Will emit an ER pdu if possible
16336368Ssklower *
16436368Ssklower * NOTES: This code assumes that we have previously tried to pull
16536368Ssklower * up the header of the datagram into one mbuf.
16636368Ssklower */
16736368Ssklower clnp_discard(m, reason)
16836368Ssklower struct mbuf *m; /* header of packet to discard */
16936368Ssklower char reason; /* reason for discard */
17036368Ssklower {
17136368Ssklower IFDEBUG(D_DISCARD)
17236368Ssklower printf("clnp_discard: m x%x, reason x%x\n", m, reason);
17336368Ssklower ENDDEBUG
17436368Ssklower
17536368Ssklower if (m != NULL) {
17636368Ssklower if (m->m_len >= sizeof(struct clnp_fixed)) {
17736368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
17836368Ssklower
17937469Ssklower if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
18037469Ssklower (clnp->cnf_type & CNF_ERR_OK)) {
18137469Ssklower clnp_emit_er(m, reason);
18237469Ssklower return;
18336368Ssklower }
18436368Ssklower }
18536368Ssklower m_freem(m);
18636368Ssklower }
18736368Ssklower }
18836368Ssklower
18936368Ssklower /*
19036368Ssklower * FUNCTION: clnp_emit_er
19136368Ssklower *
19236368Ssklower * PURPOSE: Send an ER pdu.
19336368Ssklower * The src of the of the ER pdu is the host that is sending
19436368Ssklower * the ER (ie. us), *not* the original destination of the
19536368Ssklower * packet.
19636368Ssklower *
19736368Ssklower * RETURNS: nothing
19836368Ssklower *
19936368Ssklower * SIDE EFFECTS:
20036368Ssklower *
20136368Ssklower * NOTES: Takes responsibility for freeing mbuf passed
20236368Ssklower * This function may be called with a packet that
20336368Ssklower * was created by us; in this case, do not send
20436368Ssklower * an ER.
20536368Ssklower */
20636368Ssklower clnp_emit_er(m, reason)
20736368Ssklower struct mbuf *m; /* header of packet to discard */
20836368Ssklower char reason; /* reason for discard */
20936368Ssklower {
21036368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
21136368Ssklower register struct clnp_fixed *er;
21237469Ssklower struct route_iso route;
21336368Ssklower struct ifnet *ifp;
21436368Ssklower struct sockaddr *first_hop;
21536368Ssklower struct iso_addr src, dst, *our_addr;
21636368Ssklower caddr_t hoff, hend;
21736368Ssklower int total_len; /* total len of dg */
21836368Ssklower struct mbuf *m0; /* contains er pdu hdr */
21937469Ssklower struct iso_ifaddr *ia = 0;
22036368Ssklower
22136368Ssklower IFDEBUG(D_DISCARD)
22236368Ssklower printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
22336368Ssklower ENDDEBUG
22436368Ssklower
22536368Ssklower bzero((caddr_t)&route, sizeof(route));
22636368Ssklower
22736368Ssklower /*
22836368Ssklower * If header length is incorrect, or entire header is not contained
22936368Ssklower * in this mbuf, we punt
23036368Ssklower */
23136368Ssklower if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
23236368Ssklower (clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
23336368Ssklower (clnp->cnf_hdr_len > m->m_len))
23436368Ssklower goto bad;
23536368Ssklower
23636368Ssklower /* extract src, dest address */
23736368Ssklower hend = (caddr_t)clnp + clnp->cnf_hdr_len;
23836368Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
23936368Ssklower CLNP_EXTRACT_ADDR(dst, hoff, hend);
24036368Ssklower if (hoff == (caddr_t)0) {
24136368Ssklower goto bad;
24236368Ssklower }
24336368Ssklower CLNP_EXTRACT_ADDR(src, hoff, hend);
24436368Ssklower if (hoff == (caddr_t)0) {
24536368Ssklower goto bad;
24636368Ssklower }
24736368Ssklower
24836368Ssklower /*
24936368Ssklower * Do not send ER if we generated the packet.
25036368Ssklower */
25136368Ssklower if (clnp_ours(&src))
25236368Ssklower goto bad;
25336368Ssklower
25436368Ssklower /*
25536368Ssklower * Trim mbuf to hold only the header.
25636368Ssklower * This mbuf will be the 'data' of the er pdu
25736368Ssklower */
25836368Ssklower if (m->m_next != NULL) {
25936368Ssklower m_freem(m->m_next);
26036368Ssklower m->m_next = NULL;
26136368Ssklower }
26236368Ssklower
26336368Ssklower if (m->m_len > clnp->cnf_hdr_len)
26437469Ssklower m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len));
26536368Ssklower
26636368Ssklower /* route er pdu: note we send pkt to src of original packet */
26737469Ssklower if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0)
26836368Ssklower goto bad;
26936368Ssklower
27036368Ssklower /* compute our address based upon firsthop/ifp */
27137469Ssklower if (ia)
27237469Ssklower our_addr = &ia->ia_addr.siso_addr;
27337469Ssklower else
27437469Ssklower goto bad;
27537469Ssklower ifp = ia->ia_ifp;
27636368Ssklower
27736368Ssklower IFDEBUG(D_DISCARD)
27836368Ssklower printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
27936368Ssklower printf(" from %s\n", clnp_iso_addrp(our_addr));
28036368Ssklower ENDDEBUG
28136368Ssklower
28236368Ssklower IFDEBUG(D_DISCARD)
28336368Ssklower printf("clnp_emit_er: packet routed to %s\n",
28436368Ssklower clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
28536368Ssklower ENDDEBUG
28636368Ssklower
28736368Ssklower /* allocate mbuf for er pdu header: punt on no space */
28836368Ssklower MGET(m0, M_DONTWAIT, MT_HEADER);
28936368Ssklower if (m0 == 0)
29036368Ssklower goto bad;
29136368Ssklower
29236368Ssklower m0->m_next = m;
29336368Ssklower er = mtod(m0, struct clnp_fixed *);
29436368Ssklower *er = er_template;
29536368Ssklower
29636368Ssklower /* setup src/dst on er pdu */
29736368Ssklower /* NOTE REVERSAL OF SRC/DST */
29836368Ssklower hoff = (caddr_t)er + sizeof(struct clnp_fixed);
29937469Ssklower CLNP_INSERT_ADDR(hoff, src);
30037469Ssklower CLNP_INSERT_ADDR(hoff, *our_addr);
30136368Ssklower
30236368Ssklower /*
30336368Ssklower * TODO: if complete src rt was specified, then reverse path, and
30436368Ssklower * copy into er as option.
30536368Ssklower */
30636368Ssklower
30736368Ssklower /* add er option */
30836368Ssklower *hoff++ = CLNPOVAL_ERREAS; /* code */
30936368Ssklower *hoff++ = 2; /* length */
31036368Ssklower *hoff++ = reason; /* discard reason */
31136368Ssklower *hoff++ = 0; /* error localization = not specified */
31236368Ssklower
31336368Ssklower /* set length */
31436368Ssklower er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
31536368Ssklower total_len = m0->m_len + m->m_len;
31636368Ssklower HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
31736368Ssklower
31836368Ssklower /* compute checksum (on header only) */
31936368Ssklower iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
32036368Ssklower
32136368Ssklower /* trim packet if too large for interface */
32236368Ssklower if (total_len > ifp->if_mtu)
32336368Ssklower m_adj(m0, -(total_len - ifp->if_mtu));
32436368Ssklower
32536368Ssklower /* send packet */
32639194Ssklower INCSTAT(cns_er_outhist[clnp_er_index(reason)]);
32740774Ssklower (void) (*ifp->if_output)(ifp, m0, first_hop, route.ro_rt);
32836368Ssklower goto done;
32936368Ssklower
33036368Ssklower bad:
33136368Ssklower m_freem(m);
33236368Ssklower
33336368Ssklower done:
33436368Ssklower /* free route if it is a temp */
33536368Ssklower if (route.ro_rt != NULL)
33636368Ssklower RTFREE(route.ro_rt);
33736368Ssklower }
33839194Ssklower
clnp_er_index(p)33939194Ssklower clnp_er_index(p)
34039194Ssklower u_char p;
34139194Ssklower {
34239194Ssklower register u_char *cp = clnp_er_codes + CLNP_ERRORS;
34339194Ssklower while (cp > clnp_er_codes) {
34439194Ssklower cp--;
34539194Ssklower if (*cp == p)
34639194Ssklower return (cp - clnp_er_codes);
34739194Ssklower }
34839194Ssklower return (CLNP_ERRORS + 1);
34939194Ssklower }
350