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 ---