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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
Fri May 31 11:34:20 2013 +0000
Revision:
6:55b47464d5bc
Integrated mbed friendly sockets;

Who changed what in which revision?

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