Contiki 2.6
|
00001 /** 00002 * \addtogroup uip6 00003 * @{ 00004 */ 00005 00006 /** 00007 * \file 00008 * ICMPv6 echo request and error messages (RFC 4443) 00009 * \author Julien Abeille <jabeille@cisco.com> 00010 * \author Mathilde Durvy <mdurvy@cisco.com> 00011 */ 00012 00013 /* 00014 * Copyright (c) 2001-2003, Adam Dunkels. 00015 * All rights reserved. 00016 * 00017 * Redistribution and use in source and binary forms, with or without 00018 * modification, are permitted provided that the following conditions 00019 * are met: 00020 * 1. Redistributions of source code must retain the above copyright 00021 * notice, this list of conditions and the following disclaimer. 00022 * 2. Redistributions in binary form must reproduce the above copyright 00023 * notice, this list of conditions and the following disclaimer in the 00024 * documentation and/or other materials provided with the distribution. 00025 * 3. The name of the author may not be used to endorse or promote 00026 * products derived from this software without specific prior 00027 * written permission. 00028 * 00029 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 00030 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00031 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00032 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00033 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00034 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00035 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00036 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00037 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00038 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00039 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00040 * 00041 * This file is part of the uIP TCP/IP stack. 00042 * 00043 */ 00044 00045 #include <string.h> 00046 #include "net/uip-ds6.h" 00047 #include "net/uip-icmp6.h" 00048 00049 #define DEBUG 0 00050 #if DEBUG 00051 #include <stdio.h> 00052 #define PRINTF(...) printf(__VA_ARGS__) 00053 #define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) 00054 #define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",lladdr->addr[0], lladdr->addr[1], lladdr->addr[2], lladdr->addr[3],lladdr->addr[4], lladdr->addr[5]) 00055 #else 00056 #define PRINTF(...) 00057 #define PRINT6ADDR(addr) 00058 #endif 00059 00060 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) 00061 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) 00062 #define UIP_ICMP6_ERROR_BUF ((struct uip_icmp6_error *)&uip_buf[uip_l2_l3_icmp_hdr_len]) 00063 #define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len]) 00064 #define UIP_FIRST_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[UIP_LLIPH_LEN]) 00065 00066 /** \brief temporary IP address */ 00067 static uip_ipaddr_t tmp_ipaddr; 00068 00069 #if UIP_CONF_IPV6_RPL 00070 #include "rpl/rpl.h" 00071 #endif /* UIP_CONF_IPV6_RPL */ 00072 00073 /*---------------------------------------------------------------------------*/ 00074 void 00075 uip_icmp6_echo_request_input(void) 00076 { 00077 #if UIP_CONF_IPV6_RPL 00078 uint8_t temp_ext_len; 00079 #endif /* UIP_CONF_IPV6_RPL */ 00080 /* 00081 * we send an echo reply. It is trivial if there was no extension 00082 * headers in the request otherwise we need to remove the extension 00083 * headers and change a few fields 00084 */ 00085 PRINTF("Received Echo Request from"); 00086 PRINT6ADDR(&UIP_IP_BUF->srcipaddr); 00087 PRINTF("to"); 00088 PRINT6ADDR(&UIP_IP_BUF->destipaddr); 00089 PRINTF("\n"); 00090 00091 /* IP header */ 00092 UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit; 00093 00094 if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)){ 00095 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr); 00096 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); 00097 } else { 00098 uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->srcipaddr); 00099 uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); 00100 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &tmp_ipaddr); 00101 } 00102 00103 if(uip_ext_len > 0) { 00104 #if UIP_CONF_IPV6_RPL 00105 if ((temp_ext_len=rpl_invert_header())) { 00106 /* If there were other extension headers*/ 00107 UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6; 00108 if (uip_ext_len != temp_ext_len) { 00109 uip_len -= (uip_ext_len - temp_ext_len); 00110 UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); 00111 UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); 00112 /* move the echo request payload (starting after the icmp header) 00113 * to the new location in the reply. 00114 * The shift is equal to the length of the remaining extension headers present 00115 * Note: UIP_ICMP_BUF still points to the echo request at this stage 00116 */ 00117 memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len), 00118 (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, 00119 (uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN)); 00120 } 00121 uip_ext_len=temp_ext_len; 00122 } else { 00123 #endif /* UIP_CONF_IPV6_RPL */ 00124 /* If there were extension headers*/ 00125 UIP_IP_BUF->proto = UIP_PROTO_ICMP6; 00126 uip_len -= uip_ext_len; 00127 UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); 00128 UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); 00129 /* move the echo request payload (starting after the icmp header) 00130 * to the new location in the reply. 00131 * The shift is equal to the length of the extension headers present 00132 * Note: UIP_ICMP_BUF still points to the echo request at this stage 00133 */ 00134 memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len, 00135 (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, 00136 (uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN)); 00137 uip_ext_len = 0; 00138 #if UIP_CONF_IPV6_RPL 00139 } 00140 #endif /* UIP_CONF_IPV6_RPL */ 00141 } 00142 /* Below is important for the correctness of UIP_ICMP_BUF and the 00143 * checksum 00144 */ 00145 00146 /* Note: now UIP_ICMP_BUF points to the beginning of the echo reply */ 00147 UIP_ICMP_BUF->type = ICMP6_ECHO_REPLY; 00148 UIP_ICMP_BUF->icode = 0; 00149 UIP_ICMP_BUF->icmpchksum = 0; 00150 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); 00151 00152 PRINTF("Sending Echo Reply to"); 00153 PRINT6ADDR(&UIP_IP_BUF->destipaddr); 00154 PRINTF("from"); 00155 PRINT6ADDR(&UIP_IP_BUF->srcipaddr); 00156 PRINTF("\n"); 00157 UIP_STAT(++uip_stat.icmp.sent); 00158 return; 00159 } 00160 /*---------------------------------------------------------------------------*/ 00161 void 00162 uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) { 00163 00164 /* check if originating packet is not an ICMP error*/ 00165 if (uip_ext_len) { 00166 if(UIP_EXT_BUF->next == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128){ 00167 uip_len = 0; 00168 return; 00169 } 00170 } else { 00171 if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128){ 00172 uip_len = 0; 00173 return; 00174 } 00175 } 00176 00177 #if UIP_CONF_IPV6_RPL 00178 uip_ext_len = rpl_invert_header(); 00179 #else /* UIP_CONF_IPV6_RPL */ 00180 uip_ext_len = 0; 00181 #endif /* UIP_CONF_IPV6_RPL */ 00182 00183 /* remember data of original packet before shifting */ 00184 uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->destipaddr); 00185 00186 uip_len += UIP_IPICMPH_LEN + UIP_ICMP6_ERROR_LEN; 00187 00188 if(uip_len > UIP_LINK_MTU) 00189 uip_len = UIP_LINK_MTU; 00190 00191 memmove((uint8_t *)UIP_ICMP6_ERROR_BUF + uip_ext_len + UIP_ICMP6_ERROR_LEN, 00192 (void *)UIP_IP_BUF, uip_len - UIP_IPICMPH_LEN - uip_ext_len - UIP_ICMP6_ERROR_LEN); 00193 00194 UIP_IP_BUF->vtc = 0x60; 00195 UIP_IP_BUF->tcflow = 0; 00196 UIP_IP_BUF->flow = 0; 00197 if (uip_ext_len) { 00198 UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6; 00199 } else { 00200 UIP_IP_BUF->proto = UIP_PROTO_ICMP6; 00201 } 00202 UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit; 00203 00204 /* the source should not be unspecified nor multicast, the check for 00205 multicast is done in uip_process */ 00206 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)){ 00207 uip_len = 0; 00208 return; 00209 } 00210 00211 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr); 00212 00213 if(uip_is_addr_mcast(&tmp_ipaddr)){ 00214 if(type == ICMP6_PARAM_PROB && code == ICMP6_PARAMPROB_OPTION){ 00215 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr); 00216 } else { 00217 uip_len = 0; 00218 return; 00219 } 00220 } else { 00221 #if UIP_CONF_ROUTER 00222 /* need to pick a source that corresponds to this node */ 00223 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr); 00224 #else 00225 uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr); 00226 #endif 00227 } 00228 00229 UIP_ICMP_BUF->type = type; 00230 UIP_ICMP_BUF->icode = code; 00231 UIP_ICMP6_ERROR_BUF->param = uip_htonl(param); 00232 UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); 00233 UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); 00234 UIP_ICMP_BUF->icmpchksum = 0; 00235 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); 00236 00237 UIP_STAT(++uip_stat.icmp.sent); 00238 00239 PRINTF("Sending ICMPv6 ERROR message to"); 00240 PRINT6ADDR(&UIP_IP_BUF->destipaddr); 00241 PRINTF("from"); 00242 PRINT6ADDR(&UIP_IP_BUF->srcipaddr); 00243 PRINTF("\n"); 00244 return; 00245 } 00246 00247 /*---------------------------------------------------------------------------*/ 00248 void 00249 uip_icmp6_send(uip_ipaddr_t *dest, int type, int code, int payload_len) 00250 { 00251 00252 UIP_IP_BUF->vtc = 0x60; 00253 UIP_IP_BUF->tcflow = 0; 00254 UIP_IP_BUF->flow = 0; 00255 UIP_IP_BUF->proto = UIP_PROTO_ICMP6; 00256 UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit; 00257 UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + payload_len) >> 8; 00258 UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + payload_len) & 0xff; 00259 00260 memcpy(&UIP_IP_BUF->destipaddr, dest, sizeof(*dest)); 00261 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); 00262 00263 UIP_ICMP_BUF->type = type; 00264 UIP_ICMP_BUF->icode = code; 00265 00266 UIP_ICMP_BUF->icmpchksum = 0; 00267 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); 00268 00269 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len; 00270 tcpip_ipv6_output(); 00271 } 00272 /*---------------------------------------------------------------------------*/ 00273 00274 /** @} */