xref: /csrg-svn/sys/netns/ns_error.c (revision 37473)
1 /*
2  * Copyright (c) 1984, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)ns_error.c	7.7 (Berkeley) 04/22/89
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "malloc.h"
23 #include "mbuf.h"
24 #include "protosw.h"
25 #include "socket.h"
26 #include "time.h"
27 #include "kernel.h"
28 
29 #include "../net/route.h"
30 
31 #include "ns.h"
32 #include "ns_pcb.h"
33 #include "idp.h"
34 #include "ns_error.h"
35 
36 #ifdef lint
37 #define NS_ERRPRINTFS 1
38 #endif
39 
40 #ifdef NS_ERRPRINTFS
41 /*
42  * NS_ERR routines: error generation, receive packet processing, and
43  * routines to turnaround packets back to the originator.
44  */
45 int	ns_errprintfs = 0;
46 #endif
47 
48 ns_err_x(c)
49 {
50 	register u_short *w, *lim, *base = ns_errstat.ns_es_codes;
51 	u_short x = c;
52 
53 	/*
54 	 * zero is a legit error code, handle specially
55 	 */
56 	if (x == 0)
57 		return (0);
58 	lim = base + NS_ERR_MAX - 1;
59 	for (w = base + 1; w < lim; w++) {
60 		if (*w == 0)
61 			*w = x;
62 		if (*w == x)
63 			break;
64 	}
65 	return (w - base);
66 }
67 
68 /*
69  * Generate an error packet of type error
70  * in response to bad packet.
71  */
72 
73 ns_error(om, type, param)
74 	struct mbuf *om;
75 	int type;
76 {
77 	register struct ns_epidp *ep;
78 	struct mbuf *m;
79 	struct idp *nip;
80 	register struct idp *oip = mtod(om, struct idp *);
81 	extern int idpcksum;
82 
83 	/*
84 	 * If this packet was sent to the echo port,
85 	 * and nobody was there, just echo it.
86 	 * (Yes, this is a wart!)
87 	 */
88 	if (type == NS_ERR_NOSOCK &&
89 	    oip->idp_dna.x_port == htons(2) &&
90 	    (type = ns_echo(om))==0)
91 		return;
92 
93 #ifdef NS_ERRPRINTFS
94 	if (ns_errprintfs)
95 		printf("ns_err_error(%x, %d, %d)\n", oip, type, param);
96 #endif
97 	/*
98 	 * Don't Generate error packets in response to multicasts.
99 	 */
100 	if (oip->idp_dna.x_host.c_host[0] & 1)
101 		goto freeit;
102 
103 	ns_errstat.ns_es_error++;
104 	/*
105 	 * Make sure that the old IDP packet had 30 bytes of data to return;
106 	 * if not, don't bother.  Also don't EVER error if the old
107 	 * packet protocol was NS_ERR.
108 	 */
109 	if (oip->idp_len < sizeof(struct idp)) {
110 		ns_errstat.ns_es_oldshort++;
111 		goto freeit;
112 	}
113 	if (oip->idp_pt == NSPROTO_ERROR) {
114 		ns_errstat.ns_es_oldns_err++;
115 		goto freeit;
116 	}
117 
118 	/*
119 	 * First, formulate ns_err message
120 	 */
121 	m = m_gethdr(M_DONTWAIT, MT_HEADER);
122 	if (m == NULL)
123 		goto freeit;
124 	m->m_len = sizeof(*ep);
125 	MH_ALIGN(m, m->m_len);
126 	ep = mtod(m, struct ns_epidp *);
127 	if ((u_int)type > NS_ERR_TOO_BIG)
128 		panic("ns_err_error");
129 	ns_errstat.ns_es_outhist[ns_err_x(type)]++;
130 	ep->ns_ep_errp.ns_err_num = htons((u_short)type);
131 	ep->ns_ep_errp.ns_err_param = htons((u_short)param);
132 	bcopy((caddr_t)oip, (caddr_t)&ep->ns_ep_errp.ns_err_idp, 42);
133 	nip = &ep->ns_ep_idp;
134 	nip->idp_len = sizeof(*ep);
135 	nip->idp_len = htons((u_short)nip->idp_len);
136 	nip->idp_pt = NSPROTO_ERROR;
137 	nip->idp_tc = 0;
138 	nip->idp_dna = oip->idp_sna;
139 	nip->idp_sna = oip->idp_dna;
140 	if (idpcksum) {
141 		nip->idp_sum = 0;
142 		nip->idp_sum = ns_cksum(m, sizeof(*ep));
143 	} else
144 		nip->idp_sum = 0xffff;
145 	(void) ns_output(m, (struct route *)0, 0);
146 
147 freeit:
148 	m_freem(om);
149 }
150 
151 ns_printhost(p)
152 register struct ns_addr *p;
153 {
154 
155 	printf("<net:%x%x,host:%x%x%x,port:%x>",
156 			p->x_net.s_net[0],
157 			p->x_net.s_net[1],
158 			p->x_host.s_host[0],
159 			p->x_host.s_host[1],
160 			p->x_host.s_host[2],
161 			p->x_port);
162 
163 }
164 
165 /*
166  * Process a received NS_ERR message.
167  */
168 ns_err_input(m)
169 	struct mbuf *m;
170 {
171 	register struct ns_errp *ep;
172 	register struct ns_epidp *epidp = mtod(m, struct ns_epidp *);
173 	register int i;
174 	int type, code, param;
175 
176 	/*
177 	 * Locate ns_err structure in mbuf, and check
178 	 * that not corrupted and of at least minimum length.
179 	 */
180 #ifdef NS_ERRPRINTFS
181 	if (ns_errprintfs) {
182 		printf("ns_err_input from ");
183 		ns_printhost(&epidp->ns_ep_idp.idp_sna);
184 		printf("len %d\n", ntohs(epidp->ns_ep_idp.idp_len));
185 	}
186 #endif
187 	i = sizeof (struct ns_epidp);
188  	if (((m->m_flags & M_EXT) || m->m_len < i) &&
189  		(m = m_pullup(m, i)) == 0)  {
190 		ns_errstat.ns_es_tooshort++;
191 		return;
192 	}
193 	ep = &(mtod(m, struct ns_epidp *)->ns_ep_errp);
194 	type = ntohs(ep->ns_err_num);
195 	param = ntohs(ep->ns_err_param);
196 	ns_errstat.ns_es_inhist[ns_err_x(type)]++;
197 
198 #ifdef NS_ERRPRINTFS
199 	/*
200 	 * Message type specific processing.
201 	 */
202 	if (ns_errprintfs)
203 		printf("ns_err_input, type %d param %d\n", type, param);
204 #endif
205 	if (type >= NS_ERR_TOO_BIG) {
206 		goto badcode;
207 	}
208 	ns_errstat.ns_es_outhist[ns_err_x(type)]++;
209 	switch (type) {
210 
211 	case NS_ERR_UNREACH_HOST:
212 		code = PRC_UNREACH_NET;
213 		goto deliver;
214 
215 	case NS_ERR_TOO_OLD:
216 		code = PRC_TIMXCEED_INTRANS;
217 		goto deliver;
218 
219 	case NS_ERR_TOO_BIG:
220 		code = PRC_MSGSIZE;
221 		goto deliver;
222 
223 	case NS_ERR_FULLUP:
224 		code = PRC_QUENCH;
225 		goto deliver;
226 
227 	case NS_ERR_NOSOCK:
228 		code = PRC_UNREACH_PORT;
229 		goto deliver;
230 
231 	case NS_ERR_UNSPEC_T:
232 	case NS_ERR_BADSUM_T:
233 	case NS_ERR_BADSUM:
234 	case NS_ERR_UNSPEC:
235 		code = PRC_PARAMPROB;
236 		goto deliver;
237 
238 	deliver:
239 		/*
240 		 * Problem with datagram; advise higher level routines.
241 		 */
242 #ifdef NS_ERRPRINTFS
243 		if (ns_errprintfs)
244 			printf("deliver to protocol %d\n",
245 				       ep->ns_err_idp.idp_pt);
246 #endif
247 		switch(ep->ns_err_idp.idp_pt) {
248 		case NSPROTO_SPP:
249 			spp_ctlinput(code, (caddr_t)ep);
250 			break;
251 
252 		default:
253 			idp_ctlinput(code, (caddr_t)ep);
254 		}
255 
256 		goto freeit;
257 
258 	default:
259 	badcode:
260 		ns_errstat.ns_es_badcode++;
261 		goto freeit;
262 
263 	}
264 freeit:
265 	m_freem(m);
266 }
267 
268 #ifdef notdef
269 u_long
270 nstime()
271 {
272 	int s = splclock();
273 	u_long t;
274 
275 	t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
276 	splx(s);
277 	return (htonl(t));
278 }
279 #endif
280 
281 ns_echo(m)
282 struct mbuf *m;
283 {
284 	register struct idp *idp = mtod(m, struct idp *);
285 	register struct echo {
286 	    struct idp	ec_idp;
287 	    u_short		ec_op; /* Operation, 1 = request, 2 = reply */
288 	} *ec = (struct echo *)idp;
289 	struct ns_addr temp;
290 
291 	if (idp->idp_pt!=NSPROTO_ECHO) return(NS_ERR_NOSOCK);
292 	if (ec->ec_op!=htons(1)) return(NS_ERR_UNSPEC);
293 
294 	ec->ec_op = htons(2);
295 
296 	temp = idp->idp_dna;
297 	idp->idp_dna = idp->idp_sna;
298 	idp->idp_sna = temp;
299 
300 	if (idp->idp_sum != 0xffff) {
301 		idp->idp_sum = 0;
302 		idp->idp_sum = ns_cksum(m,
303 		    (int)(((ntohs(idp->idp_len) - 1)|1)+1));
304 	}
305 	(void) ns_output(m, (struct route *)0, NS_FORWARDING);
306 	return(0);
307 }
308