Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac802...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 20 Mar 2014 15:53:20 +0000 (11:53 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 20 Mar 2014 15:53:20 +0000 (11:53 -0400)
1  2 
include/linux/ieee80211.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/tx.c
net/wireless/reg.c

index 06299048c4f41dc66ac549b76c4618efccfa73c7,cde7ede8e554bc5aafe46dc95d17081ad200e244..f194ccb8539c9b7d95af35b00a426ce2a06b61a6
@@@ -154,6 -154,10 +154,10 @@@ static inline u16 ieee80211_sn_sub(u16 
     802.11e clarifies the figure in section 7.1.2. The frame body is
     up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
  #define IEEE80211_MAX_DATA_LEN                2304
+ /* 802.11ad extends maximum MSDU size for DMG (freq > 40Ghz) networks
+  * to 7920 bytes, see 8.2.3 General frame format
+  */
+ #define IEEE80211_MAX_DATA_LEN_DMG    7920
  /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
  #define IEEE80211_MAX_FRAME_LEN               2352
  
@@@ -2307,6 -2311,42 +2311,6 @@@ static inline bool ieee80211_is_public_
        return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC;
  }
  
 -/**
 - * ieee80211_dsss_chan_to_freq - get channel center frequency
 - * @channel: the DSSS channel
 - *
 - * Convert IEEE802.11 DSSS channel to the center frequency (MHz).
 - * Ref IEEE 802.11-2007 section 15.6
 - */
 -static inline int ieee80211_dsss_chan_to_freq(int channel)
 -{
 -      if ((channel > 0) && (channel < 14))
 -              return 2407 + (channel * 5);
 -      else if (channel == 14)
 -              return 2484;
 -      else
 -              return -1;
 -}
 -
 -/**
 - * ieee80211_freq_to_dsss_chan - get channel
 - * @freq: the frequency
 - *
 - * Convert frequency (MHz) to IEEE802.11 DSSS channel
 - * Ref IEEE 802.11-2007 section 15.6
 - *
 - * This routine selects the channel with the closest center frequency.
 - */
 -static inline int ieee80211_freq_to_dsss_chan(int freq)
 -{
 -      if ((freq >= 2410) && (freq < 2475))
 -              return (freq - 2405) / 5;
 -      else if ((freq >= 2482) && (freq < 2487))
 -              return 14;
 -      else
 -              return -1;
 -}
 -
  /**
   * ieee80211_tu_to_usec - convert time units (TU) to microseconds
   * @tu: the TUs
index 0d1a0f801b9413bdb0ce9a105a2c35811b4a4e30,562cedde0adae23ab31980259777968c1b7c04ec..222c28b75315f1ab43226e08566a5f911c6bacc7
@@@ -1391,6 -1391,7 +1391,7 @@@ void ieee80211_sta_reset_conn_monitor(s
  void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata);
  void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
                                  __le16 fc, bool acked);
+ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata);
  void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
  
  /* IBSS code */
@@@ -1700,8 -1701,14 +1701,8 @@@ void ieee80211_stop_queue_by_reason(str
  void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
  void ieee80211_add_pending_skb(struct ieee80211_local *local,
                               struct sk_buff *skb);
 -void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
 -                                 struct sk_buff_head *skbs,
 -                                 void (*fn)(void *data), void *data);
 -static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
 -                                            struct sk_buff_head *skbs)
 -{
 -      ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
 -}
 +void ieee80211_add_pending_skbs(struct ieee80211_local *local,
 +                              struct sk_buff_head *skbs);
  void ieee80211_flush_queues(struct ieee80211_local *local,
                            struct ieee80211_sub_if_data *sdata);
  
diff --combined net/mac80211/mlme.c
index 94f0af29b7424fd443c1f2c0e0fb7c92ba2b7fbd,bbc2175e4bfe9cc2970a0bebb135307740109c63..dee50aefd6e868e247ba869e9e9883d4640330e3
@@@ -222,7 -222,6 +222,7 @@@ ieee80211_determine_chantype(struct iee
        switch (vht_oper->chan_width) {
        case IEEE80211_VHT_CHANWIDTH_USE_HT:
                vht_chandef.width = chandef->width;
 +              vht_chandef.center_freq1 = chandef->center_freq1;
                break;
        case IEEE80211_VHT_CHANWIDTH_80MHZ:
                vht_chandef.width = NL80211_CHAN_WIDTH_80;
        ret = 0;
  
  out:
 +      /*
 +       * When tracking the current AP, don't do any further checks if the
 +       * new chandef is identical to the one we're currently using for the
 +       * connection. This keeps us from playing ping-pong with regulatory,
 +       * without it the following can happen (for example):
 +       *  - connect to an AP with 80 MHz, world regdom allows 80 MHz
 +       *  - AP advertises regdom US
 +       *  - CRDA loads regdom US with 80 MHz prohibited (old database)
 +       *  - the code below detects an unsupported channel, downgrades, and
 +       *    we disconnect from the AP in the caller
 +       *  - disconnect causes CRDA to reload world regdomain and the game
 +       *    starts anew.
 +       * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881)
 +       *
 +       * It seems possible that there are still scenarios with CSA or real
 +       * bandwidth changes where a this could happen, but those cases are
 +       * less common and wouldn't completely prevent using the AP.
 +       */
 +      if (tracking &&
 +          cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef))
 +              return ret;
 +
        /* don't print the message below for VHT mismatch if VHT is disabled */
        if (ret & IEEE80211_STA_DISABLE_VHT)
                vht_chandef = *chandef;
@@@ -2783,28 -2760,20 +2783,20 @@@ static void ieee80211_rx_bss_info(struc
                                  struct ieee802_11_elems *elems)
  {
        struct ieee80211_local *local = sdata->local;
-       int freq;
        struct ieee80211_bss *bss;
        struct ieee80211_channel *channel;
  
        sdata_assert_lock(sdata);
  
-       if (elems->ds_params)
-               freq = ieee80211_channel_to_frequency(elems->ds_params[0],
-                                                     rx_status->band);
-       else
-               freq = rx_status->freq;
-       channel = ieee80211_get_channel(local->hw.wiphy, freq);
-       if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+       channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+       if (!channel)
                return;
  
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
                                        channel);
        if (bss) {
-               ieee80211_rx_bss_put(local, bss);
                sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
+               ieee80211_rx_bss_put(local, bss);
        }
  }
  
@@@ -3599,6 -3568,32 +3591,32 @@@ static void ieee80211_restart_sta_timer
  }
  
  #ifdef CONFIG_PM
+ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
+ {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
+       sdata_lock(sdata);
+       if (ifmgd->auth_data) {
+               /*
+                * If we are trying to authenticate while suspending, cfg80211
+                * won't know and won't actually abort those attempts, thus we
+                * need to do that ourselves.
+                */
+               ieee80211_send_deauth_disassoc(sdata,
+                                              ifmgd->auth_data->bss->bssid,
+                                              IEEE80211_STYPE_DEAUTH,
+                                              WLAN_REASON_DEAUTH_LEAVING,
+                                              false, frame_buf);
+               ieee80211_destroy_auth_data(sdata, false);
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     IEEE80211_DEAUTH_FRAME_LEN);
+       }
+       sdata_unlock(sdata);
+ }
  void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
  {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@@ -3871,7 -3866,6 +3889,7 @@@ static int ieee80211_prep_connection(st
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (WARN_ON(!chanctx_conf)) {
                        rcu_read_unlock();
 +                      sta_info_free(local, new_sta);
                        return -EINVAL;
                }
                rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
@@@ -4417,37 -4411,41 +4435,41 @@@ int ieee80211_mgd_deauth(struct ieee802
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
        bool tx = !req->local_state_change;
-       bool report_frame = false;
  
-       sdata_info(sdata,
-                  "deauthenticating from %pM by local choice (Reason: %u=%s)\n",
-                  req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));
+       if (ifmgd->auth_data &&
+           ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) {
+               sdata_info(sdata,
+                          "aborting authentication with %pM by local choice (Reason: %u=%s)\n",
+                          req->bssid, req->reason_code,
+                          ieee80211_get_reason_code_string(req->reason_code));
  
-       if (ifmgd->auth_data) {
                drv_mgd_prepare_tx(sdata->local, sdata);
                ieee80211_send_deauth_disassoc(sdata, req->bssid,
                                               IEEE80211_STYPE_DEAUTH,
                                               req->reason_code, tx,
                                               frame_buf);
                ieee80211_destroy_auth_data(sdata, false);
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     IEEE80211_DEAUTH_FRAME_LEN);
  
-               report_frame = true;
-               goto out;
+               return 0;
        }
  
        if (ifmgd->associated &&
            ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
+               sdata_info(sdata,
+                          "deauthenticating from %pM by local choice (Reason: %u=%s)\n",
+                          req->bssid, req->reason_code,
+                          ieee80211_get_reason_code_string(req->reason_code));
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       req->reason_code, tx, frame_buf);
-               report_frame = true;
-       }
-  out:
-       if (report_frame)
                cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
                                      IEEE80211_DEAUTH_FRAME_LEN);
