diff options
author | Ursula Braun <ursula.braun@de.ibm.com> | 2011-12-19 17:56:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-20 14:05:04 -0500 |
commit | 08e3356cc2c0ce8f3359b3d2636c897ac71240ce (patch) | |
tree | 086303b5725541ae5d60a492a2248eca0be5b935 /drivers/s390/net/netiucv.c | |
parent | f78ac2bbb1580c2b62ae20d47aaa2ef255f54d38 (diff) |
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: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/netiucv.c')
-rw-r--r-- | drivers/s390/net/netiucv.c | 217 |
1 files changed, 135 insertions, 82 deletions
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index b6a6356d09b3..8160591913f9 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -63,6 +63,7 @@ | |||
63 | 63 | ||
64 | #include <asm/io.h> | 64 | #include <asm/io.h> |
65 | #include <asm/uaccess.h> | 65 | #include <asm/uaccess.h> |
66 | #include <asm/ebcdic.h> | ||
66 | 67 | ||
67 | #include <net/iucv/iucv.h> | 68 | #include <net/iucv/iucv.h> |
68 | #include "fsm.h" | 69 | #include "fsm.h" |
@@ -75,7 +76,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); | |||
75 | * Debug Facility stuff | 76 | * Debug Facility stuff |
76 | */ | 77 | */ |
77 | #define IUCV_DBF_SETUP_NAME "iucv_setup" | 78 | #define IUCV_DBF_SETUP_NAME "iucv_setup" |
78 | #define IUCV_DBF_SETUP_LEN 32 | 79 | #define IUCV_DBF_SETUP_LEN 64 |
79 | #define IUCV_DBF_SETUP_PAGES 2 | 80 | #define IUCV_DBF_SETUP_PAGES 2 |
80 | #define IUCV_DBF_SETUP_NR_AREAS 1 | 81 | #define IUCV_DBF_SETUP_NR_AREAS 1 |
81 | #define IUCV_DBF_SETUP_LEVEL 3 | 82 | #define IUCV_DBF_SETUP_LEVEL 3 |
@@ -226,6 +227,7 @@ struct iucv_connection { | |||
226 | struct net_device *netdev; | 227 | struct net_device *netdev; |
227 | struct connection_profile prof; | 228 | struct connection_profile prof; |
228 | char userid[9]; | 229 | char userid[9]; |
230 | char userdata[17]; | ||
229 | }; | 231 | }; |
230 | 232 | ||
231 | /** | 233 | /** |
@@ -263,7 +265,7 @@ struct ll_header { | |||
263 | }; | 265 | }; |
264 | 266 | ||
265 | #define NETIUCV_HDRLEN (sizeof(struct ll_header)) | 267 | #define NETIUCV_HDRLEN (sizeof(struct ll_header)) |
266 | #define NETIUCV_BUFSIZE_MAX 32768 | 268 | #define NETIUCV_BUFSIZE_MAX 65537 |
267 | #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX | 269 | #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX |
268 | #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) | 270 | #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) |
269 | #define NETIUCV_MTU_DEFAULT 9216 | 271 | #define NETIUCV_MTU_DEFAULT 9216 |
@@ -288,7 +290,12 @@ static inline int netiucv_test_and_set_busy(struct net_device *dev) | |||
288 | return test_and_set_bit(0, &priv->tbusy); | 290 | return test_and_set_bit(0, &priv->tbusy); |
289 | } | 291 | } |
290 | 292 | ||
291 | static u8 iucvMagic[16] = { | 293 | static u8 iucvMagic_ascii[16] = { |
294 | 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
295 | 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 | ||
296 | }; | ||
297 | |||
298 | static u8 iucvMagic_ebcdic[16] = { | ||
292 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | 299 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, |
293 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 | 300 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 |
294 | }; | 301 | }; |
@@ -301,18 +308,38 @@ static u8 iucvMagic[16] = { | |||
301 | * | 308 | * |
302 | * @returns The printable string (static data!!) | 309 | * @returns The printable string (static data!!) |
303 | */ | 310 | */ |
304 | static char *netiucv_printname(char *name) | 311 | static char *netiucv_printname(char *name, int len) |
305 | { | 312 | { |
306 | static char tmp[9]; | 313 | static char tmp[17]; |
307 | char *p = tmp; | 314 | char *p = tmp; |
308 | memcpy(tmp, name, 8); | 315 | memcpy(tmp, name, len); |
309 | tmp[8] = '\0'; | 316 | tmp[len] = '\0'; |
310 | while (*p && (!isspace(*p))) | 317 | while (*p && ((p - tmp) < len) && (!isspace(*p))) |
311 | p++; | 318 | p++; |
312 | *p = '\0'; | 319 | *p = '\0'; |
313 | return tmp; | 320 | return tmp; |
314 | } | 321 | } |
315 | 322 | ||
323 | static char *netiucv_printuser(struct iucv_connection *conn) | ||
324 | { | ||
325 | static char tmp_uid[9]; | ||
326 | static char tmp_udat[17]; | ||
327 | static char buf[100]; | ||
328 | |||
329 | if (memcmp(conn->userdata, iucvMagic_ebcdic, 16)) { | ||
330 | tmp_uid[8] = '\0'; | ||
331 | tmp_udat[16] = '\0'; | ||
332 | memcpy(tmp_uid, conn->userid, 8); | ||
333 | memcpy(tmp_uid, netiucv_printname(tmp_uid, 8), 8); | ||
334 | memcpy(tmp_udat, conn->userdata, 16); | ||
335 | EBCASC(tmp_udat, 16); | ||
336 | memcpy(tmp_udat, netiucv_printname(tmp_udat, 16), 16); | ||
337 | sprintf(buf, "%s.%s", tmp_uid, tmp_udat); | ||
338 | return buf; | ||
339 | } else | ||
340 | return netiucv_printname(conn->userid, 8); | ||
341 | } | ||
342 | |||
316 | /** | 343 | /** |
317 | * States of the interface statemachine. | 344 | * States of the interface statemachine. |
318 | */ | 345 | */ |
@@ -563,15 +590,18 @@ static int netiucv_callback_connreq(struct iucv_path *path, | |||
563 | { | 590 | { |
564 | struct iucv_connection *conn = path->private; | 591 | struct iucv_connection *conn = path->private; |
565 | struct iucv_event ev; | 592 | struct iucv_event ev; |
593 | static char tmp_user[9]; | ||
594 | static char tmp_udat[17]; | ||
566 | int rc; | 595 | int rc; |
567 | 596 | ||
568 | if (memcmp(iucvMagic, ipuser, 16)) | ||
569 | /* ipuser must match iucvMagic. */ | ||
570 | return -EINVAL; | ||
571 | rc = -EINVAL; | 597 | rc = -EINVAL; |
598 | memcpy(tmp_user, netiucv_printname(ipvmid, 8), 8); | ||
599 | memcpy(tmp_udat, ipuser, 16); | ||
600 | EBCASC(tmp_udat, 16); | ||
572 | read_lock_bh(&iucv_connection_rwlock); | 601 | read_lock_bh(&iucv_connection_rwlock); |
573 | list_for_each_entry(conn, &iucv_connection_list, list) { | 602 | list_for_each_entry(conn, &iucv_connection_list, list) { |
574 | if (strncmp(ipvmid, conn->userid, 8)) | 603 | if (strncmp(ipvmid, conn->userid, 8) || |
604 | strncmp(ipuser, conn->userdata, 16)) | ||
575 | continue; | 605 | continue; |
576 | /* Found a matching connection for this path. */ | 606 | /* Found a matching connection for this path. */ |
577 | conn->path = path; | 607 | conn->path = path; |
@@ -580,6 +610,8 @@ static int netiucv_callback_connreq(struct iucv_path *path, | |||
580 | fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); | 610 | fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); |
581 | rc = 0; | 611 | rc = 0; |
582 | } | 612 | } |
613 | IUCV_DBF_TEXT_(setup, 2, "Connection requested for %s.%s\n", | ||
614 | tmp_user, netiucv_printname(tmp_udat, 16)); | ||
583 | read_unlock_bh(&iucv_connection_rwlock); | 615 | read_unlock_bh(&iucv_connection_rwlock); |
584 | return rc; | 616 | return rc; |
585 | } | 617 | } |
@@ -816,7 +848,7 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) | |||
816 | conn->path = path; | 848 | conn->path = path; |
817 | path->msglim = NETIUCV_QUEUELEN_DEFAULT; | 849 | path->msglim = NETIUCV_QUEUELEN_DEFAULT; |
818 | path->flags = 0; | 850 | path->flags = 0; |
819 | rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); | 851 | rc = iucv_path_accept(path, &netiucv_handler, conn->userdata , conn); |
820 | if (rc) { | 852 | if (rc) { |
821 | IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc); | 853 | IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc); |
822 | return; | 854 | return; |
@@ -854,7 +886,7 @@ static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) | |||
854 | 886 | ||
855 | IUCV_DBF_TEXT(trace, 3, __func__); | 887 | IUCV_DBF_TEXT(trace, 3, __func__); |
856 | fsm_deltimer(&conn->timer); | 888 | fsm_deltimer(&conn->timer); |
857 | iucv_path_sever(conn->path, NULL); | 889 | iucv_path_sever(conn->path, conn->userdata); |
858 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 890 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
859 | } | 891 | } |
860 | 892 | ||
@@ -867,9 +899,9 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) | |||
867 | IUCV_DBF_TEXT(trace, 3, __func__); | 899 | IUCV_DBF_TEXT(trace, 3, __func__); |
868 | 900 | ||
869 | fsm_deltimer(&conn->timer); | 901 | fsm_deltimer(&conn->timer); |
870 | iucv_path_sever(conn->path, NULL); | 902 | iucv_path_sever(conn->path, conn->userdata); |
871 | dev_info(privptr->dev, "The peer interface of the IUCV device" | 903 | dev_info(privptr->dev, "The peer z/VM guest %s has closed the " |
872 | " has closed the connection\n"); | 904 | "connection\n", netiucv_printuser(conn)); |
873 | IUCV_DBF_TEXT(data, 2, | 905 | IUCV_DBF_TEXT(data, 2, |
874 | "conn_action_connsever: Remote dropped connection\n"); | 906 | "conn_action_connsever: Remote dropped connection\n"); |
875 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 907 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
@@ -886,8 +918,6 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) | |||
886 | IUCV_DBF_TEXT(trace, 3, __func__); | 918 | IUCV_DBF_TEXT(trace, 3, __func__); |
887 | 919 | ||
888 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 920 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
889 | IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n", | ||
890 | netdev->name, conn->userid); | ||
891 | 921 | ||
892 | /* | 922 | /* |
893 | * We must set the state before calling iucv_connect because the | 923 | * 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 | 927 | ||
898 | fsm_newstate(fi, CONN_STATE_SETUPWAIT); | 928 | fsm_newstate(fi, CONN_STATE_SETUPWAIT); |
899 | conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); | 929 | conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); |
930 | IUCV_DBF_TEXT_(setup, 2, "%s: connecting to %s ...\n", | ||
931 | netdev->name, netiucv_printuser(conn)); | ||
932 | |||
900 | rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, | 933 | rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, |
901 | NULL, iucvMagic, conn); | 934 | NULL, conn->userdata, conn); |
902 | switch (rc) { | 935 | switch (rc) { |
903 | case 0: | 936 | case 0: |
904 | netdev->tx_queue_len = conn->path->msglim; | 937 | netdev->tx_queue_len = conn->path->msglim; |
@@ -908,13 +941,13 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) | |||
908 | case 11: | 941 | case 11: |
909 | dev_warn(privptr->dev, | 942 | dev_warn(privptr->dev, |
910 | "The IUCV device failed to connect to z/VM guest %s\n", | 943 | "The IUCV device failed to connect to z/VM guest %s\n", |
911 | netiucv_printname(conn->userid)); | 944 | netiucv_printname(conn->userid, 8)); |
912 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 945 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
913 | break; | 946 | break; |
914 | case 12: | 947 | case 12: |
915 | dev_warn(privptr->dev, | 948 | dev_warn(privptr->dev, |
916 | "The IUCV device failed to connect to the peer on z/VM" | 949 | "The IUCV device failed to connect to the peer on z/VM" |
917 | " guest %s\n", netiucv_printname(conn->userid)); | 950 | " guest %s\n", netiucv_printname(conn->userid, 8)); |
918 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 951 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
919 | break; | 952 | break; |
920 | case 13: | 953 | case 13: |
@@ -927,7 +960,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) | |||
927 | dev_err(privptr->dev, | 960 | dev_err(privptr->dev, |
928 | "z/VM guest %s has too many IUCV connections" | 961 | "z/VM guest %s has too many IUCV connections" |
929 | " to connect with the IUCV device\n", | 962 | " to connect with the IUCV device\n", |
930 | netiucv_printname(conn->userid)); | 963 | netiucv_printname(conn->userid, 8)); |
931 | fsm_newstate(fi, CONN_STATE_CONNERR); | 964 | fsm_newstate(fi, CONN_STATE_CONNERR); |
932 | break; | 965 | break; |
933 | case 15: | 966 | case 15: |
@@ -972,7 +1005,7 @@ static void conn_action_stop(fsm_instance *fi, int event, void *arg) | |||
972 | netiucv_purge_skb_queue(&conn->collect_queue); | 1005 | netiucv_purge_skb_queue(&conn->collect_queue); |
973 | if (conn->path) { | 1006 | if (conn->path) { |
974 | IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); | 1007 | IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); |
975 | iucv_path_sever(conn->path, iucvMagic); | 1008 | iucv_path_sever(conn->path, conn->userdata); |
976 | kfree(conn->path); | 1009 | kfree(conn->path); |
977 | conn->path = NULL; | 1010 | conn->path = NULL; |
978 | } | 1011 | } |
@@ -1090,7 +1123,8 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) | |||
1090 | fsm_newstate(fi, DEV_STATE_RUNNING); | 1123 | fsm_newstate(fi, DEV_STATE_RUNNING); |
1091 | dev_info(privptr->dev, | 1124 | dev_info(privptr->dev, |
1092 | "The IUCV device has been connected" | 1125 | "The IUCV device has been connected" |
1093 | " successfully to %s\n", privptr->conn->userid); | 1126 | " successfully to %s\n", |
1127 | netiucv_printuser(privptr->conn)); | ||
1094 | IUCV_DBF_TEXT(setup, 3, | 1128 | IUCV_DBF_TEXT(setup, 3, |
1095 | "connection is up and running\n"); | 1129 | "connection is up and running\n"); |
1096 | break; | 1130 | break; |
@@ -1452,45 +1486,72 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr, | |||
1452 | struct netiucv_priv *priv = dev_get_drvdata(dev); | 1486 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1453 | 1487 | ||
1454 | IUCV_DBF_TEXT(trace, 5, __func__); | 1488 | IUCV_DBF_TEXT(trace, 5, __func__); |
1455 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); | 1489 | return sprintf(buf, "%s\n", netiucv_printuser(priv->conn)); |
1456 | } | 1490 | } |
1457 | 1491 | ||
1458 | static ssize_t user_write(struct device *dev, struct device_attribute *attr, | 1492 | static int netiucv_check_user(const char *buf, size_t count, char *username, |
1459 | const char *buf, size_t count) | 1493 | char *userdata) |
1460 | { | 1494 | { |
1461 | struct netiucv_priv *priv = dev_get_drvdata(dev); | 1495 | const char *p; |
1462 | struct net_device *ndev = priv->conn->netdev; | 1496 | int i; |
1463 | char *p; | ||
1464 | char *tmp; | ||
1465 | char username[9]; | ||
1466 | int i; | ||
1467 | struct iucv_connection *cp; | ||
1468 | 1497 | ||
1469 | IUCV_DBF_TEXT(trace, 3, __func__); | 1498 | p = strchr(buf, '.'); |
1470 | if (count > 9) { | 1499 | if ((p && ((count > 26) || |
1471 | IUCV_DBF_TEXT_(setup, 2, | 1500 | ((p - buf) > 8) || |
1472 | "%d is length of username\n", (int) count); | 1501 | (buf + count - p > 18))) || |
1502 | (!p && (count > 9))) { | ||
1503 | IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n"); | ||
1473 | return -EINVAL; | 1504 | return -EINVAL; |
1474 | } | 1505 | } |
1475 | 1506 | ||
1476 | tmp = strsep((char **) &buf, "\n"); | 1507 | for (i = 0, p = buf; i < 8 && *p && *p != '.'; i++, p++) { |
1477 | for (i = 0, p = tmp; i < 8 && *p; i++, p++) { | 1508 | if (isalnum(*p) || *p == '$') { |
1478 | if (isalnum(*p) || (*p == '$')) { | 1509 | username[i] = toupper(*p); |
1479 | username[i]= toupper(*p); | ||
1480 | continue; | 1510 | continue; |
1481 | } | 1511 | } |
1482 | if (*p == '\n') { | 1512 | if (*p == '\n') |
1483 | /* trailing lf, grr */ | 1513 | /* trailing lf, grr */ |
1484 | break; | 1514 | break; |
1485 | } | ||
1486 | IUCV_DBF_TEXT_(setup, 2, | 1515 | IUCV_DBF_TEXT_(setup, 2, |
1487 | "username: invalid character %c\n", *p); | 1516 | "conn_write: invalid character %02x\n", *p); |
1488 | return -EINVAL; | 1517 | return -EINVAL; |
1489 | } | 1518 | } |
1490 | while (i < 8) | 1519 | while (i < 8) |
1491 | username[i++] = ' '; | 1520 | username[i++] = ' '; |
1492 | username[8] = '\0'; | 1521 | username[8] = '\0'; |
1493 | 1522 | ||
1523 | if (*p == '.') { | ||
1524 | p++; | ||
1525 | for (i = 0; i < 16 && *p; i++, p++) { | ||
1526 | if (*p == '\n') | ||
1527 | break; | ||
1528 | userdata[i] = toupper(*p); | ||
1529 | } | ||
1530 | while (i > 0 && i < 16) | ||
1531 | userdata[i++] = ' '; | ||
1532 | } else | ||
1533 | memcpy(userdata, iucvMagic_ascii, 16); | ||
1534 | userdata[16] = '\0'; | ||
1535 | ASCEBC(userdata, 16); | ||
1536 | |||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | static ssize_t user_write(struct device *dev, struct device_attribute *attr, | ||
1541 | const char *buf, size_t count) | ||
1542 | { | ||
1543 | struct netiucv_priv *priv = dev_get_drvdata(dev); | ||
1544 | struct net_device *ndev = priv->conn->netdev; | ||
1545 | char username[9]; | ||
1546 | char userdata[17]; | ||
1547 | int rc; | ||
1548 | struct iucv_connection *cp; | ||
1549 | |||
1550 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1551 | rc = netiucv_check_user(buf, count, username, userdata); | ||
1552 | if (rc) | ||
1553 | return rc; | ||
1554 | |||
1494 | if (memcmp(username, priv->conn->userid, 9) && | 1555 | if (memcmp(username, priv->conn->userid, 9) && |
1495 | (ndev->flags & (IFF_UP | IFF_RUNNING))) { | 1556 | (ndev->flags & (IFF_UP | IFF_RUNNING))) { |
1496 | /* username changed while the interface is active. */ | 1557 | /* username changed while the interface is active. */ |
@@ -1499,15 +1560,17 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, | |||
1499 | } | 1560 | } |
1500 | read_lock_bh(&iucv_connection_rwlock); | 1561 | read_lock_bh(&iucv_connection_rwlock); |
1501 | list_for_each_entry(cp, &iucv_connection_list, list) { | 1562 | list_for_each_entry(cp, &iucv_connection_list, list) { |
1502 | if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { | 1563 | if (!strncmp(username, cp->userid, 9) && |
1564 | !strncmp(userdata, cp->userdata, 17) && cp->netdev != ndev) { | ||
1503 | read_unlock_bh(&iucv_connection_rwlock); | 1565 | read_unlock_bh(&iucv_connection_rwlock); |
1504 | IUCV_DBF_TEXT_(setup, 2, "user_write: Connection " | 1566 | IUCV_DBF_TEXT_(setup, 2, "user_write: Connection to %s " |
1505 | "to %s already exists\n", username); | 1567 | "already exists\n", netiucv_printuser(cp)); |
1506 | return -EEXIST; | 1568 | return -EEXIST; |
1507 | } | 1569 | } |
1508 | } | 1570 | } |
1509 | read_unlock_bh(&iucv_connection_rwlock); | 1571 | read_unlock_bh(&iucv_connection_rwlock); |
1510 | memcpy(priv->conn->userid, username, 9); | 1572 | memcpy(priv->conn->userid, username, 9); |
1573 | memcpy(priv->conn->userdata, userdata, 17); | ||
1511 | return count; | 1574 | return count; |
1512 | } | 1575 | } |
1513 | 1576 | ||
@@ -1537,7 +1600,8 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, | |||
1537 | bs1 = simple_strtoul(buf, &e, 0); | 1600 | bs1 = simple_strtoul(buf, &e, 0); |
1538 | 1601 | ||
1539 | if (e && (!isspace(*e))) { | 1602 | if (e && (!isspace(*e))) { |
1540 | IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e); | 1603 | IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %02x\n", |
1604 | *e); | ||
1541 | return -EINVAL; | 1605 | return -EINVAL; |
1542 | } | 1606 | } |
1543 | if (bs1 > NETIUCV_BUFSIZE_MAX) { | 1607 | if (bs1 > NETIUCV_BUFSIZE_MAX) { |
@@ -1864,7 +1928,8 @@ static void netiucv_unregister_device(struct device *dev) | |||
1864 | * Add it to the list of netiucv connections; | 1928 | * Add it to the list of netiucv connections; |
1865 | */ | 1929 | */ |
1866 | static struct iucv_connection *netiucv_new_connection(struct net_device *dev, | 1930 | static struct iucv_connection *netiucv_new_connection(struct net_device *dev, |
1867 | char *username) | 1931 | char *username, |
1932 | char *userdata) | ||
1868 | { | 1933 | { |
1869 | struct iucv_connection *conn; | 1934 | struct iucv_connection *conn; |
1870 | 1935 | ||
@@ -1893,6 +1958,8 @@ static struct iucv_connection *netiucv_new_connection(struct net_device *dev, | |||
1893 | fsm_settimer(conn->fsm, &conn->timer); | 1958 | fsm_settimer(conn->fsm, &conn->timer); |
1894 | fsm_newstate(conn->fsm, CONN_STATE_INVALID); | 1959 | fsm_newstate(conn->fsm, CONN_STATE_INVALID); |
1895 | 1960 | ||
1961 | if (userdata) | ||
1962 | memcpy(conn->userdata, userdata, 17); | ||
1896 | if (username) { | 1963 | if (username) { |
1897 | memcpy(conn->userid, username, 9); | 1964 | memcpy(conn->userid, username, 9); |
1898 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | 1965 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); |
@@ -1919,6 +1986,7 @@ out: | |||
1919 | */ | 1986 | */ |
1920 | static void netiucv_remove_connection(struct iucv_connection *conn) | 1987 | static void netiucv_remove_connection(struct iucv_connection *conn) |
1921 | { | 1988 | { |
1989 | |||
1922 | IUCV_DBF_TEXT(trace, 3, __func__); | 1990 | IUCV_DBF_TEXT(trace, 3, __func__); |
1923 | write_lock_bh(&iucv_connection_rwlock); | 1991 | write_lock_bh(&iucv_connection_rwlock); |
1924 | list_del_init(&conn->list); | 1992 | list_del_init(&conn->list); |
@@ -1926,7 +1994,7 @@ static void netiucv_remove_connection(struct iucv_connection *conn) | |||
1926 | fsm_deltimer(&conn->timer); | 1994 | fsm_deltimer(&conn->timer); |
1927 | netiucv_purge_skb_queue(&conn->collect_queue); | 1995 | netiucv_purge_skb_queue(&conn->collect_queue); |
1928 | if (conn->path) { | 1996 | if (conn->path) { |
1929 | iucv_path_sever(conn->path, iucvMagic); | 1997 | iucv_path_sever(conn->path, conn->userdata); |
1930 | kfree(conn->path); | 1998 | kfree(conn->path); |
1931 | conn->path = NULL; | 1999 | conn->path = NULL; |
1932 | } | 2000 | } |
@@ -1985,7 +2053,7 @@ static void netiucv_setup_netdevice(struct net_device *dev) | |||
1985 | /** | 2053 | /** |
1986 | * Allocate and initialize everything of a net device. | 2054 | * Allocate and initialize everything of a net device. |
1987 | */ | 2055 | */ |
1988 | static struct net_device *netiucv_init_netdevice(char *username) | 2056 | static struct net_device *netiucv_init_netdevice(char *username, char *userdata) |
1989 | { | 2057 | { |
1990 | struct netiucv_priv *privptr; | 2058 | struct netiucv_priv *privptr; |
1991 | struct net_device *dev; | 2059 | struct net_device *dev; |
@@ -2004,7 +2072,7 @@ static struct net_device *netiucv_init_netdevice(char *username) | |||
2004 | if (!privptr->fsm) | 2072 | if (!privptr->fsm) |
2005 | goto out_netdev; | 2073 | goto out_netdev; |
2006 | 2074 | ||
2007 | privptr->conn = netiucv_new_connection(dev, username); | 2075 | privptr->conn = netiucv_new_connection(dev, username, userdata); |
2008 | if (!privptr->conn) { | 2076 | if (!privptr->conn) { |
2009 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); | 2077 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); |
2010 | goto out_fsm; | 2078 | goto out_fsm; |
@@ -2022,47 +2090,31 @@ out_netdev: | |||
2022 | static ssize_t conn_write(struct device_driver *drv, | 2090 | static ssize_t conn_write(struct device_driver *drv, |
2023 | const char *buf, size_t count) | 2091 | const char *buf, size_t count) |
2024 | { | 2092 | { |
2025 | const char *p; | ||
2026 | char username[9]; | 2093 | char username[9]; |
2027 | int i, rc; | 2094 | char userdata[17]; |
2095 | int rc; | ||
2028 | struct net_device *dev; | 2096 | struct net_device *dev; |
2029 | struct netiucv_priv *priv; | 2097 | struct netiucv_priv *priv; |
2030 | struct iucv_connection *cp; | 2098 | struct iucv_connection *cp; |
2031 | 2099 | ||
2032 | IUCV_DBF_TEXT(trace, 3, __func__); | 2100 | IUCV_DBF_TEXT(trace, 3, __func__); |
2033 | if (count>9) { | 2101 | rc = netiucv_check_user(buf, count, username, userdata); |
2034 | IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n"); | 2102 | if (rc) |
2035 | return -EINVAL; | 2103 | return rc; |
2036 | } | ||
2037 | |||
2038 | for (i = 0, p = buf; i < 8 && *p; i++, p++) { | ||
2039 | if (isalnum(*p) || *p == '$') { | ||
2040 | username[i] = toupper(*p); | ||
2041 | continue; | ||
2042 | } | ||
2043 | if (*p == '\n') | ||
2044 | /* trailing lf, grr */ | ||
2045 | break; | ||
2046 | IUCV_DBF_TEXT_(setup, 2, | ||
2047 | "conn_write: invalid character %c\n", *p); | ||
2048 | return -EINVAL; | ||
2049 | } | ||
2050 | while (i < 8) | ||
2051 | username[i++] = ' '; | ||
2052 | username[8] = '\0'; | ||
2053 | 2104 | ||
2054 | read_lock_bh(&iucv_connection_rwlock); | 2105 | read_lock_bh(&iucv_connection_rwlock); |
2055 | list_for_each_entry(cp, &iucv_connection_list, list) { | 2106 | list_for_each_entry(cp, &iucv_connection_list, list) { |
2056 | if (!strncmp(username, cp->userid, 9)) { | 2107 | if (!strncmp(username, cp->userid, 9) && |
2108 | !strncmp(userdata, cp->userdata, 17)) { | ||
2057 | read_unlock_bh(&iucv_connection_rwlock); | 2109 | read_unlock_bh(&iucv_connection_rwlock); |
2058 | IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection " | 2110 | IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection to %s " |
2059 | "to %s already exists\n", username); | 2111 | "already exists\n", netiucv_printuser(cp)); |
2060 | return -EEXIST; | 2112 | return -EEXIST; |
2061 | } | 2113 | } |
2062 | } | 2114 | } |
2063 | read_unlock_bh(&iucv_connection_rwlock); | 2115 | read_unlock_bh(&iucv_connection_rwlock); |
2064 | 2116 | ||
2065 | dev = netiucv_init_netdevice(username); | 2117 | dev = netiucv_init_netdevice(username, userdata); |
2066 | if (!dev) { | 2118 | if (!dev) { |
2067 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); | 2119 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); |
2068 | return -ENODEV; | 2120 | return -ENODEV; |
@@ -2083,8 +2135,9 @@ static ssize_t conn_write(struct device_driver *drv, | |||
2083 | if (rc) | 2135 | if (rc) |
2084 | goto out_unreg; | 2136 | goto out_unreg; |
2085 | 2137 | ||
2086 | dev_info(priv->dev, "The IUCV interface to %s has been" | 2138 | dev_info(priv->dev, "The IUCV interface to %s has been established " |
2087 | " established successfully\n", netiucv_printname(username)); | 2139 | "successfully\n", |
2140 | netiucv_printuser(priv->conn)); | ||
2088 | 2141 | ||
2089 | return count; | 2142 | return count; |
2090 | 2143 | ||