diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 005ed54e0..7bb998dbb 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -147,9 +147,9 @@ /* followed by SSID and Supported rates; and HT capabilities if 802.11n * is used */ -@@ -5831,6 +5848,14 @@ static void handle_assoc(struct hostapd_ - pos, left, rssi, omit_rsnxe); - os_free(tmp); +@@ -5765,6 +5782,13 @@ static void handle_assoc(struct hostapd_ + } + #endif /* CONFIG_FILS */ + ubus_resp = hostapd_ubus_handle_event(hapd, &req); + if (ubus_resp) { @@ -158,11 +158,10 @@ + resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } -+ + fail: + /* - * Remove the station in case transmission of a success response fails - * (the STA was added associated to the driver) or if the station was -@@ -5858,6 +5883,7 @@ static void handle_disassoc(struct hosta +@@ -5858,6 +5882,7 @@ static void handle_disassoc(struct hosta wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code)); @@ -170,7 +169,7 @@ sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { -@@ -5927,6 +5953,8 @@ static void handle_deauth(struct hostapd +@@ -5927,6 +5952,8 @@ static void handle_deauth(struct hostapd /* Clear the PTKSA cache entries for PASN */ ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); @@ -514,3 +513,33 @@ struct os_reltime backlogged_until; #endif /* CONFIG_AIRTIME_POLICY */ +--- a/src/ap/wnm_ap.c ++++ b/src/ap/wnm_ap.c +@@ -463,7 +463,7 @@ static void ieee802_11_rx_bss_trans_mgmt + size_t len) + { + u8 dialog_token, status_code, bss_termination_delay; +- const u8 *pos, *end; ++ const u8 *pos, *end, *target_bssid; + int enabled = hapd->conf->bss_transition; + struct sta_info *sta; + +@@ -510,6 +510,7 @@ static void ieee802_11_rx_bss_trans_mgmt + wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field"); + return; + } ++ target_bssid = pos; + sta->agreed_to_steer = 1; + eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); + eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer, +@@ -529,6 +530,10 @@ static void ieee802_11_rx_bss_trans_mgmt + MAC2STR(addr), status_code, bss_termination_delay); + } + ++ hostapd_ubus_notify_bss_transition_response(hapd, sta->addr, dialog_token, ++ status_code, bss_termination_delay, ++ target_bssid, pos, end - pos); ++ + wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", + pos, end - pos); + } diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c index 367e1b652..69778596a 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.c +++ b/package/network/services/hostapd/src/src/ap/ubus.c @@ -1275,6 +1275,129 @@ hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj, #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, struct blob_attr *neighbors) +{ + struct blob_attr *cur; + struct sta_info *sta; + int nr_len = 0; + int rem; + u8 *nr = NULL; + u8 req_mode = 0; + + sta = ap_get_sta(hapd, addr); + if (!sta) + return UBUS_STATUS_NOT_FOUND; + + if (neighbors) { + u8 *nr_cur; + + if (blobmsg_check_array(neighbors, + BLOBMSG_TYPE_STRING) < 0) + return UBUS_STATUS_INVALID_ARGUMENT; + + blobmsg_for_each_attr(cur, neighbors, rem) { + int len = strlen(blobmsg_get_string(cur)); + + if (len % 2) + return UBUS_STATUS_INVALID_ARGUMENT; + + nr_len += (len / 2) + 2; + } + + if (nr_len) { + nr = os_zalloc(nr_len); + if (!nr) + return UBUS_STATUS_UNKNOWN_ERROR; + } + + nr_cur = nr; + blobmsg_for_each_attr(cur, neighbors, rem) { + int len = strlen(blobmsg_get_string(cur)) / 2; + + *nr_cur++ = WLAN_EID_NEIGHBOR_REPORT; + *nr_cur++ = (u8) len; + if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) { + free(nr); + return UBUS_STATUS_INVALID_ARGUMENT; + } + + nr_cur += len; + } + } + + if (nr) + req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; + + if (abridged) + req_mode |= WNM_BSS_TM_REQ_ABRIDGED; + + 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, @@ -1297,14 +1420,10 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj, { 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; - u8 *nr = NULL; - u8 req_mode = WNM_BSS_TM_REQ_DISASSOC_IMMINENT; u8 addr[ETH_ALEN]; + bool abridged; blobmsg_parse(wnm_disassoc_policy, __WNM_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg)); @@ -1314,61 +1433,13 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj, 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); + if (tb[WNM_DISASSOC_DURATION]) + duration = blobmsg_get_u32(tb[WNM_DISASSOC_DURATION]); - sta = ap_get_sta(hapd, addr); - if (!sta) - return UBUS_STATUS_NOT_FOUND; + abridged = !!(tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED])); - if (tb[WNM_DISASSOC_NEIGHBORS]) { - u8 *nr_cur; - - if (blobmsg_check_array(tb[WNM_DISASSOC_NEIGHBORS], - BLOBMSG_TYPE_STRING) < 0) - return UBUS_STATUS_INVALID_ARGUMENT; - - blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) { - int len = strlen(blobmsg_get_string(cur)); - - if (len % 2) - return UBUS_STATUS_INVALID_ARGUMENT; - - nr_len += (len / 2) + 2; - } - - if (nr_len) { - nr = os_zalloc(nr_len); - if (!nr) - return UBUS_STATUS_UNKNOWN_ERROR; - } - - nr_cur = nr; - blobmsg_for_each_attr(cur, tb[WNM_DISASSOC_NEIGHBORS], rem) { - int len = strlen(blobmsg_get_string(cur)) / 2; - - *nr_cur++ = WLAN_EID_NEIGHBOR_REPORT; - *nr_cur++ = (u8) len; - if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) { - free(nr); - return UBUS_STATUS_INVALID_ARGUMENT; - } - - nr_cur += len; - } - } - - if (nr) - req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; - - if (tb[WNM_DISASSOC_ABRIDGED] && blobmsg_get_bool(tb[WNM_DISASSOC_ABRIDGED])) - req_mode |= WNM_BSS_TM_REQ_ABRIDGED; - - if (wnm_send_bss_tm_req(hapd, sta, req_mode, duration, duration, NULL, - NULL, nr, nr_len, NULL, 0)) - return UBUS_STATUS_UNKNOWN_ERROR; - - return 0; + return hostapd_bss_tr_send(hapd, addr, true, abridged, duration, duration, + tb[WNM_DISASSOC_NEIGHBORS]); } #endif @@ -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 }; @@ -1757,3 +1829,36 @@ void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequen ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1); } } + +void hostapd_ubus_notify_bss_transition_response( + struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code, + u8 bss_termination_delay, const u8 *target_bssid, + const u8 *candidate_list, u16 candidate_list_len) +{ +#ifdef CONFIG_WNM_AP + char *cl_str; + u16 i; + + if (!hapd->ubus.obj.has_subscribers) + return; + + if (!addr) + return; + + blob_buf_init(&b, 0); + blobmsg_add_macaddr(&b, "address", addr); + blobmsg_add_u8(&b, "dialog-token", dialog_token); + blobmsg_add_u8(&b, "status-code", status_code); + blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay); + if (target_bssid) + blobmsg_add_macaddr(&b, "target-bssid", target_bssid); + if (candidate_list_len > 0) { + cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1); + for (i = 0; i < candidate_list_len; i++) + snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]); + blobmsg_add_string_buffer(&b); + } + + ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1); +#endif +} diff --git a/package/network/services/hostapd/src/src/ap/ubus.h b/package/network/services/hostapd/src/src/ap/ubus.h index acdac7436..899b001dd 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.h +++ b/package/network/services/hostapd/src/src/ap/ubus.h @@ -55,6 +55,10 @@ void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd, void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency, int chan_width, int cf1, int cf2); +void hostapd_ubus_notify_bss_transition_response( + struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code, + u8 bss_termination_delay, const u8 *target_bssid, + const u8 *candidate_list, u16 candidate_list_len); void hostapd_ubus_add(struct hapd_interfaces *interfaces); void hostapd_ubus_free(struct hapd_interfaces *interfaces); @@ -107,6 +111,13 @@ static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *ifac { } +static inline void hostapd_ubus_notify_bss_transition_response( + struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code, + u8 bss_termination_delay, const u8 *target_bssid, + const u8 *candidate_list, u16 candidate_list_len) +{ +} + static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces) { }