A version of LWIP, provided for backwards compatibility.

Dependents:   AA_DemoBoard DemoBoard HelloServerDemo DemoBoard_RangeIndicator ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers icmp6.c Source File

icmp6.c

00001 /*
00002  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright notice,
00009  *    this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright notice,
00011  *    this list of conditions and the following disclaimer in the documentation
00012  *    and/or other materials provided with the distribution.
00013  * 3. The name of the author may not be used to endorse or promote products
00014  *    derived from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00017  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00018  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00019  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00020  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00021  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00024  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00025  * OF SUCH DAMAGE.
00026  *
00027  * This file is part of the lwIP TCP/IP stack.
00028  *
00029  * Author: Adam Dunkels <adam@sics.se>
00030  *
00031  */
00032 
00033 /* Some ICMP messages should be passed to the transport protocols. This
00034    is not implemented. */
00035 
00036 #include "lwip/opt.h"
00037 
00038 #if IPv6
00039 
00040 #if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
00041 
00042 #include "ipv6/lwip/icmp.h"
00043 #include "ipv6/lwip/inet.h"
00044 #include "ipv6/lwip/ip.h"
00045 #include "lwip/def.h"
00046 #include "lwip/stats.h"
00047 #include "lwip/inet_chksum.h"
00048 
00049 
00050 void
00051 icmp_input(struct pbuf *p, struct netif *inp)
00052 {
00053   u8_t type;
00054   struct icmp_echo_hdr *iecho;
00055   struct ip_hdr *iphdr;
00056   struct ip_addr tmpaddr;
00057 
00058   ICMP_STATS_INC(icmp.recv);
00059 
00060   /* TODO: check length before accessing payload! */
00061 
00062   type = ((u8_t *)p->payload)[0];
00063 
00064   switch (type) {
00065   case ICMP6_ECHO:
00066     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
00067 
00068     if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
00069       LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
00070 
00071       pbuf_free(p);
00072       ICMP_STATS_INC(icmp.lenerr);
00073       return;
00074     }
00075     iecho = static_cast<struct icmp_echo_hdr *>(p->payload);
00076     iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
00077 //    if (inet_chksum_pbuf(p) != 0) {
00078 //      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
00079 //      ICMP_STATS_INC(icmp.chkerr);
00080 //    /*      return;*/
00081 //    }
00082     LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
00083     ip_addr_set(&tmpaddr, &(iphdr->src));
00084     ip_addr_set(&(iphdr->src), &(iphdr->dest));
00085     ip_addr_set(&(iphdr->dest), &tmpaddr);
00086     iecho->type = ICMP6_ER;
00087     /* adjust the checksum */
00088     if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
00089       iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
00090     } else {
00091       iecho->chksum += htons(ICMP6_ECHO << 8);
00092     }
00093     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
00094     ICMP_STATS_INC(icmp.xmit);
00095 
00096     /*    LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
00097     struct ip_addr iphdrsrc;
00098     iphdrsrc.addr = iphdr->src.addr;
00099     ip_output_if(p, &(iphdrsrc), IP_HDRINCL,
00100      iphdr->hoplim, IP_PROTO_ICMP, inp);
00101     break;
00102   default:
00103     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
00104     ICMP_STATS_INC(icmp.proterr);
00105     ICMP_STATS_INC(icmp.drop);
00106   }
00107 
00108   pbuf_free(p);
00109 }
00110 
00111 void
00112 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
00113 {
00114   struct pbuf *q;
00115   struct ip_hdr *iphdr;
00116   struct icmp_dur_hdr *idur;
00117 
00118   /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
00119   q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
00120   /* ICMP header + IP header + 8 bytes of data */
00121   if (q == NULL) {
00122     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
00123     pbuf_free(p);
00124     return;
00125   }
00126   LWIP_ASSERT("check that first pbuf can hold icmp message",
00127              (q->len >= (8 + IP_HLEN + 8)));
00128 
00129   iphdr = static_cast<struct ip_hdr *>(p->payload);
00130 
00131   idur = static_cast<struct icmp_dur_hdr *>(q->payload);
00132   idur->type = (u8_t)ICMP6_DUR;
00133   idur->icode = (u8_t)t;
00134 
00135   SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
00136 
00137   /* calculate checksum */
00138   idur->chksum = 0;
00139   idur->chksum = inet_chksum(idur, q->len);
00140   ICMP_STATS_INC(icmp.xmit);
00141 
00142   ip_output(q, static_cast<struct ip_addr *>(NULL),
00143       (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
00144   pbuf_free(q);
00145 }
00146 
00147 void
00148 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
00149 {
00150   struct pbuf *q;
00151   struct ip_hdr *iphdr;
00152   struct icmp_te_hdr *tehdr;
00153 
00154   LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
00155 
00156   /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
00157   q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
00158   /* ICMP header + IP header + 8 bytes of data */
00159   if (q == NULL) {
00160     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
00161     pbuf_free(p);
00162     return;
00163   }
00164   LWIP_ASSERT("check that first pbuf can hold icmp message",
00165              (q->len >= (8 + IP_HLEN + 8)));
00166 
00167   iphdr = static_cast<struct ip_hdr *>(p->payload);
00168 
00169   tehdr = static_cast<icmp_te_hdr *>(q->payload);
00170   tehdr->type = (u8_t)ICMP6_TE;
00171   tehdr->icode = (u8_t)t;
00172 
00173   /* copy fields from original packet */
00174   SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
00175 
00176   /* calculate checksum */
00177   tehdr->chksum = 0;
00178   tehdr->chksum = inet_chksum(tehdr, q->len);
00179   ICMP_STATS_INC(icmp.xmit);
00180   ip_output(q, static_cast<struct ip_addr *>(NULL),
00181       (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
00182   pbuf_free(q);
00183 }
00184 
00185 #endif /* LWIP_ICMP */
00186 
00187 #endif /* IPv6 */