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 12 13:35:01 2013 +0000
Revision:
31:d3b2dfcc358f
Parent:
10:dd7111d4279f
updated pico_tcp and pico_socket after the mainline.

Who changed what in which revision?

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