BDHCPClientCore.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. /**
  2. * @file BDHCPClientCore.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <misc/byteorder.h>
  25. #include <misc/minmax.h>
  26. #include <security/BRandom.h>
  27. #include <base/BLog.h>
  28. #include <dhcpclient/BDHCPClientCore.h>
  29. #include <generated/blog_channel_BDHCPClientCore.h>
  30. #define RESET_TIMEOUT 4000
  31. #define REQUEST_TIMEOUT 3000
  32. #define RENEW_REQUEST_TIMEOUT 20000
  33. #define MAX_REQUESTS 4
  34. #define RENEW_TIMEOUT(lease) ((btime_t)500 * (lease))
  35. #define XID_REUSE_MAX 8
  36. #define LEASE_TIMEOUT(lease) ((btime_t)1000 * (lease) - RENEW_TIMEOUT(lease))
  37. #define STATE_RESETTING 1
  38. #define STATE_SENT_DISCOVER 2
  39. #define STATE_SENT_REQUEST 3
  40. #define STATE_FINISHED 4
  41. #define STATE_RENEWING 5
  42. #define IP_UDP_HEADERS_SIZE 28
  43. static void report_up (BDHCPClientCore *o)
  44. {
  45. o->handler(o->user, BDHCPCLIENTCORE_EVENT_UP);
  46. return;
  47. }
  48. static void report_down (BDHCPClientCore *o)
  49. {
  50. o->handler(o->user, BDHCPCLIENTCORE_EVENT_DOWN);
  51. return;
  52. }
  53. static void send_message (
  54. BDHCPClientCore *o,
  55. int type,
  56. uint32_t xid,
  57. int have_requested_ip_address, uint32_t requested_ip_address,
  58. int have_dhcp_server_identifier, uint32_t dhcp_server_identifier
  59. )
  60. {
  61. ASSERT(type == DHCP_MESSAGE_TYPE_DISCOVER || type == DHCP_MESSAGE_TYPE_REQUEST)
  62. if (o->sending) {
  63. BLog(BLOG_ERROR, "already sending");
  64. return;
  65. }
  66. // write header
  67. memset(o->send_buf, 0, sizeof(*o->send_buf));
  68. o->send_buf->op = hton8(DHCP_OP_BOOTREQUEST);
  69. o->send_buf->htype = hton8(DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET);
  70. o->send_buf->hlen = hton8(6);
  71. o->send_buf->xid = xid;
  72. o->send_buf->secs = hton16(0);
  73. memcpy(o->send_buf->chaddr, o->client_mac_addr, sizeof(o->client_mac_addr));
  74. o->send_buf->magic = hton32(DHCP_MAGIC);
  75. // write options
  76. struct dhcp_option_header *out = (void *)(o->send_buf + 1);
  77. // DHCP message type
  78. out->type = hton8(DHCP_OPTION_DHCP_MESSAGE_TYPE);
  79. out->len = hton8(sizeof(struct dhcp_option_dhcp_message_type));
  80. ((struct dhcp_option_dhcp_message_type *)(out + 1))->type = hton8(type);
  81. out = (void *)((uint8_t *)(out + 1) + ntoh8(out->len));
  82. if (have_requested_ip_address) {
  83. // requested IP address
  84. out->type = hton8(DHCP_OPTION_REQUESTED_IP_ADDRESS);
  85. out->len = hton8(sizeof(struct dhcp_option_addr));
  86. ((struct dhcp_option_addr *)(out + 1))->addr = requested_ip_address;
  87. out = (void *)((uint8_t *)(out + 1) + ntoh8(out->len));
  88. }
  89. if (have_dhcp_server_identifier) {
  90. // DHCP server identifier
  91. out->type = hton8(DHCP_OPTION_DHCP_SERVER_IDENTIFIER);
  92. out->len = hton8(sizeof(struct dhcp_option_dhcp_server_identifier));
  93. ((struct dhcp_option_dhcp_server_identifier *)(out + 1))->id = dhcp_server_identifier;
  94. out = (void *)((uint8_t *)(out + 1) + ntoh8(out->len));
  95. }
  96. // maximum message size
  97. out->type = hton8(DHCP_OPTION_MAXIMUM_MESSAGE_SIZE);
  98. out->len = hton8(sizeof(struct dhcp_option_maximum_message_size));
  99. ((struct dhcp_option_maximum_message_size *)(out + 1))->size = hton16(IP_UDP_HEADERS_SIZE + PacketRecvInterface_GetMTU(o->recv_if));
  100. out = (void *)((uint8_t *)(out + 1) + ntoh8(out->len));
  101. // parameter request list
  102. out->type = hton8(DHCP_OPTION_PARAMETER_REQUEST_LIST);
  103. out->len = hton8(4);
  104. ((uint8_t *)(out + 1))[0] = DHCP_OPTION_SUBNET_MASK;
  105. ((uint8_t *)(out + 1))[1] = DHCP_OPTION_ROUTER;
  106. ((uint8_t *)(out + 1))[2] = DHCP_OPTION_DOMAIN_NAME_SERVER;
  107. ((uint8_t *)(out + 1))[3] = DHCP_OPTION_IP_ADDRESS_LEASE_TIME;
  108. out = (void *)((uint8_t *)(out + 1) + ntoh8(out->len));
  109. // end option
  110. *((uint8_t *)out) = 0xFF;
  111. out = (void *)((uint8_t *)out + 1);
  112. // send it
  113. PacketPassInterface_Sender_Send(o->send_if, (uint8_t *)o->send_buf, (uint8_t *)out - (uint8_t *)o->send_buf);
  114. o->sending = 1;
  115. }
  116. static void send_handler_done (BDHCPClientCore *o)
  117. {
  118. ASSERT(o->sending)
  119. DebugObject_Access(&o->d_obj);
  120. o->sending = 0;
  121. }
  122. static void recv_handler_done (BDHCPClientCore *o, int data_len)
  123. {
  124. ASSERT(data_len >= 0)
  125. DebugObject_Access(&o->d_obj);
  126. // receive more packets
  127. PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)o->recv_buf);
  128. if (o->state == STATE_RESETTING) {
  129. return;
  130. }
  131. // check header
  132. if (data_len < sizeof(*o->recv_buf)) {
  133. return;
  134. }
  135. if (ntoh8(o->recv_buf->op) != DHCP_OP_BOOTREPLY) {
  136. return;
  137. }
  138. if (ntoh8(o->recv_buf->htype) != DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET) {
  139. return;
  140. }
  141. if (ntoh8(o->recv_buf->hlen) != 6) {
  142. return;
  143. }
  144. if (o->recv_buf->xid != o->xid) {
  145. return;
  146. }
  147. if (memcmp(o->recv_buf->chaddr, o->client_mac_addr, sizeof(o->client_mac_addr))) {
  148. return;
  149. }
  150. if (ntoh32(o->recv_buf->magic) != DHCP_MAGIC) {
  151. return;
  152. }
  153. // parse and check options
  154. uint8_t *pos = (uint8_t *)o->recv_buf + sizeof(*o->recv_buf);
  155. int len = data_len - sizeof(*o->recv_buf);
  156. int have_end = 0;
  157. int dhcp_message_type = -1;
  158. int have_dhcp_server_identifier = 0;
  159. uint32_t dhcp_server_identifier;
  160. int have_ip_address_lease_time = 0;
  161. uint32_t ip_address_lease_time;
  162. int have_subnet_mask = 0;
  163. uint32_t subnet_mask;
  164. int have_router = 0;
  165. uint32_t router;
  166. int domain_name_servers_count = 0;
  167. uint32_t domain_name_servers[BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS];
  168. while (len > 0) {
  169. // padding option ?
  170. if (*pos == 0) {
  171. pos++;
  172. len--;
  173. continue;
  174. }
  175. if (have_end) {
  176. return;
  177. }
  178. // end option ?
  179. if (*pos == 0xff) {
  180. pos++;
  181. len--;
  182. have_end = 1;
  183. continue;
  184. }
  185. // check option header
  186. if (len < sizeof(struct dhcp_option_header)) {
  187. return;
  188. }
  189. struct dhcp_option_header *opt = (void *)pos;
  190. pos += sizeof(*opt);
  191. len -= sizeof(*opt);
  192. int opt_type = ntoh8(opt->type);
  193. int opt_len = ntoh8(opt->len);
  194. // check option payload
  195. if (opt_len > len) {
  196. return;
  197. }
  198. void *optval = pos;
  199. pos += opt_len;
  200. len -= opt_len;
  201. switch (opt_type) {
  202. case DHCP_OPTION_DHCP_MESSAGE_TYPE: {
  203. if (opt_len != sizeof(struct dhcp_option_dhcp_message_type)) {
  204. return;
  205. }
  206. struct dhcp_option_dhcp_message_type *val = optval;
  207. dhcp_message_type = ntoh8(val->type);
  208. } break;
  209. case DHCP_OPTION_DHCP_SERVER_IDENTIFIER: {
  210. if (opt_len != sizeof(struct dhcp_option_dhcp_server_identifier)) {
  211. return;
  212. }
  213. struct dhcp_option_dhcp_server_identifier *val = optval;
  214. dhcp_server_identifier = val->id;
  215. have_dhcp_server_identifier = 1;
  216. } break;
  217. case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: {
  218. if (opt_len != sizeof(struct dhcp_option_time)) {
  219. return;
  220. }
  221. struct dhcp_option_time *val = optval;
  222. ip_address_lease_time = ntoh32(val->time);
  223. have_ip_address_lease_time = 1;
  224. } break;
  225. case DHCP_OPTION_SUBNET_MASK: {
  226. if (opt_len != sizeof(struct dhcp_option_addr)) {
  227. return;
  228. }
  229. struct dhcp_option_addr *val = optval;
  230. subnet_mask = val->addr;
  231. have_subnet_mask = 1;
  232. } break;
  233. case DHCP_OPTION_ROUTER: {
  234. if (opt_len != sizeof(struct dhcp_option_addr)) {
  235. return;
  236. }
  237. struct dhcp_option_addr *val = optval;
  238. router = val->addr;
  239. have_router = 1;
  240. } break;
  241. case DHCP_OPTION_DOMAIN_NAME_SERVER: {
  242. if (opt_len % 4) {
  243. return;
  244. }
  245. int num_servers = opt_len / 4;
  246. int i;
  247. for (i = 0; i < num_servers && i < BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS; i++) {
  248. domain_name_servers[i] = ((struct dhcp_option_addr *)optval + i)->addr;
  249. }
  250. domain_name_servers_count = i;
  251. } break;
  252. }
  253. }
  254. if (!have_end) {
  255. return;
  256. }
  257. if (dhcp_message_type == -1) {
  258. return;
  259. }
  260. if (dhcp_message_type != DHCP_MESSAGE_TYPE_OFFER && dhcp_message_type != DHCP_MESSAGE_TYPE_ACK && dhcp_message_type != DHCP_MESSAGE_TYPE_NAK) {
  261. return;
  262. }
  263. if (!have_dhcp_server_identifier) {
  264. return;
  265. }
  266. if (dhcp_message_type == DHCP_MESSAGE_TYPE_NAK) {
  267. if (o->state != STATE_SENT_REQUEST && o->state != STATE_FINISHED && o->state != STATE_RENEWING) {
  268. return;
  269. }
  270. if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
  271. return;
  272. }
  273. if (o->state == STATE_SENT_REQUEST) {
  274. BLog(BLOG_INFO, "received NAK (in sent request)");
  275. // stop request timer
  276. BReactor_RemoveTimer(o->reactor, &o->request_timer);
  277. // start reset timer
  278. BReactor_SetTimer(o->reactor, &o->reset_timer);
  279. // set state
  280. o->state = STATE_RESETTING;
  281. }
  282. else if (o->state == STATE_FINISHED) {
  283. BLog(BLOG_INFO, "received NAK (in finished)");
  284. // stop renew timer
  285. BReactor_RemoveTimer(o->reactor, &o->renew_timer);
  286. // start reset timer
  287. BReactor_SetTimer(o->reactor, &o->reset_timer);
  288. // set state
  289. o->state = STATE_RESETTING;
  290. // report to user
  291. report_down(o);
  292. return;
  293. }
  294. else { // STATE_RENEWING
  295. BLog(BLOG_INFO, "received NAK (in renewing)");
  296. // stop renew request timer
  297. BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
  298. // stop lease timer
  299. BReactor_RemoveTimer(o->reactor, &o->lease_timer);
  300. // start reset timer
  301. BReactor_SetTimer(o->reactor, &o->reset_timer);
  302. // set state
  303. o->state = STATE_RESETTING;
  304. // report to user
  305. report_down(o);
  306. return;
  307. }
  308. return;
  309. }
  310. if (ntoh32(o->recv_buf->yiaddr) == 0) {
  311. return;
  312. }
  313. if (!have_ip_address_lease_time) {
  314. return;
  315. }
  316. if (!have_subnet_mask) {
  317. return;
  318. }
  319. if (o->state == STATE_SENT_DISCOVER && dhcp_message_type == DHCP_MESSAGE_TYPE_OFFER) {
  320. BLog(BLOG_INFO, "received OFFER");
  321. // remember offer
  322. o->offered.yiaddr = o->recv_buf->yiaddr;
  323. o->offered.dhcp_server_identifier = dhcp_server_identifier;
  324. // send request
  325. send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 1, o->offered.dhcp_server_identifier);
  326. // stop reset timer
  327. BReactor_RemoveTimer(o->reactor, &o->reset_timer);
  328. // start request timer
  329. BReactor_SetTimer(o->reactor, &o->request_timer);
  330. // set state
  331. o->state = STATE_SENT_REQUEST;
  332. // set request count
  333. o->request_count = 1;
  334. }
  335. else if (o->state == STATE_SENT_REQUEST && dhcp_message_type == DHCP_MESSAGE_TYPE_ACK) {
  336. if (o->recv_buf->yiaddr != o->offered.yiaddr) {
  337. return;
  338. }
  339. if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
  340. return;
  341. }
  342. BLog(BLOG_INFO, "received ACK (in sent request)");
  343. // remember stuff
  344. o->acked.ip_address_lease_time = ip_address_lease_time;
  345. o->acked.subnet_mask = subnet_mask;
  346. o->acked.have_router = have_router;
  347. if (have_router) {
  348. o->acked.router = router;
  349. }
  350. o->acked.domain_name_servers_count = domain_name_servers_count;
  351. memcpy(o->acked.domain_name_servers, domain_name_servers, domain_name_servers_count * sizeof(uint32_t));
  352. // stop request timer
  353. BReactor_RemoveTimer(o->reactor, &o->request_timer);
  354. // start renew timer
  355. BReactor_SetTimerAfter(o->reactor, &o->renew_timer, RENEW_TIMEOUT(o->acked.ip_address_lease_time));
  356. // set state
  357. o->state = STATE_FINISHED;
  358. // report to user
  359. report_up(o);
  360. return;
  361. }
  362. else if (o->state == STATE_RENEWING && dhcp_message_type == DHCP_MESSAGE_TYPE_ACK) {
  363. if (o->recv_buf->yiaddr != o->offered.yiaddr) {
  364. return;
  365. }
  366. if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
  367. return;
  368. }
  369. // TODO: check parameters?
  370. BLog(BLOG_INFO, "received ACK (in renewing)");
  371. // remember stuff
  372. o->acked.ip_address_lease_time = ip_address_lease_time;
  373. // stop renew request timer
  374. BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
  375. // stop lease timer
  376. BReactor_RemoveTimer(o->reactor, &o->lease_timer);
  377. // start renew timer
  378. BReactor_SetTimerAfter(o->reactor, &o->renew_timer, RENEW_TIMEOUT(o->acked.ip_address_lease_time));
  379. // set state
  380. o->state = STATE_FINISHED;
  381. }
  382. }
  383. static void start_process (BDHCPClientCore *o, int force_new_xid)
  384. {
  385. if (force_new_xid || o->xid_reuse_counter == XID_REUSE_MAX) {
  386. // generate xid
  387. BRandom_randomize((uint8_t *)&o->xid, sizeof(o->xid));
  388. // reset counter
  389. o->xid_reuse_counter = 0;
  390. }
  391. // increment counter
  392. o->xid_reuse_counter++;
  393. // send discover
  394. send_message(o, DHCP_MESSAGE_TYPE_DISCOVER, o->xid, 0, 0, 0, 0);
  395. // set timer
  396. BReactor_SetTimer(o->reactor, &o->reset_timer);
  397. // set state
  398. o->state = STATE_SENT_DISCOVER;
  399. }
  400. static void reset_timer_handler (BDHCPClientCore *o)
  401. {
  402. ASSERT(o->state == STATE_RESETTING || o->state == STATE_SENT_DISCOVER)
  403. DebugObject_Access(&o->d_obj);
  404. BLog(BLOG_INFO, "reset timer");
  405. start_process(o, (o->state == STATE_RESETTING));
  406. }
  407. static void request_timer_handler (BDHCPClientCore *o)
  408. {
  409. ASSERT(o->state == STATE_SENT_REQUEST)
  410. ASSERT(o->request_count >= 1)
  411. ASSERT(o->request_count <= MAX_REQUESTS)
  412. DebugObject_Access(&o->d_obj);
  413. // if we have sent enough requests, start again
  414. if (o->request_count == MAX_REQUESTS) {
  415. BLog(BLOG_INFO, "request timer, aborting");
  416. start_process(o, 0);
  417. return;
  418. }
  419. BLog(BLOG_INFO, "request timer, retrying");
  420. // send request
  421. send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 1, o->offered.dhcp_server_identifier);
  422. // start request timer
  423. BReactor_SetTimer(o->reactor, &o->request_timer);
  424. // increment request count
  425. o->request_count++;
  426. }
  427. static void renew_timer_handler (BDHCPClientCore *o)
  428. {
  429. ASSERT(o->state == STATE_FINISHED)
  430. DebugObject_Access(&o->d_obj);
  431. BLog(BLOG_INFO, "renew timer");
  432. // send request
  433. send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 0, 0);
  434. // start renew request timer
  435. BReactor_SetTimer(o->reactor, &o->renew_request_timer);
  436. // start lease timer
  437. BReactor_SetTimerAfter(o->reactor, &o->lease_timer, LEASE_TIMEOUT(o->acked.ip_address_lease_time));
  438. // set state
  439. o->state = STATE_RENEWING;
  440. }
  441. static void renew_request_timer_handler (BDHCPClientCore *o)
  442. {
  443. ASSERT(o->state == STATE_RENEWING)
  444. DebugObject_Access(&o->d_obj);
  445. BLog(BLOG_INFO, "renew request timer");
  446. // send request
  447. send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 0, 0);
  448. // start renew request timer
  449. BReactor_SetTimer(o->reactor, &o->renew_request_timer);
  450. }
  451. static void lease_timer_handler (BDHCPClientCore *o)
  452. {
  453. ASSERT(o->state == STATE_RENEWING)
  454. DebugObject_Access(&o->d_obj);
  455. BLog(BLOG_INFO, "lease timer");
  456. // stop renew request timer
  457. BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
  458. // start again now
  459. start_process(o, 1);
  460. // report to user
  461. report_down(o);
  462. return;
  463. }
  464. int BDHCPClientCore_Init (BDHCPClientCore *o, PacketPassInterface *send_if, PacketRecvInterface *recv_if, uint8_t *client_mac_addr, BReactor *reactor, BDHCPClientCore_handler handler, void *user)
  465. {
  466. ASSERT(PacketPassInterface_GetMTU(send_if) == PacketRecvInterface_GetMTU(recv_if))
  467. ASSERT(PacketPassInterface_GetMTU(send_if) >= 576 - IP_UDP_HEADERS_SIZE)
  468. // init arguments
  469. o->send_if = send_if;
  470. o->recv_if = recv_if;
  471. memcpy(o->client_mac_addr, client_mac_addr, sizeof(o->client_mac_addr));
  472. o->reactor = reactor;
  473. o->handler = handler;
  474. o->user = user;
  475. // allocate buffers
  476. if (!(o->send_buf = malloc(PacketPassInterface_GetMTU(send_if)))) {
  477. BLog(BLOG_ERROR, "malloc send buf failed");
  478. goto fail0;
  479. }
  480. if (!(o->recv_buf = malloc(PacketRecvInterface_GetMTU(recv_if)))) {
  481. BLog(BLOG_ERROR, "malloc recv buf failed");
  482. goto fail1;
  483. }
  484. // init send interface
  485. PacketPassInterface_Sender_Init(o->send_if, (PacketPassInterface_handler_done)send_handler_done, o);
  486. // init receive interface
  487. PacketRecvInterface_Receiver_Init(o->recv_if, (PacketRecvInterface_handler_done)recv_handler_done, o);
  488. // set not sending
  489. o->sending = 0;
  490. // init timers
  491. BTimer_Init(&o->reset_timer, RESET_TIMEOUT, (BTimer_handler)reset_timer_handler, o);
  492. BTimer_Init(&o->request_timer, REQUEST_TIMEOUT, (BTimer_handler)request_timer_handler, o);
  493. BTimer_Init(&o->renew_timer, 0, (BTimer_handler)renew_timer_handler, o);
  494. BTimer_Init(&o->renew_request_timer, RENEW_REQUEST_TIMEOUT, (BTimer_handler)renew_request_timer_handler, o);
  495. BTimer_Init(&o->lease_timer, 0, (BTimer_handler)lease_timer_handler, o);
  496. // start receving
  497. PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)o->recv_buf);
  498. // start
  499. start_process(o, 1);
  500. DebugObject_Init(&o->d_obj);
  501. return 1;
  502. fail1:
  503. free(o->send_buf);
  504. fail0:
  505. return 0;
  506. }
  507. void BDHCPClientCore_Free (BDHCPClientCore *o)
  508. {
  509. DebugObject_Free(&o->d_obj);
  510. // free timers
  511. BReactor_RemoveTimer(o->reactor, &o->lease_timer);
  512. BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
  513. BReactor_RemoveTimer(o->reactor, &o->renew_timer);
  514. BReactor_RemoveTimer(o->reactor, &o->request_timer);
  515. BReactor_RemoveTimer(o->reactor, &o->reset_timer);
  516. // free buffers
  517. free(o->recv_buf);
  518. free(o->send_buf);
  519. }
  520. void BDHCPClientCore_GetClientIP (BDHCPClientCore *o, uint32_t *out_ip)
  521. {
  522. ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
  523. DebugObject_Access(&o->d_obj);
  524. *out_ip = o->offered.yiaddr;
  525. }
  526. void BDHCPClientCore_GetClientMask (BDHCPClientCore *o, uint32_t *out_mask)
  527. {
  528. ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
  529. DebugObject_Access(&o->d_obj);
  530. *out_mask = o->acked.subnet_mask;
  531. }
  532. int BDHCPClientCore_GetRouter (BDHCPClientCore *o, uint32_t *out_router)
  533. {
  534. ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
  535. DebugObject_Access(&o->d_obj);
  536. if (!o->acked.have_router) {
  537. return 0;
  538. }
  539. *out_router = o->acked.router;
  540. return 1;
  541. }
  542. int BDHCPClientCore_GetDNS (BDHCPClientCore *o, uint32_t *out_dns_servers, size_t max_dns_servers)
  543. {
  544. ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
  545. DebugObject_Access(&o->d_obj);
  546. int num_return = bmin_int(o->acked.domain_name_servers_count, max_dns_servers);
  547. memcpy(out_dns_servers, o->acked.domain_name_servers, num_return * sizeof(uint32_t));
  548. return num_return;
  549. }