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