The Pedigree Project 0.1
icmp6.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
26/*
27 * Copyright (c) 2010 Inico Technologies Ltd.
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without modification,
31 * are permitted provided that the following conditions are met:
32 *
33 * 1. Redistributions of source code must retain the above copyright notice,
34 * this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright notice,
36 * this list of conditions and the following disclaimer in the documentation
37 * and/or other materials provided with the distribution.
38 * 3. The name of the author may not be used to endorse or promote products
39 * derived from this software without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
43 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
44 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
46 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
49 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
50 * OF SUCH DAMAGE.
51 *
52 * This file is part of the lwIP TCP/IP stack.
53 *
54 * Author: Ivan Delamer <delamer@inicotech.com>
55 *
56 *
57 * Please coordinate changes and requests with Ivan Delamer
58 * <delamer@inicotech.com>
59 */
60
61#include "lwip/opt.h"
62
63#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
64
65#include "lwip/icmp6.h"
66#include "lwip/prot/icmp6.h"
67#include "lwip/ip6.h"
68#include "lwip/ip6_addr.h"
69#include "lwip/inet_chksum.h"
70#include "lwip/pbuf.h"
71#include "lwip/netif.h"
72#include "lwip/nd6.h"
73#include "lwip/mld6.h"
74#include "lwip/ip.h"
75#include "lwip/stats.h"
76
77#include <string.h>
78
79#ifndef LWIP_ICMP6_DATASIZE
80#define LWIP_ICMP6_DATASIZE 8
81#endif
82#if LWIP_ICMP6_DATASIZE == 0
83#define LWIP_ICMP6_DATASIZE 8
84#endif
85
86/* Forward declarations */
87static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
88
89
99void
100icmp6_input(struct pbuf *p, struct netif *inp)
101{
102 struct icmp6_hdr *icmp6hdr;
103 struct pbuf *r;
104 const ip6_addr_t *reply_src;
105
106 ICMP6_STATS_INC(icmp6.recv);
107
108 /* Check that ICMPv6 header fits in payload */
109 if (p->len < sizeof(struct icmp6_hdr)) {
110 /* drop short packets */
111 pbuf_free(p);
112 ICMP6_STATS_INC(icmp6.lenerr);
113 ICMP6_STATS_INC(icmp6.drop);
114 return;
115 }
116
117 icmp6hdr = (struct icmp6_hdr *)p->payload;
118
119#if CHECKSUM_CHECK_ICMP6
120 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) {
121 if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
122 ip6_current_dest_addr()) != 0) {
123 /* Checksum failed */
124 pbuf_free(p);
125 ICMP6_STATS_INC(icmp6.chkerr);
126 ICMP6_STATS_INC(icmp6.drop);
127 return;
128 }
129 }
130#endif /* CHECKSUM_CHECK_ICMP6 */
131
132 switch (icmp6hdr->type) {
133 case ICMP6_TYPE_NA: /* Neighbor advertisement */
134 case ICMP6_TYPE_NS: /* Neighbor solicitation */
135 case ICMP6_TYPE_RA: /* Router advertisement */
136 case ICMP6_TYPE_RD: /* Redirect */
137 case ICMP6_TYPE_PTB: /* Packet too big */
138 nd6_input(p, inp);
139 return;
140 break;
141 case ICMP6_TYPE_RS:
142#if LWIP_IPV6_FORWARD
143 /* @todo implement router functionality */
144#endif
145 break;
146#if LWIP_IPV6_MLD
147 case ICMP6_TYPE_MLQ:
148 case ICMP6_TYPE_MLR:
149 case ICMP6_TYPE_MLD:
150 mld6_input(p, inp);
151 return;
152 break;
153#endif
154 case ICMP6_TYPE_EREQ:
155#if !LWIP_MULTICAST_PING
156 /* multicast destination address? */
157 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
158 /* drop */
159 pbuf_free(p);
160 ICMP6_STATS_INC(icmp6.drop);
161 return;
162 }
163#endif /* LWIP_MULTICAST_PING */
164
165 /* Allocate reply. */
167 if (r == NULL) {
168 /* drop */
169 pbuf_free(p);
170 ICMP6_STATS_INC(icmp6.memerr);
171 return;
172 }
173
174 /* Copy echo request. */
175 if (pbuf_copy(r, p) != ERR_OK) {
176 /* drop */
177 pbuf_free(p);
178 pbuf_free(r);
179 ICMP6_STATS_INC(icmp6.err);
180 return;
181 }
182
183 /* Determine reply source IPv6 address. */
184#if LWIP_MULTICAST_PING
185 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
186 reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr()));
187 if (reply_src == NULL) {
188 /* drop */
189 pbuf_free(p);
190 pbuf_free(r);
191 ICMP6_STATS_INC(icmp6.rterr);
192 return;
193 }
194 }
195 else
196#endif /* LWIP_MULTICAST_PING */
197 {
198 reply_src = ip6_current_dest_addr();
199 }
200
201 /* Set fields in reply. */
202 ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
203 ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
204#if CHECKSUM_GEN_ICMP6
205 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) {
206 ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
207 IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
208 }
209#endif /* CHECKSUM_GEN_ICMP6 */
210
211 /* Send reply. */
212 ICMP6_STATS_INC(icmp6.xmit);
213 ip6_output_if(r, reply_src, ip6_current_src_addr(),
214 LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
215 pbuf_free(r);
216
217 break;
218 default:
219 ICMP6_STATS_INC(icmp6.proterr);
220 ICMP6_STATS_INC(icmp6.drop);
221 break;
222 }
223
224 pbuf_free(p);
225}
226
227
235void
236icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
237{
238 icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
239}
240
248void
249icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
250{
251 icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
252}
253
261void
262icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
263{
264 icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
265}
266
275void
276icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
277{
278 icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP);
279}
280
290static void
291icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
292{
293 struct pbuf *q;
294 struct icmp6_hdr *icmp6hdr;
295 const ip6_addr_t *reply_src;
296 ip6_addr_t *reply_dest;
297 ip6_addr_t reply_src_local, reply_dest_local;
298 struct ip6_hdr *ip6hdr;
299 struct netif *netif;
300
301 /* ICMPv6 header + IPv6 header + data */
302 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
303 PBUF_RAM);
304 if (q == NULL) {
305 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
306 ICMP6_STATS_INC(icmp6.memerr);
307 return;
308 }
309 LWIP_ASSERT("check that first pbuf can hold icmp 6message",
310 (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
311
312 icmp6hdr = (struct icmp6_hdr *)q->payload;
313 icmp6hdr->type = type;
314 icmp6hdr->code = code;
315 icmp6hdr->data = data;
316
317 /* copy fields from original packet */
318 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
319 IP6_HLEN + LWIP_ICMP6_DATASIZE);
320
321 /* Get the destination address and netif for this ICMP message. */
322 if ((ip_current_netif() == NULL) ||
323 ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
324 /* Special case, as ip6_current_xxx is either NULL, or points
325 * to a different packet than the one that expired.
326 * We must use the addresses that are stored in the expired packet. */
327 ip6hdr = (struct ip6_hdr *)p->payload;
328 /* copy from packed address to aligned address */
329 ip6_addr_copy(reply_dest_local, ip6hdr->src);
330 ip6_addr_copy(reply_src_local, ip6hdr->dest);
331 reply_dest = &reply_dest_local;
332 reply_src = &reply_src_local;
333 netif = ip6_route(reply_src, reply_dest);
334 if (netif == NULL) {
335 /* drop */
336 pbuf_free(q);
337 ICMP6_STATS_INC(icmp6.rterr);
338 return;
339 }
340 }
341 else {
343 reply_dest = ip6_current_src_addr();
344
345 /* Select an address to use as source. */
346 reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest));
347 if (reply_src == NULL) {
348 /* drop */
349 pbuf_free(q);
350 ICMP6_STATS_INC(icmp6.rterr);
351 return;
352 }
353 }
354
355 /* calculate checksum */
356 icmp6hdr->chksum = 0;
357#if CHECKSUM_GEN_ICMP6
358 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
359 icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
360 reply_src, reply_dest);
361 }
362#endif /* CHECKSUM_GEN_ICMP6 */
363
364 ICMP6_STATS_INC(icmp6.xmit);
365 ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
366 pbuf_free(q);
367}
368
369#endif /* LWIP_ICMP6 && LWIP_IPV6 */
#define LWIP_DEBUGF(debug, message)
Definition debug.h:183
@ ERR_OK
Definition err.h:82
#define ICMP_DEBUG
Definition opt.h:2692
#define LWIP_ICMP6_HL
Definition opt.h:2252
#define LWIP_ICMP6_DATASIZE
Definition opt.h:2245
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition pbuf.c:267
u8_t pbuf_free(struct pbuf *p)
Definition pbuf.c:734
err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
Definition pbuf.c:967
@ PBUF_RAM
Definition pbuf.h:127
@ PBUF_IP
Definition pbuf.h:99
#define ip_current_netif()
Definition ip.h:152
icmp6_dur_code
Definition prot/icmp6.h:117
icmp6_pp_code
Definition prot/icmp6.h:143
@ ICMP6_TYPE_MLD
Definition prot/icmp6.h:91
@ ICMP6_TYPE_NS
Definition prot/icmp6.h:97
@ ICMP6_TYPE_RD
Definition prot/icmp6.h:101
@ ICMP6_TYPE_PTB
Definition prot/icmp6.h:70
@ ICMP6_TYPE_NA
Definition prot/icmp6.h:99
@ ICMP6_TYPE_PP
Definition prot/icmp6.h:74
@ ICMP6_TYPE_RS
Definition prot/icmp6.h:93
@ ICMP6_TYPE_MLR
Definition prot/icmp6.h:89
@ ICMP6_TYPE_DUR
Definition prot/icmp6.h:68
@ ICMP6_TYPE_EREP
Definition prot/icmp6.h:85
@ ICMP6_TYPE_MLQ
Definition prot/icmp6.h:87
@ ICMP6_TYPE_RA
Definition prot/icmp6.h:95
@ ICMP6_TYPE_EREQ
Definition prot/icmp6.h:83
@ ICMP6_TYPE_TE
Definition prot/icmp6.h:72
icmp6_te_code
Definition prot/icmp6.h:135
@ ICMP6_TE_FRAG
Definition prot/icmp6.h:139
Definition netif.h:244
Definition pbuf.h:161
u16_t tot_len
Definition pbuf.h:175
u16_t len
Definition pbuf.h:178
void * payload
Definition pbuf.h:166