OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems/] [c/] [src/] [libnetworking/] [netinet/] [ip_icmp.c] - Blame information for rev 158

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 158 chris
/*
2
 * Copyright (c) 1982, 1986, 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
 *      @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
34
 *      $Id: ip_icmp.c,v 1.1.1.1 2001-07-10 09:58:57 chris 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
#include <sys/socket.h>
46
#include <sys/sysctl.h>
47
 
48
#include <net/if.h>
49
#include <net/route.h>
50
 
51
#define _IP_VHL
52
#include <netinet/in.h>
53
#include <netinet/in_systm.h>
54
#include <netinet/in_var.h>
55
#include <netinet/ip.h>
56
#include <netinet/ip_icmp.h>
57
#include <netinet/ip_var.h>
58
#include <netinet/icmp_var.h>
59
 
60
/*
61
 * ICMP routines: error generation, receive packet processing, and
62
 * routines to turnaround packets back to the originator, and
63
 * host table maintenance routines.
64
 */
65
 
66
       struct   icmpstat icmpstat;
67
SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD,
68
        &icmpstat, icmpstat, "");
69
 
70
static int      icmpmaskrepl = 0;
71
SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
72
        &icmpmaskrepl, 0, "");
73
 
74
static int      icmpbmcastecho = 1;
75
SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho,
76
           0, "");
77
 
78
/* #define ICMPPRINTFS 1 */
79
#ifdef ICMPPRINTFS
80
int     icmpprintfs = 0;
81
#endif
82
 
83
static void     icmp_reflect __P((struct mbuf *));
84
static void     icmp_send __P((struct mbuf *, struct mbuf *));
85
static int      ip_next_mtu __P((int, int));
86
 
87
extern  struct protosw inetsw[];
88
 
89
/*
90
 * Generate an error packet of type error
91
 * in response to bad packet ip.
92
 */
93
void
94
icmp_error(n, type, code, dest, destifp)
95
        struct mbuf *n;
96
        int type, code;
97
        n_long dest;
98
        struct ifnet *destifp;
99
{
100
        register struct ip *oip = mtod(n, struct ip *), *nip;
101
        register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
102
        register struct icmp *icp;
103
        register struct mbuf *m;
104
        unsigned icmplen;
105
 
106
#ifdef ICMPPRINTFS
107
        if (icmpprintfs)
108
                printf("icmp_error(%p, %x, %d)\n", oip, type, code);
109
#endif
110
        if (type != ICMP_REDIRECT)
111
                icmpstat.icps_error++;
112
        /*
113
         * Don't send error if not the first fragment of message.
114
         * Don't error if the old packet protocol was ICMP
115
         * error message, only known informational types.
116
         */
117
        if (oip->ip_off &~ (IP_MF|IP_DF))
118
                goto freeit;
119
        if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
120
          n->m_len >= oiplen + ICMP_MINLEN &&
121
          !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
122
                icmpstat.icps_oldicmp++;
123
                goto freeit;
124
        }
125
        /* Don't send error in response to a multicast or broadcast packet */
126
        if (n->m_flags & (M_BCAST|M_MCAST))
127
                goto freeit;
128
        /*
129
         * First, formulate icmp message
130
         */
131
        m = m_gethdr(M_DONTWAIT, MT_HEADER);
132
        if (m == NULL)
133
                goto freeit;
134
        icmplen = oiplen + min(8, oip->ip_len);
135
        m->m_len = icmplen + ICMP_MINLEN;
136
        MH_ALIGN(m, m->m_len);
137
        icp = mtod(m, struct icmp *);
138
        if ((u_int)type > ICMP_MAXTYPE)
139
                panic("icmp_error");
140
        icmpstat.icps_outhist[type]++;
141
        icp->icmp_type = type;
142
        if (type == ICMP_REDIRECT)
143
                icp->icmp_gwaddr.s_addr = dest;
