source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ f5f79cd

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

support arbitrary addresses in INET_SEND and INET_GET_SRCADDR
use addr32_t instead of uint32_t

  • Property mode set to 100644
File size: 12.7 KB
RevLine 
[c76e926]1/*
2 * Copyright (c) 2012 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 inet
30 * @{
31 */
32/**
33 * @file
34 * @brief Internet Protocol service
35 */
36
37#include <adt/list.h>
38#include <async.h>
39#include <errno.h>
40#include <fibril_synch.h>
41#include <io/log.h>
42#include <ipc/inet.h>
43#include <ipc/services.h>
44#include <loc.h>
45#include <stdio.h>
[ecff3d9]46#include <stdlib.h>
[c76e926]47#include <sys/types.h>
[02a09ed]48#include <net/socket_codes.h>
[ceba4bed]49#include "addrobj.h"
[637a3b4]50#include "icmp.h"
51#include "icmp_std.h"
[1d24ad3]52#include "icmpv6.h"
53#include "icmpv6_std.h"
[b4ec1ea]54#include "inetsrv.h"
[0e25780]55#include "inetcfg.h"
[6428115]56#include "inetping.h"
[1d24ad3]57#include "inetping6.h"
[e2e56e67]58#include "inet_link.h"
[7f95c904]59#include "reass.h"
[8bf672d]60#include "sroute.h"
[c76e926]61
[b4ec1ea]62#define NAME "inetsrv"
[c76e926]63
64static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
65
66static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
67static LIST_INITIALIZE(client_list);
68
69static int inet_init(void)
70{
[a1a101d]71 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
[1038a9c]72
[c76e926]73 async_set_client_connection(inet_client_conn);
[1038a9c]74
75 int rc = loc_server_register(NAME);
[c76e926]76 if (rc != EOK) {
[a1a101d]77 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server (%d).", rc);
[c76e926]78 return EEXIST;
79 }
[1038a9c]80
81 service_id_t sid;
[0e25780]82 rc = loc_service_register_with_iface(SERVICE_NAME_INET, &sid,
83 INET_PORT_DEFAULT);
84 if (rc != EOK) {
[a1a101d]85 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
[0e25780]86 return EEXIST;
87 }
[1038a9c]88
[0e25780]89 rc = loc_service_register_with_iface(SERVICE_NAME_INETCFG, &sid,
90 INET_PORT_CFG);
[c76e926]91 if (rc != EOK) {
[a1a101d]92 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
[c76e926]93 return EEXIST;
94 }
[1038a9c]95
[6428115]96 rc = loc_service_register_with_iface(SERVICE_NAME_INETPING, &sid,
97 INET_PORT_PING);
98 if (rc != EOK) {
[a1a101d]99 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
[6428115]100 return EEXIST;
101 }
[1038a9c]102
[1d24ad3]103 rc = loc_service_register_with_iface(SERVICE_NAME_INETPING6, &sid,
104 INET_PORT_PING6);
105 if (rc != EOK) {
106 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
107 return EEXIST;
108 }
109
[25eec4ef]110 inet_sroute_t *sroute = inet_sroute_new();
111 if (sroute == NULL) {
112 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed creating default route (%d).", rc);
113 return ENOMEM;
114 }
115
[a2e3ee6]116 inet_naddr(&sroute->dest, 0, 0, 0, 0, 0);
117 inet_addr(&sroute->router, 10, 0, 2, 2);
[25eec4ef]118 sroute->name = str_dup("default");
119 inet_sroute_add(sroute);
120
[a2e3ee6]121 rc = inet_link_discovery_start();
[e2e56e67]122 if (rc != EOK)
123 return EEXIST;
[1038a9c]124
[c76e926]125 return EOK;
126}
127
[ceba4bed]128static void inet_callback_create_srv(inet_client_t *client, ipc_callid_t callid,
[c76e926]129 ipc_call_t *call)
130{
[a1a101d]131 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_callback_create_srv()");
[c76e926]132
133 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
134 if (sess == NULL) {
135 async_answer_0(callid, ENOMEM);
136 return;
137 }
138
139 client->sess = sess;
140 async_answer_0(callid, EOK);
141}
142
[8bf672d]143static int inet_find_dir(inet_addr_t *src, inet_addr_t *dest, uint8_t tos,
144 inet_dir_t *dir)
145{
146 inet_sroute_t *sr;
147
148 /* XXX Handle case where source address is specified */
149 (void) src;
150
151 dir->aobj = inet_addrobj_find(dest, iaf_net);
152 if (dir->aobj != NULL) {
153 dir->ldest = *dest;
154 dir->dtype = dt_direct;
155 } else {
156 /* No direct path, try using a static route */
157 sr = inet_sroute_find(dest);
158 if (sr != NULL) {
159 dir->aobj = inet_addrobj_find(&sr->router, iaf_net);
160 dir->ldest = sr->router;
161 dir->dtype = dt_router;
162 }
163 }
164
165 if (dir->aobj == NULL) {
[a1a101d]166 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send: No route to destination.");
[8bf672d]167 return ENOENT;
168 }
169
170 return EOK;
171}
172
[637a3b4]173int inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl,
[2ff150e]174 int df)
[ceba4bed]175{
[8bf672d]176 inet_dir_t dir;
177 int rc;
[ceba4bed]178
[8bf672d]179 rc = inet_find_dir(&dgram->src, &dgram->dest, dgram->tos, &dir);
180 if (rc != EOK)
181 return rc;
[ceba4bed]182
[8bf672d]183 return inet_addrobj_send_dgram(dir.aobj, &dir.ldest, dgram,
184 proto, ttl, df);
[ceba4bed]185}
186
[e767dbf]187static int inet_send(inet_client_t *client, inet_dgram_t *dgram,
[2ff150e]188 uint8_t proto, uint8_t ttl, int df)
[e767dbf]189{
[2ff150e]190 return inet_route_packet(dgram, proto, ttl, df);
[e767dbf]191}
192
[6428115]193int inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
[bd8bfc5a]194{
[8bf672d]195 inet_dir_t dir;
196 int rc;
[bd8bfc5a]197
[8bf672d]198 rc = inet_find_dir(NULL, remote, tos, &dir);
199 if (rc != EOK)
200 return rc;
[bd8bfc5a]201
[8bf672d]202 /* XXX dt_local? */
203
204 /* Take source address from the address object */
[a2e3ee6]205 inet_naddr_addr(&dir.aobj->naddr, local);
[8bf672d]206 return EOK;
[bd8bfc5a]207}
208
[d8b47eca]209static void inet_get_srcaddr_srv(inet_client_t *client, ipc_callid_t iid,
210 ipc_call_t *icall)
[ecff3d9]211{
[a2e3ee6]212 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
213
[d8b47eca]214 uint8_t tos = IPC_GET_ARG1(*icall);
215
216 ipc_callid_t callid;
217 size_t size;
218 if (!async_data_write_receive(&callid, &size)) {
219 async_answer_0(callid, EREFUSED);
220 async_answer_0(iid, EREFUSED);
221 return;
222 }
223
224 if (size != sizeof(inet_addr_t)) {
225 async_answer_0(callid, EINVAL);
226 async_answer_0(iid, EINVAL);
227 return;
228 }
[a2e3ee6]229
[02a09ed]230 inet_addr_t remote;
[d8b47eca]231 int rc = async_data_write_finalize(callid, &remote, size);
232 if (rc != EOK) {
233 async_answer_0(callid, rc);
234 async_answer_0(iid, rc);
235 }
[02a09ed]236
[bd8bfc5a]237 inet_addr_t local;
[d8b47eca]238 rc = inet_get_srcaddr(&remote, tos, &local);
[a2e3ee6]239 if (rc != EOK) {
[d8b47eca]240 async_answer_0(iid, rc);
[a2e3ee6]241 return;
242 }
243
[d8b47eca]244 if (!async_data_read_receive(&callid, &size)) {
245 async_answer_0(callid, EREFUSED);
246 async_answer_0(iid, EREFUSED);
247 return;
248 }
249
250 if (size != sizeof(inet_addr_t)) {
[02a09ed]251 async_answer_0(callid, EINVAL);
[d8b47eca]252 async_answer_0(iid, EINVAL);
[a2e3ee6]253 return;
254 }
255
[d8b47eca]256 rc = async_data_read_finalize(callid, &local, size);
257 if (rc != EOK) {
258 async_answer_0(callid, rc);
259 async_answer_0(iid, rc);
260 return;
261 }
262
263 async_answer_0(iid, rc);
[ecff3d9]264}
265
[d8b47eca]266static void inet_send_srv(inet_client_t *client, ipc_callid_t iid,
267 ipc_call_t *icall)
[c76e926]268{
[a1a101d]269 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
[a2e3ee6]270
271 inet_dgram_t dgram;
272
[d8b47eca]273 dgram.tos = IPC_GET_ARG1(*icall);
[a2e3ee6]274
[d8b47eca]275 uint8_t ttl = IPC_GET_ARG2(*icall);
276 int df = IPC_GET_ARG3(*icall);
[a2e3ee6]277
[d8b47eca]278 ipc_callid_t callid;
279 size_t size;
280 if (!async_data_write_receive(&callid, &size)) {
281 async_answer_0(callid, EREFUSED);
282 async_answer_0(iid, EREFUSED);
283 return;
284 }
285
286 if (size != sizeof(inet_addr_t)) {
287 async_answer_0(callid, EINVAL);
288 async_answer_0(iid, EINVAL);
289 return;
290 }
291
292 int rc = async_data_write_finalize(callid, &dgram.src, size);
293 if (rc != EOK) {
294 async_answer_0(callid, rc);
295 async_answer_0(iid, rc);
296 }
297
298 if (!async_data_write_receive(&callid, &size)) {
299 async_answer_0(callid, EREFUSED);
300 async_answer_0(iid, EREFUSED);
301 return;
302 }
303
304 if (size != sizeof(inet_addr_t)) {
305 async_answer_0(callid, EINVAL);
306 async_answer_0(iid, EINVAL);
307 return;
308 }
309
310 rc = async_data_write_finalize(callid, &dgram.dest, size);
[ecff3d9]311 if (rc != EOK) {
312 async_answer_0(callid, rc);
[d8b47eca]313 async_answer_0(iid, rc);
314 }
315
316 rc = async_data_write_accept(&dgram.data, false, 0, 0, 0,
317 &dgram.size);
318 if (rc != EOK) {
319 async_answer_0(iid, rc);
[ecff3d9]320 return;
321 }
[a2e3ee6]322
[2ff150e]323 rc = inet_send(client, &dgram, client->protocol, ttl, df);
[a2e3ee6]324
[59157eb]325 free(dgram.data);
[d8b47eca]326 async_answer_0(iid, rc);
[c76e926]327}
328
[ceba4bed]329static void inet_set_proto_srv(inet_client_t *client, ipc_callid_t callid,
[c76e926]330 ipc_call_t *call)
331{
332 sysarg_t proto;
333
334 proto = IPC_GET_ARG1(*call);
[a1a101d]335 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
[c76e926]336
337 if (proto > UINT8_MAX) {
338 async_answer_0(callid, EINVAL);
339 return;
340 }
341
342 client->protocol = proto;
343 async_answer_0(callid, EOK);
344}
345
346static void inet_client_init(inet_client_t *client)
347{
348 client->sess = NULL;
349
350 fibril_mutex_lock(&client_list_lock);
351 list_append(&client->client_list, &client_list);
352 fibril_mutex_unlock(&client_list_lock);
353}
354
355static void inet_client_fini(inet_client_t *client)
356{
357 async_hangup(client->sess);
358 client->sess = NULL;
359
360 fibril_mutex_lock(&client_list_lock);
361 list_remove(&client->client_list);
362 fibril_mutex_unlock(&client_list_lock);
363}
364
[0e25780]365static void inet_default_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[c76e926]366{
367 inet_client_t client;
368
[a1a101d]369 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
[c76e926]370
371 /* Accept the connection */
372 async_answer_0(iid, EOK);
373
374 inet_client_init(&client);
375
376 while (true) {
377 ipc_call_t call;
378 ipc_callid_t callid = async_get_call(&call);
379 sysarg_t method = IPC_GET_IMETHOD(call);
380
381 if (!method) {
382 /* The other side has hung up */
383 async_answer_0(callid, EOK);
384 return;
385 }
386
387 switch (method) {
388 case INET_CALLBACK_CREATE:
[ceba4bed]389 inet_callback_create_srv(&client, callid, &call);
[c76e926]390 break;
[ecff3d9]391 case INET_GET_SRCADDR:
[ceba4bed]392 inet_get_srcaddr_srv(&client, callid, &call);
[ecff3d9]393 break;
[c76e926]394 case INET_SEND:
[ceba4bed]395 inet_send_srv(&client, callid, &call);
[c76e926]396 break;
397 case INET_SET_PROTO:
[ceba4bed]398 inet_set_proto_srv(&client, callid, &call);
[c76e926]399 break;
400 default:
401 async_answer_0(callid, EINVAL);
402 }
403 }
404
405 inet_client_fini(&client);
406}
407
[0e25780]408static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
409{
410 sysarg_t port;
411
412 port = IPC_GET_ARG1(*icall);
413
414 switch (port) {
415 case INET_PORT_DEFAULT:
416 inet_default_conn(iid, icall, arg);
417 break;
418 case INET_PORT_CFG:
419 inet_cfg_conn(iid, icall, arg);
420 break;
[6428115]421 case INET_PORT_PING:
422 inetping_conn(iid, icall, arg);
423 break;
[1d24ad3]424 case INET_PORT_PING6:
425 inetping6_conn(iid, icall, arg);
426 break;
[0e25780]427 default:
428 async_answer_0(iid, ENOTSUP);
429 break;
430 }
431}
432
[fe4310f]433static inet_client_t *inet_client_find(uint8_t proto)
434{
435 fibril_mutex_lock(&client_list_lock);
436
437 list_foreach(client_list, link) {
438 inet_client_t *client = list_get_instance(link, inet_client_t,
439 client_list);
440
441 if (client->protocol == proto) {
442 fibril_mutex_unlock(&client_list_lock);
443 return client;
444 }
445 }
446
447 fibril_mutex_unlock(&client_list_lock);
448 return NULL;
449}
450
[59157eb]451int inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
452{
[02a09ed]453 async_exch_t *exch = async_exchange_begin(client->sess);
[a2e3ee6]454
[02a09ed]455 ipc_call_t answer;
456 aid_t req = async_send_1(exch, INET_EV_RECV, dgram->tos, &answer);
457
458 int rc = async_data_write_start(exch, &dgram->src, sizeof(inet_addr_t));
459 if (rc != EOK) {
460 async_exchange_end(exch);
461 async_forget(req);
[a2e3ee6]462 return rc;
[02a09ed]463 }
[a2e3ee6]464
[02a09ed]465 rc = async_data_write_start(exch, &dgram->dest, sizeof(inet_addr_t));
466 if (rc != EOK) {
467 async_exchange_end(exch);
468 async_forget(req);
469 return rc;
470 }
[a2e3ee6]471
472 rc = async_data_write_start(exch, dgram->data, dgram->size);
[02a09ed]473
[59157eb]474 async_exchange_end(exch);
[a2e3ee6]475
[59157eb]476 if (rc != EOK) {
[50b581d]477 async_forget(req);
[59157eb]478 return rc;
479 }
[a2e3ee6]480
[59157eb]481 sysarg_t retval;
482 async_wait_for(req, &retval);
[a2e3ee6]483
[02a09ed]484 return (int) retval;
[59157eb]485}
486
[7f95c904]487int inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
[e767dbf]488{
[fe4310f]489 inet_client_t *client;
490
[a1a101d]491 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
[fe4310f]492
[1d24ad3]493 /* ICMP and ICMPv6 messages are handled internally */
[637a3b4]494 if (proto == IP_PROTO_ICMP)
495 return icmp_recv(dgram);
[1d24ad3]496
497 if (proto == IP_PROTO_ICMPV6)
498 return icmpv6_recv(dgram);
[637a3b4]499
[fe4310f]500 client = inet_client_find(proto);
501 if (client == NULL) {
[a1a101d]502 log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
[fe4310f]503 proto);
504 return ENOENT;
505 }
506
507 return inet_ev_recv(client, dgram);
508}
509
510int inet_recv_packet(inet_packet_t *packet)
511{
512 inet_addrobj_t *addr;
513 inet_dgram_t dgram;
514
515 addr = inet_addrobj_find(&packet->dest, iaf_addr);
516 if (addr != NULL) {
517 /* Destined for one of the local addresses */
518
[7f95c904]519 /* Check if packet is a complete datagram */
520 if (packet->offs == 0 && !packet->mf) {
521 /* It is complete deliver it immediately */
522 dgram.src = packet->src;
523 dgram.dest = packet->dest;
524 dgram.tos = packet->tos;
525 dgram.data = packet->data;
526 dgram.size = packet->size;
527
528 return inet_recv_dgram_local(&dgram, packet->proto);
529 } else {
530 /* It is a fragment, queue it for reassembly */
531 inet_reass_queue_packet(packet);
532 }
[fe4310f]533 }
534
535 return ENOENT;
[e767dbf]536}
537
[c76e926]538int main(int argc, char *argv[])
539{
540 int rc;
541
[e2e56e67]542 printf(NAME ": HelenOS Internet Protocol service\n");
[c76e926]543
[267f235]544 if (log_init(NAME) != EOK) {
[e2e56e67]545 printf(NAME ": Failed to initialize logging.\n");
[c76e926]546 return 1;
547 }
548
549 rc = inet_init();
550 if (rc != EOK)
551 return 1;
552
[ecff3d9]553 printf(NAME ": Accepting connections.\n");
[c76e926]554 task_retval(0);
555 async_manager();
556
557 /* Not reached */
558 return 0;
559}
560
561/** @}
562 */
Note: See TracBrowser for help on using the repository browser.