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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [redboot/] [v2_0/] [src/] [net/] [tcp.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1254 phoenix
//==========================================================================
2
//
3
//      net/tcp.c
4
//
5
//      Stand-alone TCP networking support for RedBoot
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):    gthomas
44
// Contributors: gthomas
45
// Date:         2000-07-14
46
// Purpose:      
47
// Description:  
48
//              
49
// This code is part of RedBoot (tm).
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include <net/net.h>
56
 
57
#define MAX_TCP_SEGMENT (ETH_MAX_PKTLEN - (sizeof(eth_header_t) + sizeof(ip_header_t)))
58
#define MAX_TCP_DATA    (MAX_TCP_SEGMENT - sizeof(tcp_header_t))
59
 
60
 
61
/* sequence number comparison macros */
62
#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
63
#define SEQ_LE(a,b) ((int)((a)-(b)) <= 0)
64
#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
65
#define SEQ_GE(a,b) ((int)((a)-(b)) >= 0)
66
 
67
/* Set a timer which will send an RST and abort a connection. */
68
static timer_t abort_timer;
69
 
70
static void do_retrans(void *p);
71
static void do_close(void *p);
72
 
73
#ifdef BSP_LOG
74
static char *
75
flags_to_str(octet f)
76
{
77
    static char str[7], *p;
78
 
79
    p = str;
80
 
81
    if (f & TCP_FLAG_FIN)
82
        *p++ = 'F';
83
    if (f & TCP_FLAG_SYN)
84
        *p++ = 'S';
85
    if (f & TCP_FLAG_RST)
86
        *p++ = 'R';
87
    if (f & TCP_FLAG_PSH)
88
        *p++ = 'P';
89
    if (f & TCP_FLAG_ACK)
90
        *p++ = 'A';
91
    if (f & TCP_FLAG_URG)
92
        *p++ = 'U';
93
    *p = '\0';
94
    return str;
95
}
96
#endif
97
 
98
/*
99
 * A major assumption is that only a very small number of sockets will
100
 * active, so a simple linear search of those sockets is acceptible.
101
 */
102
static tcp_socket_t *tcp_list;
103
 
104
/*
105
 * Format and send an outgoing segment.
106
 */
107
static void
108
tcp_send(tcp_socket_t *s, int flags, int resend)
109
{
110
    tcp_header_t *tcp;
111
    ip_header_t  *ip;
112
    pktbuf_t     *pkt = &s->pkt;
113
    unsigned short cksum;
114
    dword         tcp_magic;
115
    int           tcp_magic_size = sizeof(tcp_magic);
116
 
117
    ip = pkt->ip_hdr;
118
    tcp = pkt->tcp_hdr;
119
 
120
    if (flags & TCP_FLAG_SYN) {
121
        /* If SYN, assume no data and send MSS option in tcp header */
122
        pkt->pkt_bytes = sizeof(tcp_header_t) + 4;
123
        tcp->hdr_len = 6;
124
        tcp_magic = htonl(0x02040000 | MAX_TCP_DATA);
125
        memcpy((unsigned char *)(tcp+1), &tcp_magic, tcp_magic_size);
126
        s->data_bytes = 0;
127
    } else {
128
        pkt->pkt_bytes = s->data_bytes + sizeof(tcp_header_t);
129
        tcp->hdr_len = 5;
130
    }
131
 
132
    /* tcp header */
133
    tcp->reserved = 0;
134
    tcp->seqnum = htonl(s->seq);
135
    tcp->acknum = htonl(s->ack);
136
    tcp->checksum = 0;
137
 
138
    if (!resend) {
139
        tcp->src_port = htons(s->our_port);
140
        tcp->dest_port = htons(s->his_port);
141
        tcp->flags = flags;
142
        /* always set PUSH flag if sending data */
143
        if (s->data_bytes)
144
            tcp->flags |= TCP_FLAG_PSH;
145
        tcp->window = htons(MAX_TCP_DATA);
146
        tcp->urgent = 0;
147
 
148
        /* fill in some pseudo-header fields */
149
        memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
150
        memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
151
        ip->protocol = IP_PROTO_TCP;
152
    }
153
 
154
    /* another pseudo-header field */
155
    ip->length = htons(pkt->pkt_bytes);
156
 
157
    /* compute tcp checksum */
158
    cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
159
    tcp->checksum = htons(cksum);
160
 
161
    __ip_send(pkt, IP_PROTO_TCP, &s->his_addr);
162
 
163
    BSPLOG(bsp_log("tcp_send: state[%d] flags[%s] ack[%x] data[%d].\n",
164
                   s->state, flags_to_str(tcp->flags), s->ack, s->data_bytes));
165
 
166
    if (s->state == _TIME_WAIT) {
167
        // If 'reuse' is set on socket, close after 1 second, otherwise 2 minutes
168
        __timer_set(&s->timer, s->reuse ? 1000 : 120000, do_close, s);
169
    }
170
    else if ((tcp->flags & (TCP_FLAG_FIN | TCP_FLAG_SYN)) || s->data_bytes)
171
        __timer_set(&s->timer, 1000, do_retrans, s);
172
}
173
 