144
        else {
145
                icp->icmp_void = 0;
146
                /*
147
                 * The following assignments assume an overlay with the
148
                 * zeroed icmp_void field.
149
                 */
150
                if (type == ICMP_PARAMPROB) {
151
                        icp->icmp_pptr = code;
152
                        code = 0;
153
                } else if (type == ICMP_UNREACH &&
154
                        code == ICMP_UNREACH_NEEDFRAG && destifp) {
155
                        icp->icmp_nextmtu = htons(destifp->if_mtu);
156
                }
157
        }
158
 
159
        icp->icmp_code = code;
160
        bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
161
        nip = &icp->icmp_ip;
162
        nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
163
 
164
        /*
165
         * Now, copy old ip header (without options)
166
         * in front of icmp message.
167
         */
168
        if (m->m_data - sizeof(struct ip) < m->m_pktdat)
169
                panic("icmp len");
170
        m->m_data -= sizeof(struct ip);
171
        m->m_len += sizeof(struct ip);
172
        m->m_pkthdr.len = m->m_len;
173
        m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
174
        nip = mtod(m, struct ip *);
175
        bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
176
        nip->ip_len = m->m_len;
177
        nip->ip_vhl = IP_VHL_BORING;
178
        nip->ip_p = IPPROTO_ICMP;
179
        nip->ip_tos = 0;
180
        icmp_reflect(m);
181
 
182
freeit:
183
        m_freem(n);
184
}
185
 
186
static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
187
static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
188
static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
189
 
190
/*
191
 * Process a received ICMP message.
192
 */
193
void
194
icmp_input(m, hlen)
195
        register struct mbuf *m;
196
        int hlen;
197
{
198
        register struct icmp *icp;
199
        register struct ip *ip = mtod(m, struct ip *);
200
        int icmplen = ip->ip_len;
201
        register int i;
202
        struct in_ifaddr *ia;
203
        void (*ctlfunc) __P((int, struct sockaddr *, void *));
204
        int code;
205
 
206
        /*
207
         * Locate icmp structure in mbuf, and check
208
         * that not corrupted and of at least minimum length.
209
         */
210
#ifdef ICMPPRINTFS
211
        if (icmpprintfs) {
212
                char buf[4 * sizeof "123"];
213
                strcpy(buf, inet_ntoa(ip->ip_src));
214
                printf("icmp_input from %s to %s, len %d\n",
215
                       buf, inet_ntoa(ip->ip_dst), icmplen);
216
        }
217
#endif
218
        if (icmplen < ICMP_MINLEN) {
219
                icmpstat.icps_tooshort++;
220
                goto freeit;
221
        }
222
        i = hlen + min(icmplen, ICMP_ADVLENMIN);
223
        if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
224
                icmpstat.icps_tooshort++;
225
                return;
226
        }
227
        ip = mtod(m, struct ip *);
228
        m->m_len -= hlen;
229
        m->m_data += hlen;
230
        icp = mtod(m, struct icmp *);
231
        if (in_cksum(m, icmplen)) {
232
                icmpstat.icps_checksum++;
233
                goto freeit;
234
        }
235
        m->m_len += hlen;
236
        m->m_data -= hlen;
237
 
238
#ifdef ICMPPRINTFS
239
        if (icmpprintfs)
240
                printf("icmp_input, type %d code %d\n", icp->icmp_type,
241
                    icp->icmp_code);
242
#endif
243
 
244
        /*
245
         * Message type specific processing.
246
         */
247
        if (icp->icmp_type > ICMP_MAXTYPE)
248
                goto raw;
249
        icmpstat.icps_inhist[icp->icmp_type]++;
250
        code = icp->icmp_code;
