Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
authorJeff Garzik <jeff@garzik.org>
Thu, 7 Dec 2006 10:02:40 +0000 (05:02 -0500)
committerJeff Garzik <jeff@garzik.org>
Thu, 7 Dec 2006 10:02:40 +0000 (05:02 -0500)
Conflicts:

drivers/net/wireless/zd1211rw/zd_mac.h
net/ieee80211/softmac/ieee80211softmac_assoc.c

13 files changed:
1  2 
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/hostap/hostap_info.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_mac.h
net/ieee80211/softmac/ieee80211softmac_assoc.c
net/ieee80211/softmac/ieee80211softmac_auth.c
net/ieee80211/softmac/ieee80211softmac_priv.h
net/ieee80211/softmac/ieee80211softmac_wx.c

index 08bc57a4b895f8edc11b3fa2bf1759c99304b9e8,798a8555fbd70e26f0deb615c14788c72ca5b67d..974a8e5bec8b493b6061a6433fa02fabdf5d1094
@@@ -49,10 -49,10 +49,10 @@@ MODULE_PARM_DESC(autom_ap_wds, "Add WD
  static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);
  static void hostap_event_expired_sta(struct net_device *dev,
                                     struct sta_info *sta);
 -static void handle_add_proc_queue(void *data);
 +static void handle_add_proc_queue(struct work_struct *work);
  
  #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
 -static void handle_wds_oper_queue(void *data);
 +static void handle_wds_oper_queue(struct work_struct *work);
  static void prism2_send_mgmt(struct net_device *dev,
                             u16 type_subtype, char *body,
                             int body_len, u8 *addr, u16 tx_cb_idx);
@@@ -807,7 -807,7 +807,7 @@@ void hostap_init_data(local_info_t *loc
        INIT_LIST_HEAD(&ap->sta_list);
  
        /* Initialize task queue structure for AP management */
 -      INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap);
 +      INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue);
  
        ap->tx_callback_idx =
                hostap_tx_callback_register(local, hostap_ap_tx_cb, ap);
                printk(KERN_WARNING "%s: failed to register TX callback for "
                       "AP\n", local->dev->name);
  #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
 -      INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local);
 +      INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue);
  
        ap->tx_callback_auth =
                hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
@@@ -1062,10 -1062,9 +1062,10 @@@ static int prism2_sta_proc_read(char *p
  }
  
  
 -static void handle_add_proc_queue(void *data)
 +static void handle_add_proc_queue(struct work_struct *work)
  {
 -      struct ap_data *ap = (struct ap_data *) data;
 +      struct ap_data *ap = container_of(work, struct ap_data,
 +                                        add_sta_proc_queue);
        struct sta_info *sta;
        char name[20];
        struct add_sta_proc_data *entry, *prev;
@@@ -1100,15 -1099,13 +1100,13 @@@ static struct sta_info * ap_add_sta(str
  {
        struct sta_info *sta;
  
-       sta = (struct sta_info *)
-               kmalloc(sizeof(struct sta_info), GFP_ATOMIC);
+       sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC);
        if (sta == NULL) {
                PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
                return NULL;
        }
  
        /* initialize STA info data */
-       memset(sta, 0, sizeof(struct sta_info));
        sta->local = ap->local;
        skb_queue_head_init(&sta->tx_buf);
        memcpy(sta->addr, addr, ETH_ALEN);
@@@ -1953,11 -1950,9 +1951,11 @@@ static void handle_pspoll(local_info_t 
  
  #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
  
 -static void handle_wds_oper_queue(void *data)
 +static void handle_wds_oper_queue(struct work_struct *work)
  {
 -      local_info_t *local = data;
 +      struct ap_data *ap = container_of(work, struct ap_data,
 +                                        wds_oper_queue);
 +      local_info_t *local = ap->local;
        struct wds_oper_data *entry, *prev;
  
        spin_lock_bh(&local->lock);
index ee542ec6d6a8cd03d97cd0d8f8fdb985c0327275,ef470e6e1c2a4001bbd53a96c879670c372aaa31..8d8f4b9b8b07a032ef3c04ac1b928ca4187c289e
@@@ -293,12 -293,15 +293,12 @@@ static int sandisk_enable_wireless(stru
                goto done;
        }
  
 -      tuple.DesiredTuple = CISTPL_MANFID;
        tuple.Attributes = TUPLE_RETURN_COMMON;
        tuple.TupleData = buf;
        tuple.TupleDataMax = sizeof(buf);
        tuple.TupleOffset = 0;
 -      if (pcmcia_get_first_tuple(hw_priv->link, &tuple) ||
 -          pcmcia_get_tuple_data(hw_priv->link, &tuple) ||
 -          pcmcia_parse_tuple(hw_priv->link, &tuple, parse) ||
 -          parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) {
 +
 +      if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
                /* No SanDisk manfid found */
                ret = -ENODEV;
                goto done;
@@@ -563,17 -566,22 +563,16 @@@ static int prism2_config(struct pcmcia_
        PDEBUG(DEBUG_FLOW, "prism2_config()\n");
  
        parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
-       hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+       hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
        if (parse == NULL || hw_priv == NULL) {
                ret = -ENOMEM;
                goto failed;
        }
-       memset(hw_priv, 0, sizeof(*hw_priv));
  
 -      tuple.DesiredTuple = CISTPL_CONFIG;
        tuple.Attributes = 0;
        tuple.TupleData = buf;
        tuple.TupleDataMax = sizeof(buf);
        tuple.TupleOffset = 0;
 -      CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 -      CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 -      CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse));
 -      link->conf.ConfigBase = parse->config.base;
 -      link->conf.Present = parse->config.rmask[0];
  
        CS_CHECK(GetConfigurationInfo,
                 pcmcia_get_configuration_info(link, &conf));
index c19e68636a1c89a2edf6dc5472a0386003bb0e0f,9c503364ca3fe5cca7938180162198387b2b1377..a394a23b9a20090ae54922a774725d2848cdd332
@@@ -347,14 -347,12 +347,12 @@@ static int hfa384x_cmd(struct net_devic
        if (signal_pending(current))
                return -EINTR;
  
-       entry = (struct hostap_cmd_queue *)
-               kmalloc(sizeof(*entry), GFP_ATOMIC);
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL) {
                printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n",
                       dev->name);
                return -ENOMEM;
        }
-       memset(entry, 0, sizeof(*entry));
        atomic_set(&entry->usecnt, 1);
        entry->type = CMD_SLEEP;
        entry->cmd = cmd;
@@@ -517,14 -515,12 +515,12 @@@ static int hfa384x_cmd_callback(struct 
                return -1;
        }
  
-       entry = (struct hostap_cmd_queue *)
-               kmalloc(sizeof(*entry), GFP_ATOMIC);
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL) {
                printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc "
                       "failed\n", dev->name);
                return -ENOMEM;
        }
-       memset(entry, 0, sizeof(*entry));
        atomic_set(&entry->usecnt, 1);
        entry->type = CMD_CALLBACK;
        entry->cmd = cmd;
@@@ -1645,9 -1641,9 +1641,9 @@@ static void prism2_schedule_reset(local
  
  /* Called only as scheduled task after noticing card timeout in interrupt
   * context */
 -static void handle_reset_queue(void *data)
 +static void handle_reset_queue(struct work_struct *work)
  {
 -      local_info_t *local = (local_info_t *) data;
 +      local_info_t *local = container_of(work, local_info_t, reset_queue);
  
        printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);
        prism2_hw_reset(local->dev);
@@@ -2896,10 -2892,9 +2892,10 @@@ static void hostap_passive_scan(unsigne
  
  /* Called only as a scheduled task when communications quality values should
   * be updated. */
 -static void handle_comms_qual_update(void *data)
 +static void handle_comms_qual_update(struct work_struct *work)
  {
 -      local_info_t *local = data;
 +      local_info_t *local =
 +              container_of(work, local_info_t, comms_qual_update);
        prism2_update_comms_qual(local->dev);
  }
  
@@@ -3016,14 -3011,12 +3012,12 @@@ static int prism2_set_tim(struct net_de
        iface = netdev_priv(dev);
        local = iface->local;
  
-       new_entry = (struct set_tim_data *)
-               kmalloc(sizeof(*new_entry), GFP_ATOMIC);
+       new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
        if (new_entry == NULL) {
                printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n",
                       local->dev->name);
                return -ENOMEM;
        }
-       memset(new_entry, 0, sizeof(*new_entry));
        new_entry->aid = aid;
        new_entry->set = set;
  
  }
  
  
 -static void handle_set_tim_queue(void *data)
 +static void handle_set_tim_queue(struct work_struct *work)
  {
 -      local_info_t *local = (local_info_t *) data;
 +      local_info_t *local = container_of(work, local_info_t, set_tim_queue);
        struct set_tim_data *entry;
        u16 val;
  
@@@ -3210,15 -3203,15 +3204,15 @@@ prism2_init_local_data(struct prism2_he
        local->scan_channel_mask = 0xffff;
  
        /* Initialize task queue structures */
 -      INIT_WORK(&local->reset_queue, handle_reset_queue, local);
 +      INIT_WORK(&local->reset_queue, handle_reset_queue);
        INIT_WORK(&local->set_multicast_list_queue,
 -                hostap_set_multicast_list_queue, local->dev);
 +                hostap_set_multicast_list_queue);
  
 -      INIT_WORK(&local->set_tim_queue, handle_set_tim_queue, local);
 +      INIT_WORK(&local->set_tim_queue, handle_set_tim_queue);
        INIT_LIST_HEAD(&local->set_tim_list);
        spin_lock_init(&local->set_tim_lock);
  
 -      INIT_WORK(&local->comms_qual_update, handle_comms_qual_update, local);
 +      INIT_WORK(&local->comms_qual_update, handle_comms_qual_update);
  
        /* Initialize tasklets for handling hardware IRQ related operations
         * outside hw IRQ handler */
index 5fd2b1ad7f5eac6da3a81dcf466f14c65dbbf87a,00ed6389076b27b935b1150500069e3c41c45c98..b6a02a02da74e645287aa943ea3cfc57d21b53a9
@@@ -327,11 -327,10 +327,10 @@@ static void prism2_info_hostscanresults
        ptr = (u8 *) pos;
  
        new_count = left / result_size;
-       results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
+       results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result),
                          GFP_ATOMIC);
        if (results == NULL)
                return;
-       memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result));
  
        for (i = 0; i < new_count; i++) {
                memcpy(&results[i], ptr, copy_len);
@@@ -474,9 -473,9 +473,9 @@@ static void handle_info_queue_scanresul
  
  /* Called only as scheduled task after receiving info frames (used to avoid
   * pending too much time in HW IRQ handler). */
 -static void handle_info_queue(void *data)
 +static void handle_info_queue(struct work_struct *work)
  {
 -      local_info_t *local = (local_info_t *) data;
 +      local_info_t *local = container_of(work, local_info_t, info_queue);
  
        if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
                               &local->pending_info))
