diff options
| author | Jeff Garzik <jgarzik@pobox.com> | 2005-09-14 08:19:08 -0400 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-14 08:19:08 -0400 |
| commit | 905ec87e93bc9e01b15c60035cd6a50c636cbaef (patch) | |
| tree | 46fd7618d6511611ffc19eb0dd4d7bc6b90a41c2 /net/ipv6/ipv6_sockglue.c | |
| parent | 1d6ae775d7a948c9575658eb41184fd2e506c0df (diff) | |
| parent | 2f4ba45a75d6383b4a1201169a808ffea416ffa0 (diff) | |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 186 |
1 files changed, 174 insertions, 12 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 76466af8331e..8567873d0dd8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -210,39 +210,139 @@ 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 | |||
| 267 | case IPV6_TCLASS: | ||
| 268 | if (val < 0 || val > 0xff) | ||
| 269 | goto e_inval; | ||
| 270 | np->tclass = val; | ||
| 271 | retv = 0; | ||
| 272 | break; | ||
| 273 | |||
| 274 | case IPV6_RECVTCLASS: | ||
| 275 | np->rxopt.bits.rxtclass = valbool; | ||
| 276 | retv = 0; | ||
| 277 | break; | ||
| 278 | |||
| 240 | case IPV6_FLOWINFO: | 279 | case IPV6_FLOWINFO: |
| 241 | np->rxopt.bits.rxflow = valbool; | 280 | np->rxopt.bits.rxflow = valbool; |
| 242 | retv = 0; | 281 | retv = 0; |
| 243 | break; | 282 | break; |
| 244 | 283 | ||
| 245 | case IPV6_PKTOPTIONS: | 284 | case IPV6_HOPOPTS: |
| 285 | case IPV6_RTHDRDSTOPTS: | ||
| 286 | case IPV6_RTHDR: | ||
| 287 | case IPV6_DSTOPTS: | ||
| 288 | { | ||
| 289 | struct ipv6_txoptions *opt; | ||
| 290 | if (optlen == 0) | ||
| 291 | optval = 0; | ||
| 292 | |||
| 293 | /* hop-by-hop / destination options are privileged option */ | ||
| 294 | retv = -EPERM; | ||
| 295 | if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) | ||
| 296 | break; | ||
| 297 | |||
| 298 | retv = -EINVAL; | ||
| 299 | if (optlen & 0x7 || optlen > 8 * 255) | ||
| 300 | break; | ||
| 301 | |||
| 302 | opt = ipv6_renew_options(sk, np->opt, optname, | ||
| 303 | (struct ipv6_opt_hdr __user *)optval, | ||
| 304 | optlen); | ||
| 305 | if (IS_ERR(opt)) { | ||
| 306 | retv = PTR_ERR(opt); | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* routing header option needs extra check */ | ||
| 311 | if (optname == IPV6_RTHDR && opt->srcrt) { | ||
| 312 | struct ipv6_rt_hdr *rthdr = opt->srcrt; | ||
| 313 | if (rthdr->type) | ||
| 314 | goto sticky_done; | ||
| 315 | if ((rthdr->hdrlen & 1) || | ||
| 316 | (rthdr->hdrlen >> 1) != rthdr->segments_left) | ||
| 317 | goto sticky_done; | ||
| 318 | } | ||
| 319 | |||
| 320 | retv = 0; | ||
| 321 | if (sk->sk_type == SOCK_STREAM) { | ||
| 322 | if (opt) { | ||
| 323 | struct tcp_sock *tp = tcp_sk(sk); | ||
| 324 | if (!((1 << sk->sk_state) & | ||
| 325 | (TCPF_LISTEN | TCPF_CLOSE)) | ||
| 326 | && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { | ||
| 327 | tp->ext_header_len = opt->opt_flen + opt->opt_nflen; | ||
| 328 | tcp_sync_mss(sk, tp->pmtu_cookie); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | opt = xchg(&np->opt, opt); | ||
| 332 | sk_dst_reset(sk); | ||
| 333 | } else { | ||
| 334 | write_lock(&sk->sk_dst_lock); | ||
| 335 | opt = xchg(&np->opt, opt); | ||
| 336 | write_unlock(&sk->sk_dst_lock); | ||
| 337 | sk_dst_reset(sk); | ||
| 338 | } | ||
| 339 | sticky_done: | ||
| 340 | if (opt) | ||
| 341 | sock_kfree_s(sk, opt, opt->tot_len); | ||
| 342 | break; | ||
| 343 | } | ||
| 344 | |||
| 345 | case IPV6_2292PKTOPTIONS: | ||
| 246 | { | 346 | { |
| 247 | struct ipv6_txoptions *opt = NULL; | 347 | struct ipv6_txoptions *opt = NULL; |
| 248 | struct msghdr msg; | 348 | struct msghdr msg; |
| @@ -276,7 +376,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 276 | msg.msg_controllen = optlen; | 376 | msg.msg_controllen = optlen; |
| 277 | msg.msg_control = (void*)(opt+1); | 377 | msg.msg_control = (void*)(opt+1); |
| 278 | 378 | ||
| 279 | retv = datagram_send_ctl(&msg, &fl, opt, &junk); | 379 | retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk); |
| 280 | if (retv) | 380 | if (retv) |
| 281 | goto done; | 381 | goto done; |
| 282 | update: | 382 | update: |
| @@ -529,6 +629,17 @@ e_inval: | |||
| 529 | return -EINVAL; | 629 | return -EINVAL; |
| 530 | } | 630 | } |
| 531 | 631 | ||
| 632 | int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | ||
| 633 | char __user *optval, int len) | ||
| 634 | { | ||
| 635 | if (!hdr) | ||
| 636 | return 0; | ||
| 637 | len = min_t(int, len, ipv6_optlen(hdr)); | ||
| 638 | if (copy_to_user(optval, hdr, ipv6_optlen(hdr))) | ||
| 639 | return -EFAULT; | ||
| 640 | return len; | ||
| 641 | } | ||
| 642 | |||
| 532 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | 643 | int ipv6_getsockopt(struct sock *sk, int level, int optname, |
| 533 | char __user *optval, int __user *optlen) | 644 | char __user *optval, int __user *optlen) |
| 534 | { | 645 | { |
| @@ -567,7 +678,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 567 | return err; | 678 | return err; |
| 568 | } | 679 | } |
| 569 | 680 | ||
| 570 | case IPV6_PKTOPTIONS: | 681 | case IPV6_2292PKTOPTIONS: |
| 571 | { | 682 | { |
| 572 | struct msghdr msg; | 683 | struct msghdr msg; |
| 573 | struct sk_buff *skb; | 684 | struct sk_buff *skb; |
| @@ -601,6 +712,16 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 601 | int hlim = np->mcast_hops; | 712 | int hlim = np->mcast_hops; |
| 602 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); | 713 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); |
| 603 | } | 714 | } |
| 715 | if (np->rxopt.bits.rxoinfo) { | ||
| 716 | struct in6_pktinfo src_info; | ||
| 717 | src_info.ipi6_ifindex = np->mcast_oif; | ||
| 718 | ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); | ||
| 719 | put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); | ||
| 720 | } | ||
| 721 | if (np->rxopt.bits.rxohlim) { | ||
| 722 | int hlim = np->mcast_hops; | ||
| 723 | put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); | ||
| 724 | } | ||
| 604 | } | 725 | } |
| 605 | len -= msg.msg_controllen; | 726 | len -= msg.msg_controllen; |
| 606 | return put_user(len, optlen); | 727 | return put_user(len, optlen); |
| @@ -625,26 +746,67 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 625 | val = np->ipv6only; | 746 | val = np->ipv6only; |
| 626 | break; | 747 | break; |
| 627 | 748 | ||
| 628 | case IPV6_PKTINFO: | 749 | case IPV6_RECVPKTINFO: |
| 629 | val = np->rxopt.bits.rxinfo; | 750 | val = np->rxopt.bits.rxinfo; |
| 630 | break; | 751 | break; |
| 631 | 752 | ||
| 632 | case IPV6_HOPLIMIT: | 753 | case IPV6_2292PKTINFO: |
| 754 | val = np->rxopt.bits.rxoinfo; | ||
| 755 | break; | ||
| 756 | |||
| 757 | case IPV6_RECVHOPLIMIT: | ||
| 633 | val = np->rxopt.bits.rxhlim; | 758 | val = np->rxopt.bits.rxhlim; |
| 634 | break; | 759 | break; |
| 635 | 760 | ||
| 636 | case IPV6_RTHDR: | 761 | case IPV6_2292HOPLIMIT: |
| 762 | val = np->rxopt.bits.rxohlim; | ||
| 763 | break; | ||
| 764 | |||
| 765 | case IPV6_RECVRTHDR: | ||
| 637 | val = np->rxopt.bits.srcrt; | 766 | val = np->rxopt.bits.srcrt; |
| 638 | break; | 767 | break; |
| 639 | 768 | ||
| 769 | case IPV6_2292RTHDR: | ||
| 770 | val = np->rxopt.bits.osrcrt; | ||
| 771 | break; | ||
| 772 | |||
| 640 | case IPV6_HOPOPTS: | 773 | case IPV6_HOPOPTS: |
| 774 | case IPV6_RTHDRDSTOPTS: | ||
| 775 | case IPV6_RTHDR: | ||
| 776 | case IPV6_DSTOPTS: | ||
| 777 | { | ||
| 778 | |||
| 779 | lock_sock(sk); | ||
| 780 | len = ipv6_getsockopt_sticky(sk, np->opt->hopopt, | ||
| 781 | optval, len); | ||
| 782 | release_sock(sk); | ||
| 783 | return put_user(len, optlen); | ||
| 784 | } | ||
| 785 | |||
| 786 | case IPV6_RECVHOPOPTS: | ||
| 641 | val = np->rxopt.bits.hopopts; | 787 | val = np->rxopt.bits.hopopts; |
| 642 | break; | 788 | break; |
| 643 | 789 | ||
| 644 | case IPV6_DSTOPTS: | 790 | case IPV6_2292HOPOPTS: |
| 791 | val = np->rxopt.bits.ohopopts; | ||
| 792 | break; | ||
| 793 | |||
| 794 | case IPV6_RECVDSTOPTS: | ||
| 645 | val = np->rxopt.bits.dstopts; | 795 | val = np->rxopt.bits.dstopts; |
| 646 | break; | 796 | break; |
| 647 | 797 | ||
| 798 | case IPV6_2292DSTOPTS: | ||
| 799 | val = np->rxopt.bits.odstopts; | ||
| 800 | break; | ||
| 801 | |||
| 802 | case IPV6_TCLASS: | ||
| 803 | val = np->tclass; | ||
| 804 | break; | ||
| 805 | |||
| 806 | case IPV6_RECVTCLASS: | ||
| 807 | val = np->rxopt.bits.rxtclass; | ||
| 808 | break; | ||
| 809 | |||
| 648 | case IPV6_FLOWINFO: | 810 | case IPV6_FLOWINFO: |
| 649 | val = np->rxopt.bits.rxflow; | 811 | val = np->rxopt.bits.rxflow; |
| 650 | break; | 812 | break; |