251
        switch (icp->icmp_type) {
252
 
253
        case ICMP_UNREACH:
254
                switch (code) {
255
                        case ICMP_UNREACH_NET:
256
                        case ICMP_UNREACH_HOST:
257
                        case ICMP_UNREACH_PROTOCOL:
258
                        case ICMP_UNREACH_PORT:
259
                        case ICMP_UNREACH_SRCFAIL:
260
                                code += PRC_UNREACH_NET;
261
                                break;
262
 
263
                        case ICMP_UNREACH_NEEDFRAG:
264
                                code = PRC_MSGSIZE;
265
                                break;
266
 
267
                        case ICMP_UNREACH_NET_UNKNOWN:
268
                        case ICMP_UNREACH_NET_PROHIB:
269
                        case ICMP_UNREACH_TOSNET:
270
                                code = PRC_UNREACH_NET;
271
                                break;
272
 
273
                        case ICMP_UNREACH_HOST_UNKNOWN:
274
                        case ICMP_UNREACH_ISOLATED:
275
                        case ICMP_UNREACH_HOST_PROHIB:
276
                        case ICMP_UNREACH_TOSHOST:
277
                                code = PRC_UNREACH_HOST;
278
                                break;
279
 
280
                        case ICMP_UNREACH_FILTER_PROHIB:
281
                        case ICMP_UNREACH_HOST_PRECEDENCE:
282
                        case ICMP_UNREACH_PRECEDENCE_CUTOFF:
283
                                code = PRC_UNREACH_PORT;
284
                                break;
285
 
286
                        default:
287
                                goto badcode;
288
                }
289
                goto deliver;
290
 
291
        case ICMP_TIMXCEED:
292
                if (code > 1)
293
                        goto badcode;
294
                code += PRC_TIMXCEED_INTRANS;
295
                goto deliver;
296
 
297
        case ICMP_PARAMPROB:
298
                if (code > 1)
299
                        goto badcode;
300
                code = PRC_PARAMPROB;
301
                goto deliver;
302
 
303
        case ICMP_SOURCEQUENCH:
304
                if (code)
305
                        goto badcode;
306
                code = PRC_QUENCH;
307
        deliver:
308
                /*
309
                 * Problem with datagram; advise higher level routines.
310
                 */
311
                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
312
                    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
313
                        icmpstat.icps_badlen++;
314
                        goto freeit;
315
                }
316
                NTOHS(icp->icmp_ip.ip_len);
317
                /* Discard ICMP's in response to multicast packets */
318
                if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
319
                        goto badcode;
320
#ifdef ICMPPRINTFS
321
                if (icmpprintfs)
322
                        printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
323
#endif
324
                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
325
#if 1
326
                /*
327
                 * MTU discovery:
328
                 * If we got a needfrag and there is a host route to the
329
                 * original destination, and the MTU is not locked, then
330
                 * set the MTU in the route to the suggested new value
331
                 * (if given) and then notify as usual.  The ULPs will
332
                 * notice that the MTU has changed and adapt accordingly.
333
                 * If no new MTU was suggested, then we guess a new one
334
                 * less than the current value.  If the new MTU is
335
                 * unreasonably small (arbitrarily set at 296), then
336
                 * we reset the MTU to the interface value and enable the
337
                 * lock bit, indicating that we are no longer doing MTU
338
                 * discovery.
339
                 */
340
                if (code == PRC_MSGSIZE) {
341
                        struct rtentry *rt;
342
                        int mtu;
343
 
344
                        rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
345
                                      RTF_CLONING | RTF_PRCLONING);
346
                        if (rt && (rt->rt_flags & RTF_HOST)
347
                            && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
348
                                mtu = ntohs(icp->icmp_nextmtu);
349
                                if (!mtu)
350
                                        mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
351
                                                          1);
352
#ifdef DEBUG_MTUDISC
353
                                printf("MTU for %s reduced to %d\n",
354
                                        inet_ntoa(icmpsrc.sin_addr), mtu);
