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
Line 
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>
46#include <stdlib.h>
47#include <sys/types.h>
48#include <net/socket_codes.h>
49#include "addrobj.h"
50#include "icmp.h"
51#include "icmp_std.h"
52#include "icmpv6.h"
53#include "icmpv6_std.h"
54#include "inetsrv.h"
55#include "inetcfg.h"
56#include "inetping.h"
57#include "inetping6.h"
58#include "inet_link.h"
59#include "reass.h"
60#include "sroute.h"
61
62#define NAME "inetsrv"
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{
71 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
72
73 async_set_client_connection(inet_client_conn);
74
75 int rc = loc_server_register(NAME);
76 if (rc != EOK) {
77 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server (%d).", rc);
78 return EEXIST;
79 }
80
81 service_id_t sid;
82 rc = loc_service_register_with_iface(SERVICE_NAME_INET, &sid,
83 INET_PORT_DEFAULT);
84 if (rc != EOK) {
85 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
86 return EEXIST;
87 }
88
89 rc = loc_service_register_with_iface(SERVICE_NAME_INETCFG, &sid,
90 INET_PORT_CFG);
91 if (rc != EOK) {
92 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
93 return EEXIST;
94 }
95
96 rc = loc_service_register_with_iface(SERVICE_NAME_INETPING, &sid,
97 INET_PORT_PING);
98 if (rc != EOK) {
99 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service (%d).", rc);
100 return EEXIST;
101 }
102
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
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
116 inet_naddr(&sroute->dest, 0, 0, 0, 0, 0);
117 inet_addr(&sroute->router, 10, 0, 2, 2);
118 sroute->name = str_dup("default");
119 inet_sroute_add(sroute);
120
121 rc = inet_link_discovery_start();
122 if (rc != EOK)
123 return EEXIST;
124
125 return EOK;
126}
127
128static void inet_callback_create_srv(inet_client_t *client, ipc_callid_t callid,
129 ipc_call_t *call)
130{
131 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_callback_create_srv()");
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
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) {
166 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send: No route to destination.");
167 return ENOENT;
168 }
169
170 return EOK;
171}
172
173int inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl,
174 int df)
175{
176 inet_dir_t dir;
177 int rc;
178
179 rc = inet_find_dir(&dgram->src, &dgram->dest, dgram->tos, &dir);
180 if (rc != EOK)
181 return rc;
182
183 return inet_addrobj_send_dgram(dir.aobj, &dir.ldest, dgram,
184 proto, ttl, df);
185}
186
187static int inet_send(inet_client_t *client, inet_dgram_t *dgram,
188 uint8_t proto, uint8_t ttl, int df)
189{
190 return inet_route_packet(dgram, proto, ttl, df);
191}
192
193int inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
194{
195 inet_dir_t dir;
196 int rc;
197
198 rc = inet_find_dir(NULL, remote, tos, &dir);
199 if (rc != EOK)
200 return rc;
201
202 /* XXX dt_local? */
203
204 /* Take source address from the address object */
205 inet_naddr_addr(&dir.aobj->naddr, local);
206 return EOK;
207}
208
209static void inet_get_srcaddr_srv(inet_client_t *client, ipc_callid_t callid,
210 ipc_call_t *call)
211{
212 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
213
214 addr32_t remote_v4 = IPC_GET_ARG1(*call);
215 uint8_t tos = IPC_GET_ARG2(*call);
216
217 inet_addr_t remote;
218 inet_addr_set(remote_v4, &remote);
219
220 inet_addr_t local;
221 int rc = inet_get_srcaddr(&remote, tos, &local);
222 if (rc != EOK) {
223 async_answer_0(callid, rc);
224 return;
225 }
226
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);
231 return;
232 }
233
234 async_answer_1(callid, rc, (sysarg_t) local_v4);
235}
236
237static void inet_send_srv(inet_client_t *client, ipc_callid_t callid,
238 ipc_call_t *call)
239{
240 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
241
242 addr32_t src_v4 = IPC_GET_ARG1(*call);
243 addr32_t dest_v4 = IPC_GET_ARG2(*call);
244
245 inet_dgram_t dgram;
246
247 inet_addr_set(src_v4, &dgram.src);
248 inet_addr_set(dest_v4, &dgram.dest);
249 dgram.tos = IPC_GET_ARG3(*call);
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);
256 if (rc != EOK) {
257 async_answer_0(callid, rc);
258 return;
259 }
260
261 rc = inet_send(client, &dgram, client->protocol, ttl, df);
262
263 free(dgram.data);
264 async_answer_0(callid, rc);
265}
266
267static void inet_set_proto_srv(inet_client_t *client, ipc_callid_t callid,
268 ipc_call_t *call)
269{
270 sysarg_t proto;
271
272 proto = IPC_GET_ARG1(*call);
273 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
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
303static void inet_default_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
304{
305 inet_client_t client;
306
307 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
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:
327 inet_callback_create_srv(&client, callid, &call);
328 break;
329 case INET_GET_SRCADDR:
330 inet_get_srcaddr_srv(&client, callid, &call);
331 break;
332 case INET_SEND:
333 inet_send_srv(&client, callid, &call);
334 break;
335 case INET_SET_PROTO:
336 inet_set_proto_srv(&client, callid, &call);
337 break;
338 default:
339 async_answer_0(callid, EINVAL);
340 }
341 }
342
343 inet_client_fini(&client);
344}
345
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;
359 case INET_PORT_PING:
360 inetping_conn(iid, icall, arg);
361 break;
362 case INET_PORT_PING6:
363 inetping6_conn(iid, icall, arg);
364 break;
365 default:
366 async_answer_0(iid, ENOTSUP);
367 break;
368 }
369}
370
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
389int inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
390{
391 async_exch_t *exch = async_exchange_begin(client->sess);
392
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);
400 return rc;
401 }
402
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 }
409
410 rc = async_data_write_start(exch, dgram->data, dgram->size);
411
412 async_exchange_end(exch);
413
414 if (rc != EOK) {
415 async_forget(req);
416 return rc;
417 }
418
419 sysarg_t retval;
420 async_wait_for(req, &retval);
421
422 return (int) retval;
423}
424
425int inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
426{
427 inet_client_t *client;
428
429 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
430
431 /* ICMP and ICMPv6 messages are handled internally */
432 if (proto == IP_PROTO_ICMP)
433 return icmp_recv(dgram);
434
435 if (proto == IP_PROTO_ICMPV6)
436 return icmpv6_recv(dgram);
437
438 client = inet_client_find(proto);
439 if (client == NULL) {
440 log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
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
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 }
471 }
472
473 return ENOENT;
474}
475
476int main(int argc, char *argv[])
477{
478 int rc;
479
480 printf(NAME ": HelenOS Internet Protocol service\n");
481
482 if (log_init(NAME) != EOK) {
483 printf(NAME ": Failed to initialize logging.\n");
484 return 1;
485 }
486
487 rc = inet_init();
488 if (rc != EOK)
489 return 1;
490
491 printf(NAME ": Accepting connections.\n");
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.