/*
- * $Id: netiucv.c,v 1.51 2004/04/23 08:11:21 mschwide Exp $
+ * $Id: netiucv.c,v 1.53 2004/05/07 14:29:37 mschwide Exp $
*
* IUCV network driver
*
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * RELEASE-TAG: IUCV network driver $Revision: 1.51 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.53 $
*
*/
\f
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
+#include <asm/ebcdic.h>
#include "iucv.h"
#include "fsm.h"
*/
static struct iucv_connection *connections;
-/* Keep track of interfaces. */
-static int ifno;
-
/**
* Representation of event-data for the
* connection state machine.
iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;
struct netiucv_priv *privptr = (struct netiucv_priv *)conn->netdev->priv;
- __u16 msglen = eib->ln1msg2.ipbfln1f;
+ __u32 msglen = eib->ln1msg2.ipbfln1f;
int rc;
pr_debug("%s() called\n", __FUNCTION__);
conn->rx_buff->data, msglen, NULL, NULL, NULL);
if (rc != 0 || msglen < 5) {
privptr->stats.rx_errors++;
+ printk(KERN_INFO "iucv_receive returned %08x\n", rc);
return;
}
netiucv_unpack_skb(conn, conn->rx_buff);
fsm_newstate(fi, CONN_STATE_IDLE);
if (privptr)
privptr->stats.tx_errors += txpackets;
- printk(KERN_DEBUG "iucv_send returned %08x\n",
+ printk(KERN_INFO "iucv_send returned %08x\n",
rc);
} else {
if (privptr) {
struct iucv_event *ev = (struct iucv_event *)arg;
struct iucv_connection *conn = ev->conn;
__u16 msglimit;
- int rc;
+ int rc, len;
__u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
pr_debug("%s() called\n", __FUNCTION__);
- memcpy(iucvMagic, conn->netdev->name, IFNAMSIZ);
+ len = (IFNAMSIZ < sizeof(conn->netdev->name)) ?
+ IFNAMSIZ : sizeof(conn->netdev->name);
+ memcpy(iucvMagic, conn->netdev->name, len);
+ ASCEBC (iucvMagic, len);
if (conn->handle == 0) {
conn->handle =
iucv_register_program(iucvMagic, conn->userid, mask,
dev_action_connup(fsm_instance *fi, int event, void *arg)
{
struct net_device *dev = (struct net_device *)arg;
+ struct netiucv_priv *privptr = dev->priv;
pr_debug("%s() called\n", __FUNCTION__);
case DEV_STATE_STARTWAIT:
fsm_newstate(fi, DEV_STATE_RUNNING);
printk(KERN_INFO
- "%s: connected with remote side\n",
- dev->name);
+ "%s: connected with remote side %s\n",
+ dev->name, privptr->conn->userid);
break;
case DEV_STATE_STOPWAIT:
printk(KERN_INFO
skb_pull(skb, NETIUCV_HDRLEN);
skb_trim(skb, skb->len - NETIUCV_HDRLEN);
}
- printk(KERN_DEBUG "iucv_send returned %08x\n",
+ printk(KERN_INFO "iucv_send returned %08x\n",
rc);
} else {
if (copied)
}
static int
-netiucv_register_device(struct net_device *ndev, int ifno)
+netiucv_register_device(struct net_device *ndev)
{
struct netiucv_priv *priv = ndev->priv;
struct device *dev = kmalloc(sizeof(struct device), GFP_KERNEL);
if (dev) {
memset(dev, 0, sizeof(struct device));
- snprintf(dev->bus_id, BUS_ID_SIZE, "netiucv%x", ifno);
+ snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name);
dev->bus = &iucv_bus;
dev->parent = iucv_root;
/*
* Allocate and initialize everything of a net device.
*/
static struct net_device *
-netiucv_init_netdevice(int ifno, char *username)
+netiucv_init_netdevice(char *username)
{
struct netiucv_priv *privptr;
struct net_device *dev;
- dev = alloc_netdev(sizeof(struct netiucv_priv), "",
+ dev = alloc_netdev(sizeof(struct netiucv_priv), "iucv%d",
netiucv_setup_netdevice);
if (!dev)
return NULL;
- sprintf(dev->name, "iucv%d", ifno);
privptr = (struct netiucv_priv *)dev->priv;
privptr->fsm = init_fsm("netiucvdev", dev_state_names,
while (i<9)
username[i++] = ' ';
username[9] = '\0';
- dev = netiucv_init_netdevice(ifno, username);
+ dev = netiucv_init_netdevice(username);
if (!dev) {
printk(KERN_WARNING
"netiucv: Could not allocate network device structure "
return -ENODEV;
}
- if ((ret = netiucv_register_device(dev, ifno)))
- goto out_free_ndev;
- /* sysfs magic */
- SET_NETDEV_DEV(dev, (struct device*)((struct netiucv_priv*)dev->priv)->dev);
if ((ret = register_netdev(dev))) {
- netiucv_unregister_device((struct device*)((struct netiucv_priv*)dev->priv)->dev);
goto out_free_ndev;
}
+
+ if ((ret = netiucv_register_device(dev))) {
+ unregister_netdev(dev);
+ goto out_free_ndev;
+ }
+
+ /* sysfs magic */
+ SET_NETDEV_DEV(dev, (struct device*)((struct netiucv_priv*)dev->priv)->dev);
printk(KERN_INFO "%s: '%s'\n", dev->name, netiucv_printname(username));
- ifno++;
return count;
DRIVER_ATTR(connection, 0200, NULL, conn_write);
+static ssize_t
+remove_write (struct device_driver *drv, const char *buf, size_t count)
+{
+ struct iucv_connection **clist = &connections;
+ struct net_device *ndev;
+ struct netiucv_priv *priv;
+ struct device *dev;
+ char name[IFNAMSIZ];
+ char *p;
+ int i;
+
+ pr_debug("%s() called\n", __FUNCTION__);
+
+ if (count >= IFNAMSIZ)
+ count = IFNAMSIZ-1;
+
+ for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
+ if ((*p == '\n') | (*p == ' ')) {
+ /* trailing lf, grr */
+ break;
+ } else {
+ name[i]=*p;
+ }
+ }
+ name[i] = '\0';
+
+ while (*clist) {
+ ndev = (*clist)->netdev;
+ priv = (struct netiucv_priv*)ndev->priv;
+ dev = priv->dev;
+
+ if (strncmp(name, ndev->name, count)) {
+ clist = &((*clist)->next);
+ continue;
+ }
+ if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
+ printk(KERN_WARNING
+ "netiucv: net device %s active with peer %s\n",
+ ndev->name, priv->conn->userid);
+ printk(KERN_WARNING
+ "netiucv: %s cannot be removed\n",
+ ndev->name);
+ return -EBUSY;
+ }
+ unregister_netdev(ndev);
+ netiucv_unregister_device(dev);
+ return count;
+ }
+ printk(KERN_WARNING
+ "netiucv: net device %s unknown\n", name);
+ return -EINVAL;
+}
+
+DRIVER_ATTR(remove, 0200, NULL, remove_write);
+
static struct device_driver netiucv_driver = {
.name = "netiucv",
.bus = &iucv_bus,
static void
netiucv_banner(void)
{
- char vbuf[] = "$Revision: 1.51 $";
+ char vbuf[] = "$Revision: 1.53 $";
char *version = vbuf;
if ((version = strchr(version, ':'))) {
}
driver_remove_file(&netiucv_driver, &driver_attr_connection);
+ driver_remove_file(&netiucv_driver, &driver_attr_remove);
driver_unregister(&netiucv_driver);
printk(KERN_INFO "NETIUCV driver unloaded\n");
/* Add entry for specifying connections. */
ret = driver_create_file(&netiucv_driver, &driver_attr_connection);
-
- if (ret == 0)
+ if (ret == 0) {
+ ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
netiucv_banner();
- else {
+ } else {
printk(KERN_ERR "NETIUCV: failed to add driver attribute.\n");
driver_unregister(&netiucv_driver);
}