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