From 78fd69af0ff5be1977ee3ed9171afc450a30816b Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 12 Sep 2012 05:46:57 +0300 Subject: nl80211: Remove driver command DROPBCAST (ANDROID) There's no support for this in the driver for now as the relevant patches were dropped. Therefore remove relevant code in wpa_s as well. Signed-off-by: Eyal Shapira --- src/drivers/driver_nl80211.c | 74 -------------------------------------------- 1 file changed, 74 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index f7b56b2..432b583 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9121,62 +9121,6 @@ static int nl80211_parse_wowlan_trigger_nr(char *s) return i; } -static int nl80211_toggle_dropbcast(int enable) -{ - char filename[90]; - int rv; - FILE *f; - - snprintf(filename, sizeof(filename) - 1, - "/sys/bus/platform/devices/wl12xx/drop_bcast"); - f = fopen(filename, "w"); - if (!f) { - wpa_printf(MSG_DEBUG, "Could not open file %s: %s", - filename, strerror(errno)); - return -1; - } - - rv = fprintf(f, "%d", enable); - fclose(f); - if (rv < 1) { - wpa_printf(MSG_DEBUG, "Could not write to file %s: %s", - filename, strerror(errno)); - return -1; - } - - return 0; -} - -static int nl80211_dropbcast_get(char *buf, size_t buf_len) -{ - char filename[90], value[10], *pos; - int f, rv; - - snprintf(filename, sizeof(filename) - 1, - "/sys/bus/platform/devices/wl12xx/drop_bcast"); - f = open(filename, O_RDONLY); - if (f < 0) { - wpa_printf(MSG_DEBUG, "Could not open file %s: %s", - filename, strerror(errno)); - return -1; - } - - rv = read(f, value, sizeof(value) - 1); - close(f); - if (rv < 0) { - wpa_printf(MSG_DEBUG, "Could not read file %s: %s", - filename, strerror(errno)); - return -1; - } - - value[rv] = '\0'; - pos = os_strchr(value, '\n'); - if (pos) - *pos = '\0'; - - return snprintf(buf, buf_len, "Drop bcast = %s\n", value); -} - #endif /* ANDROID */ static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) @@ -9683,24 +9627,6 @@ static int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, return nl80211_set_wowlan_triggers(bss, 1); } else if (os_strcasecmp(cmd, "RXFILTER-STOP") == 0) { return nl80211_set_wowlan_triggers(bss, 0); - } else if (os_strncasecmp(cmd, "DROPBCAST", 9) == 0) { - char *value = cmd + 10; - - if (!os_strcasecmp(value, "ENABLE") || - !os_strcasecmp(value, "1")) { - ret = nl80211_toggle_dropbcast(1); - } else if (!os_strcasecmp(value, "DISABLE") || - !os_strcasecmp(value, "0")) { - ret = nl80211_toggle_dropbcast(0); - } else if (!os_strcasecmp(value, "GET") || - !os_strlen(value)) { - ret = nl80211_dropbcast_get(buf, buf_len); - } else { - wpa_printf(MSG_ERROR, - "Invalid parameter for DROPBCAST: %s", - value); - ret = -1; - } } else if( os_strcasecmp(cmd, "LINKSPEED") == 0 ) { struct wpa_signal_info sig; int linkspeed; -- cgit v1.1 From 7eaeff42d560dcdccc13f6ad077de3b4592b06d7 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 12 Sep 2012 18:25:16 +0300 Subject: nl80211: Remove driver specific commands not used in JB (JB) The following driver specific commands aren't used in JB and were replaced by other APIs: POWERMODE,GETPOWER,LINKSPEED,RSSI,RSSI-APPROX Remove code handling these commands. Signed-off-by: Eyal Shapira --- src/drivers/driver_nl80211.c | 99 -------------------------------------------- 1 file changed, 99 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 432b583..6b223c3 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9404,65 +9404,6 @@ static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) } } - -#define WPA_PS_ENABLED 0 -#define WPA_PS_DISABLED 1 - -static int wpa_driver_set_power_save(void *priv, int state) -{ - return nl80211_set_power_save(priv, state == WPA_PS_ENABLED); -} - - -static int get_power_mode_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - int *state = arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb[NL80211_ATTR_PS_STATE]) - return NL_SKIP; - - if (state) { - int s = (int) nla_get_u32(tb[NL80211_ATTR_PS_STATE]); - wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", s); - *state = (s == NL80211_PS_ENABLED) ? - WPA_PS_ENABLED : WPA_PS_DISABLED; - } - - return NL_SKIP; -} - - -static int wpa_driver_get_power_save(void *priv, int *state) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -1; - enum nl80211_ps_state ps_state; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_POWER_SAVE); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); - - ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state); - msg = NULL; - if (ret < 0) - wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret); -nla_put_failure: - nlmsg_free(msg); - return ret; -} - - static int android_priv_cmd(struct i802_bss *bss, const char *cmd) { struct wpa_driver_nl80211_data *drv = bss->drv; @@ -9600,19 +9541,6 @@ static int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, MAC2STR(macaddr)); } else if (os_strcasecmp(cmd, "RELOAD") == 0) { wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); - } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { - int state = atoi(cmd + 10); - ret = wpa_driver_set_power_save(priv, state); - if (ret < 0) - wpa_driver_send_hang_msg(drv); - else - drv_errors = 0; - } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { - int state = -1; - ret = wpa_driver_get_power_save(priv, &state); - if (!ret && (state != -1)) - ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", - state); } else if( os_strncasecmp(cmd, "RXFILTER-ADD ", 13) == 0 ) { int i = nl80211_parse_wowlan_trigger_nr(cmd + 13); if(i < 0) @@ -9627,33 +9555,6 @@ static int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, return nl80211_set_wowlan_triggers(bss, 1); } else if (os_strcasecmp(cmd, "RXFILTER-STOP") == 0) { return nl80211_set_wowlan_triggers(bss, 0); - } else if( os_strcasecmp(cmd, "LINKSPEED") == 0 ) { - struct wpa_signal_info sig; - int linkspeed; - - if (!drv->associated) - return -1; - - ret = nl80211_get_link_signal(drv, &sig); - if (ret == 0) { - linkspeed = sig.current_txrate / 1000; - ret = os_snprintf(buf, buf_len, "LinkSpeed %d\n", - linkspeed); - } - } else if (os_strcasecmp(cmd, "RSSI") == 0 || - os_strcasecmp(cmd, "RSSI-APPROX") == 0) { - struct wpa_signal_info sig; - int rssi; - - if (!drv->associated) - return -1; - - ret = nl80211_get_link_signal(drv, &sig); - if (ret == 0) { - rssi = sig.current_signal; - ret = os_snprintf(buf, buf_len, "%s rssi %d\n", - drv->ssid, rssi); - } } else { wpa_printf(MSG_ERROR, "Unsupported command: %s", cmd); ret = -1; -- cgit v1.1 From 29657cc65d10853bbd41404c421a53850d29b080 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 12 Sep 2012 01:43:39 +0300 Subject: nl80211: make rx filters config global (ANDROID) The RX filters (wowlan) configuration is per interface but this doesn't reflect the state in the kernel where it's per hw device (effectively in Android global). In JB this is more important as wpa_s uses up to 3 different interfaces when running P2P+STA. Also, fix a minor bug in nl80211_toggle_wowlan_trigger where the wpa_s wowlan state changed even if configuring the kernel failed. Signed-off-by: Eyal Shapira --- src/drivers/driver_nl80211.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 6b223c3..b9d4d92 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -167,6 +167,10 @@ struct nl80211_global { int ioctl_sock; /* socket for ioctl() use */ struct nl_handle *nl_event; +#ifdef ANDROID + int wowlan_triggers; + int wowlan_enabled; +#endif }; struct nl80211_wiphy_data { @@ -285,10 +289,6 @@ struct wpa_driver_nl80211_data { int auth_wep_tx_keyidx; int auth_local_state_change; int auth_p2p; -#ifdef ANDROID - u8 wowlan_triggers; - u8 wowlan_enabled; -#endif }; @@ -9003,18 +9003,19 @@ static struct rx_filter rx_filters[] = { static int nl80211_set_wowlan_triggers(struct i802_bss *bss, int enable) { + struct nl80211_global *global = bss->drv->global; struct nl_msg *msg, *pats = NULL; struct nlattr *wowtrig, *pat; int i, ret = -1; int filters; - bss->drv->wowlan_enabled = !!enable; + global->wowlan_enabled = !!enable; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; - genlmsg_put(msg, 0, 0, bss->drv->global->nl80211_id, 0, + genlmsg_put(msg, 0, 0, global->nl80211_id, 0, 0, NL80211_CMD_SET_WOWLAN, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->drv->first_bss.ifindex); @@ -9040,7 +9041,7 @@ static int nl80211_set_wowlan_triggers(struct i802_bss *bss, int enable) * so unicast traffic won't be dropped in any case. */ - filters = bss->drv->wowlan_triggers |= 1; + filters = global->wowlan_triggers |= 1; for (i = 0; i < NR_RX_FILTERS; i++) { struct rx_filter *rx_filter = &rx_filters[i]; @@ -9093,20 +9094,31 @@ nla_put_failure: static int nl80211_toggle_wowlan_trigger(struct i802_bss *bss, int nr, int enabled) { + struct nl80211_global *global = bss->drv->global; + int prev_triggers; + int ret = 0; if (nr >= NR_RX_FILTERS) { wpa_printf(MSG_ERROR, "Unknown filter: %d\n", nr); return -1; } + prev_triggers = global->wowlan_triggers; + if (enabled) - bss->drv->wowlan_triggers |= 1 << nr; + global->wowlan_triggers |= 1 << nr; else - bss->drv->wowlan_triggers &= ~(1 << nr); + global->wowlan_triggers &= ~(1 << nr); - if (bss->drv->wowlan_enabled) - nl80211_set_wowlan_triggers(bss, 1); + if (global->wowlan_enabled) + ret = nl80211_set_wowlan_triggers(bss, 1); - return 0; + if (ret < 0) { + wpa_printf(MSG_ERROR, "nl80211: Failed to set wowlan triggers " + "(%d)", ret); + global->wowlan_triggers = prev_triggers; + } + + return ret; } static int nl80211_parse_wowlan_trigger_nr(char *s) -- cgit v1.1 From 5d3dfd23c978a9a74194ab881617dff3e70a94b5 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 12 Sep 2012 02:20:26 +0300 Subject: nl80211: support configuring RX filters dynamically (ANDROID) The current RX filters are statically defined and can only be enabled or disabled by the DRIVER RX-FILTER commands. Add support to add or remove RX filters "on the fly" from within wpa_s code so we can use this to add an RX filter matching unicast packets going to the new P2P interface mac. Whenever the filters change the whole list of filters needs to be configured to the kernel. Signed-off-by: Eyal Shapira --- src/drivers/driver_nl80211.c | 133 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 5 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b9d4d92..d29095e 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -312,6 +312,10 @@ static int wpa_driver_nl80211_probe_req_report(void *priv, int report); static int android_pno_start(struct i802_bss *bss, struct wpa_driver_scan_params *params); static int android_pno_stop(struct i802_bss *bss); +static int nl80211_register_rx_filter(struct i802_bss *bss, char *name, + u8 *pattern, int len, u8 *mask, + u8 action); +static int nl80211_unregister_rx_filter(struct i802_bss *bss, int filter_idx); #endif /* ANDROID */ #ifdef ANDROID_BRCM_P2P_PATCH static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, @@ -8897,7 +8901,9 @@ nl80211_self_filter_get_pattern_handler(u8 *buf, int buflen, void *arg) return 0; } -static struct rx_filter rx_filters[] = { +#define NUM_RX_FILTERS 15 + +static struct rx_filter rx_filters[NUM_RX_FILTERS] = { /* ID 0 */ {.name = "self", .pattern = {}, @@ -8999,7 +9005,12 @@ static struct rx_filter rx_filters[] = { }; -#define NR_RX_FILTERS (int)(sizeof(rx_filters) / sizeof(struct rx_filter)) +#define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y)) + +static inline int nl80211_rx_filter_configured(struct rx_filter *rx_filter) +{ + return (rx_filter->name != NULL); +} static int nl80211_set_wowlan_triggers(struct i802_bss *bss, int enable) { @@ -9043,11 +9054,14 @@ static int nl80211_set_wowlan_triggers(struct i802_bss *bss, int enable) filters = global->wowlan_triggers |= 1; - for (i = 0; i < NR_RX_FILTERS; i++) { + for (i = 0; i < NUM_RX_FILTERS; i++) { struct rx_filter *rx_filter = &rx_filters[i]; int patnr = 1; u8 *pattern; + if (!nl80211_rx_filter_configured(rx_filter)) + continue; + if (!(filters & (1 << i))) continue; @@ -9097,8 +9111,9 @@ static int nl80211_toggle_wowlan_trigger(struct i802_bss *bss, int nr, struct nl80211_global *global = bss->drv->global; int prev_triggers; int ret = 0; - if (nr >= NR_RX_FILTERS) { - wpa_printf(MSG_ERROR, "Unknown filter: %d\n", nr); + + if (nr >= NUM_RX_FILTERS) { + wpa_printf(MSG_ERROR, "nl80211: Invalid RX filter: %d\n", nr); return -1; } @@ -9133,6 +9148,114 @@ static int nl80211_parse_wowlan_trigger_nr(char *s) return i; } +/* Helper for nl80211_register_rx_filter. Don't call directly */ +static int nl80211_add_rx_filter(char *name, u8 *pattern, int len, + u8 *mask, u8 action) +{ + int i, j, pos; + + if (name == NULL || pattern == NULL || mask == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Add RX filter failed: " + "invalid params"); + return -1; + } + + if (len > MAX_PATTERN_SIZE) { + wpa_printf(MSG_ERROR, "nl80211: Add RX filter failed: " + "Pattern too big (len=%d)", len); + return -1; + } + + if (action > MAX_NL80211_WOWLAN_ACTION) { + wpa_printf(MSG_ERROR, "nl80211: Add RX filter failed: " + "bad action (action=%d)", action); + return -1; + } + + for (i = 0; i < NUM_RX_FILTERS; i++) { + struct rx_filter *filter = &rx_filters[i]; + + if (filter->name) + continue; + + filter->name = name; + filter->pattern_len = len; + memcpy(filter->pattern, pattern, len); + for (j = 0; j < len; j++) + if (mask[j]) { + pos = j / 8; + filter->mask[pos] |= 1 << (j % 8); + } + + filter->mask_len = DIV_ROUND_UP(len, 8); + filter->action = action; + break; + } + + if (i == NUM_RX_FILTERS) { + wpa_printf(MSG_ERROR, "nl80211: Out of RX filters"); + return -1; + } + + return i; +} + +/* Helper for nl80211_unregister_rx_filter. Don't call directly */ +static int nl80211_remove_rx_filter(int filter_idx) +{ + struct rx_filter *filter; + + if (filter_idx < 0 || filter_idx >= NUM_RX_FILTERS) { + wpa_printf(MSG_ERROR, "nl80211: Failed to remove RX filter: " + "bad filter (idx=%d)", filter_idx); + return -1; + } + + filter = &rx_filters[filter_idx]; + filter->name = NULL; + memset(filter->pattern, 0, MAX_PATTERN_SIZE); + memset(filter->mask, 0, MAX_MASK_SIZE); + filter->mask_len = 0; + filter->pattern_len = 0; + filter->action = 0; + + return 0; +} + +static int nl80211_register_rx_filter(struct i802_bss *bss, char *name, + u8 *pattern, int len, u8 *mask, u8 action) +{ + int filter_idx, ret; + + filter_idx = nl80211_add_rx_filter(name, pattern, len, mask, action); + + if (filter_idx < 0) + return -1; + + ret = nl80211_toggle_wowlan_trigger(bss, filter_idx, 1); + if (ret < 0) + goto fail; + + return filter_idx; + +fail: + nl80211_remove_rx_filter(filter_idx); + return -1; +} + +static int nl80211_unregister_rx_filter(struct i802_bss *bss, int filter_idx) +{ + int ret; + + ret = nl80211_toggle_wowlan_trigger(bss, filter_idx, 0); + if (ret < 0) + return ret; + + ret = nl80211_remove_rx_filter(filter_idx); + + return ret; +} + #endif /* ANDROID */ static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid) -- cgit v1.1 From d4ae515851ff23bb8d0e79ebf629fe88c40646f1 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 12 Sep 2012 02:30:00 +0300 Subject: nl80211: reconfigure RX filters whenever a new interface is added (ANDROID) This is used to reconfigure RX filters to include a new filter whenever the P2P group interface is added. The new filter matches any unicast frame sent to a dest mac which matches the P2P group interface mac. This is important as otherwise we wouldn't allow any data frames through to this interface. Signed-off-by: Eyal Shapira --- src/drivers/driver_nl80211.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index d29095e..e0bf84f 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -207,6 +207,10 @@ struct i802_bss { struct nl80211_wiphy_data *wiphy_data; struct dl_list wiphy_list; + +#ifdef ANDROID + int rx_filter_idx; +#endif }; struct wpa_driver_nl80211_data { @@ -3011,6 +3015,9 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, bss = &drv->first_bss; bss->drv = drv; os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); +#ifdef ANDROID + bss->rx_filter_idx = -1; +#endif drv->monitor_ifidx = -1; drv->monitor_sock = -1; drv->eapol_tx_sock = -1; @@ -7961,6 +7968,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; int ifidx; +#ifdef ANDROID + int filter_idx; +#endif + #ifdef HOSTAPD struct i802_bss *new_bss = NULL; @@ -8021,6 +8032,26 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } #endif /* CONFIG_P2P */ +#if defined(ANDROID) && !defined(HOSTAPD) + static u8 eth_addr_mask[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + filter_idx = nl80211_register_rx_filter(bss, "unicast", + if_addr, ETH_ALEN, + eth_addr_mask, + NL80211_WOWLAN_ACTION_ALLOW); + if (filter_idx < 0) { + nl80211_remove_iface(drv, ifidx); + return -1; + } + + if (bss->rx_filter_idx != -1) + wpa_printf(MSG_WARNING, "nl80211: Rx filter is already " + "configured when it shouldn't be (idx=%d)", + bss->rx_filter_idx); + + bss->rx_filter_idx = filter_idx; +#endif /* ANDROID && !HOSTAPD */ + #ifdef HOSTAPD if (bridge && i802_check_bridge(drv, new_bss, bridge, ifname) < 0) { @@ -8093,6 +8124,10 @@ static int wpa_driver_nl80211_if_remove(void *priv, nl80211_remove_iface(drv, ifindex); +#ifdef ANDROID + nl80211_unregister_rx_filter(bss, bss->rx_filter_idx); +#endif + #ifdef HOSTAPD if (type != WPA_IF_AP_BSS) return 0; -- cgit v1.1 From 7973c9ed86ff9694d4cb4fa81eeb5b6bf7267e64 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 12 Sep 2012 02:04:17 +0300 Subject: nl80211: make unicast RX filter always match STA iface mac (ANDROID) This is part of changing the RX filters configuration to being global and not dependent on the interface context. RX filter #0 should point to a filter matching any unicast frame sent to the STA (wlan0) mac. The configuration is done by querying the mac address of the interface. As we now have reconfiguration of filters done from the context of the p2p interface filter #0 would get reconfigured with the P2P dev mac. Avoid this by hard coded querying for the mac of wlan0 when creating the pattern for RX filter #0. Signed-off-by: Eyal Shapira --- src/drivers/driver_nl80211.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index e0bf84f..35a818f 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -8922,13 +8922,13 @@ static u8 *nl80211_rx_filter_get_pattern(struct rx_filter *filter, void *arg) } static int -nl80211_self_filter_get_pattern_handler(u8 *buf, int buflen, void *arg) +nl80211_sta_unicast_filter_get_pattern_handler(u8 *buf, int buflen, void *arg) { int ret; struct i802_bss *bss = (struct i802_bss *)arg; ret = linux_get_ifhwaddr(bss->drv->global->ioctl_sock, - bss->ifname, buf); + "wlan0", buf); if (ret) { wpa_printf(MSG_ERROR, "Failed to get own HW addr (%d)", ret); return -1; @@ -8940,12 +8940,12 @@ nl80211_self_filter_get_pattern_handler(u8 *buf, int buflen, void *arg) static struct rx_filter rx_filters[NUM_RX_FILTERS] = { /* ID 0 */ - {.name = "self", + {.name = "sta_unicast", .pattern = {}, .pattern_len = 6, .mask = { BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) }, .mask_len = 1, - .get_pattern_handler = nl80211_self_filter_get_pattern_handler, + .get_pattern_handler = nl80211_sta_unicast_filter_get_pattern_handler, .action = NL80211_WOWLAN_ACTION_ALLOW, }, -- cgit v1.1 From 7b65de18e8276ed3b5d2cbb64dc06c347f3b0e78 Mon Sep 17 00:00:00 2001 From: Victor Goldenshtein Date: Mon, 21 Nov 2011 17:02:52 +0200 Subject: hostapd: implement channel switch request drv ops (INTERNAL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New hostapd_channel_switch – to handle channel switch request. Signed-hostap: Victor Goldenshtein --- src/ap/ap_config.h | 3 +++ src/ap/ap_drv_ops.c | 31 +++++++++++++++++++++++++++++++ src/ap/ap_drv_ops.h | 2 ++ src/drivers/driver.h | 19 +++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 4e10a0f..d6b67fe 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -432,6 +432,9 @@ struct hostapd_config { int ieee80211d; + /* AP/GO channel switch count */ + int channel_switch_count; + struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; /* diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 859b529..fbeaf9c 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -596,3 +596,34 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, hapd->own_addr, hapd->own_addr, data, len, 0); } + + +int hostapd_channel_switch(struct hostapd_data *hapd, int freq, int flags, + u8 tx_block, u8 post_switch_block_tx) +{ + struct hostapd_channel_switch params; + + if (!hapd->driver || !hapd->driver->hapd_channel_switch) + return 0; + + if (flags & HOSTAPD_CHAN_RADAR) { + wpa_printf(MSG_ERROR, "Can't switch to radar channel, " + "DFS functionality is not supported"); + return -1; + } + + if (hapd->iface->conf->secondary_channel) { + wpa_printf(MSG_ERROR, "Channel switch is not supported " + "with HT40"); + return -1; + } + + params.freq = freq; + params.tx_block = tx_block; + params.post_switch_block_tx = post_switch_block_tx; + params.ch_switch_count = + (hapd->iconf->channel_switch_count > hapd->conf->dtim_period) ? + hapd->iconf->channel_switch_count : hapd->conf->dtim_period * 2; + + return hapd->driver->hapd_channel_switch(hapd->drv_priv, ¶ms); +} diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index e3b15c0..6305050 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -97,6 +97,8 @@ int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr, int reassoc, u16 status, const u8 *ie, size_t len); int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, u8 *tspec_ie, size_t tspec_ielen); +int hostapd_channel_switch(struct hostapd_data *hapd, int freq, int flags, + u8 tx_block, u8 post_switch_block_tx); #include "drivers/driver.h" diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 7afbda1..b25b4b9 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -898,6 +898,16 @@ struct hostapd_freq_params { * enabled, secondary channel above primary */ }; +struct hostapd_channel_switch { + int freq; + int tx_block; /* immediately block the tx on the + * operational channel + * (prior channel switch) */ + int post_switch_block_tx; /* block tx on the target ch (after + * channel switch) */ + int ch_switch_count; +}; + enum wpa_driver_if_type { /** * WPA_IF_STATION - Station mode interface @@ -2587,6 +2597,15 @@ struct wpa_driver_ops { * Returns: 0 on success, -1 on failure */ int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len); + + /** + * hapd_channel_switch - Perform an AP channel switch + * @priv: Private driver interface data + * @params: Channels switch parameters + * Returns: 0 on success, -1 on failure + */ + int (*hapd_channel_switch)(void *priv, + struct hostapd_channel_switch *params); }; -- cgit v1.1 From ff0a677405533513777ed413abff97483f5fda6d Mon Sep 17 00:00:00 2001 From: Victor Goldenshtein Date: Mon, 21 Nov 2011 15:19:52 +0200 Subject: hostap: add channel switch ability to AP & GO (INTERNAL) Add channel switch command and handle channel switch request/complete events. New hostapd_eid_csa() which builds the channel switch announcement IE. Add this CSA to the beacon frame prior performing a channel switch and remove it once it's completed. New EVENT_REQ_CH_SW which indicates that the driver has requested to perform a channel switch. Signed-hostap: Victor Goldenshtein --- hostapd/config_file.c | 2 ++ src/ap/beacon.c | 25 +++++++++++++++++++++++++ src/ap/drv_callbacks.c | 33 +++++++++++++++++++++++++++++++-- src/ap/hostapd.c | 31 +++++++++++++++++++++++++++++++ src/ap/hostapd.h | 5 +++++ src/ap/hw_features.c | 18 ++++++++++++++++++ src/ap/hw_features.h | 1 + src/ap/ieee802_11.c | 30 ++++++++++++++++++++++++++++++ src/drivers/driver.h | 9 ++++++++- src/drivers/driver_common.c | 1 + wpa_supplicant/events.c | 6 ++++++ 11 files changed, 158 insertions(+), 3 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 03f82b2..59745fa 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1441,6 +1441,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->country[2] = ' '; } else if (os_strcmp(buf, "ieee80211d") == 0) { conf->ieee80211d = atoi(pos); + } else if (os_strcmp(buf, "channel_switch_count") == 0) { + conf->channel_switch_count = atoi(pos); } else if (os_strcmp(buf, "ieee8021x") == 0) { bss->ieee802_1x = atoi(pos); } else if (os_strcmp(buf, "eapol_version") == 0) { diff --git a/src/ap/beacon.c b/src/ap/beacon.c index a1bb067..72c3ead 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -33,6 +33,7 @@ #include "p2p_hostapd.h" #include "ap_drv_ops.h" #include "beacon.h" +#include "hw_features.h" #ifdef NEED_AP_MLME @@ -171,6 +172,27 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, return pos; } +static u8 *hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) +{ + int current_ch_flag = 0; + + if (!hapd->next_channel) + return eid; + + current_ch_flag = hostapd_hw_get_channel_flag(hapd, + hapd->iconf->channel); + + *eid++ = WLAN_EID_CHANNEL_SWITCH; + *eid++ = 3; /* IE length */ + /* STAs should cease transmit if the switch is due to radar */ + *eid++ = (current_ch_flag & HOSTAPD_CHAN_RADAR) ? 1 : 0; + *eid++ = (u8)hapd->next_channel->chan; + *eid++ = (hapd->iconf->channel_switch_count > hapd->conf->dtim_period) ? + (u8)hapd->iconf->channel_switch_count : + hapd->conf->dtim_period * 2; + return eid; +} + static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) { @@ -573,6 +595,9 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd) tailpos = hostapd_eid_country(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - tailpos); + /* Channel Switch Announcement */ + tailpos = hostapd_eid_csa(hapd, tailpos); + /* ERP Information element */ tailpos = hostapd_eid_erp_info(hapd, tailpos); diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index f80a08c..7e478a5 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -27,6 +27,7 @@ #include "ap_drv_ops.h" #include "ap_config.h" #include "hw_features.h" +#include "beacon.h" int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, @@ -286,8 +287,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, HOSTAPD_LEVEL_INFO, "driver had channel switch: " "freq=%d, ht=%d, offset=%d", freq, ht, offset); - hapd->iface->freq = freq; - channel = hostapd_hw_get_channel(hapd, freq); if (!channel) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, @@ -299,6 +298,30 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->channel = channel; hapd->iconf->ieee80211n = ht; hapd->iconf->secondary_channel = offset; + + + if (hapd->iface->freq == freq) + return; + + hapd->iface->freq = freq; + + if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq, + hapd->iconf->channel, + hapd->iconf->ieee80211n, + hapd->iconf->secondary_channel)) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "failed to update the freq !"); + return; + } + + hapd->next_channel = NULL; + + /* update the DS IE */ + ieee802_11_set_beacon(hapd); + + wpa_printf(MSG_DEBUG, "AP/GO moved to channel %d", channel); + #endif /* NEED_AP_MLME */ } @@ -627,6 +650,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.ht_enabled, data->ch_switch.ch_offset); break; + case EVENT_REQ_CH_SW: + if (!data) + break; + ieee802_11_start_channel_switch(hapd, data->ch_switch.freq, + FALSE); + break; default: wpa_printf(MSG_DEBUG, "Unknown event %d", event); break; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 3406cd1..4e06808 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1106,3 +1106,34 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, ap_handle_timer, hapd, sta); } + +struct +hostapd_channel_data *hostapd_get_valid_channel(struct hostapd_data *hapd, + int req_freq) +{ + struct hostapd_hw_modes *mode; + struct hostapd_channel_data *chan; + int i, channel_idx = 0; + + wpa_printf(MSG_DEBUG, "Selecting next channel"); + + if (hapd->iface->current_mode == NULL) + return NULL; + + mode = hapd->iface->current_mode; + + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_RADAR)) + continue; + channel_idx++; + + /* request specific channel */ + if (req_freq && (req_freq == chan->freq)) + return chan; + } + + wpa_printf(MSG_WARNING, "Could't get requested channel"); + return NULL; +} diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 0465844..feea42d 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -162,6 +162,8 @@ struct hostapd_data { void (*setup_complete_cb)(void *ctx); void *setup_complete_cb_ctx; + struct hostapd_channel_data *next_channel; + #ifdef CONFIG_P2P struct p2p_data *p2p; struct p2p_group *p2p_group; @@ -271,6 +273,9 @@ void hostapd_interface_deinit(struct hostapd_iface *iface); void hostapd_interface_free(struct hostapd_iface *iface); void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, int reassoc); +struct +hostapd_channel_data *hostapd_get_valid_channel(struct hostapd_data *hapd, + int req_freq); /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 0900e78..930d35b 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -796,3 +796,21 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) return 0; } + + +int hostapd_hw_get_channel_flag(struct hostapd_data *hapd, int chan) +{ + int i; + + if (!hapd->iface->current_mode) + return 0; + + for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { + struct hostapd_channel_data *ch = + &hapd->iface->current_mode->channels[i]; + if (ch->chan == chan) + return ch->flag; + } + + return 0; +} diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index abadcd1..b8e287b 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -28,6 +28,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq); int hostapd_check_ht_capab(struct hostapd_iface *iface); int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode); +int hostapd_hw_get_channel_flag(struct hostapd_data *hapd, int chan); #else /* NEED_AP_MLME */ static inline void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index ed1661a..0b23561 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1889,4 +1889,34 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, } +int ieee802_11_start_channel_switch(struct hostapd_data *hapd, + int freq, u8 radar_detected) +{ + struct hostapd_channel_data *next_channel; + + next_channel = hostapd_get_valid_channel(hapd, freq); + if (!next_channel) + return -1; + + hapd->next_channel = next_channel; + u8 radar_on_next_channel = + (next_channel->flag & HOSTAPD_CHAN_RADAR) ? 1 : 0; + wpa_printf(MSG_INFO, "switching to %sch. #%d, freq %d", + radar_on_next_channel ? "(DFS) " : "", + next_channel->chan, next_channel->freq); + + /* Add CSA */ + ieee802_11_set_beacon(hapd); + + if (hostapd_channel_switch(hapd, next_channel->freq, + next_channel->flag, + radar_detected, + radar_on_next_channel)) { + wpa_printf(MSG_ERROR, "Channel switch failed"); + return -1; + } + return 0; +} + + #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index b25b4b9..6446593 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3060,7 +3060,12 @@ enum wpa_event_type { * * Described in wpa_event_data.ch_switch * */ - EVENT_CH_SWITCH + EVENT_CH_SWITCH, + + /** + * EVENT_REQ_CH_SW - a request to perform a channel switch for GO/AP + */ + EVENT_REQ_CH_SW }; @@ -3723,6 +3728,8 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, /* driver_common.c */ void wpa_scan_results_free(struct wpa_scan_results *res); +int ieee802_11_start_channel_switch(struct hostapd_data *hapd, + int freq, u8 radar_detected); /* Convert wpa_event_type to a string for logging */ const char * event_to_string(enum wpa_event_type event); diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 5e4dc89..a0ada97 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -82,6 +82,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(ROAMING_ENABLED); E2S(ROAMING_DISABLED); E2S(START_ROAMING); + E2S(REQ_CH_SW); } return "UNKNOWN"; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 56ae94c..c3e9ed6 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2556,6 +2556,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.ch_offset); #endif /* CONFIG_AP */ break; + case EVENT_REQ_CH_SW: + if (!data) + break; + ieee802_11_start_channel_switch(wpa_s->ap_iface->bss[0], + data->ch_switch.freq, FALSE); + break; case EVENT_RX_MGMT: { u16 fc, stype; const struct ieee80211_mgmt *mgmt; -- cgit v1.1 From fae6f45ba73ad0045bfbcaea8ffbf92ac8ee6490 Mon Sep 17 00:00:00 2001 From: Victor Goldenshtein Date: Mon, 21 Nov 2011 17:50:10 +0200 Subject: nl80211: add channel switch ability to AP & GO (INTERNAL) Implement AP channel switch command. Handle channel switch request and channel switch complete events. Signed-hostap: Victor Goldenshtein --- src/drivers/driver_nl80211.c | 73 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 35a818f..a1a09a5 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1217,13 +1217,14 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, - struct nlattr *freq, struct nlattr *type) + struct nlattr *freq, struct nlattr *type, + enum wpa_event_type event) { union wpa_event_data data; int ht_enabled = 1; int chan_offset = 0; - wpa_printf(MSG_DEBUG, "nl80211: Channel switch event"); + wpa_printf(MSG_INFO, "nl80211: Channel switch event"); if (!freq || !type) return; @@ -1246,7 +1247,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, data.ch_switch.ht_enabled = ht_enabled; data.ch_switch.ch_offset = chan_offset; - wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data); + wpa_supplicant_event(drv->ctx, event, &data); } @@ -2110,6 +2111,22 @@ static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); } +static void nl80211_req_ch_sw_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + if (!tb[NL80211_ATTR_WIPHY_FREQ]) + return; + + os_memset(&data, 0, sizeof(data)); + data.ch_switch.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]); + + wpa_printf(MSG_DEBUG, "nl80211: Requst to switch to %d freq", + data.ch_switch.freq); + + wpa_supplicant_event(drv->ctx, EVENT_REQ_CH_SW, &data); +} static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, int wds) @@ -2196,7 +2213,11 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv, break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ], - tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], + EVENT_CH_SWITCH); + break; + case NL80211_CMD_REQ_CH_SW: + nl80211_req_ch_sw_event(drv, tb); break; case NL80211_CMD_DISCONNECT: mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], @@ -9466,6 +9487,49 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps, } +static int nl80211_ap_channel_switch(void *priv, + struct hostapd_channel_switch *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + wpa_printf(MSG_INFO, "nl80211: Channel switch, " + "ch_switch_count = %d, tx_block = %d, " + "freq = %d, post_switch_block_tx = %d.", + params->ch_switch_count, params->tx_block, + params->freq, params->post_switch_block_tx); + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_AP_CH_SWITCH); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, params->ch_switch_count); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + + /* only HT20 is supported at this point */ + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20); + + if (params->tx_block) + NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX); + + if (params->post_switch_block_tx) + NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_POST_BLOCK_TX); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == 0) { + bss->freq = params->freq; + return 0; + } + wpa_printf(MSG_DEBUG, "nl80211: Failed to channel switch: " + "%d (%s)", ret, strerror(-ret)); +nla_put_failure: + return -1; +} #ifdef CONFIG_TDLS static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, @@ -9891,6 +9955,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_rekey_info = nl80211_set_rekey_info, .poll_client = nl80211_poll_client, .set_p2p_powersave = nl80211_set_p2p_powersave, + .hapd_channel_switch = nl80211_ap_channel_switch, #ifdef CONFIG_TDLS .send_tdls_mgmt = nl80211_send_tdls_mgmt, .tdls_oper = nl80211_tdls_oper, -- cgit v1.1 From 9c03c3c348b3660a820d7dfd4fb762d5eb9fca4c Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 13 Sep 2012 14:18:25 +0300 Subject: nl80211_copy: update from latest 12xx drv (INTERNAL) add channel switch related commands and attributes Signed-off-by: Arik Nemtsov --- src/drivers/nl80211_copy.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 9cc385a..fbe3733 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -583,6 +583,16 @@ * disabled (marked by the presence of @NL80211_ATTR_ROAMING_DISABLED flag) * userspace should disable background scans and roaming attempts. * + * @NL80211_CMD_AP_CH_SWITCH: Perform a channel switch in the driver (for + * AP/GO). + * %NL80211_ATTR_WIPHY_FREQ: new channel frequency. + * %NL80211_ATTR_CH_SWITCH_BLOCK_TX: block tx on the current channel. + * %NL80211_ATTR_CH_SWITCH_POST_BLOCK_TX: block tx on the target channel. + * %NL80211_FREQ_ATTR_CH_SWITCH_COUNT: number of TBTT's until the channel + * switch event. + * + * @NL80211_CMD_REQ_CH_SW: Request a channel switch from a GO/AP. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -736,6 +746,9 @@ enum nl80211_commands { NL80211_CMD_SET_PRIORITY, NL80211_CMD_CANCEL_PRIORITY, + NL80211_CMD_AP_CH_SWITCH, + NL80211_CMD_REQ_CH_SW, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1314,6 +1327,14 @@ enum nl80211_commands { * @NL80211_ATTR_ROAMING_DISABLED: indicates that the driver can't do roaming * currently. * + * @NL80211_ATTR_CH_SWITCH_COUNT: the number of TBTT's until the channel + * switch event + * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: block tx on the current channel before the + * channel switch operation. + * @NL80211_ATTR_CH_SWITCH_POST_BLOCK_TX: block tx on the target channel after + * the channel switch operation, should be set if the target channel is + * DFS channel. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1581,6 +1602,9 @@ enum nl80211_attrs { NL80211_ATTR_SCHED_SCAN_NUM_SHORT_INTERVALS, NL80211_ATTR_ROAMING_DISABLED, + NL80211_ATTR_CH_SWITCH_COUNT, + NL80211_ATTR_CH_SWITCH_BLOCK_TX, + NL80211_ATTR_CH_SWITCH_POST_BLOCK_TX, /* add attributes here, update the policy in nl80211.c */ @@ -3099,6 +3123,7 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_SCHED_SCAN_INTERVALS: This driver supports using * short interval for sched scan and then switching to a longer * interval. + * @NL80211_FEATURE_AP_CH_SWITCH: This driver supports AP channel switch. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3108,6 +3133,7 @@ enum nl80211_feature_flags { /* leave room for new feature flags */ NL80211_FEATURE_SCHED_SCAN_INTERVALS = 1 << 20, + NL80211_FEATURE_AP_CH_SWITCH = 1 << 21, }; /** -- cgit v1.1