diff options
Diffstat (limited to 'net/core/ethtool.c')
| -rw-r--r-- | net/core/ethtool.c | 313 |
1 files changed, 3 insertions, 310 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index fd14116ad7f0..6cdba5fc2bed 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
| @@ -169,18 +169,6 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported) | |||
| 169 | } | 169 | } |
| 170 | EXPORT_SYMBOL(ethtool_op_set_flags); | 170 | EXPORT_SYMBOL(ethtool_op_set_flags); |
| 171 | 171 | ||
| 172 | void ethtool_ntuple_flush(struct net_device *dev) | ||
| 173 | { | ||
| 174 | struct ethtool_rx_ntuple_flow_spec_container *fsc, *f; | ||
| 175 | |||
| 176 | list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) { | ||
| 177 | list_del(&fsc->list); | ||
| 178 | kfree(fsc); | ||
| 179 | } | ||
| 180 | dev->ethtool_ntuple_list.count = 0; | ||
| 181 | } | ||
| 182 | EXPORT_SYMBOL(ethtool_ntuple_flush); | ||
| 183 | |||
| 184 | /* Handlers for each ethtool command */ | 172 | /* Handlers for each ethtool command */ |
| 185 | 173 | ||
| 186 | #define ETHTOOL_DEV_FEATURE_WORDS 1 | 174 | #define ETHTOOL_DEV_FEATURE_WORDS 1 |
| @@ -865,34 +853,6 @@ out: | |||
| 865 | return ret; | 853 | return ret; |
| 866 | } | 854 | } |
| 867 | 855 | ||
| 868 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | ||
| 869 | struct ethtool_rx_ntuple_flow_spec *spec, | ||
| 870 | struct ethtool_rx_ntuple_flow_spec_container *fsc) | ||
| 871 | { | ||
| 872 | |||
| 873 | /* don't add filters forever */ | ||
| 874 | if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) { | ||
| 875 | /* free the container */ | ||
| 876 | kfree(fsc); | ||
| 877 | return; | ||
| 878 | } | ||
| 879 | |||
| 880 | /* Copy the whole filter over */ | ||
| 881 | fsc->fs.flow_type = spec->flow_type; | ||
| 882 | memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u)); | ||
| 883 | memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u)); | ||
| 884 | |||
| 885 | fsc->fs.vlan_tag = spec->vlan_tag; | ||
| 886 | fsc->fs.vlan_tag_mask = spec->vlan_tag_mask; | ||
| 887 | fsc->fs.data = spec->data; | ||
| 888 | fsc->fs.data_mask = spec->data_mask; | ||
| 889 | fsc->fs.action = spec->action; | ||
| 890 | |||
| 891 | /* add to the list */ | ||
| 892 | list_add_tail_rcu(&fsc->list, &list->list); | ||
| 893 | list->count++; | ||
| 894 | } | ||
| 895 | |||
| 896 | /* | 856 | /* |
| 897 | * ethtool does not (or did not) set masks for flow parameters that are | 857 | * ethtool does not (or did not) set masks for flow parameters that are |
| 898 | * not specified, so if both value and mask are 0 then this must be | 858 | * not specified, so if both value and mask are 0 then this must be |
| @@ -930,8 +890,6 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, | |||
| 930 | { | 890 | { |
| 931 | struct ethtool_rx_ntuple cmd; | 891 | struct ethtool_rx_ntuple cmd; |
| 932 | const struct ethtool_ops *ops = dev->ethtool_ops; | 892 | const struct ethtool_ops *ops = dev->ethtool_ops; |
| 933 | struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; | ||
| 934 | int ret; | ||
| 935 | 893 | ||
| 936 | if (!ops->set_rx_ntuple) | 894 | if (!ops->set_rx_ntuple) |
| 937 | return -EOPNOTSUPP; | 895 | return -EOPNOTSUPP; |
| @@ -944,269 +902,7 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, | |||
| 944 | 902 | ||
| 945 | rx_ntuple_fix_masks(&cmd.fs); | 903 | rx_ntuple_fix_masks(&cmd.fs); |
| 946 | 904 | ||
| 947 | /* | 905 | return ops->set_rx_ntuple(dev, &cmd); |
| 948 | * Cache filter in dev struct for GET operation only if | ||
| 949 | * the underlying driver doesn't have its own GET operation, and | ||
| 950 | * only if the filter was added successfully. First make sure we | ||
| 951 | * can allocate the filter, then continue if successful. | ||
| 952 | */ | ||
| 953 | if (!ops->get_rx_ntuple) { | ||
| 954 | fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); | ||
| 955 | if (!fsc) | ||
| 956 | return -ENOMEM; | ||
| 957 | } | ||
| 958 | |||
| 959 | ret = ops->set_rx_ntuple(dev, &cmd); | ||
| 960 | if (ret) { | ||
| 961 | kfree(fsc); | ||
| 962 | return ret; | ||
| 963 | } | ||
| 964 | |||
| 965 | if (!ops->get_rx_ntuple) | ||
| 966 | __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc); | ||
| 967 | |||
| 968 | return ret; | ||
| 969 | } | ||
| 970 | |||
| 971 | static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr) | ||
| 972 | { | ||
| 973 | struct ethtool_gstrings gstrings; | ||
| 974 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
| 975 | struct ethtool_rx_ntuple_flow_spec_container *fsc; | ||
| 976 | u8 *data; | ||
| 977 | char *p; | ||
| 978 | int ret, i, num_strings = 0; | ||
| 979 | |||
| 980 | if (!ops->get_sset_count) | ||
| 981 | return -EOPNOTSUPP; | ||
| 982 | |||
| 983 | if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) | ||
| 984 | return -EFAULT; | ||
| 985 | |||
| 986 | ret = ops->get_sset_count(dev, gstrings.string_set); | ||
| 987 | if (ret < 0) | ||
| 988 | return ret; | ||
| 989 | |||
| 990 | gstrings.len = ret; | ||
| 991 | |||
| 992 | data = kzalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); | ||
| 993 | if (!data) | ||
| 994 | return -ENOMEM; | ||
| 995 | |||
| 996 | if (ops->get_rx_ntuple) { | ||
| 997 | /* driver-specific filter grab */ | ||
| 998 | ret = ops->get_rx_ntuple(dev, gstrings.string_set, data); | ||
| 999 | goto copy; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | /* default ethtool filter grab */ | ||
| 1003 | i = 0; | ||
| 1004 | p = (char *)data; | ||
| 1005 | list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) { | ||
| 1006 | sprintf(p, "Filter %d:\n", i); | ||
| 1007 | p += ETH_GSTRING_LEN; | ||
| 1008 | num_strings++; | ||
| 1009 | |||
| 1010 | switch (fsc->fs.flow_type) { | ||
| 1011 | case TCP_V4_FLOW: | ||
| 1012 | sprintf(p, "\tFlow Type: TCP\n"); | ||
| 1013 | p += ETH_GSTRING_LEN; | ||
| 1014 | num_strings++; | ||
| 1015 | break; | ||
| 1016 | case UDP_V4_FLOW: | ||
| 1017 | sprintf(p, "\tFlow Type: UDP\n"); | ||
| 1018 | p += ETH_GSTRING_LEN; | ||
| 1019 | num_strings++; | ||
| 1020 | break; | ||
| 1021 | case SCTP_V4_FLOW: | ||
| 1022 | sprintf(p, "\tFlow Type: SCTP\n"); | ||
| 1023 | p += ETH_GSTRING_LEN; | ||
| 1024 | num_strings++; | ||
| 1025 | break; | ||
| 1026 | case AH_ESP_V4_FLOW: | ||
| 1027 | sprintf(p, "\tFlow Type: AH ESP\n"); | ||
| 1028 | p += ETH_GSTRING_LEN; | ||
| 1029 | num_strings++; | ||
| 1030 | break; | ||
| 1031 | case ESP_V4_FLOW: | ||
| 1032 | sprintf(p, "\tFlow Type: ESP\n"); | ||
| 1033 | p += ETH_GSTRING_LEN; | ||
| 1034 | num_strings++; | ||
| 1035 | break; | ||
| 1036 | case IP_USER_FLOW: | ||
| 1037 | sprintf(p, "\tFlow Type: Raw IP\n"); | ||
| 1038 | p += ETH_GSTRING_LEN; | ||
| 1039 | num_strings++; | ||
| 1040 | break; | ||
| 1041 | case IPV4_FLOW: | ||
| 1042 | sprintf(p, "\tFlow Type: IPv4\n"); | ||
| 1043 | p += ETH_GSTRING_LEN; | ||
| 1044 | num_strings++; | ||
| 1045 | break; | ||
| 1046 | default: | ||
| 1047 | sprintf(p, "\tFlow Type: Unknown\n"); | ||
| 1048 | p += ETH_GSTRING_LEN; | ||
| 1049 | num_strings++; | ||
| 1050 | goto unknown_filter; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | /* now the rest of the filters */ | ||
| 1054 | switch (fsc->fs.flow_type) { | ||
| 1055 | case TCP_V4_FLOW: | ||
| 1056 | case UDP_V4_FLOW: | ||
| 1057 | case SCTP_V4_FLOW: | ||
| 1058 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 1059 | fsc->fs.h_u.tcp_ip4_spec.ip4src); | ||
| 1060 | p += ETH_GSTRING_LEN; | ||
| 1061 | num_strings++; | ||
| 1062 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 1063 | fsc->fs.m_u.tcp_ip4_spec.ip4src); | ||
| 1064 | p += ETH_GSTRING_LEN; | ||
| 1065 | num_strings++; | ||
| 1066 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 1067 | fsc->fs.h_u.tcp_ip4_spec.ip4dst); | ||
| 1068 | p += ETH_GSTRING_LEN; | ||
| 1069 | num_strings++; | ||
| 1070 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 1071 | fsc->fs.m_u.tcp_ip4_spec.ip4dst); | ||
| 1072 | p += ETH_GSTRING_LEN; | ||
| 1073 | num_strings++; | ||
| 1074 | sprintf(p, "\tSrc Port: %d, mask: 0x%x\n", | ||
| 1075 | fsc->fs.h_u.tcp_ip4_spec.psrc, | ||
| 1076 | fsc->fs.m_u.tcp_ip4_spec.psrc); | ||
| 1077 | p += ETH_GSTRING_LEN; | ||
| 1078 | num_strings++; | ||
| 1079 | sprintf(p, "\tDest Port: %d, mask: 0x%x\n", | ||
| 1080 | fsc->fs.h_u.tcp_ip4_spec.pdst, | ||
| 1081 | fsc->fs.m_u.tcp_ip4_spec.pdst); | ||
| 1082 | p += ETH_GSTRING_LEN; | ||
| 1083 | num_strings++; | ||
| 1084 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
| 1085 | fsc->fs.h_u.tcp_ip4_spec.tos, | ||
| 1086 | fsc->fs.m_u.tcp_ip4_spec.tos); | ||
| 1087 | p += ETH_GSTRING_LEN; | ||
| 1088 | num_strings++; | ||
| 1089 | break; | ||
| 1090 | case AH_ESP_V4_FLOW: | ||
| 1091 | case ESP_V4_FLOW: | ||
| 1092 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 1093 | fsc->fs.h_u.ah_ip4_spec.ip4src); | ||
| 1094 | p += ETH_GSTRING_LEN; | ||
| 1095 | num_strings++; | ||
| 1096 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 1097 | fsc->fs.m_u.ah_ip4_spec.ip4src); | ||
| 1098 | p += ETH_GSTRING_LEN; | ||
| 1099 | num_strings++; | ||
| 1100 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 1101 | fsc->fs.h_u.ah_ip4_spec.ip4dst); | ||
| 1102 | p += ETH_GSTRING_LEN; | ||
| 1103 | num_strings++; | ||
| 1104 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 1105 | fsc->fs.m_u.ah_ip4_spec.ip4dst); | ||
| 1106 | p += ETH_GSTRING_LEN; | ||
| 1107 | num_strings++; | ||
| 1108 | sprintf(p, "\tSPI: %d, mask: 0x%x\n", | ||
| 1109 | fsc->fs.h_u.ah_ip4_spec.spi, | ||
| 1110 | fsc->fs.m_u.ah_ip4_spec.spi); | ||
| 1111 | p += ETH_GSTRING_LEN; | ||
| 1112 | num_strings++; | ||
| 1113 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
| 1114 | fsc->fs.h_u.ah_ip4_spec.tos, | ||
| 1115 | fsc->fs.m_u.ah_ip4_spec.tos); | ||
| 1116 | p += ETH_GSTRING_LEN; | ||
| 1117 | num_strings++; | ||
| 1118 | break; | ||
| 1119 | case IP_USER_FLOW: | ||
| 1120 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 1121 | fsc->fs.h_u.usr_ip4_spec.ip4src); | ||
| 1122 | p += ETH_GSTRING_LEN; | ||
| 1123 | num_strings++; | ||
| 1124 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 1125 | fsc->fs.m_u.usr_ip4_spec.ip4src); | ||
| 1126 | p += ETH_GSTRING_LEN; | ||
| 1127 | num_strings++; | ||
| 1128 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 1129 | fsc->fs.h_u.usr_ip4_spec.ip4dst); | ||
| 1130 | p += ETH_GSTRING_LEN; | ||
| 1131 | num_strings++; | ||
| 1132 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 1133 | fsc->fs.m_u.usr_ip4_spec.ip4dst); | ||
| 1134 | p += ETH_GSTRING_LEN; | ||
| 1135 | num_strings++; | ||
| 1136 | break; | ||
| 1137 | case IPV4_FLOW: | ||
| 1138 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 1139 | fsc->fs.h_u.usr_ip4_spec.ip4src); | ||
| 1140 | p += ETH_GSTRING_LEN; | ||
| 1141 | num_strings++; | ||
| 1142 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 1143 | fsc->fs.m_u.usr_ip4_spec.ip4src); | ||
| 1144 | p += ETH_GSTRING_LEN; | ||
| 1145 | num_strings++; | ||
| 1146 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 1147 | fsc->fs.h_u.usr_ip4_spec.ip4dst); | ||
| 1148 | p += ETH_GSTRING_LEN; | ||
| 1149 | num_strings++; | ||
| 1150 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 1151 | fsc->fs.m_u.usr_ip4_spec.ip4dst); | ||
| 1152 | p += ETH_GSTRING_LEN; | ||
| 1153 | num_strings++; | ||
| 1154 | sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n", | ||
| 1155 | fsc->fs.h_u.usr_ip4_spec.l4_4_bytes, | ||
| 1156 | fsc->fs.m_u.usr_ip4_spec.l4_4_bytes); | ||
| 1157 | p += ETH_GSTRING_LEN; | ||
| 1158 | num_strings++; | ||
| 1159 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
| 1160 | fsc->fs.h_u.usr_ip4_spec.tos, | ||
| 1161 | fsc->fs.m_u.usr_ip4_spec.tos); | ||
| 1162 | p += ETH_GSTRING_LEN; | ||
| 1163 | num_strings++; | ||
| 1164 | sprintf(p, "\tIP Version: %d, mask: 0x%x\n", | ||
| 1165 | fsc->fs.h_u.usr_ip4_spec.ip_ver, | ||
| 1166 | fsc->fs.m_u.usr_ip4_spec.ip_ver); | ||
| 1167 | p += ETH_GSTRING_LEN; | ||
| 1168 | num_strings++; | ||
| 1169 | sprintf(p, "\tProtocol: %d, mask: 0x%x\n", | ||
| 1170 | fsc->fs.h_u.usr_ip4_spec.proto, | ||
| 1171 | fsc->fs.m_u.usr_ip4_spec.proto); | ||
| 1172 | p += ETH_GSTRING_LEN; | ||
| 1173 | num_strings++; | ||
| 1174 | break; | ||
| 1175 | } | ||
| 1176 | sprintf(p, "\tVLAN: %d, mask: 0x%x\n", | ||
| 1177 | fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask); | ||
| 1178 | p += ETH_GSTRING_LEN; | ||
| 1179 | num_strings++; | ||
| 1180 | sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data); | ||
| 1181 | p += ETH_GSTRING_LEN; | ||
| 1182 | num_strings++; | ||
| 1183 | sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask); | ||
| 1184 | p += ETH_GSTRING_LEN; | ||
| 1185 | num_strings++; | ||
| 1186 | if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) | ||
| 1187 | sprintf(p, "\tAction: Drop\n"); | ||
| 1188 | else | ||
| 1189 | sprintf(p, "\tAction: Direct to queue %d\n", | ||
| 1190 | fsc->fs.action); | ||
| 1191 | p += ETH_GSTRING_LEN; | ||
| 1192 | num_strings++; | ||
| 1193 | unknown_filter: | ||
| 1194 | i++; | ||
| 1195 | } | ||
| 1196 | copy: | ||
| 1197 | /* indicate to userspace how many strings we actually have */ | ||
| 1198 | gstrings.len = num_strings; | ||
| 1199 | ret = -EFAULT; | ||
| 1200 | if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) | ||
| 1201 | goto out; | ||
| 1202 | useraddr += sizeof(gstrings); | ||
| 1203 | if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) | ||
| 1204 | goto out; | ||
| 1205 | ret = 0; | ||
| 1206 | |||
| 1207 | out: | ||
| 1208 | kfree(data); | ||
| 1209 | return ret; | ||
| 1210 | } | 906 | } |
| 1211 | 907 | ||
| 1212 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) | 908 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) |
| @@ -1227,7 +923,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) | |||
| 1227 | regs.len = reglen; | 923 | regs.len = reglen; |
| 1228 | 924 | ||
| 1229 | regbuf = vzalloc(reglen); | 925 | regbuf = vzalloc(reglen); |
| 1230 | if (!regbuf) | 926 | if (reglen && !regbuf) |
| 1231 | return -ENOMEM; | 927 | return -ENOMEM; |
| 1232 | 928 | ||
| 1233 | ops->get_regs(dev, ®s, regbuf); | 929 | ops->get_regs(dev, ®s, regbuf); |
| @@ -1236,7 +932,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) | |||
| 1236 | if (copy_to_user(useraddr, ®s, sizeof(regs))) | 932 | if (copy_to_user(useraddr, ®s, sizeof(regs))) |
| 1237 | goto out; | 933 | goto out; |
| 1238 | useraddr += offsetof(struct ethtool_regs, data); | 934 | useraddr += offsetof(struct ethtool_regs, data); |
| 1239 | if (copy_to_user(useraddr, regbuf, regs.len)) | 935 | if (regbuf && copy_to_user(useraddr, regbuf, regs.len)) |
| 1240 | goto out; | 936 | goto out; |
| 1241 | ret = 0; | 937 | ret = 0; |
| 1242 | 938 | ||
| @@ -2101,9 +1797,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
| 2101 | case ETHTOOL_SRXNTUPLE: | 1797 | case ETHTOOL_SRXNTUPLE: |
| 2102 | rc = ethtool_set_rx_ntuple(dev, useraddr); | 1798 | rc = ethtool_set_rx_ntuple(dev, useraddr); |
| 2103 | break; | 1799 | break; |
| 2104 | case ETHTOOL_GRXNTUPLE: | ||
| 2105 | rc = ethtool_get_rx_ntuple(dev, useraddr); | ||
| 2106 | break; | ||
| 2107 | case ETHTOOL_GSSET_INFO: | 1800 | case ETHTOOL_GSSET_INFO: |
| 2108 | rc = ethtool_get_sset_info(dev, useraddr); | 1801 | rc = ethtool_get_sset_info(dev, useraddr); |
| 2109 | break; | 1802 | break; |