174
static pktbuf_t ack_pkt;
175
static word     ack_buf[ETH_MIN_PKTLEN/sizeof(word)];
176
 
177
/*
178
 * Send an ack.
179
 */
180
static void
181
send_ack(tcp_socket_t *s)
182
{
183
    tcp_header_t *tcp;
184
    ip_header_t  *ip;
185
    unsigned short cksum;
186
 
187
    ack_pkt.buf = ack_buf;
188
    ack_pkt.bufsize = sizeof(ack_buf);
189
    ack_pkt.ip_hdr = ip = (ip_header_t *)ack_buf;
190
    ack_pkt.tcp_hdr = tcp = (tcp_header_t *)(ip + 1);
191
    ack_pkt.pkt_bytes = sizeof(tcp_header_t);
192
 
193
    /* tcp header */
194
    tcp->hdr_len = 5;
195
    tcp->reserved = 0;
196
    tcp->seqnum = htonl(s->seq);
197
    tcp->acknum = htonl(s->ack);
198
    tcp->checksum = 0;
199
 
200
    tcp->src_port = htons(s->our_port);
201
    tcp->dest_port = htons(s->his_port);
202
    tcp->flags = TCP_FLAG_ACK;
203
 
204
    tcp->window = htons(MAX_TCP_DATA);
205
    tcp->urgent = 0;
206
 
207
    /* fill in some pseudo-header fields */
208
    memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
209
    memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
210
    ip->protocol = IP_PROTO_TCP;
211
 
212
    /* another pseudo-header field */
213
    ip->length = htons(sizeof(tcp_header_t));
214
 
215
    /* compute tcp checksum */
216
    cksum = __sum((word *)tcp, sizeof(*tcp), __pseudo_sum(ip));
217
    tcp->checksum = htons(cksum);
218
 
219
    __ip_send(&ack_pkt, IP_PROTO_TCP, &s->his_addr);
220
}
221
 
222
 
223
/*
224
 * Send a reset for a bogus incoming segment.
225
 */
226
static void
227
send_reset(pktbuf_t *pkt, ip_route_t *r)
228
{
229
    ip_header_t   *ip = pkt->ip_hdr;
230
    tcp_header_t  *tcp = pkt->tcp_hdr;
231
    dword         seq, ack;
232
    word          src, dest;
233
    word          cksum;
234
 
235
    seq = ntohl(tcp->acknum);
236
    ack = ntohl(tcp->seqnum);
237
    src = ntohs(tcp->dest_port);
238
    dest = ntohs(tcp->src_port);
239
 
240
    tcp = (tcp_header_t *)(ip + 1);
241
    pkt->pkt_bytes = sizeof(tcp_header_t);
242
 
243
    /* tcp header */
244
    tcp->hdr_len = 5;
245
    tcp->reserved = 0;
246
    tcp->seqnum = htonl(seq);
247
    tcp->acknum = htonl(ack);
248
    tcp->window = htons(1024);
249
    tcp->urgent = 0;
250
    tcp->checksum = 0;
251
    tcp->src_port = htons(src);
252
    tcp->dest_port = htons(dest);
253
    tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
254
 
255
    /* fill in some pseudo-header fields */
256
    memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
257
    memcpy(ip->destination, r->ip_addr, sizeof(ip_addr_t));
258
    ip->protocol = IP_PROTO_TCP;
259
    ip->length = htons(pkt->pkt_bytes);
260
 
261
    /* compute tcp checksum */
262
    cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
263
    tcp->checksum = htons(cksum);
264
 
265
    __ip_send(pkt, IP_PROTO_TCP, r);
266
}
267
 
