/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 - 2020 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #define LWS_WIFI_MAX_SCAN_TRACK 16 #define LWS_ETH_ALEN 6 typedef uint8_t lws_wifi_ch_t; typedef int8_t lws_wifi_rssi_t; struct lws_netdev_instance; typedef enum { LWSNDTYP_UNKNOWN, LWSNDTYP_WIFI, LWSNDTYP_ETH, } lws_netdev_type_t; /* * Base class for netdev configuration */ typedef struct lws_netdev_config { void *plat_config; } lws_netdev_config_t; /* * Const Logical generic network interface ops */ typedef struct lws_netdev_ops { struct lws_netdev_instance * (*create)(struct lws_context *ctx, const struct lws_netdev_ops *ops, const char *name, void *platinfo); int (*configure)(struct lws_netdev_instance *nd, lws_netdev_config_t *config); int (*up)(struct lws_netdev_instance *nd); int (*down)(struct lws_netdev_instance *nd); int (*event)(struct lws_netdev_instance *nd, lws_usec_t timestamp, void *buf, size_t len); /**< these are SMD events coming from lws event loop thread context */ void (*destroy)(struct lws_netdev_instance **pnd); int (*connect)(struct lws_netdev_instance *wnd, const char *ssid, const char *passphrase, uint8_t *bssid); void (*scan)(struct lws_netdev_instance *nd); } lws_netdev_ops_t; /* * Network devices on this platform * * We also hold a list of all known network credentials (when they are needed * because there is a network interface without anything to connect to) and * the lws_settings instance they are stored in */ typedef struct lws_netdevs { lws_dll2_owner_t owner; /**< list of netdevs / lws_netdev_instance_t -based objects */ lws_dll2_owner_t owner_creds; /**< list of known credentials */ struct lwsac *ac_creds; /**< lwsac holding retreived credentials settings, or NULL */ lws_settings_instance_t *si; lws_sockaddr46 sa46_dns_resolver; uint8_t refcount_creds; /**< when there are multiple netdevs, must refcount creds in mem */ } lws_netdevs_t; /* * Base class for an allocated instantiated derived object using lws_netdev_ops, * ie, a specific ethernet device */ typedef struct lws_netdev_instance { const char *name; const lws_netdev_ops_t *ops; void *platinfo; lws_dll2_t list; uint8_t mac[LWS_ETH_ALEN]; uint8_t type; /* lws_netdev_type_t */ } lws_netdev_instance_t; enum { LNDIW_ALG_OPEN, LNDIW_ALG_WPA2, LNDIW_MODE_STA = (1 << 0), LNDIW_MODE_AP = (1 << 1), LNDIW_UP = (1 << 7), LNDIW_ACQ_IPv4 = (1 << 0), LNDIW_ACQ_IPv6 = (1 << 1), }; /* * Group AP / Station State */ typedef enum { LWSNDVWIFI_STATE_INITIAL, /* * We should gratuitously try whatever last worked for us, then * if that fails, worry about the rest of the logic */ LWSNDVWIFI_STATE_SCAN, /* * Unconnected, scanning: AP known in one of the config slots -> * configure it, start timeout + LWSNDVWIFI_STATE_STAT, if no AP * already up in same group with lower MAC, after a random * period start up our AP (LWSNDVWIFI_STATE_AP) */ LWSNDVWIFI_STATE_AP, /* Trying to be the group AP... periodically do a scan * LWSNDVWIFI_STATE_AP_SCAN, faster and then slower */ LWSNDVWIFI_STATE_AP_SCAN, /* * doing a scan while trying to be the group AP... if we see a * lower MAC being the AP for the same group AP, abandon being * an AP and join that AP as a station */ LWSNDVWIFI_STATE_STAT_GRP_AP, /* * We have decided to join another group member who is being the * AP, as its MAC is lower than ours. This is a stable state, * but we still do periodic scans * LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN and will always prefer an * AP configured in a slot. */ LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN, /* * We have joined a group member who is doing the AP job... we * want to check every now and then if a configured AP has * appeared that we should better use instead. Otherwise stay * in LWSNDVWIFI_STATE_STAT_GRP_AP */ LWSNDVWIFI_STATE_STAT, /* * trying to connect to another non-group AP. If we don't get an * IP within a timeout and retries, mark it as unusable it and go back */ LWSNDVWIFI_STATE_STAT_HAPPY, } lws_netdev_wifi_state_t; /* * Generic WIFI credentials */ typedef struct lws_wifi_creds { lws_dll2_t list; uint8_t bssid[LWS_ETH_ALEN]; char passphrase[64]; char ssid[33]; uint8_t alg; } lws_wifi_creds_t; /* * Generic WIFI Network Device Instance */ typedef struct lws_netdev_instance_wifi { lws_netdev_instance_t inst; lws_dll2_owner_t scan; /* sorted scan results */ lws_sorted_usec_list_t sul_scan; lws_wifi_creds_t *ap_cred; const char *ap_ip; const char *sta_ads; char current_attempt_ssid[33]; uint8_t current_attempt_bssid[LWS_ETH_ALEN]; uint8_t flags; uint8_t state; /* lws_netdev_wifi_state_t */ } lws_netdev_instance_wifi_t; /* * Logical scan results sorted list item */ typedef struct lws_wifi_sta { lws_dll2_t list; uint32_t last_seen; /* unix time */ uint32_t last_tried; /* unix time */ uint8_t bssid[LWS_ETH_ALEN]; char *ssid; /* points to overallocation */ uint8_t ssid_len; lws_wifi_ch_t ch; lws_wifi_rssi_t rssi[8]; int16_t rssi_avg; uint8_t authmode; uint8_t rssi_count; uint8_t rssi_next; /* ssid overallocated afterwards */ } lws_wifi_sta_t; #define rssi_averaged(_x) (_x->rssi_count ? \ ((int)_x->rssi_avg / (int)_x->rssi_count) : \ -200) LWS_VISIBLE LWS_EXTERN lws_netdevs_t * lws_netdevs_from_ctx(struct lws_context *ctx); LWS_VISIBLE LWS_EXTERN int lws_netdev_credentials_settings_set(lws_netdevs_t *nds); LWS_VISIBLE LWS_EXTERN int lws_netdev_credentials_settings_get(lws_netdevs_t *nds); LWS_VISIBLE LWS_EXTERN struct lws_netdev_instance * lws_netdev_wifi_create_plat(struct lws_context *ctx, const lws_netdev_ops_t *ops, const char *name, void *platinfo); LWS_VISIBLE LWS_EXTERN int lws_netdev_wifi_configure_plat(struct lws_netdev_instance *nd, lws_netdev_config_t *config); LWS_VISIBLE LWS_EXTERN int lws_netdev_wifi_event_plat(struct lws_netdev_instance *nd, lws_usec_t timestamp, void *buf, size_t len); LWS_VISIBLE LWS_EXTERN int lws_netdev_wifi_up_plat(struct lws_netdev_instance *nd); LWS_VISIBLE LWS_EXTERN int lws_netdev_wifi_down_plat(struct lws_netdev_instance *nd); LWS_VISIBLE LWS_EXTERN void lws_netdev_wifi_destroy_plat(struct lws_netdev_instance **pnd); LWS_VISIBLE LWS_EXTERN void lws_netdev_wifi_scan_plat(lws_netdev_instance_t *nd); LWS_VISIBLE LWS_EXTERN int lws_netdev_wifi_connect_plat(lws_netdev_instance_t *wnd, const char *ssid, const char *passphrase, uint8_t *bssid); LWS_VISIBLE LWS_EXTERN lws_netdev_instance_t * lws_netdev_find(lws_netdevs_t *netdevs, const char *ifname); #define lws_netdev_wifi_plat_ops \ .create = lws_netdev_wifi_create_plat, \ .configure = lws_netdev_wifi_configure_plat, \ .event = lws_netdev_wifi_event_plat, \ .up = lws_netdev_wifi_up_plat, \ .down = lws_netdev_wifi_down_plat, \ .connect = lws_netdev_wifi_connect_plat, \ .scan = lws_netdev_wifi_scan_plat, \ .destroy = lws_netdev_wifi_destroy_plat /* * This is for plat / OS level init that is necessary to be able to use * networking or wifi at all, without mentioning any specific device */ LWS_VISIBLE LWS_EXTERN int lws_netdev_plat_init(void); LWS_VISIBLE LWS_EXTERN int lws_netdev_plat_wifi_init(void);