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

Last change on this file 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
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
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>
41#include <inet/dhcp.h>
42#include <inet/inetcfg.h>
43#include "ops/ieee80211.h"
44#include "ieee80211_iface.h"
45#include "nic_iface.h"
46
47#define MAX_STRING_SIZE 32
48
49/** IEEE 802.11 RPC functions IDs. */
50typedef enum {
51 IEEE80211_GET_SCAN_RESULTS,
52 IEEE80211_CONNECT,
53 IEEE80211_DISCONNECT
54} ieee80211_funcs_t;
55
56/** Get scan results from IEEE 802.11 device
57 *
58 * @param[in] dev_sess Device session.
59 * @param[out] results Structure where to put scan results.
60 *
61 * @return EOK If the operation was successfully completed,
62 * error code otherwise.
63 *
64 */
65errno_t ieee80211_get_scan_results(async_sess_t *dev_sess,
66 ieee80211_scan_results_t *results, bool now)
67{
68 assert(results);
69
70 async_exch_t *exch = async_exchange_begin(dev_sess);
71
72 aid_t aid = async_send_2(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
73 IEEE80211_GET_SCAN_RESULTS, now, NULL);
74 errno_t rc = async_data_read_start(exch, results,
75 sizeof(ieee80211_scan_results_t));
76 async_exchange_end(exch);
77
78 errno_t res;
79 async_wait_for(aid, &res);
80
81 if (res != EOK)
82 return (errno_t) res;
83
84 return rc;
85}
86
87// XXX This is wrong. Wifi should not have anything to do with IP links
88static sysarg_t get_link_id(uint8_t *mac)
89{
90 sysarg_t *link_list;
91 inet_link_info_t link_info;
92 eth_addr_t eth_addr;
93 size_t count;
94
95 eth_addr_decode(mac, &eth_addr);
96
97 errno_t rc = inetcfg_get_link_list(&link_list, &count);
98 if (rc != EOK)
99 return -1;
100
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;
105
106 if (eth_addr_compare(&eth_addr, &link_info.mac_addr) == 0)
107 return link_list[i];
108 }
109
110 return -1;
111}
112
113/** Connect to specified network.
114 *
115 * @param[in] dev_sess Device session.
116 * @param[in] ssid_start Network SSID prefix.
117 * @param[in] password Network password (pass empty string if not needed).
118 *
119 * @return EOK If the operation was successfully completed,
120 * error code otherwise.
121 *
122 */
123errno_t ieee80211_connect(async_sess_t *dev_sess, char *ssid_start, char *password)
124{
125 assert(ssid_start);
126
127 errno_t rc_orig;
128
129 async_exch_t *exch = async_exchange_begin(dev_sess);
130
131 aid_t aid = async_send_1(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
132 IEEE80211_CONNECT, NULL);
133
134 errno_t rc = async_data_write_start(exch, ssid_start,
135 str_size(ssid_start) + 1);
136 if (rc != EOK) {
137 async_exchange_end(exch);
138 async_wait_for(aid, &rc_orig);
139
140 if (rc_orig == EOK)
141 return (errno_t) rc;
142
143 return (errno_t) rc_orig;
144 }
145
146 // FIXME: Typecasting string literal
147 if (password == NULL)
148 password = (char *) "";
149
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);
154
155 if (rc_orig == EOK)
156 return (errno_t) rc;
157
158 return (errno_t) rc_orig;
159 }
160
161 async_exchange_end(exch);
162
163 async_wait_for(aid, &rc);
164 if (rc != EOK)
165 return rc;
166
167 // XXX This is wrong. Wifi should not initiate DHCP
168
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;
174
175 sysarg_t link_id = get_link_id(wifi_mac.address);
176 if (link_id == ((sysarg_t) -1))
177 return EINVAL;
178
179 rc = dhcp_discover(link_id);
180
181 return (errno_t) rc;
182}
183
184/** Disconnect device from network.
185 *
186 * @param[in] dev_sess Device session.
187 *
188 * @return EOK If the operation was successfully completed,
189 * error code otherwise.
190 *
191 */
192errno_t ieee80211_disconnect(async_sess_t *dev_sess)
193{
194 async_exch_t *exch = async_exchange_begin(dev_sess);
195 errno_t rc = async_req_1_0(exch, DEV_IFACE_ID(IEEE80211_DEV_IFACE),
196 IEEE80211_DISCONNECT);
197 async_exchange_end(exch);
198
199 if (rc != EOK)
200 return rc;
201
202 nic_address_t wifi_mac;
203 rc = nic_get_address(dev_sess, &wifi_mac);
204 if (rc != EOK)
205 return rc;
206
207 eth_addr_t eth_addr;
208 eth_addr_decode(wifi_mac.address, &eth_addr);
209
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;
216
217 /// XXX This is wrong. Wifi should do nothing with DHCP
218
219 /* Remove previous DHCP address. */
220 rc = inetcfg_get_addr_list(&addr_list, &count);
221 if (rc != EOK)
222 return rc;
223
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;
228
229 rc = inetcfg_link_get(addr_info.ilink, &link_info);
230 if (rc != EOK)
231 return rc;
232
233 if (eth_addr_compare(&eth_addr, &link_info.mac_addr) == 0) {
234 if (str_test_prefix(addr_info.name, "dhcp")) {
235 rc = inetcfg_addr_delete(addr_list[i]);
236 if (rc != EOK)
237 return rc;
238
239 break;
240 }
241 }
242 }
243
244 /*
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;
253
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;
258
259 if (str_test_prefix(route_info.name, "dhcp")) {
260 rc = inetcfg_sroute_delete(route_list[i]);
261 if (rc != EOK)
262 return rc;
263
264 break;
265 }
266 }
267
268 return rc;
269}
270
271static void remote_ieee80211_get_scan_results(ddf_fun_t *fun, void *iface,
272 ipc_call_t *call)
273{
274 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
275 assert(ieee80211_iface->get_scan_results);
276
277 ieee80211_scan_results_t scan_results;
278 memset(&scan_results, 0, sizeof(ieee80211_scan_results_t));
279
280 bool now = ipc_get_arg2(call);
281
282 errno_t rc = ieee80211_iface->get_scan_results(fun, &scan_results, now);
283 if (rc == EOK) {
284 ipc_call_t data;
285 size_t max_len;
286 if (!async_data_read_receive(&data, &max_len)) {
287 async_answer_0(&data, EINVAL);
288 async_answer_0(call, EINVAL);
289 return;
290 }
291
292 if (max_len < sizeof(ieee80211_scan_results_t)) {
293 async_answer_0(&data, ELIMIT);
294 async_answer_0(call, ELIMIT);
295 return;
296 }
297
298 async_data_read_finalize(&data, &scan_results,
299 sizeof(ieee80211_scan_results_t));
300 }
301
302 async_answer_0(call, rc);
303}
304
305static void remote_ieee80211_connect(ddf_fun_t *fun, void *iface,
306 ipc_call_t *call)
307{
308 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
309 assert(ieee80211_iface->connect);
310
311 char ssid_start[MAX_STRING_SIZE];
312 char password[MAX_STRING_SIZE];
313
314 ipc_call_t data;
315 size_t len;
316 if (!async_data_write_receive(&data, &len)) {
317 async_answer_0(&data, EINVAL);
318 async_answer_0(call, EINVAL);
319 return;
320 }
321
322 if (len > MAX_STRING_SIZE) {
323 async_answer_0(&data, EINVAL);
324 async_answer_0(call, EINVAL);
325 return;
326 }
327
328 errno_t rc = async_data_write_finalize(&data, ssid_start, len);
329 if (rc != EOK) {
330 async_answer_0(&data, EINVAL);
331 async_answer_0(call, EINVAL);
332 return;
333 }
334
335 if (!async_data_write_receive(&data, &len)) {
336 async_answer_0(&data, EINVAL);
337 async_answer_0(call, EINVAL);
338 return;
339 }
340
341 if (len > MAX_STRING_SIZE) {
342 async_answer_0(&data, EINVAL);
343 async_answer_0(call, EINVAL);
344 return;
345 }
346
347 rc = async_data_write_finalize(&data, password, len);
348 if (rc != EOK) {
349 async_answer_0(&data, EINVAL);
350 async_answer_0(call, EINVAL);
351 return;
352 }
353
354 rc = ieee80211_iface->connect(fun, ssid_start, password);
355
356 async_answer_0(call, rc);
357}
358
359static void remote_ieee80211_disconnect(ddf_fun_t *fun, void *iface,
360 ipc_call_t *call)
361{
362 ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface;
363 assert(ieee80211_iface->disconnect);
364 errno_t rc = ieee80211_iface->disconnect(fun);
365 async_answer_0(call, rc);
366}
367
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,
373 [IEEE80211_CONNECT] = remote_ieee80211_connect,
374 [IEEE80211_DISCONNECT] = remote_ieee80211_disconnect
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.