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