284 lines
8.3 KiB
C
Raw Permalink Normal View History

2025-01-22 17:22:38 +01:00
/*
* 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);