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;
+}
+
+