OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipx/] [af_spx.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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@samba.org>
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/module.h>
35
#include <net/ipx.h>
36
#include <net/spx.h>
37
#include <net/sock.h>
38
#include <asm/byteorder.h>
39
#include <asm/uaccess.h>
40
#include <linux/uio.h>
41
#include <linux/unistd.h>
42
#include <linux/poll.h>
43
 
44
static struct proto_ops *ipx_operations;
45
static struct proto_ops spx_ops;
46
static __u16  connids;
47
 
48
/* Functions needed for SPX connection start up */
49
static int spx_transmit(struct sock *sk,struct sk_buff *skb,int type,int len);
50
static void spx_retransmit(unsigned long data);
51
static void spx_watchdog(unsigned long data);
52
void spx_rcv(struct sock *sk, int bytes);
53
 
54
extern void ipx_remove_socket(struct sock *sk);
55
 
56
/* Datagram poll:       the same code as datagram_poll() in net/core
57
                        but the right spx buffers are looked at and
58
                        there is no question on the type of the socket
59
                        */
60
static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, poll_table *wait)
61
{
62
        struct sock *sk = sock->sk;
63
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
64
        unsigned int mask;
65
 
66
        poll_wait(file, sk->sleep, wait);
67
        mask = 0;
68
 
69
        /* exceptional events? */
70
        if (sk->err || !skb_queue_empty(&sk->error_queue))
71
                mask |= POLLERR;
72
        if (sk->shutdown & RCV_SHUTDOWN)
73
                mask |= POLLHUP;
74
 
75
        /* readable? */
76
        if (!skb_queue_empty(&pdata->rcv_queue))
77
                mask |= POLLIN | POLLRDNORM;
78
 
79
        /* Need to check for termination and startup */
80
        if (sk->state==TCP_CLOSE)
81
                mask |= POLLHUP;
82
        /* connection hasn't started yet? */
83
        if (sk->state == TCP_SYN_SENT)
84
                return mask;
85
 
86
        /* writable? */
87
        if (sock_writeable(sk))
88
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
89
        else
90
                set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
91
 
92
        return mask;
93
}
94
 
95
/* Create the SPX specific data */
96
static int spx_sock_init(struct sock *sk)
97
{
98
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
99
 
100
        pdata->state            = SPX_CLOSED;
101
        pdata->sequence         = 0;
102
        pdata->acknowledge      = 0;
103
        pdata->source_connid    = htons(connids);
104
        pdata->rmt_seq          = 0;
105
        connids++;
106
 
107
        pdata->owner            = (void *)sk;
108
        pdata->sndbuf           = sk->sndbuf;
109
 
110
        pdata->watchdog.function = spx_watchdog;
111
        pdata->watchdog.data    = (unsigned long)sk;
112
        pdata->wd_interval      = VERIFY_TIMEOUT;
113
        pdata->retransmit.function = spx_retransmit;
114
        pdata->retransmit.data  = (unsigned long)sk;
115
        pdata->retransmits      = 0;
116
        pdata->retries          = 0;
117
        pdata->max_retries      = RETRY_COUNT;
118
 
119
        skb_queue_head_init(&pdata->rcv_queue);
120
        skb_queue_head_init(&pdata->transmit_queue);
121
        skb_queue_head_init(&pdata->retransmit_queue);
122
 
123
        return (0);
124
}
125
 
126
static int spx_create(struct socket *sock, int protocol)
127
{
128
        struct sock *sk;
129
 
130
        /*
131
         *      Called on connection receive so cannot be GFP_KERNEL
132
         */
133
 
134
        sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1);
135
        if(sk == NULL)
136
                return (-ENOMEM);
137
 
138
        switch(sock->type)
139
        {
140
                case SOCK_SEQPACKET:
141
                        sock->ops = &spx_ops;
142
                        break;
143
                default:
144
                        sk_free(sk);
145
                        return (-ESOCKTNOSUPPORT);
146
        }
147
 
148
        sock_init_data(sock, sk);
149
        spx_sock_init(sk);
150
        sk->data_ready  = spx_rcv;
151
        sk->destruct    = NULL;
152
        sk->no_check    = 1;
153
 
154
        MOD_INC_USE_COUNT;
155
 
156
        return (0);
157
}
158
 
159
 
