From b7556b2ddc906ae5b83d5b7f00fcfe8fb9b2257a Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Fri, 19 Jul 2024 23:23:01 +0800 Subject: [PATCH] feat(class/vendor/wifi/usbh_bl616): add bl616 usbwifi driver --- class/vendor/wifi/usbh_bl616.c | 505 +++++++++++++++++++++++++++++++++ class/vendor/wifi/usbh_bl616.h | 220 ++++++++++++++ 2 files changed, 725 insertions(+) create mode 100644 class/vendor/wifi/usbh_bl616.c create mode 100644 class/vendor/wifi/usbh_bl616.h diff --git a/class/vendor/wifi/usbh_bl616.c b/class/vendor/wifi/usbh_bl616.c new file mode 100644 index 00000000..6145a03d --- /dev/null +++ b/class/vendor/wifi/usbh_bl616.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbh_core.h" +#include "usbh_bl616.h" + +#undef USB_DBG_TAG +#define USB_DBG_TAG "usbh_bl616" +#include "usb_log.h" + +#define DEV_FORMAT "/dev/wifi/bl616" + +#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X" +#define ARR_ELE_6(e) (e)[0], (e)[1], (e)[2], (e)[3], (e)[4], (e)[5] + +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bl616_tx_buffer[2048 + 512]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bl616_rx_buffer[2048 + 512]; + +static struct usbh_bl616 g_bl616_class; + +static const char *auth_to_str(uint8_t auth) +{ + const char *table[RNM_WIFI_AUTH_MAX] = { + [RNM_WIFI_AUTH_UNKNOWN] = "UNKNOWN", + [RNM_WIFI_AUTH_OPEN] = "OPEN", + [RNM_WIFI_AUTH_WEP] = "WEP", + [RNM_WIFI_AUTH_WPA_PSK] = "WPA-PSK", + [RNM_WIFI_AUTH_WPA2_PSK] = "WPA2-PSK", + [RNM_WIFI_AUTH_WPA_WPA2_PSK] = "WPA2-PSK/WPA-PSK", + [RNM_WIFI_AUTH_WPA_ENTERPRISE] = "WPA-ENT", + [RNM_WIFI_AUTH_WPA3_SAE] = "WPA3-SAE", + [RNM_WIFI_AUTH_WPA2_PSK_WPA3_SAE] = "WPA2-PSK/WPA3-SAE", + }; + if (auth < RNM_WIFI_AUTH_MAX) + return table[auth]; + else + return table[RNM_WIFI_AUTH_UNKNOWN]; +} + +static const char *cipher_to_str(uint8_t cipher) +{ + const char *table[RNM_WIFI_CIPHER_MAX] = { + [RNM_WIFI_CIPHER_UNKNOWN] = "UNKNOWN", + [RNM_WIFI_CIPHER_NONE] = "NONE", + [RNM_WIFI_CIPHER_WEP] = "WEP", + [RNM_WIFI_CIPHER_AES] = "AES", + [RNM_WIFI_CIPHER_TKIP] = "TKIP", + [RNM_WIFI_CIPHER_TKIP_AES] = "TKIP/AES", + }; + if (cipher < RNM_WIFI_CIPHER_MAX) + return table[cipher]; + else + return table[RNM_WIFI_CIPHER_UNKNOWN]; +} + +static int parse_get_mac_rsp_msg(struct usbh_bl616 *bl616_class, void *buf, int buf_len) +{ + usb_data_t *usb_hdr = buf; + rnm_mac_addr_ind_msg_t *rsp = buf + sizeof(usb_data_t); + + if (buf_len != sizeof(usb_data_t) + sizeof(rnm_mac_addr_ind_msg_t)) { + return -1; + } + if (usb_hdr->type != USBWIFI_DATA_TYPE_CMD || usb_hdr->length != sizeof(rnm_mac_addr_ind_msg_t)) { + return -1; + } + if (rsp->hdr.cmd != BFLB_CMD_GET_MAC_ADDR || !(rsp->hdr.flags & RNM_MSG_FLAG_ACK)) { + return -1; + } + memcpy(bl616_class->sta_mac, rsp->sta_mac, 6); + memcpy(bl616_class->ap_mac, rsp->ap_mac, 6); + + return 0; +} + +static int usbh_bl616_bulk_in_transfer(struct usbh_bl616 *bl616_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +{ + int ret; + struct usbh_urb *urb = &bl616_class->bulkin_urb; + + usbh_bulk_urb_fill(urb, bl616_class->hport, bl616_class->bulkin, buffer, buflen, timeout, NULL, NULL); + ret = usbh_submit_urb(urb); + if (ret == 0) { + ret = urb->actual_length; + } + return ret; +} + +static int usbh_bl616_bulk_out_transfer(struct usbh_bl616 *bl616_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout) +{ + int ret; + struct usbh_urb *urb = &bl616_class->bulkout_urb; + + usbh_bulk_urb_fill(urb, bl616_class->hport, bl616_class->bulkout, buffer, buflen, timeout, NULL, NULL); + ret = usbh_submit_urb(urb); + if (ret == 0) { + ret = urb->actual_length; + } + return ret; +} + +static int usbh_bl616_get_wifi_mac(struct usbh_bl616 *bl616_class) +{ + int ret; + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_base_msg_t *rnm_msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(rnm_msg, 0, sizeof(rnm_base_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_base_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + rnm_msg->cmd = BFLB_CMD_GET_MAC_ADDR; + + msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t); + + ret = usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500); + if (ret < 0) { + return ret; + } + ret = usbh_bl616_bulk_in_transfer(bl616_class, g_bl616_rx_buffer, sizeof(g_bl616_rx_buffer), 500); + if (ret < 0) { + return ret; + } + + ret = parse_get_mac_rsp_msg(bl616_class, g_bl616_rx_buffer, ret); + return ret; +} + +static int usbh_bl616_wifi_open(struct usbh_bl616 *bl616_class) +{ + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(msg, 0, sizeof(rnm_base_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_base_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + msg->cmd = BFLB_CMD_HELLO; + + msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t); + + return usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500); +} + +static int usbh_bl616_wifi_close(struct usbh_bl616 *bl616_class) +{ + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(msg, 0, sizeof(rnm_base_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_base_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + msg->cmd = BFLB_CMD_UNLOAD_DRV; + + msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t); + + return usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500); +} + +int usbh_bl616_wifi_sta_connect(const char *ssid, + const int ssid_len, + const char *password, + const int pwd_len) +{ + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_sta_connect_msg_t *msg = (rnm_sta_connect_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(msg, 0, sizeof(rnm_sta_connect_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_sta_connect_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + msg->hdr.cmd = BFLB_CMD_STA_CONNECT; + msg->hdr.msg_id = 0x0001; + msg->hdr.session_id = 0x0002; + msg->ssid_len = ssid_len; + memcpy(msg->ssid, ssid, ssid_len); + if (password) { + memcpy(msg->password, password, pwd_len); + } + + msg_len = sizeof(usb_data_t) + sizeof(rnm_sta_connect_msg_t); + + return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500); +} + +int usbh_bl616_wifi_sta_disconnect(void) +{ + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(msg, 0, sizeof(rnm_base_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_base_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + msg->cmd = BFLB_CMD_STA_DISCONNECT; + + msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t); + + return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500); +} + +int usbh_bl616_get_wifi_scan_result(void) +{ + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(msg, 0, sizeof(rnm_base_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_base_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + msg->cmd = BFLB_CMD_SCAN_RESULTS; + + msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t); + + return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500); +} + +int usbh_bl616_wifi_scan(void) +{ + int ret; + uint32_t msg_len; + usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t)); + + memset(usb_hdr, 0, sizeof(usb_data_t)); + memset(msg, 0, sizeof(rnm_base_msg_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_CMD; + usb_hdr->length = sizeof(rnm_base_msg_t); + usb_hdr->payload_offset = sizeof(usb_data_t); + + msg->cmd = BFLB_CMD_SCAN; + + msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t); + + ret = usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500); + if (ret < 0) { + return ret; + } + + usb_osal_msleep(500); + return usbh_bl616_get_wifi_scan_result(); +} + +static int usbh_bl616_connect(struct usbh_hubport *hport, uint8_t intf) +{ + struct usb_endpoint_descriptor *ep_desc; + int ret = 0; + + struct usbh_bl616 *bl616_class = &g_bl616_class; + + memset(bl616_class, 0, sizeof(struct usbh_bl616)); + + bl616_class->hport = hport; + bl616_class->intf = intf; + + hport->config.intf[intf].priv = bl616_class; + + for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) { + ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc; + + if (ep_desc->bEndpointAddress & 0x80) { + USBH_EP_INIT(bl616_class->bulkin, ep_desc); + } else { + USBH_EP_INIT(bl616_class->bulkout, ep_desc); + } + } + + usbh_bl616_get_wifi_mac(bl616_class); + usbh_bl616_wifi_close(bl616_class); + usbh_bl616_wifi_open(bl616_class); + + USB_LOG_INFO("BL616 WIFI STA MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n", + bl616_class->sta_mac[0], + bl616_class->sta_mac[1], + bl616_class->sta_mac[2], + bl616_class->sta_mac[3], + bl616_class->sta_mac[4], + bl616_class->sta_mac[5]); + + USB_LOG_INFO("BL616 WIFI AP MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n", + bl616_class->ap_mac[0], + bl616_class->ap_mac[1], + bl616_class->ap_mac[2], + bl616_class->ap_mac[3], + bl616_class->ap_mac[4], + bl616_class->ap_mac[5]); + + strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN); + + USB_LOG_INFO("Register BL616 WIFI Class:%s\r\n", hport->config.intf[intf].devname); + + usbh_bl616_run(bl616_class); + return ret; +} + +static int usbh_bl616_disconnect(struct usbh_hubport *hport, uint8_t intf) +{ + int ret = 0; + + struct usbh_bl616 *bl616_class = (struct usbh_bl616 *)hport->config.intf[intf].priv; + + if (bl616_class) { + if (bl616_class->bulkin) { + usbh_kill_urb(&bl616_class->bulkin_urb); + } + + if (bl616_class->bulkout) { + usbh_kill_urb(&bl616_class->bulkout_urb); + } + + if (hport->config.intf[intf].devname[0] != '\0') { + USB_LOG_INFO("Unregister BL616 WIFI Class:%s\r\n", hport->config.intf[intf].devname); + usbh_bl616_stop(bl616_class); + } + + memset(bl616_class, 0, sizeof(struct usbh_bl616)); + } + + return ret; +} + +void usbh_bl616_rx_thread(void *argument) +{ + int ret; + usb_data_t *usb_hdr; + rnm_base_msg_t *msg; + rnm_sta_ip_update_ind_msg_t *ipmsg; + rnm_scan_ind_msg_t *scanmsg; + uint8_t *data; + + USB_LOG_INFO("Create bl616 wifi rx thread\r\n"); + + while (1) { + ret = usbh_bl616_bulk_in_transfer(&g_bl616_class, g_bl616_rx_buffer, sizeof(g_bl616_rx_buffer), USB_OSAL_WAITING_FOREVER); + if (ret < 0) { + break; + } + + usb_hdr = (usb_data_t *)g_bl616_rx_buffer; + + if (usb_hdr->type == USBWIFI_DATA_TYPE_CMD) { + msg = (rnm_base_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset); + + switch (msg->cmd) { + case BFLB_CMD_STA_CONNECTED_IND: + USB_LOG_INFO("AP connected\n"); + g_bl616_class.connect_status = true; + usbh_bl616_sta_connect_callback(); + + break; + case BFLB_CMD_STA_DISCONNECTED_IND: + if (g_bl616_class.connect_status == true) { + g_bl616_class.connect_status = false; + USB_LOG_INFO("AP disconnected\n"); + usbh_bl616_sta_disconnect_callback(); + } + break; + case BFLB_CMD_STA_IP_UPDATE_IND: + ipmsg = (rnm_sta_ip_update_ind_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset); + + USB_LOG_INFO("WIFI IP update\r\n"); + USB_LOG_INFO("WIFI IPv4 Address : %d:%d:%d:%d\r\n", + ipmsg->ip4_addr[0], + ipmsg->ip4_addr[1], + ipmsg->ip4_addr[2], + ipmsg->ip4_addr[3]); + USB_LOG_INFO("WIFI IPv4 Mask : %d:%d:%d:%d\r\n", + ipmsg->ip4_mask[0], + ipmsg->ip4_mask[1], + ipmsg->ip4_mask[2], + ipmsg->ip4_mask[3]); + USB_LOG_INFO("WIFI IPv4 Gateway : %d:%d:%d:%d\r\n\r\n", + ipmsg->ip4_gw[0], + ipmsg->ip4_gw[1], + ipmsg->ip4_gw[2], + ipmsg->ip4_gw[3]); + + g_bl616_class.mode = BL_MODE_STA; + usbh_bl616_sta_update_ip(ipmsg->ip4_addr, ipmsg->ip4_mask, ipmsg->ip4_gw); + break; + case BFLB_CMD_SCAN_RESULTS: + scanmsg = (rnm_scan_ind_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset); + USB_LOG_INFO("WIFI scan result:\r\n"); + for (uint32_t i = 0; i < scanmsg->num; ++i) { + struct bf1b_wifi_scan_record *r = &scanmsg->records[i]; + USB_LOG_INFO("BSSID " MAC_FMT ", channel %u, rssi %d, auth %s, cipher %s, SSID %s\r\n", + ARR_ELE_6(r->bssid), r->channel, r->rssi, + auth_to_str(r->auth_mode), cipher_to_str(r->cipher), r->ssid); + } + break; + default: + break; + } + } else if (usb_hdr->type == USBWIFI_DATA_TYPE_PKT) { + data = (uint8_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset); + usbh_bl616_eth_input(data, usb_hdr->length); + } else { + } + } + + USB_LOG_INFO("Delete bl616 wifi rx thread\r\n"); + usb_osal_thread_delete(NULL); +} + +uint8_t *usbh_bl616_get_eth_txbuf(void) +{ + return (g_bl616_tx_buffer + sizeof(usb_data_t)); +} + +int usbh_bl616_eth_output(uint32_t buflen) +{ + usb_data_t *usb_hdr; + uint32_t txlen; + + if (g_bl616_class.connect_status == false) { + return -USB_ERR_NOTCONN; + } + + usb_hdr = (usb_data_t *)g_bl616_tx_buffer; + memset(usb_hdr, 0, sizeof(usb_data_t)); + + usb_hdr->type = USBWIFI_DATA_TYPE_PKT; + usb_hdr->length = buflen; + usb_hdr->payload_offset = sizeof(usb_data_t); + + txlen = buflen + sizeof(usb_data_t); + if (!(txlen % USB_GET_MAXPACKETSIZE(g_bl616_class.bulkout->wMaxPacketSize))) { + txlen += 1; + } + USB_LOG_DBG("txlen:%d\r\n", txlen); + + usbh_bulk_urb_fill(&g_bl616_class.bulkout_urb, g_bl616_class.hport, g_bl616_class.bulkout, g_bl616_tx_buffer, txlen, USB_OSAL_WAITING_FOREVER, NULL, NULL); + return usbh_submit_urb(&g_bl616_class.bulkout_urb); +} + +int wifi_sta_connect(int argc, char **argv) +{ + if (argc < 3) { + USB_LOG_ERR("Usage: %s \r\n", argv[0]); + return -1; + } + usbh_bl616_wifi_sta_connect(argv[1], strlen(argv[1]), argv[2], strlen(argv[2])); + return 0; +} + +int wifi_scan(int argc, char **argv) +{ + usbh_bl616_wifi_scan(); + return 0; +} +__WEAK void usbh_bl616_run(struct usbh_bl616 *bl616_class) +{ +} + +__WEAK void usbh_bl616_stop(struct usbh_bl616 *bl616_class) +{ +} + +static const uint16_t bl616_id_table[][2] = { + { 0x349b, 0x616f }, + { 0, 0 }, +}; + +static const struct usbh_class_driver bl616_class_driver = { + .driver_name = "bl616_wifi", + .connect = usbh_bl616_connect, + .disconnect = usbh_bl616_disconnect +}; + +CLASS_INFO_DEFINE const struct usbh_class_info bl616_class_info = { + .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS, + .class = 0xff, + .subclass = 0x00, + .protocol = 0x00, + .id_table = bl616_id_table, + .class_driver = &bl616_class_driver +}; diff --git a/class/vendor/wifi/usbh_bl616.h b/class/vendor/wifi/usbh_bl616.h new file mode 100644 index 00000000..6ec5a7a8 --- /dev/null +++ b/class/vendor/wifi/usbh_bl616.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USBH_BL616_H +#define USBH_BL616_H + +#define USBWIFI_DATA_TYPE_CMD 0xA55A +#define USBWIFI_DATA_TYPE_PKT 0x6996 + +#define USB_DATA_FLAG_AP_PKT (1u << 0) + +typedef enum { + BFLB_CMD_REBOOT = 0, + BFLB_CMD_RESET, + BFLB_CMD_HELLO, + BFLB_CMD_PING, + + BFLB_CMD_GET_MAC_ADDR, + + // Scan + BFLB_CMD_SCAN, + BFLB_CMD_SCAN_RESULTS, + + // STA + BFLB_CMD_STA_CONNECT, + BFLB_CMD_STA_DISCONNECT, + BFLB_CMD_STA_CONNECTED_IND, + BFLB_CMD_STA_DISCONNECTED_IND, + BFLB_CMD_STA_IP_UPDATE_IND, + BFLB_CMD_STA_SET_AUTO_RECONNECT, + BFLB_CMD_STA_GET_LINK_STATUS, + + // AP + BFLB_CMD_AP_START, + BFLB_CMD_AP_STOP, + BFLB_CMD_AP_STARTED_IND, + BFLB_CMD_AP_STOPPED_IND, + BFLB_CMD_AP_GET_STA_LIST, + + // Monitor + BFLB_CMD_MONITOR_START, + BFLB_CMD_MONITOR_STOP, + BFLB_CMD_MONITOR_SET_CHANNEL, + BFLB_CMD_MONITOR_GET_CHANNEL, + + BFLB_CMD_SET_LPM_MODE, + + // OTA + BFLB_CMD_GET_DEV_VERSION, + BFLB_CMD_OTA, + + BFLB_CMD_EXT, + + BFLB_CMD_USER_EXT, + BFLB_CMD_UNLOAD_DRV, + + BFLB_CMD_MAX, +} bflb_cmd_t; + +typedef enum { + STATUS_OK, + STATUS_NOMEM = 128, + STATUS_INVALID_INPUT, + STATUS_INVALID_MODE, + STATUS_ERR_UNSPECIFIED, + STATUS_NOT_IMPLEMENTED, +} cmd_status_t; + +typedef enum { + RNM_WIFI_AUTH_UNKNOWN = 0, + RNM_WIFI_AUTH_OPEN, + RNM_WIFI_AUTH_WEP, + RNM_WIFI_AUTH_WPA_PSK, + RNM_WIFI_AUTH_WPA2_PSK, + RNM_WIFI_AUTH_WPA_WPA2_PSK, + RNM_WIFI_AUTH_WPA_ENTERPRISE, + RNM_WIFI_AUTH_WPA3_SAE, + RNM_WIFI_AUTH_WPA2_PSK_WPA3_SAE, + RNM_WIFI_AUTH_MAX, +} rnm_wifi_auth_mode_t; + +typedef enum { + RNM_WIFI_CIPHER_UNKNOWN = 0, + RNM_WIFI_CIPHER_NONE, + RNM_WIFI_CIPHER_WEP, + RNM_WIFI_CIPHER_AES, + RNM_WIFI_CIPHER_TKIP, + RNM_WIFI_CIPHER_TKIP_AES, + RNM_WIFI_CIPHER_MAX, +} rnm_wifi_cipher_t; + +/* common header */ +typedef struct { + uint16_t cmd; + // flag ACK is used by server to indicate a response to client +#define RNM_MSG_FLAG_ACK (1 << 0) + // flag TRANSPARENT is never transfered to peer but used locally +#define RNM_MSG_FLAG_TRANSPARENT (1 << 1) + // flag ASYNC is used by server to notify client events such as STA_CONNECTED +#define RNM_MSG_FLAG_ASYNC (1 << 2) + uint16_t flags; + uint16_t status; + uint16_t msg_id; + uint16_t session_id; + uint16_t msg_id_replying; +} rnm_base_msg_t; + +typedef struct { + rnm_base_msg_t hdr; +} rnm_ack_msg_t; + +typedef struct { + rnm_base_msg_t hdr; + uint8_t sta_mac[6]; + uint8_t ap_mac[6]; +} rnm_mac_addr_ind_msg_t; + +typedef struct { + rnm_base_msg_t hdr; + uint16_t ssid_len; + uint8_t ssid[32]; + uint8_t password[64]; +} rnm_sta_connect_msg_t; + +typedef struct { + rnm_base_msg_t hdr; + uint8_t ip4_addr[4]; + uint8_t ip4_mask[4]; + uint8_t ip4_gw[4]; + uint8_t ip4_dns1[4]; + uint8_t ip4_dns2[4]; + uint8_t gw_mac[6]; +} rnm_sta_ip_update_ind_msg_t; + +struct bf1b_wifi_scan_record { + uint8_t bssid[6]; + // TODO use compressed SSID encoding to save room + uint8_t ssid[32 + 1]; + uint16_t channel; + int8_t rssi; + uint8_t auth_mode; + uint8_t cipher; +} __PACKED; + +typedef struct { + rnm_base_msg_t hdr; + uint16_t num; + struct bf1b_wifi_scan_record records[]; +} rnm_scan_ind_msg_t; + +typedef enum { + BL_MODE_NONE, + BL_MODE_STA, // card is STA + BL_MODE_AP, // card is AP + BL_MODE_STA_AP, // card is STA&AP + BL_MODE_SNIFFER, // card is sniffer + BL_MODE_MAX, +} bl_wifi_mode_t; + +typedef struct { + uint16_t type; + uint16_t length; + uint16_t flags; + uint16_t payload_offset; + uint32_t rsvd[8]; + uint8_t payload[]; +} __attribute__((aligned(4))) usb_data_t; + +struct usbh_bl616 { + struct usbh_hubport *hport; + struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */ + struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */ + + struct usbh_urb bulkout_urb; + struct usbh_urb bulkin_urb; + + uint8_t intf; + + uint8_t sta_mac[6]; + uint8_t ap_mac[6]; + uint8_t mode; + bool connect_status; + + void *user_data; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int usbh_bl616_wifi_sta_connect(const char *ssid, + const int ssid_len, + const char *password, + const int pwd_len); + +int usbh_bl616_wifi_sta_disconnect(void); +int usbh_bl616_wifi_scan(void); + +void usbh_bl616_sta_connect_callback(void); +void usbh_bl616_sta_disconnect_callback(void); +void usbh_bl616_sta_update_ip(uint8_t ip4_addr[4], uint8_t ip4_mask[4], uint8_t ip4_gw[4]); + +uint8_t *usbh_bl616_get_eth_txbuf(void); +int usbh_bl616_eth_output(uint32_t buflen); +void usbh_bl616_eth_input(uint8_t *buf, uint32_t buflen); +void usbh_bl616_rx_thread(void *argument); + +void usbh_bl616_run(struct usbh_bl616 *bl616_class); +void usbh_bl616_stop(struct usbh_bl616 *bl616_class); + +int wifi_sta_connect(int argc, char **argv); +int wifi_scan(int argc, char **argv); + +#ifdef __cplusplus +} +#endif + +#endif /* USBH_BL616_H */