blob: 1bda0299890ee457555a6b82d5483d6b696be875 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18/* Changes:
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +090019 * yoshfuji : ensure not to overrun while parsing
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 * tlv options.
21 * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
22 * YOSHIFUJI Hideaki @USAGI Register inbound extension header
23 * handlers as inet6_protocol{}.
24 */
25
26#include <linux/errno.h>
27#include <linux/types.h>
28#include <linux/socket.h>
29#include <linux/sockios.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/net.h>
31#include <linux/netdevice.h>
32#include <linux/in6.h>
33#include <linux/icmpv6.h>
34
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>
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -070045#ifdef CONFIG_IPV6_MIP6
46#include <net/xfrm.h>
47#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#include <asm/uaccess.h>
50
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070051int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
52{
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -070053 const unsigned char *nh = skb_network_header(skb);
54 int packet_len = skb->tail - nh;
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070055 struct ipv6_opt_hdr *hdr;
56 int len;
57
58 if (offset + 2 > packet_len)
59 goto bad;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -070060 hdr = (struct ipv6_opt_hdr *)(nh + offset);
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070061 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) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -070070 int opttype = nh[offset];
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070071 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:
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -070081 optlen = nh[offset + 1] + 2;
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070082 if (optlen > len)
83 goto bad;
84 break;
85 }
86 offset += optlen;
87 len -= optlen;
88 }
89 /* not_found */
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070090 bad:
91 return -1;
92}
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094/*
95 * Parsing tlv encoded headers.
96 *
97 * Parsing function "func" returns 1, if parsing succeed
98 * and 0, if it failed.
99 * It MUST NOT touch skb->h.
100 */
101
102struct tlvtype_proc {
103 int type;
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700104 int (*func)(struct sk_buff **skbp, int offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105};
106
107/*********************
108 Generic functions
109 *********************/
110
111/* An unknown option is detected, decide what to do */
112
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700113static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700115 struct sk_buff *skb = *skbp;
116
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700117 switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 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 */
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700128 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 break;
130 case 2: /* send ICMP PARM PROB regardless and drop packet */
131 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
132 return 0;
133 };
134
135 kfree_skb(skb);
136 return 0;
137}
138
139/* Parse tlv encoded option header (hop-by-hop or destination) */
140
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700141static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700143 struct sk_buff *skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 struct tlvtype_proc *curr;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700145 const unsigned char *nh = skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int off = skb->h.raw - skb->nh.raw;
147 int len = ((skb->h.raw[1]+1)<<3);
148
Arnaldo Carvalho de Meloea2ae172007-04-25 17:55:53 -0700149 if (skb_transport_offset(skb) + len > skb_headlen(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 goto bad;
151
152 off += 2;
153 len -= 2;
154
155 while (len > 0) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700156 int optlen = nh[off + 1] + 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700158 switch (nh[off]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 case IPV6_TLV_PAD0:
160 optlen = 1;
161 break;
162
163 case IPV6_TLV_PADN:
164 break;
165
166 default: /* Other TLV code so scan list */
167 if (optlen > len)
168 goto bad;
169 for (curr=procs; curr->type >= 0; curr++) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700170 if (curr->type == nh[off]) {
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900171 /* type specific length/alignment
172 checks will be performed in the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 func(). */
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700174 if (curr->func(skbp, off) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 return 0;
176 break;
177 }
178 }
179 if (curr->type < 0) {
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700180 if (ip6_tlvopt_unknown(skbp, off) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return 0;
182 }
183 break;
184 }
185 off += optlen;
186 len -= optlen;
187 }
188 if (len == 0)
189 return 1;
190bad:
191 kfree_skb(skb);
192 return 0;
193}
194
195/*****************************
196 Destination options header.
197 *****************************/
198
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700199#ifdef CONFIG_IPV6_MIP6
200static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
201{
202 struct sk_buff *skb = *skbp;
203 struct ipv6_destopt_hao *hao;
204 struct inet6_skb_parm *opt = IP6CB(skb);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700205 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700206 struct in6_addr tmp_addr;
207 int ret;
208
209 if (opt->dsthao) {
210 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
211 goto discard;
212 }
213 opt->dsthao = opt->dst1;
214 opt->dst1 = 0;
215
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700216 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700217
218 if (hao->length != 16) {
219 LIMIT_NETDEBUG(
220 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
221 goto discard;
222 }
223
224 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
225 LIMIT_NETDEBUG(
226 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
227 goto discard;
228 }
229
230 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
231 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
232 if (unlikely(ret < 0))
233 goto discard;
234
235 if (skb_cloned(skb)) {
236 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
Masahide NAKAMURAdc435e62006-08-31 15:18:49 -0700237 struct inet6_skb_parm *opt2;
238
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700239 if (skb2 == NULL)
240 goto discard;
241
Masahide NAKAMURAdc435e62006-08-31 15:18:49 -0700242 opt2 = IP6CB(skb2);
243 memcpy(opt2, opt, sizeof(*opt2));
244
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700245 kfree_skb(skb);
246
247 /* update all variable using below by copied skbuff */
248 *skbp = skb = skb2;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700249 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb2) +
250 optoff);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700251 ipv6h = ipv6_hdr(skb2);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700252 }
253
254 if (skb->ip_summed == CHECKSUM_COMPLETE)
255 skb->ip_summed = CHECKSUM_NONE;
256
257 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
258 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
259 ipv6_addr_copy(&hao->addr, &tmp_addr);
260
Eric Dumazetb7aa0bf2007-04-19 16:16:32 -0700261 if (skb->tstamp.tv64 == 0)
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700262 __net_timestamp(skb);
263
264 return 1;
265
266 discard:
267 kfree_skb(skb);
268 return 0;
269}
270#endif
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272static struct tlvtype_proc tlvprocdestopt_lst[] = {
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700273#ifdef CONFIG_IPV6_MIP6
274 {
275 .type = IPV6_TLV_HAO,
276 .func = ipv6_dest_hao,
277 },
278#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 {-1, NULL}
280};
281
Patrick McHardy951dbc82006-01-06 23:02:34 -0800282static int ipv6_destopt_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
284 struct sk_buff *skb = *skbp;
285 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700286#ifdef CONFIG_IPV6_MIP6
287 __u16 dstbuf;
288#endif
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900289 struct dst_entry *dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Arnaldo Carvalho de Meloea2ae172007-04-25 17:55:53 -0700291 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
292 !pskb_may_pull(skb, (skb_transport_offset(skb) +
293 ((skb->h.raw[1] + 1) << 3)))) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900294 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
295 IPSTATS_MIB_INHDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 kfree_skb(skb);
297 return -1;
298 }
299
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900300 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 opt->dst1 = skb->h.raw - skb->nh.raw;
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700302#ifdef CONFIG_IPV6_MIP6
303 dstbuf = opt->dst1;
304#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900306 dst = dst_clone(skb->dst);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700307 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900308 dst_release(dst);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700309 skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 skb->h.raw += ((skb->h.raw[1]+1)<<3);
Masahide NAKAMURAdc435e62006-08-31 15:18:49 -0700311 opt = IP6CB(skb);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700312#ifdef CONFIG_IPV6_MIP6
313 opt->nhoff = dstbuf;
314#else
Patrick McHardy951dbc82006-01-06 23:02:34 -0800315 opt->nhoff = opt->dst1;
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700316#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 return 1;
318 }
319
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900320 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
321 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 return -1;
323}
324
325static struct inet6_protocol destopt_protocol = {
326 .handler = ipv6_destopt_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700327 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328};
329
330void __init ipv6_destopt_init(void)
331{
332 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
333 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
334}
335
336/********************************
337 NONE header. No data in packet.
338 ********************************/
339
Patrick McHardy951dbc82006-01-06 23:02:34 -0800340static int ipv6_nodata_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 struct sk_buff *skb = *skbp;
343
344 kfree_skb(skb);
345 return 0;
346}
347
348static struct inet6_protocol nodata_protocol = {
349 .handler = ipv6_nodata_rcv,
350 .flags = INET6_PROTO_NOPOLICY,
351};
352
353void __init ipv6_nodata_init(void)
354{
355 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
356 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
357}
358
359/********************************
360 Routing header.
361 ********************************/
362
Patrick McHardy951dbc82006-01-06 23:02:34 -0800363static int ipv6_rthdr_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 struct sk_buff *skb = *skbp;
366 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700367 struct in6_addr *addr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 struct in6_addr daddr;
YOSHIFUJI Hideaki0bcbc922007-04-24 14:58:30 -0700369 struct inet6_dev *idev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 int n, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 struct ipv6_rt_hdr *hdr;
372 struct rt0_hdr *rthdr;
YOSHIFUJI Hideaki0bcbc922007-04-24 14:58:30 -0700373 int accept_source_route = ipv6_devconf.accept_source_route;
374
375 if (accept_source_route < 0 ||
376 ((idev = in6_dev_get(skb->dev)) == NULL)) {
377 kfree_skb(skb);
378 return -1;
379 }
380 if (idev->cnf.accept_source_route < 0) {
381 in6_dev_put(idev);
382 kfree_skb(skb);
383 return -1;
384 }
385
386 if (accept_source_route > idev->cnf.accept_source_route)
387 accept_source_route = idev->cnf.accept_source_route;
388
389 in6_dev_put(idev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Arnaldo Carvalho de Meloea2ae172007-04-25 17:55:53 -0700391 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
392 !pskb_may_pull(skb, (skb_transport_offset(skb) +
393 ((skb->h.raw[1] + 1) << 3)))) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900394 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
395 IPSTATS_MIB_INHDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 kfree_skb(skb);
397 return -1;
398 }
399
400 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
401
YOSHIFUJI Hideaki0bcbc922007-04-24 14:58:30 -0700402 switch (hdr->type) {
403#ifdef CONFIG_IPV6_MIP6
404 break;
405#endif
406 case IPV6_SRCRT_TYPE_0:
YOSHIFUJI Hideakia23cf142007-04-25 11:13:49 +0900407 if (accept_source_route > 0)
YOSHIFUJI Hideaki0bcbc922007-04-24 14:58:30 -0700408 break;
409 kfree_skb(skb);
410 return -1;
411 default:
412 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
413 IPSTATS_MIB_INHDRERRORS);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700414 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
415 (&hdr->type) - skb_network_header(skb));
YOSHIFUJI Hideaki0bcbc922007-04-24 14:58:30 -0700416 return -1;
417 }
418
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700419 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 skb->pkt_type != PACKET_HOST) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900421 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
422 IPSTATS_MIB_INADDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 kfree_skb(skb);
424 return -1;
425 }
426
427looped_back:
428 if (hdr->segments_left == 0) {
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700429 switch (hdr->type) {
430#ifdef CONFIG_IPV6_MIP6
431 case IPV6_SRCRT_TYPE_2:
432 /* Silently discard type 2 header unless it was
433 * processed by own
434 */
435 if (!addr) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900436 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
437 IPSTATS_MIB_INADDRERRORS);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700438 kfree_skb(skb);
439 return -1;
440 }
441 break;
442#endif
443 default:
444 break;
445 }
446
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900447 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 opt->srcrt = skb->h.raw - skb->nh.raw;
449 skb->h.raw += (hdr->hdrlen + 1) << 3;
450 opt->dst0 = opt->dst1;
451 opt->dst1 = 0;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700452 opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 return 1;
454 }
455
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700456 switch (hdr->type) {
457 case IPV6_SRCRT_TYPE_0:
458 if (hdr->hdrlen & 0x01) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900459 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
460 IPSTATS_MIB_INHDRERRORS);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700461 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
462 ((&hdr->hdrlen) -
463 skb_network_header(skb)));
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700464 return -1;
465 }
466 break;
467#ifdef CONFIG_IPV6_MIP6
468 case IPV6_SRCRT_TYPE_2:
469 /* Silently discard invalid RTH type 2 */
470 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900471 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
472 IPSTATS_MIB_INHDRERRORS);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700473 kfree_skb(skb);
474 return -1;
475 }
476 break;
477#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 /*
481 * This is the routing header forwarding algorithm from
482 * RFC 2460, page 16.
483 */
484
485 n = hdr->hdrlen >> 1;
486
487 if (hdr->segments_left > n) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900488 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
489 IPSTATS_MIB_INHDRERRORS);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700490 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
491 ((&hdr->segments_left) -
492 skb_network_header(skb)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return -1;
494 }
495
496 /* We are about to mangle packet header. Be careful!
497 Do not damage packets queued somewhere.
498 */
499 if (skb_cloned(skb)) {
500 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 /* the copy is a forwarded packet */
502 if (skb2 == NULL) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900503 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
504 IPSTATS_MIB_OUTDISCARDS);
505 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 return -1;
507 }
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900508 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 *skbp = skb = skb2;
510 opt = IP6CB(skb2);
511 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
512 }
513
Patrick McHardy84fa7932006-08-29 16:44:56 -0700514 if (skb->ip_summed == CHECKSUM_COMPLETE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 skb->ip_summed = CHECKSUM_NONE;
516
517 i = n - --hdr->segments_left;
518
519 rthdr = (struct rt0_hdr *) hdr;
520 addr = rthdr->addr;
521 addr += i - 1;
522
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700523 switch (hdr->type) {
524#ifdef CONFIG_IPV6_MIP6
525 case IPV6_SRCRT_TYPE_2:
526 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700527 (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700528 IPPROTO_ROUTING) < 0) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900529 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
530 IPSTATS_MIB_INADDRERRORS);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700531 kfree_skb(skb);
532 return -1;
533 }
534 if (!ipv6_chk_home_addr(addr)) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900535 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
536 IPSTATS_MIB_INADDRERRORS);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700537 kfree_skb(skb);
538 return -1;
539 }
540 break;
541#endif
542 default:
543 break;
544 }
545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 if (ipv6_addr_is_multicast(addr)) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900547 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
548 IPSTATS_MIB_INADDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 kfree_skb(skb);
550 return -1;
551 }
552
553 ipv6_addr_copy(&daddr, addr);
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700554 ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);
555 ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 dst_release(xchg(&skb->dst, NULL));
558 ip6_route_input(skb);
559 if (skb->dst->error) {
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700560 skb_push(skb, skb->data - skb_network_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 dst_input(skb);
562 return -1;
563 }
564
565 if (skb->dst->dev->flags&IFF_LOOPBACK) {
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700566 if (ipv6_hdr(skb)->hop_limit <= 1) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900567 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
568 IPSTATS_MIB_INHDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
570 0, skb->dev);
571 kfree_skb(skb);
572 return -1;
573 }
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700574 ipv6_hdr(skb)->hop_limit--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 goto looped_back;
576 }
577
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700578 skb_push(skb, skb->data - skb_network_header(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 dst_input(skb);
580 return -1;
581}
582
583static struct inet6_protocol rthdr_protocol = {
584 .handler = ipv6_rthdr_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700585 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586};
587
588void __init ipv6_rthdr_init(void)
589{
590 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
591 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
592};
593
594/*
595 This function inverts received rthdr.
596 NOTE: specs allow to make it automatically only if
597 packet authenticated.
598
599 I will not discuss it here (though, I am really pissed off at
600 this stupid requirement making rthdr idea useless)
601
602 Actually, it creates severe problems for us.
603 Embryonic requests has no associated sockets,
604 so that user have no control over it and
605 cannot not only to set reply options, but
606 even to know, that someone wants to connect
607 without success. :-(
608
609 For now we need to test the engine, so that I created
610 temporary (or permanent) backdoor.
611 If listening socket set IPV6_RTHDR to 2, then we invert header.
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900612 --ANK (980729)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 */
614
615struct ipv6_txoptions *
616ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
617{
618 /* Received rthdr:
619
620 [ H1 -> H2 -> ... H_prev ] daddr=ME
621
622 Inverted result:
623 [ H_prev -> ... -> H1 ] daddr =sender
624
625 Note, that IP output engine will rewrite this rthdr
626 by rotating it left by one addr.
627 */
628
629 int n, i;
630 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
631 struct rt0_hdr *irthdr;
632 struct ipv6_txoptions *opt;
633 int hdrlen = ipv6_optlen(hdr);
634
635 if (hdr->segments_left ||
636 hdr->type != IPV6_SRCRT_TYPE_0 ||
637 hdr->hdrlen & 0x01)
638 return NULL;
639
640 n = hdr->hdrlen >> 1;
641 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
642 if (opt == NULL)
643 return NULL;
644 memset(opt, 0, sizeof(*opt));
645 opt->tot_len = sizeof(*opt) + hdrlen;
646 opt->srcrt = (void*)(opt+1);
647 opt->opt_nflen = hdrlen;
648
649 memcpy(opt->srcrt, hdr, sizeof(*hdr));
650 irthdr = (struct rt0_hdr*)opt->srcrt;
Brian Haleye6df4392005-09-10 00:15:06 -0700651 irthdr->reserved = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 opt->srcrt->segments_left = n;
653 for (i=0; i<n; i++)
654 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
655 return opt;
656}
657
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800658EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660/**********************************
661 Hop-by-hop options.
662 **********************************/
663
664/* Router Alert as of RFC 2711 */
665
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700666static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700668 struct sk_buff *skb = *skbp;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700669 const unsigned char *nh = skb_network_header(skb);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700670
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700671 if (nh[optoff + 1] == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 IP6CB(skb)->ra = optoff;
673 return 1;
674 }
Patrick McHardy64ce2072005-08-09 20:50:53 -0700675 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700676 nh[optoff + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 kfree_skb(skb);
678 return 0;
679}
680
681/* Jumbo payload */
682
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700683static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700685 struct sk_buff *skb = *skbp;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700686 const unsigned char *nh = skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 u32 pkt_len;
688
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700689 if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700690 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700691 nh[optoff+1]);
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900692 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
693 IPSTATS_MIB_INHDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 goto drop;
695 }
696
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700697 pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (pkt_len <= IPV6_MAXPLEN) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900699 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
701 return 0;
702 }
Arnaldo Carvalho de Melo0660e032007-04-25 17:54:47 -0700703 if (ipv6_hdr(skb)->payload_len) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900704 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
706 return 0;
707 }
708
709 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
YOSHIFUJI Hideakia11d2062006-11-04 20:11:37 +0900710 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 goto drop;
712 }
Stephen Hemminger42ca89c2005-09-08 12:57:43 -0700713
714 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
715 goto drop;
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 return 1;
718
719drop:
720 kfree_skb(skb);
721 return 0;
722}
723
724static struct tlvtype_proc tlvprochopopt_lst[] = {
725 {
726 .type = IPV6_TLV_ROUTERALERT,
727 .func = ipv6_hop_ra,
728 },
729 {
730 .type = IPV6_TLV_JUMBO,
731 .func = ipv6_hop_jumbo,
732 },
733 { -1, }
734};
735
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700736int ipv6_parse_hopopts(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700738 struct sk_buff *skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800739 struct inet6_skb_parm *opt = IP6CB(skb);
740
YOSHIFUJI Hideakiec670092006-04-18 14:46:26 -0700741 /*
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700742 * skb_network_header(skb) is equal to skb->data, and
YOSHIFUJI Hideakiec670092006-04-18 14:46:26 -0700743 * skb->h.raw - skb->nh.raw is always equal to
744 * sizeof(struct ipv6hdr) by definition of
745 * hop-by-hop options.
746 */
747 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
748 !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
749 kfree_skb(skb);
750 return -1;
751 }
752
Patrick McHardy951dbc82006-01-06 23:02:34 -0800753 opt->hop = sizeof(struct ipv6hdr);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700754 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
755 skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800756 skb->h.raw += (skb->h.raw[1]+1)<<3;
Masahide NAKAMURAdc435e62006-08-31 15:18:49 -0700757 opt = IP6CB(skb);
Patrick McHardy951dbc82006-01-06 23:02:34 -0800758 opt->nhoff = sizeof(struct ipv6hdr);
YOSHIFUJI Hideakib8097392006-04-18 14:48:45 -0700759 return 1;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return -1;
762}
763
764/*
765 * Creating outbound headers.
766 *
767 * "build" functions work when skb is filled from head to tail (datagram)
768 * "push" functions work when headers are added from tail to head (tcp)
769 *
770 * In both cases we assume, that caller reserved enough room
771 * for headers.
772 */
773
774static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
775 struct ipv6_rt_hdr *opt,
776 struct in6_addr **addr_p)
777{
778 struct rt0_hdr *phdr, *ihdr;
779 int hops;
780
781 ihdr = (struct rt0_hdr *) opt;
YOSHIFUJI Hideaki1ab14572007-02-09 23:24:49 +0900782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
784 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
785
786 hops = ihdr->rt_hdr.hdrlen >> 1;
787
788 if (hops > 1)
789 memcpy(phdr->addr, ihdr->addr + 1,
790 (hops - 1) * sizeof(struct in6_addr));
791
792 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
793 *addr_p = ihdr->addr;
794
795 phdr->rt_hdr.nexthdr = *proto;
796 *proto = NEXTHDR_ROUTING;
797}
798
799static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
800{
801 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
802
803 memcpy(h, opt, ipv6_optlen(opt));
804 h->nexthdr = *proto;
805 *proto = type;
806}
807
808void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
809 u8 *proto,
810 struct in6_addr **daddr)
811{
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900812 if (opt->srcrt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900814 /*
815 * IPV6_RTHDRDSTOPTS is ignored
816 * unless IPV6_RTHDR is set (RFC3542).
817 */
818 if (opt->dst0opt)
819 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 if (opt->hopopt)
822 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
823}
824
YOSHIFUJI Hideaki71590392007-02-22 22:05:40 +0900825EXPORT_SYMBOL(ipv6_push_nfrag_opts);
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
828{
829 if (opt->dst1opt)
830 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
831}
832
833struct ipv6_txoptions *
834ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
835{
836 struct ipv6_txoptions *opt2;
837
838 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
839 if (opt2) {
840 long dif = (char*)opt2 - (char*)opt;
841 memcpy(opt2, opt, opt->tot_len);
842 if (opt2->hopopt)
843 *((char**)&opt2->hopopt) += dif;
844 if (opt2->dst0opt)
845 *((char**)&opt2->dst0opt) += dif;
846 if (opt2->dst1opt)
847 *((char**)&opt2->dst1opt) += dif;
848 if (opt2->srcrt)
849 *((char**)&opt2->srcrt) += dif;
850 }
851 return opt2;
852}
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900853
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800854EXPORT_SYMBOL_GPL(ipv6_dup_options);
855
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900856static int ipv6_renew_option(void *ohdr,
857 struct ipv6_opt_hdr __user *newopt, int newoptlen,
858 int inherit,
859 struct ipv6_opt_hdr **hdr,
860 char **p)
861{
862 if (inherit) {
863 if (ohdr) {
864 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
865 *hdr = (struct ipv6_opt_hdr *)*p;
866 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
867 }
868 } else {
869 if (newopt) {
870 if (copy_from_user(*p, newopt, newoptlen))
871 return -EFAULT;
872 *hdr = (struct ipv6_opt_hdr *)*p;
873 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
874 return -EINVAL;
875 *p += CMSG_ALIGN(newoptlen);
876 }
877 }
878 return 0;
879}
880
881struct ipv6_txoptions *
882ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
883 int newtype,
884 struct ipv6_opt_hdr __user *newopt, int newoptlen)
885{
886 int tot_len = 0;
887 char *p;
888 struct ipv6_txoptions *opt2;
889 int err;
890
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700891 if (opt) {
892 if (newtype != IPV6_HOPOPTS && opt->hopopt)
893 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
894 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
895 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
896 if (newtype != IPV6_RTHDR && opt->srcrt)
897 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
898 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
899 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
900 }
901
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900902 if (newopt && newoptlen)
903 tot_len += CMSG_ALIGN(newoptlen);
904
905 if (!tot_len)
906 return NULL;
907
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900908 tot_len += sizeof(*opt2);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900909 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
910 if (!opt2)
911 return ERR_PTR(-ENOBUFS);
912
913 memset(opt2, 0, tot_len);
914
915 opt2->tot_len = tot_len;
916 p = (char *)(opt2 + 1);
917
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700918 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900919 newtype != IPV6_HOPOPTS,
920 &opt2->hopopt, &p);
921 if (err)
922 goto out;
923
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700924 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900925 newtype != IPV6_RTHDRDSTOPTS,
926 &opt2->dst0opt, &p);
927 if (err)
928 goto out;
929
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700930 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900931 newtype != IPV6_RTHDR,
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700932 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900933 if (err)
934 goto out;
935
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700936 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900937 newtype != IPV6_DSTOPTS,
938 &opt2->dst1opt, &p);
939 if (err)
940 goto out;
941
942 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
943 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
944 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
945 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
946
947 return opt2;
948out:
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900949 sock_kfree_s(sk, opt2, opt2->tot_len);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900950 return ERR_PTR(err);
951}
952
YOSHIFUJI Hideakidf9890c2005-11-20 12:23:18 +0900953struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
954 struct ipv6_txoptions *opt)
955{
956 /*
957 * ignore the dest before srcrt unless srcrt is being included.
958 * --yoshfuji
959 */
960 if (opt && opt->dst0opt && !opt->srcrt) {
961 if (opt_space != opt) {
962 memcpy(opt_space, opt, sizeof(*opt_space));
963 opt = opt_space;
964 }
965 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
966 opt->dst0opt = NULL;
967 }
968
969 return opt;
970}
971