160
void spx_close_socket(struct sock *sk)
161
{
162
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
163
 
164
        pdata->state    = SPX_CLOSED;
165
        sk->state       = TCP_CLOSE;
166
        del_timer(&pdata->retransmit);
167
        del_timer(&pdata->watchdog);
168
}
169
 
170
void spx_destroy_socket(struct sock *sk)
171
{
172
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
173
        struct sk_buff *skb;
174
 
175
        ipx_remove_socket(sk);
176
        while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
177
                kfree_skb(skb);
178
        while((skb = skb_dequeue(&pdata->transmit_queue)) != NULL)
179
                kfree_skb(skb);
180
        while((skb = skb_dequeue(&pdata->retransmit_queue)) != NULL)
181
                kfree_skb(skb);
182
        while((skb = skb_dequeue(&pdata->rcv_queue)) != NULL)
183
                kfree_skb(skb);
184
 
185
        sk_free(sk);
186
        MOD_DEC_USE_COUNT;
187
}
188
 
189
/* Release an SPX socket */
190
static int spx_release(struct socket *sock)
191
{
192
        struct sock *sk = sock->sk;
193
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
194
 
195
        if(sk == NULL)
196
                return (0);
197
        if(!sk->dead)
198
                sk->state_change(sk);
199
        sk->dead = 1;
200
 
201
        if(pdata->state != SPX_CLOSED)
202
        {
203
                spx_transmit(sk, NULL, DISCON, 0);
204
                spx_close_socket(sk);
205
        }
206
 
207
        sock->sk        = NULL;
208
        sk->socket      = NULL;
209
        spx_destroy_socket(sk);
210
 
211
        return (0);
212
}
213
 
214
/* Move a socket into listening state. */
215
static int spx_listen(struct socket *sock, int backlog)
216
{
217
        struct sock *sk = sock->sk;
218
 
219
        if(sock->state != SS_UNCONNECTED)
220
                return (-EINVAL);
221
        if(sock->type != SOCK_SEQPACKET)
222
                return (-EOPNOTSUPP);
223
        if(sk->zapped != 0)
224
                return (-EAGAIN);
225
 
226
        sk->max_ack_backlog = backlog;
227
        if(sk->state != TCP_LISTEN)
228
        {
229
                sk->ack_backlog = 0;
230
                sk->state = TCP_LISTEN;
231
        }
232
        sk->socket->flags |= __SO_ACCEPTCON;
233
 
234
        return (0);
235
}
236
 
237
/* Accept a pending SPX connection */
238
static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
239
{
240
        struct sock *sk;
241
        struct sock *newsk;
242
        struct sk_buff *skb;
243
        int err;
244
 
245
        if(sock->sk == NULL)
246
                return (-EINVAL);
247
        sk = sock->sk;
248
 
249
        if((sock->state != SS_UNCONNECTED) || !(sock->flags & __SO_ACCEPTCON))
250
                return (-EINVAL);
251
        if(sock->type != SOCK_SEQPACKET)
252
                return (-EOPNOTSUPP);
253
        if(sk->state != TCP_LISTEN)
254
                return (-EINVAL);
255
 
256
        cli();
257
        do {
258
                skb = skb_dequeue(&sk->receive_queue);
259
                if(skb == NULL)
260
                {
261
                        if(flags & O_NONBLOCK)
262
                        {
263
                                sti();
264
                                return (-EWOULDBLOCK);
265
                        }
266
                        interruptible_sleep_on(sk->sleep);
267
                        if(signal_pending(current))
268
                        {
269
                                sti();
270
                                return (-ERESTARTSYS);
271
                        }
272
                }
273
        } while (skb == NULL);
274
 
275
        newsk           = skb->sk;
276
        newsk->pair     = NULL;
277
        sti();
278
 
279
        err = spx_transmit(newsk, skb, CONACK, 0);   /* Connection ACK */
280
        if(err)
281
                return (err);
282
 
283
        /* Now attach up the new socket */
284
        sock->sk        = NULL;
285
        sk->ack_backlog--;
286
        newsock->sk     = newsk;
287
        newsk->state    = TCP_ESTABLISHED;
288
        newsk->protinfo.af_ipx.dest_addr = newsk->tp_pinfo.af_spx.dest_addr;
289
 
290
        return (0);
291
}
292
 
293
/* Build a connection to an SPX socket */
294
static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
295
                int addr_len, int flags)
296
{
297
        struct sock *sk = sock->sk;
298
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
299
        struct sockaddr_ipx src;
300
        struct sk_buff *skb;
301
        int size, err;
302
 
303
        size = sizeof(src);
304
        err  = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0);
