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:
Thu Sep 19 12:38:53 2013 +0000
Revision:
63:97f481e33cb2
Parent:
58:5f6eedbbbd5b
Update from the master branch

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