blob: 80a3b8f57c773ce816ce364392de27fb8c008f33 [file] [log] [blame]
//
// Copyright (C) 2016 Google, Inc.
//
// 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 <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <base.h>
#include <base/at_exit.h>
#include <base/command_line.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <utils/command_receiver.h>
#include <utils/common_utils.h>
#include <wifi_hal.h>
#include <wifi_hal_stub.h>
#include "wifi_facade.h"
const char kWlanInterface[] = "wlan0";
const char kP2pInterface[] = "p2p0";
std::tuple<bool, int> WifiFacade::WifiInit() {
if (!WifiStartHal()) {
return std::make_tuple(false, sl4n_error_codes::kFailInt);
}
if (!WifiGetInterfaces() || wlan0_index == -1) {
return std::make_tuple(false, sl4n_error_codes::kFailInt);
}
return std::make_tuple(true, sl4n_error_codes::kPassInt);
}
bool WifiFacade::WifiStartHal() {
if (wifi_hal_handle == NULL) {
if (init_wifi_stub_hal_func_table(&hal_fn) != 0) {
LOG(ERROR) << sl4n::kTagStr
<< ": Can not initialize the basic function pointer table";
return false;
}
wifi_error res = init_wifi_vendor_hal_func_table(&hal_fn);
if (res != WIFI_SUCCESS) {
LOG(ERROR) << sl4n::kTagStr
<< ": Can not initialize the vendor function pointer table";
return false;
}
int ret = BringInterfaceUpDown(kWlanInterface, 1);
if (ret != 0) {
return false;
}
res = hal_fn.wifi_initialize(&wifi_hal_handle);
return res == WIFI_SUCCESS;
} else {
return BringInterfaceUpDown(kWlanInterface, 1) == 0;
}
}
bool WifiFacade::WifiGetInterfaces() {
int num_ifaces;
int result = hal_fn.wifi_get_ifaces(wifi_hal_handle, &num_ifaces,
&wifi_iface_handles);
if (result < 0) {
LOG(ERROR) << sl4n::kTagStr << ": Can not get Wi-Fi interfaces";
return false;
}
if (num_ifaces < 0) {
LOG(ERROR) << sl4n::kTagStr << ": Negative number of interfaces";
return false;
}
if (wifi_iface_handles == NULL) {
LOG(ERROR) << sl4n::kTagStr
<< "wifi_get_ifaces returned null interface array";
return false;
}
if (num_ifaces > 8) {
LOG(ERROR) << sl4n::kTagStr
<< "wifi_get_ifaces returned too many interfaces";
return false;
}
char buf[128];
for (int i = 0; i < num_ifaces; ++i) {
int result = hal_fn.wifi_get_iface_name(wifi_iface_handles[i], buf,
sizeof(buf));
if (result < 0) {
LOG(ERROR) << sl4n::kTagStr
<< "Can't obtain interface name for interface #" << i;
continue;
}
if (!strcmp(buf, kWlanInterface)) {
wlan0_index = i;
} else if (!strcmp(buf, kP2pInterface)) {
p2p0_index = i;
}
}
return true;
}
bool WifiFacade::SharedValidator() {
if (wifi_hal_handle == NULL) {
LOG(ERROR) << sl4n::kTagStr << "HAL handle not initialized";
return false;
}
if (wifi_iface_handles == NULL) {
LOG(ERROR) << sl4n::kTagStr << "HAL interfaces not initialized";
return false;
}
if (wlan0_index == -1) {
LOG(ERROR) << sl4n::kTagStr << kWlanInterface << " interface not found";
return false;
}
return true;
}
std::tuple<int, int> WifiFacade::WifiGetSupportedFeatureSet() {
if (!SharedValidator()) {
return std::make_tuple(0, sl4n_error_codes::kFailInt);
}
feature_set set = 0;
int result = hal_fn.wifi_get_supported_feature_set(
wifi_iface_handles[wlan0_index], &set);
if (result == WIFI_SUCCESS) {
return std::make_tuple(set, sl4n_error_codes::kPassInt);
} else {
return std::make_tuple(0, sl4n_error_codes::kFailInt);
}
}
// TODO: copy of set_iface_flags from Wi-Fi JNI. Consolidate into a support
// library.
int WifiFacade::BringInterfaceUpDown(const char *ifname, int dev_up) {
struct ifreq ifr;
int ret;
int sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
LOG(ERROR) << "Bad socket: " << sock;
return -errno;
}
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
ret = errno ? -errno : -999;
LOG(ERROR) << "Could not read interface " << ifname << " flags: " << errno;
close(sock);
return ret;
}
if (dev_up) {
if (ifr.ifr_flags & IFF_UP) {
close(sock);
return 0;
}
ifr.ifr_flags |= IFF_UP;
} else {
if (!(ifr.ifr_flags & IFF_UP)) {
close(sock);
return 0;
}
ifr.ifr_flags &= ~IFF_UP;
}
if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
LOG(ERROR) << "Could not set interface " << ifname << " flags: " << errno;
ret = errno ? -errno : -999;
close(sock);
return ret;
}
close(sock);
return 0;
}
//////////////////
// wrappers
/////////////////
static WifiFacade facade; // triggers registration with CommandReceiver
void wifi_init_wrapper(rapidjson::Document &doc) {
int expected_param_size = 0;
if (!CommonUtils::IsParamLengthMatching(doc, expected_param_size)) {
return;
}
bool result;
int error_code;
std::tie(result, error_code) = facade.WifiInit();
if (error_code == sl4n_error_codes::kFailInt) {
doc.AddMember(sl4n::kResultStr, false, doc.GetAllocator());
doc.AddMember(sl4n::kErrorStr, sl4n::kFailStr, doc.GetAllocator());
} else {
doc.AddMember(sl4n::kResultStr, result, doc.GetAllocator());
doc.AddMember(sl4n::kErrorStr, NULL, doc.GetAllocator());
}
}
void wifi_get_supported_feature_set_wrapper(rapidjson::Document &doc) {
int expected_param_size = 0;
if (!CommonUtils::IsParamLengthMatching(doc, expected_param_size)) {
return;
}
int result;
int error_code;
std::tie(result, error_code) = facade.WifiGetSupportedFeatureSet();
if (error_code == sl4n_error_codes::kFailInt) {
doc.AddMember(sl4n::kResultStr, false, doc.GetAllocator());
doc.AddMember(sl4n::kErrorStr, sl4n::kFailStr, doc.GetAllocator());
} else {
doc.AddMember(sl4n::kResultStr, result, doc.GetAllocator());
doc.AddMember(sl4n::kErrorStr, NULL, doc.GetAllocator());
}
}
////////////////
// constructor
////////////////
WifiFacade::WifiFacade() {
wifi_hal_handle = NULL;
wifi_iface_handles = NULL;
num_wifi_iface_handles = 0;
wlan0_index = -1;
p2p0_index = -1;
CommandReceiver::RegisterCommand("WifiInit", &wifi_init_wrapper);
CommandReceiver::RegisterCommand("WifiGetSupportedFeatureSet",
&wifi_get_supported_feature_set_wrapper);
}