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:
Fri Feb 07 11:21:12 2014 +0100
Revision:
137:a1c8bfa9d691
Parent:
133:5b075f5e141a
Child:
149:5f4cb161cec3
Update from masterbranch

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