268
 
269
 
270
/*
271
 * Remove given socket from socket list.
272
 */
273
static void
274
unlink_socket(tcp_socket_t *s)
275
{
276
    tcp_socket_t *prev, *tp;
277
 
278
    for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next)
279
        if (tp == s) {
280
            BSPLOG(bsp_log("unlink tcp socket.\n"));
281
            if (prev)
282
                prev->next = s->next;
283
            else
284
                tcp_list = s->next;
285
        }
286
}
287
 
288
/*
289
 * Retransmit last packet.
290
 */
291
static void
292
do_retrans(void *p)
293
{
294
    BSPLOG(bsp_log("tcp do_retrans.\n"));
295
    tcp_send((tcp_socket_t *)p, 0, 1);
296
}
297
 
298
 
299
static void
300
do_close(void *p)
301
{
302
    BSPLOG(bsp_log("tcp do_close.\n"));
303
    /* close connection */
304
    ((tcp_socket_t *)p)->state = _CLOSED;
305
    unlink_socket(p);
306
}
307
 
308
 
309
static void
310
free_rxlist(tcp_socket_t *s)
311
{
312
    pktbuf_t *p;
313
 
314
    BSPLOG(bsp_log("tcp free_rxlist.\n"));
315
 
316
    while ((p = s->rxlist) != NULL) {
317
        s->rxlist = p->next;
318
        __pktbuf_free(p);
319
    }
320
}
321
 
322
 
323
/*
324
 * Handle a conection reset.
325
 */
326
static void
327
do_reset(tcp_socket_t *s)
328
{
329
    /* close connection */
330
    s->state = _CLOSED;
331
    __timer_cancel(&s->timer);
332
    free_rxlist(s);
333
    unlink_socket(s);
334
}
335
 
336
 
337
/*
338
 * Extract data from incoming tcp segment.
339
 * Returns true if packet is queued on rxlist, false otherwise.
340
 */
341
static int
342
handle_data(tcp_socket_t *s, pktbuf_t *pkt)
343
{
344
    tcp_header_t  *tcp = pkt->tcp_hdr;
345
    unsigned int  diff, seq;
346
    int           data_len;
347
    char          *data_ptr;
348
    pktbuf_t      *p;
349
 
350
    data_len = pkt->pkt_bytes - (tcp->hdr_len << 2);
351
    data_ptr = ((char *)tcp)  + (tcp->hdr_len << 2);
352
 
353
    seq = ntohl(tcp->seqnum);
354
 
355
    BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len));
356
 
357
    if (SEQ_LE(seq, s->ack)) {
358
        /*
359
         * Figure difference between which byte we're expecting and which byte
360
         * is sent first. Adjust data length and data pointer accordingly.
361
         */
362
        diff = s->ack - seq;
363
        data_len -= diff;
364
        data_ptr += diff;
365
 
366
        if (data_len > 0) {
367
            /* queue the new data */
368
            s->ack += data_len;
369
            pkt->next = NULL;
370
            if ((p = s->rxlist) != NULL) {
371
                while (p->next)
372
                    p = p->next;
373
                p->next = pkt;
374
                BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",
375
                               pkt, data_len));
376
            } else {
377
                s->rxlist = pkt;
378
                s->rxcnt = data_len;
379
                s->rxptr = data_ptr;
380
                BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n",
381
                               pkt, data_len));
382
            }
383
            return 1;
384
        }
385
    }
386
    return 0;
387
}
388
 
389
 
390
static void
391
handle_ack(tcp_socket_t *s, pktbuf_t *pkt)
392
{
393
    tcp_header_t *tcp = pkt->tcp_hdr;
394
    dword        ack;
395
    int          advance;
396
    char         *dp;
397
 
398
    /* process ack value in packet */
399
    ack = ntohl(tcp->acknum);
400
 
401
    BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack));
402
 
