Contiki-NG
uip-icmp6.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2001-2003, Adam Dunkels.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 * products derived from this software without specific prior
15 * written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * This file is part of the uIP TCP/IP stack.
30 *
31 */
32
33/**
34 * \addtogroup uip
35 * @{
36 */
37
38/**
39 * \file
40 * ICMPv6 (RFC 4443) implementation, with message and error handling
41 * \author Julien Abeille <jabeille@cisco.com>
42 * \author Mathilde Durvy <mdurvy@cisco.com>
43 */
44
45#include <string.h>
46#include "net/ipv6/uip-ds6.h"
47#include "net/ipv6/uip-icmp6.h"
48#include "contiki-default-conf.h"
49#include "net/routing/routing.h"
50
51/* Log configuration */
52#include "sys/log.h"
53#define LOG_MODULE "ICMPv6"
54#define LOG_LEVEL LOG_LEVEL_IPV6
55
56#define UIP_ICMP6_ERROR_BUF ((struct uip_icmp6_error *)UIP_ICMP_PAYLOAD)
57
58/** \brief temporary IP address */
59static uip_ipaddr_t tmp_ipaddr;
60
61LIST(echo_reply_callback_list);
62/*---------------------------------------------------------------------------*/
63/* List of input handlers */
64LIST(input_handler_list);
65/*---------------------------------------------------------------------------*/
66static uip_icmp6_input_handler_t *
67input_handler_lookup(uint8_t type, uint8_t icode)
68{
69 uip_icmp6_input_handler_t *handler = NULL;
70
71 for(handler = list_head(input_handler_list);
72 handler != NULL;
73 handler = list_item_next(handler)) {
74 if(handler->type == type &&
75 (handler->icode == icode ||
76 handler->icode == UIP_ICMP6_HANDLER_CODE_ANY)) {
77 return handler;
78 }
79 }
80
81 return NULL;
82}
83/*---------------------------------------------------------------------------*/
84uint8_t
85uip_icmp6_input(uint8_t type, uint8_t icode)
86{
87 uip_icmp6_input_handler_t *handler = input_handler_lookup(type, icode);
88
89 if(handler == NULL) {
90 return UIP_ICMP6_INPUT_ERROR;
91 }
92
93 if(handler->handler == NULL) {
94 return UIP_ICMP6_INPUT_ERROR;
95 }
96
97 handler->handler();
98 return UIP_ICMP6_INPUT_SUCCESS;
99}
100/*---------------------------------------------------------------------------*/
101void
102uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
103{
104 list_add(input_handler_list, handler);
105}
106/*---------------------------------------------------------------------------*/
107static void
108echo_request_input(void)
109{
110 /*
111 * we send an echo reply. It is trivial if there was no extension
112 * headers in the request otherwise we need to remove the extension
113 * headers and change a few fields
114 */
115 LOG_INFO("Received Echo Request from ");
116 LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
117 LOG_INFO_(" to ");
118 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
119 LOG_INFO_("\n");
120
121 /* IP header */
122 UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
123
124 if(uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)){
125 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
126 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
127 } else {
129 uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
130 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &tmp_ipaddr);
131 }
132
134
135 /* Below is important for the correctness of UIP_ICMP_BUF and the
136 * checksum
137 */
138
139 /* Note: now UIP_ICMP_BUF points to the beginning of the echo reply */
141 UIP_ICMP_BUF->icode = 0;
142 UIP_ICMP_BUF->icmpchksum = 0;
143 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
144
145 LOG_INFO("Sending Echo Reply to ");
146 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
147 LOG_INFO_(" from ");
148 LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
149 LOG_INFO_("\n");
150 UIP_STAT(++uip_stat.icmp.sent);
151 return;
152}
153/*---------------------------------------------------------------------------*/
154void
155uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param)
156{
157 /* check if originating packet is not an ICMP error */
158 uint16_t shift;
159
160 if(uip_last_proto == UIP_PROTO_ICMP6 && UIP_ICMP_BUF->type < 128) {
161 uipbuf_clear();
162 return;
163 }
164
165 /* the source should not be unspecified nor multicast */
166 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr) ||
167 uip_is_addr_mcast(&UIP_IP_BUF->srcipaddr)) {
168 uipbuf_clear();
169 return;
170 }
171
172 /* Remove all extension headers related to the routing protocol in place.
173 * Keep all other extension headers, so as to match original packet. */
174 if(NETSTACK_ROUTING.ext_header_remove() == 0) {
175 LOG_WARN("Unable to remove ext header before sending ICMPv6 ERROR message\n");
176 }
177
178 /* remember data of original packet before shifting */
179 uip_ipaddr_copy(&tmp_ipaddr, &UIP_IP_BUF->destipaddr);
180
181 /* The ICMPv6 error message contains as much of possible of the invoking packet
182 * (see RFC 4443 section 3). Make space for the additional IPv6 and
183 * ICMPv6 headers here and move payload to the "right". What we move includes
184 * extension headers */
185 shift = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ICMP6_ERROR_LEN;
186 uip_len += shift;
188 uip_ext_len = 0;
189 memmove(uip_buf + shift, (void *)UIP_IP_BUF, uip_len - shift);
190
191 UIP_IP_BUF->vtc = 0x60;
192 UIP_IP_BUF->tcflow = 0;
193 UIP_IP_BUF->flow = 0;
194 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
195 UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
196
197 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr);
198
200 if(type == ICMP6_PARAM_PROB && code == ICMP6_PARAMPROB_OPTION){
202 } else {
203 uipbuf_clear();
204 return;
205 }
206 } else {
207 /* need to pick a source that corresponds to this node */
209 }
210
211 UIP_ICMP_BUF->type = type;
212 UIP_ICMP_BUF->icode = code;
213 UIP_ICMP6_ERROR_BUF->param = uip_htonl(param);
214 uipbuf_set_len_field(UIP_IP_BUF, uip_len - UIP_IPH_LEN);
215 UIP_ICMP_BUF->icmpchksum = 0;
216 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
217
218 UIP_STAT(++uip_stat.icmp.sent);
219
220 LOG_WARN("Sending ICMPv6 ERROR message type %d code %d to ", type, code);
221 LOG_WARN_6ADDR(&UIP_IP_BUF->destipaddr);
222 LOG_WARN_(" from ");
223 LOG_WARN_6ADDR(&UIP_IP_BUF->srcipaddr);
224 LOG_WARN_("\n");
225 return;
226}
227
228/*---------------------------------------------------------------------------*/
229void
230uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
231{
232 UIP_IP_BUF->vtc = 0x60;
233 UIP_IP_BUF->tcflow = 0;
234 UIP_IP_BUF->flow = 0;
235 UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
236 UIP_IP_BUF->ttl = uip_ds6_if.cur_hop_limit;
237 uipbuf_set_len_field(UIP_IP_BUF, UIP_ICMPH_LEN + payload_len);
238
239 if(dest == NULL) {
240 LOG_ERR("invalid argument; dest is NULL\n");
241 return;
242 }
243
244 memcpy(&UIP_IP_BUF->destipaddr, dest, sizeof(*dest));
245 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
246
247 UIP_ICMP_BUF->type = type;
248 UIP_ICMP_BUF->icode = code;
249
250 UIP_ICMP_BUF->icmpchksum = 0;
251 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();
252
253 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len;
254
255 UIP_STAT(++uip_stat.icmp.sent);
256 UIP_STAT(++uip_stat.ip.sent);
257
258 LOG_INFO("Sending ICMPv6 packet to ");
259 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
260 LOG_INFO_(", type %u, code %u, len %u\n", type, code, payload_len);
261
263}
264/*---------------------------------------------------------------------------*/
265static void
266echo_reply_input(void)
267{
268 int ttl;
269 uip_ipaddr_t sender;
270
271 LOG_INFO("Received Echo Reply from ");
272 LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
273 LOG_INFO_(" to ");
274 LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
275 LOG_INFO_("\n");
276
277 uip_ipaddr_copy(&sender, &UIP_IP_BUF->srcipaddr);
278 ttl = UIP_IP_BUF->ttl;
279
281
282 /* Call all registered applications to let them know an echo reply
283 has been received. */
284 {
285 struct uip_icmp6_echo_reply_notification *n;
286 for(n = list_head(echo_reply_callback_list);
287 n != NULL;
288 n = list_item_next(n)) {
289 if(n->callback != NULL) {
290 n->callback(&sender, ttl,
291 (uint8_t *)UIP_ICMP_PAYLOAD,
292 uip_len - sizeof(struct uip_icmp_hdr) - UIP_IPH_LEN);
293 }
294 }
295 }
296
297 uipbuf_clear();
298 return;
299}
300/*---------------------------------------------------------------------------*/
301void
302uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n,
303 uip_icmp6_echo_reply_callback_t c)
304{
305 if(n != NULL && c != NULL) {
306 n->callback = c;
307 list_add(echo_reply_callback_list, n);
308 }
309}
310/*---------------------------------------------------------------------------*/
311void
312uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n)
313{
314 list_remove(echo_reply_callback_list, n);
315}
316/*---------------------------------------------------------------------------*/
317UIP_ICMP6_HANDLER(echo_request_handler, ICMP6_ECHO_REQUEST,
318 UIP_ICMP6_HANDLER_CODE_ANY, echo_request_input);
319UIP_ICMP6_HANDLER(echo_reply_handler, ICMP6_ECHO_REPLY,
320 UIP_ICMP6_HANDLER_CODE_ANY, echo_reply_input);
321/*---------------------------------------------------------------------------*/
322void
324{
325 /* Register Echo Request and Reply handlers */
326 uip_icmp6_register_input_handler(&echo_request_handler);
327 uip_icmp6_register_input_handler(&echo_reply_handler);
328}
329/*---------------------------------------------------------------------------*/
330/** @} */
#define LIST(name)
Declare a linked list.
Definition: list.h:89
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:89
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition: list.c:152
void * list_item_next(const void *item)
Get the next item following this item.
Definition: list.c:203
void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition: list.c:63
void tcpip_ipv6_output(void)
This function does address resolution and then calls tcpip_output.
Definition: tcpip.c:631
void uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n)
Remove a callback function for ping replies.
Definition: uip-icmp6.c:312
void uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param)
Send an icmpv6 error message.
Definition: uip-icmp6.c:155
#define ICMP6_ECHO_REPLY
Echo reply.
Definition: uip-icmp6.h:58
void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
Send an icmpv6 message.
Definition: uip-icmp6.c:230
uint8_t uip_icmp6_input(uint8_t type, uint8_t icode)
Handle an incoming ICMPv6 message.
Definition: uip-icmp6.c:85
static uip_ipaddr_t tmp_ipaddr
temporary IP address
Definition: uip-icmp6.c:59
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
Definition: uip.h:1734
#define UIP_ICMP6_ERROR_LEN
ICMPv6 Error message constant part length.
Definition: uip-icmp6.h:104
#define UIP_ICMP_BUF
Direct access to ICMP, UDP, and TCP headers and payload, with implicit ext header offset (global uip_...
Definition: uip.h:77
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 4291 a is of type uip_ipaddr_t*
Definition: uip.h:1869
void uip_icmp6_init()
Initialise the uIP ICMPv6 core.
Definition: uip-icmp6.c:323
#define ICMP6_PARAM_PROB
ip6 header bad
Definition: uip-icmp6.h:56
bool uip_remove_ext_hdr(void)
Removes all IPv6 extension headers from uip_buf, updates length fields (uip_len and uip_ext_len)
Definition: uip6.c:493
#define UIP_STAT(s)
The uIP TCP/IP statistics.
Definition: uip.h:1351
void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst)
Source address selection, see RFC 3484.
Definition: uip-ds6.c:538
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
Register a handler which can handle a specific ICMPv6 message type.
Definition: uip-icmp6.c:102
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
#define ICMP6_PARAMPROB_OPTION
unrecognized option
Definition: uip-icmp6.h:97
void uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n, uip_icmp6_echo_reply_callback_t c)
Add a callback function for ping replies.
Definition: uip-icmp6.c:302
#define ICMP6_ECHO_REQUEST
Echo request.
Definition: uip-icmp6.h:57
#define UIP_IP_BUF
Direct access to IPv6 header.
Definition: uip.h:71
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:969
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:465
uint16_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:122
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
uint8_t uip_last_proto
The final protocol after IPv6 extension headers: UIP_PROTO_TCP, UIP_PROTO_UDP or UIP_PROTO_ICMP6.
Definition: uip6.c:125
#define UIP_LINK_MTU
The maximum transmission unit at the IP Layer.
Definition: uipopt.h:154
Header file for the logging system.
Routing driver header file.
bool(* ext_header_remove)(void)
Removes all extension headers that pertain to the routing protocol.
Definition: routing.h:132
Header file for IPv6-related data structures.
Header file for ICMPv6 message and error handing (RFC 4443)