source: rtems/cpukit/libnetworking/netinet/ip_icmp.c @ 005c3fe7

5
Last change on this file since 005c3fe7 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

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