source: mainline/uspace/srv/net/inetsrv/addrobj.c

Last change on this file was 36fcd0a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 9 months ago

Fix 32b build

  • Property mode set to 100644
File size: 11.3 KB
Line 
1/*
2 * Copyright (c) 2024 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
35 */
36
37#include <bitops.h>
38#include <errno.h>
39#include <fibril_synch.h>
40#include <inet/eth_addr.h>
41#include <io/log.h>
42#include <ipc/loc.h>
43#include <sif.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <str.h>
47#include "addrobj.h"
48#include "inetsrv.h"
49#include "inet_link.h"
50#include "ndp.h"
51
52static inet_addrobj_t *inet_addrobj_find_by_name_locked(const char *, inet_link_t *);
53
54static FIBRIL_MUTEX_INITIALIZE(addr_list_lock);
55static LIST_INITIALIZE(addr_list);
56static sysarg_t addr_id = 0;
57
58inet_addrobj_t *inet_addrobj_new(void)
59{
60 inet_addrobj_t *addr = calloc(1, sizeof(inet_addrobj_t));
61
62 if (addr == NULL) {
63 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating address object. "
64 "Out of memory.");
65 return NULL;
66 }
67
68 link_initialize(&addr->addr_list);
69 fibril_mutex_lock(&addr_list_lock);
70 addr->id = ++addr_id;
71 fibril_mutex_unlock(&addr_list_lock);
72
73 return addr;
74}
75
76void inet_addrobj_delete(inet_addrobj_t *addr)
77{
78 if (addr->name != NULL)
79 free(addr->name);
80 free(addr);
81}
82
83errno_t inet_addrobj_add(inet_addrobj_t *addr)
84{
85 inet_addrobj_t *aobj;
86
87 fibril_mutex_lock(&addr_list_lock);
88 aobj = inet_addrobj_find_by_name_locked(addr->name, addr->ilink);
89 if (aobj != NULL) {
90 /* Duplicate address name */
91 fibril_mutex_unlock(&addr_list_lock);
92 return EEXIST;
93 }
94
95 list_append(&addr->addr_list, &addr_list);
96 fibril_mutex_unlock(&addr_list_lock);
97
98 return EOK;
99}
100
101void inet_addrobj_remove(inet_addrobj_t *addr)
102{
103 fibril_mutex_lock(&addr_list_lock);
104 list_remove(&addr->addr_list);
105 fibril_mutex_unlock(&addr_list_lock);
106}
107
108/** Find address object matching address @a addr.
109 *
110 * @param addr Address
111 * @oaram find iaf_net to find network (using mask),
112 * iaf_addr to find local address (exact match)
113 *
114 */
115inet_addrobj_t *inet_addrobj_find(inet_addr_t *addr, inet_addrobj_find_t find)
116{
117 fibril_mutex_lock(&addr_list_lock);
118
119 list_foreach(addr_list, addr_list, inet_addrobj_t, naddr) {
120 switch (find) {
121 case iaf_net:
122 if (inet_naddr_compare_mask(&naddr->naddr, addr)) {
123 fibril_mutex_unlock(&addr_list_lock);
124 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: found %p",
125 naddr);
126 return naddr;
127 }
128 break;
129 case iaf_addr:
130 if (inet_naddr_compare(&naddr->naddr, addr)) {
131 fibril_mutex_unlock(&addr_list_lock);
132 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: found %p",
133 naddr);
134 return naddr;
135 }
136 break;
137 }
138 }
139
140 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find: Not found");
141 fibril_mutex_unlock(&addr_list_lock);
142
143 return NULL;
144}
145
146/** Find address object on a link, with a specific name.
147 *
148 * @param name Address object name
149 * @param ilink Inet link
150 * @return Address object
151 */
152static inet_addrobj_t *inet_addrobj_find_by_name_locked(const char *name, inet_link_t *ilink)
153{
154 assert(fibril_mutex_is_locked(&addr_list_lock));
155
156 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked('%s', '%s')",
157 name, ilink->svc_name);
158
159 list_foreach(addr_list, addr_list, inet_addrobj_t, naddr) {
160 if (naddr->ilink == ilink && str_cmp(naddr->name, name) == 0) {
161 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked: found %p",
162 naddr);
163 return naddr;
164 }
165 }
166
167 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name_locked: Not found");
168
169 return NULL;
170}
171
172/** Find address object on a link, with a specific name.
173 *
174 * @param name Address object name
175 * @param ilink Inet link
176 * @return Address object
177 */
178inet_addrobj_t *inet_addrobj_find_by_name(const char *name, inet_link_t *ilink)
179{
180 inet_addrobj_t *aobj;
181
182 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_find_by_name('%s', '%s')",
183 name, ilink->svc_name);
184
185 fibril_mutex_lock(&addr_list_lock);
186 aobj = inet_addrobj_find_by_name_locked(name, ilink);
187 fibril_mutex_unlock(&addr_list_lock);
188
189 return aobj;
190}
191
192/** Find address object with the given ID.
193 *
194 * @param id Address object ID
195 * @return Address object
196 */
197inet_addrobj_t *inet_addrobj_get_by_id(sysarg_t id)
198{
199 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_get_by_id(%zu)", (size_t)id);
200
201 fibril_mutex_lock(&addr_list_lock);
202
203 list_foreach(addr_list, addr_list, inet_addrobj_t, naddr) {
204 if (naddr->id == id) {
205 fibril_mutex_unlock(&addr_list_lock);
206 return naddr;
207 }
208 }
209
210 fibril_mutex_unlock(&addr_list_lock);
211
212 return NULL;
213}
214
215/** Count number of non-temporary address objects configured for link.
216 *
217 * @param ilink Inet link
218 * @return Number of address objects configured for this link
219 */
220unsigned inet_addrobj_cnt_by_link(inet_link_t *ilink)
221{
222 unsigned cnt;
223
224 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_cnt_by_link()");
225
226 fibril_mutex_lock(&addr_list_lock);
227
228 cnt = 0;
229 list_foreach(addr_list, addr_list, inet_addrobj_t, naddr) {
230 if (naddr->ilink == ilink && naddr->temp == false)
231 ++cnt;
232 }
233
234 fibril_mutex_unlock(&addr_list_lock);
235 return cnt;
236}
237
238/** Send datagram from address object */
239errno_t inet_addrobj_send_dgram(inet_addrobj_t *addr, inet_addr_t *ldest,
240 inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
241{
242 inet_addr_t lsrc_addr;
243 inet_naddr_addr(&addr->naddr, &lsrc_addr);
244
245 addr32_t lsrc_v4;
246 addr128_t lsrc_v6;
247 ip_ver_t lsrc_ver = inet_addr_get(&lsrc_addr, &lsrc_v4, &lsrc_v6);
248
249 addr32_t ldest_v4;
250 addr128_t ldest_v6;
251 ip_ver_t ldest_ver = inet_addr_get(ldest, &ldest_v4, &ldest_v6);
252
253 if (lsrc_ver != ldest_ver)
254 return EINVAL;
255
256 errno_t rc;
257 eth_addr_t ldest_mac;
258
259 switch (ldest_ver) {
260 case ip_v4:
261 return inet_link_send_dgram(addr->ilink, lsrc_v4, ldest_v4,
262 dgram, proto, ttl, df);
263 case ip_v6:
264 /*
265 * Translate local destination IPv6 address.
266 */
267 rc = ndp_translate(lsrc_v6, ldest_v6, &ldest_mac, addr->ilink);
268 if (rc != EOK)
269 return rc;
270
271 return inet_link_send_dgram6(addr->ilink, &ldest_mac, dgram,
272 proto, ttl, df);
273 default:
274 assert(false);
275 break;
276 }
277
278 return ENOTSUP;
279}
280
281/** Get IDs of all address objects. */
282errno_t inet_addrobj_get_id_list(sysarg_t **rid_list, size_t *rcount)
283{
284 sysarg_t *id_list;
285 size_t count, i;
286
287 fibril_mutex_lock(&addr_list_lock);
288 count = list_count(&addr_list);
289
290 id_list = calloc(count, sizeof(sysarg_t));
291 if (id_list == NULL) {
292 fibril_mutex_unlock(&addr_list_lock);
293 return ENOMEM;
294 }
295
296 i = 0;
297 list_foreach(addr_list, addr_list, inet_addrobj_t, addr) {
298 id_list[i++] = addr->id;
299 }
300
301 fibril_mutex_unlock(&addr_list_lock);
302
303 *rid_list = id_list;
304 *rcount = count;
305
306 return EOK;
307}
308
309/** Load address object from SIF node.
310 *
311 * @param anode SIF node to load address object from
312 * @return EOK on success or an error code
313 */
314static errno_t inet_addrobj_load(sif_node_t *anode)
315{
316 errno_t rc;
317 const char *sid;
318 const char *snaddr;
319 const char *slink;
320 const char *name;
321 char *endptr;
322 int id;
323 inet_naddr_t naddr;
324 inet_addrobj_t *addr;
325 inet_link_t *link;
326
327 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_load()");
328
329 sid = sif_node_get_attr(anode, "id");
330 if (sid == NULL)
331 return EIO;
332
333 snaddr = sif_node_get_attr(anode, "naddr");
334 if (snaddr == NULL)
335 return EIO;
336
337 slink = sif_node_get_attr(anode, "link");
338 if (slink == NULL)
339 return EIO;
340
341 name = sif_node_get_attr(anode, "name");
342 if (name == NULL)
343 return EIO;
344
345 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_addrobj_load(): id='%s' "
346 "naddr='%s' link='%s' name='%s'", sid, snaddr, slink, name);
347
348 id = strtoul(sid, &endptr, 10);
349 if (*endptr != '\0')
350 return EIO;
351
352 rc = inet_naddr_parse(snaddr, &naddr, NULL);
353 if (rc != EOK)
354 return EIO;
355
356 link = inet_link_get_by_svc_name(slink);
357 if (link == NULL) {
358 log_msg(LOG_DEFAULT, LVL_ERROR, "Link '%s' not found",
359 slink);
360 return EIO;
361 }
362
363 addr = inet_addrobj_new();
364 if (addr == NULL)
365 return ENOMEM;
366
367 addr->id = id;
368 addr->naddr = naddr;
369 addr->ilink = link;
370 addr->name = str_dup(name);
371
372 if (addr->name == NULL) {
373 inet_addrobj_delete(addr);
374 return ENOMEM;
375 }
376
377 inet_addrobj_add(addr);
378 return EOK;
379}
380
381/** Load address objects from SIF node.
382 *
383 * @param naddrs SIF node to load address objects from
384 * @return EOK on success or an error code
385 */
386errno_t inet_addrobjs_load(sif_node_t *naddrs)
387{
388 sif_node_t *naddr;
389 const char *ntype;
390 errno_t rc;
391
392 naddr = sif_node_first_child(naddrs);
393 while (naddr != NULL) {
394 ntype = sif_node_get_type(naddr);
395 if (str_cmp(ntype, "address") != 0) {
396 rc = EIO;
397 goto error;
398 }
399
400 rc = inet_addrobj_load(naddr);
401 if (rc != EOK)
402 goto error;
403
404 naddr = sif_node_next_child(naddr);
405 }
406
407 return EOK;
408error:
409 return rc;
410
411}
412
413/** Save address object to SIF node.
414 *
415 * @param addr Address object
416 * @param naddr SIF node to save addres to
417 * @return EOK on success or an error code
418 */
419static errno_t inet_addrobj_save(inet_addrobj_t *addr, sif_node_t *naddr)
420{
421 char *str = NULL;
422 errno_t rc;
423 int rv;
424
425 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobj_save(%p, %p)",
426 addr, naddr);
427
428 /* id */
429
430 rv = asprintf(&str, "%zu", addr->id);
431 if (rv < 0) {
432 str = NULL;
433 rc = ENOMEM;
434 goto error;
435 }
436
437 rc = sif_node_set_attr(naddr, "id", str);
438 if (rc != EOK)
439 goto error;
440
441 free(str);
442 str = NULL;
443
444 /* dest */
445
446 rc = inet_naddr_format(&addr->naddr, &str);
447 if (rc != EOK)
448 goto error;
449
450 rc = sif_node_set_attr(naddr, "naddr", str);
451 if (rc != EOK)
452 goto error;
453
454 free(str);
455 str = NULL;
456
457 /* link */
458
459 rc = sif_node_set_attr(naddr, "link", addr->ilink->svc_name);
460 if (rc != EOK)
461 goto error;
462
463 /* name */
464
465 rc = sif_node_set_attr(naddr, "name", addr->name);
466 if (rc != EOK)
467 goto error;
468
469 free(str);
470
471 return rc;
472error:
473 if (str != NULL)
474 free(str);
475 return rc;
476}
477
478/** Save address objects to SIF node.
479 *
480 * @param cnode SIF node to save address objects to
481 * @return EOK on success or an error code
482 */
483errno_t inet_addrobjs_save(sif_node_t *cnode)
484{
485 sif_node_t *naddr;
486 errno_t rc;
487
488 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_addrobjs_save()");
489
490 fibril_mutex_lock(&addr_list_lock);
491
492 list_foreach(addr_list, addr_list, inet_addrobj_t, addr) {
493 if (addr->temp == false) {
494 rc = sif_node_append_child(cnode, "address", &naddr);
495 if (rc != EOK)
496 goto error;
497
498 rc = inet_addrobj_save(addr, naddr);
499 if (rc != EOK)
500 goto error;
501 }
502 }
503
504 fibril_mutex_unlock(&addr_list_lock);
505 return EOK;
506error:
507 fibril_mutex_unlock(&addr_list_lock);
508 return rc;
509}
510
511/** @}
512 */
Note: See TracBrowser for help on using the repository browser.