source: mainline/uspace/srv/net/dhcp/dhcp.c@ 9aa51406

Last change on this file since 9aa51406 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: 16.1 KB
RevLine 
[695b6ff]1/*
[1bbc6dc]2 * Copyright (c) 2024 Jiri Svoboda
[695b6ff]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 dhcp
30 * @{
31 */
32/**
33 * @file
34 * @brief DHCP client
35 */
36
[66ec63a]37#include <adt/list.h>
[695b6ff]38#include <bitops.h>
[fab2746]39#include <byteorder.h>
[5a324d99]40#include <errno.h>
[c1694b6b]41#include <str_error.h>
[b417559]42#include <fibril_synch.h>
[695b6ff]43#include <inet/addr.h>
[b4edc96]44#include <inet/eth_addr.h>
[695b6ff]45#include <inet/dnsr.h>
46#include <inet/inetcfg.h>
[bd88bee]47#include <io/log.h>
[695b6ff]48#include <loc.h>
[bbb7ffe]49#include <rndgen.h>
[695b6ff]50#include <stdio.h>
51#include <stdlib.h>
[1d6dd2a]52#include <str.h>
[695b6ff]53
[bd88bee]54#include "dhcp.h"
[695b6ff]55#include "dhcp_std.h"
[66ec63a]56#include "transport.h"
[695b6ff]57
[1b0602a3]58enum {
59 /** In microseconds */
60 dhcp_discover_timeout_val = 5 * 1000 * 1000,
61 /** In microseconds */
62 dhcp_request_timeout_val = 1 * 1000 * 1000,
63 dhcp_discover_retries = 5,
64 dhcp_request_retries = 3
65};
[b417559]66
[695b6ff]67#define MAX_MSG_SIZE 1024
68static uint8_t msgbuf[MAX_MSG_SIZE];
69
[b417559]70/** List of registered links (of dhcp_link_t) */
[66ec63a]71static list_t dhcp_links;
72
[1bbc6dc]73bool inetcfg_inited = false;
74
[b417559]75static void dhcpsrv_discover_timeout(void *);
76static void dhcpsrv_request_timeout(void *);
77
78typedef enum {
79 ds_bound,
[1b0602a3]80 ds_fail,
[b417559]81 ds_init,
82 ds_init_reboot,
83 ds_rebinding,
84 ds_renewing,
85 ds_requesting,
86 ds_selecting
87} dhcp_state_t;
88
[695b6ff]89typedef struct {
90 /** Message type */
91 enum dhcp_msg_type msg_type;
92 /** Offered address */
93 inet_naddr_t oaddr;
94 /** Server address */
95 inet_addr_t srv_addr;
96 /** Router address */
97 inet_addr_t router;
98 /** DNS server */
99 inet_addr_t dns_server;
[bbb7ffe]100 /** Transaction ID */
101 uint32_t xid;
[695b6ff]102} dhcp_offer_t;
103
[66ec63a]104typedef struct {
[b417559]105 /** Link to dhcp_links list */
[66ec63a]106 link_t links;
[b417559]107 /** Link service ID */
[66ec63a]108 service_id_t link_id;
[b417559]109 /** Link info */
[66ec63a]110 inet_link_info_t link_info;
[b417559]111 /** Transport */
[66ec63a]112 dhcp_transport_t dt;
[b417559]113 /** Transport timeout */
114 fibril_timer_t *timeout;
[1b0602a3]115 /** Number of retries */
116 int retries_left;
[b417559]117 /** Link state */
118 dhcp_state_t state;
119 /** Last received offer */
120 dhcp_offer_t offer;
[bbb7ffe]121 /** Random number generator */
122 rndgen_t *rndgen;
[66ec63a]123} dhcp_link_t;
124
125static void dhcpsrv_recv(void *, void *, size_t);
126
[695b6ff]127/** Decode subnet mask into subnet prefix length. */
[b7fd2a0]128static errno_t subnet_mask_decode(uint32_t mask, int *bits)
[695b6ff]129{
130 int zbits;
131 uint32_t nmask;
132
133 if (mask == 0xffffffff) {
134 *bits = 32;
135 return EOK;
136 }
137
138 zbits = 1 + fnzb32(mask ^ 0xffffffff);
139 nmask = BIT_RRANGE(uint32_t, zbits);
140
141 if ((mask ^ nmask) != 0xffffffff) {
142 /* The mask is not in the form 1**n,0**m */
143 return EINVAL;
144 }
145
146 *bits = 32 - zbits;
147 return EOK;
148}
149
150static uint32_t dhcp_uint32_decode(uint8_t *data)
151{
152 return
153 ((uint32_t)data[0] << 24) |
154 ((uint32_t)data[1] << 16) |
155 ((uint32_t)data[2] << 8) |
156 ((uint32_t)data[3]);
157}
158
[b7fd2a0]159static errno_t dhcp_send_discover(dhcp_link_t *dlink)
[695b6ff]160{
161 dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
162 uint8_t *opt = msgbuf + sizeof(dhcp_hdr_t);
[bbb7ffe]163 uint32_t xid;
164 errno_t rc;
[b7155d7]165 size_t i;
[bbb7ffe]166
167 rc = rndgen_uint32(dlink->rndgen, &xid);
168 if (rc != EOK)
169 return rc;
[695b6ff]170
171 memset(msgbuf, 0, MAX_MSG_SIZE);
172 hdr->op = op_bootrequest;
173 hdr->htype = 1; /* AHRD_ETHERNET */
[b4edc96]174 hdr->hlen = ETH_ADDR_SIZE;
[bbb7ffe]175 hdr->xid = host2uint32_t_be(xid);
176 hdr->flags = host2uint16_t_be(flag_broadcast);
[695b6ff]177
[3e6bca8]178 eth_addr_encode(&dlink->link_info.mac_addr, hdr->chaddr);
[695b6ff]179 hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
180
[b7155d7]181 i = 0;
[bbb7ffe]182
[b7155d7]183 opt[i++] = opt_msg_type;
184 opt[i++] = 1;
185 opt[i++] = msg_dhcpdiscover;
[695b6ff]186
[b7155d7]187 opt[i++] = opt_param_req_list;
188 opt[i++] = 3;
189 opt[i++] = 1; /* subnet mask */
190 opt[i++] = 6; /* DNS server */
191 opt[i++] = 3; /* router */
192
193 opt[i++] = opt_end;
194
195 return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i);
[695b6ff]196}
197
[b7fd2a0]198static errno_t dhcp_send_request(dhcp_link_t *dlink, dhcp_offer_t *offer)
[695b6ff]199{
200 dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
201 uint8_t *opt = msgbuf + sizeof(dhcp_hdr_t);
202 size_t i;
203
204 memset(msgbuf, 0, MAX_MSG_SIZE);
205 hdr->op = op_bootrequest;
206 hdr->htype = 1; /* AHRD_ETHERNET */
207 hdr->hlen = 6;
[bbb7ffe]208 hdr->xid = host2uint32_t_be(offer->xid);
209 hdr->flags = host2uint16_t_be(flag_broadcast);
[3e6bca8]210 eth_addr_encode(&dlink->link_info.mac_addr, hdr->chaddr);
[695b6ff]211 hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
212
213 i = 0;
214
215 opt[i++] = opt_msg_type;
216 opt[i++] = 1;
217 opt[i++] = msg_dhcprequest;
218
219 opt[i++] = opt_req_ip_addr;
220 opt[i++] = 4;
221 opt[i++] = offer->oaddr.addr >> 24;
222 opt[i++] = (offer->oaddr.addr >> 16) & 0xff;
223 opt[i++] = (offer->oaddr.addr >> 8) & 0xff;
224 opt[i++] = offer->oaddr.addr & 0xff;
225
226 opt[i++] = opt_server_id;
227 opt[i++] = 4;
228 opt[i++] = offer->srv_addr.addr >> 24;
229 opt[i++] = (offer->srv_addr.addr >> 16) & 0xff;
230 opt[i++] = (offer->srv_addr.addr >> 8) & 0xff;
231 opt[i++] = offer->srv_addr.addr & 0xff;
232
233 opt[i++] = opt_end;
234
[66ec63a]235 return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i);
[695b6ff]236}
237
[b7fd2a0]238static errno_t dhcp_parse_reply(void *msg, size_t size, dhcp_offer_t *offer)
[695b6ff]239{
240 dhcp_hdr_t *hdr = (dhcp_hdr_t *)msg;
241 inet_addr_t yiaddr;
242 inet_addr_t siaddr;
243 inet_addr_t giaddr;
244 uint32_t subnet_mask;
245 bool have_subnet_mask = false;
246 bool have_server_id = false;
247 int subnet_bits;
248 char *saddr;
249 uint8_t opt_type, opt_len;
250 uint8_t *msgb;
[b7fd2a0]251 errno_t rc;
[695b6ff]252 size_t i;
253
[bd88bee]254 log_msg(LOG_DEFAULT, LVL_DEBUG, "Receive reply");
[695b6ff]255 memset(offer, 0, sizeof(*offer));
256
[f023251]257 inet_addr_set(uint32_t_be2host(hdr->yiaddr), &yiaddr);
[695b6ff]258 rc = inet_addr_format(&yiaddr, &saddr);
259 if (rc != EOK)
260 return rc;
261
[bd88bee]262 log_msg(LOG_DEFAULT, LVL_DEBUG, "Your IP address: %s", saddr);
[695b6ff]263 free(saddr);
264
[f023251]265 inet_addr_set(uint32_t_be2host(hdr->siaddr), &siaddr);
[695b6ff]266 rc = inet_addr_format(&siaddr, &saddr);
267 if (rc != EOK)
268 return rc;
269
[bd88bee]270 log_msg(LOG_DEFAULT, LVL_DEBUG, "Next server IP address: %s", saddr);
[695b6ff]271 free(saddr);
272
[f023251]273 inet_addr_set(uint32_t_be2host(hdr->giaddr), &giaddr);
[695b6ff]274 rc = inet_addr_format(&giaddr, &saddr);
275 if (rc != EOK)
276 return rc;
277
[bd88bee]278 log_msg(LOG_DEFAULT, LVL_DEBUG, "Relay agent IP address: %s", saddr);
[695b6ff]279 free(saddr);
280
[f023251]281 inet_naddr_set(yiaddr.addr, 0, &offer->oaddr);
[bbb7ffe]282 offer->xid = uint32_t_be2host(hdr->xid);
[695b6ff]283
284 msgb = (uint8_t *)msg;
285
286 i = sizeof(dhcp_hdr_t);
287 while (i < size) {
288 opt_type = msgb[i++];
289
290 if (opt_type == opt_pad)
291 continue;
292 if (opt_type == opt_end)
293 break;
294
295 if (i >= size)
296 return EINVAL;
297
298 opt_len = msgb[i++];
299
300 if (i + opt_len > size)
301 return EINVAL;
302
303 switch (opt_type) {
304 case opt_subnet_mask:
305 if (opt_len != 4)
306 return EINVAL;
307 subnet_mask = dhcp_uint32_decode(&msgb[i]);
308 rc = subnet_mask_decode(subnet_mask, &subnet_bits);
309 if (rc != EOK)
310 return EINVAL;
311 offer->oaddr.prefix = subnet_bits;
312 have_subnet_mask = true;
313 break;
314 case opt_msg_type:
315 if (opt_len != 1)
316 return EINVAL;
317 offer->msg_type = msgb[i];
318 break;
319 case opt_server_id:
320 if (opt_len != 4)
321 return EINVAL;
[f023251]322 inet_addr_set(dhcp_uint32_decode(&msgb[i]),
323 &offer->srv_addr);
[695b6ff]324 have_server_id = true;
325 break;
326 case opt_router:
327 if (opt_len != 4)
328 return EINVAL;
[f023251]329 inet_addr_set(dhcp_uint32_decode(&msgb[i]),
330 &offer->router);
[695b6ff]331 break;
332 case opt_dns_server:
[23ce2d9]333 if (opt_len < 4 || opt_len % 4 != 0)
[695b6ff]334 return EINVAL;
[23ce2d9]335 /* XXX Handle multiple DNS servers properly */
[f023251]336 inet_addr_set(dhcp_uint32_decode(&msgb[i]),
337 &offer->dns_server);
[695b6ff]338 break;
339 case opt_end:
340 break;
341 default:
342 break;
343 }
344
345 /* Advance to the next option */
346 i = i + opt_len;
347 }
348
349 if (!have_server_id) {
[bd88bee]350 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing server ID option.");
[695b6ff]351 return rc;
352 }
353
354 if (!have_subnet_mask) {
[bd88bee]355 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing subnet mask option.");
[695b6ff]356 return rc;
357 }
358
359 rc = inet_naddr_format(&offer->oaddr, &saddr);
360 if (rc != EOK)
361 return rc;
362
[bd88bee]363 log_msg(LOG_DEFAULT, LVL_DEBUG, "Offered network address: %s", saddr);
[695b6ff]364 free(saddr);
365
366 if (offer->router.addr != 0) {
367 rc = inet_addr_format(&offer->router, &saddr);
368 if (rc != EOK)
369 return rc;
370
[bd88bee]371 log_msg(LOG_DEFAULT, LVL_DEBUG, "Router address: %s", saddr);
[695b6ff]372 free(saddr);
373 }
374
375 if (offer->dns_server.addr != 0) {
376 rc = inet_addr_format(&offer->dns_server, &saddr);
377 if (rc != EOK)
378 return rc;
379
[bd88bee]380 log_msg(LOG_DEFAULT, LVL_DEBUG, "DNS server: %s", saddr);
[695b6ff]381 free(saddr);
382 }
383
384 return EOK;
385}
386
[b7fd2a0]387static errno_t dhcp_cfg_create(service_id_t iplink, dhcp_offer_t *offer)
[695b6ff]388{
[b7fd2a0]389 errno_t rc;
[695b6ff]390 service_id_t addr_id;
391 service_id_t sroute_id;
392 inet_naddr_t defr;
393
394 rc = inetcfg_addr_create_static("dhcp4a", &offer->oaddr, iplink,
395 &addr_id);
396 if (rc != EOK) {
[bd88bee]397 log_msg(LOG_DEFAULT, LVL_ERROR,
[c1694b6b]398 "Error creating IP address %s: %s", "dhcp4a", str_error(rc));
[695b6ff]399 return rc;
400 }
401
402 if (offer->router.addr != 0) {
[f023251]403 inet_naddr_set(0, 0, &defr);
[695b6ff]404
405 rc = inetcfg_sroute_create("dhcpdef", &defr, &offer->router, &sroute_id);
406 if (rc != EOK) {
[bd88bee]407 log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating "
[c1694b6b]408 "default route %s: %s.", "dhcpdef", str_error(rc));
[695b6ff]409 return rc;
410 }
411 }
412
413 if (offer->dns_server.addr != 0) {
414 rc = dnsr_set_srvaddr(&offer->dns_server);
415 if (rc != EOK) {
[66ec63a]416 log_msg(LOG_DEFAULT, LVL_ERROR, "Error setting "
[c1694b6b]417 "nameserver address: %s)", str_error(rc));
[695b6ff]418 return rc;
419 }
420 }
421
422 return EOK;
423}
424
[b417559]425void dhcpsrv_links_init(void)
426{
427 list_initialize(&dhcp_links);
428}
429
430static dhcp_link_t *dhcpsrv_link_find(service_id_t link_id)
431{
432 list_foreach(dhcp_links, links, dhcp_link_t, dlink) {
433 if (dlink->link_id == link_id)
434 return dlink;
435 }
436
437 return NULL;
438}
439
[ee20e8a]440static void dhcp_link_set_failed(dhcp_link_t *dlink)
441{
442 log_msg(LOG_DEFAULT, LVL_NOTE, "Giving up on link %s",
443 dlink->link_info.name);
444 dlink->state = ds_fail;
445}
446
[b7fd2a0]447static errno_t dhcp_discover_proc(dhcp_link_t *dlink)
[053fc2b]448{
449 dlink->state = ds_selecting;
450
[b7fd2a0]451 errno_t rc = dhcp_send_discover(dlink);
[053fc2b]452 if (rc != EOK)
453 return EIO;
454
455 dlink->retries_left = dhcp_discover_retries;
[a35b458]456
[8a64320e]457 if ((dlink->timeout->state == fts_not_set) ||
458 (dlink->timeout->state == fts_fired))
[053fc2b]459 fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
[8a64320e]460 dhcpsrv_discover_timeout, dlink);
[a35b458]461
[053fc2b]462 return rc;
463}
464
[b7fd2a0]465errno_t dhcpsrv_link_add(service_id_t link_id)
[695b6ff]466{
[66ec63a]467 dhcp_link_t *dlink;
[b7fd2a0]468 errno_t rc;
[695b6ff]469
[bd88bee]470 log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
[695b6ff]471
[1bbc6dc]472 if (!inetcfg_inited) {
473 rc = inetcfg_init();
474 if (rc != EOK) {
475 log_msg(LOG_DEFAULT, LVL_ERROR, "Error contacting "
476 "inet configuration service.\n");
477 return EIO;
478 }
479
480 inetcfg_inited = true;
481 }
482
[b417559]483 if (dhcpsrv_link_find(link_id) != NULL) {
[c6bf6be]484 log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added",
[b417559]485 link_id);
486 return EEXIST;
487 }
488
[66ec63a]489 dlink = calloc(1, sizeof(dhcp_link_t));
490 if (dlink == NULL)
491 return ENOMEM;
492
[bbb7ffe]493 rc = rndgen_create(&dlink->rndgen);
494 if (rc != EOK)
495 goto error;
496
[66ec63a]497 dlink->link_id = link_id;
[78192cc7]498 dlink->timeout = fibril_timer_create(NULL);
[b417559]499 if (dlink->timeout == NULL) {
500 rc = ENOMEM;
501 goto error;
502 }
[66ec63a]503
[947e2ef]504 /* Get link hardware address */
[66ec63a]505 rc = inetcfg_link_get(link_id, &dlink->link_info);
[947e2ef]506 if (rc != EOK) {
[bd88bee]507 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting properties "
508 "for link %zu.", link_id);
[66ec63a]509 rc = EIO;
510 goto error;
[947e2ef]511 }
[695b6ff]512
[66ec63a]513 rc = dhcp_transport_init(&dlink->dt, link_id, dhcpsrv_recv, dlink);
514 if (rc != EOK) {
515 log_msg(LOG_DEFAULT, LVL_ERROR, "Error initializing DHCP "
516 "transport for link %s.", dlink->link_info.name);
517 rc = EIO;
518 goto error;
519 }
[695b6ff]520
[bd88bee]521 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
[053fc2b]522 rc = dhcp_discover_proc(dlink);
[66ec63a]523 if (rc != EOK) {
[ee20e8a]524 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER.");
525 dhcp_link_set_failed(dlink);
[66ec63a]526 rc = EIO;
527 goto error;
528 }
[695b6ff]529
[b417559]530 list_append(&dlink->links, &dhcp_links);
[695b6ff]531
[bd88bee]532 return EOK;
[66ec63a]533error:
[bbb7ffe]534 if (dlink != NULL && dlink->rndgen != NULL)
535 rndgen_destroy(dlink->rndgen);
[b417559]536 if (dlink != NULL && dlink->timeout != NULL)
537 fibril_timer_destroy(dlink->timeout);
[66ec63a]538 free(dlink);
539 return rc;
[bd88bee]540}
541
[b7fd2a0]542errno_t dhcpsrv_link_remove(service_id_t link_id)
[bd88bee]543{
544 return ENOTSUP;
[695b6ff]545}
546
[b7fd2a0]547errno_t dhcpsrv_discover(service_id_t link_id)
[053fc2b]548{
549 log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
[a35b458]550
[053fc2b]551 dhcp_link_t *dlink = dhcpsrv_link_find(link_id);
[a35b458]552
[053fc2b]553 if (dlink == NULL) {
554 log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu doesn't exist",
555 link_id);
556 return EINVAL;
557 }
[a35b458]558
[053fc2b]559 return dhcp_discover_proc(dlink);
560}
561
[b417559]562static void dhcpsrv_recv_offer(dhcp_link_t *dlink, dhcp_offer_t *offer)
563{
[b7fd2a0]564 errno_t rc;
[b417559]565
566 if (dlink->state != ds_selecting) {
567 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received offer in state "
568 " %d, ignoring.", (int)dlink->state);
569 return;
570 }
571
572 fibril_timer_clear(dlink->timeout);
573 dlink->offer = *offer;
574 dlink->state = ds_requesting;
575
576 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
577 rc = dhcp_send_request(dlink, offer);
578 if (rc != EOK) {
579 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
580 return;
581 }
582
[1b0602a3]583 dlink->retries_left = dhcp_request_retries;
584 fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
[b417559]585 dhcpsrv_request_timeout, dlink);
586}
587
588static void dhcpsrv_recv_ack(dhcp_link_t *dlink, dhcp_offer_t *offer)
589{
[b7fd2a0]590 errno_t rc;
[b417559]591
592 if (dlink->state != ds_requesting) {
593 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received ack in state "
594 " %d, ignoring.", (int)dlink->state);
595 return;
596 }
597
598 fibril_timer_clear(dlink->timeout);
599 dlink->offer = *offer;
600 dlink->state = ds_bound;
601
602 rc = dhcp_cfg_create(dlink->link_id, offer);
603 if (rc != EOK) {
604 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error creating configuration.");
605 return;
606 }
[ee20e8a]607
608 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: Successfully configured.",
609 dlink->link_info.name);
[b417559]610}
611
[66ec63a]612static void dhcpsrv_recv(void *arg, void *msg, size_t size)
613{
614 dhcp_link_t *dlink = (dhcp_link_t *)arg;
615 dhcp_offer_t offer;
[b7fd2a0]616 errno_t rc;
[66ec63a]617
[ee20e8a]618 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: dhcpsrv_recv() %zu bytes",
619 dlink->link_info.name, size);
[66ec63a]620
621 rc = dhcp_parse_reply(msg, size, &offer);
622 if (rc != EOK) {
623 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error parsing reply");
624 return;
625 }
626
[b417559]627 switch (offer.msg_type) {
628 case msg_dhcpoffer:
629 dhcpsrv_recv_offer(dlink, &offer);
630 break;
631 case msg_dhcpack:
632 dhcpsrv_recv_ack(dlink, &offer);
633 break;
634 default:
635 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received unexpected "
636 "message type. %d", (int)offer.msg_type);
637 break;
[66ec63a]638 }
[b417559]639}
[66ec63a]640
[b417559]641static void dhcpsrv_discover_timeout(void *arg)
642{
643 dhcp_link_t *dlink = (dhcp_link_t *)arg;
[b7fd2a0]644 errno_t rc;
[b417559]645
646 assert(dlink->state == ds_selecting);
[8d58fca]647 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dhcpsrv_discover_timeout",
[ee20e8a]648 dlink->link_info.name);
[b417559]649
[1b0602a3]650 if (dlink->retries_left == 0) {
651 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
[ee20e8a]652 dhcp_link_set_failed(dlink);
[1b0602a3]653 return;
654 }
655 --dlink->retries_left;
656
[b417559]657 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
658 rc = dhcp_send_discover(dlink);
659 if (rc != EOK) {
660 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER");
[ee20e8a]661 dhcp_link_set_failed(dlink);
[b417559]662 return;
[66ec63a]663 }
[b417559]664
[1b0602a3]665 fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
[b417559]666 dhcpsrv_discover_timeout, dlink);
667}
668
669static void dhcpsrv_request_timeout(void *arg)
670{
671 dhcp_link_t *dlink = (dhcp_link_t *)arg;
[b7fd2a0]672 errno_t rc;
[b417559]673
674 assert(dlink->state == ds_requesting);
[8d58fca]675 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dhcpsrv_request_timeout",
[ee20e8a]676 dlink->link_info.name);
[b417559]677
[1b0602a3]678 if (dlink->retries_left == 0) {
679 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
[ee20e8a]680 dhcp_link_set_failed(dlink);
[1b0602a3]681 return;
682 }
683 --dlink->retries_left;
684
[b417559]685 log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
686 rc = dhcp_send_request(dlink, &dlink->offer);
687 if (rc != EOK) {
688 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
[ee20e8a]689 dhcp_link_set_failed(dlink);
[b417559]690 return;
691 }
692
[1b0602a3]693 fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
[b417559]694 dhcpsrv_request_timeout, dlink);
[66ec63a]695}
[bd88bee]696
[695b6ff]697/** @}
698 */
Note: See TracBrowser for help on using the repository browser.