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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Thu Dec 05 08:31:32 2013 +0000
Revision:
128:ae39e6e81531
Parent:
123:dd26752a4538
Child:
131:4758606c9316
updated repo to work with uint64 tick.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 29:1a47b7151851 1 /*********************************************************************
daniele 29:1a47b7151851 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 29:1a47b7151851 3 See LICENSE and COPYING for usage.
daniele 29:1a47b7151851 4
daniele 29:1a47b7151851 5 .
daniele 29:1a47b7151851 6
daniele 29:1a47b7151851 7 Authors: Daniele Lacamera, Philippe Mariman
daniele 29:1a47b7151851 8 *********************************************************************/
daniele 29:1a47b7151851 9
daniele 29:1a47b7151851 10 #include "pico_tcp.h"
daniele 29:1a47b7151851 11 #include "pico_config.h"
daniele 29:1a47b7151851 12 #include "pico_eth.h"
daniele 29:1a47b7151851 13 #include "pico_socket.h"
daniele 29:1a47b7151851 14 #include "pico_stack.h"
daniele 29:1a47b7151851 15 #include "pico_socket.h"
daniele 29:1a47b7151851 16 #include "pico_queue.h"
daniele 29:1a47b7151851 17 #include "pico_tree.h"
daniele 29:1a47b7151851 18
tass 68:0847e35d08a6 19 #define TCP_IS_STATE(s,st) (s->state & st)
daniele 29:1a47b7151851 20 #define TCP_SOCK(s) ((struct pico_socket_tcp *)s)
tass 110:0ece1bbbd36e 21 #define SEQN(f) ((f)?(long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->seq)):0)
tass 110:0ece1bbbd36e 22 #define ACKN(f) ((f)?(long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->ack)):0)
daniele 29:1a47b7151851 23
tass 122:5b1e9de8bf7f 24 #define PICO_TCP_RTO_MIN 50
daniele 29:1a47b7151851 25 #define PICO_TCP_RTO_MAX 120000
tass 68:0847e35d08a6 26 #define PICO_TCP_IW 2
tass 70:cd218dd180e5 27 #define PICO_TCP_SYN_TO 1000u
tass 48:40fc4462265c 28 #define PICO_TCP_ZOMBIE_TO 30000
daniele 29:1a47b7151851 29
tass 97:e73b01cb3147 30 #define PICO_TCP_MAX_RETRANS 10
daniele 29:1a47b7151851 31 #define PICO_TCP_MAX_CONNECT_RETRIES 7
daniele 29:1a47b7151851 32
daniele 29:1a47b7151851 33 #define PICO_TCP_LOOKAHEAD 0x00
daniele 29:1a47b7151851 34 #define PICO_TCP_FIRST_DUPACK 0x01
daniele 29:1a47b7151851 35 #define PICO_TCP_SECOND_DUPACK 0x02
daniele 29:1a47b7151851 36 #define PICO_TCP_RECOVER 0x03
daniele 29:1a47b7151851 37 #define PICO_TCP_BLACKOUT 0x04
daniele 29:1a47b7151851 38 #define PICO_TCP_UNREACHABLE 0x05
daniele 29:1a47b7151851 39 #define PICO_TCP_WINDOW_FULL 0x06
daniele 29:1a47b7151851 40
daniele 29:1a47b7151851 41 /* check if the Nagle algorithm is enabled on the socket */
daniele 29:1a47b7151851 42 #define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
daniele 29:1a47b7151851 43 /* check if tcp connection is "idle" according to Nagle (RFC 896) */
daniele 29:1a47b7151851 44 #define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0))
daniele 29:1a47b7151851 45 /* check if the hold queue contains data (again Nagle) */
daniele 29:1a47b7151851 46 #define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0)
daniele 29:1a47b7151851 47
tass 110:0ece1bbbd36e 48 #define IS_INPUT_QUEUE(q) (q->pool.compare==input_segment_compare)
tass 110:0ece1bbbd36e 49 #define TCP_INPUT_OVERHEAD (sizeof(struct tcp_input_segment)+sizeof(struct pico_tree_node))
tass 110:0ece1bbbd36e 50
tass 123:dd26752a4538 51
daniele 29:1a47b7151851 52 #ifdef PICO_SUPPORT_TCP
tass 45:ca30069e49bb 53 #define tcp_dbg_nagle(...) do{}while(0)
tass 45:ca30069e49bb 54 #define tcp_dbg_options(...) do{}while(0)
tass 45:ca30069e49bb 55
tass 45:ca30069e49bb 56
tass 68:0847e35d08a6 57 #define tcp_dbg(...) do{}while(0)
tass 68:0847e35d08a6 58 //#define tcp_dbg dbg
daniele 29:1a47b7151851 59
daniele 29:1a47b7151851 60 #ifdef PICO_SUPPORT_MUTEX
daniele 29:1a47b7151851 61 static void * Mutex = NULL;
daniele 29:1a47b7151851 62 #define LOCK(x) {\
daniele 29:1a47b7151851 63 if (x == NULL) \
daniele 29:1a47b7151851 64 x = pico_mutex_init(); \
daniele 29:1a47b7151851 65 pico_mutex_lock(x); \
daniele 29:1a47b7151851 66 }
daniele 29:1a47b7151851 67 #define UNLOCK(x) pico_mutex_unlock(x);
daniele 29:1a47b7151851 68
daniele 29:1a47b7151851 69 #else
daniele 29:1a47b7151851 70 #define LOCK(x) do{}while(0)
daniele 29:1a47b7151851 71 #define UNLOCK(x) do{}while(0)
daniele 29:1a47b7151851 72 #endif
daniele 29:1a47b7151851 73
daniele 29:1a47b7151851 74
daniele 29:1a47b7151851 75 static inline int seq_compare(uint32_t a, uint32_t b)
daniele 29:1a47b7151851 76 {
daniele 29:1a47b7151851 77 uint32_t thresh = ((uint32_t)(-1))>>1;
daniele 29:1a47b7151851 78 if (((a > thresh) && (b > thresh)) || ((a <= thresh) && (b <= thresh))) {
daniele 29:1a47b7151851 79 if (a > b)
daniele 29:1a47b7151851 80 return 1;
daniele 29:1a47b7151851 81 if (b > a)
daniele 29:1a47b7151851 82 return -1;
daniele 29:1a47b7151851 83 } else {
daniele 29:1a47b7151851 84 if (a > b)
daniele 29:1a47b7151851 85 return -2;
daniele 29:1a47b7151851 86 if (b > a)
daniele 29:1a47b7151851 87 return 2;
daniele 29:1a47b7151851 88 }
daniele 29:1a47b7151851 89 return 0;
daniele 29:1a47b7151851 90 }
daniele 29:1a47b7151851 91
tass 110:0ece1bbbd36e 92 // Input segment, used to keep only needed data, not the full frame
tass 110:0ece1bbbd36e 93 struct tcp_input_segment
tass 110:0ece1bbbd36e 94 {
tass 110:0ece1bbbd36e 95 uint32_t seq;
tass 110:0ece1bbbd36e 96 /* Pointer to payload */
tass 110:0ece1bbbd36e 97 unsigned char *payload;
tass 110:0ece1bbbd36e 98 uint16_t payload_len;
tass 110:0ece1bbbd36e 99 };
tass 110:0ece1bbbd36e 100
tass 110:0ece1bbbd36e 101 // Function to compare input segments
tass 110:0ece1bbbd36e 102 static int input_segment_compare(void *ka, void *kb)
tass 110:0ece1bbbd36e 103 {
tass 110:0ece1bbbd36e 104 struct tcp_input_segment *a = ka, *b = kb;
tass 110:0ece1bbbd36e 105 return seq_compare(a->seq,b->seq);
tass 110:0ece1bbbd36e 106 }
tass 110:0ece1bbbd36e 107
tass 110:0ece1bbbd36e 108 static struct tcp_input_segment * segment_from_frame(struct pico_frame * f)
tass 110:0ece1bbbd36e 109 {
tass 110:0ece1bbbd36e 110 struct tcp_input_segment * seg = pico_zalloc(sizeof(struct tcp_input_segment));
tass 110:0ece1bbbd36e 111 if(!seg)
tass 110:0ece1bbbd36e 112 return NULL;
tass 110:0ece1bbbd36e 113 seg->payload = pico_zalloc(f->payload_len);
tass 110:0ece1bbbd36e 114 if(!seg->payload)
tass 110:0ece1bbbd36e 115 {
tass 110:0ece1bbbd36e 116 pico_free(seg);
tass 110:0ece1bbbd36e 117 return NULL;
tass 110:0ece1bbbd36e 118 }
tass 110:0ece1bbbd36e 119 seg->seq = SEQN(f);
tass 110:0ece1bbbd36e 120 seg->payload_len = f->payload_len;
tass 110:0ece1bbbd36e 121 memcpy(seg->payload,f->payload,seg->payload_len);
tass 110:0ece1bbbd36e 122 return seg;
tass 110:0ece1bbbd36e 123 }
tass 110:0ece1bbbd36e 124
daniele 29:1a47b7151851 125 static int segment_compare(void * ka, void * kb)
daniele 29:1a47b7151851 126 {
daniele 29:1a47b7151851 127 struct pico_frame *a = ka, *b = kb;
daniele 29:1a47b7151851 128 return seq_compare(SEQN(a), SEQN(b));
daniele 29:1a47b7151851 129 }
daniele 29:1a47b7151851 130
daniele 29:1a47b7151851 131 struct pico_tcp_queue
daniele 29:1a47b7151851 132 {
daniele 29:1a47b7151851 133 struct pico_tree pool;
daniele 29:1a47b7151851 134 uint32_t max_size;
daniele 29:1a47b7151851 135 uint32_t size;
daniele 29:1a47b7151851 136 uint32_t frames;
tass 111:4003cf17bc15 137 uint16_t overhead;
daniele 29:1a47b7151851 138 };
tass 97:e73b01cb3147 139 static void tcp_discard_all_segments(struct pico_tcp_queue *tq);
tass 110:0ece1bbbd36e 140 static void *peek_segment(struct pico_tcp_queue *tq, uint32_t seq)
daniele 29:1a47b7151851 141 {
tass 110:0ece1bbbd36e 142 if(!IS_INPUT_QUEUE(tq))
tass 110:0ece1bbbd36e 143 {
tass 110:0ece1bbbd36e 144 struct pico_tcp_hdr H;
tass 110:0ece1bbbd36e 145 struct pico_frame f = {0};
tass 110:0ece1bbbd36e 146 f.transport_hdr = (uint8_t *) (&H);
tass 110:0ece1bbbd36e 147 H.seq = long_be(seq);
daniele 29:1a47b7151851 148
tass 110:0ece1bbbd36e 149 return pico_tree_findKey(&tq->pool,&f);
tass 110:0ece1bbbd36e 150 }
tass 110:0ece1bbbd36e 151 else
tass 110:0ece1bbbd36e 152 {
tass 128:ae39e6e81531 153 struct tcp_input_segment dummy={.seq=seq};
tass 128:ae39e6e81531 154
tass 110:0ece1bbbd36e 155 return pico_tree_findKey(&tq->pool,&dummy);
tass 110:0ece1bbbd36e 156 }
tass 110:0ece1bbbd36e 157
daniele 29:1a47b7151851 158 }
daniele 29:1a47b7151851 159
tass 110:0ece1bbbd36e 160 static void *first_segment(struct pico_tcp_queue *tq)
daniele 29:1a47b7151851 161 {
daniele 29:1a47b7151851 162 return pico_tree_first(&tq->pool);
daniele 29:1a47b7151851 163 }
daniele 29:1a47b7151851 164
tass 110:0ece1bbbd36e 165 static void *next_segment(struct pico_tcp_queue *tq, void *cur)
daniele 29:1a47b7151851 166 {
daniele 29:1a47b7151851 167 if (!cur)
daniele 29:1a47b7151851 168 return NULL;
tass 110:0ece1bbbd36e 169 if(IS_INPUT_QUEUE(tq))
tass 110:0ece1bbbd36e 170 {
tass 110:0ece1bbbd36e 171 return peek_segment(tq,((struct tcp_input_segment *)cur)->seq + ((struct tcp_input_segment *)cur)->payload_len);
tass 110:0ece1bbbd36e 172 }
tass 110:0ece1bbbd36e 173 else
tass 110:0ece1bbbd36e 174 {
tass 110:0ece1bbbd36e 175 return peek_segment(tq, SEQN((struct pico_frame *)cur) + ((struct pico_frame *)cur)->payload_len);
tass 110:0ece1bbbd36e 176 }
daniele 29:1a47b7151851 177 }
daniele 29:1a47b7151851 178
tass 110:0ece1bbbd36e 179 static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, void *f)
daniele 29:1a47b7151851 180 {
tass 110:0ece1bbbd36e 181 int32_t ret = -1;
tass 110:0ece1bbbd36e 182 uint16_t payload_len = (uint16_t)(IS_INPUT_QUEUE(tq) ?
tass 111:4003cf17bc15 183 ((struct tcp_input_segment *)f)->payload_len:
tass 111:4003cf17bc15 184 ((struct pico_frame *)f)->buffer_len);
tass 110:0ece1bbbd36e 185
tass 110:0ece1bbbd36e 186 if (payload_len <= 0) {
daniele 29:1a47b7151851 187 tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n");
daniele 29:1a47b7151851 188 //abort();
daniele 29:1a47b7151851 189 return -1;
daniele 29:1a47b7151851 190 }
tass 68:0847e35d08a6 191 LOCK(Mutex);
tass 110:0ece1bbbd36e 192 if ((tq->size + payload_len) > tq->max_size)
daniele 29:1a47b7151851 193 {
daniele 29:1a47b7151851 194 ret = 0;
daniele 29:1a47b7151851 195 goto out;
daniele 29:1a47b7151851 196 }
daniele 29:1a47b7151851 197 if (pico_tree_insert(&tq->pool,f) != 0)
daniele 29:1a47b7151851 198 {
daniele 29:1a47b7151851 199 ret = 0;
daniele 29:1a47b7151851 200 goto out;
daniele 29:1a47b7151851 201 }
tass 111:4003cf17bc15 202 tq->size += (uint16_t)(payload_len + tq->overhead);
tass 110:0ece1bbbd36e 203 if (payload_len > 0)
daniele 29:1a47b7151851 204 tq->frames++;
tass 110:0ece1bbbd36e 205 ret = (int32_t)payload_len;
daniele 29:1a47b7151851 206
daniele 29:1a47b7151851 207 out :
daniele 29:1a47b7151851 208 UNLOCK(Mutex);
daniele 29:1a47b7151851 209 return ret;
daniele 29:1a47b7151851 210 }
daniele 29:1a47b7151851 211
tass 110:0ece1bbbd36e 212 static void pico_discard_segment(struct pico_tcp_queue *tq, void *f)
daniele 29:1a47b7151851 213 {
tass 110:0ece1bbbd36e 214 void *f1;
tass 110:0ece1bbbd36e 215 uint16_t payload_len = (uint16_t)(IS_INPUT_QUEUE(tq)?
tass 111:4003cf17bc15 216 ((struct tcp_input_segment *)f)->payload_len:
tass 111:4003cf17bc15 217 ((struct pico_frame *)f)->buffer_len);
daniele 29:1a47b7151851 218 LOCK(Mutex);
daniele 29:1a47b7151851 219 f1 = pico_tree_delete(&tq->pool,f);
daniele 29:1a47b7151851 220 if (f1) {
tass 111:4003cf17bc15 221 tq->size -= (uint16_t)(payload_len + tq->overhead);
tass 110:0ece1bbbd36e 222 if (payload_len > 0)
daniele 29:1a47b7151851 223 tq->frames--;
daniele 29:1a47b7151851 224 }
tass 110:0ece1bbbd36e 225 if(IS_INPUT_QUEUE(tq))
tass 110:0ece1bbbd36e 226 {
tass 110:0ece1bbbd36e 227 struct tcp_input_segment * inp = f1;
tass 110:0ece1bbbd36e 228 pico_free(inp->payload);
tass 110:0ece1bbbd36e 229 pico_free(inp);
tass 110:0ece1bbbd36e 230 }
tass 110:0ece1bbbd36e 231 else
tass 110:0ece1bbbd36e 232 pico_frame_discard(f);
daniele 29:1a47b7151851 233 UNLOCK(Mutex);
daniele 29:1a47b7151851 234 }
daniele 29:1a47b7151851 235
daniele 29:1a47b7151851 236 /* Structure for TCP socket */
daniele 29:1a47b7151851 237 struct tcp_sack_block {
daniele 29:1a47b7151851 238 uint32_t left;
daniele 29:1a47b7151851 239 uint32_t right;
daniele 29:1a47b7151851 240 struct tcp_sack_block *next;
daniele 29:1a47b7151851 241 };
daniele 29:1a47b7151851 242
daniele 29:1a47b7151851 243 struct pico_socket_tcp {
daniele 29:1a47b7151851 244 struct pico_socket sock;
daniele 29:1a47b7151851 245
daniele 29:1a47b7151851 246 /* Tree/queues */
tass 110:0ece1bbbd36e 247 struct pico_tcp_queue tcpq_in; // updated the input queue to hold input segments not the full frame.
daniele 29:1a47b7151851 248 struct pico_tcp_queue tcpq_out;
daniele 29:1a47b7151851 249 struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */
daniele 29:1a47b7151851 250
daniele 29:1a47b7151851 251 /* tcp_output */
daniele 29:1a47b7151851 252 uint32_t snd_nxt;
daniele 29:1a47b7151851 253 uint32_t snd_last;
daniele 29:1a47b7151851 254 uint32_t snd_old_ack;
daniele 29:1a47b7151851 255 uint32_t snd_retry;
daniele 29:1a47b7151851 256 uint32_t snd_last_out;
daniele 29:1a47b7151851 257
daniele 29:1a47b7151851 258 /* congestion control */
daniele 29:1a47b7151851 259 uint32_t avg_rtt;
daniele 29:1a47b7151851 260 uint32_t rttvar;
daniele 29:1a47b7151851 261 uint32_t rto;
daniele 29:1a47b7151851 262 uint32_t in_flight;
daniele 29:1a47b7151851 263 uint8_t timer_running;
tass 70:cd218dd180e5 264 struct pico_timer * retrans_tmr;
daniele 29:1a47b7151851 265 uint8_t keepalive_timer_running;
daniele 29:1a47b7151851 266 uint16_t cwnd_counter;
daniele 29:1a47b7151851 267 uint16_t cwnd;
daniele 29:1a47b7151851 268 uint16_t ssthresh;
daniele 29:1a47b7151851 269 uint16_t recv_wnd;
daniele 29:1a47b7151851 270 uint16_t recv_wnd_scale;
daniele 29:1a47b7151851 271
daniele 29:1a47b7151851 272 /* tcp_input */
daniele 29:1a47b7151851 273 uint32_t rcv_nxt;
daniele 29:1a47b7151851 274 uint32_t rcv_ackd;
daniele 29:1a47b7151851 275 uint32_t rcv_processed;
daniele 29:1a47b7151851 276 uint16_t wnd;
daniele 29:1a47b7151851 277 uint16_t wnd_scale;
daniele 29:1a47b7151851 278
daniele 29:1a47b7151851 279 /* options */
daniele 29:1a47b7151851 280 uint32_t ts_nxt;
daniele 29:1a47b7151851 281 uint16_t mss;
daniele 29:1a47b7151851 282 uint8_t sack_ok;
daniele 29:1a47b7151851 283 uint8_t ts_ok;
daniele 29:1a47b7151851 284 uint8_t mss_ok;
daniele 29:1a47b7151851 285 uint8_t scale_ok;
daniele 29:1a47b7151851 286 struct tcp_sack_block *sacks;
daniele 29:1a47b7151851 287 uint8_t jumbo;
daniele 29:1a47b7151851 288
daniele 29:1a47b7151851 289 /* Transmission */
daniele 29:1a47b7151851 290 uint8_t x_mode;
daniele 29:1a47b7151851 291 uint8_t dupacks;
daniele 29:1a47b7151851 292 uint8_t backoff;
tass 75:a9abf10138d6 293 uint8_t localZeroWindow;
daniele 29:1a47b7151851 294 };
daniele 29:1a47b7151851 295
daniele 29:1a47b7151851 296 /* Queues */
tass 68:0847e35d08a6 297 static struct pico_queue tcp_in = {0};
tass 68:0847e35d08a6 298 static struct pico_queue tcp_out = {0};
daniele 29:1a47b7151851 299
daniele 29:1a47b7151851 300 /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */
daniele 29:1a47b7151851 301 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t);
daniele 29:1a47b7151851 302
daniele 29:1a47b7151851 303 /* checks if tcpq_in is empty */
daniele 29:1a47b7151851 304 int pico_tcp_queue_in_is_empty(struct pico_socket *s)
daniele 29:1a47b7151851 305 {
daniele 29:1a47b7151851 306 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 29:1a47b7151851 307
daniele 29:1a47b7151851 308 if (t->tcpq_in.frames == 0)
daniele 29:1a47b7151851 309 return 1;
daniele 29:1a47b7151851 310 else
daniele 29:1a47b7151851 311 return 0;
daniele 29:1a47b7151851 312 }
daniele 29:1a47b7151851 313
daniele 29:1a47b7151851 314 /* Useful for getting rid of the beginning of the buffer (read() op) */
daniele 29:1a47b7151851 315 static int release_until(struct pico_tcp_queue *q, uint32_t seq)
daniele 29:1a47b7151851 316 {
tass 110:0ece1bbbd36e 317 void *head = first_segment(q);
daniele 29:1a47b7151851 318 int ret = 0;
tass 110:0ece1bbbd36e 319 int seq_result = 0;
tass 110:0ece1bbbd36e 320 if(head)
tass 110:0ece1bbbd36e 321 seq_result = IS_INPUT_QUEUE(q) ?
tass 110:0ece1bbbd36e 322 seq_compare( ((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq) :
tass 110:0ece1bbbd36e 323 seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq);
tass 110:0ece1bbbd36e 324
tass 110:0ece1bbbd36e 325 while (head && (seq_result <= 0)) {
tass 110:0ece1bbbd36e 326 void *cur = head;
daniele 29:1a47b7151851 327 head = next_segment(q, cur);
tass 37:bdf736327c71 328 tcp_dbg("Releasing %p\n", q);
daniele 29:1a47b7151851 329 pico_discard_segment(q, cur);
daniele 29:1a47b7151851 330 ret++;
tass 110:0ece1bbbd36e 331 if(head)
tass 110:0ece1bbbd36e 332 seq_result = IS_INPUT_QUEUE(q) ?
tass 110:0ece1bbbd36e 333 seq_compare( ((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq) :
tass 110:0ece1bbbd36e 334 seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq);
daniele 29:1a47b7151851 335 }
daniele 29:1a47b7151851 336 return ret;
daniele 29:1a47b7151851 337 }
daniele 29:1a47b7151851 338
tass 128:ae39e6e81531 339 static int release_all_until(struct pico_tcp_queue *q, uint32_t seq,pico_time * timestamp)
daniele 29:1a47b7151851 340 {
tass 110:0ece1bbbd36e 341 void *f = NULL, *tmp __attribute__((unused));
daniele 29:1a47b7151851 342 struct pico_tree_node * idx, * temp;
tass 110:0ece1bbbd36e 343 int seq_result;
daniele 29:1a47b7151851 344 int ret = 0;
tass 123:dd26752a4538 345 *timestamp = 0;
daniele 29:1a47b7151851 346
daniele 29:1a47b7151851 347 pico_tree_foreach_safe(idx,&q->pool,temp){
daniele 29:1a47b7151851 348 f = idx->keyValue;
tass 110:0ece1bbbd36e 349 seq_result = IS_INPUT_QUEUE(q) ?
tass 110:0ece1bbbd36e 350 seq_compare( ((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq):
tass 110:0ece1bbbd36e 351 seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq);
tass 110:0ece1bbbd36e 352 if (seq_result<= 0) {
tass 37:bdf736327c71 353 tcp_dbg("Releasing %p\n", f);
tass 123:dd26752a4538 354 if(seq_result == 0)
tass 123:dd26752a4538 355 *timestamp = ((struct pico_frame *)f)->timestamp;
daniele 29:1a47b7151851 356 pico_discard_segment(q, f);
daniele 29:1a47b7151851 357 ret++;
daniele 29:1a47b7151851 358 } else
daniele 29:1a47b7151851 359 return ret;
daniele 29:1a47b7151851 360 }
daniele 29:1a47b7151851 361 return ret;
daniele 29:1a47b7151851 362 }
daniele 29:1a47b7151851 363
daniele 29:1a47b7151851 364 /* API calls */
daniele 29:1a47b7151851 365
daniele 29:1a47b7151851 366 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f)
daniele 29:1a47b7151851 367 {
daniele 29:1a47b7151851 368 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
daniele 29:1a47b7151851 369 struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 370 struct pico_socket *s = f->sock;
daniele 29:1a47b7151851 371 struct pico_ipv4_pseudo_hdr pseudo;
daniele 29:1a47b7151851 372
daniele 29:1a47b7151851 373 if (s) {
daniele 29:1a47b7151851 374 /* Case of outgoing frame */
daniele 29:1a47b7151851 375 //dbg("TCP CRC: on outgoing frame\n");
daniele 29:1a47b7151851 376 pseudo.src.addr = s->local_addr.ip4.addr;
daniele 29:1a47b7151851 377 pseudo.dst.addr = s->remote_addr.ip4.addr;
daniele 29:1a47b7151851 378 } else {
daniele 29:1a47b7151851 379 /* Case of incomming frame */
daniele 29:1a47b7151851 380 //dbg("TCP CRC: on incomming frame\n");
daniele 29:1a47b7151851 381 pseudo.src.addr = hdr->src.addr;
daniele 29:1a47b7151851 382 pseudo.dst.addr = hdr->dst.addr;
daniele 29:1a47b7151851 383 }
daniele 29:1a47b7151851 384 pseudo.zeros = 0;
daniele 29:1a47b7151851 385 pseudo.proto = PICO_PROTO_TCP;
tass 70:cd218dd180e5 386 pseudo.len = (uint16_t)short_be(f->transport_len);
daniele 29:1a47b7151851 387
daniele 29:1a47b7151851 388 return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len);
daniele 29:1a47b7151851 389 }
daniele 29:1a47b7151851 390
tass 32:865c101e0874 391 static void tcp_send_fin(struct pico_socket_tcp *t);
daniele 29:1a47b7151851 392 static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f)
daniele 29:1a47b7151851 393 {
daniele 29:1a47b7151851 394 struct pico_tcp_hdr *hdr;
daniele 29:1a47b7151851 395 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
tass 68:0847e35d08a6 396 IGNORE_PARAMETER(self);
daniele 29:1a47b7151851 397 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
tass 68:0847e35d08a6 398 f->sock->timestamp = PICO_TIME_MS();
daniele 29:1a47b7151851 399 if (f->payload_len > 0) {
daniele 29:1a47b7151851 400 tcp_dbg("Process out: sending %p (%d bytes)\n",f, f->payload_len);
daniele 29:1a47b7151851 401 } else {
daniele 29:1a47b7151851 402 tcp_dbg("Sending empty packet\n");
daniele 29:1a47b7151851 403 }
daniele 29:1a47b7151851 404
daniele 29:1a47b7151851 405 if (f->payload_len > 0) {
daniele 29:1a47b7151851 406 if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) {
daniele 29:1a47b7151851 407 t->snd_nxt = SEQN(f) + f->payload_len;
daniele 29:1a47b7151851 408 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
daniele 29:1a47b7151851 409 }
daniele 29:1a47b7151851 410 } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */
tass 40:c8ab0d2bba0b 411 //hdr->seq = long_be(t->snd_nxt); /* XXX disabled this to not to mess with seq nrs of ACKs anymore */
daniele 29:1a47b7151851 412 } else {
daniele 29:1a47b7151851 413 tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags);
daniele 29:1a47b7151851 414 }
tass 32:865c101e0874 415
daniele 29:1a47b7151851 416 pico_network_send(f);
daniele 29:1a47b7151851 417 return 0;
daniele 29:1a47b7151851 418 }
daniele 29:1a47b7151851 419
tass 95:f4ca916a26fe 420 int32_t pico_tcp_push(struct pico_protocol *self, struct pico_frame *data);
daniele 29:1a47b7151851 421
daniele 29:1a47b7151851 422 /* Interface: protocol definition */
daniele 29:1a47b7151851 423 struct pico_protocol pico_proto_tcp = {
daniele 29:1a47b7151851 424 .name = "tcp",
daniele 29:1a47b7151851 425 .proto_number = PICO_PROTO_TCP,
daniele 29:1a47b7151851 426 .layer = PICO_LAYER_TRANSPORT,
daniele 29:1a47b7151851 427 .process_in = pico_transport_process_in,
daniele 29:1a47b7151851 428 .process_out = pico_tcp_process_out,
daniele 29:1a47b7151851 429 .push = pico_tcp_push,
daniele 29:1a47b7151851 430 .q_in = &tcp_in,
daniele 29:1a47b7151851 431 .q_out = &tcp_out,
daniele 29:1a47b7151851 432 };
daniele 29:1a47b7151851 433
daniele 29:1a47b7151851 434 static uint32_t pico_paws(void)
daniele 29:1a47b7151851 435 {
tass 74:c146c4e346c4 436 static uint32_t _paws = 0;
daniele 29:1a47b7151851 437 _paws = pico_rand();
daniele 29:1a47b7151851 438 return long_be(_paws); /*XXX: implement paws */
daniele 29:1a47b7151851 439 }
daniele 29:1a47b7151851 440
tass 70:cd218dd180e5 441 static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz)
daniele 29:1a47b7151851 442 {
tass 128:ae39e6e81531 443 uint32_t tsval = long_be((uint32_t)pico_tick);
daniele 29:1a47b7151851 444 uint32_t tsecr = long_be(ts->ts_nxt);
tass 70:cd218dd180e5 445 uint32_t i = 0;
daniele 29:1a47b7151851 446 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 447
daniele 29:1a47b7151851 448 memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */
daniele 29:1a47b7151851 449
daniele 29:1a47b7151851 450 if (flags & PICO_TCP_SYN) {
daniele 29:1a47b7151851 451 f->start[i++] = PICO_TCP_OPTION_MSS;
daniele 29:1a47b7151851 452 f->start[i++] = PICO_TCPOPTLEN_MSS;
tass 70:cd218dd180e5 453 f->start[i++] = (uint8_t)((ts->mss >> 8) & 0xFF);
tass 70:cd218dd180e5 454 f->start[i++] = (uint8_t)(ts->mss & 0xFF);
daniele 29:1a47b7151851 455 f->start[i++] = PICO_TCP_OPTION_SACK_OK;
daniele 29:1a47b7151851 456 f->start[i++] = PICO_TCPOPTLEN_SACK_OK;
daniele 29:1a47b7151851 457 }
daniele 29:1a47b7151851 458
daniele 29:1a47b7151851 459 f->start[i++] = PICO_TCP_OPTION_WS;
daniele 29:1a47b7151851 460 f->start[i++] = PICO_TCPOPTLEN_WS;
tass 70:cd218dd180e5 461 f->start[i++] = (uint8_t)(ts->wnd_scale);
daniele 29:1a47b7151851 462
tass 128:ae39e6e81531 463 if ((flags & PICO_TCP_SYN) || ts->ts_ok) {
daniele 29:1a47b7151851 464 f->start[i++] = PICO_TCP_OPTION_TIMESTAMP;
daniele 29:1a47b7151851 465 f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP;
daniele 29:1a47b7151851 466 memcpy(f->start + i, &tsval, 4);
daniele 29:1a47b7151851 467 i += 4;
daniele 29:1a47b7151851 468 memcpy(f->start + i, &tsecr, 4);
daniele 29:1a47b7151851 469 i += 4;
daniele 29:1a47b7151851 470 }
daniele 29:1a47b7151851 471
daniele 29:1a47b7151851 472 if (flags & PICO_TCP_ACK) {
daniele 29:1a47b7151851 473 struct tcp_sack_block *sb;
tass 70:cd218dd180e5 474 uint32_t len_off;
daniele 29:1a47b7151851 475
daniele 29:1a47b7151851 476 if (ts->sack_ok && ts->sacks) {
daniele 29:1a47b7151851 477 f->start[i++] = PICO_TCP_OPTION_SACK;
daniele 29:1a47b7151851 478 len_off = i;
daniele 29:1a47b7151851 479 f->start[i++] = PICO_TCPOPTLEN_SACK;
daniele 29:1a47b7151851 480 while(ts->sacks) {
daniele 29:1a47b7151851 481 sb = ts->sacks;
daniele 29:1a47b7151851 482 ts->sacks = sb->next;
daniele 29:1a47b7151851 483 memcpy(f->start + i, sb, 2 * sizeof(uint32_t));
tass 74:c146c4e346c4 484 i += (2 * (uint32_t)sizeof(uint32_t));
tass 73:dfb737147f6e 485 f->start[len_off] = (uint8_t)(f->start[len_off] + (2 * sizeof(uint32_t)));
daniele 29:1a47b7151851 486 pico_free(sb);
daniele 29:1a47b7151851 487 }
daniele 29:1a47b7151851 488 }
daniele 29:1a47b7151851 489 }
daniele 29:1a47b7151851 490 if (i < optsiz)
daniele 29:1a47b7151851 491 f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END;
daniele 29:1a47b7151851 492 }
daniele 29:1a47b7151851 493
daniele 29:1a47b7151851 494 static void tcp_send_ack(struct pico_socket_tcp *t);
tass 75:a9abf10138d6 495 #define tcp_send_windowUpdate(t) (tcp_send_ack(t))
daniele 29:1a47b7151851 496
daniele 29:1a47b7151851 497 static void tcp_set_space(struct pico_socket_tcp *t)
daniele 29:1a47b7151851 498 {
tass 70:cd218dd180e5 499 uint32_t mtu;
tass 70:cd218dd180e5 500 int32_t space;
tass 70:cd218dd180e5 501 uint32_t shift = 0;
daniele 29:1a47b7151851 502
daniele 29:1a47b7151851 503 mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN ;
daniele 29:1a47b7151851 504 if (t->tcpq_in.max_size == 0) {
daniele 29:1a47b7151851 505 space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */
daniele 29:1a47b7151851 506 } else {
tass 70:cd218dd180e5 507 space = (int32_t)(((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss);
daniele 29:1a47b7151851 508 }
daniele 29:1a47b7151851 509 if (space < 0)
daniele 29:1a47b7151851 510 space = 0;
daniele 29:1a47b7151851 511 while(space > 0xFFFF) {
daniele 29:1a47b7151851 512 space >>= 1;
daniele 29:1a47b7151851 513 shift++;
daniele 29:1a47b7151851 514 }
daniele 29:1a47b7151851 515 if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space>>2))) {
tass 70:cd218dd180e5 516 t->wnd = (uint16_t)space;
tass 70:cd218dd180e5 517 t->wnd_scale = (uint16_t)shift;
tass 75:a9abf10138d6 518
tass 75:a9abf10138d6 519 if(t->wnd == 0) // mark the entering to zero window state
tass 75:a9abf10138d6 520 t->localZeroWindow = 1u;
tass 75:a9abf10138d6 521 else if(t->localZeroWindow)
tass 75:a9abf10138d6 522 {
tass 75:a9abf10138d6 523 t->localZeroWindow = 0u;
tass 75:a9abf10138d6 524 tcp_send_windowUpdate(t);
tass 75:a9abf10138d6 525 }
daniele 29:1a47b7151851 526 }
daniele 29:1a47b7151851 527 }
daniele 29:1a47b7151851 528
daniele 29:1a47b7151851 529 /* Return 32-bit aligned option size */
tass 70:cd218dd180e5 530 static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags)
daniele 29:1a47b7151851 531 {
tass 70:cd218dd180e5 532 uint16_t size = 0;
daniele 29:1a47b7151851 533 struct tcp_sack_block *sb = t->sacks;
daniele 29:1a47b7151851 534
daniele 29:1a47b7151851 535 if (flags & PICO_TCP_SYN) { /* Full options */
daniele 29:1a47b7151851 536 size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP;
daniele 29:1a47b7151851 537 } else {
daniele 29:1a47b7151851 538
daniele 29:1a47b7151851 539 /* Always update window scale. */
tass 73:dfb737147f6e 540 size = (uint16_t)(size + PICO_TCPOPTLEN_WS);
daniele 29:1a47b7151851 541
daniele 29:1a47b7151851 542 if (t->ts_ok)
tass 73:dfb737147f6e 543 size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP);
daniele 29:1a47b7151851 544
tass 73:dfb737147f6e 545 size= (uint16_t)(size + PICO_TCPOPTLEN_END);
daniele 29:1a47b7151851 546 }
daniele 29:1a47b7151851 547 if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) {
tass 73:dfb737147f6e 548 size = (uint16_t)(size + 2);
daniele 29:1a47b7151851 549 while(sb) {
tass 73:dfb737147f6e 550 size = (uint16_t)(size + (2 * sizeof(uint32_t)));
daniele 29:1a47b7151851 551 sb = sb->next;
daniele 29:1a47b7151851 552 }
daniele 29:1a47b7151851 553 }
tass 70:cd218dd180e5 554 size = (uint16_t)(((size + 3) >> 2) << 2);
daniele 29:1a47b7151851 555 return size;
daniele 29:1a47b7151851 556 }
daniele 29:1a47b7151851 557
tass 70:cd218dd180e5 558 uint16_t pico_tcp_overhead(struct pico_socket *s)
daniele 29:1a47b7151851 559 {
daniele 29:1a47b7151851 560 if (!s)
daniele 29:1a47b7151851 561 return 0;
daniele 29:1a47b7151851 562
tass 70:cd218dd180e5 563 return (uint16_t)(PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, (uint16_t)0)); /* hdr + Options size for data pkt */
daniele 29:1a47b7151851 564
daniele 29:1a47b7151851 565 }
daniele 29:1a47b7151851 566
daniele 29:1a47b7151851 567 static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end)
daniele 29:1a47b7151851 568 {
daniele 29:1a47b7151851 569 struct pico_frame *f;
daniele 29:1a47b7151851 570 struct pico_tree_node * index, * temp;
daniele 29:1a47b7151851 571 int cmp;
tass 68:0847e35d08a6 572 uint16_t count = 0;
daniele 29:1a47b7151851 573
daniele 29:1a47b7151851 574 pico_tree_foreach_safe(index,&t->tcpq_out.pool,temp){
daniele 29:1a47b7151851 575 f = index->keyValue;
daniele 29:1a47b7151851 576 cmp = seq_compare(SEQN(f), start);
daniele 29:1a47b7151851 577 if (cmp > 0)
daniele 29:1a47b7151851 578 goto done;
daniele 29:1a47b7151851 579
daniele 29:1a47b7151851 580 if (cmp == 0) {
daniele 29:1a47b7151851 581 cmp = seq_compare(SEQN(f) + f->payload_len, end);
daniele 29:1a47b7151851 582 if (cmp > 0) {
daniele 29:1a47b7151851 583 tcp_dbg("Invalid SACK: ignoring.\n");
daniele 29:1a47b7151851 584 }
daniele 29:1a47b7151851 585
daniele 29:1a47b7151851 586 tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end);
daniele 29:1a47b7151851 587 f->flags |= PICO_FRAME_FLAG_SACKED;
daniele 29:1a47b7151851 588 count++;
daniele 29:1a47b7151851 589
daniele 29:1a47b7151851 590 if (cmp == 0) {
daniele 29:1a47b7151851 591 /* that was last segment sacked. Job done */
daniele 29:1a47b7151851 592 goto done;
daniele 29:1a47b7151851 593 }
daniele 29:1a47b7151851 594 }
daniele 29:1a47b7151851 595 }
daniele 29:1a47b7151851 596
daniele 29:1a47b7151851 597 done:
daniele 29:1a47b7151851 598 if (t->x_mode > PICO_TCP_LOOKAHEAD) {
daniele 29:1a47b7151851 599 if (t->in_flight > (count))
daniele 29:1a47b7151851 600 t->in_flight -= (count);
daniele 29:1a47b7151851 601 else
daniele 29:1a47b7151851 602 t->in_flight = 0;
daniele 29:1a47b7151851 603 }
daniele 29:1a47b7151851 604 }
daniele 29:1a47b7151851 605
tass 70:cd218dd180e5 606 inline static void tcp_add_header(struct pico_socket_tcp *t, struct pico_frame * f)
tass 70:cd218dd180e5 607 {
tass 70:cd218dd180e5 608 struct pico_tcp_hdr * hdr = (struct pico_tcp_hdr *)f->transport_hdr;
tass 70:cd218dd180e5 609 f->timestamp = pico_tick;
tass 70:cd218dd180e5 610 tcp_add_options(t, f, 0, (uint16_t)(f->transport_len - f->payload_len - (uint16_t)PICO_SIZE_TCPHDR));
tass 70:cd218dd180e5 611 hdr->rwnd = short_be(t->wnd);
tass 70:cd218dd180e5 612 hdr->flags |= PICO_TCP_PSH;
tass 70:cd218dd180e5 613 hdr->ack = long_be(t->rcv_nxt);
tass 70:cd218dd180e5 614 hdr->crc = 0;
tass 70:cd218dd180e5 615 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
tass 70:cd218dd180e5 616 }
tass 70:cd218dd180e5 617
daniele 29:1a47b7151851 618 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
daniele 29:1a47b7151851 619 {
daniele 29:1a47b7151851 620 uint32_t start, end;
daniele 29:1a47b7151851 621 int i = 0;
daniele 29:1a47b7151851 622 if (len % 8) {
daniele 29:1a47b7151851 623 tcp_dbg("SACK: Invalid len.\n");
daniele 29:1a47b7151851 624 return;
daniele 29:1a47b7151851 625 }
daniele 29:1a47b7151851 626 while (i < len) {
daniele 29:1a47b7151851 627 start = long_from(opt + i);
daniele 29:1a47b7151851 628 i += 4;
daniele 29:1a47b7151851 629 end = long_from(opt + i);
daniele 29:1a47b7151851 630 i += 4;
daniele 29:1a47b7151851 631 tcp_process_sack(t, long_be(start), long_be(end));
daniele 29:1a47b7151851 632 }
daniele 29:1a47b7151851 633 }
daniele 29:1a47b7151851 634
daniele 29:1a47b7151851 635 static void tcp_parse_options(struct pico_frame *f)
daniele 29:1a47b7151851 636 {
daniele 29:1a47b7151851 637 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
daniele 29:1a47b7151851 638 uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR;
tass 68:0847e35d08a6 639 uint32_t i = 0;
tass 45:ca30069e49bb 640 f->timestamp = 0;
daniele 29:1a47b7151851 641 while (i < (f->transport_len - PICO_SIZE_TCPHDR)) {
daniele 29:1a47b7151851 642 uint8_t type = opt[i++];
daniele 29:1a47b7151851 643 uint8_t len;
daniele 29:1a47b7151851 644 if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1))
daniele 29:1a47b7151851 645 len = opt[i++];
daniele 29:1a47b7151851 646 else
daniele 29:1a47b7151851 647 len = 1;
daniele 29:1a47b7151851 648 if (f->payload && ((opt + i) > f->payload))
daniele 29:1a47b7151851 649 break;
tass 45:ca30069e49bb 650 tcp_dbg_options("Received option '%d', len = %d \n", type, len);
daniele 29:1a47b7151851 651 switch (type) {
daniele 29:1a47b7151851 652 case PICO_TCP_OPTION_NOOP:
daniele 29:1a47b7151851 653 case PICO_TCP_OPTION_END:
daniele 29:1a47b7151851 654 break;
daniele 29:1a47b7151851 655 case PICO_TCP_OPTION_WS:
daniele 29:1a47b7151851 656 if (len != PICO_TCPOPTLEN_WS) {
tass 45:ca30069e49bb 657 tcp_dbg_options("TCP Window scale: bad len received (%d).\n", len);
tass 73:dfb737147f6e 658 i = i + len - 2;
daniele 29:1a47b7151851 659 break;
daniele 29:1a47b7151851 660 }
daniele 29:1a47b7151851 661 t->recv_wnd_scale = opt[i++];
tass 45:ca30069e49bb 662 tcp_dbg_options("TCP Window scale: received %d\n", t->recv_wnd_scale);
daniele 29:1a47b7151851 663 break;
daniele 29:1a47b7151851 664 case PICO_TCP_OPTION_SACK_OK:
daniele 29:1a47b7151851 665 if (len != PICO_TCPOPTLEN_SACK_OK) {
tass 45:ca30069e49bb 666 tcp_dbg_options("TCP option sack: bad len received.\n");
tass 73:dfb737147f6e 667 i = i + len - 2;
daniele 29:1a47b7151851 668 break;
daniele 29:1a47b7151851 669 }
daniele 29:1a47b7151851 670 t->sack_ok = 1;
daniele 29:1a47b7151851 671 break;
daniele 29:1a47b7151851 672 case PICO_TCP_OPTION_MSS: {
daniele 29:1a47b7151851 673 uint16_t mss;
daniele 29:1a47b7151851 674 if (len != PICO_TCPOPTLEN_MSS) {
tass 45:ca30069e49bb 675 tcp_dbg_options("TCP option mss: bad len received.\n");
tass 73:dfb737147f6e 676 i = i + len - 2;
daniele 29:1a47b7151851 677 break;
daniele 29:1a47b7151851 678 }
daniele 29:1a47b7151851 679 t->mss_ok = 1;
daniele 29:1a47b7151851 680 mss = short_from(opt + i);
tass 74:c146c4e346c4 681 i += (uint32_t)sizeof(uint16_t);
daniele 29:1a47b7151851 682 if (t->mss > short_be(mss))
daniele 29:1a47b7151851 683 t->mss = short_be(mss);
daniele 29:1a47b7151851 684 break;
daniele 29:1a47b7151851 685 }
daniele 29:1a47b7151851 686 case PICO_TCP_OPTION_TIMESTAMP: {
daniele 29:1a47b7151851 687 uint32_t tsval, tsecr;
daniele 29:1a47b7151851 688 if (len != PICO_TCPOPTLEN_TIMESTAMP) {
tass 45:ca30069e49bb 689 tcp_dbg_options("TCP option timestamp: bad len received.\n");
tass 73:dfb737147f6e 690 i = i + len - 2;
daniele 29:1a47b7151851 691 break;
daniele 29:1a47b7151851 692 }
daniele 29:1a47b7151851 693 t->ts_ok = 1;
daniele 29:1a47b7151851 694 tsval = long_from(opt + i);
tass 74:c146c4e346c4 695 i += (uint32_t)sizeof(uint32_t);
daniele 29:1a47b7151851 696 tsecr = long_from(opt + i);
daniele 29:1a47b7151851 697 f->timestamp = long_be(tsecr);
tass 74:c146c4e346c4 698 i += (uint32_t)sizeof(uint32_t);
daniele 29:1a47b7151851 699 t->ts_nxt = long_be(tsval);
daniele 29:1a47b7151851 700 break;
daniele 29:1a47b7151851 701 }
daniele 29:1a47b7151851 702 case PICO_TCP_OPTION_SACK:
daniele 29:1a47b7151851 703 {
daniele 29:1a47b7151851 704 tcp_rcv_sack(t, opt + i, len - 2);
tass 73:dfb737147f6e 705 i = i + len - 2;
daniele 29:1a47b7151851 706 break;
daniele 29:1a47b7151851 707 }
daniele 29:1a47b7151851 708 default:
tass 45:ca30069e49bb 709 tcp_dbg_options("TCP: received unsupported option %u\n", type);
tass 73:dfb737147f6e 710 i = i + len - 2;
daniele 29:1a47b7151851 711 }
daniele 29:1a47b7151851 712 }
daniele 29:1a47b7151851 713 }
daniele 29:1a47b7151851 714
daniele 29:1a47b7151851 715 static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f)
daniele 29:1a47b7151851 716 {
daniele 29:1a47b7151851 717 struct pico_tcp_hdr *hdr= (struct pico_tcp_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 718 struct pico_frame *cpy;
daniele 29:1a47b7151851 719 hdr->trans.sport = ts->sock.local_port;
daniele 29:1a47b7151851 720 hdr->trans.dport = ts->sock.remote_port;
daniele 29:1a47b7151851 721 if (!hdr->seq)
daniele 29:1a47b7151851 722 hdr->seq = long_be(ts->snd_nxt);
daniele 29:1a47b7151851 723
daniele 29:1a47b7151851 724 if (ts->rcv_nxt != 0) {
daniele 29:1a47b7151851 725 if ( (ts->rcv_ackd == 0) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) {
daniele 29:1a47b7151851 726 hdr->flags |= PICO_TCP_ACK;
daniele 29:1a47b7151851 727 hdr->ack = long_be(ts->rcv_nxt);
daniele 29:1a47b7151851 728 ts->rcv_ackd = ts->rcv_nxt;
daniele 29:1a47b7151851 729 }
daniele 29:1a47b7151851 730 }
daniele 29:1a47b7151851 731
daniele 29:1a47b7151851 732 if (hdr->flags & PICO_TCP_SYN) {
daniele 29:1a47b7151851 733 ts->snd_nxt++;
daniele 29:1a47b7151851 734 }
daniele 29:1a47b7151851 735 if (f->payload_len > 0) {
daniele 29:1a47b7151851 736 hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK;
daniele 29:1a47b7151851 737 hdr->ack = long_be(ts->rcv_nxt);
daniele 29:1a47b7151851 738 ts->rcv_ackd = ts->rcv_nxt;
tass 40:c8ab0d2bba0b 739 ts->keepalive_timer_running = 2; /* XXX TODO check fix: added 1 to counter to postpone sending keepalive, ACK is in data segments */
daniele 29:1a47b7151851 740 }
daniele 29:1a47b7151851 741
daniele 29:1a47b7151851 742 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 743 hdr->rwnd = short_be(ts->wnd);
daniele 29:1a47b7151851 744 hdr->crc = 0;
daniele 29:1a47b7151851 745 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 746
daniele 29:1a47b7151851 747 /* TCP: ENQUEUE to PROTO ( Transmit ) */
daniele 29:1a47b7151851 748 cpy = pico_frame_copy(f);
tass 40:c8ab0d2bba0b 749 if ((pico_enqueue(&tcp_out, cpy) > 0)) {
tass 40:c8ab0d2bba0b 750 if (f->payload_len > 0) {
daniele 29:1a47b7151851 751 ts->in_flight++;
tass 40:c8ab0d2bba0b 752 ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */
tass 40:c8ab0d2bba0b 753 }
daniele 29:1a47b7151851 754 tcp_dbg("DBG> [tcp output] state: %02x --> local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n",
daniele 29:1a47b7151851 755 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 );
daniele 29:1a47b7151851 756 } else {
daniele 29:1a47b7151851 757 pico_frame_discard(cpy);
daniele 29:1a47b7151851 758 }
daniele 29:1a47b7151851 759 return 0;
daniele 29:1a47b7151851 760 }
daniele 29:1a47b7151851 761
daniele 29:1a47b7151851 762 //#define PICO_TCP_SUPPORT_SOCKET_STATS
daniele 29:1a47b7151851 763
daniele 29:1a47b7151851 764 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
tass 73:dfb737147f6e 765 static void sock_stats(uint32_t when, void *arg)
daniele 29:1a47b7151851 766 {
daniele 29:1a47b7151851 767 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
daniele 29:1a47b7151851 768 tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x timer: %d cwnd: %d\n",
daniele 29:1a47b7151851 769 when, t->sock.state, short_be(t->sock.local_port), short_be(t->sock.remote_port), t->tcpq_out.size, SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, t->timer_running, t->cwnd);
daniele 29:1a47b7151851 770 pico_timer_add(2000, sock_stats, t);
daniele 29:1a47b7151851 771 }
daniele 29:1a47b7151851 772 #endif
daniele 29:1a47b7151851 773
daniele 29:1a47b7151851 774 struct pico_socket *pico_tcp_open(void)
daniele 29:1a47b7151851 775 {
daniele 29:1a47b7151851 776 struct pico_socket_tcp *t = pico_zalloc(sizeof(struct pico_socket_tcp));
daniele 29:1a47b7151851 777 if (!t)
daniele 29:1a47b7151851 778 return NULL;
tass 68:0847e35d08a6 779 t->sock.timestamp = PICO_TIME_MS();
daniele 29:1a47b7151851 780 t->mss = PICO_TCP_DEFAULT_MSS;
daniele 29:1a47b7151851 781
daniele 29:1a47b7151851 782 t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF;
tass 110:0ece1bbbd36e 783 t->tcpq_hold.pool.compare = t->tcpq_out.pool.compare = segment_compare;
tass 110:0ece1bbbd36e 784 t->tcpq_in.pool.compare = input_segment_compare;
daniele 29:1a47b7151851 785 t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 786 t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 787 t->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS;
tass 111:4003cf17bc15 788 t->tcpq_in.overhead=(sizeof(struct tcp_input_segment)+sizeof(struct pico_tree_node));
tass 111:4003cf17bc15 789 t->tcpq_out.overhead=t->tcpq_hold.overhead=sizeof(struct pico_frame)+sizeof(struct pico_tree_node);
tass 40:c8ab0d2bba0b 790 /* disable Nagle by default */
tass 68:0847e35d08a6 791 //t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY);
tass 68:0847e35d08a6 792 /* Nagle is enabled by default */
tass 73:dfb737147f6e 793 t->sock.opt_flags &= (uint16_t)~(1 << PICO_SOCKET_OPT_TCPNODELAY);
daniele 29:1a47b7151851 794
daniele 29:1a47b7151851 795 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
daniele 29:1a47b7151851 796 pico_timer_add(2000, sock_stats, t);
daniele 29:1a47b7151851 797 #endif
daniele 29:1a47b7151851 798 tcp_set_space(t);
daniele 29:1a47b7151851 799
daniele 29:1a47b7151851 800 return &t->sock;
daniele 29:1a47b7151851 801 }
daniele 29:1a47b7151851 802
tass 70:cd218dd180e5 803 uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len)
daniele 29:1a47b7151851 804 {
daniele 29:1a47b7151851 805 struct pico_socket_tcp *t = TCP_SOCK(s);
tass 110:0ece1bbbd36e 806 struct tcp_input_segment *f;
daniele 29:1a47b7151851 807 uint32_t in_frame_off, in_frame_len;
tass 70:cd218dd180e5 808 uint32_t tot_rd_len = 0;
daniele 29:1a47b7151851 809
daniele 29:1a47b7151851 810 while (tot_rd_len < len) {
daniele 29:1a47b7151851 811 /* To be sure we don't have garbage at the beginning */
daniele 29:1a47b7151851 812 release_until(&t->tcpq_in, t->rcv_processed);
daniele 29:1a47b7151851 813 f = first_segment(&t->tcpq_in);
daniele 29:1a47b7151851 814 if (!f) {
daniele 29:1a47b7151851 815 tcp_set_space(t);
daniele 29:1a47b7151851 816 goto out;
daniele 29:1a47b7151851 817 }
daniele 29:1a47b7151851 818
daniele 29:1a47b7151851 819 /* Hole at the beginning of data, awaiting retransmissions. */
tass 110:0ece1bbbd36e 820 if (seq_compare(t->rcv_processed, f->seq) < 0) {
tass 110:0ece1bbbd36e 821 tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n",t->rcv_processed, f->seq, t->rcv_nxt);
daniele 29:1a47b7151851 822 goto out;
daniele 29:1a47b7151851 823 }
daniele 29:1a47b7151851 824
tass 110:0ece1bbbd36e 825 if(seq_compare(t->rcv_processed, f->seq) > 0) {
tass 110:0ece1bbbd36e 826 in_frame_off = t->rcv_processed - f->seq;
daniele 29:1a47b7151851 827 in_frame_len = f->payload_len - in_frame_off;
daniele 29:1a47b7151851 828 } else {
daniele 29:1a47b7151851 829 in_frame_off = 0;
daniele 29:1a47b7151851 830 in_frame_len = f->payload_len;
daniele 29:1a47b7151851 831 }
tass 68:0847e35d08a6 832 if ((in_frame_len + tot_rd_len) > (uint32_t)len) {
daniele 29:1a47b7151851 833 in_frame_len = len - tot_rd_len;
daniele 29:1a47b7151851 834 }
daniele 29:1a47b7151851 835
daniele 29:1a47b7151851 836 if (in_frame_len > f->payload_len - in_frame_off)
daniele 29:1a47b7151851 837 in_frame_len = f->payload_len - in_frame_off;
daniele 29:1a47b7151851 838
daniele 29:1a47b7151851 839 memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len);
daniele 29:1a47b7151851 840 tot_rd_len += in_frame_len;
daniele 29:1a47b7151851 841 t->rcv_processed += in_frame_len;
daniele 29:1a47b7151851 842
tass 68:0847e35d08a6 843 if ((in_frame_len == 0u) || (in_frame_len == (uint32_t)f->payload_len)) {
daniele 29:1a47b7151851 844 pico_discard_segment(&t->tcpq_in, f);
daniele 29:1a47b7151851 845 }
daniele 29:1a47b7151851 846 }
daniele 29:1a47b7151851 847
daniele 29:1a47b7151851 848 out:
daniele 29:1a47b7151851 849 tcp_set_space(t);
daniele 29:1a47b7151851 850 if (t->tcpq_in.size == 0) {
tass 70:cd218dd180e5 851 s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD);
daniele 29:1a47b7151851 852 }
daniele 29:1a47b7151851 853 return tot_rd_len;
daniele 29:1a47b7151851 854 }
daniele 29:1a47b7151851 855
daniele 29:1a47b7151851 856 int pico_tcp_initconn(struct pico_socket *s);
tass 128:ae39e6e81531 857 static void initconn_retry(pico_time when, void *arg)
daniele 29:1a47b7151851 858 {
daniele 29:1a47b7151851 859 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
tass 68:0847e35d08a6 860 IGNORE_PARAMETER(when);
tass 122:5b1e9de8bf7f 861 if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_SYN_SENT
tass 122:5b1e9de8bf7f 862 && !(t->sock.state & PICO_SOCKET_STATE_SHUT_LOCAL)
tass 122:5b1e9de8bf7f 863 && !(t->sock.state & PICO_SOCKET_STATE_SHUT_REMOTE)) {
daniele 29:1a47b7151851 864 if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) {
daniele 29:1a47b7151851 865 tcp_dbg("TCP> Connection timeout. \n");
daniele 29:1a47b7151851 866 if (t->sock.wakeup)
daniele 29:1a47b7151851 867 t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock);
daniele 29:1a47b7151851 868 return;
daniele 29:1a47b7151851 869 }
daniele 29:1a47b7151851 870 tcp_dbg("TCP> SYN retry %d...\n", t->backoff);
daniele 29:1a47b7151851 871 t->backoff++;
daniele 29:1a47b7151851 872 pico_tcp_initconn(&t->sock);
daniele 29:1a47b7151851 873 } else {
daniele 29:1a47b7151851 874 tcp_dbg("TCP> Connection is already established: no retry needed. good.\n");
daniele 29:1a47b7151851 875 }
daniele 29:1a47b7151851 876 }
daniele 29:1a47b7151851 877
daniele 29:1a47b7151851 878 int pico_tcp_initconn(struct pico_socket *s)
daniele 29:1a47b7151851 879 {
daniele 29:1a47b7151851 880 struct pico_socket_tcp *ts = TCP_SOCK(s);
daniele 29:1a47b7151851 881 struct pico_frame *syn;
daniele 29:1a47b7151851 882 struct pico_tcp_hdr *hdr;
tass 70:cd218dd180e5 883 uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN);
daniele 29:1a47b7151851 884
tass 70:cd218dd180e5 885 syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
daniele 29:1a47b7151851 886 if (!syn)
daniele 29:1a47b7151851 887 return -1;
daniele 29:1a47b7151851 888 hdr = (struct pico_tcp_hdr *) syn->transport_hdr;
daniele 29:1a47b7151851 889
daniele 29:1a47b7151851 890 if (!ts->snd_nxt)
daniele 29:1a47b7151851 891 ts->snd_nxt = long_be(pico_paws());
daniele 29:1a47b7151851 892 ts->snd_last = ts->snd_nxt;
daniele 29:1a47b7151851 893 ts->cwnd = PICO_TCP_IW;
daniele 29:1a47b7151851 894 ts->ssthresh = 40;
daniele 29:1a47b7151851 895 syn->sock = s;
daniele 29:1a47b7151851 896 hdr->seq = long_be(ts->snd_nxt);
tass 70:cd218dd180e5 897 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
daniele 29:1a47b7151851 898 hdr->flags = PICO_TCP_SYN;
daniele 29:1a47b7151851 899 tcp_set_space(ts);
daniele 29:1a47b7151851 900 hdr->rwnd = short_be(ts->wnd);
daniele 29:1a47b7151851 901 tcp_add_options(ts,syn, PICO_TCP_SYN, opt_len);
daniele 29:1a47b7151851 902 hdr->trans.sport = ts->sock.local_port;
daniele 29:1a47b7151851 903 hdr->trans.dport = ts->sock.remote_port;
daniele 29:1a47b7151851 904
daniele 29:1a47b7151851 905 hdr->crc = 0;
daniele 29:1a47b7151851 906 hdr->crc = short_be(pico_tcp_checksum_ipv4(syn));
daniele 29:1a47b7151851 907
daniele 29:1a47b7151851 908 /* TCP: ENQUEUE to PROTO ( SYN ) */
daniele 29:1a47b7151851 909 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);
daniele 29:1a47b7151851 910 pico_enqueue(&tcp_out, syn);
tass 37:bdf736327c71 911 pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts);
daniele 29:1a47b7151851 912 return 0;
daniele 29:1a47b7151851 913 }
daniele 29:1a47b7151851 914
daniele 29:1a47b7151851 915 static int tcp_send_synack(struct pico_socket *s)
daniele 29:1a47b7151851 916 {
daniele 29:1a47b7151851 917 struct pico_socket_tcp *ts = TCP_SOCK(s);
daniele 29:1a47b7151851 918 struct pico_frame *synack;
daniele 29:1a47b7151851 919 struct pico_tcp_hdr *hdr;
tass 70:cd218dd180e5 920 uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK);
daniele 29:1a47b7151851 921
tass 70:cd218dd180e5 922 synack = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
daniele 29:1a47b7151851 923 if (!synack)
daniele 29:1a47b7151851 924 return -1;
daniele 29:1a47b7151851 925 hdr = (struct pico_tcp_hdr *) synack->transport_hdr;
daniele 29:1a47b7151851 926
daniele 29:1a47b7151851 927 synack->sock = s;
tass 70:cd218dd180e5 928 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
daniele 29:1a47b7151851 929 hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK;
daniele 29:1a47b7151851 930 hdr->rwnd = short_be(ts->wnd);
daniele 29:1a47b7151851 931 hdr->seq = long_be(ts->snd_nxt);
daniele 29:1a47b7151851 932 ts->rcv_processed = long_be(hdr->seq);
daniele 29:1a47b7151851 933 ts->snd_last = ts->snd_nxt;
daniele 29:1a47b7151851 934 tcp_set_space(ts);
daniele 29:1a47b7151851 935 tcp_add_options(ts,synack, hdr->flags, opt_len);
daniele 29:1a47b7151851 936 synack->payload_len = 0;
daniele 29:1a47b7151851 937 synack->timestamp = pico_tick;
daniele 29:1a47b7151851 938 tcp_send(ts, synack);
daniele 29:1a47b7151851 939 pico_frame_discard(synack);
daniele 29:1a47b7151851 940 return 0;
daniele 29:1a47b7151851 941 }
daniele 29:1a47b7151851 942
daniele 29:1a47b7151851 943 static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags)
daniele 29:1a47b7151851 944 {
daniele 29:1a47b7151851 945 struct pico_frame *f;
daniele 29:1a47b7151851 946 struct pico_tcp_hdr *hdr;
tass 70:cd218dd180e5 947 uint16_t opt_len = tcp_options_size(t, flags);
tass 70:cd218dd180e5 948 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
daniele 29:1a47b7151851 949 if (!f) {
daniele 29:1a47b7151851 950 return;
daniele 29:1a47b7151851 951 }
daniele 29:1a47b7151851 952 f->sock = &t->sock;
daniele 29:1a47b7151851 953 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
tass 70:cd218dd180e5 954 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
tass 70:cd218dd180e5 955 hdr->flags = (uint8_t)flags;
daniele 29:1a47b7151851 956 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 957 tcp_set_space(t);
daniele 29:1a47b7151851 958 tcp_add_options(t,f, flags, opt_len);
daniele 29:1a47b7151851 959 hdr->trans.sport = t->sock.local_port;
daniele 29:1a47b7151851 960 hdr->trans.dport = t->sock.remote_port;
daniele 29:1a47b7151851 961 hdr->seq = long_be(t->snd_nxt);
daniele 29:1a47b7151851 962 if ((flags & PICO_TCP_ACK) != 0)
daniele 29:1a47b7151851 963 hdr->ack = long_be(t->rcv_nxt);
daniele 29:1a47b7151851 964 t->rcv_ackd = t->rcv_nxt;
daniele 29:1a47b7151851 965
daniele 29:1a47b7151851 966 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 967 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 968 hdr->crc = 0;
daniele 29:1a47b7151851 969 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 970
daniele 29:1a47b7151851 971 /* TCP: ENQUEUE to PROTO */
daniele 29:1a47b7151851 972 pico_enqueue(&tcp_out, f);
daniele 29:1a47b7151851 973 }
daniele 29:1a47b7151851 974
daniele 29:1a47b7151851 975 static void tcp_send_ack(struct pico_socket_tcp *t)
daniele 29:1a47b7151851 976 {
daniele 29:1a47b7151851 977 return tcp_send_empty(t, PICO_TCP_ACK);
daniele 29:1a47b7151851 978 }
daniele 29:1a47b7151851 979
daniele 29:1a47b7151851 980 static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr)
daniele 29:1a47b7151851 981 {
daniele 29:1a47b7151851 982 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 29:1a47b7151851 983 struct pico_frame *f;
daniele 29:1a47b7151851 984 struct pico_tcp_hdr *hdr, *hdr_rcv;
tass 70:cd218dd180e5 985 uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST);
daniele 29:1a47b7151851 986 int close;
daniele 29:1a47b7151851 987
daniele 29:1a47b7151851 988 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n");
daniele 29:1a47b7151851 989
tass 70:cd218dd180e5 990 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
daniele 29:1a47b7151851 991
daniele 29:1a47b7151851 992 if (!f) {
daniele 29:1a47b7151851 993 return -1;
daniele 29:1a47b7151851 994 }
daniele 29:1a47b7151851 995
daniele 29:1a47b7151851 996 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
daniele 29:1a47b7151851 997
daniele 29:1a47b7151851 998 f->sock = &t->sock;
daniele 29:1a47b7151851 999 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
tass 70:cd218dd180e5 1000 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
daniele 29:1a47b7151851 1001 hdr->flags = PICO_TCP_RST;
daniele 29:1a47b7151851 1002 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 1003 tcp_set_space(t);
daniele 29:1a47b7151851 1004 tcp_add_options(t,f, PICO_TCP_RST, opt_len);
daniele 29:1a47b7151851 1005 hdr->trans.sport = t->sock.local_port;
daniele 29:1a47b7151851 1006 hdr->trans.dport = t->sock.remote_port;
daniele 29:1a47b7151851 1007 hdr->seq = long_be(t->snd_nxt);
daniele 29:1a47b7151851 1008
daniele 29:1a47b7151851 1009 /* check if state is synchronized */
daniele 29:1a47b7151851 1010 if (((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) {
daniele 29:1a47b7151851 1011 /* in synchronized state: send RST with seq = ack from previous segment */
daniele 29:1a47b7151851 1012 hdr->seq = hdr_rcv->ack;
daniele 29:1a47b7151851 1013 close = 0;
daniele 29:1a47b7151851 1014 } else {
daniele 29:1a47b7151851 1015 /* non-synchronized state */
daniele 29:1a47b7151851 1016 /* go to CLOSED here to prevent timer callback to go on after timeout */
daniele 29:1a47b7151851 1017 (t->sock).state &= 0x00FFU;
daniele 29:1a47b7151851 1018 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 29:1a47b7151851 1019 close = 1;
daniele 29:1a47b7151851 1020 }
daniele 29:1a47b7151851 1021
daniele 29:1a47b7151851 1022 hdr->ack = long_be(t->rcv_nxt);
daniele 29:1a47b7151851 1023 t->rcv_ackd = t->rcv_nxt;
daniele 29:1a47b7151851 1024 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 1025 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 1026 hdr->crc = 0;
daniele 29:1a47b7151851 1027 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 1028
daniele 29:1a47b7151851 1029 /* TCP: ENQUEUE to PROTO */
daniele 29:1a47b7151851 1030 pico_enqueue(&tcp_out, f);
daniele 29:1a47b7151851 1031
daniele 29:1a47b7151851 1032 /* goto CLOSED */
daniele 29:1a47b7151851 1033 if (close) {
daniele 29:1a47b7151851 1034 (t->sock).state &= 0xFF00U;
daniele 29:1a47b7151851 1035 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 29:1a47b7151851 1036
daniele 29:1a47b7151851 1037 /* call EV_FIN wakeup before deleting */
daniele 29:1a47b7151851 1038 if ((t->sock).wakeup)
daniele 29:1a47b7151851 1039 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
daniele 29:1a47b7151851 1040
daniele 29:1a47b7151851 1041 /* delete socket */
daniele 29:1a47b7151851 1042 pico_socket_del(&t->sock);
daniele 29:1a47b7151851 1043
daniele 29:1a47b7151851 1044 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE, deleted socket\n");
daniele 29:1a47b7151851 1045 }
daniele 29:1a47b7151851 1046
daniele 29:1a47b7151851 1047 return 0;
daniele 29:1a47b7151851 1048 }
daniele 29:1a47b7151851 1049
daniele 29:1a47b7151851 1050 int pico_tcp_reply_rst(struct pico_frame *fr)
daniele 29:1a47b7151851 1051 {
daniele 29:1a47b7151851 1052 struct pico_tcp_hdr *hdr;
daniele 29:1a47b7151851 1053 struct pico_frame *f;
tass 70:cd218dd180e5 1054 uint16_t size = PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 1055
daniele 29:1a47b7151851 1056 tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n");
daniele 29:1a47b7151851 1057
daniele 29:1a47b7151851 1058 f = fr->sock->net->alloc(fr->sock->net, size);
daniele 29:1a47b7151851 1059
daniele 29:1a47b7151851 1060 /* fill in IP data from original frame */
daniele 29:1a47b7151851 1061 // TODO if IPv4
daniele 29:1a47b7151851 1062 ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr;
daniele 29:1a47b7151851 1063 ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr;
daniele 29:1a47b7151851 1064
daniele 29:1a47b7151851 1065 /* fill in TCP data from original frame */
daniele 29:1a47b7151851 1066 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport;
daniele 29:1a47b7151851 1067 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport;
daniele 29:1a47b7151851 1068 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
tass 70:cd218dd180e5 1069 hdr->len = (uint8_t)(size << 2);
daniele 29:1a47b7151851 1070 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
daniele 29:1a47b7151851 1071 hdr->rwnd = 0;
daniele 29:1a47b7151851 1072 if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) {
daniele 29:1a47b7151851 1073 hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack;
daniele 29:1a47b7151851 1074 } else {
daniele 29:1a47b7151851 1075 hdr->seq = 0U;
daniele 29:1a47b7151851 1076 }
daniele 29:1a47b7151851 1077
tass 116:34b8859c5537 1078 hdr->ack = long_be(long_be(((struct pico_tcp_hdr *)(fr->transport_hdr))->seq) + fr->payload_len);
tass 107:841ae542f96c 1079 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 1080 /* enqueue for transmission */
daniele 29:1a47b7151851 1081 pico_ipv4_frame_push(f,&(((struct pico_ipv4_hdr *)(f->net_hdr))->dst),PICO_PROTO_TCP);
daniele 29:1a47b7151851 1082
daniele 29:1a47b7151851 1083 return 0;
daniele 29:1a47b7151851 1084 }
daniele 29:1a47b7151851 1085
daniele 29:1a47b7151851 1086 static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr)
daniele 29:1a47b7151851 1087 {
daniele 29:1a47b7151851 1088 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 29:1a47b7151851 1089 struct pico_frame *f;
daniele 29:1a47b7151851 1090 struct pico_tcp_hdr *hdr, *hdr_rcv;
tass 70:cd218dd180e5 1091 uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK);
daniele 29:1a47b7151851 1092
daniele 29:1a47b7151851 1093 tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n",(s->state & PICO_SOCKET_STATE_TCP));
daniele 29:1a47b7151851 1094 if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) {
daniele 29:1a47b7151851 1095 /* XXX TODO NOTE: to prevent the parent socket from trying to send, because this socket has no knowledge of dst IP !!! */
daniele 29:1a47b7151851 1096 return pico_tcp_reply_rst(fr);
daniele 29:1a47b7151851 1097 }
daniele 29:1a47b7151851 1098
daniele 29:1a47b7151851 1099 /***************************************************************************/
daniele 29:1a47b7151851 1100 /* sending RST */
tass 70:cd218dd180e5 1101 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
daniele 29:1a47b7151851 1102
daniele 29:1a47b7151851 1103 if (!f) {
daniele 29:1a47b7151851 1104 return -1;
daniele 29:1a47b7151851 1105 }
daniele 29:1a47b7151851 1106
daniele 29:1a47b7151851 1107 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
daniele 29:1a47b7151851 1108
daniele 29:1a47b7151851 1109 f->sock = &t->sock;
daniele 29:1a47b7151851 1110 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
tass 70:cd218dd180e5 1111 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
daniele 29:1a47b7151851 1112 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
daniele 29:1a47b7151851 1113 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 1114 tcp_set_space(t);
daniele 29:1a47b7151851 1115 tcp_add_options(t,f, PICO_TCP_RST | PICO_TCP_ACK, opt_len);
daniele 29:1a47b7151851 1116 hdr->trans.sport = t->sock.local_port;
daniele 29:1a47b7151851 1117 hdr->trans.dport = t->sock.remote_port;
daniele 29:1a47b7151851 1118
daniele 29:1a47b7151851 1119 /* non-synchronized state */
daniele 29:1a47b7151851 1120 if (hdr_rcv->flags & PICO_TCP_ACK) {
daniele 29:1a47b7151851 1121 hdr->seq = hdr_rcv->ack;
daniele 29:1a47b7151851 1122 } else {
daniele 29:1a47b7151851 1123 hdr->seq = 0U;
daniele 29:1a47b7151851 1124 }
daniele 29:1a47b7151851 1125
tass 122:5b1e9de8bf7f 1126 hdr->ack = long_be(SEQN(fr) + fr->payload_len);
daniele 29:1a47b7151851 1127
daniele 29:1a47b7151851 1128 t->rcv_ackd = t->rcv_nxt;
daniele 29:1a47b7151851 1129 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 1130 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 1131 hdr->crc = 0;
daniele 29:1a47b7151851 1132 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 1133
daniele 29:1a47b7151851 1134 /* TCP: ENQUEUE to PROTO */
daniele 29:1a47b7151851 1135 pico_enqueue(&tcp_out, f);
daniele 29:1a47b7151851 1136
daniele 29:1a47b7151851 1137 /***************************************************************************/
daniele 29:1a47b7151851 1138
daniele 29:1a47b7151851 1139 tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n");
daniele 29:1a47b7151851 1140
daniele 29:1a47b7151851 1141 return 0;
daniele 29:1a47b7151851 1142 }
daniele 29:1a47b7151851 1143
daniele 29:1a47b7151851 1144 static void tcp_send_fin(struct pico_socket_tcp *t)
daniele 29:1a47b7151851 1145 {
daniele 29:1a47b7151851 1146 struct pico_frame *f;
daniele 29:1a47b7151851 1147 struct pico_tcp_hdr *hdr;
tass 70:cd218dd180e5 1148 uint16_t opt_len = tcp_options_size(t, PICO_TCP_FIN);
tass 70:cd218dd180e5 1149 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
daniele 29:1a47b7151851 1150 if (!f) {
daniele 29:1a47b7151851 1151 return;
daniele 29:1a47b7151851 1152 }
daniele 29:1a47b7151851 1153 f->sock = &t->sock;
daniele 29:1a47b7151851 1154 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
tass 70:cd218dd180e5 1155 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
daniele 29:1a47b7151851 1156 hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK;
daniele 29:1a47b7151851 1157 hdr->ack = long_be(t->rcv_nxt);
daniele 29:1a47b7151851 1158 t->rcv_ackd = t->rcv_nxt;
daniele 29:1a47b7151851 1159 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 1160 tcp_set_space(t);
daniele 29:1a47b7151851 1161 tcp_add_options(t,f, PICO_TCP_FIN, opt_len);
daniele 29:1a47b7151851 1162 hdr->trans.sport = t->sock.local_port;
daniele 29:1a47b7151851 1163 hdr->trans.dport = t->sock.remote_port;
tass 40:c8ab0d2bba0b 1164 hdr->seq = long_be(t->snd_nxt); /* XXX TODO check correct ?? --> snd_last? otherwise maybe data after FIN */
daniele 29:1a47b7151851 1165
daniele 29:1a47b7151851 1166 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 29:1a47b7151851 1167 hdr->rwnd = short_be(t->wnd);
daniele 29:1a47b7151851 1168 hdr->crc = 0;
daniele 29:1a47b7151851 1169 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 1170 //tcp_dbg("SENDING FIN...\n");
daniele 29:1a47b7151851 1171 /* TCP: ENQUEUE to PROTO ( Pure ACK ) */
daniele 29:1a47b7151851 1172 pico_enqueue(&tcp_out, f);
daniele 29:1a47b7151851 1173 t->snd_nxt++;
daniele 29:1a47b7151851 1174 }
daniele 29:1a47b7151851 1175
daniele 29:1a47b7151851 1176 static void tcp_sack_prepare(struct pico_socket_tcp *t)
daniele 29:1a47b7151851 1177 {
tass 110:0ece1bbbd36e 1178 struct tcp_input_segment *pkt;
daniele 29:1a47b7151851 1179 uint32_t left=0, right=0;
daniele 29:1a47b7151851 1180 struct tcp_sack_block *sb;
daniele 29:1a47b7151851 1181 int n = 0;
daniele 29:1a47b7151851 1182 if (t->sacks) /* previous sacks are pending */
daniele 29:1a47b7151851 1183 return;
daniele 29:1a47b7151851 1184
daniele 29:1a47b7151851 1185 pkt = first_segment(&t->tcpq_in);
daniele 29:1a47b7151851 1186 while(n < 3) {
daniele 29:1a47b7151851 1187 if (!pkt) {
daniele 29:1a47b7151851 1188 if(left) {
daniele 29:1a47b7151851 1189 sb = pico_zalloc(sizeof(struct tcp_sack_block));
daniele 29:1a47b7151851 1190 if (!sb)
daniele 29:1a47b7151851 1191 break;
daniele 29:1a47b7151851 1192 sb->left = long_be(left);
daniele 29:1a47b7151851 1193 sb->right = long_be(right);
daniele 29:1a47b7151851 1194 n++;
daniele 29:1a47b7151851 1195 sb->next = t->sacks;
daniele 29:1a47b7151851 1196 t->sacks = sb;
daniele 29:1a47b7151851 1197 left = 0;
daniele 29:1a47b7151851 1198 right = 0;
daniele 29:1a47b7151851 1199 }
daniele 29:1a47b7151851 1200 break;
daniele 29:1a47b7151851 1201 }
tass 110:0ece1bbbd36e 1202 if (pkt->seq < t->rcv_nxt) {
daniele 29:1a47b7151851 1203 pkt = next_segment(&t->tcpq_in, pkt);
daniele 29:1a47b7151851 1204 continue;
daniele 29:1a47b7151851 1205 }
daniele 29:1a47b7151851 1206 if (!left) {
tass 110:0ece1bbbd36e 1207 left = pkt->seq;
tass 110:0ece1bbbd36e 1208 right = pkt->seq + pkt->payload_len;
daniele 29:1a47b7151851 1209 pkt = next_segment(&t->tcpq_in, pkt);
daniele 29:1a47b7151851 1210 continue;
daniele 29:1a47b7151851 1211 }
tass 128:ae39e6e81531 1212 if(pkt->seq == right) {
daniele 29:1a47b7151851 1213 right += pkt->payload_len;
daniele 29:1a47b7151851 1214 pkt = next_segment(&t->tcpq_in, pkt);
daniele 29:1a47b7151851 1215 continue;
daniele 29:1a47b7151851 1216 } else {
daniele 29:1a47b7151851 1217 sb = pico_zalloc(sizeof(struct tcp_sack_block));
daniele 29:1a47b7151851 1218 if (!sb)
daniele 29:1a47b7151851 1219 break;
daniele 29:1a47b7151851 1220 sb->left = long_be(left);
daniele 29:1a47b7151851 1221 sb->right = long_be(right);
daniele 29:1a47b7151851 1222 n++;
daniele 29:1a47b7151851 1223 sb->next = t->sacks;
daniele 29:1a47b7151851 1224 t->sacks = sb;
daniele 29:1a47b7151851 1225 left = 0;
daniele 29:1a47b7151851 1226 right = 0;
daniele 29:1a47b7151851 1227 pkt = next_segment(&t->tcpq_in, pkt);
daniele 29:1a47b7151851 1228 }
daniele 29:1a47b7151851 1229 }
daniele 29:1a47b7151851 1230 }
daniele 29:1a47b7151851 1231
daniele 29:1a47b7151851 1232 static int tcp_data_in(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1233 {
daniele 29:1a47b7151851 1234 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1235 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 1236
daniele 29:1a47b7151851 1237 if (((hdr->len & 0xf0) >> 2) <= f->transport_len) {
daniele 29:1a47b7151851 1238 tcp_parse_options(f);
daniele 29:1a47b7151851 1239 f->payload = f->transport_hdr + ((hdr->len & 0xf0) >>2);
tass 70:cd218dd180e5 1240 f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >>2));
tass 45:ca30069e49bb 1241 tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
daniele 29:1a47b7151851 1242
tass 45:ca30069e49bb 1243 if (seq_compare(SEQN(f), t->rcv_nxt) <= 0) {
tass 110:0ece1bbbd36e 1244 struct tcp_input_segment *nxt;
daniele 29:1a47b7151851 1245 if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */
tass 110:0ece1bbbd36e 1246 // Create new segment and enqueue it
tass 110:0ece1bbbd36e 1247 struct tcp_input_segment * input = segment_from_frame(f);
tass 110:0ece1bbbd36e 1248 if(input && pico_enqueue_segment(&t->tcpq_in,input) <= 0)
tass 110:0ece1bbbd36e 1249 {
tass 110:0ece1bbbd36e 1250 // failed to enqueue, destroy segment
tass 110:0ece1bbbd36e 1251 pico_free(input->payload);
tass 110:0ece1bbbd36e 1252 pico_free(input);
tass 110:0ece1bbbd36e 1253 }
tass 110:0ece1bbbd36e 1254
daniele 29:1a47b7151851 1255 t->rcv_nxt = SEQN(f) + f->payload_len;
daniele 29:1a47b7151851 1256 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
daniele 29:1a47b7151851 1257 while(nxt) {
daniele 29:1a47b7151851 1258 tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt);
tass 128:ae39e6e81531 1259 t->rcv_nxt += nxt->payload_len;
daniele 29:1a47b7151851 1260 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
daniele 29:1a47b7151851 1261 }
daniele 29:1a47b7151851 1262 t->sock.ev_pending |= PICO_SOCK_EV_RD;
daniele 29:1a47b7151851 1263 } else {
tass 45:ca30069e49bb 1264 tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
daniele 29:1a47b7151851 1265 }
daniele 29:1a47b7151851 1266 } else {
daniele 29:1a47b7151851 1267 tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
daniele 29:1a47b7151851 1268 if (t->sack_ok) {
tass 128:ae39e6e81531 1269 struct tcp_input_segment * input = segment_from_frame(f);
tass 128:ae39e6e81531 1270 if(input && pico_enqueue_segment(&t->tcpq_in,input) <= 0){
tass 128:ae39e6e81531 1271 // failed to enqueue, destroy segment
tass 128:ae39e6e81531 1272 pico_free(input->payload);
tass 128:ae39e6e81531 1273 pico_free(input);
tass 128:ae39e6e81531 1274 }
tass 128:ae39e6e81531 1275 tcp_sack_prepare(t);
daniele 29:1a47b7151851 1276 }
tass 128:ae39e6e81531 1277 }
daniele 29:1a47b7151851 1278 /* In either case, ack til recv_nxt. */
daniele 29:1a47b7151851 1279 if ( ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV)) {
daniele 29:1a47b7151851 1280 //tcp_dbg("SENDACK CALLED FROM OUTSIDE tcp_synack, state %x\n",t->sock.state);
daniele 29:1a47b7151851 1281 tcp_send_ack(t);
daniele 29:1a47b7151851 1282 } else {
daniele 29:1a47b7151851 1283 //tcp_dbg("SENDACK PREVENTED IN SYNSENT STATE\n");
daniele 29:1a47b7151851 1284 }
daniele 29:1a47b7151851 1285 return 0;
daniele 29:1a47b7151851 1286 } else {
daniele 29:1a47b7151851 1287 tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len);
daniele 29:1a47b7151851 1288 return -1;
daniele 29:1a47b7151851 1289 }
daniele 29:1a47b7151851 1290 }
daniele 29:1a47b7151851 1291
tass 128:ae39e6e81531 1292 static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, pico_time * timestamp)
daniele 29:1a47b7151851 1293 {
tass 123:dd26752a4538 1294 int ret = release_all_until(&t->tcpq_out, ACKN(f),timestamp);
daniele 29:1a47b7151851 1295 if (ret > 0)
daniele 29:1a47b7151851 1296 t->sock.ev_pending |= PICO_SOCK_EV_WR;
daniele 29:1a47b7151851 1297 return ret;
daniele 29:1a47b7151851 1298 }
daniele 29:1a47b7151851 1299
tass 128:ae39e6e81531 1300 static uint16_t time_diff(pico_time a, pico_time b)
daniele 29:1a47b7151851 1301 {
daniele 29:1a47b7151851 1302 if (a >= b)
tass 73:dfb737147f6e 1303 return (uint16_t)(a - b);
daniele 29:1a47b7151851 1304 else
tass 73:dfb737147f6e 1305 return (uint16_t)(b - a);
daniele 29:1a47b7151851 1306 }
daniele 29:1a47b7151851 1307
daniele 29:1a47b7151851 1308 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt)
daniele 29:1a47b7151851 1309 {
daniele 29:1a47b7151851 1310
daniele 29:1a47b7151851 1311 uint32_t avg = t->avg_rtt;
daniele 29:1a47b7151851 1312 uint32_t rvar = t->rttvar;
daniele 29:1a47b7151851 1313 if (!avg) {
daniele 29:1a47b7151851 1314 /* This follows RFC2988
daniele 29:1a47b7151851 1315 * (2.2) When the first RTT measurement R is made, the host MUST set
daniele 29:1a47b7151851 1316 *
daniele 29:1a47b7151851 1317 * SRTT <- R
daniele 29:1a47b7151851 1318 * RTTVAR <- R/2
daniele 29:1a47b7151851 1319 * RTO <- SRTT + max (G, K*RTTVAR)
daniele 29:1a47b7151851 1320 */
daniele 29:1a47b7151851 1321 t->avg_rtt = rtt;
daniele 29:1a47b7151851 1322 t->rttvar = rtt >> 1;
daniele 29:1a47b7151851 1323 t->rto = t->avg_rtt + (t->rttvar << 4);
daniele 29:1a47b7151851 1324 } else {
tass 70:cd218dd180e5 1325 int32_t var = (int32_t)(t->avg_rtt - rtt);
daniele 29:1a47b7151851 1326 if (var < 0)
daniele 29:1a47b7151851 1327 var = 0-var;
daniele 29:1a47b7151851 1328 /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */
daniele 29:1a47b7151851 1329
daniele 29:1a47b7151851 1330 /* First, evaluate a new value for the rttvar */
daniele 29:1a47b7151851 1331 t->rttvar <<= 2;
daniele 29:1a47b7151851 1332 t->rttvar -= rvar;
tass 70:cd218dd180e5 1333 t->rttvar += (uint32_t)var;
daniele 29:1a47b7151851 1334 t->rttvar >>= 2;
daniele 29:1a47b7151851 1335
daniele 29:1a47b7151851 1336 /* Then, calculate the new avg_rtt */
daniele 29:1a47b7151851 1337 t->avg_rtt <<= 3;
daniele 29:1a47b7151851 1338 t->avg_rtt -= avg;
daniele 29:1a47b7151851 1339 t->avg_rtt += rtt;
daniele 29:1a47b7151851 1340 t->avg_rtt >>= 3;
daniele 29:1a47b7151851 1341
daniele 29:1a47b7151851 1342 /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */
daniele 29:1a47b7151851 1343 t->rto = t->avg_rtt + (t->rttvar << 2);
daniele 29:1a47b7151851 1344 }
tass 45:ca30069e49bb 1345 tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto);
daniele 29:1a47b7151851 1346 }
daniele 29:1a47b7151851 1347
daniele 29:1a47b7151851 1348 static void tcp_congestion_control(struct pico_socket_tcp *t)
daniele 29:1a47b7151851 1349 {
daniele 29:1a47b7151851 1350 if (t->x_mode > PICO_TCP_LOOKAHEAD)
daniele 29:1a47b7151851 1351 return;
daniele 29:1a47b7151851 1352 if (t->cwnd > t->tcpq_out.frames) {
daniele 29:1a47b7151851 1353 tcp_dbg("Limited by app: %d\n", t->cwnd);
tass 45:ca30069e49bb 1354 if (t->sock.wakeup)
tass 45:ca30069e49bb 1355 t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock);
daniele 29:1a47b7151851 1356 return;
daniele 29:1a47b7151851 1357 }
daniele 29:1a47b7151851 1358 tcp_dbg("Doing congestion control\n");
daniele 29:1a47b7151851 1359 if (t->cwnd < t->ssthresh) {
daniele 29:1a47b7151851 1360 t->cwnd++;
daniele 29:1a47b7151851 1361 } else {
daniele 29:1a47b7151851 1362 t->cwnd_counter++;
daniele 29:1a47b7151851 1363 if (t->cwnd_counter >= t->cwnd) {
daniele 29:1a47b7151851 1364 t->cwnd++;
daniele 29:1a47b7151851 1365 t->cwnd_counter = 0;
daniele 29:1a47b7151851 1366 }
daniele 29:1a47b7151851 1367 }
daniele 29:1a47b7151851 1368 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
daniele 29:1a47b7151851 1369 }
daniele 29:1a47b7151851 1370
tass 128:ae39e6e81531 1371 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts);
tass 128:ae39e6e81531 1372 static void tcp_retrans_timeout(pico_time val, void *sock)
daniele 29:1a47b7151851 1373 {
daniele 29:1a47b7151851 1374 struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock;
daniele 29:1a47b7151851 1375 struct pico_frame *f = NULL;
tass 128:ae39e6e81531 1376 pico_time limit = val - t->rto;
tass 32:865c101e0874 1377 if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED
tass 97:e73b01cb3147 1378 || (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && t->backoff < PICO_TCP_MAX_RETRANS)
daniele 29:1a47b7151851 1379 {
tass 68:0847e35d08a6 1380 tcp_dbg("TIMEOUT! backoff = %d\n", t->backoff);
tass 68:0847e35d08a6 1381 /* was timer cancelled? */
tass 68:0847e35d08a6 1382 if (t->timer_running == 0) {
tass 68:0847e35d08a6 1383 add_retransmission_timer(t, 0);
tass 68:0847e35d08a6 1384 return;
tass 68:0847e35d08a6 1385 }
tass 68:0847e35d08a6 1386 t->timer_running--;
daniele 29:1a47b7151851 1387
tass 68:0847e35d08a6 1388 f = first_segment(&t->tcpq_out);
tass 68:0847e35d08a6 1389 while (f) {
tass 68:0847e35d08a6 1390 if ((t->x_mode == PICO_TCP_WINDOW_FULL) ||
tass 68:0847e35d08a6 1391 ((f->timestamp != 0) && (f->timestamp <= limit))) {
tass 68:0847e35d08a6 1392 struct pico_frame *cpy;
tass 68:0847e35d08a6 1393 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);
tass 68:0847e35d08a6 1394 if ((t->x_mode != PICO_TCP_WINDOW_FULL) ) {
tass 68:0847e35d08a6 1395 t->x_mode = PICO_TCP_BLACKOUT;
tass 68:0847e35d08a6 1396 tcp_dbg("Mode: Blackout.\n");
tass 68:0847e35d08a6 1397 t->cwnd = PICO_TCP_IW;
tass 68:0847e35d08a6 1398 t->in_flight = 0;
tass 68:0847e35d08a6 1399 }
tass 70:cd218dd180e5 1400 tcp_add_header(t,f);
tass 68:0847e35d08a6 1401 /* TCP: ENQUEUE to PROTO ( retransmit )*/
tass 68:0847e35d08a6 1402 cpy = pico_frame_copy(f);
tass 68:0847e35d08a6 1403 if (pico_enqueue(&tcp_out, cpy) > 0) {
tass 68:0847e35d08a6 1404 t->backoff++;
tass 123:dd26752a4538 1405 t->snd_last_out = SEQN(cpy);
tass 68:0847e35d08a6 1406 add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
tass 68:0847e35d08a6 1407 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
tass 68:0847e35d08a6 1408 return;
tass 68:0847e35d08a6 1409 } else {
tass 68:0847e35d08a6 1410 add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
tass 68:0847e35d08a6 1411 pico_frame_discard(cpy);
tass 68:0847e35d08a6 1412 }
tass 68:0847e35d08a6 1413 }
tass 68:0847e35d08a6 1414 f = next_segment(&t->tcpq_out, f);
tass 68:0847e35d08a6 1415 }
tass 68:0847e35d08a6 1416 t->backoff = 0;
tass 68:0847e35d08a6 1417 add_retransmission_timer(t, 0);
tass 68:0847e35d08a6 1418 if (t->tcpq_out.size < t->tcpq_out.max_size)
tass 97:e73b01cb3147 1419 t->sock.ev_pending |= PICO_SOCK_EV_WR;
tass 68:0847e35d08a6 1420 return;
tass 68:0847e35d08a6 1421 }
tass 97:e73b01cb3147 1422 else if(t->backoff >= PICO_TCP_MAX_RETRANS && (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED )
tass 97:e73b01cb3147 1423 {
tass 97:e73b01cb3147 1424 // the retransmission timer, failed to get an ack for a frame, giving up on the connection
tass 97:e73b01cb3147 1425 tcp_discard_all_segments(&t->tcpq_out);
tass 97:e73b01cb3147 1426 if(t->sock.wakeup)
tass 97:e73b01cb3147 1427 t->sock.wakeup(PICO_SOCK_EV_FIN,&t->sock);
tass 97:e73b01cb3147 1428 }
daniele 29:1a47b7151851 1429 }
daniele 29:1a47b7151851 1430
tass 128:ae39e6e81531 1431 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts)
daniele 29:1a47b7151851 1432 {
daniele 29:1a47b7151851 1433 struct pico_tree_node * index;
daniele 29:1a47b7151851 1434
daniele 29:1a47b7151851 1435 if (t->timer_running > 0)
daniele 29:1a47b7151851 1436 return;
daniele 29:1a47b7151851 1437
daniele 29:1a47b7151851 1438 if (next_ts == 0) {
daniele 29:1a47b7151851 1439 struct pico_frame *f;
daniele 29:1a47b7151851 1440
daniele 29:1a47b7151851 1441 pico_tree_foreach(index,&t->tcpq_out.pool){
daniele 29:1a47b7151851 1442 f = index->keyValue;
daniele 29:1a47b7151851 1443 if (((next_ts == 0) || (f->timestamp < next_ts)) && (f->timestamp > 0)) {
daniele 29:1a47b7151851 1444 next_ts = f->timestamp;
daniele 29:1a47b7151851 1445 }
daniele 29:1a47b7151851 1446 }
daniele 29:1a47b7151851 1447 }
daniele 29:1a47b7151851 1448 if (next_ts > 0) {
daniele 29:1a47b7151851 1449 if ((next_ts + t->rto) > pico_tick) {
tass 70:cd218dd180e5 1450 t->retrans_tmr = pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t);
daniele 29:1a47b7151851 1451 } else {
tass 70:cd218dd180e5 1452 t->retrans_tmr = pico_timer_add(1, tcp_retrans_timeout, t);
daniele 29:1a47b7151851 1453 }
daniele 29:1a47b7151851 1454 t->timer_running++;
daniele 29:1a47b7151851 1455 }
daniele 29:1a47b7151851 1456 }
daniele 29:1a47b7151851 1457
daniele 29:1a47b7151851 1458 static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f)
daniele 29:1a47b7151851 1459 {
daniele 29:1a47b7151851 1460 struct pico_frame *cpy;
daniele 29:1a47b7151851 1461 if (f) {
daniele 29:1a47b7151851 1462 tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len);
tass 70:cd218dd180e5 1463 tcp_add_header(t,f);
daniele 29:1a47b7151851 1464 /* TCP: ENQUEUE to PROTO ( retransmit )*/
daniele 29:1a47b7151851 1465 cpy = pico_frame_copy(f);
daniele 29:1a47b7151851 1466 if (pico_enqueue(&tcp_out, cpy) > 0) {
daniele 29:1a47b7151851 1467 t->in_flight++;
daniele 29:1a47b7151851 1468 t->snd_last_out = SEQN(cpy);
daniele 29:1a47b7151851 1469 add_retransmission_timer(t, pico_tick + t->rto);
daniele 29:1a47b7151851 1470 } else {
daniele 29:1a47b7151851 1471 pico_frame_discard(cpy);
daniele 29:1a47b7151851 1472 }
daniele 29:1a47b7151851 1473 return(f->payload_len);
daniele 29:1a47b7151851 1474 }
daniele 29:1a47b7151851 1475 return 0;
daniele 29:1a47b7151851 1476 }
daniele 29:1a47b7151851 1477
daniele 29:1a47b7151851 1478 #ifdef TCP_ACK_DBG
daniele 29:1a47b7151851 1479 static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1480 {
daniele 29:1a47b7151851 1481 uint32_t una, nxt, ack, cur;
daniele 29:1a47b7151851 1482 struct pico_frame *una_f = NULL, *cur_f;
daniele 29:1a47b7151851 1483 struct pico_tree_node *idx;
daniele 29:1a47b7151851 1484 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1485 char info[64];
daniele 29:1a47b7151851 1486 char tmp[64];
daniele 29:1a47b7151851 1487 ack = ACKN(f);
daniele 29:1a47b7151851 1488 nxt = t->snd_nxt;
daniele 29:1a47b7151851 1489 tcp_dbg("===================================\n");
daniele 29:1a47b7151851 1490 tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack);
daniele 29:1a47b7151851 1491
daniele 29:1a47b7151851 1492 pico_tree_foreach(idx, &t->tcpq_out.pool) {
daniele 29:1a47b7151851 1493 info[0] = 0;
daniele 29:1a47b7151851 1494 cur_f = idx->keyValue;
daniele 29:1a47b7151851 1495 cur = SEQN(cur_f);
daniele 29:1a47b7151851 1496 if (!una_f) {
daniele 29:1a47b7151851 1497 una_f = cur_f;
daniele 29:1a47b7151851 1498 una = SEQN(una_f);
daniele 29:1a47b7151851 1499 }
daniele 29:1a47b7151851 1500
daniele 29:1a47b7151851 1501 if (cur == nxt) {
daniele 29:1a47b7151851 1502 strncpy(tmp, info, strlen(info));
daniele 29:1a47b7151851 1503 snprintf(info,64, "%s SND_NXT", tmp);
daniele 29:1a47b7151851 1504 }
daniele 29:1a47b7151851 1505 if (cur == ack) {
daniele 29:1a47b7151851 1506 strncpy(tmp, info, strlen(info));
daniele 29:1a47b7151851 1507 snprintf(info,64, "%s ACK", tmp);
daniele 29:1a47b7151851 1508 }
daniele 29:1a47b7151851 1509 if (cur == una) {
daniele 29:1a47b7151851 1510 strncpy(tmp, info, strlen(info));
daniele 29:1a47b7151851 1511 snprintf(info,64, "%s SND_UNA", tmp);
daniele 29:1a47b7151851 1512 }
daniele 29:1a47b7151851 1513 if (cur == t->snd_last) {
daniele 29:1a47b7151851 1514 strncpy(tmp, info, strlen(info));
daniele 29:1a47b7151851 1515 snprintf(info,64, "%s SND_LAST", tmp);
daniele 29:1a47b7151851 1516 }
daniele 29:1a47b7151851 1517 tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info);
daniele 29:1a47b7151851 1518
daniele 29:1a47b7151851 1519 }
tass 82:93915e13262a 1520 tcp_dbg("SND_NXT is %08x, snd_LAST is %08x\n", nxt, t->snd_last);
daniele 29:1a47b7151851 1521 tcp_dbg("===================================\n");
daniele 29:1a47b7151851 1522 tcp_dbg("\n\n");
daniele 29:1a47b7151851 1523 }
daniele 29:1a47b7151851 1524 #endif
daniele 29:1a47b7151851 1525
daniele 29:1a47b7151851 1526 static int tcp_ack(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1527 {
daniele 29:1a47b7151851 1528 struct pico_frame *f_new; /* use with Nagle to push to out queue */
daniele 29:1a47b7151851 1529 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1530 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 1531 uint32_t rtt = 0;
tass 68:0847e35d08a6 1532 uint16_t acked = 0;
tass 128:ae39e6e81531 1533 pico_time acked_timestamp = 0;
tass 123:dd26752a4538 1534 uint8_t restart_tmr = 0;
tass 123:dd26752a4538 1535
daniele 29:1a47b7151851 1536 struct pico_frame *una = NULL;
daniele 29:1a47b7151851 1537 if ((hdr->flags & PICO_TCP_ACK) == 0)
daniele 29:1a47b7151851 1538 return -1;
daniele 29:1a47b7151851 1539
daniele 29:1a47b7151851 1540 #ifdef TCP_ACK_DBG
daniele 29:1a47b7151851 1541 tcp_ack_dbg(s,f);
daniele 29:1a47b7151851 1542 #endif
daniele 29:1a47b7151851 1543
daniele 29:1a47b7151851 1544 tcp_parse_options(f);
daniele 29:1a47b7151851 1545 t->recv_wnd = short_be(hdr->rwnd);
daniele 29:1a47b7151851 1546
tass 123:dd26752a4538 1547 acked = (uint16_t)tcp_ack_advance_una(t, f,&acked_timestamp);
daniele 29:1a47b7151851 1548 una = first_segment(&t->tcpq_out);
daniele 29:1a47b7151851 1549
daniele 29:1a47b7151851 1550 if ((t->x_mode == PICO_TCP_BLACKOUT) ||
daniele 29:1a47b7151851 1551 ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) {
tass 123:dd26752a4538 1552 int prev_mode = t->x_mode;
daniele 29:1a47b7151851 1553 tcp_dbg("Re-entering look-ahead...\n\n\n");
daniele 29:1a47b7151851 1554 t->x_mode = PICO_TCP_LOOKAHEAD;
daniele 29:1a47b7151851 1555 t->backoff = 0;
tass 123:dd26752a4538 1556
tass 123:dd26752a4538 1557 if((prev_mode == PICO_TCP_BLACKOUT) && (acked>0) && una)
tass 123:dd26752a4538 1558 {
tass 123:dd26752a4538 1559 t->snd_nxt = SEQN(una);
tass 123:dd26752a4538 1560 // restart the retrans timer
tass 123:dd26752a4538 1561 pico_timer_cancel(t->retrans_tmr);
tass 123:dd26752a4538 1562 t->timer_running = 0;
tass 123:dd26752a4538 1563 restart_tmr = 1u;
tass 123:dd26752a4538 1564 }
daniele 29:1a47b7151851 1565 }
daniele 29:1a47b7151851 1566
daniele 29:1a47b7151851 1567 /* One should be acked. */
daniele 29:1a47b7151851 1568 if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0))
daniele 29:1a47b7151851 1569 t->in_flight--;
daniele 29:1a47b7151851 1570 if (!una || acked > 0) {
daniele 29:1a47b7151851 1571 t->x_mode = PICO_TCP_LOOKAHEAD;
daniele 29:1a47b7151851 1572 tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames);
daniele 29:1a47b7151851 1573 t->backoff = 0;
daniele 29:1a47b7151851 1574
daniele 29:1a47b7151851 1575 /* Do rtt/rttvar/rto calculations */
tass 45:ca30069e49bb 1576 /* First, try with timestamps, using the value from options */
tass 45:ca30069e49bb 1577 if(f && (f->timestamp != 0)) {
tass 45:ca30069e49bb 1578 rtt = time_diff(pico_tick, f->timestamp);
daniele 29:1a47b7151851 1579 if (rtt)
daniele 29:1a47b7151851 1580 tcp_rtt(t, rtt);
tass 123:dd26752a4538 1581 } else if(acked_timestamp) {
tass 45:ca30069e49bb 1582 /* If no timestamps are there, use conservatve estimation on the una */
tass 123:dd26752a4538 1583 rtt = time_diff(pico_tick, acked_timestamp);
tass 45:ca30069e49bb 1584 if (rtt)
tass 45:ca30069e49bb 1585 tcp_rtt(t, rtt);
daniele 29:1a47b7151851 1586 }
daniele 29:1a47b7151851 1587
daniele 29:1a47b7151851 1588 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));
daniele 29:1a47b7151851 1589 if (acked > t->in_flight) {
daniele 29:1a47b7151851 1590 tcp_dbg("WARNING: in flight < 0\n");
daniele 29:1a47b7151851 1591 t->in_flight = 0;
daniele 29:1a47b7151851 1592 } else
daniele 29:1a47b7151851 1593 t->in_flight -= (acked);
daniele 29:1a47b7151851 1594
daniele 29:1a47b7151851 1595 } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */
daniele 29:1a47b7151851 1596 ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) &&
daniele 29:1a47b7151851 1597 (f->payload_len == 0)) && /* This is a pure ack, and... */
daniele 29:1a47b7151851 1598 (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */
daniele 29:1a47b7151851 1599 {
daniele 29:1a47b7151851 1600 /* Process incoming duplicate ack. */
daniele 29:1a47b7151851 1601 if (t->x_mode < PICO_TCP_RECOVER) {
daniele 29:1a47b7151851 1602 t->x_mode++;
daniele 29:1a47b7151851 1603 tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len);
daniele 29:1a47b7151851 1604 tcp_dbg("ACK: %x - QUEUE: %x\n",ACKN(f), SEQN(first_segment(&t->tcpq_out)));
daniele 29:1a47b7151851 1605 if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */
tass 110:0ece1bbbd36e 1606 t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out));
daniele 29:1a47b7151851 1607 if (t->ssthresh > t->cwnd)
daniele 29:1a47b7151851 1608 t->ssthresh >>=2;
daniele 29:1a47b7151851 1609 else
daniele 29:1a47b7151851 1610 t->ssthresh = (t->cwnd >> 1);
daniele 29:1a47b7151851 1611 if (t->ssthresh < 2)
daniele 29:1a47b7151851 1612 t->ssthresh = 2;
daniele 29:1a47b7151851 1613 }
daniele 29:1a47b7151851 1614 } else if (t->x_mode == PICO_TCP_RECOVER) {
daniele 29:1a47b7151851 1615 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));
daniele 29:1a47b7151851 1616 if (t->in_flight <= t->cwnd) {
daniele 29:1a47b7151851 1617 struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry);
daniele 29:1a47b7151851 1618 if (!nxt)
daniele 29:1a47b7151851 1619 nxt = first_segment(&t->tcpq_out);
daniele 29:1a47b7151851 1620
daniele 29:1a47b7151851 1621 while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) {
daniele 29:1a47b7151851 1622 tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt));
daniele 29:1a47b7151851 1623 nxt = next_segment(&t->tcpq_out, nxt);
daniele 29:1a47b7151851 1624 }
daniele 29:1a47b7151851 1625
daniele 29:1a47b7151851 1626 if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0)
daniele 29:1a47b7151851 1627 nxt = NULL;
tass 110:0ece1bbbd36e 1628 if (nxt && (seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (t->recv_wnd << t->recv_wnd_scale)))
daniele 29:1a47b7151851 1629 nxt = NULL;
daniele 29:1a47b7151851 1630
daniele 29:1a47b7151851 1631 if(!nxt)
daniele 29:1a47b7151851 1632 nxt = first_segment(&t->tcpq_out);
daniele 29:1a47b7151851 1633 if (nxt) {
daniele 29:1a47b7151851 1634 tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry));
daniele 29:1a47b7151851 1635 t->snd_retry = SEQN(nxt);
daniele 29:1a47b7151851 1636 }
daniele 29:1a47b7151851 1637 }
daniele 29:1a47b7151851 1638
daniele 29:1a47b7151851 1639 if (++t->cwnd_counter > 1) {
daniele 29:1a47b7151851 1640 t->cwnd--;
daniele 29:1a47b7151851 1641 if (t->cwnd < 2)
daniele 29:1a47b7151851 1642 t->cwnd = 2;
daniele 29:1a47b7151851 1643 t->cwnd_counter = 0;
daniele 29:1a47b7151851 1644 }
daniele 29:1a47b7151851 1645 } else {
daniele 29:1a47b7151851 1646 tcp_dbg("DUPACK in mode %d \n", t->x_mode);
daniele 29:1a47b7151851 1647
daniele 29:1a47b7151851 1648 }
daniele 29:1a47b7151851 1649 } /* End case duplicate ack detection */
daniele 29:1a47b7151851 1650
daniele 29:1a47b7151851 1651 /* Do congestion control */
daniele 29:1a47b7151851 1652 tcp_congestion_control(t);
daniele 29:1a47b7151851 1653 if ((acked > 0) && t->sock.wakeup) {
daniele 29:1a47b7151851 1654 if (t->tcpq_out.size < t->tcpq_out.max_size)
daniele 29:1a47b7151851 1655 t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock));
daniele 29:1a47b7151851 1656 //t->sock.ev_pending |= PICO_SOCK_EV_WR;
daniele 29:1a47b7151851 1657 }
daniele 29:1a47b7151851 1658
daniele 29:1a47b7151851 1659 /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */
daniele 29:1a47b7151851 1660 if (IS_NAGLE_ENABLED((&(t->sock)))) {
daniele 29:1a47b7151851 1661 while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {
tass 45:ca30069e49bb 1662 tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n");
daniele 29:1a47b7151851 1663 f_new = pico_hold_segment_make(t);
daniele 29:1a47b7151851 1664 if (f_new == NULL)
daniele 29:1a47b7151851 1665 break; /* XXX corrupt !!! (or no memory) */
daniele 29:1a47b7151851 1666 if (pico_enqueue_segment(&t->tcpq_out,f_new) <= 0)
daniele 29:1a47b7151851 1667 // handle error
tass 45:ca30069e49bb 1668 tcp_dbg_nagle("TCP_ACK - NAGLE FAILED to enqueue in out\n");
daniele 29:1a47b7151851 1669 }
daniele 29:1a47b7151851 1670 }
daniele 29:1a47b7151851 1671
daniele 29:1a47b7151851 1672 /* If some space was created, put a few segments out. */
daniele 29:1a47b7151851 1673 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
daniele 29:1a47b7151851 1674 if (t->x_mode == PICO_TCP_LOOKAHEAD) {
daniele 29:1a47b7151851 1675 if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) {
tass 70:cd218dd180e5 1676 pico_tcp_output(&t->sock, (int)t->cwnd - (int)t->in_flight);
daniele 29:1a47b7151851 1677 }
daniele 29:1a47b7151851 1678 }
daniele 29:1a47b7151851 1679
tass 123:dd26752a4538 1680 if(restart_tmr)
tass 123:dd26752a4538 1681 {
tass 123:dd26752a4538 1682 add_retransmission_timer(t,pico_tick+t->rto);
tass 123:dd26752a4538 1683 }
tass 123:dd26752a4538 1684
daniele 29:1a47b7151851 1685 t->snd_old_ack = ACKN(f);
daniele 29:1a47b7151851 1686 return 0;
daniele 29:1a47b7151851 1687 }
daniele 29:1a47b7151851 1688
daniele 29:1a47b7151851 1689 static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1690 {
tass 68:0847e35d08a6 1691 tcp_dbg("RECEIVED ACK IN FIN_WAIT1\n");
tass 68:0847e35d08a6 1692 tcp_dbg("TCP> IN STATE FIN_WAIT2\n");
daniele 29:1a47b7151851 1693
daniele 29:1a47b7151851 1694 /* acking part */
daniele 29:1a47b7151851 1695 tcp_ack(s,f);
daniele 29:1a47b7151851 1696 /* update TCP state */
daniele 29:1a47b7151851 1697 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1698 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2;
daniele 29:1a47b7151851 1699
daniele 29:1a47b7151851 1700 return 0;
daniele 29:1a47b7151851 1701 }
daniele 29:1a47b7151851 1702
tass 128:ae39e6e81531 1703 static void tcp_deltcb(pico_time when, void *arg)
daniele 29:1a47b7151851 1704 {
daniele 29:1a47b7151851 1705 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
tass 68:0847e35d08a6 1706 IGNORE_PARAMETER(when);
tass 68:0847e35d08a6 1707
daniele 29:1a47b7151851 1708 if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_TIME_WAIT) {
daniele 29:1a47b7151851 1709 tcp_dbg("TCP> state: time_wait, final timer expired, going to closed state\n");
daniele 29:1a47b7151851 1710 /* update state */
daniele 29:1a47b7151851 1711 (t->sock).state &= 0x00FFU;
daniele 29:1a47b7151851 1712 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 29:1a47b7151851 1713 (t->sock).state &= 0xFF00U;
daniele 29:1a47b7151851 1714 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 29:1a47b7151851 1715 /* call EV_FIN wakeup before deleting */
daniele 29:1a47b7151851 1716 if (t->sock.wakeup) {
daniele 29:1a47b7151851 1717 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
daniele 29:1a47b7151851 1718 }
daniele 29:1a47b7151851 1719 /* delete socket */
daniele 29:1a47b7151851 1720 pico_socket_del(&t->sock);
daniele 29:1a47b7151851 1721 } else {
daniele 29:1a47b7151851 1722 tcp_dbg("TCP> trying to go to closed, wrong state\n");
daniele 29:1a47b7151851 1723 }
daniele 29:1a47b7151851 1724 }
daniele 29:1a47b7151851 1725
daniele 29:1a47b7151851 1726 static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1727 {
daniele 29:1a47b7151851 1728 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1729 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 29:1a47b7151851 1730 tcp_dbg("TCP> received fin in FIN_WAIT2\n");
daniele 29:1a47b7151851 1731 /* received FIN, increase ACK nr */
daniele 29:1a47b7151851 1732 t->rcv_nxt = long_be(hdr->seq) + 1;
daniele 29:1a47b7151851 1733 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1734 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
daniele 29:1a47b7151851 1735 /* set SHUT_REMOTE */
daniele 29:1a47b7151851 1736 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
daniele 29:1a47b7151851 1737 if (s->wakeup)
daniele 29:1a47b7151851 1738 s->wakeup(PICO_SOCK_EV_CLOSE, s);
daniele 29:1a47b7151851 1739 if (f->payload_len > 0) /* needed?? */
daniele 29:1a47b7151851 1740 tcp_data_in(s,f);
daniele 29:1a47b7151851 1741 /* send ACK */
daniele 29:1a47b7151851 1742 tcp_send_ack(t);
daniele 29:1a47b7151851 1743 /* set timer */
daniele 29:1a47b7151851 1744 pico_timer_add(200, tcp_deltcb, t);
daniele 29:1a47b7151851 1745 return 0;
daniele 29:1a47b7151851 1746 }
daniele 29:1a47b7151851 1747
daniele 29:1a47b7151851 1748 static int tcp_closewaitack(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1749 {
daniele 29:1a47b7151851 1750 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1751 tcp_dbg("TCP> received ack in CLOSING\n");
daniele 29:1a47b7151851 1752 /* acking part */
daniele 29:1a47b7151851 1753 tcp_ack(s,f);
daniele 29:1a47b7151851 1754 /* update TCP state */
daniele 29:1a47b7151851 1755 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1756 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
daniele 29:1a47b7151851 1757 /* set timer */
daniele 29:1a47b7151851 1758 pico_timer_add(200, tcp_deltcb, t);
daniele 29:1a47b7151851 1759 return 0;
daniele 29:1a47b7151851 1760 }
daniele 29:1a47b7151851 1761
daniele 29:1a47b7151851 1762 static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1763 {
tass 68:0847e35d08a6 1764 IGNORE_PARAMETER(f);
daniele 29:1a47b7151851 1765 tcp_dbg("TCP> state: last_ack, received ack, to closed\n");
daniele 29:1a47b7151851 1766 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1767 s->state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 29:1a47b7151851 1768 s->state &= 0xFF00U;
daniele 29:1a47b7151851 1769 s->state |= PICO_SOCKET_STATE_CLOSED;
daniele 29:1a47b7151851 1770 /* call socket wakeup with EV_FIN */
daniele 29:1a47b7151851 1771 if (s->wakeup)
daniele 29:1a47b7151851 1772 s->wakeup(PICO_SOCK_EV_FIN, s);
daniele 29:1a47b7151851 1773 /* delete socket */
daniele 29:1a47b7151851 1774 pico_socket_del(s);
daniele 29:1a47b7151851 1775 return 0;
daniele 29:1a47b7151851 1776 }
daniele 29:1a47b7151851 1777
daniele 29:1a47b7151851 1778 static int tcp_syn(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1779 {
tass 95:f4ca916a26fe 1780 struct pico_socket_tcp *new=NULL;
tass 95:f4ca916a26fe 1781 struct pico_tcp_hdr *hdr=NULL;
tass 95:f4ca916a26fe 1782 if(s->number_of_pending_conn >= s->max_backlog)
tass 95:f4ca916a26fe 1783 return -1;
tass 95:f4ca916a26fe 1784 new = (struct pico_socket_tcp *)pico_socket_clone(s);
tass 95:f4ca916a26fe 1785 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 29:1a47b7151851 1786 if (!new)
daniele 29:1a47b7151851 1787 return -1;
daniele 29:1a47b7151851 1788
daniele 29:1a47b7151851 1789 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
daniele 29:1a47b7151851 1790 pico_timer_add(2000, sock_stats, s);
daniele 29:1a47b7151851 1791 #endif
daniele 29:1a47b7151851 1792
daniele 29:1a47b7151851 1793 new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport;
daniele 29:1a47b7151851 1794 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 1795 if (IS_IPV4(f)) {
daniele 29:1a47b7151851 1796 new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr;
daniele 29:1a47b7151851 1797 new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr;
daniele 29:1a47b7151851 1798 }
daniele 29:1a47b7151851 1799 #endif
daniele 29:1a47b7151851 1800 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 1801 if (IS_IPV6(f)) {
tass 45:ca30069e49bb 1802 new->sock.remote_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->src;
tass 45:ca30069e49bb 1803 new->sock.local_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->dst;
daniele 29:1a47b7151851 1804 }
daniele 29:1a47b7151851 1805 #endif
daniele 29:1a47b7151851 1806
daniele 29:1a47b7151851 1807 /* Set socket limits */
daniele 29:1a47b7151851 1808 new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 1809 new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 1810 new->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS;
tass 111:4003cf17bc15 1811 new->tcpq_in.overhead=(sizeof(struct tcp_input_segment)+sizeof(struct pico_tree_node));
tass 111:4003cf17bc15 1812 new->tcpq_out.overhead=new->tcpq_hold.overhead=sizeof(struct pico_frame)+sizeof(struct pico_tree_node);
daniele 29:1a47b7151851 1813
daniele 29:1a47b7151851 1814 f->sock = &new->sock;
daniele 29:1a47b7151851 1815 tcp_parse_options(f);
daniele 29:1a47b7151851 1816 new->mss = PICO_TCP_DEFAULT_MSS;
daniele 29:1a47b7151851 1817 new->rcv_nxt = long_be(hdr->seq) + 1;
daniele 29:1a47b7151851 1818 new->snd_nxt = long_be(pico_paws());
daniele 29:1a47b7151851 1819 new->snd_last = new->snd_nxt;
daniele 29:1a47b7151851 1820 new->cwnd = PICO_TCP_IW;
daniele 29:1a47b7151851 1821 new->ssthresh = 40;
daniele 29:1a47b7151851 1822 new->recv_wnd = short_be(hdr->rwnd);
daniele 29:1a47b7151851 1823 new->jumbo = hdr->len & 0x07;
tass 95:f4ca916a26fe 1824 s->number_of_pending_conn++;
daniele 29:1a47b7151851 1825 new->sock.parent = s;
daniele 29:1a47b7151851 1826 new->sock.wakeup = s->wakeup;
daniele 29:1a47b7151851 1827 /* Initialize timestamp values */
daniele 29:1a47b7151851 1828 new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV;
daniele 29:1a47b7151851 1829 pico_socket_add(&new->sock);
daniele 29:1a47b7151851 1830 tcp_send_synack(&new->sock);
daniele 29:1a47b7151851 1831 tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt);
daniele 29:1a47b7151851 1832 return 0;
daniele 29:1a47b7151851 1833 }
daniele 29:1a47b7151851 1834
daniele 29:1a47b7151851 1835 static void tcp_set_init_point(struct pico_socket *s)
daniele 29:1a47b7151851 1836 {
daniele 29:1a47b7151851 1837 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1838 t->rcv_processed = t->rcv_nxt;
daniele 29:1a47b7151851 1839 }
daniele 29:1a47b7151851 1840
daniele 29:1a47b7151851 1841 static int tcp_synack(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1842 {
daniele 29:1a47b7151851 1843 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 29:1a47b7151851 1844 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 29:1a47b7151851 1845
daniele 29:1a47b7151851 1846 if (ACKN(f) == (1 + t->snd_nxt)) {
daniele 29:1a47b7151851 1847 t->rcv_nxt = long_be(hdr->seq);
daniele 29:1a47b7151851 1848 t->rcv_processed = t->rcv_nxt + 1;
daniele 29:1a47b7151851 1849 tcp_ack(s, f);
daniele 29:1a47b7151851 1850
daniele 29:1a47b7151851 1851 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1852 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED;
daniele 29:1a47b7151851 1853 tcp_dbg("TCP> Established. State: %x\n", s->state);
daniele 29:1a47b7151851 1854
daniele 29:1a47b7151851 1855 if (s->wakeup)
daniele 29:1a47b7151851 1856 s->wakeup(PICO_SOCK_EV_CONN, s);
daniele 29:1a47b7151851 1857 s->ev_pending |= PICO_SOCK_EV_WR;
daniele 29:1a47b7151851 1858
daniele 29:1a47b7151851 1859 t->rcv_nxt++;
daniele 29:1a47b7151851 1860 t->snd_nxt++;
daniele 29:1a47b7151851 1861 tcp_send_ack(t); /* return ACK */
daniele 29:1a47b7151851 1862
daniele 29:1a47b7151851 1863 return 0;
daniele 29:1a47b7151851 1864
daniele 29:1a47b7151851 1865 } else {
daniele 29:1a47b7151851 1866 tcp_dbg("TCP> Not established, RST sent.\n");
daniele 29:1a47b7151851 1867 tcp_nosync_rst(s,f);
daniele 29:1a47b7151851 1868 return 0;
daniele 29:1a47b7151851 1869 }
daniele 29:1a47b7151851 1870 }
daniele 29:1a47b7151851 1871
daniele 29:1a47b7151851 1872 static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1873 {
daniele 29:1a47b7151851 1874 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1875 tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f));
daniele 29:1a47b7151851 1876 if (t->snd_nxt == ACKN(f)) {
daniele 29:1a47b7151851 1877 tcp_set_init_point(s);
daniele 29:1a47b7151851 1878 tcp_ack(s, f);
daniele 29:1a47b7151851 1879 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1880 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED;
daniele 29:1a47b7151851 1881 tcp_dbg("TCP: Established. State now: %04x\n", s->state);
daniele 29:1a47b7151851 1882 if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */
daniele 29:1a47b7151851 1883 tcp_dbg("FIRST ACK - No parent found -> sending socket\n");
daniele 29:1a47b7151851 1884 s->wakeup(PICO_SOCK_EV_CONN, s);
daniele 29:1a47b7151851 1885 }
daniele 29:1a47b7151851 1886 if (s->parent && s->parent->wakeup) {
daniele 29:1a47b7151851 1887 tcp_dbg("FIRST ACK - Parent found -> listening socket\n");
daniele 29:1a47b7151851 1888 s->wakeup = s->parent->wakeup;
daniele 29:1a47b7151851 1889 s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent);
daniele 29:1a47b7151851 1890 }
daniele 29:1a47b7151851 1891 s->ev_pending |= PICO_SOCK_EV_WR;
daniele 29:1a47b7151851 1892 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
daniele 29:1a47b7151851 1893 return 0;
daniele 29:1a47b7151851 1894 } else {
daniele 29:1a47b7151851 1895 tcp_nosync_rst(s,f);
daniele 29:1a47b7151851 1896 return 0;
daniele 29:1a47b7151851 1897 }
daniele 29:1a47b7151851 1898 }
daniele 29:1a47b7151851 1899
daniele 29:1a47b7151851 1900 static int tcp_closewait(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1901 {
daniele 29:1a47b7151851 1902
daniele 29:1a47b7151851 1903 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 1904 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 29:1a47b7151851 1905
tass 32:865c101e0874 1906
daniele 29:1a47b7151851 1907 if (f->payload_len > 0)
daniele 29:1a47b7151851 1908 tcp_data_in(s,f);
daniele 29:1a47b7151851 1909 if (f->flags & PICO_TCP_ACK)
daniele 29:1a47b7151851 1910 tcp_ack(s,f);
daniele 29:1a47b7151851 1911 if (seq_compare(SEQN(f), t->rcv_nxt) == 0) {
daniele 29:1a47b7151851 1912 /* received FIN, increase ACK nr */
tass 68:0847e35d08a6 1913 t->rcv_nxt = long_be(hdr->seq) + 1;
tass 68:0847e35d08a6 1914 s->state &= 0x00FFU;
tass 68:0847e35d08a6 1915 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
tass 68:0847e35d08a6 1916 /* set SHUT_REMOTE */
daniele 29:1a47b7151851 1917 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
daniele 29:1a47b7151851 1918 tcp_dbg("TCP> Close-wait\n");
tass 32:865c101e0874 1919
daniele 29:1a47b7151851 1920 if (s->wakeup){
daniele 29:1a47b7151851 1921 if(f->payload_len>0){
tass 68:0847e35d08a6 1922 struct pico_socket_tcp *_t = (struct pico_socket_tcp *)s;
tass 68:0847e35d08a6 1923 _t->sock.ev_pending |=PICO_SOCK_EV_CLOSE;
daniele 29:1a47b7151851 1924 }else
daniele 29:1a47b7151851 1925 s->wakeup(PICO_SOCK_EV_CLOSE, s);
daniele 29:1a47b7151851 1926 }
daniele 29:1a47b7151851 1927 } else {
daniele 29:1a47b7151851 1928 tcp_send_ack(t); /* return ACK */
daniele 29:1a47b7151851 1929 }
daniele 29:1a47b7151851 1930 return 0;
daniele 29:1a47b7151851 1931 }
daniele 29:1a47b7151851 1932
daniele 29:1a47b7151851 1933 /*static int tcp_fin(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1934 {
daniele 29:1a47b7151851 1935 return 0;
daniele 29:1a47b7151851 1936 }*/
daniele 29:1a47b7151851 1937
daniele 29:1a47b7151851 1938 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1939 {
daniele 29:1a47b7151851 1940 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
tass 68:0847e35d08a6 1941 IGNORE_PARAMETER(f);
daniele 29:1a47b7151851 1942 tcp_dbg("TCP> Received FIN in FIN_WAIT1\n");
daniele 29:1a47b7151851 1943 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1944 s->state |= PICO_SOCKET_STATE_TCP_CLOSING;
daniele 29:1a47b7151851 1945 t->rcv_processed = t->rcv_nxt + 1;
daniele 29:1a47b7151851 1946 t->rcv_nxt++;
daniele 29:1a47b7151851 1947 /* send ACK */
daniele 29:1a47b7151851 1948 tcp_send_ack(t);
daniele 29:1a47b7151851 1949 return 0;
daniele 29:1a47b7151851 1950 }
daniele 29:1a47b7151851 1951
daniele 29:1a47b7151851 1952 static int tcp_finack(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1953 {
daniele 29:1a47b7151851 1954 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
tass 68:0847e35d08a6 1955 IGNORE_PARAMETER(f);
tass 68:0847e35d08a6 1956
daniele 29:1a47b7151851 1957 tcp_dbg("TCP> ENTERED finack\n");
daniele 29:1a47b7151851 1958 t->rcv_nxt++;
daniele 29:1a47b7151851 1959 /* send ACK */
daniele 29:1a47b7151851 1960 tcp_send_ack(t);
daniele 29:1a47b7151851 1961
daniele 29:1a47b7151851 1962 /* call socket wakeup with EV_FIN */
daniele 29:1a47b7151851 1963 if (s->wakeup)
daniele 29:1a47b7151851 1964 s->wakeup(PICO_SOCK_EV_FIN, s);
daniele 29:1a47b7151851 1965 s->state &= 0x00FFU;
daniele 29:1a47b7151851 1966 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
daniele 29:1a47b7151851 1967 /* set SHUT_REMOTE */
daniele 29:1a47b7151851 1968 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
daniele 29:1a47b7151851 1969 pico_timer_add(2000, tcp_deltcb, t);
daniele 29:1a47b7151851 1970
daniele 29:1a47b7151851 1971 return 0;
daniele 29:1a47b7151851 1972 }
daniele 29:1a47b7151851 1973
tass 70:cd218dd180e5 1974 static void tcp_force_closed(struct pico_socket *s)
tass 70:cd218dd180e5 1975 {
tass 70:cd218dd180e5 1976 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
tass 70:cd218dd180e5 1977 /* update state */
tass 70:cd218dd180e5 1978 (t->sock).state &= 0x00FFU;
tass 70:cd218dd180e5 1979 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
tass 70:cd218dd180e5 1980 (t->sock).state &= 0xFF00U;
tass 70:cd218dd180e5 1981 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
tass 70:cd218dd180e5 1982 }
tass 70:cd218dd180e5 1983
tass 70:cd218dd180e5 1984 static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev)
tass 70:cd218dd180e5 1985 {
tass 70:cd218dd180e5 1986 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
tass 70:cd218dd180e5 1987 if ((t->sock).wakeup)
tass 70:cd218dd180e5 1988 (t->sock).wakeup(ev, &(t->sock));
tass 70:cd218dd180e5 1989 }
tass 70:cd218dd180e5 1990
daniele 29:1a47b7151851 1991 static int tcp_rst(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 1992 {
daniele 29:1a47b7151851 1993 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 29:1a47b7151851 1994 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 29:1a47b7151851 1995
daniele 29:1a47b7151851 1996 tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n");
daniele 29:1a47b7151851 1997 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
daniele 29:1a47b7151851 1998 /* the RST is acceptable if the ACK field acknowledges the SYN */
daniele 29:1a47b7151851 1999 if ((t->snd_nxt + 1) == ACKN(f)) { /* valid, got to closed state */
tass 70:cd218dd180e5 2000 tcp_force_closed(s);
daniele 29:1a47b7151851 2001 pico_err = PICO_ERR_ECONNRESET;
tass 70:cd218dd180e5 2002 tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
tass 70:cd218dd180e5 2003 pico_socket_del(&t->sock); /* delete socket */
daniele 29:1a47b7151851 2004 } else { /* not valid, ignore */
daniele 29:1a47b7151851 2005 tcp_dbg("TCP RST> IGNORE\n");
daniele 29:1a47b7151851 2006 return 0;
daniele 29:1a47b7151851 2007 }
daniele 29:1a47b7151851 2008 } else { /* all other states */
daniele 29:1a47b7151851 2009 /* all reset (RST) segments are validated by checking their SEQ-fields,
daniele 29:1a47b7151851 2010 a reset is valid if its sequence number is in the window */
tass 70:cd218dd180e5 2011 if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((uint32_t)(short_be(hdr->rwnd)<<(t->wnd_scale)) + t->rcv_ackd))) {
daniele 29:1a47b7151851 2012 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) {
tass 106:d34698d89baf 2013 s->parent->number_of_pending_conn--;
tass 70:cd218dd180e5 2014 tcp_force_closed(s);
daniele 29:1a47b7151851 2015 pico_err = PICO_ERR_ECONNRESET;
tass 70:cd218dd180e5 2016 tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
tass 70:cd218dd180e5 2017 pico_socket_del(&t->sock); /* delete socket */
daniele 29:1a47b7151851 2018 tcp_dbg("TCP RST> SOCKET BACK TO LISTEN\n");
tass 109:f630e6230063 2019 // pico_socket_del(s);
daniele 29:1a47b7151851 2020 } else {
tass 70:cd218dd180e5 2021 tcp_force_closed(s);
tass 70:cd218dd180e5 2022 tcp_wakeup_pending(s, PICO_SOCK_EV_FIN);
daniele 29:1a47b7151851 2023 pico_err = PICO_ERR_ECONNRESET;
tass 70:cd218dd180e5 2024 tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
tass 70:cd218dd180e5 2025 pico_socket_del(&t->sock); /* delete socket */
daniele 29:1a47b7151851 2026 }
daniele 29:1a47b7151851 2027 } else { /* not valid, ignore */
daniele 29:1a47b7151851 2028 tcp_dbg("TCP RST> IGNORE\n");
daniele 29:1a47b7151851 2029 return 0;
daniele 29:1a47b7151851 2030 }
daniele 29:1a47b7151851 2031 }
daniele 29:1a47b7151851 2032
daniele 29:1a47b7151851 2033 return 0;
daniele 29:1a47b7151851 2034 }
tass 79:6d1cb906043d 2035 static int tcp_halfopencon(struct pico_socket *s, struct pico_frame *fr)
tass 79:6d1cb906043d 2036 {
tass 79:6d1cb906043d 2037 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
tass 79:6d1cb906043d 2038 IGNORE_PARAMETER(fr);
tass 79:6d1cb906043d 2039 tcp_send_ack(t);
tass 79:6d1cb906043d 2040 return 0;
tass 79:6d1cb906043d 2041 }
tass 110:0ece1bbbd36e 2042
tass 109:f630e6230063 2043 static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr)
tass 109:f630e6230063 2044 {
tass 109:f630e6230063 2045 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
tass 109:f630e6230063 2046 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (fr->transport_hdr);
tass 109:f630e6230063 2047
tass 109:f630e6230063 2048 if (seq_compare(SEQN(fr), t->rcv_nxt) == 0) {
tass 109:f630e6230063 2049 /* received FIN, increase ACK nr */
tass 109:f630e6230063 2050 t->rcv_nxt = long_be(hdr->seq) + 1;
tass 109:f630e6230063 2051 s->state &= 0x00FFU;
tass 109:f630e6230063 2052 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
tass 109:f630e6230063 2053 /* set SHUT_LOCAL */
tass 109:f630e6230063 2054 s->state |= PICO_SOCKET_STATE_SHUT_LOCAL;
tass 109:f630e6230063 2055 pico_socket_close(s);
tass 109:f630e6230063 2056 s->parent->number_of_pending_conn--;
tass 109:f630e6230063 2057 return 1;
tass 109:f630e6230063 2058 }
tass 109:f630e6230063 2059 return 0;
tass 109:f630e6230063 2060 }
tass 110:0ece1bbbd36e 2061
daniele 29:1a47b7151851 2062 struct tcp_action_entry {
daniele 29:1a47b7151851 2063 uint16_t tcpstate;
daniele 29:1a47b7151851 2064 int (*syn)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2065 int (*synack)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2066 int (*ack)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2067 int (*data)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2068 int (*fin)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2069 int (*finack)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2070 int (*rst)(struct pico_socket *s, struct pico_frame *f);
daniele 29:1a47b7151851 2071 };
daniele 29:1a47b7151851 2072
daniele 29:1a47b7151851 2073 static struct tcp_action_entry tcp_fsm[] = {
daniele 29:1a47b7151851 2074 /* State syn synack ack data fin finack rst*/
daniele 29:1a47b7151851 2075 { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
daniele 29:1a47b7151851 2076 { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
daniele 29:1a47b7151851 2077 { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, NULL },
tass 40:c8ab0d2bba0b 2078 { PICO_SOCKET_STATE_TCP_SYN_SENT, &tcp_nosync_rst, &tcp_synack, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_rst },
tass 110:0ece1bbbd36e 2079 { PICO_SOCKET_STATE_TCP_SYN_RECV, NULL, &tcp_nosync_rst, &tcp_first_ack, &tcp_data_in, &tcp_nosync_rst, &tcp_closeconn, &tcp_rst },
tass 79:6d1cb906043d 2080 { PICO_SOCKET_STATE_TCP_ESTABLISHED, &tcp_halfopencon,&tcp_ack, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst },
tass 45:ca30069e49bb 2081 { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, NULL, &tcp_ack, &tcp_ack, &tcp_send_rst, &tcp_closewait, &tcp_closewait, &tcp_rst },
tass 40:c8ab0d2bba0b 2082 { PICO_SOCKET_STATE_TCP_LAST_ACK, NULL, &tcp_ack, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst },
tass 40:c8ab0d2bba0b 2083 { PICO_SOCKET_STATE_TCP_FIN_WAIT1, NULL, &tcp_ack, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst },
tass 40:c8ab0d2bba0b 2084 { PICO_SOCKET_STATE_TCP_FIN_WAIT2, NULL, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst },
tass 40:c8ab0d2bba0b 2085 { PICO_SOCKET_STATE_TCP_CLOSING, NULL, &tcp_ack, &tcp_closewaitack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst },
tass 40:c8ab0d2bba0b 2086 { PICO_SOCKET_STATE_TCP_TIME_WAIT, NULL, &tcp_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }
daniele 29:1a47b7151851 2087 };
daniele 29:1a47b7151851 2088
daniele 29:1a47b7151851 2089 /*
daniele 29:1a47b7151851 2090 NOTE: in SYN-RECV receiving syn when cloned by default (see yellow pos-it), should send reset.
daniele 29:1a47b7151851 2091 */
daniele 29:1a47b7151851 2092
daniele 29:1a47b7151851 2093 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
daniele 29:1a47b7151851 2094 {
daniele 29:1a47b7151851 2095 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 29:1a47b7151851 2096 int ret = 0;
daniele 29:1a47b7151851 2097 uint8_t flags = hdr->flags;
daniele 29:1a47b7151851 2098 struct tcp_action_entry *action = &tcp_fsm[s->state >> 8];
daniele 29:1a47b7151851 2099
daniele 29:1a47b7151851 2100 f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2));
tass 70:cd218dd180e5 2101 f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >> 2));
daniele 29:1a47b7151851 2102
daniele 29:1a47b7151851 2103 tcp_dbg("[%lu] TCP> [tcp input] socket: %p state: %d <-- local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", pico_tick,
daniele 29:1a47b7151851 2104 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 );
daniele 29:1a47b7151851 2105
daniele 29:1a47b7151851 2106 /* This copy of the frame has the current socket as owner */
daniele 29:1a47b7151851 2107 f->sock = s;
tass 68:0847e35d08a6 2108 s->timestamp = PICO_TIME_MS();
daniele 29:1a47b7151851 2109 /* Those are not supported at this time. */
tass 73:dfb737147f6e 2110 flags &= (uint8_t)~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN);
daniele 29:1a47b7151851 2111 if (flags == PICO_TCP_SYN) {
daniele 29:1a47b7151851 2112 if (action->syn)
daniele 29:1a47b7151851 2113 action->syn(s,f);
daniele 29:1a47b7151851 2114 } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) {
daniele 29:1a47b7151851 2115 if (action->synack)
daniele 29:1a47b7151851 2116 action->synack(s,f);
daniele 29:1a47b7151851 2117 } else {
daniele 29:1a47b7151851 2118 if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) {
daniele 29:1a47b7151851 2119 if (action->ack) {
daniele 29:1a47b7151851 2120 action->ack(s,f);
daniele 29:1a47b7151851 2121 }
daniele 29:1a47b7151851 2122 }
tass 68:0847e35d08a6 2123 if (f->payload_len > 0 && !(s->state & PICO_SOCKET_STATE_CLOSED) && !TCP_IS_STATE(s,PICO_SOCKET_STATE_TCP_LISTEN))
tass 68:0847e35d08a6 2124 {
daniele 29:1a47b7151851 2125 ret = f->payload_len;
daniele 29:1a47b7151851 2126 if (action->data)
daniele 29:1a47b7151851 2127 action->data(s,f);
daniele 29:1a47b7151851 2128 }
daniele 29:1a47b7151851 2129 if (flags == PICO_TCP_FIN) {
daniele 29:1a47b7151851 2130 if (action->fin)
daniele 29:1a47b7151851 2131 action->fin(s,f);
daniele 29:1a47b7151851 2132 }
daniele 29:1a47b7151851 2133 if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) {
daniele 29:1a47b7151851 2134 if (action->finack)
daniele 29:1a47b7151851 2135 action->finack(s,f);
daniele 29:1a47b7151851 2136 }
daniele 29:1a47b7151851 2137 if (flags & PICO_TCP_RST) {
daniele 29:1a47b7151851 2138 if (action->rst)
daniele 29:1a47b7151851 2139 action->rst(s,f);
daniele 29:1a47b7151851 2140 }
daniele 29:1a47b7151851 2141 }
daniele 29:1a47b7151851 2142
daniele 29:1a47b7151851 2143 //discard:
daniele 29:1a47b7151851 2144 pico_frame_discard(f);
daniele 29:1a47b7151851 2145 return ret;
daniele 29:1a47b7151851 2146 }
daniele 29:1a47b7151851 2147
tass 128:ae39e6e81531 2148 static void tcp_send_keepalive(pico_time when, void *_t)
daniele 29:1a47b7151851 2149 {
daniele 29:1a47b7151851 2150 struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t;
tass 68:0847e35d08a6 2151 IGNORE_PARAMETER(when);
tass 82:93915e13262a 2152 tcp_dbg("Sending keepalive (%d), [State = %d]...\n", t->backoff,t->sock.state );
daniele 29:1a47b7151851 2153 if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) )
daniele 29:1a47b7151851 2154 {
tass 68:0847e35d08a6 2155 tcp_send_ack(t);
daniele 29:1a47b7151851 2156
tass 68:0847e35d08a6 2157 if (t->keepalive_timer_running > 0) {
tass 68:0847e35d08a6 2158 t->keepalive_timer_running--;
tass 68:0847e35d08a6 2159 }
daniele 29:1a47b7151851 2160
tass 68:0847e35d08a6 2161 if (t->keepalive_timer_running == 0) {
tass 68:0847e35d08a6 2162 t->keepalive_timer_running++;
tass 68:0847e35d08a6 2163 tcp_dbg("[Self] Adding timer(retransmit keepalive)\n");
tass 68:0847e35d08a6 2164 pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t);
tass 68:0847e35d08a6 2165 }
daniele 29:1a47b7151851 2166 }
daniele 29:1a47b7151851 2167 }
daniele 29:1a47b7151851 2168
tass 76:938a140caf12 2169 inline static int checkLocalClosing(struct pico_socket *s);
tass 76:938a140caf12 2170 inline static int checkRemoteClosing(struct pico_socket *s);
tass 76:938a140caf12 2171
tass 48:40fc4462265c 2172
daniele 29:1a47b7151851 2173 int pico_tcp_output(struct pico_socket *s, int loop_score)
daniele 29:1a47b7151851 2174 {
daniele 29:1a47b7151851 2175 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 29:1a47b7151851 2176 struct pico_frame *f, *una;
daniele 29:1a47b7151851 2177 struct pico_tcp_hdr *hdr;
daniele 29:1a47b7151851 2178 int sent = 0;
daniele 29:1a47b7151851 2179
daniele 29:1a47b7151851 2180 una = first_segment(&t->tcpq_out);
tass 123:dd26752a4538 2181 f = peek_segment(&t->tcpq_out, t->snd_nxt);
daniele 29:1a47b7151851 2182
daniele 29:1a47b7151851 2183 while((f) && (t->cwnd >= t->in_flight)) {
daniele 29:1a47b7151851 2184 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 29:1a47b7151851 2185 f->timestamp = pico_tick;
daniele 29:1a47b7151851 2186 tcp_add_options(t, f, hdr->flags, tcp_options_size(t, hdr->flags));
tass 70:cd218dd180e5 2187 if (seq_compare((SEQN(f) + f->payload_len), (SEQN(una) + (uint32_t)(t->recv_wnd << t->recv_wnd_scale))) > 0) {
tass 70:cd218dd180e5 2188 t->cwnd = (uint16_t)t->in_flight;
daniele 29:1a47b7151851 2189 if (t->cwnd < 1)
daniele 29:1a47b7151851 2190 t->cwnd = 1;
daniele 29:1a47b7151851 2191 if (t->x_mode != PICO_TCP_WINDOW_FULL) {
daniele 29:1a47b7151851 2192 tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n",t->recv_wnd << t->recv_wnd_scale, f->payload_len);
daniele 29:1a47b7151851 2193 tcp_dbg("In window full...\n");
tass 45:ca30069e49bb 2194 t->snd_nxt = SEQN(una); /* XXX prevent out-of-order-packets ! */ /*DLA re-enabled.*/
tass 40:c8ab0d2bba0b 2195 t->snd_retry = SEQN(una); /* XXX replace by retry pointer? */
daniele 29:1a47b7151851 2196
daniele 29:1a47b7151851 2197 /* Alternative to the line above: (better performance, but seems to lock anyway with larger buffers)
daniele 29:1a47b7151851 2198 if (seq_compare(t->snd_nxt, SEQN(una)) > 0)
daniele 29:1a47b7151851 2199 t->snd_nxt -= f->payload_len;
daniele 29:1a47b7151851 2200 */
daniele 29:1a47b7151851 2201
daniele 29:1a47b7151851 2202 t->x_mode = PICO_TCP_WINDOW_FULL;
daniele 29:1a47b7151851 2203 if (t->keepalive_timer_running == 0) {
daniele 29:1a47b7151851 2204 tcp_dbg("[Window full] Adding timer(send keepalive)\n");
daniele 29:1a47b7151851 2205 tcp_send_keepalive(0, t);
daniele 29:1a47b7151851 2206 }
daniele 29:1a47b7151851 2207 }
daniele 29:1a47b7151851 2208 break;
daniele 29:1a47b7151851 2209 }
daniele 29:1a47b7151851 2210 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);
daniele 29:1a47b7151851 2211 tcp_send(t, f);
daniele 29:1a47b7151851 2212 sent++;
daniele 29:1a47b7151851 2213 loop_score--;
daniele 29:1a47b7151851 2214 t->snd_last_out = SEQN(f);
daniele 29:1a47b7151851 2215 if (loop_score < 1)
daniele 29:1a47b7151851 2216 break;
daniele 29:1a47b7151851 2217 if (f->payload_len > 0) {
daniele 29:1a47b7151851 2218 f = next_segment(&t->tcpq_out, f);
daniele 29:1a47b7151851 2219 } else {
daniele 29:1a47b7151851 2220 f = NULL;
daniele 29:1a47b7151851 2221 }
daniele 29:1a47b7151851 2222 }
daniele 29:1a47b7151851 2223 if (sent > 0) {
daniele 29:1a47b7151851 2224 if (t->rto < PICO_TCP_RTO_MIN)
daniele 29:1a47b7151851 2225 t->rto = PICO_TCP_RTO_MIN;
tass 45:ca30069e49bb 2226 //if (s->wakeup)
tass 45:ca30069e49bb 2227 // t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock);
daniele 29:1a47b7151851 2228 add_retransmission_timer(t, pico_tick + t->rto);
daniele 29:1a47b7151851 2229 } else {
tass 45:ca30069e49bb 2230 /* Nothing to transmit. */
daniele 29:1a47b7151851 2231 }
daniele 29:1a47b7151851 2232
daniele 29:1a47b7151851 2233 if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replacled !f by tcpq check */
tass 76:938a140caf12 2234 if(!checkLocalClosing(&t->sock)) // check if local closing started and send fin
tass 76:938a140caf12 2235 {
tass 76:938a140caf12 2236 checkRemoteClosing(&t->sock); // check if remote closing started and send fin
tass 76:938a140caf12 2237 }
daniele 29:1a47b7151851 2238 }
daniele 29:1a47b7151851 2239 return loop_score;
daniele 29:1a47b7151851 2240 }
daniele 29:1a47b7151851 2241
daniele 29:1a47b7151851 2242 /* function to make new segment from hold queue with specific size (mss) */
daniele 29:1a47b7151851 2243 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t)
daniele 29:1a47b7151851 2244 {
daniele 29:1a47b7151851 2245 struct pico_frame *f_temp,*f_new;
daniele 29:1a47b7151851 2246 struct pico_socket *s = (struct pico_socket *) &t->sock;
daniele 29:1a47b7151851 2247 struct pico_tcp_hdr *hdr;
tass 70:cd218dd180e5 2248 uint16_t total_len = 0, total_payload_len = 0;
tass 70:cd218dd180e5 2249 uint16_t off = 0, test = 0;
daniele 29:1a47b7151851 2250
daniele 29:1a47b7151851 2251 off = pico_tcp_overhead(s);
daniele 29:1a47b7151851 2252
daniele 29:1a47b7151851 2253 /* init with first frame in hold queue */
daniele 29:1a47b7151851 2254 f_temp = first_segment(&t->tcpq_hold);
daniele 29:1a47b7151851 2255 total_len = f_temp->payload_len;
daniele 29:1a47b7151851 2256 f_temp = next_segment(&t->tcpq_hold, f_temp);
daniele 29:1a47b7151851 2257
daniele 29:1a47b7151851 2258 /* check till total_len <= MSS */
daniele 29:1a47b7151851 2259 while ((f_temp != NULL) && ((total_len+f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) {
tass 73:dfb737147f6e 2260 total_len = (uint16_t)(total_len + f_temp->payload_len);
daniele 29:1a47b7151851 2261 f_temp = next_segment(&t->tcpq_hold, f_temp);
daniele 29:1a47b7151851 2262 if (f_temp == NULL)
daniele 29:1a47b7151851 2263 break;
daniele 29:1a47b7151851 2264 }
daniele 29:1a47b7151851 2265 /* alloc new frame with payload size = off + total_len */
tass 70:cd218dd180e5 2266 f_new = pico_socket_frame_alloc(s, (uint16_t)(off + total_len));
daniele 29:1a47b7151851 2267 if (!f_new) {
daniele 29:1a47b7151851 2268 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 2269 return f_new;
daniele 29:1a47b7151851 2270 }
daniele 29:1a47b7151851 2271
daniele 29:1a47b7151851 2272 hdr = (struct pico_tcp_hdr *) f_new->transport_hdr;
daniele 29:1a47b7151851 2273 /* init new frame */
daniele 29:1a47b7151851 2274 f_new->payload += off;
tass 73:dfb737147f6e 2275 f_new->payload_len = (uint16_t)(f_new->payload_len - off);
daniele 29:1a47b7151851 2276 f_new->sock = s;
daniele 29:1a47b7151851 2277
daniele 29:1a47b7151851 2278 f_temp = first_segment(&t->tcpq_hold);
daniele 29:1a47b7151851 2279 hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */
daniele 29:1a47b7151851 2280 hdr->trans.sport = t->sock.local_port;
daniele 29:1a47b7151851 2281 hdr->trans.dport = t->sock.remote_port;
daniele 29:1a47b7151851 2282
daniele 29:1a47b7151851 2283 /* check till total_payload_len <= MSS */
daniele 29:1a47b7151851 2284 while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) {
daniele 29:1a47b7151851 2285 /* cpy data and discard frame */
daniele 29:1a47b7151851 2286 test++;
daniele 29:1a47b7151851 2287 memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len);
tass 73:dfb737147f6e 2288 total_payload_len = (uint16_t)(total_payload_len + f_temp->payload_len);
daniele 29:1a47b7151851 2289 pico_discard_segment(&t->tcpq_hold, f_temp);
daniele 29:1a47b7151851 2290 f_temp = first_segment(&t->tcpq_hold);
daniele 29:1a47b7151851 2291 }
daniele 29:1a47b7151851 2292
tass 70:cd218dd180e5 2293 hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2 | t->jumbo);
daniele 29:1a47b7151851 2294
tass 45:ca30069e49bb 2295 tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n",test,total_payload_len);
daniele 29:1a47b7151851 2296
daniele 29:1a47b7151851 2297 return f_new;
daniele 29:1a47b7151851 2298 }
daniele 29:1a47b7151851 2299
daniele 29:1a47b7151851 2300 /* original behavior kept when Nagle disabled;
daniele 29:1a47b7151851 2301 Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */
tass 70:cd218dd180e5 2302 int32_t pico_tcp_push(struct pico_protocol *self, struct pico_frame *f)
daniele 29:1a47b7151851 2303 {
daniele 29:1a47b7151851 2304 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 29:1a47b7151851 2305 struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock;
daniele 29:1a47b7151851 2306 struct pico_frame *f_new;
tass 70:cd218dd180e5 2307 uint32_t total_len = 0;
tass 68:0847e35d08a6 2308 IGNORE_PARAMETER(self);
tass 68:0847e35d08a6 2309 pico_err = PICO_ERR_NOERR;
daniele 29:1a47b7151851 2310 hdr->trans.sport = t->sock.local_port;
daniele 29:1a47b7151851 2311 hdr->trans.dport = t->sock.remote_port;
daniele 29:1a47b7151851 2312 hdr->seq = long_be(t->snd_last + 1);
tass 70:cd218dd180e5 2313 hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2 | t->jumbo);
daniele 29:1a47b7151851 2314
tass 68:0847e35d08a6 2315 if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size))
tass 70:cd218dd180e5 2316 t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR);
daniele 29:1a47b7151851 2317
daniele 29:1a47b7151851 2318 /***************************************************************************/
daniele 29:1a47b7151851 2319
daniele 29:1a47b7151851 2320 if (!IS_NAGLE_ENABLED((&(t->sock)))) {
daniele 29:1a47b7151851 2321 /* TCP_NODELAY enabled, original behavior */
daniele 29:1a47b7151851 2322 if (pico_enqueue_segment(&t->tcpq_out,f) > 0) {
tass 45:ca30069e49bb 2323 tcp_dbg_nagle("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t);
daniele 29:1a47b7151851 2324 t->snd_last += f->payload_len;
daniele 29:1a47b7151851 2325 return f->payload_len;
daniele 29:1a47b7151851 2326 } else {
daniele 29:1a47b7151851 2327 tcp_dbg("Enqueue failed.\n");
daniele 29:1a47b7151851 2328 return 0;
daniele 29:1a47b7151851 2329 }
daniele 29:1a47b7151851 2330 }
daniele 29:1a47b7151851 2331 /***************************************************************************/
daniele 29:1a47b7151851 2332 else {
daniele 29:1a47b7151851 2333 /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */
daniele 29:1a47b7151851 2334 if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) { /* opt 1. send frame */
daniele 29:1a47b7151851 2335 if (pico_enqueue_segment(&t->tcpq_out,f) > 0) {
tass 45:ca30069e49bb 2336 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t);
daniele 29:1a47b7151851 2337 t->snd_last += f->payload_len;
daniele 29:1a47b7151851 2338 return f->payload_len;
daniele 29:1a47b7151851 2339 } else {
daniele 29:1a47b7151851 2340 tcp_dbg("Enqueue failed.\n");
daniele 29:1a47b7151851 2341 return 0;
daniele 29:1a47b7151851 2342 }
daniele 29:1a47b7151851 2343 } else { /* opt 2. hold data back */
daniele 29:1a47b7151851 2344 total_len = f->payload_len + t->tcpq_hold.size;
daniele 29:1a47b7151851 2345 if ((total_len >= PICO_TCP_DEFAULT_MSS) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {/* TODO check mss socket */
daniele 29:1a47b7151851 2346 /* IF enough data in hold (>mss) AND space in out queue (>mss) */
daniele 29:1a47b7151851 2347 /* add current frame in hold and make new segment */
daniele 29:1a47b7151851 2348 if (pico_enqueue_segment(&t->tcpq_hold,f) > 0 ) {
tass 45:ca30069e49bb 2349 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n",t->tcpq_out.frames);
daniele 29:1a47b7151851 2350 t->snd_last += f->payload_len; /* XXX WATCH OUT */
daniele 29:1a47b7151851 2351 f_new = pico_hold_segment_make(t);
daniele 29:1a47b7151851 2352 } else {
tass 45:ca30069e49bb 2353 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 1\n");
daniele 29:1a47b7151851 2354 return 0;
daniele 29:1a47b7151851 2355 }
daniele 29:1a47b7151851 2356 /* and put new frame in out queue */
daniele 29:1a47b7151851 2357 if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out,f_new) > 0)) {
daniele 29:1a47b7151851 2358 return f_new->payload_len;
daniele 29:1a47b7151851 2359 } else {
tass 45:ca30069e49bb 2360 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n",f_new);
daniele 29:1a47b7151851 2361 return -1; /* XXX something seriously wrong */
daniele 29:1a47b7151851 2362 }
daniele 29:1a47b7151851 2363 } else {
daniele 29:1a47b7151851 2364 /* ELSE put frame in hold queue */
daniele 29:1a47b7151851 2365 if (pico_enqueue_segment(&t->tcpq_hold,f) > 0) {
tass 45:ca30069e49bb 2366 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n",t->tcpq_out.frames);
daniele 29:1a47b7151851 2367 t->snd_last += f->payload_len; /* XXX WATCH OUT */
daniele 29:1a47b7151851 2368 return f->payload_len;
daniele 29:1a47b7151851 2369 } else {
tass 68:0847e35d08a6 2370 pico_err = PICO_ERR_EAGAIN;
tass 45:ca30069e49bb 2371 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 2\n");
daniele 29:1a47b7151851 2372 return 0;
daniele 29:1a47b7151851 2373 }
daniele 29:1a47b7151851 2374 }
daniele 29:1a47b7151851 2375 }
tass 97:e73b01cb3147 2376 }
daniele 29:1a47b7151851 2377 /***************************************************************************/
daniele 29:1a47b7151851 2378 }
tass 68:0847e35d08a6 2379
tass 68:0847e35d08a6 2380 inline static void tcp_discard_all_segments(struct pico_tcp_queue *tq)
tass 68:0847e35d08a6 2381 {
tass 68:0847e35d08a6 2382 struct pico_tree_node *index = NULL, *index_safe = NULL;
tass 68:0847e35d08a6 2383 LOCK(Mutex);
tass 68:0847e35d08a6 2384 pico_tree_foreach_safe(index,&tq->pool,index_safe)
tass 68:0847e35d08a6 2385 {
tass 110:0ece1bbbd36e 2386 void *f = index->keyValue;
tass 68:0847e35d08a6 2387 if(!f)
tass 68:0847e35d08a6 2388 break;
tass 68:0847e35d08a6 2389 pico_tree_delete(&tq->pool,f);
tass 110:0ece1bbbd36e 2390 if(IS_INPUT_QUEUE(tq))
tass 110:0ece1bbbd36e 2391 {
tass 110:0ece1bbbd36e 2392 struct tcp_input_segment *inp = (struct tcp_input_segment *)f;
tass 110:0ece1bbbd36e 2393 pico_free(inp->payload);
tass 110:0ece1bbbd36e 2394 pico_free(inp);
tass 110:0ece1bbbd36e 2395 }
tass 110:0ece1bbbd36e 2396 else
tass 110:0ece1bbbd36e 2397 pico_frame_discard(f);
tass 68:0847e35d08a6 2398 }
tass 68:0847e35d08a6 2399 tq->frames = 0;
tass 68:0847e35d08a6 2400 tq->size = 0;
tass 68:0847e35d08a6 2401 UNLOCK(Mutex);
tass 68:0847e35d08a6 2402 }
tass 68:0847e35d08a6 2403
tass 68:0847e35d08a6 2404 void pico_tcp_cleanup_queues(struct pico_socket *sck)
tass 68:0847e35d08a6 2405 {
tass 68:0847e35d08a6 2406 struct pico_socket_tcp * tcp = (struct pico_socket_tcp *)sck;
tass 70:cd218dd180e5 2407 if(tcp->retrans_tmr)
tass 70:cd218dd180e5 2408 pico_timer_cancel(tcp->retrans_tmr);
tass 68:0847e35d08a6 2409 tcp_discard_all_segments(&tcp->tcpq_in);
tass 68:0847e35d08a6 2410 tcp_discard_all_segments(&tcp->tcpq_out);
tass 68:0847e35d08a6 2411 tcp_discard_all_segments(&tcp->tcpq_hold);
tass 68:0847e35d08a6 2412 }
tass 68:0847e35d08a6 2413
tass 76:938a140caf12 2414 static int checkLocalClosing(struct pico_socket *s)
tass 76:938a140caf12 2415 {
tass 76:938a140caf12 2416 struct pico_socket_tcp * t = (struct pico_socket_tcp *)s;
tass 76:938a140caf12 2417 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) {
tass 76:938a140caf12 2418 tcp_dbg("TCP> buffer empty, shutdown established ...\n");
tass 76:938a140caf12 2419 /* send fin if queue empty and in state shut local (write) */
tass 76:938a140caf12 2420 tcp_send_fin(t);
tass 76:938a140caf12 2421 /* change tcp state to FIN_WAIT1 */
tass 76:938a140caf12 2422 s->state &= 0x00FFU;
tass 76:938a140caf12 2423 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1;
tass 76:938a140caf12 2424 return 1;
tass 76:938a140caf12 2425 }
tass 76:938a140caf12 2426 return 0;
tass 76:938a140caf12 2427 }
tass 76:938a140caf12 2428
tass 76:938a140caf12 2429 static int checkRemoteClosing(struct pico_socket *s)
tass 76:938a140caf12 2430 {
tass 76:938a140caf12 2431 struct pico_socket_tcp * t = (struct pico_socket_tcp *)s;
tass 76:938a140caf12 2432 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) {
tass 76:938a140caf12 2433 /* send fin if queue empty and in state shut local (write) */
tass 76:938a140caf12 2434 tcp_send_fin(t);
tass 76:938a140caf12 2435 /* change tcp state to LAST_ACK */
tass 76:938a140caf12 2436 s->state &= 0x00FFU;
tass 76:938a140caf12 2437 s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK;
tass 76:938a140caf12 2438 tcp_dbg("TCP> STATE: LAST_ACK.\n");
tass 76:938a140caf12 2439 return 1;
tass 76:938a140caf12 2440 }
tass 76:938a140caf12 2441 return 0;
tass 76:938a140caf12 2442 }
tass 76:938a140caf12 2443
tass 76:938a140caf12 2444 void pico_tcp_notify_closing(struct pico_socket *sck)
tass 76:938a140caf12 2445 {
tass 76:938a140caf12 2446 struct pico_socket_tcp *t=(struct pico_socket_tcp *)sck;
tass 76:938a140caf12 2447 if(t->tcpq_out.frames == 0)
tass 76:938a140caf12 2448 {
tass 122:5b1e9de8bf7f 2449 // canceling retrans timer when closing
tass 122:5b1e9de8bf7f 2450 if(t->retrans_tmr)
tass 122:5b1e9de8bf7f 2451 {
tass 122:5b1e9de8bf7f 2452 pico_timer_cancel(t->retrans_tmr);
tass 122:5b1e9de8bf7f 2453 t->retrans_tmr = NULL;
tass 122:5b1e9de8bf7f 2454 }
tass 122:5b1e9de8bf7f 2455
tass 109:f630e6230063 2456 if(!checkLocalClosing(sck))
tass 109:f630e6230063 2457 checkRemoteClosing(sck);
tass 76:938a140caf12 2458 }
tass 76:938a140caf12 2459 }
tass 76:938a140caf12 2460
daniele 29:1a47b7151851 2461 #endif //PICO_SUPPORT_TCP
tass 79:6d1cb906043d 2462
tass 79:6d1cb906043d 2463