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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c8c43cae was c8c43cae, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Merge TCP rewrite.

  • Property mode set to 100644
File size: 10.3 KB
RevLine 
[21580dd]1/*
[c5808b41]2 * Copyright (c) 2011 Jiri Svoboda
[21580dd]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
[c5808b41]33/**
34 * @file TCP (Transmission Control Protocol) network module
[21580dd]35 */
36
37#include <async.h>
[1812a0d]38#include <byteorder.h>
[e98b1d5]39#include <errno.h>
[c5808b41]40#include <io/log.h>
41#include <stdio.h>
42#include <task.h>
[21580dd]43
[1812a0d]44#include <icmp_remote.h>
[849ed54]45#include <ip_client.h>
46#include <ip_interface.h>
[1812a0d]47#include <ipc/services.h>
48#include <ipc/tl.h>
[849ed54]49#include <tl_common.h>
[014dd57b]50#include <tl_skel.h>
[1812a0d]51#include <packet_client.h>
52#include <packet_remote.h>
[014dd57b]53
[8218b6b]54#include "ncsim.h"
[762b48a]55#include "pdu.h"
[c5808b41]56#include "rqueue.h"
[04cd242]57#include "sock.h"
[1812a0d]58#include "std.h"
[014dd57b]59#include "tcp.h"
[c5808b41]60#include "test.h"
[21580dd]61
[c5808b41]62#define NAME "tcp"
[21580dd]63
[04cd242]64async_sess_t *net_sess;
[1812a0d]65static async_sess_t *icmp_sess;
[0ac2158]66async_sess_t *ip_sess;
[04cd242]67packet_dimensions_t pkt_dims;
[21580dd]68
[1812a0d]69static void tcp_received_pdu(tcp_pdu_t *pdu);
[21580dd]70
[1812a0d]71/* Pull up packets into a single memory block. */
72static int pq_pullup(packet_t *packet, void **data, size_t *dsize)
73{
74 packet_t *npacket;
75 size_t tot_len;
76 int length;
[21580dd]77
[1812a0d]78 npacket = packet;
79 tot_len = 0;
80 do {
81 length = packet_get_data_length(packet);
82 if (length <= 0)
83 return EINVAL;
[21580dd]84
[1812a0d]85 tot_len += length;
86 } while ((npacket = pq_next(npacket)) != NULL);
[21580dd]87
[1812a0d]88 uint8_t *buf;
89 uint8_t *dp;
[21580dd]90
[1812a0d]91 buf = calloc(tot_len, 1);
92 if (buf == NULL) {
93 free(buf);
94 return ENOMEM;
95 }
[7c8267b]96
[1812a0d]97 npacket = packet;
98 dp = buf;
99 do {
100 length = packet_get_data_length(packet);
101 if (length <= 0) {
102 free(buf);
103 return EINVAL;
104 }
[7c8267b]105
[1812a0d]106 memcpy(dp, packet_get_data(packet), length);
107 dp += length;
108 } while ((npacket = pq_next(npacket)) != NULL);
[21580dd]109
[1812a0d]110 *data = buf;
111 *dsize = tot_len;
112 return EOK;
[21580dd]113}
114
[1812a0d]115/** Process packet received from network layer. */
[c8c43cae]116static int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
[1812a0d]117 services_t error)
[7c8267b]118{
[0578271]119 int rc;
[1812a0d]120 size_t offset;
121 int length;
122 struct sockaddr_in *src_addr;
123 struct sockaddr_in *dest_addr;
124 size_t addr_len;
125
126 log_msg(LVL_DEBUG, "tcp_received_msg()");
[aadf01e]127
[89e57cee]128 switch (error) {
129 case SERVICE_NONE:
130 break;
131 case SERVICE_ICMP:
132 default:
[1812a0d]133 log_msg(LVL_WARN, "Unsupported service number %u",
134 (unsigned)error);
135 pq_release_remote(net_sess, packet_get_id(packet));
136 return ENOTSUP;
[21580dd]137 }
138
[1812a0d]139 /* Process and trim off IP header */
140 log_msg(LVL_DEBUG, "tcp_received_msg() - IP header");
[7c8267b]141
[1812a0d]142 rc = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
143 if (rc < 0) {
144 log_msg(LVL_WARN, "ip_client_process_packet() failed");
145 pq_release_remote(net_sess, packet_get_id(packet));
146 return rc;
147 }
[21580dd]148
[1812a0d]149 offset = (size_t)rc;
[aadf01e]150 length = packet_get_data_length(packet);
[21580dd]151
[1812a0d]152 if (length < 0 || (size_t)length < offset) {
153 log_msg(LVL_WARN, "length=%d, dropping.", length);
154 pq_release_remote(net_sess, packet_get_id(packet));
155 return EINVAL;
[89e57cee]156 }
[fb04cba8]157
[1812a0d]158 addr_len = packet_get_addr(packet, (uint8_t **)&src_addr,
159 (uint8_t **)&dest_addr);
160 if (addr_len <= 0) {
161 log_msg(LVL_WARN, "Failed to get packet address.");
162 pq_release_remote(net_sess, packet_get_id(packet));
163 return EINVAL;
[21580dd]164 }
[89e57cee]165
[1812a0d]166 if (addr_len != sizeof(struct sockaddr_in)) {
167 log_msg(LVL_WARN, "Unsupported address size %zu (!= %zu)",
168 addr_len, sizeof(struct sockaddr_in));
169 pq_release_remote(net_sess, packet_get_id(packet));
170 return EINVAL;
171 }
[21580dd]172
[1812a0d]173 rc = packet_trim(packet, offset, 0);
174 if (rc != EOK) {
175 log_msg(LVL_WARN, "Failed to trim packet.");
176 pq_release_remote(net_sess, packet_get_id(packet));
177 return rc;
178 }
[21580dd]179
[1812a0d]180 /* Pull up packets into a single memory block, pdu_raw. */
181 log_msg(LVL_DEBUG, "tcp_received_msg() - pull up");
182 uint8_t *pdu_raw;
183 size_t pdu_raw_size = 0;
[7c8267b]184
[1812a0d]185 pq_pullup(packet, (void **)&pdu_raw, &pdu_raw_size);
[7c8267b]186
[1812a0d]187 /* Split into header and payload. */
[21580dd]188
[1812a0d]189 log_msg(LVL_DEBUG, "tcp_received_msg() - split header/payload");
[7c8267b]190
[1812a0d]191 tcp_pdu_t *pdu;
192 size_t hdr_size;
[7c8267b]193
[1812a0d]194 /* XXX Header options */
195 hdr_size = sizeof(tcp_header_t);
[7c8267b]196
[1812a0d]197 if (pdu_raw_size < hdr_size) {
198 log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
199 pdu_raw_size, hdr_size);
200 pq_release_remote(net_sess, packet_get_id(packet));
201 return EINVAL;
[7c8267b]202 }
203
[1812a0d]204 log_msg(LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
205 pdu_raw_size, hdr_size);
206 pdu = tcp_pdu_create(pdu_raw, hdr_size, pdu_raw + hdr_size,
207 pdu_raw_size - hdr_size);
208 if (pdu == NULL) {
209 log_msg(LVL_WARN, "Failed creating PDU. Dropped.");
210 return ENOMEM;
[21580dd]211 }
212
[1812a0d]213 free(pdu_raw);
[21580dd]214
[1812a0d]215 pdu->src_addr.ipv4 = uint32_t_be2host(src_addr->sin_addr.s_addr);
216 pdu->dest_addr.ipv4 = uint32_t_be2host(dest_addr->sin_addr.s_addr);
217 log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
218 pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
[21580dd]219
[1812a0d]220 tcp_received_pdu(pdu);
221 tcp_pdu_delete(pdu);
[7c8267b]222
[21580dd]223 return EOK;
224}
225
[1812a0d]226/** Receive packets from network layer. */
227static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[7c8267b]228{
[1812a0d]229 packet_t *packet;
[0578271]230 int rc;
[aadf01e]231
[1812a0d]232 log_msg(LVL_DEBUG, "tcp_receiver()");
[7c8267b]233
[1812a0d]234 while (true) {
235 switch (IPC_GET_IMETHOD(*icall)) {
236 case NET_TL_RECEIVED:
237 log_msg(LVL_DEBUG, "method = NET_TL_RECEIVED");
238 rc = packet_translate_remote(net_sess, &packet,
239 IPC_GET_PACKET(*icall));
[0578271]240 if (rc != EOK) {
[1812a0d]241 log_msg(LVL_DEBUG, "Error %d translating packet.", rc);
242 async_answer_0(iid, (sysarg_t)rc);
[21580dd]243 break;
244 }
[1812a0d]245 rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
246 IPC_GET_ERROR(*icall));
247 async_answer_0(iid, (sysarg_t)rc);
[d493830e]248 break;
[7c8267b]249 default:
[1812a0d]250 log_msg(LVL_DEBUG, "method = %u",
251 (unsigned)IPC_GET_IMETHOD(*icall));
252 async_answer_0(iid, ENOTSUP);
[7c8267b]253 break;
[21580dd]254 }
[fb04cba8]255
[1812a0d]256 iid = async_get_call(icall);
[21580dd]257 }
258}
259
[1812a0d]260/** Transmit PDU over network layer. */
261void tcp_transmit_pdu(tcp_pdu_t *pdu)
[7c8267b]262{
[1812a0d]263 struct sockaddr_in dest;
[c8c43cae]264 nic_device_id_t dev_id;
[1812a0d]265 void *phdr;
266 size_t phdr_len;
267 packet_dimension_t *pkt_dim;
[0578271]268 int rc;
[1812a0d]269 packet_t *packet;
270 void *pkt_data;
271 size_t pdu_size;
[aadf01e]272
[1812a0d]273 dest.sin_family = AF_INET;
274 dest.sin_port = 0; /* not needed */
275 dest.sin_addr.s_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
[21580dd]276
[1812a0d]277 /* Find route. Obtained pseudo-header is not used. */
278 rc = ip_get_route_req(ip_sess, IPPROTO_TCP, (struct sockaddr *)&dest,
279 sizeof(dest), &dev_id, &phdr, &phdr_len);
[0578271]280 if (rc != EOK) {
[1812a0d]281 log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to find route.");
282 return;
[7c8267b]283 }
[21580dd]284
[1812a0d]285 rc = tl_get_ip_packet_dimension(ip_sess, &pkt_dims, dev_id, &pkt_dim);
[0578271]286 if (rc != EOK) {
[1812a0d]287 log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get dimension.");
288 return;
[7c8267b]289 }
[21580dd]290
[1812a0d]291 pdu_size = pdu->header_size + pdu->text_size;
[21580dd]292
[1812a0d]293 packet = packet_get_4_remote(net_sess, pdu_size, pkt_dim->addr_len,
294 pkt_dim->prefix, pkt_dim->suffix);
295 if (!packet) {
296 log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get packet.");
297 return;
[21580dd]298 }
[7c8267b]299
[1812a0d]300 pkt_data = packet_suffix(packet, pdu_size);
301 if (!pkt_data) {
302 log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get pkt_data ptr.");
303 pq_release_remote(net_sess, packet_get_id(packet));
304 return;
[7c8267b]305 }
306
[1812a0d]307 rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
[0578271]308 if (rc != EOK) {
[1812a0d]309 log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to prepare IP packet part.");
310 pq_release_remote(net_sess, packet_get_id(packet));
311 return;
[7c8267b]312 }
313
[1812a0d]314 rc = packet_set_addr(packet, NULL, (uint8_t *)&dest, sizeof(dest));
315 if (rc != EOK) {
316 log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to set packet address.");
317 pq_release_remote(net_sess, packet_get_id(packet));
318 return;
[7c8267b]319 }
[21580dd]320
[1812a0d]321 /* Copy PDU data to packet */
322 memcpy(pkt_data, pdu->header, pdu->header_size);
323 memcpy((uint8_t *)pkt_data + pdu->header_size, pdu->text,
324 pdu->text_size);
[7c8267b]325
[1812a0d]326 /* Transmit packet. XXX Transfers packet ownership to IP? */
327 ip_send_msg(ip_sess, dev_id, packet, SERVICE_TCP, 0);
[21580dd]328}
329
[1812a0d]330/** Process received PDU. */
331static void tcp_received_pdu(tcp_pdu_t *pdu)
[7c8267b]332{
[1812a0d]333 tcp_segment_t *dseg;
334 tcp_sockpair_t rident;
[fb04cba8]335
[1812a0d]336 log_msg(LVL_DEBUG, "tcp_received_pdu()");
[fb04cba8]337
[1812a0d]338 if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
339 log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
[7c8267b]340 return;
341 }
[fb04cba8]342
[1812a0d]343 /* Insert decoded segment into rqueue */
344 tcp_rqueue_insert_seg(&rident, dseg);
[21580dd]345}
346
[1812a0d]347/* Called from libnet */
[f1938c6]348void tl_connection(void)
349{
[1812a0d]350 log_msg(LVL_DEBUG, "tl_connection()");
[f1938c6]351}
352
[1812a0d]353/* Called from libnet */
354int tl_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
355 size_t *answer_count)
[7c8267b]356{
[04cd242]357 async_sess_t *callback;
358
[1812a0d]359 log_msg(LVL_DEBUG, "tl_message()");
[04cd242]360
[aadf01e]361 *answer_count = 0;
[04cd242]362 callback = async_callback_receive_start(EXCHANGE_SERIALIZE, call);
[6b82009]363 if (callback)
[04cd242]364 return tcp_sock_connection(callback, callid, *call);
365
[21580dd]366 return ENOTSUP;
367}
368
[1812a0d]369/* Called from libnet */
370int tl_initialize(async_sess_t *sess)
[7c8267b]371{
[1812a0d]372 int rc;
[21580dd]373
[1812a0d]374 net_sess = sess;
375 icmp_sess = icmp_connect_module();
376
377 log_msg(LVL_DEBUG, "tl_initialize()");
378
[a4ee3ab2]379 tcp_sock_init();
380
[1812a0d]381 ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP, SERVICE_TCP,
382 tcp_receiver);
383 if (ip_sess == NULL)
384 return ENOENT;
[21580dd]385
[1812a0d]386 rc = packet_dimensions_initialize(&pkt_dims);
387 if (rc != EOK)
388 return rc;
389
390 return EOK;
[21580dd]391}
392
[c5808b41]393int main(int argc, char **argv)
[7c8267b]394{
[0578271]395 int rc;
[2e99277]396
[c5808b41]397 printf(NAME ": TCP (Transmission Control Protocol) network module\n");
[7c8267b]398
[a52de0e]399 rc = log_init(NAME, LVL_ERROR);
[0578271]400 if (rc != EOK) {
[c5808b41]401 printf(NAME ": Failed to initialize log.\n");
402 return 1;
[21580dd]403 }
[7c8267b]404
[1812a0d]405// printf(NAME ": Accepting connections\n");
[c5808b41]406// task_retval(0);
[7c8267b]407
[c5808b41]408 tcp_rqueue_init();
409 tcp_rqueue_thread_start();
[7c8267b]410
[8218b6b]411 tcp_ncsim_init();
412 tcp_ncsim_thread_start();
[7c8267b]413
[c5808b41]414 tcp_test();
[1812a0d]415/*
[c5808b41]416 async_manager();
[1812a0d]417*/
418 tl_module_start(SERVICE_TCP);
[849ed54]419
[c5808b41]420 /* Not reached */
421 return 0;
[014dd57b]422}
423
[c5808b41]424/**
425 * @}
[21580dd]426 */
Note: See TracBrowser for help on using the repository browser.