1
0

dhcpc.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. * Copyright (c) 2005, Swedish Institute of Computer Science
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the Institute nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * This file is part of the uIP TCP/IP stack
  30. *
  31. * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $
  32. */
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include "uip.h"
  36. #include "dhcpc.h"
  37. #include "timer.h"
  38. #include "pt.h"
  39. #define STATE_INITIAL 0
  40. #define STATE_SENDING 1
  41. #define STATE_OFFER_RECEIVED 2
  42. #define STATE_CONFIG_RECEIVED 3
  43. static struct dhcpc_state s;
  44. struct dhcp_msg {
  45. u8_t op, htype, hlen, hops;
  46. u8_t xid[4];
  47. u16_t secs, flags;
  48. u8_t ciaddr[4];
  49. u8_t yiaddr[4];
  50. u8_t siaddr[4];
  51. u8_t giaddr[4];
  52. u8_t chaddr[16];
  53. #ifndef UIP_CONF_DHCP_LIGHT
  54. u8_t sname[64];
  55. u8_t file[128];
  56. #endif
  57. u8_t options[312];
  58. };
  59. #define BOOTP_BROADCAST 0x8000
  60. #define DHCP_REQUEST 1
  61. #define DHCP_REPLY 2
  62. #define DHCP_HTYPE_ETHERNET 1
  63. #define DHCP_HLEN_ETHERNET 6
  64. #define DHCP_MSG_LEN 236
  65. #define DHCPC_SERVER_PORT 67
  66. #define DHCPC_CLIENT_PORT 68
  67. #define DHCPDISCOVER 1
  68. #define DHCPOFFER 2
  69. #define DHCPREQUEST 3
  70. #define DHCPDECLINE 4
  71. #define DHCPACK 5
  72. #define DHCPNAK 6
  73. #define DHCPRELEASE 7
  74. #define DHCP_OPTION_SUBNET_MASK 1
  75. #define DHCP_OPTION_ROUTER 3
  76. #define DHCP_OPTION_DNS_SERVER 6
  77. #define DHCP_OPTION_REQ_IPADDR 50
  78. #define DHCP_OPTION_LEASE_TIME 51
  79. #define DHCP_OPTION_MSG_TYPE 53
  80. #define DHCP_OPTION_SERVER_ID 54
  81. #define DHCP_OPTION_REQ_LIST 55
  82. #define DHCP_OPTION_END 255
  83. static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
  84. static const u8_t magic_cookie[4] = {99, 130, 83, 99};
  85. /*---------------------------------------------------------------------------*/
  86. static u8_t *
  87. add_msg_type(u8_t *optptr, u8_t type)
  88. {
  89. *optptr++ = DHCP_OPTION_MSG_TYPE;
  90. *optptr++ = 1;
  91. *optptr++ = type;
  92. return optptr;
  93. }
  94. /*---------------------------------------------------------------------------*/
  95. static u8_t *
  96. add_server_id(u8_t *optptr)
  97. {
  98. *optptr++ = DHCP_OPTION_SERVER_ID;
  99. *optptr++ = 4;
  100. memcpy(optptr, s.serverid, 4);
  101. return optptr + 4;
  102. }
  103. /*---------------------------------------------------------------------------*/
  104. static u8_t *
  105. add_req_ipaddr(u8_t *optptr)
  106. {
  107. *optptr++ = DHCP_OPTION_REQ_IPADDR;
  108. *optptr++ = 4;
  109. memcpy(optptr, s.ipaddr, 4);
  110. return optptr + 4;
  111. }
  112. /*---------------------------------------------------------------------------*/
  113. static u8_t *
  114. add_req_options(u8_t *optptr)
  115. {
  116. *optptr++ = DHCP_OPTION_REQ_LIST;
  117. *optptr++ = 3;
  118. *optptr++ = DHCP_OPTION_SUBNET_MASK;
  119. *optptr++ = DHCP_OPTION_ROUTER;
  120. *optptr++ = DHCP_OPTION_DNS_SERVER;
  121. return optptr;
  122. }
  123. /*---------------------------------------------------------------------------*/
  124. static u8_t *
  125. add_end(u8_t *optptr)
  126. {
  127. *optptr++ = DHCP_OPTION_END;
  128. return optptr;
  129. }
  130. /*---------------------------------------------------------------------------*/
  131. static void
  132. create_msg(register struct dhcp_msg *m)
  133. {
  134. m->op = DHCP_REQUEST;
  135. m->htype = DHCP_HTYPE_ETHERNET;
  136. m->hlen = s.mac_len;
  137. m->hops = 0;
  138. memcpy(m->xid, xid, sizeof(m->xid));
  139. m->secs = 0;
  140. m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
  141. /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
  142. memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
  143. memset(m->yiaddr, 0, sizeof(m->yiaddr));
  144. memset(m->siaddr, 0, sizeof(m->siaddr));
  145. memset(m->giaddr, 0, sizeof(m->giaddr));
  146. memcpy(m->chaddr, s.mac_addr, s.mac_len);
  147. memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
  148. #ifndef UIP_CONF_DHCP_LIGHT
  149. memset(m->sname, 0, sizeof(m->sname));
  150. memset(m->file, 0, sizeof(m->file));
  151. #endif
  152. memcpy(m->options, magic_cookie, sizeof(magic_cookie));
  153. }
  154. /*---------------------------------------------------------------------------*/
  155. static void
  156. send_discover(void)
  157. {
  158. u8_t *end;
  159. struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
  160. create_msg(m);
  161. end = add_msg_type(&m->options[4], DHCPDISCOVER);
  162. end = add_req_options(end);
  163. end = add_end(end);
  164. uip_send(uip_appdata, end - (u8_t *)uip_appdata);
  165. }
  166. /*---------------------------------------------------------------------------*/
  167. static void
  168. send_request(void)
  169. {
  170. u8_t *end;
  171. struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
  172. create_msg(m);
  173. end = add_msg_type(&m->options[4], DHCPREQUEST);
  174. end = add_server_id(end);
  175. end = add_req_ipaddr(end);
  176. end = add_end(end);
  177. uip_send(uip_appdata, end - (u8_t *)uip_appdata);
  178. }
  179. /*---------------------------------------------------------------------------*/
  180. static u8_t
  181. parse_options(u8_t *optptr, int len)
  182. {
  183. u8_t *end = optptr + len;
  184. u8_t type = 0;
  185. while(optptr < end) {
  186. switch(*optptr) {
  187. case DHCP_OPTION_SUBNET_MASK:
  188. memcpy(s.netmask, optptr + 2, 4);
  189. break;
  190. case DHCP_OPTION_ROUTER:
  191. memcpy(s.default_router, optptr + 2, 4);
  192. break;
  193. case DHCP_OPTION_DNS_SERVER:
  194. memcpy(s.dnsaddr, optptr + 2, 4);
  195. break;
  196. case DHCP_OPTION_MSG_TYPE:
  197. type = *(optptr + 2);
  198. break;
  199. case DHCP_OPTION_SERVER_ID:
  200. memcpy(s.serverid, optptr + 2, 4);
  201. break;
  202. case DHCP_OPTION_LEASE_TIME:
  203. memcpy(s.lease_time, optptr + 2, 4);
  204. break;
  205. case DHCP_OPTION_END:
  206. return type;
  207. }
  208. optptr += optptr[1] + 2;
  209. }
  210. return type;
  211. }
  212. /*---------------------------------------------------------------------------*/
  213. static u8_t
  214. parse_msg(void)
  215. {
  216. struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
  217. if(m->op == DHCP_REPLY &&
  218. memcmp(m->xid, xid, sizeof(xid)) == 0 &&
  219. memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
  220. memcpy(s.ipaddr, m->yiaddr, 4);
  221. return parse_options(&m->options[4], uip_datalen());
  222. }
  223. return 0;
  224. }
  225. /*---------------------------------------------------------------------------*/
  226. static
  227. PT_THREAD(handle_dhcp(void))
  228. {
  229. PT_BEGIN(&s.pt);
  230. /* try_again:*/
  231. s.state = STATE_SENDING;
  232. s.ticks = CLOCK_SECOND;
  233. do {
  234. send_discover();
  235. timer_set(&s.timer, s.ticks);
  236. PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
  237. if(uip_newdata() && parse_msg() == DHCPOFFER) {
  238. s.state = STATE_OFFER_RECEIVED;
  239. break;
  240. }
  241. if(s.ticks < CLOCK_SECOND * 60) {
  242. s.ticks *= 2;
  243. }
  244. } while(s.state != STATE_OFFER_RECEIVED);
  245. s.ticks = CLOCK_SECOND;
  246. do {
  247. send_request();
  248. timer_set(&s.timer, s.ticks);
  249. PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
  250. if(uip_newdata() && parse_msg() == DHCPACK) {
  251. s.state = STATE_CONFIG_RECEIVED;
  252. break;
  253. }
  254. if(s.ticks <= CLOCK_SECOND * 10) {
  255. s.ticks += CLOCK_SECOND;
  256. } else {
  257. PT_RESTART(&s.pt);
  258. }
  259. } while(s.state != STATE_CONFIG_RECEIVED);
  260. #if 0
  261. printf("Got IP address %d.%d.%d.%d\n",
  262. uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
  263. uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
  264. printf("Got netmask %d.%d.%d.%d\n",
  265. uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
  266. uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
  267. printf("Got DNS server %d.%d.%d.%d\n",
  268. uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
  269. uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
  270. printf("Got default router %d.%d.%d.%d\n",
  271. uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
  272. uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));
  273. printf("Lease expires in %ld seconds\n",
  274. ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1]));
  275. #endif
  276. dhcpc_configured(&s);
  277. /* timer_stop(&s.timer);*/
  278. /*
  279. * PT_END restarts the thread so we do this instead. Eventually we
  280. * should reacquire expired leases here.
  281. */
  282. while(1) {
  283. PT_YIELD(&s.pt);
  284. }
  285. PT_END(&s.pt);
  286. }
  287. /*---------------------------------------------------------------------------*/
  288. void
  289. dhcpc_init(const void *mac_addr, int mac_len)
  290. {
  291. uip_ipaddr_t addr;
  292. s.mac_addr = mac_addr;
  293. s.mac_len = mac_len;
  294. s.state = STATE_INITIAL;
  295. uip_ipaddr(addr, 255,255,255,255);
  296. s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT));
  297. if(s.conn != NULL) {
  298. uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
  299. }
  300. PT_INIT(&s.pt);
  301. }
  302. /*---------------------------------------------------------------------------*/
  303. void
  304. dhcpc_appcall(void)
  305. {
  306. handle_dhcp();
  307. }
  308. /*---------------------------------------------------------------------------*/
  309. void
  310. dhcpc_request(void)
  311. {
  312. u16_t ipaddr[2];
  313. if(s.state == STATE_INITIAL) {
  314. uip_ipaddr(ipaddr, 0,0,0,0);
  315. uip_sethostaddr(ipaddr);
  316. /* handle_dhcp(PROCESS_EVENT_NONE, NULL);*/
  317. }
  318. }
  319. /*---------------------------------------------------------------------------*/