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

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

use default IP address 10.0.2.15 and default gateway 10.0.2.2
this should be convenient for the majority of people running HelenOS in QEMU

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