dhcp_client.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. #include "luat_base.h"
  2. #include "luat_mem.h"
  3. #include "luat_mcu.h"
  4. #if 1
  5. #include "luat_network_adapter.h"
  6. #include "dhcp_def.h"
  7. #define LUAT_LOG_TAG "DHCP"
  8. #include "luat_log.h"
  9. #define DHCP_OPTION_138 138
  10. // DHCP超时和重传配置
  11. #define DHCP_MIN_LEASE_SEC 60
  12. #define DHCP_RETRY_BASE_MS 1000
  13. #define DHCP_RETRY_MAX_MS 8000
  14. #define DHCP_RENEW_TIMEOUT_MS 2500
  15. #define DHCP_REBIND_TIMEOUT_MS 2500
  16. #define DHCP_SELECT_ACK_TIMEOUT_MS 1900
  17. #define DHCP_MAX_SELECT_RETRIES 3
  18. //extern void DBG_Printf(const char* format, ...);
  19. //extern void DBG_HexPrintf(void *Data, unsigned int len);
  20. //#define DBG(x,y...) DBG_Printf("%s %d:"x"\r\n", __FUNCTION__,__LINE__,##y)
  21. void make_ip4_dhcp_msg_base(dhcp_client_info_t *dhcp, uint16_t flag, Buffer_Struct *out)
  22. {
  23. uint16_t escape_time = 0;
  24. if (dhcp->last_tx_time)
  25. {
  26. escape_time = (luat_mcu_tick64_ms() - dhcp->last_tx_time) / 1000;
  27. }
  28. // 确保缓冲区至少能容纳DHCP基本消息(236) + magic(4) + 选项空间
  29. if (out->MaxLen < DHCP_MSG_LEN + 4 + 64) {
  30. LLOGE("buffer too small for DHCP message");
  31. return;
  32. }
  33. BytesPut8ToBuf(out, DHCP_BOOTREQUEST);
  34. BytesPut8ToBuf(out, DHCP_HTYPE_ETH);
  35. BytesPut8ToBuf(out, 6);
  36. BytesPut8ToBuf(out, 0);
  37. BytesPutBe32ToBuf(out, dhcp->xid);
  38. BytesPutBe16ToBuf(out, escape_time);
  39. BytesPutBe16ToBuf(out, flag);
  40. BytesPutLe32ToBuf(out, dhcp->ip);
  41. BytesPutLe32ToBuf(out, 0);
  42. BytesPutLe32ToBuf(out, 0);
  43. BytesPutLe32ToBuf(out, 0);
  44. OS_BufferWrite(out, dhcp->mac, 6);
  45. // 使用OS_BufferWrite确保安全,填充chaddr剩余10字节 + sname(64) + file(128)
  46. uint8_t zeros[202] = {0}; // 10 + 64 + 128
  47. OS_BufferWrite(out, zeros, sizeof(zeros));
  48. BytesPutBe32ToBuf(out, DHCP_MAGIC_COOKIE);
  49. }
  50. void ip4_dhcp_msg_add_bytes_option(uint8_t id, uint8_t *data, uint8_t len, Buffer_Struct *out)
  51. {
  52. BytesPut8ToBuf(out, id);
  53. BytesPut8ToBuf(out, len);
  54. OS_BufferWrite(out, data, len);
  55. }
  56. void ip4_dhcp_msg_add_client_id_option(uint8_t id, uint8_t *data, uint8_t len, Buffer_Struct *out)
  57. {
  58. BytesPut8ToBuf(out, id);
  59. BytesPut8ToBuf(out, len + 1);
  60. BytesPut8ToBuf(out, 1);
  61. OS_BufferWrite(out, data, len);
  62. }
  63. void ip4_dhcp_msg_add_ip_option(uint8_t id, uint32_t ip, Buffer_Struct *out)
  64. {
  65. BytesPut8ToBuf(out, id);
  66. BytesPut8ToBuf(out, 4);
  67. // 保持与系统内部IP存储格式一致(小端序)
  68. // 该系统所有IP读取都用BytesGetLe32,写入也需要用Le32保持一致
  69. BytesPutLe32ToBuf(out, ip);
  70. }
  71. void ip4_dhcp_msg_add_integer_option(uint8_t id, uint8_t len, uint32_t value, Buffer_Struct *out)
  72. {
  73. BytesPut8ToBuf(out, id);
  74. BytesPut8ToBuf(out, len);
  75. switch (len)
  76. {
  77. case 1:
  78. BytesPut8ToBuf(out, value);
  79. break;
  80. case 2:
  81. BytesPutBe16ToBuf(out, value);
  82. break;
  83. default:
  84. BytesPutBe32ToBuf(out, value);
  85. break;
  86. }
  87. }
  88. void make_ip4_dhcp_discover_msg(dhcp_client_info_t *dhcp, Buffer_Struct *out)
  89. {
  90. uint8_t dhcp_discover_request_options[] = {
  91. DHCP_OPTION_SUBNET_MASK,
  92. DHCP_OPTION_ROUTER,
  93. DHCP_OPTION_BROADCAST,
  94. DHCP_OPTION_SERVER_ID,
  95. DHCP_OPTION_LEASE_TIME,
  96. DHCP_OPTION_IP_TTL,
  97. };
  98. out->Pos = 0;
  99. dhcp->xid++;
  100. make_ip4_dhcp_msg_base(dhcp, 0x8000, out);
  101. ip4_dhcp_msg_add_integer_option(DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, DHCP_DISCOVER, out);
  102. ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_PARAMETER_REQUEST_LIST, dhcp_discover_request_options, sizeof(dhcp_discover_request_options), out);
  103. ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_HOSTNAME, (uint8_t*)dhcp->name, strlen(dhcp->name), out);
  104. ip4_dhcp_msg_add_client_id_option(DHCP_OPTION_CLIENT_ID, (uint8_t*)dhcp->mac, 6, out);
  105. BytesPut8ToBuf(out, 0xff);
  106. // DHCP选项无需强制4字节对齐,避免产生冗余填充
  107. }
  108. void make_ip4_dhcp_select_msg(dhcp_client_info_t *dhcp, uint16_t flag, Buffer_Struct *out)
  109. {
  110. uint8_t dhcp_discover_request_options[] = {
  111. DHCP_OPTION_SUBNET_MASK,
  112. DHCP_OPTION_ROUTER,
  113. DHCP_OPTION_DNS_SERVER,
  114. 15,
  115. 31,33,43,44,46,47,
  116. DHCP_OPTION_SERVER_ID,
  117. DHCP_OPTION_LEASE_TIME,
  118. 119,121,249,252
  119. //DHCP_OPTION_138,
  120. };
  121. out->Pos = 0;
  122. // 构造FQDN(Option 81): Flags(1) + RCode1(1) + RCode2(1) + Hostname
  123. uint8_t full_name[96] = {0};
  124. make_ip4_dhcp_msg_base(dhcp, flag, out);
  125. ip4_dhcp_msg_add_integer_option(DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, DHCP_REQUEST, out);
  126. ip4_dhcp_msg_add_client_id_option(DHCP_OPTION_CLIENT_ID, (uint8_t*)dhcp->mac, 6, out);
  127. ip4_dhcp_msg_add_ip_option(DHCP_OPTION_REQUESTED_IP, dhcp->temp_ip, out);
  128. if (dhcp->server_ip)
  129. {
  130. ip4_dhcp_msg_add_ip_option(DHCP_OPTION_SERVER_ID, dhcp->server_ip, out);
  131. }
  132. // HOSTNAME(长度限制避免超过255)
  133. {
  134. size_t name_len = strlen(dhcp->name);
  135. if (name_len > 63) name_len = 63; // 常见实现对主机名长度做限制
  136. ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_HOSTNAME, (uint8_t*)dhcp->name, (uint8_t)name_len, out);
  137. // FQDN: Flags=0x01(服务器进行更新),RCode1=0,RCode2=0
  138. full_name[0] = 0x01;
  139. full_name[1] = 0x00;
  140. full_name[2] = 0x00;
  141. memcpy(full_name + 3, (uint8_t*)dhcp->name, name_len);
  142. ip4_dhcp_msg_add_bytes_option(81, full_name, (uint8_t)(name_len + 3), out);
  143. }
  144. // Vendor Class已移除(原"MSFT 5.0"),避免服务器施加Windows特定策略
  145. // 如有需要,可根据实际平台配置添加
  146. ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_PARAMETER_REQUEST_LIST, dhcp_discover_request_options, sizeof(dhcp_discover_request_options), out);
  147. BytesPut8ToBuf(out, 0xff);
  148. }
  149. //void make_ip4_dhcp_info_msg(dhcp_client_info_t *dhcp, Buffer_Struct *out)
  150. //{
  151. // uint8_t dhcp_discover_request_options[] = {
  152. // DHCP_OPTION_SUBNET_MASK,
  153. // DHCP_OPTION_ROUTER,
  154. // DHCP_OPTION_BROADCAST,
  155. // DHCP_OPTION_SERVER_ID,
  156. // DHCP_OPTION_LEASE_TIME,
  157. // DHCP_OPTION_DNS_SERVER,
  158. // DHCP_OPTION_IP_TTL,
  159. // DHCP_OPTION_138,
  160. // };
  161. // out->Pos = 0;
  162. // dhcp->xid++;
  163. // make_ip4_dhcp_msg_base(dhcp, 0x8000, out);
  164. // ip4_dhcp_msg_add_integer_option(DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, DHCP_INFORM, out);
  165. // ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_HOSTNAME, (uint8_t*)dhcp->name, strlen(dhcp->name), out);
  166. // ip4_dhcp_msg_add_client_id_option(DHCP_OPTION_CLIENT_ID, (uint8_t*)dhcp->mac, 6, out);
  167. // ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_PARAMETER_REQUEST_LIST, dhcp_discover_request_options, sizeof(dhcp_discover_request_options), out);
  168. // BytesPut8ToBuf(out, 0xff);
  169. //}
  170. void make_ip4_dhcp_decline_msg(dhcp_client_info_t *dhcp, Buffer_Struct *out)
  171. {
  172. out->Pos = 0;
  173. dhcp->xid++;
  174. make_ip4_dhcp_msg_base(dhcp, 0, out);
  175. ip4_dhcp_msg_add_integer_option(DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, DHCP_DECLINE, out);
  176. ip4_dhcp_msg_add_ip_option(DHCP_OPTION_REQUESTED_IP, dhcp->temp_ip, out);
  177. ip4_dhcp_msg_add_ip_option(DHCP_OPTION_SERVER_ID, dhcp->server_ip, out);
  178. ip4_dhcp_msg_add_bytes_option(DHCP_OPTION_HOSTNAME, (uint8_t*)dhcp->name, strlen(dhcp->name), out);
  179. ip4_dhcp_msg_add_client_id_option(DHCP_OPTION_CLIENT_ID, (uint8_t*)dhcp->mac, 6, out);
  180. BytesPut8ToBuf(out, 0xff);
  181. }
  182. int analyze_ip4_dhcp(dhcp_client_info_t *dhcp, Buffer_Struct *in)
  183. {
  184. int ack = 0;
  185. uint64_t lease_time;
  186. if (in->Data[0] != DHCP_BOOTREPLY)
  187. {
  188. LLOGD("head error");
  189. return -1;
  190. }
  191. if (BytesGetBe32(&in->Data[DHCP_MSG_LEN]) != DHCP_MAGIC_COOKIE)
  192. {
  193. LLOGD("cookie error");
  194. return -2;
  195. }
  196. // 基本类型校验:HTYPE=ETH(1),HLEN=6
  197. if (in->Data[1] != DHCP_HTYPE_ETH || in->Data[2] != 6)
  198. {
  199. LLOGD("htype/hlen error %d/%d", in->Data[1], in->Data[2]);
  200. return -1;
  201. }
  202. if (BytesGetBe32(&in->Data[4]) != dhcp->xid)
  203. {
  204. // LLOGD("xid error %x,%x", BytesGetBe32(&in->Data[4]), dhcp->xid);
  205. if (BytesGetBe32(&in->Data[4]) == (dhcp->xid - 1))
  206. {
  207. LLOGD("maybe get same ack, drop %x,%x", BytesGetBe32(&in->Data[4]), dhcp->xid);
  208. return 0;
  209. }
  210. LLOGD("xid error %x,%x not for us, drop", BytesGetBe32(&in->Data[4]), dhcp->xid);
  211. return -3;
  212. }
  213. if (memcmp(dhcp->mac, &in->Data[28], 6))
  214. {
  215. LLOGD("mac error");
  216. return -4;
  217. }
  218. dhcp->temp_ip = BytesGetLe32(&in->Data[16]);
  219. LLOGD("find ip %x %d.%d.%d.%d", dhcp->temp_ip, in->Data[16], in->Data[17], in->Data[18], in->Data[19]);
  220. in->Pos = DHCP_OPTIONS_OFS;
  221. while (in->Pos < in->MaxLen)
  222. {
  223. __CHECK:
  224. // 边界检查,确保能读取type/len
  225. if (in->Pos + 1 >= in->MaxLen)
  226. break;
  227. uint8_t opt = in->Data[in->Pos];
  228. uint8_t len = in->Data[in->Pos + 1];
  229. if (opt == DHCP_OPTION_PAD)
  230. {
  231. in->Pos++;
  232. goto __CHECK;
  233. }
  234. if (opt == DHCP_OPTION_END)
  235. {
  236. return ack;
  237. }
  238. if (in->Pos + 2 + len > in->MaxLen)
  239. {
  240. LLOGW("option overflow opt=%d len=%d pos=%d", opt, len, in->Pos);
  241. break;
  242. }
  243. switch(opt)
  244. {
  245. case DHCP_OPTION_MESSAGE_TYPE:
  246. ack = in->Data[in->Pos + 2];
  247. break;
  248. case DHCP_OPTION_SERVER_ID:
  249. dhcp->server_ip = BytesGetLe32(&in->Data[in->Pos + 2]);
  250. break;
  251. case DHCP_OPTION_LEASE_TIME:
  252. if (DHCP_ACK == ack)
  253. {
  254. dhcp->lease_time = BytesGetBe32(&in->Data[in->Pos + 2]);
  255. if (dhcp->lease_time < DHCP_MIN_LEASE_SEC)
  256. {
  257. LLOGW("lease time too short %d, set to %d", dhcp->lease_time, DHCP_MIN_LEASE_SEC);
  258. dhcp->lease_time = DHCP_MIN_LEASE_SEC;
  259. }
  260. lease_time = dhcp->lease_time;
  261. lease_time *= 1000;
  262. dhcp->lease_end_time = luat_mcu_tick64_ms() + lease_time;
  263. // 默认按比例,若后续解析到T1/T2会覆盖
  264. dhcp->lease_p1_time = dhcp->lease_end_time - (lease_time >> 1);
  265. dhcp->lease_p2_time = dhcp->lease_end_time - (lease_time >> 3);
  266. }
  267. break;
  268. case DHCP_OPTION_SUBNET_MASK:
  269. dhcp->submask = BytesGetLe32(&in->Data[in->Pos + 2]);
  270. break;
  271. case DHCP_OPTION_ROUTER:
  272. dhcp->gateway = BytesGetLe32(&in->Data[in->Pos + 2]);
  273. break;
  274. case DHCP_OPTION_DNS_SERVER:
  275. {
  276. // 解析所有DNS,每4字节一个地址
  277. uint8_t count = len / 4;
  278. for (uint8_t i = 0; i < count && i < 2; i++)
  279. {
  280. uint32_t addr = BytesGetLe32(&in->Data[in->Pos + 2 + i * 4]);
  281. dhcp->dns_server[i] = addr;
  282. }
  283. for (uint8_t i = count; i < 2; i++) dhcp->dns_server[i] = 0;
  284. }
  285. break;
  286. case 58: // Renewal Time (T1)
  287. if (DHCP_ACK == ack && len == 4)
  288. {
  289. uint64_t t1 = BytesGetBe32(&in->Data[in->Pos + 2]);
  290. if (t1 < DHCP_MIN_LEASE_SEC) t1 = DHCP_MIN_LEASE_SEC;
  291. dhcp->lease_p1_time = luat_mcu_tick64_ms() + t1 * 1000;
  292. LLOGD("T1(Renew)=%llu sec", t1);
  293. }
  294. break;
  295. case 59: // Rebinding Time (T2)
  296. if (DHCP_ACK == ack && len == 4)
  297. {
  298. uint64_t t2 = BytesGetBe32(&in->Data[in->Pos + 2]);
  299. if (t2 < DHCP_MIN_LEASE_SEC) t2 = DHCP_MIN_LEASE_SEC;
  300. dhcp->lease_p2_time = luat_mcu_tick64_ms() + t2 * 1000;
  301. LLOGD("T2(Rebind)=%llu sec", t2);
  302. }
  303. break;
  304. default:
  305. //LLOGD("jump %d,%d", in->Data[in->Pos], in->Data[in->Pos+1]);
  306. break;
  307. }
  308. in->Pos += 2 + len;
  309. }
  310. return ack;
  311. }
  312. int ip4_dhcp_run(dhcp_client_info_t *dhcp, Buffer_Struct *in, Buffer_Struct *out, uint32_t *remote_ip)
  313. {
  314. uint16_t flag = 0x8000;
  315. *remote_ip = 0xffffffff;
  316. int result = 0;
  317. uint64_t tnow = luat_mcu_tick64_ms();
  318. LLOGD("dhcp state %d tnow %lld p1 %lld p2 %lld", dhcp->state, tnow, dhcp->lease_p1_time, dhcp->lease_p2_time);
  319. if (in)
  320. {
  321. result = analyze_ip4_dhcp(dhcp, in);
  322. LLOGD("result %d", result);
  323. if (result > 0)
  324. {
  325. if (result == DHCP_NAK)
  326. {
  327. dhcp->state = DHCP_STATE_DISCOVER;
  328. dhcp->temp_ip = 0;
  329. dhcp->server_ip = 0;
  330. dhcp->submask = 0;
  331. dhcp->gateway = 0;
  332. dhcp->ip = 0;
  333. dhcp->last_tx_time = 0;
  334. dhcp->lease_p1_time = 0;
  335. dhcp->lease_p2_time = 0;
  336. dhcp->weak_temp_ip = 0;
  337. dhcp->weak_server_ip = 0;
  338. }
  339. }
  340. else
  341. {
  342. return -1;
  343. }
  344. }
  345. // LLOGD("%d,%d", dhcp->state, result);
  346. switch(dhcp->state)
  347. {
  348. case DHCP_STATE_WAIT_LEASE_P1:
  349. if (tnow >= dhcp->lease_p1_time)
  350. {
  351. flag = 0;
  352. *remote_ip = dhcp->server_ip;
  353. dhcp->state = DHCP_STATE_WAIT_LEASE_P1_ACK;
  354. goto DHCP_NEED_REQUIRE;
  355. }
  356. break;
  357. case DHCP_STATE_WAIT_LEASE_P1_ACK:
  358. if (in && (result == DHCP_ACK))
  359. {
  360. LLOGD("lease p1 renew ip ok");
  361. dhcp->state = DHCP_STATE_WAIT_LEASE_P1;
  362. break;
  363. }
  364. if (tnow >= (dhcp->last_tx_time + DHCP_RENEW_TIMEOUT_MS))
  365. {
  366. LLOGD("lease p1 renew timeout, enter rebind phase");
  367. dhcp->state = DHCP_STATE_WAIT_LEASE_P2;
  368. }
  369. break;
  370. case DHCP_STATE_WAIT_LEASE_P2:
  371. if (tnow >= dhcp->lease_p2_time)
  372. {
  373. LLOGD("lease p2 rebind time reached, broadcast request");
  374. // Rebind阶段使用广播,不指定server_ip
  375. flag = 0x8000;
  376. *remote_ip = 0xffffffff;
  377. dhcp->state = DHCP_STATE_WAIT_LEASE_P2_ACK;
  378. goto DHCP_NEED_REQUIRE;
  379. }
  380. break;
  381. case DHCP_STATE_WAIT_LEASE_P2_ACK:
  382. if (in && (result == DHCP_ACK))
  383. {
  384. LLOGD("lease p2 rebind ip ok");
  385. dhcp->state = DHCP_STATE_WAIT_LEASE_P1;
  386. break;
  387. }
  388. if (tnow >= (dhcp->last_tx_time + DHCP_REBIND_TIMEOUT_MS))
  389. {
  390. LLOGD("lease p2 rebind timeout, wait for lease expiry");
  391. dhcp->state = DHCP_STATE_WAIT_LEASE_END;
  392. }
  393. break;
  394. case DHCP_STATE_WAIT_LEASE_END:
  395. if (tnow >= dhcp->lease_end_time)
  396. {
  397. LLOGD("lease expired, restart from discover");
  398. dhcp->state = DHCP_STATE_DISCOVER;
  399. dhcp->temp_ip = 0;
  400. dhcp->server_ip = 0;
  401. dhcp->ip = 0;
  402. dhcp->last_tx_time = 0;
  403. dhcp->discover_cnt = 0;
  404. // 下一轮循环会触发DISCOVER
  405. }
  406. break;
  407. // case DHCP_STATE_WAIT_REQUIRE_ACK:
  408. // if (in && (result == DHCP_ACK))
  409. // {
  410. // LLOGD("require ip ok");
  411. // dhcp->state = DHCP_STATE_WAIT_LEASE_P1;
  412. // break;
  413. // }
  414. // if (luat_mcu_tick64_ms() >= (dhcp->last_tx_time + 2500))
  415. // {
  416. // LLOGD("require ip long time no ack");
  417. // OS_ReInitBuffer(out, 512);
  418. // make_ip4_dhcp_discover_msg(dhcp, out);
  419. // dhcp->last_tx_time = luat_mcu_tick64_ms();
  420. // dhcp->discover_cnt = 0;
  421. // dhcp->state = DHCP_STATE_WAIT_OFFER;
  422. // }
  423. // break;
  424. case DHCP_STATE_DISCOVER:
  425. LLOGD("dhcp discover %02X%02X%02X%02X%02X%02X", (uint8_t)dhcp->mac[0], (uint8_t)dhcp->mac[1], (uint8_t)dhcp->mac[2], (uint8_t)dhcp->mac[3], (uint8_t)dhcp->mac[4], (uint8_t)dhcp->mac[5]);
  426. OS_ReInitBuffer(out, 512);
  427. make_ip4_dhcp_discover_msg(dhcp, out);
  428. dhcp->last_tx_time = luat_mcu_tick64_ms();
  429. dhcp->state = DHCP_STATE_WAIT_OFFER;
  430. break;
  431. case DHCP_STATE_WAIT_OFFER:
  432. if (in && (result == DHCP_OFFER))
  433. {
  434. LLOGD("got offer, send request");
  435. dhcp->state = DHCP_STATE_WAIT_SELECT_ACK;
  436. dhcp->wait_selec_ack_cnt = 0;
  437. goto DHCP_NEED_REQUIRE;
  438. }
  439. // 指数退避:1s, 2s, 4s, 8s...
  440. {
  441. uint32_t backoff = DHCP_RETRY_BASE_MS << dhcp->discover_cnt;
  442. if (backoff > DHCP_RETRY_MAX_MS) backoff = DHCP_RETRY_MAX_MS;
  443. if (tnow >= (dhcp->last_tx_time + backoff))
  444. {
  445. LLOGD("no offer after %ums, resend discover (retry %d)", backoff, dhcp->discover_cnt);
  446. dhcp->discover_cnt++;
  447. OS_ReInitBuffer(out, 512);
  448. make_ip4_dhcp_discover_msg(dhcp, out);
  449. dhcp->last_tx_time = luat_mcu_tick64_ms();
  450. }
  451. }
  452. break;
  453. case DHCP_STATE_WAIT_SELECT_ACK:
  454. if (in && (result == DHCP_ACK))
  455. {
  456. dhcp->ip = dhcp->temp_ip;
  457. dhcp->state = DHCP_STATE_CHECK;
  458. dhcp->weak_temp_ip = 0;
  459. dhcp->weak_server_ip = 0;
  460. LLOGD("DHCP acquired IP %d.%d.%d.%d",
  461. (dhcp->ip) & 0xFF, (dhcp->ip >> 8) & 0xFF,
  462. (dhcp->ip >> 16) & 0xFF, (dhcp->ip >> 24) & 0xFF);
  463. break;
  464. }
  465. if (dhcp->wait_selec_ack_cnt >= DHCP_MAX_SELECT_RETRIES)
  466. {
  467. LLOGD("select request timeout after %d retries", dhcp->wait_selec_ack_cnt);
  468. if ((dhcp->weak_temp_ip == dhcp->temp_ip) && (dhcp->weak_server_ip == dhcp->server_ip))
  469. {
  470. LLOGW("same offer repeated, assume server issue, accept IP");
  471. dhcp->ip = dhcp->temp_ip;
  472. dhcp->state = DHCP_STATE_CHECK;
  473. dhcp->weak_temp_ip = 0;
  474. dhcp->weak_server_ip = 0;
  475. break;
  476. }
  477. else
  478. {
  479. dhcp->weak_temp_ip = dhcp->temp_ip;
  480. dhcp->weak_server_ip = dhcp->server_ip;
  481. }
  482. // 重新DISCOVER
  483. OS_ReInitBuffer(out, 512);
  484. make_ip4_dhcp_discover_msg(dhcp, out);
  485. dhcp->last_tx_time = luat_mcu_tick64_ms();
  486. dhcp->discover_cnt = 0;
  487. dhcp->state = DHCP_STATE_WAIT_OFFER;
  488. }
  489. else
  490. {
  491. if (tnow >= (dhcp->last_tx_time + DHCP_SELECT_ACK_TIMEOUT_MS * (dhcp->wait_selec_ack_cnt + 1)))
  492. {
  493. dhcp->wait_selec_ack_cnt++;
  494. LLOGD("select request no ack, retry %d", dhcp->wait_selec_ack_cnt);
  495. goto DHCP_NEED_REQUIRE;
  496. }
  497. }
  498. break;
  499. case DHCP_STATE_REQUIRE:
  500. case DHCP_STATE_SELECT:
  501. dhcp->state = DHCP_STATE_WAIT_SELECT_ACK;
  502. goto DHCP_NEED_REQUIRE;
  503. break;
  504. case DHCP_STATE_CHECK:
  505. break;
  506. case DHCP_STATE_DECLINE:
  507. dhcp->weak_temp_ip = 0;
  508. dhcp->weak_server_ip = 0;
  509. flag = 0;
  510. *remote_ip = dhcp->server_ip;
  511. OS_ReInitBuffer(out, 512);
  512. make_ip4_dhcp_decline_msg(dhcp, out);
  513. dhcp->last_tx_time = luat_mcu_tick64_ms();
  514. dhcp->state = DHCP_STATE_DISCOVER;
  515. break;
  516. case DHCP_STATE_NOT_WORK:
  517. break;
  518. }
  519. return 0;
  520. DHCP_NEED_REQUIRE:
  521. OS_ReInitBuffer(out, 512);
  522. make_ip4_dhcp_select_msg(dhcp, flag, out);
  523. dhcp->last_tx_time = luat_mcu_tick64_ms();
  524. return 0;
  525. }
  526. #endif