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 07:32:47 2013 +0000
Revision:
75:a9abf10138d6
Parent:
74:c146c4e346c4
Child:
76:938a140caf12
Update for issue #33

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