SAMV71 Xplained Ultra Software Package 1.0

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 LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
00039 
00040 #include "lwip/icmp.h"
00041 #include "lwip/inet.h"
00042 #include "lwip/ip.h"
00043 #include "lwip/def.h"
00044 #include "lwip/stats.h"
00045 
00046 void
00047 icmp_input(struct pbuf *p, struct netif *inp)
00048 {
00049   u8_t type;
00050   struct icmp_echo_hdr *iecho;
00051   struct ip_hdr *iphdr;
00052   struct ip_addr tmpaddr;
00053 
00054   ICMP_STATS_INC(icmp.recv);
00055 
00056   /* TODO: check length before accessing payload! */
00057 
00058   type = ((u8_t *)p->payload)[0];
00059 
00060   switch (type) {
00061   case ICMP6_ECHO:
00062     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
00063 
00064     if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
00065       LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
00066 
00067       pbuf_free(p);
00068       ICMP_STATS_INC(icmp.lenerr);
00069       return;
00070     }
00071     iecho = p->payload;
00072     iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
00073     if (inet_chksum_pbuf(p) != 0) {
00074       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)));
00075       ICMP_STATS_INC(icmp.chkerr);
00076     /*      return;*/
00077     }
00078     LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
00079     ip_addr_set(&tmpaddr, &(iphdr->src));
00080     ip_addr_set(&(iphdr->src), &(iphdr->dest));
00081     ip_addr_set(&(iphdr->dest), &tmpaddr);
00082     iecho->type = ICMP6_ER;
00083     /* adjust the checksum */
00084     if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
00085       iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
00086     } else {
00087       iecho->chksum += htons(ICMP6_ECHO << 8);
00088     }
00089     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)));
00090     ICMP_STATS_INC(icmp.xmit);
00091 
00092     /*    LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
00093     ip_output_if (p, &(iphdr->src), IP_HDRINCL,
00094      iphdr->hoplim, IP_PROTO_ICMP, inp);
00095     break;
00096   default:
00097     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
00098     ICMP_STATS_INC(icmp.proterr);
00099     ICMP_STATS_INC(icmp.drop);
00100   }
00101 
00102   pbuf_free(p);
00103 }
00104 
00105 void
00106 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
00107 {
00108   struct pbuf *q;
00109   struct ip_hdr *iphdr;
00110   struct icmp_dur_hdr *idur;
00111 
00112   /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
00113   q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
00114   /* ICMP header + IP header + 8 bytes of data */
00115   if (q == NULL) {
00116     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
00117     pbuf_free(p);
00118     return;
00119   }
00120   LWIP_ASSERT("check that first pbuf can hold icmp message",
00121              (q->len >= (8 + IP_HLEN + 8)));
00122 
00123   iphdr = p->payload;
00124 
00125   idur = q->payload;
00126   idur->type = (u8_t)ICMP6_DUR;
00127   idur->icode = (u8_t)t;
00128 
00129   SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
00130 
00131   /* calculate checksum */
00132   idur->chksum = 0;
00133   idur->chksum = inet_chksum(idur, q->len);
00134   ICMP_STATS_INC(icmp.xmit);
00135 
00136   ip_output(q, NULL,
00137       (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
00138   pbuf_free(q);
00139 }
00140 
00141 void
00142 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
00143 {
00144   struct pbuf *q;
00145   struct ip_hdr *iphdr;
00146   struct icmp_te_hdr *tehdr;
00147 
00148   LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
00149 
00150   /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
00151   q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
00152   /* ICMP header + IP header + 8 bytes of data */
00153   if (q == NULL) {
00154     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
00155     pbuf_free(p);
00156     return;
00157   }
00158   LWIP_ASSERT("check that first pbuf can hold icmp message",
00159              (q->len >= (8 + IP_HLEN + 8)));
00160 
00161   iphdr = p->payload;
00162 
00163   tehdr = q->payload;
00164   tehdr->type = (u8_t)ICMP6_TE;
00165   tehdr->icode = (u8_t)t;
00166 
00167   /* copy fields from original packet */
00168   SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
00169 
00170   /* calculate checksum */
00171   tehdr->chksum = 0;
00172   tehdr->chksum = inet_chksum(tehdr, q->len);
00173   ICMP_STATS_INC(icmp.xmit);
00174   ip_output(q, NULL,
00175       (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
00176   pbuf_free(q);
00177 }
00178 
00179 #endif /* LWIP_ICMP */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines