Commit 08e3356c authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller

netiucv: allow multiple interfaces to same peer

The NETIUCV device driver allows to connect a Linux guest on z/VM to
another z/VM guest based on the z/VM communication facility IUCV.
Multiple output paths to different guests are possible, as well as
multiple input paths from different guests.
With this feature, you can configure multiple point-to-point NETIUCV
interfaces between your Linux on System z instance and another z/VM
guest.
Signed-off-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarFrank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f78ac2bb
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ebcdic.h>
#include <net/iucv/iucv.h> #include <net/iucv/iucv.h>
#include "fsm.h" #include "fsm.h"
...@@ -75,7 +76,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); ...@@ -75,7 +76,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
* Debug Facility stuff * Debug Facility stuff
*/ */
#define IUCV_DBF_SETUP_NAME "iucv_setup" #define IUCV_DBF_SETUP_NAME "iucv_setup"
#define IUCV_DBF_SETUP_LEN 32 #define IUCV_DBF_SETUP_LEN 64
#define IUCV_DBF_SETUP_PAGES 2 #define IUCV_DBF_SETUP_PAGES 2
#define IUCV_DBF_SETUP_NR_AREAS 1 #define IUCV_DBF_SETUP_NR_AREAS 1
#define IUCV_DBF_SETUP_LEVEL 3 #define IUCV_DBF_SETUP_LEVEL 3
...@@ -226,6 +227,7 @@ struct iucv_connection { ...@@ -226,6 +227,7 @@ struct iucv_connection {
struct net_device *netdev; struct net_device *netdev;
struct connection_profile prof; struct connection_profile prof;
char userid[9]; char userid[9];
char userdata[17];
}; };
/** /**
...@@ -263,7 +265,7 @@ struct ll_header { ...@@ -263,7 +265,7 @@ struct ll_header {
}; };
#define NETIUCV_HDRLEN (sizeof(struct ll_header)) #define NETIUCV_HDRLEN (sizeof(struct ll_header))
#define NETIUCV_BUFSIZE_MAX 32768 #define NETIUCV_BUFSIZE_MAX 65537
#define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX
#define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
#define NETIUCV_MTU_DEFAULT 9216 #define NETIUCV_MTU_DEFAULT 9216
...@@ -288,7 +290,12 @@ static inline int netiucv_test_and_set_busy(struct net_device *dev) ...@@ -288,7 +290,12 @@ static inline int netiucv_test_and_set_busy(struct net_device *dev)
return test_and_set_bit(0, &priv->tbusy); return test_and_set_bit(0, &priv->tbusy);
} }
static u8 iucvMagic[16] = { static u8 iucvMagic_ascii[16] = {
0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
};
static u8 iucvMagic_ebcdic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
}; };
...@@ -301,18 +308,38 @@ static u8 iucvMagic[16] = { ...@@ -301,18 +308,38 @@ static u8 iucvMagic[16] = {
* *
* @returns The printable string (static data!!) * @returns The printable string (static data!!)
*/ */
static char *netiucv_printname(char *name) static char *netiucv_printname(char *name, int len)
{ {
static char tmp[9]; static char tmp[17];
char *p = tmp; char *p = tmp;
memcpy(tmp, name, 8); memcpy(tmp, name, len);
tmp[8] = '\0'; tmp[len] = '\0';
while (*p && (!isspace(*p))) while (*p && ((p - tmp) < len) && (!isspace(*p)))
p++; p++;
*p = '\0'; *p = '\0';
return tmp; return tmp;
} }
static char *netiucv_printuser(struct iucv_connection *conn)
{
static char tmp_uid[9];
static char tmp_udat[17];
static char buf[100];
if (memcmp(conn->userdata, iucvMagic_ebcdic, 16)) {
tmp_uid[8] = '\0';
tmp_udat[16] = '\0';
memcpy(tmp_uid, conn->userid, 8);
memcpy(tmp_uid, netiucv_printname(tmp_uid, 8), 8);
memcpy(tmp_udat, conn->userdata, 16);
EBCASC(tmp_udat, 16);
memcpy(tmp_udat, netiucv_printname(tmp_udat, 16), 16);
sprintf(buf, "%s.%s", tmp_uid, tmp_udat);
return buf;
} else
return netiucv_printname(conn->userid, 8);
}
/** /**
* States of the interface statemachine. * States of the interface statemachine.
*/ */
...@@ -563,15 +590,18 @@ static int netiucv_callback_connreq(struct iucv_path *path, ...@@ -563,15 +590,18 @@ static int netiucv_callback_connreq(struct iucv_path *path,
{ {
struct iucv_connection *conn = path->private; struct iucv_connection *conn = path->private;
struct iucv_event ev; struct iucv_event ev;
static char tmp_user[9];
static char tmp_udat[17];
int rc; int rc;
if (memcmp(iucvMagic, ipuser, 16))
/* ipuser must match iucvMagic. */
return -EINVAL;
rc = -EINVAL; rc = -EINVAL;
memcpy(tmp_user, netiucv_printname(ipvmid, 8), 8);
memcpy(tmp_udat, ipuser, 16);
EBCASC(tmp_udat, 16);
read_lock_bh(&iucv_connection_rwlock); read_lock_bh(&iucv_connection_rwlock);
list_for_each_entry(conn, &iucv_connection_list, list) { list_for_each_entry(conn, &iucv_connection_list, list) {
if (strncmp(ipvmid, conn->userid, 8)) if (strncmp(ipvmid, conn->userid, 8) ||
strncmp(ipuser, conn->userdata, 16))
continue; continue;
/* Found a matching connection for this path. */ /* Found a matching connection for this path. */
conn->path = path; conn->path = path;
...@@ -580,6 +610,8 @@ static int netiucv_callback_connreq(struct iucv_path *path, ...@@ -580,6 +610,8 @@ static int netiucv_callback_connreq(struct iucv_path *path,
fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
rc = 0; rc = 0;
} }
IUCV_DBF_TEXT_(setup, 2, "Connection requested for %s.%s\n",
tmp_user, netiucv_printname(tmp_udat, 16));
read_unlock_bh(&iucv_connection_rwlock); read_unlock_bh(&iucv_connection_rwlock);
return rc; return rc;
} }
...@@ -816,7 +848,7 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) ...@@ -816,7 +848,7 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
conn->path = path; conn->path = path;
path->msglim = NETIUCV_QUEUELEN_DEFAULT; path->msglim = NETIUCV_QUEUELEN_DEFAULT;
path->flags = 0; path->flags = 0;
rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); rc = iucv_path_accept(path, &netiucv_handler, conn->userdata , conn);
if (rc) { if (rc) {
IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc); IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc);
return; return;
...@@ -854,7 +886,7 @@ static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) ...@@ -854,7 +886,7 @@ static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
IUCV_DBF_TEXT(trace, 3, __func__); IUCV_DBF_TEXT(trace, 3, __func__);
fsm_deltimer(&conn->timer); fsm_deltimer(&conn->timer);
iucv_path_sever(conn->path, NULL); iucv_path_sever(conn->path, conn->userdata);
fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_newstate(fi, CONN_STATE_STARTWAIT);
} }
...@@ -867,9 +899,9 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) ...@@ -867,9 +899,9 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg)
IUCV_DBF_TEXT(trace, 3, __func__); IUCV_DBF_TEXT(trace, 3, __func__);
fsm_deltimer(&conn->timer); fsm_deltimer(&conn->timer);
iucv_path_sever(conn->path, NULL); iucv_path_sever(conn->path, conn->userdata);
dev_info(privptr->dev, "The peer interface of the IUCV device" dev_info(privptr->dev, "The peer z/VM guest %s has closed the "
" has closed the connection\n"); "connection\n", netiucv_printuser(conn));
IUCV_DBF_TEXT(data, 2, IUCV_DBF_TEXT(data, 2,
"conn_action_connsever: Remote dropped connection\n"); "conn_action_connsever: Remote dropped connection\n");
fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_newstate(fi, CONN_STATE_STARTWAIT);
...@@ -886,8 +918,6 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -886,8 +918,6 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg)
IUCV_DBF_TEXT(trace, 3, __func__); IUCV_DBF_TEXT(trace, 3, __func__);
fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_newstate(fi, CONN_STATE_STARTWAIT);
IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n",
netdev->name, conn->userid);
/* /*
* We must set the state before calling iucv_connect because the * We must set the state before calling iucv_connect because the
...@@ -897,8 +927,11 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -897,8 +927,11 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg)
fsm_newstate(fi, CONN_STATE_SETUPWAIT); fsm_newstate(fi, CONN_STATE_SETUPWAIT);
conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
IUCV_DBF_TEXT_(setup, 2, "%s: connecting to %s ...\n",
netdev->name, netiucv_printuser(conn));
rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
NULL, iucvMagic, conn); NULL, conn->userdata, conn);
switch (rc) { switch (rc) {
case 0: case 0:
netdev->tx_queue_len = conn->path->msglim; netdev->tx_queue_len = conn->path->msglim;
...@@ -908,13 +941,13 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -908,13 +941,13 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg)
case 11: case 11:
dev_warn(privptr->dev, dev_warn(privptr->dev,
"The IUCV device failed to connect to z/VM guest %s\n", "The IUCV device failed to connect to z/VM guest %s\n",
netiucv_printname(conn->userid)); netiucv_printname(conn->userid, 8));
fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_newstate(fi, CONN_STATE_STARTWAIT);
break; break;
case 12: case 12:
dev_warn(privptr->dev, dev_warn(privptr->dev,
"The IUCV device failed to connect to the peer on z/VM" "The IUCV device failed to connect to the peer on z/VM"
" guest %s\n", netiucv_printname(conn->userid)); " guest %s\n", netiucv_printname(conn->userid, 8));
fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_newstate(fi, CONN_STATE_STARTWAIT);
break; break;
case 13: case 13:
...@@ -927,7 +960,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -927,7 +960,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg)
dev_err(privptr->dev, dev_err(privptr->dev,
"z/VM guest %s has too many IUCV connections" "z/VM guest %s has too many IUCV connections"
" to connect with the IUCV device\n", " to connect with the IUCV device\n",
netiucv_printname(conn->userid)); netiucv_printname(conn->userid, 8));
fsm_newstate(fi, CONN_STATE_CONNERR); fsm_newstate(fi, CONN_STATE_CONNERR);
break; break;
case 15: case 15:
...@@ -972,7 +1005,7 @@ static void conn_action_stop(fsm_instance *fi, int event, void *arg) ...@@ -972,7 +1005,7 @@ static void conn_action_stop(fsm_instance *fi, int event, void *arg)
netiucv_purge_skb_queue(&conn->collect_queue); netiucv_purge_skb_queue(&conn->collect_queue);
if (conn->path) { if (conn->path) {
IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
iucv_path_sever(conn->path, iucvMagic); iucv_path_sever(conn->path, conn->userdata);
kfree(conn->path); kfree(conn->path);
conn->path = NULL; conn->path = NULL;
} }
...@@ -1090,7 +1123,8 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) ...@@ -1090,7 +1123,8 @@ dev_action_connup(fsm_instance *fi, int event, void *arg)
fsm_newstate(fi, DEV_STATE_RUNNING); fsm_newstate(fi, DEV_STATE_RUNNING);
dev_info(privptr->dev, dev_info(privptr->dev,
"The IUCV device has been connected" "The IUCV device has been connected"
" successfully to %s\n", privptr->conn->userid); " successfully to %s\n",
netiucv_printuser(privptr->conn));
IUCV_DBF_TEXT(setup, 3, IUCV_DBF_TEXT(setup, 3,
"connection is up and running\n"); "connection is up and running\n");
break; break;
...@@ -1452,45 +1486,72 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr, ...@@ -1452,45 +1486,72 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr,
struct netiucv_priv *priv = dev_get_drvdata(dev); struct netiucv_priv *priv = dev_get_drvdata(dev);
IUCV_DBF_TEXT(trace, 5, __func__); IUCV_DBF_TEXT(trace, 5, __func__);
return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); return sprintf(buf, "%s\n", netiucv_printuser(priv->conn));
} }
static ssize_t user_write(struct device *dev, struct device_attribute *attr, static int netiucv_check_user(const char *buf, size_t count, char *username,
const char *buf, size_t count) char *userdata)
{ {
struct netiucv_priv *priv = dev_get_drvdata(dev); const char *p;
struct net_device *ndev = priv->conn->netdev;
char *p;
char *tmp;
char username[9];
int i; int i;
struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __func__); p = strchr(buf, '.');
if (count > 9) { if ((p && ((count > 26) ||
IUCV_DBF_TEXT_(setup, 2, ((p - buf) > 8) ||
"%d is length of username\n", (int) count); (buf + count - p > 18))) ||
(!p && (count > 9))) {
IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n");
return -EINVAL; return -EINVAL;
} }
tmp = strsep((char **) &buf, "\n"); for (i = 0, p = buf; i < 8 && *p && *p != '.'; i++, p++) {
for (i = 0, p = tmp; i < 8 && *p; i++, p++) { if (isalnum(*p) || *p == '$') {
if (isalnum(*p) || (*p == '$')) { username[i] = toupper(*p);
username[i]= toupper(*p);
continue; continue;
} }
if (*p == '\n') { if (*p == '\n')
/* trailing lf, grr */ /* trailing lf, grr */
break; break;
}
IUCV_DBF_TEXT_(setup, 2, IUCV_DBF_TEXT_(setup, 2,
"username: invalid character %c\n", *p); "conn_write: invalid character %02x\n", *p);
return -EINVAL; return -EINVAL;
} }
while (i < 8) while (i < 8)
username[i++] = ' '; username[i++] = ' ';
username[8] = '\0'; username[8] = '\0';
if (*p == '.') {
p++;
for (i = 0; i < 16 && *p; i++, p++) {
if (*p == '\n')
break;
userdata[i] = toupper(*p);
}
while (i > 0 && i < 16)
userdata[i++] = ' ';
} else
memcpy(userdata, iucvMagic_ascii, 16);
userdata[16] = '\0';
ASCEBC(userdata, 16);
return 0;
}
static ssize_t user_write(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct netiucv_priv *priv = dev_get_drvdata(dev);
struct net_device *ndev = priv->conn->netdev;
char username[9];
char userdata[17];
int rc;
struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __func__);
rc = netiucv_check_user(buf, count, username, userdata);
if (rc)
return rc;
if (memcmp(username, priv->conn->userid, 9) && if (memcmp(username, priv->conn->userid, 9) &&
(ndev->flags & (IFF_UP | IFF_RUNNING))) { (ndev->flags & (IFF_UP | IFF_RUNNING))) {
/* username changed while the interface is active. */ /* username changed while the interface is active. */
...@@ -1499,15 +1560,17 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, ...@@ -1499,15 +1560,17 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr,
} }
read_lock_bh(&iucv_connection_rwlock); read_lock_bh(&iucv_connection_rwlock);
list_for_each_entry(cp, &iucv_connection_list, list) { list_for_each_entry(cp, &iucv_connection_list, list) {
if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { if (!strncmp(username, cp->userid, 9) &&
!strncmp(userdata, cp->userdata, 17) && cp->netdev != ndev) {
read_unlock_bh(&iucv_connection_rwlock); read_unlock_bh(&iucv_connection_rwlock);
IUCV_DBF_TEXT_(setup, 2, "user_write: Connection " IUCV_DBF_TEXT_(setup, 2, "user_write: Connection to %s "
"to %s already exists\n", username); "already exists\n", netiucv_printuser(cp));
return -EEXIST; return -EEXIST;
} }
} }
read_unlock_bh(&iucv_connection_rwlock); read_unlock_bh(&iucv_connection_rwlock);
memcpy(priv->conn->userid, username, 9); memcpy(priv->conn->userid, username, 9);
memcpy(priv->conn->userdata, userdata, 17);
return count; return count;
} }
...@@ -1537,7 +1600,8 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, ...@@ -1537,7 +1600,8 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
bs1 = simple_strtoul(buf, &e, 0); bs1 = simple_strtoul(buf, &e, 0);
if (e && (!isspace(*e))) { if (e && (!isspace(*e))) {
IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e); IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %02x\n",
*e);
return -EINVAL; return -EINVAL;
} }
if (bs1 > NETIUCV_BUFSIZE_MAX) { if (bs1 > NETIUCV_BUFSIZE_MAX) {
...@@ -1864,7 +1928,8 @@ static void netiucv_unregister_device(struct device *dev) ...@@ -1864,7 +1928,8 @@ static void netiucv_unregister_device(struct device *dev)
* Add it to the list of netiucv connections; * Add it to the list of netiucv connections;
*/ */
static struct iucv_connection *netiucv_new_connection(struct net_device *dev, static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
char *username) char *username,
char *userdata)
{ {
struct iucv_connection *conn; struct iucv_connection *conn;
...@@ -1893,6 +1958,8 @@ static struct iucv_connection *netiucv_new_connection(struct net_device *dev, ...@@ -1893,6 +1958,8 @@ static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
fsm_settimer(conn->fsm, &conn->timer); fsm_settimer(conn->fsm, &conn->timer);
fsm_newstate(conn->fsm, CONN_STATE_INVALID); fsm_newstate(conn->fsm, CONN_STATE_INVALID);
if (userdata)
memcpy(conn->userdata, userdata, 17);
if (username) { if (username) {
memcpy(conn->userid, username, 9); memcpy(conn->userid, username, 9);
fsm_newstate(conn->fsm, CONN_STATE_STOPPED); fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
...@@ -1919,6 +1986,7 @@ static struct iucv_connection *netiucv_new_connection(struct net_device *dev, ...@@ -1919,6 +1986,7 @@ static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
*/ */
static void netiucv_remove_connection(struct iucv_connection *conn) static void netiucv_remove_connection(struct iucv_connection *conn)
{ {
IUCV_DBF_TEXT(trace, 3, __func__); IUCV_DBF_TEXT(trace, 3, __func__);
write_lock_bh(&iucv_connection_rwlock); write_lock_bh(&iucv_connection_rwlock);
list_del_init(&conn->list); list_del_init(&conn->list);
...@@ -1926,7 +1994,7 @@ static void netiucv_remove_connection(struct iucv_connection *conn) ...@@ -1926,7 +1994,7 @@ static void netiucv_remove_connection(struct iucv_connection *conn)
fsm_deltimer(&conn->timer); fsm_deltimer(&conn->timer);
netiucv_purge_skb_queue(&conn->collect_queue); netiucv_purge_skb_queue(&conn->collect_queue);
if (conn->path) { if (conn->path) {
iucv_path_sever(conn->path, iucvMagic); iucv_path_sever(conn->path, conn->userdata);
kfree(conn->path); kfree(conn->path);
conn->path = NULL; conn->path = NULL;
} }
...@@ -1985,7 +2053,7 @@ static void netiucv_setup_netdevice(struct net_device *dev) ...@@ -1985,7 +2053,7 @@ static void netiucv_setup_netdevice(struct net_device *dev)
/** /**
* Allocate and initialize everything of a net device. * Allocate and initialize everything of a net device.
*/ */
static struct net_device *netiucv_init_netdevice(char *username) static struct net_device *netiucv_init_netdevice(char *username, char *userdata)
{ {
struct netiucv_priv *privptr; struct netiucv_priv *privptr;
struct net_device *dev; struct net_device *dev;
...@@ -2004,7 +2072,7 @@ static struct net_device *netiucv_init_netdevice(char *username) ...@@ -2004,7 +2072,7 @@ static struct net_device *netiucv_init_netdevice(char *username)
if (!privptr->fsm) if (!privptr->fsm)
goto out_netdev; goto out_netdev;
privptr->conn = netiucv_new_connection(dev, username); privptr->conn = netiucv_new_connection(dev, username, userdata);
if (!privptr->conn) { if (!privptr->conn) {
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
goto out_fsm; goto out_fsm;
...@@ -2022,47 +2090,31 @@ static struct net_device *netiucv_init_netdevice(char *username) ...@@ -2022,47 +2090,31 @@ static struct net_device *netiucv_init_netdevice(char *username)
static ssize_t conn_write(struct device_driver *drv, static ssize_t conn_write(struct device_driver *drv,
const char *buf, size_t count) const char *buf, size_t count)
{ {
const char *p;
char username[9]; char username[9];
int i, rc; char userdata[17];
int rc;
struct net_device *dev; struct net_device *dev;
struct netiucv_priv *priv; struct netiucv_priv *priv;
struct iucv_connection *cp; struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __func__); IUCV_DBF_TEXT(trace, 3, __func__);
if (count>9) { rc = netiucv_check_user(buf, count, username, userdata);
IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n"); if (rc)
return -EINVAL; return rc;
}
for (i = 0, p = buf; i < 8 && *p; i++, p++) {
if (isalnum(*p) || *p == '$') {
username[i] = toupper(*p);
continue;
}
if (*p == '\n')
/* trailing lf, grr */
break;
IUCV_DBF_TEXT_(setup, 2,
"conn_write: invalid character %c\n", *p);
return -EINVAL;
}
while (i < 8)
username[i++] = ' ';
username[8] = '\0';
read_lock_bh(&iucv_connection_rwlock); read_lock_bh(&iucv_connection_rwlock);
list_for_each_entry(cp, &iucv_connection_list, list) { list_for_each_entry(cp, &iucv_connection_list, list) {
if (!strncmp(username, cp->userid, 9)) { if (!strncmp(username, cp->userid, 9) &&
!strncmp(userdata, cp->userdata, 17)) {
read_unlock_bh(&iucv_connection_rwlock); read_unlock_bh(&iucv_connection_rwlock);
IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection " IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection to %s "
"to %s already exists\n", username); "already exists\n", netiucv_printuser(cp));
return -EEXIST; return -EEXIST;
} }
} }
read_unlock_bh(&iucv_connection_rwlock); read_unlock_bh(&iucv_connection_rwlock);
dev = netiucv_init_netdevice(username); dev = netiucv_init_netdevice(username, userdata);
if (!dev) { if (!dev) {
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
return -ENODEV; return -ENODEV;
...@@ -2083,8 +2135,9 @@ static ssize_t conn_write(struct device_driver *drv, ...@@ -2083,8 +2135,9 @@ static ssize_t conn_write(struct device_driver *drv,
if (rc) if (rc)
goto out_unreg; goto out_unreg;
dev_info(priv->dev, "The IUCV interface to %s has been" dev_info(priv->dev, "The IUCV interface to %s has been established "
" established successfully\n", netiucv_printname(username)); "successfully\n",
netiucv_printuser(priv->conn));
return count; return count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment