2 * Copyright (C) 2012-2018 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2010 Martin Willi
6 * Copyright (C) 2010 revosec AG
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "dhcp_socket.h"
24 #include <netinet/in.h>
25 #include <netinet/ip.h>
26 #include <netinet/udp.h>
27 #include <linux/if_arp.h>
28 #include <linux/if_ether.h>
29 #include <linux/filter.h>
31 #include <collections/linked_list.h>
32 #include <utils/identification.h>
33 #include <threading/mutex.h>
34 #include <threading/condvar.h>
35 #include <threading/thread.h>
38 #include <processing/jobs/callback_job.h>
40 #define DHCP_SERVER_PORT 67
41 #define DHCP_CLIENT_PORT 68
44 typedef struct private_dhcp_socket_t private_dhcp_socket_t
;
47 * Private data of an dhcp_socket_t object.
49 struct private_dhcp_socket_t
{
52 * Public dhcp_socket_t interface.
57 * Random number generator
62 * List of transactions in DISCOVER
64 linked_list_t
*discover
;
67 * List of transactions in REQUEST
69 linked_list_t
*request
;
72 * List of successfully completed transactions
74 linked_list_t
*completed
;
77 * Lock for transactions
82 * Condvar to wait for transaction completion
87 * Threads waiting in condvar
102 * Do we use per-identity or random leases (and MAC addresses)
107 * DHCP server address, or broadcast
112 * Force configured destination address
118 * DHCP opcode (or BOOTP actually)
126 * Some DHCP options used
131 DHCP_NBNS_SERVER
= 44,
132 DHCP_REQUESTED_IP
= 50,
133 DHCP_MESSAGE_TYPE
= 53,
135 DHCP_PARAM_REQ_LIST
= 55,
138 } dhcp_option_type_t
;
141 * DHCP messages types in the DHCP_MESSAGE_TYPE option
152 } dhcp_message_type_t
;
154 * DHCP option encoding, a TLV
156 typedef struct __attribute__((packed
)) {
163 * DHCP message format, with a maximum size options buffer
165 typedef struct __attribute__((packed
)) {
170 uint32_t transaction_id
;
171 uint16_t number_of_seconds
;
173 uint32_t client_address
;
174 uint32_t your_address
;
175 uint32_t server_address
;
176 uint32_t gateway_address
;
177 char client_hw_addr
[6];
178 char client_hw_padding
[10];
179 char server_hostname
[64];
180 char boot_filename
[128];
181 uint32_t magic_cookie
;
186 * Check if the given address equals the broadcast address
188 static inline bool is_broadcast(host_t
*host
)
190 chunk_t broadcast
= chunk_from_chars(0xFF,0xFF,0xFF,0xFF);
192 return chunk_equals(broadcast
, host
->get_address(host
));
196 * Prepare a DHCP message for a given transaction
198 static int prepare_dhcp(private_dhcp_socket_t
*this,
199 dhcp_transaction_t
*transaction
,
200 dhcp_message_type_t type
, dhcp_t
*dhcp
)
203 identification_t
*identity
;
204 dhcp_option_t
*option
;
209 memset(dhcp
, 0, sizeof(*dhcp
));
210 dhcp
->opcode
= BOOTREQUEST
;
211 dhcp
->hw_type
= ARPHRD_ETHER
;
212 dhcp
->hw_addr_len
= 6;
213 dhcp
->transaction_id
= transaction
->get_id(transaction
);
214 if (is_broadcast(this->dst
))
216 /* Set broadcast flag to get broadcasted replies, as we actually
217 * do not own the MAC we request an address for. */
218 dhcp
->flags
= htons(0x8000);
219 /* TODO: send with 0.0.0.0 source address */
223 /* act as relay agent */
224 src
= charon
->kernel
->get_source_addr(charon
->kernel
, this->dst
, NULL
);
227 memcpy(&dhcp
->gateway_address
, src
->get_address(src
).ptr
,
228 sizeof(dhcp
->gateway_address
));
233 identity
= transaction
->get_identity(transaction
);
234 chunk
= identity
->get_encoding(identity
);
235 /* magic bytes, a locally administered unicast MAC */
236 dhcp
->client_hw_addr
[0] = 0x7A;
237 dhcp
->client_hw_addr
[1] = 0xA7;
238 /* with ID specific postfix */
239 if (this->identity_lease
)
241 id
= htonl(chunk_hash_static(chunk
));
245 id
= transaction
->get_id(transaction
);
247 memcpy(&dhcp
->client_hw_addr
[2], &id
, sizeof(id
));
249 dhcp
->magic_cookie
= htonl(0x63825363);
251 option
= (dhcp_option_t
*)&dhcp
->options
[optlen
];
252 option
->type
= DHCP_MESSAGE_TYPE
;
254 option
->data
[0] = type
;
255 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
257 if (identity
->get_type(identity
) == ID_FQDN
)
259 option
= (dhcp_option_t
*)&dhcp
->options
[optlen
];
260 option
->type
= DHCP_HOST_NAME
;
261 option
->len
= min(chunk
.len
, 64);
262 memcpy(option
->data
, chunk
.ptr
, option
->len
);
263 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
266 option
= (dhcp_option_t
*)&dhcp
->options
[optlen
];
267 option
->type
= DHCP_CLIENT_ID
;
268 option
->len
= min(chunk
.len
, 64);
269 memcpy(option
->data
, chunk
.ptr
, option
->len
);
270 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
276 * Send a DHCP message with given options length
278 static bool send_dhcp(private_dhcp_socket_t
*this,
279 dhcp_transaction_t
*transaction
, dhcp_t
*dhcp
, int optlen
)
284 dst
= transaction
->get_server(transaction
);
285 if (!dst
|| this->force_dst
)
289 len
= offsetof(dhcp_t
, magic_cookie
) + ((optlen
+ 4) / 64 * 64 + 64);
290 return sendto(this->send
, dhcp
, len
, 0, dst
->get_sockaddr(dst
),
291 *dst
->get_sockaddr_len(dst
)) == len
;
295 * Send DHCP discover using a given transaction
297 static bool discover(private_dhcp_socket_t
*this,
298 dhcp_transaction_t
*transaction
)
300 dhcp_option_t
*option
;
304 optlen
= prepare_dhcp(this, transaction
, DHCP_DISCOVER
, &dhcp
);
306 DBG1(DBG_CFG
, "sending DHCP DISCOVER to %H", this->dst
);
308 option
= (dhcp_option_t
*)&dhcp
.options
[optlen
];
309 option
->type
= DHCP_PARAM_REQ_LIST
;
311 option
->data
[0] = DHCP_DNS_SERVER
;
312 option
->data
[1] = DHCP_NBNS_SERVER
;
313 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
315 dhcp
.options
[optlen
++] = DHCP_OPTEND
;
317 if (!send_dhcp(this, transaction
, &dhcp
, optlen
))
319 DBG1(DBG_CFG
, "sending DHCP DISCOVER failed: %s", strerror(errno
));
326 * Send DHCP request using a given transaction
328 static bool request(private_dhcp_socket_t
*this,
329 dhcp_transaction_t
*transaction
)
331 dhcp_option_t
*option
;
333 host_t
*offer
, *server
;
337 optlen
= prepare_dhcp(this, transaction
, DHCP_REQUEST
, &dhcp
);
339 offer
= transaction
->get_address(transaction
);
340 server
= transaction
->get_server(transaction
);
341 if (!offer
|| !server
)
345 DBG1(DBG_CFG
, "sending DHCP REQUEST for %H to %H", offer
, server
);
347 option
= (dhcp_option_t
*)&dhcp
.options
[optlen
];
348 option
->type
= DHCP_REQUESTED_IP
;
350 chunk
= offer
->get_address(offer
);
351 memcpy(option
->data
, chunk
.ptr
, min(chunk
.len
, option
->len
));
352 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
354 option
= (dhcp_option_t
*)&dhcp
.options
[optlen
];
355 option
->type
= DHCP_SERVER_ID
;
357 chunk
= server
->get_address(server
);
358 memcpy(option
->data
, chunk
.ptr
, min(chunk
.len
, option
->len
));
359 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
361 option
= (dhcp_option_t
*)&dhcp
.options
[optlen
];
362 option
->type
= DHCP_PARAM_REQ_LIST
;
364 option
->data
[0] = DHCP_DNS_SERVER
;
365 option
->data
[1] = DHCP_NBNS_SERVER
;
366 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
368 dhcp
.options
[optlen
++] = DHCP_OPTEND
;
370 if (!send_dhcp(this, transaction
, &dhcp
, optlen
))
372 DBG1(DBG_CFG
, "sending DHCP REQUEST failed: %s", strerror(errno
));
378 METHOD(dhcp_socket_t
, enroll
, dhcp_transaction_t
*,
379 private_dhcp_socket_t
*this, identification_t
*identity
)
381 dhcp_transaction_t
*transaction
;
385 if (!this->rng
->get_bytes(this->rng
, sizeof(id
), (uint8_t*)&id
))
387 DBG1(DBG_CFG
, "DHCP DISCOVER failed, no transaction ID");
390 transaction
= dhcp_transaction_create(id
, identity
);
392 this->mutex
->lock(this->mutex
);
393 this->discover
->insert_last(this->discover
, transaction
);
395 while (try <= DHCP_TRIES
&& discover(this, transaction
))
397 if (!this->condvar
->timed_wait(this->condvar
, this->mutex
, 1000 * try) &&
398 this->request
->find_first(this->request
, NULL
, (void**)&transaction
))
404 if (this->discover
->remove(this->discover
, transaction
, NULL
))
405 { /* no OFFER received */
406 this->mutex
->unlock(this->mutex
);
407 transaction
->destroy(transaction
);
408 DBG1(DBG_CFG
, "DHCP DISCOVER timed out");
413 while (try <= DHCP_TRIES
&& request(this, transaction
))
415 if (!this->condvar
->timed_wait(this->condvar
, this->mutex
, 1000 * try) &&
416 this->completed
->remove(this->completed
, transaction
, NULL
))
422 if (this->request
->remove(this->request
, transaction
, NULL
))
423 { /* no ACK received */
424 this->mutex
->unlock(this->mutex
);
425 transaction
->destroy(transaction
);
426 DBG1(DBG_CFG
, "DHCP REQUEST timed out");
429 this->mutex
->unlock(this->mutex
);
434 METHOD(dhcp_socket_t
, release
, void,
435 private_dhcp_socket_t
*this, dhcp_transaction_t
*transaction
)
437 dhcp_option_t
*option
;
439 host_t
*release
, *server
;
443 optlen
= prepare_dhcp(this, transaction
, DHCP_RELEASE
, &dhcp
);
445 release
= transaction
->get_address(transaction
);
446 server
= transaction
->get_server(transaction
);
447 if (!release
|| !server
)
451 DBG1(DBG_CFG
, "sending DHCP RELEASE for %H to %H", release
, server
);
453 chunk
= release
->get_address(release
);
454 memcpy((char*)&dhcp
.client_address
, chunk
.ptr
,
455 min(chunk
.len
, sizeof(dhcp
.client_address
)));
457 option
= (dhcp_option_t
*)&dhcp
.options
[optlen
];
458 option
->type
= DHCP_SERVER_ID
;
460 chunk
= server
->get_address(server
);
461 memcpy(option
->data
, chunk
.ptr
, min(chunk
.len
, option
->len
));
462 optlen
+= sizeof(dhcp_option_t
) + option
->len
;
464 dhcp
.options
[optlen
++] = DHCP_OPTEND
;
466 if (!send_dhcp(this, transaction
, &dhcp
, optlen
))
468 DBG1(DBG_CFG
, "sending DHCP RELEASE failed: %s", strerror(errno
));
473 * Handle a DHCP OFFER
475 static void handle_offer(private_dhcp_socket_t
*this, dhcp_t
*dhcp
, int optlen
)
477 dhcp_transaction_t
*transaction
= NULL
;
478 enumerator_t
*enumerator
;
479 host_t
*offer
, *server
= NULL
;
481 offer
= host_create_from_chunk(AF_INET
,
482 chunk_from_thing(dhcp
->your_address
), 0);
484 this->mutex
->lock(this->mutex
);
485 enumerator
= this->discover
->create_enumerator(this->discover
);
486 while (enumerator
->enumerate(enumerator
, &transaction
))
488 if (transaction
->get_id(transaction
) == dhcp
->transaction_id
)
490 this->discover
->remove_at(this->discover
, enumerator
);
491 this->request
->insert_last(this->request
, transaction
);
495 enumerator
->destroy(enumerator
);
499 int optsize
, optpos
= 0, pos
;
500 dhcp_option_t
*option
;
502 while (optlen
> sizeof(dhcp_option_t
))
504 option
= (dhcp_option_t
*)&dhcp
->options
[optpos
];
505 optsize
= sizeof(dhcp_option_t
) + option
->len
;
506 if (option
->type
== DHCP_OPTEND
|| optlen
< optsize
)
510 if (option
->type
== DHCP_DNS_SERVER
||
511 option
->type
== DHCP_NBNS_SERVER
)
513 for (pos
= 0; pos
+ 4 <= option
->len
; pos
+= 4)
515 transaction
->add_attribute(transaction
, option
->type
==
516 DHCP_DNS_SERVER
? INTERNAL_IP4_DNS
: INTERNAL_IP4_NBNS
,
517 chunk_create((char*)&option
->data
[pos
], 4));
520 if (!server
&& option
->type
== DHCP_SERVER_ID
&& option
->len
== 4)
522 server
= host_create_from_chunk(AF_INET
,
523 chunk_create(option
->data
, 4), DHCP_SERVER_PORT
);
530 server
= host_create_from_chunk(AF_INET
,
531 chunk_from_thing(dhcp
->server_address
), DHCP_SERVER_PORT
);
533 DBG1(DBG_CFG
, "received DHCP OFFER %H from %H", offer
, server
);
534 transaction
->set_address(transaction
, offer
->clone(offer
));
535 transaction
->set_server(transaction
, server
);
537 this->mutex
->unlock(this->mutex
);
538 this->condvar
->broadcast(this->condvar
);
539 offer
->destroy(offer
);
545 static void handle_ack(private_dhcp_socket_t
*this, dhcp_t
*dhcp
, int optlen
)
547 dhcp_transaction_t
*transaction
;
548 enumerator_t
*enumerator
;
551 offer
= host_create_from_chunk(AF_INET
,
552 chunk_from_thing(dhcp
->your_address
), 0);
554 this->mutex
->lock(this->mutex
);
555 enumerator
= this->request
->create_enumerator(this->request
);
556 while (enumerator
->enumerate(enumerator
, &transaction
))
558 if (transaction
->get_id(transaction
) == dhcp
->transaction_id
)
560 DBG1(DBG_CFG
, "received DHCP ACK for %H", offer
);
561 this->request
->remove_at(this->request
, enumerator
);
562 this->completed
->insert_last(this->completed
, transaction
);
566 enumerator
->destroy(enumerator
);
567 this->mutex
->unlock(this->mutex
);
568 this->condvar
->broadcast(this->condvar
);
569 offer
->destroy(offer
);
573 * Receive DHCP responses
575 static bool receive_dhcp(private_dhcp_socket_t
*this, int fd
,
576 watcher_event_t event
)
578 struct sockaddr_ll addr
;
579 socklen_t addr_len
= sizeof(addr
);
580 struct __attribute__((packed
)) {
585 int optlen
, origoptlen
, optsize
, optpos
= 0;
587 dhcp_option_t
*option
;
589 len
= recvfrom(fd
, &packet
, sizeof(packet
), MSG_DONTWAIT
,
590 (struct sockaddr
*)&addr
, &addr_len
);
592 if (len
>= sizeof(struct iphdr
) + sizeof(struct udphdr
) +
593 offsetof(dhcp_t
, options
))
595 origoptlen
= optlen
= len
- sizeof(struct iphdr
) +
596 sizeof(struct udphdr
) + offsetof(dhcp_t
, options
);
597 while (optlen
> sizeof(dhcp_option_t
))
599 option
= (dhcp_option_t
*)&packet
.dhcp
.options
[optpos
];
600 optsize
= sizeof(dhcp_option_t
) + option
->len
;
601 if (option
->type
== DHCP_OPTEND
|| optlen
< optsize
)
605 if (option
->type
== DHCP_MESSAGE_TYPE
&& option
->len
== 1)
607 switch (option
->data
[0])
610 handle_offer(this, &packet
.dhcp
, origoptlen
);
613 handle_ack(this, &packet
.dhcp
, origoptlen
);
626 METHOD(dhcp_socket_t
, destroy
, void,
627 private_dhcp_socket_t
*this)
629 while (this->waiting
)
631 this->condvar
->signal(this->condvar
);
637 if (this->receive
> 0)
639 lib
->watcher
->remove(lib
->watcher
, this->receive
);
640 close(this->receive
);
642 this->mutex
->destroy(this->mutex
);
643 this->condvar
->destroy(this->condvar
);
644 this->discover
->destroy_offset(this->discover
,
645 offsetof(dhcp_transaction_t
, destroy
));
646 this->request
->destroy_offset(this->request
,
647 offsetof(dhcp_transaction_t
, destroy
));
648 this->completed
->destroy_offset(this->completed
,
649 offsetof(dhcp_transaction_t
, destroy
));
650 DESTROY_IF(this->rng
);
651 DESTROY_IF(this->dst
);
656 * Bind a socket to a particular interface name
658 static bool bind_to_device(int fd
, char *iface
)
662 if (strlen(iface
) > sizeof(ifreq
.ifr_name
))
664 DBG1(DBG_CFG
, "name for DHCP interface too long: '%s'", iface
);
667 memcpy(ifreq
.ifr_name
, iface
, sizeof(ifreq
.ifr_name
));
668 if (setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifreq
, sizeof(ifreq
)))
670 DBG1(DBG_CFG
, "binding DHCP socket to '%s' failed: %s",
671 iface
, strerror(errno
));
680 dhcp_socket_t
*dhcp_socket_create()
682 private_dhcp_socket_t
*this;
683 struct sockaddr_in src
= {
684 .sin_family
= AF_INET
,
685 .sin_port
= htons(DHCP_CLIENT_PORT
),
687 .s_addr
= INADDR_ANY
,
692 struct sock_filter dhcp_filter_code
[] = {
693 BPF_STMT(BPF_LD
+BPF_B
+BPF_ABS
,
694 offsetof(struct iphdr
, protocol
)),
695 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, IPPROTO_UDP
, 0, 16),
696 BPF_STMT(BPF_LD
+BPF_H
+BPF_ABS
, sizeof(struct iphdr
) +
697 offsetof(struct udphdr
, source
)),
698 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, DHCP_SERVER_PORT
, 0, 14),
699 BPF_STMT(BPF_LD
+BPF_H
+BPF_ABS
, sizeof(struct iphdr
) +
700 offsetof(struct udphdr
, dest
)),
701 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, DHCP_CLIENT_PORT
, 2, 0),
702 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, DHCP_SERVER_PORT
, 1, 0),
703 BPF_JUMP(BPF_JMP
+BPF_JA
, 10, 0, 0),
704 BPF_STMT(BPF_LD
+BPF_B
+BPF_ABS
, sizeof(struct iphdr
) +
705 sizeof(struct udphdr
) + offsetof(dhcp_t
, opcode
)),
706 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, BOOTREPLY
, 0, 8),
707 BPF_STMT(BPF_LD
+BPF_B
+BPF_ABS
, sizeof(struct iphdr
) +
708 sizeof(struct udphdr
) + offsetof(dhcp_t
, hw_type
)),
709 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, ARPHRD_ETHER
, 0, 6),
710 BPF_STMT(BPF_LD
+BPF_B
+BPF_ABS
, sizeof(struct iphdr
) +
711 sizeof(struct udphdr
) + offsetof(dhcp_t
, hw_addr_len
)),
712 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, 6, 0, 4),
713 BPF_STMT(BPF_LD
+BPF_W
+BPF_ABS
, sizeof(struct iphdr
) +
714 sizeof(struct udphdr
) + offsetof(dhcp_t
, magic_cookie
)),
715 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, 0x63825363, 0, 2),
716 BPF_STMT(BPF_LD
+BPF_W
+BPF_LEN
, 0),
717 BPF_STMT(BPF_RET
+BPF_A
, 0),
718 BPF_STMT(BPF_RET
+BPF_K
, 0),
720 struct sock_fprog dhcp_filter
= {
721 sizeof(dhcp_filter_code
) / sizeof(struct sock_filter
),
731 .rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
),
732 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
733 .condvar
= condvar_create(CONDVAR_TYPE_DEFAULT
),
734 .discover
= linked_list_create(),
735 .request
= linked_list_create(),
736 .completed
= linked_list_create(),
741 DBG1(DBG_CFG
, "unable to create RNG");
745 this->identity_lease
= lib
->settings
->get_bool(lib
->settings
,
746 "%s.plugins.dhcp.identity_lease", FALSE
,
748 this->force_dst
= lib
->settings
->get_str(lib
->settings
,
749 "%s.plugins.dhcp.force_server_address", FALSE
,
751 this->dst
= host_create_from_string(lib
->settings
->get_str(lib
->settings
,
752 "%s.plugins.dhcp.server", "255.255.255.255",
753 lib
->ns
), DHCP_SERVER_PORT
);
754 iface
= lib
->settings
->get_str(lib
->settings
, "%s.plugins.dhcp.interface",
758 DBG1(DBG_CFG
, "configured DHCP server address invalid");
763 this->send
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
764 if (this->send
== -1)
766 DBG1(DBG_CFG
, "unable to create DHCP send socket: %s", strerror(errno
));
770 if (setsockopt(this->send
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1)
772 DBG1(DBG_CFG
, "unable to reuse DHCP socket address: %s", strerror(errno
));
776 if (setsockopt(this->send
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)) == -1)
778 DBG1(DBG_CFG
, "unable to broadcast on DHCP socket: %s", strerror(errno
));
782 if (!is_broadcast(this->dst
))
784 /* when setting giaddr (which we do when we don't broadcast), the server
785 * should respond to the server port on that IP, according to RFC 2131,
786 * section 4.1. while we do receive such messages via raw socket, the
787 * kernel will respond with an ICMP port unreachable if there is no
788 * socket bound to that port, which might be problematic with certain
789 * DHCP servers. instead of opening an additional socket, that we don't
790 * actually use, we can also just send our requests from port 67 */
791 src
.sin_port
= htons(DHCP_SERVER_PORT
);
793 if (bind(this->send
, (struct sockaddr
*)&src
, sizeof(src
)) == -1)
795 DBG1(DBG_CFG
, "unable to bind DHCP send socket: %s", strerror(errno
));
800 this->receive
= socket(AF_PACKET
, SOCK_DGRAM
, htons(ETH_P_IP
));
801 if (this->receive
== -1)
803 DBG1(DBG_NET
, "opening DHCP receive socket failed: %s", strerror(errno
));
807 if (setsockopt(this->receive
, SOL_SOCKET
, SO_ATTACH_FILTER
,
808 &dhcp_filter
, sizeof(dhcp_filter
)) < 0)
810 DBG1(DBG_CFG
, "installing DHCP socket filter failed: %s",
817 if (!bind_to_device(this->send
, iface
) ||
818 !bind_to_device(this->receive
, iface
))
825 lib
->watcher
->add(lib
->watcher
, this->receive
, WATCHER_READ
,
826 (watcher_cb_t
)receive_dhcp
, this);
828 return &this->public;