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