1 | /* |
2 | * libwebsockets - small server side websockets and web server implementation |
3 | * |
4 | * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to |
8 | * deal in the Software without restriction, including without limitation the |
9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | * sell copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | * IN THE SOFTWARE. |
23 | */ |
24 | |
25 | #define LWS_WIFI_MAX_SCAN_TRACK 16 |
26 | #define LWS_ETH_ALEN 6 |
27 | |
28 | typedef uint8_t lws_wifi_ch_t; |
29 | typedef int8_t ; |
30 | struct lws_netdev_instance; |
31 | |
32 | typedef enum { |
33 | LWSNDTYP_UNKNOWN, |
34 | LWSNDTYP_WIFI, |
35 | LWSNDTYP_ETH, |
36 | } lws_netdev_type_t; |
37 | |
38 | /* |
39 | * Base class for netdev configuration |
40 | */ |
41 | |
42 | typedef struct lws_netdev_config { |
43 | void *plat_config; |
44 | } lws_netdev_config_t; |
45 | |
46 | /* |
47 | * Const Logical generic network interface ops |
48 | */ |
49 | |
50 | typedef struct lws_netdev_ops { |
51 | struct lws_netdev_instance * (*create)(struct lws_context *ctx, |
52 | const struct lws_netdev_ops *ops, |
53 | const char *name, void *platinfo); |
54 | int (*configure)(struct lws_netdev_instance *nd, |
55 | lws_netdev_config_t *config); |
56 | int (*up)(struct lws_netdev_instance *nd); |
57 | int (*down)(struct lws_netdev_instance *nd); |
58 | int (*event)(struct lws_netdev_instance *nd, lws_usec_t timestamp, |
59 | void *buf, size_t len); |
60 | /**< these are SMD events coming from lws event loop thread context */ |
61 | void (*destroy)(struct lws_netdev_instance **pnd); |
62 | int (*connect)(struct lws_netdev_instance *wnd, const char *ssid, |
63 | const char *passphrase, uint8_t *bssid); |
64 | void (*scan)(struct lws_netdev_instance *nd); |
65 | } lws_netdev_ops_t; |
66 | |
67 | /* |
68 | * Network devices on this platform |
69 | * |
70 | * We also hold a list of all known network credentials (when they are needed |
71 | * because there is a network interface without anything to connect to) and |
72 | * the lws_settings instance they are stored in |
73 | */ |
74 | |
75 | typedef struct lws_netdevs { |
76 | lws_dll2_owner_t owner; |
77 | /**< list of netdevs / lws_netdev_instance_t -based objects */ |
78 | |
79 | lws_dll2_owner_t owner_creds; |
80 | /**< list of known credentials */ |
81 | struct lwsac *ac_creds; |
82 | /**< lwsac holding retreived credentials settings, or NULL */ |
83 | lws_settings_instance_t *si; |
84 | |
85 | lws_sockaddr46 sa46_dns_resolver; |
86 | |
87 | uint8_t refcount_creds; |
88 | /**< when there are multiple netdevs, must refcount creds in mem */ |
89 | } lws_netdevs_t; |
90 | |
91 | /* |
92 | * Base class for an allocated instantiated derived object using lws_netdev_ops, |
93 | * ie, a specific ethernet device |
94 | */ |
95 | |
96 | typedef struct lws_netdev_instance { |
97 | const char *name; |
98 | const lws_netdev_ops_t *ops; |
99 | void *platinfo; |
100 | lws_dll2_t list; |
101 | uint8_t mac[LWS_ETH_ALEN]; |
102 | uint8_t type; /* lws_netdev_type_t */ |
103 | } lws_netdev_instance_t; |
104 | |
105 | enum { |
106 | LNDIW_ALG_OPEN, |
107 | LNDIW_ALG_WPA2, |
108 | |
109 | LNDIW_MODE_STA = (1 << 0), |
110 | LNDIW_MODE_AP = (1 << 1), |
111 | LNDIW_UP = (1 << 7), |
112 | |
113 | LNDIW_ACQ_IPv4 = (1 << 0), |
114 | LNDIW_ACQ_IPv6 = (1 << 1), |
115 | }; |
116 | |
117 | /* |
118 | * Group AP / Station State |
119 | */ |
120 | |
121 | typedef enum { |
122 | LWSNDVWIFI_STATE_INITIAL, |
123 | /* |
124 | * We should gratuitously try whatever last worked for us, then |
125 | * if that fails, worry about the rest of the logic |
126 | */ |
127 | LWSNDVWIFI_STATE_SCAN, |
128 | /* |
129 | * Unconnected, scanning: AP known in one of the config slots -> |
130 | * configure it, start timeout + LWSNDVWIFI_STATE_STAT, if no AP |
131 | * already up in same group with lower MAC, after a random |
132 | * period start up our AP (LWSNDVWIFI_STATE_AP) |
133 | */ |
134 | LWSNDVWIFI_STATE_AP, |
135 | /* Trying to be the group AP... periodically do a scan |
136 | * LWSNDVWIFI_STATE_AP_SCAN, faster and then slower |
137 | */ |
138 | LWSNDVWIFI_STATE_AP_SCAN, |
139 | /* |
140 | * doing a scan while trying to be the group AP... if we see a |
141 | * lower MAC being the AP for the same group AP, abandon being |
142 | * an AP and join that AP as a station |
143 | */ |
144 | LWSNDVWIFI_STATE_STAT_GRP_AP, |
145 | /* |
146 | * We have decided to join another group member who is being the |
147 | * AP, as its MAC is lower than ours. This is a stable state, |
148 | * but we still do periodic scans |
149 | * LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN and will always prefer an |
150 | * AP configured in a slot. |
151 | */ |
152 | LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN, |
153 | /* |
154 | * We have joined a group member who is doing the AP job... we |
155 | * want to check every now and then if a configured AP has |
156 | * appeared that we should better use instead. Otherwise stay |
157 | * in LWSNDVWIFI_STATE_STAT_GRP_AP |
158 | */ |
159 | LWSNDVWIFI_STATE_STAT, |
160 | /* |
161 | * trying to connect to another non-group AP. If we don't get an |
162 | * IP within a timeout and retries, mark it as unusable it and go back |
163 | */ |
164 | LWSNDVWIFI_STATE_STAT_HAPPY, |
165 | } lws_netdev_wifi_state_t; |
166 | |
167 | /* |
168 | * Generic WIFI credentials |
169 | */ |
170 | |
171 | typedef struct lws_wifi_creds { |
172 | lws_dll2_t list; |
173 | |
174 | uint8_t bssid[LWS_ETH_ALEN]; |
175 | char passphrase[64]; |
176 | char ssid[33]; |
177 | uint8_t alg; |
178 | } lws_wifi_creds_t; |
179 | |
180 | /* |
181 | * Generic WIFI Network Device Instance |
182 | */ |
183 | |
184 | typedef struct lws_netdev_instance_wifi { |
185 | lws_netdev_instance_t inst; |
186 | lws_dll2_owner_t scan; /* sorted scan results */ |
187 | lws_sorted_usec_list_t sul_scan; |
188 | |
189 | lws_wifi_creds_t *ap_cred; |
190 | const char *ap_ip; |
191 | |
192 | const char *sta_ads; |
193 | |
194 | char current_attempt_ssid[33]; |
195 | uint8_t current_attempt_bssid[LWS_ETH_ALEN]; |
196 | |
197 | uint8_t flags; |
198 | uint8_t state; /* lws_netdev_wifi_state_t */ |
199 | } lws_netdev_instance_wifi_t; |
200 | |
201 | /* |
202 | * Logical scan results sorted list item |
203 | */ |
204 | |
205 | typedef struct lws_wifi_sta { |
206 | lws_dll2_t list; |
207 | |
208 | uint32_t last_seen; /* unix time */ |
209 | uint32_t last_tried; /* unix time */ |
210 | |
211 | uint8_t bssid[LWS_ETH_ALEN]; |
212 | char *ssid; /* points to overallocation */ |
213 | uint8_t ssid_len; |
214 | lws_wifi_ch_t ch; |
215 | lws_wifi_rssi_t [8]; |
216 | int16_t ; |
217 | uint8_t authmode; |
218 | |
219 | uint8_t ; |
220 | uint8_t ; |
221 | |
222 | /* ssid overallocated afterwards */ |
223 | } lws_wifi_sta_t; |
224 | |
225 | #define (_x) (_x->rssi_count ? \ |
226 | ((int)_x->rssi_avg / (int)_x->rssi_count) : \ |
227 | -200) |
228 | |
229 | LWS_VISIBLE LWS_EXTERN lws_netdevs_t * |
230 | lws_netdevs_from_ctx(struct lws_context *ctx); |
231 | |
232 | LWS_VISIBLE LWS_EXTERN int |
233 | lws_netdev_credentials_settings_set(lws_netdevs_t *nds); |
234 | |
235 | LWS_VISIBLE LWS_EXTERN int |
236 | lws_netdev_credentials_settings_get(lws_netdevs_t *nds); |
237 | |
238 | LWS_VISIBLE LWS_EXTERN struct lws_netdev_instance * |
239 | lws_netdev_wifi_create_plat(struct lws_context *ctx, |
240 | const lws_netdev_ops_t *ops, const char *name, |
241 | void *platinfo); |
242 | LWS_VISIBLE LWS_EXTERN int |
243 | lws_netdev_wifi_configure_plat(struct lws_netdev_instance *nd, |
244 | lws_netdev_config_t *config); |
245 | LWS_VISIBLE LWS_EXTERN int |
246 | lws_netdev_wifi_event_plat(struct lws_netdev_instance *nd, lws_usec_t timestamp, |
247 | void *buf, size_t len); |
248 | LWS_VISIBLE LWS_EXTERN int |
249 | lws_netdev_wifi_up_plat(struct lws_netdev_instance *nd); |
250 | LWS_VISIBLE LWS_EXTERN int |
251 | lws_netdev_wifi_down_plat(struct lws_netdev_instance *nd); |
252 | LWS_VISIBLE LWS_EXTERN void |
253 | lws_netdev_wifi_destroy_plat(struct lws_netdev_instance **pnd); |
254 | LWS_VISIBLE LWS_EXTERN void |
255 | lws_netdev_wifi_scan_plat(lws_netdev_instance_t *nd); |
256 | |
257 | LWS_VISIBLE LWS_EXTERN int |
258 | lws_netdev_wifi_connect_plat(lws_netdev_instance_t *wnd, const char *ssid, |
259 | const char *passphrase, uint8_t *bssid); |
260 | |
261 | LWS_VISIBLE LWS_EXTERN lws_netdev_instance_t * |
262 | lws_netdev_find(lws_netdevs_t *netdevs, const char *ifname); |
263 | |
264 | #define lws_netdev_wifi_plat_ops \ |
265 | .create = lws_netdev_wifi_create_plat, \ |
266 | .configure = lws_netdev_wifi_configure_plat, \ |
267 | .event = lws_netdev_wifi_event_plat, \ |
268 | .up = lws_netdev_wifi_up_plat, \ |
269 | .down = lws_netdev_wifi_down_plat, \ |
270 | .connect = lws_netdev_wifi_connect_plat, \ |
271 | .scan = lws_netdev_wifi_scan_plat, \ |
272 | .destroy = lws_netdev_wifi_destroy_plat |
273 | |
274 | /* |
275 | * This is for plat / OS level init that is necessary to be able to use |
276 | * networking or wifi at all, without mentioning any specific device |
277 | */ |
278 | |
279 | LWS_VISIBLE LWS_EXTERN int |
280 | lws_netdev_plat_init(void); |
281 | |
282 | LWS_VISIBLE LWS_EXTERN int |
283 | lws_netdev_plat_wifi_init(void); |
284 | |