aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2014-01-08 03:11:11 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-02-03 15:23:36 -0500
commitc87163b9ae894b94c87746fceddb593e7be62ab4 (patch)
tree297225db7073765e964fbe96a309f9dbe56ad616 /drivers/net/wireless/iwlwifi/mvm
parentfc1471f0613b8a31e6905d12e18aab0433375de8 (diff)
iwlwifi: mvm: add basic bcast filtering implementation
Broadcast filtering allows dropping broadcast frames that don't match the configured patterns. Use predefined filters, and configure them for each associated station vif. There is no need to optimize and attach the same filter to multiple vifs, as a following patch will configure each filter to have per-vif unique values. Configure the bcast filtering on assoc changes. Add a new IWLWIFI_BCAST_FILTERING Kconfig option in order to enable broadcast filtering. Signed-off-by: Eliad Peller <eliadx.peller@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h85
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c116
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c1
4 files changed, 207 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 21ee59e88b85..32844e3f5a85 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -191,6 +191,7 @@ enum {
191 REPLY_DEBUG_CMD = 0xf0, 191 REPLY_DEBUG_CMD = 0xf0,
192 DEBUG_LOG_MSG = 0xf7, 192 DEBUG_LOG_MSG = 0xf7,
193 193
194 BCAST_FILTER_CMD = 0xcf,
194 MCAST_FILTER_CMD = 0xd0, 195 MCAST_FILTER_CMD = 0xd0,
195 196
196 /* D3 commands/notifications */ 197 /* D3 commands/notifications */
@@ -1156,6 +1157,90 @@ struct iwl_mcast_filter_cmd {
1156 u8 addr_list[0]; 1157 u8 addr_list[0];
1157} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ 1158} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
1158 1159
1160#define MAX_BCAST_FILTERS 8
1161#define MAX_BCAST_FILTER_ATTRS 2
1162
1163/**
1164 * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet
1165 * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start.
1166 * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e.
1167 * start of ip payload).
1168 */
1169enum iwl_mvm_bcast_filter_attr_offset {
1170 BCAST_FILTER_OFFSET_PAYLOAD_START = 0,
1171 BCAST_FILTER_OFFSET_IP_END = 1,
1172};
1173
1174/**
1175 * struct iwl_fw_bcast_filter_attr - broadcast filter attribute
1176 * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset.
1177 * @offset: starting offset of this pattern.
1178 * @val: value to match - big endian (MSB is the first
1179 * byte to match from offset pos).
1180 * @mask: mask to match (big endian).
1181 */
1182struct iwl_fw_bcast_filter_attr {
1183 u8 offset_type;
1184 u8 offset;
1185 __le16 reserved1;
1186 __be32 val;
1187 __be32 mask;
1188} __packed; /* BCAST_FILTER_ATT_S_VER_1 */
1189
1190/**
1191 * enum iwl_mvm_bcast_filter_frame_type - filter frame type
1192 * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames.
1193 * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames
1194 */
1195enum iwl_mvm_bcast_filter_frame_type {
1196 BCAST_FILTER_FRAME_TYPE_ALL = 0,
1197 BCAST_FILTER_FRAME_TYPE_IPV4 = 1,
1198};
1199
1200/**
1201 * struct iwl_fw_bcast_filter - broadcast filter
1202 * @discard: discard frame (1) or let it pass (0).
1203 * @frame_type: &enum iwl_mvm_bcast_filter_frame_type.
1204 * @num_attrs: number of valid attributes in this filter.
1205 * @attrs: attributes of this filter. a filter is considered matched
1206 * only when all its attributes are matched (i.e. AND relationship)
1207 */
1208struct iwl_fw_bcast_filter {
1209 u8 discard;
1210 u8 frame_type;
1211 u8 num_attrs;
1212 u8 reserved1;
1213 struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS];
1214} __packed; /* BCAST_FILTER_S_VER_1 */
1215
1216/**
1217 * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration.
1218 * @default_discard: default action for this mac (discard (1) / pass (0)).
1219 * @attached_filters: bitmap of relevant filters for this mac.
1220 */
1221struct iwl_fw_bcast_mac {
1222 u8 default_discard;
1223 u8 reserved1;
1224 __le16 attached_filters;
1225} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */
1226
1227/**
1228 * struct iwl_bcast_filter_cmd - broadcast filtering configuration
1229 * @disable: enable (0) / disable (1)
1230 * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS)
1231 * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER)
1232 * @filters: broadcast filters
1233 * @macs: broadcast filtering configuration per-mac
1234 */
1235struct iwl_bcast_filter_cmd {
1236 u8 disable;
1237 u8 max_bcast_filters;
1238 u8 max_macs;
1239 u8 reserved1;
1240 struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS];
1241 struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
1242} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
1243
1159struct mvm_statistics_dbg { 1244struct mvm_statistics_dbg {
1160 __le32 burst_check; 1245 __le32 burst_check;
1161 __le32 burst_count; 1246 __le32 burst_count;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 5b9cfe1f35bd..08b8051e56f8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -872,6 +872,121 @@ out:
872 *total_flags = 0; 872 *total_flags = 0;
873} 873}
874 874
875#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
876struct iwl_bcast_iter_data {
877 struct iwl_mvm *mvm;
878 struct iwl_bcast_filter_cmd *cmd;
879 u8 current_filter;
880};
881
882static void
883iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif,
884 const struct iwl_fw_bcast_filter *in_filter,
885 struct iwl_fw_bcast_filter *out_filter)
886{
887 struct iwl_fw_bcast_filter_attr *attr;
888 int i;
889
890 memcpy(out_filter, in_filter, sizeof(*out_filter));
891
892 for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) {
893 attr = &out_filter->attrs[i];
894
895 if (!attr->mask)
896 break;
897
898 out_filter->num_attrs++;
899 }
900}
901
902static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac,
903 struct ieee80211_vif *vif)
904{
905 struct iwl_bcast_iter_data *data = _data;
906 struct iwl_mvm *mvm = data->mvm;
907 struct iwl_bcast_filter_cmd *cmd = data->cmd;
908 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
909 struct iwl_fw_bcast_mac *bcast_mac;
910 int i;
911
912 if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs)))
913 return;
914
915 bcast_mac = &cmd->macs[mvmvif->id];
916
917 /* enable filtering only for associated stations */
918 if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc)
919 return;
920
921 bcast_mac->default_discard = 1;
922
923 /* copy all configured filters */
924 for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) {
925 /*
926 * Make sure we don't exceed our filters limit.
927 * if there is still a valid filter to be configured,
928 * be on the safe side and just allow bcast for this mac.
929 */
930 if (WARN_ON_ONCE(data->current_filter >=
931 ARRAY_SIZE(cmd->filters))) {
932 bcast_mac->default_discard = 0;
933 bcast_mac->attached_filters = 0;
934 break;
935 }
936
937 iwl_mvm_set_bcast_filter(vif,
938 &mvm->bcast_filters[i],
939 &cmd->filters[data->current_filter]);
940
941 /* skip current filter if it contains no attributes */
942 if (!cmd->filters[data->current_filter].num_attrs)
943 continue;
944
945 /* attach the filter to current mac */
946 bcast_mac->attached_filters |=
947 cpu_to_le16(BIT(data->current_filter));
948
949 data->current_filter++;
950 }
951}
952
953static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
954 struct ieee80211_vif *vif)
955{
956 /* initialize cmd to pass broadcasts on all vifs */
957 struct iwl_bcast_filter_cmd cmd = {
958 .disable = 0,
959 .max_bcast_filters = ARRAY_SIZE(cmd.filters),
960 .max_macs = ARRAY_SIZE(cmd.macs),
961 };
962 struct iwl_bcast_iter_data iter_data = {
963 .mvm = mvm,
964 .cmd = &cmd,
965 };
966
967 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
968 return 0;
969
970 /* if no filters are configured, do nothing */
971 if (!mvm->bcast_filters)
972 return 0;
973
974 /* configure and attach these filters for each associated sta vif */
975 ieee80211_iterate_active_interfaces(
976 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
977 iwl_mvm_bcast_filter_iterator, &iter_data);
978
979 return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
980 sizeof(cmd), &cmd);
981}
982#else
983static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
984 struct ieee80211_vif *vif)
985{
986 return 0;
987}
988#endif
989
875static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, 990static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
876 struct ieee80211_vif *vif, 991 struct ieee80211_vif *vif,
877 struct ieee80211_bss_conf *bss_conf, 992 struct ieee80211_bss_conf *bss_conf,
@@ -944,6 +1059,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
944 } 1059 }
945 1060
946 iwl_mvm_recalc_multicast(mvm); 1061 iwl_mvm_recalc_multicast(mvm);
1062 iwl_mvm_configure_bcast_filter(mvm, vif);
947 1063
948 /* reset rssi values */ 1064 /* reset rssi values */
949 mvmvif->bf_data.ave_beacon_signal = 0; 1065 mvmvif->bf_data.ave_beacon_signal = 0;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 00bc4ce06cca..2da17d107ab3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -497,6 +497,11 @@ struct iwl_mvm {
497 /* rx chain antennas set through debugfs for the scan command */ 497 /* rx chain antennas set through debugfs for the scan command */
498 u8 scan_rx_ant; 498 u8 scan_rx_ant;
499 499
500#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
501 /* broadcast filters to configure for each associated station */
502 const struct iwl_fw_bcast_filter *bcast_filters;
503#endif
504
500 /* Internal station */ 505 /* Internal station */
501 struct iwl_mvm_int_sta aux_sta; 506 struct iwl_mvm_int_sta aux_sta;
502 507
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index fdadfe95d314..24afbd60c02e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -313,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
313 CMD(BT_PROFILE_NOTIFICATION), 313 CMD(BT_PROFILE_NOTIFICATION),
314 CMD(BT_CONFIG), 314 CMD(BT_CONFIG),
315 CMD(MCAST_FILTER_CMD), 315 CMD(MCAST_FILTER_CMD),
316 CMD(BCAST_FILTER_CMD),
316 CMD(REPLY_SF_CFG_CMD), 317 CMD(REPLY_SF_CFG_CMD),
317 CMD(REPLY_BEACON_FILTERING_CMD), 318 CMD(REPLY_BEACON_FILTERING_CMD),
318 CMD(REPLY_THERMAL_MNG_BACKOFF), 319 CMD(REPLY_THERMAL_MNG_BACKOFF),