xref: /csrg-svn/sys/netiso/clnp_er.c (revision 39194)
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 $ */
29*39194Ssklower /*	@(#)clnp_er.c	7.5 (Berkeley) 09/22/89 */
3036368Ssklower 
3136368Ssklower #ifndef lint
3236763Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $";
3336368Ssklower #endif lint
3436368Ssklower 
3537469Ssklower #include "param.h"
3637469Ssklower #include "mbuf.h"
3737469Ssklower #include "domain.h"
3837469Ssklower #include "protosw.h"
3937469Ssklower #include "socket.h"
4037469Ssklower #include "socketvar.h"
4137469Ssklower #include "errno.h"
4236368Ssklower 
4336368Ssklower #include "../net/if.h"
4436368Ssklower #include "../net/route.h"
4536368Ssklower 
4637469Ssklower #include "iso.h"
4737469Ssklower #include "iso_var.h"
4837469Ssklower #include "iso_pcb.h"
49*39194Ssklower #define CLNP_ER_CODES
5037469Ssklower #include "clnp.h"
5137469Ssklower #include "clnp_stat.h"
5237469Ssklower #include "argo_debug.h"
5336368Ssklower 
5436368Ssklower static struct clnp_fixed er_template = {
5536368Ssklower 	ISO8473_CLNP,	/* network identifier */
5636368Ssklower 	0,				/* length */
5736368Ssklower 	ISO8473_V1,		/* version */
5836368Ssklower 	CLNP_TTL,		/* ttl */
5936368Ssklower 	CLNP_ER,		/* type */
6036368Ssklower 	0,				/* segment length */
6136368Ssklower 	0				/* checksum */
6236368Ssklower };
6336368Ssklower 
6436368Ssklower /*
6536368Ssklower  * FUNCTION:		clnp_er_input
6636368Ssklower  *
6736368Ssklower  * PURPOSE:			Process an ER pdu.
6836368Ssklower  *
6936368Ssklower  * RETURNS:
7036368Ssklower  *
7136368Ssklower  * SIDE EFFECTS:
7236368Ssklower  *
7336368Ssklower  * NOTES:
7436368Ssklower  */
7536368Ssklower clnp_er_input(m, src, reason)
7636368Ssklower struct mbuf		*m;		/* ptr to packet itself */
7736368Ssklower struct iso_addr	*src;	/* ptr to src of er */
7837469Ssklower u_char			reason;	/* reason code of er */
7936368Ssklower {
8036368Ssklower 	int	cmd = -1;
8136368Ssklower 	extern u_char clnp_protox[];
8236368Ssklower 
8336368Ssklower 	IFDEBUG(D_CTLINPUT)
8436368Ssklower 		printf("clnp_er_input: m x%x, src %s, reason x%x\n", m,
8536368Ssklower 			clnp_iso_addrp(src), reason);
8636368Ssklower 	ENDDEBUG
8736368Ssklower 
88*39194Ssklower 	INCSTAT(cns_er_inhist[clnp_er_index(reason)]);
8936368Ssklower 	switch (reason) {
9036368Ssklower 		case GEN_NOREAS:
9136368Ssklower 		case GEN_PROTOERR:
9236368Ssklower 			break;
9336368Ssklower 		case GEN_BADCSUM:
9436368Ssklower 			cmd = PRC_PARAMPROB;
9536368Ssklower 			break;
9636368Ssklower 		case GEN_CONGEST:
9736368Ssklower 			cmd = PRC_QUENCH;
9836368Ssklower 			break;
9936368Ssklower 		case GEN_HDRSYNTAX:
10036368Ssklower 			cmd = PRC_PARAMPROB;
10136368Ssklower 			break;
10236368Ssklower 		case GEN_SEGNEEDED:
10336368Ssklower 			cmd = PRC_UNREACH_NEEDFRAG;
10436368Ssklower 			break;
10536368Ssklower 		case GEN_INCOMPLETE:
10636368Ssklower 			cmd = PRC_PARAMPROB;
10736368Ssklower 			break;
10836368Ssklower 		case GEN_DUPOPT:
10936368Ssklower 			cmd = PRC_PARAMPROB;
11036368Ssklower 			break;
11136368Ssklower 		case ADDR_DESTUNREACH:
11236368Ssklower 			cmd = PRC_UNREACH_HOST;
11336368Ssklower 			break;
11436368Ssklower 		case ADDR_DESTUNKNOWN:
11536368Ssklower 			cmd = PRC_UNREACH_PROTOCOL;
11636368Ssklower 			break;
11736368Ssklower 		case SRCRT_UNSPECERR:
11836368Ssklower 		case SRCRT_SYNTAX:
11936368Ssklower 		case SRCRT_UNKNOWNADDR:
12036368Ssklower 		case SRCRT_BADPATH:
12136368Ssklower 			cmd = PRC_UNREACH_SRCFAIL;
12236368Ssklower 			break;
12336368Ssklower 		case TTL_EXPTRANSIT:
12436368Ssklower 			cmd = PRC_TIMXCEED_INTRANS;
12536368Ssklower 			break;
12636368Ssklower 		case TTL_EXPREASS:
12736368Ssklower 			cmd = PRC_TIMXCEED_REASS;
12836368Ssklower 			break;
12936368Ssklower 		case DISC_UNSUPPOPT:
13036368Ssklower 		case DISC_UNSUPPVERS:
13136368Ssklower 		case DISC_UNSUPPSECURE:
13236368Ssklower 		case DISC_UNSUPPSRCRT:
13336368Ssklower 		case DISC_UNSUPPRECRT:
13436368Ssklower 			cmd = PRC_PARAMPROB;
13536368Ssklower 			break;
13636368Ssklower 		case REASS_INTERFERE:
13736368Ssklower 			cmd = PRC_TIMXCEED_REASS;
13836368Ssklower 			break;
13936368Ssklower 	}
14036368Ssklower 
14136763Ssklower 	/*
14236763Ssklower 	 *	tpclnp_ctlinput1 is called directly so that we don't
14336763Ssklower 	 *	have to build an iso_sockaddr out of src.
14436763Ssklower 	 */
14536368Ssklower 	if (cmd >= 0)
14636763Ssklower 		tpclnp_ctlinput1(cmd, src);
14736368Ssklower 
14836368Ssklower 	m_freem(m);
14936368Ssklower }
15036368Ssklower 
15136368Ssklower /*
15236368Ssklower  * FUNCTION:		clnp_discard
15336368Ssklower  *
15436368Ssklower  * PURPOSE:			Discard a clnp datagram
15536368Ssklower  *
15636368Ssklower  * RETURNS:			nothing
15736368Ssklower  *
15836368Ssklower  * SIDE EFFECTS:	Will emit an ER pdu if possible
15936368Ssklower  *
16036368Ssklower  * NOTES:			This code assumes that we have previously tried to pull
16136368Ssklower  *					up the header of the datagram into one mbuf.
16236368Ssklower  */
16336368Ssklower clnp_discard(m, reason)
16436368Ssklower struct mbuf	*m;		/* header of packet to discard */
16536368Ssklower char					reason;	/* reason for discard */
16636368Ssklower {
16736368Ssklower 	IFDEBUG(D_DISCARD)
16836368Ssklower 		printf("clnp_discard: m x%x, reason x%x\n", m, reason);
16936368Ssklower 	ENDDEBUG
17036368Ssklower 
17136368Ssklower 	if (m != NULL) {
17236368Ssklower 		if (m->m_len >= sizeof(struct clnp_fixed)) {
17336368Ssklower 			register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
17436368Ssklower 
17537469Ssklower 			if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
17637469Ssklower 				(clnp->cnf_type & CNF_ERR_OK)) {
17737469Ssklower 					clnp_emit_er(m, reason);
17837469Ssklower 					return;
17936368Ssklower 			}
18036368Ssklower 		}
18136368Ssklower 		m_freem(m);
18236368Ssklower 	}
18336368Ssklower }
18436368Ssklower 
18536368Ssklower /*
18636368Ssklower  * FUNCTION:		clnp_emit_er
18736368Ssklower  *
18836368Ssklower  * PURPOSE:			Send an ER pdu.
18936368Ssklower  *					The src of the of the ER pdu is the host that is sending
19036368Ssklower  *					the ER (ie. us), *not* the original destination of the
19136368Ssklower  *					packet.
19236368Ssklower  *
19336368Ssklower  * RETURNS:			nothing
19436368Ssklower  *
19536368Ssklower  * SIDE EFFECTS:
19636368Ssklower  *
19736368Ssklower  * NOTES:			Takes responsibility for freeing mbuf passed
19836368Ssklower  *					This function may be called with a packet that
19936368Ssklower  *					was created by us; in this case, do not send
20036368Ssklower  *					an ER.
20136368Ssklower  */
20236368Ssklower clnp_emit_er(m, reason)
20336368Ssklower struct mbuf	*m;		/* header of packet to discard */
20436368Ssklower char					reason;	/* reason for discard */
20536368Ssklower {
20636368Ssklower 	register struct clnp_fixed	*clnp = mtod(m, struct clnp_fixed *);
20736368Ssklower 	register struct clnp_fixed	*er;
20837469Ssklower 	struct route_iso			route;
20936368Ssklower 	struct ifnet				*ifp;
21036368Ssklower 	struct sockaddr				*first_hop;
21136368Ssklower 	struct iso_addr				src, dst, *our_addr;
21236368Ssklower 	caddr_t						hoff, hend;
21336368Ssklower 	int							total_len;		/* total len of dg */
21436368Ssklower 	struct mbuf 				*m0;			/* contains er pdu hdr */
21537469Ssklower 	struct iso_ifaddr			*ia = 0;
21636368Ssklower 
21736368Ssklower 	IFDEBUG(D_DISCARD)
21836368Ssklower 		printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
21936368Ssklower 	ENDDEBUG
22036368Ssklower 
22136368Ssklower 	bzero((caddr_t)&route, sizeof(route));
22236368Ssklower 
22336368Ssklower 	/*
22436368Ssklower 	 *	If header length is incorrect, or entire header is not contained
22536368Ssklower 	 *	in this mbuf, we punt
22636368Ssklower 	 */
22736368Ssklower 	if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
22836368Ssklower 		(clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
22936368Ssklower 		(clnp->cnf_hdr_len > m->m_len))
23036368Ssklower 		goto bad;
23136368Ssklower 
23236368Ssklower 	/* extract src, dest address */
23336368Ssklower 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
23436368Ssklower 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
23536368Ssklower 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
23636368Ssklower 	if (hoff == (caddr_t)0) {
23736368Ssklower 		goto bad;
23836368Ssklower 	}
23936368Ssklower 	CLNP_EXTRACT_ADDR(src, hoff, hend);
24036368Ssklower 	if (hoff == (caddr_t)0) {
24136368Ssklower 		goto bad;
24236368Ssklower 	}
24336368Ssklower 
24436368Ssklower 	/*
24536368Ssklower 	 *	Do not send ER if we generated the packet.
24636368Ssklower 	 */
24736368Ssklower 	if (clnp_ours(&src))
24836368Ssklower 		goto bad;
24936368Ssklower 
25036368Ssklower 	/*
25136368Ssklower 	 *	Trim mbuf to hold only the header.
25236368Ssklower 	 *	This mbuf will be the 'data' of the er pdu
25336368Ssklower 	 */
25436368Ssklower 	if (m->m_next != NULL) {
25536368Ssklower 		m_freem(m->m_next);
25636368Ssklower 		m->m_next = NULL;
25736368Ssklower 	}
25836368Ssklower 
25936368Ssklower 	if (m->m_len > clnp->cnf_hdr_len)
26037469Ssklower 		m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len));
26136368Ssklower 
26236368Ssklower 	/* route er pdu: note we send pkt to src of original packet  */
26337469Ssklower 	if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0)
26436368Ssklower 		goto bad;
26536368Ssklower 
26636368Ssklower 	/* compute our address based upon firsthop/ifp */
26737469Ssklower 	if (ia)
26837469Ssklower 			our_addr = &ia->ia_addr.siso_addr;
26937469Ssklower 	else
27037469Ssklower 			goto bad;
27137469Ssklower 	ifp = ia->ia_ifp;
27236368Ssklower 
27336368Ssklower 	IFDEBUG(D_DISCARD)
27436368Ssklower 		printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
27536368Ssklower 		printf(" from %s\n", clnp_iso_addrp(our_addr));
27636368Ssklower 	ENDDEBUG
27736368Ssklower 
27836368Ssklower 	IFDEBUG(D_DISCARD)
27936368Ssklower 		printf("clnp_emit_er: packet routed to %s\n",
28036368Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
28136368Ssklower 	ENDDEBUG
28236368Ssklower 
28336368Ssklower 	/* allocate mbuf for er pdu header: punt on no space */
28436368Ssklower 	MGET(m0, M_DONTWAIT, MT_HEADER);
28536368Ssklower 	if (m0 == 0)
28636368Ssklower 		goto bad;
28736368Ssklower 
28836368Ssklower 	m0->m_next = m;
28936368Ssklower 	er = mtod(m0, struct clnp_fixed *);
29036368Ssklower 	*er = er_template;
29136368Ssklower 
29236368Ssklower 	/* setup src/dst on er pdu */
29336368Ssklower 	/* NOTE REVERSAL OF SRC/DST */
29436368Ssklower 	hoff = (caddr_t)er + sizeof(struct clnp_fixed);
29537469Ssklower 	CLNP_INSERT_ADDR(hoff, src);
29637469Ssklower 	CLNP_INSERT_ADDR(hoff, *our_addr);
29736368Ssklower 
29836368Ssklower 	/*
29936368Ssklower 	 *	TODO: if complete src rt was specified, then reverse path, and
30036368Ssklower 	 *	copy into er as option.
30136368Ssklower 	 */
30236368Ssklower 
30336368Ssklower 	/* add er option */
30436368Ssklower 	*hoff++ = CLNPOVAL_ERREAS;	/* code */
30536368Ssklower 	*hoff++ = 2;				/* length */
30636368Ssklower 	*hoff++ = reason;			/* discard reason */
30736368Ssklower 	*hoff++ = 0;				/* error localization = not specified */
30836368Ssklower 
30936368Ssklower 	/* set length */
31036368Ssklower 	er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
31136368Ssklower 	total_len = m0->m_len + m->m_len;
31236368Ssklower 	HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
31336368Ssklower 
31436368Ssklower 	/* compute checksum (on header only) */
31536368Ssklower 	iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
31636368Ssklower 
31736368Ssklower 	/* trim packet if too large for interface */
31836368Ssklower 	if (total_len > ifp->if_mtu)
31936368Ssklower 		m_adj(m0, -(total_len - ifp->if_mtu));
32036368Ssklower 
32136368Ssklower 	/* send packet */
322*39194Ssklower 	INCSTAT(cns_er_outhist[clnp_er_index(reason)]);
32336368Ssklower 	(void) (*ifp->if_output)(ifp, m0, first_hop);
32436368Ssklower 	goto done;
32536368Ssklower 
32636368Ssklower bad:
32736368Ssklower 	m_freem(m);
32836368Ssklower 
32936368Ssklower done:
33036368Ssklower 	/* free route if it is a temp */
33136368Ssklower 	if (route.ro_rt != NULL)
33236368Ssklower 		RTFREE(route.ro_rt);
33336368Ssklower }
334*39194Ssklower 
335*39194Ssklower clnp_er_index(p)
336*39194Ssklower u_char p;
337*39194Ssklower {
338*39194Ssklower 	register u_char *cp = clnp_er_codes + CLNP_ERRORS;
339*39194Ssklower 	while (cp > clnp_er_codes) {
340*39194Ssklower 		cp--;
341*39194Ssklower 		if (*cp == p)
342*39194Ssklower 			return (cp - clnp_er_codes);
343*39194Ssklower 	}
344*39194Ssklower 	return (CLNP_ERRORS + 1);
345*39194Ssklower }
346