1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18#include <errno.h> 19#include <sys/types.h> 20#include <sys/socket.h> 21#include <arpa/inet.h> 22#include <pthread.h> 23 24#define LOG_TAG "DhcpClient" 25#include <cutils/log.h> 26#include <cutils/properties.h> 27 28#include <sysutils/ServiceManager.h> 29 30#include "DhcpClient.h" 31#include "DhcpState.h" 32#include "DhcpListener.h" 33#include "IDhcpEventHandlers.h" 34#include "Controller.h" 35 36extern "C" { 37int ifc_disable(const char *ifname); 38int ifc_add_host_route(const char *ifname, uint32_t addr); 39int ifc_remove_host_routes(const char *ifname); 40int ifc_set_default_route(const char *ifname, uint32_t gateway); 41int ifc_get_default_route(const char *ifname); 42int ifc_remove_default_route(const char *ifname); 43int ifc_reset_connections(const char *ifname); 44int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2); 45 46int dhcp_do_request(const char *ifname, 47 in_addr_t *ipaddr, 48 in_addr_t *gateway, 49 in_addr_t *mask, 50 in_addr_t *dns1, 51 in_addr_t *dns2, 52 in_addr_t *server, 53 uint32_t *lease); 54int dhcp_stop(const char *ifname); 55int dhcp_release_lease(const char *ifname); 56char *dhcp_get_errmsg(); 57} 58 59DhcpClient::DhcpClient(IDhcpEventHandlers *handlers) : 60 mState(DhcpState::INIT), mHandlers(handlers) { 61 mServiceManager = new ServiceManager(); 62 mListener = NULL; 63 mListenerSocket = NULL; 64 mController = NULL; 65 mDoArpProbe = false; 66 pthread_mutex_init(&mLock, NULL); 67} 68 69DhcpClient::~DhcpClient() { 70 delete mServiceManager; 71 if (mListener) 72 delete mListener; 73} 74 75int DhcpClient::start(Controller *c) { 76 LOGD("Starting DHCP service (arp probe = %d)", mDoArpProbe); 77 char svc[PROPERTY_VALUE_MAX]; 78 snprintf(svc, 79 sizeof(svc), 80 "dhcpcd:%s%s", 81 (!mDoArpProbe ? "-A " : ""), 82 c->getBoundInterface()); 83 84 pthread_mutex_lock(&mLock); 85 86 if (mController) { 87 pthread_mutex_unlock(&mLock); 88 errno = EBUSY; 89 return -1; 90 } 91 mController = c; 92 93 sockaddr_in addr; 94 if ((mListenerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 95 LOGE("Failed to create DHCP listener socket"); 96 pthread_mutex_unlock(&mLock); 97 return -1; 98 } 99 memset(&addr, 0, sizeof(addr)); 100 addr.sin_family = AF_INET; 101 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 102 addr.sin_port = htons(DhcpClient::STATUS_MONITOR_PORT); 103 104 if (bind(mListenerSocket, (struct sockaddr *) &addr, sizeof(addr))) { 105 LOGE("Failed to bind DHCP listener socket"); 106 close(mListenerSocket); 107 mListenerSocket = -1; 108 pthread_mutex_unlock(&mLock); 109 return -1; 110 } 111 112 if (mServiceManager->start(svc)) { 113 LOGE("Failed to start dhcp service"); 114 pthread_mutex_unlock(&mLock); 115 return -1; 116 } 117 118 mListener = new DhcpListener(mController, mListenerSocket, mHandlers); 119 if (mListener->startListener()) { 120 LOGE("Failed to start listener"); 121#if 0 122 mServiceManager->stop("dhcpcd"); 123 return -1; 124#endif 125 delete mListener; 126 mListener = NULL; 127 pthread_mutex_unlock(&mLock); 128 } 129 130 pthread_mutex_unlock(&mLock); 131 return 0; 132} 133 134int DhcpClient::stop() { 135 pthread_mutex_lock(&mLock); 136 if (!mController) { 137 pthread_mutex_unlock(&mLock); 138 return 0; 139 } 140 141 if (mListener) { 142 mListener->stopListener(); 143 delete mListener; 144 mListener = NULL; 145 } 146 close(mListenerSocket); 147 148 if (mServiceManager->stop("dhcpcd")) { 149 LOGW("Failed to stop DHCP service (%s)", strerror(errno)); 150 // XXX: Kill it the hard way.. but its gotta go! 151 } 152 153 mController = NULL; 154 pthread_mutex_unlock(&mLock); 155 return 0; 156} 157 158void DhcpClient::setDoArpProbe(bool probe) { 159 mDoArpProbe = probe; 160} 161