Add missing calls to refcount_init()
[helenos.git] / uspace / lib / drv / generic / remote_ieee80211.c
blob89564f7192c48573ebbec475e2f4d03a0faf6a3b
1 /*
2 * Copyright (c) 2015 Jan Kolarik
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup libdrv
30 * @{
32 /**
33 * @file
34 * @brief Driver-side RPC skeletons for IEEE 802.11 interface
37 #include <errno.h>
38 #include <macros.h>
39 #include <str.h>
40 #include <inet/dhcp.h>
41 #include <inet/inetcfg.h>
42 #include "ops/ieee80211.h"
43 #include "ieee80211_iface.h"
44 #include "nic_iface.h"
46 #define MAX_STRING_SIZE 32
48 /** IEEE 802.11 RPC functions IDs. */
49 typedef enum {
50 IEEE80211_GET_SCAN_RESULTS,
51 IEEE80211_CONNECT,
52 IEEE80211_DISCONNECT
53 } ieee80211_funcs_t;
55 /** Get scan results from IEEE 802.11 device
57 * @param[in] dev_sess Device session.
58 * @param[out] results Structure where to put scan results.
60 * @return EOK If the operation was successfully completed,
61 * error code otherwise.
64 errno_t ieee80211_get_scan_results(async_sess_t *dev_sess,
65 ieee80211_scan_results_t *results, bool now)
67 assert(results);
69 async_exch_t *exch = async_exchange_begin(dev_sess);
71 aid_t aid = async_send_2(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
72 IEEE80211_GET_SCAN_RESULTS, now, NULL);
73 errno_t rc = async_data_read_start(exch, results,
74 sizeof(ieee80211_scan_results_t));
75 async_exchange_end(exch);
77 errno_t res;
78 async_wait_for(aid, &res);
80 if (res != EOK)
81 return (errno_t) res;
83 return rc;
86 static bool mac_matches(uint8_t *mac1, uint8_t *mac2)
88 for (size_t i = 0; i < ETH_ADDR; i++) {
89 if (mac1[i] != mac2[i])
90 return false;
93 return true;
96 static sysarg_t get_link_id(uint8_t *mac)
98 sysarg_t *link_list;
99 inet_link_info_t link_info;
100 size_t count;
102 errno_t rc = inetcfg_get_link_list(&link_list, &count);
103 if (rc != EOK)
104 return -1;
106 for (size_t i = 0; i < count; i++) {
107 rc = inetcfg_link_get(link_list[i], &link_info);
108 if (rc != EOK)
109 return -1;
111 if (mac_matches(mac, link_info.mac_addr))
112 return link_list[i];
115 return -1;
118 /** Connect to specified network.
120 * @param[in] dev_sess Device session.
121 * @param[in] ssid_start Network SSID prefix.
122 * @param[in] password Network password (pass empty string if not needed).
124 * @return EOK If the operation was successfully completed,
125 * error code otherwise.
128 errno_t ieee80211_connect(async_sess_t *dev_sess, char *ssid_start, char *password)
130 assert(ssid_start);
132 errno_t rc_orig;
134 async_exch_t *exch = async_exchange_begin(dev_sess);
136 aid_t aid = async_send_1(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
137 IEEE80211_CONNECT, NULL);
139 errno_t rc = async_data_write_start(exch, ssid_start,
140 str_size(ssid_start) + 1);
141 if (rc != EOK) {
142 async_exchange_end(exch);
143 async_wait_for(aid, &rc_orig);
145 if (rc_orig == EOK)
146 return (errno_t) rc;
148 return (errno_t) rc_orig;
151 // FIXME: Typecasting string literal
152 if (password == NULL)
153 password = (char *) "";
155 rc = async_data_write_start(exch, password, str_size(password) + 1);
156 if (rc != EOK) {
157 async_exchange_end(exch);
158 async_wait_for(aid, &rc_orig);
160 if (rc_orig == EOK)
161 return (errno_t) rc;
163 return (errno_t) rc_orig;
166 async_exchange_end(exch);
168 async_wait_for(aid, &rc);
169 if (rc != EOK)
170 return rc;
172 /* Send DHCP discover. */
173 nic_address_t wifi_mac;
174 rc = nic_get_address(dev_sess, &wifi_mac);
175 if (rc != EOK)
176 return rc;
178 sysarg_t link_id = get_link_id(wifi_mac.address);
179 if (link_id == ((sysarg_t) -1))
180 return EINVAL;
182 rc = dhcp_discover(link_id);
184 return (errno_t) rc;
187 /** Disconnect device from network.
189 * @param[in] dev_sess Device session.
191 * @return EOK If the operation was successfully completed,
192 * error code otherwise.
195 errno_t ieee80211_disconnect(async_sess_t *dev_sess)
197 async_exch_t *exch = async_exchange_begin(dev_sess);
198 errno_t rc = async_req_1_0(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
199 IEEE80211_DISCONNECT);
200 async_exchange_end(exch);
202 if (rc != EOK)
203 return rc;
205 nic_address_t wifi_mac;
206 rc = nic_get_address(dev_sess, &wifi_mac);
207 if (rc != EOK)
208 return rc;
210 inet_link_info_t link_info;
211 inet_addr_info_t addr_info;
212 inet_sroute_info_t route_info;
213 sysarg_t *addr_list;
214 sysarg_t *route_list;
215 size_t count;
217 /* Remove previous DHCP address. */
218 rc = inetcfg_get_addr_list(&addr_list, &count);
219 if (rc != EOK)
220 return rc;
222 for (size_t i = 0; i < count; i++) {
223 rc = inetcfg_addr_get(addr_list[i], &addr_info);
224 if (rc != EOK)
225 return rc;
227 rc = inetcfg_link_get(addr_info.ilink, &link_info);
228 if (rc != EOK)
229 return rc;
231 if (mac_matches(wifi_mac.address, link_info.mac_addr)) {
232 if (str_test_prefix(addr_info.name, "dhcp")) {
233 rc = inetcfg_addr_delete(addr_list[i]);
234 if (rc != EOK)
235 return rc;
237 break;
243 * TODO: At this moment there can be only one DHCP route,
244 * so it must be reimplemented after this limitation will be
245 * dropped.
247 /* Remove previous DHCP static route. */
248 rc = inetcfg_get_sroute_list(&route_list, &count);
249 if (rc != EOK)
250 return rc;
252 for (size_t i = 0; i < count; i++) {
253 rc = inetcfg_sroute_get(route_list[i], &route_info);
254 if (rc != EOK)
255 return rc;
257 if (str_test_prefix(route_info.name, "dhcp")) {
258 rc = inetcfg_sroute_delete(route_list[i]);
259 if (rc != EOK)
260 return rc;
262 break;
266 return rc;
269 static void remote_ieee80211_get_scan_results(ddf_fun_t *fun, void *iface,
270 ipc_call_t *call)
272 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
273 assert(ieee80211_iface->get_scan_results);
275 ieee80211_scan_results_t scan_results;
276 memset(&scan_results, 0, sizeof(ieee80211_scan_results_t));
278 bool now = IPC_GET_ARG2(*call);
280 errno_t rc = ieee80211_iface->get_scan_results(fun, &scan_results, now);
281 if (rc == EOK) {
282 ipc_call_t data;
283 size_t max_len;
284 if (!async_data_read_receive(&data, &max_len)) {
285 async_answer_0(&data, EINVAL);
286 async_answer_0(call, EINVAL);
287 return;
290 if (max_len < sizeof(ieee80211_scan_results_t)) {
291 async_answer_0(&data, ELIMIT);
292 async_answer_0(call, ELIMIT);
293 return;
296 async_data_read_finalize(&data, &scan_results,
297 sizeof(ieee80211_scan_results_t));
300 async_answer_0(call, rc);
303 static void remote_ieee80211_connect(ddf_fun_t *fun, void *iface,
304 ipc_call_t *call)
306 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
307 assert(ieee80211_iface->connect);
309 char ssid_start[MAX_STRING_SIZE];
310 char password[MAX_STRING_SIZE];
312 ipc_call_t data;
313 size_t len;
314 if (!async_data_write_receive(&data, &len)) {
315 async_answer_0(&data, EINVAL);
316 async_answer_0(call, EINVAL);
317 return;
320 if (len > MAX_STRING_SIZE) {
321 async_answer_0(&data, EINVAL);
322 async_answer_0(call, EINVAL);
323 return;
326 errno_t rc = async_data_write_finalize(&data, ssid_start, len);
327 if (rc != EOK) {
328 async_answer_0(&data, EINVAL);
329 async_answer_0(call, EINVAL);
330 return;
333 if (!async_data_write_receive(&data, &len)) {
334 async_answer_0(&data, EINVAL);
335 async_answer_0(call, EINVAL);
336 return;
339 if (len > MAX_STRING_SIZE) {
340 async_answer_0(&data, EINVAL);
341 async_answer_0(call, EINVAL);
342 return;
345 rc = async_data_write_finalize(&data, password, len);
346 if (rc != EOK) {
347 async_answer_0(&data, EINVAL);
348 async_answer_0(call, EINVAL);
349 return;
352 rc = ieee80211_iface->connect(fun, ssid_start, password);
354 async_answer_0(call, rc);
357 static void remote_ieee80211_disconnect(ddf_fun_t *fun, void *iface,
358 ipc_call_t *call)
360 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
361 assert(ieee80211_iface->disconnect);
362 errno_t rc = ieee80211_iface->disconnect(fun);
363 async_answer_0(call, rc);
366 /** Remote IEEE 802.11 interface operations.
369 static const remote_iface_func_ptr_t remote_ieee80211_iface_ops[] = {
370 [IEEE80211_GET_SCAN_RESULTS] = remote_ieee80211_get_scan_results,
371 [IEEE80211_CONNECT] = remote_ieee80211_connect,
372 [IEEE80211_DISCONNECT] = remote_ieee80211_disconnect
375 /** Remote IEEE 802.11 interface structure.
377 * Interface for processing request from remote
378 * clients addressed to the IEEE 802.11 interface.
381 const remote_iface_t remote_ieee80211_iface = {
382 .method_count = ARRAY_SIZE(remote_ieee80211_iface_ops),
383 .methods = remote_ieee80211_iface_ops
387 * @}