BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file BDHCPClientCore.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. 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 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <string.h>
31 #include <stdlib.h>
32  
33 #include <misc/byteorder.h>
34 #include <misc/minmax.h>
35 #include <misc/balloc.h>
36 #include <misc/bsize.h>
37 #include <misc/dhcp_proto.h>
38 #include <base/BLog.h>
39  
40 #include <dhcpclient/BDHCPClientCore.h>
41  
42 #include <generated/blog_channel_BDHCPClientCore.h>
43  
44 #define RESET_TIMEOUT 4000
45 #define REQUEST_TIMEOUT 3000
46 #define RENEW_REQUEST_TIMEOUT 20000
47 #define MAX_REQUESTS 4
48 #define RENEW_TIMEOUT(lease) ((btime_t)500 * (lease))
49 #define XID_REUSE_MAX 8
50  
51 #define LEASE_TIMEOUT(lease) ((btime_t)1000 * (lease) - RENEW_TIMEOUT(lease))
52  
53 #define STATE_RESETTING 1
54 #define STATE_SENT_DISCOVER 2
55 #define STATE_SENT_REQUEST 3
56 #define STATE_FINISHED 4
57 #define STATE_RENEWING 5
58  
59 #define IP_UDP_HEADERS_SIZE 28
60  
61 static void report_up (BDHCPClientCore *o)
62 {
63 o->handler(o->user, BDHCPCLIENTCORE_EVENT_UP);
64 return;
65 }
66  
67 static void report_down (BDHCPClientCore *o)
68 {
69 o->handler(o->user, BDHCPCLIENTCORE_EVENT_DOWN);
70 return;
71 }
72  
73 static void send_message (
74 BDHCPClientCore *o,
75 int type,
76 uint32_t xid,
77 int have_requested_ip_address, uint32_t requested_ip_address,
78 int have_dhcp_server_identifier, uint32_t dhcp_server_identifier
79 )
80 {
81 ASSERT(type == DHCP_MESSAGE_TYPE_DISCOVER || type == DHCP_MESSAGE_TYPE_REQUEST)
82  
83 if (o->sending) {
84 BLog(BLOG_ERROR, "already sending");
85 return;
86 }
87  
88 // write header
89 struct dhcp_header header;
90 memset(&header, 0, sizeof(header));
91 header.op = hton8(DHCP_OP_BOOTREQUEST);
92 header.htype = hton8(DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET);
93 header.hlen = hton8(6);
94 header.xid = xid;
95 header.secs = hton16(0);
96 memcpy(header.chaddr, o->client_mac_addr, sizeof(o->client_mac_addr));
97 header.magic = hton32(DHCP_MAGIC);
98 memcpy(o->send_buf, &header, sizeof(header));
99  
100 // write options
101  
102 char *out = o->send_buf + sizeof(header);
103 struct dhcp_option_header oh;
104  
105 // DHCP message type
106 {
107 oh.type = hton8(DHCP_OPTION_DHCP_MESSAGE_TYPE);
108 oh.len = hton8(sizeof(struct dhcp_option_dhcp_message_type));
109 struct dhcp_option_dhcp_message_type opt;
110 opt.type = hton8(type);
111 memcpy(out, &oh, sizeof(oh));
112 memcpy(out + sizeof(oh), &opt, sizeof(opt));
113 out += sizeof(oh) + sizeof(opt);
114 }
115  
116 if (have_requested_ip_address) {
117 // requested IP address
118 oh.type = hton8(DHCP_OPTION_REQUESTED_IP_ADDRESS);
119 oh.len = hton8(sizeof(struct dhcp_option_addr));
120 struct dhcp_option_addr opt;
121 opt.addr = requested_ip_address;
122 memcpy(out, &oh, sizeof(oh));
123 memcpy(out + sizeof(oh), &opt, sizeof(opt));
124 out += sizeof(oh) + sizeof(opt);
125 }
126  
127 if (have_dhcp_server_identifier) {
128 // DHCP server identifier
129 oh.type = hton8(DHCP_OPTION_DHCP_SERVER_IDENTIFIER);
130 oh.len = hton8(sizeof(struct dhcp_option_dhcp_server_identifier));
131 struct dhcp_option_dhcp_server_identifier opt;
132 opt.id = dhcp_server_identifier;
133 memcpy(out, &oh, sizeof(oh));
134 memcpy(out + sizeof(oh), &opt, sizeof(opt));
135 out += sizeof(oh) + sizeof(opt);
136 }
137  
138 // maximum message size
139 {
140 oh.type = hton8(DHCP_OPTION_MAXIMUM_MESSAGE_SIZE);
141 oh.len = hton8(sizeof(struct dhcp_option_maximum_message_size));
142 struct dhcp_option_maximum_message_size opt;
143 opt.size = hton16(IP_UDP_HEADERS_SIZE + PacketRecvInterface_GetMTU(o->recv_if));
144 memcpy(out, &oh, sizeof(oh));
145 memcpy(out + sizeof(oh), &opt, sizeof(opt));
146 out += sizeof(oh) + sizeof(opt);
147 }
148  
149 // parameter request list
150 {
151 oh.type = hton8(DHCP_OPTION_PARAMETER_REQUEST_LIST);
152 oh.len = hton8(4);
153 uint8_t opt[4];
154 opt[0] = DHCP_OPTION_SUBNET_MASK;
155 opt[1] = DHCP_OPTION_ROUTER;
156 opt[2] = DHCP_OPTION_DOMAIN_NAME_SERVER;
157 opt[3] = DHCP_OPTION_IP_ADDRESS_LEASE_TIME;
158 memcpy(out, &oh, sizeof(oh));
159 memcpy(out + sizeof(oh), &opt, sizeof(opt));
160 out += sizeof(oh) + sizeof(opt);
161 }
162  
163 if (o->hostname) {
164 // host name
165 oh.type = hton8(DHCP_OPTION_HOST_NAME);
166 oh.len = hton8(strlen(o->hostname));
167 memcpy(out, &oh, sizeof(oh));
168 memcpy(out + sizeof(oh), o->hostname, strlen(o->hostname));
169 out += sizeof(oh) + strlen(o->hostname);
170 }
171  
172 if (o->vendorclassid) {
173 // vendor class identifier
174 oh.type = hton8(DHCP_OPTION_VENDOR_CLASS_IDENTIFIER);
175 oh.len = hton8(strlen(o->vendorclassid));
176 memcpy(out, &oh, sizeof(oh));
177 memcpy(out + sizeof(oh), o->vendorclassid, strlen(o->vendorclassid));
178 out += sizeof(oh) + strlen(o->vendorclassid);
179 }
180  
181 if (o->clientid) {
182 // client identifier
183 oh.type = hton8(DHCP_OPTION_CLIENT_IDENTIFIER);
184 oh.len = hton8(o->clientid_len);
185 memcpy(out, &oh, sizeof(oh));
186 memcpy(out + sizeof(oh), o->clientid, o->clientid_len);
187 out += sizeof(oh) + o->clientid_len;
188 }
189  
190 // end option
191 uint8_t end = 0xFF;
192 memcpy(out, &end, sizeof(end));
193 out += sizeof(end);
194  
195 // send it
196 PacketPassInterface_Sender_Send(o->send_if, (uint8_t *)o->send_buf, out - o->send_buf);
197 o->sending = 1;
198 }
199  
200 static void send_handler_done (BDHCPClientCore *o)
201 {
202 ASSERT(o->sending)
203 DebugObject_Access(&o->d_obj);
204  
205 o->sending = 0;
206 }
207  
208 static void recv_handler_done (BDHCPClientCore *o, int data_len)
209 {
210 ASSERT(data_len >= 0)
211 DebugObject_Access(&o->d_obj);
212  
213 // receive more packets
214 PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)o->recv_buf);
215  
216 if (o->state == STATE_RESETTING) {
217 return;
218 }
219  
220 // check header
221  
222 if (data_len < sizeof(struct dhcp_header)) {
223 return;
224 }
225  
226 struct dhcp_header header;
227 memcpy(&header, o->recv_buf, sizeof(header));
228  
229 if (ntoh8(header.op) != DHCP_OP_BOOTREPLY) {
230 return;
231 }
232  
233 if (ntoh8(header.htype) != DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET) {
234 return;
235 }
236  
237 if (ntoh8(header.hlen) != 6) {
238 return;
239 }
240  
241 if (header.xid != o->xid) {
242 return;
243 }
244  
245 if (memcmp(header.chaddr, o->client_mac_addr, sizeof(o->client_mac_addr))) {
246 return;
247 }
248  
249 if (ntoh32(header.magic) != DHCP_MAGIC) {
250 return;
251 }
252  
253 // parse and check options
254  
255 uint8_t *pos = (uint8_t *)o->recv_buf + sizeof(header);
256 int len = data_len - sizeof(header);
257  
258 int have_end = 0;
259  
260 int dhcp_message_type = -1;
261  
262 int have_dhcp_server_identifier = 0;
263 uint32_t dhcp_server_identifier = 0; // to remove warning
264  
265 int have_ip_address_lease_time = 0;
266 uint32_t ip_address_lease_time = 0; // to remove warning
267  
268 int have_subnet_mask = 0;
269 uint32_t subnet_mask = 0; // to remove warning
270  
271 int have_router = 0;
272 uint32_t router = 0; // to remove warning
273  
274 int domain_name_servers_count = 0;
275 uint32_t domain_name_servers[BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS];
276  
277 while (len > 0) {
278 // padding option ?
279 if (*pos == 0) {
280 pos++;
281 len--;
282 continue;
283 }
284  
285 if (have_end) {
286 return;
287 }
288  
289 // end option ?
290 if (*pos == 0xff) {
291 pos++;
292 len--;
293 have_end = 1;
294 continue;
295 }
296  
297 // check option header
298 if (len < sizeof(struct dhcp_option_header)) {
299 return;
300 }
301 struct dhcp_option_header opt;
302 memcpy(&opt, pos, sizeof(opt));
303 pos += sizeof(opt);
304 len -= sizeof(opt);
305 int opt_type = ntoh8(opt.type);
306 int opt_len = ntoh8(opt.len);
307  
308 // check option payload
309 if (opt_len > len) {
310 return;
311 }
312 uint8_t *optval = pos;
313 pos += opt_len;
314 len -= opt_len;
315  
316 switch (opt_type) {
317 case DHCP_OPTION_DHCP_MESSAGE_TYPE: {
318 if (opt_len != sizeof(struct dhcp_option_dhcp_message_type)) {
319 return;
320 }
321 struct dhcp_option_dhcp_message_type val;
322 memcpy(&val, optval, sizeof(val));
323  
324 dhcp_message_type = ntoh8(val.type);
325 } break;
326  
327 case DHCP_OPTION_DHCP_SERVER_IDENTIFIER: {
328 if (opt_len != sizeof(struct dhcp_option_dhcp_server_identifier)) {
329 return;
330 }
331 struct dhcp_option_dhcp_server_identifier val;
332 memcpy(&val, optval, sizeof(val));
333  
334 dhcp_server_identifier = val.id;
335 have_dhcp_server_identifier = 1;
336 } break;
337  
338 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: {
339 if (opt_len != sizeof(struct dhcp_option_time)) {
340 return;
341 }
342 struct dhcp_option_time val;
343 memcpy(&val, optval, sizeof(val));
344  
345 ip_address_lease_time = ntoh32(val.time);
346 have_ip_address_lease_time = 1;
347 } break;
348  
349 case DHCP_OPTION_SUBNET_MASK: {
350 if (opt_len != sizeof(struct dhcp_option_addr)) {
351 return;
352 }
353 struct dhcp_option_addr val;
354 memcpy(&val, optval, sizeof(val));
355  
356 subnet_mask = val.addr;
357 have_subnet_mask = 1;
358 } break;
359  
360 case DHCP_OPTION_ROUTER: {
361 if (opt_len != sizeof(struct dhcp_option_addr)) {
362 return;
363 }
364 struct dhcp_option_addr val;
365 memcpy(&val, optval, sizeof(val));
366  
367 router = val.addr;
368 have_router = 1;
369 } break;
370  
371 case DHCP_OPTION_DOMAIN_NAME_SERVER: {
372 if (opt_len % sizeof(struct dhcp_option_addr)) {
373 return;
374 }
375  
376 int num_servers = opt_len / sizeof(struct dhcp_option_addr);
377  
378 int i;
379 for (i = 0; i < num_servers && i < BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS; i++) {
380 struct dhcp_option_addr addr;
381 memcpy(&addr, optval + i * sizeof(addr), sizeof(addr));
382 domain_name_servers[i] = addr.addr;
383 }
384  
385 domain_name_servers_count = i;
386 } break;
387 }
388 }
389  
390 if (!have_end) {
391 return;
392 }
393  
394 if (dhcp_message_type == -1) {
395 return;
396 }
397  
398 if (dhcp_message_type != DHCP_MESSAGE_TYPE_OFFER && dhcp_message_type != DHCP_MESSAGE_TYPE_ACK && dhcp_message_type != DHCP_MESSAGE_TYPE_NAK) {
399 return;
400 }
401  
402 if (!have_dhcp_server_identifier) {
403 return;
404 }
405  
406 if (dhcp_message_type == DHCP_MESSAGE_TYPE_NAK) {
407 if (o->state != STATE_SENT_REQUEST && o->state != STATE_FINISHED && o->state != STATE_RENEWING) {
408 return;
409 }
410  
411 if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
412 return;
413 }
414  
415 if (o->state == STATE_SENT_REQUEST) {
416 BLog(BLOG_INFO, "received NAK (in sent request)");
417  
418 // stop request timer
419 BReactor_RemoveTimer(o->reactor, &o->request_timer);
420  
421 // start reset timer
422 BReactor_SetTimer(o->reactor, &o->reset_timer);
423  
424 // set state
425 o->state = STATE_RESETTING;
426 }
427 else if (o->state == STATE_FINISHED) {
428 BLog(BLOG_INFO, "received NAK (in finished)");
429  
430 // stop renew timer
431 BReactor_RemoveTimer(o->reactor, &o->renew_timer);
432  
433 // start reset timer
434 BReactor_SetTimer(o->reactor, &o->reset_timer);
435  
436 // set state
437 o->state = STATE_RESETTING;
438  
439 // report to user
440 report_down(o);
441 return;
442 }
443 else { // STATE_RENEWING
444 BLog(BLOG_INFO, "received NAK (in renewing)");
445  
446 // stop renew request timer
447 BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
448  
449 // stop lease timer
450 BReactor_RemoveTimer(o->reactor, &o->lease_timer);
451  
452 // start reset timer
453 BReactor_SetTimer(o->reactor, &o->reset_timer);
454  
455 // set state
456 o->state = STATE_RESETTING;
457  
458 // report to user
459 report_down(o);
460 return;
461 }
462  
463 return;
464 }
465  
466 if (ntoh32(header.yiaddr) == 0) {
467 return;
468 }
469  
470 if (!have_ip_address_lease_time) {
471 return;
472 }
473  
474 if (!have_subnet_mask) {
475 return;
476 }
477  
478 if (o->state == STATE_SENT_DISCOVER && dhcp_message_type == DHCP_MESSAGE_TYPE_OFFER) {
479 BLog(BLOG_INFO, "received OFFER");
480  
481 // remember offer
482 o->offered.yiaddr = header.yiaddr;
483 o->offered.dhcp_server_identifier = dhcp_server_identifier;
484  
485 // send request
486 send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 1, o->offered.dhcp_server_identifier);
487  
488 // stop reset timer
489 BReactor_RemoveTimer(o->reactor, &o->reset_timer);
490  
491 // start request timer
492 BReactor_SetTimer(o->reactor, &o->request_timer);
493  
494 // set state
495 o->state = STATE_SENT_REQUEST;
496  
497 // set request count
498 o->request_count = 1;
499 }
500 else if (o->state == STATE_SENT_REQUEST && dhcp_message_type == DHCP_MESSAGE_TYPE_ACK) {
501 if (header.yiaddr != o->offered.yiaddr) {
502 return;
503 }
504  
505 if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
506 return;
507 }
508  
509 BLog(BLOG_INFO, "received ACK (in sent request)");
510  
511 // remember stuff
512 o->acked.ip_address_lease_time = ip_address_lease_time;
513 o->acked.subnet_mask = subnet_mask;
514 o->acked.have_router = have_router;
515 if (have_router) {
516 o->acked.router = router;
517 }
518 o->acked.domain_name_servers_count = domain_name_servers_count;
519 memcpy(o->acked.domain_name_servers, domain_name_servers, domain_name_servers_count * sizeof(uint32_t));
520 o->func_getsendermac(o->user, o->acked.server_mac);
521  
522 // stop request timer
523 BReactor_RemoveTimer(o->reactor, &o->request_timer);
524  
525 // start renew timer
526 BReactor_SetTimerAfter(o->reactor, &o->renew_timer, RENEW_TIMEOUT(o->acked.ip_address_lease_time));
527  
528 // set state
529 o->state = STATE_FINISHED;
530  
531 // report to user
532 report_up(o);
533 return;
534 }
535 else if (o->state == STATE_RENEWING && dhcp_message_type == DHCP_MESSAGE_TYPE_ACK) {
536 if (header.yiaddr != o->offered.yiaddr) {
537 return;
538 }
539  
540 if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
541 return;
542 }
543  
544 // TODO: check parameters?
545  
546 BLog(BLOG_INFO, "received ACK (in renewing)");
547  
548 // remember stuff
549 o->acked.ip_address_lease_time = ip_address_lease_time;
550  
551 // stop renew request timer
552 BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
553  
554 // stop lease timer
555 BReactor_RemoveTimer(o->reactor, &o->lease_timer);
556  
557 // start renew timer
558 BReactor_SetTimerAfter(o->reactor, &o->renew_timer, RENEW_TIMEOUT(o->acked.ip_address_lease_time));
559  
560 // set state
561 o->state = STATE_FINISHED;
562 }
563 }
564  
565 static void start_process (BDHCPClientCore *o, int force_new_xid)
566 {
567 if (force_new_xid || o->xid_reuse_counter == XID_REUSE_MAX) {
568 // generate xid
569 if (!BRandom2_GenBytes(o->random2, &o->xid, sizeof(o->xid))) {
570 BLog(BLOG_ERROR, "BRandom2_GenBytes failed");
571 o->xid = UINT32_C(3416960072);
572 }
573  
574 // reset counter
575 o->xid_reuse_counter = 0;
576 }
577  
578 // increment counter
579 o->xid_reuse_counter++;
580  
581 // send discover
582 send_message(o, DHCP_MESSAGE_TYPE_DISCOVER, o->xid, 0, 0, 0, 0);
583  
584 // set timer
585 BReactor_SetTimer(o->reactor, &o->reset_timer);
586  
587 // set state
588 o->state = STATE_SENT_DISCOVER;
589 }
590  
591 static void reset_timer_handler (BDHCPClientCore *o)
592 {
593 ASSERT(o->state == STATE_RESETTING || o->state == STATE_SENT_DISCOVER)
594 DebugObject_Access(&o->d_obj);
595  
596 BLog(BLOG_INFO, "reset timer");
597  
598 start_process(o, (o->state == STATE_RESETTING));
599 }
600  
601 static void request_timer_handler (BDHCPClientCore *o)
602 {
603 ASSERT(o->state == STATE_SENT_REQUEST)
604 ASSERT(o->request_count >= 1)
605 ASSERT(o->request_count <= MAX_REQUESTS)
606 DebugObject_Access(&o->d_obj);
607  
608 // if we have sent enough requests, start again
609 if (o->request_count == MAX_REQUESTS) {
610 BLog(BLOG_INFO, "request timer, aborting");
611  
612 start_process(o, 0);
613 return;
614 }
615  
616 BLog(BLOG_INFO, "request timer, retrying");
617  
618 // send request
619 send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 1, o->offered.dhcp_server_identifier);
620  
621 // start request timer
622 BReactor_SetTimer(o->reactor, &o->request_timer);
623  
624 // increment request count
625 o->request_count++;
626 }
627  
628 static void renew_timer_handler (BDHCPClientCore *o)
629 {
630 ASSERT(o->state == STATE_FINISHED)
631 DebugObject_Access(&o->d_obj);
632  
633 BLog(BLOG_INFO, "renew timer");
634  
635 // send request
636 send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 0, 0);
637  
638 // start renew request timer
639 BReactor_SetTimer(o->reactor, &o->renew_request_timer);
640  
641 // start lease timer
642 BReactor_SetTimerAfter(o->reactor, &o->lease_timer, LEASE_TIMEOUT(o->acked.ip_address_lease_time));
643  
644 // set state
645 o->state = STATE_RENEWING;
646 }
647  
648 static void renew_request_timer_handler (BDHCPClientCore *o)
649 {
650 ASSERT(o->state == STATE_RENEWING)
651 DebugObject_Access(&o->d_obj);
652  
653 BLog(BLOG_INFO, "renew request timer");
654  
655 // send request
656 send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 0, 0);
657  
658 // start renew request timer
659 BReactor_SetTimer(o->reactor, &o->renew_request_timer);
660 }
661  
662 static void lease_timer_handler (BDHCPClientCore *o)
663 {
664 ASSERT(o->state == STATE_RENEWING)
665 DebugObject_Access(&o->d_obj);
666  
667 BLog(BLOG_INFO, "lease timer");
668  
669 // stop renew request timer
670 BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
671  
672 // start again now
673 start_process(o, 1);
674  
675 // report to user
676 report_down(o);
677 return;
678 }
679  
680 static bsize_t maybe_len (const char *str)
681 {
682 return bsize_fromsize(str ? strlen(str) : 0);
683 }
684  
685 int BDHCPClientCore_Init (BDHCPClientCore *o, PacketPassInterface *send_if, PacketRecvInterface *recv_if,
686 uint8_t *client_mac_addr, struct BDHCPClientCore_opts opts, BReactor *reactor,
687 BRandom2 *random2, void *user,
688 BDHCPClientCore_func_getsendermac func_getsendermac,
689 BDHCPClientCore_handler handler)
690 {
691 ASSERT(PacketPassInterface_GetMTU(send_if) == PacketRecvInterface_GetMTU(recv_if))
692 ASSERT(PacketPassInterface_GetMTU(send_if) >= 576 - IP_UDP_HEADERS_SIZE)
693 ASSERT(func_getsendermac)
694 ASSERT(handler)
695  
696 // init arguments
697 o->send_if = send_if;
698 o->recv_if = recv_if;
699 memcpy(o->client_mac_addr, client_mac_addr, sizeof(o->client_mac_addr));
700 o->reactor = reactor;
701 o->random2 = random2;
702 o->user = user;
703 o->func_getsendermac = func_getsendermac;
704 o->handler = handler;
705  
706 o->hostname = NULL;
707 o->vendorclassid = NULL;
708 o->clientid = NULL;
709 o->clientid_len = 0;
710  
711 // copy options
712 if (opts.hostname && !(o->hostname = strdup(opts.hostname))) {
713 BLog(BLOG_ERROR, "strdup failed");
714 goto fail0;
715 }
716 if (opts.vendorclassid && !(o->vendorclassid = strdup(opts.vendorclassid))) {
717 BLog(BLOG_ERROR, "strdup failed");
718 goto fail0;
719 }
720 if (opts.clientid) {
721 if (!(o->clientid = BAlloc(opts.clientid_len))) {
722 BLog(BLOG_ERROR, "BAlloc failed");
723 goto fail0;
724 }
725 memcpy(o->clientid, opts.clientid, opts.clientid_len);
726 o->clientid_len = opts.clientid_len;
727 }
728  
729 // make sure options aren't too long
730 bsize_t opts_size = bsize_add(maybe_len(o->hostname), bsize_add(maybe_len(o->vendorclassid), bsize_fromsize(o->clientid_len)));
731 if (opts_size.is_overflow || opts_size.value > 100) {
732 BLog(BLOG_ERROR, "options too long together");
733 goto fail0;
734 }
735 if (o->hostname && strlen(o->hostname) > 255) {
736 BLog(BLOG_ERROR, "hostname too long");
737 goto fail0;
738 }
739 if (o->vendorclassid && strlen(o->vendorclassid) > 255) {
740 BLog(BLOG_ERROR, "vendorclassid too long");
741 goto fail0;
742 }
743 if (o->clientid && o->clientid_len > 255) {
744 BLog(BLOG_ERROR, "clientid too long");
745 goto fail0;
746 }
747  
748 // allocate buffers
749 if (!(o->send_buf = BAlloc(PacketPassInterface_GetMTU(send_if)))) {
750 BLog(BLOG_ERROR, "BAlloc send buf failed");
751 goto fail0;
752 }
753 if (!(o->recv_buf = BAlloc(PacketRecvInterface_GetMTU(recv_if)))) {
754 BLog(BLOG_ERROR, "BAlloc recv buf failed");
755 goto fail1;
756 }
757  
758 // init send interface
759 PacketPassInterface_Sender_Init(o->send_if, (PacketPassInterface_handler_done)send_handler_done, o);
760  
761 // init receive interface
762 PacketRecvInterface_Receiver_Init(o->recv_if, (PacketRecvInterface_handler_done)recv_handler_done, o);
763  
764 // set not sending
765 o->sending = 0;
766  
767 // init timers
768 BTimer_Init(&o->reset_timer, RESET_TIMEOUT, (BTimer_handler)reset_timer_handler, o);
769 BTimer_Init(&o->request_timer, REQUEST_TIMEOUT, (BTimer_handler)request_timer_handler, o);
770 BTimer_Init(&o->renew_timer, 0, (BTimer_handler)renew_timer_handler, o);
771 BTimer_Init(&o->renew_request_timer, RENEW_REQUEST_TIMEOUT, (BTimer_handler)renew_request_timer_handler, o);
772 BTimer_Init(&o->lease_timer, 0, (BTimer_handler)lease_timer_handler, o);
773  
774 // start receving
775 PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)o->recv_buf);
776  
777 // start
778 start_process(o, 1);
779  
780 DebugObject_Init(&o->d_obj);
781  
782 return 1;
783  
784 fail1:
785 BFree(o->send_buf);
786 fail0:
787 BFree(o->clientid);
788 free(o->vendorclassid);
789 free(o->hostname);
790 return 0;
791 }
792  
793 void BDHCPClientCore_Free (BDHCPClientCore *o)
794 {
795 DebugObject_Free(&o->d_obj);
796  
797 // free timers
798 BReactor_RemoveTimer(o->reactor, &o->lease_timer);
799 BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
800 BReactor_RemoveTimer(o->reactor, &o->renew_timer);
801 BReactor_RemoveTimer(o->reactor, &o->request_timer);
802 BReactor_RemoveTimer(o->reactor, &o->reset_timer);
803  
804 // free buffers
805 BFree(o->recv_buf);
806 BFree(o->send_buf);
807  
808 // free options
809 BFree(o->clientid);
810 free(o->vendorclassid);
811 free(o->hostname);
812 }
813  
814 void BDHCPClientCore_GetClientIP (BDHCPClientCore *o, uint32_t *out_ip)
815 {
816 ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
817 DebugObject_Access(&o->d_obj);
818  
819 *out_ip = o->offered.yiaddr;
820 }
821  
822 void BDHCPClientCore_GetClientMask (BDHCPClientCore *o, uint32_t *out_mask)
823 {
824 ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
825 DebugObject_Access(&o->d_obj);
826  
827 *out_mask = o->acked.subnet_mask;
828 }
829  
830 int BDHCPClientCore_GetRouter (BDHCPClientCore *o, uint32_t *out_router)
831 {
832 ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
833 DebugObject_Access(&o->d_obj);
834  
835 if (!o->acked.have_router) {
836 return 0;
837 }
838  
839 *out_router = o->acked.router;
840 return 1;
841 }
842  
843 int BDHCPClientCore_GetDNS (BDHCPClientCore *o, uint32_t *out_dns_servers, size_t max_dns_servers)
844 {
845 ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
846 DebugObject_Access(&o->d_obj);
847  
848 int num_return = bmin_int(o->acked.domain_name_servers_count, max_dns_servers);
849  
850 memcpy(out_dns_servers, o->acked.domain_name_servers, num_return * sizeof(uint32_t));
851 return num_return;
852 }
853  
854 void BDHCPClientCore_GetServerMAC (BDHCPClientCore *o, uint8_t *out_mac)
855 {
856 DebugObject_Access(&o->d_obj);
857 ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
858  
859 memcpy(out_mac, o->acked.server_mac, 6);
860 }