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

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

Rename app/inetcfg to app/inet, srv/inet to srv/inetsrv. Administration tools are run more often from the command line than the services they configure. It makes sense for them to have the shorter name.

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