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