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