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