1 /**
2  * Copyright (c) 2018 Texas Instruments, Incorporated
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "simplelink_log.h"
8 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/net/net_if.h>
13 #include <zephyr/net/wifi_mgmt.h>
14 #include <zephyr/net/net_offload.h>
15 #include <zephyr/net/conn_mgr/connectivity_wifi_mgmt.h>
16 #ifdef CONFIG_NET_SOCKETS_OFFLOAD
17 #include <zephyr/net/socket_offload.h>
18 #endif
19 
20 #include <ti/drivers/net/wifi/wlan.h>
21 #include "simplelink_support.h"
22 #include "simplelink_sockets.h"
23 
24 #define SCAN_RETRY_DELAY 2000  /* ms */
25 #define FC_TIMEOUT K_SECONDS(CONFIG_WIFI_SIMPLELINK_FAST_CONNECT_TIMEOUT)
26 
27 #define SIMPLELINK_IPV4 0x1
28 #define SIMPLELINK_IPV6 0x2
29 
30 struct simplelink_data {
31 	struct net_if *iface;
32 	unsigned char mac[6];
33 
34 	/* Fields for scan API to emulate an asynchronous scan: */
35 	struct k_work_delayable work;
36 	scan_result_cb_t cb;
37 	int num_results_or_err;
38 	int scan_retries;
39 	bool initialized;
40 	uint8_t mask;
41 };
42 
43 static struct simplelink_data simplelink_data;
44 static K_SEM_DEFINE(ip_acquired, 0, 1);
45 
46 /* Handle connection events from the SimpleLink Event Handlers: */
simplelink_wifi_cb(uint32_t event,struct sl_connect_state * conn)47 static void simplelink_wifi_cb(uint32_t event, struct sl_connect_state *conn)
48 {
49 	int status;
50 
51 	/*
52 	 * Once Zephyr wifi_mgmt wifi_status codes are defined, will need
53 	 * to map from SimpleLink error codes.  For now, just return -EIO.
54 	 */
55 	status = (conn->error ? -EIO : 0);
56 
57 	switch (event) {
58 	case SL_WLAN_EVENT_CONNECT:
59 		/* Only get this event if connect succeeds: */
60 		wifi_mgmt_raise_connect_result_event(simplelink_data.iface,
61 						     status);
62 		break;
63 
64 	case SL_WLAN_EVENT_DISCONNECT:
65 		/* Could be during a connect, disconnect, or async error: */
66 		wifi_mgmt_raise_disconnect_result_event(simplelink_data.iface,
67 							status);
68 		break;
69 
70 	case SIMPLELINK_WIFI_CB_IPACQUIRED:
71 		simplelink_data.mask &= ~SIMPLELINK_IPV4;
72 		if ((simplelink_data.mask == 0) &&
73 			(!simplelink_data.initialized)) {
74 			simplelink_data.initialized = true;
75 			k_sem_give(&ip_acquired);
76 		}
77 		break;
78 
79 	case SIMPLELINK_WIFI_CB_IPV6ACQUIRED:
80 		simplelink_data.mask &= ~SIMPLELINK_IPV6;
81 		if ((simplelink_data.mask == 0) &&
82 			(!simplelink_data.initialized)) {
83 			simplelink_data.initialized = true;
84 			k_sem_give(&ip_acquired);
85 		}
86 		break;
87 
88 	default:
89 		LOG_DBG("Unrecognized mgmt event: 0x%x", event);
90 		break;
91 	}
92 }
93 
simplelink_scan_work_handler(struct k_work * work)94 static void simplelink_scan_work_handler(struct k_work *work)
95 {
96 	if (simplelink_data.num_results_or_err > 0) {
97 		int index = 0;
98 		struct wifi_scan_result scan_result;
99 
100 		/* Iterate over the table, and call the scan_result callback. */
101 		while (index < simplelink_data.num_results_or_err) {
102 			z_simplelink_get_scan_result(index, &scan_result);
103 			simplelink_data.cb(simplelink_data.iface, 0,
104 					   &scan_result);
105 			/* Yield, to ensure notifications get delivered:  */
106 			k_yield();
107 			index++;
108 		}
109 
110 		/* Sending a NULL entry indicates e/o results, and
111 		 * triggers the NET_EVENT_WIFI_SCAN_DONE event:
112 		 */
113 		simplelink_data.cb(simplelink_data.iface, 0, NULL);
114 
115 	} else if ((simplelink_data.num_results_or_err ==
116 		    SL_ERROR_WLAN_GET_NETWORK_LIST_EAGAIN) &&
117 		   (simplelink_data.scan_retries++ <
118 		    CONFIG_WIFI_SIMPLELINK_MAX_SCAN_RETRIES)) {
119 		int32_t delay;
120 
121 		/* Try again: */
122 		simplelink_data.num_results_or_err = z_simplelink_start_scan();
123 		simplelink_data.scan_retries++;
124 		delay = (simplelink_data.num_results_or_err > 0 ? 0 :
125 			 SCAN_RETRY_DELAY);
126 		if (delay > 0) {
127 			LOG_DBG("Retrying scan...");
128 		}
129 		k_work_reschedule(&simplelink_data.work, K_MSEC(delay));
130 
131 	} else {
132 		/* Encountered an error, or max retries exceeded: */
133 		LOG_ERR("Scan failed: retries: %d; err: %d",
134 			simplelink_data.scan_retries,
135 			simplelink_data.num_results_or_err);
136 		simplelink_data.cb(simplelink_data.iface, -EIO, NULL);
137 	}
138 }
139 
simplelink_mgmt_scan(const struct device * dev,struct wifi_scan_params * params,scan_result_cb_t cb)140 static int simplelink_mgmt_scan(const struct device *dev,
141 				struct wifi_scan_params *params,
142 				scan_result_cb_t cb)
143 {
144 	int err;
145 	int status;
146 
147 	ARG_UNUSED(params);
148 
149 	/* Cancel any previous scan processing in progress: */
150 	k_work_cancel_delayable(&simplelink_data.work);
151 
152 	/* "Request" the scan: */
153 	err = z_simplelink_start_scan();
154 
155 	/* Now, launch a delayed work handler to do retries and reporting.
156 	 * Indicate (to the work handler) either a positive number of results
157 	 * already returned, or indicate a retry is required:
158 	 */
159 	if ((err > 0) || (err == SL_ERROR_WLAN_GET_NETWORK_LIST_EAGAIN)) {
160 		int32_t delay = (err > 0 ? 0 : SCAN_RETRY_DELAY);
161 
162 		/* Store for later reference by delayed work handler: */
163 		simplelink_data.cb = cb;
164 		simplelink_data.num_results_or_err = err;
165 		simplelink_data.scan_retries = 0;
166 
167 		k_work_reschedule(&simplelink_data.work, K_MSEC(delay));
168 		status = 0;
169 	} else {
170 		status = -EIO;
171 	}
172 
173 	return status;
174 }
175 
simplelink_mgmt_connect(const struct device * dev,struct wifi_connect_req_params * params)176 static int simplelink_mgmt_connect(const struct device *dev,
177 				   struct wifi_connect_req_params *params)
178 {
179 	int ret;
180 
181 	ret = z_simplelink_connect(params);
182 
183 	return ret ? -EIO : ret;
184 }
185 
simplelink_mgmt_disconnect(const struct device * dev)186 static int simplelink_mgmt_disconnect(const struct device *dev)
187 {
188 	int ret;
189 
190 	ret = z_simplelink_disconnect();
191 
192 	return ret ? -EIO : ret;
193 }
194 
simplelink_dummy_get(sa_family_t family,enum net_sock_type type,enum net_ip_protocol ip_proto,struct net_context ** context)195 static int simplelink_dummy_get(sa_family_t family,
196 				enum net_sock_type type,
197 				enum net_ip_protocol ip_proto,
198 				struct net_context **context)
199 {
200 
201 	LOG_ERR("NET_SOCKETS_OFFLOAD must be configured for this driver");
202 
203 	return -1;
204 }
205 
206 /* Placeholders, until Zephyr IP stack updated to handle a NULL net_offload */
207 static struct net_offload simplelink_offload = {
208 	.get	       = simplelink_dummy_get,
209 	.bind	       = NULL,
210 	.listen	       = NULL,
211 	.connect       = NULL,
212 	.accept	       = NULL,
213 	.send	       = NULL,
214 	.sendto	       = NULL,
215 	.recv	       = NULL,
216 	.put	       = NULL,
217 };
218 
simplelink_iface_init(struct net_if * iface)219 static void simplelink_iface_init(struct net_if *iface)
220 {
221 	int ret;
222 
223 	simplelink_data.iface = iface;
224 	simplelink_data.mask = 0;
225 
226 	simplelink_data.mask |= IS_ENABLED(CONFIG_NET_IPV4) ?
227 		SIMPLELINK_IPV4 : 0;
228 	simplelink_data.mask |= IS_ENABLED(CONFIG_NET_IPV6) ?
229 		SIMPLELINK_IPV6 : 0;
230 
231 	/* Direct socket offload used instead of net offload: */
232 	iface->if_dev->offload = &simplelink_offload;
233 
234 	/* Initialize and configure NWP to defaults: */
235 	ret = z_simplelink_init(simplelink_wifi_cb);
236 	if (ret) {
237 		LOG_ERR("z_simplelink_init failed!");
238 		return;
239 	}
240 
241 	ret = k_sem_take(&ip_acquired, FC_TIMEOUT);
242 	if (ret < 0) {
243 		simplelink_data.initialized = false;
244 		LOG_ERR("FastConnect timed out connecting to previous AP.");
245 		LOG_ERR("Please re-establish WiFi connection.");
246 	}
247 
248 	/* Grab our MAC address: */
249 	z_simplelink_get_mac(simplelink_data.mac);
250 
251 	LOG_DBG("MAC Address %02X:%02X:%02X:%02X:%02X:%02X",
252 		simplelink_data.mac[0], simplelink_data.mac[1],
253 		simplelink_data.mac[2],
254 		simplelink_data.mac[3], simplelink_data.mac[4],
255 		simplelink_data.mac[5]);
256 
257 	net_if_set_link_addr(iface, simplelink_data.mac,
258 			     sizeof(simplelink_data.mac),
259 			     NET_LINK_ETHERNET);
260 
261 #ifdef CONFIG_NET_SOCKETS_OFFLOAD
262 	/* Direct socket offload: */
263 	socket_offload_dns_register(&simplelink_dns_ops);
264 	simplelink_sockets_init();
265 
266 	net_if_socket_offload_set(iface, simplelink_socket_create);
267 #endif
268 
269 }
270 
simplelink_get_type(void)271 static enum offloaded_net_if_types simplelink_get_type(void)
272 {
273 	return L2_OFFLOADED_NET_IF_TYPE_WIFI;
274 }
275 
276 static const struct wifi_mgmt_ops simplelink_mgmt = {
277 	.scan		= simplelink_mgmt_scan,
278 	.connect	= simplelink_mgmt_connect,
279 	.disconnect	= simplelink_mgmt_disconnect,
280 };
281 
282 static const struct net_wifi_mgmt_offload simplelink_api = {
283 	.wifi_iface.iface_api.init = simplelink_iface_init,
284 	.wifi_iface.get_type = simplelink_get_type,
285 	.wifi_mgmt_api = &simplelink_mgmt,
286 };
287 
simplelink_init(const struct device * dev)288 static int simplelink_init(const struct device *dev)
289 {
290 	ARG_UNUSED(dev);
291 
292 	/* We use system workqueue to deal with scan retries: */
293 	k_work_init_delayable(&simplelink_data.work,
294 			      simplelink_scan_work_handler);
295 
296 	LOG_DBG("SimpleLink driver Initialized");
297 
298 	return 0;
299 }
300 
301 NET_DEVICE_OFFLOAD_INIT(simplelink, CONFIG_WIFI_SIMPLELINK_NAME,
302 			simplelink_init, NULL,
303 			&simplelink_data, NULL,
304 			CONFIG_WIFI_INIT_PRIORITY, &simplelink_api,
305 			CONFIG_WIFI_SIMPLELINK_MAX_PACKET_SIZE);
306 
307 CONNECTIVITY_WIFI_MGMT_BIND(simplelink);
308