si->bss_transition_response.status_code = blobmsg_get_u8(tb[BSS_TM_RESPONSE_STATUS_CODE]);
si->bss_transition_response.timestamp = current_time;
+ if (si->bss_transition_response.status_code) {
+ /* Cancel imminent kick in case BSS transition was rejected */
+ si->kick_time = 0;
+ }
+
return 0;
}
[BR_RSNI] = { .name = "rsni", .type = BLOBMSG_TYPE_INT16 },
};
struct blob_attr *tb[__BR_MAX];
-
- struct usteer_beacon_report br;
struct usteer_node *node;
uint8_t *addr;
struct sta *sta;
if (!node)
return 0;
- br.rcpi = (uint8_t)blobmsg_get_u16(tb[BR_RCPI]);
- br.rsni = (uint8_t)blobmsg_get_u16(tb[BR_RSNI]);
+ usteer_measurement_report_add(sta, node,
+ (uint8_t)blobmsg_get_u16(tb[BR_RCPI]),
+ (uint8_t)blobmsg_get_u16(tb[BR_RSNI]),
+ current_time);
+ return 0;
+}
+
+static int
+usteer_local_node_handle_link_measurement_report(struct usteer_local_node *ln, struct blob_attr *msg)
+{
+ enum {
+ LMR_ADDRESS,
+ LMR_RCPI,
+ LMR_RSNI,
+ __LMR_MAX
+ };
+ struct blobmsg_policy policy[__LMR_MAX] = {
+ [LMR_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING },
+ [LMR_RCPI] = { .name = "rcpi", .type = BLOBMSG_TYPE_INT16 },
+ [LMR_RSNI] = { .name = "rsni", .type = BLOBMSG_TYPE_INT16 },
+ };
+ struct blob_attr *tb[__LMR_MAX];
+ uint8_t *addr;
+ struct sta *sta;
- usteer_measurement_report_add_beacon_report(sta, node, &br, current_time);
+ blobmsg_parse(policy, __LMR_MAX, tb, blob_data(msg), blob_len(msg));
+ if (!tb[LMR_ADDRESS] || !tb[LMR_RCPI] || !tb[LMR_RSNI])
+ return 0;
+
+ addr = (uint8_t *) ether_aton(blobmsg_get_string(tb[LMR_ADDRESS]));
+ if (!addr)
+ return 0;
+
+ sta = usteer_sta_get(addr, false);
+ if (!sta)
+ return 0;
+
+ usteer_measurement_report_add(sta, &ln->node,
+ (uint8_t)blobmsg_get_u16(tb[LMR_RCPI]),
+ (uint8_t)blobmsg_get_u16(tb[LMR_RSNI]),
+ current_time);
return 0;
}
return usteer_handle_bss_tm_response(ln, msg);
} else if(!strcmp(method, "beacon-report")) {
return usteer_local_node_handle_beacon_report(ln, msg);
+ } else if(!strcmp(method, "link-measurement-report")) {
+ return usteer_local_node_handle_link_measurement_report(ln, msg);
}
for (i = 0; i < ARRAY_SIZE(event_types); i++) {
}
static void
-usteer_local_node_update_sta_rrm(const uint8_t *addr, struct blob_attr *client_attr)
+usteer_local_node_update_sta_rrm_wnm(struct sta_info *si, struct blob_attr *client_attr)
{
static const struct blobmsg_policy rrm_policy = {
.name = "rrm",
.type = BLOBMSG_TYPE_ARRAY,
};
- struct blob_attr *sta_blob = NULL;
- struct sta *sta;
+ static const struct blobmsg_policy ext_capa_policy = {
+ .name = "extended_capabilities",
+ .type = BLOBMSG_TYPE_ARRAY,
+ };
+ struct blob_attr *rrm_blob = NULL, *wnm_blob = NULL, *cur;
+ int rem;
+ int i = 0;
- if (!addr)
+ /* RRM */
+ blobmsg_parse(&rrm_policy, 1, &rrm_blob, blobmsg_data(client_attr), blobmsg_data_len(client_attr));
+ if (!rrm_blob)
return;
- /* Don't create the STA */
- sta = usteer_sta_get(addr, false);
- if (!sta)
- return;
+ si->rrm = blobmsg_get_u32(blobmsg_data(rrm_blob));
- blobmsg_parse(&rrm_policy, 1, &sta_blob, blobmsg_data(client_attr), blobmsg_data_len(client_attr));
- if (!sta_blob)
+ /* Extended Capabilities / WNM */
+ blobmsg_parse(&ext_capa_policy, 1, &wnm_blob, blobmsg_data(client_attr), blobmsg_data_len(client_attr));
+ if (!wnm_blob)
return;
- sta->rrm = blobmsg_get_u32(blobmsg_data(sta_blob));
+ blobmsg_for_each_attr(cur, wnm_blob, rem) {
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_INT32)
+ return;
+
+ if (i == 2) {
+ if (blobmsg_get_u32(cur) & (1 << 3))
+ si->bss_transition = true;
+ }
+
+ i++;
+ }
}
static void
}
/* Read RRM information */
- usteer_local_node_update_sta_rrm(addr, cur);
+ usteer_local_node_update_sta_rrm_wnm(si, cur);
}
node->n_assoc = n_assoc;
ubus_complete_request_async(ubus_ctx, &ln->req);
}
+static void
+usteer_local_node_request_link_measurement(struct usteer_local_node *ln)
+{
+ unsigned int min_count = DIV_ROUND_UP(config.link_measurement_interval, config.local_sta_update);
+ struct usteer_node *node;
+ struct sta_info *si;
+
+ node = &ln->node;
+
+ if (ln->link_measurement_tries < min_count) {
+ ln->link_measurement_tries++;
+ return;
+ }
+
+ ln->link_measurement_tries = 0;
+
+ if (!config.link_measurement_interval)
+ return;
+
+ list_for_each_entry(si, &node->sta_info, node_list) {
+ if (si->connected != STA_CONNECTED)
+ continue;
+
+ usteer_ubus_trigger_link_measurement(si);
+ }
+}
+
static void
usteer_local_node_update(struct uloop_timeout *timeout)
{
usteer_local_node_state_reset(ln);
uloop_timeout_set(&ln->req_timer, 1);
usteer_local_node_kick(ln);
+ usteer_band_steering_perform_steer(ln);
+ usteer_local_node_request_link_measurement(ln);
+
uloop_timeout_set(timeout, config.local_sta_update);
}
if (!si)
continue;
- usteer_ubus_bss_transition_request(si, query->dialog_token, false, false, validity_period);
+ usteer_ubus_bss_transition_request(si, query->dialog_token, false, false, validity_period, NULL);
}
/* Free pending queries we can not handle */
blob_buf_init(&b, 0);
blobmsg_add_u8(&b, "neighbor_report", 1);
+ blobmsg_add_u8(&b, "link_measurement", 1);
blobmsg_add_u8(&b, "beacon_report", 1);
blobmsg_add_u8(&b, "bss_transition", 1);
ubus_invoke(ctx, id, "bss_mgmt_enable", b.head, NULL, NULL, 1000);