source: rtems/cpukit/libnetworking/netinet/ip_icmp.c @ 0e16fa45

5
Last change on this file since 0e16fa45 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

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