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 Nov 21 09:48:05 2013 +0000
Revision:
122:5b1e9de8bf7f
Parent:
117:b853bfe76990
Child:
123:dd26752a4538
Update from masterbranch.

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