xref: /csrg-svn/sys/netiso/clnp_er.c (revision 63222)
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