Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Fri, 8 May 2009 19:46:17 +0000 (12:46 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 May 2009 19:46:17 +0000 (12:46 -0700)
1  2 
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_pid_algo.c
net/mac80211/tx.c
net/wireless/reg.c
net/wireless/scan.c

@@@ -490,7 -490,7 +490,7 @@@ void iwl_clear_stations_table(struct iw
        /* keep track of static keys */
        for (i = 0; i < WEP_KEYS_MAX ; i++) {
                if (priv->wep_keys[i].key_size)
-                       test_and_set_bit(i, &priv->ucode_key_table);
+                       set_bit(i, &priv->ucode_key_table);
        }
  
        spin_unlock_irqrestore(&priv->sta_lock, flags);
@@@ -719,14 -719,6 +719,14 @@@ static int iwl_set_tkip_dynamic_key_inf
  {
        unsigned long flags;
        int ret = 0;
 +      __le16 key_flags = 0;
 +
 +      key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
 +      key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
 +      key_flags &= ~STA_KEY_FLG_INVALID;
 +
 +      if (sta_id == priv->hw_params.bcast_sta_id)
 +              key_flags |= STA_KEY_MULTICAST_MSK;
  
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
        WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
                "no space for a new key");
  
 +      priv->stations[sta_id].sta.key.key_flags = key_flags;
 +
 +
        /* This copy is acutally not needed: we get the key with each TX */
        memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
  
@@@ -765,7 -754,9 +765,7 @@@ void iwl_update_tkip_key(struct iwl_pri
  {
        u8 sta_id = IWL_INVALID_STATION;
        unsigned long flags;
 -      __le16 key_flags = 0;
        int i;
 -      DECLARE_MAC_BUF(mac);
  
        sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION) {
                return;
        }
  
 -      key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
 -      key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
 -      key_flags &= ~STA_KEY_FLG_INVALID;
 -
 -      if (sta_id == priv->hw_params.bcast_sta_id)
 -              key_flags |= STA_KEY_MULTICAST_MSK;
 -
        spin_lock_irqsave(&priv->sta_lock, flags);
  
 -      priv->stations[sta_id].sta.key.key_flags = key_flags;
        priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
  
        for (i = 0; i < 5; i++)
@@@ -551,7 -551,8 +551,8 @@@ static void iwl3945_setup_rxon_timing(s
                priv->rxon_timing.atim_window = 0;
        } else {
                priv->rxon_timing.beacon_interval =
-                       iwl3945_adjust_beacon_interval(conf->beacon_int);
+                       iwl3945_adjust_beacon_interval(
+                               priv->vif->bss_conf.beacon_int);
                /* TODO: we need to get atim_window from upper stack
                 * for now we set to 0 */
                priv->rxon_timing.atim_window = 0;
@@@ -1343,15 -1344,24 +1344,24 @@@ static void iwl3945_rx_allocate(struct 
        struct list_head *element;
        struct iwl_rx_mem_buffer *rxb;
        unsigned long flags;
-       spin_lock_irqsave(&rxq->lock, flags);
-       while (!list_empty(&rxq->rx_used)) {
+       while (1) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       return;
+               }
                element = rxq->rx_used.next;
                rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+               spin_unlock_irqrestore(&rxq->lock, flags);
  
                /* Alloc a new receive buffer */
                rxb->skb =
                    alloc_skb(priv->hw_params.rx_buf_size,
-                               __GFP_NOWARN | GFP_ATOMIC);
+                               GFP_KERNEL);
                if (!rxb->skb) {
                        if (net_ratelimit())
                                IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
                 */
                skb_reserve(rxb->skb, 4);
  
-               priv->alloc_rxb_skb++;
-               list_del(element);
                /* Get physical address of RB/SKB */
                rxb->real_dma_addr = pci_map_single(priv->pci_dev,
                                                rxb->skb->data,
                                                priv->hw_params.rx_buf_size,
                                                PCI_DMA_FROMDEVICE);
+               spin_lock_irqsave(&rxq->lock, flags);
                list_add_tail(&rxb->list, &rxq->rx_free);
+               priv->alloc_rxb_skb++;
                rxq->free_count++;
+               spin_unlock_irqrestore(&rxq->lock, flags);
        }
-       spin_unlock_irqrestore(&rxq->lock, flags);
  }
  
  void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
        spin_unlock_irqrestore(&rxq->lock, flags);
  }
  
- /*
-  * this should be called while priv->lock is locked
-  */
- static void __iwl3945_rx_replenish(void *data)
- {
-       struct iwl_priv *priv = data;
-       iwl3945_rx_allocate(priv);
-       iwl3945_rx_queue_restock(priv);
- }
  void iwl3945_rx_replenish(void *data)
  {
        struct iwl_priv *priv = data;
@@@ -1462,6 -1460,7 +1460,6 @@@ static void iwl3945_rx_queue_free(struc
        rxq->bd = NULL;
        rxq->rb_stts  = NULL;
  }
 -EXPORT_SYMBOL(iwl3945_rx_queue_free);
  
  
  /* Convert linear signal-to-noise ratio into dB */
@@@ -1642,7 -1641,7 +1640,7 @@@ static void iwl3945_rx_handle(struct iw
                        count++;
                        if (count >= 8) {
                                priv->rxq.read = i;
-                               __iwl3945_rx_replenish(priv);
+                               iwl3945_rx_queue_restock(priv);
                                count = 0;
                        }
                }
@@@ -3596,7 -3595,7 +3594,7 @@@ static int iwl3945_mac_set_key(struct i
  static ssize_t show_debug_level(struct device *d,
                                struct device_attribute *attr, char *buf)
  {
-       struct iwl_priv *priv = d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
  
        return sprintf(buf, "0x%08X\n", priv->debug_level);
  }
@@@ -3604,7 -3603,7 +3602,7 @@@ static ssize_t store_debug_level(struc
                                struct device_attribute *attr,
                                 const char *buf, size_t count)
  {
-       struct iwl_priv *priv = d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
        unsigned long val;
        int ret;
  
@@@ -3625,7 -3624,7 +3623,7 @@@ static DEVICE_ATTR(debug_level, S_IWUS
  static ssize_t show_temperature(struct device *d,
                                struct device_attribute *attr, char *buf)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
  
        if (!iwl_is_alive(priv))
                return -EAGAIN;
@@@ -3638,7 -3637,7 +3636,7 @@@ static DEVICE_ATTR(temperature, S_IRUGO
  static ssize_t show_tx_power(struct device *d,
                             struct device_attribute *attr, char *buf)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
        return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
  }
  
@@@ -3646,7 -3645,7 +3644,7 @@@ static ssize_t store_tx_power(struct de
                              struct device_attribute *attr,
                              const char *buf, size_t count)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
        char *p = (char *)buf;
        u32 val;
  
@@@ -3664,7 -3663,7 +3662,7 @@@ static DEVICE_ATTR(tx_power, S_IWUSR | 
  static ssize_t show_flags(struct device *d,
                          struct device_attribute *attr, char *buf)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
  
        return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
  }
@@@ -3673,7 -3672,7 +3671,7 @@@ static ssize_t store_flags(struct devic
                           struct device_attribute *attr,
                           const char *buf, size_t count)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
        u32 flags = simple_strtoul(buf, NULL, 0);
  
        mutex_lock(&priv->mutex);
@@@ -3698,7 -3697,7 +3696,7 @@@ static DEVICE_ATTR(flags, S_IWUSR | S_I
  static ssize_t show_filter_flags(struct device *d,
                                 struct device_attribute *attr, char *buf)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
  
        return sprintf(buf, "0x%04X\n",
                le32_to_cpu(priv->active_rxon.filter_flags));
@@@ -3708,7 -3707,7 +3706,7 @@@ static ssize_t store_filter_flags(struc
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
        u32 filter_flags = simple_strtoul(buf, NULL, 0);
  
        mutex_lock(&priv->mutex);
@@@ -3993,7 -3992,7 +3991,7 @@@ static DEVICE_ATTR(antenna, S_IWUSR | S
  static ssize_t show_status(struct device *d,
                           struct device_attribute *attr, char *buf)
  {
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+       struct iwl_priv *priv = dev_get_drvdata(d);
        if (!iwl_is_alive(priv))
                return -EAGAIN;
        return sprintf(buf, "0x%08x\n", (int)priv->status);
@@@ -4005,10 -4004,11 +4003,11 @@@ static ssize_t dump_error_log(struct de
                              struct device_attribute *attr,
                              const char *buf, size_t count)
  {
+       struct iwl_priv *priv = dev_get_drvdata(d);
        char *p = (char *)buf;
  
        if (p[0] == '1')
-               iwl3945_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+               iwl3945_dump_nic_error_log(priv);
  
        return strnlen(buf, count);
  }
@@@ -4019,10 -4019,11 +4018,11 @@@ static ssize_t dump_event_log(struct de
                              struct device_attribute *attr,
                              const char *buf, size_t count)
  {
+       struct iwl_priv *priv = dev_get_drvdata(d);
        char *p = (char *)buf;
  
        if (p[0] == '1')
-               iwl3945_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+               iwl3945_dump_nic_event_log(priv);
  
        return strnlen(buf, count);
  }
@@@ -4104,7 -4105,6 +4104,6 @@@ static struct ieee80211_ops iwl3945_hw_
        .add_interface = iwl_mac_add_interface,
        .remove_interface = iwl_mac_remove_interface,
        .config = iwl_mac_config,
-       .config_interface = iwl_mac_config_interface,
        .configure_filter = iwl_configure_filter,
        .set_key = iwl3945_mac_set_key,
        .get_tx_stats = iwl_mac_get_tx_stats,
@@@ -4210,8 -4210,6 +4209,6 @@@ static int iwl3945_setup_mac(struct iwl
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
  
-       hw->conf.beacon_int = 100;
        if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
                priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
                        &priv->bands[IEEE80211_BAND_2GHZ];
@@@ -80,8 -80,7 +80,7 @@@ use_low_rate(struct sk_buff *skb
        fc = le16_to_cpu(hdr->frame_control);
  
        return ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
-               (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-               is_multicast_ether_addr(hdr->addr1));
+               (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA);
  }
  
  
@@@ -245,7 -244,10 +244,10 @@@ minstrel_get_rate(void *priv, struct ie
  
        if (!sta || !mi || use_low_rate(skb)) {
                ar[0].idx = rate_lowest_index(sband, sta);
-               ar[0].count = mp->max_retry;
+               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+                       ar[0].count = 1;
+               else
+                       ar[0].count = mp->max_retry;
                return;
        }
  
@@@ -476,7 -478,7 +478,7 @@@ minstrel_alloc_sta(void *priv, struct i
                return NULL;
  
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
 -              sband = hw->wiphy->bands[hw->conf.channel->band];
 +              sband = hw->wiphy->bands[i];
                if (sband->n_bitrates > max_rates)
                        max_rates = sband->n_bitrates;
        }
@@@ -289,13 -289,15 +289,15 @@@ rate_control_pid_get_rate(void *priv, s
                info->control.rates[0].count =
                        txrc->hw->conf.short_frame_max_tx_count;
  
-       /* Send management frames and broadcast/multicast data using lowest
-        * rate. */
+       /* Send management frames and NO_ACK data using lowest rate. */
        fc = le16_to_cpu(hdr->frame_control);
        if (!sta || !spinfo ||
            (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           is_multicast_ether_addr(hdr->addr1)) {
+           info->flags & IEEE80211_TX_CTL_NO_ACK) {
                info->control.rates[0].idx = rate_lowest_index(sband, sta);
+               if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+                       info->control.rates[0].count = 1;
                return;
        }
  
@@@ -317,44 -319,13 +319,44 @@@ rate_control_pid_rate_init(void *priv, 
                           struct ieee80211_sta *sta, void *priv_sta)
  {
        struct rc_pid_sta_info *spinfo = priv_sta;
 +      struct rc_pid_info *pinfo = priv;
 +      struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
        struct sta_info *si;
 +      int i, j, tmp;
 +      bool s;
  
        /* TODO: This routine should consider using RSSI from previous packets
         * as we need to have IEEE 802.1X auth succeed immediately after assoc..
         * Until that method is implemented, we will use the lowest supported
         * rate as a workaround. */
  
 +      /* Sort the rates. This is optimized for the most common case (i.e.
 +       * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
 +       * mapping too. */
 +      for (i = 0; i < sband->n_bitrates; i++) {
 +              rinfo[i].index = i;
 +              rinfo[i].rev_index = i;
 +              if (RC_PID_FAST_START)
 +                      rinfo[i].diff = 0;
 +              else
 +                      rinfo[i].diff = i * pinfo->norm_offset;
 +      }
 +      for (i = 1; i < sband->n_bitrates; i++) {
 +              s = 0;
 +              for (j = 0; j < sband->n_bitrates - i; j++)
 +                      if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
 +                                   sband->bitrates[rinfo[j + 1].index].bitrate)) {
 +                              tmp = rinfo[j].index;
 +                              rinfo[j].index = rinfo[j + 1].index;
 +                              rinfo[j + 1].index = tmp;
 +                              rinfo[rinfo[j].index].rev_index = j;
 +                              rinfo[rinfo[j + 1].index].rev_index = j + 1;
 +                              s = 1;
 +                      }
 +              if (!s)
 +                      break;
 +      }
 +
        spinfo->txrate_idx = rate_lowest_index(sband, sta);
        /* HACK */
        si = container_of(sta, struct sta_info, sta);
@@@ -367,22 -338,21 +369,22 @@@ static void *rate_control_pid_alloc(str
        struct rc_pid_info *pinfo;
        struct rc_pid_rateinfo *rinfo;
        struct ieee80211_supported_band *sband;
 -      int i, j, tmp;
 -      bool s;
 +      int i, max_rates = 0;
  #ifdef CONFIG_MAC80211_DEBUGFS
        struct rc_pid_debugfs_entries *de;
  #endif
  
 -      sband = hw->wiphy->bands[hw->conf.channel->band];
 -
        pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
        if (!pinfo)
                return NULL;
  
 -      /* We can safely assume that sband won't change unless we get
 -       * reinitialized. */
 -      rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC);
 +      for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
 +              sband = hw->wiphy->bands[i];
 +              if (sband->n_bitrates > max_rates)
 +                      max_rates = sband->n_bitrates;
 +      }
 +
 +      rinfo = kmalloc(sizeof(*rinfo) * max_rates, GFP_ATOMIC);
        if (!rinfo) {
                kfree(pinfo);
                return NULL;
        pinfo->rinfo = rinfo;
        pinfo->oldrate = 0;
  
 -      /* Sort the rates. This is optimized for the most common case (i.e.
 -       * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
 -       * mapping too. */
 -      for (i = 0; i < sband->n_bitrates; i++) {
 -              rinfo[i].index = i;
 -              rinfo[i].rev_index = i;
 -              if (RC_PID_FAST_START)
 -                      rinfo[i].diff = 0;
 -              else
 -                      rinfo[i].diff = i * pinfo->norm_offset;
 -      }
 -      for (i = 1; i < sband->n_bitrates; i++) {
 -              s = 0;
 -              for (j = 0; j < sband->n_bitrates - i; j++)
 -                      if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
 -                                   sband->bitrates[rinfo[j + 1].index].bitrate)) {
 -                              tmp = rinfo[j].index;
 -                              rinfo[j].index = rinfo[j + 1].index;
 -                              rinfo[j + 1].index = tmp;
 -                              rinfo[rinfo[j].index].rev_index = j;
 -                              rinfo[rinfo[j + 1].index].rev_index = j + 1;
 -                              s = 1;
 -                      }
 -              if (!s)
 -                      break;
 -      }
 -
  #ifdef CONFIG_MAC80211_DEBUGFS
        de = &pinfo->dentries;
        de->target = debugfs_create_u32("target_pf", S_IRUSR | S_IWUSR,
diff --combined net/mac80211/tx.c
@@@ -25,6 -25,7 +25,7 @@@
  #include <asm/unaligned.h>
  
  #include "ieee80211_i.h"
+ #include "driver-ops.h"
  #include "led.h"
  #include "mesh.h"
  #include "wep.h"
@@@ -557,6 -558,10 +558,10 @@@ ieee80211_tx_h_rate_ctrl(struct ieee802
        if (unlikely(!info->control.rates[0].count))
                info->control.rates[0].count = 1;
  
+       if (WARN_ON_ONCE((info->control.rates[0].count > 1) &&
+                        (info->flags & IEEE80211_TX_CTL_NO_ACK)))
+               info->control.rates[0].count = 1;
        if (is_multicast_ether_addr(hdr->addr1)) {
                /*
                 * XXX: verify the rate is in the basic rateset
@@@ -787,7 -792,7 +792,7 @@@ ieee80211_tx_h_fragment(struct ieee8021
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
  
        /* internal error, why is TX_FRAGMENTED set? */
 -      if (WARN_ON(skb->len <= frag_threshold))
 +      if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
                return TX_DROP;
  
        /*
@@@ -1162,7 -1167,7 +1167,7 @@@ static int __ieee80211_tx(struct ieee80
  
                next = skb->next;
                len = skb->len;
-               ret = local->ops->tx(local_to_hw(local), skb);
+               ret = drv_tx(local, skb);
                if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) {
                        dev_kfree_skb(skb);
                        ret = NETDEV_TX_OK;
@@@ -2132,7 -2137,7 +2137,7 @@@ struct sk_buff *ieee80211_beacon_get(st
                memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
                /* BSSID is left zeroed, wildcard value */
                mgmt->u.beacon.beacon_int =
-                       cpu_to_le16(local->hw.conf.beacon_int);
+                       cpu_to_le16(sdata->vif.bss_conf.beacon_int);
                mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
  
                pos = skb_put(skb, 2);
diff --combined net/wireless/reg.c
@@@ -906,7 -906,6 +906,7 @@@ EXPORT_SYMBOL(freq_reg_info)
  int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
                         const struct ieee80211_reg_rule **reg_rule)
  {
 +      assert_cfg80211_lock();
        return freq_reg_info_regd(wiphy, center_freq,
                bandwidth, reg_rule, NULL);
  }
@@@ -1135,8 -1134,7 +1135,8 @@@ static bool reg_is_world_roaming(struc
        if (is_world_regdom(cfg80211_regdomain->alpha2) ||
            (wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))
                return true;
 -      if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
 +      if (last_request &&
 +          last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
            wiphy->custom_regulatory)
                return true;
        return false;
  /* Reap the advantages of previously found beacons */
  static void reg_process_beacons(struct wiphy *wiphy)
  {
 +      /*
 +       * Means we are just firing up cfg80211, so no beacons would
 +       * have been processed yet.
 +       */
 +      if (!last_request)
 +              return;
        if (!reg_is_world_roaming(wiphy))
                return;
        wiphy_update_beacon_reg(wiphy);
@@@ -1185,8 -1177,6 +1185,8 @@@ static void handle_channel_custom(struc
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
  
 +      assert_cfg80211_lock();
 +
        sband = wiphy->bands[band];
        BUG_ON(chan_idx >= sband->n_channels);
        chan = &sband->channels[chan_idx];
@@@ -1225,13 -1215,10 +1225,13 @@@ void wiphy_apply_custom_regulatory(stru
                                   const struct ieee80211_regdomain *regd)
  {
        enum ieee80211_band band;
 +
 +      mutex_lock(&cfg80211_mutex);
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (wiphy->bands[band])
                        handle_band_custom(wiphy, band, regd);
        }
 +      mutex_unlock(&cfg80211_mutex);
  }
  EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
  
@@@ -1437,7 -1424,7 +1437,7 @@@ new_request
        return call_crda(last_request->alpha2);
  }
  
 -/* This currently only processes user and driver regulatory hints */
 +/* This processes *all* regulatory hints */
  static void reg_process_hint(struct regulatory_request *reg_request)
  {
        int r = 0;
@@@ -2113,14 -2100,14 +2113,14 @@@ void reg_device_remove(struct wiphy *wi
  
        assert_cfg80211_lock();
  
+       kfree(wiphy->regd);
        if (last_request)
                request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
  
-       kfree(wiphy->regd);
-       if (!last_request || !request_wiphy)
-               return;
-       if (request_wiphy != wiphy)
+       if (!request_wiphy || request_wiphy != wiphy)
                return;
        last_request->wiphy_idx = WIPHY_IDX_STALE;
        last_request->country_ie_env = ENVIRON_ANY;
  }
diff --combined net/wireless/scan.c
@@@ -377,25 -377,22 +377,23 @@@ cfg80211_bss_update(struct cfg80211_reg
                        size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
                        size_t ielen = res->pub.len_information_elements;
  
-                       if (ksize(found) >= used + ielen) {
+                       if (!found->ies_allocated && ksize(found) >= used + ielen) {
                                memcpy(found->pub.information_elements,
                                       res->pub.information_elements, ielen);
                                found->pub.len_information_elements = ielen;
                        } else {
                                u8 *ies = found->pub.information_elements;
  
-                               if (found->ies_allocated) {
-                                       if (ksize(ies) < ielen)
-                                               ies = krealloc(ies, ielen,
-                                                              GFP_ATOMIC);
-                               } else
+                               if (found->ies_allocated)
+                                       ies = krealloc(ies, ielen, GFP_ATOMIC);
+                               else
                                        ies = kmalloc(ielen, GFP_ATOMIC);
  
                                if (ies) {
                                        memcpy(ies, res->pub.information_elements, ielen);
                                        found->ies_allocated = true;
                                        found->pub.information_elements = ies;
 +                                      found->pub.len_information_elements = ielen;
                                }
                        }
                }