00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "lwip/opt.h"
00043
00044 #if LWIP_ICMP
00045
00046 #include "lwip/icmp.h"
00047 #include "lwip/inet.h"
00048 #include "lwip/inet_chksum.h"
00049 #include "lwip/ip.h"
00050 #include "lwip/def.h"
00051 #include "lwip/stats.h"
00052 #include "lwip/snmp.h"
00053
00054 #include <string.h>
00055
00056
00057
00058
00059 #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
00060 #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
00061 #endif
00062
00063
00064 #define ICMP_DEST_UNREACH_DATASIZE 8
00065
00066 static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 void
00078 icmp_input(struct pbuf *p, struct netif *inp)
00079 {
00080 u8_t type;
00081 #ifdef LWIP_DEBUG
00082 u8_t code;
00083 #endif
00084 struct icmp_echo_hdr *iecho;
00085 struct ip_hdr *iphdr;
00086 struct ip_addr tmpaddr;
00087 s16_t hlen;
00088
00089 ICMP_STATS_INC(icmp.recv);
00090 snmp_inc_icmpinmsgs();
00091
00092
00093 iphdr = p->payload;
00094 hlen = IPH_HL(iphdr) * 4;
00095 if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
00096 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
00097 goto lenerr;
00098 }
00099
00100 type = *((u8_t *)p->payload);
00101 #ifdef LWIP_DEBUG
00102 code = *(((u8_t *)p->payload)+1);
00103 #endif
00104 switch (type) {
00105 case ICMP_ECHO:
00106 #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
00107 {
00108 int accepted = 1;
00109 #if !LWIP_MULTICAST_PING
00110
00111 if (ip_addr_ismulticast(&iphdr->dest)) {
00112 accepted = 0;
00113 }
00114 #endif
00115 #if !LWIP_BROADCAST_PING
00116
00117 if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
00118 accepted = 0;
00119 }
00120 #endif
00121
00122 if (!accepted) {
00123 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
00124 ICMP_STATS_INC(icmp.err);
00125 pbuf_free(p);
00126 return;
00127 }
00128 }
00129 #endif
00130 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
00131 if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
00132 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
00133 goto lenerr;
00134 }
00135 if (inet_chksum_pbuf(p) != 0) {
00136 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
00137 pbuf_free(p);
00138 ICMP_STATS_INC(icmp.chkerr);
00139 snmp_inc_icmpinerrors();
00140 return;
00141 }
00142 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
00143 if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
00144
00145
00146
00147 struct pbuf *r;
00148
00149 if (pbuf_header(p, hlen)) {
00150 LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
00151 goto memerr;
00152 }
00153
00154 r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
00155 if (r == NULL) {
00156 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
00157 goto memerr;
00158 }
00159 LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
00160 (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
00161
00162 if (pbuf_copy(r, p) != ERR_OK) {
00163 LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
00164 goto memerr;
00165 }
00166 iphdr = r->payload;
00167
00168 if (pbuf_header(r, -hlen)) {
00169 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
00170 goto memerr;
00171 }
00172
00173 pbuf_free(p);
00174
00175 p = r;
00176 } else {
00177
00178 if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
00179 LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
00180 goto memerr;
00181 }
00182 }
00183 #endif
00184
00185
00186
00187 iecho = p->payload;
00188 tmpaddr.addr = iphdr->src.addr;
00189 iphdr->src.addr = iphdr->dest.addr;
00190 iphdr->dest.addr = tmpaddr.addr;
00191 ICMPH_TYPE_SET(iecho, ICMP_ER);
00192
00193 if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
00194 iecho->chksum += htons(ICMP_ECHO << 8) + 1;
00195 } else {
00196 iecho->chksum += htons(ICMP_ECHO << 8);
00197 }
00198
00199
00200 IPH_TTL_SET(iphdr, ICMP_TTL);
00201 IPH_CHKSUM_SET(iphdr, 0);
00202 #if CHECKSUM_GEN_IP
00203 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
00204 #endif
00205
00206 ICMP_STATS_INC(icmp.xmit);
00207
00208 snmp_inc_icmpoutmsgs();
00209
00210 snmp_inc_icmpoutechoreps();
00211
00212 if(pbuf_header(p, hlen)) {
00213 LWIP_ASSERT("Can't move over header in packet", 0);
00214 } else {
00215 err_t ret;
00216 ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
00217 ICMP_TTL, 0, IP_PROTO_ICMP, inp);
00218 if (ret != ERR_OK) {
00219 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
00220 }
00221 }
00222 break;
00223 default:
00224 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
00225 (s16_t)type, (s16_t)code));
00226 ICMP_STATS_INC(icmp.proterr);
00227 ICMP_STATS_INC(icmp.drop);
00228 }
00229 pbuf_free(p);
00230 return;
00231 lenerr:
00232 pbuf_free(p);
00233 ICMP_STATS_INC(icmp.lenerr);
00234 snmp_inc_icmpinerrors();
00235 return;
00236 #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
00237 memerr:
00238 pbuf_free(p);
00239 ICMP_STATS_INC(icmp.err);
00240 snmp_inc_icmpinerrors();
00241 return;
00242 #endif
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 void
00255 icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
00256 {
00257 icmp_send_response(p, ICMP_DUR, t);
00258 }
00259
00260 #if IP_FORWARD || IP_REASSEMBLY
00261
00262
00263
00264
00265
00266
00267
00268 void
00269 icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
00270 {
00271 icmp_send_response(p, ICMP_TE, t);
00272 }
00273
00274 #endif
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 static void
00285 icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
00286 {
00287 struct pbuf *q;
00288 struct ip_hdr *iphdr;
00289
00290 struct icmp_echo_hdr *icmphdr;
00291
00292
00293 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
00294 PBUF_RAM);
00295 if (q == NULL) {
00296 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
00297 return;
00298 }
00299 LWIP_ASSERT("check that first pbuf can hold icmp message",
00300 (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
00301
00302 iphdr = p->payload;
00303 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
00304 ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
00305 LWIP_DEBUGF(ICMP_DEBUG, (" to "));
00306 ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
00307 LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
00308
00309 icmphdr = q->payload;
00310 icmphdr->type = type;
00311 icmphdr->code = code;
00312 icmphdr->id = 0;
00313 icmphdr->seqno = 0;
00314
00315
00316 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
00317 IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
00318
00319
00320 icmphdr->chksum = 0;
00321 icmphdr->chksum = inet_chksum(icmphdr, q->len);
00322 ICMP_STATS_INC(icmp.xmit);
00323
00324 snmp_inc_icmpoutmsgs();
00325
00326 snmp_inc_icmpouttimeexcds();
00327 ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
00328 pbuf_free(q);
00329 }
00330
00331 #endif