403
    if (SEQ_GT(ack, s->seq)) {
404
        __timer_cancel(&s->timer);
405
        advance = ack - s->seq;
406
        if (advance > s->data_bytes)
407
            advance = s->data_bytes;
408
 
409
        BSPLOG(bsp_log("seq advance %d", advance));
410
 
411
        if (advance > 0) {
412
            s->seq += advance;
413
            s->data_bytes -= advance;
414
            if (s->data_bytes) {
415
                /* other end ack'd only part of the pkt */
416
                BSPLOG(bsp_log(" %d bytes left", s->data_bytes));
417
                dp = (char *)(s->pkt.tcp_hdr + 1);
418
                memcpy(dp, dp + advance, s->data_bytes);
419
            }
420
        }
421
    }
422
    BSPLOG(bsp_log("\n"));
423
}
424
 
425
 
426
/*
427
 * Handle incoming TCP packets.
428
 */
429
void
430
__tcp_handler(pktbuf_t *pkt, ip_route_t *r)
431
{
432
    tcp_header_t *tcp = pkt->tcp_hdr;
433
    ip_header_t  *ip = pkt->ip_hdr;
434
    tcp_socket_t *prev,*s;
435
    dword        ack;
436
    int          queued = 0;
437
 
438
    /* set length for pseudo sum calculation */
439
    ip->length = htons(pkt->pkt_bytes);
440
 
441
    if (__sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)) == 0) {
442
        for (prev = NULL, s = tcp_list; s; prev = s, s = s->next) {
443
            if (s->our_port == ntohs(tcp->dest_port)) {
444
                if (s->his_port == 0)
445
                    break;
446
                if (s->his_port == ntohs(tcp->src_port) &&
447
                    !memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
448
                    break;
449
            }
450
        }
451
 
452
        if (s) {
453
            /* found the socket this packet belongs to */
454
 
455
            /* refresh his ethernet address */
456
            memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
457
 
458
            if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
459
                BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));
460
                do_reset(s);
461
                __pktbuf_free(pkt);
462
                return;
463
            }
464
 
465
            switch (s->state) {
466
 
467
              case _SYN_SENT:
468
                /* active open not supported */
469
                  if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
470
                      do_reset(s);
471
                      __pktbuf_free(pkt);
472
                      return;
473
                  }
474
                  s->state = _ESTABLISHED;
475
                  s->ack = ntohl(tcp->seqnum) + 1;
476
                  s->seq = ntohl(tcp->acknum);
477
                  send_ack(s);
478
                break;
479
 
480
              case _LISTEN:
481
                if (tcp->flags & TCP_FLAG_SYN) {
482
                    s->state = _SYN_RCVD;
483
                    s->ack = ntohl(tcp->seqnum) + 1;
484
                    s->his_port = ntohs(tcp->src_port);
485
                    memcpy(s->his_addr.ip_addr, r->ip_addr, sizeof(ip_addr_t));
486
                    s->data_bytes = 0;
487
 
488
                    BSPLOG(bsp_log("SYN from %d.%d.%d.%d:%d (seq %x)\n",
489
                               s->his_addr.ip_addr[0],s->his_addr.ip_addr[1],
490
                               s->his_addr.ip_addr[2],s->his_addr.ip_addr[3],
491
                               s->his_port, ntohl(tcp->seqnum)));
492
 
493
                    tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
494
                }
495
                else
496
                    send_reset(pkt, r);
497
                break;
498
 
499
              case _SYN_RCVD:
500
                BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));
501
                __timer_cancel(&s->timer);
502
 
503
                /* go back to _LISTEN state if reset */
504
                if (tcp->flags & TCP_FLAG_RST) {
505
                    s->state = _LISTEN;
506
 
507
                    BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));
508
 
509
                } else if (tcp->flags & TCP_FLAG_SYN) {
510
                    /* apparently our SYN/ACK was lost? */
511
                    tcp_send(s, 0, 1);
512
 
513
                    BSPLOG(bsp_log("retransmitting SYN/ACK\n"));
514
 
515
                } else if ((tcp->flags & TCP_FLAG_ACK) &&
516
                           ntohl(tcp->acknum) == (s->seq + 1)) {
517
                    /* we've established the connection */
518
                    s->state = _ESTABLISHED;
519
                    s->seq++;
520
 
521
                    BSPLOG(bsp_log("ACK received - connection established\n"));
522
                }
523
                break;
524
 
525
              case _ESTABLISHED:
526
              case _CLOSE_WAIT:
527
                ack = s->ack;  /* save original ack */
