source: mainline/uspace/srv/net/tl/tcp/tcp.c@ 774e6d1a

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

partial networking stack overhaul

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