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