📄 af_spx.c
字号:
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 + -