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 "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);
00152
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
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
00310
00311
00312
00313
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
00354 }
00355 }
00356