hostapd: add mbo flag to get_clients ubus method
[openwrt/staging/stintel.git] / package / network / services / hostapd / src / src / ap / ubus.c
index 5aad5a7dd5d4a3a2f0a1e4db7542534a6d44171d..622eab8838acc3c4bbce0064e8d0fa237efa412f 100644 (file)
@@ -318,6 +318,10 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
                        blobmsg_add_u8(&b, sta_flags[i].name,
                                       !!(sta->flags & sta_flags[i].flag));
 
+#ifdef CONFIG_MBO
+               blobmsg_add_u8(&b, "mbo", !!(sta->cell_capa));
+#endif
+
                r = blobmsg_open_array(&b, "rrm");
                for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
                        blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
@@ -445,6 +449,12 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
        blobmsg_add_u32(&b, "channel", channel);
        blobmsg_add_u32(&b, "op_class", op_class);
        blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
+#ifdef CONFIG_IEEE80211AX
+       blobmsg_add_u32(&b, "bss_color", hapd->iface->conf->he_op.he_bss_color_disabled ? -1 :
+                                        hapd->iface->conf->he_op.he_bss_color);
+#else
+       blobmsg_add_u32(&b, "bss_color", -1);
+#endif
 
        snprintf(phy_name, 17, "%s", hapd->iface->phy);
        blobmsg_add_string(&b, "phy", phy_name);
@@ -888,10 +898,13 @@ hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
                                css.freq_params.ht_enabled,
                                css.freq_params.vht_enabled,
                                css.freq_params.he_enabled,
+                               css.freq_params.eht_enabled,
                                css.freq_params.sec_channel_offset,
                                chwidth, seg0, seg1,
                                iconf->vht_capab,
                                mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+                               NULL,
+                               mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
                                NULL);
 
        for (i = 0; i < hapd->iface->num_bss; i++) {
@@ -1412,12 +1425,40 @@ hostapd_rrm_lm_req(struct ubus_context *ctx, struct ubus_object *obj,
 }
 
 
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) data;
+       const u8 *pos, *end;
+       u8 token;
+
+       end = data + len;
+       token = mgmt->u.action.u.rrm.dialog_token;
+       pos = mgmt->u.action.u.rrm.variable;
+
+       if (end - pos < 8)
+               return;
+
+       if (!hapd->ubus.obj.has_subscribers)
+               return;
+
+       blob_buf_init(&b, 0);
+       blobmsg_add_macaddr(&b, "address", mgmt->sa);
+       blobmsg_add_u16(&b, "dialog-token", token);
+       blobmsg_add_u16(&b, "rx-antenna-id", pos[4]);
+       blobmsg_add_u16(&b, "tx-antenna-id", pos[5]);
+       blobmsg_add_u16(&b, "rcpi", pos[6]);
+       blobmsg_add_u16(&b, "rsni", pos[7]);
+
+       ubus_notify(ctx, &hapd->ubus.obj, "link-measurement-report", b.head, -1);
+}
+
+
 #ifdef CONFIG_WNM_AP
 
 static int
 hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
                    u16 disassoc_timer, u8 validity_period, u8 dialog_token,
-                   struct blob_attr *neighbors)
+                   struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
 {
        struct blob_attr *cur;
        struct sta_info *sta;
@@ -1425,6 +1466,8 @@ hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent,
        int rem;
        u8 *nr = NULL;
        u8 req_mode = 0;
+       u8 mbo[10];
+       size_t mbo_len = 0;
 
        sta = ap_get_sta(hapd, addr);
        if (!sta)
@@ -1476,8 +1519,37 @@ hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent,
        if (disassoc_imminent)
                req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
 
+#ifdef CONFIG_MBO
+       u8 *mbo_pos = mbo;
+
+       if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+       *mbo_pos++ = 1;
+       *mbo_pos++ = mbo_reason;
+       *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+       *mbo_pos++ = 1;
+       *mbo_pos++ = cell_pref;
+
+       if (reassoc_delay) {
+               *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+               *mbo_pos++ = 2;
+               WPA_PUT_LE16(mbo_pos, reassoc_delay);
+               mbo_pos += 2;
+       }
+
+       mbo_len = mbo_pos - mbo;
+#endif
+
        if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
-                               dialog_token, NULL, nr, nr_len, NULL, 0))
+                               dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
                return UBUS_STATUS_UNKNOWN_ERROR;
 
        return 0;
