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;
182 static word ack_buf[ETH_MIN_PKTLEN/sizeof(word)];
188 send_ack(tcp_socket_t *s)
192 unsigned short cksum;
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);
203 tcp->seqnum = htonl(s->seq);
204 tcp->acknum = htonl(s->ack);
207 tcp->src_port = htons(s->our_port);
208 tcp->dest_port = htons(s->his_port);
209 tcp->flags = TCP_FLAG_ACK;
211 tcp->window = htons(MAX_TCP_DATA);
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;
219 /* another pseudo-header field */
220 ip->length = htons(sizeof(tcp_header_t));
222 /* compute tcp checksum */
223 cksum = __sum((word *)tcp, sizeof(*tcp), __pseudo_sum(ip));
224 tcp->checksum = htons(cksum);
226 __ip_send(&ack_pkt, IP_PROTO_TCP, &s->his_addr);
231 * Send a reset for a bogus incoming segment.
234 send_reset(pktbuf_t *pkt, ip_route_t *r)
236 ip_header_t *ip = pkt->ip_hdr;
237 tcp_header_t *tcp = pkt->tcp_hdr;
242 seq = ntohl(tcp->acknum);
243 ack = ntohl(tcp->seqnum);
244 src = ntohs(tcp->dest_port);
245 dest = ntohs(tcp->src_port);
247 tcp = (tcp_header_t *)(ip + 1);
248 pkt->pkt_bytes = sizeof(tcp_header_t);
253 tcp->seqnum = htonl(seq);
254 tcp->acknum = htonl(ack);
255 tcp->window = htons(1024);
258 tcp->src_port = htons(src);
259 tcp->dest_port = htons(dest);
260 tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
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);
268 /* compute tcp checksum */
269 cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
270 tcp->checksum = htons(cksum);
272 __ip_send(pkt, IP_PROTO_TCP, r);
278 * Remove given socket from socket list.
281 unlink_socket(tcp_socket_t *s)
283 tcp_socket_t *prev, *tp;
285 for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next)
287 BSPLOG(bsp_log("unlink tcp socket.\n"));
289 prev->next = s->next;
296 * Retransmit last packet.
301 BSPLOG(bsp_log("tcp do_retrans.\n"));
302 tcp_send((tcp_socket_t *)p, 0, 1);
309 BSPLOG(bsp_log("tcp do_close.\n"));
310 /* close connection */
311 ((tcp_socket_t *)p)->state = _CLOSED;
317 free_rxlist(tcp_socket_t *s)
321 BSPLOG(bsp_log("tcp free_rxlist.\n"));
323 while ((p = s->rxlist) != NULL) {
331 * Handle a conection reset.
334 do_reset(tcp_socket_t *s)
336 /* close connection */
338 __timer_cancel(&s->timer);
345 * Extract data from incoming tcp segment.
346 * Returns true if packet is queued on rxlist, false otherwise.
349 handle_data(tcp_socket_t *s, pktbuf_t *pkt)
351 tcp_header_t *tcp = pkt->tcp_hdr;
352 unsigned int diff, seq;
357 data_len = pkt->pkt_bytes - (tcp->hdr_len << 2);
358 data_ptr = ((char *)tcp) + (tcp->hdr_len << 2);
360 seq = ntohl(tcp->seqnum);
362 BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len));
364 if (SEQ_LE(seq, s->ack)) {
366 * Figure difference between which byte we're expecting and which byte
367 * is sent first. Adjust data length and data pointer accordingly.
374 /* queue the new data */
377 if ((p = s->rxlist) != NULL) {
381 BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",
387 BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n",
398 handle_ack(tcp_socket_t *s, pktbuf_t *pkt)
400 tcp_header_t *tcp = pkt->tcp_hdr;
405 /* process ack value in packet */
406 ack = ntohl(tcp->acknum);
408 BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack));
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;
416 BSPLOG(bsp_log("seq advance %d", advance));
420 s->data_bytes -= advance;
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);
429 BSPLOG(bsp_log("\n"));
434 * Handle incoming TCP packets.
437 __tcp_handler(pktbuf_t *pkt, ip_route_t *r)
439 tcp_header_t *tcp = pkt->tcp_hdr;
440 ip_header_t *ip = pkt->ip_hdr;
441 tcp_socket_t *prev,*s;
445 /* set length for pseudo sum calculation */
446 ip->length = htons(pkt->pkt_bytes);
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)
453 if (s->his_port == ntohs(tcp->src_port) &&
454 !memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
460 /* found the socket this packet belongs to */
462 /* refresh his ethernet address */
463 memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
465 if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
466 BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));
475 /* active open not supported */
476 if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
481 s->state = _ESTABLISHED;
482 s->ack = ntohl(tcp->seqnum) + 1;
483 s->seq = ntohl(tcp->acknum);
484 __timer_cancel(&s->timer);
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));
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)));
501 tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
508 BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));
509 __timer_cancel(&s->timer);
511 /* go back to _LISTEN state if reset */
512 if (tcp->flags & TCP_FLAG_RST) {
515 BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));
517 } else if (tcp->flags & TCP_FLAG_SYN) {
518 /* apparently our SYN/ACK was lost? */
521 BSPLOG(bsp_log("retransmitting SYN/ACK\n"));
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;
529 BSPLOG(bsp_log("ACK received - connection established\n"));
535 ack = s->ack; /* save original ack */
536 if (tcp->flags & TCP_FLAG_ACK)
539 queued = handle_data(s, pkt);
541 if ((tcp->flags & TCP_FLAG_FIN) &&
542 ntohl(tcp->seqnum) == s->ack) {
544 BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));
547 s->state = _CLOSE_WAIT;
550 * Send an ack if neccessary.
552 if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))
557 if (tcp->flags & TCP_FLAG_ACK) {
559 if (ntohl(tcp->acknum) == (s->seq + 1)) {
560 BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));
568 if (tcp->flags & TCP_FLAG_ACK) {
570 if (ntohl(tcp->acknum) == (s->seq + 1)) {
571 /* got ACK for FIN packet */
573 if (tcp->flags & TCP_FLAG_FIN) {
574 BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));
576 s->state = _TIME_WAIT;
579 s->state = _FIN_WAIT_2;
580 BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
582 break; /* All done for now */
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);
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);
603 queued = handle_data(s, pkt);
604 if (tcp->flags & TCP_FLAG_FIN) {
605 BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));
607 s->state = _TIME_WAIT;
613 if (tcp->flags & TCP_FLAG_ACK) {
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;
625 BSPLOG(bsp_log("_TIME_WAIT resend.\n"));
626 if (tcp->flags & TCP_FLAG_FIN)
627 tcp_send(s, 0, 1); /* just resend ack */
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)));
651 __tcp_listen(tcp_socket_t *s, word port)
653 BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));
655 memset(s, 0, sizeof(tcp_socket_t));
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);
666 /* limit to one open socket at a time */
668 BSPLOG(bsp_log("tcp_listen: recursion error\n"));
679 * SO_REUSEADDR, no 2MSL.
682 __tcp_so_reuseaddr(tcp_socket_t *s)
684 // BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));
689 * Block while waiting for all data to be transmitted.
692 __tcp_drain(tcp_socket_t *s)
694 // BSPLOG(bsp_log("__tcp_drain.\n"));
695 while (s->state != _CLOSED && s->data_bytes)
697 // BSPLOG(bsp_log("__tcp_drain done.\n"));
702 * Close the tcp connection.
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);
716 __tcp_abort(tcp_socket_t *s, unsigned long delay)
718 __timer_set(&abort_timer, delay, do_abort, s);
722 * Close the tcp connection.
725 __tcp_close(tcp_socket_t *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) {
734 BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));
736 s->state = _LAST_ACK;
737 tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
744 * Wait for connection to be fully closed.
747 __tcp_close_wait(tcp_socket_t *s)
749 BSPLOG(bsp_log("__tcp_close_wait.\n"));
750 while (s->state != _CLOSED)
752 BSPLOG(bsp_log("__tcp_close_wait done.\n"));
757 * Read up to 'len' bytes without blocking.
760 __tcp_read(tcp_socket_t *s, char *buf, int len)
766 if (len <= 0 || s->rxcnt == 0)
769 if (s->state != _ESTABLISHED && s->rxcnt == 0)
774 if (len < s->rxcnt) {
775 memcpy(buf, s->rxptr, len);
776 BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));
781 BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",
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));
793 /* setup for next packet in list */
795 s->rxlist = pkt->next;
798 if ((pkt = s->rxlist) != NULL) {
800 s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);
801 s->rxptr = ((char *)tcp) + (tcp->hdr_len << 2);
803 BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",
804 s->rxlist, s->rxcnt));
807 BSPLOG(bsp_log("tcp_read: no more data.\n"));
819 * Write up to 'len' bytes without blocking
822 __tcp_write(tcp_socket_t *s, char *buf, int len)
824 tcp_header_t *tcp = s->pkt.tcp_hdr;
829 if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)
835 if (len > MAX_TCP_DATA)
838 memcpy(tcp + 1, buf, len);
841 tcp_send(s, TCP_FLAG_ACK, 0);
847 * Write 'len' bytes from 'buf', blocking until sent.
848 * If connection collapses, return -1
851 __tcp_write_block(tcp_socket_t *s, char *buf, int 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)
863 if (s->state == _CLOSED) {
864 // The connection is gone!
867 n = __tcp_write(s, buf, len);
879 * Establish a new [outgoing] connection, with a timeout.
882 __tcp_open(tcp_socket_t *s, struct sockaddr_in *host,
883 word port, int timeout, int *err)
885 // Fill in socket details
886 memset(s, 0, sizeof(tcp_socket_t));
887 s->state = _SYN_SENT;
889 s->his_port = host->sin_port;
890 s->pkt.buf = (word *)s->pktbuf;
891 s->pkt.bufsize = ETH_MAX_PKTLEN;
892 s->pkt.ip_hdr = (ip_header_t *)s->pkt.buf;
893 s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
894 s->seq = (port << 16) | 0xDE77;
896 if (__arp_lookup((ip_addr_t *)&host->sin_addr, &s->his_addr) < 0) {
897 diag_printf("%s: Can't find address of server\n", __FUNCTION__);
903 // Send off the SYN packet to open the connection
904 tcp_send(s, TCP_FLAG_SYN, 0);
905 // Wait for connection to establish
906 while (s->state != _ESTABLISHED) {
907 if (s->state == _CLOSED) {
908 diag_printf("TCP open - host closed connection\n");
911 if (--timeout <= 0) {
912 diag_printf("TCP open - connection timed out\n");