dhcpserver.c 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <assert.h>
  9. #include "lwip/dhcp.h"
  10. #include "lwip/err.h"
  11. #include "lwip/pbuf.h"
  12. #include "lwip/udp.h"
  13. #include "lwip/mem.h"
  14. #include "lwip/ip_addr.h"
  15. #include "lwip/timeouts.h"
  16. #include "lwip/etharp.h"
  17. #include "lwip/prot/ethernet.h"
  18. #include "dhcpserver/dhcpserver.h"
  19. #include "dhcpserver/dhcpserver_options.h"
  20. #if ESP_DHCPS
  21. #ifdef LWIP_HOOK_FILENAME
  22. #include LWIP_HOOK_FILENAME
  23. #endif
  24. #ifndef LWIP_HOOK_DHCPS_POST_APPEND_OPTS
  25. #define LWIP_HOOK_DHCPS_POST_APPEND_OPTS(netif, dhcps, state, pp_opts)
  26. #endif
  27. #define BOOTP_BROADCAST 0x8000
  28. #define BROADCAST_BIT_IS_SET(flag) (flag & BOOTP_BROADCAST)
  29. #define DHCP_REQUEST 1
  30. #define DHCP_REPLY 2
  31. #define DHCP_HTYPE_ETHERNET 1
  32. #define DHCP_HLEN_ETHERNET 6
  33. #define DHCP_MSG_LEN 236
  34. #define DHCPS_SERVER_PORT 67
  35. #define DHCPS_CLIENT_PORT 68
  36. #define DHCPDISCOVER 1
  37. #define DHCPOFFER 2
  38. #define DHCPREQUEST 3
  39. #define DHCPDECLINE 4
  40. #define DHCPACK 5
  41. #define DHCPNAK 6
  42. #define DHCPRELEASE 7
  43. #define DHCP_OPTION_SUBNET_MASK 1
  44. #define DHCP_OPTION_ROUTER 3
  45. #define DHCP_OPTION_DNS_SERVER 6
  46. #define DHCP_OPTION_REQ_IPADDR 50
  47. #define DHCP_OPTION_LEASE_TIME 51
  48. #define DHCP_OPTION_MSG_TYPE 53
  49. #define DHCP_OPTION_SERVER_ID 54
  50. #define DHCP_OPTION_INTERFACE_MTU 26
  51. #define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31
  52. #define DHCP_OPTION_BROADCAST_ADDRESS 28
  53. #define DHCP_OPTION_REQ_LIST 55
  54. #define DHCP_OPTION_END 255
  55. //#define USE_CLASS_B_NET 1
  56. #define DHCPS_DEBUG 0
  57. #define DHCPS_LOG printf
  58. #define IS_INVALID_SUBNET_MASK(x) (((x-1) | x) != 0xFFFFFFFF)
  59. /* Notes:
  60. * CIDR eliminates the traditional Class A, Class B and Class C addresses.
  61. */
  62. #define IP_CLASS_HOST_NUM(mask) (0xffffffff & ~mask)
  63. #define DHCP_CHECK_SUBNET_MASK_IP(mask) \
  64. do { \
  65. if (IS_INVALID_SUBNET_MASK(mask)) { \
  66. DHCPS_LOG("dhcps: Illegal subnet mask.\n"); \
  67. return ERR_ARG; \
  68. } \
  69. } while (0)
  70. #define DHCP_CHECK_IP_MATCH_SUBNET_MASK(mask, ip) \
  71. u32_t start_ip = 0; \
  72. u32_t end_ip = 0; \
  73. do { \
  74. start_ip = ip & mask; \
  75. end_ip = start_ip | ~mask; \
  76. if (ip == end_ip || ip == start_ip) { \
  77. DHCPS_LOG("dhcps: ip address and subnet mask do not match.\n"); \
  78. return ERR_ARG; \
  79. } \
  80. } while (0)
  81. #define MAX_STATION_NUM CONFIG_LWIP_DHCPS_MAX_STATION_NUM
  82. #define DHCPS_STATE_OFFER 1
  83. #define DHCPS_STATE_DECLINE 2
  84. #define DHCPS_STATE_ACK 3
  85. #define DHCPS_STATE_NAK 4
  86. #define DHCPS_STATE_IDLE 5
  87. #define DHCPS_STATE_RELEASE 6
  88. typedef enum {
  89. DHCPS_HANDLE_CREATED = 0,
  90. DHCPS_HANDLE_STARTED,
  91. DHCPS_HANDLE_STOPPED,
  92. DHCPS_HANDLE_DELETE_PENDING,
  93. } dhcps_handle_state;
  94. typedef struct list_node {
  95. void *pnode;
  96. struct list_node *pnext;
  97. } list_node;
  98. typedef struct {
  99. ip4_addr_t ip;
  100. ip4_addr_t netmask;
  101. ip4_addr_t gw;
  102. } ip_info_t;
  103. ////////////////////////////////////////////////////////////////////////////////////
  104. static const u32_t magic_cookie = 0x63538263;
  105. struct dhcps_t {
  106. struct netif *dhcps_netif;
  107. ip4_addr_t broadcast_dhcps;
  108. ip4_addr_t server_address;
  109. ip4_addr_t dns_server;
  110. ip4_addr_t client_address;
  111. ip4_addr_t client_address_plus;
  112. ip4_addr_t dhcps_mask;
  113. list_node *plist;
  114. bool renew;
  115. dhcps_lease_t dhcps_poll;
  116. dhcps_time_t dhcps_lease_time;
  117. dhcps_offer_t dhcps_offer;
  118. dhcps_offer_t dhcps_dns;
  119. dhcps_cb_t dhcps_cb;
  120. void* dhcps_cb_arg;
  121. struct udp_pcb *dhcps_pcb;
  122. dhcps_handle_state state;
  123. };
  124. static void dhcps_tmr(void* arg);
  125. dhcps_t *dhcps_new(void)
  126. {
  127. dhcps_t *dhcps = mem_calloc(1, sizeof(dhcps_t));
  128. if (dhcps == NULL) {
  129. return NULL;
  130. }
  131. dhcps->dhcps_netif = NULL;
  132. dhcps->dns_server.addr = 0;
  133. #ifdef USE_CLASS_B_NET
  134. dhcps->dhcps_mask.addr = PP_HTONL(LWIP_MAKEU32(255, 240, 0, 0));
  135. #else
  136. dhcps->dhcps_mask.addr = PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0));
  137. #endif
  138. dhcps->plist = NULL;
  139. dhcps->renew = false;
  140. dhcps->dhcps_lease_time = DHCPS_LEASE_TIME_DEF;
  141. dhcps->dhcps_offer = 0xFF;
  142. dhcps->dhcps_dns = 0x00;
  143. dhcps->dhcps_pcb = NULL;
  144. dhcps->state = DHCPS_HANDLE_CREATED;
  145. return dhcps;
  146. }
  147. void dhcps_delete(dhcps_t *dhcps)
  148. {
  149. if (dhcps) {
  150. if (dhcps->state == DHCPS_HANDLE_STARTED) {
  151. // if the dhcp-server has started already, we have to postpone the deletion
  152. dhcps->state = DHCPS_HANDLE_DELETE_PENDING;
  153. } else {
  154. // otherwise, we're free to delete the handle immediately
  155. free(dhcps);
  156. }
  157. }
  158. }
  159. static void get_ip_info(struct netif * netif, ip_info_t *ip_info)
  160. {
  161. if (netif != NULL && netif_is_up(netif)) {
  162. ip4_addr_set(&ip_info->ip, ip_2_ip4(&netif->ip_addr));
  163. ip4_addr_set(&ip_info->netmask, ip_2_ip4(&netif->netmask));
  164. ip4_addr_set(&ip_info->gw, ip_2_ip4(&netif->gw));
  165. }
  166. }
  167. /******************************************************************************
  168. * FunctionName : dhcps_option_info
  169. * Description : get the DHCP message option info
  170. * Parameters : op_id -- DHCP message option id
  171. * opt_len -- DHCP message option length
  172. * Returns : DHCP message option addr
  173. *******************************************************************************/
  174. void *dhcps_option_info(dhcps_t *dhcps, u8_t op_id, u32_t opt_len)
  175. {
  176. void *option_arg = NULL;
  177. if (dhcps == NULL) {
  178. return NULL;
  179. }
  180. switch (op_id) {
  181. case IP_ADDRESS_LEASE_TIME:
  182. if (opt_len == sizeof(dhcps_time_t)) {
  183. option_arg = &dhcps->dhcps_lease_time;
  184. }
  185. break;
  186. case REQUESTED_IP_ADDRESS:
  187. if (opt_len == sizeof(dhcps_lease_t)) {
  188. option_arg = &dhcps->dhcps_poll;
  189. }
  190. break;
  191. case ROUTER_SOLICITATION_ADDRESS:
  192. if (opt_len == sizeof(dhcps_offer_t)) {
  193. option_arg = &dhcps->dhcps_offer;
  194. }
  195. break;
  196. case DOMAIN_NAME_SERVER:
  197. if (opt_len == sizeof(dhcps_offer_t)) {
  198. option_arg = &dhcps->dhcps_dns;
  199. }
  200. break;
  201. case SUBNET_MASK:
  202. if (opt_len == sizeof(dhcps->dhcps_mask)) {
  203. option_arg = &dhcps->dhcps_mask;
  204. }
  205. break;
  206. default:
  207. break;
  208. }
  209. return option_arg;
  210. }
  211. /******************************************************************************
  212. * FunctionName : dhcps_set_option_info
  213. * Description : set the DHCP message option info
  214. * Parameters : op_id -- DHCP message option id
  215. * opt_info -- DHCP message option info
  216. * opt_len -- DHCP message option length
  217. * Returns : none
  218. *******************************************************************************/
  219. err_t dhcps_set_option_info(dhcps_t *dhcps, u8_t op_id, void *opt_info, u32_t opt_len)
  220. {
  221. if (dhcps == NULL || opt_info == NULL) {
  222. return ERR_ARG;
  223. }
  224. switch (op_id) {
  225. case IP_ADDRESS_LEASE_TIME:
  226. if (opt_len == sizeof(dhcps_time_t)) {
  227. dhcps->dhcps_lease_time = *(dhcps_time_t *)opt_info;
  228. }
  229. break;
  230. case REQUESTED_IP_ADDRESS:
  231. if (opt_len == sizeof(dhcps_lease_t)) {
  232. dhcps->dhcps_poll = *(dhcps_lease_t *)opt_info;
  233. }
  234. break;
  235. case ROUTER_SOLICITATION_ADDRESS:
  236. if (opt_len == sizeof(dhcps_offer_t)) {
  237. dhcps->dhcps_offer = *(dhcps_offer_t *)opt_info;
  238. }
  239. break;
  240. case DOMAIN_NAME_SERVER:
  241. if (opt_len == sizeof(dhcps_offer_t)) {
  242. dhcps->dhcps_dns = *(dhcps_offer_t *)opt_info;
  243. }
  244. break;
  245. case SUBNET_MASK:
  246. if (opt_len == sizeof(dhcps->dhcps_mask)) {
  247. dhcps->dhcps_mask = *(ip4_addr_t *)opt_info;
  248. }
  249. default:
  250. break;
  251. }
  252. return ERR_OK;
  253. }
  254. /******************************************************************************
  255. * FunctionName : node_insert_to_list
  256. * Description : insert the node to the list
  257. * Parameters : phead -- the head node of the list
  258. * pinsert -- the insert node of the list
  259. * Returns : none
  260. *******************************************************************************/
  261. static void node_insert_to_list(list_node **phead, list_node *pinsert)
  262. {
  263. list_node *plist = NULL;
  264. struct dhcps_pool *pdhcps_pool = NULL;
  265. struct dhcps_pool *pdhcps_node = NULL;
  266. if (*phead == NULL) {
  267. *phead = pinsert;
  268. } else {
  269. plist = *phead;
  270. pdhcps_node = pinsert->pnode;
  271. pdhcps_pool = plist->pnode;
  272. if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
  273. pinsert->pnext = plist;
  274. *phead = pinsert;
  275. } else {
  276. while (plist->pnext != NULL) {
  277. pdhcps_pool = plist->pnext->pnode;
  278. if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {
  279. pinsert->pnext = plist->pnext;
  280. plist->pnext = pinsert;
  281. break;
  282. }
  283. plist = plist->pnext;
  284. }
  285. if (plist->pnext == NULL) {
  286. plist->pnext = pinsert;
  287. }
  288. }
  289. }
  290. // pinsert->pnext = NULL;
  291. }
  292. /******************************************************************************
  293. * FunctionName : node_delete_from_list
  294. * Description : remove the node from list
  295. * Parameters : phead -- the head node of the list
  296. * pdelete -- the remove node of the list
  297. * Returns : none
  298. *******************************************************************************/
  299. void node_remove_from_list(list_node **phead, list_node *pdelete)
  300. {
  301. list_node *plist = NULL;
  302. plist = *phead;
  303. if (plist == NULL) {
  304. *phead = NULL;
  305. } else {
  306. if (plist == pdelete) {
  307. // Note: Ignoring the "use after free" warnings, as it could only happen
  308. // if the linked list contains loops
  309. *phead = plist->pnext; // NOLINT(clang-analyzer-unix.Malloc)
  310. pdelete->pnext = NULL;
  311. } else {
  312. while (plist != NULL) {
  313. if (plist->pnext == pdelete) { // NOLINT(clang-analyzer-unix.Malloc)
  314. plist->pnext = pdelete->pnext;
  315. pdelete->pnext = NULL;
  316. }
  317. plist = plist->pnext;
  318. }
  319. }
  320. }
  321. }
  322. /******************************************************************************
  323. * FunctionName : add_msg_type
  324. * Description : add TYPE option of DHCP message
  325. * Parameters : optptr -- the addr of DHCP message option
  326. * Returns : the addr of DHCP message option
  327. *******************************************************************************/
  328. static u8_t *add_msg_type(u8_t *optptr, u8_t type)
  329. {
  330. *optptr++ = DHCP_OPTION_MSG_TYPE;
  331. *optptr++ = 1;
  332. *optptr++ = type;
  333. return optptr;
  334. }
  335. /******************************************************************************
  336. * FunctionName : add_offer_options
  337. * Description : add OFFER option of DHCP message
  338. * Parameters : optptr -- the addr of DHCP message option
  339. * Returns : the addr of DHCP message option
  340. *******************************************************************************/
  341. static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr)
  342. {
  343. ip4_addr_t ipadd;
  344. ipadd.addr = *((u32_t *) &dhcps->server_address);
  345. *optptr++ = DHCP_OPTION_SUBNET_MASK;
  346. *optptr++ = 4;
  347. *optptr++ = ip4_addr1(&dhcps->dhcps_mask);
  348. *optptr++ = ip4_addr2(&dhcps->dhcps_mask);
  349. *optptr++ = ip4_addr3(&dhcps->dhcps_mask);
  350. *optptr++ = ip4_addr4(&dhcps->dhcps_mask);
  351. *optptr++ = DHCP_OPTION_LEASE_TIME;
  352. *optptr++ = 4;
  353. *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 24) & 0xFF;
  354. *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 16) & 0xFF;
  355. *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 8) & 0xFF;
  356. *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 0) & 0xFF;
  357. *optptr++ = DHCP_OPTION_SERVER_ID;
  358. *optptr++ = 4;
  359. *optptr++ = ip4_addr1(&ipadd);
  360. *optptr++ = ip4_addr2(&ipadd);
  361. *optptr++ = ip4_addr3(&ipadd);
  362. *optptr++ = ip4_addr4(&ipadd);
  363. if (dhcps_router_enabled(dhcps->dhcps_offer)) {
  364. ip_info_t if_ip = { 0 };
  365. get_ip_info(dhcps->dhcps_netif, &if_ip);
  366. ip4_addr_t* gw_ip = (ip4_addr_t*)&if_ip.gw;
  367. if (!ip4_addr_isany_val(*gw_ip)) {
  368. *optptr++ = DHCP_OPTION_ROUTER;
  369. *optptr++ = 4;
  370. *optptr++ = ip4_addr1(gw_ip);
  371. *optptr++ = ip4_addr2(gw_ip);
  372. *optptr++ = ip4_addr3(gw_ip);
  373. *optptr++ = ip4_addr4(gw_ip);
  374. }
  375. }
  376. *optptr++ = DHCP_OPTION_DNS_SERVER;
  377. *optptr++ = 4;
  378. if (dhcps_dns_enabled(dhcps->dhcps_dns)) {
  379. *optptr++ = ip4_addr1(&dhcps->dns_server);
  380. *optptr++ = ip4_addr2(&dhcps->dns_server);
  381. *optptr++ = ip4_addr3(&dhcps->dns_server);
  382. *optptr++ = ip4_addr4(&dhcps->dns_server);
  383. }else {
  384. *optptr++ = ip4_addr1(&ipadd);
  385. *optptr++ = ip4_addr2(&ipadd);
  386. *optptr++ = ip4_addr3(&ipadd);
  387. *optptr++ = ip4_addr4(&ipadd);
  388. }
  389. ip4_addr_t broadcast_addr = { .addr = (ipadd.addr & dhcps->dhcps_mask.addr) | ~dhcps->dhcps_mask.addr };
  390. *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
  391. *optptr++ = 4;
  392. *optptr++ = ip4_addr1(&broadcast_addr);
  393. *optptr++ = ip4_addr2(&broadcast_addr);
  394. *optptr++ = ip4_addr3(&broadcast_addr);
  395. *optptr++ = ip4_addr4(&broadcast_addr);
  396. *optptr++ = DHCP_OPTION_INTERFACE_MTU;
  397. *optptr++ = 2;
  398. *optptr++ = 0x05;
  399. *optptr++ = 0xdc;
  400. *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY;
  401. *optptr++ = 1;
  402. *optptr++ = 0x00;
  403. *optptr++ = 43;
  404. *optptr++ = 6;
  405. *optptr++ = 0x01;
  406. *optptr++ = 4;
  407. *optptr++ = 0x00;
  408. *optptr++ = 0x00;
  409. *optptr++ = 0x00;
  410. *optptr++ = 0x02;
  411. return optptr;
  412. }
  413. /******************************************************************************
  414. * FunctionName : add_end
  415. * Description : add end option of DHCP message
  416. * Parameters : optptr -- the addr of DHCP message option
  417. * Returns : the addr of DHCP message option
  418. *******************************************************************************/
  419. static u8_t *add_end(u8_t *optptr)
  420. {
  421. *optptr++ = DHCP_OPTION_END;
  422. return optptr;
  423. }
  424. /******************************************************************************
  425. * FunctionName : create_msg
  426. * Description : create response message
  427. * Parameters : m -- DHCP message info
  428. * Returns : none
  429. *******************************************************************************/
  430. static void create_msg(dhcps_t *dhcps, struct dhcps_msg *m)
  431. {
  432. ip4_addr_t client;
  433. client.addr = *((uint32_t *) &dhcps->client_address);
  434. m->op = DHCP_REPLY;
  435. m->htype = DHCP_HTYPE_ETHERNET;
  436. m->hlen = 6;
  437. #if !ETHARP_SUPPORT_STATIC_ENTRIES
  438. /* If the DHCP server does not support sending unicast message to the client,
  439. * need to set the 'flags' field to broadcast */
  440. m->flags = htons(BOOTP_BROADCAST);
  441. #endif
  442. memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr));
  443. memcpy((char *) m->options, &magic_cookie, sizeof(magic_cookie));
  444. }
  445. /******************************************************************************
  446. * FunctionName : dhcps_response_ip_set
  447. * Description : set the ip address for sending to the DHCP client
  448. * Parameters : m -- DHCP message info
  449. * ip4_out -- ip address for sending
  450. * Returns : none
  451. *******************************************************************************/
  452. static void dhcps_response_ip_set(dhcps_t *dhcps, struct dhcps_msg *m, ip4_addr_t *ip4_out)
  453. {
  454. #if ETHARP_SUPPORT_STATIC_ENTRIES
  455. ip4_addr_t ip4_giaddr;
  456. ip4_addr_t ip4_ciaddr;
  457. ip4_addr_t ip4_yiaddr;
  458. struct eth_addr chaddr;
  459. memcpy(chaddr.addr, m->chaddr, sizeof(chaddr.addr));
  460. memcpy((char *)&ip4_giaddr.addr, (char *)m->giaddr, sizeof(m->giaddr));
  461. memcpy((char *)&ip4_ciaddr.addr, (char *)m->ciaddr, sizeof(m->ciaddr));
  462. memcpy((char *)&ip4_yiaddr.addr, (char *)m->yiaddr, sizeof(m->yiaddr));
  463. if (!ip4_addr_isany_val(ip4_giaddr)) {
  464. /* If the 'giaddr' field is non-zero, send return message to the address in 'giaddr'. (RFC 2131)*/
  465. ip4_addr_set(ip4_out, &ip4_giaddr);
  466. /* add the IP<->MAC as static entry into the arp table. */
  467. etharp_add_static_entry(&ip4_giaddr, &chaddr);
  468. } else {
  469. if (!ip4_addr_isany_val(ip4_ciaddr)) {
  470. /* If the 'giaddr' field is zero and the 'ciaddr' is nonzero,
  471. * the server unicasts DHCPOFFER and DHCPACK message to the address in 'ciaddr'*/
  472. ip4_addr_set(ip4_out, &ip4_ciaddr);
  473. etharp_add_static_entry(&ip4_ciaddr, &chaddr);
  474. } else if (!BROADCAST_BIT_IS_SET(htons(m->flags))) {
  475. /* If the 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is not set,
  476. * the server unicasts DHCPOFFER and DHCPACK message to the client's hardware address and
  477. * 'yiaddr' address. */
  478. ip4_addr_set(ip4_out, &ip4_yiaddr);
  479. etharp_add_static_entry(&ip4_yiaddr, &chaddr);
  480. } else {
  481. /* The server broadcast DHCPOFFER and DHCPACK message to 0xffffffff*/
  482. ip4_addr_set(ip4_out, &dhcps->broadcast_dhcps);
  483. }
  484. }
  485. #else
  486. ip4_addr_set(ip4_out, &dhcps->broadcast_dhcps);
  487. #endif
  488. }
  489. struct pbuf * dhcps_pbuf_alloc(u16_t len)
  490. {
  491. u16_t mlen = sizeof(struct dhcps_msg);
  492. if (len > mlen) {
  493. #if DHCPS_DEBUG
  494. DHCPS_LOG("dhcps: len=%d mlen=%d", len, mlen);
  495. #endif
  496. mlen = len;
  497. }
  498. return pbuf_alloc(PBUF_TRANSPORT, mlen, PBUF_RAM);
  499. }
  500. /******************************************************************************
  501. * FunctionName : send_offer
  502. * Description : DHCP message OFFER Response
  503. * Parameters : m -- DHCP message info
  504. * Returns : none
  505. *******************************************************************************/
  506. static void send_offer(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
  507. {
  508. u8_t *end;
  509. struct pbuf *p, *q;
  510. u8_t *data;
  511. u16_t cnt = 0;
  512. u16_t i;
  513. #if DHCPS_DEBUG
  514. err_t SendOffer_err_t;
  515. #endif
  516. create_msg(dhcps, m);
  517. end = add_msg_type(&m->options[4], DHCPOFFER);
  518. end = add_offer_options(dhcps, end);
  519. LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPOFFER, &end)
  520. end = add_end(end);
  521. p = dhcps_pbuf_alloc(len);
  522. #if DHCPS_DEBUG
  523. DHCPS_LOG("udhcp: send_offer>>p->ref = %d\n", p->ref);
  524. #endif
  525. if (p != NULL) {
  526. #if DHCPS_DEBUG
  527. DHCPS_LOG("dhcps: send_offer>>pbuf_alloc succeed\n");
  528. DHCPS_LOG("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len);
  529. DHCPS_LOG("dhcps: send_offer>>p->len = %d\n", p->len);
  530. #endif
  531. q = p;
  532. while (q != NULL) {
  533. data = (u8_t *)q->payload;
  534. for (i = 0; i < q->len; i++) {
  535. data[i] = ((u8_t *) m)[cnt++];
  536. #if DHCPS_DEBUG
  537. DHCPS_LOG("%02x ", data[i]);
  538. if ((i + 1) % 16 == 0) {
  539. DHCPS_LOG("\n");
  540. }
  541. #endif
  542. }
  543. q = q->next;
  544. }
  545. } else {
  546. #if DHCPS_DEBUG
  547. DHCPS_LOG("dhcps: send_offer>>pbuf_alloc failed\n");
  548. #endif
  549. return;
  550. }
  551. ip_addr_t ip_temp = IPADDR4_INIT(0x0);
  552. dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp));
  553. #if DHCPS_DEBUG
  554. SendOffer_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
  555. DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t);
  556. #else
  557. udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
  558. #endif
  559. #if ETHARP_SUPPORT_STATIC_ENTRIES
  560. /* remove the IP<->MAC from the arp table. */
  561. etharp_remove_static_entry(ip_2_ip4(&ip_temp));
  562. #endif
  563. if (p->ref != 0) {
  564. #if DHCPS_DEBUG
  565. DHCPS_LOG("udhcp: send_offer>>free pbuf\n");
  566. #endif
  567. pbuf_free(p);
  568. }
  569. }
  570. /******************************************************************************
  571. * FunctionName : send_nak
  572. * Description : DHCP message NACK Response
  573. * Parameters : m -- DHCP message info
  574. * Returns : none
  575. *******************************************************************************/
  576. static void send_nak(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
  577. {
  578. u8_t *end;
  579. struct pbuf *p, *q;
  580. u8_t *data;
  581. u16_t cnt = 0;
  582. u16_t i;
  583. #if DHCPS_DEBUG
  584. err_t SendNak_err_t;
  585. #endif
  586. create_msg(dhcps, m);
  587. end = add_msg_type(&m->options[4], DHCPNAK);
  588. LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPNAK, &end)
  589. end = add_end(end);
  590. p = dhcps_pbuf_alloc(len);
  591. #if DHCPS_DEBUG
  592. DHCPS_LOG("udhcp: send_nak>>p->ref = %d\n", p->ref);
  593. #endif
  594. if (p != NULL) {
  595. #if DHCPS_DEBUG
  596. DHCPS_LOG("dhcps: send_nak>>pbuf_alloc succeed\n");
  597. DHCPS_LOG("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len);
  598. DHCPS_LOG("dhcps: send_nak>>p->len = %d\n", p->len);
  599. #endif
  600. q = p;
  601. while (q != NULL) {
  602. data = (u8_t *)q->payload;
  603. for (i = 0; i < q->len; i++) {
  604. data[i] = ((u8_t *) m)[cnt++];
  605. #if DHCPS_DEBUG
  606. DHCPS_LOG("%02x ", data[i]);
  607. if ((i + 1) % 16 == 0) {
  608. DHCPS_LOG("\n");
  609. }
  610. #endif
  611. }
  612. q = q->next;
  613. }
  614. } else {
  615. #if DHCPS_DEBUG
  616. DHCPS_LOG("dhcps: send_nak>>pbuf_alloc failed\n");
  617. #endif
  618. return;
  619. }
  620. ip_addr_t ip_temp = IPADDR4_INIT(0x0);
  621. #if ETHARP_SUPPORT_STATIC_ENTRIES
  622. ip4_addr_t ip4_giaddr;
  623. struct eth_addr chaddr;
  624. memcpy(chaddr.addr, m->chaddr, sizeof(chaddr.addr));
  625. memcpy((char *)&ip4_giaddr.addr, (char *)m->giaddr, sizeof(m->giaddr));
  626. if (!ip4_addr_isany_val(ip4_giaddr)) {
  627. ip4_addr_set(ip_2_ip4(&ip_temp), &ip4_giaddr);
  628. /* add the IP<->MAC as static entry into the arp table. */
  629. etharp_add_static_entry(&ip4_giaddr, &chaddr);
  630. } else {
  631. /* when 'giaddr' is zero, the server broadcasts any DHCPNAK message to 0xffffffff. (RFC 2131)*/
  632. ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps);
  633. }
  634. #else
  635. ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps);
  636. #endif
  637. #if DHCPS_DEBUG
  638. SendNak_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
  639. DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n", SendNak_err_t);
  640. #else
  641. udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
  642. #endif
  643. #if ETHARP_SUPPORT_STATIC_ENTRIES
  644. /* remove the IP<->MAC from the arp table. */
  645. etharp_remove_static_entry(ip_2_ip4(&ip_temp));
  646. #endif
  647. if (p->ref != 0) {
  648. #if DHCPS_DEBUG
  649. DHCPS_LOG("udhcp: send_nak>>free pbuf\n");
  650. #endif
  651. pbuf_free(p);
  652. }
  653. }
  654. /******************************************************************************
  655. * FunctionName : send_ack
  656. * Description : DHCP message ACK Response
  657. * Parameters : m -- DHCP message info
  658. * Returns : none
  659. *******************************************************************************/
  660. static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
  661. {
  662. u8_t *end;
  663. struct pbuf *p, *q;
  664. u8_t *data;
  665. u16_t cnt = 0;
  666. u16_t i;
  667. err_t SendAck_err_t;
  668. create_msg(dhcps, m);
  669. end = add_msg_type(&m->options[4], DHCPACK);
  670. end = add_offer_options(dhcps, end);
  671. LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPACK, &end)
  672. end = add_end(end);
  673. p = dhcps_pbuf_alloc(len);
  674. #if DHCPS_DEBUG
  675. DHCPS_LOG("udhcp: send_ack>>p->ref = %d\n", p->ref);
  676. #endif
  677. if (p != NULL) {
  678. #if DHCPS_DEBUG
  679. DHCPS_LOG("dhcps: send_ack>>pbuf_alloc succeed\n");
  680. DHCPS_LOG("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len);
  681. DHCPS_LOG("dhcps: send_ack>>p->len = %d\n", p->len);
  682. #endif
  683. q = p;
  684. while (q != NULL) {
  685. data = (u8_t *)q->payload;
  686. for (i = 0; i < q->len; i++) {
  687. data[i] = ((u8_t *) m)[cnt++];
  688. #if DHCPS_DEBUG
  689. DHCPS_LOG("%02x ", data[i]);
  690. if ((i + 1) % 16 == 0) {
  691. DHCPS_LOG("\n");
  692. }
  693. #endif
  694. }
  695. q = q->next;
  696. }
  697. } else {
  698. #if DHCPS_DEBUG
  699. DHCPS_LOG("dhcps: send_ack>>pbuf_alloc failed\n");
  700. #endif
  701. return;
  702. }
  703. ip_addr_t ip_temp = IPADDR4_INIT(0x0);
  704. dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp));
  705. SendAck_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
  706. #if DHCPS_DEBUG
  707. DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n", SendAck_err_t);
  708. #endif
  709. #if ETHARP_SUPPORT_STATIC_ENTRIES
  710. /* remove the IP<->MAC from the arp table. */
  711. etharp_remove_static_entry(ip_2_ip4(&ip_temp));
  712. #endif
  713. if (SendAck_err_t == ERR_OK) {
  714. dhcps->dhcps_cb(dhcps->dhcps_cb_arg, m->yiaddr, m->chaddr);
  715. }
  716. if (p->ref != 0) {
  717. #if DHCPS_DEBUG
  718. DHCPS_LOG("udhcp: send_ack>>free pbuf\n");
  719. #endif
  720. pbuf_free(p);
  721. }
  722. }
  723. /******************************************************************************
  724. * FunctionName : parse_options
  725. * Description : parse DHCP message options
  726. * Parameters : optptr -- DHCP message option info
  727. * len -- DHCP message option length
  728. * Returns : none
  729. *******************************************************************************/
  730. static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len)
  731. {
  732. ip4_addr_t client;
  733. bool is_dhcp_parse_end = false;
  734. struct dhcps_state s;
  735. client.addr = *((uint32_t *) &dhcps->client_address);
  736. u8_t *end = optptr + len;
  737. u16_t type = 0;
  738. s.state = DHCPS_STATE_IDLE;
  739. while (optptr < end) {
  740. #if DHCPS_DEBUG
  741. DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr);
  742. #endif
  743. switch ((s16_t) *optptr) {
  744. case DHCP_OPTION_MSG_TYPE: //53
  745. type = *(optptr + 2);
  746. break;
  747. case DHCP_OPTION_REQ_IPADDR://50
  748. if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) {
  749. #if DHCPS_DEBUG
  750. DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n");
  751. #endif
  752. s.state = DHCPS_STATE_ACK;
  753. } else {
  754. #if DHCPS_DEBUG
  755. DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n");
  756. #endif
  757. s.state = DHCPS_STATE_NAK;
  758. }
  759. break;
  760. case DHCP_OPTION_END: {
  761. is_dhcp_parse_end = true;
  762. }
  763. break;
  764. }
  765. if (is_dhcp_parse_end) {
  766. break;
  767. }
  768. optptr += optptr[1] + 2;
  769. }
  770. switch (type) {
  771. case DHCPDISCOVER://1
  772. s.state = DHCPS_STATE_OFFER;
  773. #if DHCPS_DEBUG
  774. DHCPS_LOG("dhcps: DHCPD_STATE_OFFER\n");
  775. #endif
  776. break;
  777. case DHCPREQUEST://3
  778. if (!(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK)) {
  779. if (dhcps->renew == true) {
  780. s.state = DHCPS_STATE_ACK;
  781. } else {
  782. s.state = DHCPS_STATE_NAK;
  783. }
  784. #if DHCPS_DEBUG
  785. DHCPS_LOG("dhcps: DHCPD_STATE_NAK\n");
  786. #endif
  787. }
  788. break;
  789. case DHCPDECLINE://4
  790. s.state = DHCPS_STATE_IDLE;
  791. #if DHCPS_DEBUG
  792. DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
  793. #endif
  794. break;
  795. case DHCPRELEASE://7
  796. s.state = DHCPS_STATE_RELEASE;
  797. #if DHCPS_DEBUG
  798. DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n");
  799. #endif
  800. break;
  801. }
  802. #if DHCPS_DEBUG
  803. DHCPS_LOG("dhcps: return s.state = %d\n", s.state);
  804. #endif
  805. return s.state;
  806. }
  807. /******************************************************************************
  808. * FunctionName : parse_msg
  809. * Description : parse DHCP message from netif
  810. * Parameters : m -- DHCP message info
  811. * len -- DHCP message length
  812. * Returns : DHCP message type
  813. *******************************************************************************/
  814. static s16_t parse_msg(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
  815. {
  816. u32_t lease_timer = (dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT)/DHCPS_COARSE_TIMER_SECS;
  817. if (memcmp((char *)m->options, &magic_cookie, sizeof(magic_cookie)) == 0) {
  818. #if DHCPS_DEBUG
  819. DHCPS_LOG("dhcps: len = %d\n", len);
  820. #endif
  821. ip4_addr_t addr_tmp;
  822. struct dhcps_pool *pdhcps_pool = NULL;
  823. list_node *pnode = NULL;
  824. list_node *pback_node = NULL;
  825. ip4_addr_t first_address;
  826. bool flag = false;
  827. first_address.addr = dhcps->dhcps_poll.start_ip.addr;
  828. dhcps->client_address.addr = dhcps->client_address_plus.addr;
  829. dhcps->renew = false;
  830. if (dhcps->plist != NULL) {
  831. for (pback_node = dhcps->plist; pback_node != NULL; pback_node = pback_node->pnext) {
  832. pdhcps_pool = pback_node->pnode;
  833. if (memcmp(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)) == 0) {
  834. if (memcmp(&pdhcps_pool->ip.addr, m->ciaddr, sizeof(pdhcps_pool->ip.addr)) == 0) {
  835. dhcps->renew = true;
  836. }
  837. dhcps->client_address.addr = pdhcps_pool->ip.addr;
  838. pdhcps_pool->lease_timer = lease_timer;
  839. pnode = pback_node;
  840. goto POOL_CHECK;
  841. } else if (pdhcps_pool->ip.addr == dhcps->client_address_plus.addr) {
  842. addr_tmp.addr = htonl(dhcps->client_address_plus.addr);
  843. addr_tmp.addr++;
  844. dhcps->client_address_plus.addr = htonl(addr_tmp.addr);
  845. dhcps->client_address.addr = dhcps->client_address_plus.addr;
  846. }
  847. if (flag == false) { // search the fisrt unused ip
  848. if (first_address.addr < pdhcps_pool->ip.addr) {
  849. flag = true;
  850. } else {
  851. addr_tmp.addr = htonl(first_address.addr);
  852. addr_tmp.addr++;
  853. first_address.addr = htonl(addr_tmp.addr);
  854. }
  855. }
  856. }
  857. } else {
  858. dhcps->client_address.addr = dhcps->dhcps_poll.start_ip.addr;
  859. }
  860. if (dhcps->client_address_plus.addr > dhcps->dhcps_poll.end_ip.addr) {
  861. dhcps->client_address.addr = first_address.addr;
  862. }
  863. if (dhcps->client_address.addr > dhcps->dhcps_poll.end_ip.addr) {
  864. dhcps->client_address_plus.addr = dhcps->dhcps_poll.start_ip.addr;
  865. pdhcps_pool = NULL;
  866. pnode = NULL;
  867. } else {
  868. pdhcps_pool = (struct dhcps_pool *)mem_calloc(1, sizeof(struct dhcps_pool));
  869. pdhcps_pool->ip.addr = dhcps->client_address.addr;
  870. memcpy(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac));
  871. pdhcps_pool->lease_timer = lease_timer;
  872. pnode = (list_node *)mem_calloc(1, sizeof(list_node));
  873. pnode->pnode = pdhcps_pool;
  874. pnode->pnext = NULL;
  875. node_insert_to_list(&dhcps->plist, pnode);
  876. if (dhcps->client_address.addr == dhcps->dhcps_poll.end_ip.addr) {
  877. dhcps->client_address_plus.addr = dhcps->dhcps_poll.start_ip.addr;
  878. } else {
  879. addr_tmp.addr = htonl(dhcps->client_address.addr);
  880. addr_tmp.addr++;
  881. dhcps->client_address_plus.addr = htonl(addr_tmp.addr);
  882. }
  883. }
  884. POOL_CHECK:
  885. if ((dhcps->client_address.addr > dhcps->dhcps_poll.end_ip.addr) || (ip4_addr_isany(&dhcps->client_address))) {
  886. if (pnode != NULL) {
  887. node_remove_from_list(&dhcps->plist, pnode);
  888. free(pnode);
  889. pnode = NULL;
  890. }
  891. if (pdhcps_pool != NULL) {
  892. free(pdhcps_pool);
  893. pdhcps_pool = NULL;
  894. }
  895. return 4;
  896. }
  897. s16_t ret = parse_options(dhcps, &m->options[4], len);;
  898. if (ret == DHCPS_STATE_RELEASE || ret == DHCPS_STATE_NAK) {
  899. if (pnode != NULL) {
  900. node_remove_from_list(&dhcps->plist, pnode);
  901. free(pnode);
  902. pnode = NULL;
  903. }
  904. if (pdhcps_pool != NULL) {
  905. free(pdhcps_pool);
  906. pdhcps_pool = NULL;
  907. }
  908. memset(&dhcps->client_address, 0x0, sizeof(dhcps->client_address));
  909. }
  910. #if DHCPS_DEBUG
  911. DHCPS_LOG("dhcps: xid changed\n");
  912. DHCPS_LOG("dhcps: client_address.addr = %x\n", dhcps->client_address.addr);
  913. #endif
  914. return ret;
  915. }
  916. return 0;
  917. }
  918. /******************************************************************************
  919. * FunctionName : handle_dhcp
  920. * Description : If an incoming DHCP message is in response to us, then trigger the state machine
  921. * Parameters : arg -- arg user supplied argument (udp_pcb.recv_arg)
  922. * pcb -- the udp_pcb which received data
  923. * p -- the packet buffer that was received
  924. * addr -- the remote IP address from which the packet was received
  925. * port -- the remote port from which the packet was received
  926. * Returns : none
  927. *******************************************************************************/
  928. static void handle_dhcp(void *arg,
  929. struct udp_pcb *pcb,
  930. struct pbuf *p,
  931. const ip_addr_t *addr,
  932. u16_t port)
  933. {
  934. struct dhcps_t *dhcps = arg;
  935. struct dhcps_msg *pmsg_dhcps = NULL;
  936. s16_t tlen, malloc_len;
  937. u16_t i;
  938. u16_t dhcps_msg_cnt = 0;
  939. u8_t *p_dhcps_msg = NULL;
  940. u8_t *data;
  941. s16_t state;
  942. #if DHCPS_DEBUG
  943. DHCPS_LOG("dhcps: handle_dhcp-> receive a packet\n");
  944. #endif
  945. if (p == NULL) {
  946. return;
  947. }
  948. malloc_len = sizeof(struct dhcps_msg);
  949. #if DHCPS_DEBUG
  950. DHCPS_LOG("dhcps: handle_dhcp malloc_len=%d rx_len=%d", malloc_len, p->tot_len);
  951. #endif
  952. if (malloc_len < p->tot_len) {
  953. malloc_len = p->tot_len;
  954. }
  955. pmsg_dhcps = (struct dhcps_msg *)mem_calloc(1, malloc_len);
  956. if (NULL == pmsg_dhcps) {
  957. pbuf_free(p);
  958. return;
  959. }
  960. p_dhcps_msg = (u8_t *)pmsg_dhcps;
  961. tlen = p->tot_len;
  962. data = p->payload;
  963. #if DHCPS_DEBUG
  964. DHCPS_LOG("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen);
  965. DHCPS_LOG("dhcps: handle_dhcp-> p->len = %d\n", p->len);
  966. #endif
  967. for (i = 0; i < p->len; i++) {
  968. p_dhcps_msg[dhcps_msg_cnt++] = data[i];
  969. #if DHCPS_DEBUG
  970. DHCPS_LOG("%02x ", data[i]);
  971. if ((i + 1) % 16 == 0) {
  972. DHCPS_LOG("\n");
  973. }
  974. #endif
  975. }
  976. if (p->next != NULL) {
  977. #if DHCPS_DEBUG
  978. DHCPS_LOG("dhcps: handle_dhcp-> p->next != NULL\n");
  979. DHCPS_LOG("dhcps: handle_dhcp-> p->next->tot_len = %d\n", p->next->tot_len);
  980. DHCPS_LOG("dhcps: handle_dhcp-> p->next->len = %d\n", p->next->len);
  981. #endif
  982. data = p->next->payload;
  983. for (i = 0; i < p->next->len; i++) {
  984. p_dhcps_msg[dhcps_msg_cnt++] = data[i];
  985. #if DHCPS_DEBUG
  986. DHCPS_LOG("%02x ", data[i]);
  987. if ((i + 1) % 16 == 0) {
  988. DHCPS_LOG("\n");
  989. }
  990. #endif
  991. }
  992. }
  993. #if DHCPS_DEBUG
  994. DHCPS_LOG("dhcps: handle_dhcp-> parse_msg(p)\n");
  995. #endif
  996. state = parse_msg(dhcps, pmsg_dhcps, tlen - 240);
  997. #ifdef LWIP_HOOK_DHCPS_POST_STATE
  998. state = LWIP_HOOK_DHCPS_POST_STATE(pmsg_dhcps, malloc_len, state);
  999. #endif /* LWIP_HOOK_DHCPS_POST_STATE */
  1000. switch (state) {
  1001. case DHCPS_STATE_OFFER://1
  1002. #if DHCPS_DEBUG
  1003. DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n");
  1004. #endif
  1005. send_offer(dhcps, pmsg_dhcps, malloc_len);
  1006. break;
  1007. case DHCPS_STATE_ACK://3
  1008. #if DHCPS_DEBUG
  1009. DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n");
  1010. #endif
  1011. send_ack(dhcps, pmsg_dhcps, malloc_len);
  1012. break;
  1013. case DHCPS_STATE_NAK://4
  1014. #if DHCPS_DEBUG
  1015. DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n");
  1016. #endif
  1017. send_nak(dhcps, pmsg_dhcps, malloc_len);
  1018. break;
  1019. default :
  1020. break;
  1021. }
  1022. #if DHCPS_DEBUG
  1023. DHCPS_LOG("dhcps: handle_dhcp-> pbuf_free(p)\n");
  1024. #endif
  1025. pbuf_free(p);
  1026. free(pmsg_dhcps);
  1027. pmsg_dhcps = NULL;
  1028. }
  1029. /******************************************************************************
  1030. * FunctionName : dhcps_poll_set
  1031. * Description : set ip poll from start to end for station
  1032. * Parameters : ip -- The current ip addr
  1033. * Returns : none
  1034. *******************************************************************************/
  1035. static void dhcps_poll_set(dhcps_t *dhcps, u32_t ip)
  1036. {
  1037. u32_t server_ip = 0;
  1038. u32_t start_ip = 0;
  1039. u32_t end_ip = 0;
  1040. u32_t range_start_ip = 0;
  1041. u32_t range_end_ip = 0;
  1042. dhcps_lease_t *dhcps_poll = &dhcps->dhcps_poll;
  1043. if (dhcps_poll->enable == true) {
  1044. server_ip = htonl(ip);
  1045. start_ip = htonl(dhcps_poll->start_ip.addr);
  1046. end_ip = htonl(dhcps_poll->end_ip.addr);
  1047. /*config ip information can't contain local ip*/
  1048. if ((server_ip >= start_ip) && (server_ip <= end_ip)) {
  1049. dhcps_poll->enable = false;
  1050. } else {
  1051. /*config ip information must be in the same segment as the local ip*/
  1052. if (!ip4_addr_netcmp(&dhcps_poll->start_ip, &dhcps->server_address, &dhcps->dhcps_mask)
  1053. || !ip4_addr_netcmp(&dhcps_poll->end_ip, &dhcps->server_address, &dhcps->dhcps_mask)
  1054. || (end_ip - start_ip + 1 > DHCPS_MAX_LEASE)) {
  1055. dhcps_poll->enable = false;
  1056. }
  1057. }
  1058. }
  1059. if (dhcps_poll->enable == false) {
  1060. server_ip = htonl(ip);
  1061. range_start_ip = server_ip & htonl(dhcps->dhcps_mask.addr);
  1062. range_end_ip = range_start_ip | ~htonl(dhcps->dhcps_mask.addr);
  1063. if (server_ip - range_start_ip > range_end_ip - server_ip) {
  1064. range_start_ip = range_start_ip + 1;
  1065. range_end_ip = server_ip - 1;
  1066. } else {
  1067. range_start_ip = server_ip + 1;
  1068. range_end_ip = range_end_ip - 1;
  1069. }
  1070. if (range_end_ip - range_start_ip + 1 > DHCPS_MAX_LEASE) {
  1071. range_end_ip = range_start_ip + DHCPS_MAX_LEASE - 1;
  1072. }
  1073. bzero(dhcps_poll, sizeof(*dhcps_poll));
  1074. dhcps_poll->start_ip.addr = range_start_ip;
  1075. dhcps_poll->end_ip.addr = range_end_ip;
  1076. dhcps_poll->start_ip.addr = htonl(dhcps_poll->start_ip.addr);
  1077. dhcps_poll->end_ip.addr = htonl(dhcps_poll->end_ip.addr);
  1078. dhcps_poll->enable = true;
  1079. }
  1080. }
  1081. /******************************************************************************
  1082. * FunctionName : dhcps_set_new_lease_cb
  1083. * Description : set callback for dhcp server when it assign an IP
  1084. * to the connected dhcp client
  1085. * Parameters : cb -- callback for dhcp server
  1086. * Returns : ERR_OK on success
  1087. *******************************************************************************/
  1088. err_t dhcps_set_new_lease_cb(dhcps_t *dhcps, dhcps_cb_t cb, void* cb_arg)
  1089. {
  1090. if (dhcps == NULL) {
  1091. return ERR_ARG;
  1092. }
  1093. dhcps->dhcps_cb = cb;
  1094. dhcps->dhcps_cb_arg = cb_arg;
  1095. return ERR_OK;
  1096. }
  1097. /******************************************************************************
  1098. * FunctionName : dhcps_start
  1099. * Description : start dhcp server function
  1100. * Parameters : netif -- The current netif addr
  1101. * : info -- The current ip info
  1102. * Returns : none
  1103. *******************************************************************************/
  1104. err_t dhcps_start(dhcps_t *dhcps, struct netif *netif, ip4_addr_t ip)
  1105. {
  1106. if (dhcps == NULL || netif == NULL) {
  1107. return ERR_ARG;
  1108. }
  1109. dhcps->dhcps_netif = netif;
  1110. if (dhcps->dhcps_pcb != NULL) {
  1111. udp_remove(dhcps->dhcps_pcb);
  1112. }
  1113. dhcps->dhcps_pcb = udp_new();
  1114. if (dhcps->dhcps_pcb == NULL || ip4_addr_isany_val(ip)) {
  1115. DHCPS_LOG("dhcps_start(): could not obtain pcb\n");
  1116. return ERR_ARG;
  1117. }
  1118. IP4_ADDR(&dhcps->broadcast_dhcps, 255, 255, 255, 255);
  1119. dhcps->server_address.addr = ip.addr;
  1120. DHCP_CHECK_SUBNET_MASK_IP(htonl(dhcps->dhcps_mask.addr));
  1121. DHCP_CHECK_IP_MATCH_SUBNET_MASK(htonl(dhcps->dhcps_mask.addr), htonl(ip.addr));
  1122. dhcps_poll_set(dhcps, dhcps->server_address.addr);
  1123. dhcps->client_address_plus.addr = dhcps->dhcps_poll.start_ip.addr;
  1124. udp_bind(dhcps->dhcps_pcb, &netif->ip_addr, DHCPS_SERVER_PORT);
  1125. udp_recv(dhcps->dhcps_pcb, handle_dhcp, dhcps);
  1126. #if DHCPS_DEBUG
  1127. DHCPS_LOG("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n");
  1128. #endif
  1129. dhcps->state = DHCPS_HANDLE_STARTED;
  1130. sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcps_tmr, dhcps);
  1131. return ERR_OK;
  1132. }
  1133. /******************************************************************************
  1134. * FunctionName : dhcps_stop
  1135. * Description : stop dhcp server function
  1136. * Parameters : netif -- The current netif addr
  1137. * Returns : none
  1138. *******************************************************************************/
  1139. err_t dhcps_stop(dhcps_t *dhcps, struct netif *netif)
  1140. {
  1141. if (dhcps == NULL || netif == NULL || dhcps->dhcps_netif != netif) {
  1142. #if DHCPS_DEBUG
  1143. DHCPS_LOG("dhcps_stop: netif is NULL or invalid\n");
  1144. #endif
  1145. return ERR_ARG;
  1146. }
  1147. if (dhcps->dhcps_pcb != NULL) {
  1148. udp_disconnect(dhcps->dhcps_pcb);
  1149. udp_remove(dhcps->dhcps_pcb);
  1150. dhcps->dhcps_pcb = NULL;
  1151. }
  1152. list_node *pnode = NULL;
  1153. list_node *pback_node = NULL;
  1154. pnode = dhcps->plist;
  1155. while (pnode != NULL) {
  1156. pback_node = pnode;
  1157. pnode = pback_node->pnext;
  1158. node_remove_from_list(&dhcps->plist, pback_node);
  1159. free(pback_node->pnode);
  1160. pback_node->pnode = NULL;
  1161. free(pback_node);
  1162. pback_node = NULL;
  1163. }
  1164. sys_untimeout(dhcps_tmr, dhcps);
  1165. dhcps->state = DHCPS_HANDLE_STOPPED;
  1166. return ERR_OK;
  1167. }
  1168. /******************************************************************************
  1169. * FunctionName : kill_oldest_dhcps_pool
  1170. * Description : remove the oldest node from list
  1171. * Parameters : none
  1172. * Returns : none
  1173. *******************************************************************************/
  1174. static void kill_oldest_dhcps_pool(dhcps_t *dhcps)
  1175. {
  1176. list_node *pre = NULL, *p = NULL;
  1177. list_node *minpre = NULL, *minp = NULL;
  1178. struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL;
  1179. pre = dhcps->plist;
  1180. assert(pre != NULL && pre->pnext != NULL); // Expect the list to have at least 2 nodes
  1181. p = pre->pnext;
  1182. minpre = pre;
  1183. minp = p;
  1184. while (p != NULL) {
  1185. pdhcps_pool = p->pnode;
  1186. pmin_pool = minp->pnode;
  1187. if (pdhcps_pool->lease_timer < pmin_pool->lease_timer) {
  1188. minp = p;
  1189. minpre = pre;
  1190. }
  1191. pre = p;
  1192. p = p->pnext;
  1193. }
  1194. minpre->pnext = minp->pnext;
  1195. free(minp->pnode);
  1196. minp->pnode = NULL;
  1197. free(minp);
  1198. minp = NULL;
  1199. }
  1200. /******************************************************************************
  1201. * FunctionName : dhcps_coarse_tmr
  1202. * Description : the lease time count
  1203. * Parameters : none
  1204. * Returns : none
  1205. *******************************************************************************/
  1206. static void dhcps_tmr(void *arg)
  1207. {
  1208. dhcps_t *dhcps = arg;
  1209. dhcps_handle_state state = dhcps->state;
  1210. if (state == DHCPS_HANDLE_DELETE_PENDING) {
  1211. free(dhcps);
  1212. return;
  1213. }
  1214. if (state != DHCPS_HANDLE_STARTED) {
  1215. return;
  1216. }
  1217. sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcps_tmr, dhcps);
  1218. u8_t num_dhcps_pool = 0;
  1219. list_node *pback_node = NULL;
  1220. list_node *pnode = NULL;
  1221. struct dhcps_pool *pdhcps_pool = NULL;
  1222. pnode = dhcps->plist;
  1223. while (pnode != NULL) {
  1224. pdhcps_pool = pnode->pnode;
  1225. pdhcps_pool->lease_timer --;
  1226. if (pdhcps_pool->lease_timer == 0) {
  1227. pback_node = pnode;
  1228. pnode = pback_node->pnext;
  1229. node_remove_from_list(&dhcps->plist, pback_node);
  1230. free(pback_node->pnode);
  1231. pback_node->pnode = NULL;
  1232. free(pback_node);
  1233. pback_node = NULL;
  1234. } else {
  1235. pnode = pnode ->pnext;
  1236. num_dhcps_pool ++;
  1237. }
  1238. }
  1239. if (num_dhcps_pool > MAX_STATION_NUM) {
  1240. kill_oldest_dhcps_pool(dhcps);
  1241. }
  1242. }
  1243. /******************************************************************************
  1244. * FunctionName : dhcp_search_ip_on_mac
  1245. * Description : Search ip address based on mac address
  1246. * Parameters : mac -- The MAC addr
  1247. * ip -- The IP info
  1248. * Returns : true or false
  1249. *******************************************************************************/
  1250. bool dhcp_search_ip_on_mac(dhcps_t *dhcps, u8_t *mac, ip4_addr_t *ip)
  1251. {
  1252. struct dhcps_pool *pdhcps_pool = NULL;
  1253. list_node *pback_node = NULL;
  1254. bool ret = false;
  1255. if (dhcps == NULL) {
  1256. return false;
  1257. }
  1258. for (pback_node = dhcps->plist; pback_node != NULL; pback_node = pback_node->pnext) {
  1259. pdhcps_pool = pback_node->pnode;
  1260. if (memcmp(pdhcps_pool->mac, mac, sizeof(pdhcps_pool->mac)) == 0) {
  1261. memcpy(&ip->addr, &pdhcps_pool->ip.addr, sizeof(pdhcps_pool->ip.addr));
  1262. ret = true;
  1263. break;
  1264. }
  1265. }
  1266. return ret;
  1267. }
  1268. /******************************************************************************
  1269. * FunctionName : dhcps_dns_setserver
  1270. * Description : set DNS server address for dhcpserver
  1271. * Parameters : dnsserver -- The DNS server address
  1272. * Returns : ERR_ARG if invalid handle, ERR_OK on success
  1273. *******************************************************************************/
  1274. err_t dhcps_dns_setserver(dhcps_t *dhcps, const ip_addr_t *dnsserver)
  1275. {
  1276. if (dhcps == NULL) {
  1277. return ERR_ARG;
  1278. }
  1279. if (dnsserver != NULL) {
  1280. dhcps->dns_server = *(ip_2_ip4(dnsserver));
  1281. } else {
  1282. dhcps->dns_server = *(ip_2_ip4(IP_ADDR_ANY));
  1283. }
  1284. return ERR_OK;
  1285. }
  1286. /******************************************************************************
  1287. * FunctionName : dhcps_dns_getserver
  1288. * Description : get DNS server address for dhcpserver
  1289. * Parameters : none
  1290. * Returns : ip4_addr_t
  1291. *******************************************************************************/
  1292. err_t dhcps_dns_getserver(dhcps_t *dhcps, ip4_addr_t *dnsserver)
  1293. {
  1294. if (dhcps) {
  1295. *dnsserver = dhcps->dns_server;
  1296. return ERR_OK;
  1297. }
  1298. return ERR_ARG;
  1299. }
  1300. #endif // ESP_DHCPS