]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/tcp.c
TX51 pre-release
[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 union {
183         word            w[ETH_MIN_PKTLEN / sizeof(word)];
184         struct {
185                 ip_header_t ip;
186                 tcp_header_t tcp;
187         };
188 } ack_buf;
189
190 /*
191  * Send an ack.
192  */
193 static void
194 send_ack(tcp_socket_t *s)
195 {
196         tcp_header_t *tcp;
197         ip_header_t  *ip;
198         unsigned short cksum;
199
200         ack_pkt.buf = ack_buf.w;
201         ack_pkt.bufsize = sizeof(ack_buf.w);
202         ack_pkt.ip_hdr = ip = &ack_buf.ip;
203         ack_pkt.tcp_hdr = tcp = &ack_buf.tcp;//(tcp_header_t *)(ip + 1);
204         ack_pkt.pkt_bytes = sizeof(tcp_header_t);
205
206         /* tcp header */
207         tcp->hdr_len = 5;
208         tcp->reserved = 0;
209         tcp->seqnum = htonl(s->seq);
210         tcp->acknum = htonl(s->ack);
211         tcp->checksum = 0;
212
213         tcp->src_port = htons(s->our_port);
214         tcp->dest_port = htons(s->his_port);
215         tcp->flags = TCP_FLAG_ACK;
216
217         tcp->window = htons(MAX_TCP_DATA);
218         tcp->urgent = 0;
219
220         /* fill in some pseudo-header fields */
221         memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
222         memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
223         ip->protocol = IP_PROTO_TCP;
224
225         /* another pseudo-header field */
226         ip->length = htons(sizeof(tcp_header_t));
227
228         /* compute tcp checksum */
229         cksum = __sum((word *)tcp, sizeof(*tcp), __pseudo_sum(ip));
230         tcp->checksum = htons(cksum);
231
232         __ip_send(&ack_pkt, IP_PROTO_TCP, &s->his_addr);
233 }
234
235
236 /*
237  * Send a reset for a bogus incoming segment.
238  */
239 static void
240 send_reset(pktbuf_t *pkt, ip_route_t *r)
241 {
242         ip_header_t       *ip = pkt->ip_hdr;
243         tcp_header_t  *tcp = pkt->tcp_hdr;
244         dword             seq, ack;
245         word              src, dest;
246         word              cksum;
247
248         seq = ntohl(tcp->acknum);
249         ack = ntohl(tcp->seqnum);
250         src = ntohs(tcp->dest_port);
251         dest = ntohs(tcp->src_port);
252
253         tcp = (tcp_header_t *)(ip + 1);
254         pkt->pkt_bytes = sizeof(tcp_header_t);
255
256         /* tcp header */
257         tcp->hdr_len = 5;
258         tcp->reserved = 0;
259         tcp->seqnum = htonl(seq);
260         tcp->acknum = htonl(ack);
261         tcp->window = htons(1024);
262         tcp->urgent = 0;
263         tcp->checksum = 0;
264         tcp->src_port = htons(src);
265         tcp->dest_port = htons(dest);
266         tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
267
268         /* fill in some pseudo-header fields */
269         memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
270         memcpy(ip->destination, r->ip_addr, sizeof(ip_addr_t));
271         ip->protocol = IP_PROTO_TCP;
272         ip->length = htons(pkt->pkt_bytes);
273
274         /* compute tcp checksum */
275         cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
276         tcp->checksum = htons(cksum);
277
278         __ip_send(pkt, IP_PROTO_TCP, r);
279 }
280
281
282
283 /*
284  * Remove given socket from socket list.
285  */
286 static void
287 unlink_socket(tcp_socket_t *s)
288 {
289         tcp_socket_t *prev, *tp;
290
291         for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next)
292                 if (tp == s) {
293                         BSPLOG(bsp_log("unlink tcp socket.\n"));
294                         if (prev)
295                                 prev->next = s->next;
296                         else
297                                 tcp_list = s->next;
298                 }
299 }
300
301 /*
302  * Retransmit last packet.
303  */
304 static void
305 do_retrans(void *p)
306 {
307         BSPLOG(bsp_log("tcp do_retrans.\n"));
308         tcp_send((tcp_socket_t *)p, 0, 1);
309 }
310
311
312 static void
313 do_close(void *p)
314 {
315         BSPLOG(bsp_log("tcp do_close.\n"));
316         /* close connection */
317         ((tcp_socket_t *)p)->state = _CLOSED;
318         unlink_socket(p);
319 }
320
321
322 static void
323 free_rxlist(tcp_socket_t *s)
324 {
325         pktbuf_t *p;
326
327         BSPLOG(bsp_log("tcp free_rxlist.\n"));
328
329         while ((p = s->rxlist) != NULL) {
330                 s->rxlist = p->next;
331                 __pktbuf_free(p);
332         }
333 }
334
335
336 /*
337  * Handle a conection reset.
338  */
339 static void
340 do_reset(tcp_socket_t *s)
341 {
342         /* close connection */
343         s->state = _CLOSED;
344         __timer_cancel(&s->timer);
345         free_rxlist(s);
346         unlink_socket(s);
347 }
348
349
350 /*
351  * Extract data from incoming tcp segment.
352  * Returns true if packet is queued on rxlist, false otherwise.
353  */
354 static int
355 handle_data(tcp_socket_t *s, pktbuf_t *pkt)
356 {
357         tcp_header_t  *tcp = pkt->tcp_hdr;
358         unsigned int  diff, seq;
359         int                       data_len;
360         char              *data_ptr;
361         pktbuf_t          *p;
362
363         data_len = pkt->pkt_bytes - (tcp->hdr_len << 2);
364         data_ptr = ((char *)tcp)  + (tcp->hdr_len << 2);
365
366         seq = ntohl(tcp->seqnum);
367
368         BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len));
369
370         if (SEQ_LE(seq, s->ack)) {
371                 /*
372                  * Figure difference between which byte we're expecting and which byte
373                  * is sent first. Adjust data length and data pointer accordingly.
374                  */
375                 diff = s->ack - seq;
376                 data_len -= diff;
377                 data_ptr += diff;
378
379                 if (data_len > 0) {
380                         /* queue the new data */
381                         s->ack += data_len;
382                         pkt->next = NULL;
383                         if ((p = s->rxlist) != NULL) {
384                                 while (p->next)
385                                         p = p->next;
386                                 p->next = pkt;
387                                 BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",
388                                                                 pkt, data_len));
389                         } else {
390                                 s->rxlist = pkt;
391                                 s->rxcnt = data_len;
392                                 s->rxptr = data_ptr;
393                                 BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n",
394                                                                 pkt, data_len));
395                         }
396                         return 1;
397                 }
398         }
399         return 0;
400 }
401
402
403 static void
404 handle_ack(tcp_socket_t *s, pktbuf_t *pkt)
405 {
406         tcp_header_t *tcp = pkt->tcp_hdr;
407         dword            ack;
408         int                      advance;
409         char             *dp;
410
411         /* process ack value in packet */
412         ack = ntohl(tcp->acknum);
413
414         BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack));
415
416         if (SEQ_GT(ack, s->seq)) {
417                 __timer_cancel(&s->timer);
418                 advance = ack - s->seq;
419                 if (advance > s->data_bytes)
420                         advance = s->data_bytes;
421
422                 BSPLOG(bsp_log("seq advance %d", advance));
423
424                 if (advance > 0) {
425                         s->seq += advance;
426                         s->data_bytes -= advance;
427                         if (s->data_bytes) {
428                                 /* other end ack'd only part of the pkt */
429                                 BSPLOG(bsp_log(" %d bytes left", s->data_bytes));
430                                 dp = (char *)(s->pkt.tcp_hdr + 1);
431                                 memcpy(dp, dp + advance, s->data_bytes);
432                         }
433                 }
434         }
435         BSPLOG(bsp_log("\n"));
436 }
437
438
439 /*
440  * Handle incoming TCP packets.
441  */
442 void
443 __tcp_handler(pktbuf_t *pkt, ip_route_t *r)
444 {
445         tcp_header_t *tcp = pkt->tcp_hdr;
446         ip_header_t      *ip = pkt->ip_hdr;
447         tcp_socket_t *prev,*s;
448         dword            ack;
449         int                      queued = 0;
450
451         /* set length for pseudo sum calculation */
452         ip->length = htons(pkt->pkt_bytes);
453
454         if (__sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)) == 0) {
455                 for (prev = NULL, s = tcp_list; s; prev = s, s = s->next) {
456                         if (s->our_port == ntohs(tcp->dest_port)) {
457                                 if (s->his_port == 0)
458                                         break;
459                                 if (s->his_port == ntohs(tcp->src_port) &&
460                                         !memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
461                                         break;
462                         }
463                 }
464
465                 if (s) {
466                         /* found the socket this packet belongs to */
467
468                         /* refresh his ethernet address */
469                         memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
470
471                         if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
472                                 BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));
473                                 do_reset(s);
474                                 __pktbuf_free(pkt);
475                                 return;
476                         }
477
478                         switch (s->state) {
479
480                         case _SYN_SENT:
481                                 /* active open not supported */
482                                 if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
483                                         do_reset(s);
484                                         __pktbuf_free(pkt);
485                                         return;
486                                 }
487                                 s->state = _ESTABLISHED;
488                                 s->ack = ntohl(tcp->seqnum) + 1;
489                                 s->seq = ntohl(tcp->acknum);
490                                 __timer_cancel(&s->timer);
491                                 send_ack(s);
492                                 break;
493
494                         case _LISTEN:
495                                 if (tcp->flags & TCP_FLAG_SYN) {
496                                         s->state = _SYN_RCVD;
497                                         s->ack = ntohl(tcp->seqnum) + 1;
498                                         s->his_port = ntohs(tcp->src_port);
499                                         memcpy(s->his_addr.ip_addr, r->ip_addr, sizeof(ip_addr_t));
500                                         s->data_bytes = 0;
501
502                                         BSPLOG(bsp_log("SYN from %d.%d.%d.%d:%d (seq %x)\n",
503                                                                         s->his_addr.ip_addr[0],s->his_addr.ip_addr[1],
504                                                                         s->his_addr.ip_addr[2],s->his_addr.ip_addr[3],
505                                                                         s->his_port, ntohl(tcp->seqnum)));
506
507                                         tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
508                                 }
509                                 else
510                                         send_reset(pkt, r);
511                                 break;
512
513                         case _SYN_RCVD:
514                                 BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));
515                                 __timer_cancel(&s->timer);
516
517                                 /* go back to _LISTEN state if reset */
518                                 if (tcp->flags & TCP_FLAG_RST) {
519                                         s->state = _LISTEN;
520
521                                         BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));
522
523                                 } else if (tcp->flags & TCP_FLAG_SYN) {
524                                         /* apparently our SYN/ACK was lost? */
525                                         tcp_send(s, 0, 1);
526
527                                         BSPLOG(bsp_log("retransmitting SYN/ACK\n"));
528
529                                 } else if ((tcp->flags & TCP_FLAG_ACK) &&
530                                                 ntohl(tcp->acknum) == (s->seq + 1)) {
531                                         /* we've established the connection */
532                                         s->state = _ESTABLISHED;
533                                         s->seq++;
534
535                                         BSPLOG(bsp_log("ACK received - connection established\n"));
536                                 }
537                                 break;
538
539                         case _ESTABLISHED:
540                         case _CLOSE_WAIT:
541                                 ack = s->ack;  /* save original ack */
542                                 if (tcp->flags & TCP_FLAG_ACK)
543                                         handle_ack(s, pkt);
544
545                                 queued = handle_data(s, pkt);
546
547                                 if ((tcp->flags & TCP_FLAG_FIN) &&
548                                         ntohl(tcp->seqnum) == s->ack) {
549
550                                         BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));
551
552                                         s->ack++;
553                                         s->state = _CLOSE_WAIT;
554                                 }
555                                 /*
556                                  * Send an ack if neccessary.
557                                  */
558                                 if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))
559                                         send_ack(s);
560                                 break;
561
562                         case _LAST_ACK:
563                                 if (tcp->flags & TCP_FLAG_ACK) {
564                                         handle_ack(s, pkt);
565                                         if (ntohl(tcp->acknum) == (s->seq + 1)) {
566                                                 BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));
567                                                 s->state = _CLOSED;
568                                                 unlink_socket(s);
569                                         }
570                                 }
571                                 break;
572
573                         case _FIN_WAIT_1:
574                                 if (tcp->flags & TCP_FLAG_ACK) {
575                                         handle_ack(s, pkt);
576                                         if (ntohl(tcp->acknum) == (s->seq + 1)) {
577                                                 /* got ACK for FIN packet */
578                                                 s->seq++;
579                                                 if (tcp->flags & TCP_FLAG_FIN) {
580                                                         BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));
581                                                         s->ack++;
582                                                         s->state = _TIME_WAIT;
583                                                         send_ack(s);
584                                                 } else {
585                                                         s->state = _FIN_WAIT_2;
586                                                         BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
587                                                 }
588                                                 break; /* All done for now */
589                                         }
590                                 }
591                                 /* At this point, no ACK for FIN has been seen, so check for
592                                    simultaneous close */
593                                 if (tcp->flags & TCP_FLAG_FIN) {
594                                         BSPLOG(bsp_log("_FIN_WAIT_1 --> _CLOSING\n"));
595                                         __timer_cancel(&s->timer);
596                                         s->ack++;
597                                         s->state = _CLOSING;
598                                         /* FIN is resent so the timeout and retry for this packet
599                                            will also take care of timeout and resend of the
600                                            previously sent FIN (which got us to FIN_WAIT_1). While
601                                            not technically correct, resending FIN only causes a
602                                            duplicate FIN (same sequence number) which should be
603                                            ignored by the other end. */
604                                         tcp_send(s, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);
605                                 }
606                                 break;
607
608                         case _FIN_WAIT_2:
609                                 queued = handle_data(s, pkt);
610                                 if (tcp->flags & TCP_FLAG_FIN) {
611                                         BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));
612                                         s->ack++;
613                                         s->state = _TIME_WAIT;
614                                         send_ack(s);
615                                 }
616                                 break;
617
618                         case _CLOSING:
619                                 if (tcp->flags & TCP_FLAG_ACK) {
620                                         handle_ack(s, pkt);
621                                         if (ntohl(tcp->acknum) == (s->seq + 1)) {
622                                                 /* got ACK for FIN packet */
623                                                 BSPLOG(bsp_log("_CLOSING --> _TIME_WAIT\n"));
624                                                 __timer_cancel(&s->timer);
625                                                 s->state = _TIME_WAIT;
626                                         }
627                                 }
628                                 break;
629
630                         case _TIME_WAIT:
631                                 BSPLOG(bsp_log("_TIME_WAIT resend.\n"));
632                                 if (tcp->flags & TCP_FLAG_FIN)
633                                         tcp_send(s, 0, 1); /* just resend ack */
634                                 break;
635                         }
636                 } else {
637                         BSPLOG(bsp_log("Unexpected segment from: %d.%d.%d.%d:%d\n",
638                                                         r->ip_addr[0], r->ip_addr[1], r->ip_addr[3],
639                                                         r->ip_addr[4], ntohs(tcp->src_port)));
640                         send_reset(pkt, r);
641                 }
642         }
643         if (!queued)
644                 __pktbuf_free(pkt);
645 }
646
647
648 void
649 __tcp_poll(void)
650 {
651         __enet_poll();
652         __timer_poll();
653 }
654
655
656 int
657 __tcp_listen(tcp_socket_t *s, word port)
658 {
659         BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));
660
661         memset(s, 0, sizeof(tcp_socket_t));
662         s->state        = _LISTEN;
663         s->our_port = port;
664         s->pkt.buf = (word *)s->pktbuf;
665         s->pkt.bufsize = ETH_MAX_PKTLEN;
666         s->pkt.ip_hdr  = (ip_header_t *)s->pkt.buf;
667         s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
668
669         s->next = tcp_list;
670
671 #if 0
672         /* limit to one open socket at a time */
673         if (s->next) {
674                 BSPLOG(bsp_log("tcp_listen: recursion error\n"));
675                 BSPLOG(while(1));
676         }
677 #endif
678
679         tcp_list = s;
680
681         return 0;
682 }
683
684 /*
685  * SO_REUSEADDR, no 2MSL.
686  */
687 void
688 __tcp_so_reuseaddr(tcp_socket_t *s)
689 {
690 //    BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));
691         s->reuse = 0x01;
692 }
693
694 /*
695  * Block while waiting for all data to be transmitted.
696  */
697 void
698 __tcp_drain(tcp_socket_t *s)
699 {
700 //    BSPLOG(bsp_log("__tcp_drain.\n"));
701         while (s->state != _CLOSED && s->data_bytes)
702                 __tcp_poll();
703 //    BSPLOG(bsp_log("__tcp_drain done.\n"));
704 }
705
706
707 /*
708  * Close the tcp connection.
709  */
710 static void
711 do_abort(void *s)
712 {
713         BSPLOG(bsp_log("do_abort: send RST\n"));
714         tcp_send((tcp_socket_t *)s, TCP_FLAG_ACK | TCP_FLAG_RST, 0);
715         __timer_cancel(&abort_timer);
716         ((tcp_socket_t *)s)->state = _CLOSED;
717         free_rxlist((tcp_socket_t *)s);
718         unlink_socket((tcp_socket_t *)s);
719 }
720
721 void
722 __tcp_abort(tcp_socket_t *s, unsigned long delay)
723 {
724         __timer_set(&abort_timer, delay, do_abort, s);
725 }
726
727 /*
728  * Close the tcp connection.
729  */
730 void
731 __tcp_close(tcp_socket_t *s)
732 {
733         __tcp_drain(s);
734         if (s->state == _ESTABLISHED || s->state == _SYN_RCVD) {
735                 BSPLOG(bsp_log("__tcp_close: going to _FIN_WAIT_1\n"));
736                 s->state = _FIN_WAIT_1;
737                 tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
738         } else if (s->state == _CLOSE_WAIT) {
739
740                 BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));
741
742                 s->state = _LAST_ACK;
743                 tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
744         }
745         free_rxlist(s);
746 }
747
748
749 /*
750  * Wait for connection to be fully closed.
751  */
752 void
753 __tcp_close_wait(tcp_socket_t *s)
754 {
755         BSPLOG(bsp_log("__tcp_close_wait.\n"));
756         while (s->state != _CLOSED)
757                 __tcp_poll();
758         BSPLOG(bsp_log("__tcp_close_wait done.\n"));
759 }
760
761
762 /*
763  * Read up to 'len' bytes without blocking.
764  */
765 int
766 __tcp_read(tcp_socket_t *s, void *buf, int len)
767 {
768         int                      nread;
769         pktbuf_t         *pkt;
770         tcp_header_t *tcp;
771
772         if (len <= 0 || s->rxcnt == 0)
773                 return 0;
774
775         if (s->state != _ESTABLISHED && s->rxcnt == 0)
776                 return -1;
777
778         nread = 0;
779         while (len) {
780                 if (len < s->rxcnt) {
781                         memcpy(buf, s->rxptr, len);
782                         BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));
783                         s->rxptr += len;
784                         s->rxcnt -= len;
785                         nread    += len;
786
787                         BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",
788                                                         s->rxcnt));
789
790                         break;
791                 } else {
792                         memcpy(buf, s->rxptr, s->rxcnt);
793                         BSPLOG(bsp_log("tcp_read: read %d bytes. pkt[%x] freed.\n",
794                                                         s->rxcnt, s->rxlist));
795                         nread += s->rxcnt;
796                         buf   = (char *)buf + s->rxcnt;
797                         len   -= s->rxcnt;
798
799                         /* setup for next packet in list */
800                         pkt = s->rxlist;
801                         s->rxlist = pkt->next;
802                         __pktbuf_free(pkt);
803
804                         if ((pkt = s->rxlist) != NULL) {
805                                 tcp = pkt->tcp_hdr;
806                                 s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);
807                                 s->rxptr = ((char *)tcp)  + (tcp->hdr_len << 2);
808
809                                 BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",
810                                                                 s->rxlist, s->rxcnt));
811                         } else {
812
813                                 BSPLOG(bsp_log("tcp_read: no more data.\n"));
814
815                                 s->rxcnt = 0;
816                                 break;
817                         }
818                 }
819         }
820         return nread;
821 }
822
823
824 /*
825  * Write up to 'len' bytes without blocking
826  */
827 int
828 __tcp_write(tcp_socket_t *s, void *buf, int len)
829 {
830         tcp_header_t *tcp = s->pkt.tcp_hdr;
831
832         if (len <= 0)
833                 return 0;
834
835         if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)
836                 return -1;
837
838         if (s->data_bytes)
839                 return 0;
840
841         if (len > MAX_TCP_DATA)
842                 len = MAX_TCP_DATA;
843
844         memcpy(tcp + 1, buf, len);
845         s->data_bytes = len;
846
847         tcp_send(s, TCP_FLAG_ACK, 0);
848
849         return len;
850 }
851
852 /*
853  * Write 'len' bytes from 'buf', blocking until sent.
854  * If connection collapses, return -1
855  */
856 int
857 __tcp_write_block(tcp_socket_t *s, void *buf, int len)
858 {
859         int total = 0;
860         int n;
861
862         while (len) {
863                 if (s->state == _CLOSE_WAIT) {
864                         // This connection is tring to close
865                         // This connection is breaking
866                         if (s->data_bytes == 0 && s->rxcnt == 0)
867                                 __tcp_close(s);
868                 }
869                 if (s->state == _CLOSED) {
870                         // The connection is gone!
871                         return -1;
872                 }
873                 n = __tcp_write(s, buf, len);
874                 if (n > 0) {
875                         len -= n;
876                         buf = (char *)buf + n;
877                         total += n;
878                 }
879                 __tcp_poll();
880         }
881         __tcp_drain(s);
882         return total;
883 }
884
885 /*
886  * Establish a new [outgoing] connection, with a timeout.
887  */
888 int
889 __tcp_open(tcp_socket_t *s, struct sockaddr_in *host,
890                 word port, int timeout, int *err)
891 {
892         // Fill in socket details
893         memset(s, 0, sizeof(tcp_socket_t));
894         s->state = _SYN_SENT;
895         s->our_port = port;
896         s->his_port = host->sin_port;
897         s->pkt.buf = (word *)s->pktbuf;
898         s->pkt.bufsize = ETH_MAX_PKTLEN;
899         s->pkt.ip_hdr  = (ip_header_t *)s->pkt.buf;
900         s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
901         s->seq = (port << 16) | 0xDE77;
902         s->ack = 0;
903         if (__arp_lookup((ip_addr_t *)&host->sin_addr, &s->his_addr) < 0) {
904                 diag_printf("%s: Can't find address of server\n", __FUNCTION__);
905                 return -1;
906         }
907         s->next = tcp_list;
908         tcp_list = s;
909
910         // Send off the SYN packet to open the connection
911         tcp_send(s, TCP_FLAG_SYN, 0);
912         // Wait for connection to establish
913         while (s->state != _ESTABLISHED) {
914                 if (s->state == _CLOSED) {
915                         diag_printf("TCP open - host closed connection\n");
916                         return -1;
917                 }
918                 if (--timeout <= 0) {
919                         diag_printf("TCP open - connection timed out\n");
920                         return -1;
921                 }
922                 MS_TICKS_DELAY();
923                 __tcp_poll();
924         }
925         return 0;
926 }