@@@ -493,7 -492,7 +492,7 @@@ void hostap_info_init(local_info_t *loc
  {
        skb_queue_head_init(&local->info_list);
  #ifndef PRISM2_NO_STATION_MODES
 -      INIT_WORK(&local->info_queue, handle_info_queue, local);
 +      INIT_WORK(&local->info_queue, handle_info_queue);
  #endif /* PRISM2_NO_STATION_MODES */
  }
  
index 1bcd352a813bc24e71284a09f877cd66451d031d,060018e084b4d4ebd65e2c37b5fc50a270f52d8c..dd9ba4aad7bb402b080518351f87db32da015f83
@@@ -316,7 -316,7 +316,7 @@@ static void ipw2100_release_firmware(st
                                     struct ipw2100_fw *fw);
  static int ipw2100_ucode_download(struct ipw2100_priv *priv,
                                  struct ipw2100_fw *fw);
 -static void ipw2100_wx_event_work(struct ipw2100_priv *priv);
 +static void ipw2100_wx_event_work(struct work_struct *work);
  static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
  static struct iw_handler_def ipw2100_wx_handler_def;
  
@@@ -679,8 -679,7 +679,8 @@@ static void schedule_reset(struct ipw21
                        queue_delayed_work(priv->workqueue, &priv->reset_work,
                                           priv->reset_backoff * HZ);
                else
 -                      queue_work(priv->workqueue, &priv->reset_work);
 +                      queue_delayed_work(priv->workqueue, &priv->reset_work,
 +                                         0);
  
                if (priv->reset_backoff < MAX_RESET_BACKOFF)
                        priv->reset_backoff++;
@@@ -1874,10 -1873,8 +1874,10 @@@ static void ipw2100_down(struct ipw2100
        netif_stop_queue(priv->net_dev);
  }
  
 -static void ipw2100_reset_adapter(struct ipw2100_priv *priv)
 +static void ipw2100_reset_adapter(struct work_struct *work)
  {
 +      struct ipw2100_priv *priv =
 +              container_of(work, struct ipw2100_priv, reset_work.work);
        unsigned long flags;
        union iwreq_data wrqu = {
                .ap_addr = {
@@@ -2074,9 -2071,9 +2074,9 @@@ static void isr_indicate_association_lo
                return;
  
        if (priv->status & STATUS_SECURITY_UPDATED)
 -              queue_work(priv->workqueue, &priv->security_work);
 +              queue_delayed_work(priv->workqueue, &priv->security_work, 0);
  
 -      queue_work(priv->workqueue, &priv->wx_event_work);
 +      queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0);
  }
  
  static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
@@@ -5527,11 -5524,8 +5527,11 @@@ static int ipw2100_configure_security(s
        return err;
  }
  
 -static void ipw2100_security_work(struct ipw2100_priv *priv)
 +static void ipw2100_security_work(struct work_struct *work)
  {
 +      struct ipw2100_priv *priv =
 +              container_of(work, struct ipw2100_priv, security_work.work);
 +
        /* If we happen to have reconnected before we get a chance to
         * process this, then update the security settings--which causes
         * a disassociation to occur */
@@@ -5754,7 -5748,7 +5754,7 @@@ static int ipw2100_set_address(struct n
  
        priv->reset_backoff = 0;
        mutex_unlock(&priv->action_mutex);
 -      ipw2100_reset_adapter(priv);
 +      ipw2100_reset_adapter(&priv->reset_work.work);
        return 0;
  
        done:
@@@ -5916,10 -5910,9 +5916,10 @@@ static const struct ethtool_ops ipw2100
        .get_drvinfo = ipw_ethtool_get_drvinfo,
  };
  
 -static void ipw2100_hang_check(void *adapter)
 +static void ipw2100_hang_check(struct work_struct *work)
  {
 -      struct ipw2100_priv *priv = adapter;
 +      struct ipw2100_priv *priv =
 +              container_of(work, struct ipw2100_priv, hang_check.work);
        unsigned long flags;
        u32 rtc = 0xa5a5a5a5;
        u32 len = sizeof(rtc);
        spin_unlock_irqrestore(&priv->low_lock, flags);
  }
  
 -static void ipw2100_rf_kill(void *adapter)
 +static void ipw2100_rf_kill(struct work_struct *work)
  {
 -      struct ipw2100_priv *priv = adapter;
 +      struct ipw2100_priv *priv =
 +              container_of(work, struct ipw2100_priv, rf_kill.work);
        unsigned long flags;
  
        spin_lock_irqsave(&priv->low_lock, flags);
@@@ -6111,11 -6103,14 +6111,11 @@@ static struct net_device *ipw2100_alloc
  
        priv->workqueue = create_workqueue(DRV_NAME);
  
 -      INIT_WORK(&priv->reset_work,
 -                (void (*)(void *))ipw2100_reset_adapter, priv);
 -      INIT_WORK(&priv->security_work,
 -                (void (*)(void *))ipw2100_security_work, priv);
 -      INIT_WORK(&priv->wx_event_work,
 -                (void (*)(void *))ipw2100_wx_event_work, priv);
 -      INIT_WORK(&priv->hang_check, ipw2100_hang_check, priv);
 -      INIT_WORK(&priv->rf_kill, ipw2100_rf_kill, priv);
 +      INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
 +      INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
 +      INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
 +      INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
 +      INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
  
        tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                     ipw2100_irq_tasklet, (unsigned long)priv);
@@@ -6220,7 -6215,7 +6220,7 @@@ static int ipw2100_pci_init_one(struct 
        /* Allocate and initialize the Tx/Rx queues and lists */
        if (ipw2100_queues_allocate(priv)) {
                printk(KERN_WARNING DRV_NAME
-                      "Error calilng ipw2100_queues_allocate.\n");
+                      "Error calling ipw2100_queues_allocate.\n");
                err = -ENOMEM;
                goto fail;
        }
@@@ -8286,10 -8281,8 +8286,10 @@@ static struct iw_handler_def ipw2100_wx
        .get_wireless_stats = ipw2100_wx_wireless_stats,
  };
  
 -static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
 +static void ipw2100_wx_event_work(struct work_struct *work)
  {
 +      struct ipw2100_priv *priv =
 +              container_of(work, struct ipw2100_priv, wx_event_work.work);
        union iwreq_data wrqu;
        int len = ETH_ALEN;
  
index e82e56bb85e14071859055624c6ee53018294d04,d29f42773a83b88a01ebde8604701b6229be7e24..22cb3fb7502e280a16a4d5e73f95bb42482ead3a
@@@ -70,7 -70,7 +70,7 @@@
  #define VQ
  #endif
  
- #define IPW2200_VERSION "1.1.4" VK VD VM VP VR VQ
+ #define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ
  #define DRV_DESCRIPTION       "Intel(R) PRO/Wireless 2200/2915 Network Driver"
  #define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
  #define DRV_VERSION     IPW2200_VERSION
@@@ -187,9 -187,9 +187,9 @@@ static struct ipw_rx_queue *ipw_rx_queu
  static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
  static void ipw_rx_queue_replenish(void *);
  static int ipw_up(struct ipw_priv *);
 -static void ipw_bg_up(void *);
 +static void ipw_bg_up(struct work_struct *work);
  static void ipw_down(struct ipw_priv *);
 -static void ipw_bg_down(void *);
 +static void ipw_bg_down(struct work_struct *work);
  static int ipw_config(struct ipw_priv *);
  static int init_supported_rates(struct ipw_priv *priv,
                                struct ipw_supported_rates *prates);
@@@ -862,12 -862,11 +862,12 @@@ static void ipw_led_link_on(struct ipw_
        spin_unlock_irqrestore(&priv->lock, flags);
  }
  
 -static void ipw_bg_led_link_on(void *data)
 +static void ipw_bg_led_link_on(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, led_link_on.work);
        mutex_lock(&priv->mutex);
 -      ipw_led_link_on(data);
 +      ipw_led_link_on(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -907,12 -906,11 +907,12 @@@ static void ipw_led_link_off(struct ipw
        spin_unlock_irqrestore(&priv->lock, flags);
  }
  
 -static void ipw_bg_led_link_off(void *data)
 +static void ipw_bg_led_link_off(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, led_link_off.work);
        mutex_lock(&priv->mutex);
 -      ipw_led_link_off(data);
 +      ipw_led_link_off(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -987,12 -985,11 +987,12 @@@ static void ipw_led_activity_off(struc
        spin_unlock_irqrestore(&priv->lock, flags);
  }
  
 -static void ipw_bg_led_activity_off(void *data)
 +static void ipw_bg_led_activity_off(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, led_act_off.work);
        mutex_lock(&priv->mutex);
 -      ipw_led_activity_off(data);
 +      ipw_led_activity_off(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -2231,12 -2228,11 +2231,12 @@@ static void ipw_adapter_restart(void *a
        }
  }
  
 -static void ipw_bg_adapter_restart(void *data)
 +static void ipw_bg_adapter_restart(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, adapter_restart);
        mutex_lock(&priv->mutex);
 -      ipw_adapter_restart(data);
 +      ipw_adapter_restart(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -2253,12 -2249,11 +2253,12 @@@ static void ipw_scan_check(void *data
        }
  }
  
 -static void ipw_bg_scan_check(void *data)
 +static void ipw_bg_scan_check(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, scan_check.work);
        mutex_lock(&priv->mutex);
 -      ipw_scan_check(data);
 +      ipw_scan_check(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -3836,19 -3831,17 +3836,19 @@@ static int ipw_disassociate(void *data
        return 1;
  }
  
 -static void ipw_bg_disassociate(void *data)
 +static void ipw_bg_disassociate(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, disassociate);
        mutex_lock(&priv->mutex);
 -      ipw_disassociate(data);
 +      ipw_disassociate(priv);
        mutex_unlock(&priv->mutex);
  }
  
 -static void ipw_system_config(void *data)
 +static void ipw_system_config(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, system_config);
  
  #ifdef CONFIG_IPW2200_PROMISCUOUS
        if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
@@@ -4215,12 -4208,11 +4215,12 @@@ static void ipw_gather_stats(struct ipw
                           IPW_STATS_INTERVAL);
  }
  
 -static void ipw_bg_gather_stats(void *data)
 +static void ipw_bg_gather_stats(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, gather_stats.work);
        mutex_lock(&priv->mutex);
 -      ipw_gather_stats(data);
 +      ipw_gather_stats(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -4276,8 -4268,8 +4276,8 @@@ static void ipw_handle_missed_beacon(st
                if (!(priv->status & STATUS_ROAMING)) {
                        priv->status |= STATUS_ROAMING;
                        if (!(priv->status & STATUS_SCANNING))
 -                              queue_work(priv->workqueue,
 -                                         &priv->request_scan);
 +                              queue_delayed_work(priv->workqueue,
 +                                                 &priv->request_scan, 0);
                }
                return;
        }
@@@ -4615,8 -4607,8 +4615,8 @@@ static void ipw_rx_notification(struct 
  #ifdef CONFIG_IPW2200_MONITOR
                        if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
                                priv->status |= STATUS_SCAN_FORCED;
 -                              queue_work(priv->workqueue,
 -                                         &priv->request_scan);
 +                              queue_delayed_work(priv->workqueue,
 +                                                 &priv->request_scan, 0);
                                break;
                        }
                        priv->status &= ~STATUS_SCAN_FORCED;
                                        /* Don't schedule if we aborted the scan */
                                        priv->status &= ~STATUS_ROAMING;
                        } else if (priv->status & STATUS_SCAN_PENDING)
 -                              queue_work(priv->workqueue,
 -                                         &priv->request_scan);
 +                              queue_delayed_work(priv->workqueue,
 +                                                 &priv->request_scan, 0);
                        else if (priv->config & CFG_BACKGROUND_SCAN
                                 && priv->status & STATUS_ASSOCIATED)
                                queue_delayed_work(priv->workqueue,
@@@ -5063,12 -5055,11 +5063,12 @@@ static void ipw_rx_queue_replenish(voi
        ipw_rx_queue_restock(priv);
  }
  
 -static void ipw_bg_rx_queue_replenish(void *data)
 +static void ipw_bg_rx_queue_replenish(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, rx_replenish);
        mutex_lock(&priv->mutex);
 -      ipw_rx_queue_replenish(data);
 +      ipw_rx_queue_replenish(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -5498,10 -5489,9 +5498,10 @@@ static int ipw_find_adhoc_network(struc
        return 1;
  }
  
 -static void ipw_merge_adhoc_network(void *data)
 +static void ipw_merge_adhoc_network(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, merge_networks);
        struct ieee80211_network *network = NULL;
        struct ipw_network_match match = {
                .network = priv->assoc_network
@@@ -5958,12 -5948,11 +5958,12 @@@ static void ipw_adhoc_check(void *data
                           priv->assoc_request.beacon_interval);
  }
  
 -static void ipw_bg_adhoc_check(void *data)
 +static void ipw_bg_adhoc_check(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, adhoc_check.work);
        mutex_lock(&priv->mutex);
 -      ipw_adhoc_check(data);
 +      ipw_adhoc_check(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -6310,26 -6299,19 +6310,26 @@@ done
        return err;
  }
  
 -static int ipw_request_passive_scan(struct ipw_priv *priv) {
 -      return ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
 +static void ipw_request_passive_scan(struct work_struct *work)
 +{
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, request_passive_scan);
 +      ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
  }
  
 -static int ipw_request_scan(struct ipw_priv *priv) {
 -      return ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
 +static void ipw_request_scan(struct work_struct *work)
 +{
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, request_scan.work);
 +      ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
  }
  
 -static void ipw_bg_abort_scan(void *data)
 +static void ipw_bg_abort_scan(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, abort_scan);
        mutex_lock(&priv->mutex);
 -      ipw_abort_scan(data);
 +      ipw_abort_scan(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -7102,10 -7084,9 +7102,10 @@@ static int ipw_qos_set_tx_queue_command
  /*
  * background support to run QoS activate functionality
  */
 -static void ipw_bg_qos_activate(void *data)
 +static void ipw_bg_qos_activate(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, qos_activate);
  
        if (priv == NULL)
                return;
@@@ -7413,12 -7394,11 +7413,12 @@@ static void ipw_roam(void *data
        priv->status &= ~STATUS_ROAMING;
  }
  
 -static void ipw_bg_roam(void *data)
 +static void ipw_bg_roam(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, roam);
        mutex_lock(&priv->mutex);
 -      ipw_roam(data);
 +      ipw_roam(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -7499,8 -7479,8 +7499,8 @@@ static int ipw_associate(void *data
                                                   &priv->request_scan,
                                                   SCAN_INTERVAL);
                        else
 -                              queue_work(priv->workqueue,
 -                                         &priv->request_scan);
 +                              queue_delayed_work(priv->workqueue,
 +                                                 &priv->request_scan, 0);
                }
  
                return 0;
        return 1;
  }
  
 -static void ipw_bg_associate(void *data)
 +static void ipw_bg_associate(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, associate);
        mutex_lock(&priv->mutex);
 -      ipw_associate(data);
 +      ipw_associate(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -7677,7 -7656,8 +7677,8 @@@ static void ipw_handle_data_packet_moni
  
        /* Big bitfield of all the fields we provide in radiotap */
        ipw_rt->rt_hdr.it_present =
-           ((1 << IEEE80211_RADIOTAP_FLAGS) |
+           ((1 << IEEE80211_RADIOTAP_TSFT) |
+            (1 << IEEE80211_RADIOTAP_FLAGS) |
             (1 << IEEE80211_RADIOTAP_RATE) |
             (1 << IEEE80211_RADIOTAP_CHANNEL) |
             (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
  
        /* Zero the flags, we'll add to them as we go */
        ipw_rt->rt_flags = 0;
-       ipw_rt->rt_tsf = 0ULL;
+       ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
+                              frame->parent_tsf[2] << 16 |
+                              frame->parent_tsf[1] << 8  |
+                              frame->parent_tsf[0]);
  
        /* Convert signal to DBM */
        ipw_rt->rt_dbmsignal = antsignal;
+       ipw_rt->rt_dbmnoise = frame->noise;
  
        /* Convert the channel data and set the flags */
        ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
@@@ -7889,7 -7873,8 +7894,8 @@@ static void ipw_handle_promiscuous_rx(s
  
        /* Big bitfield of all the fields we provide in radiotap */
        ipw_rt->rt_hdr.it_present =
-           ((1 << IEEE80211_RADIOTAP_FLAGS) |
+           ((1 << IEEE80211_RADIOTAP_TSFT) |
+            (1 << IEEE80211_RADIOTAP_FLAGS) |
             (1 << IEEE80211_RADIOTAP_RATE) |
             (1 << IEEE80211_RADIOTAP_CHANNEL) |
             (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
  
        /* Zero the flags, we'll add to them as we go */
        ipw_rt->rt_flags = 0;
-       ipw_rt->rt_tsf = 0ULL;
+       ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
+                              frame->parent_tsf[2] << 16 |
+                              frame->parent_tsf[1] << 8  |
+                              frame->parent_tsf[0]);
  
        /* Convert to DBM */
        ipw_rt->rt_dbmsignal = signal;
@@@ -8297,7 -8285,7 +8306,7 @@@ static void ipw_rx(struct ipw_priv *pri
                                    ("Notification: subtype=%02X flags=%02X size=%d\n",
                                     pkt->u.notification.subtype,
                                     pkt->u.notification.flags,
-                                    pkt->u.notification.size);
+                                    le16_to_cpu(pkt->u.notification.size));
                                ipw_rx_notification(priv, &pkt->u.notification);
                                break;
                        }
@@@ -9431,7 -9419,7 +9440,7 @@@ static int ipw_wx_set_scan(struct net_d
  
        IPW_DEBUG_WX("Start scan\n");
  
 -      queue_work(priv->workqueue, &priv->request_scan);
 +      queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
  
        return 0;
  }
@@@ -10568,12 -10556,11 +10577,12 @@@ static void ipw_rf_kill(void *adapter
        spin_unlock_irqrestore(&priv->lock, flags);
  }
  
 -static void ipw_bg_rf_kill(void *data)
 +static void ipw_bg_rf_kill(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, rf_kill.work);
        mutex_lock(&priv->mutex);
 -      ipw_rf_kill(data);
 +      ipw_rf_kill(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -10604,12 -10591,11 +10613,12 @@@ static void ipw_link_up(struct ipw_pri
                queue_delayed_work(priv->workqueue, &priv->request_scan, HZ);
  }
  
 -static void ipw_bg_link_up(void *data)
 +static void ipw_bg_link_up(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, link_up);
        mutex_lock(&priv->mutex);
 -      ipw_link_up(data);
 +      ipw_link_up(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -10629,16 -10615,15 +10638,16 @@@ static void ipw_link_down(struct ipw_pr
  
        if (!(priv->status & STATUS_EXIT_PENDING)) {
                /* Queue up another scan... */
 -              queue_work(priv->workqueue, &priv->request_scan);
 +              queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
        }
  }
  
 -static void ipw_bg_link_down(void *data)
 +static void ipw_bg_link_down(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, link_down);
        mutex_lock(&priv->mutex);
 -      ipw_link_down(data);
 +      ipw_link_down(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -10650,30 -10635,38 +10659,30 @@@ static int ipw_setup_deferred_work(stru
        init_waitqueue_head(&priv->wait_command_queue);
        init_waitqueue_head(&priv->wait_state);
  
 -      INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv);
 -      INIT_WORK(&priv->associate, ipw_bg_associate, priv);
 -      INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv);
 -      INIT_WORK(&priv->system_config, ipw_system_config, priv);
 -      INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv);
 -      INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv);
 -      INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv);
 -      INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv);
 -      INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv);
 -      INIT_WORK(&priv->request_scan,
 -                (void (*)(void *))ipw_request_scan, priv);
 -      INIT_WORK(&priv->request_passive_scan,
 -                (void (*)(void *))ipw_request_passive_scan, priv);
 -      INIT_WORK(&priv->gather_stats,
 -                (void (*)(void *))ipw_bg_gather_stats, priv);
 -      INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv);
 -      INIT_WORK(&priv->roam, ipw_bg_roam, priv);
 -      INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv);
 -      INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv);
 -      INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv);
 -      INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on,
 -                priv);
 -      INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off,
 -                priv);
 -      INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off,
 -                priv);
 -      INIT_WORK(&priv->merge_networks,
 -                (void (*)(void *))ipw_merge_adhoc_network, priv);
 +      INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check);
 +      INIT_WORK(&priv->associate, ipw_bg_associate);
 +      INIT_WORK(&priv->disassociate, ipw_bg_disassociate);
 +      INIT_WORK(&priv->system_config, ipw_system_config);
 +      INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish);
 +      INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart);
 +      INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill);
 +      INIT_WORK(&priv->up, ipw_bg_up);
 +      INIT_WORK(&priv->down, ipw_bg_down);
 +      INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
 +      INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
 +      INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
 +      INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
 +      INIT_WORK(&priv->roam, ipw_bg_roam);
 +      INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check);
 +      INIT_WORK(&priv->link_up, ipw_bg_link_up);
 +      INIT_WORK(&priv->link_down, ipw_bg_link_down);
 +      INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on);
 +      INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off);
 +      INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off);
 +      INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network);
  
  #ifdef CONFIG_IPW2200_QOS
 -      INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate,
 -                priv);
 +      INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate);
  #endif                                /* CONFIG_IPW2200_QOS */
  
        tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
