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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
Tue Oct 01 06:13:42 2013 +0000
Revision:
74:c146c4e346c4
Parent:
73:dfb737147f6e
Child:
75:a9abf10138d6
Complete Issue #17

Who changed what in which revision?

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