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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
Wed Jun 26 06:27:32 2013 +0000
Revision:
36:afa3ab5e06b3
Parent:
32:865c101e0874
Child:
37:bdf736327c71
Fixed send flag, that was causing assertion failure.

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