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