1/* 2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 25 * OF SUCH DAMAGE. 26 * 27 * This file is part of the lwIP TCP/IP stack. 28 * 29 * Author: Adam Dunkels <adam@sics.se> 30 * 31 */ 32 33/* Some ICMP messages should be passed to the transport protocols. This 34 is not implemented. */ 35 36#include "lwip/opt.h" 37 38#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ 39 40#include "lwip/icmp.h" 41#include "lwip/inet.h" 42#include "lwip/ip.h" 43#include "lwip/def.h" 44#include "lwip/stats.h" 45 46void icmp_input(struct pbuf *p, struct netif *inp) 47{ 48 u8_t type; 49 struct icmp_echo_hdr *iecho; 50 struct ip_hdr *iphdr; 51 struct ip_addr tmpaddr; 52 53 ICMP_STATS_INC(icmp.recv); 54 55 /* TODO: check length before accessing payload! */ 56 57 type = ((u8_t *) p->payload)[0]; 58 59 switch (type) { 60 case ICMP6_ECHO: 61 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); 62 63 if (p->tot_len < sizeof(struct icmp_echo_hdr)) { 64 LWIP_DEBUGF(ICMP_DEBUG, 65 ("icmp_input: bad ICMP echo received\n")); 66 67 pbuf_free(p); 68 ICMP_STATS_INC(icmp.lenerr); 69 return; 70 } 71 iecho = p->payload; 72 iphdr = (struct ip_hdr *) ((u8_t *) p->payload - IP_HLEN); 73 if (inet_chksum_pbuf(p) != 0) { 74 LWIP_DEBUGF(ICMP_DEBUG, 75 ("icmp_input: checksum failed for received ICMP echo (%" 76 X16_F ")\n", inet_chksum_pseudo(p, &(iphdr->src), 77 &(iphdr->dest), 78 IP_PROTO_ICMP, 79 p->tot_len))); 80 ICMP_STATS_INC(icmp.chkerr); 81 /* return; */ 82 } 83 LWIP_DEBUGF(ICMP_DEBUG, 84 ("icmp: p->len %" S16_F " p->tot_len %" S16_F "\n", 85 p->len, p->tot_len)); 86 ip_addr_set(&tmpaddr, &(iphdr->src)); 87 ip_addr_set(&(iphdr->src), &(iphdr->dest)); 88 ip_addr_set(&(iphdr->dest), &tmpaddr); 89 iecho->type = ICMP6_ER; 90 /* adjust the checksum */ 91 if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) { 92 iecho->chksum += htons(ICMP6_ECHO << 8) + 1; 93 } else { 94 iecho->chksum += htons(ICMP6_ECHO << 8); 95 } 96 LWIP_DEBUGF(ICMP_DEBUG, 97 ("icmp_input: checksum failed for received ICMP echo (%" 98 X16_F ")\n", inet_chksum_pseudo(p, &(iphdr->src), 99 &(iphdr->dest), 100 IP_PROTO_ICMP, 101 p->tot_len))); 102 ICMP_STATS_INC(icmp.xmit); 103 104 /* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len); */ 105 ip_output_if(p, &(iphdr->src), IP_HDRINCL, 106 iphdr->hoplim, IP_PROTO_ICMP, inp); 107 break; 108 default: 109 LWIP_DEBUGF(ICMP_DEBUG, 110 ("icmp_input: ICMP type %" S16_F " not supported.\n", 111 (s16_t) type)); 112 ICMP_STATS_INC(icmp.proterr); 113 ICMP_STATS_INC(icmp.drop); 114 } 115 116 pbuf_free(p); 117} 118 119void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) 120{ 121 struct pbuf *q; 122 struct ip_hdr *iphdr; 123 struct icmp_dur_hdr *idur; 124 125 /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ 126 q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); 127 /* ICMP header + IP header + 8 bytes of data */ 128 if (q == NULL) { 129 LWIP_DEBUGF(ICMP_DEBUG, 130 ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); 131 pbuf_free(p); 132 return; 133 } 134 LWIP_ASSERT("check that first pbuf can hold icmp message", 135 (q->len >= (8 + IP_HLEN + 8))); 136 137 iphdr = p->payload; 138 139 idur = q->payload; 140 idur->type = (u8_t) ICMP6_DUR; 141 idur->icode = (u8_t) t; 142 143 SMEMCPY((u8_t *) q->payload + 8, p->payload, IP_HLEN + 8); 144 145 /* calculate checksum */ 146 idur->chksum = 0; 147 idur->chksum = inet_chksum(idur, q->len); 148 ICMP_STATS_INC(icmp.xmit); 149 150 ip_output(q, NULL, 151 (struct ip_addr *) &(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); 152 pbuf_free(q); 153} 154 155void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) 156{ 157 struct pbuf *q; 158 struct ip_hdr *iphdr; 159 struct icmp_te_hdr *tehdr; 160 161 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n")); 162 163 /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ 164 q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); 165 /* ICMP header + IP header + 8 bytes of data */ 166 if (q == NULL) { 167 LWIP_DEBUGF(ICMP_DEBUG, 168 ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); 169 pbuf_free(p); 170 return; 171 } 172 LWIP_ASSERT("check that first pbuf can hold icmp message", 173 (q->len >= (8 + IP_HLEN + 8))); 174 175 iphdr = p->payload; 176 177 tehdr = q->payload; 178 tehdr->type = (u8_t) ICMP6_TE; 179 tehdr->icode = (u8_t) t; 180 181 /* copy fields from original packet */ 182 SMEMCPY((u8_t *) q->payload + 8, (u8_t *) p->payload, IP_HLEN + 8); 183 184 /* calculate checksum */ 185 tehdr->chksum = 0; 186 tehdr->chksum = inet_chksum(tehdr, q->len); 187 ICMP_STATS_INC(icmp.xmit); 188 ip_output(q, NULL, 189 (struct ip_addr *) &(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); 190 pbuf_free(q); 191} 192 193#endif /* LWIP_ICMP */ 194