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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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