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 #include "lwip/opt.h"
00037
00038 #if LWIP_ICMP
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
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
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
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
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
00113 q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
00114
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
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
00151 q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
00152
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
00168 SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
00169
00170
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