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