@@ -1491,6 +1563,11 @@ enum {
        BSS_TR_NEIGHBORS,
        BSS_TR_ABRIDGED,
        BSS_TR_DIALOG_TOKEN,
+#ifdef CONFIG_MBO
+       BSS_TR_MBO_REASON,
+       BSS_TR_CELL_PREF,
+       BSS_TR_REASSOC_DELAY,
+#endif
        __BSS_TR_DISASSOC_MAX
 };
 
@@ -1502,6 +1579,11 @@ static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
        [BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
        [BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
        [BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
+#ifdef CONFIG_MBO
+       [BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
+       [BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
+       [BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
+#endif
 };
 
 static int
@@ -1518,6 +1600,9 @@ hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj
        u32 dialog_token = 1;
        bool abridged;
        bool da_imminent;
+       u8 mbo_reason;
+       u8 cell_pref;
+       u8 reassoc_delay;
 
        blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
 
@@ -1539,52 +1624,19 @@ hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj
        da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
        abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
 
-       return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
-                                  dialog_token, tb[BSS_TR_NEIGHBORS]);
-}
+#ifdef CONFIG_MBO
+       if (tb[BSS_TR_MBO_REASON])
+               mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
 
-enum {
-       WNM_DISASSOC_ADDR,
-       WNM_DISASSOC_DURATION,
-       WNM_DISASSOC_NEIGHBORS,
-       WNM_DISASSOC_ABRIDGED,
-       __WNM_DISASSOC_MAX,
-};
-
-static const struct blobmsg_policy wnm_disassoc_policy[__WNM_DISASSOC_MAX] = {
-       [WNM_DISASSOC_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
-       [WNM_DISASSOC_DURATION] { "duration", BLOBMSG_TYPE_INT32 },
-       [WNM_DISASSOC_NEIGHBORS] { "neighbors", BLOBMSG_TYPE_ARRAY },
-       [WNM_DISASSOC_ABRIDGED] { "abridged", BLOBMSG_TYPE_BOOL },
-};
+       if (tb[BSS_TR_CELL_PREF])
+               cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
 
-static int
-hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
-                             struct ubus_request_data *ureq, const char *method,
-                             struct blob_attr *msg)
-{
-       struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
-       struct blob_attr *tb[__WNM_DISASSOC_MAX];
-       struct sta_info *sta;
-       int duration = 10;
-       u8 addr[ETH_ALEN];
-       bool abridged;
-
-       blobmsg_parse(wnm_disassoc_policy, __WNM_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
-
-       if (!tb[WNM_DISASSOC_ADDR])
-               return UBUS_STATUS_INVALID_ARGUMENT;
-
-       if (hwaddr_aton(blobmsg_data(tb[WNM_DISASSOC_ADDR]), addr))
-               return UBUS_STATUS_INVALID_ARGUMENT;
-
-       if (tb[WNM_DISASSOC_DURATION])
-               duration = blobmsg_get_u32(tb[WNM_DISASSOC_DURATION]);
-
-       abridged = !!(tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]));
+       if (tb[BSS_TR_REASSOC_DELAY])
+               reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
+#endif
 
-       return hostapd_bss_tr_send(hapd, addr, true, abridged, duration, duration,
-                                  1, tb[WNM_DISASSOC_NEIGHBORS]);
+       return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
+                                  dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
 }
 #endif
 
@@ -1670,7 +1722,6 @@ static const struct ubus_method bss_methods[] = {
        UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
        UBUS_METHOD("link_measurement_req", hostapd_rrm_lm_req, lm_req_policy),
 #ifdef CONFIG_WNM_AP
-       UBUS_METHOD("wnm_disassoc_imminent", hostapd_wnm_disassoc_imminent, wnm_disassoc_policy),
        UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
 #endif
 };