dhserver.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. #include "dhserver.h"
  25. #include "usb_eth.h"
  26. /* DHCP message type */
  27. #define DHCP_DISCOVER 1
  28. #define DHCP_OFFER 2
  29. #define DHCP_REQUEST 3
  30. #define DHCP_DECLINE 4
  31. #define DHCP_ACK 5
  32. #define DHCP_NAK 6
  33. #define DHCP_RELEASE 7
  34. #define DHCP_INFORM 8
  35. /* DHCP options */
  36. enum DHCP_OPTIONS
  37. {
  38. DHCP_PAD = 0,
  39. DHCP_SUBNETMASK = 1,
  40. DHCP_ROUTER = 3,
  41. DHCP_DNSSERVER = 6,
  42. DHCP_HOSTNAME = 12,
  43. DHCP_DNSDOMAIN = 15,
  44. DHCP_MTU = 26,
  45. DHCP_BROADCAST = 28,
  46. DHCP_PERFORMROUTERDISC = 31,
  47. DHCP_STATICROUTE = 33,
  48. DHCP_NISDOMAIN = 40,
  49. DHCP_NISSERVER = 41,
  50. DHCP_NTPSERVER = 42,
  51. DHCP_VENDOR = 43,
  52. DHCP_IPADDRESS = 50,
  53. DHCP_LEASETIME = 51,
  54. DHCP_OPTIONSOVERLOADED = 52,
  55. DHCP_MESSAGETYPE = 53,
  56. DHCP_SERVERID = 54,
  57. DHCP_PARAMETERREQUESTLIST = 55,
  58. DHCP_MESSAGE = 56,
  59. DHCP_MAXMESSAGESIZE = 57,
  60. DHCP_RENEWALTIME = 58,
  61. DHCP_REBINDTIME = 59,
  62. DHCP_CLASSID = 60,
  63. DHCP_CLIENTID = 61,
  64. DHCP_USERCLASS = 77, /* RFC 3004 */
  65. DHCP_FQDN = 81,
  66. DHCP_DNSSEARCH = 119, /* RFC 3397 */
  67. DHCP_CSR = 121, /* RFC 3442 */
  68. DHCP_MSCSR = 249, /* MS code for RFC 3442 */
  69. DHCP_END = 255,
  70. };
  71. typedef struct
  72. {
  73. uint8_t dp_op; /* packet opcode type */
  74. uint8_t dp_htype; /* hardware addr type */
  75. uint8_t dp_hlen; /* hardware addr length */
  76. uint8_t dp_hops; /* gateway hops */
  77. uint32_t dp_xid; /* transaction ID */
  78. uint16_t dp_secs; /* seconds since boot began */
  79. uint16_t dp_flags;
  80. uint8_t dp_ciaddr[4]; /* client IP address */
  81. uint8_t dp_yiaddr[4]; /* 'your' IP address */
  82. uint8_t dp_siaddr[4]; /* server IP address */
  83. uint8_t dp_giaddr[4]; /* gateway IP address */
  84. uint8_t dp_chaddr[16]; /* client hardware address */
  85. uint8_t dp_legacy[192];
  86. uint8_t dp_magic[4];
  87. uint8_t dp_options[275]; /* options area */
  88. } DHCP_TYPE;
  89. DHCP_TYPE dhcp_data;
  90. static struct udp_pcb *pcb = NULL;
  91. static dhcp_config_t *config = NULL;
  92. char magic_cookie[] = {0x63,0x82,0x53,0x63};
  93. static dhcp_entry_t *entry_by_ip(uint32_t ip)
  94. {
  95. int i;
  96. for (i = 0; i < config->num_entry; i++)
  97. if (*(uint32_t *)config->entries[i].addr == ip)
  98. return &config->entries[i];
  99. return NULL;
  100. }
  101. static dhcp_entry_t *entry_by_mac(uint8_t *mac)
  102. {
  103. int i;
  104. for (i = 0; i < config->num_entry; i++)
  105. if (memcmp(config->entries[i].mac, mac, 6) == 0)
  106. return &config->entries[i];
  107. return NULL;
  108. }
  109. static inline bool is_vacant(dhcp_entry_t *entry)
  110. {
  111. return memcmp("\0\0\0\0\0", entry->mac, 6) == 0;
  112. }
  113. static dhcp_entry_t *vacant_address()
  114. {
  115. int i;
  116. for (i = 0; i < config->num_entry; i++)
  117. if (is_vacant(config->entries + i))
  118. return config->entries + 1;
  119. return NULL;
  120. }
  121. static inline void free_entry(dhcp_entry_t *entry)
  122. {
  123. memset(entry->mac, 0, 6);
  124. }
  125. uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr)
  126. {
  127. int i = 0;
  128. while ((i + 1) < size)
  129. {
  130. int next = i + attrs[i + 1] + 2;
  131. if (next > size) return NULL;
  132. if (attrs[i] == attr)
  133. return attrs + i;
  134. i = next;
  135. }
  136. return NULL;
  137. }
  138. int fill_options(void *dest,
  139. uint8_t msg_type,
  140. const char *domain,
  141. uint32_t dns,
  142. int lease_time,
  143. uint32_t serverid,
  144. uint32_t router,
  145. uint32_t subnet)
  146. {
  147. uint8_t *ptr = (uint8_t *)dest;
  148. // ACK message type
  149. *ptr++ = 53;
  150. *ptr++ = 1;
  151. *ptr++ = msg_type;
  152. // dhcp server identifier
  153. *ptr++ = DHCP_SERVERID;
  154. *ptr++ = 4;
  155. *(uint32_t *)ptr = serverid;
  156. ptr += 4;
  157. // lease time
  158. *ptr++ = DHCP_LEASETIME;
  159. *ptr++ = 4;
  160. *ptr++ = (lease_time >> 24) & 0xFF;
  161. *ptr++ = (lease_time >> 16) & 0xFF;
  162. *ptr++ = (lease_time >> 8) & 0xFF;
  163. *ptr++ = (lease_time >> 0) & 0xFF;
  164. // subnet mask
  165. *ptr++ = DHCP_SUBNETMASK;
  166. *ptr++ = 4;
  167. *(uint32_t *)ptr = subnet;
  168. ptr += 4;
  169. // router
  170. if (router != 0)
  171. {
  172. *ptr++ = DHCP_ROUTER;
  173. *ptr++ = 4;
  174. *(uint32_t *)ptr = router;
  175. ptr += 4;
  176. }
  177. // domain name
  178. if (domain != NULL)
  179. {
  180. int len = strlen(domain);
  181. *ptr++ = DHCP_DNSDOMAIN;
  182. *ptr++ = len;
  183. memcpy(ptr, domain, len);
  184. ptr += len;
  185. }
  186. // domain name server (DNS)
  187. if (dns != 0)
  188. {
  189. *ptr++ = DHCP_DNSSERVER;
  190. *ptr++ = 4;
  191. *(uint32_t *)ptr = dns;
  192. ptr += 4;
  193. }
  194. // end
  195. *ptr++ = DHCP_END;
  196. return ptr - (uint8_t *)dest;
  197. ///*
  198. // // static route
  199. // *option_ptr++ = DHCP_STATICROUTE;
  200. // *option_ptr++ = 8;
  201. // *option_ptr++ = ((uint8_t *)&server_ip)[0];
  202. // *option_ptr++ = ((uint8_t *)&server_ip)[1];
  203. // *option_ptr++ = ((uint8_t *)&server_ip)[2];
  204. // *option_ptr++ = 0;
  205. // memcpy(option_ptr, &server_ip, 4);
  206. // option_ptr += 4;
  207. //*/
  208. ///*
  209. // *option_ptr++ = 0x2e; // NetBIOS over TCP/IP Node Type Option
  210. // *option_ptr++ = 1;
  211. // *option_ptr++ = 1;
  212. //
  213. // *option_ptr++ = 0x2c; // NetBIOS over TCP/IP Name Server Option
  214. // *option_ptr++ = 4;
  215. // memcpy(option_ptr, &server_ip, 4);
  216. // option_ptr += 4;
  217. //*/
  218. // /*
  219. // *option_ptr++ = DHCP_MSCSR;
  220. // *option_ptr++ = 8;
  221. // *option_ptr++ = 24;
  222. // *option_ptr++ = 192;
  223. // *option_ptr++ = 168;
  224. // *option_ptr++ = 0;
  225. // *option_ptr++ = 192;
  226. // *option_ptr++ = 168;
  227. // *option_ptr++ = 0;
  228. // *option_ptr++ = 11;
  229. // */
  230. // // renewal time
  231. //
  232. // *option_ptr++ = DHCP_RENEWALTIME;
  233. // *option_ptr++ = 4;
  234. // *option_ptr++ = 0;
  235. // *option_ptr++ = 0;
  236. // *option_ptr++ = 0x38;
  237. // *option_ptr++ = 0x40;
  238. //
  239. //
  240. // // rebinding time
  241. //
  242. // *option_ptr++ = DHCP_REBINDTIME;
  243. // *option_ptr++ = 4;
  244. // *option_ptr++ = 0;
  245. // *option_ptr++ = 0;
  246. // *option_ptr++ = 0x62;
  247. // *option_ptr++ = 0x70;
  248. //
  249. ///*
  250. // // domain name
  251. // *option_ptr++ = DHCP_DNSDOMAIN;
  252. // int len = sprintf((char*)option_ptr+1, "stm32f4.net");
  253. // *option_ptr = (len + 1);
  254. // option_ptr += (len + 2);
  255. // // Option: (31) Perform Router Discover
  256. // *option_ptr++ = DHCP_PERFORMROUTERDISC;
  257. // *option_ptr++ = 1;
  258. // *option_ptr++ = 1;
  259. //*/
  260. // end
  261. }
  262. static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
  263. {
  264. uint8_t *ptr;
  265. dhcp_entry_t *entry;
  266. struct pbuf *pp;
  267. int n = p->len;
  268. if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data);
  269. memcpy(&dhcp_data, p->payload, n);
  270. switch (dhcp_data.dp_options[2])
  271. {
  272. case DHCP_DISCOVER:
  273. entry = entry_by_mac(dhcp_data.dp_chaddr);
  274. if (entry == NULL) entry = vacant_address();
  275. if (entry == NULL) break;
  276. dhcp_data.dp_op = 2; // reply
  277. dhcp_data.dp_secs = 0;
  278. dhcp_data.dp_flags = 0;
  279. *(uint32_t *)dhcp_data.dp_yiaddr = *(uint32_t *)entry->addr;
  280. memcpy(dhcp_data.dp_magic, magic_cookie, 4);
  281. memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
  282. fill_options(dhcp_data.dp_options,
  283. DHCP_OFFER,
  284. config->domain,
  285. *(uint32_t *)config->dns,
  286. entry->lease,
  287. *(uint32_t *)config->addr,
  288. *(uint32_t *)config->addr,
  289. *(uint32_t *)entry->subnet);
  290. pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
  291. if (pp == NULL) break;
  292. memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
  293. //udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
  294. udp_sendto_if(upcb, pp, IP_ADDR_BROADCAST, port, &netif_data);
  295. pbuf_free(pp);
  296. break;
  297. case DHCP_REQUEST:
  298. // 1. find requested ipaddr in option list
  299. ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS);
  300. if (ptr == NULL) break;
  301. if (ptr[1] != 4) break;
  302. ptr += 2;
  303. // 2. does hw-address registered?
  304. entry = entry_by_mac(dhcp_data.dp_chaddr);
  305. if (entry != NULL) free_entry(entry);
  306. // 3. find requested ipaddr
  307. entry = entry_by_ip(*(uint32_t *)ptr);
  308. if (entry == NULL) break;
  309. if (!is_vacant(entry)) break;
  310. // 4. fill struct fields
  311. memcpy(dhcp_data.dp_yiaddr, ptr, 4);
  312. dhcp_data.dp_op = 2; // reply
  313. dhcp_data.dp_secs = 0;
  314. dhcp_data.dp_flags = 0;
  315. memcpy(dhcp_data.dp_magic, magic_cookie, 4);
  316. // 5. fill options
  317. memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
  318. fill_options(dhcp_data.dp_options,
  319. DHCP_ACK,
  320. config->domain,
  321. *(uint32_t *)config->dns,
  322. entry->lease,
  323. *(uint32_t *)config->addr,
  324. *(uint32_t *)config->addr,
  325. *(uint32_t *)entry->subnet);
  326. // 6. send ACK
  327. pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
  328. if (pp == NULL) break;
  329. memcpy(entry->mac, dhcp_data.dp_chaddr, 6);
  330. memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
  331. //udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
  332. udp_sendto_if(upcb, pp, IP_ADDR_BROADCAST, port, &netif_data);
  333. pbuf_free(pp);
  334. break;
  335. default:
  336. break;
  337. }
  338. pbuf_free(p);
  339. }
  340. err_t dhserv_init(dhcp_config_t *c)
  341. {
  342. err_t err;
  343. udp_init();
  344. dhserv_free();
  345. pcb = udp_new();
  346. if (pcb == NULL)
  347. return ERR_MEM;
  348. err = udp_bind(pcb, IP_ADDR_ANY, c->port);
  349. if (err != ERR_OK)
  350. {
  351. dhserv_free();
  352. return err;
  353. }
  354. //typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
  355. udp_recv(pcb, (udp_recv_fn)udp_recv_proc, NULL);
  356. config = c;
  357. return ERR_OK;
  358. }
  359. void dhserv_free(void)
  360. {
  361. if (pcb == NULL) return;
  362. udp_remove(pcb);
  363. pcb = NULL;
  364. }