diff --git a/src/core/cntlr_tlv_generator.c b/src/core/cntlr_tlv_generator.c index 72df47432ec3b8a17520079176ef1468a0ac1cd2..59496837c965f7ff5b57dd3268eb1a67c874987c 100644 --- a/src/core/cntlr_tlv_generator.c +++ b/src/core/cntlr_tlv_generator.c @@ -480,3 +480,42 @@ struct tlv_backhaul_steer_req *cntlr_gen_backhaul_steer_req(struct controller *c p->op_class = op_class; return p; } + +struct tlv_client_assoc_control_req *cntlr_gen_assoc_control_req( + uint8_t *bss_id, uint32_t assoc_cntl_mode, uint32_t assoc_timeout, + uint32_t sta_nr, uint8_t sta_id[][18]) +{ + struct tlv_client_assoc_control_req *p = NULL; + int j = 0; + + p = calloc(1, sizeof(struct tlv_client_assoc_control_req)); + if (!p) { + fprintf(stderr, "failed to malloc cmdu\n"); + return NULL; + } + + p->tlv_type = MAP_TLV_CLIENT_ASSOCIATION_CONTROL_REQUEST; + hwaddr_aton(bss_id, p->bssid); + p->validity_period = assoc_timeout; + p->assoc_control = assoc_cntl_mode; + p->sta_list_cnt = sta_nr; + + if (p->sta_list_cnt > 0) { + p->client_assoc_ctrl_req_stas = calloc(p->sta_list_cnt, + sizeof(*p->client_assoc_ctrl_req_stas)); + if (!p->client_assoc_ctrl_req_stas) { + fprintf(stderr, "|%s:%d| out of memory!\n", + __func__, __LINE__); + p->sta_list_cnt = 0; + goto fail_p; + } + } + for (j = 0; j < p->sta_list_cnt; j++) + hwaddr_aton(sta_id[j], p->client_assoc_ctrl_req_stas[j].addr); + + return p; +fail_p: + if (p != NULL) + map_free_tlv_cstruct((uint8_t *) p); + return NULL; +} diff --git a/src/core/cntlr_tlv_generator.h b/src/core/cntlr_tlv_generator.h index 74adb4f98a713331f0cf2db65dd27d67d43c6dad..4296df10beec01f5a0dc25b2c3c506e83844a09a 100644 --- a/src/core/cntlr_tlv_generator.h +++ b/src/core/cntlr_tlv_generator.h @@ -48,4 +48,7 @@ struct tlv_client_info *cntlr_gen_client_info(struct controller *c, struct tlv_backhaul_steer_req *cntlr_gen_backhaul_steer_req(struct controller *c, uint8_t *bssid, uint8_t *bkhaul, uint8_t op_class, uint8_t channel); +struct tlv_client_assoc_control_req *cntlr_gen_assoc_control_req( + uint8_t *bss_id, uint32_t assoc_cntl_mode, uint32_t assoc_timeout, + uint32_t sta_nr, uint8_t sta_id[][18]); #endif diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c index bc383006588ca63e19c75edcf08d08fe2b85dc69..5a70e03fee3223628dc15c03b013f199ccaa7c89 100644 --- a/src/core/cntlr_ubus.c +++ b/src/core/cntlr_ubus.c @@ -149,6 +149,23 @@ static const struct blobmsg_policy ap_policy_config_params[__AP_POLICY_CONFIG_MA [AP_POLICY_CONFIG_BSS] = { .name = "bsslist", .type = BLOBMSG_TYPE_ARRAY }, }; +enum { + CLIENT_POLICY_ASSOC_CONTROL_AGENT, + CLIENT_POLICY_ASSOC_CONTROL_BSSID, + CLIENT_POLICY_ASSOC_CONTROL_MODE, + CLIENT_POLICY_ASSOC_CONTROL_VALID_TIME, + CLIENT_POLICY_ASSOC_CONTROL_STALIST, + __CLIENT_POLICY_ASSOC_CONTROL_MAX, +}; + +static const struct blobmsg_policy client_assoc_cntrl_policy_config_params[__CLIENT_POLICY_ASSOC_CONTROL_MAX] = { + [CLIENT_POLICY_ASSOC_CONTROL_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING }, + [CLIENT_POLICY_ASSOC_CONTROL_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, + [CLIENT_POLICY_ASSOC_CONTROL_MODE] = { .name = "assoc_cntl_mode", .type = BLOBMSG_TYPE_INT32 }, + [CLIENT_POLICY_ASSOC_CONTROL_VALID_TIME] = { .name = "assoc_valid_timeout", .type = BLOBMSG_TYPE_INT32 }, + [CLIENT_POLICY_ASSOC_CONTROL_STALIST] = { .name = "stalist", .type = BLOBMSG_TYPE_ARRAY }, +}; + void send_cmdu_cb(struct ubus_request *req, int type, struct blob_attr *msg) { @@ -576,6 +593,108 @@ fail_cmdu: return UBUS_STATUS_UNKNOWN_ERROR; } +static int client_assoc_cntlr(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CLIENT_POLICY_ASSOC_CONTROL_MAX]; + struct controller *c = container_of(obj, struct controller, obj); + char agent[18] = {0}; + char bss_id[18] = {0}; + struct cmdu_cstruct *cmdu_data; + uint32_t assoc_cntl_mode = 0, assoc_timeout = 0, sta_nr = 0; + uint32_t bssid_present = -1, sta_present = -1; + uint32_t assoc_timeout_present = -1, tlv_index = 0; + char sta_id[30][18] = {0}; + struct tlv_client_assoc_control_req *p = NULL; + uint32_t count = 0, j = 0, l = 0; + struct blob_attr *cur; + int rem = 0; + + cmdu_data = (struct cmdu_cstruct *)calloc(1, + sizeof(struct cmdu_cstruct)); + if (!cmdu_data) { + fprintf(stderr, "failed to malloc cmdu\n"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + blobmsg_parse(client_assoc_cntrl_policy_config_params, + __CLIENT_POLICY_ASSOC_CONTROL_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (tb[CLIENT_POLICY_ASSOC_CONTROL_AGENT]) { + strncpy(agent, blobmsg_data(tb[CLIENT_POLICY_ASSOC_CONTROL_AGENT]), + sizeof(agent) - 1); + if (!hwaddr_aton(agent, cmdu_data->origin)) + return UBUS_STATUS_UNKNOWN_ERROR; + } + + // TODO: ff:ff:ff:ff:ff:ff = send to all agents + + if (tb[CLIENT_POLICY_ASSOC_CONTROL_BSSID]) { + strncpy(bss_id, blobmsg_data(tb[CLIENT_POLICY_ASSOC_CONTROL_BSSID]), + sizeof(bss_id) - 1); + bssid_present = 1; + } + + if (tb[CLIENT_POLICY_ASSOC_CONTROL_MODE]) + assoc_cntl_mode = (int) blobmsg_get_u32( + tb[CLIENT_POLICY_ASSOC_CONTROL_MODE]); + + if (tb[CLIENT_POLICY_ASSOC_CONTROL_VALID_TIME]) { + assoc_timeout_present = 1; + assoc_timeout = (int) blobmsg_get_u32( + tb[CLIENT_POLICY_ASSOC_CONTROL_VALID_TIME]); + } + + if (tb[CLIENT_POLICY_ASSOC_CONTROL_STALIST]) { + sta_present = 1; + sta_nr = blobmsg_check_array(tb[CLIENT_POLICY_ASSOC_CONTROL_STALIST], + BLOBMSG_TYPE_STRING); + l = 0; + blobmsg_for_each_attr(cur, tb[CLIENT_POLICY_ASSOC_CONTROL_STALIST], rem) + strncpy(sta_id[l++], blobmsg_get_string(cur), 18); + } + + cmdu_data->message_type = CMDU_CLIENT_ASSOC_CONTROL_REQUEST; + + if (bssid_present == 1 && sta_present == 1 && assoc_timeout_present == 1 + && assoc_cntl_mode >= 0) { + + trace("values are assoc_mode %d assoc_timeout %d sta_cnt %d\n", + assoc_cntl_mode, assoc_timeout, sta_nr); + + /* Client ASSOC CONTROL TLV REQUEST 17.2.31 */ + p = cntlr_gen_assoc_control_req(bss_id, assoc_cntl_mode, + assoc_timeout, sta_nr, sta_id); + if (!p) + goto fail_cmdu; + count++; + } + + cmdu_data->num_tlvs = count; + + /*This CMDU has one or more TLVs*/ + if (cmdu_data->num_tlvs == 0) { + fprintf(stderr, "|%s:%d| No TLvs\n", __func__, __LINE__); + goto fail_cmdu; + } + + cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs, + sizeof(uint8_t *)); + if (cmdu_data->tlvs && p != NULL) + cmdu_data->tlvs[tlv_index++] = (uint8_t *)p; + send_cmdu(c, cmdu_data); + map_free_cmdu(cmdu_data); + return 0; +fail_p: + if (p != NULL) + map_free_tlv_cstruct((uint8_t *) p); +fail_cmdu: + map_free_cmdu(cmdu_data); + return UBUS_STATUS_UNKNOWN_ERROR; +} + static int cntlr_sta_caps(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) @@ -1106,7 +1225,7 @@ int cntlr_publish_object(struct controller *c, const char *objname) struct ubus_object *obj; struct ubus_object_type *obj_type; struct ubus_method *obj_methods; - struct ubus_method m[8] = { + struct ubus_method m[9] = { UBUS_METHOD_NOARG("status", cntlr_status), UBUS_METHOD("ap_caps", cntlr_ap_caps, ap_caps_policy_params), @@ -1121,6 +1240,7 @@ int cntlr_publish_object(struct controller *c, const char *objname) channel_select_policy_params), UBUS_METHOD("reconfig_ap", cntlr_reconfig_ap, reconfig_policy_params), + UBUS_METHOD("client_assoc_cntlr", client_assoc_cntlr, client_assoc_cntrl_policy_config_params), /* UBUS_METHOD("teardown_ap", cntlr_teardown_ap, config_policy_params),