Warning, cross-references for /kernel/lwip/core/ipv4/icmp.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include "lwip/opt.h"
0043
0044 #if LWIP_ICMP
0045
0046 #include "lwip/icmp.h"
0047 #include "lwip/inet.h"
0048 #include "lwip/inet_chksum.h"
0049 #include "lwip/ip.h"
0050 #include "lwip/def.h"
0051 #include "lwip/stats.h"
0052 #include "lwip/snmp.h"
0053
0054 #include <string.h>
0055
0056
0057
0058
0059 #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
0060 #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
0061 #endif
0062
0063
0064 #define ICMP_DEST_UNREACH_DATASIZE 8
0065
0066 static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 void
0078 icmp_input(struct pbuf *p, struct netif *inp)
0079 {
0080 u8_t type;
0081 #ifdef LWIP_DEBUG
0082 u8_t code;
0083 #endif
0084 struct icmp_echo_hdr *iecho;
0085 struct ip_hdr *iphdr;
0086 struct ip_addr tmpaddr;
0087 s16_t hlen;
0088
0089 ICMP_STATS_INC(icmp.recv);
0090 snmp_inc_icmpinmsgs();
0091
0092
0093 iphdr = p->payload;
0094 hlen = IPH_HL(iphdr) * 4;
0095 if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
0096 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
0097 goto lenerr;
0098 }
0099
0100 type = *((u8_t *)p->payload);
0101 #ifdef LWIP_DEBUG
0102 code = *(((u8_t *)p->payload)+1);
0103 #endif
0104 switch (type) {
0105 case ICMP_ECHO:
0106 #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
0107 {
0108 int accepted = 1;
0109 #if !LWIP_MULTICAST_PING
0110
0111 if (ip_addr_ismulticast(&iphdr->dest)) {
0112 accepted = 0;
0113 }
0114 #endif
0115 #if !LWIP_BROADCAST_PING
0116
0117 if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
0118 accepted = 0;
0119 }
0120 #endif
0121
0122 if (!accepted) {
0123 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
0124 ICMP_STATS_INC(icmp.err);
0125 pbuf_free(p);
0126 return;
0127 }
0128 }
0129 #endif
0130 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
0131 if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
0132 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
0133 goto lenerr;
0134 }
0135 if (inet_chksum_pbuf(p) != 0) {
0136 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
0137 pbuf_free(p);
0138 ICMP_STATS_INC(icmp.chkerr);
0139 snmp_inc_icmpinerrors();
0140 return;
0141 }
0142 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
0143 if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
0144
0145
0146
0147 struct pbuf *r;
0148
0149 if (pbuf_header(p, hlen)) {
0150 LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
0151 goto memerr;
0152 }
0153
0154 r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
0155 if (r == NULL) {
0156 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
0157 goto memerr;
0158 }
0159 LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
0160 (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
0161
0162 if (pbuf_copy(r, p) != ERR_OK) {
0163 LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
0164 goto memerr;
0165 }
0166 iphdr = r->payload;
0167
0168 if (pbuf_header(r, -hlen)) {
0169 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
0170 goto memerr;
0171 }
0172
0173 pbuf_free(p);
0174
0175 p = r;
0176 } else {
0177
0178 if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
0179 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
0180 goto memerr;
0181 }
0182 }
0183 #endif
0184
0185
0186
0187 iecho = p->payload;
0188 tmpaddr.addr = iphdr->src.addr;
0189 iphdr->src.addr = iphdr->dest.addr;
0190 iphdr->dest.addr = tmpaddr.addr;
0191 ICMPH_TYPE_SET(iecho, ICMP_ER);
0192
0193 if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
0194 iecho->chksum += htons(ICMP_ECHO << 8) + 1;
0195 } else {
0196 iecho->chksum += htons(ICMP_ECHO << 8);
0197 }
0198
0199
0200 IPH_TTL_SET(iphdr, ICMP_TTL);
0201 IPH_CHKSUM_SET(iphdr, 0);
0202 #if CHECKSUM_GEN_IP
0203 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
0204 #endif
0205
0206 ICMP_STATS_INC(icmp.xmit);
0207
0208 snmp_inc_icmpoutmsgs();
0209
0210 snmp_inc_icmpoutechoreps();
0211
0212 if(pbuf_header(p, hlen)) {
0213 LWIP_ASSERT("Can't move over header in packet", 0);
0214 } else {
0215 err_t ret;
0216 ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
0217 ICMP_TTL, 0, IP_PROTO_ICMP, inp);
0218 if (ret != ERR_OK) {
0219 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
0220 }
0221 }
0222 break;
0223 default:
0224 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
0225 (s16_t)type, (s16_t)code));
0226 ICMP_STATS_INC(icmp.proterr);
0227 ICMP_STATS_INC(icmp.drop);
0228 }
0229 pbuf_free(p);
0230 return;
0231 lenerr:
0232 pbuf_free(p);
0233 ICMP_STATS_INC(icmp.lenerr);
0234 snmp_inc_icmpinerrors();
0235 return;
0236 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
0237 memerr:
0238 pbuf_free(p);
0239 ICMP_STATS_INC(icmp.err);
0240 snmp_inc_icmpinerrors();
0241 return;
0242 #endif
0243 }
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254 void
0255 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
0256 {
0257 icmp_send_response(p, ICMP_DUR, t);
0258 }
0259
0260 #if IP_FORWARD || IP_REASSEMBLY
0261
0262
0263
0264
0265
0266
0267
0268 void
0269 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
0270 {
0271 icmp_send_response(p, ICMP_TE, t);
0272 }
0273
0274 #endif
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284 static void
0285 icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
0286 {
0287 struct pbuf *q;
0288 struct ip_hdr *iphdr;
0289
0290 struct icmp_echo_hdr *icmphdr;
0291
0292
0293 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
0294 PBUF_RAM);
0295 if (q == NULL) {
0296 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
0297 return;
0298 }
0299 LWIP_ASSERT("check that first pbuf can hold icmp message",
0300 (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
0301
0302 iphdr = p->payload;
0303 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
0304 ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
0305 LWIP_DEBUGF(ICMP_DEBUG, (" to "));
0306 ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
0307 LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
0308
0309 icmphdr = q->payload;
0310 icmphdr->type = type;
0311 icmphdr->code = code;
0312 icmphdr->id = 0;
0313 icmphdr->seqno = 0;
0314
0315
0316 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
0317 IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
0318
0319
0320 icmphdr->chksum = 0;
0321 icmphdr->chksum = inet_chksum(icmphdr, q->len);
0322 ICMP_STATS_INC(icmp.xmit);
0323
0324 snmp_inc_icmpoutmsgs();
0325
0326 snmp_inc_icmpouttimeexcds();
0327 ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
0328 pbuf_free(q);
0329 }
0330
0331 #endif