policy: make roam-steers client-rejectable
[project/usteer.git] / local_node.c
index 9f4a2df41c997f2d43c9366996a56099ffc259c6..92c2dcbddd31f92aeb10038e1157c63dba6275f3 100644 (file)
@@ -180,6 +180,11 @@ usteer_handle_bss_tm_response(struct usteer_local_node *ln, struct blob_attr *ms
        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;
 }
 
@@ -344,28 +349,43 @@ usteer_local_node_assoc_update(struct sta_info *si, struct blob_attr *data)
 }
 
 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
@@ -408,7 +428,7 @@ usteer_local_node_set_assoc(struct usteer_local_node *ln, struct blob_attr *cl)
                }
 
                /* 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;
@@ -457,12 +477,14 @@ usteer_local_node_status_cb(struct ubus_request *req, int type, struct blob_attr
                MSG_FREQ,
                MSG_CHANNEL,
                MSG_OP_CLASS,
+               MSG_BEACON_INTERVAL,
                __MSG_MAX,
        };
        static struct blobmsg_policy policy[__MSG_MAX] = {
                [MSG_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
                [MSG_CHANNEL] = { "channel", BLOBMSG_TYPE_INT32 },
                [MSG_OP_CLASS] = { "op_class", BLOBMSG_TYPE_INT32 },
+               [MSG_BEACON_INTERVAL] = { "beacon_interval", BLOBMSG_TYPE_INT32 },
        };
        struct blob_attr *tb[__MSG_MAX];
        struct usteer_local_node *ln;
@@ -476,8 +498,12 @@ usteer_local_node_status_cb(struct ubus_request *req, int type, struct blob_attr
                node->freq = blobmsg_get_u32(tb[MSG_FREQ]);
        if (tb[MSG_CHANNEL])
                node->channel = blobmsg_get_u32(tb[MSG_CHANNEL]);
-       if (tb[MSG_FREQ])
+       if (tb[MSG_OP_CLASS])
                node->op_class = blobmsg_get_u32(tb[MSG_OP_CLASS]);     
+
+       /* Local-Node */
+       if (tb[MSG_BEACON_INTERVAL])
+               ln->beacon_interval = blobmsg_get_u32(tb[MSG_BEACON_INTERVAL]);
 }
 
 static void
@@ -627,12 +653,13 @@ usteer_local_node_process_bss_tm_queries(struct uloop_timeout *timeout)
        struct usteer_node *node;
        struct sta_info *si;
        struct sta *sta;
-
-       uint8_t validity_period = 100; /* ~ 10 seconds */
+       uint8_t validity_period;
 
        ln = container_of(timeout, struct usteer_local_node, bss_tm_queries_timeout);
        node = &ln->node;
 
+       validity_period = 10000 / usteer_local_node_get_beacon_interval(ln); /* ~ 10 seconds */
+
        list_for_each_entry_safe(query, tmp, &ln->bss_tm_queries, list) {
                sta = usteer_sta_get(query->sta_addr, false);
                if (!sta)
@@ -806,6 +833,16 @@ node_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv)
        usteer_register_node(ctx, obj->path, obj->id);
 }
 
+int
+usteer_local_node_get_beacon_interval(struct usteer_local_node *ln)
+{
+       /* Check if beacon-interval is not available (pre-21.02+) */
+       if (ln->beacon_interval < 1)
+               return 100;
+
+       return ln->beacon_interval;
+}
+
 void config_set_node_up_script(struct blob_attr *data)
 {
        const char *val;