source: mainline/uspace/lib/drv/generic/remote_ieee80211.c@ c77cfd8

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c77cfd8 was 3e6bca8, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Represent Ethernet address as a number instead of an array

Carefully document the design since this breaks the principle of least
surprise. Also add unit tests.

  • Property mode set to 100644
File size: 9.5 KB
RevLine 
[59fa7ab]1/*
[3e6bca8]2 * Copyright (c) 2021 Jiri Svoboda
[59fa7ab]3 * Copyright (c) 2015 Jan Kolarik
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libdrv
31 * @{
32 */
33/**
34 * @file
35 * @brief Driver-side RPC skeletons for IEEE 802.11 interface
36 */
37
38#include <errno.h>
39#include <macros.h>
40#include <str.h>
[053fc2b]41#include <inet/dhcp.h>
42#include <inet/inetcfg.h>
[59fa7ab]43#include "ops/ieee80211.h"
44#include "ieee80211_iface.h"
[053fc2b]45#include "nic_iface.h"
[59fa7ab]46
[8a64320e]47#define MAX_STRING_SIZE 32
[59fa7ab]48
49/** IEEE 802.11 RPC functions IDs. */
50typedef enum {
51 IEEE80211_GET_SCAN_RESULTS,
[1dcc0b9]52 IEEE80211_CONNECT,
53 IEEE80211_DISCONNECT
[59fa7ab]54} ieee80211_funcs_t;
55
56/** Get scan results from IEEE 802.11 device
57 *
[8a64320e]58 * @param[in] dev_sess Device session.
59 * @param[out] results Structure where to put scan results.
[59fa7ab]60 *
61 * @return EOK If the operation was successfully completed,
[cde999a]62 * error code otherwise.
[8a64320e]63 *
[59fa7ab]64 */
[b7fd2a0]65errno_t ieee80211_get_scan_results(async_sess_t *dev_sess,
[8a64320e]66 ieee80211_scan_results_t *results, bool now)
[59fa7ab]67{
68 assert(results);
[a35b458]69
[59fa7ab]70 async_exch_t *exch = async_exchange_begin(dev_sess);
[a35b458]71
[1dcc0b9]72 aid_t aid = async_send_2(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
73 IEEE80211_GET_SCAN_RESULTS, now, NULL);
[b7fd2a0]74 errno_t rc = async_data_read_start(exch, results,
[8a64320e]75 sizeof(ieee80211_scan_results_t));
[59fa7ab]76 async_exchange_end(exch);
[a35b458]77
[b7fd2a0]78 errno_t res;
[59fa7ab]79 async_wait_for(aid, &res);
[a35b458]80
[3bacee1]81 if (res != EOK)
[b7fd2a0]82 return (errno_t) res;
[a35b458]83
[8a64320e]84 return rc;
[59fa7ab]85}
86
[3e6bca8]87// XXX This is wrong. Wifi should not have anything to do with IP links
[053fc2b]88static sysarg_t get_link_id(uint8_t *mac)
89{
90 sysarg_t *link_list;
91 inet_link_info_t link_info;
[3e6bca8]92 eth_addr_t eth_addr;
[053fc2b]93 size_t count;
[a35b458]94
[3e6bca8]95 eth_addr_decode(mac, &eth_addr);
96
[b7fd2a0]97 errno_t rc = inetcfg_get_link_list(&link_list, &count);
[053fc2b]98 if (rc != EOK)
99 return -1;
[a35b458]100
[053fc2b]101 for (size_t i = 0; i < count; i++) {
102 rc = inetcfg_link_get(link_list[i], &link_info);
103 if (rc != EOK)
104 return -1;
[a35b458]105
[3e6bca8]106 if (eth_addr_compare(&eth_addr, &link_info.mac_addr) == 0)
[053fc2b]107 return link_list[i];
108 }
[a35b458]109
[053fc2b]110 return -1;
111}
112
[59fa7ab]113/** Connect to specified network.
114 *
[8a64320e]115 * @param[in] dev_sess Device session.
[1dcc0b9]116 * @param[in] ssid_start Network SSID prefix.
[8a64320e]117 * @param[in] password Network password (pass empty string if not needed).
[59fa7ab]118 *
119 * @return EOK If the operation was successfully completed,
[cde999a]120 * error code otherwise.
[8a64320e]121 *
[59fa7ab]122 */
[b7fd2a0]123errno_t ieee80211_connect(async_sess_t *dev_sess, char *ssid_start, char *password)
[59fa7ab]124{
[1dcc0b9]125 assert(ssid_start);
[a35b458]126
[b7fd2a0]127 errno_t rc_orig;
[a35b458]128
[59fa7ab]129 async_exch_t *exch = async_exchange_begin(dev_sess);
[a35b458]130
[59fa7ab]131 aid_t aid = async_send_1(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
132 IEEE80211_CONNECT, NULL);
[a35b458]133
[b7fd2a0]134 errno_t rc = async_data_write_start(exch, ssid_start,
[8a64320e]135 str_size(ssid_start) + 1);
[59fa7ab]136 if (rc != EOK) {
137 async_exchange_end(exch);
138 async_wait_for(aid, &rc_orig);
[a35b458]139
[59fa7ab]140 if (rc_orig == EOK)
[b7fd2a0]141 return (errno_t) rc;
[a35b458]142
[b7fd2a0]143 return (errno_t) rc_orig;
[59fa7ab]144 }
[a35b458]145
[8a64320e]146 // FIXME: Typecasting string literal
147 if (password == NULL)
[59fa7ab]148 password = (char *) "";
[a35b458]149
[59fa7ab]150 rc = async_data_write_start(exch, password, str_size(password) + 1);
151 if (rc != EOK) {
152 async_exchange_end(exch);
153 async_wait_for(aid, &rc_orig);
[a35b458]154
[59fa7ab]155 if (rc_orig == EOK)
[b7fd2a0]156 return (errno_t) rc;
[a35b458]157
[b7fd2a0]158 return (errno_t) rc_orig;
[59fa7ab]159 }
[a35b458]160
[59fa7ab]161 async_exchange_end(exch);
[a35b458]162
[59fa7ab]163 async_wait_for(aid, &rc);
[053fc2b]164 if (rc != EOK)
165 return rc;
[a35b458]166
[3e6bca8]167 // XXX This is wrong. Wifi should not initiate DHCP
168
[053fc2b]169 /* Send DHCP discover. */
170 nic_address_t wifi_mac;
171 rc = nic_get_address(dev_sess, &wifi_mac);
172 if (rc != EOK)
173 return rc;
[a35b458]174
[053fc2b]175 sysarg_t link_id = get_link_id(wifi_mac.address);
[8a64320e]176 if (link_id == ((sysarg_t) -1))
[053fc2b]177 return EINVAL;
[a35b458]178
[053fc2b]179 rc = dhcp_discover(link_id);
[a35b458]180
[b7fd2a0]181 return (errno_t) rc;
[59fa7ab]182}
183
[1dcc0b9]184/** Disconnect device from network.
185 *
186 * @param[in] dev_sess Device session.
187 *
188 * @return EOK If the operation was successfully completed,
[cde999a]189 * error code otherwise.
[8a64320e]190 *
[1dcc0b9]191 */
[b7fd2a0]192errno_t ieee80211_disconnect(async_sess_t *dev_sess)
[1dcc0b9]193{
194 async_exch_t *exch = async_exchange_begin(dev_sess);
[b7fd2a0]195 errno_t rc = async_req_1_0(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
[1dcc0b9]196 IEEE80211_DISCONNECT);
197 async_exchange_end(exch);
[a35b458]198
[8a64320e]199 if (rc != EOK)
[053fc2b]200 return rc;
[a35b458]201
[053fc2b]202 nic_address_t wifi_mac;
203 rc = nic_get_address(dev_sess, &wifi_mac);
204 if (rc != EOK)
205 return rc;
[a35b458]206
[3e6bca8]207 eth_addr_t eth_addr;
208 eth_addr_decode(wifi_mac.address, &eth_addr);
209
[053fc2b]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;
[a35b458]216
[3e6bca8]217 /// XXX This is wrong. Wifi should do nothing with DHCP
218
[053fc2b]219 /* Remove previous DHCP address. */
220 rc = inetcfg_get_addr_list(&addr_list, &count);
221 if (rc != EOK)
222 return rc;
[a35b458]223
[053fc2b]224 for (size_t i = 0; i < count; i++) {
225 rc = inetcfg_addr_get(addr_list[i], &addr_info);
226 if (rc != EOK)
227 return rc;
[a35b458]228
[053fc2b]229 rc = inetcfg_link_get(addr_info.ilink, &link_info);
230 if (rc != EOK)
231 return rc;
[a35b458]232
[3e6bca8]233 if (eth_addr_compare(&eth_addr, &link_info.mac_addr) == 0) {
[8a64320e]234 if (str_test_prefix(addr_info.name, "dhcp")) {
[053fc2b]235 rc = inetcfg_addr_delete(addr_list[i]);
[8a64320e]236 if (rc != EOK)
[053fc2b]237 return rc;
[a35b458]238
[053fc2b]239 break;
240 }
241 }
242 }
[a35b458]243
[8a64320e]244 /*
[053fc2b]245 * TODO: At this moment there can be only one DHCP route,
246 * so it must be reimplemented after this limitation will be
247 * dropped.
248 */
249 /* Remove previous DHCP static route. */
250 rc = inetcfg_get_sroute_list(&route_list, &count);
251 if (rc != EOK)
252 return rc;
[a35b458]253
[053fc2b]254 for (size_t i = 0; i < count; i++) {
255 rc = inetcfg_sroute_get(route_list[i], &route_info);
256 if (rc != EOK)
257 return rc;
[a35b458]258
[8a64320e]259 if (str_test_prefix(route_info.name, "dhcp")) {
[053fc2b]260 rc = inetcfg_sroute_delete(route_list[i]);
[8a64320e]261 if (rc != EOK)
[053fc2b]262 return rc;
[a35b458]263
[053fc2b]264 break;
265 }
266 }
[a35b458]267
[1dcc0b9]268 return rc;
269}
270
[59fa7ab]271static void remote_ieee80211_get_scan_results(ddf_fun_t *fun, void *iface,
[984a9ba]272 ipc_call_t *call)
[59fa7ab]273{
274 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
275 assert(ieee80211_iface->get_scan_results);
[a35b458]276
[59fa7ab]277 ieee80211_scan_results_t scan_results;
278 memset(&scan_results, 0, sizeof(ieee80211_scan_results_t));
[a35b458]279
[fafb8e5]280 bool now = ipc_get_arg2(call);
[a35b458]281
[b7fd2a0]282 errno_t rc = ieee80211_iface->get_scan_results(fun, &scan_results, now);
[59fa7ab]283 if (rc == EOK) {
[984a9ba]284 ipc_call_t data;
[59fa7ab]285 size_t max_len;
[984a9ba]286 if (!async_data_read_receive(&data, &max_len)) {
287 async_answer_0(&data, EINVAL);
288 async_answer_0(call, EINVAL);
[59fa7ab]289 return;
290 }
[a35b458]291
[59fa7ab]292 if (max_len < sizeof(ieee80211_scan_results_t)) {
[984a9ba]293 async_answer_0(&data, ELIMIT);
294 async_answer_0(call, ELIMIT);
[59fa7ab]295 return;
296 }
[a35b458]297
[984a9ba]298 async_data_read_finalize(&data, &scan_results,
[59fa7ab]299 sizeof(ieee80211_scan_results_t));
300 }
[a35b458]301
[984a9ba]302 async_answer_0(call, rc);
[59fa7ab]303}
304
305static void remote_ieee80211_connect(ddf_fun_t *fun, void *iface,
[984a9ba]306 ipc_call_t *call)
[59fa7ab]307{
308 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
309 assert(ieee80211_iface->connect);
[a35b458]310
[1dcc0b9]311 char ssid_start[MAX_STRING_SIZE];
[59fa7ab]312 char password[MAX_STRING_SIZE];
[a35b458]313
[984a9ba]314 ipc_call_t data;
[59fa7ab]315 size_t len;
[984a9ba]316 if (!async_data_write_receive(&data, &len)) {
317 async_answer_0(&data, EINVAL);
318 async_answer_0(call, EINVAL);
[59fa7ab]319 return;
320 }
[a35b458]321
[59fa7ab]322 if (len > MAX_STRING_SIZE) {
[984a9ba]323 async_answer_0(&data, EINVAL);
324 async_answer_0(call, EINVAL);
[59fa7ab]325 return;
326 }
[a35b458]327
[984a9ba]328 errno_t rc = async_data_write_finalize(&data, ssid_start, len);
[59fa7ab]329 if (rc != EOK) {
[984a9ba]330 async_answer_0(&data, EINVAL);
331 async_answer_0(call, EINVAL);
[59fa7ab]332 return;
333 }
[a35b458]334
[984a9ba]335 if (!async_data_write_receive(&data, &len)) {
336 async_answer_0(&data, EINVAL);
337 async_answer_0(call, EINVAL);
[59fa7ab]338 return;
339 }
[a35b458]340
[59fa7ab]341 if (len > MAX_STRING_SIZE) {
[984a9ba]342 async_answer_0(&data, EINVAL);
343 async_answer_0(call, EINVAL);
[59fa7ab]344 return;
345 }
[a35b458]346
[984a9ba]347 rc = async_data_write_finalize(&data, password, len);
[59fa7ab]348 if (rc != EOK) {
[984a9ba]349 async_answer_0(&data, EINVAL);
350 async_answer_0(call, EINVAL);
[59fa7ab]351 return;
352 }
[a35b458]353
[1dcc0b9]354 rc = ieee80211_iface->connect(fun, ssid_start, password);
[a35b458]355
[984a9ba]356 async_answer_0(call, rc);
[59fa7ab]357}
358
[1dcc0b9]359static void remote_ieee80211_disconnect(ddf_fun_t *fun, void *iface,
[984a9ba]360 ipc_call_t *call)
[1dcc0b9]361{
362 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
363 assert(ieee80211_iface->disconnect);
[b7fd2a0]364 errno_t rc = ieee80211_iface->disconnect(fun);
[984a9ba]365 async_answer_0(call, rc);
[1dcc0b9]366}
367
[59fa7ab]368/** Remote IEEE 802.11 interface operations.
369 *
370 */
371static const remote_iface_func_ptr_t remote_ieee80211_iface_ops[] = {
372 [IEEE80211_GET_SCAN_RESULTS] = remote_ieee80211_get_scan_results,
[1dcc0b9]373 [IEEE80211_CONNECT] = remote_ieee80211_connect,
374 [IEEE80211_DISCONNECT] = remote_ieee80211_disconnect
[59fa7ab]375};
376
377/** Remote IEEE 802.11 interface structure.
378 *
379 * Interface for processing request from remote
380 * clients addressed to the IEEE 802.11 interface.
381 *
382 */
383const remote_iface_t remote_ieee80211_iface = {
384 .method_count = ARRAY_SIZE(remote_ieee80211_iface_ops),
385 .methods = remote_ieee80211_iface_ops
386};
387
388/**
389 * @}
390 */
Note: See TracBrowser for help on using the repository browser.