]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OCV: Add function to verify a received OCI element
authorMathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
Mon, 6 Aug 2018 19:46:29 +0000 (15:46 -0400)
committerJouni Malinen <j@w1.fi>
Sun, 16 Dec 2018 22:02:14 +0000 (00:02 +0200)
ocv_verify_tx_params() verifies that the receive OCI element includes
field values that are compatible with the local channel configuration.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
src/common/ocv.c
src/common/ocv.h

index 17f385506a93b631b8e2421223de0519a3edb170..06badfbfb4549b59b4710af0f9a1c9af11fa7a6f 100644 (file)
@@ -93,3 +93,80 @@ int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
        *pos++ = WLAN_EID_EXT_OCV_OCI;
        return ocv_insert_oci(ci, &pos);
 }
+
+
+int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+                        struct wpa_channel_info *ci, int tx_chanwidth,
+                        int tx_seg1_idx)
+{
+       struct oci_info oci;
+
+       if (!oci_ie) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: did not receive mandatory OCI");
+               return -1;
+       }
+
+       if (oci_ie_len != 3) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: received OCI of unexpected length (%d)",
+                           (int) oci_ie_len);
+               return -1;
+       }
+
+       os_memset(&oci, 0, sizeof(oci));
+       oci.op_class = oci_ie[0];
+       oci.channel = oci_ie[1];
+       oci.seg1_idx = oci_ie[2];
+       if (ocv_derive_all_parameters(&oci) != 0) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: unable to interpret received OCI");
+               return -1;
+       }
+
+       /* Primary frequency used to send frames to STA must match the STA's */
+       if ((int) ci->frequency != oci.freq) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
+                           ci->frequency, oci.freq);
+               return -1;
+       }
+
+       /* We shouldn't transmit with a higher bandwidth than the STA supports
+        */
+       if (tx_chanwidth > oci.chanwidth) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
+                           tx_chanwidth, oci.chanwidth);
+               return -1;
+       }
+
+       /*
+        * Secondary channel only needs be checked for 40 MHz in the 2.4 GHz
+        * band. In the 5 GHz band it's verified through the primary frequency.
+        * Note that the field ci->sec_channel is only filled in when we use
+        * 40 MHz.
+        */
+       if (tx_chanwidth == 40 && ci->frequency < 2500 &&
+           ci->sec_channel != oci.sec_channel) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
+                           ci->sec_channel, oci.sec_channel);
+               return -1;
+       }
+
+       /*
+        * When using a 160 or 80+80 MHz channel to transmit, verify that we use
+        * the same segments as the receiver by comparing frequency segment 1.
+        */
+       if ((ci->chanwidth == CHAN_WIDTH_160 ||
+            ci->chanwidth == CHAN_WIDTH_80P80) &&
+           tx_seg1_idx != oci.seg1_idx) {
+               os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+                           "OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
+                           tx_seg1_idx, oci.seg1_idx);
+               return -1;
+       }
+
+       return 0;
+}
index 3f7743876e89b9ce437fd568115b88aad5c043cf..6379d9d06c9ac4c5e85a75f37a02d6ea524a8fd1 100644 (file)
@@ -33,5 +33,8 @@ int ocv_derive_all_parameters(struct oci_info *oci);
 int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
 int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
 int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
+int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+                        struct wpa_channel_info *ci, int tx_chanwidth,
+                        int tx_seg1_idx);
 
 #endif /* OCV_H */