528
                if (tcp->flags & TCP_FLAG_ACK)
529
                    handle_ack(s, pkt);
530
 
531
                queued = handle_data(s, pkt);
532
 
533
                if ((tcp->flags & TCP_FLAG_FIN) &&
534
                    ntohl(tcp->seqnum) == s->ack) {
535
 
536
                    BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));
537
 
538
                    s->ack++;
539
                    s->state = _CLOSE_WAIT;
540
                }
541
                /*
542
                 * Send an ack if neccessary.
543
                 */
544
                if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))
545
                    send_ack(s);
546
                break;
547
 
548
              case _LAST_ACK:
549
                if (tcp->flags & TCP_FLAG_ACK) {
550
                    handle_ack(s, pkt);
551
                    if (ntohl(tcp->acknum) == (s->seq + 1)) {
552
                        BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));
553
                        s->state = _CLOSED;
554
                        unlink_socket(s);
555
                    }
556
                }
557
                break;
558
 
559
              case _FIN_WAIT_1:
560
                if (tcp->flags & TCP_FLAG_ACK) {
561
                    handle_ack(s, pkt);
562
                    if (ntohl(tcp->acknum) == (s->seq + 1)) {
563
                        /* got ACK for FIN packet */
564
                        s->seq++;
565
                        if (tcp->flags & TCP_FLAG_FIN) {
566
                            BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));
567
                            s->ack++;
568
                            s->state = _TIME_WAIT;
569
                            send_ack(s);
570
                        } else {
571
                            s->state = _FIN_WAIT_2;
572
                            BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
573
                        }
574
                        break; /* All done for now */
575
                    }
576
                }
577
                /* At this point, no ACK for FIN has been seen, so check for
578
                   simultaneous close */
579
                if (tcp->flags & TCP_FLAG_FIN) {
580
                    BSPLOG(bsp_log("_FIN_WAIT_1 --> _CLOSING\n"));
581
                    __timer_cancel(&s->timer);
582
                    s->ack++;
583
                    s->state = _CLOSING;
584
                    /* FIN is resent so the timeout and retry for this packet
585
                       will also take care of timeout and resend of the
586
                       previously sent FIN (which got us to FIN_WAIT_1). While
587
                       not technically correct, resending FIN only causes a
588
                       duplicate FIN (same sequence number) which should be
589
                       ignored by the other end. */
590
                    tcp_send(s, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);
591
                }
592
                break;
593
 
594
              case _FIN_WAIT_2:
595
                queued = handle_data(s, pkt);
596
                if (tcp->flags & TCP_FLAG_FIN) {
597
                    BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));
598
                    s->ack++;
599
                    s->state = _TIME_WAIT;
600
                    send_ack(s);
601
                }
602
                break;
603
 
604
              case _CLOSING:
605
                if (tcp->flags & TCP_FLAG_ACK) {
606
                    handle_ack(s, pkt);
607
                    if (ntohl(tcp->acknum) == (s->seq + 1)) {
608
                        /* got ACK for FIN packet */
609
                        BSPLOG(bsp_log("_CLOSING --> _TIME_WAIT\n"));
610
                        __timer_cancel(&s->timer);
611
                        s->state = _TIME_WAIT;
612
                    }
613
                }
614
                break;
615
 
616
              case _TIME_WAIT:
617
                BSPLOG(bsp_log("_TIME_WAIT resend.\n"));
618
                if (tcp->flags & TCP_FLAG_FIN)
619
                    tcp_send(s, 0, 1); /* just resend ack */
620
                break;
621
            }
622
        } else {
623
            BSPLOG(bsp_log("Unexpected segment from: %d.%d.%d.%d:%d\n",
624
                           r->ip_addr[0], r->ip_addr[1], r->ip_addr[3],
625
                           r->ip_addr[4], ntohs(tcp->src_port)));
626
            send_reset(pkt, r);
627
        }
628
    }
629
    if (!queued)
630
        __pktbuf_free(pkt);
631
}
632
 
633
 
634
void
635
__tcp_poll(void)
636
{
637
    __enet_poll();
638
    MS_TICKS_DELAY();
639
    __timer_poll();
640
}
641
 
642
 
643
int
644
__tcp_listen(tcp_socket_t *s, word port)
645
{
646
    BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));
647
 
