auto import from //depot/cupcake/@135843
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
new file mode 100644
index 0000000..46102d5
--- /dev/null
+++ b/libnetutils/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+        dhcpclient.c \
+        dhcpmsg.c \
+        dhcp_utils.c \
+        ifc_utils.c \
+	packet.c
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils
+
+# need "-lrt" on Linux simulator to pick up clock_gettime
+ifeq ($(TARGET_SIMULATOR),true)
+	ifeq ($(HOST_OS),linux)
+		LOCAL_LDLIBS += -lrt -lpthread
+	endif
+endif
+
+LOCAL_MODULE:= libnetutils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
new file mode 100644
index 0000000..bad2e2f
--- /dev/null
+++ b/libnetutils/dhcp_utils.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+/* Utilities for managing the dhcpcd DHCP client daemon */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <cutils/properties.h>
+
+static const char DAEMON_NAME[]       = "dhcpcd";
+static const char DAEMON_PROP_NAME[]  = "init.svc.dhcpcd";
+static const char DHCP_PROP_NAME_PREFIX[]  = "dhcp";
+static const int  NAP_TIME = 1;   /* wait for 1 second at a time */
+                                  /* when polling for property values */
+static char errmsg[100];
+
+/*
+ * Wait for a system property to be assigned a specified value.
+ * If desired_value is NULL, then just wait for the property to
+ * be created with any value. maxwait is the maximum amount of
+ * time in seconds to wait before giving up.
+ */
+static int wait_for_property(const char *name, const char *desired_value, int maxwait)
+{
+    char value[PROPERTY_VALUE_MAX] = {'\0'};
+    int maxnaps = maxwait / NAP_TIME;
+
+    if (maxnaps < 1) {
+        maxnaps = 1;
+    }
+
+    while (maxnaps-- > 0) {
+        usleep(1000000);
+        if (property_get(name, value, NULL)) {
+            if (desired_value == NULL || 
+                    strcmp(value, desired_value) == 0) {
+                return 0;
+            }
+        }
+    }
+    return -1; /* failure */
+}
+
+static void fill_ip_info(const char *interface,
+                     in_addr_t *ipaddr,
+                     in_addr_t *gateway,
+                     in_addr_t *mask,
+                     in_addr_t *dns1,
+                     in_addr_t *dns2,
+                     in_addr_t *server,
+                     uint32_t  *lease)
+{
+    char prop_name[PROPERTY_KEY_MAX];
+    char prop_value[PROPERTY_VALUE_MAX];
+    struct in_addr addr;
+    in_addr_t iaddr;
+
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
+        *ipaddr = addr.s_addr;
+    } else {
+        *ipaddr = 0;
+    }
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
+        *gateway = addr.s_addr;
+    } else {
+        *gateway = 0;
+    }
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
+        *mask = addr.s_addr;
+    } else {
+        *mask = 0;
+    }
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
+        *dns1 = addr.s_addr;
+    } else {
+        *dns1 = 0;
+    }
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
+        *dns2 = addr.s_addr;
+    } else {
+        *dns2 = 0;
+    }
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
+        *server = addr.s_addr;
+    } else {
+        *server = 0;
+    }
+    snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
+    if (property_get(prop_name, prop_value, NULL)) {
+        *lease = atol(prop_value);
+    }
+}
+
+/*
+ * Start the dhcp client daemon, and wait for it to finish
+ * configuring the interface.
+ */
+int dhcp_do_request(const char *interface,
+                    in_addr_t *ipaddr,
+                    in_addr_t *gateway,
+                    in_addr_t *mask,
+                    in_addr_t *dns1,
+                    in_addr_t *dns2,
+                    in_addr_t *server,
+                    uint32_t  *lease)
+{
+    char result_prop_name[PROPERTY_KEY_MAX];
+    char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
+    const char *ctrl_prop = "ctl.start";
+    const char *desired_status = "running";
+
+    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
+            DHCP_PROP_NAME_PREFIX,
+            interface);
+    /* Erase any previous setting of the dhcp result property */
+    property_set(result_prop_name, "");
+
+    /* Start the daemon and wait until it's ready */
+    property_set(ctrl_prop, DAEMON_NAME);
+    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 10) < 0) {
+        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
+        return -1;
+    }
+
+    /* Wait for the daemon to return a result */
+    if (wait_for_property(result_prop_name, NULL, 30) < 0) {
+        snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
+        return -1;
+    }
+
+    if (!property_get(result_prop_name, prop_value, NULL)) {
+        /* shouldn't ever happen, given the success of wait_for_property() */
+        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
+        return -1;
+    }
+    if (strcmp(prop_value, "ok") == 0) {
+        fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
+        return 0;
+    } else {
+        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
+        return -1;
+    }
+}
+
+/**
+ * Stop the DHCP client daemon.
+ */
+int dhcp_stop(const char *interface)
+{
+    char result_prop_name[PROPERTY_KEY_MAX];
+    const char *ctrl_prop = "ctl.stop";
+    const char *desired_status = "stopped";
+
+    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
+            DHCP_PROP_NAME_PREFIX,
+            interface);
+    /* Stop the daemon and wait until it's reported to be stopped */
+    property_set(ctrl_prop, DAEMON_NAME);
+    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
+        return -1;
+    }
+    property_set(result_prop_name, "failed");
+    return 0;
+}
+
+/**
+ * Release the current DHCP client lease.
+ */
+int dhcp_release_lease(const char *interface)
+{
+    const char *ctrl_prop = "ctl.stop";
+    const char *desired_status = "stopped";
+
+    /* Stop the daemon and wait until it's reported to be stopped */
+    property_set(ctrl_prop, DAEMON_NAME);
+    if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+char *dhcp_get_errmsg() {
+    return errmsg;
+}
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
new file mode 100644
index 0000000..45e392a
--- /dev/null
+++ b/libnetutils/dhcpclient.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <time.h>
+#include <sys/time.h>
+#include <poll.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <cutils/properties.h>
+#define LOG_TAG "DHCP"
+#include <cutils/log.h>
+
+#include <dirent.h>
+
+#include "dhcpmsg.h"
+#include "ifc_utils.h"
+#include "packet.h"
+
+#define VERBOSE 2
+
+static int verbose = 1;
+static char errmsg[2048];
+
+typedef unsigned long long msecs_t;
+#if VERBOSE
+void dump_dhcp_msg();
+#endif
+
+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));
+    }
+}
+
+void printerr(char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
+    va_end(ap);
+
+    LOGD(errmsg);
+}
+
+const char *dhcp_lasterror()
+{
+    return errmsg;
+}
+
+int fatal(const char *reason)
+{
+    printerr("%s: %s\n", reason, strerror(errno));
+    return -1;
+//    exit(1);
+}
+
+const char *ipaddr(uint32_t addr)
+{
+    static char buf[32];
+
+    sprintf(buf,"%d.%d.%d.%d",
+            addr & 255,
+            ((addr >> 8) & 255),
+            ((addr >> 16) & 255),
+            (addr >> 24));
+    return buf;
+}
+
+typedef struct dhcp_info dhcp_info;
+
+struct dhcp_info {
+    uint32_t type;
+
+    uint32_t ipaddr;
+    uint32_t gateway;
+    uint32_t netmask;
+
+    uint32_t dns1;
+    uint32_t dns2;
+
+    uint32_t serveraddr;
+    uint32_t lease;
+};
+
+dhcp_info last_good_info;
+
+void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
+                   uint32_t *dns1, uint32_t *dns2, uint32_t *server,
+                   uint32_t *lease)
+{
+    *ipaddr = last_good_info.ipaddr;
+    *gateway = last_good_info.gateway;
+    *mask = last_good_info.netmask;
+    *dns1 = last_good_info.dns1;
+    *dns2 = last_good_info.dns2;
+    *server = last_good_info.serveraddr;
+    *lease = last_good_info.lease;
+}
+
+static int ifc_configure(const char *ifname, dhcp_info *info)
+{
+    char dns_prop_name[PROPERTY_KEY_MAX];
+
+    if (ifc_set_addr(ifname, info->ipaddr)) {
+        printerr("failed to set ipaddr %s: %s\n", ipaddr(info->ipaddr), strerror(errno));
+        return -1;
+    }
+    if (ifc_set_mask(ifname, info->netmask)) {
+        printerr("failed to set netmask %s: %s\n", ipaddr(info->netmask), strerror(errno));
+        return -1;
+    }
+    if (ifc_create_default_route(ifname, info->gateway)) {
+        printerr("failed to set default route %s: %s\n", ipaddr(info->gateway), strerror(errno));
+        return -1;
+    }
+
+    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
+    property_set(dns_prop_name, info->dns1 ? ipaddr(info->dns1) : "");
+    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
+    property_set(dns_prop_name, info->dns2 ? ipaddr(info->dns2) : "");
+
+    last_good_info = *info;
+
+    return 0;
+}
+
+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 "???";
+    }
+}
+
+void dump_dhcp_info(dhcp_info *info)
+{
+    char addr[20], gway[20], mask[20];
+    LOGD("--- dhcp %s (%d) ---",
+            dhcp_type_to_name(info->type), info->type);
+    strcpy(addr, ipaddr(info->ipaddr));
+    strcpy(gway, ipaddr(info->gateway));
+    strcpy(mask, ipaddr(info->netmask));
+    LOGD("ip %s gw %s mask %s", addr, gway, mask);
+    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);
+}
+
+
+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) memcpy(&info->netmask, x, 4);
+            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;
+}
+
+#if VERBOSE
+
+static void hex2str(char *buf, const unsigned char *array, int len)
+{
+    int i;
+    char *cp = buf;
+
+    for (i = 0; i < len; i++) {
+        cp += sprintf(cp, " %02x ", array[i]);
+    }
+}
+
+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, msg->chaddr, c);
+    LOGD("chaddr = {%s}", buf);
+
+    for (n = 0; n < 64; n++) {
+        if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
+            if (msg->sname[n] == 0) break;
+            msg->sname[n] = '.';
+        }
+    }
+    msg->sname[63] = 0;
+
+    for (n = 0; n < 128; n++) {
+        if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
+            if (msg->file[n] == 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, &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;
+    }
+}
+
+#endif
+
+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 int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
+{
+    if (sz < DHCP_MSG_FIXED_SIZE) {
+        if (verbose) LOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
+        return 0;
+    }
+    if (reply->op != OP_BOOTREPLY) {
+        if (verbose) LOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
+        return 0;
+    }
+    if (reply->xid != msg->xid) {
+        if (verbose) LOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
+                          ntohl(msg->xid));
+        return 0;
+    }
+    if (reply->htype != msg->htype) {
+        if (verbose) LOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
+        return 0;
+    }
+    if (reply->hlen != msg->hlen) {
+        if (verbose) LOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
+        return 0;
+    }
+    if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
+        if (verbose) LOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
+        return 0;
+    }
+    return 1;
+}
+
+#define STATE_SELECTING  1
+#define STATE_REQUESTING 2
+
+#define TIMEOUT_INITIAL   4000
+#define TIMEOUT_MAX      32000
+
+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 (ifc_get_hwaddr(ifname, hwaddr)) {
+        return fatal("cannot obtain interface address");
+    }
+    if (ifc_get_ifindex(ifname, &if_index)) {
+        return fatal("cannot obtain interface index");
+    }
+
+    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
+            printerr("TIMEOUT\n");
+#endif
+            if (timeout >= TIMEOUT_MAX) {
+                printerr("timed out\n");
+                if ( info.type == DHCPOFFER ) {
+                    printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
+                    return ifc_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) {
+                    printerr("error sending dhcp msg: %s\n", strerror(errno));
+                }
+            }
+            continue;
+        }
+
+        if (r < 0) {
+            if ((errno == EAGAIN) || (errno == EINTR)) {
+                continue;
+            }
+            return fatal("poll failed");
+        }
+
+        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) {
+            printerr("invalid reply\n");
+            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) {
+                printerr("configuring %s\n", ifname);
+                close(s);
+                return ifc_configure(ifname, &info);
+            } else if (info.type == DHCPNAK) {
+                printerr("configuration request denied\n");
+                close(s);
+                return -1;
+            } else {
+                printerr("ignoring %s message in state %d\n",
+                         dhcp_type_to_name(info.type), state);
+            }
+            break;
+        }
+    }
+    close(s);
+    return 0;
+}
+
+int do_dhcp(char *iname)
+{
+    if (ifc_set_addr(iname, 0)) {
+        printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
+        return -1;
+    }
+
+    if (ifc_up(iname)) {
+        printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
+        return -1;
+    }
+
+    return dhcp_init_ifc(iname);
+}
diff --git a/libnetutils/dhcpmsg.c b/libnetutils/dhcpmsg.c
new file mode 100644
index 0000000..1e0a233
--- /dev/null
+++ b/libnetutils/dhcpmsg.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "dhcpmsg.h"
+
+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;
+}
+
+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);
+}
+
+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);
+}
diff --git a/libnetutils/dhcpmsg.h b/libnetutils/dhcpmsg.h
new file mode 100644
index 0000000..c86e400
--- /dev/null
+++ b/libnetutils/dhcpmsg.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+#ifndef _WIFI_DHCP_H_
+#define _WIFI_DHCP_H_
+
+#include <sys/types.h>
+
+#define PORT_BOOTP_SERVER 67
+#define PORT_BOOTP_CLIENT 68
+
+/* RFC 2131 p 9 */
+typedef struct dhcp_msg dhcp_msg;
+
+#define OP_BOOTREQUEST 1
+#define OP_BOOTREPLY   2
+
+#define FLAGS_BROADCAST 0x8000
+
+#define HTYPE_ETHER    1
+
+struct dhcp_msg
+{
+    uint8_t op;           /* BOOTREQUEST / BOOTREPLY    */
+    uint8_t htype;        /* hw addr type               */
+    uint8_t hlen;         /* hw addr len                */
+    uint8_t hops;         /* client set to 0            */
+    
+    uint32_t xid;         /* transaction id             */
+
+    uint16_t secs;        /* seconds since start of acq */
+    uint16_t flags;
+
+    uint32_t ciaddr;      /* client IP addr             */
+    uint32_t yiaddr;      /* your (client) IP addr      */
+    uint32_t siaddr;      /* ip addr of next server     */
+                          /* (DHCPOFFER and DHCPACK)    */
+    uint32_t giaddr;      /* relay agent IP addr        */
+
+    uint8_t chaddr[16];  /* client hw addr             */
+    char sname[64];      /* asciiz server hostname     */
+    char file[128];      /* asciiz boot file name      */
+
+    uint8_t options[1024];  /* optional parameters        */
+};
+
+#define DHCP_MSG_FIXED_SIZE 236
+
+/* first four bytes of options are a cookie to indicate that
+** the payload are DHCP options as opposed to some other BOOTP
+** extension.
+*/
+#define OPT_COOKIE1          0x63
+#define OPT_COOKIE2          0x82
+#define OPT_COOKIE3          0x53
+#define OPT_COOKIE4          0x63
+
+/* BOOTP/DHCP options - see RFC 2132 */
+#define OPT_PAD              0
+
+#define OPT_SUBNET_MASK      1     /* 4 <ipaddr> */
+#define OPT_TIME_OFFSET      2     /* 4 <seconds> */
+#define OPT_GATEWAY          3     /* 4*n <ipaddr> * n */
+#define OPT_DNS              6     /* 4*n <ipaddr> * n */
+#define OPT_DOMAIN_NAME      15    /* n <domainnamestring> */
+#define OPT_BROADCAST_ADDR   28    /* 4 <ipaddr> */
+
+#define OPT_REQUESTED_IP     50    /* 4 <ipaddr> */
+#define OPT_LEASE_TIME       51    /* 4 <seconds> */
+#define OPT_MESSAGE_TYPE     53    /* 1 <msgtype> */
+#define OPT_SERVER_ID        54    /* 4 <ipaddr> */
+#define OPT_PARAMETER_LIST   55    /* n <optcode> * n */
+#define OPT_MESSAGE          56    /* n <errorstring> */
+#define OPT_CLASS_ID         60    /* n <opaque> */
+#define OPT_CLIENT_ID        61    /* n <opaque> */
+#define OPT_END              255
+
+/* DHCP message types */
+#define DHCPDISCOVER         1
+#define DHCPOFFER            2
+#define DHCPREQUEST          3
+#define DHCPDECLINE          4
+#define DHCPACK              5
+#define DHCPNAK              6
+#define DHCPRELEASE          7
+#define DHCPINFORM           8
+
+int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid);
+
+int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
+                          uint32_t ipaddr, uint32_t serveraddr);
+
+#endif
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
new file mode 100644
index 0000000..88635d9
--- /dev/null
+++ b/libnetutils/ifc_utils.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/route.h>
+#include <linux/wireless.h>
+
+#ifdef ANDROID
+#define LOG_TAG "NetUtils"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#define LOGD printf
+#define LOGW printf
+#endif
+
+static int ifc_ctl_sock = -1;
+void printerr(char *fmt, ...);
+
+static const char *ipaddr_to_string(uint32_t addr)
+{
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
+}
+
+int ifc_init(void)
+{
+    if (ifc_ctl_sock == -1) {
+        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);    
+        if (ifc_ctl_sock < 0) {
+            printerr("socket() failed: %s\n", strerror(errno));
+        }
+    }
+    return ifc_ctl_sock < 0 ? -1 : 0;
+}
+
+void ifc_close(void)
+{
+    if (ifc_ctl_sock != -1) {
+        (void)close(ifc_ctl_sock);
+        ifc_ctl_sock = -1;
+    }
+}
+
+static void ifc_init_ifr(const char *name, struct ifreq *ifr)
+{
+    memset(ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr->ifr_name, name, IFNAMSIZ);
+    ifr->ifr_name[IFNAMSIZ - 1] = 0;
+}
+
+int ifc_get_hwaddr(const char *name, void *ptr)
+{
+    int r;
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
+    if(r < 0) return -1;
+
+    memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6);
+    return 0;    
+}
+
+int ifc_get_ifindex(const char *name, int *if_indexp)
+{
+    int r;
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
+    if(r < 0) return -1;
+
+    *if_indexp = ifr.ifr_ifindex;
+    return 0;    
+}
+
+static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
+{
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
+    ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
+    return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
+}
+
+int ifc_up(const char *name)
+{
+    return ifc_set_flags(name, IFF_UP, 0);
+}
+
+int ifc_down(const char *name)
+{
+    return ifc_set_flags(name, 0, IFF_UP);
+}
+
+static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
+{
+    struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+    sin->sin_addr.s_addr = addr;
+}
+
+int ifc_set_addr(const char *name, in_addr_t addr)
+{
+    struct ifreq ifr;
+
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, addr);
+    
+    return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
+}
+
+int ifc_set_mask(const char *name, in_addr_t mask)
+{
+    struct ifreq ifr;
+
+    ifc_init_ifr(name, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, mask);
+    
+    return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
+}
+
+int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
+{
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    if (addr != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
+            *addr = 0;
+        } else {
+            *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+    
+    if (mask != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
+            *mask = 0;
+        } else {
+            *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+        }
+    }
+
+    if (flags != NULL) {
+        if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
+            *flags = 0;
+        } else {
+            *flags = ifr.ifr_flags;
+        }
+    }
+
+    return 0;
+}
+
+
+int ifc_create_default_route(const char *name, in_addr_t addr)
+{
+    struct rtentry rt;
+
+    memset(&rt, 0, sizeof(rt));
+    
+    rt.rt_dst.sa_family = AF_INET;
+    rt.rt_flags = RTF_UP | RTF_GATEWAY;
+    rt.rt_dev = (void*) name;
+    init_sockaddr_in(&rt.rt_genmask, 0);
+    init_sockaddr_in(&rt.rt_gateway, addr);
+    
+    return ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
+}
+
+int ifc_add_host_route(const char *name, in_addr_t addr)
+{
+    struct rtentry rt;
+    int result;
+
+    memset(&rt, 0, sizeof(rt));
+    
+    rt.rt_dst.sa_family = AF_INET;
+    rt.rt_flags = RTF_UP | RTF_HOST;
+    rt.rt_dev = (void*) name;
+    init_sockaddr_in(&rt.rt_dst, addr);
+    init_sockaddr_in(&rt.rt_genmask, 0);
+    init_sockaddr_in(&rt.rt_gateway, 0);
+    
+    ifc_init();
+    result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
+    if (result < 0 && errno == EEXIST) {
+        result = 0;
+    }
+    ifc_close();
+    return result;
+}
+
+int ifc_disable(const char *ifname)
+{
+    int result;
+
+    ifc_init();
+    result = ifc_down(ifname);
+    ifc_set_addr(ifname, 0);
+    ifc_close();
+    return result;
+}
+
+int ifc_reset_connections(const char *ifname)
+{
+#ifdef HAVE_ANDROID_OS
+    int result;
+    in_addr_t myaddr;
+    struct ifreq ifr;
+
+    ifc_init();
+    ifc_get_info(ifname, &myaddr, NULL, NULL);
+    ifc_init_ifr(ifname, &ifr);
+    init_sockaddr_in(&ifr.ifr_addr, myaddr);
+    result = ioctl(ifc_ctl_sock, SIOCKILLADDR,  &ifr);
+    ifc_close();
+    
+    return result;
+#else
+    return 0;
+#endif
+}
+
+/*
+ * Remove the routes associated with the named interface.
+ */
+int ifc_remove_host_routes(const char *name)
+{
+    char ifname[64];
+    in_addr_t dest, gway, mask;
+    int flags, refcnt, use, metric, mtu, win, irtt;
+    struct rtentry rt;
+    FILE *fp;
+    struct in_addr addr;
+
+    fp = fopen("/proc/net/route", "r");
+    if (fp == NULL)
+        return -1;
+    /* Skip the header line */
+    if (fscanf(fp, "%*[^\n]\n") < 0) {
+        fclose(fp);
+        return -1;
+    }
+    ifc_init();
+    for (;;) {
+        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
+                           ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
+                           &mtu, &win, &irtt);
+        if (nread != 11) {
+            break;
+        }
+        if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
+                || strcmp(ifname, name) != 0) {
+            continue;
+        }
+        memset(&rt, 0, sizeof(rt));
+        rt.rt_dev = (void *)name;
+        init_sockaddr_in(&rt.rt_dst, dest);
+        init_sockaddr_in(&rt.rt_gateway, gway);
+        init_sockaddr_in(&rt.rt_genmask, mask);
+        addr.s_addr = dest;
+        if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
+            LOGD("failed to remove route for %s to %s: %s",
+                 ifname, inet_ntoa(addr), strerror(errno));
+        }
+    }
+    fclose(fp);
+    ifc_close();
+    return 0;
+}
+
+/*
+ * Return the address of the default gateway
+ *
+ * TODO: factor out common code from this and remove_host_routes()
+ * so that we only scan /proc/net/route in one place.
+ */
+int ifc_get_default_route(const char *ifname)
+{
+    char name[64];
+    in_addr_t dest, gway, mask;
+    int flags, refcnt, use, metric, mtu, win, irtt;
+    int result;
+    FILE *fp;
+
+    fp = fopen("/proc/net/route", "r");
+    if (fp == NULL)
+        return 0;
+    /* Skip the header line */
+    if (fscanf(fp, "%*[^\n]\n") < 0) {
+        fclose(fp);
+        return 0;
+    }
+    ifc_init();
+    result = 0;
+    for (;;) {
+        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
+                           name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
+                           &mtu, &win, &irtt);
+        if (nread != 11) {
+            break;
+        }
+        if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
+                && dest == 0
+                && strcmp(ifname, name) == 0) {
+            result = gway;
+            break;
+        }
+    }
+    fclose(fp);
+    ifc_close();
+    return result;
+}
+
+/*
+ * Sets the specified gateway as the default route for the named interface.
+ */
+int ifc_set_default_route(const char *ifname, in_addr_t gateway)
+{
+    struct in_addr addr;
+    int result;
+
+    ifc_init();
+    addr.s_addr = gateway;
+    if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
+        LOGD("failed to add %s as default route for %s: %s",
+             inet_ntoa(addr), ifname, strerror(errno));
+    }
+    ifc_close();
+    return result;
+}
+
+/*
+ * Removes the default route for the named interface.
+ */
+int ifc_remove_default_route(const char *ifname)
+{
+    struct rtentry rt;
+    int result;
+
+    ifc_init();
+    memset(&rt, 0, sizeof(rt));
+    rt.rt_dev = (void *)ifname;
+    rt.rt_flags = RTF_UP|RTF_GATEWAY;
+    init_sockaddr_in(&rt.rt_dst, 0);
+    if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) {
+        LOGD("failed to remove default route for %s: %s", ifname, strerror(errno));
+    }
+    ifc_close();
+    return result;
+}
+
+int
+ifc_configure(const char *ifname,
+        in_addr_t address,
+        in_addr_t netmask,
+        in_addr_t gateway,
+        in_addr_t dns1,
+        in_addr_t dns2) {
+
+    char dns_prop_name[PROPERTY_KEY_MAX];
+
+    ifc_init();
+
+    if (ifc_up(ifname)) {
+        printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno));
+        ifc_close();
+        return -1;
+    }
+    if (ifc_set_addr(ifname, address)) {
+        printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno));
+        ifc_close();
+        return -1;
+    }
+    if (ifc_set_mask(ifname, netmask)) {
+        printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
+        ifc_close();
+        return -1;
+    }
+    if (ifc_create_default_route(ifname, gateway)) {
+        printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno));
+        ifc_close();
+        return -1;
+    }
+
+    ifc_close();
+
+    snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname);
+    property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
+    snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname);
+    property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
+
+    return 0;
+}
diff --git a/libnetutils/ifc_utils.h b/libnetutils/ifc_utils.h
new file mode 100644
index 0000000..49b8747
--- /dev/null
+++ b/libnetutils/ifc_utils.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+#ifndef _IFC_UTILS_H_
+#define _IFC_UTILS_H_
+
+int ifc_init(void);
+
+int ifc_get_ifindex(const char *name, int *if_indexp);
+int ifc_get_hwaddr(const char *name, void *ptr);
+
+int ifc_up(const char *name);
+int ifc_down(const char *name);
+
+int ifc_set_addr(const char *name, unsigned addr);
+int ifc_set_mask(const char *name, unsigned mask);
+
+int ifc_create_default_route(const char *name, unsigned addr);
+
+int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
+
+#endif
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
new file mode 100644
index 0000000..9388345
--- /dev/null
+++ b/libnetutils/packet.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+#include <errno.h>
+
+#ifdef ANDROID
+#define LOG_TAG "DHCP"
+#include <cutils/log.h>
+#else
+#include <stdio.h>
+#include <string.h>
+#define LOGD printf
+#define LOGW printf
+#endif
+
+#include "dhcpmsg.h"
+
+int fatal();
+
+int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index)
+{
+    int s, flag;
+    struct sockaddr_ll bindaddr;
+
+    if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
+        return fatal("socket(PF_PACKET)");
+    }
+
+    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) {
+        return fatal("Cannot bind raw socket to interface");
+    }
+
+    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;
+}
+
+int send_packet(int s, int if_index, struct 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);
+}
+
+int receive_packet(int s, struct dhcp_msg *msg)
+{
+    int nread;
+    int is_valid;
+    struct dhcp_packet {
+        struct iphdr ip;
+        struct udphdr udp;
+        struct 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);
+    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 (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;
+}
diff --git a/libnetutils/packet.h b/libnetutils/packet.h
new file mode 100644
index 0000000..aade392
--- /dev/null
+++ b/libnetutils/packet.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+#ifndef _WIFI_PACKET_H_
+#define _WIFI_PACKET_H_
+
+int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
+int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
+                uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
+int receive_packet(int s, struct dhcp_msg *msg);
+
+#endif