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

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

Hook TCP into network stack IP layer.

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