648
    memset(s, 0, sizeof(tcp_socket_t));
649
    s->state    = _LISTEN;
650
    s->our_port = port;
651
    s->pkt.buf = (word *)s->pktbuf;
652
    s->pkt.bufsize = ETH_MAX_PKTLEN;
653
    s->pkt.ip_hdr  = (ip_header_t *)s->pkt.buf;
654
    s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
655
 
656
    s->next = tcp_list;
657
 
658
#if 0
659
    /* limit to one open socket at a time */
660
    if (s->next) {
661
        BSPLOG(bsp_log("tcp_listen: recursion error\n"));
662
        BSPLOG(while(1));
663
    }
664
#endif
665
 
666
    tcp_list = s;
667
 
668
    return 0;
669
}
670
 
671
/*
672
 * SO_REUSEADDR, no 2MSL.
673
 */
674
void
675
__tcp_so_reuseaddr(tcp_socket_t *s)
676
{
677
//    BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));
678
    s->reuse = 0x01;
679
}
680
 
681
/*
682
 * Block while waiting for all data to be transmitted.
683
 */
684
void
685
__tcp_drain(tcp_socket_t *s)
686
{
687
//    BSPLOG(bsp_log("__tcp_drain.\n"));
688
    while (s->state != _CLOSED && s->data_bytes)
689
        __tcp_poll();
690
//    BSPLOG(bsp_log("__tcp_drain done.\n"));
691
}
692
 
693
 
694
/*
695
 * Close the tcp connection.
696
 */
697
static void
698
do_abort(void *s)
699
{
700
    BSPLOG(bsp_log("do_abort: send RST\n"));
701
    tcp_send((tcp_socket_t *)s, TCP_FLAG_ACK | TCP_FLAG_RST, 0);
702
    __timer_cancel(&abort_timer);
703
    ((tcp_socket_t *)s)->state = _CLOSED;
704
    free_rxlist((tcp_socket_t *)s);
705
    unlink_socket((tcp_socket_t *)s);
706
}
707
 
708
void
709
__tcp_abort(tcp_socket_t *s, unsigned long delay)
710
{
711
  __timer_set(&abort_timer, delay, do_abort, s);
712
}
713
 
714
/*
715
 * Close the tcp connection.
716
 */
717
void
718
__tcp_close(tcp_socket_t *s)
719
{
720
    __tcp_drain(s);
721
    if (s->state == _ESTABLISHED || s->state == _SYN_RCVD) {
722
        BSPLOG(bsp_log("__tcp_close: going to _FIN_WAIT_1\n"));
723
        s->state = _FIN_WAIT_1;
724
        tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
725
    } else if (s->state == _CLOSE_WAIT) {
726
 
727
        BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));
728
 
729
        s->state = _LAST_ACK;
730
        tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
731
    }
732
    free_rxlist(s);
733
}
734
 
735
 
736
/*
737
 * Wait for connection to be fully closed.
738
 */
739
void
740
__tcp_close_wait(tcp_socket_t *s)
741
{
742
    BSPLOG(bsp_log("__tcp_close_wait.\n"));
743
    while (s->state != _CLOSED)
744
        __tcp_poll();
745
    BSPLOG(bsp_log("__tcp_close_wait done.\n"));
746
}
747
 
748
 
749
/*
750
 * Read up to 'len' bytes without blocking.
751
 */
752
int
753
__tcp_read(tcp_socket_t *s, char *buf, int len)
754
{
755
    int          nread;
756
    pktbuf_t     *pkt;
757
    tcp_header_t *tcp;
758
 
759
    if (len <= 0 || s->rxcnt == 0)
760
        return 0;
761
 
762
    if (s->state != _ESTABLISHED && s->rxcnt == 0)
763
        return -1;
764
 
765
    nread = 0;
766
    while (len) {
767
        if (len < s->rxcnt) {
768
            memcpy(buf, s->rxptr, len);
769
            BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));
770
            s->rxptr += len;
771
            s->rxcnt -= len;
772
            nread    += len;
773
 
774
            BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",
775
                       s->rxcnt));
776
 
777
            break;
