STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
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/ip6.h"
48 #include "lwip/ip6_addr.h"
49 #include "lwip/inet_chksum.h"
50 #include "lwip/pbuf.h"
51 #include "lwip/netif.h"
52 #include "lwip/nd6.h"
53 #include "lwip/mld6.h"
54 #include "lwip/ip.h"
55 #include "lwip/stats.h"
56 
57 #include <string.h>
58 
59 #ifndef LWIP_ICMP6_DATASIZE
60 #define LWIP_ICMP6_DATASIZE 8
61 #endif
62 #if LWIP_ICMP6_DATASIZE == 0
63 #define LWIP_ICMP6_DATASIZE 8
64 #endif
65 
66 /* Forward declarations */
67 static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
68 
69 
79 void
80 icmp6_input(struct pbuf *p, struct netif *inp)
81 {
82  struct icmp6_hdr *icmp6hdr;
83  struct pbuf * r;
84  const ip6_addr_t * reply_src;
85 
86  ICMP6_STATS_INC(icmp6.recv);
87 
88  /* Check that ICMPv6 header fits in payload */
89  if (p->len < sizeof(struct icmp6_hdr)) {
90  /* drop short packets */
91  pbuf_free(p);
92  ICMP6_STATS_INC(icmp6.lenerr);
93  ICMP6_STATS_INC(icmp6.drop);
94  return;
95  }
96 
97  icmp6hdr = (struct icmp6_hdr *)p->payload;
98 
100  IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) {
101  if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
102  ip6_current_dest_addr()) != 0) {
103  /* Checksum failed */
104  pbuf_free(p);
105  ICMP6_STATS_INC(icmp6.chkerr);
106  ICMP6_STATS_INC(icmp6.drop);
107  return;
108  }
109  }
110 #endif /* CHECKSUM_CHECK_ICMP6 */
111 
112  switch (icmp6hdr->type) {
113  case ICMP6_TYPE_NA: /* Neighbor advertisement */
114  case ICMP6_TYPE_NS: /* Neighbor solicitation */
115  case ICMP6_TYPE_RA: /* Router advertisement */
116  case ICMP6_TYPE_RD: /* Redirect */
117  case ICMP6_TYPE_PTB: /* Packet too big */
118  nd6_input(p, inp);
119  return;
120  break;
121  case ICMP6_TYPE_RS:
122 #if LWIP_IPV6_FORWARD
123  /* TODO implement router functionality */
124 #endif
125  break;
126 #if LWIP_IPV6_MLD
127  case ICMP6_TYPE_MLQ:
128  case ICMP6_TYPE_MLR:
129  case ICMP6_TYPE_MLD:
130  mld6_input(p, inp);
131  return;
132  break;
133 #endif
134  case ICMP6_TYPE_EREQ:
135 #if !LWIP_MULTICAST_PING
136  /* multicast destination address? */
137  if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
138  /* drop */
139  pbuf_free(p);
140  ICMP6_STATS_INC(icmp6.drop);
141  return;
142  }
143 #endif /* LWIP_MULTICAST_PING */
144 
145  /* Allocate reply. */
147  if (r == NULL) {
148  /* drop */
149  pbuf_free(p);
150  ICMP6_STATS_INC(icmp6.memerr);
151  return;
152  }
153 
154  /* Copy echo request. */
155  if (pbuf_copy(r, p) != ERR_OK) {
156  /* drop */
157  pbuf_free(p);
158  pbuf_free(r);
159  ICMP6_STATS_INC(icmp6.err);
160  return;
161  }
162 
163  /* Determine reply source IPv6 address. */
164 #if LWIP_MULTICAST_PING
165  if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
166  reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr()));
167  if (reply_src == NULL) {
168  /* drop */
169  pbuf_free(p);
170  pbuf_free(r);
171  ICMP6_STATS_INC(icmp6.rterr);
172  return;
173  }
174  }
175  else
176 #endif /* LWIP_MULTICAST_PING */
177  {
178  reply_src = ip6_current_dest_addr();
179  }
180 
181  /* Set fields in reply. */
182  ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
183  ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
184 #if CHECKSUM_GEN_ICMP6
185  IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) {
186  ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
187  IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
188  }
189 #endif /* CHECKSUM_GEN_ICMP6 */
190 
191  /* Send reply. */
192  ICMP6_STATS_INC(icmp6.xmit);
193  ip6_output_if(r, reply_src, ip6_current_src_addr(),
194  LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
195  pbuf_free(r);
196 
197  break;
198  default:
199  ICMP6_STATS_INC(icmp6.proterr);
200  ICMP6_STATS_INC(icmp6.drop);
201  break;
202  }
203 
204  pbuf_free(p);
205 }
206 
207 
215 void
216 icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
217 {
218  icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
219 }
220 
228 void
229 icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
230 {
231  icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
232 }
233 
241 void
242 icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
243 {
244  icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
245 }
246 
255 void
256 icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
257 {
258  icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP);
259 }
260 
270 static void
271 icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
272 {
273  struct pbuf *q;
274  struct icmp6_hdr *icmp6hdr;
275  const ip6_addr_t *reply_src;
276  ip6_addr_t *reply_dest;
277  ip6_addr_t reply_src_local, reply_dest_local;
278  struct ip6_hdr *ip6hdr;
279  struct netif *netif;
280 
281  /* ICMPv6 header + IPv6 header + data */
282  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
283  PBUF_RAM);
284  if (q == NULL) {
285  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
286  ICMP6_STATS_INC(icmp6.memerr);
287  return;
288  }
289  LWIP_ASSERT("check that first pbuf can hold icmp 6message",
290  (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
291 
292  icmp6hdr = (struct icmp6_hdr *)q->payload;
293  icmp6hdr->type = type;
294  icmp6hdr->code = code;
295  icmp6hdr->data = data;
296 
297  /* copy fields from original packet */
298  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
299  IP6_HLEN + LWIP_ICMP6_DATASIZE);
300 
301  /* Get the destination address and netif for this ICMP message. */
302  if ((ip_current_netif() == NULL) ||
303  ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
304  /* Special case, as ip6_current_xxx is either NULL, or points
305  * to a different packet than the one that expired.
306  * We must use the addresses that are stored in the expired packet. */
307  ip6hdr = (struct ip6_hdr *)p->payload;
308  /* copy from packed address to aligned address */
309  ip6_addr_copy(reply_dest_local, ip6hdr->src);
310  ip6_addr_copy(reply_src_local, ip6hdr->dest);
311  reply_dest = &reply_dest_local;
312  reply_src = &reply_src_local;
313  netif = ip6_route(reply_src, reply_dest);
314  if (netif == NULL) {
315  /* drop */
316  pbuf_free(q);
317  ICMP6_STATS_INC(icmp6.rterr);
318  return;
319  }
320  }
321  else {
322  netif = ip_current_netif();
323  reply_dest = ip6_current_src_addr();
324 
325  /* Select an address to use as source. */
326  reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest));
327  if (reply_src == NULL) {
328  /* drop */
329  pbuf_free(q);
330  ICMP6_STATS_INC(icmp6.rterr);
331  return;
332  }
333  }
334 
335  /* calculate checksum */
336  icmp6hdr->chksum = 0;
337 #if CHECKSUM_GEN_ICMP6
338  IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
339  icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
340  reply_src, reply_dest);
341  }
342 #endif /* CHECKSUM_GEN_ICMP6 */
343 
344  ICMP6_STATS_INC(icmp6.xmit);
345  ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
346  pbuf_free(q);
347 }
348 
349 #endif /* LWIP_ICMP6 && LWIP_IPV6 */
350 
icmp6_dur_code
Definition: icmp6.h:81
icmp6_te_code
Definition: icmp6.h:91
#define ip_current_netif()
Definition: ip.h:154
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:200
#define SMEMCPY(dst, src, len)
Definition: opt.h:92
#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag)
Definition: netif.h:313
u16_t len
Definition: pbuf.h:125
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
Definition: pbuf.h:77
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
Definition: pbuf.c:886
unsigned long u32_t
Definition: cc.h:42
#define ERR_OK
Definition: err.h:52
u16_t tot_len
Definition: pbuf.h:122
Definition: pbuf.h:108
#define LWIP_ICMP6_HL
Definition: opt.h:2480
#define CHECKSUM_CHECK_ICMP6
Definition: opt.h:2424
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
Definition: netif.h:182
#define LWIP_ICMP6_DATASIZE
Definition: opt.h:2473
#define ICMP6_STATS_INC(x)
Definition: stats.h:376
unsigned char u8_t
Definition: cc.h:38
Definition: pbuf.h:65
#define ICMP_DEBUG
Definition: opt.h:2816
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:113
void * payload
Definition: pbuf.h:113
icmp6_pp_code
Definition: icmp6.h:96