source: mainline/uspace/srv/net/inetsrv/inet_link.c@ ca48672

Last change on this file since ca48672 was 1bbc6dc, checked in by Jiri Svoboda <jiri@…>, 10 months ago

Network configuration persistence.

nconfsrv is folded into inetsrv
DHCP is disabled when a static address is configured on a link

  • Property mode set to 100644
File size: 17.9 KB
RevLine 
[e2e56e67]1/*
[1bbc6dc]2 * Copyright (c) 2024 Jiri Svoboda
[e2e56e67]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 <errno.h>
38#include <fibril_synch.h>
[1bbc6dc]39#include <inet/dhcp.h>
[b4edc96]40#include <inet/eth_addr.h>
[e2e56e67]41#include <inet/iplink.h>
42#include <io/log.h>
43#include <loc.h>
[b4edc96]44#include <stdbool.h>
[e2e56e67]45#include <stdlib.h>
[0e94b979]46#include <str.h>
[b4edc96]47#include <str_error.h>
[ceba4bed]48#include "addrobj.h"
[b4ec1ea]49#include "inetsrv.h"
[e2e56e67]50#include "inet_link.h"
[ceba4bed]51#include "pdu.h"
[e2e56e67]52
[3aece36]53static bool first_link = true;
54static bool first_link6 = true;
55
[313824a]56static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
57static uint16_t ip_ident = 0;
58
[b7fd2a0]59static errno_t inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
[b4edc96]60static errno_t inet_iplink_change_addr(iplink_t *, eth_addr_t *);
[b417559]61static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
[e2e56e67]62
63static iplink_ev_ops_t inet_iplink_ev_ops = {
[c3b25985]64 .recv = inet_iplink_recv,
65 .change_addr = inet_iplink_change_addr,
[e2e56e67]66};
67
[7af0cc5]68static LIST_INITIALIZE(inet_links);
69static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
[e2e56e67]70
[3aece36]71static addr128_t link_local_node_ip =
[1433ecda]72 { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0, 0 };
[3aece36]73
[b4edc96]74static void inet_link_local_node_ip(eth_addr_t *mac_addr,
[3aece36]75 addr128_t ip_addr)
76{
[3e6bca8]77 uint8_t b[ETH_ADDR_SIZE];
[8d48c7e]78
[3e6bca8]79 memcpy(ip_addr, link_local_node_ip, 16);
80 eth_addr_encode(mac_addr, b);
81
82 ip_addr[8] = b[0] ^ 0x02;
83 ip_addr[9] = b[1];
84 ip_addr[10] = b[2];
85 ip_addr[13] = b[3];
86 ip_addr[14] = b[4];
87 ip_addr[15] = b[5];
[3aece36]88}
89
[b7fd2a0]90static errno_t inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, ip_ver_t ver)
[e2e56e67]91{
[a1a101d]92 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
[8d48c7e]93
[b7fd2a0]94 errno_t rc;
[02a09ed]95 inet_packet_t packet;
[8d48c7e]96 inet_link_t *ilink;
97
98 ilink = (inet_link_t *)iplink_get_userptr(iplink);
99
[417a2ba1]100 switch (ver) {
101 case ip_v4:
[8d48c7e]102 rc = inet_pdu_decode(sdu->data, sdu->size, ilink->svc_id,
103 &packet);
[02a09ed]104 break;
[417a2ba1]105 case ip_v6:
[8d48c7e]106 rc = inet_pdu_decode6(sdu->data, sdu->size, ilink->svc_id,
107 &packet);
[1d24ad3]108 break;
[02a09ed]109 default:
[417a2ba1]110 log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid IP version");
[02a09ed]111 return EINVAL;
112 }
[8d48c7e]113
[fe4310f]114 if (rc != EOK) {
[a1a101d]115 log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
[e767dbf]116 return rc;
[fe4310f]117 }
[8d48c7e]118
[ac415d50]119 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv: link_id=%zu", packet.link_id);
[a1a101d]120 log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
[fe4310f]121 rc = inet_recv_packet(&packet);
[c1694b6b]122 log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %s", str_error_name(rc));
[7f95c904]123 free(packet.data);
[8d48c7e]124
[fe4310f]125 return rc;
[e2e56e67]126}
127
[b4edc96]128static errno_t inet_iplink_change_addr(iplink_t *iplink, eth_addr_t *mac)
[c3b25985]129{
[3e6bca8]130 eth_addr_str_t saddr;
131
132 eth_addr_format(mac, &saddr);
[c3b25985]133 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_change_addr(): "
[3e6bca8]134 "new addr=%s", saddr.str);
[c3b25985]135
136 list_foreach(inet_links, link_list, inet_link_t, ilink) {
137 if (ilink->sess == iplink->sess)
[b4edc96]138 ilink->mac = *mac;
[c3b25985]139 }
140
141 return EOK;
142}
143
[e2e56e67]144static inet_link_t *inet_link_new(void)
145{
146 inet_link_t *ilink = calloc(1, sizeof(inet_link_t));
147
148 if (ilink == NULL) {
[a1a101d]149 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating link structure. "
[e2e56e67]150 "Out of memory.");
151 return NULL;
152 }
153
154 link_initialize(&ilink->link_list);
155
156 return ilink;
157}
158
159static void inet_link_delete(inet_link_t *ilink)
160{
161 if (ilink->svc_name != NULL)
162 free(ilink->svc_name);
[a35b458]163
[e2e56e67]164 free(ilink);
165}
166
[1bbc6dc]167/** Open new IP link while inet_links_lock is held.
168 *
169 * @param sid IP link service ID
170 * @return EOK on success or an error code
171 */
172static errno_t inet_link_open_locked(service_id_t sid)
[e2e56e67]173{
174 inet_link_t *ilink;
[a2e3ee6]175 inet_addr_t iaddr;
[b7fd2a0]176 errno_t rc;
[e2e56e67]177
[1bbc6dc]178 assert(fibril_mutex_is_locked(&inet_links_lock));
179
180 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_link_open_locked()");
[e2e56e67]181 ilink = inet_link_new();
182 if (ilink == NULL)
183 return ENOMEM;
184
[45aa22c]185 ilink->svc_id = sid;
[347768d]186 ilink->iplink = NULL;
[45aa22c]187
[e2e56e67]188 rc = loc_service_get_name(sid, &ilink->svc_name);
189 if (rc != EOK) {
[a1a101d]190 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
[e2e56e67]191 goto error;
192 }
193
[f9b2cb4c]194 ilink->sess = loc_service_connect(sid, INTERFACE_IPLINK, 0);
[e2e56e67]195 if (ilink->sess == NULL) {
[a1a101d]196 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting '%s'", ilink->svc_name);
[e2e56e67]197 goto error;
198 }
199
[8d48c7e]200 rc = iplink_open(ilink->sess, &inet_iplink_ev_ops, ilink, &ilink->iplink);
[e2e56e67]201 if (rc != EOK) {
[a1a101d]202 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening IP link '%s'",
[e2e56e67]203 ilink->svc_name);
204 goto error;
205 }
206
[347768d]207 rc = iplink_get_mtu(ilink->iplink, &ilink->def_mtu);
208 if (rc != EOK) {
[a1a101d]209 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed determinning MTU of link '%s'",
[347768d]210 ilink->svc_name);
211 goto error;
212 }
[a35b458]213
[a17356fd]214 /*
215 * Get the MAC address of the link. If the link has a MAC
216 * address, we assume that it supports NDP.
217 */
218 rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
219 ilink->mac_valid = (rc == EOK);
[347768d]220
[a1a101d]221 log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
[b417559]222
223 if (inet_link_get_by_id_locked(sid) != NULL) {
224 log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
225 sid);
226 rc = EEXIST;
227 goto error;
228 }
229
[7af0cc5]230 list_append(&ilink->link_list, &inet_links);
[e2e56e67]231
[3aece36]232 inet_addrobj_t *addr = NULL;
[a35b458]233
[695b6ff]234 /* XXX FIXME Cannot rely on loopback being the first IP link service!! */
[3aece36]235 if (first_link) {
236 addr = inet_addrobj_new();
[a35b458]237
[a2e3ee6]238 inet_naddr(&addr->naddr, 127, 0, 0, 1, 24);
[3aece36]239 first_link = false;
[081971b]240 }
[a35b458]241
[3aece36]242 if (addr != NULL) {
243 addr->ilink = ilink;
244 addr->name = str_dup("v4a");
[1bbc6dc]245 addr->temp = true;
[a35b458]246
[3aece36]247 rc = inet_addrobj_add(addr);
248 if (rc == EOK) {
249 inet_naddr_addr(&addr->naddr, &iaddr);
250 rc = iplink_addr_add(ilink->iplink, &iaddr);
251 if (rc != EOK) {
252 log_msg(LOG_DEFAULT, LVL_ERROR,
253 "Failed setting IPv4 address on internet link.");
254 inet_addrobj_remove(addr);
255 inet_addrobj_delete(addr);
256 }
257 } else {
258 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv4 address.");
259 inet_addrobj_delete(addr);
260 }
[bf9e6fc]261 }
[a35b458]262
[3aece36]263 inet_addrobj_t *addr6 = NULL;
[a35b458]264
[3aece36]265 if (first_link6) {
266 addr6 = inet_addrobj_new();
[a35b458]267
[3aece36]268 inet_naddr6(&addr6->naddr, 0, 0, 0, 0, 0, 0, 0, 1, 128);
269 first_link6 = false;
270 } else if (ilink->mac_valid) {
271 addr6 = inet_addrobj_new();
[a35b458]272
[3aece36]273 addr128_t link_local;
[f05edcb]274 inet_link_local_node_ip(&ilink->mac, link_local);
[a35b458]275
[3aece36]276 inet_naddr_set6(link_local, 64, &addr6->naddr);
[962f03b]277 }
[a35b458]278
[3aece36]279 if (addr6 != NULL) {
280 addr6->ilink = ilink;
281 addr6->name = str_dup("v6a");
[1bbc6dc]282 addr6->temp = true;
[a35b458]283
[3aece36]284 rc = inet_addrobj_add(addr6);
285 if (rc == EOK) {
286 inet_naddr_addr(&addr6->naddr, &iaddr);
287 rc = iplink_addr_add(ilink->iplink, &iaddr);
288 if (rc != EOK) {
289 log_msg(LOG_DEFAULT, LVL_ERROR,
290 "Failed setting IPv6 address on internet link.");
291 inet_addrobj_remove(addr6);
292 inet_addrobj_delete(addr6);
293 }
294 } else {
295 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv6 address.");
296 inet_addrobj_delete(addr6);
297 }
[1d24ad3]298 }
[a35b458]299
[bd88bee]300 log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
[e2e56e67]301 return EOK;
[a35b458]302
[e2e56e67]303error:
[347768d]304 if (ilink->iplink != NULL)
305 iplink_close(ilink->iplink);
[a35b458]306
[e2e56e67]307 inet_link_delete(ilink);
308 return rc;
309}
310
[1bbc6dc]311/** Open new IP link..
312 *
313 * @param sid IP link service ID
314 * @return EOK on success or an error code
315 */
316errno_t inet_link_open(service_id_t sid)
317{
318 errno_t rc;
319
320 fibril_mutex_lock(&inet_links_lock);
321 rc = inet_link_open_locked(sid);
322 fibril_mutex_unlock(&inet_links_lock);
323
324 return rc;
325}
326
[1f97352]327/** Send IPv4 datagram over Internet link
328 *
329 * @param ilink Internet link
330 * @param lsrc Source IPv4 address
331 * @param ldest Destination IPv4 address
332 * @param dgram IPv4 datagram body
333 * @param proto Protocol
334 * @param ttl Time-to-live
335 * @param df Do-not-Fragment flag
336 *
337 * @return EOK on success
338 * @return ENOMEM when not enough memory to create the datagram
339 * @return ENOTSUP if networking mode is not supported
340 *
341 */
[b7fd2a0]342errno_t inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
[a17356fd]343 inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
[ceba4bed]344{
[a17356fd]345 addr32_t src_v4;
[f023251]346 ip_ver_t src_ver = inet_addr_get(&dgram->src, &src_v4, NULL);
347 if (src_ver != ip_v4)
[a17356fd]348 return EINVAL;
[a35b458]349
[a17356fd]350 addr32_t dest_v4;
[f023251]351 ip_ver_t dest_ver = inet_addr_get(&dgram->dest, &dest_v4, NULL);
352 if (dest_ver != ip_v4)
[a17356fd]353 return EINVAL;
[a35b458]354
[347768d]355 /*
356 * Fill packet structure. Fragmentation is performed by
357 * inet_pdu_encode().
358 */
[a35b458]359
[a17356fd]360 iplink_sdu_t sdu;
[a35b458]361
[a17356fd]362 sdu.src = lsrc;
363 sdu.dest = ldest;
[a35b458]364
[a2e3ee6]365 inet_packet_t packet;
[a35b458]366
[fe4310f]367 packet.src = dgram->src;
368 packet.dest = dgram->dest;
369 packet.tos = dgram->tos;
[2ff150e]370 packet.proto = proto;
[fe4310f]371 packet.ttl = ttl;
[a35b458]372
[313824a]373 /* Allocate identifier */
374 fibril_mutex_lock(&ip_ident_lock);
375 packet.ident = ++ip_ident;
376 fibril_mutex_unlock(&ip_ident_lock);
[a35b458]377
[fe4310f]378 packet.df = df;
379 packet.data = dgram->data;
380 packet.size = dgram->size;
[a35b458]381
[b7fd2a0]382 errno_t rc;
[313824a]383 size_t offs = 0;
[a35b458]384
[347768d]385 do {
386 /* Encode one fragment */
[a35b458]387
[02a09ed]388 size_t roffs;
[a17356fd]389 rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
390 &sdu.data, &sdu.size, &roffs);
[347768d]391 if (rc != EOK)
392 return rc;
[a35b458]393
[347768d]394 /* Send the PDU */
395 rc = iplink_send(ilink->iplink, &sdu);
[a35b458]396
[347768d]397 free(sdu.data);
[a17356fd]398 offs = roffs;
399 } while (offs < packet.size);
[a35b458]400
[a17356fd]401 return rc;
402}
403
[1f97352]404/** Send IPv6 datagram over Internet link
405 *
406 * @param ilink Internet link
407 * @param ldest Destination MAC address
408 * @param dgram IPv6 datagram body
409 * @param proto Next header
410 * @param ttl Hop limit
411 * @param df Do-not-Fragment flag (unused)
412 *
413 * @return EOK on success
414 * @return ENOMEM when not enough memory to create the datagram
415 *
416 */
[b4edc96]417errno_t inet_link_send_dgram6(inet_link_t *ilink, eth_addr_t *ldest,
[a17356fd]418 inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
419{
420 addr128_t src_v6;
[f023251]421 ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
422 if (src_ver != ip_v6)
[a17356fd]423 return EINVAL;
[a35b458]424
[a17356fd]425 addr128_t dest_v6;
[f023251]426 ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
427 if (dest_ver != ip_v6)
[a17356fd]428 return EINVAL;
[a35b458]429
[a17356fd]430 iplink_sdu6_t sdu6;
[d5ed54b]431 sdu6.dest = *ldest;
[a35b458]432
[a17356fd]433 /*
434 * Fill packet structure. Fragmentation is performed by
435 * inet_pdu_encode6().
436 */
[a35b458]437
[a17356fd]438 inet_packet_t packet;
[a35b458]439
[a17356fd]440 packet.src = dgram->src;
441 packet.dest = dgram->dest;
442 packet.tos = dgram->tos;
443 packet.proto = proto;
444 packet.ttl = ttl;
[a35b458]445
[313824a]446 /* Allocate identifier */
447 fibril_mutex_lock(&ip_ident_lock);
448 packet.ident = ++ip_ident;
449 fibril_mutex_unlock(&ip_ident_lock);
[a35b458]450
[a17356fd]451 packet.df = df;
452 packet.data = dgram->data;
453 packet.size = dgram->size;
[a35b458]454
[b7fd2a0]455 errno_t rc;
[a17356fd]456 size_t offs = 0;
[a35b458]457
[a17356fd]458 do {
459 /* Encode one fragment */
[a35b458]460
[a17356fd]461 size_t roffs;
462 rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
463 &sdu6.data, &sdu6.size, &roffs);
464 if (rc != EOK)
465 return rc;
[a35b458]466
[a17356fd]467 /* Send the PDU */
468 rc = iplink_send6(ilink->iplink, &sdu6);
[a35b458]469
[a17356fd]470 free(sdu6.data);
[347768d]471 offs = roffs;
472 } while (offs < packet.size);
[a35b458]473
[ceba4bed]474 return rc;
475}
476
[b417559]477static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
[45aa22c]478{
[b417559]479 assert(fibril_mutex_is_locked(&inet_links_lock));
[45aa22c]480
[7af0cc5]481 list_foreach(inet_links, link_list, inet_link_t, ilink) {
[b417559]482 if (ilink->svc_id == link_id)
[45aa22c]483 return ilink;
484 }
485
486 return NULL;
487}
[ceba4bed]488
[b417559]489inet_link_t *inet_link_get_by_id(sysarg_t link_id)
490{
491 inet_link_t *ilink;
492
493 fibril_mutex_lock(&inet_links_lock);
494 ilink = inet_link_get_by_id_locked(link_id);
495 fibril_mutex_unlock(&inet_links_lock);
496
497 return ilink;
498}
499
[1bbc6dc]500/** Find link by service name while inet_links_lock is held.
501 *
502 * @param svc_name Service name
503 * @return Link or @c NULL if not found
504 */
505static inet_link_t *inet_link_get_by_svc_name_locked(const char *svc_name)
506{
507 assert(fibril_mutex_is_locked(&inet_links_lock));
508
509 list_foreach(inet_links, link_list, inet_link_t, ilink) {
510 if (str_cmp(ilink->svc_name, svc_name) == 0)
511 return ilink;
512 }
513
514 return NULL;
515}
516
517/** Find link by service name.
518 *
519 * @param svc_name Service name
520 * @return Link or @c NULL if not found
521 */
522inet_link_t *inet_link_get_by_svc_name(const char *svc_name)
523{
524 inet_link_t *ilink;
525
526 fibril_mutex_lock(&inet_links_lock);
527 ilink = inet_link_get_by_svc_name_locked(svc_name);
528 fibril_mutex_unlock(&inet_links_lock);
529
530 return ilink;
531}
532
[b8b1adb1]533/** Get IDs of all links. */
[b7fd2a0]534errno_t inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
[b8b1adb1]535{
536 sysarg_t *id_list;
537 size_t count, i;
538
[7af0cc5]539 fibril_mutex_lock(&inet_links_lock);
540 count = list_count(&inet_links);
[b8b1adb1]541
542 id_list = calloc(count, sizeof(sysarg_t));
543 if (id_list == NULL) {
[7af0cc5]544 fibril_mutex_unlock(&inet_links_lock);
[b8b1adb1]545 return ENOMEM;
546 }
547
548 i = 0;
[7af0cc5]549 list_foreach(inet_links, link_list, inet_link_t, ilink) {
[b8b1adb1]550 id_list[i++] = ilink->svc_id;
551 }
552
[7af0cc5]553 fibril_mutex_unlock(&inet_links_lock);
[b8b1adb1]554
555 *rid_list = id_list;
556 *rcount = count;
557
558 return EOK;
559}
560
[1bbc6dc]561/** Check for new IP links.
562 *
563 * @return EOK on success or an error code
564 */
565static errno_t inet_link_check_new(void)
566{
567 bool already_known;
568 category_id_t iplink_cat;
569 service_id_t *svcs;
570 inet_link_cfg_info_t info;
571 size_t count, i;
572 errno_t rc;
573
574 fibril_mutex_lock(&inet_links_lock);
575
576 rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
577 if (rc != EOK) {
578 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category "
579 "'iplink'.");
580 fibril_mutex_unlock(&inet_links_lock);
581 return ENOENT;
582 }
583
584 rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
585 if (rc != EOK) {
586 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP "
587 "links.");
588 fibril_mutex_unlock(&inet_links_lock);
589 return EIO;
590 }
591
592 for (i = 0; i < count; i++) {
593 already_known = false;
594
595 list_foreach(inet_links, link_list, inet_link_t, ilink) {
596 if (ilink->svc_id == svcs[i]) {
597 already_known = true;
598 break;
599 }
600 }
601
602 if (!already_known) {
603 log_msg(LOG_DEFAULT, LVL_NOTE, "Found IP link '%lu'",
604 (unsigned long) svcs[i]);
605 rc = inet_link_open_locked(svcs[i]);
606 if (rc != EOK) {
607 log_msg(LOG_DEFAULT, LVL_ERROR, "Could not "
608 "add IP link.");
609 }
610 } else {
611 /* Clear so it won't be autoconfigured below */
612 svcs[i] = 0;
613 }
614 }
615
616 fibril_mutex_unlock(&inet_links_lock);
617
618 /*
619 * Auto-configure new links. Note that newly discovered links
620 * cannot have any configured address objects, because we only
621 * retain configuration for present links.
622 */
623 for (i = 0; i < count; i++) {
624 if (svcs[i] != 0) {
625 info.svc_id = svcs[i];
626 rc = loc_service_get_name(info.svc_id, &info.svc_name);
627 if (rc != EOK) {
628 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed "
629 "getting service name.");
630 return rc;
631 }
632
633 inet_link_autoconf_link(&info);
634 free(info.svc_name);
635 info.svc_name = NULL;
636 }
637 }
638
639 return EOK;
640}
641
642/** IP link category change callback.
643 *
644 * @param arg Not used
645 */
646static void inet_link_cat_change_cb(void *arg)
647{
648 (void) inet_link_check_new();
649}
650
651/** Start IP link discovery.
652 *
653 * @return EOK on success or an error code
654 */
655errno_t inet_link_discovery_start(void)
656{
657 errno_t rc;
658
659 rc = loc_register_cat_change_cb(inet_link_cat_change_cb, NULL);
660 if (rc != EOK) {
661 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
662 "for IP link discovery: %s.", str_error(rc));
663 return rc;
664 }
665
666 return inet_link_check_new();
667}
668
669/** Start DHCP autoconfiguration on IP link.
670 *
671 * @param info Link information
672 */
673void inet_link_autoconf_link(inet_link_cfg_info_t *info)
674{
675 errno_t rc;
676
677 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf_link");
678
679 if (str_lcmp(info->svc_name, "net/eth", str_length("net/eth")) == 0) {
680 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf_link : dhcp link add for link '%s' (%u)",
681 info->svc_name, (unsigned)info->svc_id);
682 rc = dhcp_link_add(info->svc_id);
683 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf_link : dhcp link add for link '%s' (%u) DONE",
684 info->svc_name, (unsigned)info->svc_id);
685 if (rc != EOK) {
686 log_msg(LOG_DEFAULT, LVL_WARN, "Failed configuring "
687 "DHCP on link '%s'.\n", info->svc_name);
688 }
689 }
690}
691
692/** Start DHCP autoconfiguration on IP links. */
693errno_t inet_link_autoconf(void)
694{
695 inet_link_cfg_info_t *link_info;
696 size_t link_cnt;
697 size_t acnt;
698 size_t i;
699 errno_t rc;
700
701 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : initialize DHCP");
702 rc = dhcp_init();
703 if (rc != EOK) {
704 log_msg(LOG_DEFAULT, LVL_WARN, "Failed initializing DHCP "
705 "service.");
706 return rc;
707 }
708
709 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : initialize DHCP done");
710
711 fibril_mutex_lock(&inet_links_lock);
712 link_cnt = list_count(&inet_links);
713
714 link_info = calloc(link_cnt, sizeof(inet_link_cfg_info_t));
715 if (link_info == NULL) {
716 fibril_mutex_unlock(&inet_links_lock);
717 return ENOMEM;
718 }
719
720 i = 0;
721 list_foreach(inet_links, link_list, inet_link_t, ilink) {
722 assert(i < link_cnt);
723
724 acnt = inet_addrobj_cnt_by_link(ilink);
725 if (acnt != 0) {
726 /*
727 * No autoconfiguration if link has configured
728 * addresses.
729 */
730 continue;
731 }
732
733 link_info[i].svc_id = ilink->svc_id;
734 link_info[i].svc_name = str_dup(ilink->svc_name);
735 if (link_info[i].svc_name == NULL) {
736 fibril_mutex_unlock(&inet_links_lock);
737 goto error;
738 }
739
740 ++i;
741 }
742
743 fibril_mutex_unlock(&inet_links_lock);
744
745 /* Update link_cnt to include only links slated for autoconfig. */
746 link_cnt = i;
747
748 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : autoconf links...");
749
750 for (i = 0; i < link_cnt; i++)
751 inet_link_autoconf_link(&link_info[i]);
752
753 for (i = 0; i < link_cnt; i++) {
754 if (link_info[i].svc_name != NULL)
755 free(link_info[i].svc_name);
756 }
757
758 log_msg(LOG_DEFAULT, LVL_NOTE, "inet_link_autoconf : autoconf links done");
759 return EOK;
760error:
761 for (i = 0; i < link_cnt; i++) {
762 if (link_info[i].svc_name != NULL)
763 free(link_info[i].svc_name);
764 }
765 free(link_info);
766 return ENOMEM;
767}
768
[e2e56e67]769/** @}
770 */
Note: See TracBrowser for help on using the repository browser.