source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ 1d24ad3

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

more IPv6 stub code

  • Property mode set to 100644
File size: 11.5 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
[ceba4bed]209static void inet_get_srcaddr_srv(inet_client_t *client, ipc_callid_t callid,
[ecff3d9]210 ipc_call_t *call)
211{
[a2e3ee6]212 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
213
[02a09ed]214 addr32_t remote_v4 = IPC_GET_ARG1(*call);
[a2e3ee6]215 uint8_t tos = IPC_GET_ARG2(*call);
216
[02a09ed]217 inet_addr_t remote;
218 inet_addr_set(remote_v4, &remote);
219
[bd8bfc5a]220 inet_addr_t local;
[a2e3ee6]221 int rc = inet_get_srcaddr(&remote, tos, &local);
222 if (rc != EOK) {
223 async_answer_0(callid, rc);
224 return;
225 }
226
[02a09ed]227 addr32_t local_v4;
228 uint16_t family = inet_addr_get(&local, &local_v4, NULL);
229 if (family != AF_INET) {
230 async_answer_0(callid, EINVAL);
[a2e3ee6]231 return;
232 }
233
[02a09ed]234 async_answer_1(callid, rc, (sysarg_t) local_v4);
[ecff3d9]235}
236
[ceba4bed]237static void inet_send_srv(inet_client_t *client, ipc_callid_t callid,
[c76e926]238 ipc_call_t *call)
239{
[a1a101d]240 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
[a2e3ee6]241
[02a09ed]242 addr32_t src_v4 = IPC_GET_ARG1(*call);
243 addr32_t dest_v4 = IPC_GET_ARG2(*call);
244
[a2e3ee6]245 inet_dgram_t dgram;
246
[02a09ed]247 inet_addr_set(src_v4, &dgram.src);
248 inet_addr_set(dest_v4, &dgram.dest);
[59157eb]249 dgram.tos = IPC_GET_ARG3(*call);
[a2e3ee6]250
251 uint8_t ttl = IPC_GET_ARG4(*call);
252 int df = IPC_GET_ARG5(*call);
253
254 int rc = async_data_write_accept(&dgram.data, false, 0, 0, 0,
255 &dgram.size);
[ecff3d9]256 if (rc != EOK) {
257 async_answer_0(callid, rc);
258 return;
259 }
[a2e3ee6]260
[2ff150e]261 rc = inet_send(client, &dgram, client->protocol, ttl, df);
[a2e3ee6]262
[59157eb]263 free(dgram.data);
[ceba4bed]264 async_answer_0(callid, rc);
[c76e926]265}
266
[ceba4bed]267static void inet_set_proto_srv(inet_client_t *client, ipc_callid_t callid,
[c76e926]268 ipc_call_t *call)
269{
270 sysarg_t proto;
271
272 proto = IPC_GET_ARG1(*call);
[a1a101d]273 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
[c76e926]274
275 if (proto > UINT8_MAX) {
276 async_answer_0(callid, EINVAL);
277 return;
278 }
279
280 client->protocol = proto;
281 async_answer_0(callid, EOK);
282}
283
284static void inet_client_init(inet_client_t *client)
285{
286 client->sess = NULL;
287
288 fibril_mutex_lock(&client_list_lock);
289 list_append(&client->client_list, &client_list);
290 fibril_mutex_unlock(&client_list_lock);
291}
292
293static void inet_client_fini(inet_client_t *client)
294{
295 async_hangup(client->sess);
296 client->sess = NULL;
297
298 fibril_mutex_lock(&client_list_lock);
299 list_remove(&client->client_list);
300 fibril_mutex_unlock(&client_list_lock);
301}
302
[0e25780]303static void inet_default_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[c76e926]304{
305 inet_client_t client;
306
[a1a101d]307 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
[c76e926]308
309 /* Accept the connection */
310 async_answer_0(iid, EOK);
311
312 inet_client_init(&client);
313
314 while (true) {
315 ipc_call_t call;
316 ipc_callid_t callid = async_get_call(&call);
317 sysarg_t method = IPC_GET_IMETHOD(call);
318
319 if (!method) {
320 /* The other side has hung up */
321 async_answer_0(callid, EOK);
322 return;
323 }
324
325 switch (method) {
326 case INET_CALLBACK_CREATE:
[ceba4bed]327 inet_callback_create_srv(&client, callid, &call);
[c76e926]328 break;
[ecff3d9]329 case INET_GET_SRCADDR:
[ceba4bed]330 inet_get_srcaddr_srv(&client, callid, &call);
[ecff3d9]331 break;
[c76e926]332 case INET_SEND:
[ceba4bed]333 inet_send_srv(&client, callid, &call);
[c76e926]334 break;
335 case INET_SET_PROTO:
[ceba4bed]336 inet_set_proto_srv(&client, callid, &call);
[c76e926]337 break;
338 default:
339 async_answer_0(callid, EINVAL);
340 }
341 }
342
343 inet_client_fini(&client);
344}
345
[0e25780]346static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
347{
348 sysarg_t port;
349
350 port = IPC_GET_ARG1(*icall);
351
352 switch (port) {
353 case INET_PORT_DEFAULT:
354 inet_default_conn(iid, icall, arg);
355 break;
356 case INET_PORT_CFG:
357 inet_cfg_conn(iid, icall, arg);
358 break;
[6428115]359 case INET_PORT_PING:
360 inetping_conn(iid, icall, arg);
361 break;
[1d24ad3]362 case INET_PORT_PING6:
363 inetping6_conn(iid, icall, arg);
364 break;
[0e25780]365 default:
366 async_answer_0(iid, ENOTSUP);
367 break;
368 }
369}
370
[fe4310f]371static inet_client_t *inet_client_find(uint8_t proto)
372{
373 fibril_mutex_lock(&client_list_lock);
374
375 list_foreach(client_list, link) {
376 inet_client_t *client = list_get_instance(link, inet_client_t,
377 client_list);
378
379 if (client->protocol == proto) {
380 fibril_mutex_unlock(&client_list_lock);
381 return client;
382 }
383 }
384
385 fibril_mutex_unlock(&client_list_lock);
386 return NULL;
387}
388
[59157eb]389int inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
390{
[02a09ed]391 async_exch_t *exch = async_exchange_begin(client->sess);
[a2e3ee6]392
[02a09ed]393 ipc_call_t answer;
394 aid_t req = async_send_1(exch, INET_EV_RECV, dgram->tos, &answer);
395
396 int rc = async_data_write_start(exch, &dgram->src, sizeof(inet_addr_t));
397 if (rc != EOK) {
398 async_exchange_end(exch);
399 async_forget(req);
[a2e3ee6]400 return rc;
[02a09ed]401 }
[a2e3ee6]402
[02a09ed]403 rc = async_data_write_start(exch, &dgram->dest, sizeof(inet_addr_t));
404 if (rc != EOK) {
405 async_exchange_end(exch);
406 async_forget(req);
407 return rc;
408 }
[a2e3ee6]409
410 rc = async_data_write_start(exch, dgram->data, dgram->size);
[02a09ed]411
[59157eb]412 async_exchange_end(exch);
[a2e3ee6]413
[59157eb]414 if (rc != EOK) {
[50b581d]415 async_forget(req);
[59157eb]416 return rc;
417 }
[a2e3ee6]418
[59157eb]419 sysarg_t retval;
420 async_wait_for(req, &retval);
[a2e3ee6]421
[02a09ed]422 return (int) retval;
[59157eb]423}
424
[7f95c904]425int inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
[e767dbf]426{
[fe4310f]427 inet_client_t *client;
428
[a1a101d]429 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
[fe4310f]430
[1d24ad3]431 /* ICMP and ICMPv6 messages are handled internally */
[637a3b4]432 if (proto == IP_PROTO_ICMP)
433 return icmp_recv(dgram);
[1d24ad3]434
435 if (proto == IP_PROTO_ICMPV6)
436 return icmpv6_recv(dgram);
[637a3b4]437
[fe4310f]438 client = inet_client_find(proto);
439 if (client == NULL) {
[a1a101d]440 log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
[fe4310f]441 proto);
442 return ENOENT;
443 }
444
445 return inet_ev_recv(client, dgram);
446}
447
448int inet_recv_packet(inet_packet_t *packet)
449{
450 inet_addrobj_t *addr;
451 inet_dgram_t dgram;
452
453 addr = inet_addrobj_find(&packet->dest, iaf_addr);
454 if (addr != NULL) {
455 /* Destined for one of the local addresses */
456
[7f95c904]457 /* Check if packet is a complete datagram */
458 if (packet->offs == 0 && !packet->mf) {
459 /* It is complete deliver it immediately */
460 dgram.src = packet->src;
461 dgram.dest = packet->dest;
462 dgram.tos = packet->tos;
463 dgram.data = packet->data;
464 dgram.size = packet->size;
465
466 return inet_recv_dgram_local(&dgram, packet->proto);
467 } else {
468 /* It is a fragment, queue it for reassembly */
469 inet_reass_queue_packet(packet);
470 }
[fe4310f]471 }
472
473 return ENOENT;
[e767dbf]474}
475
[c76e926]476int main(int argc, char *argv[])
477{
478 int rc;
479
[e2e56e67]480 printf(NAME ": HelenOS Internet Protocol service\n");
[c76e926]481
[267f235]482 if (log_init(NAME) != EOK) {
[e2e56e67]483 printf(NAME ": Failed to initialize logging.\n");
[c76e926]484 return 1;
485 }
486
487 rc = inet_init();
488 if (rc != EOK)
489 return 1;
490
[ecff3d9]491 printf(NAME ": Accepting connections.\n");
[c76e926]492 task_retval(0);
493 async_manager();
494
495 /* Not reached */
496 return 0;
497}
498
499/** @}
500 */
Note: See TracBrowser for help on using the repository browser.