~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipx/af_spx.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
  7  *
  8  *      Developers:
  9  *      Jay Schulist    <jschlst@turbolinux.com>
 10  *      Jim Freeman     <jfree@caldera.com>
 11  *
 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.
 23  *
 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.
 28  *
 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.
 32  */
 33 
 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>
 45 
 46 static struct proto_ops *ipx_operations;
 47 static struct proto_ops spx_ops;
 48 static __u16  connids;
 49 
 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);
 55 
 56 extern void ipx_remove_socket(struct sock *sk);
 57 
 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
 61                         */
 62 static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, poll_table *wait)
 63 {
 64         struct sock *sk = sock->sk;
 65         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
 66         unsigned int mask;
 67 
 68         poll_wait(file, sk->sleep, wait);
 69         mask = 0;
 70 
 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;
 76 
 77         /* readable? */
 78         if (!skb_queue_empty(&pdata->rcv_queue))
 79                 mask |= POLLIN | POLLRDNORM;
 80 
 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;
 87 
 88         /* writable? */
 89         if (sock_writeable(sk))
 90                 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 91         else
 92                 set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
 93 
 94         return mask;
 95 }
 96 
 97 /* Create the SPX specific data */
 98 static int spx_sock_init(struct sock *sk)
 99 {
100         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
101 
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++;
108 
109         pdata->owner            = (void *)sk;
110         pdata->sndbuf           = sk->sndbuf;
111 
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;
120 
121         skb_queue_head_init(&pdata->rcv_queue);
122         skb_queue_head_init(&pdata->transmit_queue);
123         skb_queue_head_init(&pdata->retransmit_queue);
124 
125         return (0);
126 }
127 
128 static int spx_create(struct socket *sock, int protocol)
129 {
130         struct sock *sk;
131 
132         /*
133          *      Called on connection receive so cannot be GFP_KERNEL
134          */
135          
136         sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1);
137         if(sk == NULL)
138                 return (-ENOMEM);
139 
140         switch(sock->type)
141         {
142                 case SOCK_SEQPACKET:
143                         sock->ops = &spx_ops;
144                         break;
145                 default:
146                         sk_free(sk);
147                         return (-ESOCKTNOSUPPORT);
148         }
149 
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;
155 
156         MOD_INC_USE_COUNT;
157 
158         return (0);
159 }
160 
161 
162 void spx_close_socket(struct sock *sk)
163 {
164         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
165 
166         pdata->state    = SPX_CLOSED;
167         sk->state       = TCP_CLOSE;
168         del_timer(&pdata->retransmit);
169         del_timer(&pdata->watchdog);
170 }
171 
172 void spx_destroy_socket(struct sock *sk)
173 {
174         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
175         struct sk_buff *skb;
176 
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);
186 
187         sk_free(sk);
188         MOD_DEC_USE_COUNT;
189 }
190 
191 /* Release an SPX socket */
192 static int spx_release(struct socket *sock)
193 {
194         struct sock *sk = sock->sk;
195         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
196 
197         if(sk == NULL)
198                 return (0);
199         if(!sk->dead)
200                 sk->state_change(sk);
201         sk->dead = 1;
202 
203         if(pdata->state != SPX_CLOSED)
204         {
205                 spx_transmit(sk, NULL, DISCON, 0);
206                 spx_close_socket(sk);
207         }
208 
209         sock->sk        = NULL;
210         sk->socket      = NULL;
211         spx_destroy_socket(sk);
212 
213         return (0);
214 }
215 
216 /* Move a socket into listening state. */
217 static int spx_listen(struct socket *sock, int backlog)
218 {
219         struct sock *sk = sock->sk;
220 
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);
227 
228         sk->max_ack_backlog = backlog;
229         if(sk->state != TCP_LISTEN)
230         {
231                 sk->ack_backlog = 0;
232                 sk->state = TCP_LISTEN;
233         }
234         sk->socket->flags |= __SO_ACCEPTCON;
235 
236         return (0);
237 }
238 
239 /* Accept a pending SPX connection */
240 static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
241 {
242         struct sock *sk;
243         struct sock *newsk;
244         struct sk_buff *skb;
245         int err;
246 
247         if(sock->sk == NULL)
248                 return (-EINVAL);
249         sk = sock->sk;
250 
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);
257 
258         cli();
259         do {
260                 skb = skb_dequeue(&sk->receive_queue);
261                 if(skb == NULL)
262                 {
263                         if(flags & O_NONBLOCK)
264                         {
265                                 sti();
266                                 return (-EWOULDBLOCK);
267                         }
268                         interruptible_sleep_on(sk->sleep);
269                         if(signal_pending(current))
270                         {
271                                 sti();
272                                 return (-ERESTARTSYS);
273                         }
274                 }
275         } while (skb == NULL);
276 
277         newsk           = skb->sk;
278         newsk->pair     = NULL;
279         sti();
280 
281         err = spx_transmit(newsk, skb, CONACK, 0);   /* Connection ACK */
282         if(err)
283                 return (err);
284 
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;
291 
292         return (0);
293 }
294 
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)
298 {
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;
304 
305         size = sizeof(src);
306         err  = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0);
307         if(err)
308                 return (err);
309 
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;
313 
314         err = ipx_operations->connect(sock, uaddr, addr_len, flags);
315         if(err)
316                 return (err);
317 
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;
322 
323         /* Send Connection request */
324         err = spx_transmit(sk, NULL, CONREQ, 0);
325         if(err)
326                 return (err);
327 
328         cli();
329         do {
330                 skb = skb_dequeue(&sk->receive_queue);
331                 if(skb == NULL)
332                 {
333                         if(flags & O_NONBLOCK)
334                         {
335                                 sti();
336                                 return (-EWOULDBLOCK);
337                         }
338                         interruptible_sleep_on(sk->sleep);
339                         if(signal_pending(current))
340                         {
341                                 sti();
342                                 return (-ERESTARTSYS);
343                         }
344                 }
345         } while (skb == NULL);
346 
347         if(pdata->state == SPX_CLOSED)
348         {
349                 sti();
350                 del_timer(&pdata->watchdog);
351                 return (-ETIMEDOUT);
352         }
353 
354         sock->state     = SS_CONNECTED;
355         sk->state       = TCP_ESTABLISHED;
356         kfree_skb(skb);
357         sti();
358 
359         return (0);
360 }
361 
362 /*
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.
368  *
369  * FixMe: This is quite fake, but will work for now. (JS)
370  */
371 static inline unsigned long spx_calc_rtt(int tries)
372 {
373         if(tries < 1)
374                 return (RETRY_TIME);
375         if(tries > 5)
376                 return (MAX_RETRY_DELAY);
377         return (tries * HZ);
378 }
379 
380 static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
381 {
382         struct sk_buff *skb2;
383         int err = 0;
384 
385         skb = skb_unshare(skb, GFP_ATOMIC);
386         if(skb == NULL)
387                 return (-ENOBUFS);
388 
389         switch(type)
390         {
391                 case (CONREQ):
392                 case (DATA):
393                         if(!skb_queue_empty(&pdata->retransmit_queue))
394                         {
395                                 skb_queue_tail(&pdata->transmit_queue, skb);
396                                 return 0;
397                         }
398 
399                 case (TQUEUE):
400                         pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
401                         add_timer(&pdata->retransmit);
402 
403                         skb2 = skb_clone(skb, GFP_BUFFER);
404                         if(skb2 == NULL)
405                                 return -ENOBUFS;
406                         skb_queue_tail(&pdata->retransmit_queue, skb2);
407 
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);
420         }
421 
422         return (err);
423 }
424 
425 /* SPX packet transmit engine */
426 static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
427 {
428         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
429         struct ipxspxhdr *ipxh;
430         unsigned long flags;
431         int err;
432 
433         if(skb == NULL)
434         {
435                 int offset  = ipx_if_offset(pdata->dest_addr.net);
436                 int size    = offset + sizeof(struct ipxspxhdr);
437 
438                 if (offset < 0) /* ENETUNREACH */
439                         return(-ENETUNREACH);
440 
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);
447                 }
448                 skb_reserve(skb, offset);
449                 skb->h.raw = skb->nh.raw = skb_put(skb,sizeof(struct ipxspxhdr));
450                 restore_flags(flags);
451         }
452 
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;
461 
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);
469 
470         /* Reset/Set WD timer */
471         mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
472 
473         switch(type)
474         {
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;
480 
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;
488 
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;
500 
501                 case (DISCON):  /* Informed Disconnect */
502                         ipxh->spx.cctl          = CCTL_ACK;
503                         ipxh->spx.dtype         = SPX_DTYPE_ECONN;
504                         break;
505 
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;
512 
513                 default:
514                         return (-EOPNOTSUPP);
515         }
516 
517         /* Send data */
518         return (spx_route_skb(pdata, skb, type));
519 }
520 
521 /* Check the state of the connection and send a WD request if needed. */
522 static void spx_watchdog(unsigned long data)
523 {
524         struct sock *sk = (struct sock*)data;
525         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
526 
527         del_timer(&pdata->watchdog);
528         if(pdata->state == SPX_CLOSED)
529                 return;
530         if(pdata->retries > pdata->max_retries)
531         {
532                 spx_close_socket(sk);   /* Unilateral Abort */
533                 return;
534         }
535 
536         /* Send WD request */
537         spx_transmit(sk, NULL, WDREQ, 0);
538         pdata->retries++;
539 
540         return;
541 }
542 
543 static void spx_retransmit(unsigned long data)
544 {
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;
550 
551         del_timer(&pdata->retransmit);
552         if(pdata->state == SPX_CLOSED)
553                 return;
554         if(pdata->retransmits > RETRY_COUNT)
555         {
556                 spx_close_socket(sk);   /* Unilateral Abort */
557                 return;
558         }
559 
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);
569 
570         pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
571         add_timer(&pdata->retransmit);
572 
573         err = spx_route_skb(pdata, skb, RETRAN);
574         pdata->retransmits++;
575 
576         return;
577 }
578 
579 /* Check packet for retransmission, ConReqAck aware */
580 static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type)
581 {
582         struct ipxspxhdr *ipxh;
583         struct sk_buff *skb;
584 
585         skb = skb_dequeue(&pdata->retransmit_queue);
586         if(!skb)
587                 return (-ENOENT);
588 
589         /* Check Data/ACK seq */
590         switch(type)
591         {
592                 case ACK:       /* Check Sequence, Should == 1 */
593                         ipxh = (struct ipxspxhdr *)skb->nh.raw;
594                         if(!(ntohs(ipxh->spx.sequence) - htons(ackseq)))
595                                 break;
596 
597                 case CONACK:
598                         del_timer(&pdata->retransmit);
599                         pdata->retransmits = 0;
600                         kfree_skb(skb);
601                         if(skb_queue_empty(&pdata->retransmit_queue))
602                         {
603                                 skb = skb_dequeue(&pdata->transmit_queue);
604                                 if(skb != NULL)
605                                         spx_route_skb(pdata, skb, TQUEUE);
606                         }
607                         return (0);
608         }
609 
610         skb_queue_head(&pdata->retransmit_queue, skb);
611         return (-1);
612 }
613 
614 /* SPX packet receive engine */
615 void spx_rcv(struct sock *sk, int bytes)
616 {
617         struct sk_buff *skb;
618         struct ipxspxhdr *ipxh;
619         struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
620 
621         skb = skb_dequeue(&sk->receive_queue);
622         if(skb == NULL)
623                 return;
624         ipxh = (struct ipxspxhdr *)skb->nh.raw;
625 
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;
635 
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);
641 
642         switch(ipxh->spx.cctl)
643         {
644                 case (CCTL_SYS | CCTL_ACK):
645                         if((ipxh->spx.sequence == 0)    /* ConReq */
646                                 && (ipxh->spx.ackseq == 0)
647                                 && (ipxh->spx.dconn == 0xFFFF))
648                         {
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);
654 
655                                 skb_queue_tail(&sk->receive_queue, skb);
656                                 wake_up_interruptible(sk->sleep);
657                         }
658                         else    /* WD Request */
659                                 spx_transmit(sk, skb, WDACK, 0);
660                         goto finish;
661 
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))
669                         {
670                                 pdata->state = SPX_CONNECTED;
671                                 pdata->dest_connid = ipxh->spx.sconn;
672 
673                                 if(spx_retransmit_chk(pdata, 0, CONACK) < 0)
674                                         goto toss_skb;
675 
676                                 skb_queue_tail(&sk->receive_queue, skb);
677                                 wake_up_interruptible(sk->sleep);
678                                 goto finish;
679                         }
680 
681                         spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);
682                         goto toss_skb;
683 
684                 case (CCTL_ACK):
685                         /* Informed Disconnect */
686                         if(ipxh->spx.dtype == SPX_DTYPE_ECONN)
687                         {
688                                 
689                                 spx_transmit(sk, skb, DISACK, 0);
690                                 spx_close_socket(sk);
691                                 goto finish;
692                         }
693                         /* Fall through */
694 
695                 default:
696                         if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)
697                         {
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);
703 
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;
709                         }
710 
711                         if(ipxh->spx.dtype == SPX_DTYPE_ECACK)
712                         {
713                                 if(pdata->state != SPX_CLOSED)
714                                         spx_close_socket(sk);
715                                 goto toss_skb;
716                         }
717         }
718 
719 toss_skb:       /* Catch All */
720         kfree_skb(skb);
721 finish:
722         return;
723 }
724 
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)
728 {
729         struct sock *sk = sock->sk;
730         int flags = msg->msg_flags;
731         struct sk_buff *skb;
732         int err, offset, size;
733 
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);
740 
741         offset  = ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);
742         size    = offset + sizeof(struct ipxspxhdr) + len;
743 
744         cli();
745         skb     = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
746         sti();
747         if(skb == NULL)
748                 return (err);
749 
750         skb->sk = sk;
751         skb_reserve(skb, offset);
752         skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
753 
754         err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
755         if(err)
756         {
757                 kfree_skb(skb);
758                 return (-EFAULT);
759         }
760 
761         err = spx_transmit(sk, skb, DATA, len);
762         if(err)
763                 return (-EAGAIN);
764 
765         return (len);
766 }
767 
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)
771 {
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;
778 
779         if(sk->zapped)
780                 return (-ENOTCONN); /* Socket not bound */
781 
782         lock_sock(sk);
783 restart:
784         while(skb_queue_empty(&pdata->rcv_queue))      /* No data */
785         {
786                 /* Socket errors? */
787                 err = sock_error(sk);
788                 if(err)
789                         return (err);
790 
791                 /* Socket shut down? */
792                 if(sk->shutdown & RCV_SHUTDOWN)
793                         return (-ESHUTDOWN);
794 
795                 /* handle signals */
796                 if(signal_pending(current))
797                         return (-ERESTARTSYS);
798 
799                 /* User doesn't want to wait */
800                 if(flags&MSG_DONTWAIT)
801                         return (-EAGAIN);
802 
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);
810         }
811 
812         skb = skb_dequeue(&pdata->rcv_queue);
813         if(skb == NULL) 
814                 goto restart;
815 
816         ispxh   = (struct ipxspxhdr *)skb->nh.raw;
817         copied  = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
818         if(copied > size)
819         {
820                 copied = size;
821                 msg->msg_flags |= MSG_TRUNC;
822         }
823 
824         err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);
825         if(err)
826                 return (-EFAULT);
827 
828         msg->msg_namelen = sizeof(*sipx);
829         if(sipx)
830         {
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;
836         }
837         kfree_skb(skb);
838         release_sock(sk);
839 
840         return (copied);
841 }
842 
843 /*
844  * Functions which just wrap their IPX cousins
845  */
846 
847 static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
848 {
849         int err;
850         err = ipx_operations->bind(sock, uaddr, addr_len);
851         return (err);
852 }
853 
854 static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
855                          int *usockaddr_len, int peer)
856 {
857         int err;
858         err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
859         return (err);
860 }
861 
862 static int spx_ioctl (struct socket *sock, unsigned int cmd,
863                          unsigned long arg)
864 {
865         int err;
866         err = ipx_operations->ioctl(sock, cmd, arg);
867         return (err);
868 }
869 
870 static int spx_setsockopt(struct socket *sock, int level, int optname,
871                          char *optval, int optlen)
872 {
873         int err;
874         err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
875         return (err);
876 }
877 
878 static int spx_getsockopt(struct socket *sock, int level, int optname,
879                          char *optval, int *optlen)
880 {
881         int err;
882         err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
883         return (err);
884 }
885 
886 static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
887         family:         PF_IPX,
888 
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,
904 };
905 
906 #include <linux/smp_lock.h>
907 SOCKOPS_WRAP(spx, PF_IPX);
908 
909 
910 static struct net_proto_family spx_family_ops=
911 {
912         PF_IPX,
913         spx_create
914 };
915 
916 
917 void spx_proto_init(void)
918 {
919         int error;
920 
921         connids = (__u16)jiffies;       /* initalize random */
922 
923         error = ipx_register_spx(&ipx_operations, &spx_family_ops);
924         if (error)
925                 printk(KERN_ERR "SPX: unable to register with IPX.\n");
926 
927         /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
928 
929         printk(KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n");
930         return;
931 }
932 
933 void spx_proto_finito(void)
934 {
935         ipx_unregister_spx();
936         return;
937 }
938 
939 #ifdef MODULE
940 
941 int init_module(void)
942 {
943         spx_proto_init();
944         return 0;
945 }
946 
947 void cleanup_module(void)
948 {
949         spx_proto_finito();
950         return;
951 }
952 
953 #endif /* MODULE */
954 #endif /* CONFIG_SPX || CONFIG_SPX_MODULE */
955 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.