|
|
@@ -1275,60 +1275,30 @@ hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_WNM_AP
|
|
|
-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 },
|
|
|
-};
|
|
|
|
|
|
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)
|
|
|
+hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
|
|
|
+ u16 disassoc_timer, u8 validity_period, struct blob_attr *neighbors)
|
|
|
{
|
|
|
- struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
|
|
|
- struct blob_attr *tb[__WNM_DISASSOC_MAX];
|
|
|
struct blob_attr *cur;
|
|
|
struct sta_info *sta;
|
|
|
- int duration = 10;
|
|
|
- int rem;
|
|
|
int nr_len = 0;
|
|
|
+ int rem;
|
|
|
u8 *nr = NULL;
|
|
|
- u8 req_mode = WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
|
|
|
- u8 addr[ETH_ALEN];
|
|
|
-
|
|
|
- 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 ((cur = tb[WNM_DISASSOC_DURATION]) != NULL)
|
|
|
- duration = blobmsg_get_u32(cur);
|
|
|
+ u8 req_mode = 0;
|
|
|
|
|
|
sta = ap_get_sta(hapd, addr);
|
|
|
if (!sta)
|
|
|
return UBUS_STATUS_NOT_FOUND;
|
|
|
|
|
|
- if (tb[WNM_DISASSOC_NEIGHBORS]) {
|
|
|
+ if (neighbors) {
|
|
|
u8 *nr_cur;
|
|
|
|
|
|
- if (blobmsg_check_array(tb[WNM_DISASSOC_NEIGHBORS],
|
|
|
+ if (blobmsg_check_array(neighbors,
|
|
|
BLOBMSG_TYPE_STRING) < 0)
|
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
|
|
|
- blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
|
|
|
+ blobmsg_for_each_attr(cur, neighbors, rem) {
|
|
|
int len = strlen(blobmsg_get_string(cur));
|
|
|
|
|
|
if (len % 2)
|
|
|
@@ -1344,7 +1314,7 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
}
|
|
|
|
|
|
nr_cur = nr;
|
|
|
- blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) {
|
|
|
+ blobmsg_for_each_attr(cur, neighbors, rem) {
|
|
|
int len = strlen(blobmsg_get_string(cur)) / 2;
|
|
|
|
|
|
*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
|
|
|
@@ -1361,15 +1331,116 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
if (nr)
|
|
|
req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
|
|
|
|
|
|
- if (tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED]))
|
|
|
+ if (abridged)
|
|
|
req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
|
|
|
|
|
|
- if (wnm_send_bss_tm_req(hapd, sta, req_mode, duration, duration, NULL,
|
|
|
+ if (disassoc_imminent)
|
|
|
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
|
|
|
+
|
|
|
+ if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
|
|
|
NULL, nr, nr_len, NULL, 0))
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+enum {
|
|
|
+ BSS_TR_ADDR,
|
|
|
+ BSS_TR_DA_IMMINENT,
|
|
|
+ BSS_TR_DA_TIMER,
|
|
|
+ BSS_TR_VALID_PERIOD,
|
|
|
+ BSS_TR_NEIGHBORS,
|
|
|
+ BSS_TR_ABRIDGED,
|
|
|
+ __BSS_TR_DISASSOC_MAX
|
|
|
+};
|
|
|
+
|
|
|
+static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
|
|
|
+ [BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
|
|
|
+ [BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
|
|
|
+ [BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
|
|
|
+ [BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
|
|
|
+ [BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
|
|
|
+ [BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
|
|
|
+};
|
|
|
+
|
|
|
+static int
|
|
|
+hostapd_bss_transition_request(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[__BSS_TR_DISASSOC_MAX];
|
|
|
+ struct sta_info *sta;
|
|
|
+ u32 da_timer = 0;
|
|
|
+ u32 valid_period = 0;
|
|
|
+ u8 addr[ETH_ALEN];
|
|
|
+ bool abridged;
|
|
|
+ bool da_imminent;
|
|
|
+
|
|
|
+ blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
|
|
|
+
|
|
|
+ if (!tb[BSS_TR_ADDR])
|
|
|
+ return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
+
|
|
|
+ if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
|
|
|
+ return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
+
|
|
|
+ if (tb[BSS_TR_DA_TIMER])
|
|
|
+ da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
|
|
|
+
|
|
|
+ if (tb[BSS_TR_VALID_PERIOD])
|
|
|
+ valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
|
|
|
+
|
|
|
+ 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,
|
|
|
+ tb[BSS_TR_NEIGHBORS]);
|
|
|
+}
|
|
|
+
|
|
|
+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 },
|
|
|
+};
|
|
|
+
|
|
|
+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]));
|
|
|
+
|
|
|
+ return hostapd_bss_tr_send(hapd, addr, true, abridged, duration, duration,
|
|
|
+ tb[WNM_DISASSOC_NEIGHBORS]);
|
|
|
+}
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_AIRTIME_POLICY
|
|
|
@@ -1454,6 +1525,7 @@ static const struct ubus_method bss_methods[] = {
|
|
|
UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_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
|
|
|
};
|
|
|
|