From 5f980054146ba39280c6c184efcd8c5efb964dd1 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 4 Mar 2016 17:02:33 +0100 Subject: [PATCH] handle WTP QoS IE --- conf/wtp.conf | 36 ++++++++++++ src/wtp/binding/ieee80211/wifi_drivers.c | 31 ++++++++++ src/wtp/binding/ieee80211/wifi_drivers.h | 5 ++ src/wtp/binding/ieee80211/wifi_nl80211.c | 75 ++++++++++++++++++++++++ src/wtp/wtp.c | 60 +++++++++++++++++++ src/wtp/wtp_radio.c | 11 +++- 6 files changed, 217 insertions(+), 1 deletion(-) diff --git a/conf/wtp.conf b/conf/wtp.conf index a6c4bb2..f5cb5bf 100755 --- a/conf/wtp.conf +++ b/conf/wtp.conf @@ -113,6 +113,42 @@ application: { current = 100; supported = [ 100 ]; }; + qos = { + taggingpolicy = 0; # not used yet + voice = { + queuedepth = 1; # not used yet + cwmin = 2; + cwmax = 3; + aifs = 2; + priority8021p = 0; # not used yet + dscp = 0; # not used yet + }; + video = { + queuedepth = 1; # not used yet + cwmin = 3; + cwmax = 4; + aifs = 2; + priority8021p = 0; # not used yet + dscp = 0; # not used yet + }; + + besteffort = { + queuedepth = 1; # not used yet + cwmin = 4; + cwmax = 10; + aifs = 3; + priority8021p = 0; # not used yet + dscp = 0; # not used yet + }; + background = { + queuedepth = 1; # not used yet + cwmin = 4; + cwmax = 10; + aifs = 7; + priority8021p = 0; # not used yet + dscp = 0; # not used yet + }; + }; } ); diff --git a/src/wtp/binding/ieee80211/wifi_drivers.c b/src/wtp/binding/ieee80211/wifi_drivers.c index 1ceead5..c5bcd73 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.c +++ b/src/wtp/binding/ieee80211/wifi_drivers.c @@ -1438,6 +1438,37 @@ int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t return result; } +int wifi_device_settxqueue(struct wifi_device *device, struct capwap_80211_wtpqos_element *qos) +{ + int i, txop; + + for (i = 0; i < CAPWAP_UPDATE_STATION_QOS_SUBELEMENTS; i++) { + switch (i) { + case 0: /* Best Effort */ + txop = 0; + break; + case 1: /* Background */ + txop = 0; + break; + case 2: /* Video */ + txop = 94; + break; + case 3: /* Voice */ + txop = 47; + break; + default: + return -1; + } + + if (device->instance->ops->device_settxqueue(device, i, + qos->qos[i].aifs, + qos->qos[i].cwmin, + qos->qos[i].cwmax, txop) < 0) + return -1; + } + return 0; +} + /* */ int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount) { struct device_setrates_params buildrate; diff --git a/src/wtp/binding/ieee80211/wifi_drivers.h b/src/wtp/binding/ieee80211/wifi_drivers.h index 6569bd4..1fe6a14 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.h +++ b/src/wtp/binding/ieee80211/wifi_drivers.h @@ -67,6 +67,8 @@ DECLARE_OPAQUE_TYPE(wifi_global_handle); DECLARE_OPAQUE_TYPE(wifi_device_handle); DECLARE_OPAQUE_TYPE(wifi_wlan_handle); +struct capwap_80211_wtpqos_element; + /* */ struct device_setrates_params { int supportedratescount; @@ -380,6 +382,8 @@ struct wifi_driver_ops { int (*device_getcapability)(struct wifi_device* device, struct wifi_capability* capability); void (*device_updatebeacons)(struct wifi_device* device); int (*device_setfrequency)(struct wifi_device* device); + int (*device_settxqueue)(struct wifi_device* device, int queue, int aifs, + int cw_min, int cw_max, int txop); void (*device_deinit)(struct wifi_device* device); /* WLAN functions */ @@ -410,6 +414,7 @@ struct wifi_device* wifi_device_connect(const char* ifname, const char* driver); const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device); int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params); int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel); +int wifi_device_settxqueue(struct wifi_device *device, struct capwap_80211_wtpqos_element *qos); int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount); /* WLAN management */ diff --git a/src/wtp/binding/ieee80211/wifi_nl80211.c b/src/wtp/binding/ieee80211/wifi_nl80211.c index 2434656..bb1f384 100644 --- a/src/wtp/binding/ieee80211/wifi_nl80211.c +++ b/src/wtp/binding/ieee80211/wifi_nl80211.c @@ -1553,6 +1553,80 @@ static void nl80211_device_updatebeacons(struct wifi_device* device) { } } +/* */ +static int nl80211_device_settxqueue(struct wifi_device* device, int queue, int aifs, + int cw_min, int cw_max, int txop) +{ + int result; + struct nl_msg* msg; + struct capwap_list_item* wlansearch; + struct nl80211_device_handle* devicehandle; + struct wifi_wlan* wlan = NULL; + struct nlattr *txq, *params; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + + /* Search a valid interface */ + for (wlansearch = device->wlans->first; wlansearch; wlansearch = wlansearch->next) { + struct wifi_wlan* element = (struct wifi_wlan*)wlansearch->item; + + if (element->flags & WIFI_WLAN_RUNNING) { + wlan = element; + break; + } + } + if (!wlan) + return -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + /* Set TX Queue using device index of first BSS */ + devicehandle = (struct nl80211_device_handle*)device->handle; + genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_WIPHY, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + + txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); + + /* We are only sending parameters for a single TXQ at a time */ + params = nla_nest_start(msg, 1); + + switch (queue) { + case 0: + nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO); + break; + case 1: + nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI); + break; + case 2: + nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE); + break; + case 3: + nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK); + break; + default: + nlmsg_free(msg); + return -1; + } + + nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP, txop); + nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); + nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); + nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs); + nla_nest_end(msg, params); + + nla_nest_end(msg, txq); + + result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); + if (result) + capwap_logging_error("Unable set TX Queue, error code: %d", result); + + nlmsg_free(msg); + return result; +} + /* */ static int nl80211_device_setfrequency(struct wifi_device* device) { ASSERT(device != NULL); @@ -1793,6 +1867,7 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = { .device_getfdevent = nl80211_device_getfdevent, .device_getcapability = nl80211_device_getcapability, .device_updatebeacons = nl80211_device_updatebeacons, + .device_settxqueue = nl80211_device_settxqueue, .device_setfrequency = nl80211_device_setfrequency, .device_deinit = nl80211_device_deinit, diff --git a/src/wtp/wtp.c b/src/wtp/wtp.c index c897ecd..4ba6387 100644 --- a/src/wtp/wtp.c +++ b/src/wtp/wtp.c @@ -157,6 +157,49 @@ static void wtp_print_usage(void) { /* TODO */ } +static int wtp_parsing_radio_qos_configuration(config_setting_t *elem, const char *section, + struct capwap_80211_wtpqos_subelement *qos) +{ + config_setting_t *sect; + LIBCONFIG_LOOKUP_INT_ARG val; + + sect = config_setting_get_member(elem, section); + if (!sect) + return 0; + + if (config_setting_lookup_int(sect, "queuedepth", &val) != CONFIG_TRUE || + val > 255) + return 0; + qos->queuedepth = val; + + if (config_setting_lookup_int(sect, "cwmin", &val) != CONFIG_TRUE || + val > 65565) + return 0; + qos->cwmin = val; + + if (config_setting_lookup_int(sect, "cwmax", &val) != CONFIG_TRUE || + val > 65565) + return 0; + qos->cwmax = val; + + if (config_setting_lookup_int(sect, "aifs", &val) != CONFIG_TRUE || + val > 255) + return 0; + qos->aifs = val; + + if (config_setting_lookup_int(sect, "priority8021p", &val) != CONFIG_TRUE || + val > 7) + return 0; + qos->priority8021p = val; + + if (config_setting_lookup_int(sect, "dscp", &val) != CONFIG_TRUE || + val > 255) + return 0; + qos->dscp = val; + + return 1; +} + /* */ static int wtp_parsing_radio_configuration(config_setting_t* configElement, struct wtp_radio* radio) { int i, len, cnt; @@ -398,6 +441,23 @@ static int wtp_parsing_radio_configuration(config_setting_t* configElement, stru else radio->radioconfig.country[2] = (uint8_t)' '; + /* QoS */ + radio->qos.radioid = radio->radioid; + + configSection = config_setting_get_member(configElement, "qos"); + if (!configSection) + return 0; + + if (config_setting_lookup_int(configSection, "taggingpolicy", &configInt) != CONFIG_TRUE || + configInt > 255) + return 0; + radio->qos.taggingpolicy = (uint8_t)configInt; + + if (wtp_parsing_radio_qos_configuration(configSection, "voice", &radio->qos.qos[3]) == 0 || + wtp_parsing_radio_qos_configuration(configSection, "video", &radio->qos.qos[2]) == 0 || + wtp_parsing_radio_qos_configuration(configSection, "besteffort", &radio->qos.qos[0]) == 0 || + wtp_parsing_radio_qos_configuration(configSection, "background", &radio->qos.qos[1]) == 0) + return 0; return 1; } diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index d4d5646..cdd90e2 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -8,8 +8,9 @@ /* */ #define WTP_UPDATE_FREQUENCY_DSSS 1 #define WTP_UPDATE_FREQUENCY_OFDM 2 -#define WTP_UPDATE_RATES 3 +#define WTP_UPDATE_RATES 3 #define WTP_UPDATE_CONFIGURATION 4 +#define WTP_UPDATE_TX_QUEUE 5 struct wtp_update_configuration_item { int type; @@ -403,6 +404,11 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { radio = wtp_radio_get_phy(qos->radioid); if (radio && (radio->radioid == qos->radioid)) { memcpy(&radio->qos, qos, sizeof(struct capwap_80211_wtpqos_element)); + + /* Pending change radio channel */ + item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); + item->type = WTP_UPDATE_TX_QUEUE; + item->radio = radio; } } } @@ -483,6 +489,9 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { result = wifi_device_setconfiguration(item->radio->devicehandle, ¶ms); break; } + case WTP_UPDATE_TX_QUEUE: + result = wifi_device_settxqueue(item->radio->devicehandle, &item->radio->qos); + break; } }