ieee80211: Support parsing TPC report element in action frames
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Wed, 30 Jul 2014 11:36:18 +0000 (14:36 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 26 Aug 2014 09:15:58 +0000 (11:15 +0200)
TPC report element is contained in spectrum management's tpc report
action frames and in radio measurement's link measurement report
action frames. Add a function which checks whether an action frame
contains this element. This may be needed by the drivers in order
to set the correct tx power value in these frames.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/linux/ieee80211.h

index 63ab387..8018c91 100644 (file)
@@ -838,6 +838,16 @@ enum ieee80211_vht_opmode_bits {
 
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 
+/**
+ * struct ieee80211_tpc_report_ie
+ *
+ * This structure refers to "TPC Report element"
+ */
+struct ieee80211_tpc_report_ie {
+       u8 tx_power;
+       u8 link_margin;
+} __packed;
+
 struct ieee80211_mgmt {
        __le16 frame_control;
        __le16 duration;
@@ -973,6 +983,13 @@ struct ieee80211_mgmt {
                                        u8 action_code;
                                        u8 operating_mode;
                                } __packed vht_opmode_notif;
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       u8 tpc_elem_id;
+                                       u8 tpc_elem_length;
+                                       struct ieee80211_tpc_report_ie tpc;
+                               } __packed tpc_report;
                        } u;
                } __packed action;
        } u;
@@ -1865,6 +1882,7 @@ enum ieee80211_category {
        WLAN_CATEGORY_DLS = 2,
        WLAN_CATEGORY_BACK = 3,
        WLAN_CATEGORY_PUBLIC = 4,
+       WLAN_CATEGORY_RADIO_MEASUREMENT = 5,
        WLAN_CATEGORY_HT = 7,
        WLAN_CATEGORY_SA_QUERY = 8,
        WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
@@ -2378,4 +2396,51 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
 #define TU_TO_JIFFIES(x)       (usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)      (jiffies + TU_TO_JIFFIES(x))
 
+/**
+ * ieee80211_action_contains_tpc - checks if the frame contains TPC element
+ * @skb: the skb containing the frame, length will be checked
+ *
+ * This function checks if it's either TPC report action frame or Link
+ * Measurement report action frame as defined in IEEE Std. 802.11-2012 8.5.2.5
+ * and 8.5.7.5 accordingly.
+ */
+static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
+{
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+       if (!ieee80211_is_action(mgmt->frame_control))
+               return false;
+
+       if (skb->len < IEEE80211_MIN_ACTION_SIZE +
+                      sizeof(mgmt->u.action.u.tpc_report))
+               return false;
+
+       /*
+        * TPC report - check that:
+        * category = 0 (Spectrum Management) or 5 (Radio Measurement)
+        * spectrum management action = 3 (TPC/Link Measurement report)
+        * TPC report EID = 35
+        * TPC report element length = 2
+        *
+        * The spectrum management's tpc_report struct is used here both for
+        * parsing tpc_report and radio measurement's link measurement report
+        * frame, since the relevant part is identical in both frames.
+        */
+       if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT &&
+           mgmt->u.action.category != WLAN_CATEGORY_RADIO_MEASUREMENT)
+               return false;
+
+       /* both spectrum mgmt and link measurement have same action code */
+       if (mgmt->u.action.u.tpc_report.action_code !=
+           WLAN_ACTION_SPCT_TPC_RPRT)
+               return false;
+
+       if (mgmt->u.action.u.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT ||
+           mgmt->u.action.u.tpc_report.tpc_elem_length !=
+           sizeof(struct ieee80211_tpc_report_ie))
+               return false;
+
+       return true;
+}
+
 #endif /* LINUX_IEEE80211_H */