Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
Mon Sep 28 13:16:18 2015 +0200
Revision:
152:a3d286bf94e5
Parent:
149:5f4cb161cec3
Child:
154:6c0e92a80c4a
Mercurial: latest development version of PicoTCP

Who changed what in which revision?

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