@@ -557,6 +557,23 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
557
557
return ret ;
558
558
}
559
559
560
+ static int ethtool_copy_validate_indir (u32 * indir , void __user * useraddr ,
561
+ struct ethtool_rxnfc * rx_rings ,
562
+ u32 size )
563
+ {
564
+ int ret = 0 , i ;
565
+
566
+ if (copy_from_user (indir , useraddr , size * sizeof (indir [0 ])))
567
+ ret = - EFAULT ;
568
+
569
+ /* Validate ring indices */
570
+ for (i = 0 ; i < size ; i ++ ) {
571
+ if (indir [i ] >= rx_rings -> data )
572
+ ret = - EINVAL ;
573
+ }
574
+ return ret ;
575
+ }
576
+
560
577
static noinline_for_stack int ethtool_get_rxfh_indir (struct net_device * dev ,
561
578
void __user * useraddr )
562
579
{
@@ -613,6 +630,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
613
630
u32 * indir ;
614
631
const struct ethtool_ops * ops = dev -> ethtool_ops ;
615
632
int ret ;
633
+ u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir , ring_index [0 ]);
616
634
617
635
if (!ops -> get_rxfh_indir_size || !ops -> set_rxfh_indir ||
618
636
!ops -> get_rxnfc )
@@ -643,28 +661,196 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
643
661
for (i = 0 ; i < dev_size ; i ++ )
644
662
indir [i ] = ethtool_rxfh_indir_default (i , rx_rings .data );
645
663
} else {
646
- if (copy_from_user (indir ,
647
- useraddr +
648
- offsetof(struct ethtool_rxfh_indir ,
649
- ring_index [0 ]),
650
- dev_size * sizeof (indir [0 ]))) {
664
+ ret = ethtool_copy_validate_indir (indir ,
665
+ useraddr + ringidx_offset ,
666
+ & rx_rings ,
667
+ dev_size );
668
+ if (ret )
669
+ goto out ;
670
+ }
671
+
672
+ ret = ops -> set_rxfh_indir (dev , indir );
673
+
674
+ out :
675
+ kfree (indir );
676
+ return ret ;
677
+ }
678
+
679
+ static noinline_for_stack int ethtool_get_rxfh (struct net_device * dev ,
680
+ void __user * useraddr )
681
+ {
682
+ int ret ;
683
+ const struct ethtool_ops * ops = dev -> ethtool_ops ;
684
+ u32 user_indir_size = 0 , user_key_size = 0 ;
685
+ u32 dev_indir_size = 0 , dev_key_size = 0 ;
686
+ u32 total_size ;
687
+ u32 indir_offset , indir_bytes ;
688
+ u32 key_offset ;
689
+ u32 * indir = NULL ;
690
+ u8 * hkey = NULL ;
691
+ u8 * rss_config ;
692
+
693
+ if (!(dev -> ethtool_ops -> get_rxfh_indir_size ||
694
+ dev -> ethtool_ops -> get_rxfh_key_size ) ||
695
+ !dev -> ethtool_ops -> get_rxfh )
696
+ return - EOPNOTSUPP ;
697
+
698
+ if (ops -> get_rxfh_indir_size )
699
+ dev_indir_size = ops -> get_rxfh_indir_size (dev );
700
+
701
+ indir_offset = offsetof(struct ethtool_rxfh , indir_size );
702
+
703
+ if (copy_from_user (& user_indir_size ,
704
+ useraddr + indir_offset ,
705
+ sizeof (user_indir_size )))
706
+ return - EFAULT ;
707
+
708
+ if (copy_to_user (useraddr + indir_offset ,
709
+ & dev_indir_size , sizeof (dev_indir_size )))
710
+ return - EFAULT ;
711
+
712
+ if (ops -> get_rxfh_key_size )
713
+ dev_key_size = ops -> get_rxfh_key_size (dev );
714
+
715
+ if ((dev_key_size + dev_indir_size ) == 0 )
716
+ return - EOPNOTSUPP ;
717
+
718
+ key_offset = offsetof(struct ethtool_rxfh , key_size );
719
+
720
+ if (copy_from_user (& user_key_size ,
721
+ useraddr + key_offset ,
722
+ sizeof (user_key_size )))
723
+ return - EFAULT ;
724
+
725
+ if (copy_to_user (useraddr + key_offset ,
726
+ & dev_key_size , sizeof (dev_key_size )))
727
+ return - EFAULT ;
728
+
729
+ /* If the user buffer size is 0, this is just a query for the
730
+ * device table size and key size. Otherwise, if the User size is
731
+ * not equal to device table size or key size it's an error.
732
+ */
733
+ if (!user_indir_size && !user_key_size )
734
+ return 0 ;
735
+
736
+ if ((user_indir_size && (user_indir_size != dev_indir_size )) ||
737
+ (user_key_size && (user_key_size != dev_key_size )))
738
+ return - EINVAL ;
739
+
740
+ indir_bytes = user_indir_size * sizeof (indir [0 ]);
741
+ total_size = indir_bytes + user_key_size ;
742
+ rss_config = kzalloc (total_size , GFP_USER );
743
+ if (!rss_config )
744
+ return - ENOMEM ;
745
+
746
+ if (user_indir_size )
747
+ indir = (u32 * )rss_config ;
748
+
749
+ if (user_key_size )
750
+ hkey = rss_config + indir_bytes ;
751
+
752
+ ret = dev -> ethtool_ops -> get_rxfh (dev , indir , hkey );
753
+ if (!ret ) {
754
+ if (copy_to_user (useraddr +
755
+ offsetof(struct ethtool_rxfh , rss_config [0 ]),
756
+ rss_config , total_size ))
651
757
ret = - EFAULT ;
758
+ }
759
+
760
+ kfree (rss_config );
761
+
762
+ return ret ;
763
+ }
764
+
765
+ static noinline_for_stack int ethtool_set_rxfh (struct net_device * dev ,
766
+ void __user * useraddr )
767
+ {
768
+ int ret ;
769
+ const struct ethtool_ops * ops = dev -> ethtool_ops ;
770
+ struct ethtool_rxnfc rx_rings ;
771
+ u32 user_indir_size = 0 , dev_indir_size = 0 , i ;
772
+ u32 user_key_size = 0 , dev_key_size = 0 ;
773
+ u32 * indir = NULL , indir_bytes = 0 ;
774
+ u8 * hkey = NULL ;
775
+ u8 * rss_config ;
776
+ u32 indir_offset , key_offset ;
777
+ u32 rss_cfg_offset = offsetof(struct ethtool_rxfh , rss_config [0 ]);
778
+
779
+ if (!(ops -> get_rxfh_indir_size || ops -> get_rxfh_key_size ) ||
780
+ !ops -> get_rxnfc || !ops -> set_rxfh )
781
+ return - EOPNOTSUPP ;
782
+
783
+ if (ops -> get_rxfh_indir_size )
784
+ dev_indir_size = ops -> get_rxfh_indir_size (dev );
785
+
786
+ indir_offset = offsetof(struct ethtool_rxfh , indir_size );
787
+ if (copy_from_user (& user_indir_size ,
788
+ useraddr + indir_offset ,
789
+ sizeof (user_indir_size )))
790
+ return - EFAULT ;
791
+
792
+ if (ops -> get_rxfh_key_size )
793
+ dev_key_size = dev -> ethtool_ops -> get_rxfh_key_size (dev );
794
+
795
+ if ((dev_key_size + dev_indir_size ) == 0 )
796
+ return - EOPNOTSUPP ;
797
+
798
+ key_offset = offsetof(struct ethtool_rxfh , key_size );
799
+ if (copy_from_user (& user_key_size ,
800
+ useraddr + key_offset ,
801
+ sizeof (user_key_size )))
802
+ return - EFAULT ;
803
+
804
+ /* If either indir or hash key is valid, proceed further.
805
+ */
806
+ if ((user_indir_size && ((user_indir_size != 0xDEADBEEF ) &&
807
+ user_indir_size != dev_indir_size )) ||
808
+ (user_key_size && (user_key_size != dev_key_size )))
809
+ return - EINVAL ;
810
+
811
+ if (user_indir_size != 0xDEADBEEF )
812
+ indir_bytes = dev_indir_size * sizeof (indir [0 ]);
813
+
814
+ rss_config = kzalloc (indir_bytes + user_key_size , GFP_USER );
815
+ if (!rss_config )
816
+ return - ENOMEM ;
817
+
818
+ rx_rings .cmd = ETHTOOL_GRXRINGS ;
819
+ ret = ops -> get_rxnfc (dev , & rx_rings , NULL );
820
+ if (ret )
821
+ goto out ;
822
+
823
+ /* user_indir_size == 0 means reset the indir table to default.
824
+ * user_indir_size == 0xDEADBEEF means indir setting is not requested.
825
+ */
826
+ if (user_indir_size && user_indir_size != 0xDEADBEEF ) {
827
+ indir = (u32 * )rss_config ;
828
+ ret = ethtool_copy_validate_indir (indir ,
829
+ useraddr + rss_cfg_offset ,
830
+ & rx_rings ,
831
+ user_indir_size );
832
+ if (ret )
652
833
goto out ;
653
- }
834
+ } else if (user_indir_size == 0 ) {
835
+ indir = (u32 * )rss_config ;
836
+ for (i = 0 ; i < dev_indir_size ; i ++ )
837
+ indir [i ] = ethtool_rxfh_indir_default (i , rx_rings .data );
838
+ }
654
839
655
- /* Validate ring indices */
656
- for (i = 0 ; i < dev_size ; i ++ ) {
657
- if (indir [i ] >= rx_rings .data ) {
658
- ret = - EINVAL ;
659
- goto out ;
660
- }
840
+ if (user_key_size ) {
841
+ hkey = rss_config + indir_bytes ;
842
+ if (copy_from_user (hkey ,
843
+ useraddr + rss_cfg_offset + indir_bytes ,
844
+ user_key_size )) {
845
+ ret = - EFAULT ;
846
+ goto out ;
661
847
}
662
848
}
663
849
664
- ret = ops -> set_rxfh_indir (dev , indir );
850
+ ret = ops -> set_rxfh (dev , indir , hkey );
665
851
666
852
out :
667
- kfree (indir );
853
+ kfree (rss_config );
668
854
return ret ;
669
855
}
670
856
@@ -1491,6 +1677,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1491
1677
case ETHTOOL_GRXCLSRULE :
1492
1678
case ETHTOOL_GRXCLSRLALL :
1493
1679
case ETHTOOL_GRXFHINDIR :
1680
+ case ETHTOOL_GRSSH :
1494
1681
case ETHTOOL_GFEATURES :
1495
1682
case ETHTOOL_GCHANNELS :
1496
1683
case ETHTOOL_GET_TS_INFO :
@@ -1628,6 +1815,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1628
1815
case ETHTOOL_SRXFHINDIR :
1629
1816
rc = ethtool_set_rxfh_indir (dev , useraddr );
1630
1817
break ;
1818
+ case ETHTOOL_GRSSH :
1819
+ rc = ethtool_get_rxfh (dev , useraddr );
1820
+ break ;
1821
+ case ETHTOOL_SRSSH :
1822
+ rc = ethtool_set_rxfh (dev , useraddr );
1823
+ break ;
1631
1824
case ETHTOOL_GFEATURES :
1632
1825
rc = ethtool_get_features (dev , useraddr );
1633
1826
break ;
0 commit comments