- Linus: drop support for old-style Makefiles entirely. Big.
[davej-history.git] / net / ipx / af_spx.c
blobfa90429f96c568448356d4cb9109a36883e5b539
1 /*
2 * This module implements the (SPP-derived) Sequenced Packet eXchange
3 * (SPX) protocol for Linux 2.1.X as specified in
4 * NetWare SPX Services Specification, Semantics and API
5 * Revision: 1.00
6 * Revision Date: February 9, 1993
8 * Developers:
9 * Jay Schulist <jschlst@turbolinux.com>
10 * Jim Freeman <jfree@caldera.com>
12 * Changes:
13 * Alan Cox : Fixed an skb_unshare check for NULL
14 * that crashed it under load. Renamed and
15 * made static the ipx ops. Removed the hack
16 * ipx methods interface. Dropped AF_SPX - its
17 * the wrong abstraction.
18 * Eduardo Trapani : Added a check for the return value of
19 * ipx_if_offset that crashed sock_alloc_send_skb.
20 * Added spx_datagram_poll() so that select()
21 * works now on SPX sockets. Added updating
22 * of the alloc count to follow rmt_seq.
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * as published by the Free Software Foundation; either version
27 * 2 of the License, or (at your option) any later version.
29 * None of the authors or maintainers or their employers admit
30 * liability nor provide warranty for any of this software.
31 * This material is provided "as is" and at no charge.
34 #include <linux/config.h>
35 #if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
36 #include <linux/module.h>
37 #include <net/ipx.h>
38 #include <net/spx.h>
39 #include <net/sock.h>
40 #include <asm/byteorder.h>
41 #include <asm/uaccess.h>
42 #include <linux/uio.h>
43 #include <linux/unistd.h>
44 #include <linux/poll.h>
46 static struct proto_ops *ipx_operations;
47 static struct proto_ops spx_ops;
48 static __u16 connids;
50 /* Functions needed for SPX connection start up */
51 static int spx_transmit(struct sock *sk,struct sk_buff *skb,int type,int len);
52 static void spx_retransmit(unsigned long data);
53 static void spx_watchdog(unsigned long data);
54 void spx_rcv(struct sock *sk, int bytes);
56 extern void ipx_remove_socket(struct sock *sk);
58 /* Datagram poll: the same code as datagram_poll() in net/core
59 but the right spx buffers are looked at and
60 there is no question on the type of the socket
62 static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, poll_table *wait)
64 struct sock *sk = sock->sk;
65 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
66 unsigned int mask;
68 poll_wait(file, sk->sleep, wait);
69 mask = 0;
71 /* exceptional events? */
72 if (sk->err || !skb_queue_empty(&sk->error_queue))
73 mask |= POLLERR;
74 if (sk->shutdown & RCV_SHUTDOWN)
75 mask |= POLLHUP;
77 /* readable? */
78 if (!skb_queue_empty(&pdata->rcv_queue))
79 mask |= POLLIN | POLLRDNORM;
81 /* Need to check for termination and startup */
82 if (sk->state==TCP_CLOSE)
83 mask |= POLLHUP;
84 /* connection hasn't started yet? */
85 if (sk->state == TCP_SYN_SENT)
86 return mask;
88 /* writable? */
89 if (sock_writeable(sk))
90 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
91 else
92 set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
94 return mask;
97 /* Create the SPX specific data */
98 static int spx_sock_init(struct sock *sk)
100 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
102 pdata->state = SPX_CLOSED;
103 pdata->sequence = 0;
104 pdata->acknowledge = 0;
105 pdata->source_connid = htons(connids);
106 pdata->rmt_seq = 0;
107 connids++;
109 pdata->owner = (void *)sk;
110 pdata->sndbuf = sk->sndbuf;
112 pdata->watchdog.function = spx_watchdog;
113 pdata->watchdog.data = (unsigned long)sk;
114 pdata->wd_interval = VERIFY_TIMEOUT;
115 pdata->retransmit.function = spx_retransmit;
116 pdata->retransmit.data = (unsigned long)sk;
117 pdata->retransmits = 0;
118 pdata->retries = 0;
119 pdata->max_retries = RETRY_COUNT;
121 skb_queue_head_init(&pdata->rcv_queue);
122 skb_queue_head_init(&pdata->transmit_queue);
123 skb_queue_head_init(&pdata->retransmit_queue);
125 return (0);
128 static int spx_create(struct socket *sock, int protocol)
130 struct sock *sk;
133 * Called on connection receive so cannot be GFP_KERNEL
136 sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1);
137 if(sk == NULL)
138 return (-ENOMEM);
140 switch(sock->type)
142 case SOCK_SEQPACKET:
143 sock->ops = &spx_ops;
144 break;
145 default:
146 sk_free(sk);
147 return (-ESOCKTNOSUPPORT);
150 sock_init_data(sock, sk);
151 spx_sock_init(sk);
152 sk->data_ready = spx_rcv;
153 sk->destruct = NULL;
154 sk->no_check = 1;
156 MOD_INC_USE_COUNT;
158 return (0);
162 void spx_close_socket(struct sock *sk)
164 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
166 pdata->state = SPX_CLOSED;
167 sk->state = TCP_CLOSE;
168 del_timer(&pdata->retransmit);
169 del_timer(&pdata->watchdog);
172 void spx_destroy_socket(struct sock *sk)
174 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
175 struct sk_buff *skb;
177 ipx_remove_socket(sk);
178 while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
179 kfree_skb(skb);
180 while((skb = skb_dequeue(&pdata->transmit_queue)) != NULL)
181 kfree_skb(skb);
182 while((skb = skb_dequeue(&pdata->retransmit_queue)) != NULL)
183 kfree_skb(skb);
184 while((skb = skb_dequeue(&pdata->rcv_queue)) != NULL)
185 kfree_skb(skb);
187 sk_free(sk);
188 MOD_DEC_USE_COUNT;
191 /* Release an SPX socket */
192 static int spx_release(struct socket *sock)
194 struct sock *sk = sock->sk;
195 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
197 if(sk == NULL)
198 return (0);
199 if(!sk->dead)
200 sk->state_change(sk);
201 sk->dead = 1;
203 if(pdata->state != SPX_CLOSED)
205 spx_transmit(sk, NULL, DISCON, 0);
206 spx_close_socket(sk);
209 sock->sk = NULL;
210 sk->socket = NULL;
211 spx_destroy_socket(sk);
213 return (0);
216 /* Move a socket into listening state. */
217 static int spx_listen(struct socket *sock, int backlog)
219 struct sock *sk = sock->sk;
221 if(sock->state != SS_UNCONNECTED)
222 return (-EINVAL);
223 if(sock->type != SOCK_SEQPACKET)
224 return (-EOPNOTSUPP);
225 if(sk->zapped != 0)
226 return (-EAGAIN);
228 sk->max_ack_backlog = backlog;
229 if(sk->state != TCP_LISTEN)
231 sk->ack_backlog = 0;
232 sk->state = TCP_LISTEN;
234 sk->socket->flags |= __SO_ACCEPTCON;
236 return (0);
239 /* Accept a pending SPX connection */
240 static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
242 struct sock *sk;
243 struct sock *newsk;
244 struct sk_buff *skb;
245 int err;
247 if(sock->sk == NULL)
248 return (-EINVAL);
249 sk = sock->sk;
251 if((sock->state != SS_UNCONNECTED) || !(sock->flags & __SO_ACCEPTCON))
252 return (-EINVAL);
253 if(sock->type != SOCK_SEQPACKET)
254 return (-EOPNOTSUPP);
255 if(sk->state != TCP_LISTEN)
256 return (-EINVAL);
258 cli();
259 do {
260 skb = skb_dequeue(&sk->receive_queue);
261 if(skb == NULL)
263 if(flags & O_NONBLOCK)
265 sti();
266 return (-EWOULDBLOCK);
268 interruptible_sleep_on(sk->sleep);
269 if(signal_pending(current))
271 sti();
272 return (-ERESTARTSYS);
275 } while (skb == NULL);
277 newsk = skb->sk;
278 newsk->pair = NULL;
279 sti();
281 err = spx_transmit(newsk, skb, CONACK, 0); /* Connection ACK */
282 if(err)
283 return (err);
285 /* Now attach up the new socket */
286 sock->sk = NULL;
287 sk->ack_backlog--;
288 newsock->sk = newsk;
289 newsk->state = TCP_ESTABLISHED;
290 newsk->protinfo.af_ipx.dest_addr = newsk->tp_pinfo.af_spx.dest_addr;
292 return (0);
295 /* Build a connection to an SPX socket */
296 static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
297 int addr_len, int flags)
299 struct sock *sk = sock->sk;
300 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
301 struct sockaddr_ipx src;
302 struct sk_buff *skb;
303 int size, err;
305 size = sizeof(src);
306 err = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0);
307 if(err)
308 return (err);
310 pdata->source_addr.net = src.sipx_network;
311 memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
312 pdata->source_addr.sock = (unsigned short)src.sipx_port;
314 err = ipx_operations->connect(sock, uaddr, addr_len, flags);
315 if(err)
316 return (err);
318 pdata->dest_addr = sk->protinfo.af_ipx.dest_addr;
319 pdata->state = SPX_CONNECTING;
320 sock->state = SS_CONNECTING;
321 sk->state = TCP_SYN_SENT;
323 /* Send Connection request */
324 err = spx_transmit(sk, NULL, CONREQ, 0);
325 if(err)
326 return (err);
328 cli();
329 do {
330 skb = skb_dequeue(&sk->receive_queue);
331 if(skb == NULL)
333 if(flags & O_NONBLOCK)
335 sti();
336 return (-EWOULDBLOCK);
338 interruptible_sleep_on(sk->sleep);
339 if(signal_pending(current))
341 sti();
342 return (-ERESTARTSYS);
345 } while (skb == NULL);
347 if(pdata->state == SPX_CLOSED)
349 sti();
350 del_timer(&pdata->watchdog);
351 return (-ETIMEDOUT);
354 sock->state = SS_CONNECTED;
355 sk->state = TCP_ESTABLISHED;
356 kfree_skb(skb);
357 sti();
359 return (0);
363 * Calculate the timeout for a packet. Thankfully SPX has a large
364 * fudge factor (3/4 secs) and does not pay much attention to RTT.
365 * As we simply have a default retry time of 1*HZ and a max retry
366 * time of 5*HZ. Between those values we increase the timeout based
367 * on the number of retransmit tries.
369 * FixMe: This is quite fake, but will work for now. (JS)
371 static inline unsigned long spx_calc_rtt(int tries)
373 if(tries < 1)
374 return (RETRY_TIME);
375 if(tries > 5)
376 return (MAX_RETRY_DELAY);
377 return (tries * HZ);
380 static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
382 struct sk_buff *skb2;
383 int err = 0;
385 skb = skb_unshare(skb, GFP_ATOMIC);
386 if(skb == NULL)
387 return (-ENOBUFS);
389 switch(type)
391 case (CONREQ):
392 case (DATA):
393 if(!skb_queue_empty(&pdata->retransmit_queue))
395 skb_queue_tail(&pdata->transmit_queue, skb);
396 return 0;
399 case (TQUEUE):
400 pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
401 add_timer(&pdata->retransmit);
403 skb2 = skb_clone(skb, GFP_BUFFER);
404 if(skb2 == NULL)
405 return -ENOBUFS;
406 skb_queue_tail(&pdata->retransmit_queue, skb2);
408 case (ACK):
409 case (CONACK):
410 case (WDREQ):
411 case (WDACK):
412 case (DISCON):
413 case (DISACK):
414 case (RETRAN):
415 default:
416 /* Send data */
417 err = ipxrtr_route_skb(skb);
418 if(err)
419 kfree_skb(skb);
422 return (err);
425 /* SPX packet transmit engine */
426 static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
428 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
429 struct ipxspxhdr *ipxh;
430 unsigned long flags;
431 int err;
433 if(skb == NULL)
435 int offset = ipx_if_offset(pdata->dest_addr.net);
436 int size = offset + sizeof(struct ipxspxhdr);
438 if (offset < 0) /* ENETUNREACH */
439 return(-ENETUNREACH);
441 save_flags(flags);
442 cli();
443 skb = sock_alloc_send_skb(sk, size, 1, 0, &err);
444 if(skb == NULL) {
445 restore_flags(flags);
446 return (-ENOMEM);
448 skb_reserve(skb, offset);
449 skb->h.raw = skb->nh.raw = skb_put(skb,sizeof(struct ipxspxhdr));
450 restore_flags(flags);
453 /* IPX header */
454 ipxh = (struct ipxspxhdr *)skb->nh.raw;
455 ipxh->ipx.ipx_checksum = 0xFFFF;
456 ipxh->ipx.ipx_pktsize = htons(SPX_SYS_PKT_LEN);
457 ipxh->ipx.ipx_tctrl = 0;
458 ipxh->ipx.ipx_type = IPX_TYPE_SPX;
459 ipxh->ipx.ipx_dest = pdata->dest_addr;
460 ipxh->ipx.ipx_source = pdata->source_addr;
462 /* SPX header */
463 ipxh->spx.dtype = 0;
464 ipxh->spx.sequence = htons(pdata->sequence);
465 ipxh->spx.ackseq = htons(pdata->rmt_seq);
466 ipxh->spx.sconn = pdata->source_connid;
467 ipxh->spx.dconn = pdata->dest_connid;
468 ipxh->spx.allocseq = htons(pdata->alloc);
470 /* Reset/Set WD timer */
471 mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
473 switch(type)
475 case (DATA): /* Data */
476 ipxh->ipx.ipx_pktsize = htons(SPX_SYS_PKT_LEN + len);
477 ipxh->spx.cctl = (CCTL_ACK | CCTL_EOM);
478 pdata->sequence++;
479 break;
481 case (ACK): /* ACK */
482 pdata->rmt_seq++;
483 case (WDACK): /* WD ACK */
484 case (CONACK): /* Connection ACK */
485 ipxh->spx.cctl = CCTL_SYS;
486 ipxh->spx.ackseq = htons(pdata->rmt_seq);
487 break;
489 case (CONREQ): /* Connection Request */
490 del_timer(&pdata->watchdog);
491 case (WDREQ): /* WD Request */
492 pdata->source_connid = htons(connids++);
493 pdata->dest_connid = 0xFFFF;
494 pdata->alloc = 3 + pdata->rmt_seq;
495 ipxh->spx.cctl = (CCTL_ACK | CCTL_SYS);
496 ipxh->spx.sconn = pdata->source_connid;
497 ipxh->spx.dconn = pdata->dest_connid;
498 ipxh->spx.allocseq = htons(pdata->alloc);
499 break;
501 case (DISCON): /* Informed Disconnect */
502 ipxh->spx.cctl = CCTL_ACK;
503 ipxh->spx.dtype = SPX_DTYPE_ECONN;
504 break;
506 case (DISACK): /* Informed Disconnect ACK */
507 ipxh->spx.cctl = 0;
508 ipxh->spx.dtype = SPX_DTYPE_ECACK;
509 ipxh->spx.sequence = 0;
510 ipxh->spx.ackseq = htons(pdata->rmt_seq++);
511 break;
513 default:
514 return (-EOPNOTSUPP);
517 /* Send data */
518 return (spx_route_skb(pdata, skb, type));
521 /* Check the state of the connection and send a WD request if needed. */
522 static void spx_watchdog(unsigned long data)
524 struct sock *sk = (struct sock*)data;
525 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
527 del_timer(&pdata->watchdog);
528 if(pdata->state == SPX_CLOSED)
529 return;
530 if(pdata->retries > pdata->max_retries)
532 spx_close_socket(sk); /* Unilateral Abort */
533 return;
536 /* Send WD request */
537 spx_transmit(sk, NULL, WDREQ, 0);
538 pdata->retries++;
540 return;
543 static void spx_retransmit(unsigned long data)
545 struct sock *sk = (struct sock*)data;
546 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
547 struct sk_buff *skb;
548 unsigned long flags;
549 int err;
551 del_timer(&pdata->retransmit);
552 if(pdata->state == SPX_CLOSED)
553 return;
554 if(pdata->retransmits > RETRY_COUNT)
556 spx_close_socket(sk); /* Unilateral Abort */
557 return;
560 /* Need to leave skb on the queue, aye the fear */
561 save_flags(flags);
562 cli();
563 skb = skb_peek(&pdata->retransmit_queue);
564 if(skb_cloned(skb))
565 skb = skb_copy(skb, GFP_ATOMIC);
566 else
567 skb = skb_clone(skb, GFP_ATOMIC);
568 restore_flags(flags);
570 pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
571 add_timer(&pdata->retransmit);
573 err = spx_route_skb(pdata, skb, RETRAN);
574 pdata->retransmits++;
576 return;
579 /* Check packet for retransmission, ConReqAck aware */
580 static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type)
582 struct ipxspxhdr *ipxh;
583 struct sk_buff *skb;
585 skb = skb_dequeue(&pdata->retransmit_queue);
586 if(!skb)
587 return (-ENOENT);
589 /* Check Data/ACK seq */
590 switch(type)
592 case ACK: /* Check Sequence, Should == 1 */
593 ipxh = (struct ipxspxhdr *)skb->nh.raw;
594 if(!(ntohs(ipxh->spx.sequence) - htons(ackseq)))
595 break;
597 case CONACK:
598 del_timer(&pdata->retransmit);
599 pdata->retransmits = 0;
600 kfree_skb(skb);
601 if(skb_queue_empty(&pdata->retransmit_queue))
603 skb = skb_dequeue(&pdata->transmit_queue);
604 if(skb != NULL)
605 spx_route_skb(pdata, skb, TQUEUE);
607 return (0);
610 skb_queue_head(&pdata->retransmit_queue, skb);
611 return (-1);
614 /* SPX packet receive engine */
615 void spx_rcv(struct sock *sk, int bytes)
617 struct sk_buff *skb;
618 struct ipxspxhdr *ipxh;
619 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
621 skb = skb_dequeue(&sk->receive_queue);
622 if(skb == NULL)
623 return;
624 ipxh = (struct ipxspxhdr *)skb->nh.raw;
626 /* Can't receive on a closed connection */
627 if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0))
628 goto toss_skb;
629 if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN)
630 goto toss_skb;
631 if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)
632 goto toss_skb;
633 if(ntohs(ipxh->spx.ackseq) > pdata->sequence)
634 goto toss_skb;
636 /* Reset WD timer on any received packet */
637 del_timer(&pdata->watchdog);
638 pdata->retries = 0;
639 pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
640 add_timer(&pdata->watchdog);
642 switch(ipxh->spx.cctl)
644 case (CCTL_SYS | CCTL_ACK):
645 if((ipxh->spx.sequence == 0) /* ConReq */
646 && (ipxh->spx.ackseq == 0)
647 && (ipxh->spx.dconn == 0xFFFF))
649 pdata->state = SPX_CONNECTED;
650 pdata->dest_addr = ipxh->ipx.ipx_source;
651 pdata->source_addr = ipxh->ipx.ipx_dest;
652 pdata->dest_connid = ipxh->spx.sconn;
653 pdata->alloc = 3 + ntohs(ipxh->spx.sequence);
655 skb_queue_tail(&sk->receive_queue, skb);
656 wake_up_interruptible(sk->sleep);
658 else /* WD Request */
659 spx_transmit(sk, skb, WDACK, 0);
660 goto finish;
662 case CCTL_SYS: /* ACK */
663 if((ipxh->spx.dtype == 0) /* ConReq ACK */
664 && (ipxh->spx.sconn != 0xFFFF)
665 && (ipxh->spx.dconn != 0xFFFF)
666 && (ipxh->spx.sequence == 0)
667 && (ipxh->spx.ackseq == 0)
668 && (pdata->state != SPX_CONNECTED))
670 pdata->state = SPX_CONNECTED;
671 pdata->dest_connid = ipxh->spx.sconn;
673 if(spx_retransmit_chk(pdata, 0, CONACK) < 0)
674 goto toss_skb;
676 skb_queue_tail(&sk->receive_queue, skb);
677 wake_up_interruptible(sk->sleep);
678 goto finish;
681 spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);
682 goto toss_skb;
684 case (CCTL_ACK):
685 /* Informed Disconnect */
686 if(ipxh->spx.dtype == SPX_DTYPE_ECONN)
689 spx_transmit(sk, skb, DISACK, 0);
690 spx_close_socket(sk);
691 goto finish;
693 /* Fall through */
695 default:
696 if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)
698 pdata->rmt_seq = ntohs(ipxh->spx.sequence);
699 pdata->rmt_ack = ntohs(ipxh->spx.ackseq);
700 pdata->alloc = pdata->rmt_seq + 3;
701 if(pdata->rmt_ack > 0 || pdata->rmt_ack == 0)
702 spx_retransmit_chk(pdata,pdata->rmt_ack, ACK);
704 skb_queue_tail(&pdata->rcv_queue, skb);
705 wake_up_interruptible(sk->sleep);
706 if(ipxh->spx.cctl&CCTL_ACK)
707 spx_transmit(sk, NULL, ACK, 0);
708 goto finish;
711 if(ipxh->spx.dtype == SPX_DTYPE_ECACK)
713 if(pdata->state != SPX_CLOSED)
714 spx_close_socket(sk);
715 goto toss_skb;
719 toss_skb: /* Catch All */
720 kfree_skb(skb);
721 finish:
722 return;
725 /* Get message/packet data from user-land */
726 static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
727 struct scm_cookie *scm)
729 struct sock *sk = sock->sk;
730 int flags = msg->msg_flags;
731 struct sk_buff *skb;
732 int err, offset, size;
734 if(len > 534)
735 return (-EMSGSIZE);
736 if(sk->zapped)
737 return (-ENOTCONN); /* Socket not bound */
738 if(flags&~MSG_DONTWAIT)
739 return (-EINVAL);
741 offset = ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);
742 size = offset + sizeof(struct ipxspxhdr) + len;
744 cli();
745 skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
746 sti();
747 if(skb == NULL)
748 return (err);
750 skb->sk = sk;
751 skb_reserve(skb, offset);
752 skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
754 err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
755 if(err)
757 kfree_skb(skb);
758 return (-EFAULT);
761 err = spx_transmit(sk, skb, DATA, len);
762 if(err)
763 return (-EAGAIN);
765 return (len);
768 /* Send message/packet data to user-land */
769 static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
770 int flags, struct scm_cookie *scm)
772 struct sk_buff *skb;
773 struct ipxspxhdr *ispxh;
774 struct sock *sk = sock->sk;
775 struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
776 struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
777 int copied, err;
779 if(sk->zapped)
780 return (-ENOTCONN); /* Socket not bound */
782 lock_sock(sk);
783 restart:
784 while(skb_queue_empty(&pdata->rcv_queue)) /* No data */
786 /* Socket errors? */
787 err = sock_error(sk);
788 if(err)
789 return (err);
791 /* Socket shut down? */
792 if(sk->shutdown & RCV_SHUTDOWN)
793 return (-ESHUTDOWN);
795 /* handle signals */
796 if(signal_pending(current))
797 return (-ERESTARTSYS);
799 /* User doesn't want to wait */
800 if(flags&MSG_DONTWAIT)
801 return (-EAGAIN);
803 release_sock(sk);
804 save_flags(flags);
805 cli();
806 if(skb_peek(&pdata->rcv_queue) == NULL)
807 interruptible_sleep_on(sk->sleep);
808 restore_flags(flags);
809 lock_sock(sk);
812 skb = skb_dequeue(&pdata->rcv_queue);
813 if(skb == NULL)
814 goto restart;
816 ispxh = (struct ipxspxhdr *)skb->nh.raw;
817 copied = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
818 if(copied > size)
820 copied = size;
821 msg->msg_flags |= MSG_TRUNC;
824 err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);
825 if(err)
826 return (-EFAULT);
828 msg->msg_namelen = sizeof(*sipx);
829 if(sipx)
831 sipx->sipx_family = AF_IPX;
832 sipx->sipx_port = ispxh->ipx.ipx_source.sock;
833 memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
834 sipx->sipx_network = ispxh->ipx.ipx_source.net;
835 sipx->sipx_type = ispxh->ipx.ipx_type;
837 kfree_skb(skb);
838 release_sock(sk);
840 return (copied);
844 * Functions which just wrap their IPX cousins
847 static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
849 int err;
850 err = ipx_operations->bind(sock, uaddr, addr_len);
851 return (err);
854 static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
855 int *usockaddr_len, int peer)
857 int err;
858 err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
859 return (err);
862 static int spx_ioctl (struct socket *sock, unsigned int cmd,
863 unsigned long arg)
865 int err;
866 err = ipx_operations->ioctl(sock, cmd, arg);
867 return (err);
870 static int spx_setsockopt(struct socket *sock, int level, int optname,
871 char *optval, int optlen)
873 int err;
874 err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
875 return (err);
878 static int spx_getsockopt(struct socket *sock, int level, int optname,
879 char *optval, int *optlen)
881 int err;
882 err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
883 return (err);
886 static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
887 family: PF_IPX,
889 release: spx_release,
890 bind: spx_bind,
891 connect: spx_connect,
892 socketpair: sock_no_socketpair,
893 accept: spx_accept,
894 getname: spx_getname,
895 poll: spx_datagram_poll,
896 ioctl: spx_ioctl,
897 listen: spx_listen,
898 shutdown: sock_no_shutdown,
899 setsockopt: spx_setsockopt,
900 getsockopt: spx_getsockopt,
901 sendmsg: spx_sendmsg,
902 recvmsg: spx_recvmsg,
903 mmap: sock_no_mmap,
906 #include <linux/smp_lock.h>
907 SOCKOPS_WRAP(spx, PF_IPX);
910 static struct net_proto_family spx_family_ops=
912 PF_IPX,
913 spx_create
917 void spx_proto_init(void)
919 int error;
921 connids = (__u16)jiffies; /* initalize random */
923 error = ipx_register_spx(&ipx_operations, &spx_family_ops);
924 if (error)
925 printk(KERN_ERR "SPX: unable to register with IPX.\n");
927 /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
929 printk(KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n");
930 return;
933 void spx_proto_finito(void)
935 ipx_unregister_spx();
936 return;
939 #ifdef MODULE
941 int init_module(void)
943 spx_proto_init();
944 return 0;
947 void cleanup_module(void)
949 spx_proto_finito();
950 return;
953 #endif /* MODULE */
954 #endif /* CONFIG_SPX || CONFIG_SPX_MODULE */