wizchip_dhcp.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. #include "wizchip_socket.h"
  2. #include "wizchip_dhcp.h"
  3. #define DBG_ENABLE
  4. #define DBG_SECTION_NAME "dhcp"
  5. #define DBG_LEVEL DBG_WARNING
  6. #define DBG_COLOR
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include "RyanW5500Store.h"
  10. /*DHCP 状态机。*/
  11. typedef enum
  12. {
  13. STATE_DHCP_INIT = 0, // 初始化
  14. STATE_DHCP_DISCOVER = 1, // 发送 DISCOVER 并等待 OFFER
  15. STATE_DHCP_REQUEST = 2, // 发送请求并等待 ACK 或 NACK
  16. STATE_DHCP_LEASED = 3, // 接收D ACK和IP租用
  17. STATE_DHCP_REREQUEST = 4, // 发送维护租用 IP 的请求
  18. STATE_DHCP_RELEASE = 5, // 没用
  19. STATE_DHCP_STOP = 6, // 停止处理 DHCP
  20. } wizchipDhcpState_e;
  21. #define DHCP_FLAGSBROADCAST 0x8000 //@ref RIP_MSG 中标志的广播值
  22. #define DHCP_FLAGSUNICAST 0x0000 //@ref RIP_MSG 中标志的单播值
  23. /*DHCP 消息 OP 代码*/
  24. #define DHCP_BOOTREQUEST 1 // 在@ref RIP_MSG 的操作中使用的请求消息
  25. #define DHCP_BOOTREPLY 2 // 回复消息使用了@ref RIP_MSG 的 i op
  26. /*DHCP 消息类型*/
  27. #define DHCP_DISCOVER 1 // 在@ref RIP_MSG 的 OPT 中发现消息
  28. #define DHCP_OFFER 2 //@ref RIP_MSG 的 OPT 中的 OFFER 消息
  29. #define DHCP_REQUEST 3 //@ref RIP_MSG 的 OPT 中的请求消息
  30. #define DHCP_DECLINE 4 //@ref RIP_MSG 的 OPT 中的 DECLINE 消息
  31. #define DHCP_ACK 5 //@ref RIP_MSG 的 OPT 中的 ACK 消息
  32. #define DHCP_NAK 6 //@ref RIP_MSG 的 OPT 中的 NACK 消息
  33. #define DHCP_RELEASE 7 // 在@ref RIP_MSG 的 OPT 中释放消息。没用
  34. #define DHCP_INFORM 8 //@ref RIP_MSG 的 OPT 中的 INFORM 消息。没用
  35. #define DHCP_HTYPE10MB 1 // 用于@ref RIP_MSG 类型
  36. #define DHCP_HTYPE100MB 2 // 用于@ref RIP_MSG 类型
  37. #define DHCP_HLENETHERNET 6 // 在@ref RIP_MSG 的 hlen 中使用
  38. #define DHCP_HOPS 0 // 在@ref RIP_MSG 的跃点中使用
  39. #define DHCP_SECS 0 // 在 @ref RIP_MSG 的秒中使用
  40. #define INFINITE_LEASETIME 0xffffffff // 无限租用时间
  41. #define OPT_SIZE 312 ///@ref RIP_MSG 的最大 OPT 大小
  42. #define RIP_MSG_SIZE (236 + OPT_SIZE) ///@ref RIP_MSG 的最大大小
  43. /**
  44. *@brief DHCP 选项和值(参见 RFC1533)
  45. *
  46. */
  47. enum
  48. {
  49. padOption = 0,
  50. subnetMask = 1,
  51. timerOffset = 2,
  52. routersOnSubnet = 3,
  53. timeServer = 4,
  54. nameServer = 5,
  55. dns = 6,
  56. logServer = 7,
  57. cookieServer = 8,
  58. lprServer = 9,
  59. impressServer = 10,
  60. resourceLocationServer = 11,
  61. hostName = 12,
  62. bootFileSize = 13,
  63. meritDumpFile = 14,
  64. domainName = 15,
  65. swapServer = 16,
  66. rootPath = 17,
  67. extentionsPath = 18,
  68. IPforwarding = 19,
  69. nonLocalSourceRouting = 20,
  70. policyFilter = 21,
  71. maxDgramReasmSize = 22,
  72. defaultIPTTL = 23,
  73. pathMTUagingTimeout = 24,
  74. pathMTUplateauTable = 25,
  75. ifMTU = 26,
  76. allSubnetsLocal = 27,
  77. broadcastAddr = 28,
  78. performMaskDiscovery = 29,
  79. maskSupplier = 30,
  80. performRouterDiscovery = 31,
  81. routerSolicitationAddr = 32,
  82. staticRoute = 33,
  83. trailerEncapsulation = 34,
  84. arpCacheTimeout = 35,
  85. ethernetEncapsulation = 36,
  86. tcpDefaultTTL = 37,
  87. tcpKeepaliveInterval = 38,
  88. tcpKeepaliveGarbage = 39,
  89. nisDomainName = 40,
  90. nisServers = 41,
  91. ntpServers = 42,
  92. vendorSpecificInfo = 43,
  93. netBIOSnameServer = 44,
  94. netBIOSdgramDistServer = 45,
  95. netBIOSnodeType = 46,
  96. netBIOSscope = 47,
  97. xFontServer = 48,
  98. xDisplayManager = 49,
  99. dhcpRequestedIPaddr = 50,
  100. dhcpIPaddrLeaseTime = 51,
  101. dhcpOptionOverload = 52,
  102. dhcpMessageType = 53,
  103. dhcpServerIdentifier = 54,
  104. dhcpParamRequest = 55,
  105. dhcpMsg = 56,
  106. dhcpMaxMsgSize = 57,
  107. dhcpT1value = 58,
  108. dhcpT2value = 59,
  109. dhcpClassIdentifier = 60,
  110. dhcpClientIdentifier = 61,
  111. endOption = 255
  112. };
  113. /**
  114. *@brief DHCP消息格式
  115. */
  116. typedef struct
  117. {
  118. uint8_t op; //@ref DHCP_BOOTREQUEST 或 @ref DHCP_BOOTREPLY
  119. uint8_t htype; //@ref DHCP_HTYPE10MB 或 @ref DHCP_HTYPE100MB
  120. uint8_t hlen; //@ref DHCP_HLENETHERNET
  121. uint8_t hops; //@ref DHCP_HOPS
  122. uint32_t xid; //@ref DHCP_XID 这会在每个 DHCP 事务中增加一个。
  123. uint16_t secs; //@ref DHCP_SECS
  124. uint16_t flags; //@ref DHCP_FLAGSBROADCAST 或 @ref DHCP_FLAGSUNICAST
  125. uint8_t ciaddr[4]; //@ref 向 DHCP 服务器请求 IP
  126. uint8_t yiaddr[4]; //@ref 从 DHCP 服务器提供的 IP
  127. uint8_t siaddr[4]; // 没用
  128. uint8_t giaddr[4]; // 没用
  129. uint8_t chaddr[16]; // DHCP 客户端 6 字节 MAC 地址。其他填充为零
  130. uint8_t sname[64]; // 没用
  131. uint8_t file[128]; // 没用
  132. uint8_t OPT[OPT_SIZE]; // 选项
  133. } RIP_MSG;
  134. uint8_t DHCP_SOCKET; // DHCP 的套接字号
  135. uint8_t DHCP_SIP[4]; // DHCP 服务器 IP 地址
  136. uint8_t DHCP_REAL_SIP[4]; // 用于在几个 DHCP 服务器中提取我的 DHCP 服务器
  137. // 来自 DHCP 服务器的网络信息
  138. uint8_t OLD_allocated_ip[4] = {0}; // 以前的 IP 地址
  139. wizchipDhcpState_e dhcp_state = STATE_DHCP_INIT; // DHCP 状态
  140. // INFINITE_LEASETIME
  141. platformTimer_t dhcp_lease_time = {0};
  142. uint32_t DHCP_XID; // 任何数字
  143. RIP_MSG *pDHCPMSG; // DHCP 处理的缓冲区指针
  144. uint8_t HOST_NAME[] = DCHP_HOST_NAME;
  145. char NibbleToHex(uint8_t nibble)
  146. {
  147. nibble &= 0x0F;
  148. if (nibble <= 9)
  149. return nibble + '0';
  150. else
  151. return nibble + ('A' - 0x0A);
  152. }
  153. /**
  154. *@brief 生成通用dhcp消息
  155. *
  156. */
  157. void makeDHCPMSG(void)
  158. {
  159. uint8_t bk_mac[6];
  160. uint8_t *ptmp;
  161. uint8_t i;
  162. getSHAR(bk_mac);
  163. pDHCPMSG->op = DHCP_BOOTREQUEST;
  164. pDHCPMSG->htype = DHCP_HTYPE10MB;
  165. pDHCPMSG->hlen = DHCP_HLENETHERNET;
  166. pDHCPMSG->hops = DHCP_HOPS;
  167. ptmp = (uint8_t *)(&pDHCPMSG->xid);
  168. *(ptmp + 0) = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
  169. *(ptmp + 1) = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
  170. *(ptmp + 2) = (uint8_t)((DHCP_XID & 0x0000FF00) >> 8);
  171. *(ptmp + 3) = (uint8_t)((DHCP_XID & 0x000000FF) >> 0);
  172. pDHCPMSG->secs = DHCP_SECS;
  173. ptmp = (uint8_t *)(&pDHCPMSG->flags);
  174. *(ptmp + 0) = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
  175. *(ptmp + 1) = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);
  176. memset(pDHCPMSG->ciaddr, 0, 4);
  177. memset(pDHCPMSG->yiaddr, 0, 4);
  178. memset(pDHCPMSG->siaddr, 0, 4);
  179. memset(pDHCPMSG->giaddr, 0, 4);
  180. memcpy(pDHCPMSG->chaddr, gWIZNETINFO.mac, 6);
  181. for (i = 6; i < 16; i++)
  182. pDHCPMSG->chaddr[i] = 0;
  183. for (i = 0; i < 64; i++)
  184. pDHCPMSG->sname[i] = 0;
  185. for (i = 0; i < 128; i++)
  186. pDHCPMSG->file[i] = 0;
  187. // 魔法饼干
  188. pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
  189. pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
  190. pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >> 8);
  191. pDHCPMSG->OPT[3] = (uint8_t)(MAGIC_COOKIE & 0x000000FF) >> 0;
  192. }
  193. /*SEND DHCP DISCOVER*/
  194. /**
  195. *@brief 发送dhcp discover消息
  196. *
  197. */
  198. void send_DHCP_DISCOVER(void)
  199. {
  200. uint16_t i;
  201. uint8_t ip[4] = {255, 255, 255, 255};
  202. uint16_t k = 0;
  203. makeDHCPMSG();
  204. memset(DHCP_SIP, 0, 4);
  205. memset(DHCP_REAL_SIP, 0, 4);
  206. k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
  207. // 选项请求参数
  208. pDHCPMSG->OPT[k++] = dhcpMessageType;
  209. pDHCPMSG->OPT[k++] = 0x01;
  210. pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
  211. // 客户端标识符
  212. pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
  213. pDHCPMSG->OPT[k++] = 0x07;
  214. pDHCPMSG->OPT[k++] = 0x01;
  215. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
  216. k += 6;
  217. // 主机名
  218. pDHCPMSG->OPT[k++] = hostName;
  219. pDHCPMSG->OPT[k++] = 0; // 填充零长度的主机名
  220. for (i = 0; HOST_NAME[i] != 0; i++)
  221. pDHCPMSG->OPT[k++] = HOST_NAME[i];
  222. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3] >> 4);
  223. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3]);
  224. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4] >> 4);
  225. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4]);
  226. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5] >> 4);
  227. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5]);
  228. pDHCPMSG->OPT[k - (i + 6 + 1)] = i + 6; // 主机名长度
  229. pDHCPMSG->OPT[k++] = dhcpParamRequest;
  230. pDHCPMSG->OPT[k++] = 0x06; // 请求长度
  231. pDHCPMSG->OPT[k++] = subnetMask;
  232. pDHCPMSG->OPT[k++] = routersOnSubnet;
  233. pDHCPMSG->OPT[k++] = dns;
  234. pDHCPMSG->OPT[k++] = domainName;
  235. pDHCPMSG->OPT[k++] = dhcpT1value;
  236. pDHCPMSG->OPT[k++] = dhcpT2value;
  237. pDHCPMSG->OPT[k++] = endOption;
  238. for (i = k; i < OPT_SIZE; i++)
  239. pDHCPMSG->OPT[i] = 0;
  240. LOG_D("> Send DHCP_DISCOVER");
  241. // 广播发送
  242. wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
  243. }
  244. /**
  245. *@brief 发送请求地址租用 request报文
  246. *
  247. */
  248. void send_DHCP_REQUEST(void)
  249. {
  250. int i;
  251. uint16_t k = 0;
  252. uint8_t ip[4] = {255, 255, 255, 255};
  253. makeDHCPMSG();
  254. if (dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
  255. {
  256. *((uint8_t *)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00) >> 8);
  257. *((uint8_t *)(&pDHCPMSG->flags) + 1) = (DHCP_FLAGSUNICAST & 0x00FF);
  258. memcpy(pDHCPMSG->ciaddr, gWIZNETINFO.ip, 4);
  259. memcpy(ip, DHCP_SIP, 4);
  260. }
  261. k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
  262. // 选项请求参数。
  263. pDHCPMSG->OPT[k++] = dhcpMessageType;
  264. pDHCPMSG->OPT[k++] = 0x01;
  265. pDHCPMSG->OPT[k++] = DHCP_REQUEST;
  266. pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
  267. pDHCPMSG->OPT[k++] = 0x07;
  268. pDHCPMSG->OPT[k++] = 0x01;
  269. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
  270. k += 6;
  271. if (ip[3] == 255) // 如果(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
  272. {
  273. pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
  274. pDHCPMSG->OPT[k++] = 0x04;
  275. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.ip, 4);
  276. k += 4;
  277. pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
  278. pDHCPMSG->OPT[k++] = 0x04;
  279. memcpy(pDHCPMSG->OPT + k, DHCP_SIP, 4);
  280. k += 4;
  281. }
  282. // 主机名
  283. pDHCPMSG->OPT[k++] = hostName;
  284. pDHCPMSG->OPT[k++] = 0; // 主机名长度
  285. for (i = 0; HOST_NAME[i] != 0; i++)
  286. pDHCPMSG->OPT[k++] = HOST_NAME[i];
  287. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3] >> 4);
  288. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3]);
  289. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4] >> 4);
  290. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4]);
  291. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5] >> 4);
  292. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5]);
  293. pDHCPMSG->OPT[k - (i + 6 + 1)] = i + 6; // 主机名长度
  294. pDHCPMSG->OPT[k++] = dhcpParamRequest;
  295. pDHCPMSG->OPT[k++] = 0x08;
  296. pDHCPMSG->OPT[k++] = subnetMask;
  297. pDHCPMSG->OPT[k++] = routersOnSubnet;
  298. pDHCPMSG->OPT[k++] = dns;
  299. pDHCPMSG->OPT[k++] = domainName;
  300. pDHCPMSG->OPT[k++] = dhcpT1value;
  301. pDHCPMSG->OPT[k++] = dhcpT2value;
  302. pDHCPMSG->OPT[k++] = performRouterDiscovery;
  303. pDHCPMSG->OPT[k++] = staticRoute;
  304. pDHCPMSG->OPT[k++] = endOption;
  305. for (i = k; i < OPT_SIZE; i++)
  306. pDHCPMSG->OPT[i] = 0;
  307. LOG_D("> Send DHCP_REQUEST");
  308. wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
  309. }
  310. /*发送 DHCP DHCPDECLINE*/
  311. void send_DHCP_DECLINE(void)
  312. {
  313. int i;
  314. uint8_t ip[4];
  315. uint16_t k = 0;
  316. makeDHCPMSG();
  317. k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
  318. *((uint8_t *)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00) >> 8);
  319. *((uint8_t *)(&pDHCPMSG->flags) + 1) = (DHCP_FLAGSUNICAST & 0x00FF);
  320. // 选项请求参数。
  321. pDHCPMSG->OPT[k++] = dhcpMessageType;
  322. pDHCPMSG->OPT[k++] = 0x01;
  323. pDHCPMSG->OPT[k++] = DHCP_DECLINE;
  324. pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
  325. pDHCPMSG->OPT[k++] = 0x07;
  326. pDHCPMSG->OPT[k++] = 0x01;
  327. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
  328. k += 6;
  329. pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
  330. pDHCPMSG->OPT[k++] = 0x04;
  331. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.ip, 4);
  332. k += 4;
  333. pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
  334. pDHCPMSG->OPT[k++] = 0x04;
  335. memcpy(pDHCPMSG->OPT + k, DHCP_SIP, 4);
  336. k += 4;
  337. pDHCPMSG->OPT[k++] = endOption;
  338. for (i = k; i < OPT_SIZE; i++)
  339. pDHCPMSG->OPT[i] = 0;
  340. // 发送广播包
  341. memset(ip, 0xFF, 4);
  342. LOG_D("> Send DHCP_DECLINE");
  343. wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
  344. }
  345. /**
  346. *@brief 解析回复的dhcp报文
  347. *
  348. *@return int8_t
  349. */
  350. int8_t parseDHCPMSG(void)
  351. {
  352. uint8_t svr_addr[6];
  353. uint16_t svr_port;
  354. uint16_t len;
  355. uint8_t *p;
  356. uint8_t *e;
  357. uint8_t type = 0;
  358. uint8_t opt_len;
  359. len = getSn_RX_RSR(DHCP_SOCKET);
  360. if (len <= 0)
  361. return 0;
  362. len = wizchip_recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);
  363. LOG_D("DHCP message : %d.%d.%d.%d(%d) %d received. ", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3], svr_port, len);
  364. if (DHCP_SERVER_PORT != svr_port)
  365. return 0;
  366. // 校验mac地址
  367. if (0 != memcmp(gWIZNETINFO.mac, pDHCPMSG->chaddr, sizeof(gWIZNETINFO.mac)))
  368. {
  369. LOG_D("No My DHCP Message. This message is ignored.");
  370. return 0;
  371. }
  372. // 比较 DHCP 服务器 ip 地址
  373. if ((DHCP_SIP[0] != 0) || (DHCP_SIP[1] != 0) || (DHCP_SIP[2] != 0) || (DHCP_SIP[3] != 0))
  374. {
  375. if (0 != memcmp(DHCP_SIP, svr_addr, sizeof(DHCP_SIP)) &&
  376. 0 != memcmp(DHCP_REAL_SIP, svr_addr, sizeof(DHCP_REAL_SIP)))
  377. {
  378. LOG_D("Another DHCP sever send a response message. This is ignored.");
  379. return 0;
  380. }
  381. }
  382. p = (uint8_t *)(&pDHCPMSG->op);
  383. p = p + 240; // 240 = sizeof(RIP_MSG) + RIP_MSG.opt 中的 MAGIC_COOKIE 大小 -sizeof(RIP_MSG.opt)
  384. e = p + (len - 240);
  385. while (p < e)
  386. {
  387. switch (*p)
  388. {
  389. case endOption:
  390. p = e; // 中断 while(p < e)
  391. break;
  392. case padOption:
  393. p++;
  394. break;
  395. case dhcpMessageType:
  396. p++;
  397. p++;
  398. type = *p++;
  399. break;
  400. case subnetMask:
  401. p++;
  402. p++;
  403. gWIZNETINFO.sn[0] = *p++;
  404. gWIZNETINFO.sn[1] = *p++;
  405. gWIZNETINFO.sn[2] = *p++;
  406. gWIZNETINFO.sn[3] = *p++;
  407. break;
  408. case routersOnSubnet:
  409. p++;
  410. opt_len = *p++;
  411. gWIZNETINFO.gw[0] = *p++;
  412. gWIZNETINFO.gw[1] = *p++;
  413. gWIZNETINFO.gw[2] = *p++;
  414. gWIZNETINFO.gw[3] = *p++;
  415. p = p + (opt_len - 4);
  416. break;
  417. case dns:
  418. p++;
  419. opt_len = *p++;
  420. gWIZNETINFO.dns[0] = *p++;
  421. gWIZNETINFO.dns[1] = *p++;
  422. gWIZNETINFO.dns[2] = *p++;
  423. gWIZNETINFO.dns[3] = *p++;
  424. p = p + (opt_len - 4);
  425. break;
  426. case dhcpIPaddrLeaseTime:
  427. p++;
  428. opt_len = *p++;
  429. uint32_t dhcpLeaseTime = 0;
  430. dhcpLeaseTime = *p++;
  431. dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
  432. dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
  433. dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
  434. platformTimerCutdown(&dhcp_lease_time, dhcpLeaseTime * 1000);
  435. break;
  436. case dhcpServerIdentifier:
  437. p++;
  438. opt_len = *p++;
  439. DHCP_SIP[0] = *p++;
  440. DHCP_SIP[1] = *p++;
  441. DHCP_SIP[2] = *p++;
  442. DHCP_SIP[3] = *p++;
  443. memcpy(DHCP_REAL_SIP, svr_addr, 4);
  444. break;
  445. default:
  446. p++;
  447. opt_len = *p++;
  448. p += opt_len;
  449. break;
  450. } // 转变
  451. } // 尽管
  452. return type;
  453. }
  454. /**
  455. *@简短的
  456. *
  457. *@return int8_t
  458. */
  459. int8_t check_DHCP_leasedIP(void)
  460. {
  461. uint8_t tmp;
  462. int32_t ret;
  463. // WIZchip RCR 值更改为 ARP 超时计数控制
  464. tmp = getRCR();
  465. setRCR(0x03);
  466. // IP 冲突检测:ARP 请求 -ARP 回复
  467. // 使用 UDP wizchip_sendto() 函数广播 ARP 请求以检查 IP 冲突
  468. ret = wizchip_sendto(DHCP_SOCKET, (uint8_t *)"CHECK_IP_CONFLICT", 17, gWIZNETINFO.ip, 5000);
  469. // Rcr值恢复
  470. setRCR(tmp);
  471. if (ret == SOCKERR_TIMEOUT)
  472. {
  473. // UDP 发送超时发生:分配的 IP 地址是唯一的,DHCP 成功
  474. LOG_D("> Check leased IP - OK");
  475. return 1;
  476. }
  477. else
  478. {
  479. // 收到 ARP 回复等:发生 IP 地址冲突,DHCP 失败
  480. send_DHCP_DECLINE();
  481. // 等待 1s 结束;等待完成发送 DECLINE 消息;
  482. rt_thread_mdelay(1000);
  483. return 0;
  484. }
  485. }
  486. /**
  487. *@brief 主循环中的 DHCP 客户端
  488. *
  489. *@return uint8_t
  490. */
  491. uint8_t DHCP_run(uint8_t flag)
  492. {
  493. uint8_t type = 0;
  494. setSHAR(gWIZNETINFO.mac); // 设置w5500 mac
  495. RyanW5500Socket *sock = RyanW5500SocketCreate(Sn_MR_UDP, DHCP_CLIENT_PORT);
  496. if (NULL == sock)
  497. {
  498. LOG_W("dhcp socket失败");
  499. return -1;
  500. }
  501. uint8_t *dhcpDataBuf = (uint8_t *)rt_malloc(RIP_MSG_SIZE);
  502. DHCP_SOCKET = sock->socket; // SOCK_DHCP
  503. pDHCPMSG = (RIP_MSG *)dhcpDataBuf;
  504. if (1 != flag) // flag 1表示处于续租状态
  505. {
  506. // 生成唯一事务id
  507. DHCP_XID = 0x12345678;
  508. DHCP_XID += gWIZNETINFO.mac[3];
  509. DHCP_XID += gWIZNETINFO.mac[4];
  510. DHCP_XID += gWIZNETINFO.mac[5];
  511. DHCP_XID += (gWIZNETINFO.mac[3] ^ gWIZNETINFO.mac[4] ^ gWIZNETINFO.mac[5]);
  512. dhcp_state = STATE_DHCP_INIT;
  513. platformTimerInit(&dhcp_lease_time);
  514. }
  515. uint8_t dhcp_retry_count = 0;
  516. platformTimer_t recvTimer = {0};
  517. platformTimerCutdown(&recvTimer, DHCP_WAIT_TIME);
  518. while (1)
  519. {
  520. type = parseDHCPMSG();
  521. switch (dhcp_state)
  522. {
  523. case STATE_DHCP_INIT: // dhcp初始化状态
  524. memset(gWIZNETINFO.ip, 0, sizeof(gWIZNETINFO.ip));
  525. send_DHCP_DISCOVER(); // 客户端发送Discover报文
  526. dhcp_state = STATE_DHCP_DISCOVER;
  527. break;
  528. case STATE_DHCP_DISCOVER:
  529. if (DHCP_OFFER == type) // 服务器提供地址续约,offer报文
  530. {
  531. LOG_D("> Receive DHCP_OFFER");
  532. memcpy(gWIZNETINFO.ip, pDHCPMSG->yiaddr, sizeof(gWIZNETINFO.ip));
  533. send_DHCP_REQUEST(); // 发送请求地址租用 request报文
  534. dhcp_state = STATE_DHCP_REQUEST;
  535. }
  536. break;
  537. case STATE_DHCP_REQUEST: // 客户端选择并请求地址租用
  538. if (DHCP_NAK == type) // 服务器取消把地址租用给客户端
  539. {
  540. LOG_D("> Receive DHCP_NACK");
  541. dhcp_state = STATE_DHCP_DISCOVER;
  542. }
  543. else if (DHCP_ACK == type) // 服务器确认将地址租用给客户端 ack报文
  544. {
  545. LOG_D("> Receive DHCP_ACK");
  546. // 发生 IP 地址冲突
  547. dhcp_state = check_DHCP_leasedIP() ? STATE_DHCP_LEASED : STATE_DHCP_INIT;
  548. }
  549. break;
  550. case STATE_DHCP_LEASED: // 当租期超过50%(1/2)时,客户端会以单播形式向DHCP服务器发送DHCP Request报文来续租IP地址。
  551. if (dhcp_lease_time.timeOut != 0 && platformTimerRemain(&dhcp_lease_time) < (dhcp_lease_time.timeOut / 2))
  552. {
  553. LOG_D("> Maintains the IP address ");
  554. DHCP_XID++;
  555. send_DHCP_REQUEST();
  556. dhcp_state = STATE_DHCP_REREQUEST;
  557. }
  558. break;
  559. case STATE_DHCP_REREQUEST: // 如果收到DHCP服务器发送的DHCP ACK报文,则按相应时间延长IP地址租期。如果没有,还是保持使用该IP地址。
  560. if (type == DHCP_ACK)
  561. {
  562. // 不需要判断续租分配的新ip还是旧ip,都会写入到w5500寄存器里
  563. LOG_D("> Receive DHCP_ACK, Maintains the IP address");
  564. dhcp_state = STATE_DHCP_LEASED;
  565. }
  566. else if (type == DHCP_NAK)
  567. {
  568. LOG_D("> Receive DHCP_NACK, Failed to maintain ip");
  569. dhcp_state = STATE_DHCP_DISCOVER;
  570. }
  571. break;
  572. default:
  573. break;
  574. }
  575. if (STATE_DHCP_LEASED == dhcp_state)
  576. goto next;
  577. // 如果超时,根据现有状态进行报文重发尝试
  578. if (0 == platformTimerRemain(&recvTimer))
  579. {
  580. switch (dhcp_state)
  581. {
  582. case STATE_DHCP_DISCOVER:
  583. LOG_D("<<timeout>> state : STATE_DHCP_DISCOVER");
  584. send_DHCP_DISCOVER();
  585. break;
  586. case STATE_DHCP_REQUEST:
  587. LOG_D("<<timeout>> state : STATE_DHCP_REQUEST");
  588. send_DHCP_REQUEST();
  589. break;
  590. case STATE_DHCP_REREQUEST:
  591. LOG_D("<<timeout>> state : STATE_DHCP_REREQUEST");
  592. send_DHCP_REQUEST();
  593. break;
  594. default:
  595. break;
  596. }
  597. platformTimerCutdown(&recvTimer, DHCP_WAIT_TIME);
  598. dhcp_retry_count++;
  599. }
  600. if (dhcp_retry_count >= MAX_DHCP_RETRY)
  601. {
  602. wiz_closesocket(sock->socket);
  603. free(dhcpDataBuf);
  604. return -1;
  605. }
  606. delay(100);
  607. }
  608. next:
  609. wiz_closesocket(sock->socket);
  610. free(dhcpDataBuf);
  611. return 0;
  612. }
  613. /**
  614. *@brief 获取租用总时长 ms
  615. *
  616. *@return uint32_t
  617. */
  618. uint32_t getDHCPLeaseTime(void)
  619. {
  620. if (NETINFO_DHCP != gWIZNETINFO.dhcp)
  621. return 0;
  622. return dhcp_lease_time.timeOut;
  623. }
  624. uint32_t getDHCPRemainLeaseTime(void)
  625. {
  626. return platformTimerRemain(&dhcp_lease_time);
  627. }