dhcpc.c

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 uIP TCP/IP stack
00030  *
00031  * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $
00032  */
00033 
00034 #include <stdio.h>
00035 #include <string.h>
00036 
00037 #include "uip.h"
00038 #include "dhcpc.h"
00039 #include "timer.h"
00040 #include "pt.h"
00041 
00042 #define STATE_INITIAL         0
00043 #define STATE_SENDING         1
00044 #define STATE_OFFER_RECEIVED  2
00045 #define STATE_CONFIG_RECEIVED 3
00046 
00047 static struct dhcpc_state s;
00048 
00049 struct dhcp_msg {
00050   u8_t op, htype, hlen, hops;
00051   u8_t xid[4];
00052   u16_t secs, flags;
00053   u8_t ciaddr[4];
00054   u8_t yiaddr[4];
00055   u8_t siaddr[4];
00056   u8_t giaddr[4];
00057   u8_t chaddr[16];
00058 #ifndef UIP_CONF_DHCP_LIGHT
00059   u8_t sname[64];
00060   u8_t file[128];
00061 #endif
00062   u8_t options[312];
00063 };
00064 
00065 #define BOOTP_BROADCAST 0x8000
00066 
00067 #define DHCP_REQUEST        1
00068 #define DHCP_REPLY          2
00069 #define DHCP_HTYPE_ETHERNET 1
00070 #define DHCP_HLEN_ETHERNET  6
00071 #define DHCP_MSG_LEN      236
00072 
00073 #define DHCPC_SERVER_PORT  67
00074 #define DHCPC_CLIENT_PORT  68
00075 
00076 #define DHCPDISCOVER  1
00077 #define DHCPOFFER     2
00078 #define DHCPREQUEST   3
00079 #define DHCPDECLINE   4
00080 #define DHCPACK       5
00081 #define DHCPNAK       6
00082 #define DHCPRELEASE   7
00083 
00084 #define DHCP_OPTION_SUBNET_MASK   1
00085 #define DHCP_OPTION_ROUTER        3
00086 #define DHCP_OPTION_DNS_SERVER    6
00087 #define DHCP_OPTION_REQ_IPADDR   50
00088 #define DHCP_OPTION_LEASE_TIME   51
00089 #define DHCP_OPTION_MSG_TYPE     53
00090 #define DHCP_OPTION_SERVER_ID    54
00091 #define DHCP_OPTION_REQ_LIST     55
00092 #define DHCP_OPTION_END         255
00093 
00094 static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
00095 static const u8_t magic_cookie[4] = {99, 130, 83, 99};
00096 /*---------------------------------------------------------------------------*/
00097 static u8_t *
00098 add_msg_type(u8_t *optptr, u8_t type)
00099 {
00100   *optptr++ = DHCP_OPTION_MSG_TYPE;
00101   *optptr++ = 1;
00102   *optptr++ = type;
00103   return optptr;
00104 }
00105 /*---------------------------------------------------------------------------*/
00106 static u8_t *
00107 add_server_id(u8_t *optptr)
00108 {
00109   *optptr++ = DHCP_OPTION_SERVER_ID;
00110   *optptr++ = 4;
00111   memcpy(optptr, s.serverid, 4);
00112   return optptr + 4;
00113 }
00114 /*---------------------------------------------------------------------------*/
00115 static u8_t *
00116 add_req_ipaddr(u8_t *optptr)
00117 {
00118   *optptr++ = DHCP_OPTION_REQ_IPADDR;
00119   *optptr++ = 4;
00120   memcpy(optptr, s.ipaddr, 4);
00121   return optptr + 4;
00122 }
00123 /*---------------------------------------------------------------------------*/
00124 static u8_t *
00125 add_req_options(u8_t *optptr)
00126 {
00127   *optptr++ = DHCP_OPTION_REQ_LIST;
00128   *optptr++ = 3;
00129   *optptr++ = DHCP_OPTION_SUBNET_MASK;
00130   *optptr++ = DHCP_OPTION_ROUTER;
00131   *optptr++ = DHCP_OPTION_DNS_SERVER;
00132   return optptr;
00133 }
00134 /*---------------------------------------------------------------------------*/
00135 static u8_t *
00136 add_end(u8_t *optptr)
00137 {
00138   *optptr++ = DHCP_OPTION_END;
00139   return optptr;
00140 }
00141 /*---------------------------------------------------------------------------*/
00142 static void
00143 create_msg(register struct dhcp_msg *m)
00144 {
00145   m->op = DHCP_REQUEST;
00146   m->htype = DHCP_HTYPE_ETHERNET;
00147   m->hlen = s.mac_len;
00148   m->hops = 0;
00149   memcpy(m->xid, xid, sizeof(m->xid));
00150   m->secs = 0;
00151   m->flags = HTONS(BOOTP_BROADCAST); /*  Broadcast bit. */
00152   /*  uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
00153   memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
00154   memset(m->yiaddr, 0, sizeof(m->yiaddr));
00155   memset(m->siaddr, 0, sizeof(m->siaddr));
00156   memset(m->giaddr, 0, sizeof(m->giaddr));
00157   memcpy(m->chaddr, s.mac_addr, s.mac_len);
00158   memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
00159 #ifndef UIP_CONF_DHCP_LIGHT
00160   memset(m->sname, 0, sizeof(m->sname));
00161   memset(m->file, 0, sizeof(m->file));
00162 #endif
00163 
00164   memcpy(m->options, magic_cookie, sizeof(magic_cookie));
00165 }
00166 /*---------------------------------------------------------------------------*/
00167 static void
00168 send_discover(void)
00169 {
00170   u8_t *end;
00171   struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00172 
00173   create_msg(m);
00174 
00175   end = add_msg_type(&m->options[4], DHCPDISCOVER);
00176   end = add_req_options(end);
00177   end = add_end(end);
00178 
00179   uip_send(uip_appdata, end - (u8_t *)uip_appdata);
00180 }
00181 /*---------------------------------------------------------------------------*/
00182 static void
00183 send_request(void)
00184 {
00185   u8_t *end;
00186   struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00187 
00188   create_msg(m);
00189   
00190   end = add_msg_type(&m->options[4], DHCPREQUEST);
00191   end = add_server_id(end);
00192   end = add_req_ipaddr(end);
00193   end = add_end(end);
00194   
00195   uip_send(uip_appdata, end - (u8_t *)uip_appdata);
00196 }
00197 /*---------------------------------------------------------------------------*/
00198 static u8_t
00199 parse_options(u8_t *optptr, int len)
00200 {
00201   u8_t *end = optptr + len;
00202   u8_t type = 0;
00203 
00204   while(optptr < end) {
00205     switch(*optptr) {
00206     case DHCP_OPTION_SUBNET_MASK:
00207       memcpy(s.netmask, optptr + 2, 4);
00208       break;
00209     case DHCP_OPTION_ROUTER:
00210       memcpy(s.default_router, optptr + 2, 4);
00211       break;
00212     case DHCP_OPTION_DNS_SERVER:
00213       memcpy(s.dnsaddr, optptr + 2, 4);
00214       break;
00215     case DHCP_OPTION_MSG_TYPE:
00216       type = *(optptr + 2);
00217       break;
00218     case DHCP_OPTION_SERVER_ID:
00219       memcpy(s.serverid, optptr + 2, 4);
00220       break;
00221     case DHCP_OPTION_LEASE_TIME:
00222       memcpy(s.lease_time, optptr + 2, 4);
00223       break;
00224     case DHCP_OPTION_END:
00225       return type;
00226     }
00227 
00228     optptr += optptr[1] + 2;
00229   }
00230   return type;
00231 }
00232 /*---------------------------------------------------------------------------*/
00233 static u8_t
00234 parse_msg(void)
00235 {
00236   struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00237   
00238   if(m->op == DHCP_REPLY &&
00239      memcmp(m->xid, xid, sizeof(xid)) == 0 &&
00240      memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
00241     memcpy(s.ipaddr, m->yiaddr, 4);
00242     return parse_options(&m->options[4], uip_datalen());
00243   }
00244   return 0;
00245 }
00246 /*---------------------------------------------------------------------------*/
00247 static
00248 PT_THREAD(handle_dhcp(void))
00249 {
00250   PT_BEGIN(&s.pt);
00251   
00252   /* try_again:*/
00253   s.state = STATE_SENDING;
00254   s.ticks = CLOCK_SECOND;
00255 
00256   do {
00257     send_discover();
00258     timer_set(&s.timer, s.ticks);
00259     PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
00260 
00261     if(uip_newdata() && parse_msg() == DHCPOFFER) {
00262       s.state = STATE_OFFER_RECEIVED;
00263       break;
00264     }
00265 
00266     if(s.ticks < CLOCK_SECOND * 60) {
00267       s.ticks *= 2;
00268     }
00269   } while(s.state != STATE_OFFER_RECEIVED);
00270   
00271   s.ticks = CLOCK_SECOND;
00272 
00273   do {
00274     send_request();
00275     timer_set(&s.timer, s.ticks);
00276     PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
00277 
00278     if(uip_newdata() && parse_msg() == DHCPACK) {
00279       s.state = STATE_CONFIG_RECEIVED;
00280       break;
00281     }
00282 
00283     if(s.ticks <= CLOCK_SECOND * 10) {
00284       s.ticks += CLOCK_SECOND;
00285     } else {
00286       PT_RESTART(&s.pt);
00287     }
00288   } while(s.state != STATE_CONFIG_RECEIVED);
00289   
00290 #if 0
00291   printf("Got IP address %d.%d.%d.%d\n",
00292          uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
00293          uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
00294   printf("Got netmask %d.%d.%d.%d\n",
00295          uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
00296          uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
00297   printf("Got DNS server %d.%d.%d.%d\n",
00298          uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
00299          uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
00300   printf("Got default router %d.%d.%d.%d\n",
00301          uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
00302          uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));
00303   printf("Lease expires in %ld seconds\n",
00304          ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1]));
00305 #endif
00306 
00307   dhcpc_configured(&s);
00308   
00309   /*  timer_stop(&s.timer);*/
00310 
00311   /*
00312    * PT_END restarts the thread so we do this instead. Eventually we
00313    * should reacquire expired leases here.
00314    */
00315   while(1) {
00316     PT_YIELD(&s.pt);
00317   }
00318 
00319   PT_END(&s.pt);
00320 }
00321 /*---------------------------------------------------------------------------*/
00322 void
00323 dhcpc_init(const void *mac_addr, int mac_len)
00324 {
00325   uip_ipaddr_t addr;
00326   
00327   s.mac_addr = mac_addr;
00328   s.mac_len  = mac_len;
00329 
00330   s.state = STATE_INITIAL;
00331   uip_ipaddr(addr, 255,255,255,255);
00332   s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT));
00333   if(s.conn != NULL) {
00334     uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
00335   }
00336   PT_INIT(&s.pt);
00337 }
00338 /*---------------------------------------------------------------------------*/
00339 void
00340 dhcpc_appcall(void)
00341 {
00342   handle_dhcp();
00343 }
00344 /*---------------------------------------------------------------------------*/
00345 void
00346 dhcpc_request(void)
00347 {
00348   u16_t ipaddr[2];
00349   
00350   if(s.state == STATE_INITIAL) {
00351     uip_ipaddr(ipaddr, 0,0,0,0);
00352     uip_sethostaddr(ipaddr);
00353     /*    handle_dhcp(PROCESS_EVENT_NONE, NULL);*/
00354   }
00355 }
00356 /*---------------------------------------------------------------------------*/

Generated on Mon Jun 12 10:23:01 2006 for uIP 1.0 by  doxygen 1.4.6