355
#endif
356
                                if (mtu < 296) {
357
                                        /* rt->rt_rmx.rmx_mtu =
358
                                                rt->rt_ifp->if_mtu; */
359
                                        rt->rt_rmx.rmx_locks |= RTV_MTU;
360
                                } else if (rt->rt_rmx.rmx_mtu > mtu) {
361
                                        rt->rt_rmx.rmx_mtu = mtu;
362
                                }
363
                        }
364
                        if (rt)
365
                                RTFREE(rt);
366
                }
367
 
368
#endif
369
                ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
370
                if (ctlfunc)
371
                        (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
372
                                   (void *)&icp->icmp_ip);
373
                break;
374
 
375
        badcode:
376
                icmpstat.icps_badcode++;
377
                break;
378
 
379
        case ICMP_ECHO:
380
                if (!icmpbmcastecho
381
                    && (m->m_flags & (M_MCAST | M_BCAST)) != 0
382
                    && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
383
                        icmpstat.icps_bmcastecho++;
384
                        break;
385
                }
386
                icp->icmp_type = ICMP_ECHOREPLY;
387
                goto reflect;
388
 
389
        case ICMP_TSTAMP:
390
                if (!icmpbmcastecho
391
                    && (m->m_flags & (M_MCAST | M_BCAST)) != 0
392
                    && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
393
                        icmpstat.icps_bmcasttstamp++;
394
                        break;
395
                }
396
                if (icmplen < ICMP_TSLEN) {
397
                        icmpstat.icps_badlen++;
398
                        break;
399
                }
400
                icp->icmp_type = ICMP_TSTAMPREPLY;
401
                icp->icmp_rtime = iptime();
402
                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
403
                goto reflect;
404
 
405
        case ICMP_MASKREQ:
406
#define satosin(sa)     ((struct sockaddr_in *)(sa))
407
                if (icmpmaskrepl == 0)
408
                        break;
409
                /*
410
                 * We are not able to respond with all ones broadcast
411
                 * unless we receive it over a point-to-point interface.
412
                 */
413
                if (icmplen < ICMP_MASKLEN)
414
                        break;
415
                switch (ip->ip_dst.s_addr) {
416
 
417
                case INADDR_BROADCAST:
418
                case INADDR_ANY:
419
                        icmpdst.sin_addr = ip->ip_src;
420
                        break;
421
 
422
                default:
423
                        icmpdst.sin_addr = ip->ip_dst;
424
                }
425
                ia = (struct in_ifaddr *)ifaof_ifpforaddr(
426
                            (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
427
                if (ia == 0)
428
                        break;
429
                if (ia->ia_ifp == 0)
430
                        break;
431
                icp->icmp_type = ICMP_MASKREPLY;
432
                icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
433
                if (ip->ip_src.s_addr == 0) {
434
                        if (ia->ia_ifp->if_flags & IFF_BROADCAST)
435
                            ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
436
                        else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
437
                            ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
438
                }
439
reflect:
440
                ip->ip_len += hlen;     /* since ip_input deducts this */
441
                icmpstat.icps_reflect++;
442
                icmpstat.icps_outhist[icp->icmp_type]++;
443
                icmp_reflect(m);
444
                return;
445
 
446
        case ICMP_REDIRECT:
447
                if (code > 3)
448
                        goto badcode;
449
                if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
450
                    IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
451
                        icmpstat.icps_badlen++;
452
                        break;
453
                }
454
                /*
455
                 * Short circuit routing redirects to force
456
                 * immediate change in the kernel's routing
457
                 * tables.  The message is also handed to anyone
458
                 * listening on a raw socket (e.g. the routing
459
                 * daemon for use in updating its tables).
460
                 */
461
                icmpgw.sin_addr = ip->ip_src;
462
                icmpdst.sin_addr = icp->icmp_gwaddr;
463
#ifdef  ICMPPRINTFS
464
                if (icmpprintfs) {
465
                        char buf[4 * sizeof "123"];
466
                        strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
467
 
468
                        printf("redirect dst %s to %s\n",
469
                               buf, inet_ntoa(icp->icmp_gwaddr));
470
                }
471
#endif
472
                icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
473
                rtredirect((struct sockaddr *)&icmpsrc,
474
                  (struct sockaddr *)&icmpdst,
475
                  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
476
                  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
477
                pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
478
                break;
479
 
480
        /*
481
         * No kernel processing for the following;
482
         * just fall through to send to raw listener.
483
         */
484
        case ICMP_ECHOREPLY:
485
        case ICMP_ROUTERADVERT:
486
        case ICMP_ROUTERSOLICIT:
487
        case ICMP_TSTAMPREPLY:
488
        case ICMP_IREQREPLY:
489
        case ICMP_MASKREPLY:
490
        default:
491
                break;
492
        }
493
 
494
raw:
495
        rip_input(m, hlen);
496
        return;
497
 
498
freeit:
499
        m_freem(m);
500
}
501
 
