aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r--drivers/net/wireless/libertas/main.c167
1 files changed, 101 insertions, 66 deletions
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);