History

nl80211: allow splitting wiphy information in dumps

The per-wiphy information is getting large, to the point where with more than the typical number of channels it's too large and overflows, and userspace can't get any of the information at all. To address this (in a way that doesn't require making all messages bigger) allow userspace to specify that it can deal with wiphy information split across multiple parts of the dump, and if it can split up the data. This also splits up each channel separately so an arbitrary number of channels can be supported. Additionally, since GET_WIPHY has the same problem, add support for filtering the wiphy dump and get information for a single wiphy only, this allows userspace apps to use dump in this case to retrieve all data from a single device. As userspace needs to know if all this this is supported, add a global nl80211 feature set and include a bit for this behaviour in it.

Johannes Berg committed 13 years ago

Commit 3713b4e1 parent 191922c2 files · +599 −362Browse files

Unified · Split

2 files
  1. include/uapi/linux/nl80211.h +28 −0
  2. net/wireless/nl80211.c +571 −362
include/uapi/linux/nl80211.h+28−0
@@ -625,6 +625,10 @@ · 624 unmodified lines
625625 * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
626626 * event.
627627 *
628+ * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features,
629+ * i.e. features for the nl80211 protocol rather than device features.
630+ * Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
631+ *
628632 * @NL80211_CMD_MAX: highest used command number
629633 * @__NL80211_CMD_AFTER_LAST: internal use
630634 */
@@ -779,6 +783,8 @@ enum nl80211_commands { · 148 unmodified lines
779783
780784 NL80211_CMD_RADAR_DETECT,
781785
786+ NL80211_CMD_GET_PROTOCOL_FEATURES,
787+
782788 /* add new commands above here */
783789
784790 /* used to define NL80211_CMD_MAX below */
@@ -1383,6 +1389,13 @@ enum nl80211_commands { · 598 unmodified lines
13831389 * advertised to the driver, e.g., to enable TDLS off channel operations
13841390 * and PU-APSD.
13851391 *
1392+ * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see
1393+ * &enum nl80211_protocol_features, the attribute is a u32.
1394+ *
1395+ * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports
1396+ * receiving the data for a single wiphy split across multiple
1397+ * messages, given with wiphy dump message
1398+ *
13861399 * @NL80211_ATTR_MAX: highest attribute number currently defined
13871400 * @__NL80211_ATTR_AFTER_LAST: internal use
13881401 */
@@ -1669,6 +1682,9 @@ enum nl80211_attrs { · 280 unmodified lines
16691682 NL80211_ATTR_STA_CAPABILITY,
16701683 NL80211_ATTR_STA_EXT_CAPABILITY,
16711684
1685+ NL80211_ATTR_PROTOCOL_FEATURES,
1686+ NL80211_ATTR_SPLIT_WIPHY_DUMP,
1687+
16721688 /* add attributes here, update the policy in nl80211.c */
16731689
16741690 __NL80211_ATTR_AFTER_LAST,
@@ -3619,4 +3635,16 @@ enum nl80211_dfs_state { · 1944 unmodified lines
36193635 NL80211_DFS_AVAILABLE,
36203636 };
36213637
3638+/**
3639+ * enum enum nl80211_protocol_features - nl80211 protocol features
3640+ * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
3641+ * wiphy dumps (if requested by the application with the attribute
3642+ * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
3643+ * wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or
3644+ * %NL80211_ATTR_WDEV.
3645+ */
3646+enum nl80211_protocol_features {
3647+ NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0,
3648+};
3649+
36223650 #endif /* __LINUX_NL80211_H */
net/wireless/nl80211.c+571−362
@@ -370,6 +370,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { · 369 unmodified lines
370370 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
371371 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
372372 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
373+ [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
373374 };
374375
375376 /* policy for the key attributes */
@@ -892,412 +893,545 @@ nla_put_failure: · 516 unmodified lines
892893 return -ENOBUFS;
893894 }
894895
895−static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags,
896− struct cfg80211_registered_device *dev)
896+#ifdef CONFIG_PM
897+static int nl80211_send_wowlan(struct sk_buff *msg,
898+ struct cfg80211_registered_device *dev)
897899 {
898− void *hdr;
899− struct nlattr *nl_bands, *nl_band;
900− struct nlattr *nl_freqs, *nl_freq;
901− struct nlattr *nl_rates, *nl_rate;
902− struct nlattr *nl_cmds;
903− enum ieee80211_band band;
904− struct ieee80211_channel *chan;
905− struct ieee80211_rate *rate;
906− int i;
907− const struct ieee80211_txrx_stypes *mgmt_stypes =
908− dev->wiphy.mgmt_stypes;
900+ struct nlattr *nl_wowlan;
909901
910− hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
911− if (!hdr)
912− return -1;
902+ if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns)
903+ return 0;
913904
914− if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
915− nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) ||
916− nla_put_u32(msg, NL80211_ATTR_GENERATION,
917− cfg80211_rdev_list_generation) ||
918− nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
919− dev->wiphy.retry_short) ||
920− nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
921− dev->wiphy.retry_long) ||
922− nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
923− dev->wiphy.frag_threshold) ||
924− nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
925− dev->wiphy.rts_threshold) ||
926− nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
927− dev->wiphy.coverage_class) ||
928− nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
929− dev->wiphy.max_scan_ssids) ||
930− nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
931− dev->wiphy.max_sched_scan_ssids) ||
932− nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
933− dev->wiphy.max_scan_ie_len) ||
934− nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
935− dev->wiphy.max_sched_scan_ie_len) ||
936− nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
937− dev->wiphy.max_match_sets))
938− goto nla_put_failure;
905+ nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
906+ if (!nl_wowlan)
907+ return -ENOBUFS;
939908
940− if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
941− nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
942− goto nla_put_failure;
943− if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
944− nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
945− goto nla_put_failure;
946− if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
947− nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
948− goto nla_put_failure;
949− if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
950− nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
951− goto nla_put_failure;
952− if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
953− nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
954− goto nla_put_failure;
955− if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
956− nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
957− goto nla_put_failure;
909+ if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
910+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
911+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
912+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
913+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
914+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
915+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
916+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
917+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
918+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
919+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
920+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
921+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
922+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
923+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
924+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
925+ return -ENOBUFS;
958926
959− if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
960− sizeof(u32) * dev->wiphy.n_cipher_suites,
961− dev->wiphy.cipher_suites))
962− goto nla_put_failure;
927+ if (dev->wiphy.wowlan.n_patterns) {
928+ struct nl80211_wowlan_pattern_support pat = {
929+ .max_patterns = dev->wiphy.wowlan.n_patterns,
930+ .min_pattern_len = dev->wiphy.wowlan.pattern_min_len,
931+ .max_pattern_len = dev->wiphy.wowlan.pattern_max_len,
932+ .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset,
933+ };
963934
964− if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
965− dev->wiphy.max_num_pmkids))
966− goto nla_put_failure;
935+ if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
936+ sizeof(pat), &pat))
937+ return -ENOBUFS;
938+ }
967939
968− if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
969− nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
970− goto nla_put_failure;
940+ nla_nest_end(msg, nl_wowlan);
971941
972− if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
973− dev->wiphy.available_antennas_tx) ||
974− nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
975− dev->wiphy.available_antennas_rx))
976− goto nla_put_failure;
942+ return 0;
943+}
944+#endif
977945
978− if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
979− nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
980− dev->wiphy.probe_resp_offload))
981− goto nla_put_failure;
946+static int nl80211_send_band_rateinfo(struct sk_buff *msg,
947+ struct ieee80211_supported_band *sband)
948+{
949+ struct nlattr *nl_rates, *nl_rate;
950+ struct ieee80211_rate *rate;
951+ int i;
982952
983− if ((dev->wiphy.available_antennas_tx ||
984− dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
985− u32 tx_ant = 0, rx_ant = 0;
986− int res;
987− res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
988− if (!res) {
989− if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX,
990− tx_ant) ||
991− nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX,
992− rx_ant))
993− goto nla_put_failure;
994− }
995− }
953+ /* add HT info */
954+ if (sband->ht_cap.ht_supported &&
955+ (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
956+ sizeof(sband->ht_cap.mcs),
957+ &sband->ht_cap.mcs) ||
958+ nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
959+ sband->ht_cap.cap) ||
960+ nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
961+ sband->ht_cap.ampdu_factor) ||
962+ nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
963+ sband->ht_cap.ampdu_density)))
964+ return -ENOBUFS;
996965
997− if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
998− dev->wiphy.interface_modes))
999− goto nla_put_failure;
966+ /* add VHT info */
967+ if (sband->vht_cap.vht_supported &&
968+ (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
969+ sizeof(sband->vht_cap.vht_mcs),
970+ &sband->vht_cap.vht_mcs) ||
971+ nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
972+ sband->vht_cap.cap)))
973+ return -ENOBUFS;
1000974
1001− nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1002− if (!nl_bands)
1003− goto nla_put_failure;
975+ /* add bitrates */
976+ nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
977+ if (!nl_rates)
978+ return -ENOBUFS;
1004979
1005− for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1006− if (!dev->wiphy.bands[band])
1007− continue;
980+ for (i = 0; i < sband->n_bitrates; i++) {
981+ nl_rate = nla_nest_start(msg, i);
982+ if (!nl_rate)
983+ return -ENOBUFS;
1008984
1009− nl_band = nla_nest_start(msg, band);
1010− if (!nl_band)
1011− goto nla_put_failure;
985+ rate = &sband->bitrates[i];
986+ if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
987+ rate->bitrate))
988+ return -ENOBUFS;
989+ if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
990+ nla_put_flag(msg,
991+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
992+ return -ENOBUFS;
1012993
1013− /* add HT info */
1014− if (dev->wiphy.bands[band]->ht_cap.ht_supported &&
1015− (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
1016− sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
1017− &dev->wiphy.bands[band]->ht_cap.mcs) ||
1018− nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
1019− dev->wiphy.bands[band]->ht_cap.cap) ||
1020− nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
1021− dev->wiphy.bands[band]->ht_cap.ampdu_factor) ||
1022− nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
1023− dev->wiphy.bands[band]->ht_cap.ampdu_density)))
1024− goto nla_put_failure;
994+ nla_nest_end(msg, nl_rate);
995+ }
1025996
1026− /* add VHT info */
1027− if (dev->wiphy.bands[band]->vht_cap.vht_supported &&
1028− (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
1029− sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs),
1030− &dev->wiphy.bands[band]->vht_cap.vht_mcs) ||
1031− nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
1032− dev->wiphy.bands[band]->vht_cap.cap)))
1033− goto nla_put_failure;
997+ nla_nest_end(msg, nl_rates);
1034998
1035− /* add frequencies */
1036− nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
1037− if (!nl_freqs)
1038− goto nla_put_failure;
999+ return 0;
1000+}
10391001
1040− for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
1041− nl_freq = nla_nest_start(msg, i);
1042− if (!nl_freq)
1043− goto nla_put_failure;
1002+static int
1003+nl80211_send_mgmt_stypes(struct sk_buff *msg,
1004+ const struct ieee80211_txrx_stypes *mgmt_stypes)
1005+{
1006+ u16 stypes;
1007+ struct nlattr *nl_ftypes, *nl_ifs;
1008+ enum nl80211_iftype ift;
1009+ int i;
10441010
1045− chan = &dev->wiphy.bands[band]->channels[i];
1011+ if (!mgmt_stypes)
1012+ return 0;
10461013
1047− if (nl80211_msg_put_channel(msg, chan))
1048− goto nla_put_failure;
1014+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1015+ if (!nl_ifs)
1016+ return -ENOBUFS;
10491017
1050− nla_nest_end(msg, nl_freq);
1018+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1019+ nl_ftypes = nla_nest_start(msg, ift);
1020+ if (!nl_ftypes)
1021+ return -ENOBUFS;
1022+ i = 0;
1023+ stypes = mgmt_stypes[ift].tx;
1024+ while (stypes) {
1025+ if ((stypes & 1) &&
1026+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1027+ (i << 4) | IEEE80211_FTYPE_MGMT))
1028+ return -ENOBUFS;
1029+ stypes >>= 1;
1030+ i++;
10511031 }
1032+ nla_nest_end(msg, nl_ftypes);
1033+ }
10521034
1053− nla_nest_end(msg, nl_freqs);
1035+ nla_nest_end(msg, nl_ifs);
10541036
1055− /* add bitrates */
1056− nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
1057− if (!nl_rates)
1058− goto nla_put_failure;
1037+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1038+ if (!nl_ifs)
1039+ return -ENOBUFS;
10591040
1060− for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
1061− nl_rate = nla_nest_start(msg, i);
1062− if (!nl_rate)
1063− goto nla_put_failure;
1041+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1042+ nl_ftypes = nla_nest_start(msg, ift);
1043+ if (!nl_ftypes)
1044+ return -ENOBUFS;
1045+ i = 0;
1046+ stypes = mgmt_stypes[ift].rx;
1047+ while (stypes) {
1048+ if ((stypes & 1) &&
1049+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1050+ (i << 4) | IEEE80211_FTYPE_MGMT))
1051+ return -ENOBUFS;
1052+ stypes >>= 1;
1053+ i++;
1054+ }
1055+ nla_nest_end(msg, nl_ftypes);
1056+ }
1057+ nla_nest_end(msg, nl_ifs);
10641058
1065− rate = &dev->wiphy.bands[band]->bitrates[i];
1066− if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
1067− rate->bitrate))
1068− goto nla_put_failure;
1069− if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
1070− nla_put_flag(msg,
1071− NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
1072− goto nla_put_failure;
1059+ return 0;
1060+}
10731061
1074− nla_nest_end(msg, nl_rate);
1075− }
1062+static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1063+ struct sk_buff *msg, u32 portid, u32 seq,
1064+ int flags, bool split, long *split_start,
1065+ long *band_start, long *chan_start)
1066+{
1067+ void *hdr;
1068+ struct nlattr *nl_bands, *nl_band;
1069+ struct nlattr *nl_freqs, *nl_freq;
1070+ struct nlattr *nl_cmds;
1071+ enum ieee80211_band band;
1072+ struct ieee80211_channel *chan;
1073+ int i;
1074+ const struct ieee80211_txrx_stypes *mgmt_stypes =
1075+ dev->wiphy.mgmt_stypes;
1076+ long start = 0, start_chan = 0, start_band = 0;
10761077
1077− nla_nest_end(msg, nl_rates);
1078+ hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
1079+ if (!hdr)
1080+ return -ENOBUFS;
10781081
1079− nla_nest_end(msg, nl_band);
1082+ /* allow always using the variables */
1083+ if (!split) {
1084+ split_start = &start;
1085+ band_start = &start_band;
1086+ chan_start = &start_chan;
10801087 }
1081− nla_nest_end(msg, nl_bands);
10821088
1083− nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1084− if (!nl_cmds)
1085− goto nla_put_failure;
1089+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
1090+ nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
1091+ wiphy_name(&dev->wiphy)) ||
1092+ nla_put_u32(msg, NL80211_ATTR_GENERATION,
1093+ cfg80211_rdev_list_generation))
1094+ goto nla_put_failure;
1095+
1096+ switch (*split_start) {
1097+ case 0:
1098+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
1099+ dev->wiphy.retry_short) ||
1100+ nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
1101+ dev->wiphy.retry_long) ||
1102+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
1103+ dev->wiphy.frag_threshold) ||
1104+ nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
1105+ dev->wiphy.rts_threshold) ||
1106+ nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
1107+ dev->wiphy.coverage_class) ||
1108+ nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
1109+ dev->wiphy.max_scan_ssids) ||
1110+ nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
1111+ dev->wiphy.max_sched_scan_ssids) ||
1112+ nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
1113+ dev->wiphy.max_scan_ie_len) ||
1114+ nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
1115+ dev->wiphy.max_sched_scan_ie_len) ||
1116+ nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
1117+ dev->wiphy.max_match_sets))
1118+ goto nla_put_failure;
10861119
1087− i = 0;
1088−#define CMD(op, n) \
1089− do { \
1090− if (dev->ops->op) { \
1091− i++; \
1092− if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1093− goto nla_put_failure; \
1094− } \
1095− } while (0)
1096−
1097− CMD(add_virtual_intf, NEW_INTERFACE);
1098− CMD(change_virtual_intf, SET_INTERFACE);
1099− CMD(add_key, NEW_KEY);
1100− CMD(start_ap, START_AP);
1101− CMD(add_station, NEW_STATION);
1102− CMD(add_mpath, NEW_MPATH);
1103− CMD(update_mesh_config, SET_MESH_CONFIG);
1104− CMD(change_bss, SET_BSS);
1105− CMD(auth, AUTHENTICATE);
1106− CMD(assoc, ASSOCIATE);
1107− CMD(deauth, DEAUTHENTICATE);
1108− CMD(disassoc, DISASSOCIATE);
1109− CMD(join_ibss, JOIN_IBSS);
1110− CMD(join_mesh, JOIN_MESH);
1111− CMD(set_pmksa, SET_PMKSA);
1112− CMD(del_pmksa, DEL_PMKSA);
1113− CMD(flush_pmksa, FLUSH_PMKSA);
1114− if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1115− CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1116− CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1117− CMD(mgmt_tx, FRAME);
1118− CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1119− if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1120− i++;
1121− if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
1120+ if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
1121+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
11221122 goto nla_put_failure;
1123− }
1124− if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
1125− dev->ops->join_mesh) {
1126− i++;
1127− if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1123+ if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
1124+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
11281125 goto nla_put_failure;
1129− }
1130− CMD(set_wds_peer, SET_WDS_PEER);
1131− if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1132− CMD(tdls_mgmt, TDLS_MGMT);
1133− CMD(tdls_oper, TDLS_OPER);
1134− }
1135− if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
1136− CMD(sched_scan_start, START_SCHED_SCAN);
1137− CMD(probe_client, PROBE_CLIENT);
1138− CMD(set_noack_map, SET_NOACK_MAP);
1139− if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1140− i++;
1141− if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1126+ if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
1127+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
1128+ goto nla_put_failure;
1129+ if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
1130+ nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
1131+ goto nla_put_failure;
1132+ if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
1133+ nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
1134+ goto nla_put_failure;
1135+ if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
1136+ nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
11421137 goto nla_put_failure;
1143− }
1144− CMD(start_p2p_device, START_P2P_DEVICE);
1145− CMD(set_mcast_rate, SET_MCAST_RATE);
11461138
1147−#ifdef CONFIG_NL80211_TESTMODE
1148− CMD(testmode_cmd, TESTMODE);
1149−#endif
1139+ (*split_start)++;
1140+ if (split)
1141+ break;
1142+ case 1:
1143+ if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
1144+ sizeof(u32) * dev->wiphy.n_cipher_suites,
1145+ dev->wiphy.cipher_suites))
1146+ goto nla_put_failure;
11501147
1151−#undef CMD
1148+ if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
1149+ dev->wiphy.max_num_pmkids))
1150+ goto nla_put_failure;
11521151
1153− if (dev->ops->connect || dev->ops->auth) {
1154− i++;
1155− if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
1152+ if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
1153+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
11561154 goto nla_put_failure;
1157− }
11581155
1159− if (dev->ops->disconnect || dev->ops->deauth) {
1160− i++;
1161− if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1156+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
1157+ dev->wiphy.available_antennas_tx) ||
1158+ nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
1159+ dev->wiphy.available_antennas_rx))
11621160 goto nla_put_failure;
1163− }
11641161
1165− nla_nest_end(msg, nl_cmds);
1162+ if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
1163+ nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
1164+ dev->wiphy.probe_resp_offload))
1165+ goto nla_put_failure;
11661166
1167− if (dev->ops->remain_on_channel &&
1168− (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
1169− nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
1170− dev->wiphy.max_remain_on_channel_duration))
1171− goto nla_put_failure;
1167+ if ((dev->wiphy.available_antennas_tx ||
1168+ dev->wiphy.available_antennas_rx) &&
1169+ dev->ops->get_antenna) {
1170+ u32 tx_ant = 0, rx_ant = 0;
1171+ int res;
1172+ res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
1173+ if (!res) {
1174+ if (nla_put_u32(msg,
1175+ NL80211_ATTR_WIPHY_ANTENNA_TX,
1176+ tx_ant) ||
1177+ nla_put_u32(msg,
1178+ NL80211_ATTR_WIPHY_ANTENNA_RX,
1179+ rx_ant))
1180+ goto nla_put_failure;
1181+ }
1182+ }
11721183
1173− if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
1174− nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1175− goto nla_put_failure;
1184+ (*split_start)++;
1185+ if (split)
1186+ break;
1187+ case 2:
1188+ if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
1189+ dev->wiphy.interface_modes))
1190+ goto nla_put_failure;
1191+ (*split_start)++;
1192+ if (split)
1193+ break;
1194+ case 3:
1195+ nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
1196+ if (!nl_bands)
1197+ goto nla_put_failure;
11761198
1177− if (mgmt_stypes) {
1178− u16 stypes;
1179− struct nlattr *nl_ftypes, *nl_ifs;
1180− enum nl80211_iftype ift;
1199+ for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) {
1200+ struct ieee80211_supported_band *sband;
11811201
1182− nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
1183− if (!nl_ifs)
1184− goto nla_put_failure;
1202+ sband = dev->wiphy.bands[band];
11851203
1186− for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1187− nl_ftypes = nla_nest_start(msg, ift);
1188− if (!nl_ftypes)
1204+ if (!sband)
1205+ continue;
1206+
1207+ nl_band = nla_nest_start(msg, band);
1208+ if (!nl_band)
11891209 goto nla_put_failure;
1190− i = 0;
1191− stypes = mgmt_stypes[ift].tx;
1192− while (stypes) {
1193− if ((stypes & 1) &&
1194− nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1195− (i << 4) | IEEE80211_FTYPE_MGMT))
1210+
1211+ switch (*chan_start) {
1212+ case 0:
1213+ if (nl80211_send_band_rateinfo(msg, sband))
11961214 goto nla_put_failure;
1197− stypes >>= 1;
1198− i++;
1215+ (*chan_start)++;
1216+ if (split)
1217+ break;
1218+ default:
1219+ /* add frequencies */
1220+ nl_freqs = nla_nest_start(
1221+ msg, NL80211_BAND_ATTR_FREQS);
1222+ if (!nl_freqs)
1223+ goto nla_put_failure;
1224+
1225+ for (i = *chan_start - 1;
1226+ i < sband->n_channels;
1227+ i++) {
1228+ nl_freq = nla_nest_start(msg, i);
1229+ if (!nl_freq)
1230+ goto nla_put_failure;
1231+
1232+ chan = &sband->channels[i];
1233+
1234+ if (nl80211_msg_put_channel(msg, chan))
1235+ goto nla_put_failure;
1236+
1237+ nla_nest_end(msg, nl_freq);
1238+ if (split)
1239+ break;
1240+ }
1241+ if (i < sband->n_channels)
1242+ *chan_start = i + 2;
1243+ else
1244+ *chan_start = 0;
1245+ nla_nest_end(msg, nl_freqs);
1246+ }
1247+
1248+ nla_nest_end(msg, nl_band);
1249+
1250+ if (split) {
1251+ /* start again here */
1252+ if (*chan_start)
1253+ band--;
1254+ break;
11991255 }
1200− nla_nest_end(msg, nl_ftypes);
12011256 }
1257+ nla_nest_end(msg, nl_bands);
12021258
1203− nla_nest_end(msg, nl_ifs);
1259+ if (band < IEEE80211_NUM_BANDS)
1260+ *band_start = band + 1;
1261+ else
1262+ *band_start = 0;
12041263
1205− nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
1206− if (!nl_ifs)
1264+ /* if bands & channels are done, continue outside */
1265+ if (*band_start == 0 && *chan_start == 0)
1266+ (*split_start)++;
1267+ if (split)
1268+ break;
1269+ case 4:
1270+ nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
1271+ if (!nl_cmds)
12071272 goto nla_put_failure;
12081273
1209− for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
1210− nl_ftypes = nla_nest_start(msg, ift);
1211− if (!nl_ftypes)
1274+ i = 0;
1275+#define CMD(op, n) \
1276+ do { \
1277+ if (dev->ops->op) { \
1278+ i++; \
1279+ if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
1280+ goto nla_put_failure; \
1281+ } \
1282+ } while (0)
1283+
1284+ CMD(add_virtual_intf, NEW_INTERFACE);
1285+ CMD(change_virtual_intf, SET_INTERFACE);
1286+ CMD(add_key, NEW_KEY);
1287+ CMD(start_ap, START_AP);
1288+ CMD(add_station, NEW_STATION);
1289+ CMD(add_mpath, NEW_MPATH);
1290+ CMD(update_mesh_config, SET_MESH_CONFIG);
1291+ CMD(change_bss, SET_BSS);
1292+ CMD(auth, AUTHENTICATE);
1293+ CMD(assoc, ASSOCIATE);
1294+ CMD(deauth, DEAUTHENTICATE);
1295+ CMD(disassoc, DISASSOCIATE);
1296+ CMD(join_ibss, JOIN_IBSS);
1297+ CMD(join_mesh, JOIN_MESH);
1298+ CMD(set_pmksa, SET_PMKSA);
1299+ CMD(del_pmksa, DEL_PMKSA);
1300+ CMD(flush_pmksa, FLUSH_PMKSA);
1301+ if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
1302+ CMD(remain_on_channel, REMAIN_ON_CHANNEL);
1303+ CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
1304+ CMD(mgmt_tx, FRAME);
1305+ CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
1306+ if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
1307+ i++;
1308+ if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
12121309 goto nla_put_failure;
1213− i = 0;
1214− stypes = mgmt_stypes[ift].rx;
1215− while (stypes) {
1216− if ((stypes & 1) &&
1217− nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
1218− (i << 4) | IEEE80211_FTYPE_MGMT))
1219− goto nla_put_failure;
1220− stypes >>= 1;
1221− i++;
1222− }
1223− nla_nest_end(msg, nl_ftypes);
12241310 }
1225− nla_nest_end(msg, nl_ifs);
1226− }
1311+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
1312+ dev->ops->join_mesh) {
1313+ i++;
1314+ if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
1315+ goto nla_put_failure;
1316+ }
1317+ CMD(set_wds_peer, SET_WDS_PEER);
1318+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
1319+ CMD(tdls_mgmt, TDLS_MGMT);
1320+ CMD(tdls_oper, TDLS_OPER);
1321+ }
1322+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
1323+ CMD(sched_scan_start, START_SCHED_SCAN);
1324+ CMD(probe_client, PROBE_CLIENT);
1325+ CMD(set_noack_map, SET_NOACK_MAP);
1326+ if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
1327+ i++;
1328+ if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1329+ goto nla_put_failure;
1330+ }
1331+ CMD(start_p2p_device, START_P2P_DEVICE);
1332+ CMD(set_mcast_rate, SET_MCAST_RATE);
12271333
1228−#ifdef CONFIG_PM
1229− if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
1230− struct nlattr *nl_wowlan;
1334+#ifdef CONFIG_NL80211_TESTMODE
1335+ CMD(testmode_cmd, TESTMODE);
1336+#endif
12311337
1232− nl_wowlan = nla_nest_start(msg,
1233− NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
1234− if (!nl_wowlan)
1235− goto nla_put_failure;
1338+#undef CMD
12361339
1237− if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
1238− nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
1239− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
1240− nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
1241− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
1242− nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
1243− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
1244− nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
1245− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
1246− nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
1247− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
1248− nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
1249− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
1250− nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
1251− ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
1252− nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
1253− goto nla_put_failure;
1254− if (dev->wiphy.wowlan.n_patterns) {
1255− struct nl80211_wowlan_pattern_support pat = {
1256− .max_patterns = dev->wiphy.wowlan.n_patterns,
1257− .min_pattern_len =
1258− dev->wiphy.wowlan.pattern_min_len,
1259− .max_pattern_len =
1260− dev->wiphy.wowlan.pattern_max_len,
1261− .max_pkt_offset =
1262− dev->wiphy.wowlan.max_pkt_offset,
1263− };
1264− if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
1265− sizeof(pat), &pat))
1340+ if (dev->ops->connect || dev->ops->auth) {
1341+ i++;
1342+ if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
12661343 goto nla_put_failure;
12671344 }
12681345
1269− nla_nest_end(msg, nl_wowlan);
1270− }
1346+ if (dev->ops->disconnect || dev->ops->deauth) {
1347+ i++;
1348+ if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
1349+ goto nla_put_failure;
1350+ }
1351+
1352+ nla_nest_end(msg, nl_cmds);
1353+ (*split_start)++;
1354+ if (split)
1355+ break;
1356+ case 5:
1357+ if (dev->ops->remain_on_channel &&
1358+ (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
1359+ nla_put_u32(msg,
1360+ NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
1361+ dev->wiphy.max_remain_on_channel_duration))
1362+ goto nla_put_failure;
1363+
1364+ if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
1365+ nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
1366+ goto nla_put_failure;
1367+
1368+ if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
1369+ goto nla_put_failure;
1370+ (*split_start)++;
1371+ if (split)
1372+ break;
1373+ case 6:
1374+#ifdef CONFIG_PM
1375+ if (nl80211_send_wowlan(msg, dev))
1376+ goto nla_put_failure;
1377+ (*split_start)++;
1378+ if (split)
1379+ break;
1380+#else
1381+ (*split_start)++;
12711382 #endif
1383+ case 7:
1384+ if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
1385+ dev->wiphy.software_iftypes))
1386+ goto nla_put_failure;
12721387
1273− if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
1274− dev->wiphy.software_iftypes))
1275− goto nla_put_failure;
1388+ if (nl80211_put_iface_combinations(&dev->wiphy, msg))
1389+ goto nla_put_failure;
12761390
1277− if (nl80211_put_iface_combinations(&dev->wiphy, msg))
1278− goto nla_put_failure;
1391+ (*split_start)++;
1392+ if (split)
1393+ break;
1394+ case 8:
1395+ if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
1396+ nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
1397+ dev->wiphy.ap_sme_capa))
1398+ goto nla_put_failure;
12791399
1280− if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
1281− nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
1282− dev->wiphy.ap_sme_capa))
1283− goto nla_put_failure;
1400+ if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS,
1401+ dev->wiphy.features))
1402+ goto nla_put_failure;
12841403
1285− if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS,
1286− dev->wiphy.features))
1287− goto nla_put_failure;
1404+ if (dev->wiphy.ht_capa_mod_mask &&
1405+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
1406+ sizeof(*dev->wiphy.ht_capa_mod_mask),
1407+ dev->wiphy.ht_capa_mod_mask))
1408+ goto nla_put_failure;
12881409
1289− if (dev->wiphy.ht_capa_mod_mask &&
1290− nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
1291− sizeof(*dev->wiphy.ht_capa_mod_mask),
1292− dev->wiphy.ht_capa_mod_mask))
1293− goto nla_put_failure;
1410+ if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1411+ dev->wiphy.max_acl_mac_addrs &&
1412+ nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
1413+ dev->wiphy.max_acl_mac_addrs))
1414+ goto nla_put_failure;
12941415
1295− if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1296− dev->wiphy.max_acl_mac_addrs &&
1297− nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
1298− dev->wiphy.max_acl_mac_addrs))
1299− goto nla_put_failure;
1416+ /*
1417+ * Any information below this point is only available to
1418+ * applications that can deal with it being split. This
1419+ * helps ensure that newly added capabilities don't break
1420+ * older tools by overrunning their buffers.
1421+ *
1422+ * We still increment split_start so that in the split
1423+ * case we'll continue with more data in the next round,
1424+ * but break unconditionally so unsplit data stops here.
1425+ */
1426+ (*split_start)++;
1427+ break;
1428+ case 9:
1429+ /* placeholder */
13001430
1431+ /* done */
1432+ *split_start = 0;
1433+ break;
1434+ }
13011435 return genlmsg_end(msg, hdr);
13021436
13031437 nla_put_failure:
@@ -1310,39 +1444,80 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) · 6 unmodified lines
13101444 int idx = 0, ret;
13111445 int start = cb->args[0];
13121446 struct cfg80211_registered_device *dev;
1447+ s64 filter_wiphy = -1;
1448+ bool split = false;
1449+ struct nlattr **tb = nl80211_fam.attrbuf;
1450+ int res;
13131451
13141452 mutex_lock(&cfg80211_mutex);
1453+ res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1454+ tb, nl80211_fam.maxattr, nl80211_policy);
1455+ if (res == 0) {
1456+ split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
1457+ if (tb[NL80211_ATTR_WIPHY])
1458+ filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
1459+ if (tb[NL80211_ATTR_WDEV])
1460+ filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
1461+ if (tb[NL80211_ATTR_IFINDEX]) {
1462+ struct net_device *netdev;
1463+ int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
1464+
1465+ netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
1466+ if (!netdev) {
1467+ mutex_unlock(&cfg80211_mutex);
1468+ return -ENODEV;
1469+ }
1470+ if (netdev->ieee80211_ptr) {
1471+ dev = wiphy_to_dev(
1472+ netdev->ieee80211_ptr->wiphy);
1473+ filter_wiphy = dev->wiphy_idx;
1474+ }
1475+ dev_put(netdev);
1476+ }
1477+ }
1478+
13151479 list_for_each_entry(dev, &cfg80211_rdev_list, list) {
13161480 if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
13171481 continue;
13181482 if (++idx <= start)
13191483 continue;
1320− ret = nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).portid,
1321− cb->nlh->nlmsg_seq, NLM_F_MULTI,
1322− dev);
1323− if (ret < 0) {
1324− /*
1325− * If sending the wiphy data didn't fit (ENOBUFS or
1326− * EMSGSIZE returned), this SKB is still empty (so
1327− * it's not too big because another wiphy dataset is
1328− * already in the skb) and we've not tried to adjust
1329− * the dump allocation yet ... then adjust the alloc
1330− * size to be bigger, and return 1 but with the empty
1331− * skb. This results in an empty message being RX'ed
1332− * in userspace, but that is ignored.
1333− *
1334− * We can then retry with the larger buffer.
1335− */
1336− if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
1337− !skb->len &&
1338− cb->min_dump_alloc < 4096) {
1339− cb->min_dump_alloc = 4096;
1340− mutex_unlock(&cfg80211_mutex);
1341− return 1;
1484+ if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy)
1485+ continue;
1486+ /* attempt to fit multiple wiphy data chunks into the skb */
1487+ do {
1488+ ret = nl80211_send_wiphy(dev, skb,
1489+ NETLINK_CB(cb->skb).portid,
1490+ cb->nlh->nlmsg_seq,
1491+ NLM_F_MULTI,
1492+ split, &cb->args[1],
1493+ &cb->args[2],
1494+ &cb->args[3]);
1495+ if (ret < 0) {
1496+ /*
1497+ * If sending the wiphy data didn't fit (ENOBUFS
1498+ * or EMSGSIZE returned), this SKB is still
1499+ * empty (so it's not too big because another
1500+ * wiphy dataset is already in the skb) and
1501+ * we've not tried to adjust the dump allocation
1502+ * yet ... then adjust the alloc size to be
1503+ * bigger, and return 1 but with the empty skb.
1504+ * This results in an empty message being RX'ed
1505+ * in userspace, but that is ignored.
1506+ *
1507+ * We can then retry with the larger buffer.
1508+ */
1509+ if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
1510+ !skb->len &&
1511+ cb->min_dump_alloc < 4096) {
1512+ cb->min_dump_alloc = 4096;
1513+ mutex_unlock(&cfg80211_mutex);
1514+ return 1;
1515+ }
1516+ idx--;
1517+ break;
13421518 }
1343− idx--;
1344− break;
1345− }
1519+ } while (cb->args[1] > 0);
1520+ break;
13461521 }
13471522 mutex_unlock(&cfg80211_mutex);
13481523
@@ -1360,7 +1535,8 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) · 11 unmodified lines
13601535 if (!msg)
13611536 return -ENOMEM;
13621537
1363− if (nl80211_send_wiphy(msg, info->snd_portid, info->snd_seq, 0, dev) < 0) {
1538+ if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0,
1539+ false, NULL, NULL, NULL) < 0) {
13641540 nlmsg_free(msg);
13651541 return -ENOBUFS;
13661542 }
@@ -7821,6 +7997,33 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) · 6454 unmodified lines
78217997 return 0;
78227998 }
78237999
8000+static int nl80211_get_protocol_features(struct sk_buff *skb,
8001+ struct genl_info *info)
8002+{
8003+ void *hdr;
8004+ struct sk_buff *msg;
8005+
8006+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8007+ if (!msg)
8008+ return -ENOMEM;
8009+
8010+ hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
8011+ NL80211_CMD_GET_PROTOCOL_FEATURES);
8012+ if (!hdr)
8013+ goto nla_put_failure;
8014+
8015+ if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
8016+ NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
8017+ goto nla_put_failure;
8018+
8019+ genlmsg_end(msg, hdr);
8020+ return genlmsg_reply(msg, info);
8021+
8022+ nla_put_failure:
8023+ kfree_skb(msg);
8024+ return -ENOBUFS;
8025+}
8026+
78248027 #define NL80211_FLAG_NEED_WIPHY 0x01
78258028 #define NL80211_FLAG_NEED_NETDEV 0x02
78268029 #define NL80211_FLAG_NEED_RTNL 0x04
@@ -8497,6 +8700,11 @@ static struct genl_ops nl80211_ops[] = { · 670 unmodified lines
84978700 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
84988701 NL80211_FLAG_NEED_RTNL,
84998702 },
8703+ {
8704+ .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
8705+ .doit = nl80211_get_protocol_features,
8706+ .policy = nl80211_policy,
8707+ },
85008708 };
85018709
85028710 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -8524,7 +8732,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) · 21 unmodified lines
85248732 if (!msg)
85258733 return;
85268734
8527− if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
8735+ if (nl80211_send_wiphy(rdev, msg, 0, 0, 0,
8736+ false, NULL, NULL, NULL) < 0) {
85288737 nlmsg_free(msg);
85298738 return;
85308739 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t