source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ 1543d4c

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1543d4c was 4c6fd56, checked in by Jiri Svoboda <jiri@…>, 2 years ago

loc_server_register() should be callable more than once (API only)

Now loc_server_register() returns a pointer to a loc_srv_t object,
that is then passed to loc_service_register() and
loc_service_add_to_cat().

Added loc_server_unregister() that unregisters the server
and frees the loc_srv_t object.

Updated all callers. The implementation, however, is a stub.
It is not actually possible to call loc_server_register() more
than once, yet.

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