diff options
-rw-r--r-- | include/net/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 2 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 22 | ||||
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 16 | ||||
-rw-r--r-- | net/ipv6/raw.c | 4 | ||||
-rw-r--r-- | net/ipv6/udp.c | 4 |
6 files changed, 36 insertions, 14 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 6addb4d464d6..0a2ad51cff82 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -237,6 +237,8 @@ extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_t | |||
237 | int newtype, | 237 | int newtype, |
238 | struct ipv6_opt_hdr __user *newopt, | 238 | struct ipv6_opt_hdr __user *newopt, |
239 | int newoptlen); | 239 | int newoptlen); |
240 | struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, | ||
241 | struct ipv6_txoptions *opt); | ||
240 | 242 | ||
241 | extern int ip6_frag_nqueues; | 243 | extern int ip6_frag_nqueues; |
242 | extern atomic_t ip6_frag_mem; | 244 | extern atomic_t ip6_frag_mem; |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index cc518405b3e1..c4a3a993acb7 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -437,7 +437,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
437 | break; | 437 | break; |
438 | case IPPROTO_AH: | 438 | case IPPROTO_AH: |
439 | nexthdr = ptr[0]; | 439 | nexthdr = ptr[0]; |
440 | len = (ptr[1] + 1) << 2; | 440 | len = (ptr[1] + 2) << 2; |
441 | break; | 441 | break; |
442 | default: | 442 | default: |
443 | nexthdr = ptr[0]; | 443 | nexthdr = ptr[0]; |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 922549581abc..be6faf311387 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -628,6 +628,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | |||
628 | if (!tot_len) | 628 | if (!tot_len) |
629 | return NULL; | 629 | return NULL; |
630 | 630 | ||
631 | tot_len += sizeof(*opt2); | ||
631 | opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC); | 632 | opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC); |
632 | if (!opt2) | 633 | if (!opt2) |
633 | return ERR_PTR(-ENOBUFS); | 634 | return ERR_PTR(-ENOBUFS); |
@@ -668,7 +669,26 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | |||
668 | 669 | ||
669 | return opt2; | 670 | return opt2; |
670 | out: | 671 | out: |
671 | sock_kfree_s(sk, p, tot_len); | 672 | sock_kfree_s(sk, opt2, opt2->tot_len); |
672 | return ERR_PTR(err); | 673 | return ERR_PTR(err); |
673 | } | 674 | } |
674 | 675 | ||
676 | struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, | ||
677 | struct ipv6_txoptions *opt) | ||
678 | { | ||
679 | /* | ||
680 | * ignore the dest before srcrt unless srcrt is being included. | ||
681 | * --yoshfuji | ||
682 | */ | ||
683 | if (opt && opt->dst0opt && !opt->srcrt) { | ||
684 | if (opt_space != opt) { | ||
685 | memcpy(opt_space, opt, sizeof(*opt_space)); | ||
686 | opt = opt_space; | ||
687 | } | ||
688 | opt->opt_nflen -= ipv6_optlen(opt->dst0opt); | ||
689 | opt->dst0opt = NULL; | ||
690 | } | ||
691 | |||
692 | return opt; | ||
693 | } | ||
694 | |||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index bbbe80cdaf72..1cf02765fb5c 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -225,20 +225,16 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, | |||
225 | struct ip6_flowlabel * fl, | 225 | struct ip6_flowlabel * fl, |
226 | struct ipv6_txoptions * fopt) | 226 | struct ipv6_txoptions * fopt) |
227 | { | 227 | { |
228 | struct ipv6_txoptions * fl_opt = fl ? fl->opt : NULL; | 228 | struct ipv6_txoptions * fl_opt = fl->opt; |
229 | 229 | ||
230 | if (fopt == NULL || fopt->opt_flen == 0) { | 230 | if (fopt == NULL || fopt->opt_flen == 0) |
231 | if (!fl_opt || !fl_opt->dst0opt || fl_opt->srcrt) | 231 | return fl_opt; |
232 | return fl_opt; | 232 | |
233 | } | ||
234 | |||
235 | if (fl_opt != NULL) { | 233 | if (fl_opt != NULL) { |
236 | opt_space->hopopt = fl_opt->hopopt; | 234 | opt_space->hopopt = fl_opt->hopopt; |
237 | opt_space->dst0opt = fl_opt->srcrt ? fl_opt->dst0opt : NULL; | 235 | opt_space->dst0opt = fl_opt->dst0opt; |
238 | opt_space->srcrt = fl_opt->srcrt; | 236 | opt_space->srcrt = fl_opt->srcrt; |
239 | opt_space->opt_nflen = fl_opt->opt_nflen; | 237 | opt_space->opt_nflen = fl_opt->opt_nflen; |
240 | if (fl_opt->dst0opt && !fl_opt->srcrt) | ||
241 | opt_space->opt_nflen -= ipv6_optlen(fl_opt->dst0opt); | ||
242 | } else { | 238 | } else { |
243 | if (fopt->opt_nflen == 0) | 239 | if (fopt->opt_nflen == 0) |
244 | return fopt; | 240 | return fopt; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 8e9628f1c4c5..a66900cda2af 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -748,7 +748,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
748 | } | 748 | } |
749 | if (opt == NULL) | 749 | if (opt == NULL) |
750 | opt = np->opt; | 750 | opt = np->opt; |
751 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 751 | if (flowlabel) |
752 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | ||
753 | opt = ipv6_fixup_options(&opt_space, opt); | ||
752 | 754 | ||
753 | fl.proto = proto; | 755 | fl.proto = proto; |
754 | rawv6_probe_proto_opt(&fl, msg); | 756 | rawv6_probe_proto_opt(&fl, msg); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index e671153b47b2..5cc8731eb55b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -771,7 +771,9 @@ do_udp_sendmsg: | |||
771 | } | 771 | } |
772 | if (opt == NULL) | 772 | if (opt == NULL) |
773 | opt = np->opt; | 773 | opt = np->opt; |
774 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 774 | if (flowlabel) |
775 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | ||
776 | opt = ipv6_fixup_options(&opt_space, opt); | ||
775 | 777 | ||
776 | fl->proto = IPPROTO_UDP; | 778 | fl->proto = IPPROTO_UDP; |
777 | ipv6_addr_copy(&fl->fl6_dst, daddr); | 779 | ipv6_addr_copy(&fl->fl6_dst, daddr); |