xref: /csrg-svn/sys/netiso/clnp_er.c (revision 38841)
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.4 (Berkeley) 08/29/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 #ifdef ISO
36 
37 #include "types.h"
38 #include "param.h"
39 #include "mbuf.h"
40 #include "domain.h"
41 #include "protosw.h"
42 #include "socket.h"
43 #include "socketvar.h"
44 #include "errno.h"
45 
46 #include "../net/if.h"
47 #include "../net/route.h"
48 
49 #include "iso.h"
50 #include "iso_var.h"
51 #include "iso_pcb.h"
52 #include "clnp.h"
53 #include "clnp_stat.h"
54 #include "argo_debug.h"
55 
56 static struct clnp_fixed er_template = {
57 	ISO8473_CLNP,	/* network identifier */
58 	0,				/* length */
59 	ISO8473_V1,		/* version */
60 	CLNP_TTL,		/* ttl */
61 	CLNP_ER,		/* type */
62 	0,				/* segment length */
63 	0				/* checksum */
64 };
65 
66 /*
67  * FUNCTION:		clnp_er_input
68  *
69  * PURPOSE:			Process an ER pdu.
70  *
71  * RETURNS:
72  *
73  * SIDE EFFECTS:
74  *
75  * NOTES:
76  */
77 clnp_er_input(m, src, reason)
78 struct mbuf		*m;		/* ptr to packet itself */
79 struct iso_addr	*src;	/* ptr to src of er */
80 u_char			reason;	/* reason code of er */
81 {
82 	int	cmd = -1;
83 	extern u_char clnp_protox[];
84 
85 	IFDEBUG(D_CTLINPUT)
86 		printf("clnp_er_input: m x%x, src %s, reason x%x\n", m,
87 			clnp_iso_addrp(src), reason);
88 	ENDDEBUG
89 
90 	INCSTAT(cns_errcvd);
91 
92 	switch (reason) {
93 		case GEN_NOREAS:
94 		case GEN_PROTOERR:
95 			INCSTAT(er_protoerr);
96 			break;
97 		case GEN_BADCSUM:
98 			cmd = PRC_PARAMPROB;
99 			INCSTAT(er_badcsum);
100 			break;
101 		case GEN_CONGEST:
102 			cmd = PRC_QUENCH;
103 			INCSTAT(er_congest);
104 			break;
105 		case GEN_HDRSYNTAX:
106 			cmd = PRC_PARAMPROB;
107 			INCSTAT(er_protoerr);
108 			break;
109 		case GEN_SEGNEEDED:
110 			cmd = PRC_UNREACH_NEEDFRAG;
111 			INCSTAT(er_segneeded);
112 			break;
113 		case GEN_INCOMPLETE:
114 			cmd = PRC_PARAMPROB;
115 			INCSTAT(er_reassfail);
116 			break;
117 		case GEN_DUPOPT:
118 			cmd = PRC_PARAMPROB;
119 			INCSTAT(er_protoerr);
120 			break;
121 		case ADDR_DESTUNREACH:
122 			cmd = PRC_UNREACH_HOST;
123 			INCSTAT(er_dstunreach);
124 			break;
125 		case ADDR_DESTUNKNOWN:
126 			cmd = PRC_UNREACH_PROTOCOL;
127 			INCSTAT(er_dstunreach);
128 			break;
129 		case SRCRT_UNSPECERR:
130 		case SRCRT_SYNTAX:
131 		case SRCRT_UNKNOWNADDR:
132 		case SRCRT_BADPATH:
133 			cmd = PRC_UNREACH_SRCFAIL;
134 			INCSTAT(er_srcrterr);
135 			break;
136 		case TTL_EXPTRANSIT:
137 			cmd = PRC_TIMXCEED_INTRANS;
138 			INCSTAT(er_ttlexpired);
139 			break;
140 		case TTL_EXPREASS:
141 			cmd = PRC_TIMXCEED_REASS;
142 			INCSTAT(er_ttlexpired);
143 			break;
144 		case DISC_UNSUPPOPT:
145 		case DISC_UNSUPPVERS:
146 		case DISC_UNSUPPSECURE:
147 		case DISC_UNSUPPSRCRT:
148 		case DISC_UNSUPPRECRT:
149 			cmd = PRC_PARAMPROB;
150 			INCSTAT(er_unsupported);
151 			break;
152 		case REASS_INTERFERE:
153 			cmd = PRC_TIMXCEED_REASS;
154 			INCSTAT(er_reassfail);
155 			break;
156 	}
157 
158 	/*
159 	 *	tpclnp_ctlinput1 is called directly so that we don't
160 	 *	have to build an iso_sockaddr out of src.
161 	 */
162 	if (cmd >= 0)
163 		tpclnp_ctlinput1(cmd, src);
164 
165 	m_freem(m);
166 }
167 
168 /*
169  * FUNCTION:		clnp_discard
170  *
171  * PURPOSE:			Discard a clnp datagram
172  *
173  * RETURNS:			nothing
174  *
175  * SIDE EFFECTS:	Will emit an ER pdu if possible
176  *
177  * NOTES:			This code assumes that we have previously tried to pull
178  *					up the header of the datagram into one mbuf.
179  */
180 clnp_discard(m, reason)
181 struct mbuf	*m;		/* header of packet to discard */
182 char					reason;	/* reason for discard */
183 {
184 	IFDEBUG(D_DISCARD)
185 		printf("clnp_discard: m x%x, reason x%x\n", m, reason);
186 	ENDDEBUG
187 
188 	if (m != NULL) {
189 		if (m->m_len >= sizeof(struct clnp_fixed)) {
190 			register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
191 
192 			if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
193 				(clnp->cnf_type & CNF_ERR_OK)) {
194 					clnp_emit_er(m, reason);
195 					return;
196 			}
197 		}
198 		m_freem(m);
199 	}
200 }
201 
202 /*
203  * FUNCTION:		clnp_emit_er
204  *
205  * PURPOSE:			Send an ER pdu.
206  *					The src of the of the ER pdu is the host that is sending
207  *					the ER (ie. us), *not* the original destination of the
208  *					packet.
209  *
210  * RETURNS:			nothing
211  *
212  * SIDE EFFECTS:
213  *
214  * NOTES:			Takes responsibility for freeing mbuf passed
215  *					This function may be called with a packet that
216  *					was created by us; in this case, do not send
217  *					an ER.
218  */
219 clnp_emit_er(m, reason)
220 struct mbuf	*m;		/* header of packet to discard */
221 char					reason;	/* reason for discard */
222 {
223 	register struct clnp_fixed	*clnp = mtod(m, struct clnp_fixed *);
224 	register struct clnp_fixed	*er;
225 	struct route_iso			route;
226 	struct ifnet				*ifp;
227 	struct sockaddr				*first_hop;
228 	struct iso_addr				src, dst, *our_addr;
229 	caddr_t						hoff, hend;
230 	int							total_len;		/* total len of dg */
231 	struct mbuf 				*m0;			/* contains er pdu hdr */
232 	struct iso_ifaddr			*ia = 0;
233 
234 	IFDEBUG(D_DISCARD)
235 		printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
236 	ENDDEBUG
237 
238 	bzero((caddr_t)&route, sizeof(route));
239 
240 	/*
241 	 *	If header length is incorrect, or entire header is not contained
242 	 *	in this mbuf, we punt
243 	 */
244 	if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
245 		(clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
246 		(clnp->cnf_hdr_len > m->m_len))
247 		goto bad;
248 
249 	/* extract src, dest address */
250 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
251 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
252 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
253 	if (hoff == (caddr_t)0) {
254 		goto bad;
255 	}
256 	CLNP_EXTRACT_ADDR(src, hoff, hend);
257 	if (hoff == (caddr_t)0) {
258 		goto bad;
259 	}
260 
261 	/*
262 	 *	Do not send ER if we generated the packet.
263 	 */
264 	if (clnp_ours(&src))
265 		goto bad;
266 
267 	/*
268 	 *	Trim mbuf to hold only the header.
269 	 *	This mbuf will be the 'data' of the er pdu
270 	 */
271 	if (m->m_next != NULL) {
272 		m_freem(m->m_next);
273 		m->m_next = NULL;
274 	}
275 
276 	if (m->m_len > clnp->cnf_hdr_len)
277 		m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len));
278 
279 	/* route er pdu: note we send pkt to src of original packet  */
280 	if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0)
281 		goto bad;
282 
283 	/* compute our address based upon firsthop/ifp */
284 	if (ia)
285 			our_addr = &ia->ia_addr.siso_addr;
286 	else
287 			goto bad;
288 	ifp = ia->ia_ifp;
289 
290 	IFDEBUG(D_DISCARD)
291 		printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
292 		printf(" from %s\n", clnp_iso_addrp(our_addr));
293 	ENDDEBUG
294 
295 	IFDEBUG(D_DISCARD)
296 		printf("clnp_emit_er: packet routed to %s\n",
297 			clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
298 	ENDDEBUG
299 
300 	/* allocate mbuf for er pdu header: punt on no space */
301 	MGET(m0, M_DONTWAIT, MT_HEADER);
302 	if (m0 == 0)
303 		goto bad;
304 
305 	m0->m_next = m;
306 	er = mtod(m0, struct clnp_fixed *);
307 	*er = er_template;
308 
309 	/* setup src/dst on er pdu */
310 	/* NOTE REVERSAL OF SRC/DST */
311 	hoff = (caddr_t)er + sizeof(struct clnp_fixed);
312 	CLNP_INSERT_ADDR(hoff, src);
313 	CLNP_INSERT_ADDR(hoff, *our_addr);
314 
315 	/*
316 	 *	TODO: if complete src rt was specified, then reverse path, and
317 	 *	copy into er as option.
318 	 */
319 
320 	/* add er option */
321 	*hoff++ = CLNPOVAL_ERREAS;	/* code */
322 	*hoff++ = 2;				/* length */
323 	*hoff++ = reason;			/* discard reason */
324 	*hoff++ = 0;				/* error localization = not specified */
325 
326 	/* set length */
327 	er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
328 	total_len = m0->m_len + m->m_len;
329 	HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
330 
331 	/* compute checksum (on header only) */
332 	iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
333 
334 	/* trim packet if too large for interface */
335 	if (total_len > ifp->if_mtu)
336 		m_adj(m0, -(total_len - ifp->if_mtu));
337 
338 	/* send packet */
339 	(void) (*ifp->if_output)(ifp, m0, first_hop);
340 	goto done;
341 
342 bad:
343 	m_freem(m);
344 
345 done:
346 	/* free route if it is a temp */
347 	if (route.ro_rt != NULL)
348 		RTFREE(route.ro_rt);
349 }
350 #endif	ISO
351