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