@@@ -11145,14 -11138,13 +11154,13 @@@ static int ipw_up(struct ipw_priv *priv
                return -EIO;
  
        if (cmdlog && !priv->cmdlog) {
-               priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog,
+               priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog),
                                       GFP_KERNEL);
                if (priv->cmdlog == NULL) {
                        IPW_ERROR("Error allocating %d command log entries.\n",
                                  cmdlog);
                        return -ENOMEM;
                } else {
-                       memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog);
                        priv->cmdlog_len = cmdlog;
                }
        }
  
                        /* If configure to try and auto-associate, kick
                         * off a scan. */
 -                      queue_work(priv->workqueue, &priv->request_scan);
 +                      queue_delayed_work(priv->workqueue,
 +                                         &priv->request_scan, 0);
  
                        return 0;
                }
        return -EIO;
  }
  
 -static void ipw_bg_up(void *data)
 +static void ipw_bg_up(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, up);
        mutex_lock(&priv->mutex);
 -      ipw_up(data);
 +      ipw_up(priv);
        mutex_unlock(&priv->mutex);
  }
  
@@@ -11300,12 -11290,11 +11308,12 @@@ static void ipw_down(struct ipw_priv *p
        ipw_led_radio_off(priv);
  }
  
 -static void ipw_bg_down(void *data)
 +static void ipw_bg_down(struct work_struct *work)
  {
 -      struct ipw_priv *priv = data;
 +      struct ipw_priv *priv =
 +              container_of(work, struct ipw_priv, down);
        mutex_lock(&priv->mutex);
 -      ipw_down(data);
 +      ipw_down(priv);
        mutex_unlock(&priv->mutex);
  }
  