305
        if(err)
306
                return (err);
307
 
308
        pdata->source_addr.net  = src.sipx_network;
309
        memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
310
        pdata->source_addr.sock = (unsigned short)src.sipx_port;
311
 
312
        err = ipx_operations->connect(sock, uaddr, addr_len, flags);
313
        if(err)
314
                return (err);
315
 
316
        pdata->dest_addr = sk->protinfo.af_ipx.dest_addr;
317
        pdata->state     = SPX_CONNECTING;
318
        sock->state      = SS_CONNECTING;
319
        sk->state        = TCP_SYN_SENT;
320
 
321
        /* Send Connection request */
322
        err = spx_transmit(sk, NULL, CONREQ, 0);
323
        if(err)
324
                return (err);
325
 
326
        cli();
327
        do {
328
                skb = skb_dequeue(&sk->receive_queue);
329
                if(skb == NULL)
330
                {
331
                        if(flags & O_NONBLOCK)
332
                        {
333
                                sti();
334
                                return (-EWOULDBLOCK);
335
                        }
336
                        interruptible_sleep_on(sk->sleep);
337
                        if(signal_pending(current))
338
                        {
339
                                sti();
340
                                return (-ERESTARTSYS);
341
                        }
342
                }
343
        } while (skb == NULL);
344
 
345
        if(pdata->state == SPX_CLOSED)
346
        {
347
                sti();
348
                del_timer(&pdata->watchdog);
349
                return (-ETIMEDOUT);
350
        }
351
 
352
        sock->state     = SS_CONNECTED;
353
        sk->state       = TCP_ESTABLISHED;
354
        kfree_skb(skb);
355
        sti();
356
 
357
        return (0);
358
}
359
 
360
/*
361
 * Calculate the timeout for a packet. Thankfully SPX has a large
362
 * fudge factor (3/4 secs) and does not pay much attention to RTT.
363
 * As we simply have a default retry time of 1*HZ and a max retry
364
 * time of 5*HZ. Between those values we increase the timeout based
365
 * on the number of retransmit tries.
366
 *
367
 * FixMe: This is quite fake, but will work for now. (JS)
368
 */
369
static inline unsigned long spx_calc_rtt(int tries)
370
{
371
        if(tries < 1)
372
                return (RETRY_TIME);
373
        if(tries > 5)
374
                return (MAX_RETRY_DELAY);
375
        return (tries * HZ);
376
}
377
 
378
static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
379
{
380
        struct sk_buff *skb2;
381
        int err = 0;
382
 
383
        skb = skb_unshare(skb, GFP_ATOMIC);
384
        if(skb == NULL)
385
                return (-ENOBUFS);
386
 
387
        switch(type)
388
        {
389
                case (CONREQ):
390
                case (DATA):
391
                        if(!skb_queue_empty(&pdata->retransmit_queue))
392
                        {
393
                                skb_queue_tail(&pdata->transmit_queue, skb);
394
                                return 0;
395
                        }
396
 
397
                case (TQUEUE):
398
                        pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
399
                        add_timer(&pdata->retransmit);
400
 
401
                        skb2 = skb_clone(skb, GFP_NOIO);
402
                        if(skb2 == NULL)
403
                                return -ENOBUFS;
404
                        skb_queue_tail(&pdata->retransmit_queue, skb2);
405
 
406
                case (ACK):
407
                case (CONACK):
408
                case (WDREQ):
409
                case (WDACK):
410
                case (DISCON):
411
                case (DISACK):
412
                case (RETRAN):
413
                default:
414
                        /* Send data */
415
                        err = ipxrtr_route_skb(skb);
416
                        if(err)
417
                                kfree_skb(skb);
418
        }
419
 
420
        return (err);
421
}
422
 