502
/*
503
 * Reflect the ip packet back to the source
504
 */
505
static void
506
icmp_reflect(m)
507
        struct mbuf *m;
508
{
509
        register struct ip *ip = mtod(m, struct ip *);
510
        register struct in_ifaddr *ia;
511
        struct in_addr t;
512
        struct mbuf *opts = 0;
513
        int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
514
 
515
        if (!in_canforward(ip->ip_src) &&
516
            ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
517
             (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
518
                m_freem(m);     /* Bad return address */
519
                goto done;      /* Ip_output() will check for broadcast */
520
        }
521
        t = ip->ip_dst;
522
        ip->ip_dst = ip->ip_src;
523
        /*
524
         * If the incoming packet was addressed directly to us,
525
         * use dst as the src for the reply.  Otherwise (broadcast
526
         * or anonymous), use the address which corresponds
527
         * to the incoming interface.
528
         */
529
        for (ia = in_ifaddr; ia; ia = ia->ia_next) {
530
                if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
531
                        break;
532
                if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) &&
533
                    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
534
                        break;
535
        }
536
        icmpdst.sin_addr = t;
537
        if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif)
538
                ia = (struct in_ifaddr *)ifaof_ifpforaddr(
539
                        (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
540
        /*
541
         * The following happens if the packet was not addressed to us,
542
         * and was received on an interface with no IP address.
543
         */
544
        if (ia == (struct in_ifaddr *)0)
545
                ia = in_ifaddr;
546
        t = IA_SIN(ia)->sin_addr;
547
        ip->ip_src = t;
548
        ip->ip_ttl = MAXTTL;
549
 
550
        if (optlen > 0) {
551
                register u_char *cp;
552
                int opt, cnt;
553
                u_int len;
554
 
555
                /*
556
                 * Retrieve any source routing from the incoming packet;
557
                 * add on any record-route or timestamp options.
558
                 */
559
                cp = (u_char *) (ip + 1);
560
                if ((opts = ip_srcroute()) == 0 &&
561
                    (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
562
                        opts->m_len = sizeof(struct in_addr);
563
                        mtod(opts, struct in_addr *)->s_addr = 0;
564
                }
565
                if (opts) {
566
#ifdef ICMPPRINTFS
567
                    if (icmpprintfs)
568
                            printf("icmp_reflect optlen %d rt %d => ",
569
                                optlen, opts->m_len);
570
#endif
571
                    for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
572
                            opt = cp[IPOPT_OPTVAL];
573
                            if (opt == IPOPT_EOL)
574
                                    break;
575
                            if (opt == IPOPT_NOP)
576
                                    len = 1;
577
                            else {
578
                                    len = cp[IPOPT_OLEN];
579
                                    if (len <= 0 || len > cnt)
580
                                            break;
581
                            }
582
                            /*
583
                             * Should check for overflow, but it "can't happen"
584
                             */
585
                            if (opt == IPOPT_RR || opt == IPOPT_TS ||
586
                                opt == IPOPT_SECURITY) {
587
                                    bcopy((caddr_t)cp,
588
                                        mtod(opts, caddr_t) + opts->m_len, len);
589
                                    opts->m_len += len;
590
                            }
591
                    }
592
                    /* Terminate & pad, if necessary */
593
                    cnt = opts->m_len % 4;
594
                    if (cnt) {
595
                            for (; cnt < 4; cnt++) {
596
                                    *(mtod(opts, caddr_t) + opts->m_len) =
597
                                        IPOPT_EOL;
598
                                    opts->m_len++;
599
                            }
600
                    }
601
#ifdef ICMPPRINTFS
602
                    if (icmpprintfs)
603
                            printf("%d\n", opts->m_len);
604
#endif
605
                }
606
                /*
607
                 * Now strip out original options by copying rest of first
608
                 * mbuf's data back, and adjust the IP length.
609
                 */
610
                ip->ip_len -= optlen;
611
                ip->ip_vhl = IP_VHL_BORING;
612
                m->m_len -= optlen;
613
                if (m->m_flags & M_PKTHDR)
614
                        m->m_pkthdr.len -= optlen;
615
                optlen += sizeof(struct ip);
616
                bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
617
                         (unsigned)(m->m_len - sizeof(struct ip)));
618
        }
619
        m->m_flags &= ~(M_BCAST|M_MCAST);
620
        icmp_send(m, opts);
621
done:
622
        if (opts)
623
                (void)m_free(opts);
624
}
625
 
