Branch data Line data Source code
1 : : /*
2 : : * Extension Header handling for IPv6
3 : : * Linux INET6 implementation
4 : : *
5 : : * Authors:
6 : : * Pedro Roque <roque@di.fc.ul.pt>
7 : : * Andi Kleen <ak@muc.de>
8 : : * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
9 : : *
10 : : * This program is free software; you can redistribute it and/or
11 : : * modify it under the terms of the GNU General Public License
12 : : * as published by the Free Software Foundation; either version
13 : : * 2 of the License, or (at your option) any later version.
14 : : */
15 : :
16 : : /* Changes:
17 : : * yoshfuji : ensure not to overrun while parsing
18 : : * tlv options.
19 : : * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
20 : : * YOSHIFUJI Hideaki @USAGI Register inbound extension header
21 : : * handlers as inet6_protocol{}.
22 : : */
23 : :
24 : : #include <linux/errno.h>
25 : : #include <linux/types.h>
26 : : #include <linux/socket.h>
27 : : #include <linux/sockios.h>
28 : : #include <linux/net.h>
29 : : #include <linux/netdevice.h>
30 : : #include <linux/in6.h>
31 : : #include <linux/icmpv6.h>
32 : : #include <linux/slab.h>
33 : : #include <linux/export.h>
34 : :
35 : : #include <net/dst.h>
36 : : #include <net/sock.h>
37 : : #include <net/snmp.h>
38 : :
39 : : #include <net/ipv6.h>
40 : : #include <net/protocol.h>
41 : : #include <net/transp_v6.h>
42 : : #include <net/rawv6.h>
43 : : #include <net/ndisc.h>
44 : : #include <net/ip6_route.h>
45 : : #include <net/addrconf.h>
46 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
47 : : #include <net/xfrm.h>
48 : : #endif
49 : :
50 : : #include <asm/uaccess.h>
51 : :
52 : : /*
53 : : * Parsing tlv encoded headers.
54 : : *
55 : : * Parsing function "func" returns true, if parsing succeed
56 : : * and false, if it failed.
57 : : * It MUST NOT touch skb->h.
58 : : */
59 : :
60 : : struct tlvtype_proc {
61 : : int type;
62 : : bool (*func)(struct sk_buff *skb, int offset);
63 : : };
64 : :
65 : : /*********************
66 : : Generic functions
67 : : *********************/
68 : :
69 : : /* An unknown option is detected, decide what to do */
70 : :
71 : 0 : static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
72 : : {
73 [ # # # # ]: 0 : switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
74 : : case 0: /* ignore */
75 : : return true;
76 : :
77 : : case 1: /* drop packet */
78 : : break;
79 : :
80 : : case 3: /* Send ICMP if not a multicast address and drop packet */
81 : : /* Actually, it is redundant check. icmp_send
82 : : will recheck in any case.
83 : : */
84 [ # # ]: 0 : if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
85 : : break;
86 : : case 2: /* send ICMP PARM PROB regardless and drop packet */
87 : 0 : icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
88 : 0 : return false;
89 : : }
90 : :
91 : 0 : kfree_skb(skb);
92 : 0 : return false;
93 : : }
94 : :
95 : : /* Parse tlv encoded option header (hop-by-hop or destination) */
96 : :
97 : 0 : static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
98 : : {
99 : : const struct tlvtype_proc *curr;
100 : : const unsigned char *nh = skb_network_header(skb);
101 : : int off = skb_network_header_len(skb);
102 : 0 : int len = (skb_transport_header(skb)[1] + 1) << 3;
103 : : int padlen = 0;
104 : :
105 [ # # ]: 0 : if (skb_transport_offset(skb) + len > skb_headlen(skb))
106 : : goto bad;
107 : :
108 : 0 : off += 2;
109 : 0 : len -= 2;
110 : :
111 [ # # ]: 0 : while (len > 0) {
112 : 0 : int optlen = nh[off + 1] + 2;
113 : : int i;
114 : :
115 [ # # # ]: 0 : switch (nh[off]) {
116 : : case IPV6_TLV_PAD1:
117 : : optlen = 1;
118 : 0 : padlen++;
119 [ # # ]: 0 : if (padlen > 7)
120 : : goto bad;
121 : : break;
122 : :
123 : : case IPV6_TLV_PADN:
124 : : /* RFC 2460 states that the purpose of PadN is
125 : : * to align the containing header to multiples
126 : : * of 8. 7 is therefore the highest valid value.
127 : : * See also RFC 4942, Section 2.1.9.5.
128 : : */
129 : 0 : padlen += optlen;
130 [ # # ]: 0 : if (padlen > 7)
131 : : goto bad;
132 : : /* RFC 4942 recommends receiving hosts to
133 : : * actively check PadN payload to contain
134 : : * only zeroes.
135 : : */
136 [ # # ]: 0 : for (i = 2; i < optlen; i++) {
137 [ # # ]: 0 : if (nh[off + i] != 0)
138 : : goto bad;
139 : : }
140 : : break;
141 : :
142 : : default: /* Other TLV code so scan list */
143 [ # # ]: 0 : if (optlen > len)
144 : : goto bad;
145 [ # # ]: 0 : for (curr=procs; curr->type >= 0; curr++) {
146 [ # # ]: 0 : if (curr->type == nh[off]) {
147 : : /* type specific length/alignment
148 : : checks will be performed in the
149 : : func(). */
150 [ # # ]: 0 : if (curr->func(skb, off) == false)
151 : : return false;
152 : : break;
153 : : }
154 : : }
155 [ # # ]: 0 : if (curr->type < 0) {
156 [ # # ]: 0 : if (ip6_tlvopt_unknown(skb, off) == 0)
157 : : return false;
158 : : }
159 : : padlen = 0;
160 : : break;
161 : : }
162 : 0 : off += optlen;
163 : 0 : len -= optlen;
164 : : }
165 : :
166 [ # # ]: 0 : if (len == 0)
167 : : return true;
168 : : bad:
169 : 0 : kfree_skb(skb);
170 : 0 : return false;
171 : : }
172 : :
173 : : /*****************************
174 : : Destination options header.
175 : : *****************************/
176 : :
177 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
178 : : static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
179 : : {
180 : : struct ipv6_destopt_hao *hao;
181 : : struct inet6_skb_parm *opt = IP6CB(skb);
182 : : struct ipv6hdr *ipv6h = ipv6_hdr(skb);
183 : : struct in6_addr tmp_addr;
184 : : int ret;
185 : :
186 : : if (opt->dsthao) {
187 : : LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
188 : : goto discard;
189 : : }
190 : : opt->dsthao = opt->dst1;
191 : : opt->dst1 = 0;
192 : :
193 : : hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
194 : :
195 : : if (hao->length != 16) {
196 : : LIMIT_NETDEBUG(
197 : : KERN_DEBUG "hao invalid option length = %d\n", hao->length);
198 : : goto discard;
199 : : }
200 : :
201 : : if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
202 : : LIMIT_NETDEBUG(
203 : : KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr);
204 : : goto discard;
205 : : }
206 : :
207 : : ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
208 : : (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
209 : : if (unlikely(ret < 0))
210 : : goto discard;
211 : :
212 : : if (skb_cloned(skb)) {
213 : : if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
214 : : goto discard;
215 : :
216 : : /* update all variable using below by copied skbuff */
217 : : hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
218 : : optoff);
219 : : ipv6h = ipv6_hdr(skb);
220 : : }
221 : :
222 : : if (skb->ip_summed == CHECKSUM_COMPLETE)
223 : : skb->ip_summed = CHECKSUM_NONE;
224 : :
225 : : tmp_addr = ipv6h->saddr;
226 : : ipv6h->saddr = hao->addr;
227 : : hao->addr = tmp_addr;
228 : :
229 : : if (skb->tstamp.tv64 == 0)
230 : : __net_timestamp(skb);
231 : :
232 : : return true;
233 : :
234 : : discard:
235 : : kfree_skb(skb);
236 : : return false;
237 : : }
238 : : #endif
239 : :
240 : : static const struct tlvtype_proc tlvprocdestopt_lst[] = {
241 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
242 : : {
243 : : .type = IPV6_TLV_HAO,
244 : : .func = ipv6_dest_hao,
245 : : },
246 : : #endif
247 : : {-1, NULL}
248 : : };
249 : :
250 : 0 : static int ipv6_destopt_rcv(struct sk_buff *skb)
251 : : {
252 : : struct inet6_skb_parm *opt = IP6CB(skb);
253 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
254 : : __u16 dstbuf;
255 : : #endif
256 : : struct dst_entry *dst = skb_dst(skb);
257 : :
258 [ # # ][ # # ]: 0 : if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
259 : 0 : !pskb_may_pull(skb, (skb_transport_offset(skb) +
260 : 0 : ((skb_transport_header(skb)[1] + 1) << 3)))) {
261 [ # # ]: 0 : IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst),
262 : : IPSTATS_MIB_INHDRERRORS);
263 : 0 : kfree_skb(skb);
264 : 0 : return -1;
265 : : }
266 : :
267 : 0 : opt->lastopt = opt->dst1 = skb_network_header_len(skb);
268 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
269 : : dstbuf = opt->dst1;
270 : : #endif
271 : :
272 [ # # ]: 0 : if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
273 : 0 : skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
274 : : opt = IP6CB(skb);
275 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
276 : : opt->nhoff = dstbuf;
277 : : #else
278 : 0 : opt->nhoff = opt->dst1;
279 : : #endif
280 : 0 : return 1;
281 : : }
282 : :
283 [ # # ]: 0 : IP6_INC_STATS_BH(dev_net(dst->dev),
284 : : ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
285 : 0 : return -1;
286 : : }
287 : :
288 : : /********************************
289 : : Routing header.
290 : : ********************************/
291 : :
292 : : /* called with rcu_read_lock() */
293 : 0 : static int ipv6_rthdr_rcv(struct sk_buff *skb)
294 : : {
295 : : struct inet6_skb_parm *opt = IP6CB(skb);
296 : : struct in6_addr *addr = NULL;
297 : : struct in6_addr daddr;
298 : : struct inet6_dev *idev;
299 : : int n, i;
300 : : struct ipv6_rt_hdr *hdr;
301 : : struct rt0_hdr *rthdr;
302 : : struct net *net = dev_net(skb->dev);
303 : : int accept_source_route = net->ipv6.devconf_all->accept_source_route;
304 : :
305 : : idev = __in6_dev_get(skb->dev);
306 : : if (idev && accept_source_route > idev->cnf.accept_source_route)
307 : : accept_source_route = idev->cnf.accept_source_route;
308 : :
309 [ # # ][ # # ]: 0 : if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
310 : 0 : !pskb_may_pull(skb, (skb_transport_offset(skb) +
311 : 0 : ((skb_transport_header(skb)[1] + 1) << 3)))) {
312 [ # # ]: 0 : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
313 : : IPSTATS_MIB_INHDRERRORS);
314 : 0 : kfree_skb(skb);
315 : 0 : return -1;
316 : : }
317 : :
318 : : hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
319 : :
320 [ # # ][ # # ]: 0 : if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
321 : 0 : skb->pkt_type != PACKET_HOST) {
322 [ # # ]: 0 : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
323 : : IPSTATS_MIB_INADDRERRORS);
324 : 0 : kfree_skb(skb);
325 : 0 : return -1;
326 : : }
327 : :
328 : : looped_back:
329 [ # # ]: 0 : if (hdr->segments_left == 0) {
330 : : switch (hdr->type) {
331 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
332 : : case IPV6_SRCRT_TYPE_2:
333 : : /* Silently discard type 2 header unless it was
334 : : * processed by own
335 : : */
336 : : if (!addr) {
337 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
338 : : IPSTATS_MIB_INADDRERRORS);
339 : : kfree_skb(skb);
340 : : return -1;
341 : : }
342 : : break;
343 : : #endif
344 : : default:
345 : : break;
346 : : }
347 : :
348 : 0 : opt->lastopt = opt->srcrt = skb_network_header_len(skb);
349 : 0 : skb->transport_header += (hdr->hdrlen + 1) << 3;
350 : 0 : opt->dst0 = opt->dst1;
351 : 0 : opt->dst1 = 0;
352 : 0 : opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
353 : 0 : return 1;
354 : : }
355 : :
356 : : switch (hdr->type) {
357 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
358 : : case IPV6_SRCRT_TYPE_2:
359 : : if (accept_source_route < 0)
360 : : goto unknown_rh;
361 : : /* Silently discard invalid RTH type 2 */
362 : : if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
363 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
364 : : IPSTATS_MIB_INHDRERRORS);
365 : : kfree_skb(skb);
366 : : return -1;
367 : : }
368 : : break;
369 : : #endif
370 : : default:
371 : : goto unknown_rh;
372 : : }
373 : :
374 : : /*
375 : : * This is the routing header forwarding algorithm from
376 : : * RFC 2460, page 16.
377 : : */
378 : :
379 : : n = hdr->hdrlen >> 1;
380 : :
381 : : if (hdr->segments_left > n) {
382 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
383 : : IPSTATS_MIB_INHDRERRORS);
384 : : icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
385 : : ((&hdr->segments_left) -
386 : : skb_network_header(skb)));
387 : : return -1;
388 : : }
389 : :
390 : : /* We are about to mangle packet header. Be careful!
391 : : Do not damage packets queued somewhere.
392 : : */
393 : : if (skb_cloned(skb)) {
394 : : /* the copy is a forwarded packet */
395 : : if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
396 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
397 : : IPSTATS_MIB_OUTDISCARDS);
398 : : kfree_skb(skb);
399 : : return -1;
400 : : }
401 : : hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
402 : : }
403 : :
404 : : if (skb->ip_summed == CHECKSUM_COMPLETE)
405 : : skb->ip_summed = CHECKSUM_NONE;
406 : :
407 : : i = n - --hdr->segments_left;
408 : :
409 : : rthdr = (struct rt0_hdr *) hdr;
410 : : addr = rthdr->addr;
411 : : addr += i - 1;
412 : :
413 : : switch (hdr->type) {
414 : : #if IS_ENABLED(CONFIG_IPV6_MIP6)
415 : : case IPV6_SRCRT_TYPE_2:
416 : : if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
417 : : (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
418 : : IPPROTO_ROUTING) < 0) {
419 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
420 : : IPSTATS_MIB_INADDRERRORS);
421 : : kfree_skb(skb);
422 : : return -1;
423 : : }
424 : : if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
425 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
426 : : IPSTATS_MIB_INADDRERRORS);
427 : : kfree_skb(skb);
428 : : return -1;
429 : : }
430 : : break;
431 : : #endif
432 : : default:
433 : : break;
434 : : }
435 : :
436 : : if (ipv6_addr_is_multicast(addr)) {
437 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
438 : : IPSTATS_MIB_INADDRERRORS);
439 : : kfree_skb(skb);
440 : : return -1;
441 : : }
442 : :
443 : : daddr = *addr;
444 : : *addr = ipv6_hdr(skb)->daddr;
445 : : ipv6_hdr(skb)->daddr = daddr;
446 : :
447 : : skb_dst_drop(skb);
448 : : ip6_route_input(skb);
449 : : if (skb_dst(skb)->error) {
450 : : skb_push(skb, skb->data - skb_network_header(skb));
451 : : dst_input(skb);
452 : : return -1;
453 : : }
454 : :
455 : : if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
456 : : if (ipv6_hdr(skb)->hop_limit <= 1) {
457 : : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
458 : : IPSTATS_MIB_INHDRERRORS);
459 : : icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
460 : : 0);
461 : : kfree_skb(skb);
462 : : return -1;
463 : : }
464 : : ipv6_hdr(skb)->hop_limit--;
465 : : goto looped_back;
466 : : }
467 : :
468 : : skb_push(skb, skb->data - skb_network_header(skb));
469 : : dst_input(skb);
470 : : return -1;
471 : :
472 : : unknown_rh:
473 [ # # ]: 0 : IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
474 : 0 : icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
475 : 0 : (&hdr->type) - skb_network_header(skb));
476 : 0 : return -1;
477 : : }
478 : :
479 : : static const struct inet6_protocol rthdr_protocol = {
480 : : .handler = ipv6_rthdr_rcv,
481 : : .flags = INET6_PROTO_NOPOLICY,
482 : : };
483 : :
484 : : static const struct inet6_protocol destopt_protocol = {
485 : : .handler = ipv6_destopt_rcv,
486 : : .flags = INET6_PROTO_NOPOLICY,
487 : : };
488 : :
489 : : static const struct inet6_protocol nodata_protocol = {
490 : : .handler = dst_discard,
491 : : .flags = INET6_PROTO_NOPOLICY,
492 : : };
493 : :
494 : 0 : int __init ipv6_exthdrs_init(void)
495 : : {
496 : : int ret;
497 : :
498 : 0 : ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
499 [ # # ]: 0 : if (ret)
500 : : goto out;
501 : :
502 : 0 : ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
503 [ # # ]: 0 : if (ret)
504 : : goto out_rthdr;
505 : :
506 : 0 : ret = inet6_add_protocol(&nodata_protocol, IPPROTO_NONE);
507 [ # # ]: 0 : if (ret)
508 : : goto out_destopt;
509 : :
510 : : out:
511 : 0 : return ret;
512 : : out_destopt:
513 : 0 : inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
514 : : out_rthdr:
515 : 0 : inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
516 : 0 : goto out;
517 : : };
518 : :
519 : 0 : void ipv6_exthdrs_exit(void)
520 : : {
521 : 0 : inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
522 : 0 : inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
523 : 0 : inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
524 : 0 : }
525 : :
526 : : /**********************************
527 : : Hop-by-hop options.
528 : : **********************************/
529 : :
530 : : /*
531 : : * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input().
532 : : */
533 : 0 : static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
534 : : {
535 [ # # ][ # # ]: 0 : return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev);
[ # # ][ # # ]
536 : : }
537 : :
538 : : static inline struct net *ipv6_skb_net(struct sk_buff *skb)
539 : : {
540 : : return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev);
541 : : }
542 : :
543 : : /* Router Alert as of RFC 2711 */
544 : :
545 : 0 : static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
546 : : {
547 : : const unsigned char *nh = skb_network_header(skb);
548 : :
549 [ # # ]: 0 : if (nh[optoff + 1] == 2) {
550 : 0 : IP6CB(skb)->flags |= IP6SKB_ROUTERALERT;
551 : 0 : memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra));
552 : 0 : return true;
553 : : }
554 [ # # ][ # # ]: 0 : LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
555 : : nh[optoff + 1]);
556 : 0 : kfree_skb(skb);
557 : 0 : return false;
558 : : }
559 : :
560 : : /* Jumbo payload */
561 : :
562 : 0 : static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
563 : : {
564 : : const unsigned char *nh = skb_network_header(skb);
565 : : struct net *net = ipv6_skb_net(skb);
566 : : u32 pkt_len;
567 : :
568 [ # # ][ # # ]: 0 : if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
569 [ # # ][ # # ]: 0 : LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
570 : : nh[optoff+1]);
571 [ # # ]: 0 : IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
572 : : IPSTATS_MIB_INHDRERRORS);
573 : : goto drop;
574 : : }
575 : :
576 [ # # ]: 0 : pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
577 [ # # ]: 0 : if (pkt_len <= IPV6_MAXPLEN) {
578 [ # # ]: 0 : IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
579 : : IPSTATS_MIB_INHDRERRORS);
580 : 0 : icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
581 : 0 : return false;
582 : : }
583 [ # # ]: 0 : if (ipv6_hdr(skb)->payload_len) {
584 [ # # ]: 0 : IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
585 : : IPSTATS_MIB_INHDRERRORS);
586 : 0 : icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
587 : 0 : return false;
588 : : }
589 : :
590 [ # # ]: 0 : if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
591 [ # # ]: 0 : IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
592 : : IPSTATS_MIB_INTRUNCATEDPKTS);
593 : : goto drop;
594 : : }
595 : :
596 [ # # ]: 0 : if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
597 : : goto drop;
598 : :
599 : : return true;
600 : :
601 : : drop:
602 : 0 : kfree_skb(skb);
603 : 0 : return false;
604 : : }
605 : :
606 : : static const struct tlvtype_proc tlvprochopopt_lst[] = {
607 : : {
608 : : .type = IPV6_TLV_ROUTERALERT,
609 : : .func = ipv6_hop_ra,
610 : : },
611 : : {
612 : : .type = IPV6_TLV_JUMBO,
613 : : .func = ipv6_hop_jumbo,
614 : : },
615 : : { -1, }
616 : : };
617 : :
618 : 0 : int ipv6_parse_hopopts(struct sk_buff *skb)
619 : : {
620 : : struct inet6_skb_parm *opt = IP6CB(skb);
621 : :
622 : : /*
623 : : * skb_network_header(skb) is equal to skb->data, and
624 : : * skb_network_header_len(skb) is always equal to
625 : : * sizeof(struct ipv6hdr) by definition of
626 : : * hop-by-hop options.
627 : : */
628 [ # # ][ # # ]: 0 : if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
629 : 0 : !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
630 : 0 : ((skb_transport_header(skb)[1] + 1) << 3)))) {
631 : 0 : kfree_skb(skb);
632 : 0 : return -1;
633 : : }
634 : :
635 : 0 : opt->hop = sizeof(struct ipv6hdr);
636 [ # # ]: 0 : if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
637 : 0 : skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
638 : : opt = IP6CB(skb);
639 : 0 : opt->nhoff = sizeof(struct ipv6hdr);
640 : 0 : return 1;
641 : : }
642 : : return -1;
643 : : }
644 : :
645 : : /*
646 : : * Creating outbound headers.
647 : : *
648 : : * "build" functions work when skb is filled from head to tail (datagram)
649 : : * "push" functions work when headers are added from tail to head (tcp)
650 : : *
651 : : * In both cases we assume, that caller reserved enough room
652 : : * for headers.
653 : : */
654 : :
655 : 0 : static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
656 : : struct ipv6_rt_hdr *opt,
657 : : struct in6_addr **addr_p)
658 : : {
659 : : struct rt0_hdr *phdr, *ihdr;
660 : : int hops;
661 : :
662 : : ihdr = (struct rt0_hdr *) opt;
663 : :
664 : 0 : phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
665 : 0 : memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
666 : :
667 : 0 : hops = ihdr->rt_hdr.hdrlen >> 1;
668 : :
669 [ # # ]: 0 : if (hops > 1)
670 : 0 : memcpy(phdr->addr, ihdr->addr + 1,
671 : 0 : (hops - 1) * sizeof(struct in6_addr));
672 : :
673 : 0 : phdr->addr[hops - 1] = **addr_p;
674 : 0 : *addr_p = ihdr->addr;
675 : :
676 : 0 : phdr->rt_hdr.nexthdr = *proto;
677 : 0 : *proto = NEXTHDR_ROUTING;
678 : 0 : }
679 : :
680 : 0 : static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
681 : : {
682 : 0 : struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
683 : :
684 : 0 : memcpy(h, opt, ipv6_optlen(opt));
685 : 0 : h->nexthdr = *proto;
686 : 0 : *proto = type;
687 : 0 : }
688 : :
689 : 0 : void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
690 : : u8 *proto,
691 : : struct in6_addr **daddr)
692 : : {
693 [ # # ]: 0 : if (opt->srcrt) {
694 : 0 : ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
695 : : /*
696 : : * IPV6_RTHDRDSTOPTS is ignored
697 : : * unless IPV6_RTHDR is set (RFC3542).
698 : : */
699 [ # # ]: 0 : if (opt->dst0opt)
700 : 0 : ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
701 : : }
702 [ # # ]: 0 : if (opt->hopopt)
703 : 0 : ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
704 : 0 : }
705 : : EXPORT_SYMBOL(ipv6_push_nfrag_opts);
706 : :
707 : 0 : void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
708 : : {
709 [ # # ]: 0 : if (opt->dst1opt)
710 : 0 : ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
711 : 0 : }
712 : :
713 : : struct ipv6_txoptions *
714 : 0 : ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
715 : : {
716 : : struct ipv6_txoptions *opt2;
717 : :
718 : 0 : opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
719 [ # # ]: 0 : if (opt2) {
720 : 0 : long dif = (char *)opt2 - (char *)opt;
721 : 0 : memcpy(opt2, opt, opt->tot_len);
722 [ # # ]: 0 : if (opt2->hopopt)
723 : 0 : *((char **)&opt2->hopopt) += dif;
724 [ # # ]: 0 : if (opt2->dst0opt)
725 : 0 : *((char **)&opt2->dst0opt) += dif;
726 [ # # ]: 0 : if (opt2->dst1opt)
727 : 0 : *((char **)&opt2->dst1opt) += dif;
728 [ # # ]: 0 : if (opt2->srcrt)
729 : 0 : *((char **)&opt2->srcrt) += dif;
730 : : }
731 : 0 : return opt2;
732 : : }
733 : : EXPORT_SYMBOL_GPL(ipv6_dup_options);
734 : :
735 : 0 : static int ipv6_renew_option(void *ohdr,
736 : : struct ipv6_opt_hdr __user *newopt, int newoptlen,
737 : : int inherit,
738 : : struct ipv6_opt_hdr **hdr,
739 : : char **p)
740 : : {
741 [ # # ]: 0 : if (inherit) {
742 [ # # ]: 0 : if (ohdr) {
743 : 0 : memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
744 : 0 : *hdr = (struct ipv6_opt_hdr *)*p;
745 : 0 : *p += CMSG_ALIGN(ipv6_optlen(*hdr));
746 : : }
747 : : } else {
748 [ # # ]: 0 : if (newopt) {
749 [ # # ]: 0 : if (copy_from_user(*p, newopt, newoptlen))
750 : : return -EFAULT;
751 : 0 : *hdr = (struct ipv6_opt_hdr *)*p;
752 [ # # ]: 0 : if (ipv6_optlen(*hdr) > newoptlen)
753 : : return -EINVAL;
754 : 0 : *p += CMSG_ALIGN(newoptlen);
755 : : }
756 : : }
757 : : return 0;
758 : : }
759 : :
760 : : struct ipv6_txoptions *
761 : 0 : ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
762 : : int newtype,
763 : : struct ipv6_opt_hdr __user *newopt, int newoptlen)
764 : : {
765 : : int tot_len = 0;
766 : : char *p;
767 : : struct ipv6_txoptions *opt2;
768 : : int err;
769 : :
770 [ # # ]: 0 : if (opt) {
771 [ # # ][ # # ]: 0 : if (newtype != IPV6_HOPOPTS && opt->hopopt)
772 : 0 : tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
773 [ # # ][ # # ]: 0 : if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
774 : 0 : tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
775 [ # # ][ # # ]: 0 : if (newtype != IPV6_RTHDR && opt->srcrt)
776 : 0 : tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
777 [ # # ][ # # ]: 0 : if (newtype != IPV6_DSTOPTS && opt->dst1opt)
778 : 0 : tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
779 : : }
780 : :
781 [ # # ]: 0 : if (newopt && newoptlen)
782 : 0 : tot_len += CMSG_ALIGN(newoptlen);
783 : :
784 [ # # ]: 0 : if (!tot_len)
785 : : return NULL;
786 : :
787 : 0 : tot_len += sizeof(*opt2);
788 : 0 : opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
789 [ # # ]: 0 : if (!opt2)
790 : : return ERR_PTR(-ENOBUFS);
791 : :
792 [ # # ]: 0 : memset(opt2, 0, tot_len);
793 : :
794 : 0 : opt2->tot_len = tot_len;
795 : 0 : p = (char *)(opt2 + 1);
796 : :
797 [ # # ]: 0 : err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
798 : : newtype != IPV6_HOPOPTS,
799 : : &opt2->hopopt, &p);
800 [ # # ]: 0 : if (err)
801 : : goto out;
802 : :
803 [ # # ]: 0 : err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
804 : : newtype != IPV6_RTHDRDSTOPTS,
805 : : &opt2->dst0opt, &p);
806 [ # # ]: 0 : if (err)
807 : : goto out;
808 : :
809 [ # # ]: 0 : err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
810 : : newtype != IPV6_RTHDR,
811 : 0 : (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
812 [ # # ]: 0 : if (err)
813 : : goto out;
814 : :
815 [ # # ]: 0 : err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
816 : : newtype != IPV6_DSTOPTS,
817 : : &opt2->dst1opt, &p);
818 [ # # ]: 0 : if (err)
819 : : goto out;
820 : :
821 [ # # ][ # # ]: 0 : opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
[ # # ]
822 : 0 : (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
823 : 0 : (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
824 [ # # ]: 0 : opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
825 : :
826 : 0 : return opt2;
827 : : out:
828 : 0 : sock_kfree_s(sk, opt2, opt2->tot_len);
829 : 0 : return ERR_PTR(err);
830 : : }
831 : :
832 : 0 : struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
833 : : struct ipv6_txoptions *opt)
834 : : {
835 : : /*
836 : : * ignore the dest before srcrt unless srcrt is being included.
837 : : * --yoshfuji
838 : : */
839 [ # # ][ # # ]: 0 : if (opt && opt->dst0opt && !opt->srcrt) {
[ # # ]
840 [ # # ]: 0 : if (opt_space != opt) {
841 : 0 : memcpy(opt_space, opt, sizeof(*opt_space));
842 : : opt = opt_space;
843 : : }
844 : 0 : opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
845 : 0 : opt->dst0opt = NULL;
846 : : }
847 : :
848 : 0 : return opt;
849 : : }
850 : : EXPORT_SYMBOL_GPL(ipv6_fixup_options);
851 : :
852 : : /**
853 : : * fl6_update_dst - update flowi destination address with info given
854 : : * by srcrt option, if any.
855 : : *
856 : : * @fl6: flowi6 for which daddr is to be updated
857 : : * @opt: struct ipv6_txoptions in which to look for srcrt opt
858 : : * @orig: copy of original daddr address if modified
859 : : *
860 : : * Returns NULL if no txoptions or no srcrt, otherwise returns orig
861 : : * and initial value of fl6->daddr set in orig
862 : : */
863 : 0 : struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
864 : : const struct ipv6_txoptions *opt,
865 : : struct in6_addr *orig)
866 : : {
867 [ # # ][ # # ]: 0 : if (!opt || !opt->srcrt)
868 : : return NULL;
869 : :
870 : 0 : *orig = fl6->daddr;
871 : 0 : fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
872 : 0 : return orig;
873 : : }
874 : : EXPORT_SYMBOL_GPL(fl6_update_dst);
|