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