aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ipv6.h2
-rw-r--r--net/ipv6/datagram.c2
-rw-r--r--net/ipv6/exthdrs.c22
-rw-r--r--net/ipv6/ip6_flowlabel.c16
-rw-r--r--net/ipv6/raw.c4
-rw-r--r--net/ipv6/udp.c4
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);
240struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
241 struct ipv6_txoptions *opt);
240 242
241extern int ip6_frag_nqueues; 243extern int ip6_frag_nqueues;
242extern atomic_t ip6_frag_mem; 244extern 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;
670out: 671out:
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
676struct 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);