xref: /csrg-svn/sys/netiso/clnp_er.c (revision 37469)
136368Ssklower /***********************************************************
236368Ssklower 		Copyright IBM Corporation 1987
336368Ssklower 
436368Ssklower                       All Rights Reserved
536368Ssklower 
636368Ssklower Permission to use, copy, modify, and distribute this software and its
736368Ssklower documentation for any purpose and without fee is hereby granted,
836368Ssklower provided that the above copyright notice appear in all copies and that
936368Ssklower both that copyright notice and this permission notice appear in
1036368Ssklower supporting documentation, and that the name of IBM not be
1136368Ssklower used in advertising or publicity pertaining to distribution of the
1236368Ssklower software without specific, written prior permission.
1336368Ssklower 
1436368Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536368Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636368Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736368Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836368Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936368Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036368Ssklower SOFTWARE.
2136368Ssklower 
2236368Ssklower ******************************************************************/
2336368Ssklower 
2436368Ssklower /*
2536368Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636368Ssklower  */
2736763Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $ */
2836763Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_er.c,v $ */
2936368Ssklower 
3036368Ssklower #ifndef lint
3136763Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $";
3236368Ssklower #endif lint
3336368Ssklower 
3436368Ssklower #ifdef ISO
3536368Ssklower 
36*37469Ssklower #include "types.h"
37*37469Ssklower #include "param.h"
38*37469Ssklower #include "mbuf.h"
39*37469Ssklower #include "domain.h"
40*37469Ssklower #include "protosw.h"
41*37469Ssklower #include "socket.h"
42*37469Ssklower #include "socketvar.h"
43*37469Ssklower #include "errno.h"
4436368Ssklower 
4536368Ssklower #include "../net/if.h"
4636368Ssklower #include "../net/route.h"
4736368Ssklower 
48*37469Ssklower #include "iso.h"
49*37469Ssklower #include "iso_var.h"
50*37469Ssklower #include "iso_pcb.h"
51*37469Ssklower #include "clnp.h"
52*37469Ssklower #include "clnp_stat.h"
53*37469Ssklower #include "argo_debug.h"
5436368Ssklower 
5536368Ssklower static struct clnp_fixed er_template = {
5636368Ssklower 	ISO8473_CLNP,	/* network identifier */
5736368Ssklower 	0,				/* length */
5836368Ssklower 	ISO8473_V1,		/* version */
5936368Ssklower 	CLNP_TTL,		/* ttl */
6036368Ssklower 	CLNP_ER,		/* type */
6136368Ssklower 	0,				/* segment length */
6236368Ssklower 	0				/* checksum */
6336368Ssklower };
6436368Ssklower 
6536368Ssklower /*
6636368Ssklower  * FUNCTION:		clnp_er_input
6736368Ssklower  *
6836368Ssklower  * PURPOSE:			Process an ER pdu.
6936368Ssklower  *
7036368Ssklower  * RETURNS:
7136368Ssklower  *
7236368Ssklower  * SIDE EFFECTS:
7336368Ssklower  *
7436368Ssklower  * NOTES:
7536368Ssklower  */
7636368Ssklower clnp_er_input(m, src, reason)
7736368Ssklower struct mbuf		*m;		/* ptr to packet itself */
7836368Ssklower struct iso_addr	*src;	/* ptr to src of er */
79*37469Ssklower u_char			reason;	/* reason code of er */
8036368Ssklower {
8136368Ssklower 	int	cmd = -1;
8236368Ssklower 	extern u_char clnp_protox[];
8336368Ssklower 
8436368Ssklower 	IFDEBUG(D_CTLINPUT)
8536368Ssklower 		printf("clnp_er_input: m x%x, src %s, reason x%x\n", m,
8636368Ssklower 			clnp_iso_addrp(src), reason);
8736368Ssklower 	ENDDEBUG
8836368Ssklower 
8936368Ssklower 	INCSTAT(cns_errcvd);
9036368Ssklower 
9136368Ssklower 	switch (reason) {
9236368Ssklower 		case GEN_NOREAS:
9336368Ssklower 		case GEN_PROTOERR:
9436368Ssklower 			INCSTAT(er_protoerr);
9536368Ssklower 			break;
9636368Ssklower 		case GEN_BADCSUM:
9736368Ssklower 			cmd = PRC_PARAMPROB;
9836368Ssklower 			INCSTAT(er_badcsum);
9936368Ssklower 			break;
10036368Ssklower 		case GEN_CONGEST:
10136368Ssklower 			cmd = PRC_QUENCH;
10236368Ssklower 			INCSTAT(er_congest);
10336368Ssklower 			break;
10436368Ssklower 		case GEN_HDRSYNTAX:
10536368Ssklower 			cmd = PRC_PARAMPROB;
10636368Ssklower 			INCSTAT(er_protoerr);
10736368Ssklower 			break;
10836368Ssklower 		case GEN_SEGNEEDED:
10936368Ssklower 			cmd = PRC_UNREACH_NEEDFRAG;
11036368Ssklower 			INCSTAT(er_segneeded);
11136368Ssklower 			break;
11236368Ssklower 		case GEN_INCOMPLETE:
11336368Ssklower 			cmd = PRC_PARAMPROB;
11436368Ssklower 			INCSTAT(er_reassfail);
11536368Ssklower 			break;
11636368Ssklower 		case GEN_DUPOPT:
11736368Ssklower 			cmd = PRC_PARAMPROB;
11836368Ssklower 			INCSTAT(er_protoerr);
11936368Ssklower 			break;
12036368Ssklower 		case ADDR_DESTUNREACH:
12136368Ssklower 			cmd = PRC_UNREACH_HOST;
12236368Ssklower 			INCSTAT(er_dstunreach);
12336368Ssklower 			break;
12436368Ssklower 		case ADDR_DESTUNKNOWN:
12536368Ssklower 			cmd = PRC_UNREACH_PROTOCOL;
12636368Ssklower 			INCSTAT(er_dstunreach);
12736368Ssklower 			break;
12836368Ssklower 		case SRCRT_UNSPECERR:
12936368Ssklower 		case SRCRT_SYNTAX:
13036368Ssklower 		case SRCRT_UNKNOWNADDR:
13136368Ssklower 		case SRCRT_BADPATH:
13236368Ssklower 			cmd = PRC_UNREACH_SRCFAIL;
13336368Ssklower 			INCSTAT(er_srcrterr);
13436368Ssklower 			break;
13536368Ssklower 		case TTL_EXPTRANSIT:
13636368Ssklower 			cmd = PRC_TIMXCEED_INTRANS;
13736368Ssklower 			INCSTAT(er_ttlexpired);
13836368Ssklower 			break;
13936368Ssklower 		case TTL_EXPREASS:
14036368Ssklower 			cmd = PRC_TIMXCEED_REASS;
14136368Ssklower 			INCSTAT(er_ttlexpired);
14236368Ssklower 			break;
14336368Ssklower 		case DISC_UNSUPPOPT:
14436368Ssklower 		case DISC_UNSUPPVERS:
14536368Ssklower 		case DISC_UNSUPPSECURE:
14636368Ssklower 		case DISC_UNSUPPSRCRT:
14736368Ssklower 		case DISC_UNSUPPRECRT:
14836368Ssklower 			cmd = PRC_PARAMPROB;
14936368Ssklower 			INCSTAT(er_unsupported);
15036368Ssklower 			break;
15136368Ssklower 		case REASS_INTERFERE:
15236368Ssklower 			cmd = PRC_TIMXCEED_REASS;
15336368Ssklower 			INCSTAT(er_reassfail);
15436368Ssklower 			break;
15536368Ssklower 	}
15636368Ssklower 
15736763Ssklower 	/*
15836763Ssklower 	 *	tpclnp_ctlinput1 is called directly so that we don't
15936763Ssklower 	 *	have to build an iso_sockaddr out of src.
16036763Ssklower 	 */
16136368Ssklower 	if (cmd >= 0)
16236763Ssklower 		tpclnp_ctlinput1(cmd, src);
16336368Ssklower 
16436368Ssklower 	m_freem(m);
16536368Ssklower }
16636368Ssklower 
16736368Ssklower /*
16836368Ssklower  * FUNCTION:		clnp_discard
16936368Ssklower  *
17036368Ssklower  * PURPOSE:			Discard a clnp datagram
17136368Ssklower  *
17236368Ssklower  * RETURNS:			nothing
17336368Ssklower  *
17436368Ssklower  * SIDE EFFECTS:	Will emit an ER pdu if possible
17536368Ssklower  *
17636368Ssklower  * NOTES:			This code assumes that we have previously tried to pull
17736368Ssklower  *					up the header of the datagram into one mbuf.
17836368Ssklower  */
17936368Ssklower clnp_discard(m, reason)
18036368Ssklower struct mbuf	*m;		/* header of packet to discard */
18136368Ssklower char					reason;	/* reason for discard */
18236368Ssklower {
18336368Ssklower 	IFDEBUG(D_DISCARD)
18436368Ssklower 		printf("clnp_discard: m x%x, reason x%x\n", m, reason);
18536368Ssklower 	ENDDEBUG
18636368Ssklower 
18736368Ssklower 	if (m != NULL) {
18836368Ssklower 		if (m->m_len >= sizeof(struct clnp_fixed)) {
18936368Ssklower 			register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
19036368Ssklower 
191*37469Ssklower 			if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
192*37469Ssklower 				(clnp->cnf_type & CNF_ERR_OK)) {
193*37469Ssklower 					clnp_emit_er(m, reason);
194*37469Ssklower 					return;
19536368Ssklower 			}
19636368Ssklower 		}
19736368Ssklower 		m_freem(m);
19836368Ssklower 	}
19936368Ssklower }
20036368Ssklower 
20136368Ssklower /*
20236368Ssklower  * FUNCTION:		clnp_emit_er
20336368Ssklower  *
20436368Ssklower  * PURPOSE:			Send an ER pdu.
20536368Ssklower  *					The src of the of the ER pdu is the host that is sending
20636368Ssklower  *					the ER (ie. us), *not* the original destination of the
20736368Ssklower  *					packet.
20836368Ssklower  *
20936368Ssklower  * RETURNS:			nothing
21036368Ssklower  *
21136368Ssklower  * SIDE EFFECTS:
21236368Ssklower  *
21336368Ssklower  * NOTES:			Takes responsibility for freeing mbuf passed
21436368Ssklower  *					This function may be called with a packet that
21536368Ssklower  *					was created by us; in this case, do not send
21636368Ssklower  *					an ER.
21736368Ssklower  */
21836368Ssklower clnp_emit_er(m, reason)
21936368Ssklower struct mbuf	*m;		/* header of packet to discard */
22036368Ssklower char					reason;	/* reason for discard */
22136368Ssklower {
22236368Ssklower 	register struct clnp_fixed	*clnp = mtod(m, struct clnp_fixed *);
22336368Ssklower 	register struct clnp_fixed	*er;
224*37469Ssklower 	struct route_iso			route;
22536368Ssklower 	struct ifnet				*ifp;
22636368Ssklower 	struct sockaddr				*first_hop;
22736368Ssklower 	struct iso_addr				src, dst, *our_addr;
22836368Ssklower 	caddr_t						hoff, hend;
22936368Ssklower 	int							total_len;		/* total len of dg */
23036368Ssklower 	struct mbuf 				*m0;			/* contains er pdu hdr */
231*37469Ssklower 	struct iso_ifaddr			*ia = 0;
23236368Ssklower 
23336368Ssklower 	IFDEBUG(D_DISCARD)
23436368Ssklower 		printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
23536368Ssklower 	ENDDEBUG
23636368Ssklower 
23736368Ssklower 	bzero((caddr_t)&route, sizeof(route));
23836368Ssklower 
23936368Ssklower 	/*
24036368Ssklower 	 *	If header length is incorrect, or entire header is not contained
24136368Ssklower 	 *	in this mbuf, we punt
24236368Ssklower 	 */
24336368Ssklower 	if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
24436368Ssklower 		(clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
24536368Ssklower 		(clnp->cnf_hdr_len > m->m_len))
24636368Ssklower 		goto bad;
24736368Ssklower 
24836368Ssklower 	/* extract src, dest address */
24936368Ssklower 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
25036368Ssklower 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
25136368Ssklower 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
25236368Ssklower 	if (hoff == (caddr_t)0) {
25336368Ssklower 		goto bad;
25436368Ssklower 	}
25536368Ssklower 	CLNP_EXTRACT_ADDR(src, hoff, hend);
25636368Ssklower 	if (hoff == (caddr_t)0) {
25736368Ssklower 		goto bad;
25836368Ssklower 	}
25936368Ssklower 
26036368Ssklower 	/*
26136368Ssklower 	 *	Do not send ER if we generated the packet.
26236368Ssklower 	 */
26336368Ssklower 	if (clnp_ours(&src))
26436368Ssklower 		goto bad;
26536368Ssklower 
26636368Ssklower 	/*
26736368Ssklower 	 *	Trim mbuf to hold only the header.
26836368Ssklower 	 *	This mbuf will be the 'data' of the er pdu
26936368Ssklower 	 */
27036368Ssklower 	if (m->m_next != NULL) {
27136368Ssklower 		m_freem(m->m_next);
27236368Ssklower 		m->m_next = NULL;
27336368Ssklower 	}
27436368Ssklower 
27536368Ssklower 	if (m->m_len > clnp->cnf_hdr_len)
276*37469Ssklower 		m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len));
27736368Ssklower 
27836368Ssklower 	/* route er pdu: note we send pkt to src of original packet  */
279*37469Ssklower 	if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0)
28036368Ssklower 		goto bad;
28136368Ssklower 
28236368Ssklower 	/* compute our address based upon firsthop/ifp */
283*37469Ssklower 	if (ia)
284*37469Ssklower 			our_addr = &ia->ia_addr.siso_addr;
285*37469Ssklower 	else
286*37469Ssklower 			goto bad;
287*37469Ssklower 	ifp = ia->ia_ifp;
28836368Ssklower 
28936368Ssklower 	IFDEBUG(D_DISCARD)
29036368Ssklower 		printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
29136368Ssklower 		printf(" from %s\n", clnp_iso_addrp(our_addr));
29236368Ssklower 	ENDDEBUG
29336368Ssklower 
29436368Ssklower 	IFDEBUG(D_DISCARD)
29536368Ssklower 		printf("clnp_emit_er: packet routed to %s\n",
29636368Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
29736368Ssklower 	ENDDEBUG
29836368Ssklower 
29936368Ssklower 	/* allocate mbuf for er pdu header: punt on no space */
30036368Ssklower 	MGET(m0, M_DONTWAIT, MT_HEADER);
30136368Ssklower 	if (m0 == 0)
30236368Ssklower 		goto bad;
30336368Ssklower 
30436368Ssklower 	m0->m_next = m;
30536368Ssklower 	er = mtod(m0, struct clnp_fixed *);
30636368Ssklower 	*er = er_template;
30736368Ssklower 
30836368Ssklower 	/* setup src/dst on er pdu */
30936368Ssklower 	/* NOTE REVERSAL OF SRC/DST */
31036368Ssklower 	hoff = (caddr_t)er + sizeof(struct clnp_fixed);
311*37469Ssklower 	CLNP_INSERT_ADDR(hoff, src);
312*37469Ssklower 	CLNP_INSERT_ADDR(hoff, *our_addr);
31336368Ssklower 
31436368Ssklower 	/*
31536368Ssklower 	 *	TODO: if complete src rt was specified, then reverse path, and
31636368Ssklower 	 *	copy into er as option.
31736368Ssklower 	 */
31836368Ssklower 
31936368Ssklower 	/* add er option */
32036368Ssklower 	*hoff++ = CLNPOVAL_ERREAS;	/* code */
32136368Ssklower 	*hoff++ = 2;				/* length */
32236368Ssklower 	*hoff++ = reason;			/* discard reason */
32336368Ssklower 	*hoff++ = 0;				/* error localization = not specified */
32436368Ssklower 
32536368Ssklower 	/* set length */
32636368Ssklower 	er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
32736368Ssklower 	total_len = m0->m_len + m->m_len;
32836368Ssklower 	HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
32936368Ssklower 
33036368Ssklower 	/* compute checksum (on header only) */
33136368Ssklower 	iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
33236368Ssklower 
33336368Ssklower 	/* trim packet if too large for interface */
33436368Ssklower 	if (total_len > ifp->if_mtu)
33536368Ssklower 		m_adj(m0, -(total_len - ifp->if_mtu));
33636368Ssklower 
33736368Ssklower 	/* send packet */
33836368Ssklower 	(void) (*ifp->if_output)(ifp, m0, first_hop);
33936368Ssklower 	goto done;
34036368Ssklower 
34136368Ssklower bad:
34236368Ssklower 	m_freem(m);
34336368Ssklower 
34436368Ssklower done:
34536368Ssklower 	/* free route if it is a temp */
34636368Ssklower 	if (route.ro_rt != NULL)
34736368Ssklower 		RTFREE(route.ro_rt);
34836368Ssklower }
34936368Ssklower #endif	ISO
350