diff options
-rw-r--r-- | drivers/s390/net/qeth_main.c | 106 |
1 files changed, 80 insertions, 26 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index ab50e0ea9313..0a5d758b531e 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * linux/drivers/s390/net/qeth_main.c ($Revision: 1.235 $) | 3 | * linux/drivers/s390/net/qeth_main.c ($Revision: 1.236 $) |
4 | * | 4 | * |
5 | * Linux on zSeries OSA Express and HiperSockets support | 5 | * Linux on zSeries OSA Express and HiperSockets support |
6 | * | 6 | * |
@@ -12,7 +12,7 @@ | |||
12 | * Frank Pavlic (pavlic@de.ibm.com) and | 12 | * Frank Pavlic (pavlic@de.ibm.com) and |
13 | * Thomas Spatzier <tspat@de.ibm.com> | 13 | * Thomas Spatzier <tspat@de.ibm.com> |
14 | * | 14 | * |
15 | * $Revision: 1.235 $ $Date: 2005/05/04 20:19:18 $ | 15 | * $Revision: 1.236 $ $Date: 2005/05/04 20:19:18 $ |
16 | * | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | 17 | * This program is free software; you can redistribute it and/or modify |
18 | * it under the terms of the GNU General Public License as published by | 18 | * it under the terms of the GNU General Public License as published by |
@@ -72,7 +72,7 @@ | |||
72 | #include "qeth_eddp.h" | 72 | #include "qeth_eddp.h" |
73 | #include "qeth_tso.h" | 73 | #include "qeth_tso.h" |
74 | 74 | ||
75 | #define VERSION_QETH_C "$Revision: 1.235 $" | 75 | #define VERSION_QETH_C "$Revision: 1.236 $" |
76 | static const char *version = "qeth S/390 OSA-Express driver"; | 76 | static const char *version = "qeth S/390 OSA-Express driver"; |
77 | 77 | ||
78 | /** | 78 | /** |
@@ -602,11 +602,20 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, | |||
602 | int found = 0; | 602 | int found = 0; |
603 | 603 | ||
604 | list_for_each_entry(addr, &card->ip_list, entry) { | 604 | list_for_each_entry(addr, &card->ip_list, entry) { |
605 | if (card->options.layer2) { | ||
606 | if ((addr->type == todo->type) && | ||
607 | (memcmp(&addr->mac, &todo->mac, | ||
608 | OSA_ADDR_LEN) == 0)) { | ||
609 | found = 1; | ||
610 | break; | ||
611 | } | ||
612 | continue; | ||
613 | } | ||
605 | if ((addr->proto == QETH_PROT_IPV4) && | 614 | if ((addr->proto == QETH_PROT_IPV4) && |
606 | (todo->proto == QETH_PROT_IPV4) && | 615 | (todo->proto == QETH_PROT_IPV4) && |
607 | (addr->type == todo->type) && | 616 | (addr->type == todo->type) && |
608 | (addr->u.a4.addr == todo->u.a4.addr) && | 617 | (addr->u.a4.addr == todo->u.a4.addr) && |
609 | (addr->u.a4.mask == todo->u.a4.mask) ){ | 618 | (addr->u.a4.mask == todo->u.a4.mask)) { |
610 | found = 1; | 619 | found = 1; |
611 | break; | 620 | break; |
612 | } | 621 | } |
@@ -615,12 +624,12 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, | |||
615 | (addr->type == todo->type) && | 624 | (addr->type == todo->type) && |
616 | (addr->u.a6.pfxlen == todo->u.a6.pfxlen) && | 625 | (addr->u.a6.pfxlen == todo->u.a6.pfxlen) && |
617 | (memcmp(&addr->u.a6.addr, &todo->u.a6.addr, | 626 | (memcmp(&addr->u.a6.addr, &todo->u.a6.addr, |
618 | sizeof(struct in6_addr)) == 0)) { | 627 | sizeof(struct in6_addr)) == 0)) { |
619 | found = 1; | 628 | found = 1; |
620 | break; | 629 | break; |
621 | } | 630 | } |
622 | } | 631 | } |
623 | if (found){ | 632 | if (found) { |
624 | addr->users += todo->users; | 633 | addr->users += todo->users; |
625 | if (addr->users <= 0){ | 634 | if (addr->users <= 0){ |
626 | *__addr = addr; | 635 | *__addr = addr; |
@@ -632,7 +641,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, | |||
632 | return 0; | 641 | return 0; |
633 | } | 642 | } |
634 | } | 643 | } |
635 | if (todo->users > 0){ | 644 | if (todo->users > 0) { |
636 | /* for VIPA and RXIP limit refcount to 1 */ | 645 | /* for VIPA and RXIP limit refcount to 1 */ |
637 | if (todo->type != QETH_IP_TYPE_NORMAL) | 646 | if (todo->type != QETH_IP_TYPE_NORMAL) |
638 | todo->users = 1; | 647 | todo->users = 1; |
@@ -682,12 +691,22 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) | |||
682 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && | 691 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && |
683 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) | 692 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) |
684 | return 0; | 693 | return 0; |
694 | if (card->options.layer2) { | ||
695 | if ((tmp->type == addr->type) && | ||
696 | (tmp->is_multicast == addr->is_multicast) && | ||
697 | (memcmp(&tmp->mac, &addr->mac, | ||
698 | OSA_ADDR_LEN) == 0)) { | ||
699 | found = 1; | ||
700 | break; | ||
701 | } | ||
702 | continue; | ||
703 | } | ||
685 | if ((tmp->proto == QETH_PROT_IPV4) && | 704 | if ((tmp->proto == QETH_PROT_IPV4) && |
686 | (addr->proto == QETH_PROT_IPV4) && | 705 | (addr->proto == QETH_PROT_IPV4) && |
687 | (tmp->type == addr->type) && | 706 | (tmp->type == addr->type) && |
688 | (tmp->is_multicast == addr->is_multicast) && | 707 | (tmp->is_multicast == addr->is_multicast) && |
689 | (tmp->u.a4.addr == addr->u.a4.addr) && | 708 | (tmp->u.a4.addr == addr->u.a4.addr) && |
690 | (tmp->u.a4.mask == addr->u.a4.mask) ){ | 709 | (tmp->u.a4.mask == addr->u.a4.mask)) { |
691 | found = 1; | 710 | found = 1; |
692 | break; | 711 | break; |
693 | } | 712 | } |
@@ -697,7 +716,7 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) | |||
697 | (tmp->is_multicast == addr->is_multicast) && | 716 | (tmp->is_multicast == addr->is_multicast) && |
698 | (tmp->u.a6.pfxlen == addr->u.a6.pfxlen) && | 717 | (tmp->u.a6.pfxlen == addr->u.a6.pfxlen) && |
699 | (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr, | 718 | (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr, |
700 | sizeof(struct in6_addr)) == 0) ){ | 719 | sizeof(struct in6_addr)) == 0)) { |
701 | found = 1; | 720 | found = 1; |
702 | break; | 721 | break; |
703 | } | 722 | } |
@@ -707,7 +726,7 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) | |||
707 | tmp->users += addr->users; | 726 | tmp->users += addr->users; |
708 | else | 727 | else |
709 | tmp->users += add? 1:-1; | 728 | tmp->users += add? 1:-1; |
710 | if (tmp->users == 0){ | 729 | if (tmp->users == 0) { |
711 | list_del(&tmp->entry); | 730 | list_del(&tmp->entry); |
712 | kfree(tmp); | 731 | kfree(tmp); |
713 | } | 732 | } |
@@ -738,12 +757,15 @@ qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) | |||
738 | unsigned long flags; | 757 | unsigned long flags; |
739 | int rc = 0; | 758 | int rc = 0; |
740 | 759 | ||
741 | QETH_DBF_TEXT(trace,4,"delip"); | 760 | QETH_DBF_TEXT(trace, 4, "delip"); |
742 | if (addr->proto == QETH_PROT_IPV4) | 761 | |
743 | QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4); | 762 | if (card->options.layer2) |
763 | QETH_DBF_HEX(trace, 4, &addr->mac, 6); | ||
764 | else if (addr->proto == QETH_PROT_IPV4) | ||
765 | QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4); | ||
744 | else { | 766 | else { |
745 | QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8); | 767 | QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8); |
746 | QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8); | 768 | QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8); |
747 | } | 769 | } |
748 | spin_lock_irqsave(&card->ip_lock, flags); | 770 | spin_lock_irqsave(&card->ip_lock, flags); |
749 | rc = __qeth_insert_ip_todo(card, addr, 0); | 771 | rc = __qeth_insert_ip_todo(card, addr, 0); |
@@ -757,12 +779,14 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) | |||
757 | unsigned long flags; | 779 | unsigned long flags; |
758 | int rc = 0; | 780 | int rc = 0; |
759 | 781 | ||
760 | QETH_DBF_TEXT(trace,4,"addip"); | 782 | QETH_DBF_TEXT(trace, 4, "addip"); |
761 | if (addr->proto == QETH_PROT_IPV4) | 783 | if (card->options.layer2) |
762 | QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4); | 784 | QETH_DBF_HEX(trace, 4, &addr->mac, 6); |
785 | else if (addr->proto == QETH_PROT_IPV4) | ||
786 | QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4); | ||
763 | else { | 787 | else { |
764 | QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8); | 788 | QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8); |
765 | QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8); | 789 | QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8); |
766 | } | 790 | } |
767 | spin_lock_irqsave(&card->ip_lock, flags); | 791 | spin_lock_irqsave(&card->ip_lock, flags); |
768 | rc = __qeth_insert_ip_todo(card, addr, 1); | 792 | rc = __qeth_insert_ip_todo(card, addr, 1); |
@@ -851,6 +875,7 @@ qeth_set_ip_addr_list(struct qeth_card *card) | |||
851 | 875 | ||
852 | static void qeth_delete_mc_addresses(struct qeth_card *); | 876 | static void qeth_delete_mc_addresses(struct qeth_card *); |
853 | static void qeth_add_multicast_ipv4(struct qeth_card *); | 877 | static void qeth_add_multicast_ipv4(struct qeth_card *); |
878 | static void qeth_layer2_add_multicast(struct qeth_card *); | ||
854 | #ifdef CONFIG_QETH_IPV6 | 879 | #ifdef CONFIG_QETH_IPV6 |
855 | static void qeth_add_multicast_ipv6(struct qeth_card *); | 880 | static void qeth_add_multicast_ipv6(struct qeth_card *); |
856 | #endif | 881 | #endif |
@@ -5301,8 +5326,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) | |||
5301 | struct qeth_ipaddr *addr; | 5326 | struct qeth_ipaddr *addr; |
5302 | 5327 | ||
5303 | QETH_DBF_TEXT(trace, 4, "frvaddr4"); | 5328 | QETH_DBF_TEXT(trace, 4, "frvaddr4"); |
5304 | if (!card->vlangrp) | 5329 | |
5305 | return; | ||
5306 | rcu_read_lock(); | 5330 | rcu_read_lock(); |
5307 | in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]); | 5331 | in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]); |
5308 | if (!in_dev) | 5332 | if (!in_dev) |
@@ -5330,8 +5354,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid) | |||
5330 | struct qeth_ipaddr *addr; | 5354 | struct qeth_ipaddr *addr; |
5331 | 5355 | ||
5332 | QETH_DBF_TEXT(trace, 4, "frvaddr6"); | 5356 | QETH_DBF_TEXT(trace, 4, "frvaddr6"); |
5333 | if (!card->vlangrp) | 5357 | |
5334 | return; | ||
5335 | in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]); | 5358 | in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]); |
5336 | if (!in6_dev) | 5359 | if (!in6_dev) |
5337 | return; | 5360 | return; |
@@ -5350,6 +5373,15 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid) | |||
5350 | #endif /* CONFIG_QETH_IPV6 */ | 5373 | #endif /* CONFIG_QETH_IPV6 */ |
5351 | } | 5374 | } |
5352 | 5375 | ||
5376 | static void | ||
5377 | qeth_free_vlan_addresses(struct qeth_card *card, unsigned short vid) | ||
5378 | { | ||
5379 | if (card->options.layer2 || !card->vlangrp) | ||
5380 | return; | ||
5381 | qeth_free_vlan_addresses4(card, vid); | ||
5382 | qeth_free_vlan_addresses6(card, vid); | ||
5383 | } | ||
5384 | |||
5353 | static int | 5385 | static int |
5354 | qeth_layer2_send_setdelvlan_cb(struct qeth_card *card, | 5386 | qeth_layer2_send_setdelvlan_cb(struct qeth_card *card, |
5355 | struct qeth_reply *reply, | 5387 | struct qeth_reply *reply, |
@@ -5432,8 +5464,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) | |||
5432 | qeth_free_vlan_skbs(card, vid); | 5464 | qeth_free_vlan_skbs(card, vid); |
5433 | spin_lock_irqsave(&card->vlanlock, flags); | 5465 | spin_lock_irqsave(&card->vlanlock, flags); |
5434 | /* unregister IP addresses of vlan device */ | 5466 | /* unregister IP addresses of vlan device */ |
5435 | qeth_free_vlan_addresses4(card, vid); | 5467 | qeth_free_vlan_addresses(card, vid); |
5436 | qeth_free_vlan_addresses6(card, vid); | ||
5437 | if (card->vlangrp) | 5468 | if (card->vlangrp) |
5438 | card->vlangrp->vlan_devices[vid] = NULL; | 5469 | card->vlangrp->vlan_devices[vid] = NULL; |
5439 | spin_unlock_irqrestore(&card->vlanlock, flags); | 5470 | spin_unlock_irqrestore(&card->vlanlock, flags); |
@@ -5456,10 +5487,15 @@ qeth_set_multicast_list(struct net_device *dev) | |||
5456 | 5487 | ||
5457 | QETH_DBF_TEXT(trace,3,"setmulti"); | 5488 | QETH_DBF_TEXT(trace,3,"setmulti"); |
5458 | qeth_delete_mc_addresses(card); | 5489 | qeth_delete_mc_addresses(card); |
5490 | if (card->options.layer2) { | ||
5491 | qeth_layer2_add_multicast(card); | ||
5492 | goto out; | ||
5493 | } | ||
5459 | qeth_add_multicast_ipv4(card); | 5494 | qeth_add_multicast_ipv4(card); |
5460 | #ifdef CONFIG_QETH_IPV6 | 5495 | #ifdef CONFIG_QETH_IPV6 |
5461 | qeth_add_multicast_ipv6(card); | 5496 | qeth_add_multicast_ipv6(card); |
5462 | #endif | 5497 | #endif |
5498 | out: | ||
5463 | if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) | 5499 | if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) |
5464 | schedule_work(&card->kernel_thread_starter); | 5500 | schedule_work(&card->kernel_thread_starter); |
5465 | } | 5501 | } |
@@ -5669,6 +5705,24 @@ qeth_add_multicast_ipv4(struct qeth_card *card) | |||
5669 | in_dev_put(in4_dev); | 5705 | in_dev_put(in4_dev); |
5670 | } | 5706 | } |
5671 | 5707 | ||
5708 | static void | ||
5709 | qeth_layer2_add_multicast(struct qeth_card *card) | ||
5710 | { | ||
5711 | struct qeth_ipaddr *ipm; | ||
5712 | struct dev_mc_list *dm; | ||
5713 | |||
5714 | QETH_DBF_TEXT(trace,4,"L2addmc"); | ||
5715 | for (dm = card->dev->mc_list; dm; dm = dm->next) { | ||
5716 | ipm = qeth_get_addr_buffer(QETH_PROT_IPV4); | ||
5717 | if (!ipm) | ||
5718 | continue; | ||
5719 | memcpy(ipm->mac,dm->dmi_addr,MAX_ADDR_LEN); | ||
5720 | ipm->is_multicast = 1; | ||
5721 | if (!qeth_add_ip(card, ipm)) | ||
5722 | kfree(ipm); | ||
5723 | } | ||
5724 | } | ||
5725 | |||
5672 | #ifdef CONFIG_QETH_IPV6 | 5726 | #ifdef CONFIG_QETH_IPV6 |
5673 | static inline void | 5727 | static inline void |
5674 | qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev) | 5728 | qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev) |