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

📄 netiucv.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct net_device     *dev = conn->netdev;	struct netiucv_priv   *privptr = dev->priv;	__u16          offset = 0;	skb_put(pskb, NETIUCV_HDRLEN);	pskb->dev = dev;	pskb->ip_summed = CHECKSUM_NONE;	pskb->protocol = ntohs(ETH_P_IP);	while (1) {		struct sk_buff *skb;		ll_header *header = (ll_header *)pskb->data;		if (!header->next)			break;		skb_pull(pskb, NETIUCV_HDRLEN);		header->next -= offset;		offset += header->next;		header->next -= NETIUCV_HDRLEN;		if (skb_tailroom(pskb) < header->next) {			PRINT_WARN("%s: Illegal next field in iucv header: "			       "%d > %d\n",			       dev->name, header->next, skb_tailroom(pskb));			IUCV_DBF_TEXT_(data, 2, "Illegal next field: %d > %d\n",				header->next, skb_tailroom(pskb));			return;		}		skb_put(pskb, header->next);		pskb->mac.raw = pskb->data;		skb = dev_alloc_skb(pskb->len);		if (!skb) {			PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n",			       dev->name);			IUCV_DBF_TEXT(data, 2,				"Out of memory in netiucv_unpack_skb\n");			privptr->stats.rx_dropped++;			return;		}		memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);		skb->mac.raw = skb->data;		skb->dev = pskb->dev;		skb->protocol = pskb->protocol;		pskb->ip_summed = CHECKSUM_UNNECESSARY;		/*		 * Since receiving is always initiated from a tasklet (in iucv.c),		 * we must use netif_rx_ni() instead of netif_rx()		 */		netif_rx_ni(skb);		dev->last_rx = jiffies;		privptr->stats.rx_packets++;		privptr->stats.rx_bytes += skb->len;		skb_pull(pskb, header->next);		skb_put(pskb, NETIUCV_HDRLEN);	}}static voidconn_action_rx(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;	struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv;	__u32 msglen = eib->ln1msg2.ipbfln1f;	int rc;	IUCV_DBF_TEXT(trace, 4, __FUNCTION__);	if (!conn->netdev) {		/* FRITZ: How to tell iucv LL to drop the msg? */		PRINT_WARN("Received data for unlinked connection\n");		IUCV_DBF_TEXT(data, 2,			"Received data for unlinked connection\n");		return;	}	if (msglen > conn->max_buffsize) {		/* FRITZ: How to tell iucv LL to drop the msg? */		privptr->stats.rx_dropped++;		PRINT_WARN("msglen %d > max_buffsize %d\n",			msglen, conn->max_buffsize);		IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",			msglen, conn->max_buffsize);		return;	}	conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head;	conn->rx_buff->len = 0;	rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls,			  conn->rx_buff->data, msglen, NULL, NULL, NULL);	if (rc || msglen < 5) {		privptr->stats.rx_errors++;		PRINT_WARN("iucv_receive returned %08x\n", rc);		IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);		return;	}	netiucv_unpack_skb(conn, conn->rx_buff);}static voidconn_action_txdone(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data;	struct netiucv_priv *privptr = NULL;			         /* Shut up, gcc! skb is always below 2G. */	__u32 single_flag = eib->ipmsgtag;	__u32 txbytes = 0;	__u32 txpackets = 0;	__u32 stat_maxcq = 0;	struct sk_buff *skb;	unsigned long saveflags;	ll_header header;	IUCV_DBF_TEXT(trace, 4, __FUNCTION__);	if (conn && conn->netdev && conn->netdev->priv)		privptr = (struct netiucv_priv *)conn->netdev->priv;	conn->prof.tx_pending--;	if (single_flag) {		if ((skb = skb_dequeue(&conn->commit_queue))) {			atomic_dec(&skb->users);			dev_kfree_skb_any(skb);			if (privptr) {				privptr->stats.tx_packets++;				privptr->stats.tx_bytes +=					(skb->len - NETIUCV_HDRLEN					 	  - NETIUCV_HDRLEN);			}		}	}	conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head;	conn->tx_buff->len = 0;	spin_lock_irqsave(&conn->collect_lock, saveflags);	while ((skb = skb_dequeue(&conn->collect_queue))) {		header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN;		memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,		       NETIUCV_HDRLEN);		memcpy(skb_put(conn->tx_buff, skb->len), skb->data, skb->len);		txbytes += skb->len;		txpackets++;		stat_maxcq++;		atomic_dec(&skb->users);		dev_kfree_skb_any(skb);	}	if (conn->collect_len > conn->prof.maxmulti)		conn->prof.maxmulti = conn->collect_len;	conn->collect_len = 0;	spin_unlock_irqrestore(&conn->collect_lock, saveflags);	if (conn->tx_buff->len) {		int rc;		header.next = 0;		memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,		       NETIUCV_HDRLEN);		conn->prof.send_stamp = xtime;		rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0,			       conn->tx_buff->data, conn->tx_buff->len);		conn->prof.doios_multi++;		conn->prof.txlen += conn->tx_buff->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) {			conn->prof.tx_pending--;			fsm_newstate(fi, CONN_STATE_IDLE);			if (privptr)				privptr->stats.tx_errors += txpackets;			PRINT_WARN("iucv_send returned %08x\n",	rc);			IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);		} else {			if (privptr) {				privptr->stats.tx_packets += txpackets;				privptr->stats.tx_bytes += txbytes;			}			if (stat_maxcq > conn->prof.maxcqueue)				conn->prof.maxcqueue = stat_maxcq;		}	} else		fsm_newstate(fi, CONN_STATE_IDLE);}static voidconn_action_connaccept(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;	struct net_device *netdev = conn->netdev;	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;	int rc;	__u16 msglimit;	__u8 udata[16];	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0,			 conn->handle, conn, NULL, &msglimit);	if (rc) {		PRINT_WARN("%s: IUCV accept failed with error %d\n",		       netdev->name, rc);		IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc);		return;	}	fsm_newstate(fi, CONN_STATE_IDLE);	conn->pathid = eib->ippathid;	netdev->tx_queue_len = msglimit;	fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);}static voidconn_action_connreject(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	struct net_device *netdev = conn->netdev;	iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;	__u8 udata[16];	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	iucv_sever(eib->ippathid, udata);	if (eib->ippathid != conn->pathid) {		PRINT_INFO("%s: IR Connection Pending; "			"pathid %d does not match original pathid %d\n",			netdev->name, eib->ippathid, conn->pathid);		IUCV_DBF_TEXT_(data, 2,			"connreject: IR pathid %d, conn. pathid %d\n",			eib->ippathid, conn->pathid);		iucv_sever(conn->pathid, udata);	}}static voidconn_action_connack(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data;	struct net_device *netdev = conn->netdev;	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	fsm_deltimer(&conn->timer);	fsm_newstate(fi, CONN_STATE_IDLE);	if (eib->ippathid != conn->pathid) {		PRINT_INFO("%s: IR Connection Complete; "			"pathid %d does not match original pathid %d\n",			netdev->name, eib->ippathid, conn->pathid);		IUCV_DBF_TEXT_(data, 2,			"connack: IR pathid %d, conn. pathid %d\n",			eib->ippathid, conn->pathid);		conn->pathid = eib->ippathid;	}	netdev->tx_queue_len = eib->ipmsglim;	fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);}static voidconn_action_conntimsev(fsm_instance *fi, int event, void *arg){	struct iucv_connection *conn = (struct iucv_connection *)arg;	__u8 udata[16];	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	fsm_deltimer(&conn->timer);	iucv_sever(conn->pathid, udata);	fsm_newstate(fi, CONN_STATE_STARTWAIT);}static voidconn_action_connsever(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	struct net_device *netdev = conn->netdev;	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;	__u8 udata[16];	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	fsm_deltimer(&conn->timer);	iucv_sever(conn->pathid, udata);	PRINT_INFO("%s: Remote dropped connection\n", netdev->name);	IUCV_DBF_TEXT(data, 2,		"conn_action_connsever: Remote dropped connection\n");	fsm_newstate(fi, CONN_STATE_STARTWAIT);	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);}static voidconn_action_start(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	__u16 msglimit;	int rc;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	if (!conn->handle) {		IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n");		conn->handle =			iucv_register_program(iucvMagic, conn->userid,					      netiucv_mask,					      &netiucv_ops, conn);		fsm_newstate(fi, CONN_STATE_STARTWAIT);		if (!conn->handle) {			fsm_newstate(fi, CONN_STATE_REGERR);			conn->handle = NULL;			IUCV_DBF_TEXT(setup, 2,				"NULL from iucv_register_program\n");			return;		}		PRINT_DEBUG("%s('%s'): registered successfully\n",			 conn->netdev->name, conn->userid);	}	PRINT_DEBUG("%s('%s'): connecting ...\n",		 conn->netdev->name, conn->userid);	/* We must set the state before calling iucv_connect because the callback	 * handler could be called at any point after the connection request is	 * sent */	fsm_newstate(fi, CONN_STATE_SETUPWAIT);	rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,			  conn->userid, iucv_host, 0, NULL, &msglimit,			  conn->handle, conn);	switch (rc) {		case 0:			conn->netdev->tx_queue_len = msglimit;			fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,				CONN_EVENT_TIMER, conn);			return;		case 11:			PRINT_INFO("%s: User %s is currently not available.\n",			       conn->netdev->name,			       netiucv_printname(conn->userid));			fsm_newstate(fi, CONN_STATE_STARTWAIT);			return;		case 12:			PRINT_INFO("%s: User %s is currently not ready.\n",			       conn->netdev->name,			       netiucv_printname(conn->userid));			fsm_newstate(fi, CONN_STATE_STARTWAIT);			return;		case 13:			PRINT_WARN("%s: Too many IUCV connections.\n",			       conn->netdev->name);			fsm_newstate(fi, CONN_STATE_CONNERR);			break;		case 14:			PRINT_WARN(			       "%s: User %s has too many IUCV connections.\n",			       conn->netdev->name,			       netiucv_printname(conn->userid));			fsm_newstate(fi, CONN_STATE_CONNERR);			break;		case 15:			PRINT_WARN(			       "%s: No IUCV authorization in CP directory.\n",			       conn->netdev->name);			fsm_newstate(fi, CONN_STATE_CONNERR);			break;		default:			PRINT_WARN("%s: iucv_connect returned error %d\n",			       conn->netdev->name, rc);			fsm_newstate(fi, CONN_STATE_CONNERR);			break;	}	IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc);	IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");	iucv_unregister_program(conn->handle);	conn->handle = NULL;}static voidnetiucv_purge_skb_queue(struct sk_buff_head *q){	struct sk_buff *skb;	while ((skb = skb_dequeue(q))) {		atomic_dec(&skb->users);		dev_kfree_skb_any(skb);	}}static voidconn_action_stop(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	struct net_device *netdev = conn->netdev;	struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	fsm_deltimer(&conn->timer);	fsm_newstate(fi, CONN_STATE_STOPPED);	netiucv_purge_skb_queue(&conn->collect_queue);	if (conn->handle)		IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");		iucv_unregister_program(conn->handle);	conn->handle = NULL;	netiucv_purge_skb_queue(&conn->commit_queue);	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);}static voidconn_action_inval(fsm_instance *fi, int event, void *arg){	struct iucv_event *ev = (struct iucv_event *)arg;	struct iucv_connection *conn = ev->conn;	struct net_device *netdev = conn->netdev;	PRINT_WARN("%s: Cannot connect without username\n",	       netdev->name);	IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");}static const fsm_node conn_fsm[] = {	{ CONN_STATE_INVALID,   CONN_EVENT_START,    conn_action_inval      },	{ CONN_STATE_STOPPED,   CONN_EVENT_START,    conn_action_start      },	{ CONN_STATE_STOPPED,   CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_STARTWAIT, CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_SETUPWAIT, CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_IDLE,      CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_TX,        CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_REGERR,    CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_CONNERR,   CONN_EVENT_STOP,     conn_action_stop       },	{ CONN_STATE_STOPPED,   CONN_EVENT_CONN_REQ, conn_action_connreject },        { CONN_STATE_STARTWAIT, CONN_EVENT_CONN_REQ, conn_action_connaccept },	{ CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REQ, conn_action_connaccept },	{ CONN_STATE_IDLE,      CONN_EVENT_CONN_REQ, conn_action_connreject },	{ CONN_STATE_TX,        CONN_EVENT_CONN_REQ, conn_action_connreject },	{ CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_ACK, conn_action_connack    },	{ CONN_STATE_SETUPWAIT, CONN_EVENT_TIMER,    conn_action_conntimsev },	{ CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REJ, conn_action_connsever  },	{ CONN_STATE_IDLE,      CONN_EVENT_CONN_REJ, conn_action_connsever  },	{ CONN_STATE_TX,        CONN_EVENT_CONN_REJ, conn_action_connsever  },	{ CONN_STATE_IDLE,      CONN_EVENT_RX,       conn_action_rx         },	{ CONN_STATE_TX,        CONN_EVENT_RX,       conn_action_rx         },	{ CONN_STATE_TX,        CONN_EVENT_TXDONE,   conn_action_txdone     },	{ CONN_STATE_IDLE,      CONN_EVENT_TXDONE,   conn_action_txdone     },};static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);/** * Actions for interface - statemachine. *****************************************************************************//** * Startup connection by sending CONN_EVENT_START to it. * * @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_start(fsm_instance *fi, int event, void *arg){	struct net_device   *dev = (struct net_device *)arg;	struct netiucv_priv *privptr = dev->priv;	struct iucv_event   ev;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	ev.conn = privptr->conn;	fsm_newstate(fi, DEV_STATE_STARTWAIT);	fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);}/** * Shutdown connection by sending CONN_EVENT_STOP to it. * * @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_stop(fsm_instance *fi, int event, void *arg){	struct net_device   *dev = (struct net_device *)arg;	struct netiucv_priv *privptr = dev->priv;	struct iucv_event   ev;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	ev.conn = privptr->conn;	fsm_newstate(fi, DEV_STATE_STOPWAIT);	fsm_event(privptr->conn->fsm, CONN_EVENT_STOP, &ev);}/** * Called from connection statemachine * when a connection is up and running. * * @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_connup(fsm_instance *fi, int event, void *arg){	struct net_device   *dev = (struct net_device *)arg;	struct netiucv_priv *privptr = dev->priv;	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);	switch (fsm_getstate(fi)) {		case DEV_STATE_STARTWAIT:			fsm_newstate(fi, DEV_STATE_RUNNING);			PRINT_INFO("%s: connected with remote side %s\n",			       dev->name, privptr->conn->userid);			IUCV_DBF_TEXT(setup, 3,				"connection is up and running\n");			break;		case DEV_STATE_STOPWAIT:			PRINT_INFO(			       "%s: got connection UP event during shutdown!\n",			       dev->name);			IUCV_DBF_TEXT(data, 2,				"dev_action_connup: in DEV_STATE_STOPWAIT\n");

⌨️ 快捷键说明

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