[RFC 1/4] nl80211/hostap: extend channel switch notify handling

Janusz Dziedzic janusz.dziedzic at gmail.com
Sun Nov 24 10:08:44 EST 2013


2013/11/23 Janusz Dziedzic <janusz.dziedzic at tieto.com>:
> Adds support for VHT by parsing bandwidth and
> center_freq{1,2}.
>
> Signed-hostap: Michal Kazior <michal.kazior at tieto.com>
> Signed-hostap: Janusz Dziedzic <janusz.dziedzic at tieto.com>
> ---
>  src/ap/drv_callbacks.c       |   36 ++++++++++++--
>  src/ap/hostapd.h             |    2 +-
>  src/drivers/driver.h         |    6 +++
>  src/drivers/driver_nl80211.c |  113 ++++++++++++++++++++++++++----------------
>  wpa_supplicant/ap.c          |    4 +-
>  wpa_supplicant/ap.h          |    2 +-
>  wpa_supplicant/events.c      |    5 +-
>  7 files changed, 116 insertions(+), 52 deletions(-)
>
> diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
> index 1b69ba8..acd0c3d 100644
> --- a/src/ap/drv_callbacks.c
> +++ b/src/ap/drv_callbacks.c
> @@ -381,14 +381,15 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
>
>
>  void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
> -                            int offset)
> +                            int offset, int width, int cf1, int cf2)
>  {
>  #ifdef NEED_AP_MLME
> -       int channel;
> +       int channel, chwidth, seg0_idx, seg1_idx;;
>
>         hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
>                        HOSTAPD_LEVEL_INFO, "driver had channel switch: "
> -                      "freq=%d, ht=%d, offset=%d", freq, ht, offset);
> +                      "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
> +                      freq, ht, offset, width, cf1, cf2);
>
>         hapd->iface->freq = freq;
>
> @@ -400,9 +401,33 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
>                 return;
>         }
>
> +       switch (width) {
> +       case CHAN_WIDTH_80:
> +               chwidth = VHT_CHANWIDTH_80MHZ;
> +               break;
> +       case CHAN_WIDTH_80P80:
> +               chwidth = VHT_CHANWIDTH_80P80MHZ;
> +               break;
> +       case CHAN_WIDTH_160:
> +               chwidth = VHT_CHANWIDTH_160MHZ;
> +               break;
> +       case CHAN_WIDTH_20_NOHT:
> +       case CHAN_WIDTH_20:
> +       case CHAN_WIDTH_40:
> +       default:
> +               chwidth = VHT_CHANWIDTH_USE_HT;
> +               break;
> +       }
> +
> +       seg0_idx = hostapd_hw_get_channel(hapd, cf1);
> +       seg1_idx = hostapd_hw_get_channel(hapd, cf2);
Seems this is calculated wrong, we can use here
+               seg0_idx = (cf1 - 5000) / 5;


