Add toolchain and mbtk source

Change-Id: Ie12546301367ea59240bf23d5e184ad7e36e40b3
diff --git a/mbtk/mbtk_lib/src/mbtk_dhcp.c b/mbtk/mbtk_lib/src/mbtk_dhcp.c
new file mode 100755
index 0000000..b764f34
--- /dev/null
+++ b/mbtk/mbtk_lib/src/mbtk_dhcp.c
@@ -0,0 +1,885 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_ifc.h"
+#include "mbtk_dhcp.h"
+
+#define VERBOSE 2
+#define STATE_SELECTING  1
+#define STATE_REQUESTING 2
+
+#define TIMEOUT_INITIAL   4000
+#define TIMEOUT_MAX      32000
+
+static int verbose = 1;
+// static char errmsg[2048];
+
+static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
+{
+    uint8_t *x;
+
+    memset(msg, 0, sizeof(dhcp_msg));
+
+    msg->op = OP_BOOTREQUEST;
+    msg->htype = HTYPE_ETHER;
+    msg->hlen = 6;
+    msg->hops = 0;
+
+    msg->flags = htons(FLAGS_BROADCAST);
+
+    msg->xid = xid;
+
+    memcpy(msg->chaddr, hwaddr, 6);
+
+    x = msg->options;
+
+    *x++ = OPT_COOKIE1;
+    *x++ = OPT_COOKIE2;
+    *x++ = OPT_COOKIE3;
+    *x++ = OPT_COOKIE4;
+
+    *x++ = OPT_MESSAGE_TYPE;
+    *x++ = 1;
+    *x++ = type;
+
+    return x;
+}
+
+static int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
+{
+    uint8_t *x;
+
+    x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);
+
+    *x++ = OPT_PARAMETER_LIST;
+    *x++ = 4;
+    *x++ = OPT_SUBNET_MASK;
+    *x++ = OPT_GATEWAY;
+    *x++ = OPT_DNS;
+    *x++ = OPT_BROADCAST_ADDR;
+
+    *x++ = OPT_END;
+
+    return DHCP_MSG_FIXED_SIZE + (x - msg->options);
+}
+
+static int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
+                                 uint32_t ipaddr, uint32_t serveraddr)
+{
+    uint8_t *x;
+
+    x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
+
+    *x++ = OPT_PARAMETER_LIST;
+    *x++ = 4;
+    *x++ = OPT_SUBNET_MASK;
+    *x++ = OPT_GATEWAY;
+    *x++ = OPT_DNS;
+    *x++ = OPT_BROADCAST_ADDR;
+
+    *x++ = OPT_REQUESTED_IP;
+    *x++ = 4;
+    memcpy(x, &ipaddr, 4);
+    x +=  4;
+
+    *x++ = OPT_SERVER_ID;
+    *x++ = 4;
+    memcpy(x, &serveraddr, 4);
+    x += 4;
+
+    *x++ = OPT_END;
+
+    return DHCP_MSG_FIXED_SIZE + (x - msg->options);
+}
+
+
+static msecs_t get_msecs(void)
+{
+    struct timespec ts;
+
+    if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    {
+        return 0;
+    }
+    else
+    {
+        return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
+               (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
+    }
+}
+
+static int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
+{
+    int s;
+    struct sockaddr_ll bindaddr;
+
+    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0)
+    {
+        LOGE("socket(PF_PACKET)");
+        return -1;
+    }
+
+    memset(&bindaddr, 0, sizeof(bindaddr));
+    bindaddr.sll_family = AF_PACKET;
+    bindaddr.sll_protocol = htons(ETH_P_IP);
+    bindaddr.sll_halen = ETH_ALEN;
+    memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
+    bindaddr.sll_ifindex = if_index;
+
+    if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0)
+    {
+        LOGE("Cannot bind raw socket to interface");
+        return -1;
+    }
+
+    return s;
+}
+
+static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
+{
+    uint16_t *up = (uint16_t *)buffer;
+    uint32_t sum = startsum;
+    uint32_t upper16;
+
+    while (count > 1)
+    {
+        sum += *up++;
+        count -= 2;
+    }
+    if (count > 0)
+    {
+        sum += (uint16_t) *(uint8_t *)up;
+    }
+    while ((upper16 = (sum >> 16)) != 0)
+    {
+        sum = (sum & 0xffff) + upper16;
+    }
+    return sum;
+}
+
+static uint32_t finish_sum(uint32_t sum)
+{
+    return ~sum & 0xffff;
+}
+
+static int send_packet(int s, int if_index, dhcp_msg *msg, int size,
+                       uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
+{
+    struct iphdr ip;
+    struct udphdr udp;
+    struct iovec iov[3];
+    uint32_t udpsum;
+    uint16_t temp;
+    struct msghdr msghdr;
+    struct sockaddr_ll destaddr;
+
+    ip.version = IPVERSION;
+    ip.ihl = sizeof(ip) >> 2;
+    ip.tos = 0;
+    ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
+    ip.id = 0;
+    ip.frag_off = 0;
+    ip.ttl = IPDEFTTL;
+    ip.protocol = IPPROTO_UDP;
+    ip.check = 0;
+    ip.saddr = saddr;
+    ip.daddr = daddr;
+    ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
+
+    udp.source = htons(sport);
+    udp.dest = htons(dport);
+    udp.len = htons(sizeof(udp) + size);
+    udp.check = 0;
+
+    /* Calculate checksum for pseudo header */
+    udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
+    udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
+    temp = htons(IPPROTO_UDP);
+    udpsum = checksum(&temp, sizeof(temp), udpsum);
+    temp = udp.len;
+    udpsum = checksum(&temp, sizeof(temp), udpsum);
+
+    /* Add in the checksum for the udp header */
+    udpsum = checksum(&udp, sizeof(udp), udpsum);
+
+    /* Add in the checksum for the data */
+    udpsum = checksum(msg, size, udpsum);
+    udp.check = finish_sum(udpsum);
+
+    iov[0].iov_base = (char *)&ip;
+    iov[0].iov_len = sizeof(ip);
+    iov[1].iov_base = (char *)&udp;
+    iov[1].iov_len = sizeof(udp);
+    iov[2].iov_base = (char *)msg;
+    iov[2].iov_len = size;
+    memset(&destaddr, 0, sizeof(destaddr));
+    destaddr.sll_family = AF_PACKET;
+    destaddr.sll_protocol = htons(ETH_P_IP);
+    destaddr.sll_ifindex = if_index;
+    destaddr.sll_halen = ETH_ALEN;
+    memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
+
+    msghdr.msg_name = &destaddr;
+    msghdr.msg_namelen = sizeof(destaddr);
+    msghdr.msg_iov = iov;
+    msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
+    msghdr.msg_flags = 0;
+    msghdr.msg_control = 0;
+    msghdr.msg_controllen = 0;
+    return sendmsg(s, &msghdr, 0);
+}
+
+static int receive_packet(int s, dhcp_msg *msg)
+{
+    int nread;
+    int is_valid;
+    struct dhcp_packet
+    {
+        struct iphdr ip;
+        struct udphdr udp;
+        dhcp_msg dhcp;
+    } packet;
+    int dhcp_size;
+    uint32_t sum;
+    uint16_t temp;
+    uint32_t saddr, daddr;
+
+    nread = read(s, &packet, sizeof(packet));
+    if (nread < 0)
+    {
+        return -1;
+    }
+    /*
+     * The raw packet interface gives us all packets received by the
+     * network interface. We need to filter out all packets that are
+     * not meant for us.
+     */
+    is_valid = 0;
+    if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr)))
+    {
+#if VERBOSE
+        LOGD("Packet is too small (%d) to be a UDP datagram", nread);
+#endif
+    }
+    else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2))
+    {
+#if VERBOSE
+        LOGD("Not a valid IP packet");
+#endif
+    }
+    else if (nread < ntohs(packet.ip.tot_len))
+    {
+#if VERBOSE
+        LOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
+#endif
+    }
+    else if (packet.ip.protocol != IPPROTO_UDP)
+    {
+#if VERBOSE
+        LOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
+#endif
+    }
+    else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT))
+    {
+#if VERBOSE
+        LOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
+#endif
+    }
+    else
+    {
+        is_valid = 1;
+    }
+
+    if (!is_valid)
+    {
+        return -1;
+    }
+
+    /* Seems like it's probably a valid DHCP packet */
+    /* validate IP header checksum */
+    sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
+    if (sum != 0)
+    {
+        LOGW("IP header checksum failure (0x%x)", packet.ip.check);
+        return -1;
+    }
+    /*
+     * Validate the UDP checksum.
+     * Since we don't need the IP header anymore, we "borrow" it
+     * to construct the pseudo header used in the checksum calculation.
+     */
+    dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
+    /*
+     * check validity of dhcp_size.
+     * 1) cannot be negative or zero.
+     * 2) src buffer contains enough bytes to copy
+     * 3) cannot exceed destination buffer
+     */
+    if ((dhcp_size <= 0) ||
+        ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) ||
+        ((int)sizeof(dhcp_msg) < dhcp_size))
+    {
+#if VERBOSE
+        LOGD("Malformed Packet");
+#endif
+        return -1;
+    }
+    saddr = packet.ip.saddr;
+    daddr = packet.ip.daddr;
+    nread = ntohs(packet.ip.tot_len);
+    memset(&packet.ip, 0, sizeof(packet.ip));
+    packet.ip.saddr = saddr;
+    packet.ip.daddr = daddr;
+    packet.ip.protocol = IPPROTO_UDP;
+    packet.ip.tot_len = packet.udp.len;
+    temp = packet.udp.check;
+    packet.udp.check = 0;
+    sum = finish_sum(checksum(&packet, nread, 0));
+    packet.udp.check = temp;
+    if (!sum)
+        sum = finish_sum(sum);
+    if (temp != sum)
+    {
+        LOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
+        return -1;
+    }
+    memcpy(msg, &packet.dhcp, dhcp_size);
+    return dhcp_size;
+}
+
+static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len)
+{
+    int i;
+    char *cp = buf;
+    char *buf_end = buf + buf_size;
+    for (i = 0; i < len; i++)
+    {
+        cp += snprintf(cp, buf_end - cp, " %02x ", array[i]);
+    }
+}
+
+static const char *ipaddr(in_addr_t addr)
+{
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
+}
+
+static const char *dhcp_type_to_name(uint32_t type)
+{
+    switch(type)
+    {
+        case DHCPDISCOVER:
+            return "discover";
+        case DHCPOFFER:
+            return "offer";
+        case DHCPREQUEST:
+            return "request";
+        case DHCPDECLINE:
+            return "decline";
+        case DHCPACK:
+            return "ack";
+        case DHCPNAK:
+            return "nak";
+        case DHCPRELEASE:
+            return "release";
+        case DHCPINFORM:
+            return "inform";
+        default:
+            return "???";
+    }
+}
+
+static void dump_dhcp_msg(dhcp_msg *msg, int len)
+{
+    unsigned char *x;
+    unsigned int n,c;
+    int optsz;
+    const char *name;
+    char buf[2048];
+
+    LOGD("===== DHCP message:");
+    if (len < DHCP_MSG_FIXED_SIZE)
+    {
+        LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
+        return;
+    }
+
+    len -= DHCP_MSG_FIXED_SIZE;
+
+    if (msg->op == OP_BOOTREQUEST)
+        name = "BOOTREQUEST";
+    else if (msg->op == OP_BOOTREPLY)
+        name = "BOOTREPLY";
+    else
+        name = "????";
+    LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
+         name, msg->op, msg->htype, msg->hlen, msg->hops);
+    LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
+         ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
+    LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
+    LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
+    LOGD("siaddr = %s", ipaddr(msg->siaddr));
+    LOGD("giaddr = %s", ipaddr(msg->giaddr));
+
+    c = msg->hlen > 16 ? 16 : msg->hlen;
+    hex2str(buf, sizeof(buf), msg->chaddr, c);
+    LOGD("chaddr = {%s}", buf);
+
+    for (n = 0; n < 64; n++)
+    {
+        unsigned char x = msg->sname[n];
+        if ((x < ' ') || (x > 127))
+        {
+            if (x == 0) break;
+            msg->sname[n] = '.';
+        }
+    }
+    msg->sname[63] = 0;
+
+    for (n = 0; n < 128; n++)
+    {
+        unsigned char x = msg->file[n];
+        if ((x < ' ') || (x > 127))
+        {
+            if (x == 0) break;
+            msg->file[n] = '.';
+        }
+    }
+    msg->file[127] = 0;
+
+    LOGD("sname = '%s'", msg->sname);
+    LOGD("file = '%s'", msg->file);
+
+    if (len < 4) return;
+    len -= 4;
+    x = msg->options + 4;
+
+    while (len > 2)
+    {
+        if (*x == 0)
+        {
+            x++;
+            len--;
+            continue;
+        }
+        if (*x == OPT_END)
+        {
+            break;
+        }
+        len -= 2;
+        optsz = x[1];
+        if (optsz > len) break;
+        if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE)
+        {
+            if ((unsigned int)optsz < sizeof(buf) - 1)
+            {
+                n = optsz;
+            }
+            else
+            {
+                n = sizeof(buf) - 1;
+            }
+            memcpy(buf, &x[2], n);
+            buf[n] = '\0';
+        }
+        else
+        {
+            hex2str(buf, sizeof(buf), &x[2], optsz);
+        }
+        if (x[0] == OPT_MESSAGE_TYPE)
+            name = dhcp_type_to_name(x[2]);
+        else
+            name = NULL;
+        LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
+        len -= optsz;
+        x = x + optsz + 2;
+    }
+}
+
+static int send_message(int sock, int if_index, dhcp_msg  *msg, int size)
+{
+#if VERBOSE > 1
+    dump_dhcp_msg(msg, size);
+#endif
+    return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
+                       PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
+}
+
+// static dhcp_info last_good_info;
+static int dhcp_configure(const char *ifname, dhcp_info *info)
+{
+    //last_good_info = *info;
+    return mbtk_ifc_configure1(ifname, info->ipaddr, info->prefixLength, info->gateway, 0);
+}
+
+static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
+{
+    if (sz < DHCP_MSG_FIXED_SIZE)
+    {
+        if (verbose) LOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
+        return 0;
+    }
+    if (reply->op != OP_BOOTREPLY)
+    {
+        if (verbose) LOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
+        return 0;
+    }
+    if (reply->xid != msg->xid)
+    {
+        if (verbose) LOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
+                              ntohl(msg->xid));
+        return 0;
+    }
+    if (reply->htype != msg->htype)
+    {
+        if (verbose) LOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype);
+        return 0;
+    }
+    if (reply->hlen != msg->hlen)
+    {
+        if (verbose) LOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
+        return 0;
+    }
+    if (memcmp(msg->chaddr, reply->chaddr, msg->hlen))
+    {
+        if (verbose) LOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
+        return 0;
+    }
+    return 1;
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask)
+{
+    int prefixLength = 0;
+    uint32_t m = (uint32_t)ntohl(mask);
+    while (m & 0x80000000)
+    {
+        prefixLength++;
+        m = m << 1;
+    }
+    return prefixLength;
+}
+
+static int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
+{
+    uint8_t *x;
+    unsigned int opt;
+    int optlen;
+
+    memset(info, 0, sizeof(dhcp_info));
+    if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
+
+    len -= (DHCP_MSG_FIXED_SIZE + 4);
+
+    if (msg->options[0] != OPT_COOKIE1) return -1;
+    if (msg->options[1] != OPT_COOKIE2) return -1;
+    if (msg->options[2] != OPT_COOKIE3) return -1;
+    if (msg->options[3] != OPT_COOKIE4) return -1;
+
+    x = msg->options + 4;
+
+    while (len > 2)
+    {
+        opt = *x++;
+        if (opt == OPT_PAD)
+        {
+            len--;
+            continue;
+        }
+        if (opt == OPT_END)
+        {
+            break;
+        }
+        optlen = *x++;
+        len -= 2;
+        if (optlen > len)
+        {
+            break;
+        }
+        switch(opt)
+        {
+            case OPT_SUBNET_MASK:
+                if (optlen >= 4)
+                {
+                    in_addr_t mask;
+                    memcpy(&mask, x, 4);
+                    info->prefixLength = ipv4NetmaskToPrefixLength(mask);
+                }
+                break;
+            case OPT_GATEWAY:
+                if (optlen >= 4) memcpy(&info->gateway, x, 4);
+                break;
+            case OPT_DNS:
+                if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
+                if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
+                break;
+            case OPT_LEASE_TIME:
+                if (optlen >= 4)
+                {
+                    memcpy(&info->lease, x, 4);
+                    info->lease = ntohl(info->lease);
+                }
+                break;
+            case OPT_SERVER_ID:
+                if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
+                break;
+            case OPT_MESSAGE_TYPE:
+                info->type = *x;
+                break;
+            default:
+                break;
+        }
+        x += optlen;
+        len -= optlen;
+    }
+
+    info->ipaddr = msg->yiaddr;
+
+    return 0;
+}
+
+void dump_dhcp_info(dhcp_info *info)
+{
+    char addr[20], gway[20];
+    LOGD("--- dhcp %s (%d) ---",
+    dhcp_type_to_name(info->type), info->type);
+    strcpy(addr, ipaddr(info->ipaddr));
+    strcpy(gway, ipaddr(info->gateway));
+    LOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
+    if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
+    if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
+    LOGD("server %s, lease %d seconds",
+         ipaddr(info->serveraddr), info->lease);
+}
+
+static int dhcp_init_ifc(const char *ifname)
+{
+    dhcp_msg discover_msg;
+    dhcp_msg request_msg;
+    dhcp_msg reply;
+    dhcp_msg *msg;
+    dhcp_info info;
+    int s, r, size;
+    int valid_reply;
+    uint32_t xid;
+    unsigned char hwaddr[6];
+    struct pollfd pfd;
+    unsigned int state;
+    unsigned int timeout;
+    int if_index;
+
+    xid = (uint32_t) get_msecs();
+    if (mbtk_ifc_get_hwaddr(ifname, hwaddr))
+    {
+        LOGE("cannot obtain interface address");
+        return -1;
+    }
+    if (mbtk_ifc_get_ifindex(ifname, &if_index))
+    {
+        LOGE("cannot obtain interface index");
+        return -1;
+    }
+
+    s = open_raw_socket(ifname, hwaddr, if_index);
+
+    timeout = TIMEOUT_INITIAL;
+    state = STATE_SELECTING;
+    info.type = 0;
+    goto transmit;
+
+    for (;;)
+    {
+        pfd.fd = s;
+        pfd.events = POLLIN;
+        pfd.revents = 0;
+        r = poll(&pfd, 1, timeout);
+
+        if (r == 0)
+        {
+#if VERBOSE
+            LOGE("TIMEOUT");
+#endif
+            if (timeout >= TIMEOUT_MAX)
+            {
+                LOGE("timed out");
+                if ( info.type == DHCPOFFER )
+                {
+                    LOGE("no acknowledgement from DHCP server\nconfiguring %s with offered parameters", ifname);
+                    return dhcp_configure(ifname, &info);
+                }
+                errno = ETIME;
+                close(s);
+                return -1;
+            }
+            timeout = timeout * 2;
+
+        transmit:
+            size = 0;
+            msg = NULL;
+            switch(state)
+            {
+                case STATE_SELECTING:
+                    msg = &discover_msg;
+                    size = init_dhcp_discover_msg(msg, hwaddr, xid);
+                    break;
+                case STATE_REQUESTING:
+                    msg = &request_msg;
+                    size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
+                    break;
+                default:
+                    r = 0;
+            }
+            if (size != 0)
+            {
+                r = send_message(s, if_index, msg, size);
+                if (r < 0)
+                {
+                    LOGE("error sending dhcp msg: %s\n", strerror(errno));
+                }
+            }
+            continue;
+        }
+
+        if (r < 0)
+        {
+            if ((errno == EAGAIN) || (errno == EINTR))
+            {
+                continue;
+            }
+            LOGE("poll failed");
+            return -1;
+        }
+
+        errno = 0;
+        r = receive_packet(s, &reply);
+        if (r < 0)
+        {
+            if (errno != 0)
+            {
+                LOGD("receive_packet failed (%d): %s", r, strerror(errno));
+                if (errno == ENETDOWN || errno == ENXIO)
+                {
+                    return -1;
+                }
+            }
+            continue;
+        }
+
+#if VERBOSE > 1
+        dump_dhcp_msg(&reply, r);
+#endif
+        decode_dhcp_msg(&reply, r, &info);
+
+        if (state == STATE_SELECTING)
+        {
+            valid_reply = is_valid_reply(&discover_msg, &reply, r);
+        }
+        else
+        {
+            valid_reply = is_valid_reply(&request_msg, &reply, r);
+        }
+        if (!valid_reply)
+        {
+            LOGE("invalid reply");
+            continue;
+        }
+
+        if (verbose)
+            dump_dhcp_info(&info);
+
+        switch(state)
+        {
+            case STATE_SELECTING:
+                if (info.type == DHCPOFFER)
+                {
+                    state = STATE_REQUESTING;
+                    timeout = TIMEOUT_INITIAL;
+                    xid++;
+                    goto transmit;
+                }
+                break;
+            case STATE_REQUESTING:
+                if (info.type == DHCPACK)
+                {
+                    LOGE("configuring %s", ifname);
+                    close(s);
+                    return dhcp_configure(ifname, &info);
+                }
+                else if (info.type == DHCPNAK)
+                {
+                    LOGE("configuration request denied");
+                    close(s);
+                    return -1;
+                }
+                else
+                {
+                    LOGE("ignoring %s message in state %d",
+                         dhcp_type_to_name(info.type), state);
+                }
+                break;
+        }
+    }
+    close(s);
+    return 0;
+}
+
+
+int mbtk_do_dhcp(const char *name)
+{
+    int ret = 0;
+    if(mbtk_ifc_open())
+    {
+        LOGE("mbtk_ifc_open() fail.");
+        ret = -1;
+        goto return_result;
+    }
+
+    if (mbtk_ifc_set_addr(name, 0, 0))
+    {
+        LOGE("failed to set ip addr for %s to 0.0.0.0: %s", name, strerror(errno));
+        ret = -1;
+        goto return_result;
+    }
+
+    if (mbtk_ifc_up(name))
+    {
+        LOGE("failed to bring up interface %s: %s", name, strerror(errno));
+        ret = -1;
+        goto return_result;
+    }
+
+    if(dhcp_init_ifc(name))
+    {
+        LOGE("dhcp_init_ifc() fail.");
+        ret = -1;
+        goto return_result;
+    }
+
+return_result:
+
+    mbtk_ifc_close();
+
+    return ret;
+}
+
+