@@ -510,6 +510,62 @@ static bool mptcp_supported_sockopt(int level, int optname)
510
510
return false;
511
511
}
512
512
513
+ static int mptcp_setsockopt_sol_tcp_congestion (struct mptcp_sock * msk , sockptr_t optval ,
514
+ unsigned int optlen )
515
+ {
516
+ struct mptcp_subflow_context * subflow ;
517
+ struct sock * sk = (struct sock * )msk ;
518
+ char name [TCP_CA_NAME_MAX ];
519
+ bool cap_net_admin ;
520
+ int ret ;
521
+
522
+ if (optlen < 1 )
523
+ return - EINVAL ;
524
+
525
+ ret = strncpy_from_sockptr (name , optval ,
526
+ min_t (long , TCP_CA_NAME_MAX - 1 , optlen ));
527
+ if (ret < 0 )
528
+ return - EFAULT ;
529
+
530
+ name [ret ] = 0 ;
531
+
532
+ cap_net_admin = ns_capable (sock_net (sk )-> user_ns , CAP_NET_ADMIN );
533
+
534
+ ret = 0 ;
535
+ lock_sock (sk );
536
+ sockopt_seq_inc (msk );
537
+ mptcp_for_each_subflow (msk , subflow ) {
538
+ struct sock * ssk = mptcp_subflow_tcp_sock (subflow );
539
+ int err ;
540
+
541
+ lock_sock (ssk );
542
+ err = tcp_set_congestion_control (ssk , name , true, cap_net_admin );
543
+ if (err < 0 && ret == 0 )
544
+ ret = err ;
545
+ subflow -> setsockopt_seq = msk -> setsockopt_seq ;
546
+ release_sock (ssk );
547
+ }
548
+
549
+ if (ret == 0 )
550
+ tcp_set_congestion_control (sk , name , false, cap_net_admin );
551
+
552
+ release_sock (sk );
553
+ return ret ;
554
+ }
555
+
556
+ static int mptcp_setsockopt_sol_tcp (struct mptcp_sock * msk , int optname ,
557
+ sockptr_t optval , unsigned int optlen )
558
+ {
559
+ switch (optname ) {
560
+ case TCP_ULP :
561
+ return - EOPNOTSUPP ;
562
+ case TCP_CONGESTION :
563
+ return mptcp_setsockopt_sol_tcp_congestion (msk , optval , optlen );
564
+ }
565
+
566
+ return - EOPNOTSUPP ;
567
+ }
568
+
513
569
int mptcp_setsockopt (struct sock * sk , int level , int optname ,
514
570
sockptr_t optval , unsigned int optlen )
515
571
{
@@ -539,6 +595,49 @@ int mptcp_setsockopt(struct sock *sk, int level, int optname,
539
595
if (level == SOL_IPV6 )
540
596
return mptcp_setsockopt_v6 (msk , optname , optval , optlen );
541
597
598
+ if (level == SOL_TCP )
599
+ return mptcp_setsockopt_sol_tcp (msk , optname , optval , optlen );
600
+
601
+ return - EOPNOTSUPP ;
602
+ }
603
+
604
+ static int mptcp_getsockopt_first_sf_only (struct mptcp_sock * msk , int level , int optname ,
605
+ char __user * optval , int __user * optlen )
606
+ {
607
+ struct sock * sk = (struct sock * )msk ;
608
+ struct socket * ssock ;
609
+ int ret = - EINVAL ;
610
+ struct sock * ssk ;
611
+
612
+ lock_sock (sk );
613
+ ssk = msk -> first ;
614
+ if (ssk ) {
615
+ ret = tcp_getsockopt (ssk , level , optname , optval , optlen );
616
+ goto out ;
617
+ }
618
+
619
+ ssock = __mptcp_nmpc_socket (msk );
620
+ if (!ssock )
621
+ goto out ;
622
+
623
+ ret = tcp_getsockopt (ssock -> sk , level , optname , optval , optlen );
624
+
625
+ out :
626
+ release_sock (sk );
627
+ return ret ;
628
+ }
629
+
630
+ static int mptcp_getsockopt_sol_tcp (struct mptcp_sock * msk , int optname ,
631
+ char __user * optval , int __user * optlen )
632
+ {
633
+ switch (optname ) {
634
+ case TCP_ULP :
635
+ case TCP_CONGESTION :
636
+ case TCP_INFO :
637
+ case TCP_CC_INFO :
638
+ return mptcp_getsockopt_first_sf_only (msk , SOL_TCP , optname ,
639
+ optval , optlen );
640
+ }
542
641
return - EOPNOTSUPP ;
543
642
}
544
643
@@ -562,6 +661,8 @@ int mptcp_getsockopt(struct sock *sk, int level, int optname,
562
661
if (ssk )
563
662
return tcp_getsockopt (ssk , level , optname , optval , option );
564
663
664
+ if (level == SOL_TCP )
665
+ return mptcp_getsockopt_sol_tcp (msk , optname , optval , option );
565
666
return - EOPNOTSUPP ;
566
667
}
567
668
0 commit comments