DHCP client
diff --git a/contiki/uip/dhcpc.c b/contiki/uip/dhcpc.c
new file mode 100644
index 0000000..80f4ea8
--- /dev/null
+++ b/contiki/uip/dhcpc.c
@@ -0,0 +1,296 @@
+
+#include "contiki.h"
+#include "dhcpc.h"
+#include "uip_arp.h"
+#include "pt.h"
+
+#include <string.h>
+
+#define STATE_INITIAL 0
+#define STATE_SENDING 1
+#define STATE_OFFER_RECEIVED 2
+#define STATE_CONFIG_RECEIVED 3
+
+static struct {
+ struct pt pt;
+ char state;
+ struct uip_udp_conn *conn;
+ struct timer timer;
+ u16_t secs;
+
+ u8_t serverid[4];
+
+ u16_t ipaddr[2];
+ u16_t netmask[2];
+ u16_t dnsaddr[2];
+ u16_t default_router[2];
+} s;
+
+struct dhcp_msg {
+ u8_t op, htype, hlen, hops;
+ u8_t xid[4];
+ u16_t secs, flags;
+ u8_t ciaddr[4];
+ u8_t yiaddr[4];
+ u8_t siaddr[4];
+ u8_t giaddr[4];
+ u8_t chaddr[16];
+ u8_t sname[64];
+ u8_t file[128];
+ u8_t options[312];
+};
+#define DHCP_REQUEST 1
+#define DHCP_REPLY 2
+#define DHCP_HTYPE_ETHERNET 1
+#define DHCP_HLEN_ETHERNET 6
+#define DHCP_MSG_LEN 236
+
+#define DHCPC_SERVER_PORT 67
+#define DHCPC_CLIENT_PORT 68
+
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+
+#define DHCP_OPTION_SUBNET_MASK 1
+#define DHCP_OPTION_ROUTER 3
+#define DHCP_OPTION_DNS_SERVER 6
+#define DHCP_OPTION_REQ_IPADDR 50
+#define DHCP_OPTION_MSG_TYPE 53
+#define DHCP_OPTION_SERVER_ID 54
+#define DHCP_OPTION_END 255
+
+static const u8_t xid[4] = {0xad, 0xde, 0x00, 0x00};
+static const u8_t magic_cookie[4] = {99, 130, 83, 99};
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_msg_type(u8_t *optptr, u8_t type)
+{
+ *optptr++ = DHCP_OPTION_MSG_TYPE;
+ *optptr++ = 1;
+ *optptr++ = type;
+ return optptr;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_server_id(u8_t *optptr)
+{
+ *optptr++ = DHCP_OPTION_SERVER_ID;
+ *optptr++ = 4;
+ memcpy(optptr, s.serverid, 4);
+ return optptr + 4;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_req_ipaddr(u8_t *optptr)
+{
+ *optptr++ = DHCP_OPTION_REQ_IPADDR;
+ *optptr++ = 4;
+ memcpy(optptr, s.ipaddr, 4);
+ return optptr + 4;
+}
+/*---------------------------------------------------------------------------*/
+static u8_t *
+add_end(u8_t *optptr)
+{
+ *optptr++ = DHCP_OPTION_END;
+ return optptr;
+}
+/*---------------------------------------------------------------------------*/
+static void
+create_msg(struct dhcp_msg *m)
+{
+ m->op = DHCP_REQUEST;
+ m->htype = DHCP_HTYPE_ETHERNET;
+ m->hlen = DHCP_HLEN_ETHERNET;
+ m->hops = 0;
+ memcpy(m->xid, xid, sizeof(m->xid));
+ m->secs = 0;
+ m->flags = 0;
+ uip_ipaddr_copy((u16_t *)m->ciaddr, uip_hostaddr);
+ memset(m->yiaddr, 0, sizeof(m->yiaddr));
+ memset(m->siaddr, 0, sizeof(m->siaddr));
+ memset(m->giaddr, 0, sizeof(m->giaddr));
+ memcpy(m->chaddr, &uip_ethaddr, 6);
+ memset(&m->chaddr[6], 0, 10);
+ memset(m->sname, 0, sizeof(m->sname));
+ memset(m->file, 0, sizeof(m->file));
+
+ memcpy(m->options, magic_cookie, sizeof(magic_cookie));
+}
+/*---------------------------------------------------------------------------*/
+static void
+send_discover(void)
+{
+ struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
+
+ create_msg(m);
+
+ add_end(add_msg_type(&m->options[4], DHCPDISCOVER));
+
+ uip_udp_send(300);
+}
+/*---------------------------------------------------------------------------*/
+static void
+send_request(void)
+{
+ struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
+
+ create_msg(m);
+
+ add_end(add_req_ipaddr(add_server_id(add_msg_type(&m->options[4],
+ DHCPREQUEST))));
+
+ uip_udp_send(300);
+}
+/*---------------------------------------------------------------------------*/
+static u8_t
+parse_options(u8_t *optptr, int len)
+{
+ u8_t *optptr2;
+ u8_t type;
+
+ type = 0;
+ optptr2 = NULL;
+
+ while(*optptr != DHCP_OPTION_END) {
+ switch(*optptr) {
+ case DHCP_OPTION_SUBNET_MASK:
+ memcpy(s.netmask, optptr + 2, 4);
+ break;
+ case DHCP_OPTION_ROUTER:
+ memcpy(s.default_router, optptr + 2, 4);
+ break;
+ case DHCP_OPTION_DNS_SERVER:
+ memcpy(s.dnsaddr, optptr + 2, 4);
+ break;
+ case DHCP_OPTION_MSG_TYPE:
+ type = *(optptr + 2);
+ break;
+ case DHCP_OPTION_SERVER_ID:
+ memcpy(s.serverid, optptr + 2, 4);
+ break;
+ }
+
+ /* printf("option type %d len %d\n", *optptr, *(optptr + 1));*/
+ len -= *(optptr + 1) + 2;
+ optptr += *(optptr + 1) + 2;
+ if(len <= 0) {
+ return 0;
+ }
+
+ if(optptr == optptr2) {
+ /* Abort if we don't make progress. */
+ return 0;
+ }
+ }
+ return type;
+}
+/*---------------------------------------------------------------------------*/
+static void
+parse_msg(void)
+{
+ struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
+
+ if(m->op == DHCP_REPLY) {
+ memcpy(s.ipaddr, m->yiaddr, 4);
+ parse_options(&m->options[4], uip_datalen());
+ }
+}
+/*---------------------------------------------------------------------------*/
+static
+PT_THREAD(handle_dhcp(void))
+{
+ PT_BEGIN(&s.pt);
+
+ PT_WAIT_UNTIL(&s.pt, s.state == STATE_SENDING);
+
+ s.secs = 0;
+ timer_set(&s.timer, CLOCK_SECOND * 2);
+
+ while(s.state != STATE_OFFER_RECEIVED) {
+ send_discover();
+ PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
+
+ timer_reset(&s.timer);
+
+ if(uip_newdata()) {
+ parse_msg();
+ s.state = STATE_OFFER_RECEIVED;
+ }
+ ++s.secs;
+ }
+
+ while(s.state != STATE_CONFIG_RECEIVED) {
+
+ send_request();
+
+ PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
+
+ timer_reset(&s.timer);
+
+ if(uip_newdata()) {
+ s.state = STATE_CONFIG_RECEIVED;
+ }
+ ++s.secs;
+ }
+
+ /* printf("Got IP address %d.%d.%d.%d\n",
+ uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
+ uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
+ printf("Got netmask %d.%d.%d.%d\n",
+ uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
+ uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
+ printf("Got DNS server %d.%d.%d.%d\n",
+ uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
+ uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
+ printf("Got default router %d.%d.%d.%d\n",
+ uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
+ uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));*/
+
+ uip_sethostaddr(s.ipaddr);
+ uip_setnetmask(s.netmask);
+ uip_setdraddr(s.default_router);
+ resolv_conf(s.dnsaddr);
+ dhcpc_configured();
+
+ PT_END(&s.pt);
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_init(void)
+{
+ u16_t addr[2];
+
+ s.state = STATE_INITIAL;
+ uip_ipaddr(addr, 255,255,255,255);
+ s.conn = udp_new(addr, HTONS(DHCPC_SERVER_PORT), NULL);
+ if(s.conn != NULL) {
+ udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
+ }
+ PT_INIT(&s.pt);
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_appcall(void *state)
+{
+ handle_dhcp();
+}
+/*---------------------------------------------------------------------------*/
+void
+dhcpc_request(void)
+{
+ u16_t ipaddr[2];
+
+ if(s.state == STATE_INITIAL) {
+ uip_ipaddr(ipaddr, 0,0,0,0);
+ uip_sethostaddr(ipaddr);
+ s.state = STATE_SENDING;
+ tcpip_poll_udp(s.conn);
+ }
+}
+/*---------------------------------------------------------------------------*/
diff --git a/contiki/uip/dhcpc.h b/contiki/uip/dhcpc.h
new file mode 100644
index 0000000..d0cdf11
--- /dev/null
+++ b/contiki/uip/dhcpc.h
@@ -0,0 +1,11 @@
+#ifndef __DHCPC_H__
+#define __DHCPC_H__
+
+void dhcpc_init(void);
+void dhcpc_request(void);
+
+void dhcpc_appcall(void *state);
+
+void dhcpc_configured(void);
+
+#endif /* __DHCPC_H__ */