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

📄 netiucv.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
			break;	}}/** * Called from connection statemachine * when a connection has been shutdown. * * @param fi    An instance of an interface statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from struct net_device * upon call. */static voiddev_action_conndown(fsm_instance *fi, int event, void *arg){	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	switch (fsm_getstate(fi)) {		case DEV_STATE_RUNNING:			fsm_newstate(fi, DEV_STATE_STARTWAIT);			break;		case DEV_STATE_STOPWAIT:			fsm_newstate(fi, DEV_STATE_STOPPED);			IUCV_DBF_TEXT(setup, 3, "connection is down\n");			break;	}}static const fsm_node dev_fsm[] = {	{ DEV_STATE_STOPPED,    DEV_EVENT_START,   dev_action_start    },	{ DEV_STATE_STOPWAIT,   DEV_EVENT_START,   dev_action_start    },	{ DEV_STATE_STOPWAIT,   DEV_EVENT_CONDOWN, dev_action_conndown },	{ DEV_STATE_STARTWAIT,  DEV_EVENT_STOP,    dev_action_stop     },	{ DEV_STATE_STARTWAIT,  DEV_EVENT_CONUP,   dev_action_connup   },	{ DEV_STATE_RUNNING,    DEV_EVENT_STOP,    dev_action_stop     },	{ DEV_STATE_RUNNING,    DEV_EVENT_CONDOWN, dev_action_conndown },	{ DEV_STATE_RUNNING,    DEV_EVENT_CONUP,   fsm_action_nop      },};static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);/** * Transmit a packet. * This is a helper function for netiucv_tx(). * * @param conn Connection to be used for sending. * @param skb Pointer to struct sk_buff of packet to send. *            The linklevel header has already been set up *            by netiucv_tx(). * * @return 0 on success, -ERRNO on failure. (Never fails.) */static intnetiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {	unsigned long saveflags;	ll_header header;	int       rc = 0;	if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) {		int l = skb->len + NETIUCV_HDRLEN;		spin_lock_irqsave(&conn->collect_lock, saveflags);		if (conn->collect_len + l >		    (conn->max_buffsize - NETIUCV_HDRLEN)) {			rc = -EBUSY;			IUCV_DBF_TEXT(data, 2,				"EBUSY from netiucv_transmit_skb\n");		} else {			atomic_inc(&skb->users);			skb_queue_tail(&conn->collect_queue, skb);			conn->collect_len += l;		}		spin_unlock_irqrestore(&conn->collect_lock, saveflags);	} else {		struct sk_buff *nskb = skb;		/**		 * Copy the skb to a new allocated skb in lowmem only if the		 * data is located above 2G in memory or tailroom is < 2.		 */		unsigned long hi =			((unsigned long)(skb->tail + NETIUCV_HDRLEN)) >> 31;		int copied = 0;		if (hi || (skb_tailroom(skb) < 2)) {			nskb = alloc_skb(skb->len + NETIUCV_HDRLEN +					 NETIUCV_HDRLEN, GFP_ATOMIC | GFP_DMA);			if (!nskb) {				PRINT_WARN("%s: Could not allocate tx_skb\n",				       conn->netdev->name);				IUCV_DBF_TEXT(data, 2, "alloc_skb failed\n");				rc = -ENOMEM;				return rc;			} else {				skb_reserve(nskb, NETIUCV_HDRLEN);				memcpy(skb_put(nskb, skb->len),				       skb->data, skb->len);			}			copied = 1;		}		/**		 * skb now is below 2G and has enough room. Add headers.		 */		header.next = nskb->len + NETIUCV_HDRLEN;		memcpy(skb_push(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);		header.next = 0;		memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header,  NETIUCV_HDRLEN);		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. */		conn->prof.doios_single++;		conn->prof.txlen += skb->len;		conn->prof.tx_pending++;		if (conn->prof.tx_pending > conn->prof.tx_max_pending)			conn->prof.tx_max_pending = conn->prof.tx_pending;		if (rc) {			struct netiucv_priv *privptr;			fsm_newstate(conn->fsm, CONN_STATE_IDLE);			conn->prof.tx_pending--;			privptr = (struct netiucv_priv *)conn->netdev->priv;			if (privptr)				privptr->stats.tx_errors++;			if (copied)				dev_kfree_skb(nskb);			else {				/**				 * Remove our headers. They get added				 * again on retransmit.				 */				skb_pull(skb, NETIUCV_HDRLEN);				skb_trim(skb, skb->len - NETIUCV_HDRLEN);			}			PRINT_WARN("iucv_send returned %08x\n",	rc);			IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);		} else {			if (copied)				dev_kfree_skb(skb);			atomic_inc(&nskb->users);			skb_queue_tail(&conn->commit_queue, nskb);		}	}	return rc;}/** * Interface API for upper network layers *****************************************************************************//** * Open an interface. * Called from generic network layer when ifconfig up is run. * * @param dev Pointer to interface struct. * * @return 0 on success, -ERRNO on failure. (Never fails.) */static intnetiucv_open(struct net_device *dev) {	fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev);	return 0;}/** * Close an interface. * Called from generic network layer when ifconfig down is run. * * @param dev Pointer to interface struct. * * @return 0 on success, -ERRNO on failure. (Never fails.) */static intnetiucv_close(struct net_device *dev) {	fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);	return 0;}/** * Start transmission of a packet. * Called from generic network device layer. * * @param skb Pointer to buffer containing the packet. * @param dev Pointer to interface struct. * * @return 0 if packet consumed, !0 if packet rejected. *         Note: If we return !0, then the packet is free'd by *               the generic network layer. */static int netiucv_tx(struct sk_buff *skb, struct net_device *dev){	int          rc = 0;	struct netiucv_priv *privptr = dev->priv;	IUCV_DBF_TEXT(trace, 4, __FUNCTION__);	/**	 * Some sanity checks ...	 */	if (skb == NULL) {		PRINT_WARN("%s: NULL sk_buff passed\n", dev->name);		IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n");		privptr->stats.tx_dropped++;		return 0;	}	if (skb_headroom(skb) < NETIUCV_HDRLEN) {		PRINT_WARN("%s: Got sk_buff with head room < %ld bytes\n",		       dev->name, NETIUCV_HDRLEN);		IUCV_DBF_TEXT(data, 2,			"netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n");		dev_kfree_skb(skb);		privptr->stats.tx_dropped++;		return 0;	}	/**	 * If connection is not running, try to restart it	 * and throw away packet. 	 */	if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {		fsm_event(privptr->fsm, DEV_EVENT_START, dev);		dev_kfree_skb(skb);		privptr->stats.tx_dropped++;		privptr->stats.tx_errors++;		privptr->stats.tx_carrier_errors++;		return 0;	}	if (netiucv_test_and_set_busy(dev)) {		IUCV_DBF_TEXT(data, 2, "EBUSY from netiucv_tx\n");		return -EBUSY;	}	dev->trans_start = jiffies;	if (netiucv_transmit_skb(privptr->conn, skb))		rc = 1;	netiucv_clear_busy(dev);	return rc;}/** * Returns interface statistics of a device. * * @param dev Pointer to interface struct. * * @return Pointer to stats struct of this interface. */static struct net_device_stats *netiucv_stats (struct net_device * dev){	IUCV_DBF_TEXT(trace, 5, __FUNCTION__);	return &((struct netiucv_priv *)dev->priv)->stats;}/** * Sets MTU of an interface. * * @param dev     Pointer to interface struct. * @param new_mtu The new MTU to use for this interface. * * @return 0 on success, -EINVAL if MTU is out of valid range. *         (valid range is 576 .. NETIUCV_MTU_MAX). */static intnetiucv_change_mtu (struct net_device * dev, int new_mtu){	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) {		IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n");		return -EINVAL;	}	dev->mtu = new_mtu;	return 0;}/** * attributes in sysfs *****************************************************************************/static ssize_tuser_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, "%s\n", netiucv_printname(priv->conn->userid));}static ssize_tuser_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct netiucv_priv *priv = dev->driver_data;	struct net_device *ndev = priv->conn->netdev;	char    *p;	char    *tmp;	char 	username[10];	int 	i;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if (count>9) {		PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);		IUCV_DBF_TEXT_(setup, 2,			"%d is length of username\n", (int)count);		return -EINVAL;	}	tmp = strsep((char **) &buf, "\n");	for (i=0, p=tmp; 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 char %c in username!\n",				*p);			IUCV_DBF_TEXT_(setup, 2,				"username: invalid character %c\n",				*p);			return -EINVAL;		}	}	while (i<9)		username[i++] = ' ';	username[9] = '\0';	if (memcmp(username, priv->conn->userid, 8)) {		/* username changed */		if (ndev->flags & (IFF_UP | IFF_RUNNING)) {			PRINT_WARN(				"netiucv: device %s active, connected to %s\n",				dev->bus_id, priv->conn->userid);			PRINT_WARN("netiucv: user cannot be updated\n");			IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");			return -EBUSY;		}	}	memcpy(priv->conn->userid, username, 9);	return count;}static DEVICE_ATTR(user, 0644, user_show, user_write);static ssize_tbuffer_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, "%d\n", priv->conn->max_buffsize);}static ssize_tbuffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct netiucv_priv *priv = dev->driver_data;	struct net_device *ndev = priv->conn->netdev;	char         *e;	int          bs1;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if (count >= 39)		return -EINVAL;	bs1 = simple_strtoul(buf, &e, 0);	if (e && (!isspace(*e))) {		PRINT_WARN("netiucv: Invalid character in buffer!\n");		IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e);		return -EINVAL;	}	if (bs1 > NETIUCV_BUFSIZE_MAX) {		PRINT_WARN("netiucv: Given buffer size %d too large.\n",			bs1);		IUCV_DBF_TEXT_(setup, 2,			"buffer_write: buffer size %d too large\n",			bs1);		return -EINVAL;	}	if ((ndev->flags & IFF_RUNNING) &&	    (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2))) {		PRINT_WARN("netiucv: Given buffer size %d too small.\n",			bs1);		IUCV_DBF_TEXT_(setup, 2,			"buffer_write: buffer size %d too small\n",			bs1);		return -EINVAL;	}	if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN)) {		PRINT_WARN("netiucv: Given buffer size %d too small.\n",			bs1);		IUCV_DBF_TEXT_(setup, 2,			"buffer_write: buffer size %d too small\n",			bs1);		return -EINVAL;	}	priv->conn->max_buffsize = bs1;	if (!(ndev->flags & IFF_RUNNING))		ndev->mtu = bs1 - NETIUCV_HDRLEN - NETIUCV_HDRLEN;	return count;}static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);static ssize_tdev_fsm_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, "%s\n", fsm_getstate_str(priv->fsm));}static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);static ssize_tconn_fsm_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, "%s\n", fsm_getstate_str(priv->conn->fsm));}static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);static ssize_tmaxmulti_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.maxmulti);}static ssize_tmaxmulti_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.maxmulti = 0;	return count;}static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);static ssize_tmaxcq_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.maxcqueue);}static ssize_tmaxcq_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;}static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);static ssize_tsdoio_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.doios_single);}static ssize_tsdoio_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;}static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);static ssize_tmdoio_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.doios_multi);}static ssize_tmdoio_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;}static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);static ssize_ttxlen_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.txlen);}static ssize_ttxlen_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;}static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);

⌨️ 快捷键说明

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