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 14:14:17 2015 +0200
Revision:
154:6c0e92a80c4a
Parent:
152:a3d286bf94e5
To latest development.

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