diff --git a/src/cntlr_map.c b/src/cntlr_map.c index cac00a56bf95d495add2b2da5498acf878f1dadd..83d1214876a42840aec121ea792848603ad442eb 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -1296,6 +1296,83 @@ static int cntlr_parse_radio_scan_caps(struct controller *c, struct node *n, return 0; } +static uint32_t get_duration_data(uint8_t *buf) +{ + uint32_t val = 0; + + val = buf[2]; + val |= (buf[1] << 8); + val |= (buf[0] << 16); + + return val; +} + +static uint32_t get_supp_methods(uint8_t method) +{ + switch (method) { + case CAC_METHOD_CONTINUOUS_CAC: + return 1 << WIFI_CAC_CONTINUOUS; + case CAC_METHOD_DEDICATED_RADIO: + return 1 << WIFI_CAC_DEDICATED; + case CAC_METHOD_MIMO_DIM_REDUCED: + return 1 << WIFI_CAC_MIMO_REDUCED; + case CAC_METHOD_TIME_SLICED: + return 1 << WIFI_CAC_TIME_SLICED; + default: + break; + } + + return 0; +} + +static int cntlr_parse_radio_cac_caps(struct controller *c, struct node *n, struct tlv *t) +{ + struct tlv_cac_cap *p = (struct tlv_cac_cap *) t->data; + struct wifi_radio_opclass *opclass; + struct wifi_radio_element *radio_el; + struct netif_radio *nr; + int i, j, h, k; + int offset; + + offset = sizeof(*p); + for (h = 0; h < p->num_radio; h++) { + struct cac_cap_radio *r = + (struct cac_cap_radio *)&t->data[offset]; + offset += sizeof(*r); + + nr = find_radio_by_node(c, n, r->radio); + if (!nr) + continue; + + radio_el = nr->radio_el; + opclass = &radio_el->supp_opclass; + + for (i = 0; i < r->num_cac; i++) { + struct cac_cap_cac *cac = + (struct cac_cap_cac *)&t->data[offset]; + offset += sizeof(*cac); + for (j = 0; j < cac->num_opclass; j++) { + struct cac_cap_opclass *o = + (struct cac_cap_opclass *)&t->data[offset]; + offset += 2 + o->num_channel; + + for (k = 0; k < o->num_channel; k++) { + struct wifi_radio_opclass_channel *chan; + + chan = wifi_opclass_get_channel(opclass, o->classid, o->channel[k]); + if (WARN_ON(!chan)) + continue; + + chan->cac_methods |= get_supp_methods(cac->supp_method); + chan->cac_time = get_duration_data(cac->duration); + } + } + } + } + + return 0; +} + int handle_ap_caps_report(void *cntlr, struct cmdu_buff *cmdu, struct node *n) { trace("%s: --->\n", __func__); @@ -1465,6 +1542,10 @@ int handle_ap_caps_report(void *cntlr, struct cmdu_buff *cmdu, struct node *n) if (tv[5][0]) cntlr_parse_radio_scan_caps(c, n, tv[5][0]); + /* CAC capabilities */ + if (tv[6][0]) + cntlr_parse_radio_cac_caps(c, n, tv[6][0]); + return 0; } diff --git a/src/wifi_dataelements.h b/src/wifi_dataelements.h index 17b452c09e1e93b1e92351574f9cce54dc41a4c2..ce9b0416d49049839f4340944bd866f2a02c0034 100644 --- a/src/wifi_dataelements.h +++ b/src/wifi_dataelements.h @@ -48,6 +48,7 @@ struct wifi_radio_opclass_channel { enum wifi_radio_opclass_dfs dfs; /**< DFS channel state */ uint32_t cac_time; /**< CAC time needed */ uint32_t nop_time; /**< remaining nop time */ + uint32_t cac_methods; /**< bitmap of wifi_cac_method */ uint8_t ctrl_channels[32]; }; diff --git a/src/wifi_opclass.c b/src/wifi_opclass.c index cfe2e633d6825f605880832a6ba2baa332abe4c9..167dc81da8577c9f0d89b768670a9ae35c89f121 100644 --- a/src/wifi_opclass.c +++ b/src/wifi_opclass.c @@ -1124,3 +1124,14 @@ int wifi_opclass_get_bw(int op_class) return 20; } } + +struct wifi_radio_opclass_channel *wifi_opclass_get_channel(struct wifi_radio_opclass *opclass, uint8_t id, uint8_t channel) +{ + struct wifi_radio_opclass_entry *entry; + + entry = wifi_opclass_find_entry(opclass, id); + if (!entry) + return NULL; + + return wifi_opclass_find_channel(entry, channel); +} diff --git a/src/wifi_opclass.h b/src/wifi_opclass.h index 9980f96e20679644a935f06926a72cf3c2dd40a0..46d36525b34b78b32c81fdefc206ff39c5c2814d 100644 --- a/src/wifi_opclass.h +++ b/src/wifi_opclass.h @@ -55,4 +55,5 @@ uint32_t wifi_opclass_channel_dfs_nop_time(struct wifi_radio_opclass_channel *ch void wifi_opclass_mark_unsupported(struct wifi_radio_opclass *out, struct wifi_radio_opclass *in); enum wifi_band wifi_opclass_get_band(int opclass); int wifi_opclass_get_bw(int op_class); +struct wifi_radio_opclass_channel *wifi_opclass_get_channel(struct wifi_radio_opclass *opclass, uint8_t id, uint8_t channel); #endif /* _WIFI_RADIO_OPCLASS_H_ */