source: mainline/uspace/srv/net/tl/tcp/tcp.c@ 2afc54d

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

do not intermix low-level IPC methods with async framework methods

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