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

📄 af_spx.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 2 页
字号:
	switch(type)	{		case (DATA):	/* Data */			ipxh->ipx.ipx_pktsize 	= htons(SPX_SYS_PKT_LEN + len);			ipxh->spx.cctl 		= (CCTL_ACK | CCTL_EOM);                	pdata->sequence++;			break;		case (ACK):	/* ACK */			pdata->rmt_seq++;		case (WDACK):	/* WD ACK */		case (CONACK):	/* Connection ACK */			ipxh->spx.cctl 		= CCTL_SYS;			ipxh->spx.ackseq 	= htons(pdata->rmt_seq);			break;		case (CONREQ):	/* Connection Request */			del_timer(&pdata->watchdog);		case (WDREQ):	/* WD Request */			pdata->source_connid    = htons(connids++);                	pdata->dest_connid      = 0xFFFF;                	pdata->alloc 		= 3 + pdata->rmt_seq;			ipxh->spx.cctl          = (CCTL_ACK | CCTL_SYS);			ipxh->spx.sconn         = pdata->source_connid;		        ipxh->spx.dconn         = pdata->dest_connid;		        ipxh->spx.allocseq      = htons(pdata->alloc);			break;		case (DISCON):	/* Informed Disconnect */			ipxh->spx.cctl 		= CCTL_ACK;			ipxh->spx.dtype 	= SPX_DTYPE_ECONN;			break;		case (DISACK):	/* Informed Disconnect ACK */			ipxh->spx.cctl  	= 0;			ipxh->spx.dtype 	= SPX_DTYPE_ECACK;			ipxh->spx.sequence 	= 0;			ipxh->spx.ackseq 	= htons(pdata->rmt_seq++);			break;		default:			return (-EOPNOTSUPP);	}	/* Send data */        return (spx_route_skb(pdata, skb, type));}/* Check the state of the connection and send a WD request if needed. */static void spx_watchdog(unsigned long data){	struct sock *sk = (struct sock*)data;        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;        del_timer(&pdata->watchdog);	if(pdata->state == SPX_CLOSED)                return;	if(pdata->retries > pdata->max_retries)        {		spx_close_socket(sk);	/* Unilateral Abort */                return;        }        /* Send WD request */	spx_transmit(sk, NULL, WDREQ, 0);	pdata->retries++;        return;}static void spx_retransmit(unsigned long data){	struct sock *sk = (struct sock*)data;        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;	struct sk_buff *skb;	unsigned long flags;	int err;	del_timer(&pdata->retransmit);	if(pdata->state == SPX_CLOSED)		return;	if(pdata->retransmits > RETRY_COUNT)	{		spx_close_socket(sk);   /* Unilateral Abort */                return;        }	/* Need to leave skb on the queue, aye the fear */	save_flags(flags);	cli();	skb = skb_peek(&pdata->retransmit_queue);	if(skb_cloned(skb))                skb = skb_copy(skb, GFP_ATOMIC);        else                skb = skb_clone(skb, GFP_ATOMIC);	restore_flags(flags);	pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);	add_timer(&pdata->retransmit);	err = spx_route_skb(pdata, skb, RETRAN);	pdata->retransmits++;	return;}/* Check packet for retransmission, ConReqAck aware */static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type){	struct ipxspxhdr *ipxh;	struct sk_buff *skb;	skb = skb_dequeue(&pdata->retransmit_queue);	if(!skb)		return (-ENOENT);	/* Check Data/ACK seq */	switch(type)	{		case ACK:	/* Check Sequence, Should == 1 */			ipxh = (struct ipxspxhdr *)skb->nh.raw;			if(!(ntohs(ipxh->spx.sequence) - htons(ackseq)))				break;		case CONACK:			del_timer(&pdata->retransmit);			pdata->retransmits = 0;			kfree_skb(skb);			if(skb_queue_empty(&pdata->retransmit_queue))			{				skb = skb_dequeue(&pdata->transmit_queue);				if(skb != NULL)					spx_route_skb(pdata, skb, TQUEUE);			}			return (0);	}	skb_queue_head(&pdata->retransmit_queue, skb);	return (-1);}/* SPX packet receive engine */void spx_rcv(struct sock *sk, int bytes){	struct sk_buff *skb;	struct ipxspxhdr *ipxh;	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;	skb = skb_dequeue(&sk->receive_queue);	if(skb == NULL)		return;	ipxh = (struct ipxspxhdr *)skb->nh.raw;	/* Can't receive on a closed connection */        if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0))		goto toss_skb;	if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN)		goto toss_skb;        if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)		goto toss_skb;        if(ntohs(ipxh->spx.ackseq) > pdata->sequence)		goto toss_skb;	/* Reset WD timer on any received packet */	del_timer(&pdata->watchdog);	pdata->retries = 0;	pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;        add_timer(&pdata->watchdog);	switch(ipxh->spx.cctl)	{		case (CCTL_SYS | CCTL_ACK):			if((ipxh->spx.sequence == 0)	/* ConReq */				&& (ipxh->spx.ackseq == 0)				&& (ipxh->spx.dconn == 0xFFFF))			{				pdata->state		= SPX_CONNECTED;				pdata->dest_addr        = ipxh->ipx.ipx_source;				pdata->source_addr      = ipxh->ipx.ipx_dest;				pdata->dest_connid      = ipxh->spx.sconn;				pdata->alloc = 3 + ntohs(ipxh->spx.sequence);				skb_queue_tail(&sk->receive_queue, skb);				wake_up_interruptible(sk->sleep);			}			else	/* WD Request */				spx_transmit(sk, skb, WDACK, 0);			goto finish;		case CCTL_SYS:	/* ACK */			if((ipxh->spx.dtype == 0)       /* ConReq ACK */                                && (ipxh->spx.sconn != 0xFFFF)                                && (ipxh->spx.dconn != 0xFFFF)                                && (ipxh->spx.sequence == 0)                                && (ipxh->spx.ackseq == 0)                                && (pdata->state != SPX_CONNECTED))                        {                                pdata->state = SPX_CONNECTED;				pdata->dest_connid = ipxh->spx.sconn;				if(spx_retransmit_chk(pdata, 0, CONACK) < 0)					goto toss_skb;                                skb_queue_tail(&sk->receive_queue, skb);                                wake_up_interruptible(sk->sleep);                                goto finish;                        }			spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);			goto toss_skb;		case (CCTL_ACK):			/* Informed Disconnect */			if(ipxh->spx.dtype == SPX_DTYPE_ECONN)			{								spx_transmit(sk, skb, DISACK, 0);				spx_close_socket(sk);				goto finish;			}			/* Fall through */		default:			if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)			{				pdata->rmt_seq = ntohs(ipxh->spx.sequence);				pdata->rmt_ack = ntohs(ipxh->spx.ackseq);				pdata->alloc   = pdata->rmt_seq + 3;				if(pdata->rmt_ack > 0 || pdata->rmt_ack == 0)					spx_retransmit_chk(pdata,pdata->rmt_ack, ACK);				skb_queue_tail(&pdata->rcv_queue, skb);				wake_up_interruptible(sk->sleep);				if(ipxh->spx.cctl&CCTL_ACK)					spx_transmit(sk, NULL, ACK, 0);				goto finish;			}			if(ipxh->spx.dtype == SPX_DTYPE_ECACK)			{				if(pdata->state != SPX_CLOSED)					spx_close_socket(sk);				goto toss_skb;			}	}toss_skb:	/* Catch All */	kfree_skb(skb);finish:        return;}/* Get message/packet data from user-land */static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,			struct scm_cookie *scm){	struct sock *sk = sock->sk;	int flags = msg->msg_flags;	struct sk_buff *skb;	int err, offset, size;	if(len > 534)                return (-EMSGSIZE);        if(sk->zapped)                return (-ENOTCONN); /* Socket not bound */	if(flags&~MSG_DONTWAIT)                return (-EINVAL);	offset	= ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);        size 	= offset + sizeof(struct ipxspxhdr) + len;	cli();        skb  	= sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err);	sti();        if(skb == NULL)                return (err);	skb->sk = sk;        skb_reserve(skb, offset);	skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));	err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);	if(err)        {                kfree_skb(skb);                return (-EFAULT);        }	err = spx_transmit(sk, skb, DATA, len);	if(err)		return (-EAGAIN);        return (len);}/* Send message/packet data to user-land */static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,			int flags, struct scm_cookie *scm){	struct sk_buff *skb;	struct ipxspxhdr *ispxh;	struct sock *sk = sock->sk;	struct spx_opt *pdata = &sk->tp_pinfo.af_spx;	struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;	int copied, err;        if(sk->zapped)                return (-ENOTCONN); /* Socket not bound */	lock_sock(sk);restart:        while(skb_queue_empty(&pdata->rcv_queue))      /* No data */        {                /* Socket errors? */                err = sock_error(sk);                if(err)			return (err);                /* Socket shut down? */                if(sk->shutdown & RCV_SHUTDOWN)			return (-ESHUTDOWN);                /* handle signals */                if(signal_pending(current))			return (-ERESTARTSYS);                /* User doesn't want to wait */                if(flags&MSG_DONTWAIT)			return (-EAGAIN);		release_sock(sk);        	save_flags(flags);        	cli();        	if(skb_peek(&pdata->rcv_queue) == NULL)                	interruptible_sleep_on(sk->sleep);        	restore_flags(flags);        	lock_sock(sk);        }        skb = skb_dequeue(&pdata->rcv_queue);        if(skb == NULL) 		goto restart;	ispxh 	= (struct ipxspxhdr *)skb->nh.raw;	copied 	= ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;        if(copied > size)	{                copied = size;                msg->msg_flags |= MSG_TRUNC;        }	err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);        if(err)                return (-EFAULT);	msg->msg_namelen = sizeof(*sipx);	if(sipx)	{		sipx->sipx_family	= AF_IPX;                sipx->sipx_port		= ispxh->ipx.ipx_source.sock;                memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);                sipx->sipx_network	= ispxh->ipx.ipx_source.net;                sipx->sipx_type 	= ispxh->ipx.ipx_type;        }	kfree_skb(skb);        release_sock(sk);	return (copied);}/* * Functions which just wrap their IPX cousins */static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){        int err;        err = ipx_operations->bind(sock, uaddr, addr_len);        return (err);}static int spx_getname (struct socket *sock, struct sockaddr *uaddr,                         int *usockaddr_len, int peer){	int err;	err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);	return (err);}static int spx_ioctl (struct socket *sock, unsigned int cmd,                         unsigned long arg){	int err;	err = ipx_operations->ioctl(sock, cmd, arg);	return (err);}static int spx_setsockopt(struct socket *sock, int level, int optname,                         char *optval, int optlen){	int err;	err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);	return (err);}static int spx_getsockopt(struct socket *sock, int level, int optname,                         char *optval, int *optlen){	int err;	err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);	return (err);}static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {	family:		PF_IPX,	release:	spx_release,	bind:		spx_bind,	connect:	spx_connect,	socketpair:	sock_no_socketpair,	accept:		spx_accept,	getname:	spx_getname,	poll:		spx_datagram_poll,	ioctl:		spx_ioctl,	listen:		spx_listen,	shutdown:	sock_no_shutdown,	setsockopt:	spx_setsockopt,	getsockopt:	spx_getsockopt,	sendmsg:	spx_sendmsg,	recvmsg:	spx_recvmsg,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};#include <linux/smp_lock.h>SOCKOPS_WRAP(spx, PF_IPX);static struct net_proto_family spx_family_ops = {	family:		PF_IPX,	create:		spx_create,};static char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n";static int __init spx_proto_init(void){	int error;	connids = (__u16)jiffies;	/* initalize random */	error = ipx_register_spx(&ipx_operations, &spx_family_ops);        if (error)                printk(KERN_ERR "SPX: unable to register with IPX.\n");	/* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */	printk(banner);	return 0;}module_init(spx_proto_init);static void __exit spx_proto_finito(void){	ipx_unregister_spx();	return;}module_exit(spx_proto_finito);

⌨️ 快捷键说明

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