BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file
3 *
4 * IPv6 version of ICMP, as per RFC 4443.
5 */
6  
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 #ifndef LWIP_ICMP6_DATASIZE
61 #define LWIP_ICMP6_DATASIZE 8
62 #endif
63 #if LWIP_ICMP6_DATASIZE == 0
64 #define LWIP_ICMP6_DATASIZE 8
65 #endif
66  
67 /* Forward declarations */
68 static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
69 static void icmp6_send_response_with_addrs(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);
71 static void icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data,
72 u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr, struct netif *netif);
73  
74  
75 /**
76 * Process an input ICMPv6 message. Called by ip6_input.
77 *
78 * Will generate a reply for echo requests. Other messages are forwarded
79 * to nd6_input, or mld6_input.
80 *
81 * @param p the mld packet, p->payload pointing to the icmpv6 header
82 * @param inp the netif on which this packet was received
83 */
84 void
85 icmp6_input(struct pbuf *p, struct netif *inp)
86 {
87 struct icmp6_hdr *icmp6hdr;
88 struct pbuf *r;
89 const ip6_addr_t *reply_src;
90  
91 ICMP6_STATS_INC(icmp6.recv);
92  
93 /* Check that ICMPv6 header fits in payload */
94 if (p->len < sizeof(struct icmp6_hdr)) {
95 /* drop short packets */
96 pbuf_free(p);
97 ICMP6_STATS_INC(icmp6.lenerr);
98 ICMP6_STATS_INC(icmp6.drop);
99 return;
100 }
101  
102 icmp6hdr = (struct icmp6_hdr *)p->payload;
103  
104 #if CHECKSUM_CHECK_ICMP6
105 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) {
106 if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
107 ip6_current_dest_addr()) != 0) {
108 /* Checksum failed */
109 pbuf_free(p);
110 ICMP6_STATS_INC(icmp6.chkerr);
111 ICMP6_STATS_INC(icmp6.drop);
112 return;
113 }
114 }
115 #endif /* CHECKSUM_CHECK_ICMP6 */
116  
117 switch (icmp6hdr->type) {
118 case ICMP6_TYPE_NA: /* Neighbor advertisement */
119 case ICMP6_TYPE_NS: /* Neighbor solicitation */
120 case ICMP6_TYPE_RA: /* Router advertisement */
121 case ICMP6_TYPE_RD: /* Redirect */
122 case ICMP6_TYPE_PTB: /* Packet too big */
123 nd6_input(p, inp);
124 return;
125 case ICMP6_TYPE_RS:
126 #if LWIP_IPV6_FORWARD
127 /* @todo implement router functionality */
128 #endif
129 break;
130 #if LWIP_IPV6_MLD
131 case ICMP6_TYPE_MLQ:
132 case ICMP6_TYPE_MLR:
133 case ICMP6_TYPE_MLD:
134 mld6_input(p, inp);
135 return;
136 #endif
137 case ICMP6_TYPE_EREQ:
138 #if !LWIP_MULTICAST_PING
139 /* multicast destination address? */
140 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
141 /* drop */
142 pbuf_free(p);
143 ICMP6_STATS_INC(icmp6.drop);
144 return;
145 }
146 #endif /* LWIP_MULTICAST_PING */
147  
148 /* Allocate reply. */
149 r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
150 if (r == NULL) {
151 /* drop */
152 pbuf_free(p);
153 ICMP6_STATS_INC(icmp6.memerr);
154 return;
155 }
156  
157 /* Copy echo request. */
158 if (pbuf_copy(r, p) != ERR_OK) {
159 /* drop */
160 pbuf_free(p);
161 pbuf_free(r);
162 ICMP6_STATS_INC(icmp6.err);
163 return;
164 }
165  
166 /* Determine reply source IPv6 address. */
167 #if LWIP_MULTICAST_PING
168 if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
169 reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr()));
170 if (reply_src == NULL) {
171 /* drop */
172 pbuf_free(p);
173 pbuf_free(r);
174 ICMP6_STATS_INC(icmp6.rterr);
175 return;
176 }
177 }
178 else
179 #endif /* LWIP_MULTICAST_PING */
180 {
181 reply_src = ip6_current_dest_addr();
182 }
183  
184 /* Set fields in reply. */
185 ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
186 ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
187 #if CHECKSUM_GEN_ICMP6
188 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) {
189 ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
190 IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
191 }
192 #endif /* CHECKSUM_GEN_ICMP6 */
193  
194 /* Send reply. */
195 ICMP6_STATS_INC(icmp6.xmit);
196 ip6_output_if(r, reply_src, ip6_current_src_addr(),
197 LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
198 pbuf_free(r);
199  
200 break;
201 default:
202 ICMP6_STATS_INC(icmp6.proterr);
203 ICMP6_STATS_INC(icmp6.drop);
204 break;
205 }
206  
207 pbuf_free(p);
208 }
209  
210  
211 /**
212 * Send an icmpv6 'destination unreachable' packet.
213 *
214 * This function must be used only in direct response to a packet that is being
215 * received right now. Otherwise, address zones would be lost.
216 *
217 * @param p the input packet for which the 'unreachable' should be sent,
218 * p->payload pointing to the IPv6 header
219 * @param c ICMPv6 code for the unreachable type
220 */
221 void
222 icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
223 {
224 icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
225 }
226  
227 /**
228 * Send an icmpv6 'packet too big' packet.
229 *
230 * This function must be used only in direct response to a packet that is being
231 * received right now. Otherwise, address zones would be lost.
232 *
233 * @param p the input packet for which the 'packet too big' should be sent,
234 * p->payload pointing to the IPv6 header
235 * @param mtu the maximum mtu that we can accept
236 */
237 void
238 icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
239 {
240 icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
241 }
242  
243 /**
244 * Send an icmpv6 'time exceeded' packet.
245 *
246 * This function must be used only in direct response to a packet that is being
247 * received right now. Otherwise, address zones would be lost.
248 *
249 * @param p the input packet for which the 'time exceeded' should be sent,
250 * p->payload pointing to the IPv6 header
251 * @param c ICMPv6 code for the time exceeded type
252 */
253 void
254 icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
255 {
256 icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
257 }
258  
259 /**
260 * Send an icmpv6 'time exceeded' packet, with explicit source and destination
261 * addresses.
262 *
263 * This function may be used to send a response sometime after receiving the
264 * packet for which this response is meant. The provided source and destination
265 * addresses are used primarily to retain their zone information.
266 *
267 * @param p the input packet for which the 'time exceeded' should be sent,
268 * p->payload pointing to the IPv6 header
269 * @param c ICMPv6 code for the time exceeded type
270 * @param src_addr source address of the original packet, with zone information
271 * @param dest_addr destination address of the original packet, with zone
272 * information
273 */
274 void
275 icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c,
276 const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr)
277 {
278 icmp6_send_response_with_addrs(p, c, 0, ICMP6_TYPE_TE, src_addr, dest_addr);
279 }
280  
281 /**
282 * Send an icmpv6 'parameter problem' packet.
283 *
284 * This function must be used only in direct response to a packet that is being
285 * received right now. Otherwise, address zones would be lost and the calculated
286 * offset would be wrong (calculated against ip6_current_header()).
287 *
288 * @param p the input packet for which the 'param problem' should be sent,
289 * p->payload pointing to the IP header
290 * @param c ICMPv6 code for the param problem type
291 * @param pointer the pointer to the byte where the parameter is found
292 */
293 void
294 icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer)
295 {
296 u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header());
297 icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP);
298 }
299  
300 /**
301 * Send an ICMPv6 packet in response to an incoming packet.
302 * The packet is sent *to* ip_current_src_addr() on ip_current_netif().
303 *
304 * @param p the input packet for which the response should be sent,
305 * p->payload pointing to the IPv6 header
306 * @param code Code of the ICMPv6 header
307 * @param data Additional 32-bit parameter in the ICMPv6 header
308 * @param type Type of the ICMPv6 header
309 */
310 static void
311 icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
312 {
313 const struct ip6_addr *reply_src, *reply_dest;
314 struct netif *netif = ip_current_netif();
315  
316 LWIP_ASSERT("icmpv6 packet not a direct response", netif != NULL);
317 reply_dest = ip6_current_src_addr();
318  
319 /* Select an address to use as source. */
320 reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest));
321 if (reply_src == NULL) {
322 ICMP6_STATS_INC(icmp6.rterr);
323 return;
324 }
325 icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, reply_dest, netif);
326 }
327  
328 /**
329 * Send an ICMPv6 packet in response to an incoming packet.
330 *
331 * Call this function if the packet is NOT sent as a direct response to an
332 * incoming packet, but rather sometime later (e.g. for a fragment reassembly
333 * timeout). The caller must provide the zoned source and destination addresses
334 * from the original packet with the src_addr and dest_addr parameters. The
335 * reason for this approach is that while the addresses themselves are part of
336 * the original packet, their zone information is not, thus possibly resulting
337 * in a link-local response being sent over the wrong link.
338 *
339 * @param p the input packet for which the response should be sent,
340 * p->payload pointing to the IPv6 header
341 * @param code Code of the ICMPv6 header
342 * @param data Additional 32-bit parameter in the ICMPv6 header
343 * @param type Type of the ICMPv6 header
344 * @param src_addr original source address
345 * @param dest_addr original destination address
346 */
347 static void
348 icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type,
349 const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr)
350 {
351 const struct ip6_addr *reply_src, *reply_dest;
352 struct netif *netif;
353  
354 /* Get the destination address and netif for this ICMP message. */
355 LWIP_ASSERT("must provide both source and destination", src_addr != NULL);
356 LWIP_ASSERT("must provide both source and destination", dest_addr != NULL);
357  
358 /* Special case, as ip6_current_xxx is either NULL, or points
359 to a different packet than the one that expired. */
360 IP6_ADDR_ZONECHECK(src_addr);
361 IP6_ADDR_ZONECHECK(dest_addr);
362 /* Swap source and destination for the reply. */
363 reply_dest = src_addr;
364 reply_src = dest_addr;
365 netif = ip6_route(reply_src, reply_dest);
366 if (netif == NULL) {
367 ICMP6_STATS_INC(icmp6.rterr);
368 return;
369 }
370 icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src,
371 reply_dest, netif);
372 }
373  
374 /**
375 * Send an ICMPv6 packet (with srd/dst address and netif given).
376 *
377 * @param p the input packet for which the response should be sent,
378 * p->payload pointing to the IPv6 header
379 * @param code Code of the ICMPv6 header
380 * @param data Additional 32-bit parameter in the ICMPv6 header
381 * @param type Type of the ICMPv6 header
382 * @param reply_src source address of the packet to send
383 * @param reply_dest destination address of the packet to send
384 * @param netif netif to send the packet
385 */
386 static void
387 icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, u8_t type,
388 const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif)
389 {
390 struct pbuf *q;
391 struct icmp6_hdr *icmp6hdr;
392  
393 /* ICMPv6 header + IPv6 header + data */
394 q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
395 PBUF_RAM);
396 if (q == NULL) {
397 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
398 ICMP6_STATS_INC(icmp6.memerr);
399 return;
400 }
401 LWIP_ASSERT("check that first pbuf can hold icmp 6message",
402 (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
403  
404 icmp6hdr = (struct icmp6_hdr *)q->payload;
405 icmp6hdr->type = type;
406 icmp6hdr->code = code;
407 icmp6hdr->data = lwip_htonl(data);
408  
409 /* copy fields from original packet */
410 SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
411 IP6_HLEN + LWIP_ICMP6_DATASIZE);
412  
413 /* calculate checksum */
414 icmp6hdr->chksum = 0;
415 #if CHECKSUM_GEN_ICMP6
416 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) {
417 icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
418 reply_src, reply_dest);
419 }
420 #endif /* CHECKSUM_GEN_ICMP6 */
421  
422 ICMP6_STATS_INC(icmp6.xmit);
423 ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
424 pbuf_free(q);
425 }
426  
427 #endif /* LWIP_ICMP6 && LWIP_IPV6 */