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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
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