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
pico_tcp.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 . 00006 00007 Authors: Daniele Lacamera, Philippe Mariman 00008 *********************************************************************/ 00009 00010 #include "pico_tcp.h" 00011 #include "pico_config.h" 00012 #include "pico_eth.h" 00013 #include "pico_socket.h" 00014 #include "pico_stack.h" 00015 #include "pico_socket.h" 00016 #include "pico_queue.h" 00017 #include "pico_tree.h" 00018 00019 #define TCP_IS_STATE(s, st) ((s->state & PICO_SOCKET_STATE_TCP) == st) 00020 #define TCP_SOCK(s) ((struct pico_socket_tcp *)s) 00021 #define SEQN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->seq)) : 0) 00022 #define ACKN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->ack)) : 0) 00023 00024 #define TCP_TIME (pico_time)(PICO_TIME_MS()) 00025 00026 #define PICO_TCP_RTO_MIN (70) 00027 #define PICO_TCP_RTO_MAX (120000) 00028 #define PICO_TCP_IW 2 00029 #define PICO_TCP_SYN_TO 2000u 00030 #define PICO_TCP_ZOMBIE_TO 30000 00031 00032 #define PICO_TCP_MAX_RETRANS 10 00033 #define PICO_TCP_MAX_CONNECT_RETRIES 3 00034 00035 #define PICO_TCP_LOOKAHEAD 0x00 00036 #define PICO_TCP_FIRST_DUPACK 0x01 00037 #define PICO_TCP_SECOND_DUPACK 0x02 00038 #define PICO_TCP_RECOVER 0x03 00039 #define PICO_TCP_BLACKOUT 0x04 00040 #define PICO_TCP_UNREACHABLE 0x05 00041 #define PICO_TCP_WINDOW_FULL 0x06 00042 00043 #define ONE_GIGABYTE ((uint32_t)(1024UL * 1024UL * 1024UL)) 00044 00045 /* check if the Nagle algorithm is enabled on the socket */ 00046 #define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1u << PICO_SOCKET_OPT_TCPNODELAY))))) 00047 /* check if tcp connection is "idle" according to Nagle (RFC 896) */ 00048 #define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0)) 00049 /* check if the hold queue contains data (again Nagle) */ 00050 #define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0) 00051 00052 #define IS_INPUT_QUEUE(q) (q->pool.compare == input_segment_compare) 00053 #define TCP_INPUT_OVERHEAD (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node)) 00054 00055 00056 #ifdef PICO_SUPPORT_TCP 00057 #define tcp_dbg_nagle(...) do {} while(0) 00058 #define tcp_dbg_options(...) do {} while(0) 00059 00060 00061 #define tcp_dbg(...) do {} while(0) 00062 /* #define tcp_dbg dbg */ 00063 00064 #ifdef PICO_SUPPORT_MUTEX 00065 static void *Mutex = NULL; 00066 #endif 00067 00068 00069 00070 /* Input segment, used to keep only needed data, not the full frame */ 00071 struct tcp_input_segment 00072 { 00073 uint32_t seq; 00074 /* Pointer to payload */ 00075 unsigned char *payload; 00076 uint16_t payload_len; 00077 }; 00078 00079 /* Function to compare input segments */ 00080 static int input_segment_compare(void *ka, void *kb) 00081 { 00082 struct tcp_input_segment *a = ka, *b = kb; 00083 return pico_seq_compare(a->seq, b->seq); 00084 } 00085 00086 static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) 00087 { 00088 struct tcp_input_segment *seg = PICO_ZALLOC(sizeof(struct tcp_input_segment)); 00089 if ((!seg) || (!f->payload_len)) 00090 return NULL; 00091 00092 seg->payload = PICO_ZALLOC(f->payload_len); 00093 if(!seg->payload) 00094 { 00095 PICO_FREE(seg); 00096 return NULL; 00097 } 00098 00099 seg->seq = SEQN(f); 00100 seg->payload_len = f->payload_len; 00101 memcpy(seg->payload, f->payload, seg->payload_len); 00102 return seg; 00103 } 00104 00105 static int segment_compare(void *ka, void *kb) 00106 { 00107 struct pico_frame *a = ka, *b = kb; 00108 return pico_seq_compare(SEQN(a), SEQN(b)); 00109 } 00110 00111 struct pico_tcp_queue 00112 { 00113 struct pico_tree pool; 00114 uint32_t max_size; 00115 uint32_t size; 00116 uint32_t frames; 00117 }; 00118 00119 static void tcp_discard_all_segments(struct pico_tcp_queue *tq); 00120 static void *peek_segment(struct pico_tcp_queue *tq, uint32_t seq) 00121 { 00122 if(!IS_INPUT_QUEUE(tq)) 00123 { 00124 struct pico_tcp_hdr H; 00125 struct pico_frame f = { 00126 0 00127 }; 00128 f.transport_hdr = (uint8_t *) (&H); 00129 H.seq = long_be(seq); 00130 00131 return pico_tree_findKey(&tq->pool, &f); 00132 } 00133 else 00134 { 00135 struct tcp_input_segment dummy = { 0 }; 00136 dummy.seq = seq; 00137 00138 return pico_tree_findKey(&tq->pool, &dummy); 00139 } 00140 00141 } 00142 00143 static void *first_segment(struct pico_tcp_queue *tq) 00144 { 00145 return pico_tree_first(&tq->pool); 00146 } 00147 00148 static void *next_segment(struct pico_tcp_queue *tq, void *cur) 00149 { 00150 if (!cur) 00151 return NULL; 00152 00153 if(IS_INPUT_QUEUE(tq)) 00154 { 00155 return peek_segment(tq, ((struct tcp_input_segment *)cur)->seq + ((struct tcp_input_segment *)cur)->payload_len); 00156 } 00157 else 00158 { 00159 return peek_segment(tq, SEQN((struct pico_frame *)cur) + ((struct pico_frame *)cur)->payload_len); 00160 } 00161 } 00162 00163 static uint16_t enqueue_segment_len(struct pico_tcp_queue *tq, void *f) 00164 { 00165 if (IS_INPUT_QUEUE(tq)) { 00166 return ((struct tcp_input_segment *)f)->payload_len; 00167 } else { 00168 return (uint16_t)(((struct pico_frame *)f)->buffer_len); 00169 } 00170 } 00171 00172 00173 static int32_t do_enqueue_segment(struct pico_tcp_queue *tq, void *f, uint16_t payload_len) 00174 { 00175 int32_t ret = -1; 00176 PICOTCP_MUTEX_LOCK(Mutex); 00177 if ((tq->size + payload_len) > tq->max_size) 00178 { 00179 ret = 0; 00180 goto out; 00181 } 00182 00183 if (pico_tree_insert(&tq->pool, f) != 0) 00184 { 00185 ret = 0; 00186 goto out; 00187 } 00188 00189 tq->size += (uint16_t)payload_len; 00190 if (payload_len > 0) 00191 tq->frames++; 00192 00193 ret = (int32_t)payload_len; 00194 00195 out: 00196 PICOTCP_MUTEX_UNLOCK(Mutex); 00197 return ret; 00198 } 00199 00200 static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, void *f) 00201 { 00202 uint16_t payload_len; 00203 00204 if (!f) 00205 return -1; 00206 00207 payload_len = enqueue_segment_len(tq, f); 00208 00209 00210 if (payload_len == 0) { 00211 tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n"); 00212 return -1; 00213 } 00214 00215 return do_enqueue_segment(tq, f, payload_len); 00216 } 00217 00218 static void pico_discard_segment(struct pico_tcp_queue *tq, void *f) 00219 { 00220 void *f1; 00221 uint16_t payload_len = (uint16_t)((IS_INPUT_QUEUE(tq)) ? 00222 (((struct tcp_input_segment *)f)->payload_len) : 00223 (((struct pico_frame *)f)->buffer_len)); 00224 PICOTCP_MUTEX_LOCK(Mutex); 00225 f1 = pico_tree_delete(&tq->pool, f); 00226 if (f1) { 00227 tq->size -= (uint16_t)payload_len; 00228 if (payload_len > 0) 00229 tq->frames--; 00230 } 00231 00232 if(f1 && IS_INPUT_QUEUE(tq)) 00233 { 00234 struct tcp_input_segment *inp = f1; 00235 PICO_FREE(inp->payload); 00236 PICO_FREE(inp); 00237 } 00238 else 00239 pico_frame_discard(f); 00240 00241 PICOTCP_MUTEX_UNLOCK(Mutex); 00242 } 00243 00244 /* Structure for TCP socket */ 00245 struct tcp_sack_block { 00246 uint32_t left; 00247 uint32_t right; 00248 struct tcp_sack_block *next; 00249 }; 00250 00251 struct pico_socket_tcp { 00252 struct pico_socket sock; 00253 00254 /* Tree/queues */ 00255 struct pico_tcp_queue tcpq_in; /* updated the input queue to hold input segments not the full frame. */ 00256 struct pico_tcp_queue tcpq_out; 00257 struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */ 00258 00259 /* tcp_output */ 00260 uint32_t snd_nxt; 00261 uint32_t snd_last; 00262 uint32_t snd_old_ack; 00263 uint32_t snd_retry; 00264 uint32_t snd_last_out; 00265 00266 /* congestion control */ 00267 uint32_t avg_rtt; 00268 uint32_t rttvar; 00269 uint32_t rto; 00270 uint32_t in_flight; 00271 struct pico_timer *retrans_tmr; 00272 pico_time retrans_tmr_due; 00273 uint16_t cwnd_counter; 00274 uint16_t cwnd; 00275 uint16_t ssthresh; 00276 uint16_t recv_wnd; 00277 uint16_t recv_wnd_scale; 00278 00279 /* tcp_input */ 00280 uint32_t rcv_nxt; 00281 uint32_t rcv_ackd; 00282 uint32_t rcv_processed; 00283 uint16_t wnd; 00284 uint16_t wnd_scale; 00285 uint16_t remote_closed; 00286 00287 /* options */ 00288 uint32_t ts_nxt; 00289 uint16_t mss; 00290 uint8_t sack_ok; 00291 uint8_t ts_ok; 00292 uint8_t mss_ok; 00293 uint8_t scale_ok; 00294 struct tcp_sack_block *sacks; 00295 uint8_t jumbo; 00296 uint32_t linger_timeout; 00297 00298 /* Transmission */ 00299 uint8_t x_mode; 00300 uint8_t dupacks; 00301 uint8_t backoff; 00302 uint8_t localZeroWindow; 00303 00304 /* Keepalive */ 00305 struct pico_timer *keepalive_tmr; 00306 pico_time ack_timestamp; 00307 uint32_t ka_time; 00308 uint32_t ka_intvl; 00309 uint32_t ka_probes; 00310 uint32_t ka_retries_count; 00311 00312 /* FIN timer */ 00313 struct pico_timer *fin_tmr; 00314 }; 00315 00316 /* Queues */ 00317 static struct pico_queue tcp_in = { 00318 0 00319 }; 00320 static struct pico_queue tcp_out = { 00321 0 00322 }; 00323 00324 /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */ 00325 static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t); 00326 00327 /* checks if tcpq_in is empty */ 00328 int pico_tcp_queue_in_is_empty(struct pico_socket *s) 00329 { 00330 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 00331 00332 if (t->tcpq_in.frames == 0) 00333 return 1; 00334 else 00335 return 0; 00336 } 00337 00338 /* Useful for getting rid of the beginning of the buffer (read() op) */ 00339 static int release_until(struct pico_tcp_queue *q, uint32_t seq) 00340 { 00341 void *head = first_segment(q); 00342 int ret = 0; 00343 int32_t seq_result = 0; 00344 00345 if (!head) 00346 return ret; 00347 00348 do { 00349 void *cur = head; 00350 00351 if (IS_INPUT_QUEUE(q)) 00352 seq_result = pico_seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq); 00353 else 00354 seq_result = pico_seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); 00355 00356 if (seq_result <= 0) 00357 { 00358 head = next_segment(q, cur); 00359 //tcp_dbg("Releasing %08x, len: %d\n", SEQN((struct pico_frame *)head), ((struct pico_frame *)head)->payload_len); 00360 pico_discard_segment(q, cur); 00361 ret++; 00362 } else { 00363 break; 00364 } 00365 } while (head); 00366 00367 return ret; 00368 } 00369 00370 static int release_all_until(struct pico_tcp_queue *q, uint32_t seq, pico_time *timestamp) 00371 { 00372 void *f = NULL; 00373 struct pico_tree_node *idx, *temp; 00374 int seq_result; 00375 int ret = 0; 00376 *timestamp = 0; 00377 00378 pico_tree_foreach_safe(idx, &q->pool, temp) 00379 { 00380 f = idx->keyValue; 00381 00382 if (IS_INPUT_QUEUE(q)) 00383 seq_result = pico_seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq); 00384 else 00385 seq_result = pico_seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); 00386 00387 if (seq_result <= 0) { 00388 tcp_dbg("Releasing %p\n", f); 00389 if ((seq_result == 0) && !IS_INPUT_QUEUE(q)) 00390 *timestamp = ((struct pico_frame *)f)->timestamp; 00391 00392 pico_discard_segment(q, f); 00393 ret++; 00394 } else { 00395 return ret; 00396 } 00397 } 00398 return ret; 00399 } 00400 00401 00402 /* API calls */ 00403 00404 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f) 00405 { 00406 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00407 struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00408 struct pico_socket *s = f->sock; 00409 struct pico_ipv4_pseudo_hdr pseudo; 00410 00411 if (s) { 00412 /* Case of outgoing frame */ 00413 /* dbg("TCP CRC: on outgoing frame\n"); */ 00414 pseudo.src.addr = s->local_addr.ip4.addr; 00415 pseudo.dst.addr = s->remote_addr.ip4.addr; 00416 } else { 00417 /* Case of incoming frame */ 00418 /* dbg("TCP CRC: on incoming frame\n"); */ 00419 pseudo.src.addr = hdr->src.addr; 00420 pseudo.dst.addr = hdr->dst.addr; 00421 } 00422 00423 pseudo.zeros = 0; 00424 pseudo.proto = PICO_PROTO_TCP; 00425 pseudo.len = (uint16_t)short_be(f->transport_len); 00426 00427 return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len); 00428 } 00429 00430 #ifdef PICO_SUPPORT_IPV6 00431 uint16_t pico_tcp_checksum_ipv6(struct pico_frame *f) 00432 { 00433 struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr; 00434 struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *)f->transport_hdr; 00435 struct pico_ipv6_pseudo_hdr pseudo; 00436 struct pico_socket *s = f->sock; 00437 00438 /* XXX If the IPv6 packet contains a Routing header, the Destination 00439 * Address used in the pseudo-header is that of the final destination */ 00440 if (s) { 00441 /* Case of outgoing frame */ 00442 pseudo.src = s->local_addr.ip6; 00443 pseudo.dst = s->remote_addr.ip6; 00444 } else { 00445 /* Case of incoming frame */ 00446 pseudo.src = ipv6_hdr->src; 00447 pseudo.dst = ipv6_hdr->dst; 00448 } 00449 00450 pseudo.zero[0] = 0; 00451 pseudo.zero[1] = 0; 00452 pseudo.zero[2] = 0; 00453 pseudo.len = long_be(f->transport_len); 00454 pseudo.nxthdr = PICO_PROTO_TCP; 00455 00456 return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), tcp_hdr, f->transport_len); 00457 } 00458 #endif 00459 00460 #ifdef PICO_SUPPORT_IPV4 00461 static inline int checksum_is_ipv4(struct pico_frame *f) 00462 { 00463 return (IS_IPV4(f) || (f->sock && (f->sock->net == &pico_proto_ipv4))); 00464 } 00465 #endif 00466 00467 #ifdef PICO_SUPPORT_IPV6 00468 static inline int checksum_is_ipv6(struct pico_frame *f) 00469 { 00470 return ((IS_IPV6(f)) || (f->sock && (f->sock->net == &pico_proto_ipv6))); 00471 } 00472 #endif 00473 00474 uint16_t pico_tcp_checksum(struct pico_frame *f) 00475 { 00476 (void)f; 00477 00478 #ifdef PICO_SUPPORT_IPV4 00479 if (checksum_is_ipv4(f)) 00480 return pico_tcp_checksum_ipv4(f); 00481 00482 #endif 00483 00484 #ifdef PICO_SUPPORT_IPV6 00485 if (checksum_is_ipv6(f)) 00486 return pico_tcp_checksum_ipv6(f); 00487 00488 #endif 00489 return 0xffff; 00490 } 00491 00492 static void tcp_send_fin(struct pico_socket_tcp *t); 00493 static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f) 00494 { 00495 struct pico_tcp_hdr *hdr; 00496 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; 00497 IGNORE_PARAMETER(self); 00498 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 00499 f->sock->timestamp = TCP_TIME; 00500 if (f->payload_len > 0) { 00501 tcp_dbg("Process out: sending %p (%d bytes)\n", f, f->payload_len); 00502 } else { 00503 tcp_dbg("Sending empty packet\n"); 00504 } 00505 00506 if (f->payload_len > 0) { 00507 if (pico_seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { 00508 t->snd_nxt = SEQN(f) + f->payload_len; 00509 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); 00510 } 00511 } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */ 00512 /* hdr->seq = long_be(t->snd_nxt); / * XXX disabled this to not to mess with seq nrs of ACKs anymore * / */ 00513 } else { 00514 tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags); 00515 } 00516 00517 pico_network_send(f); 00518 return 0; 00519 } 00520 00521 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *data); 00522 00523 /* Interface: protocol definition */ 00524 struct pico_protocol pico_proto_tcp = { 00525 .name = "tcp", 00526 .proto_number = PICO_PROTO_TCP, 00527 .layer = PICO_LAYER_TRANSPORT, 00528 .process_in = pico_transport_process_in, 00529 .process_out = pico_tcp_process_out, 00530 .push = pico_tcp_push, 00531 .q_in = &tcp_in, 00532 .q_out = &tcp_out, 00533 }; 00534 00535 static uint32_t pico_paws(void) 00536 { 00537 static uint32_t _paws = 0; 00538 _paws = pico_rand(); 00539 return long_be(_paws); 00540 } 00541 00542 static inline void tcp_add_sack_option(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint32_t *ii) 00543 { 00544 if (flags & PICO_TCP_ACK) { 00545 struct tcp_sack_block *sb; 00546 uint32_t len_off; 00547 00548 if (ts->sack_ok && ts->sacks) { 00549 f->start[(*ii)++] = PICO_TCP_OPTION_SACK; 00550 len_off = *ii; 00551 f->start[(*ii)++] = PICO_TCPOPTLEN_SACK; 00552 while(ts->sacks) { 00553 sb = ts->sacks; 00554 ts->sacks = sb->next; 00555 memcpy(f->start + *ii, sb, 2 * sizeof(uint32_t)); 00556 *ii += (2 * (uint32_t)sizeof(uint32_t)); 00557 f->start[len_off] = (uint8_t)(f->start[len_off] + (2 * sizeof(uint32_t))); 00558 PICO_FREE(sb); 00559 } 00560 } 00561 } 00562 } 00563 00564 static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz) 00565 { 00566 uint32_t tsval = long_be((uint32_t)TCP_TIME); 00567 uint32_t tsecr = long_be(ts->ts_nxt); 00568 uint32_t i = 0; 00569 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00570 00571 memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ 00572 00573 if (flags & PICO_TCP_SYN) { 00574 f->start[i++] = PICO_TCP_OPTION_MSS; 00575 f->start[i++] = PICO_TCPOPTLEN_MSS; 00576 f->start[i++] = (uint8_t)((ts->mss >> 8) & 0xFF); 00577 f->start[i++] = (uint8_t)(ts->mss & 0xFF); 00578 f->start[i++] = PICO_TCP_OPTION_SACK_OK; 00579 f->start[i++] = PICO_TCPOPTLEN_SACK_OK; 00580 } 00581 00582 f->start[i++] = PICO_TCP_OPTION_WS; 00583 f->start[i++] = PICO_TCPOPTLEN_WS; 00584 f->start[i++] = (uint8_t)(ts->wnd_scale); 00585 00586 if ((flags & PICO_TCP_SYN) || ts->ts_ok) { 00587 f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; 00588 f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; 00589 memcpy(f->start + i, &tsval, 4); 00590 i += 4; 00591 memcpy(f->start + i, &tsecr, 4); 00592 i += 4; 00593 } 00594 00595 tcp_add_sack_option(ts, f, flags, &i); 00596 00597 if (i < optsiz) 00598 f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; 00599 } 00600 00601 static uint16_t tcp_options_size_frame(struct pico_frame *f) 00602 { 00603 uint16_t size = 0; 00604 00605 /* Always update window scale. */ 00606 size = (uint16_t)(size + PICO_TCPOPTLEN_WS); 00607 if (f->transport_flags_saved) 00608 size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP); 00609 00610 size = (uint16_t)(size + PICO_TCPOPTLEN_END); 00611 size = (uint16_t)(((uint16_t)(size + 3u) >> 2u) << 2u); 00612 return size; 00613 } 00614 00615 static void tcp_add_options_frame(struct pico_socket_tcp *ts, struct pico_frame *f) 00616 { 00617 uint32_t tsval = long_be((uint32_t)TCP_TIME); 00618 uint32_t tsecr = long_be(ts->ts_nxt); 00619 uint32_t i = 0; 00620 uint16_t optsiz = tcp_options_size_frame(f); 00621 00622 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00623 00624 memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ 00625 00626 00627 f->start[i++] = PICO_TCP_OPTION_WS; 00628 f->start[i++] = PICO_TCPOPTLEN_WS; 00629 f->start[i++] = (uint8_t)(ts->wnd_scale); 00630 00631 if (f->transport_flags_saved) { 00632 f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; 00633 f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; 00634 memcpy(f->start + i, &tsval, 4); 00635 i += 4; 00636 memcpy(f->start + i, &tsecr, 4); 00637 i += 4; 00638 } 00639 00640 if (i < optsiz) 00641 f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; 00642 } 00643 00644 static void tcp_send_ack(struct pico_socket_tcp *t); 00645 #define tcp_send_windowUpdate(t) (tcp_send_ack(t)) 00646 00647 static inline void tcp_set_space_check_winupdate(struct pico_socket_tcp *t, int32_t space, uint32_t shift) 00648 { 00649 if (((uint32_t)space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (int32_t)((uint32_t)space >> 2u))) { 00650 t->wnd = (uint16_t)space; 00651 t->wnd_scale = (uint16_t)shift; 00652 00653 if(t->wnd == 0) /* mark the entering to zero window state */ 00654 t->localZeroWindow = 1u; 00655 else if(t->localZeroWindow) 00656 { 00657 t->localZeroWindow = 0u; 00658 tcp_send_windowUpdate(t); 00659 } 00660 } 00661 } 00662 00663 static void tcp_set_space(struct pico_socket_tcp *t) 00664 { 00665 int32_t space; 00666 uint32_t shift = 0; 00667 00668 if (t->tcpq_in.max_size == 0) { 00669 space = ONE_GIGABYTE; 00670 } else { 00671 space = (int32_t)(t->tcpq_in.max_size - t->tcpq_in.size); 00672 } 00673 00674 if (space < 0) 00675 space = 0; 00676 00677 while(space > 0xFFFF) { 00678 space = (int32_t)(((uint32_t)space >> 1u)); 00679 shift++; 00680 } 00681 tcp_set_space_check_winupdate(t, space, shift); 00682 } 00683 00684 /* Return 32-bit aligned option size */ 00685 static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags) 00686 { 00687 uint16_t size = 0; 00688 struct tcp_sack_block *sb = t->sacks; 00689 00690 if (flags & PICO_TCP_SYN) { /* Full options */ 00691 size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP; 00692 } else { 00693 00694 /* Always update window scale. */ 00695 size = (uint16_t)(size + PICO_TCPOPTLEN_WS); 00696 00697 if (t->ts_ok) 00698 size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP); 00699 00700 size = (uint16_t)(size + PICO_TCPOPTLEN_END); 00701 } 00702 00703 if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) { 00704 size = (uint16_t)(size + 2); 00705 while(sb) { 00706 size = (uint16_t)(size + (2 * sizeof(uint32_t))); 00707 sb = sb->next; 00708 } 00709 } 00710 00711 size = (uint16_t)(((size + 3u) >> 2u) << 2u); 00712 return size; 00713 } 00714 00715 uint16_t pico_tcp_overhead(struct pico_socket *s) 00716 { 00717 if (!s) 00718 return 0; 00719 00720 return (uint16_t)(PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, (uint16_t)0)); /* hdr + Options size for data pkt */ 00721 00722 } 00723 00724 static inline int tcp_sack_marker(struct pico_frame *f, uint32_t start, uint32_t end, uint16_t *count) 00725 { 00726 int cmp; 00727 cmp = pico_seq_compare(SEQN(f), start); 00728 if (cmp > 0) 00729 return 0; 00730 00731 if (cmp == 0) { 00732 cmp = pico_seq_compare(SEQN(f) + f->payload_len, end); 00733 if (cmp > 0) { 00734 tcp_dbg("Invalid SACK: ignoring.\n"); 00735 } 00736 00737 tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end); 00738 f->flags |= PICO_FRAME_FLAG_SACKED; 00739 (*count)++; 00740 } 00741 00742 return cmp; 00743 } 00744 00745 static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end) 00746 { 00747 struct pico_frame *f; 00748 struct pico_tree_node *index, *temp; 00749 uint16_t count = 0; 00750 00751 pico_tree_foreach_safe(index, &t->tcpq_out.pool, temp){ 00752 f = index->keyValue; 00753 if (tcp_sack_marker(f, start, end, &count) == 0) 00754 goto done; 00755 } 00756 00757 done: 00758 if (t->x_mode > PICO_TCP_LOOKAHEAD) { 00759 if (t->in_flight > (count)) 00760 t->in_flight -= (count); 00761 else 00762 t->in_flight = 0; 00763 } 00764 } 00765 00766 inline static void tcp_add_header(struct pico_socket_tcp *t, struct pico_frame *f) 00767 { 00768 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 00769 f->timestamp = TCP_TIME; 00770 tcp_add_options(t, f, 0, (uint16_t)(f->transport_len - f->payload_len - (uint16_t)PICO_SIZE_TCPHDR)); 00771 hdr->rwnd = short_be(t->wnd); 00772 hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; 00773 hdr->ack = long_be(t->rcv_nxt); 00774 hdr->crc = 0; 00775 hdr->crc = short_be(pico_tcp_checksum(f)); 00776 } 00777 00778 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len) 00779 { 00780 uint32_t start, end; 00781 int i = 0; 00782 if (len % 8) { 00783 tcp_dbg("SACK: Invalid len.\n"); 00784 return; 00785 } 00786 00787 while (i < len) { 00788 start = long_from(opt + i); 00789 i += 4; 00790 end = long_from(opt + i); 00791 i += 4; 00792 tcp_process_sack(t, long_be(start), long_be(end)); 00793 } 00794 } 00795 00796 static int tcpopt_len_check(uint32_t *idx, uint8_t len, uint8_t expected) 00797 { 00798 if (len != expected) { 00799 *idx = *idx + len - 2; 00800 return -1; 00801 } 00802 00803 return 0; 00804 } 00805 00806 static inline void tcp_parse_option_ws(struct pico_socket_tcp *t, uint8_t len, uint8_t *opt, uint32_t *idx) 00807 { 00808 if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_WS) < 0) 00809 return; 00810 00811 t->recv_wnd_scale = opt[(*idx)++]; 00812 tcp_dbg_options("TCP Window scale: received %d\n", t->recv_wnd_scale); 00813 00814 } 00815 00816 static inline void tcp_parse_option_sack_ok(struct pico_socket_tcp *t, struct pico_frame *f, uint8_t len, uint32_t *idx) 00817 { 00818 if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_SACK_OK) < 0) 00819 return; 00820 00821 if(((struct pico_tcp_hdr *)(f->transport_hdr))->flags & PICO_TCP_SYN ) 00822 t->sack_ok = 1; 00823 } 00824 00825 static inline void tcp_parse_option_mss(struct pico_socket_tcp *t, uint8_t len, uint8_t *opt, uint32_t *idx) 00826 { 00827 uint16_t mss; 00828 if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_MSS) < 0) 00829 return; 00830 00831 t->mss_ok = 1; 00832 mss = short_from(opt + *idx); 00833 *idx += (uint32_t)sizeof(uint16_t); 00834 if (t->mss > short_be(mss)) 00835 t->mss = short_be(mss); 00836 } 00837 00838 static inline void tcp_parse_option_timestamp(struct pico_socket_tcp *t, struct pico_frame *f, uint8_t len, uint8_t *opt, uint32_t *idx) 00839 { 00840 uint32_t tsval, tsecr; 00841 if (tcpopt_len_check(idx, len, PICO_TCPOPTLEN_TIMESTAMP) < 0) 00842 return; 00843 00844 t->ts_ok = 1; 00845 tsval = long_from(opt + *idx); 00846 *idx += (uint32_t)sizeof(uint32_t); 00847 tsecr = long_from(opt + *idx); 00848 f->timestamp = long_be(tsecr); 00849 *idx += (uint32_t)sizeof(uint32_t); 00850 t->ts_nxt = long_be(tsval); 00851 } 00852 00853 static void tcp_parse_options(struct pico_frame *f) 00854 { 00855 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; 00856 uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR; 00857 uint32_t i = 0; 00858 f->timestamp = 0; 00859 while (i < (f->transport_len - PICO_SIZE_TCPHDR)) { 00860 uint8_t type = opt[i++]; 00861 uint8_t len; 00862 if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1)) 00863 len = opt[i++]; 00864 else 00865 len = 1; 00866 00867 if (f->payload && ((opt + i) > f->payload)) 00868 break; 00869 00870 tcp_dbg_options("Received option '%d', len = %d \n", type, len); 00871 switch (type) { 00872 case PICO_TCP_OPTION_NOOP: 00873 case PICO_TCP_OPTION_END: 00874 break; 00875 case PICO_TCP_OPTION_WS: 00876 tcp_parse_option_ws(t, len, opt, &i); 00877 break; 00878 case PICO_TCP_OPTION_SACK_OK: 00879 tcp_parse_option_sack_ok(t, f, len, &i); 00880 break; 00881 case PICO_TCP_OPTION_MSS: 00882 tcp_parse_option_mss(t, len, opt, &i); 00883 break; 00884 case PICO_TCP_OPTION_TIMESTAMP: 00885 tcp_parse_option_timestamp(t, f, len, opt, &i); 00886 break; 00887 00888 case PICO_TCP_OPTION_SACK: 00889 tcp_rcv_sack(t, opt + i, len - 2); 00890 i = i + len - 2; 00891 break; 00892 default: 00893 tcp_dbg_options("TCP: received unsupported option %u\n", type); 00894 i = i + len - 2; 00895 } 00896 } 00897 } 00898 00899 static inline void tcp_send_add_tcpflags(struct pico_socket_tcp *ts, struct pico_frame *f) 00900 { 00901 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00902 if (ts->rcv_nxt != 0) { 00903 if ((ts->rcv_ackd == 0) || (pico_seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { 00904 hdr->flags |= PICO_TCP_ACK; 00905 hdr->ack = long_be(ts->rcv_nxt); 00906 ts->rcv_ackd = ts->rcv_nxt; 00907 } 00908 } 00909 00910 if (hdr->flags & PICO_TCP_SYN) { 00911 ts->snd_nxt++; 00912 } 00913 00914 if (f->payload_len > 0) { 00915 hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; 00916 hdr->ack = long_be(ts->rcv_nxt); 00917 ts->rcv_ackd = ts->rcv_nxt; 00918 } 00919 } 00920 00921 static inline int tcp_send_try_enqueue(struct pico_socket_tcp *ts, struct pico_frame *f) 00922 { 00923 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00924 struct pico_frame *cpy; 00925 (void)hdr; 00926 00927 /* TCP: ENQUEUE to PROTO ( Transmit ) */ 00928 cpy = pico_frame_copy(f); 00929 if (!cpy) { 00930 pico_err = PICO_ERR_ENOMEM; 00931 return -1; 00932 } 00933 00934 if ((pico_enqueue(&tcp_out, cpy) > 0)) { 00935 if (f->payload_len > 0) { 00936 ts->in_flight++; 00937 ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */ 00938 } 00939 00940 tcp_dbg("DBG> [tcp output] state: %02x --> local port:%u remote port: %u seq: %08x ack: %08x flags: %02x = t_len: %u, hdr: %u payload: %d\n", 00941 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 ); 00942 } else { 00943 pico_frame_discard(cpy); 00944 } 00945 00946 return 0; 00947 00948 } 00949 00950 static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f) 00951 { 00952 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00953 hdr->trans.sport = ts->sock.local_port; 00954 hdr->trans.dport = ts->sock.remote_port; 00955 if (!hdr->seq) 00956 hdr->seq = long_be(ts->snd_nxt); 00957 00958 tcp_send_add_tcpflags(ts, f); 00959 00960 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00961 hdr->rwnd = short_be(ts->wnd); 00962 hdr->crc = 0; 00963 hdr->crc = short_be(pico_tcp_checksum(f)); 00964 00965 return tcp_send_try_enqueue(ts, f); 00966 00967 } 00968 00969 /* #define PICO_TCP_SUPPORT_SOCKET_STATS */ 00970 00971 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS 00972 static void sock_stats(uint32_t when, void *arg) 00973 { 00974 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 00975 tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x cwnd: %d\n", 00976 when, t->sock.state, short_be(t->sock.local_port), short_be(t->sock.remote_port), t->tcpq_out.size, SEQN((struct pico_frame *)first_segment(&t->tcpq_out)), t->snd_nxt, t->cwnd); 00977 pico_timer_add(2000, sock_stats, t); 00978 } 00979 #endif 00980 00981 static void tcp_send_probe(struct pico_socket_tcp *t); 00982 00983 static void pico_tcp_keepalive(pico_time now, void *arg) 00984 { 00985 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 00986 if (((t->sock.state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) && (t->ka_time > 0)) { 00987 if (t->ka_time < (now - t->ack_timestamp)) { 00988 if (t->ka_retries_count == 0) { 00989 /* First probe */ 00990 tcp_send_probe(t); 00991 t->ka_retries_count++; 00992 } 00993 if (t->ka_retries_count > t->ka_probes) { 00994 if (t->sock.wakeup) 00995 { 00996 pico_err = PICO_ERR_ECONNRESET; 00997 t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); 00998 } 00999 } 01000 if (((t->ka_retries_count * t->ka_intvl) + t->ka_time) < (now - t->ack_timestamp)) { 01001 /* Next probe */ 01002 tcp_send_probe(t); 01003 t->ka_retries_count++; 01004 } 01005 } else { 01006 t->ka_retries_count = 0; 01007 } 01008 } 01009 t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t); 01010 } 01011 01012 static inline void rto_set(struct pico_socket_tcp *t, uint32_t rto) 01013 { 01014 if (rto < PICO_TCP_RTO_MIN) 01015 rto = PICO_TCP_RTO_MIN; 01016 01017 if (rto > PICO_TCP_RTO_MAX) 01018 rto = PICO_TCP_RTO_MAX; 01019 01020 t->rto = rto; 01021 } 01022 01023 01024 struct pico_socket *pico_tcp_open(uint16_t family) 01025 { 01026 struct pico_socket_tcp *t = PICO_ZALLOC(sizeof(struct pico_socket_tcp)); 01027 if (!t) 01028 return NULL; 01029 01030 t->sock.timestamp = TCP_TIME; 01031 pico_socket_set_family(&t->sock, family); 01032 t->mss = (uint16_t)(pico_socket_get_mss(&t->sock) - PICO_SIZE_TCPHDR); 01033 t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF; 01034 t->tcpq_hold.pool.compare = t->tcpq_out.pool.compare = segment_compare; 01035 t->tcpq_in.pool.compare = input_segment_compare; 01036 t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; 01037 t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; 01038 t->tcpq_hold.max_size = 2u * t->mss; 01039 rto_set(t, PICO_TCP_RTO_MIN); 01040 01041 /* Uncomment next line and disable Nagle by default */ 01042 t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY); 01043 01044 /* Uncomment next line and Nagle is enabled by default */ 01045 /* t->sock.opt_flags &= (uint16_t) ~(1 << PICO_SOCKET_OPT_TCPNODELAY); */ 01046 01047 /* Set default linger for the socket */ 01048 t->linger_timeout = PICO_SOCKET_LINGER_TIMEOUT; 01049 01050 01051 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS 01052 pico_timer_add(2000, sock_stats, t); 01053 #endif 01054 01055 t->keepalive_tmr = pico_timer_add(1000, pico_tcp_keepalive, t); 01056 tcp_set_space(t); 01057 01058 return &t->sock; 01059 } 01060 01061 static uint32_t tcp_read_finish(struct pico_socket *s, uint32_t tot_rd_len) 01062 { 01063 struct pico_socket_tcp *t = TCP_SOCK(s); 01064 tcp_set_space(t); 01065 if (t->tcpq_in.size == 0) { 01066 s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD); 01067 } 01068 01069 if (t->remote_closed) { 01070 s->ev_pending |= (uint16_t)(PICO_SOCK_EV_CLOSE); 01071 s->state &= 0x00FFU; 01072 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; 01073 /* set SHUT_REMOTE */ 01074 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 01075 if (s->wakeup) { 01076 s->wakeup(PICO_SOCK_EV_CLOSE, s); 01077 } 01078 } 01079 01080 return tot_rd_len; 01081 } 01082 01083 static inline uint32_t tcp_read_in_frame_len(struct tcp_input_segment *f, int32_t in_frame_off, uint32_t tot_rd_len, uint32_t read_op_len) 01084 { 01085 uint32_t in_frame_len = 0; 01086 if (in_frame_off > 0) 01087 { 01088 if ((uint32_t)in_frame_off > f->payload_len) { 01089 tcp_dbg("FATAL TCP ERR: in_frame_off > f->payload_len\n"); 01090 } 01091 01092 in_frame_len = f->payload_len - (uint32_t)in_frame_off; 01093 } else { /* in_frame_off == 0 */ 01094 in_frame_len = f->payload_len; 01095 } 01096 01097 if ((in_frame_len + tot_rd_len) > (uint32_t)read_op_len) { 01098 in_frame_len = read_op_len - tot_rd_len; 01099 } 01100 01101 return in_frame_len; 01102 01103 } 01104 01105 static inline void tcp_read_check_segment_done(struct pico_socket_tcp *t, struct tcp_input_segment *f, uint32_t in_frame_len) 01106 { 01107 if ((in_frame_len == 0u) || (in_frame_len == (uint32_t)f->payload_len)) { 01108 pico_discard_segment(&t->tcpq_in, f); 01109 } 01110 } 01111 01112 uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len) 01113 { 01114 struct pico_socket_tcp *t = TCP_SOCK(s); 01115 struct tcp_input_segment *f; 01116 int32_t in_frame_off; 01117 uint32_t in_frame_len; 01118 uint32_t tot_rd_len = 0; 01119 01120 while (tot_rd_len < len) { 01121 /* To be sure we don't have garbage at the beginning */ 01122 release_until(&t->tcpq_in, t->rcv_processed); 01123 f = first_segment(&t->tcpq_in); 01124 if (!f) 01125 return tcp_read_finish(s, tot_rd_len); 01126 01127 in_frame_off = pico_seq_compare(t->rcv_processed, f->seq); 01128 /* Check for hole at the beginning of data, awaiting retransmissions. */ 01129 if (in_frame_off < 0) { 01130 tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n", t->rcv_processed, f->seq, t->rcv_nxt); 01131 return tcp_read_finish(s, tot_rd_len); 01132 } 01133 01134 in_frame_len = tcp_read_in_frame_len(f, in_frame_off, tot_rd_len, len); 01135 01136 01137 memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); 01138 tot_rd_len += in_frame_len; 01139 t->rcv_processed += in_frame_len; 01140 01141 tcp_read_check_segment_done(t, f, in_frame_len); 01142 01143 } 01144 return tcp_read_finish(s, tot_rd_len); 01145 } 01146 01147 int pico_tcp_initconn(struct pico_socket *s); 01148 static void initconn_retry(pico_time when, void *arg) 01149 { 01150 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 01151 IGNORE_PARAMETER(when); 01152 if (TCPSTATE(&t->sock) != PICO_SOCKET_STATE_TCP_ESTABLISHED) 01153 { 01154 if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) { 01155 tcp_dbg("TCP> Connection timeout. \n"); 01156 if (t->sock.wakeup) 01157 { 01158 pico_err = PICO_ERR_ECONNREFUSED; 01159 t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); 01160 } 01161 pico_socket_del(&t->sock); 01162 return; 01163 } 01164 01165 tcp_dbg("TCP> SYN retry %d...\n", t->backoff); 01166 t->backoff++; 01167 pico_tcp_initconn(&t->sock); 01168 } else { 01169 tcp_dbg("TCP> Connection is already established: no retry needed. good.\n"); 01170 } 01171 } 01172 01173 int pico_tcp_initconn(struct pico_socket *s) 01174 { 01175 struct pico_socket_tcp *ts = TCP_SOCK(s); 01176 struct pico_frame *syn; 01177 struct pico_tcp_hdr *hdr; 01178 uint16_t mtu, opt_len = tcp_options_size(ts, PICO_TCP_SYN); 01179 01180 syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); 01181 if (!syn) 01182 return -1; 01183 01184 hdr = (struct pico_tcp_hdr *) syn->transport_hdr; 01185 01186 if (!ts->snd_nxt) 01187 ts->snd_nxt = long_be(pico_paws()); 01188 01189 ts->snd_last = ts->snd_nxt; 01190 ts->cwnd = PICO_TCP_IW; 01191 mtu = (uint16_t)pico_socket_get_mss(s); 01192 ts->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR); 01193 ts->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss) - (((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss)) >> 3u)); 01194 syn->sock = s; 01195 hdr->seq = long_be(ts->snd_nxt); 01196 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo); 01197 hdr->flags = PICO_TCP_SYN; 01198 tcp_set_space(ts); 01199 hdr->rwnd = short_be(ts->wnd); 01200 tcp_add_options(ts, syn, PICO_TCP_SYN, opt_len); 01201 hdr->trans.sport = ts->sock.local_port; 01202 hdr->trans.dport = ts->sock.remote_port; 01203 01204 hdr->crc = 0; 01205 hdr->crc = short_be(pico_tcp_checksum(syn)); 01206 01207 /* TCP: ENQUEUE to PROTO ( SYN ) */ 01208 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); 01209 pico_enqueue(&tcp_out, syn); 01210 ts->retrans_tmr = pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts); 01211 return 0; 01212 } 01213 01214 static int tcp_send_synack(struct pico_socket *s) 01215 { 01216 struct pico_socket_tcp *ts = TCP_SOCK(s); 01217 struct pico_frame *synack; 01218 struct pico_tcp_hdr *hdr; 01219 uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK); 01220 01221 synack = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); 01222 if (!synack) 01223 return -1; 01224 01225 hdr = (struct pico_tcp_hdr *) synack->transport_hdr; 01226 01227 synack->sock = s; 01228 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo); 01229 hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK; 01230 hdr->rwnd = short_be(ts->wnd); 01231 hdr->seq = long_be(ts->snd_nxt); 01232 ts->rcv_processed = long_be(hdr->seq); 01233 ts->snd_last = ts->snd_nxt; 01234 tcp_set_space(ts); 01235 tcp_add_options(ts, synack, hdr->flags, opt_len); 01236 synack->payload_len = 0; 01237 synack->timestamp = TCP_TIME; 01238 tcp_send(ts, synack); 01239 pico_frame_discard(synack); 01240 return 0; 01241 } 01242 01243 static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags, int is_keepalive) 01244 { 01245 struct pico_frame *f; 01246 struct pico_tcp_hdr *hdr; 01247 uint16_t opt_len = tcp_options_size(t, flags); 01248 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); 01249 if (!f) { 01250 return; 01251 } 01252 01253 f->sock = &t->sock; 01254 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01255 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); 01256 hdr->flags = (uint8_t)flags; 01257 hdr->rwnd = short_be(t->wnd); 01258 tcp_set_space(t); 01259 tcp_add_options(t, f, flags, opt_len); 01260 hdr->trans.sport = t->sock.local_port; 01261 hdr->trans.dport = t->sock.remote_port; 01262 hdr->seq = long_be(t->snd_nxt); 01263 if ((flags & PICO_TCP_ACK) != 0) { 01264 hdr->ack = long_be(t->rcv_nxt); 01265 } 01266 01267 if (is_keepalive) 01268 hdr->seq = long_be(t->snd_nxt - 1); 01269 01270 t->rcv_ackd = t->rcv_nxt; 01271 01272 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 01273 hdr->rwnd = short_be(t->wnd); 01274 hdr->crc = 0; 01275 hdr->crc = short_be(pico_tcp_checksum(f)); 01276 01277 /* TCP: ENQUEUE to PROTO */ 01278 pico_enqueue(&tcp_out, f); 01279 } 01280 01281 static void tcp_send_ack(struct pico_socket_tcp *t) 01282 { 01283 tcp_send_empty(t, PICO_TCP_ACK, 0); 01284 } 01285 01286 static void tcp_send_probe(struct pico_socket_tcp *t) 01287 { 01288 /* tcp_dbg("Sending probe\n"); */ 01289 tcp_send_empty(t, PICO_TCP_PSHACK, 1); 01290 } 01291 01292 static int tcp_do_send_rst(struct pico_socket *s, uint32_t seq) 01293 { 01294 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 01295 uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST); 01296 struct pico_frame *f; 01297 struct pico_tcp_hdr *hdr; 01298 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); 01299 if (!f) { 01300 return -1; 01301 } 01302 f->sock = &t->sock; 01303 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n"); 01304 01305 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01306 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); 01307 hdr->flags = PICO_TCP_RST; 01308 hdr->rwnd = short_be(t->wnd); 01309 tcp_set_space(t); 01310 tcp_add_options(t, f, PICO_TCP_RST, opt_len); 01311 hdr->trans.sport = t->sock.local_port; 01312 hdr->trans.dport = t->sock.remote_port; 01313 hdr->seq = seq; 01314 hdr->ack = long_be(t->rcv_nxt); 01315 t->rcv_ackd = t->rcv_nxt; 01316 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 01317 hdr->rwnd = short_be(t->wnd); 01318 hdr->crc = 0; 01319 hdr->crc = short_be(pico_tcp_checksum(f)); 01320 01321 /* TCP: ENQUEUE to PROTO */ 01322 pico_enqueue(&tcp_out, f); 01323 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE\n"); 01324 return 0; 01325 } 01326 01327 static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr) 01328 { 01329 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 01330 struct pico_tcp_hdr *hdr_rcv; 01331 int ret; 01332 01333 if (fr && ((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) { 01334 /* in synchronized state: send RST with seq = ack from previous segment */ 01335 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; 01336 ret = tcp_do_send_rst(s, hdr_rcv->ack); 01337 } else { 01338 /* non-synchronized state */ 01339 /* go to CLOSED here to prevent timer callback to go on after timeout */ 01340 (t->sock).state &= 0x00FFU; 01341 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 01342 ret = tcp_do_send_rst(s, long_be(t->snd_nxt)); 01343 01344 /* Set generic socket state to CLOSED, too */ 01345 (t->sock).state &= 0xFF00U; 01346 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 01347 01348 /* call EV_FIN wakeup before deleting */ 01349 if ((t->sock).wakeup) 01350 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 01351 01352 /* delete socket */ 01353 pico_socket_del(&t->sock); 01354 } 01355 return ret; 01356 } 01357 01358 static inline void tcp_fill_rst_payload(struct pico_frame *fr, struct pico_frame *f) 01359 { 01360 /* fill in IP data from original frame */ 01361 if (IS_IPV4(fr)) { 01362 memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv4_hdr)); 01363 ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr; 01364 ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr; 01365 tcp_dbg("Making IPv4 reset frame...\n"); 01366 01367 } else { 01368 memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv6_hdr)); 01369 ((struct pico_ipv6_hdr *)(f->net_hdr))->dst = ((struct pico_ipv6_hdr *)(fr->net_hdr))->src; 01370 ((struct pico_ipv6_hdr *)(f->net_hdr))->src = ((struct pico_ipv6_hdr *)(fr->net_hdr))->dst; 01371 } 01372 01373 /* fill in TCP data from original frame */ 01374 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport; 01375 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport; 01376 01377 } 01378 01379 01380 static inline void tcp_fill_rst_header(struct pico_frame *fr, struct pico_tcp_hdr *hdr1, struct pico_frame *f, struct pico_tcp_hdr *hdr) 01381 { 01382 if(!(hdr1->flags & PICO_TCP_ACK)) 01383 hdr->flags |= PICO_TCP_ACK; 01384 01385 hdr->rwnd = 0; 01386 if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) { 01387 hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack; 01388 } else { 01389 hdr->seq = 0U; 01390 } 01391 01392 hdr->ack = 0; 01393 if(!(hdr1->flags & PICO_TCP_ACK)) 01394 hdr->ack = long_be(long_be(((struct pico_tcp_hdr *)(fr->transport_hdr))->seq) + fr->payload_len); 01395 01396 hdr->crc = short_be(pico_tcp_checksum(f)); 01397 } 01398 01399 int pico_tcp_reply_rst(struct pico_frame *fr) 01400 { 01401 struct pico_tcp_hdr *hdr, *hdr1; 01402 struct pico_frame *f; 01403 uint16_t size = PICO_SIZE_TCPHDR; 01404 01405 01406 hdr1 = (struct pico_tcp_hdr *) (fr->transport_hdr); 01407 if ((hdr1->flags & PICO_TCP_RST) != 0) 01408 return -1; 01409 01410 tcp_dbg("TCP> sending RST ... \n"); 01411 01412 f = fr->sock->net->alloc(fr->sock->net, size); 01413 if (!f) { 01414 pico_err = PICO_ERR_ENOMEM; 01415 return -1; 01416 } 01417 01418 tcp_fill_rst_payload(fr, f); 01419 01420 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01421 hdr->len = (uint8_t)(size << 2); 01422 hdr->flags = PICO_TCP_RST; 01423 01424 tcp_fill_rst_header(fr, hdr1, f, hdr); 01425 01426 if (0) { 01427 #ifdef PICO_SUPPORT_IPV4 01428 } else if (IS_IPV4(f)) { 01429 tcp_dbg("Pushing IPv4 reset frame...\n"); 01430 pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP); 01431 #endif 01432 #ifdef PICO_SUPPORT_IPV6 01433 } else { 01434 pico_ipv6_frame_push(f, NULL, &(((struct pico_ipv6_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP, 0); 01435 #endif 01436 } 01437 01438 01439 return 0; 01440 } 01441 01442 static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr) 01443 { 01444 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 01445 struct pico_frame *f; 01446 struct pico_tcp_hdr *hdr, *hdr_rcv; 01447 uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK); 01448 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; 01449 01450 tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n", (s->state & PICO_SOCKET_STATE_TCP)); 01451 if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) { 01452 if ((fr->flags & PICO_TCP_RST) != 0) 01453 return 0; 01454 01455 return pico_tcp_reply_rst(fr); 01456 } 01457 01458 /***************************************************************************/ 01459 /* sending RST */ 01460 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); 01461 01462 if (!f) { 01463 return -1; 01464 } 01465 01466 01467 f->sock = &t->sock; 01468 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01469 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); 01470 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; 01471 hdr->rwnd = short_be(t->wnd); 01472 tcp_set_space(t); 01473 tcp_add_options(t, f, PICO_TCP_RST | PICO_TCP_ACK, opt_len); 01474 hdr->trans.sport = t->sock.local_port; 01475 hdr->trans.dport = t->sock.remote_port; 01476 01477 /* non-synchronized state */ 01478 if (hdr_rcv->flags & PICO_TCP_ACK) { 01479 hdr->seq = hdr_rcv->ack; 01480 } else { 01481 hdr->seq = 0U; 01482 } 01483 01484 hdr->ack = long_be(SEQN(fr) + fr->payload_len); 01485 01486 t->rcv_ackd = t->rcv_nxt; 01487 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 01488 hdr->rwnd = short_be(t->wnd); 01489 hdr->crc = 0; 01490 hdr->crc = short_be(pico_tcp_checksum(f)); 01491 01492 /* TCP: ENQUEUE to PROTO */ 01493 pico_enqueue(&tcp_out, f); 01494 01495 /***************************************************************************/ 01496 01497 tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n"); 01498 01499 return 0; 01500 } 01501 01502 static void tcp_deltcb(pico_time when, void *arg); 01503 01504 static void tcp_linger(struct pico_socket_tcp *t) 01505 { 01506 if (t->fin_tmr) { 01507 pico_timer_cancel(t->fin_tmr); 01508 } 01509 t->fin_tmr = pico_timer_add(t->linger_timeout, tcp_deltcb, t); 01510 } 01511 01512 static void tcp_send_fin(struct pico_socket_tcp *t) 01513 { 01514 struct pico_frame *f; 01515 struct pico_tcp_hdr *hdr; 01516 uint16_t opt_len = tcp_options_size(t, PICO_TCP_FIN); 01517 f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); 01518 if (!f) { 01519 return; 01520 } 01521 01522 f->sock = &t->sock; 01523 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01524 hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); 01525 hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK; 01526 hdr->ack = long_be(t->rcv_nxt); 01527 t->rcv_ackd = t->rcv_nxt; 01528 hdr->rwnd = short_be(t->wnd); 01529 tcp_set_space(t); 01530 tcp_add_options(t, f, PICO_TCP_FIN, opt_len); 01531 hdr->trans.sport = t->sock.local_port; 01532 hdr->trans.dport = t->sock.remote_port; 01533 hdr->seq = long_be(t->snd_nxt); 01534 01535 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 01536 hdr->rwnd = short_be(t->wnd); 01537 hdr->crc = 0; 01538 hdr->crc = short_be(pico_tcp_checksum(f)); 01539 /* tcp_dbg("SENDING FIN...\n"); */ 01540 if (t->linger_timeout > 0) { 01541 pico_enqueue(&tcp_out, f); 01542 t->snd_nxt++; 01543 } else { 01544 pico_frame_discard(f); 01545 } 01546 tcp_linger(t); 01547 } 01548 01549 static void tcp_sack_prepare(struct pico_socket_tcp *t) 01550 { 01551 struct tcp_input_segment *pkt; 01552 uint32_t left = 0, right = 0; 01553 struct tcp_sack_block *sb; 01554 int n = 0; 01555 if (t->sacks) /* previous sacks are pending */ 01556 return; 01557 01558 pkt = first_segment(&t->tcpq_in); 01559 while(n < 3) { 01560 if (!pkt) { 01561 if(left) { 01562 sb = PICO_ZALLOC(sizeof(struct tcp_sack_block)); 01563 if (!sb) 01564 break; 01565 01566 sb->left = long_be(left); 01567 sb->right = long_be(right); 01568 n++; 01569 sb->next = t->sacks; 01570 t->sacks = sb; 01571 left = 0; 01572 right = 0; 01573 } 01574 01575 break; 01576 } 01577 01578 if (pkt->seq < t->rcv_nxt) { 01579 pkt = next_segment(&t->tcpq_in, pkt); 01580 continue; 01581 } 01582 01583 if (!left) { 01584 left = pkt->seq; 01585 right = pkt->seq + pkt->payload_len; 01586 pkt = next_segment(&t->tcpq_in, pkt); 01587 continue; 01588 } 01589 01590 if(pkt->seq == right) { 01591 right += pkt->payload_len; 01592 pkt = next_segment(&t->tcpq_in, pkt); 01593 continue; 01594 } else { 01595 sb = PICO_ZALLOC(sizeof(struct tcp_sack_block)); 01596 if (!sb) 01597 break; 01598 01599 sb->left = long_be(left); 01600 sb->right = long_be(right); 01601 n++; 01602 sb->next = t->sacks; 01603 t->sacks = sb; 01604 left = 0; 01605 right = 0; 01606 pkt = next_segment(&t->tcpq_in, pkt); 01607 } 01608 } 01609 } 01610 01611 static inline int tcp_data_in_expected(struct pico_socket_tcp *t, struct pico_frame *f) 01612 { 01613 struct tcp_input_segment *nxt; 01614 if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ 01615 /* Create new segment and enqueue it */ 01616 struct tcp_input_segment *input = segment_from_frame(f); 01617 if (!input) { 01618 pico_err = PICO_ERR_ENOMEM; 01619 return -1; 01620 } 01621 01622 if(pico_enqueue_segment(&t->tcpq_in, input) <= 0) 01623 { 01624 /* failed to enqueue, destroy segment */ 01625 PICO_FREE(input->payload); 01626 PICO_FREE(input); 01627 return -1; 01628 } else { 01629 t->rcv_nxt = SEQN(f) + f->payload_len; 01630 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); 01631 while(nxt) { 01632 tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt); 01633 t->rcv_nxt += nxt->payload_len; 01634 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); 01635 } 01636 t->sock.ev_pending |= PICO_SOCK_EV_RD; 01637 } 01638 } else { 01639 tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); 01640 } 01641 01642 return 0; 01643 } 01644 01645 static inline int tcp_data_in_high_segment(struct pico_socket_tcp *t, struct pico_frame *f) 01646 { 01647 tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); 01648 if (t->sack_ok) { 01649 struct tcp_input_segment *input = segment_from_frame(f); 01650 if (!input) { 01651 pico_err = PICO_ERR_ENOMEM; 01652 return -1; 01653 } 01654 01655 if(pico_enqueue_segment(&t->tcpq_in, input) <= 0) { 01656 /* failed to enqueue, destroy segment */ 01657 PICO_FREE(input->payload); 01658 PICO_FREE(input); 01659 return -1; 01660 } 01661 01662 tcp_sack_prepare(t); 01663 } 01664 01665 return 0; 01666 } 01667 01668 static inline void tcp_data_in_send_ack(struct pico_socket_tcp *t, struct pico_frame *f) 01669 { 01670 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01671 /* In either case, ack til recv_nxt, unless received data raises a RST flag. */ 01672 if (((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && 01673 ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) && 01674 ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV) && 01675 ((hdr->flags & PICO_TCP_RST) == 0)) 01676 tcp_send_ack(t); 01677 } 01678 01679 static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) 01680 { 01681 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01682 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01683 uint16_t payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u)); 01684 int ret = 0; 01685 (void)hdr; 01686 01687 if (((hdr->len & 0xf0u) >> 2u) <= f->transport_len) { 01688 tcp_parse_options(f); 01689 f->payload = f->transport_hdr + ((hdr->len & 0xf0u) >> 2u); 01690 f->payload_len = payload_len; 01691 tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); 01692 01693 if (pico_seq_compare(SEQN(f), t->rcv_nxt) <= 0) { 01694 ret = tcp_data_in_expected(t, f); 01695 } else { 01696 ret = tcp_data_in_high_segment(t, f); 01697 } 01698 01699 tcp_data_in_send_ack(t, f); 01700 return ret; 01701 } else { 01702 tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len); 01703 return -1; 01704 } 01705 } 01706 01707 static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, pico_time *timestamp) 01708 { 01709 int ret = release_all_until(&t->tcpq_out, ACKN(f), timestamp); 01710 if (ret > 0) { 01711 t->sock.ev_pending |= PICO_SOCK_EV_WR; 01712 } 01713 01714 return ret; 01715 } 01716 01717 static uint16_t time_diff(pico_time a, pico_time b) 01718 { 01719 if (a >= b) 01720 return (uint16_t)(a - b); 01721 else 01722 return (uint16_t)(b - a); 01723 } 01724 01725 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt) 01726 { 01727 01728 uint32_t avg = t->avg_rtt; 01729 uint32_t rvar = t->rttvar; 01730 if (!avg) { 01731 /* This follows RFC2988 01732 * (2.2) When the first RTT measurement R is made, the host MUST set 01733 * 01734 * SRTT <- R 01735 * RTTVAR <- R/2 01736 * RTO <- SRTT + max (G, K*RTTVAR) 01737 */ 01738 t->avg_rtt = rtt; 01739 t->rttvar = rtt >> 1; 01740 rto_set(t, t->avg_rtt + (t->rttvar << 2)); 01741 } else { 01742 int32_t var = (int32_t)t->avg_rtt - (int32_t)rtt; 01743 if (var < 0) 01744 var = 0 - var; 01745 01746 /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */ 01747 01748 /* First, evaluate a new value for the rttvar */ 01749 t->rttvar <<= 2; 01750 t->rttvar -= rvar; 01751 t->rttvar += (uint32_t)var; 01752 t->rttvar >>= 2; 01753 01754 /* Then, calculate the new avg_rtt */ 01755 t->avg_rtt <<= 3; 01756 t->avg_rtt -= avg; 01757 t->avg_rtt += rtt; 01758 t->avg_rtt >>= 3; 01759 01760 /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */ 01761 rto_set(t, t->avg_rtt + (t->rttvar << 2)); 01762 } 01763 01764 tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto); 01765 } 01766 01767 static void tcp_congestion_control(struct pico_socket_tcp *t) 01768 { 01769 if (t->x_mode > PICO_TCP_LOOKAHEAD) 01770 return; 01771 01772 tcp_dbg("Doing congestion control\n"); 01773 if (t->cwnd < t->ssthresh) { 01774 t->cwnd++; 01775 } else { 01776 t->cwnd_counter++; 01777 if (t->cwnd_counter >= t->cwnd) { 01778 t->cwnd++; 01779 t->cwnd_counter = 0; 01780 } 01781 } 01782 01783 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight); 01784 } 01785 01786 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts); 01787 01788 01789 /* Retransmission time out (RTO). */ 01790 01791 static void tcp_first_timeout(struct pico_socket_tcp *t) 01792 { 01793 t->x_mode = PICO_TCP_BLACKOUT; 01794 t->cwnd = PICO_TCP_IW; 01795 t->in_flight = 0; 01796 } 01797 01798 static int tcp_rto_xmit(struct pico_socket_tcp *t, struct pico_frame *f) 01799 { 01800 struct pico_frame *cpy; 01801 /* TCP: ENQUEUE to PROTO ( retransmit )*/ 01802 cpy = pico_frame_copy(f); 01803 if (!cpy) { 01804 add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME); 01805 return -1; 01806 } 01807 01808 if (pico_enqueue(&tcp_out, cpy) > 0) { 01809 t->snd_last_out = SEQN(cpy); 01810 add_retransmission_timer(t, (t->rto << (++t->backoff)) + TCP_TIME); 01811 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight); 01812 tcp_dbg("Sending RTO!\n"); 01813 return 1; 01814 } else { 01815 tcp_dbg("RTO fail, retry!\n"); 01816 add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME); 01817 pico_frame_discard(cpy); 01818 return 0; 01819 } 01820 } 01821 01822 static void tcp_next_zerowindow_probe(struct pico_socket_tcp *t) 01823 { 01824 tcp_dbg("Sending probe!\n"); 01825 tcp_send_probe(t); 01826 add_retransmission_timer(t, (t->rto << ++t->backoff) + TCP_TIME); 01827 } 01828 01829 static int tcp_is_allowed_to_send(struct pico_socket_tcp *t) 01830 { 01831 return t->sock.net && 01832 ( 01833 ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) || 01834 ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) 01835 ) && 01836 ((t->backoff < PICO_TCP_MAX_RETRANS)); 01837 } 01838 01839 static inline int tcp_retrans_timeout_check_queue(struct pico_socket_tcp *t) 01840 { 01841 struct pico_frame *f = NULL; 01842 f = first_segment(&t->tcpq_out); 01843 while (f) { 01844 tcp_dbg("Checking frame in queue \n"); 01845 if (t->x_mode == PICO_TCP_WINDOW_FULL) { 01846 tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d Win full: %d frame flags: %04x\n", SEQN(f), f->payload_len, t->rto, t->x_mode == PICO_TCP_WINDOW_FULL, f->flags); 01847 tcp_next_zerowindow_probe(t); 01848 return -1; 01849 } 01850 01851 if (t->x_mode != PICO_TCP_BLACKOUT) 01852 tcp_first_timeout(t); 01853 01854 tcp_add_header(t, f); 01855 if (tcp_rto_xmit(t, f) > 0) /* A segment has been rexmit'd */ 01856 return -1; 01857 01858 f = next_segment(&t->tcpq_out, f); 01859 } 01860 if (t->tcpq_out.size < t->tcpq_out.max_size) 01861 t->sock.ev_pending |= PICO_SOCK_EV_WR; 01862 01863 return 0; 01864 01865 01866 01867 } 01868 01869 static void tcp_retrans_timeout(pico_time val, void *sock) 01870 { 01871 struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock; 01872 01873 t->retrans_tmr = NULL; 01874 01875 if (t->retrans_tmr_due == 0ull) { 01876 return; 01877 } 01878 01879 if (t->retrans_tmr_due > val) { 01880 /* Timer was postponed... */ 01881 add_retransmission_timer(t, t->retrans_tmr_due); 01882 return; 01883 } 01884 01885 tcp_dbg("TIMEOUT! backoff = %d, rto: %d\n", t->backoff, t->rto); 01886 t->retrans_tmr_due = 0ull; 01887 01888 if (tcp_is_allowed_to_send(t)) { 01889 if (tcp_retrans_timeout_check_queue(t) < 0) 01890 return; 01891 } 01892 else if(t->backoff >= PICO_TCP_MAX_RETRANS && (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED ) 01893 { 01894 tcp_dbg("Connection timeout!\n"); 01895 /* the retransmission timer, failed to get an ack for a frame, gives up on the connection */ 01896 tcp_discard_all_segments(&t->tcpq_out); 01897 if(t->sock.wakeup) 01898 t->sock.wakeup(PICO_SOCK_EV_FIN, &t->sock); 01899 01900 /* delete socket */ 01901 pico_socket_del(&t->sock); 01902 return; 01903 } else { 01904 tcp_dbg("Retransmission not allowed, rescheduling\n"); 01905 } 01906 } 01907 01908 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts) 01909 { 01910 struct pico_tree_node *index; 01911 pico_time now = TCP_TIME; 01912 pico_time val = 0; 01913 01914 01915 if (next_ts == 0) { 01916 struct pico_frame *f; 01917 01918 pico_tree_foreach(index, &t->tcpq_out.pool){ 01919 f = index->keyValue; 01920 if ((next_ts == 0) || ((f->timestamp < next_ts) && (f->timestamp > 0))) { 01921 next_ts = f->timestamp; 01922 val = next_ts + (t->rto << t->backoff); 01923 } 01924 } 01925 } else { 01926 val = next_ts; 01927 } 01928 01929 if ((val > 0) || (val > now)) { 01930 t->retrans_tmr_due = val; 01931 } else { 01932 t->retrans_tmr_due = now + 1; 01933 } 01934 01935 if (!t->retrans_tmr) { 01936 t->retrans_tmr = pico_timer_add(t->retrans_tmr_due - now, tcp_retrans_timeout, t); 01937 tcp_dbg("Next timeout in %u msec\n", (uint32_t) (t->retrans_tmr_due - now)); 01938 } 01939 } 01940 01941 static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f) 01942 { 01943 struct pico_frame *cpy; 01944 if (f) { 01945 tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len); 01946 tcp_add_header(t, f); 01947 /* TCP: ENQUEUE to PROTO ( retransmit )*/ 01948 cpy = pico_frame_copy(f); 01949 if (!cpy) { 01950 return -1; 01951 } 01952 01953 if (pico_enqueue(&tcp_out, cpy) > 0) { 01954 t->in_flight++; 01955 t->snd_last_out = SEQN(cpy); 01956 } else { 01957 pico_frame_discard(cpy); 01958 } 01959 01960 add_retransmission_timer(t, TCP_TIME + t->rto); 01961 return(f->payload_len); 01962 } 01963 01964 return 0; 01965 } 01966 01967 #ifdef TCP_ACK_DBG 01968 static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f) 01969 { 01970 uint32_t una, nxt, ack, cur; 01971 struct pico_frame *una_f = NULL, *cur_f; 01972 struct pico_tree_node *idx; 01973 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01974 char info[64]; 01975 char tmp[64]; 01976 ack = ACKN(f); 01977 nxt = t->snd_nxt; 01978 tcp_dbg("===================================\n"); 01979 tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack); 01980 01981 pico_tree_foreach(idx, &t->tcpq_out.pool) { 01982 info[0] = 0; 01983 cur_f = idx->keyValue; 01984 cur = SEQN(cur_f); 01985 if (!una_f) { 01986 una_f = cur_f; 01987 una = SEQN(una_f); 01988 } 01989 01990 if (cur == nxt) { 01991 strncpy(tmp, info, strlen(info)); 01992 snprintf(info, 64, "%s SND_NXT", tmp); 01993 } 01994 01995 if (cur == ack) { 01996 strncpy(tmp, info, strlen(info)); 01997 snprintf(info, 64, "%s ACK", tmp); 01998 } 01999 02000 if (cur == una) { 02001 strncpy(tmp, info, strlen(info)); 02002 snprintf(info, 64, "%s SND_UNA", tmp); 02003 } 02004 02005 if (cur == t->snd_last) { 02006 strncpy(tmp, info, strlen(info)); 02007 snprintf(info, 64, "%s SND_LAST", tmp); 02008 } 02009 02010 tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info); 02011 02012 } 02013 tcp_dbg("SND_NXT is %08x, snd_LAST is %08x\n", nxt, t->snd_last); 02014 tcp_dbg("===================================\n"); 02015 tcp_dbg("\n\n"); 02016 } 02017 #endif 02018 02019 static int tcp_ack(struct pico_socket *s, struct pico_frame *f) 02020 { 02021 struct pico_frame *f_new; /* use with Nagle to push to out queue */ 02022 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02023 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 02024 uint32_t rtt = 0; 02025 uint16_t acked = 0; 02026 pico_time acked_timestamp = 0; 02027 02028 struct pico_frame *una = NULL; 02029 if ((hdr->flags & PICO_TCP_ACK) == 0) 02030 return -1; 02031 02032 #ifdef TCP_ACK_DBG 02033 tcp_ack_dbg(s, f); 02034 #endif 02035 02036 tcp_parse_options(f); 02037 t->recv_wnd = short_be(hdr->rwnd); 02038 02039 acked = (uint16_t)tcp_ack_advance_una(t, f, &acked_timestamp); 02040 una = first_segment(&t->tcpq_out); 02041 t->ack_timestamp = TCP_TIME; 02042 02043 if ((t->x_mode == PICO_TCP_BLACKOUT) || 02044 ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) { 02045 int prev_mode = t->x_mode; 02046 tcp_dbg("Re-entering look-ahead...\n\n\n"); 02047 t->x_mode = PICO_TCP_LOOKAHEAD; 02048 t->backoff = 0; 02049 02050 if((prev_mode == PICO_TCP_BLACKOUT) && (acked > 0) && una) 02051 { 02052 t->snd_nxt = SEQN(una); 02053 /* restart the retrans timer */ 02054 if (t->retrans_tmr) { 02055 t->retrans_tmr_due = 0ull; 02056 } 02057 } 02058 } 02059 02060 /* One should be acked. */ 02061 if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0)) 02062 t->in_flight--; 02063 02064 if (!una || acked > 0) { 02065 t->x_mode = PICO_TCP_LOOKAHEAD; 02066 tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames); 02067 t->backoff = 0; 02068 02069 /* Do rtt/rttvar/rto calculations */ 02070 /* First, try with timestamps, using the value from options */ 02071 if(f && (f->timestamp != 0)) { 02072 rtt = time_diff(TCP_TIME, f->timestamp); 02073 if (rtt) 02074 tcp_rtt(t, rtt); 02075 } else if(acked_timestamp) { 02076 /* If no timestamps are there, use conservative estimation on the una */ 02077 rtt = time_diff(TCP_TIME, acked_timestamp); 02078 if (rtt) 02079 tcp_rtt(t, rtt); 02080 } 02081 02082 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)); 02083 if (acked > t->in_flight) { 02084 tcp_dbg("WARNING: in flight < 0\n"); 02085 t->in_flight = 0; 02086 } else 02087 t->in_flight -= (acked); 02088 02089 } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */ 02090 ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && 02091 (f->payload_len == 0)) && /* This is a pure ack, and... */ 02092 (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */ 02093 { 02094 /* Process incoming duplicate ack. */ 02095 if (t->x_mode < PICO_TCP_RECOVER) { 02096 t->x_mode++; 02097 tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len); 02098 /* tcp_dbg("ACK: %x - QUEUE: %x\n", ACKN(f), SEQN(first_segment(&t->tcpq_out))); */ 02099 if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */ 02100 if (t->in_flight > PICO_TCP_IW) 02101 t->cwnd = (uint16_t)t->in_flight; 02102 else 02103 t->cwnd = PICO_TCP_IW; 02104 02105 t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out)); 02106 if (t->ssthresh > t->cwnd) 02107 t->ssthresh >>= 2; 02108 else 02109 t->ssthresh = (t->cwnd >> 1); 02110 02111 if (t->ssthresh < 2) 02112 t->ssthresh = 2; 02113 } 02114 } else if (t->x_mode == PICO_TCP_RECOVER) { 02115 /* 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)); */ 02116 if (t->in_flight <= t->cwnd) { 02117 struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry); 02118 if (!nxt) 02119 nxt = first_segment(&t->tcpq_out); 02120 02121 while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) { 02122 tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt)); 02123 nxt = next_segment(&t->tcpq_out, nxt); 02124 } 02125 if (nxt && (pico_seq_compare(SEQN(nxt), t->snd_nxt)) > 0) 02126 nxt = NULL; 02127 02128 if (nxt && (pico_seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale))) 02129 nxt = NULL; 02130 02131 if(!nxt) 02132 nxt = first_segment(&t->tcpq_out); 02133 02134 if (nxt) { 02135 tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry)); 02136 t->snd_retry = SEQN(nxt); 02137 } 02138 } 02139 02140 if (++t->cwnd_counter > 1) { 02141 t->cwnd--; 02142 if (t->cwnd < 2) 02143 t->cwnd = 2; 02144 02145 t->cwnd_counter = 0; 02146 } 02147 } else { 02148 tcp_dbg("DUPACK in mode %d \n", t->x_mode); 02149 02150 } 02151 } /* End case duplicate ack detection */ 02152 02153 /* Linux very special zero-window probe detection (see bug #107) */ 02154 if ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && /* This is a pure ack, and... */ 02155 (ACKN(f) == t->snd_nxt) && /* it's acking our snd_nxt, and... */ 02156 (pico_seq_compare(SEQN(f), t->rcv_nxt) < 0)) /* Has an old seq number */ 02157 { 02158 tcp_send_ack(t); 02159 } 02160 02161 02162 /* Do congestion control */ 02163 tcp_congestion_control(t); 02164 if ((acked > 0) && t->sock.wakeup) { 02165 if (t->tcpq_out.size < t->tcpq_out.max_size) 02166 t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock)); 02167 02168 /* t->sock.ev_pending |= PICO_SOCK_EV_WR; */ 02169 } 02170 02171 /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */ 02172 if (IS_NAGLE_ENABLED((&(t->sock)))) { 02173 while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) { 02174 tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n"); 02175 f_new = pico_hold_segment_make(t); 02176 if (f_new == NULL) 02177 break; /* XXX corrupt !!! (or no memory) */ 02178 02179 if (pico_enqueue_segment(&t->tcpq_out, f_new) <= 0) 02180 /* handle error */ 02181 tcp_dbg_nagle("TCP_ACK - NAGLE FAILED to enqueue in out\n"); 02182 } 02183 } 02184 02185 /* If some space was created, put a few segments out. */ 02186 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", TCP_TIME, t->cwnd, t->ssthresh, t->in_flight); 02187 if (t->x_mode == PICO_TCP_LOOKAHEAD) { 02188 if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) { 02189 pico_tcp_output(&t->sock, (int)t->cwnd - (int)t->in_flight); 02190 } 02191 } 02192 02193 add_retransmission_timer(t, 0); 02194 t->snd_old_ack = ACKN(f); 02195 return 0; 02196 } 02197 02198 static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f) 02199 { 02200 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02201 tcp_dbg("RECEIVED ACK IN FIN_WAIT1\n"); 02202 02203 /* acking part */ 02204 tcp_ack(s, f); 02205 02206 02207 tcp_dbg("FIN_WAIT1: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt); 02208 if (ACKN(f) == (t->snd_nxt - 1u)) { 02209 /* update TCP state */ 02210 s->state &= 0x00FFU; 02211 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2; 02212 tcp_dbg("TCP> IN STATE FIN_WAIT2\n"); 02213 } 02214 return 0; 02215 } 02216 02217 static void tcp_deltcb(pico_time when, void *arg) 02218 { 02219 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 02220 IGNORE_PARAMETER(when); 02221 02222 /* send RST if not yet in TIME_WAIT */ 02223 if ( (((t->sock).state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_TIME_WAIT) 02224 && (((t->sock).state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSING) ) { 02225 tcp_dbg("Called deltcb in state = %04x (sending reset!)\n", (t->sock).state); 02226 tcp_do_send_rst(&t->sock, long_be(t->snd_nxt)); 02227 } else { 02228 tcp_dbg("Called deltcb in state = %04x\n", (t->sock).state); 02229 } 02230 02231 /* update state */ 02232 (t->sock).state &= 0x00FFU; 02233 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 02234 (t->sock).state &= 0xFF00U; 02235 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 02236 /* call EV_FIN wakeup before deleting */ 02237 if (t->sock.wakeup) { 02238 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 02239 } 02240 02241 /* delete socket */ 02242 pico_socket_del(&t->sock); 02243 } 02244 02245 static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f) 02246 { 02247 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02248 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 02249 tcp_dbg("TCP> received fin in FIN_WAIT2\n"); 02250 /* received FIN, increase ACK nr */ 02251 t->rcv_nxt = long_be(hdr->seq) + 1; 02252 s->state &= 0x00FFU; 02253 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; 02254 /* set SHUT_REMOTE */ 02255 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 02256 if (s->wakeup) 02257 s->wakeup(PICO_SOCK_EV_CLOSE, s); 02258 02259 if (f->payload_len > 0) /* needed?? */ 02260 tcp_data_in(s, f); 02261 02262 /* send ACK */ 02263 tcp_send_ack(t); 02264 /* linger */ 02265 tcp_linger(t); 02266 return 0; 02267 } 02268 02269 static int tcp_closing_ack(struct pico_socket *s, struct pico_frame *f) 02270 { 02271 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02272 tcp_dbg("TCP> received ack in CLOSING\n"); 02273 /* acking part */ 02274 tcp_ack(s, f); 02275 02276 /* update TCP state DLA TODO: Only if FIN is acked! */ 02277 tcp_dbg("CLOSING: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt); 02278 if (ACKN(f) == t->snd_nxt) { 02279 s->state &= 0x00FFU; 02280 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; 02281 /* set timer */ 02282 tcp_linger(t); 02283 } 02284 return 0; 02285 } 02286 02287 static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f) 02288 { 02289 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02290 tcp_dbg("LAST_ACK: ack is %08x - snd_nxt is %08x\n", ACKN(f), t->snd_nxt); 02291 if (ACKN(f) == t->snd_nxt) { 02292 s->state &= 0x00FFU; 02293 s->state |= PICO_SOCKET_STATE_TCP_CLOSED; 02294 s->state &= 0xFF00U; 02295 s->state |= PICO_SOCKET_STATE_CLOSED; 02296 /* call socket wakeup with EV_FIN */ 02297 if (s->wakeup) 02298 s->wakeup(PICO_SOCK_EV_FIN, s); 02299 02300 /* delete socket */ 02301 pico_socket_del(s); 02302 } 02303 return 0; 02304 } 02305 02306 static int tcp_syn(struct pico_socket *s, struct pico_frame *f) 02307 { 02308 struct pico_socket_tcp *new = NULL; 02309 struct pico_tcp_hdr *hdr = NULL; 02310 uint16_t mtu; 02311 if(s->number_of_pending_conn >= s->max_backlog) 02312 return -1; 02313 02314 new = (struct pico_socket_tcp *)pico_socket_clone(s); 02315 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02316 if (!new) 02317 return -1; 02318 02319 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS 02320 pico_timer_add(2000, sock_stats, s); 02321 #endif 02322 02323 new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport; 02324 #ifdef PICO_SUPPORT_IPV4 02325 if (IS_IPV4(f)) { 02326 new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr; 02327 new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr; 02328 } 02329 02330 #endif 02331 #ifdef PICO_SUPPORT_IPV6 02332 if (IS_IPV6(f)) { 02333 new->sock.remote_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->src; 02334 new->sock.local_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->dst; 02335 } 02336 02337 #endif 02338 f->sock = &new->sock; 02339 tcp_parse_options(f); 02340 mtu = (uint16_t)pico_socket_get_mss(&new->sock); 02341 new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR); 02342 new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; 02343 new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; 02344 new->tcpq_hold.max_size = 2u * mtu; 02345 new->rcv_nxt = long_be(hdr->seq) + 1; 02346 new->snd_nxt = long_be(pico_paws()); 02347 new->snd_last = new->snd_nxt; 02348 new->cwnd = PICO_TCP_IW; 02349 new->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss) - (((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss)) >> 3u)); 02350 new->recv_wnd = short_be(hdr->rwnd); 02351 new->jumbo = hdr->len & 0x07; 02352 new->linger_timeout = PICO_SOCKET_LINGER_TIMEOUT; 02353 s->number_of_pending_conn++; 02354 new->sock.parent = s; 02355 new->sock.wakeup = s->wakeup; 02356 rto_set(new, PICO_TCP_RTO_MIN); 02357 /* Initialize timestamp values */ 02358 new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV; 02359 pico_socket_add(&new->sock); 02360 tcp_send_synack(&new->sock); 02361 tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt); 02362 return 0; 02363 } 02364 02365 static int tcp_synrecv_syn(struct pico_socket *s, struct pico_frame *f) 02366 { 02367 struct pico_tcp_hdr *hdr = NULL; 02368 struct pico_socket_tcp *t = TCP_SOCK(s); 02369 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02370 if (t->rcv_nxt == long_be(hdr->seq) + 1u) { 02371 /* take back our own SEQ number to its original value, 02372 * so the synack retransmitted is identical to the original. 02373 */ 02374 t->snd_nxt--; 02375 tcp_send_synack(s); 02376 } else { 02377 tcp_send_rst(s, f); 02378 return -1; 02379 } 02380 02381 return 0; 02382 } 02383 02384 static void tcp_set_init_point(struct pico_socket *s) 02385 { 02386 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02387 t->rcv_processed = t->rcv_nxt; 02388 } 02389 02390 02391 uint16_t pico_tcp_get_socket_mss(struct pico_socket *s) 02392 { 02393 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02394 if (t->mss > 0) 02395 return (uint16_t)(t->mss + PICO_SIZE_TCPHDR); 02396 else 02397 return (uint16_t)pico_socket_get_mss(s); 02398 } 02399 02400 static int tcp_synack(struct pico_socket *s, struct pico_frame *f) 02401 { 02402 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02403 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02404 02405 if (ACKN(f) == (1u + t->snd_nxt)) { 02406 /* Get rid of initconn retry */ 02407 if(t->retrans_tmr) { 02408 pico_timer_cancel(t->retrans_tmr); 02409 t->retrans_tmr = NULL; 02410 } 02411 02412 t->rcv_nxt = long_be(hdr->seq); 02413 t->rcv_processed = t->rcv_nxt + 1; 02414 tcp_ack(s, f); 02415 02416 s->state &= 0x00FFU; 02417 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; 02418 tcp_dbg("TCP> Established. State: %x\n", s->state); 02419 02420 if (s->wakeup) 02421 s->wakeup(PICO_SOCK_EV_CONN, s); 02422 02423 s->ev_pending |= PICO_SOCK_EV_WR; 02424 02425 t->rcv_nxt++; 02426 t->snd_nxt++; 02427 tcp_send_ack(t); /* return ACK */ 02428 02429 return 0; 02430 02431 } else if ((hdr->flags & PICO_TCP_RST) == 0) { 02432 tcp_dbg("TCP> Not established, RST sent.\n"); 02433 tcp_nosync_rst(s, f); 02434 return 0; 02435 } else { 02436 /* The segment has the reset flag on: Ignore! */ 02437 return 0; 02438 } 02439 } 02440 02441 static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f) 02442 { 02443 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02444 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02445 tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f)); 02446 if (t->snd_nxt == ACKN(f)) { 02447 tcp_set_init_point(s); 02448 tcp_ack(s, f); 02449 s->state &= 0x00FFU; 02450 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; 02451 tcp_dbg("TCP: Established. State now: %04x\n", s->state); 02452 if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */ 02453 tcp_dbg("FIRST ACK - No parent found -> sending socket\n"); 02454 s->wakeup(PICO_SOCK_EV_CONN, s); 02455 } 02456 02457 if (s->parent && s->parent->wakeup) { 02458 tcp_dbg("FIRST ACK - Parent found -> listening socket\n"); 02459 s->wakeup = s->parent->wakeup; 02460 s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent); 02461 } 02462 02463 s->ev_pending |= PICO_SOCK_EV_WR; 02464 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); 02465 return 0; 02466 } else if ((hdr->flags & PICO_TCP_RST) == 0) { 02467 tcp_nosync_rst(s, f); 02468 return 0; 02469 } else { 02470 /* The segment has the reset flag on: Ignore! */ 02471 return 0; 02472 } 02473 } 02474 02475 static void tcp_attempt_closewait(struct pico_socket *s, struct pico_frame *f) 02476 { 02477 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02478 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 02479 if (pico_seq_compare(SEQN(f), t->rcv_nxt) == 0) { 02480 /* received FIN, increase ACK nr */ 02481 t->rcv_nxt = long_be(hdr->seq) + 1; 02482 if (pico_seq_compare(SEQN(f), t->rcv_processed) == 0) { 02483 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { 02484 tcp_dbg("Changing state to CLOSE_WAIT\n"); 02485 s->state &= 0x00FFU; 02486 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; 02487 } 02488 02489 /* set SHUT_REMOTE */ 02490 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 02491 tcp_dbg("TCP> Close-wait\n"); 02492 if (s->wakeup) { 02493 s->wakeup(PICO_SOCK_EV_CLOSE, s); 02494 } 02495 } else { 02496 t->remote_closed = 1; 02497 } 02498 } 02499 02500 02501 } 02502 02503 static int tcp_closewait(struct pico_socket *s, struct pico_frame *f) 02504 { 02505 02506 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02507 if (f->payload_len > 0) 02508 tcp_data_in(s, f); 02509 02510 if (f->flags & PICO_TCP_ACK) 02511 tcp_ack(s, f); 02512 02513 tcp_dbg("called close_wait, in state %08x\n", s->state); 02514 tcp_attempt_closewait(s, f); 02515 02516 /* Ensure that the notification given to the socket 02517 * did not put us in LAST_ACK state before sending the ACK: i.e. if 02518 * pico_socket_close() has been called in the socket callback, we don't need to send 02519 * an ACK here. 02520 * 02521 */ 02522 if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) || 02523 ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) 02524 { 02525 tcp_dbg("In closewait: Sending ack! (state is %08x)\n", s->state); 02526 tcp_send_ack(t); 02527 } 02528 02529 return 0; 02530 } 02531 02532 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f) 02533 { 02534 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02535 IGNORE_PARAMETER(f); 02536 tcp_dbg("TCP> Received FIN in FIN_WAIT1\n"); 02537 s->state &= 0x00FFU; 02538 s->state |= PICO_SOCKET_STATE_TCP_CLOSING; 02539 t->rcv_processed = t->rcv_nxt + 1; 02540 t->rcv_nxt++; 02541 /* send ACK */ 02542 tcp_send_ack(t); 02543 return 0; 02544 } 02545 02546 static int tcp_finack(struct pico_socket *s, struct pico_frame *f) 02547 { 02548 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02549 IGNORE_PARAMETER(f); 02550 02551 tcp_dbg("TCP> ENTERED finack\n"); 02552 t->rcv_nxt++; 02553 /* send ACK */ 02554 tcp_send_ack(t); 02555 02556 /* call socket wakeup with EV_FIN */ 02557 if (s->wakeup) 02558 s->wakeup(PICO_SOCK_EV_FIN, s); 02559 02560 s->state &= 0x00FFU; 02561 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; 02562 /* set SHUT_REMOTE */ 02563 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 02564 02565 tcp_linger(t); 02566 02567 return 0; 02568 } 02569 02570 static void tcp_force_closed(struct pico_socket *s) 02571 { 02572 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02573 /* update state */ 02574 (t->sock).state &= 0x00FFU; 02575 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 02576 (t->sock).state &= 0xFF00U; 02577 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 02578 /* call EV_ERR wakeup before deleting */ 02579 if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) { 02580 if ((t->sock).wakeup) 02581 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 02582 } else { 02583 pico_err = PICO_ERR_ECONNRESET; 02584 if ((t->sock).wakeup) 02585 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); 02586 02587 /* delete socket */ 02588 pico_socket_del(&t->sock); 02589 } 02590 } 02591 02592 static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev) 02593 { 02594 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02595 if ((t->sock).wakeup) 02596 (t->sock).wakeup(ev, &(t->sock)); 02597 } 02598 02599 static int tcp_rst(struct pico_socket *s, struct pico_frame *f) 02600 { 02601 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02602 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 02603 02604 tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n"); 02605 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) { 02606 /* the RST is acceptable if the ACK field acknowledges the SYN */ 02607 if ((t->snd_nxt + 1u) == ACKN(f)) { /* valid, got to closed state */ 02608 tcp_force_closed(s); 02609 } else { /* not valid, ignore */ 02610 tcp_dbg("TCP RST> IGNORE\n"); 02611 return 0; 02612 } 02613 } else { /* all other states */ 02614 /* all reset (RST) segments are validated by checking their SEQ-fields, 02615 a reset is valid if its sequence number is in the window */ 02616 uint32_t this_seq = long_be(hdr->seq); 02617 if ((this_seq >= t->rcv_ackd) && (this_seq <= ((uint32_t)(short_be(hdr->rwnd) << (t->wnd_scale)) + t->rcv_ackd))) { 02618 tcp_force_closed(s); 02619 } else { /* not valid, ignore */ 02620 tcp_dbg("TCP RST> IGNORE\n"); 02621 return 0; 02622 } 02623 } 02624 02625 return 0; 02626 } 02627 static int tcp_halfopencon(struct pico_socket *s, struct pico_frame *fr) 02628 { 02629 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02630 IGNORE_PARAMETER(fr); 02631 tcp_send_ack(t); 02632 return 0; 02633 } 02634 02635 static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr) 02636 { 02637 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 02638 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (fr->transport_hdr); 02639 02640 if (pico_seq_compare(SEQN(fr), t->rcv_nxt) == 0) { 02641 /* received FIN, increase ACK nr */ 02642 t->rcv_nxt = long_be(hdr->seq) + 1; 02643 s->state &= 0x00FFU; 02644 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; 02645 /* set SHUT_LOCAL */ 02646 s->state |= PICO_SOCKET_STATE_SHUT_LOCAL; 02647 pico_socket_close(s); 02648 return 1; 02649 } 02650 02651 return 0; 02652 } 02653 02654 struct tcp_action_entry { 02655 uint16_t tcpstate; 02656 int (*syn)(struct pico_socket *s, struct pico_frame *f); 02657 int (*synack)(struct pico_socket *s, struct pico_frame *f); 02658 int (*ack)(struct pico_socket *s, struct pico_frame *f); 02659 int (*data)(struct pico_socket *s, struct pico_frame *f); 02660 int (*fin)(struct pico_socket *s, struct pico_frame *f); 02661 int (*finack)(struct pico_socket *s, struct pico_frame *f); 02662 int (*rst)(struct pico_socket *s, struct pico_frame *f); 02663 }; 02664 02665 static const struct tcp_action_entry tcp_fsm[] = { 02666 /* State syn synack ack data fin finack rst*/ 02667 { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 02668 { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 02669 { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, NULL, NULL, NULL, NULL, NULL, NULL }, 02670 { PICO_SOCKET_STATE_TCP_SYN_SENT, NULL, &tcp_synack, NULL, NULL, NULL, NULL, &tcp_rst }, 02671 { PICO_SOCKET_STATE_TCP_SYN_RECV, &tcp_synrecv_syn, NULL, &tcp_first_ack, &tcp_data_in, NULL, &tcp_closeconn, &tcp_rst }, 02672 { PICO_SOCKET_STATE_TCP_ESTABLISHED, &tcp_halfopencon, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst }, 02673 { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, NULL, &tcp_ack, &tcp_ack, &tcp_send_rst, &tcp_closewait, &tcp_closewait, &tcp_rst }, 02674 { PICO_SOCKET_STATE_TCP_LAST_ACK, NULL, &tcp_ack, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, 02675 { PICO_SOCKET_STATE_TCP_FIN_WAIT1, NULL, &tcp_ack, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst }, 02676 { PICO_SOCKET_STATE_TCP_FIN_WAIT2, NULL, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst }, 02677 { PICO_SOCKET_STATE_TCP_CLOSING, NULL, &tcp_ack, &tcp_closing_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, 02678 { PICO_SOCKET_STATE_TCP_TIME_WAIT, NULL, NULL, NULL, &tcp_send_rst, NULL, NULL, NULL} 02679 }; 02680 02681 #define MAX_VALID_FLAGS 10 /* Maximum number of valid flag combinations */ 02682 static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags) 02683 { 02684 uint8_t i; 02685 static const uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = { 02686 { /* PICO_SOCKET_STATE_TCP_UNDEF */ 0, }, 02687 { /* PICO_SOCKET_STATE_TCP_CLOSED */ 0, }, 02688 { /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN }, 02689 { /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK}, 02690 { /* PICO_SOCKET_STATE_TCP_SYN_RECV */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02691 { /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST, PICO_TCP_RSTACK}, 02692 { /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02693 { /* PICO_SOCKET_STATE_TCP_LAST_ACK */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02694 { /* PICO_SOCKET_STATE_TCP_FIN_WAIT1 */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02695 { /* PICO_SOCKET_STATE_TCP_FIN_WAIT2 */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02696 { /* PICO_SOCKET_STATE_TCP_CLOSING */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02697 { /* PICO_SOCKET_STATE_TCP_TIME_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, 02698 }; 02699 if(!flags) 02700 return 1; 02701 02702 for(i = 0; i < MAX_VALID_FLAGS; i++) { 02703 if(valid_flags[s->state >> 8u][i] == flags) 02704 return 0; 02705 } 02706 return 1; 02707 } 02708 02709 static void tcp_action_call(int (*call)(struct pico_socket *s, struct pico_frame *f), struct pico_socket *s, struct pico_frame *f ) 02710 { 02711 if (call) 02712 call(s, f); 02713 } 02714 02715 static int tcp_action_by_flags(const struct tcp_action_entry *action, struct pico_socket *s, struct pico_frame *f, uint8_t flags) 02716 { 02717 int ret = 0; 02718 if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) { 02719 tcp_action_call(action->ack, s, f); 02720 } 02721 02722 if ((f->payload_len > 0 || (flags & PICO_TCP_PSH)) && 02723 !(s->state & PICO_SOCKET_STATE_CLOSED) && !TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) 02724 { 02725 ret = f->payload_len; 02726 tcp_action_call(action->data, s, f); 02727 } 02728 02729 if (flags == PICO_TCP_FIN) { 02730 tcp_action_call(action->fin, s, f); 02731 } 02732 02733 if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) { 02734 tcp_action_call(action->finack, s, f); 02735 } 02736 02737 if (flags & PICO_TCP_RST) { 02738 tcp_action_call(action->rst, s, f); 02739 } 02740 02741 return ret; 02742 } 02743 02744 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f) 02745 { 02746 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 02747 int ret = 0; 02748 uint8_t flags = hdr->flags; 02749 const struct tcp_action_entry *action = &tcp_fsm[s->state >> 8]; 02750 02751 f->payload = (f->transport_hdr + ((hdr->len & 0xf0u) >> 2u)); 02752 f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u)); 02753 02754 tcp_dbg("[sam] TCP> [tcp input] t_len: %u\n", f->transport_len); 02755 tcp_dbg("[sam] TCP> flags = %02x\n", hdr->flags); 02756 tcp_dbg("[sam] TCP> s->state >> 8 = %u\n", s->state >> 8); 02757 tcp_dbg("[sam] TCP> [tcp input] socket: %p state: %d <-- local port:%u remote port: %u seq: %08x ack: %08x flags: %02x t_len: %u, hdr: %u payload: %d\n", 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 ); 02758 02759 /* This copy of the frame has the current socket as owner */ 02760 f->sock = s; 02761 s->timestamp = TCP_TIME; 02762 /* Those are not supported at this time. */ 02763 /* flags &= (uint8_t) ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); */ 02764 if(invalid_flags(s, flags)) { 02765 pico_tcp_reply_rst(f); 02766 } 02767 else if (flags == PICO_TCP_SYN) { 02768 tcp_action_call(action->syn, s, f); 02769 } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) { 02770 tcp_action_call(action->synack, s, f); 02771 } else { 02772 ret = tcp_action_by_flags(action, s, f, flags); 02773 } 02774 02775 if (s->ev_pending) 02776 tcp_wakeup_pending(s, s->ev_pending); 02777 02778 /* discard: */ 02779 pico_frame_discard(f); 02780 return ret; 02781 } 02782 02783 02784 inline static int checkLocalClosing(struct pico_socket *s); 02785 inline static int checkRemoteClosing(struct pico_socket *s); 02786 02787 static struct pico_frame *tcp_split_segment(struct pico_socket_tcp *t, struct pico_frame *f, uint16_t size) 02788 { 02789 struct pico_frame *f1, *f2; 02790 uint16_t size1, size2, size_f; 02791 uint16_t overhead; 02792 struct pico_tcp_hdr *hdr1, *hdr2, *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02793 overhead = pico_tcp_overhead(&t->sock); 02794 size_f = f->payload_len; 02795 02796 02797 if (size >= size_f) 02798 return f; /* no need to split! */ 02799 02800 size1 = size; 02801 size2 = (uint16_t)(size_f - size); 02802 02803 f1 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size1 + overhead)); 02804 f2 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size2 + overhead)); 02805 02806 if (!f1 || !f2) { 02807 pico_err = PICO_ERR_ENOMEM; 02808 return NULL; 02809 } 02810 02811 /* Advance payload pointer to the beginning of segment data */ 02812 f1->payload += overhead; 02813 f1->payload_len = (uint16_t)(f1->payload_len - overhead); 02814 f2->payload += overhead; 02815 f2->payload_len = (uint16_t)(f2->payload_len - overhead); 02816 02817 hdr1 = (struct pico_tcp_hdr *)f1->transport_hdr; 02818 hdr2 = (struct pico_tcp_hdr *)f2->transport_hdr; 02819 02820 /* Copy payload */ 02821 memcpy(f1->payload, f->payload, size1); 02822 memcpy(f2->payload, f->payload + size1, size2); 02823 02824 /* Copy tcp hdr */ 02825 memcpy(hdr1, hdr, sizeof(struct pico_tcp_hdr)); 02826 memcpy(hdr2, hdr, sizeof(struct pico_tcp_hdr)); 02827 02828 /* Adjust f2's sequence number */ 02829 hdr2->seq = long_be(SEQN(f) + size1); 02830 02831 /* Add TCP options */ 02832 pico_tcp_flags_update(f1, &t->sock); 02833 pico_tcp_flags_update(f2, &t->sock); 02834 tcp_add_options_frame(t, f1); 02835 tcp_add_options_frame(t, f2); 02836 02837 /* Get rid of the full frame */ 02838 pico_discard_segment(&t->tcpq_out, f); 02839 02840 /* Enqueue f2 for later send... */ 02841 pico_enqueue_segment(&t->tcpq_out, f2); 02842 02843 /* Return the partial frame */ 02844 return f1; 02845 } 02846 02847 02848 int pico_tcp_output(struct pico_socket *s, int loop_score) 02849 { 02850 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02851 struct pico_frame *f, *una; 02852 int sent = 0; 02853 int data_sent = 0; 02854 int32_t seq_diff = 0; 02855 02856 una = first_segment(&t->tcpq_out); 02857 f = peek_segment(&t->tcpq_out, t->snd_nxt); 02858 02859 while((f) && (t->cwnd >= t->in_flight)) { 02860 f->timestamp = TCP_TIME; 02861 add_retransmission_timer(t, t->rto + TCP_TIME); 02862 tcp_add_options_frame(t, f); 02863 seq_diff = pico_seq_compare(SEQN(f), SEQN(una)); 02864 if (seq_diff < 0) { 02865 tcp_dbg(">>> FATAL: seq diff is negative!\n"); 02866 break; 02867 } 02868 02869 /* Check if advertised window is full */ 02870 if ((uint32_t)seq_diff >= (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) { 02871 if (t->x_mode != PICO_TCP_WINDOW_FULL) { 02872 tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n", t->recv_wnd << t->recv_wnd_scale, f->payload_len); 02873 tcp_dbg("In window full...\n"); 02874 t->snd_nxt = SEQN(una); 02875 t->snd_retry = SEQN(una); 02876 t->x_mode = PICO_TCP_WINDOW_FULL; 02877 } 02878 02879 break; 02880 } 02881 02882 /* Check if the advertised window is too small to receive the current frame */ 02883 if ((uint32_t)(seq_diff + f->payload_len) > (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) { 02884 f = tcp_split_segment(t, f, (uint16_t)(t->recv_wnd << t->recv_wnd_scale)); 02885 if (!f) 02886 break; 02887 02888 /* Limit sending window to packets in flight (right sizing) */ 02889 t->cwnd = (uint16_t)t->in_flight; 02890 if (t->cwnd < 1) 02891 t->cwnd = 1; 02892 } 02893 02894 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); 02895 tcp_send(t, f); 02896 sent++; 02897 loop_score--; 02898 t->snd_last_out = SEQN(f); 02899 if (loop_score < 1) 02900 break; 02901 02902 if (f->payload_len > 0) { 02903 data_sent++; 02904 f = next_segment(&t->tcpq_out, f); 02905 } else { 02906 f = NULL; 02907 } 02908 } 02909 if ((sent > 0 && data_sent > 0)) { 02910 rto_set(t, t->rto); 02911 } else { 02912 /* Nothing to transmit. */ 02913 } 02914 02915 if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replaced !f by tcpq check */ 02916 if(!checkLocalClosing(&t->sock)) /* check if local closing started and send fin */ 02917 { 02918 checkRemoteClosing(&t->sock); /* check if remote closing started and send fin */ 02919 } 02920 } 02921 02922 return loop_score; 02923 } 02924 02925 /* function to make new segment from hold queue with specific size (mss) */ 02926 static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t) 02927 { 02928 struct pico_frame *f_temp, *f_new; 02929 struct pico_socket *s = (struct pico_socket *) &t->sock; 02930 struct pico_tcp_hdr *hdr; 02931 uint16_t total_len = 0, total_payload_len = 0; 02932 uint16_t off = 0, test = 0; 02933 02934 off = pico_tcp_overhead(s); 02935 02936 /* init with first frame in hold queue */ 02937 f_temp = first_segment(&t->tcpq_hold); 02938 total_len = f_temp->payload_len; 02939 f_temp = next_segment(&t->tcpq_hold, f_temp); 02940 02941 /* check till total_len <= MSS */ 02942 while ((f_temp != NULL) && ((total_len + f_temp->payload_len) <= t->mss)) { 02943 total_len = (uint16_t)(total_len + f_temp->payload_len); 02944 f_temp = next_segment(&t->tcpq_hold, f_temp); 02945 if (f_temp == NULL) 02946 break; 02947 } 02948 /* alloc new frame with payload size = off + total_len */ 02949 f_new = pico_socket_frame_alloc(s, (uint16_t)(off + total_len)); 02950 if (!f_new) { 02951 pico_err = PICO_ERR_ENOMEM; 02952 return f_new; 02953 } 02954 02955 pico_tcp_flags_update(f_new, &t->sock); 02956 hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; 02957 /* init new frame */ 02958 f_new->payload += off; 02959 f_new->payload_len = (uint16_t)(f_new->payload_len - off); 02960 f_new->sock = s; 02961 02962 f_temp = first_segment(&t->tcpq_hold); 02963 hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */ 02964 hdr->trans.sport = t->sock.local_port; 02965 hdr->trans.dport = t->sock.remote_port; 02966 02967 /* check till total_payload_len <= MSS */ 02968 while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= t->mss)) { 02969 /* cpy data and discard frame */ 02970 test++; 02971 memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len); 02972 total_payload_len = (uint16_t)(total_payload_len + f_temp->payload_len); 02973 pico_discard_segment(&t->tcpq_hold, f_temp); 02974 f_temp = first_segment(&t->tcpq_hold); 02975 } 02976 hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2u | (int8_t)t->jumbo); 02977 02978 tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n", test, total_payload_len); 02979 tcp_add_options_frame(t, f_new); 02980 02981 return f_new; 02982 } 02983 02984 02985 02986 static int pico_tcp_push_nagle_enqueue(struct pico_socket_tcp *t, struct pico_frame *f) 02987 { 02988 if (pico_enqueue_segment(&t->tcpq_out, f) > 0) { 02989 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); 02990 t->snd_last += f->payload_len; 02991 return f->payload_len; 02992 } else { 02993 tcp_dbg("Enqueue failed.\n"); 02994 return 0; 02995 } 02996 } 02997 02998 static int pico_tcp_push_nagle_hold(struct pico_socket_tcp *t, struct pico_frame *f) 02999 { 03000 struct pico_frame *f_new; 03001 uint32_t total_len = 0; 03002 total_len = f->payload_len + t->tcpq_hold.size; 03003 if ((total_len >= t->mss) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) { 03004 /* IF enough data in hold (>mss) AND space in out queue (>mss) */ 03005 /* add current frame in hold and make new segment */ 03006 if (pico_enqueue_segment(&t->tcpq_hold, f) > 0 ) { 03007 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n", t->tcpq_out.frames); 03008 t->snd_last += f->payload_len; /* XXX WATCH OUT */ 03009 f_new = pico_hold_segment_make(t); 03010 } else { 03011 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 1\n"); 03012 return 0; 03013 } 03014 03015 /* and put new frame in out queue */ 03016 if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out, f_new) > 0)) { 03017 return f_new->payload_len; 03018 } else { 03019 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n", f_new); 03020 return -1; /* XXX something seriously wrong */ 03021 } 03022 } else { 03023 /* ELSE put frame in hold queue */ 03024 if (pico_enqueue_segment(&t->tcpq_hold, f) > 0) { 03025 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n", t->tcpq_out.frames); 03026 t->snd_last += f->payload_len; /* XXX WATCH OUT */ 03027 return f->payload_len; 03028 } else { 03029 pico_err = PICO_ERR_EAGAIN; 03030 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 2\n"); 03031 } 03032 } 03033 03034 return 0; 03035 } 03036 03037 03038 static int pico_tcp_push_nagle_on(struct pico_socket_tcp *t, struct pico_frame *f) 03039 { 03040 /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */ 03041 if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) 03042 return pico_tcp_push_nagle_enqueue(t, f); 03043 03044 return pico_tcp_push_nagle_hold(t, f); 03045 } 03046 03047 03048 03049 /* original behavior kept when Nagle disabled; 03050 Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */ 03051 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f) 03052 { 03053 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 03054 struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock; 03055 IGNORE_PARAMETER(self); 03056 pico_err = PICO_ERR_NOERR; 03057 hdr->trans.sport = t->sock.local_port; 03058 hdr->trans.dport = t->sock.remote_port; 03059 hdr->seq = long_be(t->snd_last + 1); 03060 hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2u | (int8_t)t->jumbo); 03061 03062 if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size)) 03063 t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR); 03064 03065 /***************************************************************************/ 03066 03067 if (!IS_NAGLE_ENABLED((&(t->sock)))) { 03068 /* TCP_NODELAY enabled, original behavior */ 03069 if (pico_enqueue_segment(&t->tcpq_out, f) > 0) { 03070 tcp_dbg_nagle("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); 03071 t->snd_last += f->payload_len; 03072 return f->payload_len; 03073 } else { 03074 tcp_dbg("Enqueue failed.\n"); 03075 return 0; 03076 } 03077 } else { 03078 return pico_tcp_push_nagle_on(t, f); 03079 } 03080 03081 } 03082 03083 inline static void tcp_discard_all_segments(struct pico_tcp_queue *tq) 03084 { 03085 struct pico_tree_node *index = NULL, *index_safe = NULL; 03086 PICOTCP_MUTEX_LOCK(Mutex); 03087 pico_tree_foreach_safe(index, &tq->pool, index_safe) 03088 { 03089 void *f = index->keyValue; 03090 if(!f) 03091 break; 03092 03093 pico_tree_delete(&tq->pool, f); 03094 if(IS_INPUT_QUEUE(tq)) 03095 { 03096 struct tcp_input_segment *inp = (struct tcp_input_segment *)f; 03097 PICO_FREE(inp->payload); 03098 PICO_FREE(inp); 03099 } 03100 else 03101 pico_frame_discard(f); 03102 } 03103 tq->frames = 0; 03104 tq->size = 0; 03105 PICOTCP_MUTEX_UNLOCK(Mutex); 03106 } 03107 03108 void pico_tcp_cleanup_queues(struct pico_socket *sck) 03109 { 03110 struct pico_socket_tcp *tcp = (struct pico_socket_tcp *)sck; 03111 if(tcp->retrans_tmr) { 03112 pico_timer_cancel(tcp->retrans_tmr); 03113 tcp->retrans_tmr = NULL; 03114 } 03115 if(tcp->keepalive_tmr) { 03116 pico_timer_cancel(tcp->keepalive_tmr); 03117 tcp->keepalive_tmr = NULL; 03118 } 03119 if(tcp->fin_tmr) { 03120 pico_timer_cancel(tcp->fin_tmr); 03121 tcp->fin_tmr = NULL; 03122 } 03123 tcp_discard_all_segments(&tcp->tcpq_in); 03124 tcp_discard_all_segments(&tcp->tcpq_out); 03125 tcp_discard_all_segments(&tcp->tcpq_hold); 03126 } 03127 03128 static int checkLocalClosing(struct pico_socket *s) 03129 { 03130 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03131 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { 03132 tcp_dbg("TCP> buffer empty, shutdown established ...\n"); 03133 /* send fin if queue empty and in state shut local (write) */ 03134 tcp_send_fin(t); 03135 /* change tcp state to FIN_WAIT1 */ 03136 s->state &= 0x00FFU; 03137 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; 03138 return 1; 03139 } 03140 03141 return 0; 03142 } 03143 03144 static int checkRemoteClosing(struct pico_socket *s) 03145 { 03146 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03147 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { 03148 /* send fin if queue empty and in state shut local (write) */ 03149 tcp_send_fin(t); 03150 /* change tcp state to LAST_ACK */ 03151 s->state &= 0x00FFU; 03152 s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; 03153 tcp_dbg("TCP> STATE: LAST_ACK.\n"); 03154 return 1; 03155 } 03156 03157 return 0; 03158 } 03159 03160 void pico_tcp_notify_closing(struct pico_socket *sck) 03161 { 03162 struct pico_socket_tcp *t = (struct pico_socket_tcp *)sck; 03163 if(t->tcpq_out.frames == 0) 03164 { 03165 if(!checkLocalClosing(sck)) 03166 checkRemoteClosing(sck); 03167 } 03168 } 03169 03170 03171 int pico_tcp_check_listen_close(struct pico_socket *s) 03172 { 03173 if (TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) { 03174 pico_socket_del(s); 03175 return 0; 03176 } 03177 03178 return -1; 03179 } 03180 03181 void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s) 03182 { 03183 f->transport_flags_saved = ((struct pico_socket_tcp *)s)->ts_ok; 03184 } 03185 03186 int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value) 03187 { 03188 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03189 t->tcpq_in.max_size = value; 03190 return 0; 03191 } 03192 03193 int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value) 03194 { 03195 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03196 t->tcpq_out.max_size = value; 03197 return 0; 03198 } 03199 03200 int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value) 03201 { 03202 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03203 *value = t->tcpq_in.max_size; 03204 return 0; 03205 } 03206 03207 int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value) 03208 { 03209 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03210 *value = t->tcpq_out.max_size; 03211 return 0; 03212 } 03213 03214 int pico_tcp_set_keepalive_probes(struct pico_socket *s, uint32_t value) 03215 { 03216 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03217 t->ka_probes = value; 03218 return 0; 03219 } 03220 03221 int pico_tcp_set_keepalive_intvl(struct pico_socket *s, uint32_t value) 03222 { 03223 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03224 t->ka_intvl = value; 03225 return 0; 03226 } 03227 03228 int pico_tcp_set_keepalive_time(struct pico_socket *s, uint32_t value) 03229 { 03230 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03231 t->ka_time = value; 03232 return 0; 03233 } 03234 03235 int pico_tcp_set_linger(struct pico_socket *s, uint32_t value) 03236 { 03237 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 03238 t->linger_timeout = value; 03239 return 0; 03240 } 03241 03242 #endif /* PICO_SUPPORT_TCP */
Generated on Tue Jul 12 2022 15:59:22 by 1.7.2