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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
Tue Jul 23 13:22:24 2013 +0000
Revision:
45:ca30069e49bb
Parent:
40:c8ab0d2bba0b
Child:
48:40fc4462265c
Updated pico_tcp and pico_frame from masterbranch.

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