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:
Wed Aug 28 14:45:01 2013 +0000
Revision:
82:93915e13262a
Parent:
48:40fc4462265c
Child:
87:d45bc027b06d
enabled debug in tcp module + changed some debug strings, added prescaler to time functions

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