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:
Tue Oct 15 11:43:13 2013 +0000
Revision:
95:f4ca916a26fe
Parent:
93:e7a58195bfb7
Child:
97:e73b01cb3147
Issue #36: SYN flood protection implementation

Who changed what in which revision?

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