Hello,

I noticed that the zd1211rw driver does not work with ipv6 since the autoconfiguration process requires multicast to be implemented. This was working with the vendor driver. I successfully ported the needed part of the source code to zd1211rw to add multicast support (in fact, the cards needs to be instruct with the proper MAC multicast addr in order to receive the packets intended to those multicast addr). It works (patch attached, against git repository from dsd).

However, ipv6 is still not working and i got several messages "wlan0: duplicate address detected!". I'm not sure yet but i think that multicast packets sent from STA to AP are then retransmitted by the AP to all STA, including the STA which has sent it!

How to make ipv6 working?

Best regards,
Benoit

diff --git a/zd_chip.c b/zd_chip.c
diff --git a/zd_def.h b/zd_def.h
diff --git a/zd_mac.c b/zd_mac.c
index 8acd168..3698ed9 100644
--- a/zd_mac.c
+++ b/zd_mac.c
@@ -36,6 +36,9 @@ static void softmac_init(struct ieee8021
 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 zd_mac_kevent(void *);
+
+#define KEVENT_SET_MULTICAST 1
 
 int zd_mac_init(struct zd_mac *mac,
 	        struct net_device *netdev,
@@ -51,6 +54,9 @@ int zd_mac_init(struct zd_mac *mac,
 	softmac_init(ieee80211_priv(netdev));
 	zd_chip_init(&mac->chip, netdev, intf);
 	housekeeping_init(mac);
+
+        INIT_WORK(&mac->kevent, zd_mac_kevent, netdev);
+        mac->kevent_flags = 0;
 	return 0;
 }
 
@@ -220,6 +226,85 @@ int zd_mac_stop(struct net_device *netde
 	return 0;
 }
 
+/*
+  Set the proper registers from the list of multicast addr. to listen to.
+  Promiscuous and allmulti modes are handled here as well. This function cannot
+  be called in atomic context since zd_io... function needs to sleep.
+*/
+
+void zd_mac_set_multicast_list_real(struct net_device * dev)
+{
+    struct zd_mac * mac = zd_netdev_mac(dev);
+    struct zd_chip * chip = &mac->chip;
+    struct dev_mc_list * mc_list;
+    unsigned int i;
+    u32 tmp;
+
+    /* check that the interface is UP */
+    if (!(dev->flags & IFF_UP))
+        return;
+
+    zd_iowrite32(chip, CR_GROUP_HASH_P1, 0);
+    zd_iowrite32(chip, CR_GROUP_HASH_P2, 0x80000000);
+
+    for (i=0, mc_list=dev->mc_list;
+         i<dev->mc_count; i++, mc_list = mc_list->next) {
+
+        u8 val;
+
+        printk(__FILE__ " : multicast " MAC_FMT "\n",
+               MAC_ARG(mc_list->dmi_addr));
+
+        val = mc_list->dmi_addr[5] >> 2;
+        if (val < 32) {
+            zd_ioread32(chip, CR_GROUP_HASH_P1, &tmp);
+            tmp |= 1 << val;
+            zd_iowrite32(chip, CR_GROUP_HASH_P1, tmp);
+        } else {
+            val -= 32;
+            zd_ioread32(chip, CR_GROUP_HASH_P2, &tmp);
+            tmp |= 1 << val;
+            zd_iowrite32(chip, CR_GROUP_HASH_P2, tmp);
+        }
+    }
+
+    if ((dev->flags & IFF_PROMISC) ||
+        (dev->flags & IFF_ALLMULTI)) {
+        zd_iowrite32(chip, CR_GROUP_HASH_P1, 0xffffffff);
+        zd_iowrite32(chip, CR_GROUP_HASH_P2, 0xffffffff);
+    }
+
+    zd_ioread32(chip, CR_GROUP_HASH_P1, &tmp);
+    printk(__FILE__ " : GroupHashP1 = %x\n", tmp);
+    zd_ioread32(chip, CR_GROUP_HASH_P2, &tmp);
+    printk(__FILE__ " : GroupHashP2 = %x\n", tmp);
+}
+
+/*
+  This is the function called by the netdev layer. This function is in an
+  atomic context and such registers cannot be set directly. As such, the work
+  is defered to the default workqueue, which will call zd_mac_keven().
+*/
+
+void zd_mac_set_multicast_list(struct net_device * dev)
+{
+    struct zd_mac * mac = zd_netdev_mac(dev);
+
+    set_bit(KEVENT_SET_MULTICAST, &mac->kevent_flags);
+    schedule_work(&mac->kevent);
+}
+
+void zd_mac_kevent(void * data)
+{
+    struct net_device * dev = (struct net_device *) data;
+    struct zd_mac * mac = zd_netdev_mac(dev);
+
+    if (test_bit(KEVENT_SET_MULTICAST, &mac->kevent_flags)) {
+        zd_mac_set_multicast_list_real(dev);
+        clear_bit(KEVENT_SET_MULTICAST, &mac->kevent_flags);
+    }
+}
+
 int zd_mac_set_mac_address(struct net_device *netdev, void *p)
 {
 	int r;
@@ -778,8 +863,8 @@ static int is_data_packet_for_us(struct
 	}
 
 	return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
-	       is_multicast_ether_addr(hdr->addr1) ||
-	       (netdev->flags & IFF_PROMISC);
+              is_multicast_ether_addr(hdr->addr1) ||
+              (netdev->flags & IFF_PROMISC);
 }
 
 /* Filters received packets. The function returns 1 if the packet should be
diff --git a/zd_mac.h b/zd_mac.h
index fa4e61f..c53d1a3 100644
--- a/zd_mac.h
+++ b/zd_mac.h
@@ -144,6 +144,10 @@ struct zd_mac {
 	u8 regdomain;
 	u8 default_regdomain;
 	u8 requested_channel;
+    
+    /* for workqueue */
+    struct work_struct kevent;
+    int kevent_flags;
 };
 
 static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
@@ -177,6 +181,8 @@ int zd_mac_init_hw(struct zd_mac *mac, u
 
 int zd_mac_open(struct net_device *netdev);
 int zd_mac_stop(struct net_device *netdev);
+
+void zd_mac_set_multicast_list(struct net_device *dev);
 int zd_mac_set_mac_address(struct net_device *dev, void *p);
 
 int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
diff --git a/zd_netdev.c b/zd_netdev.c
index 440ef24..1c71c1f 100644
--- a/zd_netdev.c
+++ b/zd_netdev.c
@@ -253,7 +253,7 @@ struct net_device *zd_netdev_alloc(struc
 	netdev->open = zd_mac_open;
 	netdev->stop = zd_mac_stop;
 	/* netdev->get_stats = */
-	/* netdev->set_multicast_list = */
+	netdev->set_multicast_list = zd_mac_set_multicast_list;
 	netdev->set_mac_address = zd_mac_set_mac_address;
 	netdev->wireless_handlers = &iw_handler_def;
 	/* netdev->ethtool_ops = */
diff --git a/zd_usb.c b/zd_usb.c
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Zd1211-devs mailing list - http://zd1211.ath.cx/
Unsubscribe: https://lists.sourceforge.net/lists/listinfo/zd1211-devs

Reply via email to