aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/net/qeth_l3_sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/net/qeth_l3_sys.c')
-rw-r--r--drivers/s390/net/qeth_l3_sys.c387
1 files changed, 209 insertions, 178 deletions
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index ac1993708ae..adef5f5de11 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -1,6 +1,4 @@
/*
- * drivers/s390/net/qeth_l3_sys.c
- *
* Copyright IBM Corp. 2007
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
* Frank Pavlic <fpavlic@de.ibm.com>,
@@ -8,21 +6,13 @@
* Frank Blaschka <frank.blaschka@de.ibm.com>
*/
+#include <linux/slab.h>
+#include <asm/ebcdic.h>
#include "qeth_l3.h"
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
-static const char *qeth_l3_get_checksum_str(struct qeth_card *card)
-{
- if (card->options.checksum_type == SW_CHECKSUMMING)
- return "sw";
- else if (card->options.checksum_type == HW_CHECKSUMMING)
- return "hw";
- else
- return "no";
-}
-
static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
struct qeth_routing_info *route, char *buf)
{
@@ -68,10 +58,10 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
{
enum qeth_routing_types old_route_type = route->type;
char *tmp;
- int rc;
+ int rc = 0;
tmp = strsep((char **) &buf, "\n");
-
+ mutex_lock(&card->conf_mutex);
if (!strcmp(tmp, "no_router")) {
route->type = NO_ROUTER;
} else if (!strcmp(tmp, "primary_connector")) {
@@ -85,7 +75,8 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
} else if (!strcmp(tmp, "multicast_router")) {
route->type = MULTICAST_ROUTER;
} else {
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
if (((card->state == CARD_STATE_SOFTSETUP) ||
(card->state == CARD_STATE_UP)) &&
@@ -95,7 +86,11 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
else if (prot == QETH_PROT_IPV6)
rc = qeth_l3_setrouting_v6(card);
}
- return count;
+out:
+ if (rc)
+ route->type = old_route_type;
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_route4_store(struct device *dev,
@@ -121,9 +116,6 @@ static ssize_t qeth_l3_dev_route6_show(struct device *dev,
if (!card)
return -EINVAL;
- if (!qeth_is_supported(card, IPA_IPV6))
- return sprintf(buf, "%s\n", "n/a");
-
return qeth_l3_dev_route_show(card, &card->options.route6, buf);
}
@@ -135,10 +127,6 @@ static ssize_t qeth_l3_dev_route6_store(struct device *dev,
if (!card)
return -EINVAL;
- if (!qeth_is_supported(card, IPA_IPV6)) {
- return -ENOTSUPP;
- }
-
return qeth_l3_dev_route_store(card, &card->options.route6,
QETH_PROT_IPV6, buf, count);
}
@@ -162,176 +150,204 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
char *tmp;
- int i;
+ int i, rc = 0;
if (!card)
return -EINVAL;
+ mutex_lock(&card->conf_mutex);
if ((card->state != CARD_STATE_DOWN) &&
- (card->state != CARD_STATE_RECOVER))
- return -EPERM;
+ (card->state != CARD_STATE_RECOVER)) {
+ rc = -EPERM;
+ goto out;
+ }
i = simple_strtoul(buf, &tmp, 16);
if ((i == 0) || (i == 1))
card->options.fake_broadcast = i;
- else {
- return -EINVAL;
- }
- return count;
+ else
+ rc = -EINVAL;
+out:
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show,
qeth_l3_dev_fake_broadcast_store);
-static ssize_t qeth_l3_dev_broadcast_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
if (!card)
return -EINVAL;
- if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
- (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
- return sprintf(buf, "n/a\n");
-
- return sprintf(buf, "%s\n", (card->options.broadcast_mode ==
- QETH_TR_BROADCAST_ALLRINGS)?
- "all rings":"local");
+ return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
}
-static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev,
+static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
- char *tmp;
+ int rc = 0;
+ unsigned long i;
if (!card)
return -EINVAL;
- if ((card->state != CARD_STATE_DOWN) &&
- (card->state != CARD_STATE_RECOVER))
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ return -EPERM;
+ if (card->options.cq == QETH_CQ_ENABLED)
return -EPERM;
- if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
- (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
- return -EINVAL;
+ mutex_lock(&card->conf_mutex);
+ if ((card->state != CARD_STATE_DOWN) &&
+ (card->state != CARD_STATE_RECOVER)) {
+ rc = -EPERM;
+ goto out;
}
- tmp = strsep((char **) &buf, "\n");
-
- if (!strcmp(tmp, "local")) {
- card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL;
- return count;
- } else if (!strcmp(tmp, "all_rings")) {
- card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
- return count;
- } else {
- return -EINVAL;
+ rc = kstrtoul(buf, 16, &i);
+ if (rc) {
+ rc = -EINVAL;
+ goto out;
}
- return count;
+ switch (i) {
+ case 0:
+ card->options.sniffer = i;
+ break;
+ case 1:
+ qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+ if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
+ card->options.sniffer = i;
+ if (card->qdio.init_pool.buf_count !=
+ QETH_IN_BUF_COUNT_MAX)
+ qeth_realloc_buffer_pool(card,
+ QETH_IN_BUF_COUNT_MAX);
+ } else
+ rc = -EPERM;
+ break;
+ default:
+ rc = -EINVAL;
+ }
+out:
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
-static DEVICE_ATTR(broadcast_mode, 0644, qeth_l3_dev_broadcast_mode_show,
- qeth_l3_dev_broadcast_mode_store);
+static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
+ qeth_l3_dev_sniffer_store);
-static ssize_t qeth_l3_dev_canonical_macaddr_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+
+static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev_get_drvdata(dev);
+ char tmp_hsuid[9];
if (!card)
return -EINVAL;
- if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
- (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
- return sprintf(buf, "n/a\n");
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ return -EPERM;
+
+ if (card->state == CARD_STATE_DOWN)
+ return -EPERM;
- return sprintf(buf, "%i\n", (card->options.macaddr_mode ==
- QETH_TR_MACADDR_CANONICAL)? 1:0);
+ memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
+ EBCASC(tmp_hsuid, 8);
+ return sprintf(buf, "%s\n", tmp_hsuid);
}
-static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
+static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
+ struct qeth_ipaddr *addr;
char *tmp;
int i;
if (!card)
return -EINVAL;
- if ((card->state != CARD_STATE_DOWN) &&
- (card->state != CARD_STATE_RECOVER))
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ return -EPERM;
+ if (card->state != CARD_STATE_DOWN &&
+ card->state != CARD_STATE_RECOVER)
+ return -EPERM;
+ if (card->options.sniffer)
+ return -EPERM;
+ if (card->options.cq == QETH_CQ_NOTAVAILABLE)
return -EPERM;
- if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
- (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
+ tmp = strsep((char **)&buf, "\n");
+ if (strlen(tmp) > 8)
return -EINVAL;
- }
- i = simple_strtoul(buf, &tmp, 16);
- if ((i == 0) || (i == 1))
- card->options.macaddr_mode = i?
- QETH_TR_MACADDR_CANONICAL :
- QETH_TR_MACADDR_NONCANONICAL;
- else {
- return -EINVAL;
+ if (card->options.hsuid[0]) {
+ /* delete old ip address */
+ addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
+ if (addr != NULL) {
+ addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
+ addr->u.a6.addr.s6_addr32[1] = 0x00000000;
+ for (i = 8; i < 16; i++)
+ addr->u.a6.addr.s6_addr[i] =
+ card->options.hsuid[i - 8];
+ addr->u.a6.pfxlen = 0;
+ addr->type = QETH_IP_TYPE_NORMAL;
+ } else
+ return -ENOMEM;
+ if (!qeth_l3_delete_ip(card, addr))
+ kfree(addr);
+ qeth_l3_set_ip_addr_list(card);
}
- return count;
-}
-
-static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show,
- qeth_l3_dev_canonical_macaddr_store);
-
-static ssize_t qeth_l3_dev_checksum_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- return sprintf(buf, "%s checksumming\n",
- qeth_l3_get_checksum_str(card));
-}
-
-static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct qeth_card *card = dev_get_drvdata(dev);
- char *tmp;
- if (!card)
- return -EINVAL;
+ if (strlen(tmp) == 0) {
+ /* delete ip address only */
+ card->options.hsuid[0] = '\0';
+ if (card->dev)
+ memcpy(card->dev->perm_addr, card->options.hsuid, 9);
+ qeth_configure_cq(card, QETH_CQ_DISABLED);
+ return count;
+ }
- if ((card->state != CARD_STATE_DOWN) &&
- (card->state != CARD_STATE_RECOVER))
+ if (qeth_configure_cq(card, QETH_CQ_ENABLED))
return -EPERM;
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "sw_checksumming"))
- card->options.checksum_type = SW_CHECKSUMMING;
- else if (!strcmp(tmp, "hw_checksumming"))
- card->options.checksum_type = HW_CHECKSUMMING;
- else if (!strcmp(tmp, "no_checksumming"))
- card->options.checksum_type = NO_CHECKSUMMING;
- else {
- return -EINVAL;
- }
+ snprintf(card->options.hsuid, sizeof(card->options.hsuid),
+ "%-8s", tmp);
+ ASCEBC(card->options.hsuid, 8);
+ if (card->dev)
+ memcpy(card->dev->perm_addr, card->options.hsuid, 9);
+
+ addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
+ if (addr != NULL) {
+ addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
+ addr->u.a6.addr.s6_addr32[1] = 0x00000000;
+ for (i = 8; i < 16; i++)
+ addr->u.a6.addr.s6_addr[i] = card->options.hsuid[i - 8];
+ addr->u.a6.pfxlen = 0;
+ addr->type = QETH_IP_TYPE_NORMAL;
+ } else
+ return -ENOMEM;
+ if (!qeth_l3_add_ip(card, addr))
+ kfree(addr);
+ qeth_l3_set_ip_addr_list(card);
+
return count;
}
-static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
- qeth_l3_dev_checksum_store);
+static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
+ qeth_l3_dev_hsuid_store);
+
static struct attribute *qeth_l3_device_attrs[] = {
&dev_attr_route4.attr,
&dev_attr_route6.attr,
&dev_attr_fake_broadcast.attr,
- &dev_attr_broadcast_mode.attr,
- &dev_attr_canonical_macaddr.attr,
- &dev_attr_checksumming.attr,
+ &dev_attr_sniffer.attr,
+ &dev_attr_hsuid.attr,
NULL,
};
@@ -354,26 +370,45 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
+ struct qeth_ipaddr *tmpipa, *t;
char *tmp;
+ int rc = 0;
if (!card)
return -EINVAL;
+ mutex_lock(&card->conf_mutex);
if ((card->state != CARD_STATE_DOWN) &&
- (card->state != CARD_STATE_RECOVER))
- return -EPERM;
+ (card->state != CARD_STATE_RECOVER)) {
+ rc = -EPERM;
+ goto out;
+ }
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")) {
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
} else if (!strcmp(tmp, "1")) {
card->ipato.enabled = 1;
+ list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
+ if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
+ qeth_l3_is_addr_covered_by_ipato(card, tmpipa))
+ tmpipa->set_flags |=
+ QETH_IPA_SETIP_TAKEOVER_FLAG;
+ }
+
} else if (!strcmp(tmp, "0")) {
card->ipato.enabled = 0;
- } else {
- return -EINVAL;
- }
- return count;
+ list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
+ if (tmpipa->set_flags &
+ QETH_IPA_SETIP_TAKEOVER_FLAG)
+ tmpipa->set_flags &=
+ ~QETH_IPA_SETIP_TAKEOVER_FLAG;
+ }
+ } else
+ rc = -EINVAL;
+out:
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
@@ -397,10 +432,12 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
char *tmp;
+ int rc = 0;
if (!card)
return -EINVAL;
+ mutex_lock(&card->conf_mutex);
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")) {
card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
@@ -408,10 +445,10 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
card->ipato.invert4 = 1;
} else if (!strcmp(tmp, "0")) {
card->ipato.invert4 = 0;
- } else {
- return -EINVAL;
- }
- return count;
+ } else
+ rc = -EINVAL;
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
@@ -493,27 +530,28 @@ static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
struct qeth_ipato_entry *ipatoe;
u8 addr[16];
int mask_bits;
- int rc;
+ int rc = 0;
+ mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
if (rc)
- return rc;
+ goto out;
ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
if (!ipatoe) {
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out;
}
ipatoe->proto = proto;
memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
ipatoe->mask_bits = mask_bits;
rc = qeth_l3_add_ipato_entry(card, ipatoe);
- if (rc) {
+ if (rc)
kfree(ipatoe);
- return rc;
- }
-
- return count;
+out:
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
@@ -536,15 +574,14 @@ static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
{
u8 addr[16];
int mask_bits;
- int rc;
+ int rc = 0;
+ mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
- if (rc)
- return rc;
-
- qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
-
- return count;
+ if (!rc)
+ qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
@@ -577,10 +614,12 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
char *tmp;
+ int rc = 0;
if (!card)
return -EINVAL;
+ mutex_lock(&card->conf_mutex);
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")) {
card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
@@ -588,10 +627,10 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
card->ipato.invert6 = 1;
} else if (!strcmp(tmp, "0")) {
card->ipato.invert6 = 0;
- } else {
- return -EINVAL;
- }
- return count;
+ } else
+ rc = -EINVAL;
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
@@ -713,15 +752,12 @@ static ssize_t qeth_l3_dev_vipa_add_store(const char *buf, size_t count,
u8 addr[16] = {0, };
int rc;
+ mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_vipae(buf, proto, addr);
- if (rc)
- return rc;
-
- rc = qeth_l3_add_vipa(card, proto, addr);
- if (rc)
- return rc;
-
- return count;
+ if (!rc)
+ rc = qeth_l3_add_vipa(card, proto, addr);
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
@@ -745,13 +781,12 @@ static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
u8 addr[16];
int rc;
+ mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_vipae(buf, proto, addr);
- if (rc)
- return rc;
-
- qeth_l3_del_vipa(card, proto, addr);
-
- return count;
+ if (!rc)
+ qeth_l3_del_vipa(card, proto, addr);
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
@@ -879,15 +914,12 @@ static ssize_t qeth_l3_dev_rxip_add_store(const char *buf, size_t count,
u8 addr[16] = {0, };
int rc;
+ mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_rxipe(buf, proto, addr);
- if (rc)
- return rc;
-
- rc = qeth_l3_add_rxip(card, proto, addr);
- if (rc)
- return rc;
-
- return count;
+ if (!rc)
+ rc = qeth_l3_add_rxip(card, proto, addr);
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
@@ -911,13 +943,12 @@ static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
u8 addr[16];
int rc;
+ mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_rxipe(buf, proto, addr);
- if (rc)
- return rc;
-
- qeth_l3_del_rxip(card, proto, addr);
-
- return count;
+ if (!rc)
+ qeth_l3_del_rxip(card, proto, addr);
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
}
static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,