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 picotcp@tass.be
Date:
Thu Jan 16 10:13:37 2014 +0100
Revision:
133:5b075f5e141a
Parent:
131:4758606c9316
Child:
137:a1c8bfa9d691
Update from master branch

Who changed what in which revision?

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