]> Pileus Git - ~andy/linux/blobdiff - drivers/s390/net/qeth_l3_sys.c
qeth: add support for af_iucv HiperSockets transport
[~andy/linux] / drivers / s390 / net / qeth_l3_sys.c
index cd99210296e2ae5d792d3c2b59a9f765827832b4..0ea2fbfe0e993a42932221d52f0040aaf52b96db 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #include <linux/slab.h>
-
+#include <asm/ebcdic.h>
 #include "qeth_l3.h"
 
 #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
@@ -308,6 +308,8 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
 
        if (card->info.type != QETH_CARD_TYPE_IQD)
                return -EPERM;
+       if (card->options.cq == QETH_CQ_ENABLED)
+               return -EPERM;
 
        mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
@@ -347,6 +349,111 @@ out:
 static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
                qeth_l3_dev_sniffer_store);
 
+
+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.type != QETH_CARD_TYPE_IQD)
+               return -EPERM;
+
+       if (card->state == CARD_STATE_DOWN)
+               return -EPERM;
+
+       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_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->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;
+
+       tmp = strsep((char **)&buf, "\n");
+       if (strlen(tmp) > 8)
+               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);
+       }
+
+       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 (qeth_configure_cq(card, QETH_CQ_ENABLED))
+               return -EPERM;
+
+       for (i = 0; i < 8; i++)
+               card->options.hsuid[i] = ' ';
+       card->options.hsuid[8] = '\0';
+       strncpy(card->options.hsuid, tmp, strlen(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(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,
@@ -354,6 +461,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
        &dev_attr_broadcast_mode.attr,
        &dev_attr_canonical_macaddr.attr,
        &dev_attr_sniffer.attr,
+       &dev_attr_hsuid.attr,
        NULL,
 };