38 #include "contiki-net.h"
39 #include "ip64-dhcpc.h"
41 #include "ip64-addr.h"
43 #define STATE_INITIAL 0
44 #define STATE_SENDING 1
45 #define STATE_OFFER_RECEIVED 2
46 #define STATE_CONFIG_RECEIVED 3
48 static struct ip64_dhcpc_state s;
51 uint8_t op, htype, hlen, hops;
64 #if (UIP_BUFSIZE - UIP_UDPIP_HLEN) < 548
65 #error UIP_CONF_BUFFER_SIZE may be too small to accomodate DHCPv4 packets
66 #error Increase UIP_CONF_BUFFER_SIZE in your project-conf.h, platform-conf.h, or contiki-conf.h
67 #error A good size is 600 bytes
70 #define BOOTP_BROADCAST 0x8000
72 #define DHCP_REQUEST 1
74 #define DHCP_HTYPE_ETHERNET 1
75 #define DHCP_HLEN_ETHERNET 6
76 #define DHCP_MSG_LEN 236
78 #define IP64_DHCPC_SERVER_PORT 67
79 #define IP64_DHCPC_CLIENT_PORT 68
81 #define DHCPDISCOVER 1
89 #define DHCP_OPTION_SUBNET_MASK 1
90 #define DHCP_OPTION_ROUTER 3
91 #define DHCP_OPTION_DNS_SERVER 6
92 #define DHCP_OPTION_REQ_IPADDR 50
93 #define DHCP_OPTION_LEASE_TIME 51
94 #define DHCP_OPTION_MSG_TYPE 53
95 #define DHCP_OPTION_SERVER_ID 54
96 #define DHCP_OPTION_REQ_LIST 55
97 #define DHCP_OPTION_END 255
100 static const uint8_t magic_cookie[4] = {99, 130, 83, 99};
103 add_msg_type(uint8_t *optptr, uint8_t type)
105 *optptr++ = DHCP_OPTION_MSG_TYPE;
112 add_server_id(uint8_t *optptr)
114 *optptr++ = DHCP_OPTION_SERVER_ID;
116 memcpy(optptr, s.serverid, 4);
121 add_req_ipaddr(uint8_t *optptr)
123 *optptr++ = DHCP_OPTION_REQ_IPADDR;
125 memcpy(optptr, s.ipaddr.u16, 4);
130 add_req_options(uint8_t *optptr)
132 *optptr++ = DHCP_OPTION_REQ_LIST;
134 *optptr++ = DHCP_OPTION_SUBNET_MASK;
135 *optptr++ = DHCP_OPTION_ROUTER;
136 *optptr++ = DHCP_OPTION_DNS_SERVER;
141 add_end(uint8_t *optptr)
143 *optptr++ = DHCP_OPTION_END;
150 m->op = DHCP_REQUEST;
151 m->htype = DHCP_HTYPE_ETHERNET;
154 memcpy(m->xid, &xid,
sizeof(m->xid));
158 memcpy(m->ciaddr, uip_hostaddr.u16,
sizeof(m->ciaddr));
159 memset(m->yiaddr, 0,
sizeof(m->yiaddr));
160 memset(m->siaddr, 0,
sizeof(m->siaddr));
161 memset(m->giaddr, 0,
sizeof(m->giaddr));
162 memcpy(m->chaddr, s.mac_addr, s.mac_len);
163 memset(&m->chaddr[s.mac_len], 0,
sizeof(m->chaddr) - s.mac_len);
165 memset(m->sname, 0,
sizeof(m->sname));
166 strcpy((
char *)m->sname,
"Thingsquare");
167 memset(m->file, 0,
sizeof(m->file));
170 memcpy(m->options, magic_cookie,
sizeof(magic_cookie));
177 struct dhcp_msg *m = (
struct dhcp_msg *)
uip_appdata;
181 end = add_msg_type(&m->options[4], DHCPDISCOVER);
182 end = add_req_options(end);
192 struct dhcp_msg *m = (
struct dhcp_msg *)
uip_appdata;
196 end = add_msg_type(&m->options[4], DHCPREQUEST);
197 end = add_server_id(end);
198 end = add_req_ipaddr(end);
205 parse_options(uint8_t *optptr,
int len)
207 uint8_t *end = optptr + len;
210 while(optptr < end) {
212 case DHCP_OPTION_SUBNET_MASK:
213 memcpy(s.netmask.u16, optptr + 2, 4);
215 case DHCP_OPTION_ROUTER:
216 memcpy(s.default_router.u16, optptr + 2, 4);
218 case DHCP_OPTION_DNS_SERVER:
219 memcpy(s.dnsaddr.u16, optptr + 2, 4);
221 case DHCP_OPTION_MSG_TYPE:
222 type = *(optptr + 2);
224 case DHCP_OPTION_SERVER_ID:
225 memcpy(s.serverid, optptr + 2, 4);
227 case DHCP_OPTION_LEASE_TIME:
228 memcpy(s.lease_time, optptr + 2, 4);
230 case DHCP_OPTION_END:
234 optptr += optptr[1] + 2;
242 struct dhcp_msg *m = (
struct dhcp_msg *)
uip_appdata;
244 if(m->op == DHCP_REPLY &&
245 memcmp(m->xid, &xid,
sizeof(xid)) == 0 &&
246 memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
247 memcpy(s.ipaddr.u16, m->yiaddr, 4);
248 return parse_options(&m->options[4],
uip_datalen());
259 struct dhcp_msg *m = (
struct dhcp_msg *)
uip_appdata;
260 uint8_t *optptr = &m->options[4];
263 if(m->op == DHCP_REPLY &&
264 memcmp(m->xid, &xid,
sizeof(xid)) == 0 &&
265 memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
266 while(optptr < end) {
267 if(*optptr == DHCP_OPTION_MSG_TYPE) {
268 return *(optptr + 2);
269 }
else if (*optptr == DHCP_OPTION_END) {
272 optptr += optptr[1] + 2;
279 PT_THREAD(handle_dhcp(process_event_t ev,
void *data))
287 s.state = STATE_SENDING;
300 s.state = STATE_OFFER_RECEIVED;
324 s.state = STATE_CONFIG_RECEIVED;
334 }
while(s.state != STATE_CONFIG_RECEIVED);
341 printf(
"Got default router %d.%d.%d.%d\n",
343 printf(
"Lease expires in %ld seconds\n",
344 uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]));
347 ip64_dhcpc_configured(&s);
349 #define MAX_TICKS (~((clock_time_t)0) / 2)
350 #define MAX_TICKS32 (~((uint32_t)0))
351 #define IMIN(a, b) ((a) < (b) ? (a) : (b))
353 if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*
CLOCK_SECOND/2
355 s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])
358 s.ticks = MAX_TICKS32;
362 ticks = IMIN(s.ticks, MAX_TICKS);
368 if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*
CLOCK_SECOND/2
370 s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])
373 s.ticks = MAX_TICKS32;
384 ticks = IMIN(s.ticks / 2, MAX_TICKS);
399 ip64_dhcpc_unconfigured(&s);
406 ip64_dhcpc_init(
const void *mac_addr,
int mac_len)
410 uip_ip6addr_t v6addr;
414 s.mac_addr = mac_addr;
417 s.state = STATE_INITIAL;
419 ip64_addr_4to6(&v4addr, &v6addr);
432 ip64_dhcpc_appcall(process_event_t ev,
void *data)
434 if(ev ==
tcpip_event || ev == PROCESS_EVENT_TIMER) {
435 handle_dhcp(ev, data);
440 ip64_dhcpc_request(
void)
444 if(s.state == STATE_INITIAL) {
447 handle_dhcp(PROCESS_EVENT_NONE,
NULL);
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
#define uip_sethostaddr(addr)
Set the IP address of this host.
#define PT_YIELD(pt)
Yield from the current protothread.
CCIF struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Create a new UDP connection.
CCIF void uip_send(const void *data, int len)
Send data on the current connection.
#define uip_newdata()
Is new incoming data available?
#define NULL
The null pointer.
#define PT_INIT(pt)
Initialize a protothread.
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
CCIF void tcpip_poll_udp(struct uip_udp_conn *conn)
Cause a specified UDP connection to be polled.
#define PT_THREAD(name_args)
Declaration of a protothread.
Representation of an IP address.
#define uip_ipaddr_to_quad(a)
Convert an IP address to four bytes separated by commas.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
#define CC_REGISTER_ARG
Configure if the C compiler supports the "register" keyword for function arguments.
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
process_event_t tcpip_event
The uIP event.
#define PT_END(pt)
Declare the end of a protothread.
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
#define udp_bind(conn, port)
Bind a UDP connection to a local port.
Representation of a uIP UDP connection.
#define uip_ipaddr(addr, addr0, addr1, addr2, addr3)
Construct an IP address from four bytes.
uip_appdata
Pointer to the application data in the packet buffer.
#define CLOCK_SECOND
A second, measured in system clock time.