1/*	$NetBSD: clnp_er.c,v 1.24 2008/01/14 04:17:35 dyoung Exp $	*/
2
3/*-
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	@(#)clnp_er.c	8.1 (Berkeley) 6/10/93
32 */
33
34/***********************************************************
35		Copyright IBM Corporation 1987
36
37                      All Rights Reserved
38
39Permission to use, copy, modify, and distribute this software and its
40documentation for any purpose and without fee is hereby granted,
41provided that the above copyright notice appear in all copies and that
42both that copyright notice and this permission notice appear in
43supporting documentation, and that the name of IBM not be
44used in advertising or publicity pertaining to distribution of the
45software without specific, written prior permission.
46
47IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53SOFTWARE.
54
55******************************************************************/
56
57/*
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59 */
60
61#include <sys/cdefs.h>
62__KERNEL_RCSID(0, "$NetBSD: clnp_er.c,v 1.24 2008/01/14 04:17:35 dyoung Exp $");
63
64#include <sys/param.h>
65#include <sys/mbuf.h>
66#include <sys/domain.h>
67#include <sys/protosw.h>
68#include <sys/socket.h>
69#include <sys/socketvar.h>
70#include <sys/errno.h>
71#include <sys/systm.h>
72
73#include <net/if.h>
74#include <net/route.h>
75
76#include <netiso/iso.h>
77#include <netiso/iso_var.h>
78#include <netiso/iso_pcb.h>
79#define CLNP_ER_CODES
80#include <netiso/clnp.h>
81#include <netiso/clnp_stat.h>
82#include <netiso/argo_debug.h>
83#include <netiso/tp_param.h>
84#include <netiso/tp_var.h>
85
86static const struct clnp_fixed er_template = {
87	ISO8473_CLNP,		/* network identifier */
88	0,			/* length */
89	ISO8473_V1,		/* version */
90	CLNP_TTL,		/* ttl */
91	CLNP_ER,		/* type */
92	0,			/* segment length msb */
93	0,			/* segment length lsb */
94	0,			/* checksum msb */
95	0,			/* checksum lmsb */
96};
97
98/*
99 * FUNCTION:		clnp_er_input
100 *
101 * PURPOSE:			Process an ER pdu.
102 *
103 * RETURNS:
104 *
105 * SIDE EFFECTS:
106 *
107 * NOTES:
108 */
109void
110clnp_er_input(
111	struct mbuf    *m,	/* ptr to packet itself */
112	struct iso_addr *src,	/* ptr to src of er */
113	u_int           reason)	/* reason code of er */
114{
115	int             cmd = -1;
116
117#ifdef ARGO_DEBUG
118	if (argo_debug[D_CTLINPUT]) {
119		printf("clnp_er_input: m %p, src %s, reason x%x\n",
120		    m, clnp_iso_addrp(src), reason);
121	}
122#endif
123
124	INCSTAT(cns_er_inhist[clnp_er_index(reason)]);
125	switch (reason) {
126	case GEN_NOREAS:
127	case GEN_PROTOERR:
128		break;
129	case GEN_BADCSUM:
130		cmd = PRC_PARAMPROB;
131		break;
132	case GEN_CONGEST:
133		cmd = PRC_QUENCH;
134		break;
135	case GEN_HDRSYNTAX:
136		cmd = PRC_PARAMPROB;
137		break;
138	case GEN_SEGNEEDED:
139		cmd = PRC_MSGSIZE;
140		break;
141	case GEN_INCOMPLETE:
142		cmd = PRC_PARAMPROB;
143		break;
144	case GEN_DUPOPT:
145		cmd = PRC_PARAMPROB;
146		break;
147	case ADDR_DESTUNREACH:
148		cmd = PRC_UNREACH_HOST;
149		break;
150	case ADDR_DESTUNKNOWN:
151		cmd = PRC_UNREACH_PROTOCOL;
152		break;
153	case SRCRT_UNSPECERR:
154	case SRCRT_SYNTAX:
155	case SRCRT_UNKNOWNADDR:
156	case SRCRT_BADPATH:
157		cmd = PRC_UNREACH_SRCFAIL;
158		break;
159	case TTL_EXPTRANSIT:
160		cmd = PRC_TIMXCEED_INTRANS;
161		break;
162	case TTL_EXPREASS:
163		cmd = PRC_TIMXCEED_REASS;
164		break;
165	case DISC_UNSUPPOPT:
166	case DISC_UNSUPPVERS:
167	case DISC_UNSUPPSECURE:
168	case DISC_UNSUPPSRCRT:
169	case DISC_UNSUPPRECRT:
170		cmd = PRC_PARAMPROB;
171		break;
172	case REASS_INTERFERE:
173		cmd = PRC_TIMXCEED_REASS;
174		break;
175	}
176
177	/*
178	 *	tpclnp_ctlinput1 is called directly so that we don't
179	 *	have to build an iso_sockaddr out of src.
180	 */
181	if (cmd >= 0)
182		tpclnp_ctlinput1(cmd, src);
183
184	m_freem(m);
185}
186
187/*
188 * FUNCTION:		clnp_discard
189 *
190 * PURPOSE:		Discard a clnp datagram
191 *
192 * RETURNS:		nothing
193 *
194 * SIDE EFFECTS:	Will emit an ER pdu if possible
195 *
196 * NOTES:		This code assumes that we have previously tried to pull
197 *			up the header of the datagram into one mbuf.
198 */
199void
200clnp_discard(struct mbuf *m, u_int reason)
201	/* m:	 header of packet to discard */
202	/* reason:	 reason for discard */
203{
204#ifdef ARGO_DEBUG
205	if (argo_debug[D_DISCARD]) {
206		printf("clnp_discard: m %p, reason x%x\n", m, reason);
207	}
208#endif
209
210	if (m != NULL) {
211		if (m->m_len >= sizeof(struct clnp_fixed)) {
212			struct clnp_fixed *clnp =
213				mtod(m, struct clnp_fixed *);
214
215			if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
216			    (clnp->cnf_type & CNF_ERR_OK)) {
217				clnp_emit_er(m, reason);
218				return;
219			}
220		}
221		m_freem(m);
222	}
223}
224
225/*
226 * FUNCTION:		clnp_emit_er
227 *
228 * PURPOSE:		Send an ER pdu.
229 *			The src of the of the ER pdu is the host that is sending
230 *			the ER (ie. us), *not* the original destination of the
231 *			packet.
232 *
233 * RETURNS:		nothing
234 *
235 * SIDE EFFECTS:
236 *
237 * NOTES:		Takes responsibility for freeing mbuf passed
238 *			This function may be called with a packet that
239 *			was created by us; in this case, do not send
240 *			an ER.
241 */
242void
243clnp_emit_er(struct mbuf *m, u_int reason)
244	/* m:	 header of packet to discard */
245	/* reason:	 reason for discard */
246{
247	struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
248	struct clnp_fixed *er;
249	struct route route;
250	struct ifnet   *ifp;
251	const struct sockaddr *first_hop;
252	struct iso_addr src, dst, *our_addr;
253	char *hoff, *hend;
254	int total_len;	/* total len of dg */
255	struct iso_ifaddr *ia = 0;
256
257#ifdef ARGO_DEBUG
258	if (argo_debug[D_DISCARD]) {
259		printf("clnp_emit_er: m %p, hdr len %d\n",
260		       m, clnp->cnf_hdr_len);
261	}
262#endif
263
264	memset(&route, 0, sizeof(route));
265
266	/*
267	 * If header length is incorrect, or entire header is not contained
268	 * in this mbuf, we punt
269	 */
270	if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
271	    (clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
272	    (clnp->cnf_hdr_len > m->m_len))
273		goto bad;
274
275	/* extract src, dest address */
276	hend = (char *)clnp + clnp->cnf_hdr_len;
277	hoff = (char *)clnp + sizeof(struct clnp_fixed);
278	CLNP_EXTRACT_ADDR(dst, hoff, hend);
279	if (hoff == (void *) 0) {
280		goto bad;
281	}
282	CLNP_EXTRACT_ADDR(src, hoff, hend);
283	if (hoff == (void *) 0) {
284		goto bad;
285	}
286	/*
287	 * Do not send ER if we generated the packet.
288	 */
289	if (clnp_ours(&src))
290		goto bad;
291
292	/*
293	 * Trim mbuf to hold only the header. This mbuf will be the 'data' of
294	 * the er pdu
295	 */
296	if (m->m_next != NULL) {
297		m_freem(m->m_next);
298		m->m_next = NULL;
299	}
300	if (m->m_len > clnp->cnf_hdr_len)
301		m_adj(m, (int) -(m->m_len - (int) clnp->cnf_hdr_len));
302
303	/* route er pdu: note we send pkt to src of original packet  */
304	if (clnp_route(&src, &route, /* flags */ 0, &first_hop, &ia) != 0)
305		goto bad;
306
307	/* compute our address based upon firsthop/ifp */
308	if (ia)
309		our_addr = &ia->ia_addr.siso_addr;
310	else
311		goto bad;
312	ifp = ia->ia_ifp;
313
314#ifdef ARGO_DEBUG
315	if (argo_debug[D_DISCARD]) {
316		printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
317		printf(" from %s\n", clnp_iso_addrp(our_addr));
318	}
319#endif
320
321#ifdef ARGO_DEBUG
322	if (argo_debug[D_DISCARD]) {
323		printf("clnp_emit_er: packet routed to %s\n",
324		    clnp_iso_addrp(&satocsiso(first_hop)->siso_addr));
325	}
326#endif
327
328	/* allocate mbuf for er pdu header: punt on no space */
329	/*
330	 * fixed part, two addresses and their length bytes, and a
331	 * 4-byte option
332	 */
333
334	M_PREPEND(m, sizeof(struct clnp_fixed) + 4 + 1 + 1 +
335			src.isoa_len + our_addr->isoa_len, M_DONTWAIT);
336	if (m == 0)
337		goto bad;
338
339	er = mtod(m, struct clnp_fixed *);
340	*er = er_template;
341
342	/* setup src/dst on er pdu */
343	/* NOTE REVERSAL OF SRC/DST */
344	hoff = (char *)er + sizeof(struct clnp_fixed);
345	CLNP_INSERT_ADDR(hoff, src);
346	CLNP_INSERT_ADDR(hoff, *our_addr);
347
348	/*
349	 *	TODO: if complete src rt was specified, then reverse path, and
350	 *	copy into er as option.
351	 */
352
353	/* add er option */
354	*hoff++ = CLNPOVAL_ERREAS;	/* code */
355	*hoff++ = 2;		/* length */
356	*hoff++ = reason;	/* discard reason */
357	*hoff++ = 0;		/* error localization = not specified */
358
359	/* set length */
360	er->cnf_hdr_len = (u_char) (hoff - (char *)er);
361	total_len = m->m_pkthdr.len;
362	HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
363
364	/* compute checksum (on header only) */
365	iso_gen_csum(m, CLNP_CKSUM_OFF, (int) er->cnf_hdr_len);
366
367	/* trim packet if too large for interface */
368	if (total_len > ifp->if_mtu)
369		m_adj(m, -(total_len - ifp->if_mtu));
370
371	/* send packet */
372	INCSTAT(cns_er_outhist[clnp_er_index(reason)]);
373	(void) (*ifp->if_output) (ifp, m, first_hop, rtcache_validate(&route));
374	goto done;
375
376bad:
377	m_freem(m);
378
379done:
380	/* free route if it is a temp */
381	rtcache_free(&route);
382}
383
384int
385clnp_er_index(u_int p)
386{
387	u_char *cp = clnp_er_codes + CLNP_ERRORS;
388	while (cp > clnp_er_codes) {
389		cp--;
390		if (*cp == p)
391			return (cp - clnp_er_codes);
392	}
393	return (CLNP_ERRORS + 1);
394}
395