778
        } else {
779
            memcpy(buf, s->rxptr, s->rxcnt);
780
            BSPLOG(bsp_log("tcp_read: read %d bytes. pkt[%x] freed.\n",
781
                           s->rxcnt, s->rxlist));
782
            nread += s->rxcnt;
783
            buf   += s->rxcnt;
784
            len   -= s->rxcnt;
785
 
786
            /* setup for next packet in list */
787
            pkt = s->rxlist;
788
            s->rxlist = pkt->next;
789
            __pktbuf_free(pkt);
790
 
791
            if ((pkt = s->rxlist) != NULL) {
792
                tcp = pkt->tcp_hdr;
793
                s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);
794
                s->rxptr = ((char *)tcp)  + (tcp->hdr_len << 2);
795
 
796
                BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",
797
                           s->rxlist, s->rxcnt));
798
            } else {
799
 
800
                BSPLOG(bsp_log("tcp_read: no more data.\n"));
801
 
802
                s->rxcnt = 0;
803
                break;
804
            }
805
        }
806
    }
807
    return nread;
808
}
809
 
810
 
811
/*
812
 * Write up to 'len' bytes without blocking
813
 */
814
int
815
__tcp_write(tcp_socket_t *s, char *buf, int len)
816
{
817
    tcp_header_t *tcp = s->pkt.tcp_hdr;
818
 
819
    if (len <= 0)
820
        return 0;
821
 
822
    if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)
823
        return -1;
824
 
825
    if (s->data_bytes)
826
        return 0;
827
 
828
    if (len > MAX_TCP_DATA)
829
        len = MAX_TCP_DATA;
830
 
831
    memcpy(tcp + 1, buf, len);
832
    s->data_bytes = len;
833
 
834
    tcp_send(s, TCP_FLAG_ACK, 0);
835
 
836
    return len;
837
}
838
 
839
/*
840
 * Write 'len' bytes from 'buf', blocking until sent.
841
 * If connection collapses, return -1
842
 */
843
int
844
__tcp_write_block(tcp_socket_t *s, char *buf, int len)
845
{
846
    int total = 0;
847
    int n;
848
 
849
    while (len) {
850
        if (s->state == _CLOSE_WAIT) {
851
            // This connection is tring to close
852
            // This connection is breaking
853
            if (s->data_bytes == 0 && s->rxcnt == 0)
854
                __tcp_close(s);
855
        }
856
        if (s->state == _CLOSED) {
857
            // The connection is gone!
858
            return -1;
859
        }
860
        n = __tcp_write(s, buf, len);
861
        if (n > 0) {
862
            len -= n;
863
            buf += n;
864
        }
865
        __tcp_poll();
866
    }
867
    __tcp_drain(s);
868
    return total;
869
}
870
 
871
/*
872
 * Establish a new [outgoing] connection, with a timeout.
873
 */
874
int
875
__tcp_open(tcp_socket_t *s, struct sockaddr_in *host,
876
           word port, int timeout, int *err)
877
{
878
    // Fill in socket details
879
    memset(s, 0, sizeof(tcp_socket_t));
880
    s->state = _SYN_SENT;
881
    s->our_port = port;
882
    s->his_port = host->sin_port;
883
    s->pkt.buf = (word *)s->pktbuf;
884
    s->pkt.bufsize = ETH_MAX_PKTLEN;
885
    s->pkt.ip_hdr  = (ip_header_t *)s->pkt.buf;
886
    s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
887
    s->seq = (port << 16) | 0xDE77;
888
    s->ack = 0;
889
    if (__arp_lookup((ip_addr_t *)&host->sin_addr, &s->his_addr) < 0) {
890
        diag_printf("%s: Can't find address of server\n", __FUNCTION__);
891
        return -1;
892
    }
893
    s->next = tcp_list;
894
    tcp_list = s;
895
 
896
    // Send off the SYN packet to open the connection
897
    tcp_send(s, TCP_FLAG_SYN, 0);
898
    // Wait for connection to establish
899
    while (s->state != _ESTABLISHED) {
900
        if (s->state == _CLOSED) {
901
            diag_printf("TCP open - host closed connection\n");
902
            return -1;
903
        }
904
        if (--timeout <= 0) {
905
            diag_printf("TCP open - connection timed out\n");
906
            return -1;
907
        }
908
        MS_TICKS_DELAY();
909
        __tcp_poll();
910
    }
911
    return 0;
912
}
913
 
914
 

powered by: WebSVN 2.1.0

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