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
00277
00278
00279
00280
00281 PT_YIELD_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
00282
00283 if(uip_newdata() && parse_msg() == DHCPACK) {
00284 s.state = STATE_CONFIG_RECEIVED;
00285 break;
00286 }
00287
00288 if(s.ticks <= CLOCK_SECOND * 10) {
00289 s.ticks += CLOCK_SECOND;
00290 } else {
00291 PT_RESTART(&s.pt);
00292 }
00293 } while(s.state != STATE_CONFIG_RECEIVED);
00294
00295 #if 0
00296 printf("Got IP address %d.%d.%d.%d\n",
00297 uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
00298 uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
00299 printf("Got netmask %d.%d.%d.%d\n",
00300 uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
00301 uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
00302 printf("Got DNS server %d.%d.%d.%d\n",
00303 uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
00304 uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
00305 printf("Got default router %d.%d.%d.%d\n",
00306 uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
00307 uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));
00308 printf("Lease expires in %ld seconds\n",
00309 ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1]));
00310 #endif
00311
00312 dhcpc_configured(&s);
00313
00314
00315
00316
00317
00318
00319
00320 while(1) {
00321 PT_YIELD(&s.pt);
00322 }
00323
00324 PT_END(&s.pt);
00325 }
00326
00327 void
00328 dhcpc_init(const void *mac_addr, int mac_len)
00329 {
00330 uip_ipaddr_t addr;
00331
00332 s.mac_addr = mac_addr;
00333 s.mac_len = mac_len;
00334
00335 s.state = STATE_INITIAL;
00336 uip_ipaddr(addr, 255,255,255,255);
00337 s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT));
00338 if(s.conn != NULL) {
00339 uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
00340 }
00341 PT_INIT(&s.pt);
00342 }
00343
00344 void
00345 dhcpc_appcall(void)
00346 {
00347 handle_dhcp();
00348 }
00349
00350 void
00351 dhcpc_request(void)
00352 {
00353 u16_t ipaddr[2];
00354
00355 if(s.state == STATE_INITIAL) {
00356 uip_ipaddr(ipaddr, 0,0,0,0);
00357 uip_sethostaddr(ipaddr);
00358
00359 }
00360 }
00361