+               return 0;
+       }
  
-       return 0;
+       return -ENOTCONN;
  }
  
  int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
diff --combined net/mac80211/rx.c
index 5b617660b0ba5c7c12755b6a9b5ffb9a69923c97,ac8322818b282c54decd57437b2d9dae8a81a4af..216c45b949e513382447050eb560098a5edaa4b3
@@@ -333,6 -333,8 +333,8 @@@ ieee80211_add_rx_radiotap_header(struc
                /* in VHT, STBC is binary */
                if (status->flag & RX_FLAG_STBC_MASK)
                        *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
+               if (status->vht_flag & RX_VHT_FLAG_BF)
+                       *pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
                pos++;
                /* bandwidth */
                if (status->vht_flag & RX_VHT_FLAG_80MHZ)
@@@ -1092,13 -1094,6 +1094,13 @@@ static void sta_ps_end(struct sta_info 
               sta->sta.addr, sta->sta.aid);
  
        if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
 +              /*
 +               * Clear the flag only if the other one is still set
 +               * so that the TX path won't start TX'ing new frames
 +               * directly ... In the case that the driver flag isn't
 +               * set ieee80211_sta_ps_deliver_wakeup() will clear it.
 +               */
 +              clear_sta_flag(sta, WLAN_STA_PS_STA);
                ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
                       sta->sta.addr, sta->sta.aid);
                return;
@@@ -1245,6 -1240,7 +1247,7 @@@ ieee80211_rx_h_sta_process(struct ieee8
                if (ieee80211_is_data(hdr->frame_control)) {
                        sta->last_rx_rate_idx = status->rate_idx;
                        sta->last_rx_rate_flag = status->flag;
+                       sta->last_rx_rate_vht_flag = status->vht_flag;
                        sta->last_rx_rate_vht_nss = status->vht_nss;
                }
        }
