hostapd: Allow FTM functionality to be published
[mech_eap.git] / src / ap / ieee802_11_shared.c
index 76f78a7..259413b 100644 (file)
@@ -24,13 +24,13 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
 {
        u8 *pos = eid;
        u32 timeout, tu;
-       struct os_time now, passed;
+       struct os_reltime now, passed;
 
        *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
        *pos++ = 5;
        *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-       os_get_time(&now);
-       os_time_sub(&now, &sta->sa_query_start, &passed);
+       os_get_reltime(&now);
+       os_reltime_sub(&now, &sta->sa_query_start, &passed);
        tu = (passed.sec * 1000000 + passed.usec) / 1024;
        if (hapd->conf->assoc_sa_query_max_timeout > tu)
                timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
@@ -69,7 +69,7 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
                  WLAN_SA_QUERY_TR_ID_LEN);
        end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
        if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
-               perror("ieee802_11_send_sa_query_req: send");
+               wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
 }
 
 
@@ -107,7 +107,7 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
                  WLAN_SA_QUERY_TR_ID_LEN);
        end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
        if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
-               perror("ieee80211_mgmt_sa_query_request: send");
+               wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
 }
 
 
@@ -164,10 +164,74 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
 #endif /* CONFIG_IEEE80211W */
 
 
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+       *pos = 0x00;
+
+       switch (idx) {
+       case 0: /* Bits 0-7 */
+               if (hapd->iconf->obss_interval)
+                       *pos |= 0x01; /* Bit 0 - Coexistence management */
+               if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)
+                       *pos |= 0x04; /* Bit 2 - Extended Channel Switching */
+               break;
+       case 1: /* Bits 8-15 */
+               if (hapd->conf->proxy_arp)
+                       *pos |= 0x10; /* Bit 12 - Proxy ARP */
+               break;
+       case 2: /* Bits 16-23 */
+               if (hapd->conf->wnm_sleep_mode)
+                       *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+               if (hapd->conf->bss_transition)
+                       *pos |= 0x08; /* Bit 19 - BSS Transition */
+               break;
+       case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+               *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+               if (hapd->conf->time_advertisement == 2)
+                       *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+               if (hapd->conf->interworking)
+                       *pos |= 0x80; /* Bit 31 - Interworking */
+               break;
+       case 4: /* Bits 32-39 */
+               if (hapd->conf->qos_map_set_len)
+                       *pos |= 0x01; /* Bit 32 - QoS Map */
+               if (hapd->conf->tdls & TDLS_PROHIBIT)
+                       *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+               if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+                       /* Bit 39 - TDLS Channel Switching Prohibited */
+                       *pos |= 0x80;
+               }
+               break;
+       case 5: /* Bits 40-47 */
+#ifdef CONFIG_HS20
+               if (hapd->conf->hs20)
+                       *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+               if (hapd->conf->mbo_enabled)
+                       *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_MBO */
+               break;
+       case 6: /* Bits 48-55 */
+               if (hapd->conf->ssid.utf8_ssid)
+                       *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+               break;
+       case 8: /* Bits 64-71 */
+               if (hapd->conf->ftm_responder)
+                       *pos |= 0x40; /* Bit 70 - FTM responder */
+               if (hapd->conf->ftm_initiator)
+                       *pos |= 0x80; /* Bit 71 - FTM initiator */
+               break;
+       }
+}
+
+
 u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
 {
        u8 *pos = eid;
-       u8 len = 0;
+       u8 len = 0, i;
 
        if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
                len = 5;
@@ -175,59 +239,64 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
                len = 4;
        if (len < 3 && hapd->conf->wnm_sleep_mode)
                len = 3;
+       if (len < 1 && hapd->iconf->obss_interval)
+               len = 1;
        if (len < 7 && hapd->conf->ssid.utf8_ssid)
                len = 7;
+       if (len < 9 &&
+           (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
+               len = 9;
 #ifdef CONFIG_WNM
        if (len < 4)
                len = 4;
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_HS20
+       if (hapd->conf->hs20 && len < 6)
+               len = 6;
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+       if (hapd->conf->mbo_enabled && len < 6)
+               len = 6;
+#endif /* CONFIG_MBO */
+       if (len < hapd->iface->extended_capa_len)
+               len = hapd->iface->extended_capa_len;
        if (len == 0)
                return eid;
 
        *pos++ = WLAN_EID_EXT_CAPAB;
        *pos++ = len;
-       *pos++ = 0x00;
-       *pos++ = 0x00;
+       for (i = 0; i < len; i++, pos++) {
+               hostapd_ext_capab_byte(hapd, pos, i);
 
-       *pos = 0x00;
-       if (hapd->conf->wnm_sleep_mode)
-               *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
-       if (hapd->conf->bss_transition)
-               *pos |= 0x08; /* Bit 19 - BSS Transition */
-       pos++;
+               if (i < hapd->iface->extended_capa_len) {
+                       *pos &= ~hapd->iface->extended_capa_mask[i];
+                       *pos |= hapd->iface->extended_capa[i];
+               }
+       }
 
-       if (len < 4)
-               return pos;
-       *pos = 0x00;
-#ifdef CONFIG_WNM
-       *pos |= 0x02; /* Bit 25 - SSID List */
-#endif /* CONFIG_WNM */
-       if (hapd->conf->time_advertisement == 2)
-               *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
-       if (hapd->conf->interworking)
-               *pos |= 0x80; /* Bit 31 - Interworking */
-       pos++;
+       while (len > 0 && eid[1 + len] == 0) {
+               len--;
+               eid[1] = len;
+       }
+       if (len == 0)
+               return eid;
 
-       if (len < 5)
-               return pos;
-       *pos = 0x00;
-       if (hapd->conf->tdls & TDLS_PROHIBIT)
-               *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
-       if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
-               *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
-       pos++;
+       return eid + 2 + len;
+}
 
-       if (len < 6)
-               return pos;
-       *pos = 0x00;
-       pos++;
 
-       if (len < 7)
-               return pos;
-       *pos = 0x00;
-       if (hapd->conf->ssid.utf8_ssid)
-               *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
-       pos++;
+u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+       u8 len = hapd->conf->qos_map_set_len;
+
+       if (!len)
+               return eid;
+
+       *pos++ = WLAN_EID_QOS_MAP_SET;
+       *pos++ = len;
+       os_memcpy(pos, hapd->conf->qos_map_set, len);
+       pos += len;
 
        return pos;
 }
@@ -456,3 +525,62 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
 
        return pos;
 }
