ipv6_sockglue.c (01b944fe1cd4e21a2a9ed51adbdbafe2d5e905ba) | ipv6_sockglue.c (45f6fad84cc305103b28d73482b344d7f5b76f39) |
---|---|
1/* 2 * IPv6 BSD socket options interface 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * Based on linux/net/ipv4/ip_sockglue.c --- 97 unchanged lines hidden (view full) --- 106 if (opt && 107 !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && 108 inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { 109 struct inet_connection_sock *icsk = inet_csk(sk); 110 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; 111 icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); 112 } 113 } | 1/* 2 * IPv6 BSD socket options interface 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * Based on linux/net/ipv4/ip_sockglue.c --- 97 unchanged lines hidden (view full) --- 106 if (opt && 107 !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && 108 inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { 109 struct inet_connection_sock *icsk = inet_csk(sk); 110 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; 111 icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); 112 } 113 } |
114 opt = xchg(&inet6_sk(sk)->opt, opt); | 114 opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, 115 opt); |
115 sk_dst_reset(sk); 116 117 return opt; 118} 119 120static bool setsockopt_needs_rtnl(int optname) 121{ 122 switch (optname) { --- 103 unchanged lines hidden (view full) --- 226 local_bh_disable(); 227 sock_prot_inuse_add(net, sk->sk_prot, -1); 228 sock_prot_inuse_add(net, prot, 1); 229 local_bh_enable(); 230 sk->sk_prot = prot; 231 sk->sk_socket->ops = &inet_dgram_ops; 232 sk->sk_family = PF_INET; 233 } | 116 sk_dst_reset(sk); 117 118 return opt; 119} 120 121static bool setsockopt_needs_rtnl(int optname) 122{ 123 switch (optname) { --- 103 unchanged lines hidden (view full) --- 227 local_bh_disable(); 228 sock_prot_inuse_add(net, sk->sk_prot, -1); 229 sock_prot_inuse_add(net, prot, 1); 230 local_bh_enable(); 231 sk->sk_prot = prot; 232 sk->sk_socket->ops = &inet_dgram_ops; 233 sk->sk_family = PF_INET; 234 } |
234 opt = xchg(&np->opt, NULL); 235 if (opt) 236 sock_kfree_s(sk, opt, opt->tot_len); | 235 opt = xchg((__force struct ipv6_txoptions **)&np->opt, 236 NULL); 237 if (opt) { 238 atomic_sub(opt->tot_len, &sk->sk_omem_alloc); 239 txopt_put(opt); 240 } |
237 pktopt = xchg(&np->pktoptions, NULL); 238 kfree_skb(pktopt); 239 240 sk->sk_destruct = inet_sock_destruct; 241 /* 242 * ... and add it to the refcnt debug socks count 243 * in the new family. -acme 244 */ --- 153 unchanged lines hidden (view full) --- 398 optlen & 0x7 || optlen > 8 * 255) 399 goto e_inval; 400 401 /* hop-by-hop / destination options are privileged option */ 402 retv = -EPERM; 403 if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) 404 break; 405 | 241 pktopt = xchg(&np->pktoptions, NULL); 242 kfree_skb(pktopt); 243 244 sk->sk_destruct = inet_sock_destruct; 245 /* 246 * ... and add it to the refcnt debug socks count 247 * in the new family. -acme 248 */ --- 153 unchanged lines hidden (view full) --- 402 optlen & 0x7 || optlen > 8 * 255) 403 goto e_inval; 404 405 /* hop-by-hop / destination options are privileged option */ 406 retv = -EPERM; 407 if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) 408 break; 409 |
406 opt = ipv6_renew_options(sk, np->opt, optname, | 410 opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); 411 opt = ipv6_renew_options(sk, opt, optname, |
407 (struct ipv6_opt_hdr __user *)optval, 408 optlen); 409 if (IS_ERR(opt)) { 410 retv = PTR_ERR(opt); 411 break; 412 } 413 414 /* routing header option needs extra check */ --- 12 unchanged lines hidden (view full) --- 427 default: 428 goto sticky_done; 429 } 430 } 431 432 retv = 0; 433 opt = ipv6_update_options(sk, opt); 434sticky_done: | 412 (struct ipv6_opt_hdr __user *)optval, 413 optlen); 414 if (IS_ERR(opt)) { 415 retv = PTR_ERR(opt); 416 break; 417 } 418 419 /* routing header option needs extra check */ --- 12 unchanged lines hidden (view full) --- 432 default: 433 goto sticky_done; 434 } 435 } 436 437 retv = 0; 438 opt = ipv6_update_options(sk, opt); 439sticky_done: |
435 if (opt) 436 sock_kfree_s(sk, opt, opt->tot_len); | 440 if (opt) { 441 atomic_sub(opt->tot_len, &sk->sk_omem_alloc); 442 txopt_put(opt); 443 } |
437 break; 438 } 439 440 case IPV6_PKTINFO: 441 { 442 struct in6_pktinfo pkt; 443 444 if (optlen == 0) --- 36 unchanged lines hidden (view full) --- 481 break; 482 483 opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); 484 retv = -ENOBUFS; 485 if (!opt) 486 break; 487 488 memset(opt, 0, sizeof(*opt)); | 444 break; 445 } 446 447 case IPV6_PKTINFO: 448 { 449 struct in6_pktinfo pkt; 450 451 if (optlen == 0) --- 36 unchanged lines hidden (view full) --- 488 break; 489 490 opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); 491 retv = -ENOBUFS; 492 if (!opt) 493 break; 494 495 memset(opt, 0, sizeof(*opt)); |
496 atomic_set(&opt->refcnt, 1); |
|
489 opt->tot_len = sizeof(*opt) + optlen; 490 retv = -EFAULT; 491 if (copy_from_user(opt+1, optval, optlen)) 492 goto done; 493 494 msg.msg_controllen = optlen; 495 msg.msg_control = (void *)(opt+1); 496 497 retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, 498 &junk, &junk); 499 if (retv) 500 goto done; 501update: 502 retv = 0; 503 opt = ipv6_update_options(sk, opt); 504done: | 497 opt->tot_len = sizeof(*opt) + optlen; 498 retv = -EFAULT; 499 if (copy_from_user(opt+1, optval, optlen)) 500 goto done; 501 502 msg.msg_controllen = optlen; 503 msg.msg_control = (void *)(opt+1); 504 505 retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, 506 &junk, &junk); 507 if (retv) 508 goto done; 509update: 510 retv = 0; 511 opt = ipv6_update_options(sk, opt); 512done: |
505 if (opt) 506 sock_kfree_s(sk, opt, opt->tot_len); | 513 if (opt) { 514 atomic_sub(opt->tot_len, &sk->sk_omem_alloc); 515 txopt_put(opt); 516 } |
507 break; 508 } 509 case IPV6_UNICAST_HOPS: 510 if (optlen < sizeof(int)) 511 goto e_inval; 512 if (val > 255 || val < -1) 513 goto e_inval; 514 np->hop_limit = val; --- 590 unchanged lines hidden (view full) --- 1105 val = np->rxopt.bits.osrcrt; 1106 break; 1107 1108 case IPV6_HOPOPTS: 1109 case IPV6_RTHDRDSTOPTS: 1110 case IPV6_RTHDR: 1111 case IPV6_DSTOPTS: 1112 { | 517 break; 518 } 519 case IPV6_UNICAST_HOPS: 520 if (optlen < sizeof(int)) 521 goto e_inval; 522 if (val > 255 || val < -1) 523 goto e_inval; 524 np->hop_limit = val; --- 590 unchanged lines hidden (view full) --- 1115 val = np->rxopt.bits.osrcrt; 1116 break; 1117 1118 case IPV6_HOPOPTS: 1119 case IPV6_RTHDRDSTOPTS: 1120 case IPV6_RTHDR: 1121 case IPV6_DSTOPTS: 1122 { |
1123 struct ipv6_txoptions *opt; |
|
1113 1114 lock_sock(sk); | 1124 1125 lock_sock(sk); |
1115 len = ipv6_getsockopt_sticky(sk, np->opt, 1116 optname, optval, len); | 1126 opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk)); 1127 len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len); |
1117 release_sock(sk); 1118 /* check if ipv6_getsockopt_sticky() returns err code */ 1119 if (len < 0) 1120 return len; 1121 return put_user(len, optlen); 1122 } 1123 1124 case IPV6_RECVHOPOPTS: --- 260 unchanged lines hidden --- | 1128 release_sock(sk); 1129 /* check if ipv6_getsockopt_sticky() returns err code */ 1130 if (len < 0) 1131 return len; 1132 return put_user(len, optlen); 1133 } 1134 1135 case IPV6_RECVHOPOPTS: --- 260 unchanged lines hidden --- |