[PATCH] s390: qeth multicast address registration fixed
authorFrank Pavlic <fpavlic@de.ibm.com>
Thu, 10 Nov 2005 12:49:28 +0000 (13:49 +0100)
committerJeff Garzik <jgarzik@pobox.com>
Fri, 11 Nov 2005 13:26:21 +0000 (08:26 -0500)
[patch 3/7] s390: qeth multicast address registration fixed

From: Klaus Dieter Wacker <kdwacker@de.ibm.com>
- when running in Layer2 mode we don't have to register
  the multicast IP address but only group mac address.
  Therefore for Layer 2 devices it is enough to go
  through dev->mc_list list and register these entries.

Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
diffstat:
 qeth_main.c |  106 +++++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 80 insertions(+), 26 deletions(-)
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
drivers/s390/net/qeth_main.c

index ab50e0ea93132872c096c8a0b47d0c74985ca5ed..0a5d758b531e38d9f9488eb6cabd4bc6a809ed6a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.235 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.236 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -12,7 +12,7 @@
  *                       Frank Pavlic (pavlic@de.ibm.com) and
  *                       Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.235 $        $Date: 2005/05/04 20:19:18 $
+ *    $Revision: 1.236 $        $Date: 2005/05/04 20:19:18 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,7 +72,7 @@
 #include "qeth_eddp.h"
 #include "qeth_tso.h"
 
-#define VERSION_QETH_C "$Revision: 1.235 $"
+#define VERSION_QETH_C "$Revision: 1.236 $"
 static const char *version = "qeth S/390 OSA-Express driver";
 
 /**
@@ -602,11 +602,20 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
        int found = 0;
 
        list_for_each_entry(addr, &card->ip_list, entry) {
+               if (card->options.layer2) {
+                       if ((addr->type == todo->type) &&
+                           (memcmp(&addr->mac, &todo->mac, 
+                                   OSA_ADDR_LEN) == 0)) {
+                               found = 1;
+                               break;
+                       }
+                       continue;
+               } 
                if ((addr->proto     == QETH_PROT_IPV4)  &&
                    (todo->proto     == QETH_PROT_IPV4)  &&
                    (addr->type      == todo->type)      &&
                    (addr->u.a4.addr == todo->u.a4.addr) &&
-                   (addr->u.a4.mask == todo->u.a4.mask)   ){
+                   (addr->u.a4.mask == todo->u.a4.mask){
                        found = 1;
                        break;
                }
@@ -615,12 +624,12 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
                    (addr->type        == todo->type)         &&
                    (addr->u.a6.pfxlen == todo->u.a6.pfxlen)  &&
                    (memcmp(&addr->u.a6.addr, &todo->u.a6.addr,
-                           sizeof(struct in6_addr)) == 0))     {
+                           sizeof(struct in6_addr)) == 0)) {
                        found = 1;
                        break;
                }
        }
-       if (found){
+       if (found) {
                addr->users += todo->users;
                if (addr->users <= 0){
                        *__addr = addr;
@@ -632,7 +641,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
                        return 0;
                }
        }
-       if (todo->users > 0){
+       if (todo->users > 0) {
                /* for VIPA and RXIP limit refcount to 1 */
                if (todo->type != QETH_IP_TYPE_NORMAL)
                        todo->users = 1;
@@ -682,12 +691,22 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
                if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
                    (tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
                        return 0;
+               if (card->options.layer2) {
+                       if ((tmp->type  == addr->type)  &&
+                           (tmp->is_multicast == addr->is_multicast) &&
+                           (memcmp(&tmp->mac, &addr->mac, 
+                                   OSA_ADDR_LEN) == 0)) {
+                               found = 1;
+                               break;
+                       }
+                       continue;
+               }        
                if ((tmp->proto        == QETH_PROT_IPV4)     &&
                    (addr->proto       == QETH_PROT_IPV4)     &&
                    (tmp->type         == addr->type)         &&
                    (tmp->is_multicast == addr->is_multicast) &&
                    (tmp->u.a4.addr    == addr->u.a4.addr)    &&
-                   (tmp->u.a4.mask    == addr->u.a4.mask)      ){
+                   (tmp->u.a4.mask    == addr->u.a4.mask){
                        found = 1;
                        break;
                }
@@ -697,7 +716,7 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
                    (tmp->is_multicast == addr->is_multicast)  &&
                    (tmp->u.a6.pfxlen  == addr->u.a6.pfxlen)   &&
                    (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
-                           sizeof(struct in6_addr)) == 0)        ){
+                           sizeof(struct in6_addr)) == 0){
                        found = 1;
                        break;
                }
@@ -707,7 +726,7 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
                        tmp->users += addr->users;
                else
                        tmp->users += add? 1:-1;
