1/*
2 * hidl interface for wpa_supplicant daemon
3 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "hidl_manager.h"
11#include "hidl_return_util.h"
12#include "p2p_network.h"
13
14extern "C" {
15#include "config_ssid.h"
16}
17
18namespace android {
19namespace hardware {
20namespace wifi {
21namespace supplicant {
22namespace V1_1 {
23namespace implementation {
24using hidl_return_util::validateAndCall;
25
26P2pNetwork::P2pNetwork(
27    struct wpa_global *wpa_global, const char ifname[], int network_id)
28    : wpa_global_(wpa_global),
29      ifname_(ifname),
30      network_id_(network_id),
31      is_valid_(true)
32{
33}
34
35void P2pNetwork::invalidate() { is_valid_ = false; }
36bool P2pNetwork::isValid()
37{
38	return (is_valid_ && (retrieveNetworkPtr() != nullptr));
39}
40
41Return<void> P2pNetwork::getId(getId_cb _hidl_cb)
42{
43	return validateAndCall(
44	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
45	    &P2pNetwork::getIdInternal, _hidl_cb);
46}
47
48Return<void> P2pNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
49{
50	return validateAndCall(
51	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
52	    &P2pNetwork::getInterfaceNameInternal, _hidl_cb);
53}
54
55Return<void> P2pNetwork::getType(getType_cb _hidl_cb)
56{
57	return validateAndCall(
58	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
59	    &P2pNetwork::getTypeInternal, _hidl_cb);
60}
61
62Return<void> P2pNetwork::registerCallback(
63    const sp<ISupplicantP2pNetworkCallback> &callback,
64    registerCallback_cb _hidl_cb)
65{
66	return validateAndCall(
67	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
68	    &P2pNetwork::registerCallbackInternal, _hidl_cb, callback);
69}
70
71Return<void> P2pNetwork::getSsid(getSsid_cb _hidl_cb)
72{
73	return validateAndCall(
74	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
75	    &P2pNetwork::getSsidInternal, _hidl_cb);
76}
77
78Return<void> P2pNetwork::getBssid(getBssid_cb _hidl_cb)
79{
80	return validateAndCall(
81	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
82	    &P2pNetwork::getBssidInternal, _hidl_cb);
83}
84
85Return<void> P2pNetwork::isCurrent(isCurrent_cb _hidl_cb)
86{
87	return validateAndCall(
88	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
89	    &P2pNetwork::isCurrentInternal, _hidl_cb);
90}
91
92Return<void> P2pNetwork::isPersistent(isPersistent_cb _hidl_cb)
93{
94	return validateAndCall(
95	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
96	    &P2pNetwork::isPersistentInternal, _hidl_cb);
97}
98
99Return<void> P2pNetwork::isGo(isGo_cb _hidl_cb)
100{
101	return validateAndCall(
102	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
103	    &P2pNetwork::isGoInternal, _hidl_cb);
104}
105
106Return<void> P2pNetwork::setClientList(
107    const hidl_vec<hidl_array<uint8_t, 6>> &clients, setClientList_cb _hidl_cb)
108{
109	return validateAndCall(
110	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
111	    &P2pNetwork::setClientListInternal, _hidl_cb, clients);
112}
113
114Return<void> P2pNetwork::getClientList(getClientList_cb _hidl_cb)
115{
116	return validateAndCall(
117	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
118	    &P2pNetwork::getClientListInternal, _hidl_cb);
119}
120
121std::pair<SupplicantStatus, uint32_t> P2pNetwork::getIdInternal()
122{
123	return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
124}
125
126std::pair<SupplicantStatus, std::string> P2pNetwork::getInterfaceNameInternal()
127{
128	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
129}
130
131std::pair<SupplicantStatus, IfaceType> P2pNetwork::getTypeInternal()
132{
133	return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
134}
135
136SupplicantStatus P2pNetwork::registerCallbackInternal(
137    const sp<ISupplicantP2pNetworkCallback> &callback)
138{
139	HidlManager *hidl_manager = HidlManager::getInstance();
140	if (!hidl_manager ||
141	    hidl_manager->addP2pNetworkCallbackHidlObject(
142		ifname_, network_id_, callback)) {
143		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
144	}
145	return {SupplicantStatusCode::SUCCESS, ""};
146}
147
148std::pair<SupplicantStatus, std::vector<uint8_t>> P2pNetwork::getSsidInternal()
149{
150	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
151	return {{SupplicantStatusCode::SUCCESS, ""},
152		{wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len}};
153}
154
155std::pair<SupplicantStatus, std::array<uint8_t, 6>>
156P2pNetwork::getBssidInternal()
157{
158	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
159	std::array<uint8_t, 6> bssid{};
160	if (wpa_ssid->bssid_set) {
161		os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
162	}
163	return {{SupplicantStatusCode::SUCCESS, ""}, bssid};
164}
165
166std::pair<SupplicantStatus, bool> P2pNetwork::isCurrentInternal()
167{
168	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
169	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
170	return {{SupplicantStatusCode::SUCCESS, ""},
171		(wpa_s->current_ssid == wpa_ssid)};
172}
173
174std::pair<SupplicantStatus, bool> P2pNetwork::isPersistentInternal()
175{
176	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
177	return {{SupplicantStatusCode::SUCCESS, ""}, (wpa_ssid->disabled == 2)};
178}
179
180std::pair<SupplicantStatus, bool> P2pNetwork::isGoInternal()
181{
182	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
183	return {{SupplicantStatusCode::SUCCESS, ""},
184		(wpa_ssid->mode == wpa_ssid::wpas_mode::WPAS_MODE_P2P_GO)};
185}
186
187SupplicantStatus P2pNetwork::setClientListInternal(
188    const std::vector<hidl_array<uint8_t, 6>> &clients)
189{
190	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
191	os_free(wpa_ssid->p2p_client_list);
192	// Internal representation uses a generic MAC addr/mask storage format
193	// (even though the mask is always 0xFF'ed for p2p_client_list). So, the
194	// first 6 bytes holds the client MAC address and the next 6 bytes are
195	// OxFF'ed.
196	wpa_ssid->p2p_client_list =
197	    (u8 *)os_malloc(ETH_ALEN * 2 * clients.size());
198	if (!wpa_ssid->p2p_client_list) {
199		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
200	}
201	u8 *list = wpa_ssid->p2p_client_list;
202	for (const auto &client : clients) {
203		os_memcpy(list, client.data(), ETH_ALEN);
204		list += ETH_ALEN;
205		os_memset(list, 0xFF, ETH_ALEN);
206		list += ETH_ALEN;
207	}
208	wpa_ssid->num_p2p_clients = clients.size();
209	return {SupplicantStatusCode::SUCCESS, ""};
210}
211
212std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
213P2pNetwork::getClientListInternal()
214{
215	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
216	if (!wpa_ssid->p2p_client_list) {
217		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
218	}
219	std::vector<hidl_array<uint8_t, 6>> clients;
220	u8 *list = wpa_ssid->p2p_client_list;
221	for (size_t i = 0; i < wpa_ssid->num_p2p_clients; i++) {
222		clients.emplace_back(list);
223		list += 2 * ETH_ALEN;
224	}
225	return {{SupplicantStatusCode::SUCCESS, ""}, clients};
226}
227
228/**
229 * Retrieve the underlying |wpa_ssid| struct pointer for
230 * this network.
231 * If the underlying network is removed or the interface
232 * this network belong to is removed, all RPC method calls
233 * on this object will return failure.
234 */
235struct wpa_ssid *P2pNetwork::retrieveNetworkPtr()
236{
237	wpa_supplicant *wpa_s = retrieveIfacePtr();
238	if (!wpa_s)
239		return nullptr;
240	return wpa_config_get_network(wpa_s->conf, network_id_);
241}
242
243/**
244 * Retrieve the underlying |wpa_supplicant| struct
245 * pointer for this network.
246 */
247struct wpa_supplicant *P2pNetwork::retrieveIfacePtr()
248{
249	return wpa_supplicant_get_iface(
250	    (struct wpa_global *)wpa_global_, ifname_.c_str());
251}
252}  // namespace implementation
253}  // namespace V1_1
254}  // namespace wifi
255}  // namespace supplicant
256}  // namespace hardware
257}  // namespace android
258