1//
2//  Copyright (C) 2016 Google, Inc.
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#include <rapidjson/document.h>
17#include <rapidjson/writer.h>
18#include <rapidjson/stringbuffer.h>
19#include <net/if.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22
23#include <base.h>
24#include <base/at_exit.h>
25#include <base/command_line.h>
26#include <base/logging.h>
27#include <base/macros.h>
28#include <base/strings/string_split.h>
29#include <base/strings/string_util.h>
30#include <utils/command_receiver.h>
31#include <utils/common_utils.h>
32#include <wifi_hal.h>
33#include <wifi_hal_stub.h>
34
35#include "wifi_facade.h"
36
37const char kWlanInterface[] = "wlan0";
38const char kP2pInterface[] = "p2p0";
39
40std::tuple<bool, int> WifiFacade::WifiInit() {
41  if (!WifiStartHal()) {
42    return std::make_tuple(false, sl4n_error_codes::kFailInt);
43  }
44
45  if (!WifiGetInterfaces() || wlan0_index == -1) {
46    return std::make_tuple(false, sl4n_error_codes::kFailInt);
47  }
48
49  return std::make_tuple(true, sl4n_error_codes::kPassInt);
50}
51
52bool WifiFacade::WifiStartHal() {
53  if (wifi_hal_handle == NULL) {
54    if (init_wifi_stub_hal_func_table(&hal_fn) != 0) {
55      LOG(ERROR) << sl4n::kTagStr
56          << ": Can not initialize the basic function pointer table";
57      return false;
58    }
59
60    wifi_error res = init_wifi_vendor_hal_func_table(&hal_fn);
61    if (res != WIFI_SUCCESS) {
62      LOG(ERROR) << sl4n::kTagStr
63          << ": Can not initialize the vendor function pointer table";
64      return false;
65    }
66
67    int ret = BringInterfaceUpDown(kWlanInterface, 1);
68    if (ret != 0) {
69      return false;
70    }
71
72    res = hal_fn.wifi_initialize(&wifi_hal_handle);
73    return res == WIFI_SUCCESS;
74  } else {
75    return BringInterfaceUpDown(kWlanInterface, 1) == 0;
76  }
77}
78
79bool WifiFacade::WifiGetInterfaces() {
80  int num_ifaces;
81  int result = hal_fn.wifi_get_ifaces(wifi_hal_handle, &num_ifaces,
82                                      &wifi_iface_handles);
83  if (result < 0) {
84    LOG(ERROR) << sl4n::kTagStr << ": Can not get Wi-Fi interfaces";
85    return false;
86  }
87
88  if (num_ifaces < 0) {
89    LOG(ERROR) << sl4n::kTagStr << ": Negative number of interfaces";
90    return false;
91  }
92
93  if (wifi_iface_handles == NULL) {
94    LOG(ERROR) << sl4n::kTagStr
95        << "wifi_get_ifaces returned null interface array";
96    return false;
97  }
98
99  if (num_ifaces > 8) {
100    LOG(ERROR) << sl4n::kTagStr
101        << "wifi_get_ifaces returned too many interfaces";
102    return false;
103  }
104
105  char buf[128];
106  for (int i = 0; i < num_ifaces; ++i) {
107    int result = hal_fn.wifi_get_iface_name(wifi_iface_handles[i], buf,
108                                            sizeof(buf));
109    if (result < 0) {
110      LOG(ERROR) << sl4n::kTagStr
111          << "Can't obtain interface name for interface #" << i;
112      continue;
113    }
114    if (!strcmp(buf, kWlanInterface)) {
115      wlan0_index = i;
116    } else if (!strcmp(buf, kP2pInterface)) {
117      p2p0_index = i;
118    }
119  }
120
121  return true;
122}
123
124bool WifiFacade::SharedValidator() {
125  if (wifi_hal_handle == NULL) {
126    LOG(ERROR) << sl4n::kTagStr << "HAL handle not initialized";
127    return false;
128  }
129
130  if (wifi_iface_handles == NULL) {
131    LOG(ERROR) << sl4n::kTagStr << "HAL interfaces not initialized";
132    return false;
133  }
134
135  if (wlan0_index == -1) {
136    LOG(ERROR) << sl4n::kTagStr << kWlanInterface << " interface not found";
137    return false;
138  }
139
140  return true;
141}
142
143std::tuple<int, int> WifiFacade::WifiGetSupportedFeatureSet() {
144  if (!SharedValidator()) {
145    return std::make_tuple(0, sl4n_error_codes::kFailInt);
146  }
147
148  feature_set set = 0;
149  int result = hal_fn.wifi_get_supported_feature_set(
150      wifi_iface_handles[wlan0_index], &set);
151  if (result == WIFI_SUCCESS) {
152    return std::make_tuple(set, sl4n_error_codes::kPassInt);
153  } else {
154    return std::make_tuple(0, sl4n_error_codes::kFailInt);
155  }
156}
157
158// TODO: copy of set_iface_flags from Wi-Fi JNI. Consolidate into a support
159// library.
160int WifiFacade::BringInterfaceUpDown(const char *ifname, int dev_up) {
161  struct ifreq ifr;
162  int ret;
163  int sock = socket(PF_INET, SOCK_DGRAM, 0);
164  if (sock < 0) {
165    LOG(ERROR) << "Bad socket: " << sock;
166    return -errno;
167  }
168
169  memset(&ifr, 0, sizeof(ifr));
170  strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
171
172  if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
173    ret = errno ? -errno : -999;
174    LOG(ERROR) << "Could not read interface " << ifname << " flags: " << errno;
175    close(sock);
176    return ret;
177  }
178
179  if (dev_up) {
180    if (ifr.ifr_flags & IFF_UP) {
181      close(sock);
182      return 0;
183    }
184    ifr.ifr_flags |= IFF_UP;
185  } else {
186    if (!(ifr.ifr_flags & IFF_UP)) {
187      close(sock);
188      return 0;
189    }
190    ifr.ifr_flags &= ~IFF_UP;
191  }
192
193  if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
194    LOG(ERROR) << "Could not set interface " << ifname << " flags: " << errno;
195    ret = errno ? -errno : -999;
196    close(sock);
197    return ret;
198  }
199  close(sock);
200  return 0;
201}
202
203//////////////////
204// wrappers
205/////////////////
206
207static WifiFacade facade;  // triggers registration with CommandReceiver
208
209void wifi_init_wrapper(rapidjson::Document &doc) {
210  int expected_param_size = 0;
211  if (!CommonUtils::IsParamLengthMatching(doc, expected_param_size)) {
212    return;
213  }
214  bool result;
215  int error_code;
216  std::tie(result, error_code) = facade.WifiInit();
217  if (error_code == sl4n_error_codes::kFailInt) {
218    doc.AddMember(sl4n::kResultStr, false, doc.GetAllocator());
219    doc.AddMember(sl4n::kErrorStr, sl4n::kFailStr, doc.GetAllocator());
220  } else {
221    doc.AddMember(sl4n::kResultStr, result, doc.GetAllocator());
222    doc.AddMember(sl4n::kErrorStr, NULL, doc.GetAllocator());
223  }
224}
225
226void wifi_get_supported_feature_set_wrapper(rapidjson::Document &doc) {
227  int expected_param_size = 0;
228  if (!CommonUtils::IsParamLengthMatching(doc, expected_param_size)) {
229    return;
230  }
231  int result;
232  int error_code;
233  std::tie(result, error_code) = facade.WifiGetSupportedFeatureSet();
234  if (error_code == sl4n_error_codes::kFailInt) {
235    doc.AddMember(sl4n::kResultStr, false, doc.GetAllocator());
236    doc.AddMember(sl4n::kErrorStr, sl4n::kFailStr, doc.GetAllocator());
237  } else {
238    doc.AddMember(sl4n::kResultStr, result, doc.GetAllocator());
239    doc.AddMember(sl4n::kErrorStr, NULL, doc.GetAllocator());
240  }
241}
242
243////////////////
244// constructor
245////////////////
246
247WifiFacade::WifiFacade() {
248  wifi_hal_handle = NULL;
249  wifi_iface_handles = NULL;
250  num_wifi_iface_handles = 0;
251  wlan0_index = -1;
252  p2p0_index = -1;
253
254  CommandReceiver::RegisterCommand("WifiInit", &wifi_init_wrapper);
255  CommandReceiver::RegisterCommand("WifiGetSupportedFeatureSet",
256                                   &wifi_get_supported_feature_set_wrapper);
257}
258