diff options
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 164 |
1 files changed, 153 insertions, 11 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 76466af8331e..dc1d9914bf7d 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -210,39 +210,127 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
210 | retv = 0; | 210 | retv = 0; |
211 | break; | 211 | break; |
212 | 212 | ||
213 | case IPV6_PKTINFO: | 213 | case IPV6_RECVPKTINFO: |
214 | np->rxopt.bits.rxinfo = valbool; | 214 | np->rxopt.bits.rxinfo = valbool; |
215 | retv = 0; | 215 | retv = 0; |
216 | break; | 216 | break; |
217 | |||
218 | case IPV6_2292PKTINFO: | ||
219 | np->rxopt.bits.rxoinfo = valbool; | ||
220 | retv = 0; | ||
221 | break; | ||
217 | 222 | ||
218 | case IPV6_HOPLIMIT: | 223 | case IPV6_RECVHOPLIMIT: |
219 | np->rxopt.bits.rxhlim = valbool; | 224 | np->rxopt.bits.rxhlim = valbool; |
220 | retv = 0; | 225 | retv = 0; |
221 | break; | 226 | break; |
222 | 227 | ||
223 | case IPV6_RTHDR: | 228 | case IPV6_2292HOPLIMIT: |
229 | np->rxopt.bits.rxohlim = valbool; | ||
230 | retv = 0; | ||
231 | break; | ||
232 | |||
233 | case IPV6_RECVRTHDR: | ||
224 | if (val < 0 || val > 2) | 234 | if (val < 0 || val > 2) |
225 | goto e_inval; | 235 | goto e_inval; |
226 | np->rxopt.bits.srcrt = val; | 236 | np->rxopt.bits.srcrt = val; |
227 | retv = 0; | 237 | retv = 0; |
228 | break; | 238 | break; |
229 | 239 | ||
230 | case IPV6_HOPOPTS: | 240 | case IPV6_2292RTHDR: |
241 | if (val < 0 || val > 2) | ||
242 | goto e_inval; | ||
243 | np->rxopt.bits.osrcrt = val; | ||
244 | retv = 0; | ||
245 | break; | ||
246 | |||
247 | case IPV6_RECVHOPOPTS: | ||
231 | np->rxopt.bits.hopopts = valbool; | 248 | np->rxopt.bits.hopopts = valbool; |
232 | retv = 0; | 249 | retv = 0; |
233 | break; | 250 | break; |
234 | 251 | ||
235 | case IPV6_DSTOPTS: | 252 | case IPV6_2292HOPOPTS: |
253 | np->rxopt.bits.ohopopts = valbool; | ||
254 | retv = 0; | ||
255 | break; | ||
256 | |||
257 | case IPV6_RECVDSTOPTS: | ||
236 | np->rxopt.bits.dstopts = valbool; | 258 | np->rxopt.bits.dstopts = valbool; |
237 | retv = 0; | 259 | retv = 0; |
238 | break; | 260 | break; |
239 | 261 | ||
262 | case IPV6_2292DSTOPTS: | ||
263 | np->rxopt.bits.odstopts = valbool; | ||
264 | retv = 0; | ||
265 | break; | ||
266 | |||
240 | case IPV6_FLOWINFO: | 267 | case IPV6_FLOWINFO: |
241 | np->rxopt.bits.rxflow = valbool; | 268 | np->rxopt.bits.rxflow = valbool; |
242 | retv = 0; | 269 | retv = 0; |
243 | break; | 270 | break; |
244 | 271 | ||
245 | case IPV6_PKTOPTIONS: | 272 | case IPV6_HOPOPTS: |
273 | case IPV6_RTHDRDSTOPTS: | ||
274 | case IPV6_RTHDR: | ||
275 | case IPV6_DSTOPTS: | ||
276 | { | ||
277 | struct ipv6_txoptions *opt; | ||
278 | if (optlen == 0) | ||
279 | optval = 0; | ||
280 | |||
281 | /* hop-by-hop / destination options are privileged option */ | ||
282 | retv = -EPERM; | ||
283 | if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) | ||
284 | break; | ||
285 | |||
286 | retv = -EINVAL; | ||
287 | if (optlen & 0x7 || optlen > 8 * 255) | ||
288 | break; | ||
289 | |||
290 | opt = ipv6_renew_options(sk, np->opt, optname, | ||
291 | (struct ipv6_opt_hdr __user *)optval, | ||
292 | optlen); | ||
293 | if (IS_ERR(opt)) { | ||
294 | retv = PTR_ERR(opt); | ||
295 | break; | ||
296 | } | ||
297 | |||
298 | /* routing header option needs extra check */ | ||
299 | if (optname == IPV6_RTHDR && opt->srcrt) { | ||
300 | struct ipv6_rt_hdr *rthdr = opt->srcrt; | ||
301 | if (rthdr->type) | ||
302 | goto sticky_done; | ||
303 | if ((rthdr->hdrlen & 1) || | ||
304 | (rthdr->hdrlen >> 1) != rthdr->segments_left) | ||
305 | goto sticky_done; | ||
306 | } | ||
307 | |||
308 | retv = 0; | ||
309 | if (sk->sk_type == SOCK_STREAM) { | ||
310 | if (opt) { | ||
311 | struct tcp_sock *tp = tcp_sk(sk); | ||
312 | if (!((1 << sk->sk_state) & | ||
313 | (TCPF_LISTEN | TCPF_CLOSE)) | ||
314 | && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { | ||
315 | tp->ext_header_len = opt->opt_flen + opt->opt_nflen; | ||
316 | tcp_sync_mss(sk, tp->pmtu_cookie); | ||
317 | } | ||
318 | } | ||
319 | opt = xchg(&np->opt, opt); | ||
320 | sk_dst_reset(sk); | ||
321 | } else { | ||
322 | write_lock(&sk->sk_dst_lock); | ||
323 | opt = xchg(&np->opt, opt); | ||
324 | write_unlock(&sk->sk_dst_lock); | ||
325 | sk_dst_reset(sk); | ||
326 | } | ||
327 | sticky_done: | ||
328 | if (opt) | ||
329 | sock_kfree_s(sk, opt, opt->tot_len); | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | case IPV6_2292PKTOPTIONS: | ||
246 | { | 334 | { |
247 | struct ipv6_txoptions *opt = NULL; | 335 | struct ipv6_txoptions *opt = NULL; |
248 | struct msghdr msg; | 336 | struct msghdr msg; |
@@ -529,6 +617,17 @@ e_inval: | |||
529 | return -EINVAL; | 617 | return -EINVAL; |
530 | } | 618 | } |
531 | 619 | ||
620 | int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | ||
621 | char __user *optval, int len) | ||
622 | { | ||
623 | if (!hdr) | ||
624 | return 0; | ||
625 | len = min_t(int, len, ipv6_optlen(hdr)); | ||
626 | if (copy_to_user(optval, hdr, ipv6_optlen(hdr))) | ||
627 | return -EFAULT; | ||
628 | return len; | ||
629 | } | ||
630 | |||
532 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | 631 | int ipv6_getsockopt(struct sock *sk, int level, int optname, |
533 | char __user *optval, int __user *optlen) | 632 | char __user *optval, int __user *optlen) |
534 | { | 633 | { |
@@ -567,7 +666,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
567 | return err; | 666 | return err; |
568 | } | 667 | } |
569 | 668 | ||
570 | case IPV6_PKTOPTIONS: | 669 | case IPV6_2292PKTOPTIONS: |
571 | { | 670 | { |
572 | struct msghdr msg; | 671 | struct msghdr msg; |
573 | struct sk_buff *skb; | 672 | struct sk_buff *skb; |
@@ -601,6 +700,16 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
601 | int hlim = np->mcast_hops; | 700 | int hlim = np->mcast_hops; |
602 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); | 701 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); |
603 | } | 702 | } |
703 | if (np->rxopt.bits.rxoinfo) { | ||
704 | struct in6_pktinfo src_info; | ||
705 | src_info.ipi6_ifindex = np->mcast_oif; | ||
706 | ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); | ||
707 | put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); | ||
708 | } | ||
709 | if (np->rxopt.bits.rxohlim) { | ||
710 | int hlim = np->mcast_hops; | ||
711 | put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); | ||
712 | } | ||
604 | } | 713 | } |
605 | len -= msg.msg_controllen; | 714 | len -= msg.msg_controllen; |
606 | return put_user(len, optlen); | 715 | return put_user(len, optlen); |
@@ -625,26 +734,59 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
625 | val = np->ipv6only; | 734 | val = np->ipv6only; |
626 | break; | 735 | break; |
627 | 736 | ||
628 | case IPV6_PKTINFO: | 737 | case IPV6_RECVPKTINFO: |
629 | val = np->rxopt.bits.rxinfo; | 738 | val = np->rxopt.bits.rxinfo; |
630 | break; | 739 | break; |
631 | 740 | ||
632 | case IPV6_HOPLIMIT: | 741 | case IPV6_2292PKTINFO: |
742 | val = np->rxopt.bits.rxoinfo; | ||
743 | break; | ||
744 | |||
745 | case IPV6_RECVHOPLIMIT: | ||
633 | val = np->rxopt.bits.rxhlim; | 746 | val = np->rxopt.bits.rxhlim; |
634 | break; | 747 | break; |
635 | 748 | ||
636 | case IPV6_RTHDR: | 749 | case IPV6_2292HOPLIMIT: |
750 | val = np->rxopt.bits.rxohlim; | ||
751 | break; | ||
752 | |||
753 | case IPV6_RECVRTHDR: | ||
637 | val = np->rxopt.bits.srcrt; | 754 | val = np->rxopt.bits.srcrt; |
638 | break; | 755 | break; |
639 | 756 | ||
757 | case IPV6_2292RTHDR: | ||
758 | val = np->rxopt.bits.osrcrt; | ||
759 | break; | ||
760 | |||
640 | case IPV6_HOPOPTS: | 761 | case IPV6_HOPOPTS: |
762 | case IPV6_RTHDRDSTOPTS: | ||
763 | case IPV6_RTHDR: | ||
764 | case IPV6_DSTOPTS: | ||
765 | { | ||
766 | |||
767 | lock_sock(sk); | ||
768 | len = ipv6_getsockopt_sticky(sk, np->opt->hopopt, | ||
769 | optval, len); | ||
770 | release_sock(sk); | ||
771 | return put_user(len, optlen); | ||
772 | } | ||
773 | |||
774 | case IPV6_RECVHOPOPTS: | ||
641 | val = np->rxopt.bits.hopopts; | 775 | val = np->rxopt.bits.hopopts; |
642 | break; | 776 | break; |
643 | 777 | ||
644 | case IPV6_DSTOPTS: | 778 | case IPV6_2292HOPOPTS: |
779 | val = np->rxopt.bits.ohopopts; | ||
780 | break; | ||
781 | |||
782 | case IPV6_RECVDSTOPTS: | ||
645 | val = np->rxopt.bits.dstopts; | 783 | val = np->rxopt.bits.dstopts; |
646 | break; | 784 | break; |
647 | 785 | ||
786 | case IPV6_2292DSTOPTS: | ||
787 | val = np->rxopt.bits.odstopts; | ||
788 | break; | ||
789 | |||
648 | case IPV6_FLOWINFO: | 790 | case IPV6_FLOWINFO: |
649 | val = np->rxopt.bits.rxflow; | 791 | val = np->rxopt.bits.rxflow; |
650 | break; | 792 | break; |