423
/* SPX packet transmit engine */
424
static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
425
{
426
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
427
        struct ipxspxhdr *ipxh;
428
        unsigned long flags;
429
        int err;
430
 
431
        if(skb == NULL)
432
        {
433
                int offset  = ipx_if_offset(pdata->dest_addr.net);
434
                int size    = offset + sizeof(struct ipxspxhdr);
435
 
436
                if (offset < 0) /* ENETUNREACH */
437
                        return(-ENETUNREACH);
438
 
439
                save_flags(flags);
440
                cli();
441
                skb = sock_alloc_send_skb(sk, size, 0, &err);
442
                if(skb == NULL) {
443
                        restore_flags(flags);
444
                        return (-ENOMEM);
445
                }
446
                skb_reserve(skb, offset);
447
                skb->h.raw = skb->nh.raw = skb_put(skb,sizeof(struct ipxspxhdr));
448
                restore_flags(flags);
449
        }
450
 
451
        /* IPX header */
452
        ipxh = (struct ipxspxhdr *)skb->nh.raw;
453
        ipxh->ipx.ipx_checksum  = 0xFFFF;
454
        ipxh->ipx.ipx_pktsize   = htons(SPX_SYS_PKT_LEN);
455
        ipxh->ipx.ipx_tctrl     = 0;
456
        ipxh->ipx.ipx_type      = IPX_TYPE_SPX;
457
        ipxh->ipx.ipx_dest      = pdata->dest_addr;
458
        ipxh->ipx.ipx_source    = pdata->source_addr;
459
 
460
        /* SPX header */
461
        ipxh->spx.dtype         = 0;
462
        ipxh->spx.sequence      = htons(pdata->sequence);
463
        ipxh->spx.ackseq        = htons(pdata->rmt_seq);
464
        ipxh->spx.sconn         = pdata->source_connid;
465
        ipxh->spx.dconn         = pdata->dest_connid;
466
        ipxh->spx.allocseq      = htons(pdata->alloc);
467
 
468
        /* Reset/Set WD timer */
469
        mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
470
 
471
        switch(type)
472
        {
473
                case (DATA):    /* Data */
474
                        ipxh->ipx.ipx_pktsize   = htons(SPX_SYS_PKT_LEN + len);
475
                        ipxh->spx.cctl          = (CCTL_ACK | CCTL_EOM);
476
                        pdata->sequence++;
477
                        break;
478
 
479
                case (ACK):     /* ACK */
480
                        pdata->rmt_seq++;
481
                case (WDACK):   /* WD ACK */
482
                case (CONACK):  /* Connection ACK */
483
                        ipxh->spx.cctl          = CCTL_SYS;
484
                        ipxh->spx.ackseq        = htons(pdata->rmt_seq);
485
                        break;
486
 
487
                case (CONREQ):  /* Connection Request */
488
                        del_timer(&pdata->watchdog);
489
                case (WDREQ):   /* WD Request */
490
                        pdata->source_connid    = htons(connids++);
491
                        pdata->dest_connid      = 0xFFFF;
492
                        pdata->alloc            = 3 + pdata->rmt_seq;
493
                        ipxh->spx.cctl          = (CCTL_ACK | CCTL_SYS);
494
                        ipxh->spx.sconn         = pdata->source_connid;
495
                        ipxh->spx.dconn         = pdata->dest_connid;
496
                        ipxh->spx.allocseq      = htons(pdata->alloc);
497
                        break;
498
 
499
                case (DISCON):  /* Informed Disconnect */
500
                        ipxh->spx.cctl          = CCTL_ACK;
501
                        ipxh->spx.dtype         = SPX_DTYPE_ECONN;
502
                        break;
503
 
504
                case (DISACK):  /* Informed Disconnect ACK */
505
                        ipxh->spx.cctl          = 0;
506
                        ipxh->spx.dtype         = SPX_DTYPE_ECACK;
507
                        ipxh->spx.sequence      = 0;
508
                        ipxh->spx.ackseq        = htons(pdata->rmt_seq++);
509
                        break;
510
 
511
                default:
512
                        return (-EOPNOTSUPP);
513
        }
514
 
515
        /* Send data */
516
        return (spx_route_skb(pdata, skb, type));
517
}
518
 
519
/* Check the state of the connection and send a WD request if needed. */
520
static void spx_watchdog(unsigned long data)
521
{
522
        struct sock *sk = (struct sock*)data;
523
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
524
 
525
        del_timer(&pdata->watchdog);
526
        if(pdata->state == SPX_CLOSED)
527
                return;
528
        if(pdata->retries > pdata->max_retries)
529
        {
530
                spx_close_socket(sk);   /* Unilateral Abort */
531
                return;
532
        }
533
 
534
        /* Send WD request */
535
        spx_transmit(sk, NULL, WDREQ, 0);
536
        pdata->retries++;
537
 
538
        return;
539
}
540
 
