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

Fork of PicoTCP by Daniele Lacamera

Committer:
tass
Date:
Fri May 17 12:09:59 2013 +0000
Revision:
1:cfe8984a32b4
Parent:
libraries/picotcp/modules/pico_tcp.c@0:d7f2341ab245
Update for smaller SOCKETQ

Who changed what in which revision?

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