00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <stdio.h>
00035 #include <string.h>
00036
00037 #include "contiki.h"
00038 #include "contiki-net.h"
00039 #include "net/dhcpc.h"
00040
00041 #define STATE_INITIAL 0
00042 #define STATE_SENDING 1
00043 #define STATE_OFFER_RECEIVED 2
00044 #define STATE_CONFIG_RECEIVED 3
00045
00046 static struct dhcpc_state s;
00047
00048 struct dhcp_msg {
00049 u8_t op, htype, hlen, hops;
00050 u8_t xid[4];
00051 u16_t secs, flags;
00052 u8_t ciaddr[4];
00053 u8_t yiaddr[4];
00054 u8_t siaddr[4];
00055 u8_t giaddr[4];
00056 u8_t chaddr[16];
00057 #ifndef UIP_CONF_DHCP_LIGHT
00058 u8_t sname[64];
00059 u8_t file[128];
00060 #endif
00061 u8_t options[312];
00062 };
00063
00064 #define BOOTP_BROADCAST 0x8000
00065
00066 #define DHCP_REQUEST 1
00067 #define DHCP_REPLY 2
00068 #define DHCP_HTYPE_ETHERNET 1
00069 #define DHCP_HLEN_ETHERNET 6
00070 #define DHCP_MSG_LEN 236
00071
00072 #define DHCPC_SERVER_PORT 67
00073 #define DHCPC_CLIENT_PORT 68
00074
00075 #define DHCPDISCOVER 1
00076 #define DHCPOFFER 2
00077 #define DHCPREQUEST 3
00078 #define DHCPDECLINE 4
00079 #define DHCPACK 5
00080 #define DHCPNAK 6
00081 #define DHCPRELEASE 7
00082
00083 #define DHCP_OPTION_SUBNET_MASK 1
00084 #define DHCP_OPTION_ROUTER 3
00085 #define DHCP_OPTION_DNS_SERVER 6
00086 #define DHCP_OPTION_REQ_IPADDR 50
00087 #define DHCP_OPTION_LEASE_TIME 51
00088 #define DHCP_OPTION_MSG_TYPE 53
00089 #define DHCP_OPTION_SERVER_ID 54
00090 #define DHCP_OPTION_REQ_LIST 55
00091 #define DHCP_OPTION_END 255
00092
00093 static u32_t xid;
00094 static const u8_t magic_cookie[4] = {99, 130, 83, 99};
00095
00096 static u8_t *
00097 add_msg_type(u8_t *optptr, u8_t type)
00098 {
00099 *optptr++ = DHCP_OPTION_MSG_TYPE;
00100 *optptr++ = 1;
00101 *optptr++ = type;
00102 return optptr;
00103 }
00104
00105 static u8_t *
00106 add_server_id(u8_t *optptr)
00107 {
00108 *optptr++ = DHCP_OPTION_SERVER_ID;
00109 *optptr++ = 4;
00110 memcpy(optptr, s.serverid, 4);
00111 return optptr + 4;
00112 }
00113
00114 static u8_t *
00115 add_req_ipaddr(u8_t *optptr)
00116 {
00117 *optptr++ = DHCP_OPTION_REQ_IPADDR;
00118 *optptr++ = 4;
00119 memcpy(optptr, s.ipaddr.u16, 4);
00120 return optptr + 4;
00121 }
00122
00123 static u8_t *
00124 add_req_options(u8_t *optptr)
00125 {
00126 *optptr++ = DHCP_OPTION_REQ_LIST;
00127 *optptr++ = 3;
00128 *optptr++ = DHCP_OPTION_SUBNET_MASK;
00129 *optptr++ = DHCP_OPTION_ROUTER;
00130 *optptr++ = DHCP_OPTION_DNS_SERVER;
00131 return optptr;
00132 }
00133
00134 static u8_t *
00135 add_end(u8_t *optptr)
00136 {
00137 *optptr++ = DHCP_OPTION_END;
00138 return optptr;
00139 }
00140
00141 static void
00142 create_msg(CC_REGISTER_ARG struct dhcp_msg *m)
00143 {
00144 m->op = DHCP_REQUEST;
00145 m->htype = DHCP_HTYPE_ETHERNET;
00146 m->hlen = s.mac_len;
00147 m->hops = 0;
00148 memcpy(m->xid, &xid, sizeof(m->xid));
00149 m->secs = 0;
00150 m->flags = UIP_HTONS(BOOTP_BROADCAST);
00151
00152 memcpy(m->ciaddr, uip_hostaddr.u16, sizeof(m->ciaddr));
00153 memset(m->yiaddr, 0, sizeof(m->yiaddr));
00154 memset(m->siaddr, 0, sizeof(m->siaddr));
00155 memset(m->giaddr, 0, sizeof(m->giaddr));
00156 memcpy(m->chaddr, s.mac_addr, s.mac_len);
00157 memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
00158 #ifndef UIP_CONF_DHCP_LIGHT
00159 memset(m->sname, 0, sizeof(m->sname));
00160 memset(m->file, 0, sizeof(m->file));
00161 #endif
00162
00163 memcpy(m->options, magic_cookie, sizeof(magic_cookie));
00164 }
00165
00166 static void
00167 send_discover(void)
00168 {
00169 u8_t *end;
00170 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00171
00172 create_msg(m);
00173
00174 end = add_msg_type(&m->options[4], DHCPDISCOVER);
00175 end = add_req_options(end);
00176 end = add_end(end);
00177
00178 uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata));
00179 }
00180
00181 static void
00182 send_request(void)
00183 {
00184 u8_t *end;
00185 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00186
00187 create_msg(m);
00188
00189 end = add_msg_type(&m->options[4], DHCPREQUEST);
00190 end = add_server_id(end);
00191 end = add_req_ipaddr(end);
00192 end = add_end(end);
00193
00194 uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata));
00195 }
00196
00197 static u8_t
00198 parse_options(u8_t *optptr, int len)
00199 {
00200 u8_t *end = optptr + len;
00201 u8_t type = 0;
00202
00203 while(optptr < end) {
00204 switch(*optptr) {
00205 case DHCP_OPTION_SUBNET_MASK:
00206 memcpy(s.netmask.u16, optptr + 2, 4);
00207 break;
00208 case DHCP_OPTION_ROUTER:
00209 memcpy(s.default_router.u16, optptr + 2, 4);
00210 break;
00211 case DHCP_OPTION_DNS_SERVER:
00212 memcpy(s.dnsaddr.u16, optptr + 2, 4);
00213 break;
00214 case DHCP_OPTION_MSG_TYPE:
00215 type = *(optptr + 2);
00216 break;
00217 case DHCP_OPTION_SERVER_ID:
00218 memcpy(s.serverid, optptr + 2, 4);
00219 break;
00220 case DHCP_OPTION_LEASE_TIME:
00221 memcpy(s.lease_time, optptr + 2, 4);
00222 break;
00223 case DHCP_OPTION_END:
00224 return type;
00225 }
00226
00227 optptr += optptr[1] + 2;
00228 }
00229 return type;
00230 }
00231
00232 static u8_t
00233 parse_msg(void)
00234 {
00235 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00236
00237 if(m->op == DHCP_REPLY &&
00238 memcmp(m->xid, &xid, sizeof(xid)) == 0 &&
00239 memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
00240 memcpy(s.ipaddr.u16, m->yiaddr, 4);
00241 return parse_options(&m->options[4], uip_datalen());
00242 }
00243 return 0;
00244 }
00245
00246
00247
00248
00249 static int
00250 msg_for_me(void)
00251 {
00252 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00253 u8_t *optptr = &m->options[4];
00254 u8_t *end = (u8_t*)uip_appdata + uip_datalen();
00255
00256 if(m->op == DHCP_REPLY &&
00257 memcmp(m->xid, &xid, sizeof(xid)) == 0 &&
00258 memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
00259 while(optptr < end) {
00260 if(*optptr == DHCP_OPTION_MSG_TYPE) {
00261 return *(optptr + 2);
00262 } else if (*optptr == DHCP_OPTION_END) {
00263 return -1;
00264 }
00265 optptr += optptr[1] + 2;
00266 }
00267 }
00268 return -1;
00269 }
00270
00271 static
00272 PT_THREAD(handle_dhcp(process_event_t ev, void *data))
00273 {
00274 PT_BEGIN(&s.pt);
00275
00276 init:
00277 xid++;
00278 s.state = STATE_SENDING;
00279 s.ticks = CLOCK_SECOND;
00280 while (1) {
00281 while(ev != tcpip_event) {
00282 tcpip_poll_udp(s.conn);
00283 PT_YIELD(&s.pt);
00284 }
00285 send_discover();
00286 etimer_set(&s.etimer, s.ticks);
00287 do {
00288 PT_YIELD(&s.pt);
00289 if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPOFFER) {
00290 parse_msg();
00291 s.state = STATE_OFFER_RECEIVED;
00292 goto selecting;
00293 }
00294 } while (!etimer_expired(&s.etimer));
00295
00296 if(s.ticks < CLOCK_SECOND * 60) {
00297 s.ticks *= 2;
00298 }
00299 }
00300
00301 selecting:
00302 xid++;
00303 s.ticks = CLOCK_SECOND;
00304 do {
00305 while(ev != tcpip_event) {
00306 tcpip_poll_udp(s.conn);
00307 PT_YIELD(&s.pt);
00308 }
00309 send_request();
00310 etimer_set(&s.etimer, s.ticks);
00311 do {
00312 PT_YIELD(&s.pt);
00313 if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) {
00314 parse_msg();
00315 s.state = STATE_CONFIG_RECEIVED;
00316 goto bound;
00317 }
00318 } while (!etimer_expired(&s.etimer));
00319
00320 if(s.ticks <= CLOCK_SECOND * 10) {
00321 s.ticks += CLOCK_SECOND;
00322 } else {
00323 goto init;
00324 }
00325 } while(s.state != STATE_CONFIG_RECEIVED);
00326
00327 bound:
00328 #if 0
00329 printf("Got IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.ipaddr));
00330 printf("Got netmask %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.netmask));
00331 printf("Got DNS server %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.dnsaddr));
00332 printf("Got default router %d.%d.%d.%d\n",
00333 uip_ipaddr_to_quad(&s.default_router));
00334 printf("Lease expires in %ld seconds\n",
00335 uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]));
00336 #endif
00337
00338 dhcpc_configured(&s);
00339
00340 #define MAX_TICKS (~((clock_time_t)0) / 2)
00341 #define MAX_TICKS32 (~((u32_t)0))
00342 #define IMIN(a, b) ((a) < (b) ? (a) : (b))
00343
00344 if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2
00345 <= MAX_TICKS32) {
00346 s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])
00347 )*CLOCK_SECOND/2;
00348 } else {
00349 s.ticks = MAX_TICKS32;
00350 }
00351
00352 while(s.ticks > 0) {
00353 clock_time_t ticks;
00354 ticks = IMIN(s.ticks, MAX_TICKS);
00355 s.ticks -= ticks;
00356 etimer_set(&s.etimer, ticks);
00357 PT_YIELD_UNTIL(&s.pt, etimer_expired(&s.etimer));
00358 }
00359
00360 if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2
00361 <= MAX_TICKS32) {
00362 s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])
00363 )*CLOCK_SECOND/2;
00364 } else {
00365 s.ticks = MAX_TICKS32;
00366 }
00367
00368
00369 xid++;
00370 do {
00371 clock_time_t ticks;
00372 while(ev != tcpip_event) {
00373 tcpip_poll_udp(s.conn);
00374 PT_YIELD(&s.pt);
00375 }
00376 send_request();
00377 ticks = IMIN(s.ticks / 2, MAX_TICKS);
00378 s.ticks -= ticks;
00379 etimer_set(&s.etimer, ticks);
00380 do {
00381 PT_YIELD(&s.pt);
00382 if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) {
00383 parse_msg();
00384 goto bound;
00385 }
00386 } while(!etimer_expired(&s.etimer));
00387 } while(s.ticks >= CLOCK_SECOND*3);
00388
00389
00390
00391
00392 dhcpc_unconfigured(&s);
00393 goto init;
00394
00395 PT_END(&s.pt);
00396 }
00397
00398 void
00399 dhcpc_init(const void *mac_addr, int mac_len)
00400 {
00401 uip_ipaddr_t addr;
00402
00403 s.mac_addr = mac_addr;
00404 s.mac_len = mac_len;
00405
00406 s.state = STATE_INITIAL;
00407 uip_ipaddr(&addr, 255,255,255,255);
00408 s.conn = udp_new(&addr, UIP_HTONS(DHCPC_SERVER_PORT), NULL);
00409 if(s.conn != NULL) {
00410 udp_bind(s.conn, UIP_HTONS(DHCPC_CLIENT_PORT));
00411 }
00412 PT_INIT(&s.pt);
00413 }
00414
00415 void
00416 dhcpc_appcall(process_event_t ev, void *data)
00417 {
00418 if(ev == tcpip_event || ev == PROCESS_EVENT_TIMER) {
00419 handle_dhcp(ev, data);
00420 }
00421 }
00422
00423 void
00424 dhcpc_request(void)
00425 {
00426 uip_ipaddr_t ipaddr;
00427
00428 if(s.state == STATE_INITIAL) {
00429 uip_ipaddr(&ipaddr, 0,0,0,0);
00430 uip_sethostaddr(&ipaddr);
00431 handle_dhcp(PROCESS_EVENT_NONE, NULL);
00432 }
00433 }
00434