wizchip_dhcp.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #define rlogEnable 1 // 是否使能日志
  2. #define rlogColorEnable 1 // 是否使能日志颜色
  3. #define rlogLevel (rlogLvlWarning) // 日志打印等级
  4. #define rlogTag "W5500Dhcp" // 日志tag
  5. #include "wizchip_socket.h"
  6. #include "wizchip_dhcp.h"
  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. uint8_t OLD_allocated_ip[4] = {0}; // 以前的 IP 地址
  138. wizchipDhcpState_e dhcp_state = STATE_DHCP_INIT; // DHCP 状态
  139. platformTimer_t dhcp_lease_time = {0}; // dhcp租期定时器
  140. uint32_t DHCP_XID; // 任何数字
  141. uint8_t *HOST_NAME = (uint8_t *)DCHP_HOST_NAME; // 主机名
  142. RIP_MSG *pDHCPMSG; // DHCP 处理的缓冲区指针
  143. char NibbleToHex(uint8_t nibble)
  144. {
  145. nibble &= 0x0F;
  146. if (nibble <= 9)
  147. return nibble + '0';
  148. else
  149. return nibble + ('A' - 0x0A);
  150. }
  151. /**
  152. *@brief 生成通用dhcp消息
  153. *
  154. */
  155. void makeDHCPMSG(void)
  156. {
  157. uint8_t bk_mac[6];
  158. uint8_t *ptmp;
  159. uint8_t i;
  160. getSHAR(bk_mac);
  161. pDHCPMSG->op = DHCP_BOOTREQUEST;
  162. pDHCPMSG->htype = DHCP_HTYPE10MB;
  163. pDHCPMSG->hlen = DHCP_HLENETHERNET;
  164. pDHCPMSG->hops = DHCP_HOPS;
  165. ptmp = (uint8_t *)(&pDHCPMSG->xid);
  166. *(ptmp + 0) = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
  167. *(ptmp + 1) = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
  168. *(ptmp + 2) = (uint8_t)((DHCP_XID & 0x0000FF00) >> 8);
  169. *(ptmp + 3) = (uint8_t)((DHCP_XID & 0x000000FF) >> 0);
  170. pDHCPMSG->secs = DHCP_SECS;
  171. ptmp = (uint8_t *)(&pDHCPMSG->flags);
  172. *(ptmp + 0) = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
  173. *(ptmp + 1) = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);
  174. memset(pDHCPMSG->ciaddr, 0, 4);
  175. memset(pDHCPMSG->yiaddr, 0, 4);
  176. memset(pDHCPMSG->siaddr, 0, 4);
  177. memset(pDHCPMSG->giaddr, 0, 4);
  178. memcpy(pDHCPMSG->chaddr, gWIZNETINFO.mac, 6);
  179. for (i = 6; i < 16; i++)
  180. pDHCPMSG->chaddr[i] = 0;
  181. for (i = 0; i < 64; i++)
  182. pDHCPMSG->sname[i] = 0;
  183. for (i = 0; i < 128; i++)
  184. pDHCPMSG->file[i] = 0;
  185. // 魔法饼干
  186. pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
  187. pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
  188. pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >> 8);
  189. pDHCPMSG->OPT[3] = (uint8_t)(MAGIC_COOKIE & 0x000000FF) >> 0;
  190. }
  191. /*SEND DHCP DISCOVER*/
  192. /**
  193. *@brief 发送dhcp discover消息
  194. *
  195. */
  196. void send_DHCP_DISCOVER(void)
  197. {
  198. uint16_t i;
  199. uint8_t ip[4] = {255, 255, 255, 255};
  200. uint16_t k = 0;
  201. makeDHCPMSG();
  202. memset(DHCP_SIP, 0, 4);
  203. memset(DHCP_REAL_SIP, 0, 4);
  204. k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
  205. // 选项请求参数
  206. pDHCPMSG->OPT[k++] = dhcpMessageType;
  207. pDHCPMSG->OPT[k++] = 0x01;
  208. pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
  209. // 客户端标识符
  210. pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
  211. pDHCPMSG->OPT[k++] = 0x07;
  212. pDHCPMSG->OPT[k++] = 0x01;
  213. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
  214. k += 6;
  215. // 主机名
  216. pDHCPMSG->OPT[k++] = hostName;
  217. pDHCPMSG->OPT[k++] = 0; // 填充零长度的主机名
  218. for (i = 0; HOST_NAME[i] != 0; i++)
  219. pDHCPMSG->OPT[k++] = HOST_NAME[i];
  220. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3] >> 4);
  221. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3]);
  222. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4] >> 4);
  223. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4]);
  224. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5] >> 4);
  225. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5]);
  226. pDHCPMSG->OPT[k - (i + 6 + 1)] = i + 6; // 主机名长度
  227. pDHCPMSG->OPT[k++] = dhcpParamRequest;
  228. pDHCPMSG->OPT[k++] = 0x06; // 请求长度
  229. pDHCPMSG->OPT[k++] = subnetMask;
  230. pDHCPMSG->OPT[k++] = routersOnSubnet;
  231. pDHCPMSG->OPT[k++] = dns;
  232. pDHCPMSG->OPT[k++] = domainName;
  233. pDHCPMSG->OPT[k++] = dhcpT1value;
  234. pDHCPMSG->OPT[k++] = dhcpT2value;
  235. pDHCPMSG->OPT[k++] = endOption;
  236. for (i = k; i < OPT_SIZE; i++)
  237. pDHCPMSG->OPT[i] = 0;
  238. rlog_d("> Send DHCP_DISCOVER");
  239. // 广播发送
  240. wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
  241. }
  242. /**
  243. *@brief 发送请求地址租用 request报文
  244. *
  245. */
  246. void send_DHCP_REQUEST(void)
  247. {
  248. int i;
  249. uint16_t k = 0;
  250. uint8_t ip[4] = {255, 255, 255, 255};
  251. makeDHCPMSG();
  252. if (dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
  253. {
  254. *((uint8_t *)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00) >> 8);
  255. *((uint8_t *)(&pDHCPMSG->flags) + 1) = (DHCP_FLAGSUNICAST & 0x00FF);
  256. memcpy(pDHCPMSG->ciaddr, gWIZNETINFO.ip, 4);
  257. memcpy(ip, DHCP_SIP, 4);
  258. }
  259. k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
  260. // 选项请求参数。
  261. pDHCPMSG->OPT[k++] = dhcpMessageType;
  262. pDHCPMSG->OPT[k++] = 0x01;
  263. pDHCPMSG->OPT[k++] = DHCP_REQUEST;
  264. pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
  265. pDHCPMSG->OPT[k++] = 0x07;
  266. pDHCPMSG->OPT[k++] = 0x01;
  267. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
  268. k += 6;
  269. if (ip[3] == 255) // 如果(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
  270. {
  271. pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
  272. pDHCPMSG->OPT[k++] = 0x04;
  273. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.ip, 4);
  274. k += 4;
  275. pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
  276. pDHCPMSG->OPT[k++] = 0x04;
  277. memcpy(pDHCPMSG->OPT + k, DHCP_SIP, 4);
  278. k += 4;
  279. }
  280. // 主机名
  281. pDHCPMSG->OPT[k++] = hostName;
  282. pDHCPMSG->OPT[k++] = 0; // 主机名长度
  283. for (i = 0; HOST_NAME[i] != 0; i++)
  284. pDHCPMSG->OPT[k++] = HOST_NAME[i];
  285. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3] >> 4);
  286. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[3]);
  287. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4] >> 4);
  288. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[4]);
  289. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5] >> 4);
  290. pDHCPMSG->OPT[k++] = NibbleToHex(gWIZNETINFO.mac[5]);
  291. pDHCPMSG->OPT[k - (i + 6 + 1)] = i + 6; // 主机名长度
  292. pDHCPMSG->OPT[k++] = dhcpParamRequest;
  293. pDHCPMSG->OPT[k++] = 0x08;
  294. pDHCPMSG->OPT[k++] = subnetMask;
  295. pDHCPMSG->OPT[k++] = routersOnSubnet;
  296. pDHCPMSG->OPT[k++] = dns;
  297. pDHCPMSG->OPT[k++] = domainName;
  298. pDHCPMSG->OPT[k++] = dhcpT1value;
  299. pDHCPMSG->OPT[k++] = dhcpT2value;
  300. pDHCPMSG->OPT[k++] = performRouterDiscovery;
  301. pDHCPMSG->OPT[k++] = staticRoute;
  302. pDHCPMSG->OPT[k++] = endOption;
  303. for (i = k; i < OPT_SIZE; i++)
  304. pDHCPMSG->OPT[i] = 0;
  305. rlog_d("> Send DHCP_REQUEST");
  306. wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
  307. }
  308. /*发送 DHCP DHCPDECLINE*/
  309. void send_DHCP_DECLINE(void)
  310. {
  311. int i;
  312. uint8_t ip[4];
  313. uint16_t k = 0;
  314. makeDHCPMSG();
  315. k = 4; // 因为 MAGIC_COOKIE 已经由 makeDHCPMSG() 生成
  316. *((uint8_t *)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00) >> 8);
  317. *((uint8_t *)(&pDHCPMSG->flags) + 1) = (DHCP_FLAGSUNICAST & 0x00FF);
  318. // 选项请求参数。
  319. pDHCPMSG->OPT[k++] = dhcpMessageType;
  320. pDHCPMSG->OPT[k++] = 0x01;
  321. pDHCPMSG->OPT[k++] = DHCP_DECLINE;
  322. pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
  323. pDHCPMSG->OPT[k++] = 0x07;
  324. pDHCPMSG->OPT[k++] = 0x01;
  325. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.mac, 6);
  326. k += 6;
  327. pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
  328. pDHCPMSG->OPT[k++] = 0x04;
  329. memcpy(pDHCPMSG->OPT + k, gWIZNETINFO.ip, 4);
  330. k += 4;
  331. pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
  332. pDHCPMSG->OPT[k++] = 0x04;
  333. memcpy(pDHCPMSG->OPT + k, DHCP_SIP, 4);
  334. k += 4;
  335. pDHCPMSG->OPT[k++] = endOption;
  336. for (i = k; i < OPT_SIZE; i++)
  337. pDHCPMSG->OPT[i] = 0;
  338. // 发送广播包
  339. memset(ip, 0xFF, 4);
  340. rlog_d("> Send DHCP_DECLINE");
  341. wizchip_sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
  342. }
  343. /**
  344. *@brief 解析回复的dhcp报文
  345. *
  346. *@return int8_t
  347. */
  348. int8_t parseDHCPMSG(void)
  349. {
  350. uint8_t svr_addr[6];
  351. uint16_t svr_port;
  352. uint16_t len;
  353. uint8_t *p;
  354. uint8_t *e;
  355. uint8_t type = 0;
  356. uint8_t opt_len;
  357. len = getSn_RX_RSR(DHCP_SOCKET);
  358. if (len <= 0)
  359. return 0;
  360. len = wizchip_recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);
  361. rlog_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);
  362. if (DHCP_SERVER_PORT != svr_port)
  363. return 0;
  364. // 校验mac地址
  365. if (0 != memcmp(gWIZNETINFO.mac, pDHCPMSG->chaddr, sizeof(gWIZNETINFO.mac)))
  366. {
  367. rlog_d("No My DHCP Message. This message is ignored.");
  368. return 0;
  369. }
  370. // 比较 DHCP 服务器 ip 地址
  371. if ((DHCP_SIP[0] != 0) || (DHCP_SIP[1] != 0) || (DHCP_SIP[2] != 0) || (DHCP_SIP[3] != 0))
  372. {
  373. if (0 != memcmp(DHCP_SIP, svr_addr, sizeof(DHCP_SIP)) &&
  374. 0 != memcmp(DHCP_REAL_SIP, svr_addr, sizeof(DHCP_REAL_SIP)))
  375. {
  376. rlog_d("Another DHCP sever send a response message. This is ignored.");
  377. return 0;
  378. }
  379. }
  380. p = (uint8_t *)(&pDHCPMSG->op);
  381. p = p + 240; // 240 = sizeof(RIP_MSG) + RIP_MSG.opt 中的 MAGIC_COOKIE 大小 -sizeof(RIP_MSG.opt)
  382. e = p + (len - 240);
  383. while (p < e)
  384. {
  385. switch (*p)
  386. {
  387. case endOption:
  388. p = e; // 中断 while(p < e)
  389. break;
  390. case padOption:
  391. p++;
  392. break;
  393. case dhcpMessageType:
  394. p++;
  395. p++;
  396. type = *p++;
  397. break;
  398. case subnetMask:
  399. p++;
  400. p++;
  401. gWIZNETINFO.sn[0] = *p++;
  402. gWIZNETINFO.sn[1] = *p++;
  403. gWIZNETINFO.sn[2] = *p++;
  404. gWIZNETINFO.sn[3] = *p++;
  405. break;
  406. case routersOnSubnet:
  407. p++;
  408. opt_len = *p++;
  409. gWIZNETINFO.gw[0] = *p++;
  410. gWIZNETINFO.gw[1] = *p++;
  411. gWIZNETINFO.gw[2] = *p++;
  412. gWIZNETINFO.gw[3] = *p++;
  413. p = p + (opt_len - 4);
  414. break;
  415. case dns:
  416. p++;
  417. opt_len = *p++;
  418. gWIZNETINFO.dns[0] = *p++;
  419. gWIZNETINFO.dns[1] = *p++;
  420. gWIZNETINFO.dns[2] = *p++;
  421. gWIZNETINFO.dns[3] = *p++;
  422. p = p + (opt_len - 4);
  423. break;
  424. case dhcpIPaddrLeaseTime:
  425. p++;
  426. opt_len = *p++;
  427. uint32_t dhcpLeaseTime = 0;
  428. dhcpLeaseTime = *p++;
  429. dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
  430. dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
  431. dhcpLeaseTime = (dhcpLeaseTime << 8) + *p++;
  432. platformTimerCutdown(&dhcp_lease_time, dhcpLeaseTime * 1000);
  433. break;
  434. case dhcpServerIdentifier:
  435. p++;
  436. opt_len = *p++;
  437. DHCP_SIP[0] = *p++;
  438. DHCP_SIP[1] = *p++;
  439. DHCP_SIP[2] = *p++;
  440. DHCP_SIP[3] = *p++;
  441. memcpy(DHCP_REAL_SIP, svr_addr, 4);
  442. break;
  443. default:
  444. p++;
  445. opt_len = *p++;
  446. p += opt_len;
  447. break;
  448. } // 转变
  449. } // 尽管
  450. return type;
  451. }
  452. /**
  453. *@简短的
  454. *
  455. *@return int8_t
  456. */
  457. int8_t check_DHCP_leasedIP(void)
  458. {
  459. uint8_t tmp;
  460. int32_t ret;
  461. // WIZchip RCR 值更改为 ARP 超时计数控制
  462. tmp = getRCR();
  463. setRCR(0x03);
  464. // IP 冲突检测:ARP 请求 -ARP 回复
  465. // 使用 UDP wizchip_sendto() 函数广播 ARP 请求以检查 IP 冲突
  466. ret = wizchip_sendto(DHCP_SOCKET, (uint8_t *)"CHECK_IP_CONFLICT", 17, gWIZNETINFO.ip, 5000);
  467. // Rcr值恢复
  468. setRCR(tmp);
  469. if (ret == SOCKERR_TIMEOUT)
  470. {
  471. // UDP 发送超时发生:分配的 IP 地址是唯一的,DHCP 成功
  472. rlog_d("> Check leased IP - OK");
  473. return 1;
  474. }
  475. else
  476. {
  477. // 收到 ARP 回复等:发生 IP 地址冲突,DHCP 失败
  478. send_DHCP_DECLINE();
  479. // 等待 1s 结束;等待完成发送 DECLINE 消息;
  480. rt_thread_mdelay(1000);
  481. return 0;
  482. }
  483. }
  484. /**
  485. *@brief 主循环中的 DHCP 客户端
  486. *
  487. *@return uint8_t
  488. */
  489. uint8_t DHCP_run(uint8_t flag)
  490. {
  491. uint8_t type = 0;
  492. uint8_t dhcp_retry_count = 0;
  493. platformTimer_t recvTimer = {0};
  494. RyanW5500Socket *sock = NULL;
  495. setSHAR(gWIZNETINFO.mac); // 设置w5500 mac
  496. sock = RyanW5500SocketCreate(Sn_MR_UDP, DHCP_CLIENT_PORT);
  497. if (NULL == sock)
  498. {
  499. rlog_w("dhcp socket失败");
  500. return -1;
  501. }
  502. // 申请dhcp报文空间
  503. uint8_t *dhcpDataBuf = (uint8_t *)rt_malloc(RIP_MSG_SIZE);
  504. if (NULL == dhcpDataBuf)
  505. {
  506. wiz_closesocket(sock->socket);
  507. return -1;
  508. }
  509. DHCP_SOCKET = sock->socket;
  510. pDHCPMSG = (RIP_MSG *)dhcpDataBuf;
  511. if (1 != flag) // flag 1表示处于续租状态
  512. {
  513. // 生成唯一事务id
  514. DHCP_XID = platformUptimeMs();
  515. DHCP_XID += gWIZNETINFO.mac[3];
  516. DHCP_XID += gWIZNETINFO.mac[4];
  517. DHCP_XID += gWIZNETINFO.mac[5];
  518. dhcp_state = STATE_DHCP_INIT;
  519. platformTimerInit(&dhcp_lease_time);
  520. }
  521. platformTimerCutdown(&recvTimer, DHCP_WAIT_TIME);
  522. while (1)
  523. {
  524. type = parseDHCPMSG();
  525. // 根据dhcp_state发送不同报文
  526. switch (dhcp_state)
  527. {
  528. case STATE_DHCP_INIT: // dhcp初始化状态
  529. memset(gWIZNETINFO.ip, 0, sizeof(gWIZNETINFO.ip));
  530. send_DHCP_DISCOVER(); // 客户端发送Discover报文
  531. dhcp_state = STATE_DHCP_DISCOVER;
  532. break;
  533. case STATE_DHCP_DISCOVER:
  534. if (DHCP_OFFER == type) // 服务器提供地址续约,offer报文
  535. {
  536. rlog_d("> Receive DHCP_OFFER");
  537. memcpy(gWIZNETINFO.ip, pDHCPMSG->yiaddr, sizeof(gWIZNETINFO.ip));
  538. send_DHCP_REQUEST(); // 发送请求地址租用 request报文
  539. dhcp_state = STATE_DHCP_REQUEST;
  540. }
  541. break;
  542. case STATE_DHCP_REQUEST: // 客户端选择并请求地址租用
  543. if (DHCP_NAK == type) // 服务器取消把地址租用给客户端
  544. {
  545. rlog_d("> Receive DHCP_NACK");
  546. dhcp_state = STATE_DHCP_DISCOVER;
  547. }
  548. else if (DHCP_ACK == type) // 服务器确认将地址租用给客户端 ack报文
  549. {
  550. rlog_d("> Receive DHCP_ACK");
  551. // 发生 IP 地址冲突
  552. dhcp_state = check_DHCP_leasedIP() ? STATE_DHCP_LEASED : STATE_DHCP_INIT;
  553. }
  554. break;
  555. case STATE_DHCP_LEASED: // 当租期超过50%(1/2)时,客户端会以单播形式向DHCP服务器发送DHCP Request报文来续租IP地址。
  556. if (dhcp_lease_time.timeOut != 0 && platformTimerRemain(&dhcp_lease_time) < (dhcp_lease_time.timeOut / 2))
  557. {
  558. rlog_d("> Maintains the IP address ");
  559. DHCP_XID++;
  560. send_DHCP_REQUEST();
  561. dhcp_state = STATE_DHCP_REREQUEST;
  562. }
  563. break;
  564. case STATE_DHCP_REREQUEST: // 如果收到DHCP服务器发送的DHCP ACK报文,则按相应时间延长IP地址租期。如果没有,还是保持使用该IP地址。
  565. if (type == DHCP_ACK)
  566. {
  567. // 不需要判断续租分配的新ip还是旧ip,都会写入到w5500寄存器里
  568. rlog_d("> Receive DHCP_ACK, Maintains the IP address");
  569. dhcp_state = STATE_DHCP_LEASED;
  570. }
  571. else if (type == DHCP_NAK)
  572. {
  573. rlog_d("> Receive DHCP_NACK, Failed to maintain ip");
  574. dhcp_state = STATE_DHCP_DISCOVER;
  575. }
  576. break;
  577. default:
  578. break;
  579. }
  580. if (STATE_DHCP_LEASED == dhcp_state)
  581. goto next;
  582. // 如果超时,根据现有状态进行报文重发尝试
  583. if (0 == platformTimerRemain(&recvTimer))
  584. {
  585. switch (dhcp_state)
  586. {
  587. case STATE_DHCP_DISCOVER:
  588. rlog_d("<<timeout>> state : STATE_DHCP_DISCOVER");
  589. send_DHCP_DISCOVER();
  590. break;
  591. case STATE_DHCP_REQUEST:
  592. rlog_d("<<timeout>> state : STATE_DHCP_REQUEST");
  593. send_DHCP_REQUEST();
  594. break;
  595. case STATE_DHCP_REREQUEST:
  596. rlog_d("<<timeout>> state : STATE_DHCP_REREQUEST");
  597. send_DHCP_REQUEST();
  598. break;
  599. default:
  600. break;
  601. }
  602. platformTimerCutdown(&recvTimer, DHCP_WAIT_TIME);
  603. dhcp_retry_count++;
  604. }
  605. if (dhcp_retry_count >= MAX_DHCP_RETRY)
  606. {
  607. wiz_closesocket(sock->socket);
  608. free(dhcpDataBuf);
  609. return -1;
  610. }
  611. delay(100);
  612. }
  613. next:
  614. wiz_closesocket(sock->socket);
  615. free(dhcpDataBuf);
  616. return 0;
  617. }
  618. /**
  619. *@brief 获取租用总时长 ms
  620. *
  621. *@return uint32_t
  622. */
  623. uint32_t getDHCPLeaseTime(void)
  624. {
  625. if (NETINFO_DHCP != gWIZNETINFO.dhcp)
  626. return 0;
  627. return dhcp_lease_time.timeOut;
  628. }
  629. uint32_t getDHCPRemainLeaseTime(void)
  630. {
  631. return platformTimerRemain(&dhcp_lease_time);
  632. }