541
static void spx_retransmit(unsigned long data)
542
{
543
        struct sock *sk = (struct sock*)data;
544
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
545
        struct sk_buff *skb;
546
        unsigned long flags;
547
        int err;
548
 
549
        del_timer(&pdata->retransmit);
550
        if(pdata->state == SPX_CLOSED)
551
                return;
552
        if(pdata->retransmits > RETRY_COUNT)
553
        {
554
                spx_close_socket(sk);   /* Unilateral Abort */
555
                return;
556
        }
557
 
558
        /* Need to leave skb on the queue, aye the fear */
559
        save_flags(flags);
560
        cli();
561
        skb = skb_peek(&pdata->retransmit_queue);
562
        if(skb_cloned(skb))
563
                skb = skb_copy(skb, GFP_ATOMIC);
564
        else
565
                skb = skb_clone(skb, GFP_ATOMIC);
566
        restore_flags(flags);
567
 
568
        pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
569
        add_timer(&pdata->retransmit);
570
 
571
        err = spx_route_skb(pdata, skb, RETRAN);
572
        pdata->retransmits++;
573
 
574
        return;
575
}
576
 
577
/* Check packet for retransmission, ConReqAck aware */
578
static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type)
579
{
580
        struct ipxspxhdr *ipxh;
581
        struct sk_buff *skb;
582
 
583
        skb = skb_dequeue(&pdata->retransmit_queue);
584
        if(!skb)
585
                return (-ENOENT);
586
 
587
        /* Check Data/ACK seq */
588
        switch(type)
589
        {
590
                case ACK:       /* Check Sequence, Should == 1 */
591
                        ipxh = (struct ipxspxhdr *)skb->nh.raw;
592
                        if(!(ntohs(ipxh->spx.sequence) - htons(ackseq)))
593
                                break;
594
 
595
                case CONACK:
596
                        del_timer(&pdata->retransmit);
597
                        pdata->retransmits = 0;
598
                        kfree_skb(skb);
599
                        if(skb_queue_empty(&pdata->retransmit_queue))
600
                        {
601
                                skb = skb_dequeue(&pdata->transmit_queue);
602
                                if(skb != NULL)
603
                                        spx_route_skb(pdata, skb, TQUEUE);
604
                        }
605
                        return (0);
606
        }
607
 
608
        skb_queue_head(&pdata->retransmit_queue, skb);
609
        return (-1);
610
}
611
 
612
/* SPX packet receive engine */
613
void spx_rcv(struct sock *sk, int bytes)
614
{
615
        struct sk_buff *skb;
616
        struct ipxspxhdr *ipxh;
617
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
618
 
619
        skb = skb_dequeue(&sk->receive_queue);
620
        if(skb == NULL)
621
                return;
622
        ipxh = (struct ipxspxhdr *)skb->nh.raw;
623
 
624
        /* Can't receive on a closed connection */
625
        if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0))
626
                goto toss_skb;
627
        if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN)
628
                goto toss_skb;
629
        if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)
630
                goto toss_skb;
631
        if(ntohs(ipxh->spx.ackseq) > pdata->sequence)
632
                goto toss_skb;
633
 
634
        /* Reset WD timer on any received packet */
635
        del_timer(&pdata->watchdog);
636
        pdata->retries = 0;
637
        pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
638
        add_timer(&pdata->watchdog);
639
 
640
        switch(ipxh->spx.cctl)
641
        {
642
                case (CCTL_SYS | CCTL_ACK):
643
                        if((ipxh->spx.sequence == 0)     /* ConReq */
644
                                && (ipxh->spx.ackseq == 0)
645
                                && (ipxh->spx.dconn == 0xFFFF))
646
                        {
647
                                pdata->state            = SPX_CONNECTED;
648
                                pdata->dest_addr        = ipxh->ipx.ipx_source;
649
                                pdata->source_addr      = ipxh->ipx.ipx_dest;
650
                                pdata->dest_connid      = ipxh->spx.sconn;
651
                                pdata->alloc = 3 + ntohs(ipxh->spx.sequence);
652
 
653
                                skb_queue_tail(&sk->receive_queue, skb);
654
                                wake_up_interruptible(sk->sleep);
655
                        }
656
                        else    /* WD Request */
657
                                spx_transmit(sk, skb, WDACK, 0);
658
                        goto finish;
659
 
660
                case CCTL_SYS:  /* ACK */
661
                        if((ipxh->spx.dtype == 0)       /* ConReq ACK */
662
                                && (ipxh->spx.sconn != 0xFFFF)
663
                                && (ipxh->spx.dconn != 0xFFFF)
664
                                && (ipxh->spx.sequence == 0)
665
                                && (ipxh->spx.ackseq == 0)
666
                                && (pdata->state != SPX_CONNECTED))
667
                        {
668
                                pdata->state = SPX_CONNECTED;
669
                                pdata->dest_connid = ipxh->spx.sconn;
670
 
671
                                if(spx_retransmit_chk(pdata, 0, CONACK) < 0)
672
                                        goto toss_skb;
673
 
674
                                skb_queue_tail(&sk->receive_queue, skb);
675
                                wake_up_interruptible(sk->sleep);
676
                                goto finish;
677
                        }
678
 
679
                        spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);
