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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [net/] [tcp.c] - Blame information for rev 856

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

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

powered by: WebSVN 2.1.0

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