* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
-
+\f
#undef DEBUG
#include <linux/module.h>
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
-
+\f
#define PRINTK_HEADER " iucv: " /* for debugging */
static struct device_driver netiucv_driver = {
/**
* Linked list of all connection structs.
*/
-struct iucv_connection_struct {
- struct iucv_connection *iucv_connections;
- rwlock_t iucv_rwlock;
-};
-
-static struct iucv_connection_struct iucv_conns;
+static struct iucv_connection *iucv_connections;
/**
* Representation of event-data for the
*p = '\0';
return tmp;
}
-
+\f
/**
* States of the interface statemachine.
*/
"Connection up",
"Connection down",
};
-
+\f
/**
* Events of the connection statemachine
*/
"Connect error",
};
-
+\f
/**
* Debug Facility Stuff
*/
fsm_action_nop(fsm_instance *fi, int event, void *arg)
{
}
-
+\f
/**
* Actions of the connection statemachine
*****************************************************************************/
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
-
+\f
/**
* Actions for interface - statemachine.
*****************************************************************************/
fsm_newstate(conn->fsm, CONN_STATE_TX);
conn->prof.send_stamp = xtime;
-
+
rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
0, nskb->data, nskb->len);
/* Shut up, gcc! nskb is always below 2G. */
return rc;
}
-
+\f
/**
* Interface API for upper network layers
*****************************************************************************/
/**
* If connection is not running, try to restart it
- * and throw away packet.
+ * and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
fsm_event(privptr->fsm, DEV_EVENT_START, dev);
struct net_device *ndev = priv->conn->netdev;
char *p;
char *tmp;
- char username[9];
+ char username[10];
int i;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
tmp = strsep((char **) &buf, "\n");
for (i=0, p=tmp; i<8 && *p; i++, p++) {
if (isalnum(*p) || (*p == '$'))
- username[i]= toupper(*p);
+ username[i]= *p;
else if (*p == '\n') {
/* trailing lf, grr */
break;
return -EINVAL;
}
}
- while (i<8)
+ while (i<9)
username[i++] = ' ';
- username[8] = '\0';
+ username[9] = '\0';
- if (memcmp(username, priv->conn->userid, 9)) {
+ if (memcmp(username, priv->conn->userid, 8)) {
/* username changed */
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
PRINT_WARN(
return -EBUSY;
}
}
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9) ||
- ((*clist)->netdev != ndev))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
- }
memcpy(priv->conn->userid, username, 9);
return count;
maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.maxcqueue = 0;
return count;
sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.doios_single = 0;
return count;
mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
priv->conn->prof.doios_multi = 0;
return count;
txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.txlen = 0;
return count;
txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
-
+
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
priv->conn->prof.tx_time = 0;
return count;
netiucv_register_device(struct net_device *ndev)
{
struct netiucv_priv *priv = ndev->priv;
- struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ struct device *dev = kmalloc(sizeof(struct device), GFP_KERNEL);
int ret;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (dev) {
+ memset(dev, 0, sizeof(struct device));
snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name);
dev->bus = &iucv_bus;
dev->parent = iucv_root;
static struct iucv_connection *
netiucv_new_connection(struct net_device *dev, char *username)
{
- unsigned long flags;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
+ struct iucv_connection **clist = &iucv_connections;
struct iucv_connection *conn =
- kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
+ (struct iucv_connection *)
+ kmalloc(sizeof(struct iucv_connection), GFP_KERNEL);
if (conn) {
+ memset(conn, 0, sizeof(struct iucv_connection));
skb_queue_head_init(&conn->collect_queue);
skb_queue_head_init(&conn->commit_queue);
- spin_lock_init(&conn->collect_lock);
conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
conn->netdev = dev;
fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
}
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
conn->next = *clist;
*clist = conn;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
}
return conn;
}
static void
netiucv_remove_connection(struct iucv_connection *conn)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection **clist = &iucv_connections;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (conn == NULL)
return;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
while (*clist) {
if (*clist == conn) {
*clist = conn->next;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
if (conn->handle) {
iucv_unregister_program(conn->handle);
conn->handle = NULL;
}
clist = &((*clist)->next);
}
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
}
/**
conn_write(struct device_driver *drv, const char *buf, size_t count)
{
char *p;
- char username[9];
+ char username[10];
int i, ret;
struct net_device *dev;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
if (isalnum(*p) || (*p == '$'))
- username[i]= toupper(*p);
+ username[i]= *p;
else if (*p == '\n') {
/* trailing lf, grr */
break;
return -EINVAL;
}
}
- while (i<8)
+ while (i<9)
username[i++] = ' ';
- username[8] = '\0';
-
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
- }
+ username[9] = '\0';
dev = netiucv_init_netdevice(username);
if (!dev) {
PRINT_WARN(
}
PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
-
+
return count;
out_free_ndev:
static ssize_t
remove_write (struct device_driver *drv, const char *buf, size_t count)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection **clist = &iucv_connections;
struct net_device *ndev;
struct netiucv_priv *priv;
struct device *dev;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count >= IFNAMSIZ)
- count = IFNAMSIZ - 1;;
+ count = IFNAMSIZ-1;
for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
- if ((*p == '\n') || (*p == ' ')) {
+ if ((*p == '\n') | (*p == ' ')) {
/* trailing lf, grr */
break;
} else {
}
name[i] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
while (*clist) {
ndev = (*clist)->netdev;
priv = (struct netiucv_priv*)ndev->priv;
clist = &((*clist)->next);
continue;
}
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
PRINT_WARN(
"netiucv: net device %s active with peer %s\n",
netiucv_unregister_device(dev);
return count;
}
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
PRINT_WARN("netiucv: net device %s unknown\n", name);
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
return -EINVAL;
netiucv_exit(void)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- while (iucv_conns.iucv_connections) {
- struct net_device *ndev = iucv_conns.iucv_connections->netdev;
+ while (iucv_connections) {
+ struct net_device *ndev = iucv_connections->netdev;
struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
struct device *dev = priv->dev;
netiucv_init(void)
{
int ret;
-
+
ret = iucv_register_dbf_views();
if (ret) {
PRINT_WARN("netiucv_init failed, "
if (!ret) {
ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
netiucv_banner();
- rwlock_init(&iucv_conns.iucv_rwlock);
} else {
PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
}
return ret;
}
-
+
module_init(netiucv_init);
module_exit(netiucv_exit);
MODULE_LICENSE("GPL");