680
                        goto toss_skb;
681
 
682
                case (CCTL_ACK):
683
                        /* Informed Disconnect */
684
                        if(ipxh->spx.dtype == SPX_DTYPE_ECONN)
685
                        {
686
 
687
                                spx_transmit(sk, skb, DISACK, 0);
688
                                spx_close_socket(sk);
689
                                goto finish;
690
                        }
691
                        /* Fall through */
692
 
693
                default:
694
                        if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq)
695
                        {
696
                                pdata->rmt_seq = ntohs(ipxh->spx.sequence);
697
                                pdata->rmt_ack = ntohs(ipxh->spx.ackseq);
698
                                pdata->alloc   = pdata->rmt_seq + 3;
699
                                if(pdata->rmt_ack > 0 || pdata->rmt_ack == 0)
700
                                        spx_retransmit_chk(pdata,pdata->rmt_ack, ACK);
701
 
702
                                skb_queue_tail(&pdata->rcv_queue, skb);
703
                                wake_up_interruptible(sk->sleep);
704
                                if(ipxh->spx.cctl&CCTL_ACK)
705
                                        spx_transmit(sk, NULL, ACK, 0);
706
                                goto finish;
707
                        }
708
 
709
                        if(ipxh->spx.dtype == SPX_DTYPE_ECACK)
710
                        {
711
                                if(pdata->state != SPX_CLOSED)
712
                                        spx_close_socket(sk);
713
                                goto toss_skb;
714
                        }
715
        }
716
 
717
toss_skb:       /* Catch All */
718
        kfree_skb(skb);
719
finish:
720
        return;
721
}
722
 
723
/* Get message/packet data from user-land */
724
static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
725
                        struct scm_cookie *scm)
726
{
727
        struct sock *sk = sock->sk;
728
        int flags = msg->msg_flags;
729
        struct sk_buff *skb;
730
        int err, offset, size;
731
 
732
        if(len > 534)
733
                return (-EMSGSIZE);
734
        if(sk->zapped)
735
                return (-ENOTCONN); /* Socket not bound */
736
        if(flags&~MSG_DONTWAIT)
737
                return (-EINVAL);
738
 
739
        offset  = ipx_if_offset(sk->tp_pinfo.af_spx.dest_addr.net);
740
        size    = offset + sizeof(struct ipxspxhdr) + len;
741
 
742
        cli();
743
        skb     = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err);
744
        sti();
745
        if(skb == NULL)
746
                return (err);
747
 
748
        skb->sk = sk;
749
        skb_reserve(skb, offset);
750
        skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
751
 
752
        err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
753
        if(err)
754
        {
755
                kfree_skb(skb);
756
                return (-EFAULT);
757
        }
758
 
759
        err = spx_transmit(sk, skb, DATA, len);
760
        if(err)
761
                return (-EAGAIN);
762
 
763
        return (len);
764
}
765
 
766
/* Send message/packet data to user-land */
767
static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
768
                        int flags, struct scm_cookie *scm)
