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 */
87 static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
88 
89 
99 void
100 icmp6_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 
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 
235 void
236 icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
237 {
238  icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
239 }
240 
248 void
249 icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
250 {
251  icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
252 }
253 
261 void
262 icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
263 {
264  icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
265 }
266 
275 void
276 icmp6_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 
290 static void
291 icmp6_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 {
342  netif = ip_current_netif();
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 */
u16_t tot_len
Definition: pbuf.h:175
u16_t len
Definition: pbuf.h:178
#define ip_current_netif()
Definition: ip.h:152
err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
Definition: pbuf.c:967
icmp6_te_code
Definition: prot/icmp6.h:135
icmp6_pp_code
Definition: prot/icmp6.h:143
Definition: pbuf.h:161
Definition: netif.h:244
#define LWIP_DEBUGF(debug, message)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:267
#define ICMP_DEBUG
Definition: opt.h:2692
Definition: pbuf.h:127
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:734
Definition: err.h:82
void * payload
Definition: pbuf.h:166
Definition: pbuf.h:99
#define LWIP_ICMP6_HL
Definition: opt.h:2252
#define LWIP_ICMP6_DATASIZE
Definition: opt.h:2245
icmp6_dur_code
Definition: prot/icmp6.h:117
#define CHECKSUM_CHECK_ICMP6
Definition: opt.h:2144