626
/*
627
 * Send an icmp packet back to the ip level,
628
 * after supplying a checksum.
629
 */
630
static void
631
icmp_send(m, opts)
632
        register struct mbuf *m;
633
        struct mbuf *opts;
634
{
635
        register struct ip *ip = mtod(m, struct ip *);
636
        register int hlen;
637
        register struct icmp *icp;
638
        struct route ro;
639
 
640
        hlen = IP_VHL_HL(ip->ip_vhl) << 2;
641
        m->m_data += hlen;
642
        m->m_len -= hlen;
643
        icp = mtod(m, struct icmp *);
644
        icp->icmp_cksum = 0;
645
        icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
646
        m->m_data -= hlen;
647
        m->m_len += hlen;
648
#ifdef ICMPPRINTFS
649
        if (icmpprintfs) {
650
                char buf[4 * sizeof "123"];
651
                strcpy(buf, inet_ntoa(ip->ip_dst));
652
                printf("icmp_send dst %s src %s\n",
653
                       buf, inet_ntoa(ip->ip_src));
654
        }
655
#endif
656
        bzero(&ro, sizeof ro);
657
        (void) ip_output(m, opts, &ro, 0, NULL);
658
        if (ro.ro_rt)
659
                RTFREE(ro.ro_rt);
660
}
661
 
662
n_time
663
iptime()
664
{
665
        struct timeval atv;
666
        u_long t;
667
 
668
        microtime(&atv);
669
        t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
670
        return (htonl(t));
671
}
672
 
673
#if 1
674
/*
675
 * Return the next larger or smaller MTU plateau (table from RFC 1191)
676
 * given current value MTU.  If DIR is less than zero, a larger plateau
677
 * is returned; otherwise, a smaller value is returned.
678
 */
679
static int
680
ip_next_mtu(mtu, dir)
681
        int mtu;
682
        int dir;
683
{
684
        static int mtutab[] = {
685
                65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
686
                68, 0
687
        };
688
        int i;
689
 
690
        for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
691
                if (mtu >= mtutab[i])
692
                        break;
693
        }
694
 
695
        if (dir < 0) {
696
                if (i == 0) {
697
                        return 0;
698
                } else {
699
                        return mtutab[i - 1];
700
                }
701
        } else {
702
                if (mtutab[i] == 0) {
703
                        return 0;
704
                } else if(mtu > mtutab[i]) {
705
                        return mtutab[i];
706
                } else {
707
                        return mtutab[i + 1];
708
                }
709
        }
710
}
711
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.