index a87eb51886c89e3d5122a20ace2506897bbbbd23,a48edd131d7583f47b322c0a772933fe425139ba..96606ed100761bca80fc5a04524f2b5fc0868959
@@@ -157,9 -157,8 +157,9 @@@ prism54_mib_init(islpci_private *priv
   * schedule_work(), thus we can as well use sleeping semaphore
   * locking */
  void
 -prism54_update_stats(islpci_private *priv)
 +prism54_update_stats(struct work_struct *work)
  {
 +      islpci_private *priv = container_of(work, islpci_private, stats_work);
        char *data;
        int j;
        struct obj_bss bss, *bss2;
@@@ -2141,11 -2140,9 +2141,9 @@@ prism54_wpa_bss_ie_add(islpci_private *
                                         struct islpci_bss_wpa_ie, list);
                        list_del(&bss->list);
                } else {
-                       bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
-                       if (bss != NULL) {
+                       bss = kzalloc(sizeof (*bss), GFP_ATOMIC);
+                       if (bss != NULL)
                                priv->num_bss_wpa++;
-                               memset(bss, 0, sizeof (*bss));
-                       }
                }
                if (bss != NULL) {
                        memcpy(bss->bssid, bssid, ETH_ALEN);
@@@ -2494,10 -2491,9 +2492,10 @@@ prism54_process_trap_helper(islpci_priv
   * interrupt context, no locks held.
   */
  void
 -prism54_process_trap(void *data)
 +prism54_process_trap(struct work_struct *work)
  {
 -      struct islpci_mgmtframe *frame = data;
 +      struct islpci_mgmtframe *frame =
 +              container_of(work, struct islpci_mgmtframe, ws);
        struct net_device *ndev = frame->ndev;
        enum oid_num_t n = mgt_oidtonum(frame->header->oid);
  
@@@ -2686,11 -2682,10 +2684,10 @@@ prism2_ioctl_set_generic_element(struc
                 return -EINVAL;
  
         alen = sizeof(*attach) + len;
-        attach = kmalloc(alen, GFP_KERNEL);
+        attach = kzalloc(alen, GFP_KERNEL);
         if (attach == NULL)
                 return -ENOMEM;
  
-        memset(attach, 0, alen);
  #define WLAN_FC_TYPE_MGMT 0
  #define WLAN_FC_STYPE_ASSOC_REQ 0
  #define WLAN_FC_STYPE_REASSOC_REQ 2
index f1573a9c23369e5051e8571189171b160e267d03,1dd3f766ff49f32b8e3f407c47879b87f3d1edc1..61c7916b76565e7f496330c950a4c99c6b7986f3
  
  static void ieee_init(struct ieee80211_device *ieee);
  static void softmac_init(struct ieee80211softmac_device *sm);
 -static void set_rts_cts_work(void *d);
 -static void set_basic_rates_work(void *d);
 +static void set_rts_cts_work(struct work_struct *work);
 +static void set_basic_rates_work(struct work_struct *work);
  
  static void housekeeping_init(struct zd_mac *mac);
  static void housekeeping_enable(struct zd_mac *mac);
  static void housekeeping_disable(struct zd_mac *mac);
  
+ static void set_multicast_hash_handler(void *mac_ptr);
  int zd_mac_init(struct zd_mac *mac,
                struct net_device *netdev,
                struct usb_interface *intf)
        memset(mac, 0, sizeof(*mac));
        spin_lock_init(&mac->lock);
        mac->netdev = netdev;
 -      INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work, mac);
 -      INIT_WORK(&mac->set_basic_rates_work, set_basic_rates_work, mac);
 +      INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
 +      INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
  
        ieee_init(ieee);
        softmac_init(ieee80211_priv(netdev));
        zd_chip_init(&mac->chip, netdev, intf);
        housekeeping_init(mac);
+       INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler,
+                 mac);
        return 0;
  }
  
@@@ -136,6 -140,7 +140,7 @@@ out
  
  void zd_mac_clear(struct zd_mac *mac)
  {
+       flush_workqueue(zd_workqueue);
        zd_chip_clear(&mac->chip);
        ZD_ASSERT(!spin_is_locked(&mac->lock));
        ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@@ -256,6 -261,42 +261,42 @@@ int zd_mac_set_mac_address(struct net_d
        return 0;
  }
  
+ static void set_multicast_hash_handler(void *mac_ptr)
+ {
+       struct zd_mac *mac = mac_ptr;
+       struct zd_mc_hash hash;
+       spin_lock_irq(&mac->lock);
+       hash = mac->multicast_hash;
+       spin_unlock_irq(&mac->lock);
+       zd_chip_set_multicast_hash(&mac->chip, &hash);
+ }
+ void zd_mac_set_multicast_list(struct net_device *dev)
+ {
+       struct zd_mc_hash hash;
+       struct zd_mac *mac = zd_netdev_mac(dev);
+       struct dev_mc_list *mc;
+       unsigned long flags;
+       if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+               zd_mc_add_all(&hash);
+       } else {
+               zd_mc_clear(&hash);
+               for (mc = dev->mc_list; mc; mc = mc->next) {
+                       dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
+                                 MAC_ARG(mc->dmi_addr));
+                       zd_mc_add_addr(&hash, mc->dmi_addr);
+               }
+       }
+       spin_lock_irqsave(&mac->lock, flags);
+       mac->multicast_hash = hash;
+       spin_unlock_irqrestore(&mac->lock, flags);
+       queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+ }
  int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
  {
        int r;
@@@ -366,10 -407,9 +407,10 @@@ static void try_enable_tx(struct zd_ma
        spin_unlock_irqrestore(&mac->lock, flags);
  }
  
 -static void set_rts_cts_work(void *d)
 +static void set_rts_cts_work(struct work_struct *work)
  {
 -      struct zd_mac *mac = d;
 +      struct zd_mac *mac =
 +              container_of(work, struct zd_mac, set_rts_cts_work.work);
        unsigned long flags;
        u8 rts_rate;
        unsigned int short_preamble;
        try_enable_tx(mac);
  }
  
 -static void set_basic_rates_work(void *d)
 +static void set_basic_rates_work(struct work_struct *work)
  {
 -      struct zd_mac *mac = d;
 +      struct zd_mac *mac =
 +              container_of(work, struct zd_mac, set_basic_rates_work.work);
        unsigned long flags;
        u16 basic_rates;
  
@@@ -469,13 -508,12 +510,13 @@@ static void bssinfo_change(struct net_d
        if (need_set_rts_cts && !mac->updating_rts_rate) {
                mac->updating_rts_rate = 1;
                netif_stop_queue(mac->netdev);
 -              queue_work(zd_workqueue, &mac->set_rts_cts_work);
 +              queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0);
        }
        if (need_set_rates && !mac->updating_basic_rates) {
                mac->updating_basic_rates = 1;
                netif_stop_queue(mac->netdev);
 -              queue_work(zd_workqueue, &mac->set_basic_rates_work);
 +              queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work,
 +                                 0);
        }
        spin_unlock_irqrestore(&mac->lock, flags);
  }
@@@ -618,6 -656,9 +659,9 @@@ int zd_mac_get_range(struct zd_mac *mac
        range->we_version_compiled = WIRELESS_EXT;
        range->we_version_source = 20;
  
+       range->enc_capa = IW_ENC_CAPA_WPA |  IW_ENC_CAPA_WPA2 |
+                         IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
        ZD_ASSERT(!irqs_disabled());
        spin_lock_irq(&mac->lock);
        regdomain = mac->regdomain;
@@@ -930,7 -971,8 +974,8 @@@ static int is_data_packet_for_us(struc
        }
  
        return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
-              is_multicast_ether_addr(hdr->addr1) ||
+              (is_multicast_ether_addr(hdr->addr1) &&
+               memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
               (netdev->flags & IFF_PROMISC);
  }
  
@@@ -1062,10 -1104,8 +1107,8 @@@ int zd_mac_rx(struct zd_mac *mac, cons
        memcpy(skb_put(skb, length), buffer, length);
  
        r = ieee80211_rx(ieee, skb, &stats);
-       if (!r) {
-               ZD_ASSERT(in_irq());
-               dev_kfree_skb_irq(skb);
-       }
+       if (!r)
+               dev_kfree_skb_any(skb);
        return 0;
  }
  
@@@ -1185,10 -1225,9 +1228,10 @@@ struct iw_statistics *zd_mac_get_wirele
  
  #define LINK_LED_WORK_DELAY HZ
  
 -static void link_led_handler(void *p)
 +static void link_led_handler(struct work_struct *work)
  {
 -      struct zd_mac *mac = p;
 +      struct zd_mac *mac =
 +              container_of(work, struct zd_mac, housekeeping.link_led_work.work);
        struct zd_chip *chip = &mac->chip;
        struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
        int is_associated;
  
  static void housekeeping_init(struct zd_mac *mac)
  {
 -      INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
 +      INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler);
  }
  
  static void housekeeping_enable(struct zd_mac *mac)
index d4e8b870409d144c8711b5cb9dc73d5f156e1e21,77f1268080ed7581f516ee0ed9fe64dcbd2ebbfb..f0cf05dc7d3e0c9e5d36b32c348b2bac38c76c04
@@@ -119,7 -119,7 +119,7 @@@ struct rx_status 
  #define ZD_RX_ERROR                   0x80
  
  struct housekeeping {
 -      struct work_struct link_led_work;
 +      struct delayed_work link_led_work;
  };
  
  #define ZD_MAC_STATS_BUFFER_SIZE 16
@@@ -133,8 -133,10 +133,10 @@@ struct zd_mac 
        struct iw_statistics iw_stats;
  
        struct housekeeping housekeeping;
 -      struct work_struct set_rts_cts_work;
 -      struct work_struct set_basic_rates_work;
+       struct work_struct set_multicast_hash_work;
+       struct zd_mc_hash multicast_hash;
 +      struct delayed_work set_rts_cts_work;
 +      struct delayed_work set_basic_rates_work;
  
        unsigned int stats_count;
        u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
@@@ -189,6 -191,7 +191,7 @@@ int zd_mac_init_hw(struct zd_mac *mac, 
  int zd_mac_open(struct net_device *netdev);
  int zd_mac_stop(struct net_device *netdev);
  int zd_mac_set_mac_address(struct net_device *dev, void *p);
+ void zd_mac_set_multicast_list(struct net_device *netdev);
  
  int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
  
index 08386c102954c07dc7b0a18108c12564a6ff7740,614aa8d329851ba52558ab810258d586d64ee29a..eec1a1dd91da255714c88f8081ac2d28cb94956f
@@@ -58,11 -58,9 +58,11 @@@ ieee80211softmac_assoc(struct ieee80211
  }
  
  void
 -ieee80211softmac_assoc_timeout(void *d)
 +ieee80211softmac_assoc_timeout(struct work_struct *work)
  {
 -      struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
 +      struct ieee80211softmac_device *mac =
 +              container_of(work, struct ieee80211softmac_device,
 +                           associnfo.timeout.work);
        struct ieee80211softmac_network *n;
  
        mutex_lock(&mac->associnfo.mutex);
@@@ -188,11 -186,9 +188,11 @@@ ieee80211softmac_assoc_notify_auth(stru
  
  /* This function is called to handle userspace requests (asynchronously) */
  void
 -ieee80211softmac_assoc_work(void *d)
 +ieee80211softmac_assoc_work(struct work_struct *work)
  {
 -      struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
 +      struct ieee80211softmac_device *mac =
 +              container_of(work, struct ieee80211softmac_device,
 +                           associnfo.work.work);
        struct ieee80211softmac_network *found = NULL;
        struct ieee80211_network *net = NULL, *best = NULL;
        int bssvalid;
@@@ -416,7 -412,7 +416,7 @@@ ieee80211softmac_handle_assoc_response(
                                network->authenticated = 0;
                                /* we don't want to do this more than once ... */
                                network->auth_desynced_once = 1;
 -                              schedule_work(&mac->associnfo.work);
 +                              schedule_delayed_work(&mac->associnfo.work, 0);
                                break;
                        }
                default:
        return 0;
  }
  
+ void
+ ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
+ {
+       unsigned long flags;
+       spin_lock_irqsave(&mac->lock, flags);
+       mac->associnfo.associating = 1;
+       schedule_work(&mac->associnfo.work);
+       spin_unlock_irqrestore(&mac->lock, flags);
+ }
  int
  ieee80211softmac_handle_disassoc(struct net_device * dev,
                                 struct ieee80211_disassoc *disassoc)
        dprintk(KERN_INFO PFX "got disassoc frame\n");
        ieee80211softmac_disassoc(mac);
  
-       /* try to reassociate */
-       schedule_delayed_work(&mac->associnfo.work, 0);
+       ieee80211softmac_try_reassoc(mac);
  
        return 0;
  }
@@@ -470,7 -476,7 +480,7 @@@ ieee80211softmac_handle_reassoc_req(str
                dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
                return 0;
        }
 -      schedule_work(&mac->associnfo.work);
 +      schedule_delayed_work(&mac->associnfo.work, 0);
  
        return 0;
  }
index 6012705aa4f8bba10fcc4905c726730339b72d43,ec449009c3cb3b31c1214b0d330e078b69b58dc5..8ed3e59b8024fd3f5dea77fd5e5df01162b3d039
@@@ -26,7 -26,7 +26,7 @@@
  
  #include "ieee80211softmac_priv.h"
  
 -static void ieee80211softmac_auth_queue(void *data);
 +static void ieee80211softmac_auth_queue(struct work_struct *work);
  
  /* Queues an auth request to the desired AP */
  int
@@@ -54,14 -54,14 +54,14 @@@ ieee80211softmac_auth_req(struct ieee80
        auth->mac = mac;
        auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
        auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
 -      INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
 +      INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue);
        
        /* Lock (for list) */
        spin_lock_irqsave(&mac->lock, flags);
  
        /* add to list */
        list_add_tail(&auth->list, &mac->auth_queue);
 -      schedule_work(&auth->work);
 +      schedule_delayed_work(&auth->work, 0);
        spin_unlock_irqrestore(&mac->lock, flags);
        
        return 0;
  
  /* Sends an auth request to the desired AP and handles timeouts */
  static void
 -ieee80211softmac_auth_queue(void *data)
 +ieee80211softmac_auth_queue(struct work_struct *work)
  {
        struct ieee80211softmac_device *mac;
        struct ieee80211softmac_auth_queue_item *auth;
        struct ieee80211softmac_network *net;
        unsigned long flags;
  
 -      auth = (struct ieee80211softmac_auth_queue_item *)data;
 +      auth = container_of(work, struct ieee80211softmac_auth_queue_item,
 +                          work.work);
        net = auth->net;
        mac = auth->mac;
  
  
  /* Sends a response to an auth challenge (for shared key auth). */
  static void
 -ieee80211softmac_auth_challenge_response(void *_aq)
 +ieee80211softmac_auth_challenge_response(struct work_struct *work)
  {
 -      struct ieee80211softmac_auth_queue_item *aq = _aq;
 +      struct ieee80211softmac_auth_queue_item *aq =
 +              container_of(work, struct ieee80211softmac_auth_queue_item,
 +                           work.work);
  
        /* Send our response */
        ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
@@@ -237,8 -234,8 +237,8 @@@ ieee80211softmac_auth_resp(struct net_d
                         * we have obviously already sent the initial auth
                         * request. */
                        cancel_delayed_work(&aq->work);
 -                      INIT_WORK(&aq->work, &ieee80211softmac_auth_challenge_response, (void *)aq);
 -                      schedule_work(&aq->work);
 +                      INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response);
 +                      schedule_delayed_work(&aq->work, 0);
                        spin_unlock_irqrestore(&mac->lock, flags);
                        return 0;
                case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
@@@ -337,6 -334,8 +337,8 @@@ ieee80211softmac_deauth_from_net(struc
        /* can't transmit data right now... */
        netif_carrier_off(mac->dev);
        spin_unlock_irqrestore(&mac->lock, flags);
+       ieee80211softmac_try_reassoc(mac);
  }
  
  /* 
@@@ -401,6 -400,6 +403,6 @@@ ieee80211softmac_deauth_resp(struct net
        ieee80211softmac_deauth_from_net(mac, net);
  
        /* let's try to re-associate */
 -      schedule_work(&mac->associnfo.work);
 +      schedule_delayed_work(&mac->associnfo.work, 0);
        return 0;
  }
index c0dbe070e548f2faef2eb0b089ee2740b7f18a57,3ae894f0c8f7815d6fc461f34f868cc53cee9bf7..4c2bba34d328c811ad2261c83dc39b371b00d7c5
@@@ -78,7 -78,7 +78,7 @@@
  /* private definitions and prototypes */
  
  /*** prototypes from _scan.c */
 -void ieee80211softmac_scan(void *sm);
 +void ieee80211softmac_scan(struct work_struct *work);
  /* for internal use if scanning is needed */
  int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
  void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
@@@ -149,7 -149,7 +149,7 @@@ int ieee80211softmac_auth_resp(struct n
  int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
  
  /*** prototypes from _assoc.c */
 -void ieee80211softmac_assoc_work(void *d);
 +void ieee80211softmac_assoc_work(struct work_struct *work);
  int ieee80211softmac_handle_assoc_response(struct net_device * dev,
                                           struct ieee80211_assoc_response * resp,
                                           struct ieee80211_network * network);
@@@ -157,7 -157,7 +157,7 @@@ int ieee80211softmac_handle_disassoc(st
                                     struct ieee80211_disassoc * disassoc);
  int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
                                        struct ieee80211_reassoc_request * reassoc);
 -void ieee80211softmac_assoc_timeout(void *d);
 +void ieee80211softmac_assoc_timeout(struct work_struct *work);
  void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
  void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
  
@@@ -207,7 -207,7 +207,7 @@@ struct ieee80211softmac_auth_queue_ite
        struct ieee80211softmac_device  *mac;   /* SoftMAC device */
        u8 retry;                               /* Retry limit */
        u8 state;                               /* Auth State */
 -      struct work_struct              work;   /* Work queue */
 +      struct delayed_work             work;   /* Work queue */
  };
  
  /* scanning information */
@@@ -219,8 -219,7 +219,8 @@@ struct ieee80211softmac_scaninfo 
           stop:1;
        u8 skip_flags;
        struct completion finished;
 -      struct work_struct softmac_scan;
 +      struct delayed_work softmac_scan;
 +      struct ieee80211softmac_device *mac;
  };
  
  /* private event struct */
@@@ -228,7 -227,7 +228,7 @@@ struct ieee80211softmac_event 
        struct list_head list;
        int event_type;
        void *event_context;
 -      struct work_struct work;
 +      struct delayed_work work;
        notify_function_ptr fun;
        void *context;
        struct ieee80211softmac_device *mac;
@@@ -239,4 -238,6 +239,6 @@@ void ieee80211softmac_call_events_locke
  int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
        int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
  
+ void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac);
  #endif /* IEEE80211SOFTMAC_PRIV_H_ */
index 2ffaebd21c53d8931819853735bd07ddc47b16a8,5b7b5b41554dfc8a1b094e671a15ddecbf5b3529..480d72c7a42ca861bb9524a631ea23be8a03feaf
@@@ -122,7 -122,7 +122,7 @@@ ieee80211softmac_wx_set_essid(struct ne
  
        sm->associnfo.associating = 1;
        /* queue lower level code to do work (if necessary) */
 -      schedule_work(&sm->associnfo.work);
 +      schedule_delayed_work(&sm->associnfo.work, 0);
  out:
        mutex_unlock(&sm->associnfo.mutex);
  
@@@ -356,7 -356,7 +356,7 @@@ ieee80211softmac_wx_set_wap(struct net_
                /* force reassociation */
                mac->associnfo.bssvalid = 0;
                if (mac->associnfo.associated)
 -                      schedule_work(&mac->associnfo.work);
 +                      schedule_delayed_work(&mac->associnfo.work, 0);
        } else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
                /* the bssid we have is no longer fixed */
                mac->associnfo.bssfixed = 0;
                /* tell the other code that this bssid should be used no matter what */
                mac->associnfo.bssfixed = 1;
                /* queue associate if new bssid or (old one again and not associated) */
 -              schedule_work(&mac->associnfo.work);
 +              schedule_delayed_work(&mac->associnfo.work, 0);
          }
  
   out:
@@@ -495,7 -495,8 +495,8 @@@ ieee80211softmac_wx_set_mlme(struct net
                        printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
                        goto out;
                }
-               return ieee80211softmac_deauth_req(mac, net, reason);
+               err =  ieee80211softmac_deauth_req(mac, net, reason);
+               goto out;
        case IW_MLME_DISASSOC:
                ieee80211softmac_send_disassoc_req(mac, reason);
                mac->associnfo.associated = 0;