diff --combined net/mac80211/tx.c
index cd9f80498c48ef2d8811133c4dbc40eada9a39a1,6200b071992d964838221cb012f9ca7f4d841a5f..19d36d4117e0da0b5524b7e3f8102a86810dceed
@@@ -477,20 -477,6 +477,20 @@@ ieee80211_tx_h_unicast_ps_buf(struct ie
                       sta->sta.addr, sta->sta.aid, ac);
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                        purge_old_ps_buffers(tx->local);
 +
 +              /* sync with ieee80211_sta_ps_deliver_wakeup */
 +              spin_lock(&sta->ps_lock);
 +              /*
 +               * STA woke up the meantime and all the frames on ps_tx_buf have
 +               * been queued to pending queue. No reordering can happen, go
 +               * ahead and Tx the packet.
 +               */
 +              if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
 +                  !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
 +                      spin_unlock(&sta->ps_lock);
 +                      return TX_CONTINUE;
 +              }
 +
                if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
                        struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
                        ps_dbg(tx->sdata,
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
                skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
 +              spin_unlock(&sta->ps_lock);
  
                if (!timer_pending(&local->sta_cleanup))
                        mod_timer(&local->sta_cleanup,
@@@ -2900,7 -2885,7 +2900,7 @@@ ieee80211_get_buffered_bc(struct ieee80
                                cpu_to_le16(IEEE80211_FCTL_MOREDATA);
                }
  
-               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               if (sdata->vif.type == NL80211_IFTYPE_AP)
                        sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
                if (!ieee80211_tx_prepare(sdata, &tx, skb))
                        break;
diff --combined net/wireless/reg.c
index 90b82e08ae699b31bd405a495375a88dd5dd1af3,d944c25f1bb1b3644c8654cbcf8dee53e36dabf4..f59aaac586f8cf10905135324c3913646910a662
@@@ -91,10 -91,6 +91,6 @@@ static struct regulatory_request __rcu 
  /* To trigger userspace events */
  static struct platform_device *reg_pdev;
  
- static const struct device_type reg_device_type = {
-       .uevent = reg_device_uevent,
- };
  /*
   * Central wireless core regulatory domains, we only need two,
   * the current one and a world regulatory domain in case we have no
@@@ -244,19 -240,21 +240,21 @@@ static char user_alpha2[2]
  module_param(ieee80211_regdom, charp, 0444);
  MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
  
- static void reg_kfree_last_request(void)
+ static void reg_free_request(struct regulatory_request *lr)
  {
-       struct regulatory_request *lr;
-       lr = get_last_request();
        if (lr != &core_request_world && lr)
                kfree_rcu(lr, rcu_head);
  }
  
  static void reg_update_last_request(struct regulatory_request *request)
  {
-       reg_kfree_last_request();
+       struct regulatory_request *lr;
+       lr = get_last_request();
+       if (lr == request)
+               return;
+       reg_free_request(lr);
        rcu_assign_pointer(last_request, request);
  }
  
@@@ -487,11 -485,16 +485,16 @@@ static inline void reg_regdb_query(cons
  
  /*
   * This lets us keep regulatory code which is updated on a regulatory
-  * basis in userspace. Country information is filled in by
-  * reg_device_uevent
+  * basis in userspace.
   */
  static int call_crda(const char *alpha2)
  {
+       char country[12];
+       char *env[] = { country, NULL };
+       snprintf(country, sizeof(country), "COUNTRY=%c%c",
+                alpha2[0], alpha2[1]);
        if (!is_world_regdom((char *) alpha2))
                pr_info("Calling CRDA for country: %c%c\n",
                        alpha2[0], alpha2[1]);
        /* query internal regulatory database (if it exists) */
        reg_regdb_query(alpha2);
  
-       return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE);
+       return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
  }
  
  static enum reg_request_treatment
@@@ -755,6 -758,9 +758,9 @@@ static int reg_rules_intersect(const st
        power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
                power_rule2->max_antenna_gain);
  
+       intersected_rule->dfs_cac_ms = max(rule1->dfs_cac_ms,
+                                          rule2->dfs_cac_ms);
        if (!is_valid_reg_rule(intersected_rule))
                return -EINVAL;
  
@@@ -1077,6 -1083,14 +1083,14 @@@ static void handle_channel(struct wiph
                min_t(int, chan->orig_mag,
                      MBI_TO_DBI(power_rule->max_antenna_gain));
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+       if (chan->flags & IEEE80211_CHAN_RADAR) {
+               if (reg_rule->dfs_cac_ms)
+                       chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
+               else
+                       chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+       }
        if (chan->orig_mpwr) {
                /*
                 * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
@@@ -1798,7 -1812,7 +1812,7 @@@ static void reg_process_hint(struct reg
                return;
        case NL80211_REGDOM_SET_BY_USER:
                treatment = reg_process_hint_user(reg_request);
 -              if (treatment == REG_REQ_OK ||
 +              if (treatment == REG_REQ_IGNORE ||
                    treatment == REG_REQ_ALREADY_SET)
                        return;
                queue_delayed_work(system_power_efficient_wq,
@@@ -2255,9 -2269,9 +2269,9 @@@ static void print_rd_rules(const struc
        const struct ieee80211_reg_rule *reg_rule = NULL;
        const struct ieee80211_freq_range *freq_range = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
-       char bw[32];
+       char bw[32], cac_time[32];
  
-       pr_info("  (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");
+       pr_info("  (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n");
  
        for (i = 0; i < rd->n_reg_rules; i++) {
                reg_rule = &rd->reg_rules[i];
                        snprintf(bw, sizeof(bw), "%d KHz",
                                 freq_range->max_bandwidth_khz);
  
+               if (reg_rule->flags & NL80211_RRF_DFS)
+                       scnprintf(cac_time, sizeof(cac_time), "%u s",
+                                 reg_rule->dfs_cac_ms/1000);
+               else
+                       scnprintf(cac_time, sizeof(cac_time), "N/A");
                /*
                 * There may not be documentation for max antenna gain
                 * in certain regions
                 */
                if (power_rule->max_antenna_gain)
-                       pr_info("  (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n",
+                       pr_info("  (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
                                bw,
                                power_rule->max_antenna_gain,
-                               power_rule->max_eirp);
+                               power_rule->max_eirp,
+                               cac_time);
                else
-                       pr_info("  (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n",
+                       pr_info("  (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
                                bw,
-                               power_rule->max_eirp);
+                               power_rule->max_eirp,
+                               cac_time);
        }
  }
  
@@@ -2361,9 -2384,6 +2384,6 @@@ static int reg_set_rd_user(const struc
  {
        const struct ieee80211_regdomain *intersected_rd = NULL;
  
-       if (is_world_regdom(rd->alpha2))
-               return -EINVAL;
        if (!regdom_changes(rd->alpha2))
                return -EALREADY;
  
@@@ -2492,7 -2512,6 +2512,7 @@@ static int reg_set_rd_country_ie(const 
  int set_regdom(const struct ieee80211_regdomain *rd)
  {
        struct regulatory_request *lr;
 +      bool user_reset = false;
        int r;
  
        if (!reg_is_valid_request(rd->alpha2)) {
                break;
        case NL80211_REGDOM_SET_BY_USER:
                r = reg_set_rd_user(rd, lr);
 +              user_reset = true;
                break;
        case NL80211_REGDOM_SET_BY_DRIVER:
                r = reg_set_rd_driver(rd, lr);
        }
  
        if (r) {
 -              if (r == -EALREADY)
 +              switch (r) {
 +              case -EALREADY:
                        reg_set_request_processed();
 +                      break;
 +              default:
 +                      /* Back to world regulatory in case of errors */
 +                      restore_regulatory_settings(user_reset);
 +              }
  
                kfree(rd);
                return r;
        return 0;
  }
  
- int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
- {
-       struct regulatory_request *lr;
-       u8 alpha2[2];
-       bool add = false;
-       rcu_read_lock();
-       lr = get_last_request();
-       if (lr && !lr->processed) {
-               memcpy(alpha2, lr->alpha2, 2);
-               add = true;
-       }
-       rcu_read_unlock();
-       if (add)
-               return add_uevent_var(env, "COUNTRY=%c%c",
-                                     alpha2[0], alpha2[1]);
-       return 0;
- }
  void wiphy_regulatory_register(struct wiphy *wiphy)
  {
        struct regulatory_request *lr;
@@@ -2622,8 -2614,6 +2622,6 @@@ int __init regulatory_init(void
        if (IS_ERR(reg_pdev))
                return PTR_ERR(reg_pdev);
  
-       reg_pdev->dev.type = &reg_device_type;
        spin_lock_init(&reg_requests_lock);
        spin_lock_init(&reg_pending_beacons_lock);
  
This page took 0.040084 seconds and 5 git commands to generate.