summaryrefslogtreecommitdiffstats
path: root/libnetutils/dhcpclient.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:29:04 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:29:04 -0800
commite54eebbf1a908d65ee8cf80bab62821c05666d70 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /libnetutils/dhcpclient.c
parenta1e1c1b106423de09bc918502e7a51d4ffe5a4ae (diff)
downloadsystem_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.zip
system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.gz
system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libnetutils/dhcpclient.c')
-rw-r--r--libnetutils/dhcpclient.c562
1 files changed, 0 insertions, 562 deletions
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
deleted file mode 100644
index 45e392a..0000000
--- a/libnetutils/dhcpclient.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * 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);
-}