284 lines
8.3 KiB
C
284 lines
8.3 KiB
C
/*
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
*
|
|
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
|
*
|
|
* 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);
|