769
{
770
        struct sk_buff *skb;
771
        struct ipxspxhdr *ispxh;
772
        struct sock *sk = sock->sk;
773
        struct spx_opt *pdata = &sk->tp_pinfo.af_spx;
774
        struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
775
        int copied, err;
776
 
777
        if(sk->zapped)
778
                return (-ENOTCONN); /* Socket not bound */
779
 
780
        lock_sock(sk);
781
restart:
782
        while(skb_queue_empty(&pdata->rcv_queue))      /* No data */
783
        {
784
                /* Socket errors? */
785
                err = sock_error(sk);
786
                if(err)
787
                        return (err);
788
 
789
                /* Socket shut down? */
790
                if(sk->shutdown & RCV_SHUTDOWN)
791
                        return (-ESHUTDOWN);
792
 
793
                /* handle signals */
794
                if(signal_pending(current))
795
                        return (-ERESTARTSYS);
796
 
797
                /* User doesn't want to wait */
798
                if(flags&MSG_DONTWAIT)
799
                        return (-EAGAIN);
800
 
801
                release_sock(sk);
802
                save_flags(flags);
803
                cli();
804
                if(skb_peek(&pdata->rcv_queue) == NULL)
805
                        interruptible_sleep_on(sk->sleep);
806
                restore_flags(flags);
807
                lock_sock(sk);
808
        }
809
 
810
        skb = skb_dequeue(&pdata->rcv_queue);
811
        if(skb == NULL)
812
                goto restart;
813
 
814
        ispxh   = (struct ipxspxhdr *)skb->nh.raw;
815
        copied  = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
816
        if(copied > size)
817
        {
818
                copied = size;
819
                msg->msg_flags |= MSG_TRUNC;
820
        }
821
 
822
        err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied);
823
        if(err)
824
                return (-EFAULT);
825
 
826
        msg->msg_namelen = sizeof(*sipx);
827
        if(sipx)
828
        {
829
                sipx->sipx_family       = AF_IPX;
830
                sipx->sipx_port         = ispxh->ipx.ipx_source.sock;
831
                memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
832
                sipx->sipx_network      = ispxh->ipx.ipx_source.net;
833
                sipx->sipx_type         = ispxh->ipx.ipx_type;
834
        }
835
        kfree_skb(skb);
836
        release_sock(sk);
837
 
838
        return (copied);
839
}
840
 
841
/*
842
 * Functions which just wrap their IPX cousins
843
 */
844
 
845
static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
846
{
847
        int err;
848
        err = ipx_operations->bind(sock, uaddr, addr_len);
849
        return (err);
850
}
851
 
852
static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
853
                         int *usockaddr_len, int peer)
854
{
855
        int err;
856
        err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
857
        return (err);
858
}
859
 
860
static int spx_ioctl (struct socket *sock, unsigned int cmd,
861
                         unsigned long arg)
862
{
863
        int err;
864
        err = ipx_operations->ioctl(sock, cmd, arg);
865
        return (err);
866
}
867
 
868
static int spx_setsockopt(struct socket *sock, int level, int optname,
869
                         char *optval, int optlen)
870
{
871
        int err;
872
        err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
873
        return (err);
874
}
875
 
876
static int spx_getsockopt(struct socket *sock, int level, int optname,
877
                         char *optval, int *optlen)
878
{
879
        int err;
880
        err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
881
        return (err);
882
}
883
 
884
static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
885
        family:         PF_IPX,
886
 
887
        release:        spx_release,
888
        bind:           spx_bind,
889
        connect:        spx_connect,
890
        socketpair:     sock_no_socketpair,
891
        accept:         spx_accept,
892
        getname:        spx_getname,
893
        poll:           spx_datagram_poll,
894
        ioctl:          spx_ioctl,
895
        listen:         spx_listen,
896
        shutdown:       sock_no_shutdown,
897
        setsockopt:     spx_setsockopt,
898
        getsockopt:     spx_getsockopt,
899
        sendmsg:        spx_sendmsg,
900
        recvmsg:        spx_recvmsg,
901
        mmap:           sock_no_mmap,
902
        sendpage:       sock_no_sendpage,
903
};
904
 
905
#include <linux/smp_lock.h>
906
SOCKOPS_WRAP(spx, PF_IPX);
907
 
908
static struct net_proto_family spx_family_ops = {
909
        family:         PF_IPX,
910
        create:         spx_create,
911
};
912
 
913
static char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n";
914
 
915
static int __init spx_proto_init(void)
916
{
917
        int error;
918
 
919
        connids = (__u16)jiffies;       /* initalize random */
920
 
921
        error = ipx_register_spx(&ipx_operations, &spx_family_ops);
922
        if (error)
923
                printk(KERN_ERR "SPX: unable to register with IPX.\n");
924
 
925
        /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
926
 
927
        printk(banner);
928
        return 0;
929
}
930
module_init(spx_proto_init);
931
 
932
static void __exit spx_proto_finito(void)
933
{
934
        ipx_unregister_spx();
935
        return;
936
}
937
module_exit(spx_proto_finito);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.