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

Fork of PicoTCP by Daniele Lacamera

Committer:
tass
Date:
Wed Jun 12 13:35:01 2013 +0000
Revision:
31:d3b2dfcc358f
Parent:
10:dd7111d4279f
updated pico_tcp and pico_socket after the mainline.

Who changed what in which revision?

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