source: mainline/uspace/srv/net/tl/tcp/tcp.c@ 014dd57b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 014dd57b was 014dd57b, checked in by Martin Decky <martin@…>, 14 years ago

streamline and create a common skeleton for the transport layer
(in the line of the previous updates to the lower layers)

  • Property mode set to 100644
File size: 69.0 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup tcp
[89e57cee]30 * @{
[21580dd]31 */
32
33/** @file
[89e57cee]34 * TCP module implementation.
35 * @see tcp.h
[21580dd]36 */
37
38#include <assert.h>
39#include <async.h>
40#include <fibril_synch.h>
41#include <malloc.h>
[fb04cba8]42/* TODO remove stdio */
[21580dd]43#include <stdio.h>
[e98b1d5]44#include <errno.h>
[21580dd]45
46#include <ipc/ipc.h>
47#include <ipc/services.h>
[514ee46]48#include <ipc/net.h>
[8e3a65c]49#include <ipc/tl.h>
[88e127ee]50#include <ipc/socket.h>
[21580dd]51
[058edb6]52#include <net/socket_codes.h>
[fe5d3c1b]53#include <net/ip_protocols.h>
[e4554d4]54#include <net/in.h>
55#include <net/in6.h>
56#include <net/inet.h>
[c7a8442]57#include <net/modules.h>
[058edb6]58
[849ed54]59#include <adt/dynamic_fifo.h>
[0a866eeb]60#include <packet_client.h>
[14f1db0]61#include <packet_remote.h>
[849ed54]62#include <net_checksum.h>
63#include <ip_client.h>
64#include <ip_interface.h>
65#include <icmp_client.h>
66#include <icmp_interface.h>
67#include <net_interface.h>
68#include <socket_core.h>
69#include <tl_common.h>
[014dd57b]70#include <tl_remote.h>
71#include <tl_skel.h>
72
73#include "tcp.h"
74#include "tcp_header.h"
[21580dd]75
[7c8267b]76/** TCP module name. */
[014dd57b]77#define NAME "tcp"
[849ed54]78
[7c8267b]79/** The TCP window default value. */
80#define NET_DEFAULT_TCP_WINDOW 10240
[21580dd]81
[7c8267b]82/** Initial timeout for new connections. */
[21580dd]83#define NET_DEFAULT_TCP_INITIAL_TIMEOUT 3000000L
84
[7c8267b]85/** Default timeout for closing. */
86#define NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT 2000L
[21580dd]87
[7c8267b]88/** The initial outgoing sequence number. */
89#define TCP_INITIAL_SEQUENCE_NUMBER 2999
[21580dd]90
[7c8267b]91/** Maximum TCP fragment size. */
92#define MAX_TCP_FRAGMENT_SIZE 65535
[21580dd]93
[7c8267b]94/** Free ports pool start. */
95#define TCP_FREE_PORTS_START 1025
[21580dd]96
[7c8267b]97/** Free ports pool end. */
[21580dd]98#define TCP_FREE_PORTS_END 65535
99
[7c8267b]100/** Timeout for connection initialization, SYN sent. */
101#define TCP_SYN_SENT_TIMEOUT 1000000L
[21580dd]102
[7c8267b]103/** The maximum number of timeouts in a row before singaling connection lost. */
[21580dd]104#define TCP_MAX_TIMEOUTS 8
105
[7c8267b]106/** The number of acknowledgements before retransmit. */
[21580dd]107#define TCP_FAST_RETRANSMIT_COUNT 3
108
[7c8267b]109/** Returns a value indicating whether the value is in the interval respecting
[89e57cee]110 * the possible overflow.
111 *
112 * The high end and/or the value may overflow, be lower than the low value.
[7c8267b]113 *
[89e57cee]114 * @param[in] lower The last value before the interval.
115 * @param[in] value The value to be checked.
116 * @param[in] higher_equal The last value in the interval.
[21580dd]117 */
[7c8267b]118#define IS_IN_INTERVAL_OVERFLOW(lower, value, higher_equal) \
119 ((((lower) < (value)) && (((value) <= (higher_equal)) || \
120 ((higher_equal) < (lower)))) || (((value) <= (higher_equal)) && \
121 ((higher_equal) < (lower))))
[21580dd]122
123/** Type definition of the TCP timeout.
124 * @see tcp_timeout
125 */
[7c8267b]126typedef struct tcp_timeout tcp_timeout_t;
[21580dd]127
128/** TCP reply timeout data.
129 * Used as a timeouting fibril argument.
130 * @see tcp_timeout()
131 */
[7c8267b]132struct tcp_timeout {
133 /** TCP global data are going to be read only. */
[aadf01e]134 int globals_read_only;
[7c8267b]135
136 /** Socket port. */
[aadf01e]137 int port;
[7c8267b]138
139 /** Local sockets. */
[aaa3f33a]140 socket_cores_t *local_sockets;
[7c8267b]141
142 /** Socket identifier. */
[aadf01e]143 int socket_id;
[7c8267b]144
145 /** Socket state. */
[aadf01e]146 tcp_socket_state_t state;
[7c8267b]147
148 /** Sent packet sequence number. */
[aadf01e]149 int sequence_number;
[7c8267b]150
151 /** Timeout in microseconds. */
[aadf01e]152 suseconds_t timeout;
[7c8267b]153
154 /** Port map key. */
[61bfc370]155 uint8_t *key;
[7c8267b]156
157 /** Port map key length. */
[aadf01e]158 size_t key_length;
[21580dd]159};
160
[46d4d9f]161static int tcp_release_and_return(packet_t *, int);
[88a1bb9]162static void tcp_prepare_operation_header(socket_core_t *, tcp_socket_data_t *,
[4e5c7ba]163 tcp_header_t *, int synchronize, int);
[88a1bb9]164static int tcp_prepare_timeout(int (*)(void *), socket_core_t *,
[4e5c7ba]165 tcp_socket_data_t *, size_t, tcp_socket_state_t, suseconds_t, int);
[88a1bb9]166static void tcp_free_socket_data(socket_core_t *);
[89e57cee]167
168static int tcp_timeout(void *);
169
170static int tcp_release_after_timeout(void *);
171
[46d4d9f]172static int tcp_process_packet(device_id_t, packet_t *, services_t);
[aaa3f33a]173static int tcp_connect_core(socket_core_t *, socket_cores_t *,
[89e57cee]174 struct sockaddr *, socklen_t);
[88a1bb9]175static int tcp_queue_prepare_packet(socket_core_t *, tcp_socket_data_t *,
[46d4d9f]176 packet_t *, size_t);
177static int tcp_queue_packet(socket_core_t *, tcp_socket_data_t *, packet_t *,
[89e57cee]178 size_t);
[46d4d9f]179static packet_t *tcp_get_packets_to_send(socket_core_t *, tcp_socket_data_t *);
180static void tcp_send_packets(device_id_t, packet_t *);
[89e57cee]181
[88a1bb9]182static void tcp_process_acknowledgement(socket_core_t *, tcp_socket_data_t *,
[4e5c7ba]183 tcp_header_t *);
[46d4d9f]184static packet_t *tcp_send_prepare_packet(socket_core_t *, tcp_socket_data_t *,
185 packet_t *, size_t, size_t);
186static packet_t *tcp_prepare_copy(socket_core_t *, tcp_socket_data_t *,
187 packet_t *, size_t, size_t);
[88a1bb9]188/* static */ void tcp_retransmit_packet(socket_core_t *, tcp_socket_data_t *,
[89e57cee]189 size_t);
[46d4d9f]190static int tcp_create_notification_packet(packet_t **, socket_core_t *,
[4e5c7ba]191 tcp_socket_data_t *, int, int);
192static void tcp_refresh_socket_data(tcp_socket_data_t *);
193
194static void tcp_initialize_socket_data(tcp_socket_data_t *);
195
[88a1bb9]196static int tcp_process_listen(socket_core_t *, tcp_socket_data_t *,
[46d4d9f]197 tcp_header_t *, packet_t *, struct sockaddr *, struct sockaddr *, size_t);
[88a1bb9]198static int tcp_process_syn_sent(socket_core_t *, tcp_socket_data_t *,
[46d4d9f]199 tcp_header_t *, packet_t *);
[88a1bb9]200static int tcp_process_syn_received(socket_core_t *, tcp_socket_data_t *,
[46d4d9f]201 tcp_header_t *, packet_t *);
[88a1bb9]202static int tcp_process_established(socket_core_t *, tcp_socket_data_t *,
[46d4d9f]203 tcp_header_t *, packet_t *, int, size_t);
[88a1bb9]204static int tcp_queue_received_packet(socket_core_t *, tcp_socket_data_t *,
[46d4d9f]205 packet_t *, int, size_t);
[d493830e]206static void tcp_queue_received_end_of_data(socket_core_t *socket);
[89e57cee]207
[46d4d9f]208static int tcp_received_msg(device_id_t, packet_t *, services_t, services_t);
[89e57cee]209static int tcp_process_client_messages(ipc_callid_t, ipc_call_t);
210
[aaa3f33a]211static int tcp_listen_message(socket_cores_t *, int, int);
212static int tcp_connect_message(socket_cores_t *, int, struct sockaddr *,
[89e57cee]213 socklen_t);
[aaa3f33a]214static int tcp_recvfrom_message(socket_cores_t *, int, int, size_t *);
215static int tcp_send_message(socket_cores_t *, int, int, size_t *, int);
216static int tcp_accept_message(socket_cores_t *, int, int, size_t *, size_t *);
217static int tcp_close_message(socket_cores_t *, int);
[21580dd]218
[7c8267b]219/** TCP global data. */
220tcp_globals_t tcp_globals;
[21580dd]221
[46d4d9f]222int tcp_received_msg(device_id_t device_id, packet_t *packet,
[fb04cba8]223 services_t receiver, services_t error)
[7c8267b]224{
[0578271]225 int rc;
[21580dd]226
[7c8267b]227 if (receiver != SERVICE_TCP)
[aadf01e]228 return EREFUSED;
[7c8267b]229
[aadf01e]230 fibril_rwlock_write_lock(&tcp_globals.lock);
[0578271]231 rc = tcp_process_packet(device_id, packet, error);
232 if (rc != EOK)
[aadf01e]233 fibril_rwlock_write_unlock(&tcp_globals.lock);
[7c8267b]234
[0578271]235 printf("receive %d \n", rc);
[21580dd]236
[0578271]237 return rc;
[21580dd]238}
239
[46d4d9f]240int tcp_process_packet(device_id_t device_id, packet_t *packet, services_t error)
[7c8267b]241{
[aadf01e]242 size_t length;
243 size_t offset;
244 int result;
[4e5c7ba]245 tcp_header_t *header;
[88a1bb9]246 socket_core_t *socket;
[4e5c7ba]247 tcp_socket_data_t *socket_data;
[46d4d9f]248 packet_t *next_packet;
[aadf01e]249 size_t total_length;
250 uint32_t checksum;
251 int fragments;
252 icmp_type_t type;
253 icmp_code_t code;
[7c8267b]254 struct sockaddr *src;
255 struct sockaddr *dest;
[aadf01e]256 size_t addrlen;
[0578271]257 int rc;
[aadf01e]258
[89e57cee]259 switch (error) {
260 case SERVICE_NONE:
261 break;
262 case SERVICE_ICMP:
[fb04cba8]263 /* Process error */
[89e57cee]264 result = icmp_client_process_packet(packet, &type, &code, NULL,
265 NULL);
266 if (result < 0)
267 return tcp_release_and_return(packet, result);
[7c8267b]268
[89e57cee]269 length = (size_t) result;
[0578271]270 rc = packet_trim(packet, length, 0);
271 if (rc != EOK)
272 return tcp_release_and_return(packet, rc);
[89e57cee]273 break;
274 default:
275 return tcp_release_and_return(packet, ENOTSUP);
[21580dd]276 }
277
[fb04cba8]278 /* TODO process received ipopts? */
[aadf01e]279 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
[7c8267b]280 if (result < 0)
[aadf01e]281 return tcp_release_and_return(packet, result);
[7c8267b]282
[aadf01e]283 offset = (size_t) result;
[21580dd]284
[aadf01e]285 length = packet_get_data_length(packet);
[7c8267b]286 if (length <= 0)
[aadf01e]287 return tcp_release_and_return(packet, EINVAL);
[7c8267b]288
289 if (length < TCP_HEADER_SIZE + offset)
[aadf01e]290 return tcp_release_and_return(packet, NO_DATA);
[21580dd]291
[fb04cba8]292 /* Trim all but TCP header */
[0578271]293 rc = packet_trim(packet, offset, 0);
294 if (rc != EOK)
295 return tcp_release_and_return(packet, rc);
[21580dd]296
[fb04cba8]297 /* Get tcp header */
[4e5c7ba]298 header = (tcp_header_t *) packet_get_data(packet);
[7c8267b]299 if (!header)
[aadf01e]300 return tcp_release_and_return(packet, NO_DATA);
[7c8267b]301
302// printf("header len %d, port %d \n", TCP_HEADER_LENGTH(header),
303// ntohs(header->destination_port));
[21580dd]304
[aadf01e]305 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
[7c8267b]306 if (result <= 0)
[aadf01e]307 return tcp_release_and_return(packet, result);
[7c8267b]308
[aadf01e]309 addrlen = (size_t) result;
[21580dd]310
[0578271]311 rc = tl_set_address_port(src, addrlen, ntohs(header->source_port));
312 if (rc != EOK)
313 return tcp_release_and_return(packet, rc);
[7c8267b]314
[fb04cba8]315 /* Find the destination socket */
[7c8267b]316 socket = socket_port_find(&tcp_globals.sockets,
[61bfc370]317 ntohs(header->destination_port), (uint8_t *) src, addrlen);
[7c8267b]318 if (!socket) {
[fb04cba8]319 /* Find the listening destination socket */
[7c8267b]320 socket = socket_port_find(&tcp_globals.sockets,
[61bfc370]321 ntohs(header->destination_port),
322 (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
[89e57cee]323 }
[fb04cba8]324
[89e57cee]325 if (!socket) {
326 if (tl_prepare_icmp_packet(tcp_globals.net_phone,
327 tcp_globals.icmp_phone, packet, error) == EOK) {
328 icmp_destination_unreachable_msg(tcp_globals.icmp_phone,
329 ICMP_PORT_UNREACH, 0, packet);
[21580dd]330 }
[89e57cee]331 return EADDRNOTAVAIL;
[21580dd]332 }
[89e57cee]333
[aadf01e]334 printf("socket id %d\n", socket->socket_id);
[4e5c7ba]335 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]336 assert(socket_data);
[21580dd]337
[fb04cba8]338 /* Some data received, clear the timeout counter */
[21580dd]339 socket_data->timeout_count = 0;
340
[fb04cba8]341 /* Count the received packet fragments */
[21580dd]342 next_packet = packet;
343 fragments = 0;
344 checksum = 0;
345 total_length = 0;
[7c8267b]346 do {
[89e57cee]347 fragments++;
[aadf01e]348 length = packet_get_data_length(next_packet);
[7c8267b]349 if (length <= 0)
[aadf01e]350 return tcp_release_and_return(packet, NO_DATA);
[7c8267b]351
[21580dd]352 total_length += length;
[7c8267b]353
[fb04cba8]354 /* Add partial checksum if set */
[7c8267b]355 if (!error) {
356 checksum = compute_checksum(checksum,
357 packet_get_data(packet),
358 packet_get_data_length(packet));
[21580dd]359 }
360
[7c8267b]361 } while ((next_packet = pq_next(next_packet)));
362
[aadf01e]363 fibril_rwlock_write_lock(socket_data->local_lock);
[7c8267b]364
365 if (error)
[89e57cee]366 goto has_error_service;
[7c8267b]367
368 if (socket_data->state == TCP_SOCKET_LISTEN) {
369 if (socket_data->pseudo_header) {
370 free(socket_data->pseudo_header);
371 socket_data->pseudo_header = NULL;
372 socket_data->headerlen = 0;
373 }
374
[0578271]375 rc = ip_client_get_pseudo_header(IPPROTO_TCP, src, addrlen,
376 dest, addrlen, total_length, &socket_data->pseudo_header,
377 &socket_data->headerlen);
378 if (rc != EOK) {
[aadf01e]379 fibril_rwlock_write_unlock(socket_data->local_lock);
[0578271]380 return tcp_release_and_return(packet, rc);
381 }
382 } else {
383 rc = ip_client_set_pseudo_header_data_length(
384 socket_data->pseudo_header, socket_data->headerlen,
385 total_length);
386 if (rc != EOK) {
387 fibril_rwlock_write_unlock(socket_data->local_lock);
388 return tcp_release_and_return(packet, rc);
[21580dd]389 }
[7c8267b]390 }
391
392 checksum = compute_checksum(checksum, socket_data->pseudo_header,
393 socket_data->headerlen);
394 if (flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO) {
395 printf("checksum err %x -> %x\n", header->checksum,
396 flip_checksum(compact_checksum(checksum)));
397 fibril_rwlock_write_unlock(socket_data->local_lock);
398
[0578271]399 rc = tl_prepare_icmp_packet(tcp_globals.net_phone,
400 tcp_globals.icmp_phone, packet, error);
401 if (rc == EOK) {
[fb04cba8]402 /* Checksum error ICMP */
[7c8267b]403 icmp_parameter_problem_msg(tcp_globals.icmp_phone,
404 ICMP_PARAM_POINTER,
405 ((size_t) ((void *) &header->checksum)) -
406 ((size_t) ((void *) header)), packet);
[21580dd]407 }
[7c8267b]408
409 return EINVAL;
[21580dd]410 }
411
[89e57cee]412has_error_service:
[092e4f1]413 fibril_rwlock_write_unlock(&tcp_globals.lock);
[21580dd]414
[fb04cba8]415 /* TODO error reporting/handling */
[7c8267b]416 switch (socket_data->state) {
417 case TCP_SOCKET_LISTEN:
[0578271]418 rc = tcp_process_listen(socket, socket_data, header, packet,
419 src, dest, addrlen);
[7c8267b]420 break;
421 case TCP_SOCKET_SYN_RECEIVED:
[0578271]422 rc = tcp_process_syn_received(socket, socket_data, header,
423 packet);
[7c8267b]424 break;
425 case TCP_SOCKET_SYN_SENT:
[0578271]426 rc = tcp_process_syn_sent(socket, socket_data, header, packet);
[7c8267b]427 break;
428 case TCP_SOCKET_FIN_WAIT_1:
[fb04cba8]429 /* ack changing the state to FIN_WAIT_2 gets processed later */
[7c8267b]430 case TCP_SOCKET_FIN_WAIT_2:
[fb04cba8]431 /* fin changing state to LAST_ACK gets processed later */
[7c8267b]432 case TCP_SOCKET_LAST_ACK:
[fb04cba8]433 /* ack releasing the socket get processed later */
[7c8267b]434 case TCP_SOCKET_CLOSING:
[fb04cba8]435 /* ack releasing the socket gets processed later */
[7c8267b]436 case TCP_SOCKET_ESTABLISHED:
[0578271]437 rc = tcp_process_established(socket, socket_data, header,
438 packet, fragments, total_length);
[7c8267b]439 break;
440 default:
441 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[21580dd]442 }
443
[0578271]444 if (rc != EOK) {
[aadf01e]445 fibril_rwlock_write_unlock(socket_data->local_lock);
[0578271]446 printf("process %d\n", rc);
[21580dd]447 }
[7c8267b]448
[21580dd]449 return EOK;
450}
451
[88a1bb9]452int tcp_process_established(socket_core_t *socket, tcp_socket_data_t *
[46d4d9f]453 socket_data, tcp_header_t *header, packet_t *packet, int fragments,
[fb04cba8]454 size_t total_length)
[7c8267b]455{
[46d4d9f]456 packet_t *next_packet;
457 packet_t *tmp_packet;
[aadf01e]458 uint32_t old_incoming;
459 size_t order;
460 uint32_t sequence_number;
461 size_t length;
462 size_t offset;
463 uint32_t new_sequence_number;
[d493830e]464 bool forced_ack;
[0578271]465 int rc;
[aadf01e]466
467 assert(socket);
468 assert(socket_data);
469 assert(socket->specific_data == socket_data);
470 assert(header);
471 assert(packet);
472
[d493830e]473 forced_ack = false;
474
[aadf01e]475 new_sequence_number = ntohl(header->sequence_number);
[21580dd]476 old_incoming = socket_data->next_incoming;
477
[d493830e]478 if (header->finalize) {
479 socket_data->fin_incoming = new_sequence_number +
480 total_length - TCP_HEADER_LENGTH(header);
481 }
[21580dd]482
[fb04cba8]483 /* Trim begining if containing expected data */
[7c8267b]484 if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
485 socket_data->next_incoming, new_sequence_number + total_length)) {
486
[fb04cba8]487 /* Get the acknowledged offset */
[7c8267b]488 if (socket_data->next_incoming < new_sequence_number) {
489 offset = new_sequence_number -
490 socket_data->next_incoming;
491 } else {
492 offset = socket_data->next_incoming -
493 new_sequence_number;
[21580dd]494 }
[7c8267b]495
[21580dd]496 new_sequence_number += offset;
497 total_length -= offset;
[aadf01e]498 length = packet_get_data_length(packet);
[fb04cba8]499
500 /* Trim the acknowledged data */
[7c8267b]501 while (length <= offset) {
[fb04cba8]502 /* Release the acknowledged packets */
[aadf01e]503 next_packet = pq_next(packet);
[7c8267b]504 pq_release_remote(tcp_globals.net_phone,
505 packet_get_id(packet));
[21580dd]506 packet = next_packet;
507 offset -= length;
[aadf01e]508 length = packet_get_data_length(packet);
[21580dd]509 }
[7c8267b]510
[0578271]511 if (offset > 0) {
512 rc = packet_trim(packet, offset, 0);
513 if (rc != EOK)
514 return tcp_release_and_return(packet, rc);
515 }
[7c8267b]516
[aadf01e]517 assert(new_sequence_number == socket_data->next_incoming);
[21580dd]518 }
519
[fb04cba8]520 /* Release if overflowing the window */
[21580dd]521/*
[7c8267b]522 if (IS_IN_INTERVAL_OVERFLOW(socket_data->next_incoming +
523 socket_data->window, new_sequence_number, new_sequence_number +
524 total_length)) {
525 return tcp_release_and_return(packet, EOVERFLOW);
526 }
527
[21580dd]528 // trim end if overflowing the window
[7c8267b]529 if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
530 socket_data->next_incoming + socket_data->window,
531 new_sequence_number + total_length)) {
[21580dd]532 // get the allowed data length
[7c8267b]533 if (socket_data->next_incoming + socket_data->window <
534 new_sequence_number) {
535 offset = new_sequence_number -
536 socket_data->next_incoming + socket_data->window;
537 } else {
538 offset = socket_data->next_incoming +
539 socket_data->window - new_sequence_number;
[21580dd]540 }
541 next_packet = packet;
542 // trim the overflowing data
[7c8267b]543 while (next_packet && (offset > 0)) {
[aadf01e]544 length = packet_get_data_length(packet);
[7c8267b]545 if (length <= offset)
[aadf01e]546 next_packet = pq_next(next_packet);
[0578271]547 else {
548 rc = packet_trim(next_packet, 0,
549 length - offset));
550 if (rc != EOK)
551 return tcp_release_and_return(packet,
552 rc);
553 }
[21580dd]554 offset -= length;
555 total_length -= length - offset;
556 }
557 // release the overflowing packets
[aadf01e]558 next_packet = pq_next(next_packet);
[7c8267b]559 if (next_packet) {
[21580dd]560 tmp_packet = next_packet;
[aadf01e]561 next_packet = pq_next(next_packet);
562 pq_insert_after(tmp_packet, next_packet);
[7c8267b]563 pq_release_remote(tcp_globals.net_phone,
564 packet_get_id(tmp_packet));
[21580dd]565 }
[7c8267b]566 assert(new_sequence_number + total_length ==
567 socket_data->next_incoming + socket_data->window);
[21580dd]568 }
569*/
[fb04cba8]570 /* The expected one arrived? */
[7c8267b]571 if (new_sequence_number == socket_data->next_incoming) {
[21580dd]572 printf("expected\n");
[fb04cba8]573 /* Process acknowledgement */
[aadf01e]574 tcp_process_acknowledgement(socket, socket_data, header);
[21580dd]575
[fb04cba8]576 /* Remove the header */
[aadf01e]577 total_length -= TCP_HEADER_LENGTH(header);
[0578271]578 rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
579 if (rc != EOK)
580 return tcp_release_and_return(packet, rc);
[21580dd]581
[7c8267b]582 if (total_length) {
[0578271]583 rc = tcp_queue_received_packet(socket, socket_data,
584 packet, fragments, total_length);
585 if (rc != EOK)
586 return rc;
[7c8267b]587 } else {
[21580dd]588 total_length = 1;
589 }
[7c8267b]590
[21580dd]591 socket_data->next_incoming = old_incoming + total_length;
592 packet = socket_data->incoming;
[7c8267b]593 while (packet) {
[0578271]594 rc = pq_get_order(socket_data->incoming, &order, NULL);
595 if (rc != EOK) {
[fb04cba8]596 /* Remove the corrupted packet */
[aadf01e]597 next_packet = pq_detach(packet);
[7c8267b]598 if (packet == socket_data->incoming)
[21580dd]599 socket_data->incoming = next_packet;
[7c8267b]600 pq_release_remote(tcp_globals.net_phone,
601 packet_get_id(packet));
[21580dd]602 packet = next_packet;
603 continue;
604 }
[7c8267b]605
[aadf01e]606 sequence_number = (uint32_t) order;
[7c8267b]607 if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
608 old_incoming, socket_data->next_incoming)) {
[fb04cba8]609 /* Move to the next */
[aadf01e]610 packet = pq_next(packet);
[fb04cba8]611 /* Coninual data? */
[7c8267b]612 } else if (IS_IN_INTERVAL_OVERFLOW(old_incoming,
613 sequence_number, socket_data->next_incoming)) {
[fb04cba8]614 /* Detach the packet */
[aadf01e]615 next_packet = pq_detach(packet);
[7c8267b]616 if (packet == socket_data->incoming)
[21580dd]617 socket_data->incoming = next_packet;
[fb04cba8]618 /* Get data length */
[aadf01e]619 length = packet_get_data_length(packet);
[21580dd]620 new_sequence_number = sequence_number + length;
[7c8267b]621 if (length <= 0) {
[fb04cba8]622 /* Remove the empty packet */
[7c8267b]623 pq_release_remote(tcp_globals.net_phone,
624 packet_get_id(packet));
[21580dd]625 packet = next_packet;
626 continue;
627 }
[fb04cba8]628 /* Exactly following */
[7c8267b]629 if (sequence_number ==
630 socket_data->next_incoming) {
[fb04cba8]631 /* Queue received data */
[0578271]632 rc = tcp_queue_received_packet(socket,
[7c8267b]633 socket_data, packet, 1,
[0578271]634 packet_get_data_length(packet));
635 if (rc != EOK)
636 return rc;
[7c8267b]637 socket_data->next_incoming =
638 new_sequence_number;
[21580dd]639 packet = next_packet;
640 continue;
[fb04cba8]641 /* At least partly following data? */
[89e57cee]642 }
643 if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
644 socket_data->next_incoming, new_sequence_number)) {
[7c8267b]645 if (socket_data->next_incoming <
646 new_sequence_number) {
647 length = new_sequence_number -
648 socket_data->next_incoming;
649 } else {
650 length =
651 socket_data->next_incoming -
652 new_sequence_number;
[21580dd]653 }
[0578271]654 rc = packet_trim(packet,length, 0);
655 if (rc == EOK) {
[fb04cba8]656 /* Queue received data */
[0578271]657 rc = tcp_queue_received_packet(
[7c8267b]658 socket, socket_data, packet,
659 1, packet_get_data_length(
[0578271]660 packet));
661 if (rc != EOK)
662 return rc;
[7c8267b]663 socket_data->next_incoming =
664 new_sequence_number;
[21580dd]665 packet = next_packet;
666 continue;
667 }
668 }
[fb04cba8]669 /* Remove the duplicit or corrupted packet */
[7c8267b]670 pq_release_remote(tcp_globals.net_phone,
671 packet_get_id(packet));
[21580dd]672 packet = next_packet;
673 continue;
[7c8267b]674 } else {
[21580dd]675 break;
676 }
677 }
[7c8267b]678 } else if (IS_IN_INTERVAL(socket_data->next_incoming,
679 new_sequence_number,
680 socket_data->next_incoming + socket_data->window)) {
[21580dd]681 printf("in window\n");
[fb04cba8]682 /* Process acknowledgement */
[aadf01e]683 tcp_process_acknowledgement(socket, socket_data, header);
[21580dd]684
[fb04cba8]685 /* Remove the header */
[aadf01e]686 total_length -= TCP_HEADER_LENGTH(header);
[0578271]687 rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
688 if (rc != EOK)
689 return tcp_release_and_return(packet, rc);
[21580dd]690
[aadf01e]691 next_packet = pq_detach(packet);
692 length = packet_get_data_length(packet);
[0578271]693 rc = pq_add(&socket_data->incoming, packet, new_sequence_number,
694 length);
695 if (rc != EOK) {
[fb04cba8]696 /* Remove the corrupted packets */
[7c8267b]697 pq_release_remote(tcp_globals.net_phone,
698 packet_get_id(packet));
699 pq_release_remote(tcp_globals.net_phone,
700 packet_get_id(next_packet));
701 } else {
702 while (next_packet) {
[21580dd]703 new_sequence_number += length;
[aadf01e]704 tmp_packet = pq_detach(next_packet);
705 length = packet_get_data_length(next_packet);
[0578271]706
707 rc = pq_set_order(next_packet,
708 new_sequence_number, length);
709 if (rc != EOK) {
710 pq_release_remote(tcp_globals.net_phone,
711 packet_get_id(next_packet));
712 }
713 rc = pq_insert_after(packet, next_packet);
714 if (rc != EOK) {
[7c8267b]715 pq_release_remote(tcp_globals.net_phone,
716 packet_get_id(next_packet));
[21580dd]717 }
718 next_packet = tmp_packet;
719 }
720 }
[7c8267b]721 } else {
[21580dd]722 printf("unexpected\n");
[fb04cba8]723 /* Release duplicite or restricted */
[14f1db0]724 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[d493830e]725 forced_ack = true;
[21580dd]726 }
727
[d493830e]728 /* If next in sequence is an incoming FIN */
729 if (socket_data->next_incoming == socket_data->fin_incoming) {
730 /* Advance sequence number */
731 socket_data->next_incoming += 1;
732
733 /* Handle FIN */
[7c8267b]734 switch (socket_data->state) {
735 case TCP_SOCKET_FIN_WAIT_1:
736 case TCP_SOCKET_FIN_WAIT_2:
737 case TCP_SOCKET_CLOSING:
738 socket_data->state = TCP_SOCKET_CLOSING;
739 break;
[d493830e]740 case TCP_SOCKET_ESTABLISHED:
741 /* Queue end-of-data marker on the socket. */
742 tcp_queue_received_end_of_data(socket);
743 socket_data->state = TCP_SOCKET_CLOSE_WAIT;
744 break;
[7c8267b]745 default:
746 socket_data->state = TCP_SOCKET_CLOSE_WAIT;
747 break;
[21580dd]748 }
749 }
750
[aadf01e]751 packet = tcp_get_packets_to_send(socket, socket_data);
[d493830e]752 if (!packet && (socket_data->next_incoming != old_incoming || forced_ack)) {
[fb04cba8]753 /* Create the notification packet */
[0578271]754 rc = tcp_create_notification_packet(&packet, socket,
755 socket_data, 0, 0);
756 if (rc != EOK)
757 return rc;
758 rc = tcp_queue_prepare_packet(socket, socket_data, packet, 1);
759 if (rc != EOK)
760 return rc;
[7c8267b]761 packet = tcp_send_prepare_packet(socket, socket_data, packet, 1,
762 socket_data->last_outgoing + 1);
[21580dd]763 }
[7c8267b]764
[aadf01e]765 fibril_rwlock_write_unlock(socket_data->local_lock);
[7c8267b]766
[fb04cba8]767 /* Send the packet */
[aadf01e]768 tcp_send_packets(socket_data->device_id, packet);
[7c8267b]769
[21580dd]770 return EOK;
771}
772
[88a1bb9]773int tcp_queue_received_packet(socket_core_t *socket,
[46d4d9f]774 tcp_socket_data_t *socket_data, packet_t *packet, int fragments,
[7c8267b]775 size_t total_length)
776{
[f772bc55]777 packet_dimension_t *packet_dimension;
[0578271]778 int rc;
[ede63e4]779
[aadf01e]780 assert(socket);
781 assert(socket_data);
782 assert(socket->specific_data == socket_data);
783 assert(packet);
784 assert(fragments >= 1);
785 assert(socket_data->window > total_length);
[21580dd]786
[fb04cba8]787 /* Queue the received packet */
[0578271]788 rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
789 SOCKET_MAX_RECEIVED_SIZE);
790 if (rc != EOK)
791 return tcp_release_and_return(packet, rc);
792 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
793 &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
794 if (rc != EOK)
795 return tcp_release_and_return(packet, rc);
[21580dd]796
[fb04cba8]797 /* Decrease the window size */
[21580dd]798 socket_data->window -= total_length;
799
[fb04cba8]800 /* Notify the destination socket */
[7c8267b]801 async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
[96b02eb9]802 (sysarg_t) socket->socket_id,
[7c8267b]803 ((packet_dimension->content < socket_data->data_fragment_size) ?
804 packet_dimension->content : socket_data->data_fragment_size), 0, 0,
[96b02eb9]805 (sysarg_t) fragments);
[7c8267b]806
[21580dd]807 return EOK;
808}
809
[d493830e]810/** Queue end-of-data marker on the socket.
811 *
812 * Next element in the sequence space is FIN. Queue end-of-data marker
813 * on the socket.
814 *
815 * @param socket Socket
816 */
817static void tcp_queue_received_end_of_data(socket_core_t *socket)
818{
819 assert(socket != NULL);
820
821 /* Notify the destination socket */
822 async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
823 (sysarg_t) socket->socket_id,
824 0, 0, 0,
825 (sysarg_t) 0 /* 0 fragments == no more data */);
826}
827
[88a1bb9]828int tcp_process_syn_sent(socket_core_t *socket, tcp_socket_data_t *
[46d4d9f]829 socket_data, tcp_header_t *header, packet_t *packet)
[7c8267b]830{
[46d4d9f]831 packet_t *next_packet;
[0578271]832 int rc;
[21580dd]833
[aadf01e]834 assert(socket);
835 assert(socket_data);
836 assert(socket->specific_data == socket_data);
837 assert(header);
838 assert(packet);
[21580dd]839
[7c8267b]840 if (!header->synchronize)
841 return tcp_release_and_return(packet, EINVAL);
842
[fb04cba8]843 /* Process acknowledgement */
[7c8267b]844 tcp_process_acknowledgement(socket, socket_data, header);
845
846 socket_data->next_incoming = ntohl(header->sequence_number) + 1;
[fb04cba8]847
848 /* Release additional packets */
[7c8267b]849 next_packet = pq_detach(packet);
850 if (next_packet) {
851 pq_release_remote(tcp_globals.net_phone,
852 packet_get_id(next_packet));
853 }
[fb04cba8]854
855 /* Trim if longer than the header */
[0578271]856 if (packet_get_data_length(packet) > sizeof(*header)) {
857 rc = packet_trim(packet, 0,
858 packet_get_data_length(packet) - sizeof(*header));
859 if (rc != EOK)
860 return tcp_release_and_return(packet, rc);
[7c8267b]861 }
[fb04cba8]862
[7c8267b]863 tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
864 fibril_mutex_lock(&socket_data->operation.mutex);
865 socket_data->operation.result = tcp_queue_packet(socket, socket_data,
866 packet, 1);
[fb04cba8]867
[7c8267b]868 if (socket_data->operation.result == EOK) {
869 socket_data->state = TCP_SOCKET_ESTABLISHED;
870 packet = tcp_get_packets_to_send(socket, socket_data);
871 if (packet) {
872 fibril_rwlock_write_unlock( socket_data->local_lock);
[fb04cba8]873 /* Send the packet */
[7c8267b]874 tcp_send_packets(socket_data->device_id, packet);
[fb04cba8]875 /* Signal the result */
[7c8267b]876 fibril_condvar_signal( &socket_data->operation.condvar);
877 fibril_mutex_unlock( &socket_data->operation.mutex);
878 return EOK;
[21580dd]879 }
880 }
[fb04cba8]881
[7c8267b]882 fibril_mutex_unlock(&socket_data->operation.mutex);
[aadf01e]883 return tcp_release_and_return(packet, EINVAL);
[21580dd]884}
885
[88a1bb9]886int tcp_process_listen(socket_core_t *listening_socket,
[4e5c7ba]887 tcp_socket_data_t *listening_socket_data, tcp_header_t *header,
[46d4d9f]888 packet_t *packet, struct sockaddr *src, struct sockaddr *dest,
[7c8267b]889 size_t addrlen)
890{
[46d4d9f]891 packet_t *next_packet;
[88a1bb9]892 socket_core_t *socket;
[4e5c7ba]893 tcp_socket_data_t *socket_data;
[aadf01e]894 int socket_id;
895 int listening_socket_id = listening_socket->socket_id;
896 int listening_port = listening_socket->port;
[0578271]897 int rc;
[aadf01e]898
899 assert(listening_socket);
900 assert(listening_socket_data);
901 assert(listening_socket->specific_data == listening_socket_data);
902 assert(header);
903 assert(packet);
904
[7c8267b]905 if (!header->synchronize)
906 return tcp_release_and_return(packet, EINVAL);
[21580dd]907
[4e5c7ba]908 socket_data = (tcp_socket_data_t *) malloc(sizeof(*socket_data));
[7c8267b]909 if (!socket_data)
910 return tcp_release_and_return(packet, ENOMEM);
911
912 tcp_initialize_socket_data(socket_data);
913 socket_data->local_lock = listening_socket_data->local_lock;
914 socket_data->local_sockets = listening_socket_data->local_sockets;
915 socket_data->listening_socket_id = listening_socket->socket_id;
916 socket_data->next_incoming = ntohl(header->sequence_number);
917 socket_data->treshold = socket_data->next_incoming +
918 ntohs(header->window);
919 socket_data->addrlen = addrlen;
920 socket_data->addr = malloc(socket_data->addrlen);
921 if (!socket_data->addr) {
922 free(socket_data);
923 return tcp_release_and_return(packet, ENOMEM);
924 }
[fb04cba8]925
[7c8267b]926 memcpy(socket_data->addr, src, socket_data->addrlen);
927 socket_data->dest_port = ntohs(header->source_port);
[0578271]928 rc = tl_set_address_port(socket_data->addr, socket_data->addrlen,
929 socket_data->dest_port);
930 if (rc != EOK) {
[7c8267b]931 free(socket_data->addr);
932 free(socket_data);
[0578271]933 return tcp_release_and_return(packet, rc);
[7c8267b]934 }
[21580dd]935
[fb04cba8]936 /* Create a socket */
[7c8267b]937 socket_id = -1;
[0578271]938 rc = socket_create(socket_data->local_sockets, listening_socket->phone,
939 socket_data, &socket_id);
940 if (rc != EOK) {
[7c8267b]941 free(socket_data->addr);
942 free(socket_data);
[0578271]943 return tcp_release_and_return(packet, rc);
[7c8267b]944 }
[21580dd]945
[7c8267b]946 printf("new_sock %d\n", socket_id);
947 socket_data->pseudo_header = listening_socket_data->pseudo_header;
948 socket_data->headerlen = listening_socket_data->headerlen;
949 listening_socket_data->pseudo_header = NULL;
950 listening_socket_data->headerlen = 0;
[21580dd]951
[7c8267b]952 fibril_rwlock_write_unlock(socket_data->local_lock);
953 fibril_rwlock_write_lock(&tcp_globals.lock);
[21580dd]954
[fb04cba8]955 /* Find the destination socket */
[7c8267b]956 listening_socket = socket_port_find(&tcp_globals.sockets,
[61bfc370]957 listening_port, (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
[89e57cee]958 if (!listening_socket ||
[7c8267b]959 (listening_socket->socket_id != listening_socket_id)) {
960 fibril_rwlock_write_unlock(&tcp_globals.lock);
[fb04cba8]961 /* A shadow may remain until app hangs up */
[7c8267b]962 return tcp_release_and_return(packet, EOK /*ENOTSOCK*/);
963 }
964 listening_socket_data =
[4e5c7ba]965 (tcp_socket_data_t *) listening_socket->specific_data;
[7c8267b]966 assert(listening_socket_data);
[21580dd]967
[7c8267b]968 fibril_rwlock_write_lock(listening_socket_data->local_lock);
[21580dd]969
[7c8267b]970 socket = socket_cores_find(listening_socket_data->local_sockets,
971 socket_id);
972 if (!socket) {
[fb04cba8]973 /* Where is the socket?!? */
[7c8267b]974 fibril_rwlock_write_unlock(&tcp_globals.lock);
975 return ENOTSOCK;
976 }
[4e5c7ba]977 socket_data = (tcp_socket_data_t *) socket->specific_data;
[7c8267b]978 assert(socket_data);
[21580dd]979
[0578271]980 rc = socket_port_add(&tcp_globals.sockets, listening_port, socket,
[61bfc370]981 (uint8_t *) socket_data->addr, socket_data->addrlen);
[7c8267b]982 assert(socket == socket_port_find(&tcp_globals.sockets, listening_port,
[61bfc370]983 (uint8_t *) socket_data->addr, socket_data->addrlen));
[21580dd]984
[0578271]985// rc = socket_bind_free_port(&tcp_globals.sockets, socket,
[7c8267b]986// TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
987// tcp_globals.last_used_port);
988// tcp_globals.last_used_port = socket->port;
989 fibril_rwlock_write_unlock(&tcp_globals.lock);
[0578271]990 if (rc != EOK) {
[7c8267b]991 socket_destroy(tcp_globals.net_phone, socket->socket_id,
992 socket_data->local_sockets, &tcp_globals.sockets,
993 tcp_free_socket_data);
[0578271]994 return tcp_release_and_return(packet, rc);
[7c8267b]995 }
[21580dd]996
[7c8267b]997 socket_data->state = TCP_SOCKET_LISTEN;
998 socket_data->next_incoming = ntohl(header->sequence_number) + 1;
[21580dd]999
[fb04cba8]1000 /* Release additional packets */
[7c8267b]1001 next_packet = pq_detach(packet);
1002 if (next_packet) {
1003 pq_release_remote(tcp_globals.net_phone,
1004 packet_get_id(next_packet));
[21580dd]1005 }
[7c8267b]1006
[fb04cba8]1007 /* Trim if longer than the header */
[0578271]1008 if (packet_get_data_length(packet) > sizeof(*header)) {
1009 rc = packet_trim(packet, 0,
1010 packet_get_data_length(packet) - sizeof(*header));
1011 if (rc != EOK) {
1012 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1013 socket_data->local_sockets, &tcp_globals.sockets,
1014 tcp_free_socket_data);
1015 return tcp_release_and_return(packet, rc);
1016 }
[7c8267b]1017 }
1018
1019 tcp_prepare_operation_header(socket, socket_data, header, 1, 0);
1020
[0578271]1021 rc = tcp_queue_packet(socket, socket_data, packet, 1);
1022 if (rc != EOK) {
[7c8267b]1023 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1024 socket_data->local_sockets, &tcp_globals.sockets,
1025 tcp_free_socket_data);
[0578271]1026 return rc;
[7c8267b]1027 }
1028
1029 packet = tcp_get_packets_to_send(socket, socket_data);
1030 if (!packet) {
1031 socket_destroy(tcp_globals.net_phone, socket->socket_id,
1032 socket_data->local_sockets, &tcp_globals.sockets,
1033 tcp_free_socket_data);
1034 return EINVAL;
1035 }
1036
1037 socket_data->state = TCP_SOCKET_SYN_RECEIVED;
1038 fibril_rwlock_write_unlock(socket_data->local_lock);
1039
[fb04cba8]1040 /* Send the packet */
[7c8267b]1041 tcp_send_packets(socket_data->device_id, packet);
1042
1043 return EOK;
[21580dd]1044}
1045
[88a1bb9]1046int tcp_process_syn_received(socket_core_t *socket,
[46d4d9f]1047 tcp_socket_data_t *socket_data, tcp_header_t *header, packet_t *packet)
[7c8267b]1048{
[88a1bb9]1049 socket_core_t *listening_socket;
[4e5c7ba]1050 tcp_socket_data_t *listening_socket_data;
[0578271]1051 int rc;
[21580dd]1052
[aadf01e]1053 assert(socket);
1054 assert(socket_data);
1055 assert(socket->specific_data == socket_data);
1056 assert(header);
1057 assert(packet);
[21580dd]1058
[7c8267b]1059 if (!header->acknowledge)
1060 return tcp_release_and_return(packet, EINVAL);
[21580dd]1061
[fb04cba8]1062 /* Process acknowledgement */
[7c8267b]1063 tcp_process_acknowledgement(socket, socket_data, header);
1064
1065 socket_data->next_incoming = ntohl(header->sequence_number); // + 1;
1066 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
1067 socket_data->state = TCP_SOCKET_ESTABLISHED;
1068 listening_socket = socket_cores_find(socket_data->local_sockets,
1069 socket_data->listening_socket_id);
1070 if (listening_socket) {
1071 listening_socket_data =
[4e5c7ba]1072 (tcp_socket_data_t *) listening_socket->specific_data;
[7c8267b]1073 assert(listening_socket_data);
1074
[fb04cba8]1075 /* Queue the received packet */
[0578271]1076 rc = dyn_fifo_push(&listening_socket->accepted,
1077 (-1 * socket->socket_id), listening_socket_data->backlog);
1078 if (rc == EOK) {
[fb04cba8]1079 /* Notify the destination socket */
[7c8267b]1080 async_msg_5(socket->phone, NET_SOCKET_ACCEPTED,
[96b02eb9]1081 (sysarg_t) listening_socket->socket_id,
[7c8267b]1082 socket_data->data_fragment_size, TCP_HEADER_SIZE,
[96b02eb9]1083 0, (sysarg_t) socket->socket_id);
[7c8267b]1084
1085 fibril_rwlock_write_unlock(socket_data->local_lock);
1086 return EOK;
[21580dd]1087 }
[7c8267b]1088 }
[fb04cba8]1089 /* Send FIN */
[7c8267b]1090 socket_data->state = TCP_SOCKET_FIN_WAIT_1;
[21580dd]1091
[fb04cba8]1092 /* Create the notification packet */
[0578271]1093 rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
1094 if (rc != EOK)
1095 return rc;
[21580dd]1096
[fb04cba8]1097 /* Send the packet */
[0578271]1098 rc = tcp_queue_packet(socket, socket_data, packet, 1);
1099 if (rc != EOK)
1100 return rc;
[21580dd]1101
[fb04cba8]1102 /* Flush packets */
[7c8267b]1103 packet = tcp_get_packets_to_send(socket, socket_data);
1104 fibril_rwlock_write_unlock(socket_data->local_lock);
1105 if (packet) {
[fb04cba8]1106 /* Send the packet */
[7c8267b]1107 tcp_send_packets(socket_data->device_id, packet);
[21580dd]1108 }
[7c8267b]1109
1110 return EOK;
[21580dd]1111}
1112
[88a1bb9]1113void tcp_process_acknowledgement(socket_core_t *socket,
[4e5c7ba]1114 tcp_socket_data_t *socket_data, tcp_header_t *header)
[7c8267b]1115{
[aadf01e]1116 size_t number;
1117 size_t length;
[46d4d9f]1118 packet_t *packet;
1119 packet_t *next;
1120 packet_t *acknowledged = NULL;
[aadf01e]1121 uint32_t old;
1122
1123 assert(socket);
1124 assert(socket_data);
1125 assert(socket->specific_data == socket_data);
1126 assert(header);
1127
[7c8267b]1128 if (!header->acknowledge)
1129 return;
1130
1131 number = ntohl(header->acknowledgement_number);
[fb04cba8]1132
1133 /* If more data acknowledged */
[7c8267b]1134 if (number != socket_data->expected) {
1135 old = socket_data->expected;
1136 if (IS_IN_INTERVAL_OVERFLOW(old, socket_data->fin_outgoing,
1137 number)) {
1138 switch (socket_data->state) {
1139 case TCP_SOCKET_FIN_WAIT_1:
1140 socket_data->state = TCP_SOCKET_FIN_WAIT_2;
1141 break;
1142 case TCP_SOCKET_LAST_ACK:
1143 case TCP_SOCKET_CLOSING:
[fb04cba8]1144 /*
1145 * FIN acknowledged - release the socket in
1146 * another fibril.
1147 */
[7c8267b]1148 tcp_prepare_timeout(tcp_release_after_timeout,
1149 socket, socket_data, 0,
1150 TCP_SOCKET_TIME_WAIT,
1151 NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT, true);
1152 break;
1153 default:
1154 break;
[21580dd]1155 }
[7c8267b]1156 }
[fb04cba8]1157
1158 /* Update the treshold if higher than set */
[7c8267b]1159 if (number + ntohs(header->window) >
1160 socket_data->expected + socket_data->treshold) {
1161 socket_data->treshold = number + ntohs(header->window) -
1162 socket_data->expected;
1163 }
[fb04cba8]1164
1165 /* Set new expected sequence number */
[7c8267b]1166 socket_data->expected = number;
1167 socket_data->expected_count = 1;
1168 packet = socket_data->outgoing;
1169 while (pq_get_order(packet, &number, &length) == EOK) {
1170 if (IS_IN_INTERVAL_OVERFLOW((uint32_t) old,
1171 (uint32_t) (number + length),
1172 (uint32_t) socket_data->expected)) {
1173 next = pq_detach(packet);
1174 if (packet == socket_data->outgoing)
1175 socket_data->outgoing = next;
1176
[fb04cba8]1177 /* Add to acknowledged or release */
[7c8267b]1178 if (pq_add(&acknowledged, packet, 0, 0) != EOK)
1179 pq_release_remote(tcp_globals.net_phone,
1180 packet_get_id(packet));
1181 packet = next;
1182 } else if (old < socket_data->expected)
1183 break;
1184 }
[fb04cba8]1185
1186 /* Release acknowledged */
[7c8267b]1187 if (acknowledged) {
1188 pq_release_remote(tcp_globals.net_phone,
1189 packet_get_id(acknowledged));
1190 }
1191 return;
[fb04cba8]1192 /* If the same as the previous time */
[7c8267b]1193 }
[fb04cba8]1194
[7c8267b]1195 if (number == socket_data->expected) {
[fb04cba8]1196 /* Increase the counter */
[89e57cee]1197 socket_data->expected_count++;
[7c8267b]1198 if (socket_data->expected_count == TCP_FAST_RETRANSMIT_COUNT) {
1199 socket_data->expected_count = 1;
[fb04cba8]1200 /* TODO retransmit lock */
[7c8267b]1201 //tcp_retransmit_packet(socket, socket_data, number);
[21580dd]1202 }
1203 }
1204}
1205
[89e57cee]1206/** Processes the TCP message.
1207 *
1208 * @param[in] callid The message identifier.
1209 * @param[in] call The message parameters.
1210 * @param[out] answer The message answer parameters.
1211 * @param[out] answer_count The last parameter for the actual answer in the
1212 * answer parameter.
[1bfd3d3]1213 * @return EOK on success.
1214 * @return ENOTSUP if the message is not known.
[89e57cee]1215 *
1216 * @see tcp_interface.h
1217 * @see IS_NET_TCP_MESSAGE()
1218 */
[014dd57b]1219int tl_module_message(ipc_callid_t callid, ipc_call_t *call,
[774e6d1a]1220 ipc_call_t *answer, size_t *answer_count)
[7c8267b]1221{
[aadf01e]1222 assert(call);
1223 assert(answer);
1224 assert(answer_count);
[21580dd]1225
[aadf01e]1226 *answer_count = 0;
[228e490]1227 switch (IPC_GET_IMETHOD(*call)) {
[7c8267b]1228 case IPC_M_CONNECT_TO_ME:
1229 return tcp_process_client_messages(callid, *call);
[21580dd]1230 }
[7c8267b]1231
[21580dd]1232 return ENOTSUP;
1233}
1234
[4e5c7ba]1235void tcp_refresh_socket_data(tcp_socket_data_t *socket_data)
[7c8267b]1236{
[aadf01e]1237 assert(socket_data);
[21580dd]1238
[aadf01e]1239 bzero(socket_data, sizeof(*socket_data));
[21580dd]1240 socket_data->state = TCP_SOCKET_INITIAL;
[ede63e4]1241 socket_data->device_id = DEVICE_INVALID_ID;
[21580dd]1242 socket_data->window = NET_DEFAULT_TCP_WINDOW;
1243 socket_data->treshold = socket_data->window;
1244 socket_data->last_outgoing = TCP_INITIAL_SEQUENCE_NUMBER;
1245 socket_data->timeout = NET_DEFAULT_TCP_INITIAL_TIMEOUT;
1246 socket_data->acknowledged = socket_data->last_outgoing;
1247 socket_data->next_outgoing = socket_data->last_outgoing + 1;
1248 socket_data->expected = socket_data->next_outgoing;
1249}
1250
[4e5c7ba]1251void tcp_initialize_socket_data(tcp_socket_data_t *socket_data)
[7c8267b]1252{
[aadf01e]1253 assert(socket_data);
[21580dd]1254
[aadf01e]1255 tcp_refresh_socket_data(socket_data);
1256 fibril_mutex_initialize(&socket_data->operation.mutex);
1257 fibril_condvar_initialize(&socket_data->operation.condvar);
[ede63e4]1258 socket_data->data_fragment_size = MAX_TCP_FRAGMENT_SIZE;
[21580dd]1259}
1260
[7c8267b]1261int tcp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
1262{
[aadf01e]1263 int res;
1264 bool keep_on_going = true;
1265 socket_cores_t local_sockets;
[774e6d1a]1266 int app_phone = IPC_GET_PHONE(call);
[7c8267b]1267 struct sockaddr *addr;
[6092b56e]1268 int socket_id;
[aadf01e]1269 size_t addrlen;
[e417b96]1270 size_t size;
[aadf01e]1271 fibril_rwlock_t lock;
1272 ipc_call_t answer;
[774e6d1a]1273 size_t answer_count;
[4e5c7ba]1274 tcp_socket_data_t *socket_data;
[88a1bb9]1275 socket_core_t *socket;
[f772bc55]1276 packet_dimension_t *packet_dimension;
[21580dd]1277
1278 /*
1279 * Accept the connection
1280 * - Answer the first IPC_M_CONNECT_ME_TO call.
1281 */
[2e99277]1282 res = EOK;
1283 answer_count = 0;
[21580dd]1284
[aadf01e]1285 socket_cores_initialize(&local_sockets);
1286 fibril_rwlock_initialize(&lock);
[21580dd]1287
[7c8267b]1288 while (keep_on_going) {
[2e99277]1289
[fb04cba8]1290 /* Answer the call */
[aadf01e]1291 answer_call(callid, res, &answer, answer_count);
[fb04cba8]1292 /* Refresh data */
[aadf01e]1293 refresh_answer(&answer, &answer_count);
[fb04cba8]1294 /* Get the next call */
[aadf01e]1295 callid = async_get_call(&call);
[21580dd]1296
[fb04cba8]1297 /* Process the call */
[228e490]1298 switch (IPC_GET_IMETHOD(call)) {
[7c8267b]1299 case IPC_M_PHONE_HUNGUP:
1300 keep_on_going = false;
1301 res = EHANGUP;
1302 break;
1303
1304 case NET_SOCKET:
1305 socket_data =
[4e5c7ba]1306 (tcp_socket_data_t *) malloc(sizeof(*socket_data));
[7c8267b]1307 if (!socket_data) {
1308 res = ENOMEM;
[21580dd]1309 break;
[7c8267b]1310 }
1311
1312 tcp_initialize_socket_data(socket_data);
1313 socket_data->local_lock = &lock;
1314 socket_data->local_sockets = &local_sockets;
1315 fibril_rwlock_write_lock(&lock);
1316 socket_id = SOCKET_GET_SOCKET_ID(call);
1317 res = socket_create(&local_sockets, app_phone,
1318 socket_data, &socket_id);
1319 SOCKET_SET_SOCKET_ID(answer, socket_id);
1320 fibril_rwlock_write_unlock(&lock);
1321 if (res != EOK) {
1322 free(socket_data);
[21580dd]1323 break;
[7c8267b]1324 }
1325 if (tl_get_ip_packet_dimension(tcp_globals.ip_phone,
1326 &tcp_globals.dimensions, DEVICE_INVALID_ID,
1327 &packet_dimension) == EOK) {
1328 SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
1329 ((packet_dimension->content <
1330 socket_data->data_fragment_size) ?
1331 packet_dimension->content :
1332 socket_data->data_fragment_size));
1333 }
1334// SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_TCP_FRAGMENT_SIZE);
1335 SOCKET_SET_HEADER_SIZE(answer, TCP_HEADER_SIZE);
1336 answer_count = 3;
1337 break;
1338
1339 case NET_SOCKET_BIND:
[7880d58]1340 res = async_data_write_accept((void **) &addr, false,
1341 0, 0, 0, &addrlen);
[7c8267b]1342 if (res != EOK)
[21580dd]1343 break;
[7c8267b]1344 fibril_rwlock_write_lock(&tcp_globals.lock);
1345 fibril_rwlock_write_lock(&lock);
1346 res = socket_bind(&local_sockets, &tcp_globals.sockets,
1347 SOCKET_GET_SOCKET_ID(call), addr, addrlen,
1348 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
1349 tcp_globals.last_used_port);
1350 if (res == EOK) {
1351 socket = socket_cores_find(&local_sockets,
1352 SOCKET_GET_SOCKET_ID(call));
1353 if (socket) {
[4e5c7ba]1354 socket_data = (tcp_socket_data_t *)
[7c8267b]1355 socket->specific_data;
1356 assert(socket_data);
1357 socket_data->state = TCP_SOCKET_LISTEN;
[21580dd]1358 }
[7c8267b]1359 }
1360 fibril_rwlock_write_unlock(&lock);
1361 fibril_rwlock_write_unlock(&tcp_globals.lock);
1362 free(addr);
1363 break;
1364
1365 case NET_SOCKET_LISTEN:
1366 fibril_rwlock_read_lock(&tcp_globals.lock);
1367// fibril_rwlock_write_lock(&tcp_globals.lock);
1368 fibril_rwlock_write_lock(&lock);
1369 res = tcp_listen_message(&local_sockets,
1370 SOCKET_GET_SOCKET_ID(call),
1371 SOCKET_GET_BACKLOG(call));
1372 fibril_rwlock_write_unlock(&lock);
1373// fibril_rwlock_write_unlock(&tcp_globals.lock);
1374 fibril_rwlock_read_unlock(&tcp_globals.lock);
1375 break;
1376
1377 case NET_SOCKET_CONNECT:
[7880d58]1378 res = async_data_write_accept((void **) &addr, false,
1379 0, 0, 0, &addrlen);
[7c8267b]1380 if (res != EOK)
[21580dd]1381 break;
[fb04cba8]1382 /*
1383 * The global lock may be released in the
1384 * tcp_connect_message() function.
1385 */
[7c8267b]1386 fibril_rwlock_write_lock(&tcp_globals.lock);
1387 fibril_rwlock_write_lock(&lock);
1388 res = tcp_connect_message(&local_sockets,
1389 SOCKET_GET_SOCKET_ID(call), addr, addrlen);
1390 if (res != EOK) {
[aadf01e]1391 fibril_rwlock_write_unlock(&lock);
[7c8267b]1392 fibril_rwlock_write_unlock(&tcp_globals.lock);
1393 free(addr);
1394 }
1395 break;
1396
1397 case NET_SOCKET_ACCEPT:
1398 fibril_rwlock_read_lock(&tcp_globals.lock);
1399 fibril_rwlock_write_lock(&lock);
1400 res = tcp_accept_message(&local_sockets,
1401 SOCKET_GET_SOCKET_ID(call),
1402 SOCKET_GET_NEW_SOCKET_ID(call), &size, &addrlen);
1403 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
1404 fibril_rwlock_write_unlock(&lock);
1405 fibril_rwlock_read_unlock(&tcp_globals.lock);
1406 if (res > 0) {
1407 SOCKET_SET_SOCKET_ID(answer, res);
1408 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
1409 answer_count = 3;
1410 }
1411 break;
1412
1413 case NET_SOCKET_SEND:
1414 fibril_rwlock_read_lock(&tcp_globals.lock);
1415 fibril_rwlock_write_lock(&lock);
1416 res = tcp_send_message(&local_sockets,
1417 SOCKET_GET_SOCKET_ID(call),
1418 SOCKET_GET_DATA_FRAGMENTS(call), &size,
1419 SOCKET_GET_FLAGS(call));
1420 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
1421 if (res != EOK) {
[aadf01e]1422 fibril_rwlock_write_unlock(&lock);
1423 fibril_rwlock_read_unlock(&tcp_globals.lock);
[7c8267b]1424 } else {
1425 answer_count = 2;
1426 }
1427 break;
1428
1429 case NET_SOCKET_SENDTO:
[7880d58]1430 res = async_data_write_accept((void **) &addr, false,
1431 0, 0, 0, &addrlen);
[7c8267b]1432 if (res != EOK)
[21580dd]1433 break;
[7c8267b]1434 fibril_rwlock_read_lock(&tcp_globals.lock);
1435 fibril_rwlock_write_lock(&lock);
1436 res = tcp_send_message(&local_sockets,
1437 SOCKET_GET_SOCKET_ID(call),
1438 SOCKET_GET_DATA_FRAGMENTS(call), &size,
1439 SOCKET_GET_FLAGS(call));
1440 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
1441 if (res != EOK) {
[aadf01e]1442 fibril_rwlock_write_unlock(&lock);
1443 fibril_rwlock_read_unlock(&tcp_globals.lock);
[7c8267b]1444 } else {
1445 answer_count = 2;
1446 }
1447 free(addr);
1448 break;
1449
1450 case NET_SOCKET_RECV:
1451 fibril_rwlock_read_lock(&tcp_globals.lock);
1452 fibril_rwlock_write_lock(&lock);
1453 res = tcp_recvfrom_message(&local_sockets,
1454 SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
1455 NULL);
1456 fibril_rwlock_write_unlock(&lock);
1457 fibril_rwlock_read_unlock(&tcp_globals.lock);
1458 if (res > 0) {
1459 SOCKET_SET_READ_DATA_LENGTH(answer, res);
1460 answer_count = 1;
1461 res = EOK;
1462 }
1463 break;
1464
1465 case NET_SOCKET_RECVFROM:
1466 fibril_rwlock_read_lock(&tcp_globals.lock);
1467 fibril_rwlock_write_lock(&lock);
1468 res = tcp_recvfrom_message(&local_sockets,
1469 SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
1470 &addrlen);
1471 fibril_rwlock_write_unlock(&lock);
1472 fibril_rwlock_read_unlock(&tcp_globals.lock);
1473 if (res > 0) {
1474 SOCKET_SET_READ_DATA_LENGTH(answer, res);
1475 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
1476 answer_count = 3;
1477 res = EOK;
1478 }
1479 break;
1480
1481 case NET_SOCKET_CLOSE:
1482 fibril_rwlock_write_lock(&tcp_globals.lock);
1483 fibril_rwlock_write_lock(&lock);
1484 res = tcp_close_message(&local_sockets,
1485 SOCKET_GET_SOCKET_ID(call));
1486 if (res != EOK) {
1487 fibril_rwlock_write_unlock(&lock);
1488 fibril_rwlock_write_unlock(&tcp_globals.lock);
1489 }
1490 break;
1491
1492 case NET_SOCKET_GETSOCKOPT:
1493 case NET_SOCKET_SETSOCKOPT:
1494 default:
1495 res = ENOTSUP;
1496 break;
[21580dd]1497 }
1498 }
1499
[fb04cba8]1500 /* Release the application phone */
[a8a13d0]1501 ipc_hangup(app_phone);
1502
[21580dd]1503 printf("release\n");
[fb04cba8]1504 /* Release all local sockets */
[7c8267b]1505 socket_cores_release(tcp_globals.net_phone, &local_sockets,
1506 &tcp_globals.sockets, tcp_free_socket_data);
[21580dd]1507
1508 return EOK;
1509}
1510
[7c8267b]1511int tcp_timeout(void *data)
1512{
[f772bc55]1513 tcp_timeout_t *timeout = data;
[aadf01e]1514 int keep_write_lock = false;
[88a1bb9]1515 socket_core_t *socket;
[4e5c7ba]1516 tcp_socket_data_t *socket_data;
[21580dd]1517
[aadf01e]1518 assert(timeout);
[21580dd]1519
[fb04cba8]1520 /* Sleep the given timeout */
[aadf01e]1521 async_usleep(timeout->timeout);
[fb04cba8]1522 /* Lock the globals */
[7c8267b]1523 if (timeout->globals_read_only)
[aadf01e]1524 fibril_rwlock_read_lock(&tcp_globals.lock);
[7c8267b]1525 else
[aadf01e]1526 fibril_rwlock_write_lock(&tcp_globals.lock);
[7c8267b]1527
[fb04cba8]1528 /* Find the pending operation socket */
[7c8267b]1529 socket = socket_port_find(&tcp_globals.sockets, timeout->port,
1530 timeout->key, timeout->key_length);
[89e57cee]1531 if (!socket || (socket->socket_id != timeout->socket_id))
[7c8267b]1532 goto out;
1533
[4e5c7ba]1534 socket_data = (tcp_socket_data_t *) socket->specific_data;
[7c8267b]1535 assert(socket_data);
1536 if (socket_data->local_sockets != timeout->local_sockets)
1537 goto out;
1538
1539 fibril_rwlock_write_lock(socket_data->local_lock);
1540 if (timeout->sequence_number) {
[fb04cba8]1541 /* Increase the timeout counter */
[89e57cee]1542 socket_data->timeout_count++;
[7c8267b]1543 if (socket_data->timeout_count == TCP_MAX_TIMEOUTS) {
[fb04cba8]1544 /* TODO release as connection lost */
[7c8267b]1545 //tcp_refresh_socket_data(socket_data);
1546 fibril_rwlock_write_unlock(socket_data->local_lock);
1547 } else {
[fb04cba8]1548 /* Retransmit */
[7c8267b]1549// tcp_retransmit_packet(socket,
1550// socket_data, timeout->sequence_number);
1551 fibril_rwlock_write_unlock(socket_data->local_lock);
[21580dd]1552 }
[7c8267b]1553 } else {
1554 fibril_mutex_lock(&socket_data->operation.mutex);
[fb04cba8]1555 /* Set the timeout operation result if state not changed */
[7c8267b]1556 if (socket_data->state == timeout->state) {
1557 socket_data->operation.result = ETIMEOUT;
[fb04cba8]1558
1559 /* Notify the main fibril */
[7c8267b]1560 fibril_condvar_signal(&socket_data->operation.condvar);
[fb04cba8]1561
1562 /* Keep the global write lock */
[7c8267b]1563 keep_write_lock = true;
1564 } else {
[fb04cba8]1565 /*
1566 * Operation is ok, do nothing.
1567 * Unlocking from now on, so the unlocking
1568 * order does not matter.
1569 */
[7c8267b]1570 fibril_rwlock_write_unlock(socket_data->local_lock);
1571 }
1572 fibril_mutex_unlock(&socket_data->operation.mutex);
[21580dd]1573 }
[7c8267b]1574
1575out:
[fb04cba8]1576 /* Unlock only if no socket */
[7c8267b]1577 if (timeout->globals_read_only)
[aadf01e]1578 fibril_rwlock_read_unlock(&tcp_globals.lock);
[7c8267b]1579 else if (!keep_write_lock)
[fb04cba8]1580 /* Release if not desired */
[aadf01e]1581 fibril_rwlock_write_unlock(&tcp_globals.lock);
[7c8267b]1582
[fb04cba8]1583 /* Release the timeout structure */
[aadf01e]1584 free(timeout);
[21580dd]1585 return EOK;
1586}
1587
[7c8267b]1588int tcp_release_after_timeout(void *data)
1589{
[f772bc55]1590 tcp_timeout_t *timeout = data;
[88a1bb9]1591 socket_core_t *socket;
[4e5c7ba]1592 tcp_socket_data_t *socket_data;
[7c8267b]1593 fibril_rwlock_t *local_lock;
[21580dd]1594
[aadf01e]1595 assert(timeout);
[21580dd]1596
[fb04cba8]1597 /* Sleep the given timeout */
[aadf01e]1598 async_usleep(timeout->timeout);
[fb04cba8]1599
1600 /* Lock the globals */
[aadf01e]1601 fibril_rwlock_write_lock(&tcp_globals.lock);
[fb04cba8]1602
1603 /* Find the pending operation socket */
[7c8267b]1604 socket = socket_port_find(&tcp_globals.sockets, timeout->port,
1605 timeout->key, timeout->key_length);
[fb04cba8]1606
[7c8267b]1607 if (socket && (socket->socket_id == timeout->socket_id)) {
[4e5c7ba]1608 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]1609 assert(socket_data);
[7c8267b]1610 if (socket_data->local_sockets == timeout->local_sockets) {
[21580dd]1611 local_lock = socket_data->local_lock;
[aadf01e]1612 fibril_rwlock_write_lock(local_lock);
[7c8267b]1613 socket_destroy(tcp_globals.net_phone,
1614 timeout->socket_id, timeout->local_sockets,
1615 &tcp_globals.sockets, tcp_free_socket_data);
[aadf01e]1616 fibril_rwlock_write_unlock(local_lock);
[21580dd]1617 }
1618 }
[fb04cba8]1619
1620 /* Unlock the globals */
[aadf01e]1621 fibril_rwlock_write_unlock(&tcp_globals.lock);
[fb04cba8]1622
1623 /* Release the timeout structure */
[aadf01e]1624 free(timeout);
[fb04cba8]1625
[21580dd]1626 return EOK;
1627}
1628
[88a1bb9]1629void tcp_retransmit_packet(socket_core_t *socket, tcp_socket_data_t *
[fb04cba8]1630 socket_data, size_t sequence_number)
[7c8267b]1631{
[46d4d9f]1632 packet_t *packet;
1633 packet_t *copy;
[aadf01e]1634 size_t data_length;
[21580dd]1635
[aadf01e]1636 assert(socket);
1637 assert(socket_data);
1638 assert(socket->specific_data == socket_data);
[21580dd]1639
[fb04cba8]1640 /* Sent packet? */
[aadf01e]1641 packet = pq_find(socket_data->outgoing, sequence_number);
1642 printf("retransmit %d\n", packet_get_id(packet));
[7c8267b]1643 if (packet) {
[aadf01e]1644 pq_get_order(packet, NULL, &data_length);
[7c8267b]1645 copy = tcp_prepare_copy(socket, socket_data, packet,
1646 data_length, sequence_number);
[aadf01e]1647 fibril_rwlock_write_unlock(socket_data->local_lock);
[7c8267b]1648// printf("r send %d\n", packet_get_id(packet));
1649 if (copy)
[aadf01e]1650 tcp_send_packets(socket_data->device_id, copy);
[7c8267b]1651 } else {
[aadf01e]1652 fibril_rwlock_write_unlock(socket_data->local_lock);
[21580dd]1653 }
1654}
1655
[aaa3f33a]1656int tcp_listen_message(socket_cores_t *local_sockets, int socket_id,
[fb04cba8]1657 int backlog)
[7c8267b]1658{
[88a1bb9]1659 socket_core_t *socket;
[4e5c7ba]1660 tcp_socket_data_t *socket_data;
[21580dd]1661
[aadf01e]1662 assert(local_sockets);
[21580dd]1663
[7c8267b]1664 if (backlog < 0)
[aadf01e]1665 return EINVAL;
[7c8267b]1666
[fb04cba8]1667 /* Find the socket */
[aadf01e]1668 socket = socket_cores_find(local_sockets, socket_id);
[7c8267b]1669 if (!socket)
[aadf01e]1670 return ENOTSOCK;
[7c8267b]1671
[fb04cba8]1672 /* Get the socket specific data */
[4e5c7ba]1673 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]1674 assert(socket_data);
[fb04cba8]1675
1676 /* Set the backlog */
[21580dd]1677 socket_data->backlog = backlog;
[7c8267b]1678
[21580dd]1679 return EOK;
1680}
1681
[aaa3f33a]1682int tcp_connect_message(socket_cores_t *local_sockets, int socket_id,
[7c8267b]1683 struct sockaddr *addr, socklen_t addrlen)
1684{
[88a1bb9]1685 socket_core_t *socket;
[0578271]1686 int rc;
[21580dd]1687
[aadf01e]1688 assert(local_sockets);
1689 assert(addr);
1690 assert(addrlen > 0);
[21580dd]1691
[fb04cba8]1692 /* Find the socket */
[aadf01e]1693 socket = socket_cores_find(local_sockets, socket_id);
[7c8267b]1694 if (!socket)
[aadf01e]1695 return ENOTSOCK;
[7c8267b]1696
[0578271]1697 rc = tcp_connect_core(socket, local_sockets, addr, addrlen);
1698 if (rc != EOK) {
[aadf01e]1699 tcp_free_socket_data(socket);
[fb04cba8]1700 /* Unbind if bound */
[7c8267b]1701 if (socket->port > 0) {
1702 socket_ports_exclude(&tcp_globals.sockets,
1703 socket->port);
[21580dd]1704 socket->port = 0;
1705 }
1706 }
[0578271]1707 return rc;
[21580dd]1708}
1709
[aaa3f33a]1710int tcp_connect_core(socket_core_t *socket, socket_cores_t *local_sockets,
[7c8267b]1711 struct sockaddr *addr, socklen_t addrlen)
1712{
[4e5c7ba]1713 tcp_socket_data_t *socket_data;
[46d4d9f]1714 packet_t *packet;
[0578271]1715 int rc;
[21580dd]1716
[aadf01e]1717 assert(socket);
1718 assert(addr);
1719 assert(addrlen > 0);
[21580dd]1720
[fb04cba8]1721 /* Get the socket specific data */
[4e5c7ba]1722 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]1723 assert(socket_data);
1724 assert(socket->specific_data == socket_data);
[7c8267b]1725 if ((socket_data->state != TCP_SOCKET_INITIAL) &&
1726 ((socket_data->state != TCP_SOCKET_LISTEN) ||
1727 (socket->port <= 0)))
[21580dd]1728 return EINVAL;
[7c8267b]1729
[fb04cba8]1730 /* Get the destination port */
[0578271]1731 rc = tl_get_address_port(addr, addrlen, &socket_data->dest_port);
1732 if (rc != EOK)
1733 return rc;
1734
[7c8267b]1735 if (socket->port <= 0) {
[fb04cba8]1736 /* Try to find a free port */
[0578271]1737 rc = socket_bind_free_port(&tcp_globals.sockets, socket,
1738 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
1739 tcp_globals.last_used_port);
1740 if (rc != EOK)
1741 return rc;
[fb04cba8]1742 /* Set the next port as the search starting port number */
[21580dd]1743 tcp_globals.last_used_port = socket->port;
1744 }
[7c8267b]1745
[0578271]1746 rc = ip_get_route_req(tcp_globals.ip_phone, IPPROTO_TCP,
[7c8267b]1747 addr, addrlen, &socket_data->device_id,
[0578271]1748 &socket_data->pseudo_header, &socket_data->headerlen);
1749 if (rc != EOK)
1750 return rc;
[21580dd]1751
[fb04cba8]1752 /* Create the notification packet */
[0578271]1753 rc = tcp_create_notification_packet(&packet, socket, socket_data, 1, 0);
1754 if (rc != EOK)
1755 return rc;
[21580dd]1756
[fb04cba8]1757 /* Unlock the globals and wait for an operation */
[aadf01e]1758 fibril_rwlock_write_unlock(&tcp_globals.lock);
[21580dd]1759
1760 socket_data->addr = addr;
1761 socket_data->addrlen = addrlen;
[fb04cba8]1762
1763 /* Send the packet */
[0578271]1764
1765 if (((rc = tcp_queue_packet(socket, socket_data, packet, 1)) != EOK) ||
1766 ((rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data, 0,
1767 TCP_SOCKET_INITIAL, NET_DEFAULT_TCP_INITIAL_TIMEOUT, false)) !=
1768 EOK)) {
[21580dd]1769 socket_data->addr = NULL;
1770 socket_data->addrlen = 0;
[aadf01e]1771 fibril_rwlock_write_lock(&tcp_globals.lock);
[7c8267b]1772 } else {
[aadf01e]1773 packet = tcp_get_packets_to_send(socket, socket_data);
[7c8267b]1774 if (packet) {
[aadf01e]1775 fibril_mutex_lock(&socket_data->operation.mutex);
1776 fibril_rwlock_write_unlock(socket_data->local_lock);
[fb04cba8]1777
[3ac66f69]1778 socket_data->state = TCP_SOCKET_SYN_SENT;
1779
[fb04cba8]1780 /* Send the packet */
[aadf01e]1781 printf("connecting %d\n", packet_get_id(packet));
1782 tcp_send_packets(socket_data->device_id, packet);
[7c8267b]1783
[fb04cba8]1784 /* Wait for a reply */
[7c8267b]1785 fibril_condvar_wait(&socket_data->operation.condvar,
1786 &socket_data->operation.mutex);
[0578271]1787 rc = socket_data->operation.result;
1788 if (rc != EOK) {
[21580dd]1789 socket_data->addr = NULL;
1790 socket_data->addrlen = 0;
1791 }
[7c8267b]1792 } else {
[21580dd]1793 socket_data->addr = NULL;
1794 socket_data->addrlen = 0;
[0578271]1795 rc = EINTR;
[21580dd]1796 }
1797 }
1798
[aadf01e]1799 fibril_mutex_unlock(&socket_data->operation.mutex);
[0578271]1800 return rc;
[21580dd]1801}
1802
[88a1bb9]1803int tcp_queue_prepare_packet(socket_core_t *socket,
[46d4d9f]1804 tcp_socket_data_t *socket_data, packet_t *packet, size_t data_length)
[7c8267b]1805{
[4e5c7ba]1806 tcp_header_t *header;
[0578271]1807 int rc;
[21580dd]1808
[aadf01e]1809 assert(socket);
1810 assert(socket_data);
1811 assert(socket->specific_data == socket_data);
[21580dd]1812
[fb04cba8]1813 /* Get TCP header */
[4e5c7ba]1814 header = (tcp_header_t *) packet_get_data(packet);
[7c8267b]1815 if (!header)
[aadf01e]1816 return NO_DATA;
[7c8267b]1817
[aadf01e]1818 header->destination_port = htons(socket_data->dest_port);
1819 header->source_port = htons(socket->port);
1820 header->sequence_number = htonl(socket_data->next_outgoing);
[7c8267b]1821
[0578271]1822 rc = packet_set_addr(packet, NULL, (uint8_t *) socket_data->addr,
1823 socket_data->addrlen);
1824 if (rc != EOK)
[aadf01e]1825 return tcp_release_and_return(packet, EINVAL);
[7c8267b]1826
[fb04cba8]1827 /* Remember the outgoing FIN */
[7c8267b]1828 if (header->finalize)
[21580dd]1829 socket_data->fin_outgoing = socket_data->next_outgoing;
[7c8267b]1830
[21580dd]1831 return EOK;
1832}
1833
[88a1bb9]1834int tcp_queue_packet(socket_core_t *socket, tcp_socket_data_t *socket_data,
[46d4d9f]1835 packet_t *packet, size_t data_length)
[7c8267b]1836{
[0578271]1837 int rc;
[21580dd]1838
[aadf01e]1839 assert(socket);
1840 assert(socket_data);
1841 assert(socket->specific_data == socket_data);
[21580dd]1842
[0578271]1843 rc = tcp_queue_prepare_packet(socket, socket_data, packet, data_length);
1844 if (rc != EOK)
1845 return rc;
[21580dd]1846
[0578271]1847 rc = pq_add(&socket_data->outgoing, packet, socket_data->next_outgoing,
1848 data_length);
1849 if (rc != EOK)
1850 return tcp_release_and_return(packet, rc);
[7c8267b]1851
[21580dd]1852 socket_data->next_outgoing += data_length;
1853 return EOK;
1854}
1855
[46d4d9f]1856packet_t *tcp_get_packets_to_send(socket_core_t *socket, tcp_socket_data_t *
[fb04cba8]1857 socket_data)
[7c8267b]1858{
[46d4d9f]1859 packet_t *packet;
1860 packet_t *copy;
1861 packet_t *sending = NULL;
1862 packet_t *previous = NULL;
[aadf01e]1863 size_t data_length;
[0578271]1864 int rc;
[21580dd]1865
[aadf01e]1866 assert(socket);
1867 assert(socket_data);
1868 assert(socket->specific_data == socket_data);
[21580dd]1869
[aadf01e]1870 packet = pq_find(socket_data->outgoing, socket_data->last_outgoing + 1);
[7c8267b]1871 while (packet) {
[aadf01e]1872 pq_get_order(packet, NULL, &data_length);
[7c8267b]1873
[fb04cba8]1874 /*
1875 * Send only if fits into the window, respecting the possible
1876 * overflow.
1877 */
[7c8267b]1878 if (!IS_IN_INTERVAL_OVERFLOW(
1879 (uint32_t) socket_data->last_outgoing,
1880 (uint32_t) (socket_data->last_outgoing + data_length),
1881 (uint32_t) (socket_data->expected + socket_data->treshold)))
[21580dd]1882 break;
[7c8267b]1883
1884 copy = tcp_prepare_copy(socket, socket_data, packet,
1885 data_length, socket_data->last_outgoing + 1);
1886 if (!copy)
1887 return sending;
1888
1889 if (!sending) {
1890 sending = copy;
[0578271]1891 } else {
1892 rc = pq_insert_after(previous, copy);
1893 if (rc != EOK) {
1894 pq_release_remote(tcp_globals.net_phone,
1895 packet_get_id(copy));
1896 return sending;
1897 }
[7c8267b]1898 }
1899
1900 previous = copy;
1901 packet = pq_next(packet);
[fb04cba8]1902
1903 /* Overflow occurred? */
[89e57cee]1904 if (!packet &&
[7c8267b]1905 (socket_data->last_outgoing > socket_data->next_outgoing)) {
1906 printf("gpts overflow\n");
[fb04cba8]1907 /* Continue from the beginning */
[7c8267b]1908 packet = socket_data->outgoing;
[21580dd]1909 }
[7c8267b]1910 socket_data->last_outgoing += data_length;
[21580dd]1911 }
[7c8267b]1912
[21580dd]1913 return sending;
1914}
1915
[46d4d9f]1916packet_t *tcp_send_prepare_packet(socket_core_t *socket, tcp_socket_data_t *
1917 socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
[7c8267b]1918{
[4e5c7ba]1919 tcp_header_t *header;
[aadf01e]1920 uint32_t checksum;
[0578271]1921 int rc;
[21580dd]1922
[aadf01e]1923 assert(socket);
1924 assert(socket_data);
1925 assert(socket->specific_data == socket_data);
[21580dd]1926
[fb04cba8]1927 /* Adjust the pseudo header */
[0578271]1928 rc = ip_client_set_pseudo_header_data_length(socket_data->pseudo_header,
1929 socket_data->headerlen, packet_get_data_length(packet));
1930 if (rc != EOK) {
[14f1db0]1931 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[21580dd]1932 return NULL;
1933 }
1934
[fb04cba8]1935 /* Get the header */
[4e5c7ba]1936 header = (tcp_header_t *) packet_get_data(packet);
[7c8267b]1937 if (!header) {
[14f1db0]1938 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[21580dd]1939 return NULL;
1940 }
[aadf01e]1941 assert(ntohl(header->sequence_number) == sequence_number);
[21580dd]1942
[fb04cba8]1943 /* Adjust the header */
[7c8267b]1944 if (socket_data->next_incoming) {
1945 header->acknowledgement_number =
1946 htonl(socket_data->next_incoming);
[21580dd]1947 header->acknowledge = 1;
1948 }
[aadf01e]1949 header->window = htons(socket_data->window);
[21580dd]1950
[fb04cba8]1951 /* Checksum */
[21580dd]1952 header->checksum = 0;
[7c8267b]1953 checksum = compute_checksum(0, socket_data->pseudo_header,
1954 socket_data->headerlen);
[0578271]1955 checksum = compute_checksum(checksum,
1956 (uint8_t *) packet_get_data(packet),
[7c8267b]1957 packet_get_data_length(packet));
[aadf01e]1958 header->checksum = htons(flip_checksum(compact_checksum(checksum)));
[7c8267b]1959
[fb04cba8]1960 /* Prepare the packet */
[0578271]1961 rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
1962 if (rc != EOK) {
1963 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
1964 return NULL;
1965 }
[fb04cba8]1966
[0578271]1967 rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data,
1968 sequence_number, socket_data->state, socket_data->timeout, true);
1969 if (rc != EOK) {
[14f1db0]1970 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[21580dd]1971 return NULL;
1972 }
[7c8267b]1973
[21580dd]1974 return packet;
1975}
1976
[46d4d9f]1977packet_t *tcp_prepare_copy(socket_core_t *socket, tcp_socket_data_t *
1978 socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
[7c8267b]1979{
[46d4d9f]1980 packet_t *copy;
[21580dd]1981
[aadf01e]1982 assert(socket);
1983 assert(socket_data);
1984 assert(socket->specific_data == socket_data);
[21580dd]1985
[fb04cba8]1986 /* Make a copy of the packet */
[aadf01e]1987 copy = packet_get_copy(tcp_globals.net_phone, packet);
[7c8267b]1988 if (!copy)
[aadf01e]1989 return NULL;
[21580dd]1990
[7c8267b]1991 return tcp_send_prepare_packet(socket, socket_data, copy, data_length,
1992 sequence_number);
[21580dd]1993}
1994
[46d4d9f]1995void tcp_send_packets(device_id_t device_id, packet_t *packet)
[7c8267b]1996{
[46d4d9f]1997 packet_t *next;
[21580dd]1998
[7c8267b]1999 while (packet) {
[aadf01e]2000 next = pq_detach(packet);
[7c8267b]2001 ip_send_msg(tcp_globals.ip_phone, device_id, packet,
2002 SERVICE_TCP, 0);
[21580dd]2003 packet = next;
2004 }
2005}
2006
[88a1bb9]2007void tcp_prepare_operation_header(socket_core_t *socket,
[4e5c7ba]2008 tcp_socket_data_t *socket_data, tcp_header_t *header, int synchronize,
[7c8267b]2009 int finalize)
2010{
[aadf01e]2011 assert(socket);
2012 assert(socket_data);
2013 assert(socket->specific_data == socket_data);
2014 assert(header);
[21580dd]2015
[aadf01e]2016 bzero(header, sizeof(*header));
2017 header->source_port = htons(socket->port);
2018 header->source_port = htons(socket_data->dest_port);
2019 header->header_length = TCP_COMPUTE_HEADER_LENGTH(sizeof(*header));
[21580dd]2020 header->synchronize = synchronize;
2021 header->finalize = finalize;
2022}
2023
[fb04cba8]2024int tcp_prepare_timeout(int (*timeout_function)(void *tcp_timeout_t),
[88a1bb9]2025 socket_core_t *socket, tcp_socket_data_t *socket_data,
[7c8267b]2026 size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout,
2027 int globals_read_only)
2028{
[f772bc55]2029 tcp_timeout_t *operation_timeout;
[aadf01e]2030 fid_t fibril;
[21580dd]2031
[aadf01e]2032 assert(socket);
2033 assert(socket_data);
2034 assert(socket->specific_data == socket_data);
[21580dd]2035
[fb04cba8]2036 /* Prepare the timeout with key bundle structure */
[7c8267b]2037 operation_timeout = malloc(sizeof(*operation_timeout) +
2038 socket->key_length + 1);
2039 if (!operation_timeout)
[aadf01e]2040 return ENOMEM;
[7c8267b]2041
[aadf01e]2042 bzero(operation_timeout, sizeof(*operation_timeout));
[21580dd]2043 operation_timeout->globals_read_only = globals_read_only;
2044 operation_timeout->port = socket->port;
2045 operation_timeout->local_sockets = socket_data->local_sockets;
2046 operation_timeout->socket_id = socket->socket_id;
2047 operation_timeout->timeout = timeout;
2048 operation_timeout->sequence_number = sequence_number;
2049 operation_timeout->state = state;
2050
[fb04cba8]2051 /* Copy the key */
[61bfc370]2052 operation_timeout->key = ((uint8_t *) operation_timeout) +
[7c8267b]2053 sizeof(*operation_timeout);
[21580dd]2054 operation_timeout->key_length = socket->key_length;
[aadf01e]2055 memcpy(operation_timeout->key, socket->key, socket->key_length);
2056 operation_timeout->key[operation_timeout->key_length] = '\0';
[21580dd]2057
[fb04cba8]2058 /* Prepare the timeouting thread */
[aadf01e]2059 fibril = fibril_create(timeout_function, operation_timeout);
[7c8267b]2060 if (!fibril) {
[aadf01e]2061 free(operation_timeout);
[be942bc]2062 return ENOMEM;
[21580dd]2063 }
[be942bc]2064
[7c8267b]2065// fibril_mutex_lock(&socket_data->operation.mutex);
[fb04cba8]2066 /* Start the timeout fibril */
[aadf01e]2067 fibril_add_ready(fibril);
[21580dd]2068 //socket_data->state = state;
2069 return EOK;
2070}
2071
[aaa3f33a]2072int tcp_recvfrom_message(socket_cores_t *local_sockets, int socket_id,
[fb04cba8]2073 int flags, size_t *addrlen)
[7c8267b]2074{
[88a1bb9]2075 socket_core_t *socket;
[4e5c7ba]2076 tcp_socket_data_t *socket_data;
[aadf01e]2077 int packet_id;
[46d4d9f]2078 packet_t *packet;
[aadf01e]2079 size_t length;
[0578271]2080 int rc;
[21580dd]2081
[aadf01e]2082 assert(local_sockets);
[21580dd]2083
[fb04cba8]2084 /* Find the socket */
[aadf01e]2085 socket = socket_cores_find(local_sockets, socket_id);
[7c8267b]2086 if (!socket)
[aadf01e]2087 return ENOTSOCK;
[7c8267b]2088
[fb04cba8]2089 /* Get the socket specific data */
[7c8267b]2090 if (!socket->specific_data)
[aadf01e]2091 return NO_DATA;
[7c8267b]2092
[4e5c7ba]2093 socket_data = (tcp_socket_data_t *) socket->specific_data;
[21580dd]2094
[fb04cba8]2095 /* Check state */
[7c8267b]2096 if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
2097 (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
[21580dd]2098 return ENOTCONN;
2099
[fb04cba8]2100 /* Send the source address if desired */
[7c8267b]2101 if (addrlen) {
[0578271]2102 rc = data_reply(socket_data->addr, socket_data->addrlen);
2103 if (rc != EOK)
2104 return rc;
[aadf01e]2105 *addrlen = socket_data->addrlen;
[21580dd]2106 }
2107
[fb04cba8]2108 /* Get the next received packet */
[aadf01e]2109 packet_id = dyn_fifo_value(&socket->received);
[7c8267b]2110 if (packet_id < 0)
[aadf01e]2111 return NO_DATA;
[7c8267b]2112
[0578271]2113 rc = packet_translate_remote(tcp_globals.net_phone, &packet, packet_id);
2114 if (rc != EOK)
2115 return rc;
[21580dd]2116
[fb04cba8]2117 /* Reply the packets */
[0578271]2118 rc = socket_reply_packets(packet, &length);
2119 if (rc != EOK)
2120 return rc;
[21580dd]2121
[fb04cba8]2122 /* Release the packet */
[aadf01e]2123 dyn_fifo_pop(&socket->received);
[14f1db0]2124 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[fb04cba8]2125
2126 /* Return the total length */
[aadf01e]2127 return (int) length;
[21580dd]2128}
2129
[aaa3f33a]2130int tcp_send_message(socket_cores_t *local_sockets, int socket_id,
[fb04cba8]2131 int fragments, size_t *data_fragment_size, int flags)
[7c8267b]2132{
[88a1bb9]2133 socket_core_t *socket;
[4e5c7ba]2134 tcp_socket_data_t *socket_data;
[f772bc55]2135 packet_dimension_t *packet_dimension;
[46d4d9f]2136 packet_t *packet;
[aadf01e]2137 size_t total_length;
[4e5c7ba]2138 tcp_header_t *header;
[aadf01e]2139 int index;
2140 int result;
[0578271]2141 int rc;
[21580dd]2142
[aadf01e]2143 assert(local_sockets);
2144 assert(data_fragment_size);
[21580dd]2145
[fb04cba8]2146 /* Find the socket */
[aadf01e]2147 socket = socket_cores_find(local_sockets, socket_id);
[7c8267b]2148 if (!socket)
[aadf01e]2149 return ENOTSOCK;
[7c8267b]2150
[fb04cba8]2151 /* Get the socket specific data */
[7c8267b]2152 if (!socket->specific_data)
[aadf01e]2153 return NO_DATA;
[7c8267b]2154
[4e5c7ba]2155 socket_data = (tcp_socket_data_t *) socket->specific_data;
[21580dd]2156
[fb04cba8]2157 /* Check state */
[7c8267b]2158 if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
2159 (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
[21580dd]2160 return ENOTCONN;
2161
[0578271]2162 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
2163 &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
2164 if (rc != EOK)
2165 return rc;
[21580dd]2166
[7c8267b]2167 *data_fragment_size =
2168 ((packet_dimension->content < socket_data->data_fragment_size) ?
2169 packet_dimension->content : socket_data->data_fragment_size);
[21580dd]2170
[89e57cee]2171 for (index = 0; index < fragments; index++) {
[fb04cba8]2172 /* Read the data fragment */
[7c8267b]2173 result = tl_socket_read_packet_data(tcp_globals.net_phone,
2174 &packet, TCP_HEADER_SIZE, packet_dimension,
2175 socket_data->addr, socket_data->addrlen);
2176 if (result < 0)
[aadf01e]2177 return result;
[7c8267b]2178
[aadf01e]2179 total_length = (size_t) result;
[fb04cba8]2180
2181 /* Prefix the TCP header */
[aadf01e]2182 header = PACKET_PREFIX(packet, tcp_header_t);
[7c8267b]2183 if (!header)
[aadf01e]2184 return tcp_release_and_return(packet, ENOMEM);
[7c8267b]2185
[aadf01e]2186 tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
[86f6121]2187 rc = tcp_queue_packet(socket, socket_data, packet, total_length);
[0578271]2188 if (rc != EOK)
2189 return rc;
[21580dd]2190 }
2191
[fb04cba8]2192 /* Flush packets */
[aadf01e]2193 packet = tcp_get_packets_to_send(socket, socket_data);
2194 fibril_rwlock_write_unlock(socket_data->local_lock);
2195 fibril_rwlock_read_unlock(&tcp_globals.lock);
[7c8267b]2196
2197 if (packet) {
[fb04cba8]2198 /* Send the packet */
[aadf01e]2199 tcp_send_packets(socket_data->device_id, packet);
[21580dd]2200 }
2201
2202 return EOK;
2203}
2204
[7c8267b]2205int
[aaa3f33a]2206tcp_close_message(socket_cores_t *local_sockets, int socket_id)
[7c8267b]2207{
[88a1bb9]2208 socket_core_t *socket;
[4e5c7ba]2209 tcp_socket_data_t *socket_data;
[46d4d9f]2210 packet_t *packet;
[0578271]2211 int rc;
[21580dd]2212
[fb04cba8]2213 /* Find the socket */
[aadf01e]2214 socket = socket_cores_find(local_sockets, socket_id);
[7c8267b]2215 if (!socket)
[aadf01e]2216 return ENOTSOCK;
[7c8267b]2217
[fb04cba8]2218 /* Get the socket specific data */
[4e5c7ba]2219 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]2220 assert(socket_data);
[21580dd]2221
[fb04cba8]2222 /* Check state */
[7c8267b]2223 switch (socket_data->state) {
2224 case TCP_SOCKET_ESTABLISHED:
2225 socket_data->state = TCP_SOCKET_FIN_WAIT_1;
2226 break;
2227
2228 case TCP_SOCKET_CLOSE_WAIT:
2229 socket_data->state = TCP_SOCKET_LAST_ACK;
2230 break;
2231
2232// case TCP_SOCKET_LISTEN:
2233
2234 default:
[fb04cba8]2235 /* Just destroy */
[0578271]2236 rc = socket_destroy(tcp_globals.net_phone, socket_id,
[7c8267b]2237 local_sockets, &tcp_globals.sockets,
[0578271]2238 tcp_free_socket_data);
2239 if (rc == EOK) {
[7c8267b]2240 fibril_rwlock_write_unlock(socket_data->local_lock);
2241 fibril_rwlock_write_unlock(&tcp_globals.lock);
2242 }
[0578271]2243 return rc;
[21580dd]2244 }
[7c8267b]2245
[fb04cba8]2246 /*
2247 * Send FIN.
2248 * TODO should I wait to complete?
2249 */
[21580dd]2250
[fb04cba8]2251 /* Create the notification packet */
[0578271]2252 rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
2253 if (rc != EOK)
2254 return rc;
[21580dd]2255
[fb04cba8]2256 /* Send the packet */
[0578271]2257 rc = tcp_queue_packet(socket, socket_data, packet, 1);
2258 if (rc != EOK)
2259 return rc;
[21580dd]2260
[fb04cba8]2261 /* Flush packets */
[aadf01e]2262 packet = tcp_get_packets_to_send(socket, socket_data);
2263 fibril_rwlock_write_unlock(socket_data->local_lock);
2264 fibril_rwlock_write_unlock(&tcp_globals.lock);
[7c8267b]2265
2266 if (packet) {
[fb04cba8]2267 /* Send the packet */
[aadf01e]2268 tcp_send_packets(socket_data->device_id, packet);
[21580dd]2269 }
[7c8267b]2270
[21580dd]2271 return EOK;
2272}
2273
[46d4d9f]2274int tcp_create_notification_packet(packet_t **packet, socket_core_t *socket,
[4e5c7ba]2275 tcp_socket_data_t *socket_data, int synchronize, int finalize)
[7c8267b]2276{
[f772bc55]2277 packet_dimension_t *packet_dimension;
[4e5c7ba]2278 tcp_header_t *header;
[0578271]2279 int rc;
[21580dd]2280
[aadf01e]2281 assert(packet);
[21580dd]2282
[fb04cba8]2283 /* Get the device packet dimension */
[0578271]2284 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
2285 &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
2286 if (rc != EOK)
2287 return rc;
[7c8267b]2288
[fb04cba8]2289 /* Get a new packet */
[7c8267b]2290 *packet = packet_get_4_remote(tcp_globals.net_phone, TCP_HEADER_SIZE,
2291 packet_dimension->addr_len, packet_dimension->prefix,
2292 packet_dimension->suffix);
2293
2294 if (!*packet)
[aadf01e]2295 return ENOMEM;
[7c8267b]2296
[fb04cba8]2297 /* Allocate space in the packet */
[aadf01e]2298 header = PACKET_SUFFIX(*packet, tcp_header_t);
[7c8267b]2299 if (!header)
[aadf01e]2300 tcp_release_and_return(*packet, ENOMEM);
[21580dd]2301
[7c8267b]2302 tcp_prepare_operation_header(socket, socket_data, header, synchronize,
2303 finalize);
2304
[21580dd]2305 return EOK;
2306}
2307
[aaa3f33a]2308int tcp_accept_message(socket_cores_t *local_sockets, int socket_id,
[89e57cee]2309 int new_socket_id, size_t *data_fragment_size, size_t *addrlen)
[7c8267b]2310{
[88a1bb9]2311 socket_core_t *accepted;
2312 socket_core_t *socket;
[4e5c7ba]2313 tcp_socket_data_t *socket_data;
[f772bc55]2314 packet_dimension_t *packet_dimension;
[0578271]2315 int rc;
[21580dd]2316
[aadf01e]2317 assert(local_sockets);
2318 assert(data_fragment_size);
2319 assert(addrlen);
[21580dd]2320
[fb04cba8]2321 /* Find the socket */
[aadf01e]2322 socket = socket_cores_find(local_sockets, socket_id);
[7c8267b]2323 if (!socket)
[aadf01e]2324 return ENOTSOCK;
[7c8267b]2325
[fb04cba8]2326 /* Get the socket specific data */
[4e5c7ba]2327 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]2328 assert(socket_data);
[21580dd]2329
[fb04cba8]2330 /* Check state */
[7c8267b]2331 if (socket_data->state != TCP_SOCKET_LISTEN)
[21580dd]2332 return EINVAL;
2333
[7c8267b]2334 do {
[aadf01e]2335 socket_id = dyn_fifo_value(&socket->accepted);
[7c8267b]2336 if (socket_id < 0)
[aadf01e]2337 return ENOTSOCK;
[d510c0fe]2338 socket_id *= -1;
[21580dd]2339
[aadf01e]2340 accepted = socket_cores_find(local_sockets, socket_id);
[7c8267b]2341 if (!accepted)
[aadf01e]2342 return ENOTSOCK;
[7c8267b]2343
[fb04cba8]2344 /* Get the socket specific data */
[4e5c7ba]2345 socket_data = (tcp_socket_data_t *) accepted->specific_data;
[aadf01e]2346 assert(socket_data);
[fb04cba8]2347 /* TODO can it be in another state? */
[7c8267b]2348 if (socket_data->state == TCP_SOCKET_ESTABLISHED) {
[0578271]2349 rc = data_reply(socket_data->addr,
2350 socket_data->addrlen);
2351 if (rc != EOK)
2352 return rc;
2353 rc = tl_get_ip_packet_dimension(tcp_globals.ip_phone,
2354 &tcp_globals.dimensions, socket_data->device_id,
2355 &packet_dimension);
2356 if (rc != EOK)
2357 return rc;
[aadf01e]2358 *addrlen = socket_data->addrlen;
[7c8267b]2359
2360 *data_fragment_size =
2361 ((packet_dimension->content <
2362 socket_data->data_fragment_size) ?
2363 packet_dimension->content :
2364 socket_data->data_fragment_size);
2365
2366 if (new_socket_id > 0) {
[0578271]2367 rc = socket_cores_update(local_sockets,
2368 accepted->socket_id, new_socket_id);
2369 if (rc != EOK)
2370 return rc;
[ede63e4]2371 accepted->socket_id = new_socket_id;
2372 }
[21580dd]2373 }
[aadf01e]2374 dyn_fifo_pop(&socket->accepted);
[7c8267b]2375 } while (socket_data->state != TCP_SOCKET_ESTABLISHED);
2376
[aadf01e]2377 printf("ret accept %d\n", accepted->socket_id);
[21580dd]2378 return accepted->socket_id;
2379}
2380
[88a1bb9]2381void tcp_free_socket_data(socket_core_t *socket)
[7c8267b]2382{
[4e5c7ba]2383 tcp_socket_data_t *socket_data;
[21580dd]2384
[aadf01e]2385 assert(socket);
[21580dd]2386
[aadf01e]2387 printf("destroy_socket %d\n", socket->socket_id);
[21580dd]2388
[fb04cba8]2389 /* Get the socket specific data */
[4e5c7ba]2390 socket_data = (tcp_socket_data_t *) socket->specific_data;
[aadf01e]2391 assert(socket_data);
[fb04cba8]2392
2393 /* Free the pseudo header */
[7c8267b]2394 if (socket_data->pseudo_header) {
2395 if (socket_data->headerlen) {
[21580dd]2396 printf("d pseudo\n");
[aadf01e]2397 free(socket_data->pseudo_header);
[21580dd]2398 socket_data->headerlen = 0;
2399 }
2400 socket_data->pseudo_header = NULL;
2401 }
[fb04cba8]2402
[21580dd]2403 socket_data->headerlen = 0;
[fb04cba8]2404
2405 /* Free the address */
[7c8267b]2406 if (socket_data->addr) {
2407 if (socket_data->addrlen) {
[21580dd]2408 printf("d addr\n");
[aadf01e]2409 free(socket_data->addr);
[21580dd]2410 socket_data->addrlen = 0;
2411 }
2412 socket_data->addr = NULL;
2413 }
2414 socket_data->addrlen = 0;
2415}
2416
[89e57cee]2417/** Releases the packet and returns the result.
2418 *
2419 * @param[in] packet The packet queue to be released.
2420 * @param[in] result The result to be returned.
2421 * @return The result parameter.
2422 */
[46d4d9f]2423int tcp_release_and_return(packet_t *packet, int result)
[7c8267b]2424{
[14f1db0]2425 pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
[21580dd]2426 return result;
2427}
2428
[014dd57b]2429/** Process IPC messages from the IP module
[849ed54]2430 *
[014dd57b]2431 * @param[in] iid Message identifier.
2432 * @param[in,out] icall Message parameters.
[849ed54]2433 *
2434 */
[014dd57b]2435static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall)
[849ed54]2436{
[014dd57b]2437 packet_t *packet;
2438 int rc;
2439
[7c8267b]2440 while (true) {
[014dd57b]2441 switch (IPC_GET_IMETHOD(*icall)) {
2442 case NET_TL_RECEIVED:
2443 rc = packet_translate_remote(tcp_globals.net_phone, &packet,
2444 IPC_GET_PACKET(*icall));
2445 if (rc == EOK)
2446 rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
2447 SERVICE_TCP, IPC_GET_ERROR(*icall));
2448
2449 ipc_answer_0(iid, (sysarg_t) rc);
2450 break;
2451 default:
2452 ipc_answer_0(iid, (sysarg_t) ENOTSUP);
2453 }
2454
2455 iid = async_get_call(icall);
[849ed54]2456 }
2457}
2458
[014dd57b]2459/** Initialize the TCP module.
2460 *
2461 * @param[in] net_phone Network module phone.
2462 *
2463 * @return EOK on success.
2464 * @return ENOMEM if there is not enough memory left.
[849ed54]2465 *
2466 */
[014dd57b]2467int tl_initialize(int net_phone)
[849ed54]2468{
[014dd57b]2469 fibril_rwlock_initialize(&tcp_globals.lock);
2470 fibril_rwlock_write_lock(&tcp_globals.lock);
2471
2472 tcp_globals.net_phone = net_phone;
2473
2474 tcp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP,
2475 ICMP_CONNECT_TIMEOUT);
2476 tcp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_TCP,
2477 SERVICE_TCP, tcp_receiver);
2478 if (tcp_globals.ip_phone < 0) {
2479 fibril_rwlock_write_unlock(&tcp_globals.lock);
2480 return tcp_globals.ip_phone;
2481 }
2482
2483 int rc = socket_ports_initialize(&tcp_globals.sockets);
2484 if (rc != EOK)
2485 goto out;
[7c8267b]2486
[014dd57b]2487 rc = packet_dimensions_initialize(&tcp_globals.dimensions);
2488 if (rc != EOK) {
2489 socket_ports_destroy(&tcp_globals.sockets);
2490 goto out;
2491 }
2492
2493 tcp_globals.last_used_port = TCP_FREE_PORTS_START - 1;
2494
2495out:
2496 fibril_rwlock_write_unlock(&tcp_globals.lock);
[0578271]2497 return rc;
[849ed54]2498}
2499
[014dd57b]2500int main(int argc, char *argv[])
2501{
2502 return tl_module_start(SERVICE_TCP);
2503}
2504
[21580dd]2505/** @}
2506 */
Note: See TracBrowser for help on using the repository browser.