Re: [zd1211-devs] multicast support and ipv6
Uli Kunitz wrote: > Benoit, I'm doing the filtering with following change: OK. I read the patch a bit fast. My apologies... > I'm absolutely interested in test results. The patch works for me > here under IPv4. Patch is working under IPv6 as well. Thanks for the rewriting it. Benoit - 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
Re: [zd1211-devs] multicast support and ipv6
> IPv6 needs to ignore packets sent, which is not done in your patch. > However, I think such filtering is not zd1211 specific and could be > better done in the generic softmac layer. What is the process to patch > the softmac layer? I was also wondering if filtering ALL packets whose > sender mac is our MAC would be more appropriate? (currently, my patch > only filters out multicast packets with sender MAC being our MAC). Benoit, I'm doing the filtering with following change: @@ -771,7 +812,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) || + (is_multicast_ether_addr(hdr->addr1) && +memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || (netdev->flags & IFF_PROMISC); } It's exactly as you are doing, but will work also in other modes. According to RFC2462 there are problems with removing frames with the identical source address. So limiting it has some value. One could implement something more complex like updating a time-stamp variable in tx for multicast packets. And suppress the incoming packet only if it is in a certain timw window after the tx. I doubt that it is worth to do it. Sharing the code with other cards, might not be possible, because the devices might behave differently. For instance doing the filtering on its own. I'm absolutely interested in test results. The patch works for me here under IPv4. Cheers, Uli -- Uli Kunitz - 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
Re: [zd1211-devs] multicast support and ipv6
Ulrich Kunitz wrote: > On 06-11-23 22:52 Benoit PAPILLAULT wrote: > >> Patch (replacing the previous) is attached. >> >> Best regards, >> Benoit > > Benoit, > > Thank's again for demonstrating how to solve the issue. I've > reworked your patch. You can find the new patch below. Please > check it with IPv6. I don't have here a running AP with IPv6 > enabled. IPv6 needs to ignore packets sent, which is not done in your patch. However, I think such filtering is not zd1211 specific and could be better done in the generic softmac layer. What is the process to patch the softmac layer? I was also wondering if filtering ALL packets whose sender mac is our MAC would be more appropriate? (currently, my patch only filters out multicast packets with sender MAC being our MAC). I'll try your patch on my 2.6.18 kernel as well, later. Best regards, Benoit - 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
Re: [zd1211-devs] multicast support and ipv6
On 06-11-23 22:52 Benoit PAPILLAULT wrote: > Patch (replacing the previous) is attached. > > Best regards, > Benoit Benoit, Thank's again for demonstrating how to solve the issue. I've reworked your patch. You can find the new patch below. Please check it with IPv6. I don't have here a running AP with IPv6 enabled. The patch is also include in my git tree. http://www.deine-taler.de/zd1211/zd1211.git/ Please consider that the master branch compiles against 2.6.18 and not 2.6.19. For 2.6.19 use the branch wireless-dev. Regards, Uli Support for multicast adresses is implemented by supporting the set_multicast_list() function of the network device. Address filtering is supported by a group hash table in the device. Should fix bugzilla.kernel.org bug 7424. Signed-off-by: Ulrich Kunitz <[EMAIL PROTECTED]> --- zd_chip.c | 13 + zd_chip.h | 43 ++- zd_mac.c| 44 +++- zd_mac.h|3 +++ zd_netdev.c |2 +- 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/zd_chip.c b/zd_chip.c index bfff84c..4624379 100644 --- a/zd_chip.c +++ b/zd_chip.c @@ -1672,3 +1672,16 @@ int zd_rfwritev_cr_locked(struct zd_chip return 0; } + +int zd_chip_set_multicast_hash(struct zd_chip *chip, + struct zd_mc_hash *hash) +{ + struct zd_ioreq32 ioreqs[] = { + { CR_GROUP_HASH_P1, hash->low }, + { CR_GROUP_HASH_P2, hash->high }, + }; + + dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n", + ioreqs[0].value, ioreqs[1].value); + return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} diff --git a/zd_chip.h b/zd_chip.h index 0df9d5b..6ed3fb6 100644 --- a/zd_chip.h +++ b/zd_chip.h @@ -395,10 +395,19 @@ #define CR_MAC_ADDR_P2CTL_REG(0x0614) #define CR_BSSID_P1CTL_REG(0x0618) #define CR_BSSID_P2CTL_REG(0x061C) #define CR_BCN_PLCP_CFGCTL_REG(0x0620) + +/* Group hash table for filtering incoming packets. + * + * The group hash table is 64 bit large and split over two parts. The first + * part is the lower part. The upper 6 bits of the last byte of the target + * address are used as index. Packets are received if the hash table bit is + * set. This is used for multicast handling, but for broadcasts (address + * ff:ff:ff:ff:ff:ff) the highest bit in the second table must also be set. + */ #define CR_GROUP_HASH_P1 CTL_REG(0x0624) #define CR_GROUP_HASH_P2 CTL_REG(0x0628) -#define CR_RX_TIMEOUT CTL_REG(0x062C) +#define CR_RX_TIMEOUT CTL_REG(0x062C) /* Basic rates supported by the BSS. When producing ACK or CTS messages, the * device will use a rate in this table that is less than or equal to the rate * of the incoming frame which prompted the response */ @@ -850,4 +859,36 @@ int zd_chip_handle_signal_strength(struc u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status); +struct zd_mc_hash { + u32 low; + u32 high; +}; + +static inline void zd_mc_clear(struct zd_mc_hash *hash) +{ + hash->low = 0; + /* The interfaces must always received broadcasts. +* The hash of the broadcast address ff:ff:ff:ff:ff:ff is 63. +*/ + hash->high = 0x8000; +} + +static inline void zd_mc_add_all(struct zd_mc_hash *hash) +{ + hash->low = hash->high = 0x; +} + +static inline void zd_mc_add_addr(struct zd_mc_hash *hash, u8 *addr) +{ + unsigned int i = addr[5] >> 2; + if (i < 32) { + hash->low |= 1 << i; + } else { + hash->high |= 1 << (i-32); + } +} + +int zd_chip_set_multicast_hash(struct zd_chip *chip, + struct zd_mc_hash *hash); + #endif /* _ZD_CHIP_H */ diff --git a/zd_mac.c b/zd_mac.c index 30ae0c2..5b100a3 100644 --- a/zd_mac.c +++ b/zd_mac.c @@ -37,6 +37,8 @@ static void housekeeping_init(struct zd_ 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) @@ -51,6 +53,8 @@ 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->set_multicast_hash_work, set_multicast_hash_handler, + mac); return 0; } @@ -132,6 +136,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)); @@ -245,6 +250,42 @@ int zd_mac_set_mac_address(struct net_de return 0; } +stati
Re: [zd1211-devs] multicast support and ipv6
Benoit, I just send my mail and received then yours. I will rework your patch as outlined in my e-mail at the weekend. Then it will be in my master branch for 2.6.18 and in the wireless- dev for 2.6.19-rc*. Both trees are synchronized with Daniel's tree. Daniel forwards usually the patches to the John Linville, the maintainer of the wireless tree. Kind regards, UIi -- Uli Kunitz - 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
Re: [zd1211-devs] multicast support and ipv6
Benoit, I appreciate, that you have actually provided a patch. I will probably not use the code at is, I don't like particularly the kevent hacks here. It's simpler and not less prone to race conditions to handle each event in its own work function. So everything related to kevent needs to be removed. Given the structure of our driver we would certainly implement a zd_chip function, which gets the list of muliticast addresses and writes the group hash table. Your patch doesn't work however, because you didn't implement loopback handling. The easy way would be to remove all inbound packets with a source address, that is equal to our own. It would be perfect only to remove it, if we actually send out a multicast packet some time before. Cheers, Uli Am 23.11.2006 um 21:38 wrote Benoit PAPILLAULT: 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, 0x8000); + +for (i=0, mc_list=dev->mc_list; + imc_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, 0x); +zd_iowrite32(chip, CR_GROUP_HASH_P2, 0x); +} + +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_fl
Re: [zd1211-devs] multicast support and ipv6
Benoit PAPILLAULT wrote: 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 I found it. Broadcast/multicast packets sent by the AP are retransmitted by the AP and as such, received by the STA. Reading the vendor driver and the 802.11 specs, I added a filter against broadcast/multicast packets whose source address (SA) is ours. IPv6 is now working! Patch (replacing the previous) is attached. 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..fac9d65 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, 0x8000); + +for (i=0, mc_list=dev->mc_list; + imc_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, 0x); +zd_iowrite32(chip, CR_GROUP_HASH_P2, 0x); +} + +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; @@ -771,6 +856,14 @@ static int is_data_packet_for_us(struct IEEE80211_FCTL_FROMDS || memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0) return 0; + +/* broadcast or multicast packets are resent by the AP, so we + ignore packets we sent */ + +if (is_multicast_ether_addr(hdr->addr1) && +(memcmp(hdr->addr3, netdev->dev_addr, ETH