Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2005, Swedish Institute of Computer Science 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * @(#)$Id: dhcpc.c,v 1.9 2010/10/19 18:29:04 adamdunkels Exp $ 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 uint8_t op, htype, hlen, hops; 00050 uint8_t xid[4]; 00051 uint16_t secs, flags; 00052 uint8_t ciaddr[4]; 00053 uint8_t yiaddr[4]; 00054 uint8_t siaddr[4]; 00055 uint8_t giaddr[4]; 00056 uint8_t chaddr[16]; 00057 #ifndef UIP_CONF_DHCP_LIGHT 00058 uint8_t sname[64]; 00059 uint8_t file[128]; 00060 #endif 00061 uint8_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 uint32_t xid; 00094 static const uint8_t magic_cookie[4] = {99, 130, 83, 99}; 00095 /*---------------------------------------------------------------------------*/ 00096 static uint8_t * 00097 add_msg_type(uint8_t *optptr, uint8_t type) 00098 { 00099 *optptr++ = DHCP_OPTION_MSG_TYPE; 00100 *optptr++ = 1; 00101 *optptr++ = type; 00102 return optptr; 00103 } 00104 /*---------------------------------------------------------------------------*/ 00105 static uint8_t * 00106 add_server_id(uint8_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 uint8_t * 00115 add_req_ipaddr(uint8_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 uint8_t * 00124 add_req_options(uint8_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 uint8_t * 00135 add_end(uint8_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); /* Broadcast bit. */ 00151 /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/ 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 uint8_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 - (uint8_t *)uip_appdata)); 00179 } 00180 /*---------------------------------------------------------------------------*/ 00181 static void 00182 send_request(void) 00183 { 00184 uint8_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 - (uint8_t *)uip_appdata)); 00195 } 00196 /*---------------------------------------------------------------------------*/ 00197 static uint8_t 00198 parse_options(uint8_t *optptr, int len) 00199 { 00200 uint8_t *end = optptr + len; 00201 uint8_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 uint8_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 * Is this a "fresh" reply for me? If it is, return the type. 00248 */ 00249 static int 00250 msg_for_me(void) 00251 { 00252 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00253 uint8_t *optptr = &m->options[4]; 00254 uint8_t *end = (uint8_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 clock_time_t ticks; 00275 00276 PT_BEGIN(&s.pt); 00277 00278 init: 00279 xid++; 00280 s.state = STATE_SENDING; 00281 s.ticks = CLOCK_SECOND; 00282 while (1) { 00283 while(ev != tcpip_event) { 00284 tcpip_poll_udp(s.conn); 00285 PT_YIELD(&s.pt); 00286 } 00287 send_discover(); 00288 etimer_set(&s.etimer, s.ticks); 00289 do { 00290 PT_YIELD(&s.pt); 00291 if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPOFFER) { 00292 parse_msg(); 00293 s.state = STATE_OFFER_RECEIVED; 00294 goto selecting; 00295 } 00296 } while (!etimer_expired(&s.etimer)); 00297 00298 if(s.ticks < CLOCK_SECOND * 60) { 00299 s.ticks *= 2; 00300 } 00301 } 00302 00303 selecting: 00304 xid++; 00305 s.ticks = CLOCK_SECOND; 00306 do { 00307 while(ev != tcpip_event) { 00308 tcpip_poll_udp(s.conn); 00309 PT_YIELD(&s.pt); 00310 } 00311 send_request(); 00312 etimer_set(&s.etimer, s.ticks); 00313 do { 00314 PT_YIELD(&s.pt); 00315 if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) { 00316 parse_msg(); 00317 s.state = STATE_CONFIG_RECEIVED; 00318 goto bound; 00319 } 00320 } while (!etimer_expired(&s.etimer)); 00321 00322 if(s.ticks <= CLOCK_SECOND * 10) { 00323 s.ticks += CLOCK_SECOND; 00324 } else { 00325 goto init; 00326 } 00327 } while(s.state != STATE_CONFIG_RECEIVED); 00328 00329 bound: 00330 #if 0 00331 printf("Got IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.ipaddr)); 00332 printf("Got netmask %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.netmask)); 00333 printf("Got DNS server %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.dnsaddr)); 00334 printf("Got default router %d.%d.%d.%d\n", 00335 uip_ipaddr_to_quad(&s.default_router)); 00336 printf("Lease expires in %ld seconds\n", 00337 uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])); 00338 #endif 00339 00340 dhcpc_configured(&s); 00341 00342 #define MAX_TICKS (~((clock_time_t)0) / 2) 00343 #define MAX_TICKS32 (~((uint32_t)0)) 00344 #define IMIN(a, b) ((a) < (b) ? (a) : (b)) 00345 00346 if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2 00347 <= MAX_TICKS32) { 00348 s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]) 00349 )*CLOCK_SECOND/2; 00350 } else { 00351 s.ticks = MAX_TICKS32; 00352 } 00353 00354 while(s.ticks > 0) { 00355 ticks = IMIN(s.ticks, MAX_TICKS); 00356 s.ticks -= ticks; 00357 etimer_set(&s.etimer, ticks); 00358 PT_YIELD_UNTIL(&s.pt, etimer_expired(&s.etimer)); 00359 } 00360 00361 if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2 00362 <= MAX_TICKS32) { 00363 s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]) 00364 )*CLOCK_SECOND/2; 00365 } else { 00366 s.ticks = MAX_TICKS32; 00367 } 00368 00369 /* renewing: */ 00370 xid++; 00371 do { 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 /* rebinding: */ 00390 00391 /* lease_expired: */ 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 /*---------------------------------------------------------------------------*/