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:
Thu Sep 19 13:26:14 2013 +0000
Revision:
68:0847e35d08a6
Child:
70:cd218dd180e5
Imported from masterbranch, again

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