Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_tcp.c Source File

pico_tcp.c

00001 /*********************************************************************
00002    PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
00003    See LICENSE and COPYING for usage.
00004 
00005    .
00006 
00007    Authors: Daniele Lacamera, Philippe Mariman
00008  *********************************************************************/
00009 
00010 #include "pico_tcp.h"
00011 #include "pico_config.h"
00012 #include "pico_eth.h"
00013 #include "pico_socket.h"
00014 #include "pico_stack.h"
00015 #include "pico_socket.h"
00016 #include "pico_queue.h"
00017 #include "pico_tree.h"
00018 
00019 #define TCP_IS_STATE(s, st) ((s->state & PICO_SOCKET_STATE_TCP) == st)
00020 #define TCP_SOCK(s) ((struct pico_socket_tcp *)s)
00021 #define SEQN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->seq)) : 0)
00022 #define ACKN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->ack)) : 0)
00023 
00024 #define TCP_TIME (pico_time)(PICO_TIME_MS())
00025 
00026 #define PICO_TCP_RTO_MIN (70)
00027 #define PICO_TCP_RTO_MAX (120000)
00028 #define PICO_TCP_IW          2
00029 #define PICO_TCP_SYN_TO  2000u
00030 #define PICO_TCP_ZOMBIE_TO 30000
00031 
00032 #define PICO_TCP_MAX_RETRANS         10
00033 #define PICO_TCP_MAX_CONNECT_RETRIES 3
00034 
00035 #define PICO_TCP_LOOKAHEAD      0x00
00036 #define PICO_TCP_FIRST_DUPACK   0x01
00037 #define PICO_TCP_SECOND_DUPACK  0x02
00038 #define PICO_TCP_RECOVER        0x03
00039 #define PICO_TCP_BLACKOUT       0x04
00040 #define PICO_TCP_UNREACHABLE    0x05
00041 #define PICO_TCP_WINDOW_FULL    0x06
00042 
00043 #define ONE_GIGABYTE ((uint32_t)(1024UL * 1024UL * 1024UL))
00044 
00045 /* check if the Nagle algorithm is enabled on the socket */
00046 #define IS_NAGLE_ENABLED(s)     (!(!(!(s->opt_flags & (1u << PICO_SOCKET_OPT_TCPNODELAY)))))
00047 /* check if tcp connection is "idle" according to Nagle (RFC 896) */
00048 #define IS_TCP_IDLE(t)          ((t->in_flight == 0) && (t->tcpq_out.size == 0))
00049 /* check if the hold queue contains data (again Nagle) */
00050 #define IS_TCP_HOLDQ_EMPTY(t)   (t->tcpq_hold.size == 0)
00051 
00052 #define IS_INPUT_QUEUE(q)  (q->pool.compare == input_segment_compare)
00053 #define TCP_INPUT_OVERHEAD (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node))
00054 
00055 
00056 #ifdef PICO_SUPPORT_TCP
00057 #define tcp_dbg_nagle(...) do {} while(0)
00058 #define tcp_dbg_options(...) do {} while(0)
00059 
00060 
00061 #define tcp_dbg(...) do {} while(0)
00062 /* #define tcp_dbg dbg */
00063 
00064 #ifdef PICO_SUPPORT_MUTEX
00065 static void *Mutex = NULL;
00066 #endif
00067 
00068 
00069 
00070 /* Input segment, used to keep only needed data, not the full frame */
00071 struct tcp_input_segment
00072 {
00073     uint32_t seq;
00074     /* Pointer to payload */
00075     unsigned char *payload;
00076     uint16_t payload_len;
00077 };
00078 
00079 /* Function to compare input segments */
00080 static int input_segment_compare(void *ka, void *kb)
00081 {
00082     struct tcp_input_segment *a = ka, *b = kb;
00083     return pico_seq_compare(a->seq, b->seq);
00084 }
00085 
00086 static struct tcp_input_segment *segment_from_frame(struct pico_frame *f)
00087 {
00088     struct tcp_input_segment *seg = PICO_ZALLOC(sizeof(struct tcp_input_segment));
00089     if ((!seg) || (!f->payload_len))
00090         return NULL;
00091 
00092     seg->payload = PICO_ZALLOC(f->payload_len);
00093     if(!seg->payload)
00094     {
00095         PICO_FREE(seg);
00096         return NULL;
00097     }
00098 
00099     seg->seq = SEQN(f);
00100     seg->payload_len = f->payload_len;
00101     memcpy(seg->payload, f->payload, seg->payload_len);
00102     return seg;
00103 }
00104 
00105 static int segment_compare(void *ka, void *kb)
00106 {
00107     struct pico_frame *a = ka, *b = kb;
00108     return pico_seq_compare(SEQN(a), SEQN(b));
00109 }
00110 
00111 struct pico_tcp_queue
00112 {
00113     struct pico_tree pool;
00114     uint32_t max_size;
00115     uint32_t size;
00116     uint32_t frames;
00117 };
00118 
00119 static void tcp_discard_all_segments(struct pico_tcp_queue *tq);
00120 static void *peek_segment(struct pico_tcp_queue *tq, uint32_t seq)
00121 {
00122     if(!IS_INPUT_QUEUE(tq))
00123     {
00124         struct pico_tcp_hdr H;
00125         struct pico_frame f = {
00126             0
00127         };
00128         f.transport_hdr = (uint8_t *) (&H);
00129         H.seq = long_be(seq);
00130 
00131         return pico_tree_findKey(&tq->pool, &f);
00132     }
00133     else
00134     {
00135         struct tcp_input_segment dummy = { 0 };
00136         dummy.seq = seq;
00137 
00138         return pico_tree_findKey(&tq->pool, &dummy);
00139     }
00140 
00141 }
00142 
00143 static void *first_segment(struct pico_tcp_queue *tq)
00144 {
00145     return pico_tree_first(&tq->pool);
00146 }
00147 
00148 static void *next_segment(struct pico_tcp_queue *tq, void *cur)
00149 {
00150     if (!cur)
00151         return NULL;
00152 
00153     if(IS_INPUT_QUEUE(tq))
00154     {
00155         return peek_segment(tq, ((struct tcp_input_segment *)cur)->seq + ((struct tcp_input_segment *)cur)->payload_len);
00156     }
00157     else
00158     {
00159         return peek_segment(tq, SEQN((struct pico_frame *)cur) + ((struct pico_frame *)cur)->payload_len);
00160     }
00161 }
00162 
00163 static uint16_t enqueue_segment_len(struct pico_tcp_queue *tq, void *f)
00164 {
00165     if (IS_INPUT_QUEUE(tq)) {
00166         return ((struct tcp_input_segment *)f)->payload_len;
00167     } else {
00168         return (uint16_t)(((struct pico_frame *)f)->buffer_len);
00169     }
00170 }
00171 
00172 
00173 static int32_t do_enqueue_segment(struct pico_tcp_queue *tq, void *f, uint16_t payload_len)
00174 {
00175     int32_t ret = -1;
00176     PICOTCP_MUTEX_LOCK(Mutex);
00177     if ((tq->size + payload_len) > tq->max_size)
00178     {
00179         ret = 0;
00180         goto out;
00181     }
00182 
00183     if (pico_tree_insert(&tq->pool, f) != 0)
00184     {
00185         ret = 0;
00186         goto out;
00187     }
00188 
00189     tq->size += (uint16_t)payload_len;
00190     if (payload_len > 0)
00191         tq->frames++;
00192 
00193     ret = (int32_t)payload_len;
00194 
00195 out:
00196     PICOTCP_MUTEX_UNLOCK(Mutex);
00197     return ret;
00198 }
00199 
00200 static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, void *f)
00201 {
00202     uint16_t payload_len;
00203 
00204     if (!f)
00205         return -1;
00206 
00207     payload_len = enqueue_segment_len(tq, f);
00208 
00209 
00210     if (payload_len == 0) {
00211         tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n");
00212         return -1;
00213     }
00214 
00215     return do_enqueue_segment(tq, f, payload_len);
00216 }
00217 
00218 static void pico_discard_segment(struct pico_tcp_queue *tq, void *f)
00219 {
00220     void *f1;
00221     uint16_t payload_len = (uint16_t)((IS_INPUT_QUEUE(tq)) ?
00222                                       (((struct tcp_input_segment *)f)->payload_len) :
00223                                       (((struct pico_frame *)f)->buffer_len));
00224     PICOTCP_MUTEX_LOCK(Mutex);
00225     f1 = pico_tree_delete(&tq->pool, f);
00226     if (f1) {
00227         tq->size -= (uint16_t)payload_len;
00228         if (payload_len > 0)
00229             tq->frames--;
00230     }
00231 
00232     if(f1 && IS_INPUT_QUEUE(tq))
00233     {
00234         struct tcp_input_segment *inp = f1;
00235         PICO_FREE(inp->payload);
00236         PICO_FREE(inp);
00237     }
00238     else
00239         pico_frame_discard(f);
00240 
00241     PICOTCP_MUTEX_UNLOCK(Mutex);
00242 }
00243 
00244 /* Structure for TCP socket */
00245 struct tcp_sack_block {
00246     uint32_t left;
00247     uint32_t right;
00248     struct tcp_sack_block *next;
00249 };
00250 
00251 struct pico_socket_tcp {
00252     struct pico_socket sock;
00253 
00254     /* Tree/queues */
00255     struct pico_tcp_queue tcpq_in;  /* updated the input queue to hold input segments not the full frame. */
00256     struct pico_tcp_queue tcpq_out;
00257     struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */
00258 
00259     /* tcp_output */
00260     uint32_t snd_nxt;
00261     uint32_t snd_last;
00262     uint32_t snd_old_ack;
00263     uint32_t snd_retry;
00264     uint32_t snd_last_out;
00265 
00266     /* congestion control */
00267     uint32_t avg_rtt;
00268     uint32_t rttvar;
00269     uint32_t rto;
00270     uint32_t in_flight;
00271     struct pico_timer *retrans_tmr;
00272     pico_time retrans_tmr_due;
00273     uint16_t cwnd_counter;
00274     uint16_t cwnd;
00275     uint16_t ssthresh;
00276     uint16_t recv_wnd;
00277     uint16_t recv_wnd_scale;
00278 
00279     /* tcp_input */
00280     uint32_t rcv_nxt;
00281     uint32_t rcv_ackd;
00282     uint32_t rcv_processed;
00283     uint16_t wnd;
00284     uint16_t wnd_scale;
00285     uint16_t remote_closed;
00286 
00287     /* options */
00288     uint32_t ts_nxt;
00289     uint16_t mss;
00290     uint8_t sack_ok;
00291     uint8_t ts_ok;
00292     uint8_t mss_ok;
00293     uint8_t scale_ok;
00294     struct tcp_sack_block *sacks;
00295     uint8_t jumbo;
00296     uint32_t linger_timeout;
00297 
00298     /* Transmission */
00299     uint8_t x_mode;
00300     uint8_t dupacks;
00301     uint8_t backoff;
00302     uint8_t localZeroWindow;
00303 
00304     /* Keepalive */
00305     struct pico_timer *keepalive_tmr;
00306     pico_time ack_timestamp;
00307     uint32_t ka_time;
00308     uint32_t ka_intvl;
00309     uint32_t ka_probes;
00310     uint32_t ka_retries_count;
00311 
00312     /* FIN timer */
00313     struct pico_timer *fin_tmr;
00314 };
00315 
00316 /* Queues */
00317 static struct pico_queue tcp_in = {
00318     0
00319 };
00320 static struct pico_queue tcp_out = {
00321     0
00322 };
00323 
00324 /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */
00325 static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t);
00326 
00327 /* checks if tcpq_in is empty */
00328 int pico_tcp_queue_in_is_empty(struct pico_socket *s)
00329 {
00330     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
00331 
00332     if (t->tcpq_in.frames == 0)
00333         return 1;
00334     else
00335         return 0;
00336 }
00337 
00338 /* Useful for getting rid of the beginning of the buffer (read() op) */
00339 static int release_until(struct pico_tcp_queue *q, uint32_t seq)
00340 {
00341     void *head = first_segment(q);
00342     int ret = 0;
00343     int32_t seq_result = 0;
00344 
00345     if (!head)
00346         return ret;
00347 
00348     do {
00349         void *cur = head;
00350 
00351         if (IS_INPUT_QUEUE(q))
00352             seq_result = pico_seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq);
00353         else
00354             seq_result = pico_seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq);
00355 
00356         if (seq_result <= 0)
00357         {
00358             head = next_segment(q, cur);
00359             //tcp_dbg("Releasing %08x, len: %d\n", SEQN((struct pico_frame *)head), ((struct pico_frame *)head)->payload_len);
00360             pico_discard_segment(q, cur);
00361             ret++;
00362         } else {
00363             break;
00364         }
00365     } while (head);
00366 
00367     return ret;
00368 }
00369 
00370 static int release_all_until(struct pico_tcp_queue *q, uint32_t seq, pico_time *timestamp)
00371 {
00372     void *f = NULL;
00373     struct pico_tree_node *idx, *temp;
00374     int seq_result;
00375     int ret = 0;
00376     *timestamp = 0;
00377 
00378     pico_tree_foreach_safe(idx, &q->pool, temp)
00379     {
00380         f = idx->keyValue;
00381 
00382         if (IS_INPUT_QUEUE(q))
00383             seq_result = pico_seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq);
00384         else
00385             seq_result = pico_seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq);
00386 
00387         if (seq_result <= 0) {
00388             tcp_dbg("Releasing %p\n", f);
00389             if ((seq_result == 0) && !IS_INPUT_QUEUE(q))
00390                 *timestamp = ((struct pico_frame *)f)->timestamp;
00391 
00392             pico_discard_segment(q, f);
00393             ret++;
00394         } else {
00395             return ret;
00396         }
00397     }
00398     return ret;
00399 }
00400 
00401 
00402 /* API calls */
00403 
00404 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f)
00405 {
00406     struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
00407     struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00408     struct pico_socket *s = f->sock;
00409     struct pico_ipv4_pseudo_hdr pseudo;
00410 
00411     if (s) {
00412         /* Case of outgoing frame */
00413         /* dbg("TCP CRC: on outgoing frame\n"); */
00414         pseudo.src.addr = s->local_addr.ip4.addr;
00415         pseudo.dst.addr = s->remote_addr.ip4.addr;
00416     } else {
00417         /* Case of incoming frame */
00418         /* dbg("TCP CRC: on incoming frame\n"); */
00419         pseudo.src.addr = hdr->src.addr;
00420         pseudo.dst.addr = hdr->dst.addr;
00421     }
00422 
00423     pseudo.zeros = 0;
00424     pseudo.proto = PICO_PROTO_TCP;
00425     pseudo.len = (uint16_t)short_be(f->transport_len);
00426 
00427     return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len);
00428 }
00429 
00430 #ifdef PICO_SUPPORT_IPV6
00431 uint16_t pico_tcp_checksum_ipv6(struct pico_frame *f)
00432 {
00433     struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
00434     struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *)f->transport_hdr;
00435     struct pico_ipv6_pseudo_hdr pseudo;
00436     struct pico_socket *s = f->sock;
00437 
00438     /* XXX If the IPv6 packet contains a Routing header, the Destination
00439      *     Address used in the pseudo-header is that of the final destination */
00440     if (s) {
00441         /* Case of outgoing frame */
00442         pseudo.src = s->local_addr.ip6;
00443         pseudo.dst = s->remote_addr.ip6;
00444     } else {
00445         /* Case of incoming frame */
00446         pseudo.src = ipv6_hdr->src;
00447         pseudo.dst = ipv6_hdr->dst;
00448     }
00449 
00450     pseudo.zero[0] = 0;
00451     pseudo.zero[1] = 0;
00452     pseudo.zero[2] = 0;
00453     pseudo.len = long_be(f->transport_len);
00454     pseudo.nxthdr = PICO_PROTO_TCP;
00455 
00456     return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), tcp_hdr, f->transport_len);
00457 }
00458 #endif
00459 
00460 #ifdef PICO_SUPPORT_IPV4
00461 static inline int checksum_is_ipv4(struct pico_frame *f)
00462 {
00463     return (IS_IPV4(f) || (f->sock && (f->sock->net == &pico_proto_ipv4)));
00464 }
00465 #endif
00466 
00467 #ifdef PICO_SUPPORT_IPV6
00468 static inline int checksum_is_ipv6(struct pico_frame *f)
00469 {
00470     return ((IS_IPV6(f)) || (f->sock && (f->sock->net == &pico_proto_ipv6)));
00471 }
00472 #endif
00473 
00474 uint16_t pico_tcp_checksum(struct pico_frame *f)
00475 {
00476     (void)f;
00477 
00478     #ifdef PICO_SUPPORT_IPV4
00479     if (checksum_is_ipv4(f))
00480         return pico_tcp_checksum_ipv4(f);
00481 
00482     #endif
00483 
00484     #ifdef PICO_SUPPORT_IPV6
00485     if (checksum_is_ipv6(f))
00486         return pico_tcp_checksum_ipv6(f);
00487 
00488     #endif
00489     return 0xffff;
00490 }
00491 
00492 static void tcp_send_fin(struct pico_socket_tcp *t);
00493 static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f)
00494 {
00495     struct pico_tcp_hdr *hdr;
00496     struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
00497     IGNORE_PARAMETER(self);
00498     hdr = (struct pico_tcp_hdr *)f->transport_hdr;
00499     f->sock->timestamp = TCP_TIME;
00500     if (f->payload_len > 0) {
00501         tcp_dbg("Process out: sending %p (%d bytes)\n", f, f->payload_len);
00502     } else {
00503         tcp_dbg("Sending empty packet\n");
00504     }
00505 
00506     if (f->payload_len > 0) {
00507         if (pico_seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) {
00508             t->snd_nxt = SEQN(f) + f->payload_len;
00509             tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
00510         }
00511     } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */
00512         /* hdr->seq = long_be(t->snd_nxt);   / * XXX disabled this to not to mess with seq nrs of ACKs anymore * / */
00513     } else {
00514         tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags);
00515     }
00516 
00517     pico_network_send(f);
00518     return 0;
00519 }
00520 
00521 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *data);
00522 
00523 /* Interface: protocol definition */
00524 struct pico_protocol pico_proto_tcp = {
00525     .name = "tcp",
00526     .proto_number = PICO_PROTO_TCP,
00527     .layer = PICO_LAYER_TRANSPORT,
00528     .process_in = pico_transport_process_in,
00529     .process_out = pico_tcp_process_out,
00530     .push = pico_tcp_push,
00531     .q_in = &tcp_in,
00532     .q_out = &tcp_out,
00533 };
00534 
00535 static uint32_t pico_paws(void)
00536 {
00537     static uint32_t _paws = 0;
00538     _paws = pico_rand();
00539     return long_be(_paws);
00540 }
00541 
00542 static inline void tcp_add_sack_option(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint32_t *ii)
00543 {
00544     if (flags & PICO_TCP_ACK) {
00545         struct tcp_sack_block *sb;
00546         uint32_t len_off;
00547 
00548         if (ts->sack_ok && ts->sacks) {
00549             f->start[(*ii)++] = PICO_TCP_OPTION_SACK;
00550             len_off = *ii;
00551             f->start[(*ii)++] = PICO_TCPOPTLEN_SACK;
00552             while(ts->sacks) {
00553                 sb = ts->sacks;
00554                 ts->sacks = sb->next;
00555                 memcpy(f->start + *ii, sb, 2 * sizeof(uint32_t));
00556                 *ii += (2 * (uint32_t)sizeof(uint32_t));
00557                 f->start[len_off] = (uint8_t)(f->start[len_off] + (2 * sizeof(uint32_t)));
00558                 PICO_FREE(sb);
00559             }
00560         }
00561     }
00562 }
00563 
00564 static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz)
00565 {
00566     uint32_t tsval = long_be((uint32_t)TCP_TIME);
00567     uint32_t tsecr = long_be(ts->ts_nxt);
00568     uint32_t i = 0;
00569     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
00570 
00571     memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */
00572 
00573     if (flags & PICO_TCP_SYN) {
00574         f->start[i++] = PICO_TCP_OPTION_MSS;
00575         f->start[i++] = PICO_TCPOPTLEN_MSS;
00576         f->start[i++] = (uint8_t)((ts->mss >> 8) & 0xFF);
00577         f->start[i++] = (uint8_t)(ts->mss & 0xFF);
00578         f->start[i++] = PICO_TCP_OPTION_SACK_OK;
00579         f->start[i++] = PICO_TCPOPTLEN_SACK_OK;
00580     }
00581 
00582     f->start[i++] = PICO_TCP_OPTION_WS;
00583     f->start[i++] = PICO_TCPOPTLEN_WS;
00584     f->start[i++] = (uint8_t)(ts->wnd_scale);
00585 
00586     if ((flags & PICO_TCP_SYN) || ts->ts_ok) {
00587         f->start[i++] = PICO_TCP_OPTION_TIMESTAMP;
00588         f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP;
00589         memcpy(f->start + i, &tsval, 4);
00590         i += 4;
00591         memcpy(f->start + i, &tsecr, 4);
00592         i += 4;
00593     }
00594 
00595     tcp_add_sack_option(ts, f, flags, &i);
00596 
00597     if (i < optsiz)
00598         f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END;
00599 }
00600 
00601 static uint16_t tcp_options_size_frame(struct pico_frame *f)
00602 {
00603     uint16_t size = 0;
00604 
00605     /* Always update window scale. */
00606     size = (uint16_t)(size + PICO_TCPOPTLEN_WS);
00607     if (f->transport_flags_saved)
00608         size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP);
00609 
00610     size = (uint16_t)(size + PICO_TCPOPTLEN_END);
00611     size = (uint16_t)(((uint16_t)(size + 3u) >> 2u) << 2u);
00612     return size;
00613 }
00614 
00615 static void tcp_add_options_frame(struct pico_socket_tcp *ts, struct pico_frame *f)
00616 {
00617     uint32_t tsval = long_be((uint32_t)TCP_TIME);
00618     uint32_t tsecr = long_be(ts->ts_nxt);
00619     uint32_t i = 0;
00620     uint16_t optsiz = tcp_options_size_frame(f);
00621 
00622     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
00623 
00624     memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */
00625 
00626 
00627     f->start[i++] = PICO_TCP_OPTION_WS;
00628     f->start[i++] = PICO_TCPOPTLEN_WS;
00629     f->start[i++] = (uint8_t)(ts->wnd_scale);
00630 
00631     if (f->transport_flags_saved) {
00632         f->start[i++] = PICO_TCP_OPTION_TIMESTAMP;
00633         f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP;
00634         memcpy(f->start + i, &tsval, 4);
00635         i += 4;
00636         memcpy(f->start + i, &tsecr, 4);
00637         i += 4;
00638     }
00639 
00640     if (i < optsiz)
00641         f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END;
00642 }
00643 
00644 static void tcp_send_ack(struct pico_socket_tcp *t);
00645 #define tcp_send_windowUpdate(t) (tcp_send_ack(t))
00646 
00647 static inline void tcp_set_space_check_winupdate(struct pico_socket_tcp *t, int32_t space, uint32_t shift)
00648 {
00649     if (((uint32_t)space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (int32_t)((uint32_t)space >> 2u))) {
00650         t->wnd = (uint16_t)space;
00651         t->wnd_scale = (uint16_t)shift;
00652 
00653         if(t->wnd == 0) /* mark the entering to zero window state */
00654             t->localZeroWindow = 1u;
00655         else if(t->localZeroWindow)
00656         {
00657             t->localZeroWindow = 0u;
00658             tcp_send_windowUpdate(t);
00659         }
00660     }
00661 }
00662 
00663 static void tcp_set_space(struct pico_socket_tcp *t)
00664 {
00665     int32_t space;
00666     uint32_t shift = 0;
00667 
00668     if (t->tcpq_in.max_size == 0) {
00669         space = ONE_GIGABYTE;
00670     } else {
00671         space = (int32_t)(t->tcpq_in.max_size - t->tcpq_in.size);
00672     }
00673 
00674     if (space < 0)
00675         space = 0;
00676 
00677     while(space > 0xFFFF) {
00678         space = (int32_t)(((uint32_t)space >> 1u));
00679         shift++;
00680     }
00681     tcp_set_space_check_winupdate(t, space, shift);
00682 }
00683 
00684 /* Return 32-bit aligned option size */
00685 static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags)
00686 {
00687     uint16_t size = 0;
00688     struct tcp_sack_block *sb = t->sacks;
00689 
00690     if (flags & PICO_TCP_SYN) { /* Full options */
00691         size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP;
00692     } else {
00693 
00694         /* Always update window scale. */
00695         size = (uint16_t)(size + PICO_TCPOPTLEN_WS);
00696 
00697         if (t->ts_ok)
00698             size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP);
00699 
00700         size = (uint16_t)(size + PICO_TCPOPTLEN_END);
00701     }
00702 
00703     if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) {
00704         size = (uint16_t)(size + 2);
00705         while(sb) {
00706             size = (uint16_t)(size + (2 * sizeof(uint32_t)));
00707             sb = sb->next;
00708         }
00709     }
00710 
00711     size = (uint16_t)(((size + 3u) >> 2u) << 2u);
00712     return size;
00713 }
00714 
00715 uint16_t pico_tcp_overhead(struct pico_socket *s)
00716 {
00717     if (!s)
00718         return 0;
00719 
00720     return (uint16_t)(PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, (uint16_t)0)); /* hdr + Options size for data pkt */
00721 
00722 }
00723 
00724 static inline int tcp_sack_marker(struct pico_frame *f, uint32_t start, uint32_t end, uint16_t *count)
00725 {
00726     int cmp;
00727     cmp = pico_seq_compare(SEQN(f), start);
00728     if (cmp > 0)
00729         return 0;
00730 
00731     if (cmp == 0) {
00732         cmp = pico_seq_compare(SEQN(f) + f->payload_len, end);
00733         if (cmp > 0) {
00734             tcp_dbg("Invalid SACK: ignoring.\n");
00735         }
00736 
00737         tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end);
00738         f->flags |= PICO_FRAME_FLAG_SACKED;
00739         (*count)++;
00740     }
00741 
00742     return cmp;
00743 }
00744 
00745 static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end)
00746 {
00747     struct pico_frame *f;
00748     struct pico_tree_node *index, *temp;
00749     uint16_t count = 0;
00750 
00751     pico_tree_foreach_safe(index, &t->tcpq_out.pool, temp){
00752         f = index->keyValue;
00753         if (tcp_sack_marker(f, start, end, &count) == 0)
00754             goto done;
00755     }
00756 
00757 done:
00758     if (t->x_mode > PICO_TCP_LOOKAHEAD) {
00759         if (t->in_flight > (count))
00760             t->in_flight -= (count);
00761         else
00762             t->in_flight = 0;
00763     }
00764 }
00765 
00766 inline static void tcp_add_header(struct pico_socket_tcp *t, struct pico_frame *f)
00767 {
00768     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
00769     f->timestamp = TCP_TIME;
00770     tcp_add_options(t, f, 0, (uint16_t)(f->transport_len - f->payload_len - (uint16_t)PICO_SIZE_TCPHDR));
00771     hdr->rwnd = short_be(t->wnd);
00772     hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK;
00773     hdr->ack = long_be(t->rcv_nxt);
00774     hdr->crc = 0;
00775     hdr->crc = short_be(pico_tcp_checksum(f));
00776 }
00777 
00778 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
00779 {
00780     uint32_t start, end;
00781     int i = 0;
00782     if (len % 8) {
00783         tcp_dbg("SACK: Invalid len.\n");
00784         return;
00785     }
00786 
00787     while (i < len) {
00788         start = long_from(opt + i);
00789         i += 4;
00790         end = long_from(opt + i);
00791         i += 4;
00792         tcp_process_sack(t, long_be(start), long_be(end));
00793     }
00794 }
00795 
00796 static int tcpopt_len_check(uint32_t *idx, uint8_t len, uint8_t expected)
00797 {
00798     if (len != expected) {
00799         *idx = *idx + len - 2;
00800         return -1;
00801     }
00802 
00803     return 0;
00804 }
00805 
00806 static inline void tcp_parse_option_ws(struct pico_socket_tcp *t, uint8_t len, uint8_t *opt, uint32_t *idx)
00807 {
00808     if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_WS) < 0)
00809         return;
00810 
00811     t->recv_wnd_scale = opt[(*idx)++];
00812     tcp_dbg_options("TCP Window scale: received %d\n", t->recv_wnd_scale);
00813 
00814 }
00815 
00816 static inline void tcp_parse_option_sack_ok(struct pico_socket_tcp *t, struct pico_frame *f, uint8_t len, uint32_t *idx)
00817 {
00818     if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_SACK_OK) < 0)
00819         return;
00820 
00821     if(((struct pico_tcp_hdr *)(f->transport_hdr))->flags & PICO_TCP_SYN )
00822         t->sack_ok = 1;
00823 }
00824 
00825 static inline void tcp_parse_option_mss(struct pico_socket_tcp *t, uint8_t len, uint8_t *opt, uint32_t *idx)
00826 {
00827     uint16_t mss;
00828     if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_MSS) < 0)
00829         return;
00830 
00831     t->mss_ok = 1;
00832     mss = short_from(opt + *idx);
00833     *idx += (uint32_t)sizeof(uint16_t);
00834     if (t->mss > short_be(mss))
00835         t->mss = short_be(mss);
00836 }
00837 
00838 static inline void tcp_parse_option_timestamp(struct pico_socket_tcp *t, struct pico_frame *f, uint8_t len, uint8_t *opt, uint32_t *idx)
00839 {
00840     uint32_t tsval, tsecr;
00841     if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_TIMESTAMP) < 0)
00842         return;
00843 
00844     t->ts_ok = 1;
00845     tsval = long_from(opt + *idx);
00846     *idx += (uint32_t)sizeof(uint32_t);
00847     tsecr = long_from(opt + *idx);
00848     f->timestamp = long_be(tsecr);
00849     *idx += (uint32_t)sizeof(uint32_t);
00850     t->ts_nxt = long_be(tsval);
00851 }
00852 
00853 static void tcp_parse_options(struct pico_frame *f)
00854 {
00855     struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
00856     uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR;
00857     uint32_t i = 0;
00858     f->timestamp = 0;
00859     while (i < (f->transport_len - PICO_SIZE_TCPHDR)) {
00860         uint8_t type =  opt[i++];
00861         uint8_t len;
00862         if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1))
00863             len =  opt[i++];
00864         else
00865             len = 1;
00866 
00867         if (f->payload && ((opt + i) > f->payload))
00868             break;
00869 
00870         tcp_dbg_options("Received option '%d', len = %d \n", type, len);
00871         switch (type) {
00872         case PICO_TCP_OPTION_NOOP:
00873         case PICO_TCP_OPTION_END:
00874             break;
00875         case PICO_TCP_OPTION_WS:
00876             tcp_parse_option_ws(t, len, opt, &i);
00877             break;
00878         case PICO_TCP_OPTION_SACK_OK:
00879             tcp_parse_option_sack_ok(t, f, len, &i);
00880             break;
00881         case PICO_TCP_OPTION_MSS:
00882             tcp_parse_option_mss(t, len, opt, &i);
00883             break;
00884         case PICO_TCP_OPTION_TIMESTAMP:
00885             tcp_parse_option_timestamp(t, f, len, opt, &i);
00886             break;
00887 
00888         case PICO_TCP_OPTION_SACK:
00889             tcp_rcv_sack(t, opt + i, len - 2);
00890             i = i + len - 2;
00891             break;
00892         default:
00893             tcp_dbg_options("TCP: received unsupported option %u\n", type);
00894             i = i + len - 2;
00895         }
00896     }
00897 }
00898 
00899 static inline void tcp_send_add_tcpflags(struct pico_socket_tcp *ts, struct pico_frame *f)
00900 {
00901     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00902     if (ts->rcv_nxt != 0) {
00903         if ((ts->rcv_ackd == 0) || (pico_seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) {
00904             hdr->flags |= PICO_TCP_ACK;
00905             hdr->ack = long_be(ts->rcv_nxt);
00906             ts->rcv_ackd = ts->rcv_nxt;
00907         }
00908     }
00909 
00910     if (hdr->flags & PICO_TCP_SYN) {
00911         ts->snd_nxt++;
00912     }
00913 
00914     if (f->payload_len > 0) {
00915         hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK;
00916         hdr->ack = long_be(ts->rcv_nxt);
00917         ts->rcv_ackd = ts->rcv_nxt;
00918     }
00919 }
00920 
00921 static inline int tcp_send_try_enqueue(struct pico_socket_tcp *ts, struct pico_frame *f)
00922 {
00923     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00924     struct pico_frame *cpy;
00925     (void)hdr;
00926 
00927     /* TCP: ENQUEUE to PROTO ( Transmit ) */
00928     cpy = pico_frame_copy(f);
00929     if (!cpy) {
00930         pico_err = PICO_ERR_ENOMEM;
00931         return -1;
00932     }
00933 
00934     if ((pico_enqueue(&tcp_out, cpy) > 0)) {
00935         if (f->payload_len > 0) {
00936             ts->in_flight++;
00937             ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */
00938         }
00939 
00940         tcp_dbg("DBG> [tcp output] state: %02x --> local port:%u remote port: %u seq: %08x ack: %08x flags: %02x = t_len: %u, hdr: %u payload: %d\n",
00941                 TCPSTATE(&ts->sock) >> 8, short_be(hdr->trans.sport), short_be(hdr->trans.dport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
00942     } else {
00943         pico_frame_discard(cpy);
00944     }
00945 
00946     return 0;
00947 
00948 }
00949 
00950 static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f)
00951 {
00952     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
00953     hdr->trans.sport = ts->sock.local_port;
00954     hdr->trans.dport = ts->sock.remote_port;
00955     if (!hdr->seq)
00956         hdr->seq = long_be(ts->snd_nxt);
00957 
00958     tcp_send_add_tcpflags(ts, f);
00959 
00960     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
00961     hdr->rwnd = short_be(ts->wnd);
00962     hdr->crc = 0;
00963     hdr->crc = short_be(pico_tcp_checksum(f));
00964 
00965     return tcp_send_try_enqueue(ts, f);
00966 
00967 }
00968 
00969 /* #define PICO_TCP_SUPPORT_SOCKET_STATS */
00970 
00971 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
00972 static void sock_stats(uint32_t when, void *arg)
00973 {
00974     struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
00975     tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x cwnd: %d\n",
00976             when, t->sock.state, short_be(t->sock.local_port), short_be(t->sock.remote_port), t->tcpq_out.size, SEQN((struct pico_frame *)first_segment(&t->tcpq_out)), t->snd_nxt, t->cwnd);
00977     pico_timer_add(2000, sock_stats, t);
00978 }
00979 #endif
00980 
00981 static void tcp_send_probe(struct pico_socket_tcp *t);
00982 
00983 static void pico_tcp_keepalive(pico_time now, void *arg)
00984 {
00985     struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
00986     if (((t->sock.state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)  && (t->ka_time > 0)) {
00987         if (t->ka_time < (now - t->ack_timestamp)) {
00988             if (t->ka_retries_count == 0) {
00989                 /* First probe */
00990                 tcp_send_probe(t);
00991                 t->ka_retries_count++;
00992             }
00993             if (t->ka_retries_count > t->ka_probes) {
00994                 if (t->sock.wakeup)
00995                 {
00996                     pico_err = PICO_ERR_ECONNRESET;
00997                     t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock);
00998                 }
00999             }
01000             if (((t->ka_retries_count * t->ka_intvl) + t->ka_time) < (now - t->ack_timestamp)) {
01001                 /* Next probe */
01002                 tcp_send_probe(t);
01003                 t->ka_retries_count++;
01004             }
01005         } else {
01006             t->ka_retries_count = 0;
01007         }
01008     }
01009     t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t);
01010 }
01011 
01012 static inline void rto_set(struct pico_socket_tcp *t, uint32_t rto)
01013 {
01014     if (rto < PICO_TCP_RTO_MIN)
01015         rto = PICO_TCP_RTO_MIN;
01016 
01017     if (rto > PICO_TCP_RTO_MAX)
01018         rto = PICO_TCP_RTO_MAX;
01019 
01020     t->rto = rto;
01021 }
01022 
01023 
01024 struct pico_socket *pico_tcp_open(uint16_t family)
01025 {
01026     struct pico_socket_tcp *t = PICO_ZALLOC(sizeof(struct pico_socket_tcp));
01027     if (!t)
01028         return NULL;
01029 
01030     t->sock.timestamp = TCP_TIME;
01031     pico_socket_set_family(&t->sock, family);
01032     t->mss = (uint16_t)(pico_socket_get_mss(&t->sock) - PICO_SIZE_TCPHDR);
01033     t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF;
01034     t->tcpq_hold.pool.compare = t->tcpq_out.pool.compare = segment_compare;
01035     t->tcpq_in.pool.compare = input_segment_compare;
01036     t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
01037     t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
01038     t->tcpq_hold.max_size = 2u * t->mss;
01039     rto_set(t, PICO_TCP_RTO_MIN);
01040 
01041     /* Uncomment next line and disable Nagle by default */
01042     t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY);
01043 
01044     /* Uncomment next line and Nagle is enabled by default */
01045     /* t->sock.opt_flags &= (uint16_t) ~(1 << PICO_SOCKET_OPT_TCPNODELAY); */
01046 
01047     /* Set default linger for the socket */
01048     t->linger_timeout = PICO_SOCKET_LINGER_TIMEOUT;
01049 
01050 
01051 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
01052     pico_timer_add(2000, sock_stats, t);
01053 #endif
01054 
01055     t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t);
01056     tcp_set_space(t);
01057 
01058     return &t->sock;
01059 }
01060 
01061 static uint32_t tcp_read_finish(struct pico_socket *s, uint32_t tot_rd_len)
01062 {
01063     struct pico_socket_tcp *t = TCP_SOCK(s);
01064     tcp_set_space(t);
01065     if (t->tcpq_in.size == 0) {
01066         s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD);
01067     }
01068 
01069     if (t->remote_closed) {
01070         s->ev_pending |= (uint16_t)(PICO_SOCK_EV_CLOSE);
01071         s->state &= 0x00FFU;
01072         s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
01073         /* set SHUT_REMOTE */
01074         s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
01075         if (s->wakeup) {
01076             s->wakeup(PICO_SOCK_EV_CLOSE, s);
01077         }
01078     }
01079 
01080     return tot_rd_len;
01081 }
01082 
01083 static inline uint32_t tcp_read_in_frame_len(struct tcp_input_segment *f, int32_t in_frame_off, uint32_t tot_rd_len, uint32_t read_op_len)
01084 {
01085     uint32_t in_frame_len = 0;
01086     if (in_frame_off > 0)
01087     {
01088         if ((uint32_t)in_frame_off > f->payload_len) {
01089             tcp_dbg("FATAL TCP ERR: in_frame_off > f->payload_len\n");
01090         }
01091 
01092         in_frame_len = f->payload_len - (uint32_t)in_frame_off;
01093     } else { /* in_frame_off == 0 */
01094         in_frame_len = f->payload_len;
01095     }
01096 
01097     if ((in_frame_len + tot_rd_len) > (uint32_t)read_op_len) {
01098         in_frame_len = read_op_len - tot_rd_len;
01099     }
01100 
01101     return in_frame_len;
01102 
01103 }
01104 
01105 static inline void tcp_read_check_segment_done(struct pico_socket_tcp *t, struct tcp_input_segment *f, uint32_t in_frame_len)
01106 {
01107     if ((in_frame_len == 0u) || (in_frame_len == (uint32_t)f->payload_len)) {
01108         pico_discard_segment(&t->tcpq_in, f);
01109     }
01110 }
01111 
01112 uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len)
01113 {
01114     struct pico_socket_tcp *t = TCP_SOCK(s);
01115     struct tcp_input_segment *f;
01116     int32_t in_frame_off;
01117     uint32_t in_frame_len;
01118     uint32_t tot_rd_len = 0;
01119 
01120     while (tot_rd_len < len) {
01121         /* To be sure we don't have garbage at the beginning */
01122         release_until(&t->tcpq_in, t->rcv_processed);
01123         f = first_segment(&t->tcpq_in);
01124         if (!f)
01125             return tcp_read_finish(s, tot_rd_len);
01126 
01127         in_frame_off = pico_seq_compare(t->rcv_processed, f->seq);
01128         /* Check for hole at the beginning of data, awaiting retransmissions. */
01129         if (in_frame_off < 0) {
01130             tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n", t->rcv_processed, f->seq, t->rcv_nxt);
01131             return tcp_read_finish(s, tot_rd_len);
01132         }
01133 
01134         in_frame_len = tcp_read_in_frame_len(f, in_frame_off, tot_rd_len, len);
01135 
01136 
01137         memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len);
01138         tot_rd_len += in_frame_len;
01139         t->rcv_processed += in_frame_len;
01140 
01141         tcp_read_check_segment_done(t, f, in_frame_len);
01142 
01143     }
01144     return tcp_read_finish(s, tot_rd_len);
01145 }
01146 
01147 int pico_tcp_initconn(struct pico_socket *s);
01148 static void initconn_retry(pico_time when, void *arg)
01149 {
01150     struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
01151     IGNORE_PARAMETER(when);
01152     if (TCPSTATE(&t->sock) != PICO_SOCKET_STATE_TCP_ESTABLISHED)
01153     {
01154         if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) {
01155             tcp_dbg("TCP> Connection timeout. \n");
01156             if (t->sock.wakeup)
01157             {
01158                 pico_err = PICO_ERR_ECONNREFUSED;
01159                 t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock);
01160             }
01161             pico_socket_del(&t->sock);
01162             return;
01163         }
01164 
01165         tcp_dbg("TCP> SYN retry %d...\n", t->backoff);
01166         t->backoff++;
01167         pico_tcp_initconn(&t->sock);
01168     } else {
01169         tcp_dbg("TCP> Connection is already established: no retry needed. good.\n");
01170     }
01171 }
01172 
01173 int pico_tcp_initconn(struct pico_socket *s)
01174 {
01175     struct pico_socket_tcp *ts = TCP_SOCK(s);
01176     struct pico_frame *syn;
01177     struct pico_tcp_hdr *hdr;
01178     uint16_t mtu, opt_len = tcp_options_size(ts, PICO_TCP_SYN);
01179 
01180     syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
01181     if (!syn)
01182         return -1;
01183 
01184     hdr = (struct pico_tcp_hdr *) syn->transport_hdr;
01185 
01186     if (!ts->snd_nxt)
01187         ts->snd_nxt = long_be(pico_paws());
01188 
01189     ts->snd_last = ts->snd_nxt;
01190     ts->cwnd = PICO_TCP_IW;
01191     mtu = (uint16_t)pico_socket_get_mss(s);
01192     ts->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR);
01193     ts->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss) -  (((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss)) >> 3u));
01194     syn->sock = s;
01195     hdr->seq = long_be(ts->snd_nxt);
01196     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
01197     hdr->flags = PICO_TCP_SYN;
01198     tcp_set_space(ts);
01199     hdr->rwnd = short_be(ts->wnd);
01200     tcp_add_options(ts, syn, PICO_TCP_SYN, opt_len);
01201     hdr->trans.sport = ts->sock.local_port;
01202     hdr->trans.dport = ts->sock.remote_port;
01203 
01204     hdr->crc = 0;
01205     hdr->crc = short_be(pico_tcp_checksum(syn));
01206 
01207     /* TCP: ENQUEUE to PROTO ( SYN ) */
01208     tcp_dbg("Sending SYN... (ports: %d - %d) size: %d\n", short_be(ts->sock.local_port), short_be(ts->sock.remote_port), syn->buffer_len);
01209     pico_enqueue(&tcp_out, syn);
01210     ts->retrans_tmr = pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts);
01211     return 0;
01212 }
01213 
01214 static int tcp_send_synack(struct pico_socket *s)
01215 {
01216     struct pico_socket_tcp *ts = TCP_SOCK(s);
01217     struct pico_frame *synack;
01218     struct pico_tcp_hdr *hdr;
01219     uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK);
01220 
01221     synack = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
01222     if (!synack)
01223         return -1;
01224 
01225     hdr = (struct pico_tcp_hdr *) synack->transport_hdr;
01226 
01227     synack->sock = s;
01228     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
01229     hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK;
01230     hdr->rwnd = short_be(ts->wnd);
01231     hdr->seq = long_be(ts->snd_nxt);
01232     ts->rcv_processed = long_be(hdr->seq);
01233     ts->snd_last = ts->snd_nxt;
01234     tcp_set_space(ts);
01235     tcp_add_options(ts, synack, hdr->flags, opt_len);
01236     synack->payload_len = 0;
01237     synack->timestamp = TCP_TIME;
01238     tcp_send(ts, synack);
01239     pico_frame_discard(synack);
01240     return 0;
01241 }
01242 
01243 static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags, int is_keepalive)
01244 {
01245     struct pico_frame *f;
01246     struct pico_tcp_hdr *hdr;
01247     uint16_t opt_len = tcp_options_size(t, flags);
01248     f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
01249     if (!f) {
01250         return;
01251     }
01252 
01253     f->sock = &t->sock;
01254     hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01255     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
01256     hdr->flags = (uint8_t)flags;
01257     hdr->rwnd = short_be(t->wnd);
01258     tcp_set_space(t);
01259     tcp_add_options(t, f, flags, opt_len);
01260     hdr->trans.sport = t->sock.local_port;
01261     hdr->trans.dport = t->sock.remote_port;
01262     hdr->seq = long_be(t->snd_nxt);
01263     if ((flags & PICO_TCP_ACK) != 0) {
01264         hdr->ack = long_be(t->rcv_nxt);
01265     }
01266 
01267     if (is_keepalive)
01268         hdr->seq = long_be(t->snd_nxt - 1);
01269 
01270     t->rcv_ackd = t->rcv_nxt;
01271 
01272     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
01273     hdr->rwnd = short_be(t->wnd);
01274     hdr->crc = 0;
01275     hdr->crc = short_be(pico_tcp_checksum(f));
01276 
01277     /* TCP: ENQUEUE to PROTO */
01278     pico_enqueue(&tcp_out, f);
01279 }
01280 
01281 static void tcp_send_ack(struct pico_socket_tcp *t)
01282 {
01283     tcp_send_empty(t, PICO_TCP_ACK, 0);
01284 }
01285 
01286 static void tcp_send_probe(struct pico_socket_tcp *t)
01287 {
01288     /* tcp_dbg("Sending probe\n"); */
01289     tcp_send_empty(t, PICO_TCP_PSHACK, 1);
01290 }
01291 
01292 static int tcp_do_send_rst(struct pico_socket *s, uint32_t seq)
01293 {
01294     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
01295     uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST);
01296     struct pico_frame *f;
01297     struct pico_tcp_hdr *hdr;
01298     f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
01299     if (!f) {
01300         return -1;
01301     }
01302     f->sock = &t->sock;
01303     tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n");
01304 
01305     hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01306     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
01307     hdr->flags = PICO_TCP_RST;
01308     hdr->rwnd = short_be(t->wnd);
01309     tcp_set_space(t);
01310     tcp_add_options(t, f, PICO_TCP_RST, opt_len);
01311     hdr->trans.sport = t->sock.local_port;
01312     hdr->trans.dport = t->sock.remote_port;
01313     hdr->seq = seq;
01314     hdr->ack = long_be(t->rcv_nxt);
01315     t->rcv_ackd = t->rcv_nxt;
01316     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
01317     hdr->rwnd = short_be(t->wnd);
01318     hdr->crc = 0;
01319     hdr->crc = short_be(pico_tcp_checksum(f));
01320 
01321     /* TCP: ENQUEUE to PROTO */
01322     pico_enqueue(&tcp_out, f);
01323     tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE\n");
01324     return 0;
01325 }
01326 
01327 static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr)
01328 {
01329     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
01330     struct pico_tcp_hdr *hdr_rcv;
01331     int ret;
01332 
01333     if (fr && ((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) {
01334         /* in synchronized state: send RST with seq = ack from previous segment */
01335         hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
01336         ret = tcp_do_send_rst(s, hdr_rcv->ack);       
01337     } else {
01338         /* non-synchronized state */
01339         /* go to CLOSED here to prevent timer callback to go on after timeout */
01340         (t->sock).state &= 0x00FFU;
01341         (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
01342         ret = tcp_do_send_rst(s, long_be(t->snd_nxt));       
01343 
01344         /* Set generic socket state to CLOSED, too */
01345         (t->sock).state &= 0xFF00U;
01346         (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
01347 
01348         /* call EV_FIN wakeup before deleting */
01349         if ((t->sock).wakeup)
01350             (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
01351 
01352         /* delete socket */
01353         pico_socket_del(&t->sock);
01354     }
01355     return ret;
01356 }
01357 
01358 static inline void tcp_fill_rst_payload(struct pico_frame *fr, struct pico_frame *f)
01359 {
01360     /* fill in IP data from original frame */
01361     if (IS_IPV4(fr)) {
01362         memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv4_hdr));
01363         ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr;
01364         ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr;
01365         tcp_dbg("Making IPv4 reset frame...\n");
01366 
01367     } else {
01368         memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv6_hdr));
01369         ((struct pico_ipv6_hdr *)(f->net_hdr))->dst = ((struct pico_ipv6_hdr *)(fr->net_hdr))->src;
01370         ((struct pico_ipv6_hdr *)(f->net_hdr))->src = ((struct pico_ipv6_hdr *)(fr->net_hdr))->dst;
01371     }
01372 
01373     /* fill in TCP data from original frame */
01374     ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport;
01375     ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport;
01376 
01377 }
01378 
01379 
01380 static inline void tcp_fill_rst_header(struct pico_frame *fr, struct pico_tcp_hdr *hdr1, struct pico_frame *f, struct pico_tcp_hdr *hdr)
01381 {
01382     if(!(hdr1->flags & PICO_TCP_ACK))
01383         hdr->flags |= PICO_TCP_ACK;
01384 
01385     hdr->rwnd  = 0;
01386     if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) {
01387         hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack;
01388     } else {
01389         hdr->seq = 0U;
01390     }
01391 
01392     hdr->ack = 0;
01393     if(!(hdr1->flags & PICO_TCP_ACK))
01394         hdr->ack = long_be(long_be(((struct pico_tcp_hdr *)(fr->transport_hdr))->seq) + fr->payload_len);
01395 
01396     hdr->crc = short_be(pico_tcp_checksum(f));
01397 }
01398 
01399 int pico_tcp_reply_rst(struct pico_frame *fr)
01400 {
01401     struct pico_tcp_hdr *hdr, *hdr1;
01402     struct pico_frame *f;
01403     uint16_t size = PICO_SIZE_TCPHDR;
01404 
01405 
01406     hdr1 = (struct pico_tcp_hdr *) (fr->transport_hdr);
01407     if ((hdr1->flags & PICO_TCP_RST) != 0)
01408         return -1;
01409 
01410     tcp_dbg("TCP> sending RST ... \n");
01411 
01412     f = fr->sock->net->alloc(fr->sock->net, size);
01413     if (!f) {
01414         pico_err = PICO_ERR_ENOMEM;
01415         return -1;
01416     }
01417 
01418     tcp_fill_rst_payload(fr, f);
01419 
01420     hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01421     hdr->len   = (uint8_t)(size << 2);
01422     hdr->flags = PICO_TCP_RST;
01423 
01424     tcp_fill_rst_header(fr, hdr1, f, hdr);
01425 
01426     if (0) {
01427 #ifdef PICO_SUPPORT_IPV4
01428     } else if (IS_IPV4(f)) {
01429         tcp_dbg("Pushing IPv4 reset frame...\n");
01430         pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP);
01431 #endif
01432 #ifdef PICO_SUPPORT_IPV6
01433     } else {
01434         pico_ipv6_frame_push(f, NULL, &(((struct pico_ipv6_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP, 0);
01435 #endif
01436     }
01437 
01438 
01439     return 0;
01440 }
01441 
01442 static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr)
01443 {
01444     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
01445     struct pico_frame *f;
01446     struct pico_tcp_hdr *hdr, *hdr_rcv;
01447     uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK);
01448     hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
01449 
01450     tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n", (s->state & PICO_SOCKET_STATE_TCP));
01451     if (((s->state & PICO_SOCKET_STATE_TCP) ==  PICO_SOCKET_STATE_TCP_LISTEN)) {
01452         if ((fr->flags & PICO_TCP_RST) != 0)
01453             return 0;
01454 
01455         return pico_tcp_reply_rst(fr);
01456     }
01457 
01458     /***************************************************************************/
01459     /* sending RST */
01460     f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
01461 
01462     if (!f) {
01463         return -1;
01464     }
01465 
01466 
01467     f->sock = &t->sock;
01468     hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01469     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
01470     hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
01471     hdr->rwnd = short_be(t->wnd);
01472     tcp_set_space(t);
01473     tcp_add_options(t, f, PICO_TCP_RST | PICO_TCP_ACK, opt_len);
01474     hdr->trans.sport = t->sock.local_port;
01475     hdr->trans.dport = t->sock.remote_port;
01476 
01477     /* non-synchronized state */
01478     if (hdr_rcv->flags & PICO_TCP_ACK) {
01479         hdr->seq = hdr_rcv->ack;
01480     } else {
01481         hdr->seq = 0U;
01482     }
01483 
01484     hdr->ack = long_be(SEQN(fr) + fr->payload_len);
01485 
01486     t->rcv_ackd = t->rcv_nxt;
01487     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
01488     hdr->rwnd = short_be(t->wnd);
01489     hdr->crc = 0;
01490     hdr->crc = short_be(pico_tcp_checksum(f));
01491 
01492     /* TCP: ENQUEUE to PROTO */
01493     pico_enqueue(&tcp_out, f);
01494 
01495     /***************************************************************************/
01496 
01497     tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n");
01498 
01499     return 0;
01500 }
01501 
01502 static void tcp_deltcb(pico_time when, void *arg);
01503 
01504 static void tcp_linger(struct pico_socket_tcp *t)
01505 {
01506     if (t->fin_tmr) {
01507         pico_timer_cancel(t->fin_tmr);
01508     }
01509     t->fin_tmr = pico_timer_add(t->linger_timeout, tcp_deltcb, t);
01510 }
01511 
01512 static void tcp_send_fin(struct pico_socket_tcp *t)
01513 {
01514     struct pico_frame *f;
01515     struct pico_tcp_hdr *hdr;
01516     uint16_t opt_len = tcp_options_size(t, PICO_TCP_FIN);
01517     f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
01518     if (!f) {
01519         return;
01520     }
01521 
01522     f->sock = &t->sock;
01523     hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01524     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
01525     hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK;
01526     hdr->ack = long_be(t->rcv_nxt);
01527     t->rcv_ackd = t->rcv_nxt;
01528     hdr->rwnd = short_be(t->wnd);
01529     tcp_set_space(t);
01530     tcp_add_options(t, f, PICO_TCP_FIN, opt_len);
01531     hdr->trans.sport = t->sock.local_port;
01532     hdr->trans.dport = t->sock.remote_port;
01533     hdr->seq = long_be(t->snd_nxt);
01534 
01535     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
01536     hdr->rwnd = short_be(t->wnd);
01537     hdr->crc = 0;
01538     hdr->crc = short_be(pico_tcp_checksum(f));
01539     /* tcp_dbg("SENDING FIN...\n"); */
01540     if (t->linger_timeout > 0) {
01541         pico_enqueue(&tcp_out, f);
01542         t->snd_nxt++;
01543     } else {
01544         pico_frame_discard(f);
01545     }
01546     tcp_linger(t);
01547 }
01548 
01549 static void tcp_sack_prepare(struct pico_socket_tcp *t)
01550 {
01551     struct tcp_input_segment *pkt;
01552     uint32_t left = 0, right = 0;
01553     struct tcp_sack_block *sb;
01554     int n = 0;
01555     if (t->sacks) /* previous sacks are pending */
01556         return;
01557 
01558     pkt = first_segment(&t->tcpq_in);
01559     while(n < 3) {
01560         if (!pkt) {
01561             if(left) {
01562                 sb = PICO_ZALLOC(sizeof(struct tcp_sack_block));
01563                 if (!sb)
01564                     break;
01565 
01566                 sb->left = long_be(left);
01567                 sb->right = long_be(right);
01568                 n++;
01569                 sb->next = t->sacks;
01570                 t->sacks = sb;
01571                 left = 0;
01572                 right = 0;
01573             }
01574 
01575             break;
01576         }
01577 
01578         if (pkt->seq < t->rcv_nxt) {
01579             pkt = next_segment(&t->tcpq_in, pkt);
01580             continue;
01581         }
01582 
01583         if (!left) {
01584             left = pkt->seq;
01585             right = pkt->seq + pkt->payload_len;
01586             pkt = next_segment(&t->tcpq_in, pkt);
01587             continue;
01588         }
01589 
01590         if(pkt->seq == right) {
01591             right += pkt->payload_len;
01592             pkt = next_segment(&t->tcpq_in, pkt);
01593             continue;
01594         } else {
01595             sb = PICO_ZALLOC(sizeof(struct tcp_sack_block));
01596             if (!sb)
01597                 break;
01598 
01599             sb->left = long_be(left);
01600             sb->right = long_be(right);
01601             n++;
01602             sb->next = t->sacks;
01603             t->sacks = sb;
01604             left = 0;
01605             right = 0;
01606             pkt = next_segment(&t->tcpq_in, pkt);
01607         }
01608     }
01609 }
01610 
01611 static inline int tcp_data_in_expected(struct pico_socket_tcp *t, struct pico_frame *f)
01612 {
01613     struct tcp_input_segment *nxt;
01614     if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */
01615         /* Create new segment and enqueue it */
01616         struct tcp_input_segment *input = segment_from_frame(f);
01617         if (!input) {
01618             pico_err = PICO_ERR_ENOMEM;
01619             return -1;
01620         }
01621 
01622         if(pico_enqueue_segment(&t->tcpq_in, input) <= 0)
01623         {
01624             /* failed to enqueue, destroy segment */
01625             PICO_FREE(input->payload);
01626             PICO_FREE(input);
01627             return -1;
01628         } else {
01629             t->rcv_nxt = SEQN(f) + f->payload_len;
01630             nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
01631             while(nxt) {
01632                 tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt);
01633                 t->rcv_nxt += nxt->payload_len;
01634                 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
01635             }
01636             t->sock.ev_pending |= PICO_SOCK_EV_RD;
01637         }
01638     } else {
01639         tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
01640     }
01641 
01642     return 0;
01643 }
01644 
01645 static inline int tcp_data_in_high_segment(struct pico_socket_tcp *t, struct pico_frame *f)
01646 {
01647     tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
01648     if (t->sack_ok) {
01649         struct tcp_input_segment *input = segment_from_frame(f);
01650         if (!input) {
01651             pico_err = PICO_ERR_ENOMEM;
01652             return -1;
01653         }
01654 
01655         if(pico_enqueue_segment(&t->tcpq_in, input) <= 0) {
01656             /* failed to enqueue, destroy segment */
01657             PICO_FREE(input->payload);
01658             PICO_FREE(input);
01659             return -1;
01660         }
01661 
01662         tcp_sack_prepare(t);
01663     }
01664 
01665     return 0;
01666 }
01667 
01668 static inline void tcp_data_in_send_ack(struct pico_socket_tcp *t, struct pico_frame *f)
01669 {
01670     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01671     /* In either case, ack til recv_nxt, unless received data raises a RST flag. */
01672     if (((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) &&
01673         ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) &&
01674         ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV) &&
01675         ((hdr->flags & PICO_TCP_RST) == 0))
01676         tcp_send_ack(t);
01677 }
01678 
01679 static int tcp_data_in(struct pico_socket *s, struct pico_frame *f)
01680 {
01681     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
01682     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
01683     uint16_t payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u));
01684     int ret = 0;
01685     (void)hdr;
01686 
01687     if (((hdr->len & 0xf0u) >> 2u) <= f->transport_len) {
01688         tcp_parse_options(f);
01689         f->payload = f->transport_hdr + ((hdr->len & 0xf0u) >> 2u);
01690         f->payload_len = payload_len;
01691         tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
01692 
01693         if (pico_seq_compare(SEQN(f), t->rcv_nxt) <= 0) {
01694             ret = tcp_data_in_expected(t, f);
01695         } else {
01696             ret = tcp_data_in_high_segment(t, f);
01697         }
01698 
01699         tcp_data_in_send_ack(t, f);
01700         return ret;
01701     } else {
01702         tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len);
01703         return -1;
01704     }
01705 }
01706 
01707 static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, pico_time *timestamp)
01708 {
01709     int ret =  release_all_until(&t->tcpq_out, ACKN(f), timestamp);
01710     if (ret > 0) {
01711         t->sock.ev_pending |= PICO_SOCK_EV_WR;
01712     }
01713 
01714     return ret;
01715 }
01716 
01717 static uint16_t time_diff(pico_time a, pico_time b)
01718 {
01719     if (a >= b)
01720         return (uint16_t)(a - b);
01721     else
01722         return (uint16_t)(b - a);
01723 }
01724 
01725 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt)
01726 {
01727 
01728     uint32_t avg = t->avg_rtt;
01729     uint32_t rvar = t->rttvar;
01730     if (!avg) {
01731         /* This follows RFC2988
01732          * (2.2) When the first RTT measurement R is made, the host MUST set
01733          *
01734          * SRTT <- R
01735          * RTTVAR <- R/2
01736          * RTO <- SRTT + max (G, K*RTTVAR)
01737          */
01738         t->avg_rtt = rtt;
01739         t->rttvar = rtt >> 1;
01740         rto_set(t, t->avg_rtt + (t->rttvar << 2));
01741     } else {
01742         int32_t var = (int32_t)t->avg_rtt - (int32_t)rtt;
01743         if (var < 0)
01744             var = 0 - var;
01745 
01746         /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */
01747 
01748         /* First, evaluate a new value for the rttvar */
01749         t->rttvar <<= 2;
01750         t->rttvar -= rvar;
01751         t->rttvar += (uint32_t)var;
01752         t->rttvar >>= 2;
01753 
01754         /* Then, calculate the new avg_rtt */
01755         t->avg_rtt <<= 3;
01756         t->avg_rtt -= avg;
01757         t->avg_rtt += rtt;
01758         t->avg_rtt >>= 3;
01759 
01760         /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */
01761         rto_set(t, t->avg_rtt + (t->rttvar << 2));
01762     }
01763 
01764     tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto);
01765 }
01766 
01767 static void tcp_congestion_control(struct pico_socket_tcp *t)
01768 {
01769     if (t->x_mode > PICO_TCP_LOOKAHEAD)
01770         return;
01771 
01772     tcp_dbg("Doing congestion control\n");
01773     if (t->cwnd < t->ssthresh) {
01774         t->cwnd++;
01775     } else {
01776         t->cwnd_counter++;
01777         if (t->cwnd_counter >= t->cwnd) {
01778             t->cwnd++;
01779             t->cwnd_counter = 0;
01780         }
01781     }
01782 
01783     tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight);
01784 }
01785 
01786 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts);
01787 
01788 
01789 /* Retransmission time out (RTO). */
01790 
01791 static void tcp_first_timeout(struct pico_socket_tcp *t)
01792 {
01793     t->x_mode = PICO_TCP_BLACKOUT;
01794     t->cwnd = PICO_TCP_IW;
01795     t->in_flight = 0;
01796 }
01797 
01798 static int tcp_rto_xmit(struct pico_socket_tcp *t, struct pico_frame *f)
01799 {
01800     struct pico_frame *cpy;
01801     /* TCP: ENQUEUE to PROTO ( retransmit )*/
01802     cpy = pico_frame_copy(f);
01803     if (!cpy) {
01804         add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME);
01805         return -1;
01806     }
01807 
01808     if (pico_enqueue(&tcp_out, cpy) > 0) {
01809         t->snd_last_out = SEQN(cpy);
01810         add_retransmission_timer(t, (t->rto << (++t->backoff)) + TCP_TIME);
01811         tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight);
01812         tcp_dbg("Sending RTO!\n");
01813         return 1;
01814     } else {
01815         tcp_dbg("RTO fail, retry!\n");
01816         add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME);
01817         pico_frame_discard(cpy);
01818         return 0;
01819     }
01820 }
01821 
01822 static void tcp_next_zerowindow_probe(struct pico_socket_tcp *t)
01823 {
01824     tcp_dbg("Sending probe!\n");
01825     tcp_send_probe(t);
01826     add_retransmission_timer(t, (t->rto << ++t->backoff) + TCP_TIME);
01827 }
01828 
01829 static int tcp_is_allowed_to_send(struct pico_socket_tcp *t)
01830 {
01831     return t->sock.net &&
01832            (
01833                ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) ||
01834                ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT)
01835            ) &&
01836            ((t->backoff < PICO_TCP_MAX_RETRANS));
01837 }
01838 
01839 static inline int tcp_retrans_timeout_check_queue(struct pico_socket_tcp *t)
01840 {
01841     struct pico_frame *f = NULL;
01842     f = first_segment(&t->tcpq_out);
01843     while (f) {
01844         tcp_dbg("Checking frame in queue \n");
01845         if (t->x_mode == PICO_TCP_WINDOW_FULL) {
01846             tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d Win full: %d frame flags: %04x\n", SEQN(f), f->payload_len, t->rto, t->x_mode == PICO_TCP_WINDOW_FULL, f->flags);
01847             tcp_next_zerowindow_probe(t);
01848             return -1;
01849         }
01850 
01851         if (t->x_mode != PICO_TCP_BLACKOUT)
01852             tcp_first_timeout(t);
01853 
01854         tcp_add_header(t, f);
01855         if (tcp_rto_xmit(t, f) > 0) /* A segment has been rexmit'd */
01856             return -1;
01857 
01858         f = next_segment(&t->tcpq_out, f);
01859     }
01860     if (t->tcpq_out.size < t->tcpq_out.max_size)
01861         t->sock.ev_pending |= PICO_SOCK_EV_WR;
01862 
01863     return 0;
01864 
01865 
01866 
01867 }
01868 
01869 static void tcp_retrans_timeout(pico_time val, void *sock)
01870 {
01871     struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock;
01872 
01873     t->retrans_tmr = NULL;
01874 
01875     if (t->retrans_tmr_due == 0ull) {
01876         return;
01877     }
01878 
01879     if (t->retrans_tmr_due > val) {
01880         /* Timer was postponed... */
01881         add_retransmission_timer(t, t->retrans_tmr_due);
01882         return;
01883     }
01884 
01885     tcp_dbg("TIMEOUT! backoff = %d, rto: %d\n", t->backoff, t->rto);
01886     t->retrans_tmr_due = 0ull;
01887 
01888     if (tcp_is_allowed_to_send(t)) {
01889         if (tcp_retrans_timeout_check_queue(t) < 0)
01890             return;
01891     }
01892     else if(t->backoff >= PICO_TCP_MAX_RETRANS && (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED )
01893     {
01894         tcp_dbg("Connection timeout!\n");
01895         /* the retransmission timer, failed to get an ack for a frame, gives up on the connection */
01896         tcp_discard_all_segments(&t->tcpq_out);
01897         if(t->sock.wakeup)
01898             t->sock.wakeup(PICO_SOCK_EV_FIN, &t->sock);
01899 
01900         /* delete socket */
01901         pico_socket_del(&t->sock);
01902         return;
01903     } else {
01904         tcp_dbg("Retransmission not allowed, rescheduling\n");
01905     }
01906 }
01907 
01908 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts)
01909 {
01910     struct pico_tree_node *index;
01911     pico_time now = TCP_TIME;
01912     pico_time val = 0;
01913 
01914 
01915     if (next_ts == 0) {
01916         struct pico_frame *f;
01917 
01918         pico_tree_foreach(index, &t->tcpq_out.pool){
01919             f = index->keyValue;
01920             if ((next_ts == 0) || ((f->timestamp < next_ts) && (f->timestamp > 0))) {
01921                 next_ts = f->timestamp;
01922                 val = next_ts + (t->rto << t->backoff);
01923             }
01924         }
01925     } else {
01926         val = next_ts;
01927     }
01928 
01929     if ((val > 0) || (val > now)) {
01930         t->retrans_tmr_due = val;
01931     } else {
01932         t->retrans_tmr_due = now + 1;
01933     }
01934 
01935     if (!t->retrans_tmr) {
01936         t->retrans_tmr = pico_timer_add(t->retrans_tmr_due - now, tcp_retrans_timeout, t);
01937         tcp_dbg("Next timeout in %u msec\n", (uint32_t) (t->retrans_tmr_due - now));
01938     }
01939 }
01940 
01941 static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f)
01942 {
01943     struct pico_frame *cpy;
01944     if (f) {
01945         tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len);
01946         tcp_add_header(t, f);
01947         /* TCP: ENQUEUE to PROTO ( retransmit )*/
01948         cpy = pico_frame_copy(f);
01949         if (!cpy) {
01950             return -1;
01951         }
01952 
01953         if (pico_enqueue(&tcp_out, cpy) > 0) {
01954             t->in_flight++;
01955             t->snd_last_out = SEQN(cpy);
01956         } else {
01957             pico_frame_discard(cpy);
01958         }
01959 
01960         add_retransmission_timer(t, TCP_TIME + t->rto);
01961         return(f->payload_len);
01962     }
01963 
01964     return 0;
01965 }
01966 
01967 #ifdef TCP_ACK_DBG
01968 static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f)
01969 {
01970     uint32_t una, nxt, ack, cur;
01971     struct pico_frame *una_f = NULL, *cur_f;
01972     struct pico_tree_node *idx;
01973     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
01974     char info[64];
01975     char tmp[64];
01976     ack = ACKN(f);
01977     nxt = t->snd_nxt;
01978     tcp_dbg("===================================\n");
01979     tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack);
01980 
01981     pico_tree_foreach(idx, &t->tcpq_out.pool) {
01982         info[0] = 0;
01983         cur_f = idx->keyValue;
01984         cur = SEQN(cur_f);
01985         if (!una_f) {
01986             una_f = cur_f;
01987             una = SEQN(una_f);
01988         }
01989 
01990         if (cur == nxt) {
01991             strncpy(tmp, info, strlen(info));
01992             snprintf(info, 64, "%s SND_NXT", tmp);
01993         }
01994 
01995         if (cur == ack) {
01996             strncpy(tmp, info, strlen(info));
01997             snprintf(info, 64, "%s ACK", tmp);
01998         }
01999 
02000         if (cur == una) {
02001             strncpy(tmp, info, strlen(info));
02002             snprintf(info, 64, "%s SND_UNA", tmp);
02003         }
02004 
02005         if (cur == t->snd_last) {
02006             strncpy(tmp, info, strlen(info));
02007             snprintf(info, 64, "%s SND_LAST", tmp);
02008         }
02009 
02010         tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info);
02011 
02012     }
02013     tcp_dbg("SND_NXT is %08x, snd_LAST is %08x\n", nxt, t->snd_last);
02014     tcp_dbg("===================================\n");
02015     tcp_dbg("\n\n");
02016 }
02017 #endif
02018 
02019 static int tcp_ack(struct pico_socket *s, struct pico_frame *f)
02020 {
02021     struct pico_frame *f_new;              /* use with Nagle to push to out queue */
02022     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02023     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
02024     uint32_t rtt = 0;
02025     uint16_t acked = 0;
02026     pico_time acked_timestamp = 0;
02027 
02028     struct pico_frame *una = NULL;
02029     if ((hdr->flags & PICO_TCP_ACK) == 0)
02030         return -1;
02031 
02032 #ifdef TCP_ACK_DBG
02033     tcp_ack_dbg(s, f);
02034 #endif
02035 
02036     tcp_parse_options(f);
02037     t->recv_wnd = short_be(hdr->rwnd);
02038 
02039     acked = (uint16_t)tcp_ack_advance_una(t, f, &acked_timestamp);
02040     una = first_segment(&t->tcpq_out);
02041     t->ack_timestamp = TCP_TIME;
02042 
02043     if ((t->x_mode == PICO_TCP_BLACKOUT) ||
02044         ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) {
02045         int prev_mode = t->x_mode;
02046         tcp_dbg("Re-entering look-ahead...\n\n\n");
02047         t->x_mode = PICO_TCP_LOOKAHEAD;
02048         t->backoff = 0;
02049 
02050         if((prev_mode == PICO_TCP_BLACKOUT) && (acked > 0) && una)
02051         {
02052             t->snd_nxt = SEQN(una);
02053             /* restart the retrans timer */
02054             if (t->retrans_tmr) {
02055                 t->retrans_tmr_due = 0ull;
02056             }
02057         }
02058     }
02059 
02060     /* One should be acked. */
02061     if ((acked == 0) && (f->payload_len  == 0) && (t->in_flight > 0))
02062         t->in_flight--;
02063 
02064     if (!una || acked > 0) {
02065         t->x_mode = PICO_TCP_LOOKAHEAD;
02066         tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames);
02067         t->backoff = 0;
02068 
02069         /* Do rtt/rttvar/rto calculations */
02070         /* First, try with timestamps, using the value from options */
02071         if(f && (f->timestamp != 0)) {
02072             rtt = time_diff(TCP_TIME, f->timestamp);
02073             if (rtt)
02074                 tcp_rtt(t, rtt);
02075         } else if(acked_timestamp) {
02076             /* If no timestamps are there, use conservative estimation on the una */
02077             rtt = time_diff(TCP_TIME, acked_timestamp);
02078             if (rtt)
02079                 tcp_rtt(t, rtt);
02080         }
02081 
02082         tcp_dbg("TCP ACK> FRESH ACK %08x (acked %d) Queue size: %u/%u frames: %u cwnd: %u in_flight: %u snd_una: %u\n", ACKN(f), acked, t->tcpq_out.size, t->tcpq_out.max_size, t->tcpq_out.frames, t->cwnd, t->in_flight, SEQN(una));
02083         if (acked > t->in_flight) {
02084             tcp_dbg("WARNING: in flight < 0\n");
02085             t->in_flight = 0;
02086         } else
02087             t->in_flight -= (acked);
02088 
02089     } else if ((t->snd_old_ack == ACKN(f)) &&              /* We've just seen this ack, and... */
02090                ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) &&
02091                 (f->payload_len == 0)) &&              /* This is a pure ack, and... */
02092                (ACKN(f) != t->snd_nxt))              /* There is something in flight awaiting to be acked... */
02093     {
02094         /* Process incoming duplicate ack. */
02095         if (t->x_mode < PICO_TCP_RECOVER) {
02096             t->x_mode++;
02097             tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len);
02098             /* tcp_dbg("ACK: %x - QUEUE: %x\n", ACKN(f), SEQN(first_segment(&t->tcpq_out))); */
02099             if (t->x_mode == PICO_TCP_RECOVER) {              /* Switching mode */
02100                 if (t->in_flight > PICO_TCP_IW)
02101                     t->cwnd = (uint16_t)t->in_flight;
02102                 else
02103                     t->cwnd = PICO_TCP_IW;
02104 
02105                 t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out));
02106                 if (t->ssthresh > t->cwnd)
02107                     t->ssthresh >>= 2;
02108                 else
02109                     t->ssthresh = (t->cwnd >> 1);
02110 
02111                 if (t->ssthresh < 2)
02112                     t->ssthresh = 2;
02113             }
02114         } else if (t->x_mode == PICO_TCP_RECOVER) {
02115             /* tcp_dbg("TCP RECOVER> DUPACK! snd_una: %08x, snd_nxt: %08x, acked now: %08x\n", SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, ACKN(f)); */
02116             if (t->in_flight <= t->cwnd) {
02117                 struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry);
02118                 if (!nxt)
02119                     nxt = first_segment(&t->tcpq_out);
02120 
02121                 while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) {
02122                     tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt));
02123                     nxt = next_segment(&t->tcpq_out, nxt);
02124                 }
02125                 if (nxt && (pico_seq_compare(SEQN(nxt), t->snd_nxt)) > 0)
02126                     nxt = NULL;
02127 
02128                 if (nxt && (pico_seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale)))
02129                     nxt = NULL;
02130 
02131                 if(!nxt)
02132                     nxt = first_segment(&t->tcpq_out);
02133 
02134                 if (nxt) {
02135                     tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry));
02136                     t->snd_retry = SEQN(nxt);
02137                 }
02138             }
02139 
02140             if (++t->cwnd_counter > 1) {
02141                 t->cwnd--;
02142                 if (t->cwnd < 2)
02143                     t->cwnd = 2;
02144 
02145                 t->cwnd_counter = 0;
02146             }
02147         } else {
02148             tcp_dbg("DUPACK in mode %d \n", t->x_mode);
02149 
02150         }
02151     }              /* End case duplicate ack detection */
02152 
02153     /* Linux very special zero-window probe detection (see bug #107) */
02154     if ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && /* This is a pure ack, and... */
02155         (ACKN(f) == t->snd_nxt) &&                           /* it's acking our snd_nxt, and... */
02156         (pico_seq_compare(SEQN(f), t->rcv_nxt) < 0))             /* Has an old seq number */
02157     {
02158         tcp_send_ack(t);
02159     }
02160 
02161 
02162     /* Do congestion control */
02163     tcp_congestion_control(t);
02164     if ((acked > 0) && t->sock.wakeup) {
02165         if (t->tcpq_out.size < t->tcpq_out.max_size)
02166             t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock));
02167 
02168         /* t->sock.ev_pending |= PICO_SOCK_EV_WR; */
02169     }
02170 
02171     /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */
02172     if (IS_NAGLE_ENABLED((&(t->sock)))) {
02173         while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) {
02174             tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n");
02175             f_new = pico_hold_segment_make(t);
02176             if (f_new == NULL)
02177                 break;              /* XXX corrupt !!! (or no memory) */
02178 
02179             if (pico_enqueue_segment(&t->tcpq_out, f_new) <= 0)
02180                 /* handle error */
02181                 tcp_dbg_nagle("TCP_ACK - NAGLE FAILED to enqueue in out\n");
02182         }
02183     }
02184 
02185     /* If some space was created, put a few segments out. */
02186     tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight);
02187     if (t->x_mode ==  PICO_TCP_LOOKAHEAD) {
02188         if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) {
02189             pico_tcp_output(&t->sock, (int)t->cwnd - (int)t->in_flight);
02190         }
02191     }
02192 
02193     add_retransmission_timer(t, 0);
02194     t->snd_old_ack = ACKN(f);
02195     return 0;
02196 }
02197 
02198 static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f)
02199 {
02200     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02201     tcp_dbg("RECEIVED ACK IN FIN_WAIT1\n");
02202 
02203     /* acking part */
02204     tcp_ack(s, f);
02205 
02206     
02207     tcp_dbg("FIN_WAIT1: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt);
02208     if (ACKN(f) == (t->snd_nxt - 1u)) {
02209         /* update TCP state */
02210         s->state &= 0x00FFU;
02211         s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2;
02212         tcp_dbg("TCP> IN STATE FIN_WAIT2\n");
02213     }
02214     return 0;
02215 }
02216 
02217 static void tcp_deltcb(pico_time when, void *arg)
02218 {
02219     struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
02220     IGNORE_PARAMETER(when);
02221 
02222     /* send RST if not yet in TIME_WAIT */
02223     if ( (((t->sock).state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_TIME_WAIT)
02224       && (((t->sock).state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSING) ) {
02225         tcp_dbg("Called deltcb in state = %04x (sending reset!)\n", (t->sock).state);
02226         tcp_do_send_rst(&t->sock, long_be(t->snd_nxt));
02227     } else {
02228         tcp_dbg("Called deltcb in state = %04x\n", (t->sock).state);
02229     }
02230 
02231     /* update state */
02232     (t->sock).state &= 0x00FFU;
02233     (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
02234     (t->sock).state &= 0xFF00U;
02235     (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
02236     /* call EV_FIN wakeup before deleting */
02237     if (t->sock.wakeup) {
02238         (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
02239     }
02240 
02241     /* delete socket */
02242     pico_socket_del(&t->sock);
02243 }
02244 
02245 static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f)
02246 {
02247     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02248     struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *) (f->transport_hdr);
02249     tcp_dbg("TCP> received fin in FIN_WAIT2\n");
02250     /* received FIN, increase ACK nr */
02251     t->rcv_nxt = long_be(hdr->seq) + 1;
02252     s->state &= 0x00FFU;
02253     s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
02254     /* set SHUT_REMOTE */
02255     s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
02256     if (s->wakeup)
02257         s->wakeup(PICO_SOCK_EV_CLOSE, s);
02258 
02259     if (f->payload_len > 0)              /* needed?? */
02260         tcp_data_in(s, f);
02261 
02262     /* send ACK */
02263     tcp_send_ack(t);
02264     /* linger */
02265     tcp_linger(t);
02266     return 0;
02267 }
02268 
02269 static int tcp_closing_ack(struct pico_socket *s, struct pico_frame *f)
02270 {
02271     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02272     tcp_dbg("TCP> received ack in CLOSING\n");
02273     /* acking part */
02274     tcp_ack(s, f);
02275 
02276     /* update TCP state DLA TODO: Only if FIN is acked! */
02277     tcp_dbg("CLOSING: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt);
02278     if (ACKN(f) == t->snd_nxt) {
02279         s->state &= 0x00FFU;
02280         s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
02281         /* set timer */
02282         tcp_linger(t);
02283     }
02284     return 0;
02285 }
02286 
02287 static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f)
02288 {
02289     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02290     tcp_dbg("LAST_ACK: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt);
02291     if (ACKN(f) == t->snd_nxt) {
02292         s->state &= 0x00FFU;
02293         s->state |= PICO_SOCKET_STATE_TCP_CLOSED;
02294         s->state &= 0xFF00U;
02295         s->state |= PICO_SOCKET_STATE_CLOSED;
02296         /* call socket wakeup with EV_FIN */
02297         if (s->wakeup)
02298             s->wakeup(PICO_SOCK_EV_FIN, s);
02299 
02300         /* delete socket */
02301         pico_socket_del(s);
02302     }
02303     return 0;
02304 }
02305 
02306 static int tcp_syn(struct pico_socket *s, struct pico_frame *f)
02307 {
02308     struct pico_socket_tcp *new = NULL;
02309     struct pico_tcp_hdr *hdr = NULL;
02310     uint16_t mtu;
02311     if(s->number_of_pending_conn >= s->max_backlog)
02312         return -1;
02313 
02314     new = (struct pico_socket_tcp *)pico_socket_clone(s);
02315     hdr = (struct pico_tcp_hdr *)f->transport_hdr;
02316     if (!new)
02317         return -1;
02318 
02319 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
02320     pico_timer_add(2000, sock_stats, s);
02321 #endif
02322 
02323     new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport;
02324 #ifdef PICO_SUPPORT_IPV4
02325     if (IS_IPV4(f)) {
02326         new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr;
02327         new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr;
02328     }
02329 
02330 #endif
02331 #ifdef PICO_SUPPORT_IPV6
02332     if (IS_IPV6(f)) {
02333         new->sock.remote_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->src;
02334         new->sock.local_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->dst;
02335     }
02336 
02337 #endif
02338     f->sock = &new->sock;
02339     tcp_parse_options(f);
02340     mtu = (uint16_t)pico_socket_get_mss(&new->sock);
02341     new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR);
02342     new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
02343     new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
02344     new->tcpq_hold.max_size = 2u * mtu;
02345     new->rcv_nxt = long_be(hdr->seq) + 1;
02346     new->snd_nxt = long_be(pico_paws());
02347     new->snd_last = new->snd_nxt;
02348     new->cwnd = PICO_TCP_IW;
02349     new->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss) -  (((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss)) >> 3u));
02350     new->recv_wnd = short_be(hdr->rwnd);
02351     new->jumbo = hdr->len & 0x07;
02352     new->linger_timeout = PICO_SOCKET_LINGER_TIMEOUT;
02353     s->number_of_pending_conn++;
02354     new->sock.parent = s;
02355     new->sock.wakeup = s->wakeup;
02356     rto_set(new, PICO_TCP_RTO_MIN);
02357     /* Initialize timestamp values */
02358     new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV;
02359     pico_socket_add(&new->sock);
02360     tcp_send_synack(&new->sock);
02361     tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt);
02362     return 0;
02363 }
02364 
02365 static int tcp_synrecv_syn(struct pico_socket *s, struct pico_frame *f)
02366 {
02367     struct pico_tcp_hdr *hdr = NULL;
02368     struct pico_socket_tcp *t = TCP_SOCK(s);
02369     hdr = (struct pico_tcp_hdr *)f->transport_hdr;
02370     if (t->rcv_nxt == long_be(hdr->seq) + 1u) {
02371         /* take back our own SEQ number to its original value,
02372          * so the synack retransmitted is identical to the original.
02373          */
02374         t->snd_nxt--;
02375         tcp_send_synack(s);
02376     } else {
02377         tcp_send_rst(s, f);
02378         return -1;
02379     }
02380 
02381     return 0;
02382 }
02383 
02384 static void tcp_set_init_point(struct pico_socket *s)
02385 {
02386     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02387     t->rcv_processed = t->rcv_nxt;
02388 }
02389 
02390 
02391 uint16_t pico_tcp_get_socket_mss(struct pico_socket *s)
02392 {
02393     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02394     if (t->mss > 0)
02395         return (uint16_t)(t->mss + PICO_SIZE_TCPHDR);
02396     else
02397         return (uint16_t)pico_socket_get_mss(s);
02398 }
02399 
02400 static int tcp_synack(struct pico_socket *s, struct pico_frame *f)
02401 {
02402     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02403     struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *)f->transport_hdr;
02404 
02405     if (ACKN(f) ==  (1u + t->snd_nxt)) {
02406         /* Get rid of initconn retry */
02407         if(t->retrans_tmr) {
02408             pico_timer_cancel(t->retrans_tmr);
02409             t->retrans_tmr = NULL;
02410         }
02411 
02412         t->rcv_nxt = long_be(hdr->seq);
02413         t->rcv_processed = t->rcv_nxt + 1;
02414         tcp_ack(s, f);
02415 
02416         s->state &= 0x00FFU;
02417         s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED;
02418         tcp_dbg("TCP> Established. State: %x\n", s->state);
02419 
02420         if (s->wakeup)
02421             s->wakeup(PICO_SOCK_EV_CONN, s);
02422 
02423         s->ev_pending |= PICO_SOCK_EV_WR;
02424 
02425         t->rcv_nxt++;
02426         t->snd_nxt++;
02427         tcp_send_ack(t);              /* return ACK */
02428 
02429         return 0;
02430 
02431     } else if ((hdr->flags & PICO_TCP_RST) == 0) {
02432         tcp_dbg("TCP> Not established, RST sent.\n");
02433         tcp_nosync_rst(s, f);
02434         return 0;
02435     } else {
02436         /* The segment has the reset flag on: Ignore! */
02437         return 0;
02438     }
02439 }
02440 
02441 static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f)
02442 {
02443     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02444     struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *)f->transport_hdr;
02445     tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f));
02446     if (t->snd_nxt == ACKN(f)) {
02447         tcp_set_init_point(s);
02448         tcp_ack(s, f);
02449         s->state &= 0x00FFU;
02450         s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED;
02451         tcp_dbg("TCP: Established. State now: %04x\n", s->state);
02452         if( !s->parent && s->wakeup) {              /* If the socket has no parent, -> sending socket that has a sim_open */
02453             tcp_dbg("FIRST ACK - No parent found -> sending socket\n");
02454             s->wakeup(PICO_SOCK_EV_CONN,  s);
02455         }
02456 
02457         if (s->parent && s->parent->wakeup) {
02458             tcp_dbg("FIRST ACK - Parent found -> listening socket\n");
02459             s->wakeup = s->parent->wakeup;
02460             s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent);
02461         }
02462 
02463         s->ev_pending |= PICO_SOCK_EV_WR;
02464         tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
02465         return 0;
02466     } else if ((hdr->flags & PICO_TCP_RST) == 0) {
02467         tcp_nosync_rst(s, f);
02468         return 0;
02469     } else {
02470         /* The segment has the reset flag on: Ignore! */
02471         return 0;
02472     }
02473 }
02474 
02475 static void tcp_attempt_closewait(struct pico_socket *s, struct pico_frame *f)
02476 {
02477     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02478     struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *) (f->transport_hdr);
02479     if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) {
02480         /* received FIN, increase ACK nr */
02481         t->rcv_nxt = long_be(hdr->seq) + 1;
02482         if (pico_seq_compare(SEQN(f), t->rcv_processed) == 0) {
02483             if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) {
02484                 tcp_dbg("Changing state to CLOSE_WAIT\n");
02485                 s->state &= 0x00FFU;
02486                 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
02487             }
02488 
02489             /* set SHUT_REMOTE */
02490             s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
02491             tcp_dbg("TCP> Close-wait\n");
02492             if (s->wakeup) {
02493                 s->wakeup(PICO_SOCK_EV_CLOSE, s);
02494             }
02495         } else {
02496             t->remote_closed = 1;
02497         }
02498     }
02499 
02500 
02501 }
02502 
02503 static int tcp_closewait(struct pico_socket *s, struct pico_frame *f)
02504 {
02505 
02506     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02507     if (f->payload_len > 0)
02508         tcp_data_in(s, f);
02509 
02510     if (f->flags & PICO_TCP_ACK)
02511         tcp_ack(s, f);
02512 
02513     tcp_dbg("called close_wait, in state %08x\n", s->state);
02514     tcp_attempt_closewait(s, f);
02515 
02516     /* Ensure that the notification given to the socket
02517      * did not put us in LAST_ACK state before sending the ACK: i.e. if
02518      * pico_socket_close() has been called in the socket callback, we don't need to send
02519      * an ACK here.
02520      *
02521      */
02522     if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) ||
02523         ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED))
02524     {
02525         tcp_dbg("In closewait: Sending ack! (state is %08x)\n", s->state);
02526         tcp_send_ack(t);
02527     }
02528 
02529     return 0;
02530 }
02531 
02532 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f)
02533 {
02534     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02535     IGNORE_PARAMETER(f);
02536     tcp_dbg("TCP> Received FIN in FIN_WAIT1\n");
02537     s->state &= 0x00FFU;
02538     s->state |= PICO_SOCKET_STATE_TCP_CLOSING;
02539     t->rcv_processed = t->rcv_nxt + 1;
02540     t->rcv_nxt++;
02541     /* send ACK */
02542     tcp_send_ack(t);
02543     return 0;
02544 }
02545 
02546 static int tcp_finack(struct pico_socket *s, struct pico_frame *f)
02547 {
02548     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02549     IGNORE_PARAMETER(f);
02550 
02551     tcp_dbg("TCP> ENTERED finack\n");
02552     t->rcv_nxt++;
02553     /* send ACK */
02554     tcp_send_ack(t);
02555 
02556     /* call socket wakeup with EV_FIN */
02557     if (s->wakeup)
02558         s->wakeup(PICO_SOCK_EV_FIN, s);
02559 
02560     s->state &= 0x00FFU;
02561     s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
02562     /* set SHUT_REMOTE */
02563     s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
02564 
02565     tcp_linger(t);
02566 
02567     return 0;
02568 }
02569 
02570 static void tcp_force_closed(struct pico_socket *s)
02571 {
02572     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02573     /* update state */
02574     (t->sock).state &= 0x00FFU;
02575     (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
02576     (t->sock).state &= 0xFF00U;
02577     (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
02578     /* call EV_ERR wakeup before deleting */
02579     if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) {
02580         if ((t->sock).wakeup)
02581             (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
02582     } else {
02583         pico_err = PICO_ERR_ECONNRESET;
02584         if ((t->sock).wakeup)
02585             (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
02586 
02587         /* delete socket */
02588         pico_socket_del(&t->sock);
02589     }
02590 }
02591 
02592 static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev)
02593 {
02594     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02595     if ((t->sock).wakeup)
02596         (t->sock).wakeup(ev, &(t->sock));
02597 }
02598 
02599 static int tcp_rst(struct pico_socket *s, struct pico_frame *f)
02600 {
02601     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02602     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
02603 
02604     tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n");
02605     if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
02606         /* the RST is acceptable if the ACK field acknowledges the SYN */
02607         if ((t->snd_nxt + 1u) == ACKN(f)) {              /* valid, got to closed state */
02608             tcp_force_closed(s);
02609         } else {                  /* not valid, ignore */
02610             tcp_dbg("TCP RST> IGNORE\n");
02611             return 0;
02612         }
02613     } else {              /* all other states */
02614         /* all reset (RST) segments are validated by checking their SEQ-fields,
02615            a reset is valid if its sequence number is in the window */
02616         uint32_t this_seq = long_be(hdr->seq);
02617         if ((this_seq >= t->rcv_ackd) && (this_seq <= ((uint32_t)(short_be(hdr->rwnd) << (t->wnd_scale)) + t->rcv_ackd))) {
02618             tcp_force_closed(s);
02619         } else {                  /* not valid, ignore */
02620             tcp_dbg("TCP RST> IGNORE\n");
02621             return 0;
02622         }
02623     }
02624 
02625     return 0;
02626 }
02627 static int tcp_halfopencon(struct pico_socket *s, struct pico_frame *fr)
02628 {
02629     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02630     IGNORE_PARAMETER(fr);
02631     tcp_send_ack(t);
02632     return 0;
02633 }
02634 
02635 static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr)
02636 {
02637     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
02638     struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *) (fr->transport_hdr);
02639 
02640     if (pico_seq_compare(SEQN(fr), t->rcv_nxt) == 0) {
02641         /* received FIN, increase ACK nr */
02642         t->rcv_nxt = long_be(hdr->seq) + 1;
02643         s->state &= 0x00FFU;
02644         s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
02645         /* set SHUT_LOCAL */
02646         s->state |= PICO_SOCKET_STATE_SHUT_LOCAL;
02647         pico_socket_close(s);
02648         return 1;
02649     }
02650 
02651     return 0;
02652 }
02653 
02654 struct tcp_action_entry {
02655     uint16_t tcpstate;
02656     int (*syn)(struct pico_socket *s, struct pico_frame *f);
02657     int (*synack)(struct pico_socket *s, struct pico_frame *f);
02658     int (*ack)(struct pico_socket *s, struct pico_frame *f);
02659     int (*data)(struct pico_socket *s, struct pico_frame *f);
02660     int (*fin)(struct pico_socket *s, struct pico_frame *f);
02661     int (*finack)(struct pico_socket *s, struct pico_frame *f);
02662     int (*rst)(struct pico_socket *s, struct pico_frame *f);
02663 };
02664 
02665 static const struct tcp_action_entry tcp_fsm[] = {
02666     /* State                              syn              synack             ack                data             fin              finack           rst*/
02667     { PICO_SOCKET_STATE_TCP_UNDEF,        NULL,            NULL,              NULL,              NULL,            NULL,            NULL,            NULL     },
02668     { PICO_SOCKET_STATE_TCP_CLOSED,       NULL,            NULL,              NULL,              NULL,            NULL,            NULL,            NULL     },
02669     { PICO_SOCKET_STATE_TCP_LISTEN,       &tcp_syn,        NULL,              NULL,              NULL,            NULL,            NULL,            NULL     },
02670     { PICO_SOCKET_STATE_TCP_SYN_SENT,     NULL,            &tcp_synack,       NULL,              NULL,            NULL,            NULL,            &tcp_rst },
02671     { PICO_SOCKET_STATE_TCP_SYN_RECV,     &tcp_synrecv_syn, NULL,              &tcp_first_ack,    &tcp_data_in,    NULL,            &tcp_closeconn,  &tcp_rst },
02672     { PICO_SOCKET_STATE_TCP_ESTABLISHED,  &tcp_halfopencon, &tcp_ack,         &tcp_ack,          &tcp_data_in,    &tcp_closewait,  &tcp_closewait,  &tcp_rst },
02673     { PICO_SOCKET_STATE_TCP_CLOSE_WAIT,   NULL,            &tcp_ack,          &tcp_ack,          &tcp_send_rst,   &tcp_closewait,  &tcp_closewait,  &tcp_rst },
02674     { PICO_SOCKET_STATE_TCP_LAST_ACK,     NULL,            &tcp_ack,          &tcp_lastackwait,  &tcp_send_rst,   &tcp_send_rst,   &tcp_send_rst,   &tcp_rst },
02675     { PICO_SOCKET_STATE_TCP_FIN_WAIT1,    NULL,            &tcp_ack,          &tcp_finwaitack,   &tcp_data_in,    &tcp_rcvfin,     &tcp_finack,     &tcp_rst },
02676     { PICO_SOCKET_STATE_TCP_FIN_WAIT2,    NULL,            &tcp_ack,          &tcp_ack,          &tcp_data_in,    &tcp_finwaitfin, &tcp_finack,     &tcp_rst },
02677     { PICO_SOCKET_STATE_TCP_CLOSING,      NULL,            &tcp_ack,          &tcp_closing_ack, &tcp_send_rst,   &tcp_send_rst,   &tcp_send_rst,   &tcp_rst },
02678     { PICO_SOCKET_STATE_TCP_TIME_WAIT,    NULL,            NULL,          NULL,     &tcp_send_rst,   NULL, NULL, NULL}
02679 };
02680 
02681 #define MAX_VALID_FLAGS  10  /* Maximum number of valid flag combinations */
02682 static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags)
02683 {
02684     uint8_t i;
02685     static const uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = {
02686         { /* PICO_SOCKET_STATE_TCP_UNDEF      */ 0, },
02687         { /* PICO_SOCKET_STATE_TCP_CLOSED     */ 0, },
02688         { /* PICO_SOCKET_STATE_TCP_LISTEN     */ PICO_TCP_SYN },
02689         { /* PICO_SOCKET_STATE_TCP_SYN_SENT   */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK},
02690         { /* PICO_SOCKET_STATE_TCP_SYN_RECV   */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02691         { /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST, PICO_TCP_RSTACK},
02692         { /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02693         { /* PICO_SOCKET_STATE_TCP_LAST_ACK   */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02694         { /* PICO_SOCKET_STATE_TCP_FIN_WAIT1  */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02695         { /* PICO_SOCKET_STATE_TCP_FIN_WAIT2  */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02696         { /* PICO_SOCKET_STATE_TCP_CLOSING    */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02697         { /* PICO_SOCKET_STATE_TCP_TIME_WAIT  */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
02698     };
02699     if(!flags)
02700         return 1;
02701 
02702     for(i = 0; i < MAX_VALID_FLAGS; i++) {
02703         if(valid_flags[s->state >> 8u][i] == flags)
02704             return 0;
02705     }
02706     return 1;
02707 }
02708 
02709 static void tcp_action_call(int (*call)(struct pico_socket *s, struct pico_frame *f), struct pico_socket *s, struct pico_frame *f )
02710 {
02711     if (call)
02712         call(s, f);
02713 }
02714 
02715 static int tcp_action_by_flags(const struct tcp_action_entry *action, struct pico_socket *s, struct pico_frame *f, uint8_t flags)
02716 {
02717     int ret = 0;
02718     if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) {
02719         tcp_action_call(action->ack, s, f);
02720     }
02721 
02722     if ((f->payload_len > 0 || (flags & PICO_TCP_PSH)) &&
02723         !(s->state & PICO_SOCKET_STATE_CLOSED) && !TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN))
02724     {
02725         ret = f->payload_len;
02726         tcp_action_call(action->data, s, f);
02727     }
02728 
02729     if (flags == PICO_TCP_FIN) {
02730         tcp_action_call(action->fin, s, f);
02731     }
02732 
02733     if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) {
02734         tcp_action_call(action->finack, s, f);
02735     }
02736 
02737     if (flags & PICO_TCP_RST) {
02738         tcp_action_call(action->rst, s, f);
02739     }
02740 
02741     return ret;
02742 }
02743 
02744 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
02745 {
02746     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
02747     int ret = 0;
02748     uint8_t flags = hdr->flags;
02749     const struct tcp_action_entry *action = &tcp_fsm[s->state >> 8];
02750 
02751     f->payload = (f->transport_hdr + ((hdr->len & 0xf0u) >> 2u));
02752     f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u));
02753 
02754     tcp_dbg("[sam] TCP> [tcp input] t_len: %u\n", f->transport_len);
02755     tcp_dbg("[sam] TCP> flags = %02x\n", hdr->flags);
02756     tcp_dbg("[sam] TCP> s->state >> 8 = %u\n", s->state >> 8);
02757     tcp_dbg("[sam] TCP> [tcp input] socket: %p state: %d <-- local port:%u remote port: %u seq: %08x ack: %08x flags: %02x t_len: %u, hdr: %u payload: %d\n", s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
02758 
02759     /* This copy of the frame has the current socket as owner */
02760     f->sock = s;
02761     s->timestamp = TCP_TIME;
02762     /* Those are not supported at this time. */
02763     /* flags &= (uint8_t) ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); */
02764     if(invalid_flags(s, flags)) {
02765         pico_tcp_reply_rst(f);
02766     }
02767     else if (flags == PICO_TCP_SYN) {
02768         tcp_action_call(action->syn, s, f);
02769     } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) {
02770         tcp_action_call(action->synack, s, f);
02771     } else {
02772         ret = tcp_action_by_flags(action, s, f, flags);
02773     }
02774 
02775     if (s->ev_pending)
02776         tcp_wakeup_pending(s, s->ev_pending);
02777 
02778 /* discard: */
02779     pico_frame_discard(f);
02780     return ret;
02781 }
02782 
02783 
02784 inline static int checkLocalClosing(struct pico_socket *s);
02785 inline static int checkRemoteClosing(struct pico_socket *s);
02786 
02787 static struct pico_frame *tcp_split_segment(struct pico_socket_tcp *t, struct pico_frame *f, uint16_t size)
02788 {
02789     struct pico_frame *f1, *f2;
02790     uint16_t size1, size2, size_f;
02791     uint16_t overhead;
02792     struct pico_tcp_hdr *hdr1, *hdr2, *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
02793     overhead = pico_tcp_overhead(&t->sock);
02794     size_f = f->payload_len;
02795 
02796 
02797     if (size >= size_f)
02798         return f; /* no need to split! */
02799 
02800     size1 = size;
02801     size2 = (uint16_t)(size_f - size);
02802 
02803     f1 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size1 + overhead));
02804     f2 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size2 + overhead));
02805 
02806     if (!f1 || !f2) {
02807         pico_err = PICO_ERR_ENOMEM;
02808         return NULL;
02809     }
02810 
02811     /* Advance payload pointer to the beginning of segment data */
02812     f1->payload += overhead;
02813     f1->payload_len = (uint16_t)(f1->payload_len - overhead);
02814     f2->payload += overhead;
02815     f2->payload_len = (uint16_t)(f2->payload_len - overhead);
02816 
02817     hdr1 = (struct pico_tcp_hdr *)f1->transport_hdr;
02818     hdr2 = (struct pico_tcp_hdr *)f2->transport_hdr;
02819 
02820     /* Copy payload */
02821     memcpy(f1->payload, f->payload, size1);
02822     memcpy(f2->payload, f->payload + size1, size2);
02823 
02824     /* Copy tcp hdr */
02825     memcpy(hdr1, hdr, sizeof(struct pico_tcp_hdr));
02826     memcpy(hdr2, hdr, sizeof(struct pico_tcp_hdr));
02827 
02828     /* Adjust f2's sequence number */
02829     hdr2->seq = long_be(SEQN(f) + size1);
02830 
02831     /* Add TCP options */
02832     pico_tcp_flags_update(f1, &t->sock);
02833     pico_tcp_flags_update(f2, &t->sock);
02834     tcp_add_options_frame(t, f1);
02835     tcp_add_options_frame(t, f2);
02836 
02837     /* Get rid of the full frame */
02838     pico_discard_segment(&t->tcpq_out, f);
02839 
02840     /* Enqueue f2 for later send... */
02841     pico_enqueue_segment(&t->tcpq_out, f2);
02842 
02843     /* Return the partial frame */
02844     return f1;
02845 }
02846 
02847 
02848 int pico_tcp_output(struct pico_socket *s, int loop_score)
02849 {
02850     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
02851     struct pico_frame *f, *una;
02852     int sent = 0;
02853     int data_sent = 0;
02854     int32_t seq_diff = 0;
02855 
02856     una = first_segment(&t->tcpq_out);
02857     f = peek_segment(&t->tcpq_out, t->snd_nxt);
02858 
02859     while((f) && (t->cwnd >= t->in_flight)) {
02860         f->timestamp = TCP_TIME;
02861         add_retransmission_timer(t, t->rto + TCP_TIME);
02862         tcp_add_options_frame(t, f);
02863         seq_diff = pico_seq_compare(SEQN(f), SEQN(una));
02864         if (seq_diff < 0) {
02865             tcp_dbg(">>> FATAL: seq diff is negative!\n");
02866             break;
02867         }
02868 
02869         /* Check if advertised window is full */
02870         if ((uint32_t)seq_diff >= (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) {
02871             if (t->x_mode != PICO_TCP_WINDOW_FULL) {
02872                 tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n", t->recv_wnd << t->recv_wnd_scale, f->payload_len);
02873                 tcp_dbg("In window full...\n");
02874                 t->snd_nxt = SEQN(una);
02875                 t->snd_retry = SEQN(una);
02876                 t->x_mode = PICO_TCP_WINDOW_FULL;
02877             }
02878 
02879             break;
02880         }
02881 
02882         /* Check if the advertised window is too small to receive the current frame */
02883         if ((uint32_t)(seq_diff + f->payload_len) > (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) {
02884             f = tcp_split_segment(t, f, (uint16_t)(t->recv_wnd << t->recv_wnd_scale));
02885             if (!f)
02886                 break;
02887 
02888             /* Limit sending window to packets in flight (right sizing) */
02889             t->cwnd = (uint16_t)t->in_flight;
02890             if (t->cwnd < 1)
02891                 t->cwnd = 1;
02892         }
02893 
02894         tcp_dbg("TCP> DEQUEUED (for output) frame %08x, acks %08x len= %d, remaining frames %d\n", SEQN(f), ACKN(f), f->payload_len, t->tcpq_out.frames);
02895         tcp_send(t, f);
02896         sent++;
02897         loop_score--;
02898         t->snd_last_out = SEQN(f);
02899         if (loop_score < 1)
02900             break;
02901 
02902         if (f->payload_len > 0) {
02903             data_sent++;
02904             f = next_segment(&t->tcpq_out, f);
02905         } else {
02906             f = NULL;
02907         }
02908     }
02909     if ((sent > 0 && data_sent > 0)) {
02910         rto_set(t, t->rto);
02911     } else {
02912         /* Nothing to transmit. */
02913     }
02914 
02915     if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) {              /* if no more packets in queue, XXX replaced !f by tcpq check */
02916         if(!checkLocalClosing(&t->sock))              /* check if local closing started and send fin */
02917         {
02918             checkRemoteClosing(&t->sock);              /* check if remote closing started and send fin */
02919         }
02920     }
02921 
02922     return loop_score;
02923 }
02924 
02925 /* function to make new segment from hold queue with specific size (mss) */
02926 static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t)
02927 {
02928     struct pico_frame *f_temp, *f_new;
02929     struct pico_socket *s = (struct pico_socket *) &t->sock;
02930     struct pico_tcp_hdr *hdr;
02931     uint16_t total_len = 0, total_payload_len = 0;
02932     uint16_t off = 0, test = 0;
02933 
02934     off = pico_tcp_overhead(s);
02935 
02936     /* init with first frame in hold queue */
02937     f_temp = first_segment(&t->tcpq_hold);
02938     total_len = f_temp->payload_len;
02939     f_temp = next_segment(&t->tcpq_hold, f_temp);
02940 
02941     /* check till total_len <= MSS */
02942     while ((f_temp != NULL) && ((total_len + f_temp->payload_len) <= t->mss)) {
02943         total_len = (uint16_t)(total_len + f_temp->payload_len);
02944         f_temp = next_segment(&t->tcpq_hold, f_temp);
02945         if (f_temp == NULL)
02946             break;
02947     }
02948     /* alloc new frame with payload size = off + total_len */
02949     f_new = pico_socket_frame_alloc(s, (uint16_t)(off + total_len));
02950     if (!f_new) {
02951         pico_err = PICO_ERR_ENOMEM;
02952         return f_new;
02953     }
02954 
02955     pico_tcp_flags_update(f_new, &t->sock);
02956     hdr = (struct pico_tcp_hdr *) f_new->transport_hdr;
02957     /* init new frame */
02958     f_new->payload += off;
02959     f_new->payload_len = (uint16_t)(f_new->payload_len - off);
02960     f_new->sock = s;
02961 
02962     f_temp = first_segment(&t->tcpq_hold);
02963     hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq;              /* get sequence number of first frame */
02964     hdr->trans.sport = t->sock.local_port;
02965     hdr->trans.dport = t->sock.remote_port;
02966 
02967     /* check till total_payload_len <= MSS */
02968     while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= t->mss)) {
02969         /* cpy data and discard frame */
02970         test++;
02971         memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len);
02972         total_payload_len = (uint16_t)(total_payload_len + f_temp->payload_len);
02973         pico_discard_segment(&t->tcpq_hold, f_temp);
02974         f_temp = first_segment(&t->tcpq_hold);
02975     }
02976     hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2u | (int8_t)t->jumbo);
02977 
02978     tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n", test, total_payload_len);
02979     tcp_add_options_frame(t, f_new);
02980 
02981     return f_new;
02982 }
02983 
02984 
02985 
02986 static int pico_tcp_push_nagle_enqueue(struct pico_socket_tcp *t, struct pico_frame *f)
02987 {
02988     if (pico_enqueue_segment(&t->tcpq_out, f) > 0) {
02989         tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t);
02990         t->snd_last += f->payload_len;
02991         return f->payload_len;
02992     } else {
02993         tcp_dbg("Enqueue failed.\n");
02994         return 0;
02995     }
02996 }
02997 
02998 static int pico_tcp_push_nagle_hold(struct pico_socket_tcp *t, struct pico_frame *f)
02999 {
03000     struct pico_frame *f_new;
03001     uint32_t total_len = 0;
03002     total_len = f->payload_len + t->tcpq_hold.size;
03003     if ((total_len >= t->mss) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) {
03004         /* IF enough data in hold (>mss) AND space in out queue (>mss) */
03005         /* add current frame in hold and make new segment */
03006         if (pico_enqueue_segment(&t->tcpq_hold, f) > 0 ) {
03007             tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n", t->tcpq_out.frames);
03008             t->snd_last += f->payload_len;              /* XXX  WATCH OUT */
03009             f_new = pico_hold_segment_make(t);
03010         } else {
03011             tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 1\n");
03012             return 0;
03013         }
03014 
03015         /* and put new frame in out queue */
03016         if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out, f_new) > 0)) {
03017             return f_new->payload_len;
03018         } else {
03019             tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n", f_new);
03020             return -1;              /* XXX something seriously wrong */
03021         }
03022     } else {
03023         /* ELSE put frame in hold queue */
03024         if (pico_enqueue_segment(&t->tcpq_hold, f) > 0) {
03025             tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n", t->tcpq_out.frames);
03026             t->snd_last += f->payload_len;              /* XXX  WATCH OUT */
03027             return f->payload_len;
03028         } else {
03029             pico_err = PICO_ERR_EAGAIN;
03030             tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 2\n");
03031         }
03032     }
03033 
03034     return 0;
03035 }
03036 
03037 
03038 static int pico_tcp_push_nagle_on(struct pico_socket_tcp *t, struct pico_frame *f)
03039 {
03040     /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */
03041     if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t))
03042         return pico_tcp_push_nagle_enqueue(t, f);
03043 
03044     return pico_tcp_push_nagle_hold(t, f);
03045 }
03046 
03047 
03048 
03049 /* original behavior kept when Nagle disabled;
03050    Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */
03051 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f)
03052 {
03053     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
03054     struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock;
03055     IGNORE_PARAMETER(self);
03056     pico_err = PICO_ERR_NOERR;
03057     hdr->trans.sport = t->sock.local_port;
03058     hdr->trans.dport = t->sock.remote_port;
03059     hdr->seq = long_be(t->snd_last + 1);
03060     hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2u | (int8_t)t->jumbo);
03061 
03062     if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size))
03063         t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR);
03064 
03065     /***************************************************************************/
03066 
03067     if (!IS_NAGLE_ENABLED((&(t->sock)))) {
03068         /* TCP_NODELAY enabled, original behavior */
03069         if (pico_enqueue_segment(&t->tcpq_out, f) > 0) {
03070             tcp_dbg_nagle("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t);
03071             t->snd_last += f->payload_len;
03072             return f->payload_len;
03073         } else {
03074             tcp_dbg("Enqueue failed.\n");
03075             return 0;
03076         }
03077     } else {
03078         return pico_tcp_push_nagle_on(t, f);
03079     }
03080 
03081 }
03082 
03083 inline static void tcp_discard_all_segments(struct pico_tcp_queue *tq)
03084 {
03085     struct pico_tree_node *index = NULL, *index_safe = NULL;
03086     PICOTCP_MUTEX_LOCK(Mutex);
03087     pico_tree_foreach_safe(index, &tq->pool, index_safe)
03088     {
03089         void *f = index->keyValue;
03090         if(!f)
03091             break;
03092 
03093         pico_tree_delete(&tq->pool, f);
03094         if(IS_INPUT_QUEUE(tq))
03095         {
03096             struct tcp_input_segment *inp = (struct tcp_input_segment *)f;
03097             PICO_FREE(inp->payload);
03098             PICO_FREE(inp);
03099         }
03100         else
03101             pico_frame_discard(f);
03102     }
03103     tq->frames = 0;
03104     tq->size = 0;
03105     PICOTCP_MUTEX_UNLOCK(Mutex);
03106 }
03107 
03108 void pico_tcp_cleanup_queues(struct pico_socket *sck)
03109 {
03110     struct pico_socket_tcp *tcp = (struct pico_socket_tcp *)sck;
03111     if(tcp->retrans_tmr) {
03112         pico_timer_cancel(tcp->retrans_tmr);
03113         tcp->retrans_tmr = NULL;
03114     }
03115     if(tcp->keepalive_tmr) {
03116         pico_timer_cancel(tcp->keepalive_tmr);
03117         tcp->keepalive_tmr = NULL;
03118     }
03119     if(tcp->fin_tmr) {
03120         pico_timer_cancel(tcp->fin_tmr);
03121         tcp->fin_tmr = NULL;
03122     }
03123     tcp_discard_all_segments(&tcp->tcpq_in);
03124     tcp_discard_all_segments(&tcp->tcpq_out);
03125     tcp_discard_all_segments(&tcp->tcpq_hold);
03126 }
03127 
03128 static int checkLocalClosing(struct pico_socket *s)
03129 {
03130     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03131     if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) {
03132         tcp_dbg("TCP> buffer empty, shutdown established ...\n");
03133         /* send fin if queue empty and in state shut local (write) */
03134         tcp_send_fin(t);
03135         /* change tcp state to FIN_WAIT1 */
03136         s->state &= 0x00FFU;
03137         s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1;
03138         return 1;
03139     }
03140 
03141     return 0;
03142 }
03143 
03144 static int checkRemoteClosing(struct pico_socket *s)
03145 {
03146     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03147     if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) {
03148         /* send fin if queue empty and in state shut local (write) */
03149         tcp_send_fin(t);
03150         /* change tcp state to LAST_ACK */
03151         s->state &= 0x00FFU;
03152         s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK;
03153         tcp_dbg("TCP> STATE: LAST_ACK.\n");
03154         return 1;
03155     }
03156 
03157     return 0;
03158 }
03159 
03160 void pico_tcp_notify_closing(struct pico_socket *sck)
03161 {
03162     struct pico_socket_tcp *t = (struct pico_socket_tcp *)sck;
03163     if(t->tcpq_out.frames == 0)
03164     {
03165         if(!checkLocalClosing(sck))
03166             checkRemoteClosing(sck);
03167     }
03168 }
03169 
03170 
03171 int pico_tcp_check_listen_close(struct pico_socket *s)
03172 {
03173     if (TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) {
03174         pico_socket_del(s);
03175         return 0;
03176     }
03177 
03178     return -1;
03179 }
03180 
03181 void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s)
03182 {
03183     f->transport_flags_saved = ((struct pico_socket_tcp *)s)->ts_ok;
03184 }
03185 
03186 int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value)
03187 {
03188     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03189     t->tcpq_in.max_size = value;
03190     return 0;
03191 }
03192 
03193 int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value)
03194 {
03195     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03196     t->tcpq_out.max_size = value;
03197     return 0;
03198 }
03199 
03200 int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value)
03201 {
03202     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03203     *value = t->tcpq_in.max_size;
03204     return 0;
03205 }
03206 
03207 int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value)
03208 {
03209     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03210     *value = t->tcpq_out.max_size;
03211     return 0;
03212 }
03213 
03214 int pico_tcp_set_keepalive_probes(struct pico_socket *s, uint32_t value)
03215 {
03216     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03217     t->ka_probes = value;
03218     return 0;
03219 }
03220 
03221 int pico_tcp_set_keepalive_intvl(struct pico_socket *s, uint32_t value)
03222 {
03223     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03224     t->ka_intvl = value;
03225     return 0;
03226 }
03227 
03228 int pico_tcp_set_keepalive_time(struct pico_socket *s, uint32_t value)
03229 {
03230     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03231     t->ka_time = value;
03232     return 0;
03233 }
03234 
03235 int pico_tcp_set_linger(struct pico_socket *s, uint32_t value)
03236 {
03237     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
03238     t->linger_timeout = value;
03239     return 0;
03240 }
03241 
03242 #endif /* PICO_SUPPORT_TCP */