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

Fork of PicoTCP by Daniele Lacamera

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