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

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

Implement RST processing.

  • Property mode set to 100644
File size: 17.0 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup tcp
31 * @{
32 */
33
34/**
35 * @file Socket provider
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <io/log.h>
41#include <ip_client.h>
42#include <ipc/socket.h>
43#include <net/modules.h>
44#include <net/socket.h>
45
46#include "sock.h"
47#include "std.h"
48#include "tcp.h"
49#include "tcp_type.h"
50#include "ucall.h"
51
52#define FRAGMENT_SIZE 1024
53
54/** Free ports pool start. */
55#define TCP_FREE_PORTS_START 1025
56
57/** Free ports pool end. */
58#define TCP_FREE_PORTS_END 65535
59
60static int last_used_port = TCP_FREE_PORTS_START - 1;
61static socket_ports_t gsock;
62
63void tcp_sock_init(void)
64{
65 socket_ports_initialize(&gsock);
66}
67
68static void tcp_free_sock_data(socket_core_t *sock_core)
69{
70 tcp_sockdata_t *socket;
71
72 socket = (tcp_sockdata_t *)sock_core->specific_data;
73 (void)socket;
74}
75
76static void tcp_sock_notify_data(socket_core_t *sock_core)
77{
78 log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
79 async_exch_t *exch = async_exchange_begin(sock_core->sess);
80 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
81 FRAGMENT_SIZE, 0, 0, 1);
82 async_exchange_end(exch);
83}
84
85static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
86{
87 log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
88 async_exch_t *exch = async_exchange_begin(lsock_core->sess);
89 async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
90 FRAGMENT_SIZE, 0, 0, 0);
91 async_exchange_end(exch);
92}
93
94static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
95{
96 tcp_sockdata_t *sock;
97 int sock_id;
98 int rc;
99 ipc_call_t answer;
100
101 log_msg(LVL_DEBUG, "tcp_sock_socket()");
102 sock = calloc(sizeof(tcp_sockdata_t), 1);
103 if (sock == NULL) {
104 async_answer_0(callid, ENOMEM);
105 return;
106 }
107
108 sock->client = client;
109 sock->laddr.ipv4 = TCP_IPV4_ANY;
110
111 sock_id = SOCKET_GET_SOCKET_ID(call);
112 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
113 if (rc != EOK) {
114 async_answer_0(callid, rc);
115 return;
116 }
117
118 refresh_answer(&answer, NULL);
119 SOCKET_SET_SOCKET_ID(answer, sock_id);
120
121 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
122 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
123 answer_call(callid, EOK, &answer, 3);
124}
125
126static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
127{
128 int rc;
129 struct sockaddr *addr;
130 size_t addr_len;
131 socket_core_t *sock_core;
132 tcp_sockdata_t *socket;
133
134 log_msg(LVL_DEBUG, "tcp_sock_bind()");
135 log_msg(LVL_DEBUG, " - async_data_write_accept");
136 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
137 if (rc != EOK) {
138 async_answer_0(callid, rc);
139 return;
140 }
141
142 log_msg(LVL_DEBUG, " - call socket_bind");
143 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
144 addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
145 last_used_port);
146 if (rc != EOK) {
147 async_answer_0(callid, rc);
148 return;
149 }
150
151 log_msg(LVL_DEBUG, " - call socket_cores_find");
152 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
153 if (sock_core != NULL) {
154 socket = (tcp_sockdata_t *)sock_core->specific_data;
155 /* XXX Anything to do? */
156 (void) socket;
157 }
158
159 log_msg(LVL_DEBUG, " - success");
160 async_answer_0(callid, EOK);
161}
162
163static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
164{
165 int socket_id;
166 int backlog;
167 socket_core_t *sock_core;
168 tcp_sockdata_t *socket;
169
170 log_msg(LVL_DEBUG, "tcp_sock_listen()");
171
172 socket_id = SOCKET_GET_SOCKET_ID(call);
173 backlog = SOCKET_GET_BACKLOG(call);
174
175 if (backlog < 0) {
176 async_answer_0(callid, EINVAL);
177 return;
178 }
179
180 sock_core = socket_cores_find(&client->sockets, socket_id);
181 if (sock_core == NULL) {
182 async_answer_0(callid, ENOTSOCK);
183 return;
184 }
185
186 socket = (tcp_sockdata_t *)sock_core->specific_data;
187
188 /*
189 * XXX We do not do anything and defer action to accept().
190 * This is a slight difference in semantics, but most servers
191 * would just listen() and immediately accept() in a loop.
192 *
193 * The only difference is that there is a window between
194 * listen() and accept() or two accept()s where we refuse
195 * connections.
196 */
197 (void)backlog;
198 (void)socket;
199
200 async_answer_0(callid, EOK);
201 log_msg(LVL_DEBUG, "tcp_sock_listen(): notify data\n");
202 /* Push one accept notification to client's queue */
203 tcp_sock_notify_aconn(sock_core);
204}
205
206static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
207{
208 int rc;
209 struct sockaddr_in *addr;
210 int socket_id;
211 size_t addr_len;
212 socket_core_t *sock_core;
213 tcp_sockdata_t *socket;
214 tcp_error_t trc;
215 tcp_sock_t lsocket;
216 tcp_sock_t fsocket;
217 device_id_t dev_id;
218 tcp_phdr_t *phdr;
219 size_t phdr_len;
220
221 log_msg(LVL_DEBUG, "tcp_sock_connect()");
222
223 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
224 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
225 async_answer_0(callid, rc);
226 return;
227 }
228
229 socket_id = SOCKET_GET_SOCKET_ID(call);
230
231 sock_core = socket_cores_find(&client->sockets, socket_id);
232 if (sock_core == NULL) {
233 async_answer_0(callid, ENOTSOCK);
234 return;
235 }
236
237 socket = (tcp_sockdata_t *)sock_core->specific_data;
238 if (sock_core->port <= 0) {
239 rc = socket_bind_free_port(&gsock, sock_core,
240 TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
241 last_used_port);
242 if (rc != EOK) {
243 async_answer_0(callid, rc);
244 return;
245 }
246
247 last_used_port = sock_core->port;
248 }
249
250 if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
251 /* Find route to determine local IP address. */
252 rc = ip_get_route_req(ip_sess, IPPROTO_TCP,
253 (struct sockaddr *)addr, sizeof(*addr), &dev_id,
254 (void **)&phdr, &phdr_len);
255 if (rc != EOK) {
256 async_answer_0(callid, rc);
257 log_msg(LVL_DEBUG, "tcp_transmit_connect: Failed to find route.");
258 return;
259 }
260
261 socket->laddr.ipv4 = uint32_t_be2host(phdr->src_addr);
262 log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
263 free(phdr);
264 }
265
266 lsocket.addr.ipv4 = socket->laddr.ipv4;
267 lsocket.port = sock_core->port;
268 fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
269 fsocket.port = uint16_t_be2host(addr->sin_port);
270
271 trc = tcp_uc_open(&lsocket, &fsocket, ap_active, &socket->conn);
272
273 if (socket->conn != NULL)
274 socket->conn->name = (char *)"C";
275
276 switch (trc) {
277 case TCP_EOK:
278 rc = EOK;
279 break;
280 case TCP_ERESET:
281 rc = ECONNREFUSED;
282 break;
283 default:
284 assert(false);
285 }
286
287 async_answer_0(callid, rc);
288
289 /* Push one fragment notification to client's queue */
290 tcp_sock_notify_data(sock_core);
291 log_msg(LVL_DEBUG, "tcp_sock_connect(): notify conn\n");
292}
293
294static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
295{
296 ipc_call_t answer;
297 int socket_id;
298 int asock_id;
299 socket_core_t *sock_core;
300 socket_core_t *asock_core;
301 tcp_sockdata_t *socket;
302 tcp_sockdata_t *asocket;
303 tcp_error_t trc;
304 tcp_sock_t lsocket;
305 tcp_sock_t fsocket;
306 tcp_conn_t *conn;
307 int rc;
308
309 log_msg(LVL_DEBUG, "tcp_sock_accept()");
310
311 socket_id = SOCKET_GET_SOCKET_ID(call);
312 asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
313
314 sock_core = socket_cores_find(&client->sockets, socket_id);
315 if (sock_core == NULL) {
316 async_answer_0(callid, ENOTSOCK);
317 return;
318 }
319
320 socket = (tcp_sockdata_t *)sock_core->specific_data;
321
322 log_msg(LVL_DEBUG, " - verify socket->conn");
323 if (socket->conn != NULL) {
324 async_answer_0(callid, EINVAL);
325 return;
326 }
327
328 log_msg(LVL_DEBUG, " - open connection");
329
330 lsocket.addr.ipv4 = TCP_IPV4_ANY;
331 lsocket.port = sock_core->port;
332 fsocket.addr.ipv4 = TCP_IPV4_ANY;
333 fsocket.port = TCP_PORT_ANY;
334
335 trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, &conn);
336 if (conn != NULL)
337 conn->name = (char *)"S";
338
339 log_msg(LVL_DEBUG, " - decode TCP return code");
340
341 switch (trc) {
342 case TCP_EOK:
343 rc = EOK;
344 break;
345 case TCP_ERESET:
346 rc = ECONNABORTED;
347 break;
348 default:
349 assert(false);
350 }
351
352 log_msg(LVL_DEBUG, " - check TCP return code");
353 if (rc != EOK) {
354 async_answer_0(callid, rc);
355 return;
356 }
357
358 log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
359 asocket = calloc(sizeof(tcp_sockdata_t), 1);
360 if (asocket == NULL) {
361 async_answer_0(callid, ENOMEM);
362 return;
363 }
364
365 asocket->client = client;
366 asocket->conn = conn;
367 log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
368
369 rc = socket_create(&client->sockets, client->sess, asocket, &asock_id);
370 if (rc != EOK) {
371 async_answer_0(callid, rc);
372 return;
373 }
374 log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
375
376 asock_core = socket_cores_find(&client->sockets, asock_id);
377 assert(asock_core != NULL);
378
379 refresh_answer(&answer, NULL);
380
381 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
382 SOCKET_SET_SOCKET_ID(answer, asock_id);
383 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
384
385 answer_call(callid, asock_core->socket_id, &answer, 3);
386
387 /* Push one accept notification to client's queue */
388 tcp_sock_notify_aconn(sock_core);
389
390 /* Push one fragment notification to client's queue */
391 tcp_sock_notify_data(asock_core);
392 log_msg(LVL_DEBUG, "tcp_sock_accept(): notify aconn\n");
393}
394
395static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
396{
397 int socket_id;
398 int fragments;
399 int index;
400 socket_core_t *sock_core;
401 tcp_sockdata_t *socket;
402 ipc_call_t answer;
403 ipc_callid_t wcallid;
404 size_t length;
405 uint8_t buffer[FRAGMENT_SIZE];
406 tcp_error_t trc;
407 int rc;
408
409 log_msg(LVL_DEBUG, "tcp_sock_send()");
410 socket_id = SOCKET_GET_SOCKET_ID(call);
411 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
412 SOCKET_GET_FLAGS(call);
413
414 sock_core = socket_cores_find(&client->sockets, socket_id);
415 if (sock_core == NULL) {
416 async_answer_0(callid, ENOTSOCK);
417 return;
418 }
419
420 socket = (tcp_sockdata_t *)sock_core->specific_data;
421 if (socket->conn == NULL) {
422 async_answer_0(callid, ENOTCONN);
423 return;
424 }
425
426 for (index = 0; index < fragments; index++) {
427 if (!async_data_write_receive(&wcallid, &length)) {
428 async_answer_0(callid, EINVAL);
429 return;
430 }
431
432 if (length > FRAGMENT_SIZE)
433 length = FRAGMENT_SIZE;
434
435 rc = async_data_write_finalize(wcallid, buffer, length);
436 if (rc != EOK) {
437 async_answer_0(callid, rc);
438 return;
439 }
440
441 trc = tcp_uc_send(socket->conn, buffer, length, 0);
442
443 switch (trc) {
444 case TCP_EOK:
445 rc = EOK;
446 break;
447 case TCP_ENOTEXIST:
448 rc = ENOTCONN;
449 break;
450 case TCP_ECLOSING:
451 rc = ENOTCONN;
452 break;
453 case TCP_ERESET:
454 rc = ECONNABORTED;
455 break;
456 default:
457 assert(false);
458 }
459
460 if (rc != EOK) {
461 async_answer_0(callid, rc);
462 return;
463 }
464 }
465
466 refresh_answer(&answer, NULL);
467 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
468 answer_call(callid, EOK, &answer, 2);
469}
470
471static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
472{
473 log_msg(LVL_DEBUG, "tcp_sock_sendto()");
474 async_answer_0(callid, ENOTSUP);
475}
476
477static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
478{
479 int socket_id;
480 int flags;
481 size_t addr_length, length;
482 socket_core_t *sock_core;
483 tcp_sockdata_t *socket;
484 ipc_call_t answer;
485 ipc_callid_t rcallid;
486 uint8_t buffer[FRAGMENT_SIZE];
487 size_t data_len;
488 xflags_t xflags;
489 tcp_error_t trc;
490 struct sockaddr_in addr;
491 tcp_sock_t *rsock;
492 int rc;
493
494 log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
495
496 socket_id = SOCKET_GET_SOCKET_ID(call);
497 flags = SOCKET_GET_FLAGS(call);
498
499 sock_core = socket_cores_find(&client->sockets, socket_id);
500 if (sock_core == NULL) {
501 async_answer_0(callid, ENOTSOCK);
502 return;
503 }
504
505 socket = (tcp_sockdata_t *)sock_core->specific_data;
506 if (socket->conn == NULL) {
507 async_answer_0(callid, ENOTCONN);
508 return;
509 }
510
511 (void)flags;
512
513 trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
514 &xflags);
515 log_msg(LVL_DEBUG, "**** tcp_uc_receive done");
516
517 switch (trc) {
518 case TCP_EOK:
519 rc = EOK;
520 break;
521 case TCP_ENOTEXIST:
522 case TCP_ECLOSING:
523 rc = ENOTCONN;
524 break;
525 case TCP_ERESET:
526 rc = ECONNABORTED;
527 break;
528 default:
529 assert(false);
530 }
531
532 log_msg(LVL_DEBUG, "**** tcp_uc_receive -> %d", rc);
533 if (rc != EOK) {
534 async_answer_0(callid, rc);
535 return;
536 }
537
538 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
539 /* Fill addr */
540 rsock = &socket->conn->ident.foreign;
541 addr.sin_family = AF_INET;
542 addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
543 addr.sin_port = host2uint16_t_be(rsock->port);
544
545 log_msg(LVL_DEBUG, "addr read receive");
546 if (!async_data_read_receive(&rcallid, &addr_length)) {
547 async_answer_0(callid, EINVAL);
548 return;
549 }
550
551 if (addr_length > sizeof(addr))
552 addr_length = sizeof(addr);
553
554 log_msg(LVL_DEBUG, "addr read finalize");
555 rc = async_data_read_finalize(rcallid, &addr, addr_length);
556 if (rc != EOK) {
557 async_answer_0(callid, EINVAL);
558 return;
559 }
560 }
561
562 log_msg(LVL_DEBUG, "data read receive");
563 if (!async_data_read_receive(&rcallid, &length)) {
564 async_answer_0(callid, EINVAL);
565 return;
566 }
567
568 if (length > data_len)
569 length = data_len;
570
571 log_msg(LVL_DEBUG, "data read finalize");
572 rc = async_data_read_finalize(rcallid, buffer, length);
573
574 if (length < data_len && rc == EOK)
575 rc = EOVERFLOW;
576
577 SOCKET_SET_READ_DATA_LENGTH(answer, length);
578 answer_call(callid, EOK, &answer, 1);
579
580 /* Push one fragment notification to client's queue */
581 tcp_sock_notify_data(sock_core);
582}
583
584static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
585{
586 int socket_id;
587 socket_core_t *sock_core;
588 tcp_sockdata_t *socket;
589 tcp_error_t trc;
590 int rc;
591 uint8_t buffer[FRAGMENT_SIZE];
592 size_t data_len;
593 xflags_t xflags;
594
595 log_msg(LVL_DEBUG, "tcp_sock_close()");
596 socket_id = SOCKET_GET_SOCKET_ID(call);
597
598 sock_core = socket_cores_find(&client->sockets, socket_id);
599 if (sock_core == NULL) {
600 async_answer_0(callid, ENOTSOCK);
601 return;
602 }
603
604 socket = (tcp_sockdata_t *)sock_core->specific_data;
605 rc = tcp_uc_close(socket->conn);
606 if (rc != EOK) {
607 async_answer_0(callid, rc);
608 return;
609 }
610
611 /* Drain incoming data. This should really be done in the background. */
612 do {
613 trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE,
614 &data_len, &xflags);
615 } while (trc == TCP_EOK);
616
617 rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
618 tcp_free_sock_data);
619 if (rc != EOK) {
620 async_answer_0(callid, rc);
621 return;
622 }
623
624 async_answer_0(callid, EOK);
625}
626
627static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
628{
629 log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
630 async_answer_0(callid, ENOTSUP);
631}
632
633static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
634{
635 log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
636 async_answer_0(callid, ENOTSUP);
637}
638
639int tcp_sock_connection(async_sess_t *sess, ipc_callid_t iid, ipc_call_t icall)
640{
641 ipc_callid_t callid;
642 ipc_call_t call;
643 tcp_client_t client;
644
645 /* Accept the connection */
646 async_answer_0(iid, EOK);
647
648 client.sess = sess;
649 socket_cores_initialize(&client.sockets);
650
651 while (true) {
652 callid = async_get_call(&call);
653 if (!IPC_GET_IMETHOD(call))
654 break;
655
656 log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
657 (int)IPC_GET_IMETHOD(call));
658
659 switch (IPC_GET_IMETHOD(call)) {
660 case NET_SOCKET:
661 tcp_sock_socket(&client, callid, call);
662 break;
663 case NET_SOCKET_BIND:
664 tcp_sock_bind(&client, callid, call);
665 break;
666 case NET_SOCKET_LISTEN:
667 tcp_sock_listen(&client, callid, call);
668 break;
669 case NET_SOCKET_CONNECT:
670 tcp_sock_connect(&client, callid, call);
671 break;
672 case NET_SOCKET_ACCEPT:
673 tcp_sock_accept(&client, callid, call);
674 break;
675 case NET_SOCKET_SEND:
676 tcp_sock_send(&client, callid, call);
677 break;
678 case NET_SOCKET_SENDTO:
679 tcp_sock_sendto(&client, callid, call);
680 break;
681 case NET_SOCKET_RECV:
682 case NET_SOCKET_RECVFROM:
683 tcp_sock_recvfrom(&client, callid, call);
684 break;
685 case NET_SOCKET_CLOSE:
686 tcp_sock_close(&client, callid, call);
687 break;
688 case NET_SOCKET_GETSOCKOPT:
689 tcp_sock_getsockopt(&client, callid, call);
690 break;
691 case NET_SOCKET_SETSOCKOPT:
692 tcp_sock_setsockopt(&client, callid, call);
693 break;
694 default:
695 async_answer_0(callid, ENOTSUP);
696 break;
697 }
698 }
699
700 return EOK;
701}
702
703/**
704 * @}
705 */
Note: See TracBrowser for help on using the repository browser.