-               if (tmp->users == 0){
+               if (tmp->users == 0) {
                        list_del(&tmp->entry);
                        kfree(tmp);
                }
@@ -738,12 +757,15 @@ qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
        unsigned long flags;
        int rc = 0;
 
-       QETH_DBF_TEXT(trace,4,"delip");
-       if (addr->proto == QETH_PROT_IPV4)
-               QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
+       QETH_DBF_TEXT(trace, 4, "delip");
+
+       if (card->options.layer2)
+               QETH_DBF_HEX(trace, 4, &addr->mac, 6);
+       else if (addr->proto == QETH_PROT_IPV4)
+               QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4);
        else {
-               QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
-               QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
+               QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8);
+               QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8);
        }
        spin_lock_irqsave(&card->ip_lock, flags);
        rc = __qeth_insert_ip_todo(card, addr, 0);
@@ -757,12 +779,14 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
        unsigned long flags;
        int rc = 0;
 
-       QETH_DBF_TEXT(trace,4,"addip");
-       if (addr->proto == QETH_PROT_IPV4)
-               QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
+       QETH_DBF_TEXT(trace, 4, "addip");
+       if (card->options.layer2)
+               QETH_DBF_HEX(trace, 4, &addr->mac, 6);
+       else if (addr->proto == QETH_PROT_IPV4)
+               QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4);
        else {
-               QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
-               QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
+               QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8);
+               QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8);
        }
        spin_lock_irqsave(&card->ip_lock, flags);
        rc = __qeth_insert_ip_todo(card, addr, 1);
@@ -851,6 +875,7 @@ qeth_set_ip_addr_list(struct qeth_card *card)
 
 static void qeth_delete_mc_addresses(struct qeth_card *);
 static void qeth_add_multicast_ipv4(struct qeth_card *);
+static void qeth_layer2_add_multicast(struct qeth_card *);
 #ifdef CONFIG_QETH_IPV6
 static void qeth_add_multicast_ipv6(struct qeth_card *);
 #endif
@@ -5301,8 +5326,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)
        struct qeth_ipaddr *addr;
 
        QETH_DBF_TEXT(trace, 4, "frvaddr4");
-       if (!card->vlangrp)
-               return;
+
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]);
        if (!in_dev)
@@ -5330,8 +5354,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
        struct qeth_ipaddr *addr;
 
        QETH_DBF_TEXT(trace, 4, "frvaddr6");
-       if (!card->vlangrp)
-               return;
+
        in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]);
        if (!in6_dev)
                return;
@@ -5350,6 +5373,15 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
 #endif /* CONFIG_QETH_IPV6 */
 }
 
+static void
+qeth_free_vlan_addresses(struct qeth_card *card, unsigned short vid)
+{
+       if (card->options.layer2 || !card->vlangrp)
+               return;
+       qeth_free_vlan_addresses4(card, vid);
+       qeth_free_vlan_addresses6(card, vid);
+}
+
 static int
 qeth_layer2_send_setdelvlan_cb(struct qeth_card *card,
                                struct qeth_reply *reply,
@@ -5432,8 +5464,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        qeth_free_vlan_skbs(card, vid);
        spin_lock_irqsave(&card->vlanlock, flags);
        /* unregister IP addresses of vlan device */
-       qeth_free_vlan_addresses4(card, vid);
-       qeth_free_vlan_addresses6(card, vid);
+       qeth_free_vlan_addresses(card, vid);
        if (card->vlangrp)
                card->vlangrp->vlan_devices[vid] = NULL;
        spin_unlock_irqrestore(&card->vlanlock, flags);
@@ -5456,10 +5487,15 @@ qeth_set_multicast_list(struct net_device *dev)
         
        QETH_DBF_TEXT(trace,3,"setmulti");
        qeth_delete_mc_addresses(card);
+       if (card->options.layer2) {
+               qeth_layer2_add_multicast(card);
+               goto out;
+       }
        qeth_add_multicast_ipv4(card);
 #ifdef CONFIG_QETH_IPV6
        qeth_add_multicast_ipv6(card);
 #endif
+out:
        if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
                schedule_work(&card->kernel_thread_starter);
 }
@@ -5669,6 +5705,24 @@ qeth_add_multicast_ipv4(struct qeth_card *card)
        in_dev_put(in4_dev);
 }
 
+static void
+qeth_layer2_add_multicast(struct qeth_card *card)
+{
+       struct qeth_ipaddr *ipm;
+       struct dev_mc_list *dm;
+
+       QETH_DBF_TEXT(trace,4,"L2addmc");
+       for (dm = card->dev->mc_list; dm; dm = dm->next) {
+               ipm = qeth_get_addr_buffer(QETH_PROT_IPV4);
+               if (!ipm)
+                       continue;
+               memcpy(ipm->mac,dm->dmi_addr,MAX_ADDR_LEN);
+               ipm->is_multicast = 1;
+               if (!qeth_add_ip(card, ipm))
+                       kfree(ipm);
+       }
+}
+
 #ifdef CONFIG_QETH_IPV6
 static inline void
 qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)