+
+
+#ifdef CONFIG_MBO
+
+u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+       u8 mbo[6], *mbo_pos = mbo;
+       u8 *pos = eid;
+
+       if (!hapd->conf->mbo_enabled)
+               return eid;
+
+       *mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
+       *mbo_pos++ = 1;
+       /* Not Cellular aware */
+       *mbo_pos++ = 0;
+
+       if (hapd->mbo_assoc_disallow) {
+               *mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
+               *mbo_pos++ = 1;
+               *mbo_pos++ = hapd->mbo_assoc_disallow;
+       }
+
+       pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
+
+       return pos;
+}
+
+
+u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
+{
+       if (!hapd->conf->mbo_enabled)
+               return 0;
+
+       /*
+        * MBO IE header (6) + Capability Indication attribute (3) +
+        * Association Disallowed attribute (3) = 12
+        */
+       return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
+}
+
+#endif /* CONFIG_MBO */
+
+
+void ap_copy_sta_supp_op_classes(struct sta_info *sta,
+                                const u8 *supp_op_classes,
+                                size_t supp_op_classes_len)
+{
+       if (!supp_op_classes)
+               return;
+       os_free(sta->supp_op_classes);
+       sta->supp_op_classes = os_malloc(1 + supp_op_classes_len);
+       if (!sta->supp_op_classes)
+               return;
+
+       sta->supp_op_classes[0] = supp_op_classes_len;
+       os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
+                 supp_op_classes_len);
+}