1 //==========================================================================
5 // Stand-alone TCP networking support for RedBoot
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
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.
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
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.
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.
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.
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####
45 // Contributors: gthomas
50 // This code is part of RedBoot (tm).
52 //####DESCRIPTIONEND####
54 //==========================================================================
57 #include <cyg/infra/diag.h>
58 #include <cyg/hal/hal_if.h>
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))
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)
70 /* Set a timer which will send an RST and abort a connection. */
71 static timer_t abort_timer;
73 static void do_retrans(void *p);
74 static void do_close(void *p);
80 static char str[7], *p;
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.
105 static tcp_socket_t *tcp_list;
108 * Format and send an outgoing segment.
111 tcp_send(tcp_socket_t *s, int flags, int resend)
115 pktbuf_t *pkt = &s->pkt;
116 unsigned short cksum;
118 int tcp_magic_size = sizeof(tcp_magic);
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;
127 tcp_magic = htonl(0x02040000 | MAX_TCP_DATA);
128 memcpy((unsigned char *)(tcp+1), &tcp_magic, tcp_magic_size);
131 pkt->pkt_bytes = s->data_bytes + sizeof(tcp_header_t);
137 tcp->seqnum = htonl(s->seq);
138 tcp->acknum = htonl(s->ack);
142 tcp->src_port = htons(s->our_port);
143 tcp->dest_port = htons(s->his_port);
145 /* always set PUSH flag if sending data */
147 tcp->flags |= TCP_FLAG_PSH;
148 tcp->window = htons(MAX_TCP_DATA);
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;
157 /* another pseudo-header field */
158 ip->length = htons(pkt->pkt_bytes);
160 /* compute tcp checksum */
161 cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
162 tcp->checksum = htons(cksum);
164 __ip_send(pkt, IP_PROTO_TCP, &s->his_addr);
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);
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));
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);
177 else if ((tcp->flags & (TCP_FLAG_FIN | TCP_FLAG_SYN)) || s->data_bytes)
178 __timer_set(&s->timer, 1000, do_retrans, s);
181 static pktbuf_t ack_pkt;
183 word w[ETH_MIN_PKTLEN / sizeof(word)];
194 send_ack(tcp_socket_t *s)
198 unsigned short cksum;
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);
209 tcp->seqnum = htonl(s->seq);
210 tcp->acknum = htonl(s->ack);
213 tcp->src_port = htons(s->our_port);
214 tcp->dest_port = htons(s->his_port);
215 tcp->flags = TCP_FLAG_ACK;
217 tcp->window = htons(MAX_TCP_DATA);
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;
225 /* another pseudo-header field */
226 ip->length = htons(sizeof(tcp_header_t));
228 /* compute tcp checksum */
229 cksum = __sum((word *)tcp, sizeof(*tcp), __pseudo_sum(ip));
230 tcp->checksum = htons(cksum);
232 __ip_send(&ack_pkt, IP_PROTO_TCP, &s->his_addr);
237 * Send a reset for a bogus incoming segment.
240 send_reset(pktbuf_t *pkt, ip_route_t *r)
242 ip_header_t *ip = pkt->ip_hdr;
243 tcp_header_t *tcp = pkt->tcp_hdr;
248 seq = ntohl(tcp->acknum);
249 ack = ntohl(tcp->seqnum);
250 src = ntohs(tcp->dest_port);
251 dest = ntohs(tcp->src_port);
253 tcp = (tcp_header_t *)(ip + 1);
254 pkt->pkt_bytes = sizeof(tcp_header_t);
259 tcp->seqnum = htonl(seq);
260 tcp->acknum = htonl(ack);
261 tcp->window = htons(1024);
264 tcp->src_port = htons(src);
265 tcp->dest_port = htons(dest);
266 tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
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);
274 /* compute tcp checksum */
275 cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
276 tcp->checksum = htons(cksum);
278 __ip_send(pkt, IP_PROTO_TCP, r);
284 * Remove given socket from socket list.
287 unlink_socket(tcp_socket_t *s)
289 tcp_socket_t *prev, *tp;
291 for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next)
293 BSPLOG(bsp_log("unlink tcp socket.\n"));
295 prev->next = s->next;
302 * Retransmit last packet.
307 BSPLOG(bsp_log("tcp do_retrans.\n"));
308 tcp_send((tcp_socket_t *)p, 0, 1);
315 BSPLOG(bsp_log("tcp do_close.\n"));
316 /* close connection */
317 ((tcp_socket_t *)p)->state = _CLOSED;
323 free_rxlist(tcp_socket_t *s)
327 BSPLOG(bsp_log("tcp free_rxlist.\n"));
329 while ((p = s->rxlist) != NULL) {
337 * Handle a conection reset.
340 do_reset(tcp_socket_t *s)
342 /* close connection */
344 __timer_cancel(&s->timer);
351 * Extract data from incoming tcp segment.
352 * Returns true if packet is queued on rxlist, false otherwise.
355 handle_data(tcp_socket_t *s, pktbuf_t *pkt)
357 tcp_header_t *tcp = pkt->tcp_hdr;
358 unsigned int diff, seq;
363 data_len = pkt->pkt_bytes - (tcp->hdr_len << 2);
364 data_ptr = ((char *)tcp) + (tcp->hdr_len << 2);
366 seq = ntohl(tcp->seqnum);
368 BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len));
370 if (SEQ_LE(seq, s->ack)) {
372 * Figure difference between which byte we're expecting and which byte
373 * is sent first. Adjust data length and data pointer accordingly.
380 /* queue the new data */
383 if ((p = s->rxlist) != NULL) {
387 BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",
393 BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n",
404 handle_ack(tcp_socket_t *s, pktbuf_t *pkt)
406 tcp_header_t *tcp = pkt->tcp_hdr;
411 /* process ack value in packet */
412 ack = ntohl(tcp->acknum);
414 BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack));
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;
422 BSPLOG(bsp_log("seq advance %d", advance));
426 s->data_bytes -= advance;
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);
435 BSPLOG(bsp_log("\n"));
440 * Handle incoming TCP packets.
443 __tcp_handler(pktbuf_t *pkt, ip_route_t *r)
445 tcp_header_t *tcp = pkt->tcp_hdr;
446 ip_header_t *ip = pkt->ip_hdr;
447 tcp_socket_t *prev,*s;
451 /* set length for pseudo sum calculation */
452 ip->length = htons(pkt->pkt_bytes);
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)
459 if (s->his_port == ntohs(tcp->src_port) &&
460 !memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
466 /* found the socket this packet belongs to */
468 /* refresh his ethernet address */
469 memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
471 if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
472 BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));
481 /* active open not supported */
482 if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
487 s->state = _ESTABLISHED;
488 s->ack = ntohl(tcp->seqnum) + 1;
489 s->seq = ntohl(tcp->acknum);
490 __timer_cancel(&s->timer);
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));
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)));
507 tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
514 BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));
515 __timer_cancel(&s->timer);
517 /* go back to _LISTEN state if reset */
518 if (tcp->flags & TCP_FLAG_RST) {
521 BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));
523 } else if (tcp->flags & TCP_FLAG_SYN) {
524 /* apparently our SYN/ACK was lost? */
527 BSPLOG(bsp_log("retransmitting SYN/ACK\n"));
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;
535 BSPLOG(bsp_log("ACK received - connection established\n"));
541 ack = s->ack; /* save original ack */
542 if (tcp->flags & TCP_FLAG_ACK)
545 queued = handle_data(s, pkt);
547 if ((tcp->flags & TCP_FLAG_FIN) &&
548 ntohl(tcp->seqnum) == s->ack) {
550 BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));
553 s->state = _CLOSE_WAIT;
556 * Send an ack if neccessary.
558 if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))
563 if (tcp->flags & TCP_FLAG_ACK) {
565 if (ntohl(tcp->acknum) == (s->seq + 1)) {
566 BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));
574 if (tcp->flags & TCP_FLAG_ACK) {
576 if (ntohl(tcp->acknum) == (s->seq + 1)) {
577 /* got ACK for FIN packet */
579 if (tcp->flags & TCP_FLAG_FIN) {
580 BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));
582 s->state = _TIME_WAIT;
585 s->state = _FIN_WAIT_2;
586 BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
588 break; /* All done for now */
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);
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);
609 queued = handle_data(s, pkt);
610 if (tcp->flags & TCP_FLAG_FIN) {
611 BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));
613 s->state = _TIME_WAIT;
619 if (tcp->flags & TCP_FLAG_ACK) {
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;
631 BSPLOG(bsp_log("_TIME_WAIT resend.\n"));
632 if (tcp->flags & TCP_FLAG_FIN)
633 tcp_send(s, 0, 1); /* just resend ack */
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)));
657 __tcp_listen(tcp_socket_t *s, word port)
659 BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));
661 memset(s, 0, sizeof(tcp_socket_t));
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);
672 /* limit to one open socket at a time */
674 BSPLOG(bsp_log("tcp_listen: recursion error\n"));
685 * SO_REUSEADDR, no 2MSL.
688 __tcp_so_reuseaddr(tcp_socket_t *s)
690 // BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));
695 * Block while waiting for all data to be transmitted.
698 __tcp_drain(tcp_socket_t *s)
700 // BSPLOG(bsp_log("__tcp_drain.\n"));
701 while (s->state != _CLOSED && s->data_bytes)
703 // BSPLOG(bsp_log("__tcp_drain done.\n"));
708 * Close the tcp connection.
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);
722 __tcp_abort(tcp_socket_t *s, unsigned long delay)
724 __timer_set(&abort_timer, delay, do_abort, s);
728 * Close the tcp connection.
731 __tcp_close(tcp_socket_t *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) {
740 BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));
742 s->state = _LAST_ACK;
743 tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
750 * Wait for connection to be fully closed.
753 __tcp_close_wait(tcp_socket_t *s)
755 BSPLOG(bsp_log("__tcp_close_wait.\n"));
756 while (s->state != _CLOSED)
758 BSPLOG(bsp_log("__tcp_close_wait done.\n"));
763 * Read up to 'len' bytes without blocking.
766 __tcp_read(tcp_socket_t *s, void *buf, int len)
772 if (len <= 0 || s->rxcnt == 0)
775 if (s->state != _ESTABLISHED && s->rxcnt == 0)
780 if (len < s->rxcnt) {
781 memcpy(buf, s->rxptr, len);
782 BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));
787 BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",
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));
796 buf = (char *)buf + s->rxcnt;
799 /* setup for next packet in list */
801 s->rxlist = pkt->next;
804 if ((pkt = s->rxlist) != NULL) {
806 s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);
807 s->rxptr = ((char *)tcp) + (tcp->hdr_len << 2);
809 BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",
810 s->rxlist, s->rxcnt));
813 BSPLOG(bsp_log("tcp_read: no more data.\n"));
825 * Write up to 'len' bytes without blocking
828 __tcp_write(tcp_socket_t *s, void *buf, int len)
830 tcp_header_t *tcp = s->pkt.tcp_hdr;
835 if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)
841 if (len > MAX_TCP_DATA)
844 memcpy(tcp + 1, buf, len);
847 tcp_send(s, TCP_FLAG_ACK, 0);
853 * Write 'len' bytes from 'buf', blocking until sent.
854 * If connection collapses, return -1
857 __tcp_write_block(tcp_socket_t *s, void *buf, int 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)
869 if (s->state == _CLOSED) {
870 // The connection is gone!
873 n = __tcp_write(s, buf, len);
876 buf = (char *)buf + n;
886 * Establish a new [outgoing] connection, with a timeout.
889 __tcp_open(tcp_socket_t *s, struct sockaddr_in *host,
890 word port, int timeout, int *err)
892 // Fill in socket details
893 memset(s, 0, sizeof(tcp_socket_t));
894 s->state = _SYN_SENT;
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;
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__);
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");
918 if (--timeout <= 0) {
919 diag_printf("TCP open - connection timed out\n");