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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
daniele
Date:
Thu Jun 06 00:38:54 2013 +0000
Revision:
10:dd7111d4279f
Child:
31:d3b2dfcc358f
Update from masterbranch;

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