xref: /csrg-svn/sys/netiso/clnp_er.c (revision 36763)
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 
30 #ifndef lint
31 static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 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 	/*
167 	 *	tpclnp_ctlinput1 is called directly so that we don't
168 	 *	have to build an iso_sockaddr out of src.
169 	 */
170 	if (cmd >= 0)
171 		tpclnp_ctlinput1(cmd, src);
172 
173 	m_freem(m);
174 }
175 
176 /*
177  * FUNCTION:		clnp_discard
178  *
179  * PURPOSE:			Discard a clnp datagram
180  *
181  * RETURNS:			nothing
182  *
183  * SIDE EFFECTS:	Will emit an ER pdu if possible
184  *
185  * NOTES:			This code assumes that we have previously tried to pull
186  *					up the header of the datagram into one mbuf.
187  */
188 clnp_discard(m, reason)
189 struct mbuf	*m;		/* header of packet to discard */
190 char					reason;	/* reason for discard */
191 {
192 	IFDEBUG(D_DISCARD)
193 		printf("clnp_discard: m x%x, reason x%x\n", m, reason);
194 	ENDDEBUG
195 
196 	if (m != NULL) {
197 		if (m->m_len >= sizeof(struct clnp_fixed)) {
198 			register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
199 
200 			if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_err_ok)) {
201 				clnp_emit_er(m, reason);
202 				return;
203 			}
204 		}
205 		m_freem(m);
206 	}
207 }
208 
209 /*
210  * FUNCTION:		clnp_emit_er
211  *
212  * PURPOSE:			Send an ER pdu.
213  *					The src of the of the ER pdu is the host that is sending
214  *					the ER (ie. us), *not* the original destination of the
215  *					packet.
216  *
217  * RETURNS:			nothing
218  *
219  * SIDE EFFECTS:
220  *
221  * NOTES:			Takes responsibility for freeing mbuf passed
222  *					This function may be called with a packet that
223  *					was created by us; in this case, do not send
224  *					an ER.
225  */
226 clnp_emit_er(m, reason)
227 struct mbuf	*m;		/* header of packet to discard */
228 char					reason;	/* reason for discard */
229 {
230 	register struct clnp_fixed	*clnp = mtod(m, struct clnp_fixed *);
231 	register struct clnp_fixed	*er;
232 	struct route				route;
233 	struct ifnet				*ifp;
234 	struct sockaddr				*first_hop;
235 	struct iso_addr				src, dst, *our_addr;
236 	caddr_t						hoff, hend;
237 	int							total_len;		/* total len of dg */
238 	struct mbuf 				*m0;			/* contains er pdu hdr */
239 
240 	IFDEBUG(D_DISCARD)
241 		printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len);
242 	ENDDEBUG
243 
244 	bzero((caddr_t)&route, sizeof(route));
245 
246 	/*
247 	 *	If header length is incorrect, or entire header is not contained
248 	 *	in this mbuf, we punt
249 	 */
250 	if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) ||
251 		(clnp->cnf_hdr_len > CLNP_HDR_MAX) ||
252 		(clnp->cnf_hdr_len > m->m_len))
253 		goto bad;
254 
255 	/* extract src, dest address */
256 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
257 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
258 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
259 	if (hoff == (caddr_t)0) {
260 		goto bad;
261 	}
262 	CLNP_EXTRACT_ADDR(src, hoff, hend);
263 	if (hoff == (caddr_t)0) {
264 		goto bad;
265 	}
266 
267 	/*
268 	 *	Do not send ER if we generated the packet.
269 	 */
270 	if (clnp_ours(&src))
271 		goto bad;
272 
273 	/*
274 	 *	Trim mbuf to hold only the header.
275 	 *	This mbuf will be the 'data' of the er pdu
276 	 */
277 	if (m->m_next != NULL) {
278 		m_freem(m->m_next);
279 		m->m_next = NULL;
280 	}
281 
282 	if (m->m_len > clnp->cnf_hdr_len)
283 		m_adj(m, -(m->m_len - clnp->cnf_hdr_len));
284 
285 	/* route er pdu: note we send pkt to src of original packet  */
286 	if (clnp_route(&src, &route, /* flags */0, &first_hop, &ifp) != 0)
287 		goto bad;
288 
289 	/* compute our address based upon firsthop/ifp */
290 	our_addr =
291 			clnp_srcaddr(ifp, &((struct sockaddr_iso *)first_hop)->siso_addr);
292 	if (our_addr == NULL)
293 		goto bad;
294 
295 	IFDEBUG(D_DISCARD)
296 		printf("clnp_emit_er: to %s", clnp_iso_addrp(&src));
297 		printf(" from %s\n", clnp_iso_addrp(our_addr));
298 	ENDDEBUG
299 
300 	IFDEBUG(D_DISCARD)
301 		printf("clnp_emit_er: packet routed to %s\n",
302 			clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr));
303 	ENDDEBUG
304 
305 	/* allocate mbuf for er pdu header: punt on no space */
306 	MGET(m0, M_DONTWAIT, MT_HEADER);
307 	if (m0 == 0)
308 		goto bad;
309 
310 	m0->m_next = m;
311 	er = mtod(m0, struct clnp_fixed *);
312 	*er = er_template;
313 
314 	/* setup src/dst on er pdu */
315 	/* NOTE REVERSAL OF SRC/DST */
316 	hoff = (caddr_t)er + sizeof(struct clnp_fixed);
317 	CLNP_INSERT_ADDR(hoff, &src);
318 	CLNP_INSERT_ADDR(hoff, our_addr);
319 
320 	/*
321 	 *	TODO: if complete src rt was specified, then reverse path, and
322 	 *	copy into er as option.
323 	 */
324 
325 	/* add er option */
326 	*hoff++ = CLNPOVAL_ERREAS;	/* code */
327 	*hoff++ = 2;				/* length */
328 	*hoff++ = reason;			/* discard reason */
329 	*hoff++ = 0;				/* error localization = not specified */
330 
331 	/* set length */
332 	er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er);
333 	total_len = m0->m_len + m->m_len;
334 	HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len);
335 
336 	/* compute checksum (on header only) */
337 	iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len);
338 
339 	/* trim packet if too large for interface */
340 	if (total_len > ifp->if_mtu)
341 		m_adj(m0, -(total_len - ifp->if_mtu));
342 
343 	/* send packet */
344 	(void) (*ifp->if_output)(ifp, m0, first_hop);
345 	goto done;
346 
347 bad:
348 	m_freem(m);
349 
350 done:
351 	/* free route if it is a temp */
352 	if (route.ro_rt != NULL)
353 		RTFREE(route.ro_rt);
354 }
355 #endif	ISO
356