aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/libertas/cmd.c29
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c1
-rw-r--r--drivers/net/wireless/libertas/dev.h2
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h2
-rw-r--r--drivers/net/wireless/libertas/main.c167
5 files changed, 105 insertions, 96 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index bed68e9add02..b494aba869c5 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -746,28 +746,6 @@ out:
746 return ret; 746 return ret;
747} 747}
748 748
749static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
750 struct cmd_ds_command *cmd,
751 u16 cmd_action)
752{
753 struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
754
755 lbs_deb_enter(LBS_DEB_CMD);
756 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
757 S_DS_GEN);
758 cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
759
760 lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
761 pMCastAdr->action = cpu_to_le16(cmd_action);
762 pMCastAdr->nr_of_adrs =
763 cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
764 memcpy(pMCastAdr->maclist, priv->multicastlist,
765 priv->nr_of_multicastmacaddr * ETH_ALEN);
766
767 lbs_deb_leave(LBS_DEB_CMD);
768 return 0;
769}
770
771/** 749/**
772 * @brief Get the radio channel 750 * @brief Get the radio channel
773 * 751 *
@@ -1247,8 +1225,7 @@ void lbs_set_mac_control(struct lbs_private *priv)
1247 cmd.action = cpu_to_le16(priv->mac_control); 1225 cmd.action = cpu_to_le16(priv->mac_control);
1248 cmd.reserved = 0; 1226 cmd.reserved = 0;
1249 1227
1250 lbs_cmd_async(priv, CMD_MAC_CONTROL, 1228 lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
1251 &cmd.hdr, sizeof(cmd));
1252 1229
1253 lbs_deb_leave(LBS_DEB_CMD); 1230 lbs_deb_leave(LBS_DEB_CMD);
1254} 1231}
@@ -1360,10 +1337,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
1360 cmdptr, cmd_action); 1337 cmdptr, cmd_action);
1361 break; 1338 break;
1362 1339
1363 case CMD_MAC_MULTICAST_ADR:
1364 ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
1365 break;
1366
1367 case CMD_802_11_MONITOR_MODE: 1340 case CMD_802_11_MONITOR_MODE:
1368 ret = lbs_cmd_802_11_monitor_mode(cmdptr, 1341 ret = lbs_cmd_802_11_monitor_mode(cmdptr,
1369 cmd_action, pdata_buf); 1342 cmd_action, pdata_buf);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 9e50fdd94810..4c3c5ec16f98 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -316,7 +316,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
316 316
317 break; 317 break;
318 318
319 case CMD_RET(CMD_MAC_MULTICAST_ADR):
320 case CMD_RET(CMD_802_11_RESET): 319 case CMD_RET(CMD_802_11_RESET):
321 case CMD_RET(CMD_802_11_AUTHENTICATE): 320 case CMD_RET(CMD_802_11_AUTHENTICATE):
322 case CMD_RET(CMD_802_11_BEACON_STOP): 321 case CMD_RET(CMD_802_11_BEACON_STOP):
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 0d9edb9b11f5..e12ce6506729 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -140,6 +140,8 @@ struct lbs_private {
140 wait_queue_head_t waitq; 140 wait_queue_head_t waitq;
141 struct workqueue_struct *work_thread; 141 struct workqueue_struct *work_thread;
142 142
143 struct work_struct mcast_work;
144
143 /** Scanning */ 145 /** Scanning */
144 struct delayed_work scan_work; 146 struct delayed_work scan_work;
145 struct delayed_work assoc_work; 147 struct delayed_work assoc_work;
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index f29bc5bbda3e..c36ab3162238 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -219,6 +219,7 @@ struct cmd_ds_mac_control {
219}; 219};
220 220
221struct cmd_ds_mac_multicast_adr { 221struct cmd_ds_mac_multicast_adr {
222 struct cmd_header hdr;
222 __le16 action; 223 __le16 action;
223 __le16 nr_of_adrs; 224 __le16 nr_of_adrs;
224 u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; 225 u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
@@ -703,7 +704,6 @@ struct cmd_ds_command {
703 struct cmd_ds_802_11_rf_antenna rant; 704 struct cmd_ds_802_11_rf_antenna rant;
704 struct cmd_ds_802_11_monitor_mode monitor; 705 struct cmd_ds_802_11_monitor_mode monitor;
705 struct cmd_ds_802_11_rate_adapt_rateset rateset; 706 struct cmd_ds_802_11_rate_adapt_rateset rateset;
706 struct cmd_ds_mac_multicast_adr madr;
707 struct cmd_ds_802_11_ad_hoc_join adj; 707 struct cmd_ds_802_11_ad_hoc_join adj;
708 struct cmd_ds_802_11_rssi rssi; 708 struct cmd_ds_802_11_rssi rssi;
709 struct cmd_ds_802_11_rssi_rsp rssirsp; 709 struct cmd_ds_802_11_rssi_rsp rssirsp;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index e333f14dce23..a87febad8c29 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -11,6 +11,7 @@
11#include <linux/if_arp.h> 11#include <linux/if_arp.h>
12#include <linux/kthread.h> 12#include <linux/kthread.h>
13#include <linux/kfifo.h> 13#include <linux/kfifo.h>
14#include <linux/stddef.h>
14 15
15#include <net/iw_handler.h> 16#include <net/iw_handler.h>
16#include <net/ieee80211.h> 17#include <net/ieee80211.h>
@@ -446,6 +447,8 @@ static int lbs_mesh_stop(struct net_device *dev)
446 447
447 spin_unlock_irq(&priv->driver_lock); 448 spin_unlock_irq(&priv->driver_lock);
448 449
450 schedule_work(&priv->mcast_work);
451
449 lbs_deb_leave(LBS_DEB_MESH); 452 lbs_deb_leave(LBS_DEB_MESH);
450 return 0; 453 return 0;
451} 454}
@@ -467,6 +470,8 @@ static int lbs_eth_stop(struct net_device *dev)
467 netif_stop_queue(dev); 470 netif_stop_queue(dev);
468 spin_unlock_irq(&priv->driver_lock); 471 spin_unlock_irq(&priv->driver_lock);
469 472
473 schedule_work(&priv->mcast_work);
474
470 lbs_deb_leave(LBS_DEB_NET); 475 lbs_deb_leave(LBS_DEB_NET);
471 return 0; 476 return 0;
472} 477}
@@ -563,89 +568,116 @@ done:
563 return ret; 568 return ret;
564} 569}
565 570
566static int lbs_copy_multicast_address(struct lbs_private *priv, 571
567 struct net_device *dev) 572static inline int mac_in_list(unsigned char *list, int list_len,
573 unsigned char *mac)
568{ 574{
569 int i = 0; 575 while (list_len) {
570 struct dev_mc_list *mcptr = dev->mc_list; 576 if (!memcmp(list, mac, ETH_ALEN))
577 return 1;
578 list += ETH_ALEN;
579 list_len--;
580 }
581 return 0;
582}
583
571 584
572 for (i = 0; i < dev->mc_count; i++) { 585static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
573 memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); 586 struct net_device *dev, int nr_addrs)
574 mcptr = mcptr->next; 587{
588 int i = nr_addrs;
589 struct dev_mc_list *mc_list;
590 DECLARE_MAC_BUF(mac);
591
592 if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
593 return nr_addrs;
594
595 netif_tx_lock_bh(dev);
596 for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
597 if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
598 lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
599 print_mac(mac, mc_list->dmi_addr));
600 continue;
601 }
602
603 if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
604 break;
605 memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
606 lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
607 print_mac(mac, mc_list->dmi_addr));
608 i++;
575 } 609 }
610 netif_tx_unlock_bh(dev);
611 if (mc_list)
612 return -EOVERFLOW;
613
576 return i; 614 return i;
577} 615}
578 616
579static void lbs_set_multicast_list(struct net_device *dev) 617static void lbs_set_mcast_worker(struct work_struct *work)
580{ 618{
581 struct lbs_private *priv = dev->priv; 619 struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
582 int old_mac_control; 620 struct cmd_ds_mac_multicast_adr mcast_cmd;
583 DECLARE_MAC_BUF(mac); 621 int dev_flags;
622 int nr_addrs;
623 int old_mac_control = priv->mac_control;
584 624
585 lbs_deb_enter(LBS_DEB_NET); 625 lbs_deb_enter(LBS_DEB_NET);
586 626
587 old_mac_control = priv->mac_control; 627 dev_flags = priv->dev->flags;
588 628 if (priv->mesh_dev)
589 if (dev->flags & IFF_PROMISC) { 629 dev_flags |= priv->mesh_dev->flags;
590 lbs_deb_net("enable promiscuous mode\n"); 630
591 priv->mac_control |= 631 if (dev_flags & IFF_PROMISC) {
592 CMD_ACT_MAC_PROMISCUOUS_ENABLE; 632 priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
593 priv->mac_control &= 633 priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
594 ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | 634 CMD_ACT_MAC_MULTICAST_ENABLE);
595 CMD_ACT_MAC_MULTICAST_ENABLE); 635 goto out_set_mac_control;
596 } else { 636 } else if (dev_flags & IFF_ALLMULTI) {
597 /* Multicast */ 637 do_allmulti:
598 priv->mac_control &= 638 priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
599 ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; 639 priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
600 640 CMD_ACT_MAC_MULTICAST_ENABLE);
601 if (dev->flags & IFF_ALLMULTI || dev->mc_count > 641 goto out_set_mac_control;
602 MRVDRV_MAX_MULTICAST_LIST_SIZE) {
603 lbs_deb_net( "enabling all multicast\n");
604 priv->mac_control |=
605 CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
606 priv->mac_control &=
607 ~CMD_ACT_MAC_MULTICAST_ENABLE;
608 } else {
609 priv->mac_control &=
610 ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
611
612 if (!dev->mc_count) {
613 lbs_deb_net("no multicast addresses, "
614 "disabling multicast\n");
615 priv->mac_control &=
616 ~CMD_ACT_MAC_MULTICAST_ENABLE;
617 } else {
618 int i;
619
620 priv->mac_control |=
621 CMD_ACT_MAC_MULTICAST_ENABLE;
622
623 priv->nr_of_multicastmacaddr =
624 lbs_copy_multicast_address(priv, dev);
625
626 lbs_deb_net("multicast addresses: %d\n",
627 dev->mc_count);
628
629 for (i = 0; i < dev->mc_count; i++) {
630 lbs_deb_net("Multicast address %d: %s\n",
631 i, print_mac(mac,
632 priv->multicastlist[i]));
633 }
634 /* send multicast addresses to firmware */
635 lbs_prepare_and_send_command(priv,
636 CMD_MAC_MULTICAST_ADR,
637 CMD_ACT_SET, 0, 0,
638 NULL);
639 }
640 }
641 } 642 }
642 643
644 /* Once for priv->dev, again for priv->mesh_dev if it exists */
645 nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
646 if (nr_addrs >= 0 && priv->mesh_dev)
647 nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
648 if (nr_addrs < 0)
649 goto do_allmulti;
650
651 if (nr_addrs) {
652 int size = offsetof(struct cmd_ds_mac_multicast_adr,
653 maclist[6*nr_addrs]);
654
655 mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
656 mcast_cmd.hdr.size = cpu_to_le16(size);
657 mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
658
659 lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
660
661 priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
662 } else
663 priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
664
665 priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
666 CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
667 out_set_mac_control:
643 if (priv->mac_control != old_mac_control) 668 if (priv->mac_control != old_mac_control)
644 lbs_set_mac_control(priv); 669 lbs_set_mac_control(priv);
645 670
646 lbs_deb_leave(LBS_DEB_NET); 671 lbs_deb_leave(LBS_DEB_NET);
647} 672}
648 673
674static void lbs_set_multicast_list(struct net_device *dev)
675{
676 struct lbs_private *priv = dev->priv;
677
678 schedule_work(&priv->mcast_work);
679}
680
649/** 681/**
650 * @brief This function handles the major jobs in the LBS driver. 682 * @brief This function handles the major jobs in the LBS driver.
651 * It handles all events generated by firmware, RX data received 683 * It handles all events generated by firmware, RX data received
@@ -1122,6 +1154,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
1122 priv->work_thread = create_singlethread_workqueue("lbs_worker"); 1154 priv->work_thread = create_singlethread_workqueue("lbs_worker");
1123 INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); 1155 INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
1124 INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); 1156 INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
1157 INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
1125 INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); 1158 INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
1126 1159
1127 sprintf(priv->mesh_ssid, "mesh"); 1160 sprintf(priv->mesh_ssid, "mesh");
@@ -1158,6 +1191,7 @@ void lbs_remove_card(struct lbs_private *priv)
1158 1191
1159 cancel_delayed_work_sync(&priv->scan_work); 1192 cancel_delayed_work_sync(&priv->scan_work);
1160 cancel_delayed_work_sync(&priv->assoc_work); 1193 cancel_delayed_work_sync(&priv->assoc_work);
1194 cancel_work_sync(&priv->mcast_work);
1161 destroy_workqueue(priv->work_thread); 1195 destroy_workqueue(priv->work_thread);
1162 1196
1163 if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { 1197 if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
@@ -1322,6 +1356,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
1322#ifdef WIRELESS_EXT 1356#ifdef WIRELESS_EXT
1323 mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; 1357 mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
1324#endif 1358#endif
1359 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1360 mesh_dev->set_multicast_list = lbs_set_multicast_list;
1325 /* Register virtual mesh interface */ 1361 /* Register virtual mesh interface */
1326 ret = register_netdev(mesh_dev); 1362 ret = register_netdev(mesh_dev);
1327 if (ret) { 1363 if (ret) {
@@ -1554,7 +1590,6 @@ static int lbs_add_rtap(struct lbs_private *priv)
1554 rtap_dev->stop = lbs_rtap_stop; 1590 rtap_dev->stop = lbs_rtap_stop;
1555 rtap_dev->get_stats = lbs_rtap_get_stats; 1591 rtap_dev->get_stats = lbs_rtap_get_stats;
1556 rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; 1592 rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
1557 rtap_dev->set_multicast_list = lbs_set_multicast_list;
1558 rtap_dev->priv = priv; 1593 rtap_dev->priv = priv;
1559 1594
1560 ret = register_netdev(rtap_dev); 1595 ret = register_netdev(rtap_dev);