source: mainline/uspace/srv/net/dhcp/dhcp.c@ fab2746

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fab2746 was fab2746, checked in by Jiri Svoboda <jiri@…>, 10 years ago

New transport layer API. Only UDP implemented.

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