diff --git a/src/core/cntlr_map_debug.c b/src/core/cntlr_map_debug.c index 632b41e369fda31dfcf921c8c387de09f2e540a0..f4fc3a9d17cbd8ff524436d6a184181b3c5828ed 100644 --- a/src/core/cntlr_map_debug.c +++ b/src/core/cntlr_map_debug.c @@ -411,12 +411,78 @@ int debug_channel_pref_report(void *cntlr, struct cmdu_cstruct *cmdu) int debug_channel_sel_response(void *cntlr, struct cmdu_cstruct *cmdu) { trace("%s: --->\n", __func__); + trace("parsing channel selection response of |%s:" MACFMT "|\n", + cmdu->intf_name, + MAC2STR(cmdu->origin)); + + int i; + uint8_t *tlv = NULL; + + for (i = 0; i < cmdu->num_tlvs; i++) { + tlv = (uint8_t *) cmdu->tlvs[i]; + trace("CMDU type: %s\n", map_stringify_tlv_type(*tlv)); + switch (*tlv) { + case MAP_TLV_CHANNEL_SELECTION_RESPONSE: + { + struct tlv_ch_selection_resp *p = + (struct tlv_ch_selection_resp *)tlv; + + trace("\tradio_id: " MACFMT "\n", + MAC2STR(p->radio_id)); + trace("\tresponse_code: %d\n", + p->response_code); + break; + } + default: + fprintf(stdout, "unknown TLV in CMDU:|%s|", + map_stringify_cmdu_type(cmdu->message_type)); + break; + } + trace("\n"); + } return 0; } int debug_oper_channel_report(void *cntlr, struct cmdu_cstruct *cmdu) { trace("%s: --->\n", __func__); + trace("parsing operating channel report of |%s:" MACFMT "|\n", + cmdu->intf_name, + MAC2STR(cmdu->origin)); + + int i, j; + uint8_t *tlv = NULL; + + for (i = 0; i < cmdu->num_tlvs; i++) { + tlv = (uint8_t *) cmdu->tlvs[i]; + trace("CMDU type: %s\n", map_stringify_tlv_type(*tlv)); + switch (*tlv) { + case MAP_TLV_OPERATING_CHANNEL_REPORT: + { + struct tlv_oper_ch_report *p = + (struct tlv_oper_ch_report *)tlv; + + trace("\tradio_id: " MACFMT "\n", + MAC2STR(p->radio_id)); + trace("\tch_preference_op_class_nr: %d\n", + p->op_ch_op_class_nr); + for (j = 0; j < p->op_ch_op_class_nr; j++) { + trace("\t\top_class: %d\n", + p->op_ch_op_class[j].op_class); + trace("\t\top_channel: %d\n", + p->op_ch_op_class[j].channel); + } + trace("\tcurr_tx_power: %d\n", + p->curr_tx_power); + break; + } + default: + fprintf(stdout, "unknown TLV in CMDU:|%s|", + map_stringify_cmdu_type(cmdu->message_type)); + break; + } + trace("\n"); + } return 0; } diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c index 87a378d5238c93983e9bda710755dc60eb16f0ee..b1706340db6e100e686f15264a540efd63b022c7 100644 --- a/src/core/cntlr_ubus.c +++ b/src/core/cntlr_ubus.c @@ -71,6 +71,25 @@ static const struct blobmsg_policy channel_pref_policy_params[__CHANNEL_PREF_POL [CHANNEL_PREF_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING } }; +enum { + CHANNEL_SEL_POLICY_AGENT, + CHANNEL_SEL_POLICY_RADIO_ID, + CHANNEL_SEL_POLICY_CLASS_ID, + CHANNEL_SEL_POLICY_CHANNEL, + CHANNEL_SEL_POLICY_PREF, + CHANNEL_SEL_POLICY_TRANSMIT_POWER, + __CHANNEL_SEL_POLICY_MAX, +}; + +static const struct blobmsg_policy channel_select_policy_params[__CHANNEL_SEL_POLICY_MAX] = { + [CHANNEL_SEL_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING }, + [CHANNEL_SEL_POLICY_RADIO_ID] = { .name = "radio_id", .type = BLOBMSG_TYPE_STRING }, + [CHANNEL_SEL_POLICY_CLASS_ID] = { .name = "class_id", .type = BLOBMSG_TYPE_INT32 }, + [CHANNEL_SEL_POLICY_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_ARRAY }, + [CHANNEL_SEL_POLICY_PREF] = { .name = "preference", .type = BLOBMSG_TYPE_INT32 }, + [CHANNEL_SEL_POLICY_TRANSMIT_POWER] = { .name = "transmit_power", .type = BLOBMSG_TYPE_INT32 } +}; + enum { CFG_POLICY_AGENT, CFG_POLICY_RADIO, @@ -411,6 +430,151 @@ static int cntlr_channel_pref(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int cntlr_channel_select(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CHANNEL_SEL_POLICY_MAX]; + struct controller *c = container_of(obj, struct controller, obj); + struct tlv_channel_pref *p = NULL; + struct tlv_tx_power_limit *p1 = NULL; + uint32_t count = 0, tlv_index = 0, k = 0, j = 0; + char agent[18] = {0}; + char radio_id[18] = {0}; + uint32_t radio_present = 0; + uint32_t class_id = -1; + uint32_t channel_nr = 0, pref = -1, transmit_power = -1; + uint32_t channel[20]; + struct cmdu_cstruct *cmdu_data; + struct blob_attr *cur; + int rem, l = 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(channel_select_policy_params, __CHANNEL_SEL_POLICY_MAX, + tb, blob_data(msg), blob_len(msg)); + + if (tb[CHANNEL_SEL_POLICY_AGENT]) { + strncpy(agent, blobmsg_data(tb[CHANNEL_SEL_POLICY_AGENT]), + sizeof(agent) - 1); + if (!hwaddr_aton(agent, cmdu_data->origin)) + goto fail_cmdu; + } + + // TODO: ff:ff:ff:ff:ff:ff = send to all agents + if (tb[CHANNEL_SEL_POLICY_RADIO_ID]) { + strncpy(radio_id, blobmsg_data(tb[CHANNEL_SEL_POLICY_RADIO_ID]), + sizeof(radio_id) - 1); + radio_present = 1; + } + + if (tb[CHANNEL_SEL_POLICY_CLASS_ID]) + class_id = (int) blobmsg_get_u32(tb[CHANNEL_SEL_POLICY_CLASS_ID]); + + if (tb[CHANNEL_SEL_POLICY_CHANNEL]) { + channel_nr = blobmsg_check_array(tb[CHANNEL_SEL_POLICY_CHANNEL], + BLOBMSG_TYPE_INT32); + l = 0; + blobmsg_for_each_attr(cur, tb[CHANNEL_SEL_POLICY_CHANNEL], rem) + channel[l++] = blobmsg_get_u32(cur); + } + + if (tb[CHANNEL_SEL_POLICY_PREF]) + pref = (int) blobmsg_get_u32(tb[CHANNEL_SEL_POLICY_PREF]); + + if (tb[CHANNEL_SEL_POLICY_TRANSMIT_POWER]) + transmit_power = (int) blobmsg_get_u32 + (tb[CHANNEL_SEL_POLICY_TRANSMIT_POWER]); + + cmdu_data->message_type = CMDU_CHANNEL_SELECTION_REQ; + + if (radio_present == 1 && class_id != -1 && pref != -1) { + p = calloc(1, sizeof(struct tlv_channel_pref)); + if (!p) { + fprintf(stderr, "failed to malloc cmdu\n"); + goto fail_cmdu; + } + + p->tlv_type = MAP_TLV_CHANNEL_PREFERENCE; + + hwaddr_aton(radio_id, p->radio_id); + p->ch_preference_op_class_nr = 1; + + if (p->ch_preference_op_class_nr > 0) + p->op_class = calloc(p->ch_preference_op_class_nr, + sizeof(*p->op_class)); + + if (!p->op_class) { + fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__); + p->ch_preference_op_class_nr = 0; + goto fail_p; + } + + for (j = 0; j < p->ch_preference_op_class_nr; j++) { + p->op_class[j].op_class = (uint8_t)class_id; + p->op_class[j].channel_list = NULL; + if (channel_nr != 0) + p->op_class[j].channel_nr = channel_nr; + + if (p->op_class[j].channel_nr > 0) { + + p->op_class[j].channel_list = + calloc(p->op_class[j].channel_nr, + sizeof(uint8_t)); + + if (!p->op_class[j].channel_list) { + fprintf(stderr, "|%s:%d| out of memory!\n", + __func__, __LINE__); + p->op_class[j].channel_nr = 0; + goto fail_p; + } + for (k = 0; k < p->op_class[j].channel_nr; k++) + p->op_class[j].channel_list[k] = (uint8_t) channel[k]; + } + p->op_class[j].preference = (uint8_t) pref; + p->op_class[j].preference_reason = 0x00; + } + count++; + } + + if (radio_present == 1 && transmit_power != -1) { + p1 = calloc(1, sizeof(struct tlv_tx_power_limit)); + if (!p1) { + fprintf(stderr, "failed to malloc cmdu\n"); + goto fail_p; + } + + p1->tlv_type = MAP_TLV_TRANSMIT_POWER_LIMIT; + hwaddr_aton(radio_id, p1->radio_id); + p1->tx_power_limit = (uint8_t)transmit_power; + count++; + } + + cmdu_data->num_tlvs = count; + if (count) + 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; + + if (cmdu_data->tlvs && p1 != NULL) + cmdu_data->tlvs[tlv_index++] = (uint8_t *)p1; + + send_cmdu(c, cmdu_data); + map_free_cmdu(cmdu_data); + return 0; +fail_p: + 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, @@ -980,14 +1144,15 @@ 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[6] = { + struct ubus_method m[7] = { UBUS_METHOD_NOARG("status", cntlr_status), UBUS_METHOD("ap_caps", cntlr_ap_caps, ap_caps_policy_params), UBUS_METHOD("sta_caps", cntlr_sta_caps, sta_caps_policy_params), UBUS_METHOD("channels", cntlr_channel_pref, channel_pref_policy_params), UBUS_METHOD("bk_steer", cntlr_bk_steer, bk_steer_policy_params), - UBUS_METHOD("agent_policy", cntlr_ap_policy_config, ap_policy_config_params) + UBUS_METHOD("agent_policy", cntlr_ap_policy_config, ap_policy_config_params), + UBUS_METHOD("channel", cntlr_channel_select, channel_select_policy_params) /* UBUS_METHOD("teardown_ap", cntlr_teardown_ap, config_policy_params),