diff options
| -rw-r--r-- | drivers/s390/net/netiucv.c | 80 |
1 files changed, 64 insertions, 16 deletions
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 5d6e6cbfa360..d7d1cc0a5c8e 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
| @@ -112,7 +112,12 @@ struct iucv_connection { | |||
| 112 | /** | 112 | /** |
| 113 | * Linked list of all connection structs. | 113 | * Linked list of all connection structs. |
| 114 | */ | 114 | */ |
| 115 | static struct iucv_connection *iucv_connections; | 115 | struct iucv_connection_struct { |
| 116 | struct iucv_connection *iucv_connections; | ||
| 117 | rwlock_t iucv_rwlock; | ||
| 118 | }; | ||
| 119 | |||
| 120 | static struct iucv_connection_struct iucv_conns; | ||
| 116 | 121 | ||
| 117 | /** | 122 | /** |
| 118 | * Representation of event-data for the | 123 | * Representation of event-data for the |
| @@ -1368,8 +1373,10 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
| 1368 | struct net_device *ndev = priv->conn->netdev; | 1373 | struct net_device *ndev = priv->conn->netdev; |
| 1369 | char *p; | 1374 | char *p; |
| 1370 | char *tmp; | 1375 | char *tmp; |
| 1371 | char username[10]; | 1376 | char username[9]; |
| 1372 | int i; | 1377 | int i; |
| 1378 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
| 1379 | unsigned long flags; | ||
| 1373 | 1380 | ||
| 1374 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1381 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
| 1375 | if (count>9) { | 1382 | if (count>9) { |
| @@ -1382,7 +1389,7 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
| 1382 | tmp = strsep((char **) &buf, "\n"); | 1389 | tmp = strsep((char **) &buf, "\n"); |
| 1383 | for (i=0, p=tmp; i<8 && *p; i++, p++) { | 1390 | for (i=0, p=tmp; i<8 && *p; i++, p++) { |
| 1384 | if (isalnum(*p) || (*p == '$')) | 1391 | if (isalnum(*p) || (*p == '$')) |
| 1385 | username[i]= *p; | 1392 | username[i]= toupper(*p); |
| 1386 | else if (*p == '\n') { | 1393 | else if (*p == '\n') { |
| 1387 | /* trailing lf, grr */ | 1394 | /* trailing lf, grr */ |
| 1388 | break; | 1395 | break; |
| @@ -1395,11 +1402,11 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
| 1395 | return -EINVAL; | 1402 | return -EINVAL; |
| 1396 | } | 1403 | } |
| 1397 | } | 1404 | } |
| 1398 | while (i<9) | 1405 | while (i<8) |
| 1399 | username[i++] = ' '; | 1406 | username[i++] = ' '; |
| 1400 | username[9] = '\0'; | 1407 | username[8] = '\0'; |
| 1401 | 1408 | ||
| 1402 | if (memcmp(username, priv->conn->userid, 8)) { | 1409 | if (memcmp(username, priv->conn->userid, 9)) { |
| 1403 | /* username changed */ | 1410 | /* username changed */ |
| 1404 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 1411 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { |
| 1405 | PRINT_WARN( | 1412 | PRINT_WARN( |
| @@ -1410,6 +1417,19 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
| 1410 | return -EBUSY; | 1417 | return -EBUSY; |
| 1411 | } | 1418 | } |
| 1412 | } | 1419 | } |
| 1420 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
| 1421 | while (*clist) { | ||
| 1422 | if (!strncmp(username, (*clist)->userid, 9) || | ||
| 1423 | ((*clist)->netdev != ndev)) | ||
| 1424 | break; | ||
| 1425 | clist = &((*clist)->next); | ||
| 1426 | } | ||
| 1427 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 1428 | if (*clist) { | ||
| 1429 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
| 1430 | username); | ||
| 1431 | return -EEXIST; | ||
| 1432 | } | ||
| 1413 | memcpy(priv->conn->userid, username, 9); | 1433 | memcpy(priv->conn->userid, username, 9); |
| 1414 | 1434 | ||
| 1415 | return count; | 1435 | return count; |
| @@ -1781,13 +1801,15 @@ netiucv_unregister_device(struct device *dev) | |||
| 1781 | static struct iucv_connection * | 1801 | static struct iucv_connection * |
| 1782 | netiucv_new_connection(struct net_device *dev, char *username) | 1802 | netiucv_new_connection(struct net_device *dev, char *username) |
| 1783 | { | 1803 | { |
| 1784 | struct iucv_connection **clist = &iucv_connections; | 1804 | unsigned long flags; |
| 1805 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
| 1785 | struct iucv_connection *conn = | 1806 | struct iucv_connection *conn = |
| 1786 | kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); | 1807 | kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); |
| 1787 | 1808 | ||
| 1788 | if (conn) { | 1809 | if (conn) { |
| 1789 | skb_queue_head_init(&conn->collect_queue); | 1810 | skb_queue_head_init(&conn->collect_queue); |
| 1790 | skb_queue_head_init(&conn->commit_queue); | 1811 | skb_queue_head_init(&conn->commit_queue); |
| 1812 | spin_lock_init(&conn->collect_lock); | ||
| 1791 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; | 1813 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; |
| 1792 | conn->netdev = dev; | 1814 | conn->netdev = dev; |
| 1793 | 1815 | ||
| @@ -1822,8 +1844,10 @@ netiucv_new_connection(struct net_device *dev, char *username) | |||
| 1822 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | 1844 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); |
| 1823 | } | 1845 | } |
| 1824 | 1846 | ||
| 1847 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
| 1825 | conn->next = *clist; | 1848 | conn->next = *clist; |
| 1826 | *clist = conn; | 1849 | *clist = conn; |
| 1850 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 1827 | } | 1851 | } |
| 1828 | return conn; | 1852 | return conn; |
| 1829 | } | 1853 | } |
| @@ -1835,14 +1859,17 @@ netiucv_new_connection(struct net_device *dev, char *username) | |||
| 1835 | static void | 1859 | static void |
| 1836 | netiucv_remove_connection(struct iucv_connection *conn) | 1860 | netiucv_remove_connection(struct iucv_connection *conn) |
| 1837 | { | 1861 | { |
| 1838 | struct iucv_connection **clist = &iucv_connections; | 1862 | struct iucv_connection **clist = &iucv_conns.iucv_connections; |
| 1863 | unsigned long flags; | ||
| 1839 | 1864 | ||
| 1840 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1865 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
| 1841 | if (conn == NULL) | 1866 | if (conn == NULL) |
| 1842 | return; | 1867 | return; |
| 1868 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
| 1843 | while (*clist) { | 1869 | while (*clist) { |
| 1844 | if (*clist == conn) { | 1870 | if (*clist == conn) { |
| 1845 | *clist = conn->next; | 1871 | *clist = conn->next; |
| 1872 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 1846 | if (conn->handle) { | 1873 | if (conn->handle) { |
| 1847 | iucv_unregister_program(conn->handle); | 1874 | iucv_unregister_program(conn->handle); |
| 1848 | conn->handle = NULL; | 1875 | conn->handle = NULL; |
| @@ -1855,6 +1882,7 @@ netiucv_remove_connection(struct iucv_connection *conn) | |||
| 1855 | } | 1882 | } |
| 1856 | clist = &((*clist)->next); | 1883 | clist = &((*clist)->next); |
| 1857 | } | 1884 | } |
| 1885 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 1858 | } | 1886 | } |
| 1859 | 1887 | ||
| 1860 | /** | 1888 | /** |
| @@ -1947,9 +1975,11 @@ static ssize_t | |||
| 1947 | conn_write(struct device_driver *drv, const char *buf, size_t count) | 1975 | conn_write(struct device_driver *drv, const char *buf, size_t count) |
| 1948 | { | 1976 | { |
| 1949 | char *p; | 1977 | char *p; |
| 1950 | char username[10]; | 1978 | char username[9]; |
| 1951 | int i, ret; | 1979 | int i, ret; |
| 1952 | struct net_device *dev; | 1980 | struct net_device *dev; |
| 1981 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
| 1982 | unsigned long flags; | ||
| 1953 | 1983 | ||
| 1954 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1984 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
| 1955 | if (count>9) { | 1985 | if (count>9) { |
| @@ -1960,7 +1990,7 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) | |||
| 1960 | 1990 | ||
| 1961 | for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { | 1991 | for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { |
| 1962 | if (isalnum(*p) || (*p == '$')) | 1992 | if (isalnum(*p) || (*p == '$')) |
| 1963 | username[i]= *p; | 1993 | username[i]= toupper(*p); |
| 1964 | else if (*p == '\n') { | 1994 | else if (*p == '\n') { |
| 1965 | /* trailing lf, grr */ | 1995 | /* trailing lf, grr */ |
| 1966 | break; | 1996 | break; |
| @@ -1971,9 +2001,22 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) | |||
| 1971 | return -EINVAL; | 2001 | return -EINVAL; |
| 1972 | } | 2002 | } |
| 1973 | } | 2003 | } |
| 1974 | while (i<9) | 2004 | while (i<8) |
| 1975 | username[i++] = ' '; | 2005 | username[i++] = ' '; |
| 1976 | username[9] = '\0'; | 2006 | username[8] = '\0'; |
| 2007 | |||
| 2008 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
| 2009 | while (*clist) { | ||
| 2010 | if (!strncmp(username, (*clist)->userid, 9)) | ||
| 2011 | break; | ||
| 2012 | clist = &((*clist)->next); | ||
| 2013 | } | ||
| 2014 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 2015 | if (*clist) { | ||
| 2016 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
| 2017 | username); | ||
| 2018 | return -EEXIST; | ||
| 2019 | } | ||
| 1977 | dev = netiucv_init_netdevice(username); | 2020 | dev = netiucv_init_netdevice(username); |
| 1978 | if (!dev) { | 2021 | if (!dev) { |
| 1979 | PRINT_WARN( | 2022 | PRINT_WARN( |
| @@ -2015,7 +2058,8 @@ DRIVER_ATTR(connection, 0200, NULL, conn_write); | |||
| 2015 | static ssize_t | 2058 | static ssize_t |
| 2016 | remove_write (struct device_driver *drv, const char *buf, size_t count) | 2059 | remove_write (struct device_driver *drv, const char *buf, size_t count) |
| 2017 | { | 2060 | { |
| 2018 | struct iucv_connection **clist = &iucv_connections; | 2061 | struct iucv_connection **clist = &iucv_conns.iucv_connections; |
| 2062 | unsigned long flags; | ||
| 2019 | struct net_device *ndev; | 2063 | struct net_device *ndev; |
| 2020 | struct netiucv_priv *priv; | 2064 | struct netiucv_priv *priv; |
| 2021 | struct device *dev; | 2065 | struct device *dev; |
| @@ -2026,7 +2070,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
| 2026 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2070 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
| 2027 | 2071 | ||
| 2028 | if (count >= IFNAMSIZ) | 2072 | if (count >= IFNAMSIZ) |
| 2029 | count = IFNAMSIZ-1; | 2073 | count = IFNAMSIZ - 1;; |
| 2030 | 2074 | ||
| 2031 | for (i=0, p=(char *)buf; i<count && *p; i++, p++) { | 2075 | for (i=0, p=(char *)buf; i<count && *p; i++, p++) { |
| 2032 | if ((*p == '\n') || (*p == ' ')) { | 2076 | if ((*p == '\n') || (*p == ' ')) { |
| @@ -2038,6 +2082,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
| 2038 | } | 2082 | } |
| 2039 | name[i] = '\0'; | 2083 | name[i] = '\0'; |
| 2040 | 2084 | ||
| 2085 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | ||
| 2041 | while (*clist) { | 2086 | while (*clist) { |
| 2042 | ndev = (*clist)->netdev; | 2087 | ndev = (*clist)->netdev; |
| 2043 | priv = (struct netiucv_priv*)ndev->priv; | 2088 | priv = (struct netiucv_priv*)ndev->priv; |
| @@ -2047,6 +2092,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
| 2047 | clist = &((*clist)->next); | 2092 | clist = &((*clist)->next); |
| 2048 | continue; | 2093 | continue; |
| 2049 | } | 2094 | } |
| 2095 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 2050 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 2096 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { |
| 2051 | PRINT_WARN( | 2097 | PRINT_WARN( |
| 2052 | "netiucv: net device %s active with peer %s\n", | 2098 | "netiucv: net device %s active with peer %s\n", |
| @@ -2060,6 +2106,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
| 2060 | netiucv_unregister_device(dev); | 2106 | netiucv_unregister_device(dev); |
| 2061 | return count; | 2107 | return count; |
| 2062 | } | 2108 | } |
| 2109 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
| 2063 | PRINT_WARN("netiucv: net device %s unknown\n", name); | 2110 | PRINT_WARN("netiucv: net device %s unknown\n", name); |
| 2064 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); | 2111 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); |
| 2065 | return -EINVAL; | 2112 | return -EINVAL; |
| @@ -2077,8 +2124,8 @@ static void __exit | |||
| 2077 | netiucv_exit(void) | 2124 | netiucv_exit(void) |
| 2078 | { | 2125 | { |
| 2079 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2126 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
| 2080 | while (iucv_connections) { | 2127 | while (iucv_conns.iucv_connections) { |
| 2081 | struct net_device *ndev = iucv_connections->netdev; | 2128 | struct net_device *ndev = iucv_conns.iucv_connections->netdev; |
| 2082 | struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; | 2129 | struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; |
| 2083 | struct device *dev = priv->dev; | 2130 | struct device *dev = priv->dev; |
| 2084 | 2131 | ||
| @@ -2120,6 +2167,7 @@ netiucv_init(void) | |||
| 2120 | if (!ret) { | 2167 | if (!ret) { |
| 2121 | ret = driver_create_file(&netiucv_driver, &driver_attr_remove); | 2168 | ret = driver_create_file(&netiucv_driver, &driver_attr_remove); |
| 2122 | netiucv_banner(); | 2169 | netiucv_banner(); |
| 2170 | rwlock_init(&iucv_conns.iucv_rwlock); | ||
| 2123 | } else { | 2171 | } else { |
| 2124 | PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); | 2172 | PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); |
| 2125 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); | 2173 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); |
