Contiki 2.6
|
00001 /* Adapted by Simon Berg from net/dhcpc.c */ 00002 /* 00003 * Copyright (c) 2005, Swedish Institute of Computer Science 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 3. Neither the name of the Institute nor the names of its contributors 00015 * may be used to endorse or promote products derived from this software 00016 * without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00019 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00022 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00023 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00024 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00025 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00026 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00027 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 * 00030 * This file is part of the Contiki operating system. 00031 * 00032 * @(#)$Id: dhcps.c,v 1.2 2010/10/19 18:29:04 adamdunkels Exp $ 00033 */ 00034 00035 #include <stdio.h> 00036 #include <string.h> 00037 #include <uip_arp.h> 00038 #include "contiki.h" 00039 #include "contiki-net.h" 00040 #include "dhcps.h" 00041 00042 struct dhcp_msg { 00043 uint8_t op, htype, hlen, hops; 00044 uint8_t xid[4]; 00045 uint16_t secs, flags; 00046 uint8_t ciaddr[4]; 00047 uint8_t yiaddr[4]; 00048 uint8_t siaddr[4]; 00049 uint8_t giaddr[4]; 00050 uint8_t chaddr[16]; 00051 #ifndef UIP_CONF_DHCP_LIGHT 00052 uint8_t sname[64]; 00053 uint8_t file[128]; 00054 #endif 00055 uint8_t options[312]; 00056 } CC_BYTE_ALIGNED; 00057 00058 #define BOOTP_BROADCAST 0x8000 00059 00060 #define DHCP_REQUEST 1 00061 #define DHCP_REPLY 2 00062 #define DHCP_HTYPE_ETHERNET 1 00063 #define DHCP_HLEN_ETHERNET 6 00064 #define DHCP_MSG_LEN 236 00065 00066 #define DHCPS_SERVER_PORT 67 00067 #define DHCPS_CLIENT_PORT 68 00068 00069 #define DHCPDISCOVER 1 00070 #define DHCPOFFER 2 00071 #define DHCPREQUEST 3 00072 #define DHCPDECLINE 4 00073 #define DHCPACK 5 00074 #define DHCPNAK 6 00075 #define DHCPRELEASE 7 00076 #define DHCPINFORM 8 00077 00078 #define DHCP_OPTION_SUBNET_MASK 1 00079 #define DHCP_OPTION_ROUTER 3 00080 #define DHCP_OPTION_DNS_SERVER 6 00081 #define DHCP_OPTION_REQ_IPADDR 50 00082 #define DHCP_OPTION_LEASE_TIME 51 00083 #define DHCP_OPTION_MSG_TYPE 53 00084 #define DHCP_OPTION_SERVER_ID 54 00085 #define DHCP_OPTION_REQ_LIST 55 00086 #define DHCP_OPTION_END 255 00087 00088 00089 00090 #define LEASE_FLAGS_ALLOCATED 0x01 /* Lease with an allocated address*/ 00091 #define LEASE_FLAGS_VALID 0x02 /* Contains a valid but 00092 possibly outdated lease */ 00093 00094 00095 static const struct dhcps_config *config; 00096 00097 00098 static uint8_t * 00099 find_option(uint8_t option) 00100 { 00101 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00102 uint8_t *optptr = &m->options[4]; 00103 uint8_t *end = (uint8_t*)uip_appdata + uip_datalen(); 00104 while(optptr < end && *optptr != DHCP_OPTION_END) { 00105 if(*optptr == option) { 00106 return optptr; 00107 } 00108 optptr += optptr[1] + 2; 00109 } 00110 return NULL; 00111 } 00112 00113 static const uint8_t magic_cookie[4] = {99, 130, 83, 99}; 00114 00115 static int 00116 check_cookie(void) 00117 { 00118 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00119 return memcmp(m->options, magic_cookie, 4) == 0; 00120 } 00121 00122 /* Finds any valid lease for a given MAC address */ 00123 static struct dhcps_client_lease * 00124 lookup_lease_mac(const uint8_t *chaddr, uint8_t hlen) 00125 { 00126 struct dhcps_client_lease *lease = config->leases; 00127 struct dhcps_client_lease *end = config->leases + config->num_leases; 00128 while(lease != end) { 00129 if (lease->flags & LEASE_FLAGS_VALID 00130 && memcmp(lease->chaddr, chaddr, hlen) == 0) { 00131 return lease; 00132 } 00133 lease++; 00134 } 00135 return NULL; 00136 } 00137 00138 static struct dhcps_client_lease * 00139 lookup_lease_ip(const uip_ipaddr_t *ip) 00140 { 00141 struct dhcps_client_lease *lease = config->leases; 00142 struct dhcps_client_lease *end = config->leases + config->num_leases; 00143 while(lease != end) { 00144 if (uip_ipaddr_cmp(&lease->ipaddr, ip)) { 00145 return lease; 00146 } 00147 lease++; 00148 } 00149 return NULL; 00150 } 00151 00152 static struct dhcps_client_lease * 00153 find_free_lease(void) 00154 { 00155 struct dhcps_client_lease *found = NULL; 00156 struct dhcps_client_lease *lease = config->leases; 00157 struct dhcps_client_lease *end = config->leases + config->num_leases; 00158 while(lease != end) { 00159 if (!(lease->flags & LEASE_FLAGS_VALID)) return lease; 00160 if (!(lease->flags & LEASE_FLAGS_ALLOCATED)) found = lease; 00161 lease++; 00162 } 00163 return found; 00164 } 00165 00166 struct dhcps_client_lease * 00167 init_lease(struct dhcps_client_lease *lease, 00168 const uint8_t *chaddr, uint8_t hlen) 00169 { 00170 if (lease) { 00171 memcpy(lease->chaddr, chaddr, hlen); 00172 lease->flags = LEASE_FLAGS_VALID; 00173 } 00174 return lease; 00175 } 00176 00177 00178 static struct dhcps_client_lease * 00179 choose_address() 00180 { 00181 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00182 struct dhcps_client_lease *lease; 00183 lease = lookup_lease_mac(m->chaddr, m->hlen); 00184 if (lease) { 00185 return lease; 00186 } 00187 { 00188 uint8_t *opt; 00189 opt = find_option(DHCP_OPTION_REQ_IPADDR); 00190 if (opt && (lease = lookup_lease_ip((uip_ipaddr_t*)&opt[2])) 00191 && !(lease->flags & LEASE_FLAGS_ALLOCATED)) { 00192 return init_lease(lease, m->chaddr,m->hlen); 00193 } 00194 } 00195 lease = find_free_lease(); 00196 if (lease) { 00197 return init_lease(lease, m->chaddr,m->hlen); 00198 } 00199 return NULL; 00200 } 00201 00202 static struct dhcps_client_lease * 00203 allocate_address() 00204 { 00205 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00206 struct dhcps_client_lease *lease; 00207 lease = lookup_lease_mac(m->chaddr, m->hlen); 00208 if (!lease) { 00209 uint8_t *opt; 00210 opt = find_option(DHCP_OPTION_REQ_IPADDR); 00211 if (!(opt && (lease = lookup_lease_ip((uip_ipaddr_t*)&opt[2])) 00212 && !(lease->flags & LEASE_FLAGS_ALLOCATED))) { 00213 return NULL; 00214 } 00215 } 00216 lease->lease_end = clock_seconds()+config->default_lease_time; 00217 lease->flags |= LEASE_FLAGS_ALLOCATED; 00218 return lease; 00219 } 00220 00221 static struct dhcps_client_lease * 00222 release_address() 00223 { 00224 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00225 struct dhcps_client_lease *lease; 00226 lease = lookup_lease_mac(m->chaddr, m->hlen); 00227 if (!lease) { 00228 return NULL; 00229 } 00230 lease->flags &= ~LEASE_FLAGS_ALLOCATED; 00231 return lease; 00232 } 00233 00234 /*---------------------------------------------------------------------------*/ 00235 static uint8_t * 00236 add_msg_type(uint8_t *optptr, uint8_t type) 00237 { 00238 *optptr++ = DHCP_OPTION_MSG_TYPE; 00239 *optptr++ = 1; 00240 *optptr++ = type; 00241 return optptr; 00242 } 00243 /*---------------------------------------------------------------------------*/ 00244 static uint8_t * 00245 add_server_id(uint8_t *optptr) 00246 { 00247 *optptr++ = DHCP_OPTION_SERVER_ID; 00248 *optptr++ = 4; 00249 memcpy(optptr, &uip_hostaddr, 4); 00250 return optptr + 4; 00251 } 00252 /*---------------------------------------------------------------------------*/ 00253 static uint8_t * 00254 add_lease_time(uint8_t *optptr) 00255 { 00256 uint32_t lt; 00257 *optptr++ = DHCP_OPTION_LEASE_TIME; 00258 *optptr++ = 4; 00259 lt = UIP_HTONL(config->default_lease_time); 00260 memcpy(optptr, <, 4); 00261 return optptr + 4; 00262 } 00263 00264 /*---------------------------------------------------------------------------*/ 00265 static uint8_t * 00266 add_end(uint8_t *optptr) 00267 { 00268 *optptr++ = DHCP_OPTION_END; 00269 return optptr; 00270 } 00271 00272 static uint8_t * 00273 add_config(uint8_t *optptr) 00274 { 00275 if (config->flags & DHCP_CONF_NETMASK) { 00276 *optptr++ = DHCP_OPTION_SUBNET_MASK; 00277 *optptr++ = 4; 00278 memcpy(optptr, &config->netmask, 4); 00279 optptr += 4; 00280 } 00281 if (config->flags & DHCP_CONF_DNSADDR) { 00282 *optptr++ = DHCP_OPTION_DNS_SERVER; 00283 *optptr++ = 4; 00284 memcpy(optptr, &config->dnsaddr, 4); 00285 optptr += 4; 00286 } 00287 if (config->flags & DHCP_CONF_DEFAULT_ROUTER) { 00288 *optptr++ = DHCP_OPTION_ROUTER; 00289 *optptr++ = 4; 00290 memcpy(optptr, &config->default_router, 4); 00291 optptr += 4; 00292 } 00293 return optptr; 00294 } 00295 00296 static void 00297 create_msg(CC_REGISTER_ARG struct dhcp_msg *m) 00298 { 00299 m->op = DHCP_REPLY; 00300 /* m->htype = DHCP_HTYPE_ETHERNET; */ 00301 /* m->hlen = DHCP_HLEN_ETHERNET; */ 00302 /* memcpy(m->chaddr, &uip_ethaddr,DHCP_HLEN_ETHERNET); */ 00303 m->hops = 0; 00304 m->secs = 0; 00305 memcpy(m->siaddr, &uip_hostaddr, 4); 00306 m->sname[0] = '\0'; 00307 m->file[0] = '\0'; 00308 memcpy(m->options, magic_cookie, sizeof(magic_cookie)); 00309 } 00310 00311 static uip_ipaddr_t any_addr; 00312 static uip_ipaddr_t bcast_addr; 00313 00314 /*---------------------------------------------------------------------------*/ 00315 static void 00316 send_offer(struct uip_udp_conn *conn, struct dhcps_client_lease *lease) 00317 { 00318 uint8_t *end; 00319 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00320 00321 create_msg(m); 00322 memcpy(&m->yiaddr, &lease->ipaddr,4); 00323 00324 end = add_msg_type(&m->options[4], DHCPOFFER); 00325 end = add_server_id(end); 00326 end = add_lease_time(end); 00327 end = add_config(end); 00328 end = add_end(end); 00329 uip_ipaddr_copy(&conn->ripaddr, &bcast_addr); 00330 uip_send(uip_appdata, (int)(end - (uint8_t *)uip_appdata)); 00331 } 00332 00333 static void 00334 send_ack(struct uip_udp_conn *conn, struct dhcps_client_lease *lease) 00335 { 00336 uint8_t *end; 00337 uip_ipaddr_t ciaddr; 00338 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00339 00340 create_msg(m); 00341 memcpy(&m->yiaddr, &lease->ipaddr,4); 00342 00343 end = add_msg_type(&m->options[4], DHCPACK); 00344 end = add_server_id(end); 00345 end = add_lease_time(end); 00346 end = add_config(end); 00347 end = add_end(end); 00348 memcpy(&ciaddr, &lease->ipaddr,4); 00349 uip_ipaddr_copy(&conn->ripaddr, &bcast_addr); 00350 uip_send(uip_appdata, (int)(end - (uint8_t *)uip_appdata)); 00351 printf("ACK\n"); 00352 } 00353 static void 00354 send_nack(struct uip_udp_conn *conn) 00355 { 00356 uint8_t *end; 00357 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00358 00359 create_msg(m); 00360 memset(&m->yiaddr, 0, 4); 00361 00362 end = add_msg_type(&m->options[4], DHCPNAK); 00363 end = add_server_id(end); 00364 end = add_end(end); 00365 00366 uip_ipaddr_copy(&conn->ripaddr, &bcast_addr); 00367 uip_send(uip_appdata, (int)(end - (uint8_t *)uip_appdata)); 00368 printf("NACK\n"); 00369 } 00370 00371 /*---------------------------------------------------------------------------*/ 00372 PROCESS(dhcp_server_process, "DHCP server"); 00373 /*---------------------------------------------------------------------------*/ 00374 00375 PROCESS_THREAD(dhcp_server_process, ev , data) 00376 { 00377 static struct uip_udp_conn *conn; 00378 static struct uip_udp_conn *send_conn; 00379 static struct dhcps_client_lease *lease; 00380 PROCESS_BEGIN(); 00381 printf("DHCP server starting\n"); 00382 uip_ipaddr(&any_addr, 0,0,0,0); 00383 uip_ipaddr(&bcast_addr, 255,255,255,255); 00384 conn = udp_new(&any_addr, UIP_HTONS(DHCPS_CLIENT_PORT), NULL); 00385 if (!conn) goto exit; 00386 send_conn = udp_new(&bcast_addr, UIP_HTONS(DHCPS_CLIENT_PORT), NULL); 00387 if (!send_conn) goto exit; 00388 00389 uip_udp_bind(conn, UIP_HTONS(DHCPS_SERVER_PORT)); 00390 uip_udp_bind(send_conn, UIP_HTONS(DHCPS_SERVER_PORT)); 00391 while(1) { 00392 PROCESS_WAIT_EVENT(); 00393 if(ev == tcpip_event) { 00394 if (uip_newdata()) { 00395 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; 00396 struct uip_udpip_hdr *header = (struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]; 00397 00398 if (m->op == DHCP_REQUEST && check_cookie() && m->hlen <= MAX_HLEN) { 00399 uint8_t *opt = find_option(DHCP_OPTION_MSG_TYPE); 00400 if (opt) { 00401 uint8_t mtype = opt[2]; 00402 if (opt[2] == DHCPDISCOVER) { 00403 printf("Discover\n"); 00404 lease = choose_address(); 00405 if (lease) { 00406 lease->lease_end = clock_seconds()+config->default_lease_time; 00407 tcpip_poll_udp(send_conn); 00408 PROCESS_WAIT_EVENT_UNTIL(uip_poll()); 00409 send_offer(conn,lease); 00410 } 00411 } else { 00412 uint8_t *opt = find_option(DHCP_OPTION_SERVER_ID); 00413 if (!opt || uip_ipaddr_cmp((uip_ipaddr_t*)&opt[2], &uip_hostaddr)) { 00414 if (mtype == DHCPREQUEST) { 00415 printf("Request\n"); 00416 lease = allocate_address(); 00417 tcpip_poll_udp(send_conn); 00418 PROCESS_WAIT_EVENT_UNTIL(uip_poll()); 00419 if (!lease) { 00420 send_nack(send_conn); 00421 } else { 00422 send_ack(send_conn,lease); 00423 } 00424 } else if (mtype == DHCPRELEASE) { 00425 printf("Release\n"); 00426 release_address(); 00427 } else if (mtype == DHCPDECLINE) { 00428 printf("Decline\n"); 00429 } else if (mtype == DHCPINFORM) { 00430 printf("Inform\n"); 00431 } 00432 } 00433 } 00434 } 00435 } 00436 } 00437 } else if (uip_poll()) { 00438 00439 } 00440 } 00441 exit: 00442 printf("DHCP server exiting\n"); 00443 PROCESS_END(); 00444 } 00445 00446 void 00447 dhcps_init(const struct dhcps_config *conf) 00448 { 00449 config = conf; 00450 process_start(&dhcp_server_process,NULL); 00451 }