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:
daniele
Date:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

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