Contiki 2.6

dhcps.c

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, &lt, 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 }