> +
>         hapd->iconf->channel = channel;
>         hapd->iconf->ieee80211n = ht;
>         hapd->iconf->secondary_channel = offset;
> +       hapd->iconf->vht_oper_chwidth = chwidth;
> +       hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
> +       hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
>
>         if (hapd->iface->csa_in_progress && freq == hapd->iface->cs_freq) {
>                 hostapd_cleanup_cs_params(hapd);
> @@ -976,7 +1001,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
>                         break;
>                 hostapd_event_ch_switch(hapd, data->ch_switch.freq,
>                                         data->ch_switch.ht_enabled,
> -                                       data->ch_switch.ch_offset);
> +                                       data->ch_switch.ch_offset,
> +                                       data->ch_switch.ch_width,
> +                                       data->ch_switch.cf1,
> +                                       data->ch_switch.cf2);
>                 break;
>         case EVENT_CONNECT_FAILED_REASON:
>                 if (!data)
> diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
> index c25917d..932fe63 100644
> --- a/src/ap/hostapd.h
> +++ b/src/ap/hostapd.h
> @@ -414,7 +414,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
>                          const u8 *bssid, const u8 *ie, size_t ie_len,
>                          int ssi_signal);
>  void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
> -                            int offset);
> +                            int offset, int width, int cf1, int cf2);
>
>  const struct hostapd_eap_user *
>  hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
> diff --git a/src/drivers/driver.h b/src/drivers/driver.h
> index 3502eb8..a3602ed 100644
> --- a/src/drivers/driver.h
> +++ b/src/drivers/driver.h
> @@ -4028,11 +4028,17 @@ union wpa_event_data {
>          * @freq: Frequency of new channel in MHz
>          * @ht_enabled: Whether this is an HT channel
>          * @ch_offset: Secondary channel offset
> +        * @ch_width: Channel width
> +        * @cf1: Center frequency 1
> +        * @cf2: Center frequency 2
>          */
>         struct ch_switch {
>                 int freq;
>                 int ht_enabled;
>                 int ch_offset;
> +               enum chan_width ch_width;
> +               int cf1;
> +               int cf2;
>         } ch_switch;
>
>         /**
> diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
> index 9d4bcb8..77537ae 100644
> --- a/src/drivers/driver_nl80211.c
> +++ b/src/drivers/driver_nl80211.c
> @@ -504,6 +504,27 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
>  }
>
>
> +/* Converts nl80211_chan_width to a common format */
> +static enum chan_width convert2width(int width)
> +{
> +       switch (width) {
> +       case NL80211_CHAN_WIDTH_20_NOHT:
> +               return CHAN_WIDTH_20_NOHT;
> +       case NL80211_CHAN_WIDTH_20:
> +               return CHAN_WIDTH_20;
> +       case NL80211_CHAN_WIDTH_40:
> +               return CHAN_WIDTH_40;
> +       case NL80211_CHAN_WIDTH_80:
> +               return CHAN_WIDTH_80;
> +       case NL80211_CHAN_WIDTH_80P80:
> +               return CHAN_WIDTH_80P80;
> +       case NL80211_CHAN_WIDTH_160:
> +               return CHAN_WIDTH_160;
> +       }
> +       return CHAN_WIDTH_UNKNOWN;
> +}
> +
> +
>  static int is_ap_interface(enum nl80211_iftype nlmode)
>  {
>         return (nlmode == NL80211_IFTYPE_AP ||
> @@ -1487,36 +1508,59 @@ 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 *ifindex, struct nlattr *freq,
> +                                struct nlattr *type, struct nlattr *bw,
> +                                struct nlattr *cf1, struct nlattr *cf2)
>  {
> +       struct i802_bss *bss;
>         union wpa_event_data data;
>         int ht_enabled = 1;
>         int chan_offset = 0;
> +       int ifidx;
>
>         wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
>
> -       if (!freq || !type)
> +       if (!freq)
>                 return;
>
> -       switch (nla_get_u32(type)) {
> -       case NL80211_CHAN_NO_HT:
> -               ht_enabled = 0;
> -               break;
> -       case NL80211_CHAN_HT20:
> -               break;
> -       case NL80211_CHAN_HT40PLUS:
> -               chan_offset = 1;
> -               break;
> -       case NL80211_CHAN_HT40MINUS:
> -               chan_offset = -1;
> -               break;
> +       ifidx = nla_get_u32(ifindex);
> +       for (bss = drv->first_bss; bss; bss = bss->next)
> +               if (bss->ifindex == ifidx)
> +                       break;
> +
> +       if (bss == NULL) {
> +               wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
> +                          ifidx);
> +               return;
> +       }
> +
> +       if (type) {
> +               switch (nla_get_u32(type)) {
> +               case NL80211_CHAN_NO_HT:
> +                       ht_enabled = 0;
> +                       break;
> +               case NL80211_CHAN_HT20:
> +                       break;
> +               case NL80211_CHAN_HT40PLUS:
> +                       chan_offset = 1;
> +                       break;
> +               case NL80211_CHAN_HT40MINUS:
> +                       chan_offset = -1;
> +                       break;
> +               }
>         }
>
>         data.ch_switch.freq = nla_get_u32(freq);
>         data.ch_switch.ht_enabled = ht_enabled;
>         data.ch_switch.ch_offset = chan_offset;
> +       data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
> +       data.ch_switch.cf1 = nla_get_u32(cf1);
> +       data.ch_switch.cf2 = 0;
> +
> +       if (cf2)
> +               data.ch_switch.cf2 = nla_get_u32(cf2);
>
> -       drv->first_bss->freq = data.ch_switch.freq;
> +       bss->freq = data.ch_switch.freq;
>
>         wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
>  }
> @@ -2537,8 +2581,6 @@ static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
>  }
>
>
> -static enum chan_width convert2width(int width);
> -
>  static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
>                                 struct nlattr **tb)
>  {
> @@ -2705,8 +2747,13 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
>                                    tb[NL80211_ATTR_RESP_IE]);
>                 break;
>         case NL80211_CMD_CH_SWITCH_NOTIFY:
> -               mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
> -                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
> +               mlme_event_ch_switch(drv,
> +                                    tb[NL80211_ATTR_IFINDEX],
> +                                    tb[NL80211_ATTR_WIPHY_FREQ],
> +                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
> +                                    tb[NL80211_ATTR_CHANNEL_WIDTH],
> +                                    tb[NL80211_ATTR_CENTER_FREQ1],
> +                                    tb[NL80211_ATTR_CENTER_FREQ2]);
>                 break;
>         case NL80211_CMD_DISCONNECT:
>                 mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
> @@ -10023,27 +10070,6 @@ nla_put_failure:
>  }
>
>
> -/* Converts nl80211_chan_width to a common format */
> -static enum chan_width convert2width(int width)
> -{
> -       switch (width) {
> -       case NL80211_CHAN_WIDTH_20_NOHT:
> -               return CHAN_WIDTH_20_NOHT;
> -       case NL80211_CHAN_WIDTH_20:
> -               return CHAN_WIDTH_20;
> -       case NL80211_CHAN_WIDTH_40:
> -               return CHAN_WIDTH_40;
> -       case NL80211_CHAN_WIDTH_80:
> -               return CHAN_WIDTH_80;
> -       case NL80211_CHAN_WIDTH_80P80:
> -               return CHAN_WIDTH_80P80;
> -       case NL80211_CHAN_WIDTH_160:
> -               return CHAN_WIDTH_160;
> -       }
> -       return CHAN_WIDTH_UNKNOWN;
> -}
> -
> -
>  static int get_channel_width(struct nl_msg *msg, void *arg)
>  {
>         struct nlattr *tb[NL80211_ATTR_MAX + 1];
> @@ -11291,9 +11317,10 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
>         struct nlattr *beacon_csa;
>         int ret = -ENOBUFS;
>
> -       wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d)",
> -                  settings->cs_count, settings->block_tx,
> -                  settings->freq_params.freq);
> +       wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d "
> +                  "width=%d cf1=%d cf2=%d)", settings->cs_count, settings->block_tx,
> +                  settings->freq_params.freq, settings->freq_params.bandwidth,
> +                  settings->freq_params.center_freq1, settings->freq_params.center_freq2);
>
>         if (!drv->channel_switch_supported) {
>                 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
> diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
> index cbe67a4..394ab30 100644
> --- a/wpa_supplicant/ap.c
> +++ b/wpa_supplicant/ap.c
> @@ -1085,13 +1085,13 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos)
>
>
>  void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
> -                      int offset)
> +                      int offset, int width, int cf1, int cf2)
>  {
>         if (!wpa_s->ap_iface)
>                 return;
>
>         wpa_s->assoc_freq = freq;
> -       hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
> +       hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
>  }
>
>
> diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
> index 33a3d0f..c382898 100644
> --- a/wpa_supplicant/ap.h
> +++ b/wpa_supplicant/ap.h
> @@ -54,7 +54,7 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s,
>                       struct csa_settings *settings);
>  int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
>  void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
> -                      int offset);
> +                      int offset, int width, int cf1, int cf2);
>  struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
>                                              int ndef);
>  #ifdef CONFIG_AP
> diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
> index 35712e5..bcb1cbc 100644
> --- a/wpa_supplicant/events.c
> +++ b/wpa_supplicant/events.c
> @@ -2918,7 +2918,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
>
>                 wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
>                                   data->ch_switch.ht_enabled,
> -                                 data->ch_switch.ch_offset);
> +                                 data->ch_switch.ch_offset,
> +                                 data->ch_switch.ch_width,
> +                                 data->ch_switch.cf1,
> +                                 data->ch_switch.cf2);
>                 break;
>  #endif /* CONFIG_AP */
>  #if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
> --
> 1.7.9.5
>
> _______________________________________________
> HostAP mailing list
> HostAP at lists.shmoo.com
> http://lists.shmoo.com/mailman/listinfo/hostap



-- 
Janusz Dziedzic


More information about the HostAP mailing list