root/ar5315_microredboot/microredboot/ecos/packages/redboot/current/src/net/tcp.c

Revision 12368, 21.5 kB (checked in by BrainSlayer, 5 months ago)

tftp server added, supports wiligear, ubiquiti and dd-wrt webflash format

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