xref: /csrg-svn/sys/netiso/clnp_er.c (revision 36368)
1*36368Ssklower /***********************************************************
2*36368Ssklower 		Copyright IBM Corporation 1987
3*36368Ssklower 
4*36368Ssklower                       All Rights Reserved
5*36368Ssklower 
6*36368Ssklower Permission to use, copy, modify, and distribute this software and its
7*36368Ssklower documentation for any purpose and without fee is hereby granted,
8*36368Ssklower provided that the above copyright notice appear in all copies and that
9*36368Ssklower both that copyright notice and this permission notice appear in
10*36368Ssklower supporting documentation, and that the name of IBM not be
11*36368Ssklower used in advertising or publicity pertaining to distribution of the
12*36368Ssklower software without specific, written prior permission.
13*36368Ssklower 
14*36368Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36368Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36368Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36368Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36368Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36368Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36368Ssklower SOFTWARE.
21*36368Ssklower 
22*36368Ssklower ******************************************************************/
23*36368Ssklower 
24*36368Ssklower /*
25*36368Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36368Ssklower  */
27*36368Ssklower /* $Header: clnp_er.c,v 4.4 88/09/10 18:31:10 hagens Exp $ */
28*36368Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_er.c,v $ */
29*36368Ssklower 
30*36368Ssklower #ifndef lint
31*36368Ssklower static char *rcsid = "$Header: clnp_er.c,v 4.4 88/09/10 18:31:10 hagens Exp $";
32*36368Ssklower #endif lint
33*36368Ssklower 
34*36368Ssklower #ifdef ISO
35*36368Ssklower 
36*36368Ssklower #include "../h/types.h"
37*36368Ssklower #include "../h/param.h"
38*36368Ssklower #include "../h/mbuf.h"
39*36368Ssklower #include "../h/domain.h"
40*36368Ssklower #include "../h/protosw.h"
41*36368Ssklower #include "../h/socket.h"
42*36368Ssklower #include "../h/socketvar.h"
43*36368Ssklower #include "../h/errno.h"
44*36368Ssklower 
45*36368Ssklower #include "../net/if.h"
46*36368Ssklower #include "../net/route.h"
47*36368Ssklower 
48*36368Ssklower #include "../netiso/iso.h"
49*36368Ssklower #include "../netiso/clnp.h"
50*36368Ssklower #include "../netiso/clnp_stat.h"
51*36368Ssklower #include "../netiso/argo_debug.h"
52*36368Ssklower 
53*36368Ssklower static struct clnp_fixed er_template = {
54*36368Ssklower 	ISO8473_CLNP,	/* network identifier */
55*36368Ssklower 	0,				/* length */
56*36368Ssklower 	ISO8473_V1,		/* version */
57*36368Ssklower 	CLNP_TTL,		/* ttl */
58*36368Ssklower #if BYTE_ORDER == LITTLE_ENDIAN
59*36368Ssklower 	CLNP_ER,		/* type */
60*36368Ssklower 	0, 				/* error report */
61*36368Ssklower 	0, 				/* more segments */
62*36368Ssklower 	0, 				/* segmentation permitted */
63*36368Ssklower #endif
64*36368Ssklower #if BYTE_ORDER == BIG_ENDIAN
65*36368Ssklower 	0, 				/* segmentation permitted */
66*36368Ssklower 	0, 				/* more segments */
67*36368Ssklower 	0, 				/* error report */
68*36368Ssklower 	CLNP_ER,		/* type */
69*36368Ssklower #endif
70*36368Ssklower 	0,				/* segment length */
71*36368Ssklower 	0				/* checksum */
72*36368Ssklower };
73*36368Ssklower 
74*36368Ssklower /*
75*36368Ssklower  * FUNCTION:		clnp_er_input
76*36368Ssklower  *
77*36368Ssklower  * PURPOSE:			Process an ER pdu.
78*36368Ssklower  *
79*36368Ssklower  * RETURNS:
80*36368Ssklower  *
81*36368Ssklower  * SIDE EFFECTS:
82*36368Ssklower  *
83*36368Ssklower  * NOTES:
84*36368Ssklower  */
85*36368Ssklower clnp_er_input(m, src, reason)
86*36368Ssklower struct mbuf		*m;		/* ptr to packet itself */
87*36368Ssklower struct iso_addr	*src;	/* ptr to src of er */
88*36368Ssklower char			reason;	/* reason code of er */
89*36368Ssklower {
90*36368Ssklower 	int	cmd = -1;
91*36368Ssklower 	extern u_char clnp_protox[];
92*36368Ssklower 
93*36368Ssklower 	IFDEBUG(D_CTLINPUT)
94*36368Ssklower 		printf("clnp_er_input: m x%x, src %s, reason x%x\n", m,
95*36368Ssklower 			clnp_iso_addrp(src), reason);
96*36368Ssklower 	ENDDEBUG
97*36368Ssklower 
98*36368Ssklower 	INCSTAT(cns_errcvd);
99*36368Ssklower 
100*36368Ssklower 	switch (reason) {
101*36368Ssklower 		case GEN_NOREAS:
102*36368Ssklower 		case GEN_PROTOERR:
103*36368Ssklower 			INCSTAT(er_protoerr);
104*36368Ssklower 			break;
105*36368Ssklower 		case GEN_BADCSUM:
106*36368Ssklower 			cmd = PRC_PARAMPROB;
107*36368Ssklower 			INCSTAT(er_badcsum);
108*36368Ssklower 			break;
109*36368Ssklower 		case GEN_CONGEST:
110*36368Ssklower 			cmd = PRC_QUENCH;
111*36368Ssklower 			INCSTAT(er_congest);
112*36368Ssklower 			break;
113*36368Ssklower 		case GEN_HDRSYNTAX:
114*36368Ssklower 			cmd = PRC_PARAMPROB;
115*36368Ssklower 			INCSTAT(er_protoerr);
116*36368Ssklower 			break;
117*36368Ssklower 		case GEN_SEGNEEDED:
118*36368Ssklower 			cmd = PRC_UNREACH_NEEDFRAG;
119*36368Ssklower 			INCSTAT(er_segneeded);
120*36368Ssklower 			break;
121*36368Ssklower 		case GEN_INCOMPLETE:
122*36368Ssklower 			cmd = PRC_PARAMPROB;
123*36368Ssklower 			INCSTAT(er_reassfail);
124*36368Ssklower 			break;
125*36368Ssklower 		case GEN_DUPOPT:
126*36368Ssklower 			cmd = PRC_PARAMPROB;
127*36368Ssklower 			INCSTAT(er_protoerr);
128*36368Ssklower 			break;
129*36368Ssklower 		case ADDR_DESTUNREACH:
130*36368Ssklower 			cmd = PRC_UNREACH_HOST;
131*36368Ssklower 			INCSTAT(er_dstunreach);
132*36368Ssklower 			break;
133*36368Ssklower 		case ADDR_DESTUNKNOWN:
134*36368Ssklower 			cmd = PRC_UNREACH_PROTOCOL;
135*36368Ssklower 			INCSTAT(er_dstunreach);
136*36368Ssklower 			break;
137*36368Ssklower 		case SRCRT_UNSPECERR:
138*36368Ssklower 		case SRCRT_SYNTAX:
139*36368Ssklower 		case SRCRT_UNKNOWNADDR:
140*36368Ssklower 		case SRCRT_BADPATH:
141*36368Ssklower 			cmd = PRC_UNREACH_SRCFAIL;
142*36368Ssklower 			INCSTAT(er_srcrterr);
143*36368Ssklower 			break;
144*36368Ssklower 		case TTL_EXPTRANSIT:
145*36368Ssklower 			cmd = PRC_TIMXCEED_INTRANS;
146*36368Ssklower 			INCSTAT(er_ttlexpired);
147*36368Ssklower 			break;
148*36368Ssklower 		case TTL_EXPREASS:
149*36368Ssklower 			cmd = PRC_TIMXCEED_REASS;
150*36368Ssklower 			INCSTAT(er_ttlexpired);
151*36368Ssklower 			break;
152*36368Ssklower 		case DISC_UNSUPPOPT:
153*36368Ssklower 		case DISC_UNSUPPVERS:
154*36368Ssklower 		case DISC_UNSUPPSECURE:
155*36368Ssklower 		case DISC_UNSUPPSRCRT:
156*36368Ssklower 		case DISC_UNSUPPRECRT:
157*36368Ssklower 			cmd = PRC_PARAMPROB;
158*36368Ssklower 			INCSTAT(er_unsupported);
159*36368Ssklower 			break;
160*36368Ssklower 		case REASS_INTERFERE:
161*36368Ssklower 			cmd = PRC_TIMXCEED_REASS;
162*36368Ssklower 			INCSTAT(er_reassfail);
163*36368Ssklower 			break;
164*36368Ssklower 	}
165*36368Ssklower 
166*36368Ssklower 	if (cmd >= 0)
167*36368Ssklower 		(*isosw[clnp_protox[ISOPROTO_TP]].pr_ctlinput)(cmd, src);
168*36368Ssklower 
169*36368Ssklower 	m_freem(m);
170*36368Ssklower }
171*36368Ssklower 
172*36368Ssklower /*
173*36368Ssklower  * FUNCTION:		clnp_discard
174*36368Ssklower  *
175*36368Ssklower  * PURPOSE:			Discard a clnp datagram
176*36368Ssklower  *
177*36368Ssklower  * RETURNS:			nothing
178*36368Ssklower  *
179*36368Ssklower  * SIDE EFFECTS:	Will emit an ER pdu if possible
180*36368Ssklower  *
181*36368Ssklower  * NOTES:			This code assumes that we have previously tried to pull
182*36368Ssklower  *					up the header of the datagram into one mbuf.
183*36368Ssklower  */
184*36368Ssklower clnp_discard(m, reason)
185*36368Ssklower struct mbuf	*m;		/* header of packet to discard */
186*36368Ssklower char					reason;	/* reason for discard */
187*36368Ssklower {
188*36368Ssklower 	IFDEBUG(D_DISCARD)
189*36368Ssklower 		printf("clnp_discard: m x%x, reason x%x\n", m, reason);
190*36368Ssklower 	ENDDEBUG
191*36368Ssklower 
192*36368Ssklower 	if (m != NULL) {
193*36368Ssklower 		if (m->m_len >= sizeof(struct clnp_fixed)) {
194*36368Ssklower 			register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
195*36368Ssklower 
196*36368Ssklower 			if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_err_ok)) {
197*36368Ssklower 				clnp_emit_er(m, reason);
198*36368Ssklower 				return;
199*36368Ssklower 			}
200*36368Ssklower 		}
201*36368Ssklower 		m_freem(m);
202*36368Ssklower 	}
203*36368Ssklower }
204*36368Ssklower 
205*36368Ssklower /*
206*36368Ssklower  * FUNCTION:		clnp_emit_er
207*36368Ssklower  *
208*36368Ssklower  * PURPOSE:			Send an ER pdu.
209*36368Ssklower  *					The src of the of the ER pdu is the host that is sending
210*36368Ssklower  *					the ER (ie. us), *not* the original destination of the
211*36368Ssklower  *					packet.
212*36368Ssklower  *
213*36368Ssklower  * RETURNS:			nothing
214*36368Ssklower  *
215*36368Ssklower  * SIDE EFFECTS:
216*36368Ssklower  *
217*36368Ssklower  * NOTES:			Takes responsibility for freeing mbuf passed
218*36368Ssklower  *					This function may be called with a packet that
219*36368Ssklower  *					was created by us; in this case, do not send
220*36368Ssklower  *					an ER.
221*36368Ssklower  */
222*36368Ssklower clnp_emit_er(m, reason)
223*36368Ssklower struct mbuf	*m;		/* header of packet to discard */
224*36368Ssklower char					reason;	/* reason for discard */
225*36368Ssklower {
226*36368Ssklower 	register struct clnp_fixed	*clnp = mtod(m, struct clnp_fixed *);
227*36368Ssklower 	register struct clnp_fixed	*er;
228*36368Ssklower 	struct route				route;
229*36368Ssklower 	struct ifnet				*ifp;
230*36368Ssklower 	struct sockaddr				*first_hop;
231*36368Ssklower 	struct iso_addr				src, dst, *our_addr;
232*36368Ssklower 	caddr_t						hoff, hend;
233*36368Ssklower 	int							total_len;		/* total len of dg */
234*36368Ssklower 	struct mbuf 				*m0;			/* contains er pdu hdr */
235*36368Ssklower /*	struct clnp_optidx			*oidx;	 index for options on orig pkt */
236*36368Ssklower 
237*36368Ssklower 	IFDEBUG(D_DISCARD)
238*36368Ssklower 		printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
239*36368Ssklower 	ENDDEBUG
240*36368Ssklower 
241*36368Ssklower 	bzero((caddr_t)&route, sizeof(route));
242*36368Ssklower 
243*36368Ssklower 	/*
244*36368Ssklower 	 *	If header length is incorrect, or entire header is not contained
245*36368Ssklower 	 *	in this mbuf, we punt
246*36368Ssklower 	 */
247*36368Ssklower 	if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
248*36368Ssklower 		(clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
249*36368Ssklower 		(clnp->cnf_hdr_len > m->m_len))
250*36368Ssklower 		goto bad;
251*36368Ssklower 
252*36368Ssklower 	/* extract src, dest address */
253*36368Ssklower 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
254*36368Ssklower 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
255*36368Ssklower 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
256*36368Ssklower 	if (hoff == (caddr_t)0) {
257*36368Ssklower 		goto bad;
258*36368Ssklower 	}
259*36368Ssklower 	CLNP_EXTRACT_ADDR(src, hoff, hend);
260*36368Ssklower 	if (hoff == (caddr_t)0) {
261*36368Ssklower 		goto bad;
262*36368Ssklower 	}
263*36368Ssklower 
264*36368Ssklower 	/*
265*36368Ssklower 	 *	Do not send ER if we generated the packet.
266*36368Ssklower 	 */
267*36368Ssklower 	if (clnp_ours(&src))
268*36368Ssklower 		goto bad;
269*36368Ssklower 
270*36368Ssklower 	/*
271*36368Ssklower 	 *	Trim mbuf to hold only the header.
272*36368Ssklower 	 *	This mbuf will be the 'data' of the er pdu
273*36368Ssklower 	 */
274*36368Ssklower 	if (m->m_next != NULL) {
275*36368Ssklower 		m_freem(m->m_next);
276*36368Ssklower 		m->m_next = NULL;
277*36368Ssklower 	}
278*36368Ssklower 
279*36368Ssklower 	if (m->m_len > clnp->cnf_hdr_len)
280*36368Ssklower 		m_adj(m, -(m->m_len - clnp->cnf_hdr_len));
281*36368Ssklower 
282*36368Ssklower 	/* route er pdu: note we send pkt to src of original packet  */
283*36368Ssklower 	if (clnp_route(&src, &route, /* flags */0, &first_hop, &ifp) != 0)
284*36368Ssklower 		goto bad;
285*36368Ssklower 
286*36368Ssklower 	/* compute our address based upon firsthop/ifp */
287*36368Ssklower 	our_addr =
288*36368Ssklower 			clnp_srcaddr(ifp, &((struct sockaddr_iso *)first_hop)->siso_addr);
289*36368Ssklower 	if (our_addr == NULL)
290*36368Ssklower 		goto bad;
291*36368Ssklower 
292*36368Ssklower 	IFDEBUG(D_DISCARD)
293*36368Ssklower 		printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
294*36368Ssklower 		printf(" from %s\n", clnp_iso_addrp(our_addr));
295*36368Ssklower 	ENDDEBUG
296*36368Ssklower 
297*36368Ssklower 	IFDEBUG(D_DISCARD)
298*36368Ssklower 		printf("clnp_emit_er: packet routed to %s\n",
299*36368Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
300*36368Ssklower 	ENDDEBUG
301*36368Ssklower 
302*36368Ssklower 	/* allocate mbuf for er pdu header: punt on no space */
303*36368Ssklower 	MGET(m0, M_DONTWAIT, MT_HEADER);
304*36368Ssklower 	if (m0 == 0)
305*36368Ssklower 		goto bad;
306*36368Ssklower 
307*36368Ssklower 	m0->m_next = m;
308*36368Ssklower 	er = mtod(m0, struct clnp_fixed *);
309*36368Ssklower 	*er = er_template;
310*36368Ssklower 
311*36368Ssklower 	/* setup src/dst on er pdu */
312*36368Ssklower 	/* NOTE REVERSAL OF SRC/DST */
313*36368Ssklower 	hoff = (caddr_t)er + sizeof(struct clnp_fixed);
314*36368Ssklower 	CLNP_INSERT_ADDR(hoff, &src);
315*36368Ssklower 	CLNP_INSERT_ADDR(hoff, our_addr);
316*36368Ssklower 
317*36368Ssklower 	/*
318*36368Ssklower 	 *	TODO: if complete src rt was specified, then reverse path, and
319*36368Ssklower 	 *	copy into er as option.
320*36368Ssklower 	 */
321*36368Ssklower 
322*36368Ssklower 	/* add er option */
323*36368Ssklower 	*hoff++ = CLNPOVAL_ERREAS;	/* code */
324*36368Ssklower 	*hoff++ = 2;				/* length */
325*36368Ssklower 	*hoff++ = reason;			/* discard reason */
326*36368Ssklower 	*hoff++ = 0;				/* error localization = not specified */
327*36368Ssklower 
328*36368Ssklower 	/* set length */
329*36368Ssklower 	er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
330*36368Ssklower 	total_len = m0->m_len + m->m_len;
331*36368Ssklower 	HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
332*36368Ssklower 
333*36368Ssklower 	/* compute checksum (on header only) */
334*36368Ssklower 	iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
335*36368Ssklower 
336*36368Ssklower 	/* trim packet if too large for interface */
337*36368Ssklower 	if (total_len > ifp->if_mtu)
338*36368Ssklower 		m_adj(m0, -(total_len - ifp->if_mtu));
339*36368Ssklower 
340*36368Ssklower 	/* send packet */
341*36368Ssklower 	(void) (*ifp->if_output)(ifp, m0, first_hop);
342*36368Ssklower 	goto done;
343*36368Ssklower 
344*36368Ssklower bad:
345*36368Ssklower 	m_freem(m);
346*36368Ssklower 
347*36368Ssklower done:
348*36368Ssklower 	/* free route if it is a temp */
349*36368Ssklower 	if (route.ro_rt != NULL)
350*36368Ssklower 		RTFREE(route.ro_rt);
351*36368Ssklower }
352*36368Ssklower #endif	ISO
353