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:
Thu Sep 12 10:15:26 2013 +0000
Revision:
58:5f6eedbbbd5b
Parent:
57:5d5b84784344
Child:
63:97f481e33cb2
This should bring an end to the (github) Issue #24.

Who changed what in which revision?

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