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