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

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

Fibril timer locking improvements.

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