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