⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netiucv.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
static ssize_ttxtime_show (struct device *dev, struct device_attribute *attr, char *buf){	struct netiucv_priv *priv = dev->driver_data;	IUCV_DBF_TEXT(trace, 5, __FUNCTION__);	return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);}static ssize_ttxtime_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;}static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);static ssize_ttxpend_show (struct device *dev, struct device_attribute *attr, char *buf){	struct netiucv_priv *priv = dev->driver_data;	IUCV_DBF_TEXT(trace, 5, __FUNCTION__);	return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);}static ssize_ttxpend_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_pending = 0;	return count;}static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);static ssize_ttxmpnd_show (struct device *dev, struct device_attribute *attr, char *buf){	struct netiucv_priv *priv = dev->driver_data;	IUCV_DBF_TEXT(trace, 5, __FUNCTION__);	return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);}static ssize_ttxmpnd_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_max_pending = 0;	return count;}static DEVICE_ATTR(tx_max_pending, 0644, txmpnd_show, txmpnd_write);static struct attribute *netiucv_attrs[] = {	&dev_attr_buffer.attr,	&dev_attr_user.attr,	NULL,};static struct attribute_group netiucv_attr_group = {	.attrs = netiucv_attrs,};static struct attribute *netiucv_stat_attrs[] = {	&dev_attr_device_fsm_state.attr,	&dev_attr_connection_fsm_state.attr,	&dev_attr_max_tx_buffer_used.attr,	&dev_attr_max_chained_skbs.attr,	&dev_attr_tx_single_write_ops.attr,	&dev_attr_tx_multi_write_ops.attr,	&dev_attr_netto_bytes.attr,	&dev_attr_max_tx_io_time.attr,	&dev_attr_tx_pending.attr,	&dev_attr_tx_max_pending.attr,	NULL,};static struct attribute_group netiucv_stat_attr_group = {	.name  = "stats",	.attrs = netiucv_stat_attrs,};static inline intnetiucv_add_files(struct device *dev){	int ret;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	ret = sysfs_create_group(&dev->kobj, &netiucv_attr_group);	if (ret)		return ret;	ret = sysfs_create_group(&dev->kobj, &netiucv_stat_attr_group);	if (ret)		sysfs_remove_group(&dev->kobj, &netiucv_attr_group);	return ret;}static inline voidnetiucv_remove_files(struct device *dev){	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);	sysfs_remove_group(&dev->kobj, &netiucv_attr_group);}static intnetiucv_register_device(struct net_device *ndev){	struct netiucv_priv *priv = ndev->priv;	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;		/*		 * The release function could be called after the		 * module has been unloaded. It's _only_ task is to		 * free the struct. Therefore, we specify kfree()		 * directly here. (Probably a little bit obfuscating		 * but legitime ...).		 */		dev->release = (void (*)(struct device *))kfree;		dev->driver = &netiucv_driver;	} else		return -ENOMEM;	ret = device_register(dev);	if (ret)		return ret;	ret = netiucv_add_files(dev);	if (ret)		goto out_unreg;	priv->dev = dev;	dev->driver_data = priv;	return 0;out_unreg:	device_unregister(dev);	return ret;}static voidnetiucv_unregister_device(struct device *dev){	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	netiucv_remove_files(dev);	device_unregister(dev);}/** * Allocate and initialize a new connection structure. * Add it to the list of netiucv connections; */static struct iucv_connection *netiucv_new_connection(struct net_device *dev, char *username){	struct iucv_connection **clist = &iucv_connections;	struct iucv_connection *conn =		(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);		conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;		conn->netdev = dev;		conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,					  GFP_KERNEL | GFP_DMA);		if (!conn->rx_buff) {			kfree(conn);			return NULL;		}		conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,					  GFP_KERNEL | GFP_DMA);		if (!conn->tx_buff) {			kfree_skb(conn->rx_buff);			kfree(conn);			return NULL;		}		conn->fsm = init_fsm("netiucvconn", conn_state_names,				     conn_event_names, NR_CONN_STATES,				     NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,				     GFP_KERNEL);		if (!conn->fsm) {			kfree_skb(conn->tx_buff);			kfree_skb(conn->rx_buff);			kfree(conn);			return NULL;		}		fsm_settimer(conn->fsm, &conn->timer);		fsm_newstate(conn->fsm, CONN_STATE_INVALID);		if (username) {			memcpy(conn->userid, username, 9);			fsm_newstate(conn->fsm, CONN_STATE_STOPPED);		}		conn->next = *clist;		*clist = conn;	}	return conn;}/** * Release a connection structure and remove it from the * list of netiucv connections. */static voidnetiucv_remove_connection(struct iucv_connection *conn){	struct iucv_connection **clist = &iucv_connections;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if (conn == NULL)		return;	while (*clist) {		if (*clist == conn) {			*clist = conn->next;			if (conn->handle) {				iucv_unregister_program(conn->handle);				conn->handle = NULL;			}			fsm_deltimer(&conn->timer);			kfree_fsm(conn->fsm);			kfree_skb(conn->rx_buff);			kfree_skb(conn->tx_buff);			return;		}		clist = &((*clist)->next);	}}/** * Release everything of a net device. */static voidnetiucv_free_netdevice(struct net_device *dev){	struct netiucv_priv *privptr;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if (!dev)		return;	privptr = (struct netiucv_priv *)dev->priv;	if (privptr) {		if (privptr->conn)			netiucv_remove_connection(privptr->conn);		if (privptr->fsm)			kfree_fsm(privptr->fsm);		privptr->conn = NULL; privptr->fsm = NULL;		/* privptr gets freed by free_netdev() */	}	free_netdev(dev);}/** * Initialize a net device. (Called from kernel in alloc_netdev()) */static voidnetiucv_setup_netdevice(struct net_device *dev){        memset(dev->priv, 0, sizeof(struct netiucv_priv));	dev->mtu	         = NETIUCV_MTU_DEFAULT;	dev->hard_start_xmit     = netiucv_tx;	dev->open	         = netiucv_open;	dev->stop	         = netiucv_close;	dev->get_stats	         = netiucv_stats;	dev->change_mtu          = netiucv_change_mtu;	dev->destructor          = netiucv_free_netdevice;	dev->hard_header_len     = NETIUCV_HDRLEN;	dev->addr_len            = 0;	dev->type                = ARPHRD_SLIP;	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;	SET_MODULE_OWNER(dev);}/** * Allocate and initialize everything of a net device. */static struct net_device *netiucv_init_netdevice(char *username){	struct netiucv_priv *privptr;	struct net_device *dev;	dev = alloc_netdev(sizeof(struct netiucv_priv), "iucv%d",			   netiucv_setup_netdevice);	if (!dev)		return NULL;	if (dev_alloc_name(dev, dev->name) < 0) {		free_netdev(dev);		return NULL;	}	privptr = (struct netiucv_priv *)dev->priv;	privptr->fsm = init_fsm("netiucvdev", dev_state_names,				dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,				dev_fsm, DEV_FSM_LEN, GFP_KERNEL);	if (!privptr->fsm) {		free_netdev(dev);		return NULL;	}	privptr->conn = netiucv_new_connection(dev, username);	if (!privptr->conn) {		kfree_fsm(privptr->fsm);		free_netdev(dev);		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");		return NULL;	}	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);	return dev;}static ssize_tconn_write(struct device_driver *drv, const char *buf, size_t count){	char *p;	char username[10];	int i, ret;	struct net_device *dev;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if (count>9) {		PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);		IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n");		return -EINVAL;	}	for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {		if (isalnum(*p) || (*p == '$'))			username[i]= *p;		else if (*p == '\n') {			/* trailing lf, grr */			break;		} else {			PRINT_WARN("netiucv: Invalid character in username!\n");			IUCV_DBF_TEXT_(setup, 2,				"conn_write: invalid character %c\n", *p);			return -EINVAL;		}	}	while (i<9)		username[i++] = ' ';	username[9] = '\0';	dev = netiucv_init_netdevice(username);	if (!dev) {		PRINT_WARN(		       "netiucv: Could not allocate network device structure "		       "for user '%s'\n", netiucv_printname(username));		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");		return -ENODEV;	}	if ((ret = netiucv_register_device(dev))) {		IUCV_DBF_TEXT_(setup, 2,			"ret %d from netiucv_register_device\n", ret);		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;	}	PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));		return count;out_free_ndev:	PRINT_WARN("netiucv: Could not register '%s'\n", dev->name);	IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n");	netiucv_free_netdevice(dev);	return ret;}DRIVER_ATTR(connection, 0200, NULL, conn_write);static ssize_tremove_write (struct device_driver *drv, const char *buf, size_t count){	struct iucv_connection **clist = &iucv_connections;        struct net_device *ndev;        struct netiucv_priv *priv;        struct device *dev;        char name[IFNAMSIZ];        char *p;        int i;        IUCV_DBF_TEXT(trace, 3, __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)) {                        PRINT_WARN(                                "netiucv: net device %s active with peer %s\n",                                ndev->name, priv->conn->userid);                        PRINT_WARN("netiucv: %s cannot be removed\n",                                ndev->name);			IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");                        return -EBUSY;                }                unregister_netdev(ndev);                netiucv_unregister_device(dev);                return count;        }        PRINT_WARN("netiucv: net device %s unknown\n", name);	IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");        return -EINVAL;}DRIVER_ATTR(remove, 0200, NULL, remove_write);static voidnetiucv_banner(void){	char vbuf[] = "$Revision: 1.66 $";	char *version = vbuf;	if ((version = strchr(version, ':'))) {		char *p = strchr(version + 1, '$');		if (p)			*p = '\0';	} else		version = " ??? ";	PRINT_INFO("NETIUCV driver Version%s initialized\n", version);}static void __exitnetiucv_exit(void){	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	while (iucv_connections) {		struct net_device *ndev = iucv_connections->netdev;		struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;		struct device *dev = priv->dev;		unregister_netdev(ndev);		netiucv_unregister_device(dev);	}	driver_remove_file(&netiucv_driver, &driver_attr_connection);	driver_remove_file(&netiucv_driver, &driver_attr_remove);	driver_unregister(&netiucv_driver);	iucv_unregister_dbf_views();	PRINT_INFO("NETIUCV driver unloaded\n");	return;}static int __initnetiucv_init(void){	int ret;		ret = iucv_register_dbf_views();	if (ret) {		PRINT_WARN("netiucv_init failed, "			"iucv_register_dbf_views rc = %d\n", ret);		return ret;	}	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	ret = driver_register(&netiucv_driver);	if (ret) {		PRINT_ERR("NETIUCV: failed to register driver.\n");		IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret);		iucv_unregister_dbf_views();		return ret;	}	/* Add entry for specifying connections. */	ret = driver_create_file(&netiucv_driver, &driver_attr_connection);	if (!ret) {		ret = driver_create_file(&netiucv_driver, &driver_attr_remove);		netiucv_banner();	} else {		PRINT_ERR("NETIUCV: failed to add driver attribute.\n");		IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);		driver_unregister(&netiucv_driver);		iucv_unregister_dbf_views();	}	return ret;}	module_init(netiucv_init);module_exit(netiucv_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -