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

Fork of PicoTCP by Daniele Lacamera

Committer:
tass
Date:
Fri Aug 02 07:28:05 2013 +0000
Revision:
49:40fc4462265c
Parent:
45:ca30069e49bb
Fixes for issues #8,#9,#10 from github.

Who changed what in which revision?

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