source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ 659ebd86

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

unify interface API

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