Contiki 2.5
uip-icmp6.c
Go to the documentation of this file.
1 /**
2  * \addtogroup uip6
3  * @{
4  */
5 
6 /**
7  * \file
8  * ICMPv6 echo request and error messages (RFC 4443)
9  * \author Julien Abeille <jabeille@cisco.com>
10  * \author Mathilde Durvy <mdurvy@cisco.com>
11  */
12 
13 /*
14  * Copyright (c) 2001-2003, Adam Dunkels.
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  * notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  * notice, this list of conditions and the following disclaimer in the
24  * documentation and/or other materials provided with the distribution.
25  * 3. The name of the author may not be used to endorse or promote
26  * products derived from this software without specific prior
27  * written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
30  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
33  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
35  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * This file is part of the uIP TCP/IP stack.
42  *
43  */
44 
45 #include <string.h>
46 #include "net/uip-ds6.h"
47 #include "net/uip-icmp6.h"
48 
49 #define DEBUG 0
50 #if DEBUG
51 #include <stdio.h>
52 #define PRINTF(...) printf(__VA_ARGS__)
53 #define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_t *)addr)[15])
54 #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])
55 #else
56 #define PRINTF(...)
57 #define PRINT6ADDR(addr)
58 #endif
59 
60 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
61 #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
62 #define UIP_ICMP6_ERROR_BUF ((struct uip_icmp6_error *)&uip_buf[uip_l2_l3_icmp_hdr_len])
63 
64 /** \brief temporary IP address */
65 static uip_ipaddr_t tmp_ipaddr;
66 
67 /*---------------------------------------------------------------------------*/
68 void
70 {
71  /*
72  * we send an echo reply. It is trivial if there was no extension
73  * headers in the request otherwise we need to remove the extension
74  * headers and change a few fields
75  */
76  PRINTF("Received Echo Request from");
77  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
78  PRINTF("to");
79  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
80  PRINTF("\n");
81 
82  /* IP header */
83  UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
84 
85  if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)){
86  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
87  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
88  } else {
89  uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->srcipaddr);
90  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
91  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &tmp_ipaddr);
92  }
93 
94  if(uip_ext_len > 0) {
95  /* If there were extension headers*/
96  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
98  UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
99  UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
100  /* move the echo request payload (starting after the icmp header)
101  * to the new location in the reply.
102  * The shift is equal to the length of the extension headers present
103  * Note: UIP_ICMP_BUF still points to the echo request at this stage
104  */
105  memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len,
106  (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
107  (uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
108  }
109  /* Below is important for the correctness of UIP_ICMP_BUF and the
110  * checksum
111  */
112  uip_ext_len = 0;
113  /* Note: now UIP_ICMP_BUF points to the beginning of the echo reply */
115  UIP_ICMP_BUF->icode = 0;
116  UIP_ICMP_BUF->icmpchksum = 0;
117  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
118 
119  PRINTF("Sending Echo Reply to");
120  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
121  PRINTF("from");
122  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
123  PRINTF("\n");
124  UIP_STAT(++uip_stat.icmp.sent);
125  return;
126 }
127 /*---------------------------------------------------------------------------*/
128 void
129 uip_icmp6_error_output(u8_t type, u8_t code, u32_t param) {
130  uip_ext_len = 0;
131 
132  /* check if originating packet is not an ICMP error*/
133  if(UIP_IP_BUF->proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128){
134  uip_len = 0;
135  return;
136  }
137 
138  /* remember data of original packet before shifting */
139  uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->destipaddr);
140 
141  uip_len += UIP_IPICMPH_LEN + UIP_ICMP6_ERROR_LEN;
142 
143  if(uip_len > UIP_LINK_MTU)
145 
146  memmove((uint8_t *)UIP_ICMP6_ERROR_BUF + UIP_ICMP6_ERROR_LEN,
147  (void *)UIP_IP_BUF, uip_len - UIP_IPICMPH_LEN - UIP_ICMP6_ERROR_LEN);
148 
149  UIP_IP_BUF->vtc = 0x60;
150  UIP_IP_BUF->tcflow = 0;
151  UIP_IP_BUF->flow = 0;
152  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
153  UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
154 
155  /* the source should not be unspecified nor multicast, the check for
156  multicast is done in uip_process */
157  if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)){
158  uip_len = 0;
159  return;
160  }
161 
162  uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
163 
164  if(uip_is_addr_mcast(&tmp_ipaddr)){
165  if(type == ICMP6_PARAM_PROB && code == ICMP6_PARAMPROB_OPTION){
166  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr);
167  } else {
168  uip_len = 0;
169  return;
170  }
171  } else {
172 #if UIP_CONF_ROUTER
173  /* need to pick a source that corresponds to this node */
174  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr);
175 #else
176  uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr);
177 #endif
178  }
179 
180  UIP_ICMP_BUF->type = type;
181  UIP_ICMP_BUF->icode = code;
182  UIP_ICMP6_ERROR_BUF->param = uip_htonl(param);
183  UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
184  UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
185  UIP_ICMP_BUF->icmpchksum = 0;
186  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
187 
188  UIP_STAT(++uip_stat.icmp.sent);
189 
190  PRINTF("Sending ICMPv6 ERROR message to");
191  PRINT6ADDR(&UIP_IP_BUF->destipaddr);
192  PRINTF("from");
193  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
194  PRINTF("\n");
195  return;
196 }
197 
198 /*---------------------------------------------------------------------------*/
199 void
200 uip_icmp6_send(uip_ipaddr_t *dest, int type, int code, int payload_len)
201 {
202 
203  UIP_IP_BUF->vtc = 0x60;
204  UIP_IP_BUF->tcflow = 0;
205  UIP_IP_BUF->flow = 0;
206  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
207  UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
208  UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + payload_len) >> 8;
209  UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + payload_len) & 0xff;
210 
211  memcpy(&UIP_IP_BUF->destipaddr, dest, sizeof(*dest));
212  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
213 
214  UIP_ICMP_BUF->type = type;
215  UIP_ICMP_BUF->icode = code;
216 
217  UIP_ICMP_BUF->icmpchksum = 0;
218  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
219 
220  uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
221  tcpip_ipv6_output();
222 }
223 /*---------------------------------------------------------------------------*/
224 
225 /** @} */