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:
daniele
Date:
Sun Jun 16 20:19:44 2013 +0000
Revision:
29:1a47b7151851
Child:
32:865c101e0874
Updated from masterbranch;

Who changed what in which revision?

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