ReactOS 0.4.16-dev-570-g1868985
icmp6.c
Go to the documentation of this file.
1
7/*
8 * Copyright (c) 2010 Inico Technologies Ltd.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Ivan Delamer <delamer@inicotech.com>
36 *
37 *
38 * Please coordinate changes and requests with Ivan Delamer
39 * <delamer@inicotech.com>
40 */
41
42#include "lwip/opt.h"
43
44#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
45
46#include "lwip/icmp6.h"
47#include "lwip/prot/icmp6.h"
48#include "lwip/ip6.h"
49#include "lwip/ip6_addr.h"
50#include "lwip/inet_chksum.h"
51#include "lwip/pbuf.h"
52#include "lwip/netif.h"
53#include "lwip/nd6.h"
54#include "lwip/mld6.h"
55#include "lwip/ip.h"
56#include "lwip/stats.h"
57
58#include <string.h>
59
60#if !LWIP_ICMP6_DATASIZE || (LWIP_ICMP6_DATASIZE > (IP6_MIN_MTU_LENGTH - IP6_HLEN - ICMP6_HLEN))
61#undef LWIP_ICMP6_DATASIZE
62#define LWIP_ICMP6_DATASIZE (IP6_MIN_MTU_LENGTH - IP6_HLEN - ICMP6_HLEN)
63#endif
64
65/* Forward declarations */
66static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
67static void icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data,
68 u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr);
69static void icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data,
70 u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr, struct netif *netif);
71
72
82void
83icmp6_input(struct pbuf *p, struct netif *inp)
84{
85 struct icmp6_hdr *icmp6hdr;
86 struct pbuf *r;
87 const ip6_addr_t *reply_src;
88
89 ICMP6_STATS_INC(icmp6.recv);
90
91 /* Check that ICMPv6 header fits in payload */
92 if (p->len < sizeof(struct icmp6_hdr)) {
93 /* drop short packets */
94 pbuf_free(p);
95 ICMP6_STATS_INC(icmp6.lenerr);
96 ICMP6_STATS_INC(icmp6.drop);
97 return;
98 }
99
100 icmp6hdr = (struct icmp6_hdr *)p->payload;
101
103 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) {
104 if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
105 ip6_current_dest_addr()) != 0) {
106 /* Checksum failed */
107 pbuf_free(p);
108 ICMP6_STATS_INC(icmp6.chkerr);
109 ICMP6_STATS_INC(icmp6.drop);
110 return;
111 }
112 }
113#endif /* CHECKSUM_CHECK_ICMP6 */
114
115 switch (icmp6hdr->type) {
116 case ICMP6_TYPE_NA: /* Neighbor advertisement */
117 case ICMP6_TYPE_NS: /* Neighbor solicitation */
118 case ICMP6_TYPE_RA: /* Router advertisement */
119 case ICMP6_TYPE_RD: /* Redirect */
120 case ICMP6_TYPE_PTB: /* Packet too big */
121 nd6_input(p, inp);
122 return;
123 case ICMP6_TYPE_RS:
124#if LWIP_IPV6_FORWARD
125 /* @todo implement router functionality */
126#endif
127 break;
128#if LWIP_IPV6_MLD
129 case ICMP6_TYPE_MLQ:
130 case ICMP6_TYPE_MLR:
131 case ICMP6_TYPE_MLD:
132 mld6_input(p, inp);
133 return;
134#endif
135 case ICMP6_TYPE_EREQ:
136#if !LWIP_MULTICAST_PING
137 /* multicast destination address? */
138 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
139 /* drop */
140 pbuf_free(p);
141 ICMP6_STATS_INC(icmp6.drop);
142 return;
143 }
144#endif /* LWIP_MULTICAST_PING */
145
146 /* Allocate reply. */
147 r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
148 if (r == NULL) {
149 /* drop */
150 pbuf_free(p);
151 ICMP6_STATS_INC(icmp6.memerr);
152 return;
153 }
154
155 /* Copy echo request. */
156 if (pbuf_copy(r, p) != ERR_OK) {
157 /* drop */
158 pbuf_free(p);
159 pbuf_free(r);
160 ICMP6_STATS_INC(icmp6.err);
161 return;
162 }
163
164 /* Determine reply source IPv6 address. */
165#if LWIP_MULTICAST_PING
166 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
167 reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr()));
168 if (reply_src == NULL) {
169 /* drop */
170 pbuf_free(p);
171 pbuf_free(r);
172 ICMP6_STATS_INC(icmp6.rterr);
173 return;
174 }
175 }
176 else
177#endif /* LWIP_MULTICAST_PING */
178 {
179 reply_src = ip6_current_dest_addr();
180 }
181
182 /* Set fields in reply. */
183 ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
184 ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
185#if CHECKSUM_GEN_ICMP6
186 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) {
187 ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
188 IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
189 }
190#endif /* CHECKSUM_GEN_ICMP6 */
191
192 /* Send reply. */
193 ICMP6_STATS_INC(icmp6.xmit);
194 ip6_output_if(r, reply_src, ip6_current_src_addr(),
196 pbuf_free(r);
197
198 break;
199 default:
200 ICMP6_STATS_INC(icmp6.proterr);
201 ICMP6_STATS_INC(icmp6.drop);
202 break;
203 }
204
205 pbuf_free(p);
206}
207
208
219void
220icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
221{
222 icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
223}
224
235void
236icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
237{
238 icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
239}
240
251void
252icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
253{
254 icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
255}
256
272void
273icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c,
274 const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr)
275{
276 icmp6_send_response_with_addrs(p, c, 0, ICMP6_TYPE_TE, src_addr, dest_addr);
277}
278
291void
292icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer)
293{
294 u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header());
295 icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP);
296}
297
308static void
309icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
310{
311 const struct ip6_addr *reply_src, *reply_dest;
312 struct netif *netif = ip_current_netif();
313
314 LWIP_ASSERT("icmpv6 packet not a direct response", netif != NULL);
315 reply_dest = ip6_current_src_addr();
316
317 /* Select an address to use as source. */
318 reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest));
319 if (reply_src == NULL) {
320 ICMP6_STATS_INC(icmp6.rterr);
321 return;
322 }
323 icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, reply_dest, netif);
324}
325
345static void
346icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type,
347 const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr)
348{
349 const struct ip6_addr *reply_src, *reply_dest;
350 struct netif *netif;
351
352 /* Get the destination address and netif for this ICMP message. */
353 LWIP_ASSERT("must provide both source and destination", src_addr != NULL);
354 LWIP_ASSERT("must provide both source and destination", dest_addr != NULL);
355
356 /* Special case, as ip6_current_xxx is either NULL, or points
357 to a different packet than the one that expired. */
358 IP6_ADDR_ZONECHECK(src_addr);
359 IP6_ADDR_ZONECHECK(dest_addr);
360 /* Swap source and destination for the reply. */
361 reply_dest = src_addr;
362 reply_src = dest_addr;
363 netif = ip6_route(reply_src, reply_dest);
364 if (netif == NULL) {
365 ICMP6_STATS_INC(icmp6.rterr);
366 return;
367 }
368 icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src,
369 reply_dest, netif);
370}
371
384static void
385icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, u8_t type,
386 const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif)
387{
388 struct pbuf *q;
389 struct icmp6_hdr *icmp6hdr;
391
392 /* ICMPv6 header + datalen (as much of the offending packet as possible) */
393 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + datalen,
394 PBUF_RAM);
395 if (q == NULL) {
396 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
397 ICMP6_STATS_INC(icmp6.memerr);
398 return;
399 }
400 LWIP_ASSERT("check that first pbuf can hold icmp6 header",
401 (q->len >= (sizeof(struct icmp6_hdr))));
402
403 icmp6hdr = (struct icmp6_hdr *)q->payload;
404 icmp6hdr->type = type;
405 icmp6hdr->code = code;
406 icmp6hdr->data = lwip_htonl(data);
407
408 /* copy fields from original packet */
409 pbuf_copy_partial_pbuf(q, p, datalen, sizeof(struct icmp6_hdr));
410
411 /* calculate checksum */
412 icmp6hdr->chksum = 0;
413#if CHECKSUM_GEN_ICMP6
414 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
415 icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
416 reply_src, reply_dest);
417 }
418#endif /* CHECKSUM_GEN_ICMP6 */
419
420 ICMP6_STATS_INC(icmp6.xmit);
421 ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
422 pbuf_free(q);
423}
424
425#endif /* LWIP_ICMP6 && LWIP_IPV6 */
#define LWIP_MIN(x, y)
Definition: def.h:66
#define lwip_htonl(x)
Definition: def.h:88
#define NULL
Definition: types.h:112
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define ip_current_netif()
Definition: ip.h:146
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
const GLubyte * c
Definition: glext.h:8905
GLsizei const GLvoid * pointer
Definition: glext.h:5848
GLfloat GLfloat p
Definition: glext.h:8902
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
uint16_t u16_t
Definition: arch.h:127
@ ERR_OK
Definition: err.h:55
#define CHECKSUM_CHECK_ICMP6
Definition: opt.h:2412
#define ICMP_DEBUG
Definition: opt.h:3371
#define LWIP_ICMP6_HL
Definition: opt.h:2573
#define LWIP_ICMP6_DATASIZE
Definition: opt.h:2566
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:224
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
Definition: pbuf.c:959
err_t pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t copy_len, u16_t offset)
Definition: pbuf.c:986
@ PBUF_RAM
Definition: pbuf.h:152
@ PBUF_IP
Definition: pbuf.h:97
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:356
int const JOCTET unsigned int datalen
Definition: jpeglib.h:1031
#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag)
Definition: netif.h:416
icmp6_dur_code
Definition: icmp6.h:98
icmp6_pp_code
Definition: icmp6.h:124
@ ICMP6_TYPE_MLD
Definition: icmp6.h:72
@ ICMP6_TYPE_NS
Definition: icmp6.h:78
@ ICMP6_TYPE_RD
Definition: icmp6.h:82
@ ICMP6_TYPE_PTB
Definition: icmp6.h:51
@ ICMP6_TYPE_NA
Definition: icmp6.h:80
@ ICMP6_TYPE_PP
Definition: icmp6.h:55
@ ICMP6_TYPE_RS
Definition: icmp6.h:74
@ ICMP6_TYPE_MLR
Definition: icmp6.h:70
@ ICMP6_TYPE_DUR
Definition: icmp6.h:49
@ ICMP6_TYPE_EREP
Definition: icmp6.h:66
@ ICMP6_TYPE_MLQ
Definition: icmp6.h:68
@ ICMP6_TYPE_RA
Definition: icmp6.h:76
@ ICMP6_TYPE_EREQ
Definition: icmp6.h:64
@ ICMP6_TYPE_TE
Definition: icmp6.h:53
icmp6_te_code
Definition: icmp6.h:116
#define IP6_NEXTH_ICMP6
Definition: ip6.h:72
#define ICMP6_STATS_INC(x)
Definition: stats.h:436
Definition: inflate.c:139
Definition: netif.h:269
Definition: pbuf.h:186