diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_sys.c')
| -rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 387 |
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, |
