feat(xteink): add ESP32-C3 Wi-Fi emulation with qemu AP
Ports the ESP32 Wi-Fi emulation (esp32c3_wifi, esp32_wifi_ap, esp32_wlan_*) from the lcgamboa/PICSimLab QEMU fork and integrates it behind the esp32c3_wifi NIC model, plus the supporting radio peripherals (ANA/PHYA/FE/PWR manager). - Exposes an open SSID 'qemu' bridged to the host via QEMU user-mode NAT (libslirp, now enabled in the native build). - Adds ESP-IDF 5.5 compatibility fixes: channel resolution from the beacon DS Parameter Set IE / AP lookup, persistent SYSCON register backing (phy_module_has_clock_bits), DMA inlink/outlink descriptor mirroring, RX descriptor ring reset on item.next==0, and descriptor ownership/length semantics. - xteink-emu now starts with -nic user,model=esp32c3_wifi and synthesizes an eFuse image with a fixed guest MAC. Verified against a stock Arduino-ESP32 sketch: scans, finds 'qemu', associates, gets DHCP 192.168.4.15, and completes an outbound TCP connection. Unmodified CrossPoint firmware still needs the power-button hold during boot (tracked separately).
This commit is contained in:
+1
-1
@@ -42,7 +42,7 @@ nix run .#xteink-emu -- screenshot --output screen.png
|
||||
nix run .#xteink-emu -- stop
|
||||
```
|
||||
|
||||
State defaults to `/tmp/xteink-emu-$UID`; pass `--state-dir` to any subcommand for parallel instances. `wait` advances a persistent log cursor after each match.
|
||||
State defaults to `/tmp/xteink-emu-$UID`; pass `--state-dir` to any subcommand for parallel instances. `wait` advances a persistent log cursor after each match. The emulator exposes the open Wi-Fi network `qemu`; guest traffic uses QEMU's user-mode NAT.
|
||||
|
||||
### WebAssembly
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
glib
|
||||
libgcrypt
|
||||
libpng
|
||||
libslirp
|
||||
pixman
|
||||
zlib
|
||||
];
|
||||
@@ -51,10 +52,12 @@
|
||||
cp -r ${keycodemapdb} subprojects/keycodemapdb
|
||||
chmod -R u+w subprojects/keycodemapdb
|
||||
sed -i "/subdir('fp')/d" tests/meson.build
|
||||
substituteInPlace meson.build --replace-fail "static: true" "static: false"
|
||||
'';
|
||||
|
||||
configurePhase = ''
|
||||
runHook preConfigure
|
||||
export PKG_CONFIG_PATH=${pkgs.libslirp}/lib/pkgconfig''${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
|
||||
./configure \
|
||||
--prefix=$out \
|
||||
--target-list=riscv32-softmmu \
|
||||
@@ -65,6 +68,7 @@
|
||||
--enable-gcrypt \
|
||||
--enable-pixman \
|
||||
--enable-png \
|
||||
--enable-slirp \
|
||||
--disable-werror \
|
||||
--disable-docs \
|
||||
--disable-tools
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/esp32_fe.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static uint64_t esp32_fe_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
Esp32FeState *s = ESP32_FE(opaque);
|
||||
r=s->mem[addr/4];
|
||||
switch(addr){
|
||||
case 0x174:
|
||||
case 0x7C:
|
||||
r=0xffffffff;
|
||||
break;
|
||||
}
|
||||
if(DEBUG) printf("esp32_fe_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void esp32_fe_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned int size) {
|
||||
Esp32FeState *s = ESP32_FE(opaque);
|
||||
if(DEBUG) printf("esp32_fe_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
|
||||
|
||||
s->mem[addr/4]=(uint32_t)value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps esp32_fe_ops = {
|
||||
.read = esp32_fe_read,
|
||||
.write = esp32_fe_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void esp32_fe_init(Object *obj)
|
||||
{
|
||||
Esp32FeState *s = ESP32_FE(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &esp32_fe_ops, s,
|
||||
TYPE_ESP32_FE, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
memset(s->mem,0,sizeof(s->mem));
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo esp32_fe_info = {
|
||||
.name = TYPE_ESP32_FE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Esp32FeState),
|
||||
.instance_init = esp32_fe_init,
|
||||
};
|
||||
|
||||
static void esp32_fe_register_types(void)
|
||||
{
|
||||
type_register_static(&esp32_fe_info);
|
||||
}
|
||||
|
||||
type_init(esp32_fe_register_types)
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/esp32_phya.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static uint32_t *g_mem;
|
||||
|
||||
static uint64_t esp32_phya_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
Esp32PhyaState *s = ESP32_PHYA(opaque);
|
||||
r=s->mem[addr/4];
|
||||
if(DEBUG) printf("esp32_phya_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void Esp32_WLAN_Set_Packet_Status(const uint32_t state){
|
||||
if(g_mem){
|
||||
g_mem[0x270/4] = state; //ESP32
|
||||
g_mem[0x320/4] = state; //ESP32C3
|
||||
}
|
||||
}
|
||||
|
||||
static void esp32_phya_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned int size) {
|
||||
Esp32PhyaState *s = ESP32_PHYA(opaque);
|
||||
|
||||
if(DEBUG) printf("esp32_phya_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
|
||||
|
||||
s->mem[addr/4]=(uint32_t)value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps esp32_phya_ops = {
|
||||
.read = esp32_phya_read,
|
||||
.write = esp32_phya_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void esp32_phya_init(Object *obj)
|
||||
{
|
||||
Esp32PhyaState *s = ESP32_PHYA(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &esp32_phya_ops, s,
|
||||
TYPE_ESP32_PHYA, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
memset(s->mem,0,sizeof(s->mem));
|
||||
g_mem = s->mem;
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo esp32_phya_info = {
|
||||
.name = TYPE_ESP32_PHYA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Esp32PhyaState),
|
||||
.instance_init = esp32_phya_init,
|
||||
};
|
||||
|
||||
static void esp32_phya_register_types(void)
|
||||
{
|
||||
type_register_static(&esp32_phya_info);
|
||||
}
|
||||
|
||||
type_init(esp32_phya_register_types)
|
||||
@@ -0,0 +1,787 @@
|
||||
/**
|
||||
* QEMU WLAN access point emulation
|
||||
*
|
||||
* Copyright (c) 2008 Clemens Kolbitsch
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modifications:
|
||||
* 2008-February-24 Clemens Kolbitsch :
|
||||
* New implementation based on ne2000.c
|
||||
* 18/01/22 Martin Johnson : Modified for esp32 wifi emulation
|
||||
* 08/12/23 lcgamboa@yahoo.com : Modified for esp32c3, espnow and SoftAp wifi emulation
|
||||
*/
|
||||
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "net/net.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
#include "hw/irq.h"
|
||||
#include "hw/misc/esp32_wifi.h"
|
||||
#include "hw/misc/esp32_phya.h"
|
||||
#include "esp32_wlan.h"
|
||||
#include "esp32_wlan_packet.h"
|
||||
|
||||
// 50ms between beacons
|
||||
#define BEACON_TIME 500000000
|
||||
#define INTER_FRAME_TIME 5000000
|
||||
#define WAIT_ACK_TIMEOUT 10000000
|
||||
#define DEBUG 0
|
||||
#define ENABLE_BEACON 1
|
||||
#define DEBUG_DUMPFRAMES 0
|
||||
#define DEBUG_WIRESHARK_IMPORT 0
|
||||
|
||||
// color defines
|
||||
#define BLACK 0
|
||||
#define RED 1
|
||||
#define GREEN 2
|
||||
#define YELLOW 3
|
||||
#define BLUE 4
|
||||
#define MAGNETA 5
|
||||
#define CYAN 6
|
||||
#define WHITE 7
|
||||
#define ANSI_DEFAULT() printf("\033[0m")
|
||||
#define ANSI_COLOR(f, b) printf("\033[%d;%dm", (f) + 30, (b) + 40)
|
||||
#define ANSI_FG_LCOLOR(f) printf("\033[0;%dm", (f) + 30)
|
||||
#define ANSI_FG_HCOLOR(f) printf("\033[1;%dm", (f) + 30)
|
||||
|
||||
access_point_info access_points[] = {
|
||||
{"qemu", 1, -25, {0x10, 0x01, 0x00, 0xc4, 0x0a, 0x51}},
|
||||
};
|
||||
|
||||
int nb_aps=sizeof(access_points)/sizeof(access_point_info);
|
||||
|
||||
static void Esp32_WLAN_beacon_timer(void *opaque)
|
||||
{
|
||||
struct mac80211_frame *frame;
|
||||
Esp32WifiState *s = (Esp32WifiState *)opaque;
|
||||
// only send a beacon if we are an access point
|
||||
if((ENABLE_BEACON)&&(s->mode == Esp32_Mode_Station)){
|
||||
if(s->ap_state!=Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
for(int i=0;i<nb_aps;i++){
|
||||
int ap = (i + s->beacon_ap)%nb_aps;
|
||||
if (access_points[ap].channel==esp32_wifi_channel) {
|
||||
memcpy(s->ap_macaddr,access_points[ap].mac_address,6);
|
||||
frame = Esp32_WLAN_create_beacon_frame(&access_points[ap]);
|
||||
Esp32_WLAN_init_ap_frame(s, frame);
|
||||
Esp32_WLAN_insert_frame(s, frame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->beacon_ap=(s->beacon_ap+1)%nb_aps;
|
||||
}
|
||||
}
|
||||
timer_mod(s->beacon_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + BEACON_TIME);
|
||||
}
|
||||
|
||||
static void Esp32_WLAN_inject_timer(void *opaque)
|
||||
{
|
||||
Esp32WifiState *s = (Esp32WifiState *)opaque;
|
||||
struct mac80211_frame *frame;
|
||||
|
||||
frame = s->inject_queue;
|
||||
if (frame) {
|
||||
// remove from queue
|
||||
s->inject_queue_size--;
|
||||
s->inject_queue = frame->next_frame;
|
||||
Esp32_sendFrame(s, (void *)frame, frame->frame_length,frame->signal_strength);
|
||||
free(frame);
|
||||
}
|
||||
if (s->inject_queue_size > 0) {
|
||||
// there are more packets... schedule
|
||||
// the timer for sending them as well
|
||||
timer_mod(s->inject_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + INTER_FRAME_TIME);
|
||||
} else {
|
||||
// we wait until a new packet schedules
|
||||
// us again
|
||||
s->inject_timer_running = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void Esp32_WLAN_Wait_ACk_timer(void *opaque)
|
||||
{
|
||||
Esp32WifiState *s = (Esp32WifiState *)opaque;
|
||||
|
||||
Esp32_WLAN_frame_delivered(s);
|
||||
}
|
||||
|
||||
static void macprint(const uint8_t *p, const char * name) {
|
||||
printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",name, p[0],p[1],p[2],p[3],p[4],p[5]);
|
||||
}
|
||||
|
||||
static void buffer_print(uint8_t * b, unsigned size){
|
||||
for(int i=0;i < size ;i++) {
|
||||
if((i%16)==0) printf("%04x: ",i);
|
||||
printf("%02x ",b[i]);
|
||||
if((i%16)==15) printf("\n");
|
||||
}
|
||||
if((size%16)!=0)printf("\n");
|
||||
}
|
||||
|
||||
static void infoprint(struct mac80211_frame *frame) {
|
||||
if(DEBUG_DUMPFRAMES) {
|
||||
#if (DEBUG_WIRESHARK_IMPORT == 0 )
|
||||
printf("\nFrame Info type:%d subtype:%d flags:%d duration:%d length:%d\n",frame->frame_control.type,
|
||||
frame->frame_control.sub_type,frame->frame_control.flags,frame->duration_id, frame->frame_length);
|
||||
|
||||
printf("protocol_version: %i\n",frame->frame_control.protocol_version);
|
||||
printf("type: %i ",frame->frame_control.type );
|
||||
switch (frame->frame_control.type)
|
||||
{
|
||||
case IEEE80211_TYPE_MGT:
|
||||
printf("MGT\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_CTL:
|
||||
printf("CTL\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_DATA:
|
||||
printf("DATA\n");
|
||||
break;
|
||||
}
|
||||
printf("subtype: %i ",frame->frame_control.sub_type);
|
||||
switch (frame->frame_control.type)
|
||||
{
|
||||
case IEEE80211_TYPE_MGT:
|
||||
switch (frame->frame_control.sub_type)
|
||||
{
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_BEACON:
|
||||
printf("BEACON\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_ACTION:
|
||||
printf("ACTION\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ:
|
||||
printf("PROBE_REQ\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP:
|
||||
printf("PROBE_RESP\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION:
|
||||
printf("AUTHENTICATION\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION:
|
||||
printf("DEAUTHENTICATION\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ:
|
||||
printf("ASSOCIATION_REQ\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP:
|
||||
printf("ASSOCIATION_RESP\n");
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION:
|
||||
printf("DISASSOCIATION\n");
|
||||
break;
|
||||
default:
|
||||
printf("---\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_CTL:
|
||||
switch (frame->frame_control.sub_type)
|
||||
{
|
||||
case IEEE80211_TYPE_CTL_SUBTYPE_ACK:
|
||||
printf("ACK\n");
|
||||
break;
|
||||
default:
|
||||
printf("---\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_DATA:
|
||||
switch (frame->frame_control.sub_type)
|
||||
{
|
||||
case IEEE80211_TYPE_DATA_SUBTYPE_DATA:
|
||||
printf("DATA\n");
|
||||
break;
|
||||
default:
|
||||
printf("---\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
printf("flags: %i\n",frame->frame_control.flags);
|
||||
printf("duration_id: %i\n",frame->duration_id);
|
||||
macprint(frame->destination_address,"destination");
|
||||
macprint(frame->source_address,"source");
|
||||
macprint(frame->bssid_address,"bssid");
|
||||
printf("fragment_number: %u\n",frame->sequence_control.fragment_number);
|
||||
printf("sequence_number : %u\n",frame->sequence_control.sequence_number);
|
||||
|
||||
switch (frame->frame_control.type)
|
||||
{
|
||||
case IEEE80211_TYPE_MGT:
|
||||
switch (frame->frame_control.sub_type)
|
||||
{
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_BEACON:
|
||||
printf("beacon timestamp : %lu\n",(unsigned long) frame->beacon_info.timestamp);
|
||||
printf("beacon interval : %u\n",frame->beacon_info.interval);
|
||||
printf("beacon capability : %u\n",frame->beacon_info.capability);
|
||||
break;
|
||||
default:
|
||||
if(frame->frame_length > IEEE80211_HEADER_SIZE)
|
||||
buffer_print((uint8_t *)frame->data_and_fcs, frame->frame_length - IEEE80211_HEADER_SIZE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_CTL:
|
||||
switch (frame->frame_control.sub_type)
|
||||
{
|
||||
default:
|
||||
if(frame->frame_length > IEEE80211_HEADER_SIZE)
|
||||
buffer_print((uint8_t *)frame->data_and_fcs, frame->frame_length - IEEE80211_HEADER_SIZE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_DATA:
|
||||
switch (frame->frame_control.sub_type)
|
||||
{
|
||||
default:
|
||||
printf("EtherType 0x%02X%02X\n",frame->data_and_fcs[6],frame->data_and_fcs[7]);
|
||||
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==0x06) {
|
||||
printf("ARP\n");
|
||||
arp_header_t *header=(arp_header_t *)&frame->data_and_fcs[8];
|
||||
printf("Operation %i\n", header->operation>>8);
|
||||
}
|
||||
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==0x00) {
|
||||
printf("IPV4\n");
|
||||
ip_header_t *header=(ip_header_t *)&frame->data_and_fcs[8];
|
||||
printf("Protocol: 0x%04X\n",header->protocol);
|
||||
switch (header->protocol)
|
||||
{
|
||||
case 0x11:
|
||||
printf("UDP\n");
|
||||
break;
|
||||
case 0x06:
|
||||
printf("TCP\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==0xdd) {
|
||||
printf("IPV6\n");
|
||||
}
|
||||
if(frame->frame_length > IEEE80211_HEADER_SIZE)
|
||||
buffer_print((uint8_t *)frame->data_and_fcs, frame->frame_length - IEEE80211_HEADER_SIZE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("frame_length : %u\n", frame->frame_length);
|
||||
#else
|
||||
uint8_t *b=(uint8_t *)frame;
|
||||
for(int i=0;i<frame->frame_length;i++) {
|
||||
if((i%16)==0) printf("\n%04x: ",i);
|
||||
printf("%02x ",b[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Esp32_WLAN_insert_frame(Esp32WifiState *s, struct mac80211_frame *frame)
|
||||
{
|
||||
struct mac80211_frame *i_frame;
|
||||
|
||||
insertCRC(frame);
|
||||
if(DEBUG) {
|
||||
ANSI_FG_HCOLOR(GREEN);
|
||||
printf("---------------\n>IN Send Frame type:%d subtype:%d channel:%d ap_state:%d time:%ld \n",frame->frame_control.type,frame->frame_control.sub_type,esp32_wifi_channel,s->ap_state,(unsigned long) qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
|
||||
ANSI_DEFAULT();
|
||||
}
|
||||
infoprint(frame);
|
||||
s->inject_queue_size++;
|
||||
i_frame = s->inject_queue;
|
||||
if (!i_frame) {
|
||||
s->inject_queue = frame;
|
||||
} else {
|
||||
while (i_frame->next_frame) {
|
||||
i_frame = i_frame->next_frame;
|
||||
}
|
||||
i_frame->next_frame = frame;
|
||||
}
|
||||
|
||||
if (!s->inject_timer_running) {
|
||||
// if the injection timer is not
|
||||
// running currently, let's schedule
|
||||
// one run...
|
||||
s->inject_timer_running = 1;
|
||||
timer_mod(s->inject_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + INTER_FRAME_TIME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static _Bool Esp32_WLAN_can_receive(NetClientState *ncs)
|
||||
{
|
||||
Esp32WifiState *s = qemu_get_nic_opaque(ncs);
|
||||
/*
|
||||
if (s->ap_state != Esp32_WLAN__STATE_ASSOCIATED && s->ap_state != Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
// we are currently not connected
|
||||
// to the access point
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
if (s->inject_queue_size > Esp32_WLAN__MAX_INJECT_QUEUE_SIZE) {
|
||||
// overload, please give me some time...
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t Esp32_WLAN_receive(NetClientState *ncs,
|
||||
const uint8_t *buf, size_t size)
|
||||
{
|
||||
Esp32WifiState *s = qemu_get_nic_opaque(ncs);
|
||||
struct mac80211_frame *frame;
|
||||
if (!Esp32_WLAN_can_receive(ncs)) {
|
||||
// this should not happen, but in
|
||||
// case it does, let's simply drop
|
||||
// the packet
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!s) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* A 802.3 packet comes from the qemu network. The
|
||||
* access points turns it into a 802.11 frame and
|
||||
* forwards it to the wireless device
|
||||
*/
|
||||
frame = Esp32_WLAN_create_data_packet(s, buf, size);
|
||||
if (frame) {
|
||||
if(s->mode == Esp32_Mode_Station){
|
||||
memcpy(s->ap_macaddr,s->associated_ap_macaddr,6);
|
||||
|
||||
if(s->ap_state==Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
frame->frame_control.flags=1;
|
||||
// if it's an arp request put the correct reply mac address in the packet
|
||||
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==6) {
|
||||
memcpy(frame->data_and_fcs+16,s->macaddr,6);
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
memcpy(frame->destination_address, s->softap_macaddr,6);
|
||||
if(s->ap_state==Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
frame->frame_control.flags=1;
|
||||
// if it's an arp request put the correct reply mac address in the packet
|
||||
if( frame->data_and_fcs[6]==8 && frame->data_and_fcs[7]==6) {
|
||||
memcpy(frame->data_and_fcs+16,s->ap_macaddr,6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(((buf[12] & 0xE0) == IEEE80211_ENCAPSULATED)&&(buf[13] == ((IEEE80211_TYPE_MGT << 4)|IEEE80211_TYPE_MGT_SUBTYPE_ACTION)))
|
||||
{
|
||||
unsigned long ethernet_frame_size;
|
||||
unsigned char ethernet_frame[1518];
|
||||
struct mac80211_frame *reply = NULL;
|
||||
|
||||
//discard packages from others channels
|
||||
if((buf[12] & 0x0F) != esp32_wifi_channel) return -1;
|
||||
//discard packages originated from the same mac address
|
||||
if(!memcmp(&buf[6],s->macaddr,6)) return -1;
|
||||
//check destination
|
||||
if((memcmp(&buf[0],BROADCAST,6))&&(memcmp(&buf[0],s->macaddr,6))) return -1;
|
||||
|
||||
//action frame
|
||||
Esp32_WLAN_init_ap_frame(s, frame);
|
||||
memcpy(frame->data_and_fcs, buf+14, size-14);
|
||||
memcpy(frame->destination_address, &buf[0], 6);
|
||||
memcpy(frame->source_address, &buf[6], 6);
|
||||
memset(frame->bssid_address, 0xff, 6);
|
||||
frame->frame_control.type= IEEE80211_TYPE_MGT;
|
||||
frame->frame_control.sub_type= IEEE80211_TYPE_MGT_SUBTYPE_ACTION;
|
||||
frame->frame_control.flags= ((buf[12] & 0xF0) == IEEE80211_ENCAPSULATED_PROTECTED) ? 0x40 : 00;
|
||||
frame->duration_id= 0 ;
|
||||
frame->frame_length-=12;
|
||||
Esp32_WLAN_insert_frame(s, frame);
|
||||
|
||||
|
||||
//if destination is broadcast, don´t send ack
|
||||
if(!memcmp(&buf[0],BROADCAST,6)) return size;
|
||||
|
||||
//Send Ack
|
||||
reply = Esp32_WLAN_create_ack();
|
||||
memcpy(reply->destination_address, &buf[6], 6);
|
||||
memcpy(reply->source_address, s->macaddr, 6);
|
||||
memset(reply->bssid_address, 0xff, 6);
|
||||
reply->duration_id=0;
|
||||
|
||||
if(DEBUG) {
|
||||
ANSI_FG_HCOLOR(RED);
|
||||
macprint(reply->destination_address,"---------------\n<OUT ACK send: dest ");
|
||||
ANSI_DEFAULT();
|
||||
}
|
||||
infoprint(reply);
|
||||
/*
|
||||
* The access point uses the 802.11 frame
|
||||
* and sends a 802.3 frame into the network...
|
||||
* This packet is then understandable by
|
||||
* qemu-slirp
|
||||
*
|
||||
* If we ever want the access point to offer
|
||||
* some services, it can be added here!!
|
||||
*/
|
||||
// ethernet header type
|
||||
ethernet_frame[12] = IEEE80211_ENCAPSULATED | esp32_wifi_channel;
|
||||
ethernet_frame[13] = ((IEEE80211_TYPE_CTL << 4)|IEEE80211_TYPE_CTL_SUBTYPE_ACK);
|
||||
|
||||
memcpy(ðernet_frame[0], reply->destination_address, 6);
|
||||
memcpy(ðernet_frame[6], reply->source_address, 6);
|
||||
|
||||
// add size of ethernet header
|
||||
ethernet_frame_size = 14;
|
||||
/*
|
||||
* Send 802.3 frame
|
||||
*/
|
||||
qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
if(((buf[12] & 0xF0)== IEEE80211_ENCAPSULATED)&&(buf[13] == ((IEEE80211_TYPE_CTL << 4)|IEEE80211_TYPE_CTL_SUBTYPE_ACK)))
|
||||
{
|
||||
|
||||
//discard packages from others channels
|
||||
if((buf[12] & 0x0F) != esp32_wifi_channel) return -1;
|
||||
//discard packages originated from the same mac address
|
||||
if(!memcmp(&buf[6],s->macaddr,6)) return -1;
|
||||
//check destination
|
||||
if(memcmp(&buf[0],s->macaddr,6)) return -1;
|
||||
|
||||
Esp32_WLAN_Set_Packet_Status(ESP32_PHYA_ACK);
|
||||
timer_mod_anticipate(s->wait_ack_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
|
||||
|
||||
Esp32_WLAN_init_ap_frame(s, frame);
|
||||
memcpy(frame->destination_address, &buf[0], 6);
|
||||
memcpy(frame->source_address, &buf[6], 6);
|
||||
memset(frame->bssid_address, 0xff, 6);
|
||||
frame->frame_control.type= IEEE80211_TYPE_CTL;
|
||||
frame->frame_control.sub_type= IEEE80211_TYPE_CTL_SUBTYPE_ACK;
|
||||
frame->frame_control.flags= 0;
|
||||
frame->duration_id= 0 ;
|
||||
frame->frame_length = 10;
|
||||
|
||||
if(DEBUG) {
|
||||
ANSI_FG_HCOLOR(GREEN);
|
||||
macprint(&buf[6],"---------------\n>IN ACK received: source");
|
||||
ANSI_DEFAULT();
|
||||
}
|
||||
infoprint(frame);
|
||||
//ACK is not inserted in DMA
|
||||
return size;
|
||||
}
|
||||
Esp32_WLAN_init_ap_frame(s, frame);
|
||||
Esp32_WLAN_insert_frame(s, frame);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
static void Esp32_WLAN_cleanup(NetClientState *ncs) { }
|
||||
|
||||
static NetClientInfo net_info = {
|
||||
.type = NET_CLIENT_DRIVER_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = Esp32_WLAN_can_receive,
|
||||
.receive = Esp32_WLAN_receive,
|
||||
.cleanup = Esp32_WLAN_cleanup,
|
||||
};
|
||||
|
||||
void Esp32_WLAN_reset_ap(Esp32WifiState *s) {
|
||||
esp32_wifi_channel = 0;
|
||||
s->ap_state = Esp32_WLAN__STATE_NOT_AUTHENTICATED;
|
||||
s->beacon_ap=0;
|
||||
s->mode = Esp32_Mode_Station;
|
||||
memcpy(s->ap_macaddr,(uint8_t[]){0x10,0x13,0x46,0xbf,0x31,0x50},sizeof(s->ap_macaddr));
|
||||
|
||||
s->inject_timer_running = 0;
|
||||
s->inject_sequence_number = 0;
|
||||
|
||||
s->inject_queue = NULL;
|
||||
s->inject_queue_size = 0;
|
||||
}
|
||||
|
||||
void Esp32_WLAN_setup_ap(DeviceState *dev,Esp32WifiState *s) {
|
||||
|
||||
Esp32_WLAN_reset_ap(s);
|
||||
|
||||
s->beacon_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_beacon_timer, s);
|
||||
timer_mod(s->beacon_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME)+BEACON_TIME);
|
||||
|
||||
// setup the timer but only schedule
|
||||
// it when necessary...
|
||||
s->inject_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_inject_timer, s);
|
||||
|
||||
s->wait_ack_timer = timer_new_ns(QEMU_CLOCK_REALTIME, Esp32_WLAN_Wait_ACk_timer, s);
|
||||
|
||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||
memcpy(s->macaddr, s->conf.macaddr.a, sizeof(s->macaddr));
|
||||
s->nic = qemu_new_nic(&net_info, &s->conf,
|
||||
object_get_typename(OBJECT(s)), dev->id,
|
||||
&dev->mem_reentrancy_guard, s);
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->macaddr);
|
||||
}
|
||||
|
||||
static void send_single_frame(Esp32WifiState *s, struct mac80211_frame *frame, struct mac80211_frame *reply) {
|
||||
reply->sequence_control.sequence_number = s->inject_sequence_number++ +0x730;
|
||||
reply->signal_strength=-10;
|
||||
|
||||
if(frame) {
|
||||
memcpy(reply->destination_address, frame->source_address, 6);
|
||||
if(s->mode == Esp32_Mode_Station){
|
||||
memcpy(reply->source_address, s->macaddr, 6);
|
||||
}
|
||||
else{
|
||||
memcpy(reply->source_address, s->ap_macaddr, 6);
|
||||
}
|
||||
memcpy(reply->bssid_address, frame->source_address, 6);
|
||||
}
|
||||
|
||||
Esp32_WLAN_insert_frame(s, reply);
|
||||
}
|
||||
|
||||
void Esp32_WLAN_handle_frame(Esp32WifiState *s, struct mac80211_frame *frame)
|
||||
{
|
||||
struct mac80211_frame *reply = NULL;
|
||||
static access_point_info dummy_ap={0};
|
||||
static char ssid[64];
|
||||
unsigned long ethernet_frame_size;
|
||||
unsigned char ethernet_frame[1518];
|
||||
|
||||
|
||||
if(DEBUG){
|
||||
if((ENABLE_BEACON)||!((frame->frame_control.type == IEEE80211_TYPE_MGT)&&(frame->frame_control.sub_type == IEEE80211_TYPE_MGT_SUBTYPE_BEACON))){
|
||||
ANSI_FG_HCOLOR(RED);
|
||||
printf("-------------------------\n<OUT Handle Frame type:%d subtype:%d channel:%d ap_state:%d time:%ld \n",frame->frame_control.type,
|
||||
frame->frame_control.sub_type,esp32_wifi_channel,s->ap_state,(unsigned long) qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
|
||||
ANSI_DEFAULT();
|
||||
}
|
||||
}
|
||||
if((ENABLE_BEACON)||!((frame->frame_control.type == IEEE80211_TYPE_MGT)&&(frame->frame_control.sub_type == IEEE80211_TYPE_MGT_SUBTYPE_BEACON))){
|
||||
infoprint(frame);
|
||||
}
|
||||
access_point_info *ap_info=0;
|
||||
|
||||
if(s->mode == Esp32_Mode_Station){
|
||||
for(int i=0;i<nb_aps;i++)
|
||||
if(access_points[i].channel==esp32_wifi_channel){
|
||||
ap_info=&access_points[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Esp32_WLAN_Set_Packet_Status(ESP32_PHYA_ACK);
|
||||
if(frame->frame_control.type == IEEE80211_TYPE_MGT) {
|
||||
switch(frame->frame_control.sub_type) {
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_BEACON:
|
||||
if(s->ap_state==Esp32_WLAN__STATE_NOT_AUTHENTICATED || s->ap_state==Esp32_WLAN__STATE_AUTHENTICATED) {
|
||||
strncpy(ssid,(char *)frame->data_and_fcs+14,frame->data_and_fcs[13]);
|
||||
if(DEBUG) printf("beacon from %s\n",ssid);
|
||||
dummy_ap.ssid=ssid;
|
||||
dummy_ap.channel = esp32_wifi_channel;
|
||||
dummy_ap.sigstrength= -23;
|
||||
memcpy(dummy_ap.mac_address,s->ap_macaddr,6) ;
|
||||
memcpy(s->softap_macaddr,frame->bssid_address,6);
|
||||
s->mode = Esp32_Mode_SoftAP;
|
||||
s->ap_state=Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED;
|
||||
send_single_frame(s,frame,Esp32_WLAN_create_probe_request(&dummy_ap));
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_ACTION:
|
||||
if(DEBUG) printf("action\n");
|
||||
/*
|
||||
* The access point uses the 802.11 frame
|
||||
* and sends a 802.3 frame into the network...
|
||||
* This packet is then understandable by
|
||||
* qemu-slirp
|
||||
*
|
||||
* If we ever want the access point to offer
|
||||
* some services, it can be added here!!
|
||||
*/
|
||||
// ethernet header type
|
||||
ethernet_frame[12] = ((frame->frame_control.flags & 0x40) ? IEEE80211_ENCAPSULATED_PROTECTED : IEEE80211_ENCAPSULATED)| esp32_wifi_channel;
|
||||
ethernet_frame[13] = ((IEEE80211_TYPE_MGT << 4)|IEEE80211_TYPE_MGT_SUBTYPE_ACTION);
|
||||
|
||||
memcpy(ðernet_frame[0], frame->destination_address, 6);
|
||||
memcpy(ðernet_frame[6], s->macaddr, 6);
|
||||
|
||||
// add packet content
|
||||
ethernet_frame_size = frame->frame_length -IEEE80211_HEADER_SIZE;
|
||||
|
||||
if (ethernet_frame_size > sizeof(ethernet_frame)) {
|
||||
ethernet_frame_size = sizeof(ethernet_frame);
|
||||
}
|
||||
memcpy(ðernet_frame[14], &frame->data_and_fcs[0], ethernet_frame_size);
|
||||
// add size of ethernet header
|
||||
ethernet_frame_size += 14;
|
||||
/*
|
||||
* Send 802.3 frame
|
||||
*/
|
||||
qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size);
|
||||
|
||||
//if destination is not broadcast wait for ack
|
||||
if(memcmp(ðernet_frame[0],BROADCAST,6)){
|
||||
Esp32_WLAN_Set_Packet_Status(ESP32_PHYA_NACK);
|
||||
timer_mod(s->wait_ack_timer, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + WAIT_ACK_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP:
|
||||
ap_info=&dummy_ap;
|
||||
strncpy(ssid,(char *)frame->data_and_fcs+14,frame->data_and_fcs[13]);
|
||||
if(DEBUG) printf("probe resp from %s\n",ssid);
|
||||
dummy_ap.ssid=ssid;
|
||||
s->ap_state=Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED;
|
||||
send_single_frame(s,frame,Esp32_WLAN_create_deauthentication());
|
||||
send_single_frame(s,frame,Esp32_WLAN_create_authentication_request());
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP:
|
||||
if(DEBUG) printf("assoc resp\n");
|
||||
mac80211_frame *frame1=Esp32_WLAN_create_dhcp_discover(s);
|
||||
memcpy(frame1->bssid_address,BROADCAST,6);
|
||||
memcpy(frame1->source_address,frame->destination_address,6);
|
||||
memcpy(frame1->destination_address,frame->source_address,6);
|
||||
send_single_frame(s,0,frame1);
|
||||
s->ap_state=Esp32_WLAN__STATE_STA_DHCP;
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION:
|
||||
DEBUG_PRINT_AP(("Received disassociation!\n"));
|
||||
send_single_frame(s,frame,Esp32_WLAN_create_disassociation());
|
||||
if (s->ap_state == Esp32_WLAN__STATE_ASSOCIATED || s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
s->ap_state = Esp32_WLAN__STATE_AUTHENTICATED;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION:
|
||||
DEBUG_PRINT_AP(("Received deauthentication!\n"));
|
||||
//reply = Esp32_WLAN_create_authentication_response(ap_info);
|
||||
if (s->ap_state == Esp32_WLAN__STATE_AUTHENTICATED) {
|
||||
s->ap_state = Esp32_WLAN__STATE_NOT_AUTHENTICATED;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION:
|
||||
DEBUG_PRINT_AP(("Received authentication!\n"));
|
||||
if(frame->data_and_fcs[2]==2) { // response
|
||||
send_single_frame(s,frame,Esp32_WLAN_create_association_request(&dummy_ap));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(ap_info) {
|
||||
memcpy(s->ap_macaddr,ap_info->mac_address,6);
|
||||
switch(frame->frame_control.sub_type) {
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ:
|
||||
DEBUG_PRINT_AP(("Received probe request!\n"));
|
||||
reply = Esp32_WLAN_create_probe_response(ap_info);
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION:
|
||||
DEBUG_PRINT_AP(("Received authentication req!\n"));
|
||||
if(frame->data_and_fcs[2]==1) { // request
|
||||
reply = Esp32_WLAN_create_authentication_response(ap_info);
|
||||
if (s->ap_state == Esp32_WLAN__STATE_NOT_AUTHENTICATED) {
|
||||
s->ap_state = Esp32_WLAN__STATE_AUTHENTICATED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ:
|
||||
DEBUG_PRINT_AP(("Received association request!\n"));
|
||||
reply = Esp32_WLAN_create_association_response(ap_info);
|
||||
if (s->ap_state == Esp32_WLAN__STATE_AUTHENTICATED) {
|
||||
s->ap_state = Esp32_WLAN__STATE_ASSOCIATED;
|
||||
memcpy(s->associated_ap_macaddr,s->ap_macaddr,6);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (reply) {
|
||||
reply->signal_strength=ap_info->sigstrength;
|
||||
memcpy(reply->destination_address, frame->source_address, 6);
|
||||
Esp32_WLAN_init_ap_frame(s, reply);
|
||||
Esp32_WLAN_insert_frame(s, reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((frame->frame_control.type == IEEE80211_TYPE_DATA) &&
|
||||
(frame->frame_control.sub_type == IEEE80211_TYPE_DATA_SUBTYPE_DATA)) {
|
||||
if(s->ap_state == Esp32_WLAN__STATE_STA_DHCP) {
|
||||
dhcp_request_t *req=(dhcp_request_t *)&frame->data_and_fcs[8];
|
||||
// check for a dhcp offer
|
||||
if(req->dhcp.bp_options[0]==0x35 && req->dhcp.bp_options[2]==0x2) {
|
||||
mac80211_frame *frame1=Esp32_WLAN_create_dhcp_request(s,req->dhcp.yiaddr);
|
||||
memcpy(frame1->bssid_address,BROADCAST,6);
|
||||
memcpy(frame1->source_address,s->ap_macaddr,6);
|
||||
memcpy(frame1->destination_address,frame->source_address,6);
|
||||
send_single_frame(s,0,frame1);
|
||||
//memcpy(s->ap_macaddr,(uint8_t[]){0x10,0x01,0x00,0xc4,0x0a,0x25},sizeof(s->ap_macaddr));
|
||||
//memcpy(s->associated_ap_macaddr,s->ap_macaddr,sizeof(s->ap_macaddr));
|
||||
memcpy(s->associated_ap_macaddr,s->macaddr,sizeof(s->macaddr));
|
||||
s->ap_state=Esp32_WLAN__STATE_STA_ASSOCIATED;
|
||||
if(DEBUG) printf("Dhcp received addr %d.%d.%d.%d\n",req->dhcp.yiaddr[0],req->dhcp.yiaddr[1],req->dhcp.yiaddr[2],req->dhcp.yiaddr[3]);
|
||||
}
|
||||
} else if (s->ap_state == Esp32_WLAN__STATE_ASSOCIATED || s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
/*
|
||||
* The access point uses the 802.11 frame
|
||||
* and sends a 802.3 frame into the network...
|
||||
* This packet is then understandable by
|
||||
* qemu-slirp
|
||||
*
|
||||
* If we ever want the access point to offer
|
||||
* some services, it can be added here!!
|
||||
*/
|
||||
// ethernet header type
|
||||
ethernet_frame[12] = frame->data_and_fcs[6];
|
||||
ethernet_frame[13] = frame->data_and_fcs[7];
|
||||
|
||||
// the new originator of the packet is
|
||||
// the access point
|
||||
if(s->ap_state == Esp32_WLAN__STATE_ASSOCIATED)
|
||||
memcpy(ðernet_frame[6], s->ap_macaddr, 6);
|
||||
else
|
||||
memcpy(ðernet_frame[6], s->macaddr, 6);
|
||||
|
||||
if (ethernet_frame[12] == 0x08 && ethernet_frame[13] == 0x06) {
|
||||
// for arp request, we use a broadcast
|
||||
memset(ðernet_frame[0], 0xff, 6);
|
||||
} else {
|
||||
// otherwise we forward the packet to
|
||||
// where it really belongs
|
||||
memcpy(ðernet_frame[0], frame->destination_address, 6);
|
||||
}
|
||||
|
||||
// add packet content
|
||||
ethernet_frame_size = frame->frame_length - IEEE80211_HEADER_SIZE - 4 - 8;
|
||||
|
||||
// for some reason, the packet is 22 bytes too small (??)
|
||||
ethernet_frame_size += 22;
|
||||
if (ethernet_frame_size > sizeof(ethernet_frame)) {
|
||||
ethernet_frame_size = sizeof(ethernet_frame);
|
||||
}
|
||||
memcpy(ðernet_frame[14], &frame->data_and_fcs[8], ethernet_frame_size);
|
||||
// add size of ethernet header
|
||||
ethernet_frame_size += 14;
|
||||
/*
|
||||
* Send 802.3 frame
|
||||
*/
|
||||
qemu_send_packet(qemu_get_queue(s->nic), ethernet_frame, ethernet_frame_size);
|
||||
}
|
||||
}
|
||||
Esp32_WLAN_frame_delivered(s);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* QEMU WLAN device emulation
|
||||
*
|
||||
* Copyright (c) 2008 Clemens Kolbitsch
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modifications:
|
||||
* 2008-February-24 Clemens Kolbitsch :
|
||||
* New implementation based on ne2000.c
|
||||
* 18/1/22 Martin Johnson : Modified for esp32 wifi emulation
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef esp32_wlan_h
|
||||
#define esp32_wlan_h 1
|
||||
|
||||
|
||||
//#define DEBUG_Esp32_WLAN
|
||||
|
||||
#ifdef DEBUG_Esp32_WLAN
|
||||
#define DEBUG_PRINT_AP(x) \
|
||||
do { \
|
||||
struct timeval __tt; \
|
||||
gettimeofday(&__tt, NULL); \
|
||||
printf("%u:%u ", (unsigned)__tt.tv_sec, (unsigned)__tt.tv_usec); \
|
||||
printf x ;\
|
||||
} while (0)
|
||||
#else
|
||||
#define DEBUG_PRINT_AP(x)
|
||||
#endif
|
||||
|
||||
|
||||
#define IEEE80211_IDLE 0xff
|
||||
|
||||
#define IEEE80211_TYPE_MGT 0x00
|
||||
#define IEEE80211_TYPE_CTL 0x01
|
||||
#define IEEE80211_TYPE_DATA 0x02
|
||||
|
||||
#define IEEE80211_ENCAPSULATED 0xA0
|
||||
#define IEEE80211_ENCAPSULATED_PROTECTED 0xB0
|
||||
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_BEACON 0x08
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_ACTION 0x0d
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ 0x04
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP 0x05
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION 0x0b
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION 0x0c
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ 0x00
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP 0x01
|
||||
#define IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION 0x0a
|
||||
|
||||
#define IEEE80211_TYPE_CTL_SUBTYPE_ACK 0x0d
|
||||
|
||||
#define IEEE80211_TYPE_DATA_SUBTYPE_DATA 0x00
|
||||
|
||||
#define IEEE80211_BEACON_PARAM_SSID 0x00
|
||||
#define IEEE80211_BEACON_PARAM_RATES 0x01
|
||||
#define IEEE80211_BEACON_PARAM_CHANNEL 0x03
|
||||
#define IEEE80211_BEACON_PARAM_EXTENDED_RATES 0x32
|
||||
#define IEEE80211_BEACON_PARAM_TIM 0x05
|
||||
|
||||
|
||||
#define IEEE80211_HEADER_SIZE 24
|
||||
|
||||
typedef struct beacon_info_t {
|
||||
uint64_t timestamp;
|
||||
uint16_t interval;
|
||||
uint16_t capability;
|
||||
} QEMU_PACKED beacon_info_t;
|
||||
|
||||
typedef uint8_t macaddr_t[6];
|
||||
|
||||
#define BROADCAST (uint8_t[]){0xff,0xff,0xff,0xff,0xff,0xff}
|
||||
|
||||
typedef struct mac80211_frame {
|
||||
struct mac80211_frame_control {
|
||||
unsigned protocol_version : 2;
|
||||
unsigned type : 2;
|
||||
unsigned sub_type : 4;
|
||||
unsigned flags:8;
|
||||
} QEMU_PACKED frame_control;
|
||||
uint16_t duration_id;
|
||||
macaddr_t destination_address;
|
||||
macaddr_t source_address;
|
||||
macaddr_t bssid_address;
|
||||
struct mac80211_sequence_control {
|
||||
unsigned fragment_number : 4;
|
||||
unsigned sequence_number : 12;
|
||||
} QEMU_PACKED sequence_control;
|
||||
// variable length, 2312 byte plus 4 byte frame-checksum
|
||||
union {
|
||||
uint8_t data_and_fcs[2316];
|
||||
beacon_info_t beacon_info;
|
||||
};
|
||||
unsigned int frame_length;
|
||||
int signal_strength;
|
||||
int pos;
|
||||
struct mac80211_frame *next_frame;
|
||||
} QEMU_PACKED mac80211_frame;
|
||||
|
||||
typedef struct access_point_info {
|
||||
const char *ssid;
|
||||
int channel;
|
||||
int sigstrength;
|
||||
macaddr_t mac_address;
|
||||
} access_point_info;
|
||||
|
||||
enum esp32_ap_state {
|
||||
Esp32_WLAN__STATE_NOT_AUTHENTICATED,
|
||||
Esp32_WLAN__STATE_AUTHENTICATED,
|
||||
Esp32_WLAN__STATE_ASSOCIATED,
|
||||
Esp32_WLAN__STATE_STA_NOT_AUTHENTICATED,
|
||||
Esp32_WLAN__STATE_STA_AUTHENTICATED,
|
||||
Esp32_WLAN__STATE_STA_ASSOCIATED,
|
||||
Esp32_WLAN__STATE_STA_DHCP,
|
||||
};
|
||||
|
||||
#define Esp32_WLAN__MAX_INJECT_QUEUE_SIZE 20
|
||||
|
||||
typedef struct {
|
||||
signed rssi:8; /**< Received Signal Strength Indicator(RSSI) of packet. unit: dBm */
|
||||
unsigned rate:5; /**< PHY rate encoding of the packet. Only valid for non HT(11bg) packet */
|
||||
unsigned :1; /**< reserved */
|
||||
unsigned sig_mode:2; /**< 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet */
|
||||
unsigned legacy_length:12; /**< copy of the length */
|
||||
unsigned damatch0:1; /* destination matches address0 */
|
||||
unsigned damatch1:1; /* destination matches address1 */
|
||||
unsigned bssidmatch0:1; /* bssid matches address0 */
|
||||
unsigned bssidmatch1:1; /* bssid matches address1 */
|
||||
unsigned mcs:7; /**< Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76) */
|
||||
unsigned cwb:1; /**< Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz */
|
||||
unsigned :16; /**< reserved */
|
||||
unsigned smoothing:1; /**< reserved */
|
||||
unsigned not_sounding:1; /**< reserved */
|
||||
unsigned :1; /**< reserved */
|
||||
unsigned aggregation:1; /**< Aggregation. 0: MPDU packet; 1: AMPDU packet */
|
||||
unsigned stbc:2; /**< Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet */
|
||||
unsigned fec_coding:1; /**< Flag is set for 11n packets which are LDPC */
|
||||
unsigned sgi:1; /**< Short Guide Interval(SGI). 0: Long GI; 1: Short GI */
|
||||
signed noise_floor:8; /**< noise floor of Radio Frequency Module(RF). unit: 0.25dBm*/
|
||||
unsigned ampdu_cnt:8; /**< ampdu cnt */
|
||||
unsigned channel:4; /**< primary channel on which this packet is received */
|
||||
unsigned secondary_channel:4; /**< secondary channel on which this packet is received. 0: none; 1: above; 2: below */
|
||||
unsigned :8; /**< reserved */
|
||||
unsigned timestamp:32; /**< timestamp. The local time when this packet is received. It is precise only if modem sleep or light sleep is not enabled. unit: microsecond */
|
||||
unsigned :32; /**< reserved */
|
||||
unsigned :31; /**< reserved */
|
||||
unsigned ant:1; /**< antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1 */
|
||||
unsigned sig_len:12; /**< length of packet including Frame Check Sequence(FCS) */
|
||||
unsigned sig_len_copy:12; /**< another copy of the length */
|
||||
unsigned rx_state:8; /**< state of the packet. 0: no error; others: error numbers which are not public */
|
||||
} QEMU_PACKED wifi_pkt_rx_ctrl_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
signed rssi:8; /**< Received Signal Strength Indicator(RSSI) of packet. unit: dBm */
|
||||
unsigned rate:5; /**< PHY rate encoding of the packet. Only valid for non HT(11bg) packet */
|
||||
unsigned :1; /**< reserved */
|
||||
unsigned sig_mode:2; /**< 0: non HT(11bg) packet; 1: HT(11n) packet; 3: VHT(11ac) packet */
|
||||
unsigned legacy_length:12; /**< copy of the length */
|
||||
unsigned damatch0:1; /* destination matches address0 */
|
||||
unsigned damatch1:1; /* destination matches address1 */
|
||||
unsigned bssidmatch0:1; /* bssid matches address0 */
|
||||
unsigned bssidmatch1:1; /* bssid matches address1 */
|
||||
unsigned mcs:7; /**< Modulation Coding Scheme. If is HT(11n) packet, shows the modulation, range from 0 to 76(MSC0 ~ MCS76) */
|
||||
unsigned cwb:1; /**< Channel Bandwidth of the packet. 0: 20MHz; 1: 40MHz */
|
||||
unsigned :16; /**< reserved */
|
||||
unsigned smoothing:1; /**< reserved */
|
||||
unsigned not_sounding:1; /**< reserved */
|
||||
unsigned :1; /**< reserved */
|
||||
unsigned aggregation:1; /**< Aggregation. 0: MPDU packet; 1: AMPDU packet */
|
||||
unsigned stbc:2; /**< Space Time Block Code(STBC). 0: non STBC packet; 1: STBC packet */
|
||||
unsigned fec_coding:1; /**< Flag is set for 11n packets which are LDPC */
|
||||
unsigned sgi:1; /**< Short Guide Interval(SGI). 0: Long GI; 1: Short GI */
|
||||
unsigned :8; /**< reserved */
|
||||
unsigned ampdu_cnt:8; /**< ampdu cnt */
|
||||
unsigned channel:4; /**< primary channel on which this packet is received */
|
||||
unsigned secondary_channel:4; /**< secondary channel on which this packet is received. 0: none; 1: above; 2: below */
|
||||
unsigned :8; /**< reserved */
|
||||
unsigned timestamp:32; /**< timestamp. The local time when this packet is received. It is precise only if modem sleep or light sleep is not enabled. unit: microsecond */
|
||||
unsigned :32; /**< reserved */
|
||||
signed noise_floor:8; /**< noise floor of Radio Frequency Module(RF). unit: dBm*/
|
||||
unsigned :24; /**< reserved */
|
||||
unsigned :32; /**< reserved */
|
||||
unsigned :31; /**< reserved */
|
||||
unsigned ant:1; /**< antenna number from which this packet is received. 0: WiFi antenna 0; 1: WiFi antenna 1 */
|
||||
unsigned :32; /**< reserved */
|
||||
unsigned :32; /**< reserved */
|
||||
unsigned :32; /**< reserved */
|
||||
unsigned sig_len:12; /**< length of packet including Frame Check Sequence(FCS) */
|
||||
unsigned sig_len_copy:12; /**< another copy of the length */
|
||||
unsigned rx_state:8; /**< state of the packet. 0: no error; others: error numbers which are not public */
|
||||
} QEMU_PACKED wifi_pkt_rx_ctrl_c3_t;
|
||||
|
||||
extern int esp32_wifi_channel;
|
||||
|
||||
typedef uint8_t ip4_t[4];
|
||||
|
||||
#define DHCP_CHADDR_LEN 16
|
||||
#define DHCP_SNAME_LEN 64
|
||||
#define DHCP_FILE_LEN 128
|
||||
|
||||
typedef struct ip_header_t {
|
||||
uint8_t version_size;
|
||||
uint8_t dscp_ecn;
|
||||
uint8_t len_h;
|
||||
uint8_t len_l;
|
||||
uint32_t z;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t checksum;
|
||||
ip4_t source_ip;
|
||||
ip4_t dest_ip;
|
||||
}ip_header_t ;
|
||||
|
||||
typedef struct udp_header_t {
|
||||
uint8_t src_port_h;
|
||||
uint8_t src_port_l;
|
||||
uint8_t dest_port_h;
|
||||
uint8_t dest_port_l;
|
||||
uint8_t len_h;
|
||||
uint8_t len_l;
|
||||
uint16_t checksum;
|
||||
} udp_header_t;
|
||||
|
||||
typedef struct dhcp_t {
|
||||
uint8_t opcode;
|
||||
uint8_t htype;
|
||||
uint8_t hlen;
|
||||
uint8_t hops;
|
||||
uint32_t xid;
|
||||
uint16_t secs;
|
||||
uint16_t flags;
|
||||
ip4_t ciaddr;
|
||||
ip4_t yiaddr;
|
||||
ip4_t siaddr;
|
||||
ip4_t giaddr;
|
||||
uint8_t chaddr[DHCP_CHADDR_LEN];
|
||||
char bp_sname[DHCP_SNAME_LEN];
|
||||
char bp_file[DHCP_FILE_LEN];
|
||||
uint32_t magic_cookie;
|
||||
uint8_t bp_options[0];
|
||||
} dhcp_t;
|
||||
|
||||
typedef struct dhcp_request_t {
|
||||
ip_header_t ipheader;
|
||||
udp_header_t udpheader;
|
||||
dhcp_t dhcp;
|
||||
} dhcp_request_t;
|
||||
|
||||
typedef struct arp_header_t {
|
||||
uint16_t htype;
|
||||
uint16_t ptype;
|
||||
uint8_t hlen;
|
||||
uint8_t plen;
|
||||
uint16_t operation;
|
||||
uint8_t sender_mac[6];
|
||||
uint8_t sender_ip[4];
|
||||
uint8_t target_mac[6];
|
||||
uint8_t target_ip[4];
|
||||
}arp_header_t;
|
||||
|
||||
#endif // esp32_wlan_h
|
||||
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* QEMU WLAN access point emulation
|
||||
*
|
||||
* Copyright (c) 2008 Clemens Kolbitsch
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modifications:
|
||||
* 2008-February-24 Clemens Kolbitsch :
|
||||
* New implementation based on ne2000.c
|
||||
* 18/1/22 Martin Johnson : Modified for esp32 wifi emulation
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "net/net.h"
|
||||
|
||||
#include "esp32_wlan.h"
|
||||
#include "esp32_wlan_packet.h"
|
||||
|
||||
// the frame checksum isn't used so just put zero in there.
|
||||
void insertCRC(mac80211_frame *frame) {
|
||||
unsigned long crc;
|
||||
unsigned char *fcs = (unsigned char *)frame;
|
||||
crc = 0;
|
||||
memcpy(fcs+frame->frame_length, &crc, 4);
|
||||
frame->frame_length += 4;
|
||||
}
|
||||
|
||||
static void add_byte(mac80211_frame *frame, uint8_t data) {
|
||||
frame->data_and_fcs[frame->pos++]=data;
|
||||
frame->frame_length=IEEE80211_HEADER_SIZE+frame->pos;
|
||||
}
|
||||
|
||||
static void add_data(mac80211_frame *frame, int len,uint8_t *data) {
|
||||
for(int i=0;i<len;i++)
|
||||
add_byte(frame,data[i]);
|
||||
}
|
||||
|
||||
static void add_tag(mac80211_frame *frame, int tag, int len, unsigned char bytes[]) {
|
||||
add_byte(frame,tag);
|
||||
add_byte(frame,len);
|
||||
add_data(frame,len,bytes);
|
||||
}
|
||||
|
||||
void Esp32_WLAN_init_ap_frame(Esp32WifiState *s, mac80211_frame *frame) {
|
||||
frame->sequence_control.sequence_number = s->inject_sequence_number++;
|
||||
if(s->mode == Esp32_Mode_Station){
|
||||
if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED)
|
||||
memcpy(frame->source_address, s->macaddr, 6);
|
||||
else
|
||||
memcpy(frame->source_address, s->ap_macaddr, 6);
|
||||
memcpy(frame->bssid_address, s->ap_macaddr, 6);
|
||||
}
|
||||
else{
|
||||
if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED)
|
||||
memcpy(frame->source_address, s->ap_macaddr, 6);
|
||||
else
|
||||
memcpy(frame->source_address, s->softap_macaddr, 6);
|
||||
memcpy(frame->bssid_address, s->softap_macaddr, 6);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static mac80211_frame *new_frame(unsigned type, unsigned subtype) {
|
||||
mac80211_frame *frame = (mac80211_frame *)malloc(sizeof(mac80211_frame));
|
||||
frame->next_frame = NULL;
|
||||
frame->frame_control.protocol_version = 0;
|
||||
frame->frame_control.type = type;
|
||||
frame->frame_control.sub_type = subtype;
|
||||
frame->frame_control.flags = 0;
|
||||
frame->duration_id = 314;
|
||||
frame->sequence_control.fragment_number = 0;
|
||||
frame->pos=0;
|
||||
return frame;
|
||||
}
|
||||
|
||||
static void add_rates(mac80211_frame *frame) {
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_RATES,8,(uint8_t[]){0x8b,0x96,0x82,0x84,0x0c,0x18,0x30,0x60});
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_EXTENDED_RATES,4,(uint8_t[]){0x6c,0x12,0x24,0x48});
|
||||
}
|
||||
|
||||
static void add_ssid(mac80211_frame *frame, const char *ssid) {
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_SSID,strlen(ssid),(uint8_t *)ssid);
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_beacon_frame(access_point_info *ap) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_BEACON);
|
||||
frame->signal_strength=ap->sigstrength;
|
||||
memcpy(frame->destination_address,BROADCAST,6);
|
||||
frame->beacon_info.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000;
|
||||
frame->beacon_info.interval=1000;
|
||||
frame->beacon_info.capability=1;
|
||||
frame->pos=12;
|
||||
add_ssid(frame,ap->ssid);
|
||||
add_rates(frame);
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel});
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_TIM,4,(uint8_t[]){4,1,3,0,0});
|
||||
return frame;
|
||||
}
|
||||
|
||||
static uint16_t in_cksum(uint16_t *addr, int len) {
|
||||
int sum = 0;
|
||||
uint16_t answer = 0;
|
||||
uint16_t *w = addr;
|
||||
int nleft = len;
|
||||
while (nleft > 1) {
|
||||
sum += *w++;
|
||||
nleft -= 2;
|
||||
}
|
||||
/* mop up an odd byte, if necessary */
|
||||
if (nleft == 1) {
|
||||
*(uint8_t *)(&answer) = *(uint8_t *) w;
|
||||
sum += answer;
|
||||
}
|
||||
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
|
||||
sum += (sum >> 16); /* add carry */
|
||||
answer = ~sum; /* truncate to 16 bits */
|
||||
return (answer);
|
||||
}
|
||||
|
||||
static mac80211_frame *Esp32_WLAN_create_dhcp_frame(Esp32WifiState *s, int cmd_size, uint8_t dhcp_commands[]) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_DATA,IEEE80211_TYPE_DATA_SUBTYPE_DATA);
|
||||
frame->frame_control.flags=1;
|
||||
add_data(frame,8,(uint8_t[]){ 0xaa, 0xaa ,0x03 ,00 ,00 ,00 ,8 ,00});
|
||||
dhcp_request_t req={
|
||||
{.version_size=0x45,.ttl=0xff,.protocol=0x11,.dest_ip={0xff,0xff,0xff,0xff}},
|
||||
{.src_port_l=0x44,.dest_port_l=0x43},
|
||||
{.htype=1,.hlen=6,.xid=0x1d3d00,.chaddr={0,0,0,0,0,0},
|
||||
.magic_cookie=0x63538263}
|
||||
};
|
||||
memcpy(req.dhcp.chaddr, s->macaddr, 6);
|
||||
int len=sizeof(req)+cmd_size;
|
||||
req.ipheader.len_h=len>>8;
|
||||
req.ipheader.len_l=len&0xff;
|
||||
len=len-sizeof(ip_header_t);
|
||||
req.udpheader.len_h=len>>8;
|
||||
req.udpheader.len_l=len&0xff;
|
||||
req.ipheader.checksum=in_cksum((void *)&req.ipheader,sizeof(ip_header_t));
|
||||
add_data(frame,sizeof(req),(uint8_t *)&req);
|
||||
add_data(frame,cmd_size,dhcp_commands);
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_dhcp_request(Esp32WifiState *s, uint8_t *ip) {
|
||||
uint8_t dhcp_commands[]={
|
||||
0x35, 1, 3,
|
||||
0x39, 2 ,5 ,0xdc ,
|
||||
0x32, 4, ip[0],ip[1],ip[2],ip[3],
|
||||
0x3d, 0x07, 0x01, 0x3c, 0x61, 0x05, 0x0d, 0x99, 0x24,
|
||||
0x37, 0x04, 0x01, 0x03, 0x1c, 0x06,
|
||||
0xff, 0, 0
|
||||
};
|
||||
return Esp32_WLAN_create_dhcp_frame(s, sizeof(dhcp_commands),dhcp_commands);
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_dhcp_discover(Esp32WifiState *s) {
|
||||
uint8_t dhcp_commands[]={
|
||||
0x35, 1, 1,
|
||||
0x39, 2 ,5 ,0xdc ,
|
||||
0x0c ,0x09 ,0x65 ,0x73 ,0x70 ,0x72 ,0x65 ,0x73 ,0x73 ,0x69 ,0x66 ,
|
||||
0x3d ,0x07, 0x01 ,0x3c ,0x61 ,0x05 ,0x0d ,0x99 ,0x24 ,
|
||||
0x37 ,0x04 ,0x01 ,0x03 ,0x1c ,0x06 ,
|
||||
0xff, 0,0
|
||||
};
|
||||
return Esp32_WLAN_create_dhcp_frame(s,sizeof(dhcp_commands),dhcp_commands);
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_association_request(access_point_info *ap) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ);
|
||||
add_data(frame,4,(uint8_t []){0x21,4,3,0});
|
||||
add_ssid(frame,ap->ssid);
|
||||
add_rates(frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_ack(void) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_CTL,IEEE80211_TYPE_CTL_SUBTYPE_ACK);
|
||||
frame->frame_length=10;
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_probe_response(access_point_info *ap) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_PROBE_RESP);
|
||||
frame->beacon_info.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000;
|
||||
frame->beacon_info.interval=1000;
|
||||
frame->beacon_info.capability=1;
|
||||
frame->pos=12;
|
||||
add_ssid(frame,ap->ssid);
|
||||
add_rates(frame);
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel});
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_probe_request(access_point_info *ap) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ);
|
||||
memcpy(frame->destination_address,BROADCAST,6);
|
||||
memcpy(frame->bssid_address,BROADCAST,6);
|
||||
add_ssid(frame,ap->ssid);
|
||||
add_tag(frame,IEEE80211_BEACON_PARAM_CHANNEL,1,(uint8_t[]){ap->channel});
|
||||
add_rates(frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_authentication_response(access_point_info *ap) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION);
|
||||
/*
|
||||
* Fixed params... typical AP params (6 byte)
|
||||
*
|
||||
* They include
|
||||
* - Authentication Algorithm (here: Open System)
|
||||
* - Authentication SEQ
|
||||
* - Status code (successful 0x0)
|
||||
*/
|
||||
add_data(frame,6,(uint8_t []){0,0,2,0,0,0});
|
||||
add_ssid(frame,ap->ssid);
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_authentication_request(void) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION);
|
||||
/*
|
||||
* Fixed params... typical AP params (6 byte)
|
||||
*
|
||||
* They include
|
||||
* - Authentication Algorithm (here: Open System)
|
||||
* - Authentication SEQ
|
||||
* - Status code (successful 0x0)
|
||||
*/
|
||||
//frame->duration_id=0x13a;
|
||||
add_data(frame,6,(uint8_t []){0,0,1,0,0,0});
|
||||
//add_data(frame,11,(uint8_t []){0,0,0,0,0,0,0,0,0,0,0});
|
||||
//add_ssid(frame,ap->ssid);
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_deauthentication(void) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION);
|
||||
/*
|
||||
* Insert reason code:
|
||||
* "Deauthentication because sending STA is leaving"
|
||||
*/
|
||||
add_data(frame,2,(uint8_t []){3,0});
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_association_response(access_point_info *ap) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_RESP);
|
||||
/*
|
||||
* Fixed params... typical AP params (6 byte)
|
||||
*
|
||||
* They include
|
||||
* - Capability Information
|
||||
* - Status code (successful 0x0)
|
||||
* - Association ID
|
||||
*/
|
||||
add_data(frame,6,(uint8_t []){33,4,0,0,1,0xc0});
|
||||
add_ssid(frame,ap->ssid);
|
||||
add_rates(frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_disassociation(void) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_MGT,IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION);
|
||||
/*
|
||||
* Insert reason code:
|
||||
* "Disassociation because sending STA is leaving"
|
||||
*/
|
||||
add_data(frame,2,(uint8_t []){3,0});
|
||||
return frame;
|
||||
}
|
||||
|
||||
mac80211_frame *Esp32_WLAN_create_data_packet(Esp32WifiState *s, const uint8_t *buf, int size) {
|
||||
mac80211_frame *frame=new_frame(IEEE80211_TYPE_DATA,IEEE80211_TYPE_DATA_SUBTYPE_DATA);
|
||||
|
||||
frame->frame_control.flags = 0x2; /* from station back to station via AP */
|
||||
frame->duration_id = 44;
|
||||
/* send message to wlan-device */
|
||||
if(s->ap_state == Esp32_WLAN__STATE_STA_ASSOCIATED) {
|
||||
memcpy(frame->destination_address, s->ap_macaddr, 6);
|
||||
frame->frame_control.flags = 0x2;
|
||||
}
|
||||
else
|
||||
memcpy(frame->destination_address, s->macaddr, 6);
|
||||
/* LLC */
|
||||
add_data(frame,6,(uint8_t[]){ 0xaa, 0xaa ,0x03 ,0 ,0 ,0});
|
||||
memcpy(frame->data_and_fcs+6, buf+12, size-12);
|
||||
frame->frame_length = IEEE80211_HEADER_SIZE + size-6;
|
||||
return frame;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* QEMU WLAN access point emulation
|
||||
*
|
||||
* Copyright (c) 2008 Clemens Kolbitsch
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modifications:
|
||||
* 2008-February-24 Clemens Kolbitsch :
|
||||
* New implementation based on ne2000.c
|
||||
* 18/1/22 Martin Johnson : Modified for esp32 wifi emulation
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef esp32_wlan_packet_h
|
||||
#define esp32_wlan_packet_h 1
|
||||
|
||||
#include "esp32_wlan.h"
|
||||
#include "hw/misc/esp32_wifi.h"
|
||||
|
||||
void Esp32_WLAN_init_ap_frame(Esp32WifiState *s, struct mac80211_frame *frame);
|
||||
int Esp32_WLAN_dumpFrame(struct mac80211_frame *frame, int frame_len, char *filename);
|
||||
void Esp32_WLAN_insert_frame(Esp32WifiState *s, struct mac80211_frame *frame);
|
||||
struct mac80211_frame *Esp32_WLAN_create_beacon_frame(access_point_info *ap);
|
||||
struct mac80211_frame *Esp32_WLAN_create_probe_response(access_point_info *ap);
|
||||
struct mac80211_frame *Esp32_WLAN_create_probe_request(access_point_info *ap);
|
||||
struct mac80211_frame *Esp32_WLAN_create_authentication_request(void);
|
||||
struct mac80211_frame *Esp32_WLAN_create_authentication_response(access_point_info *ap);
|
||||
struct mac80211_frame *Esp32_WLAN_create_deauthentication(void);
|
||||
struct mac80211_frame *Esp32_WLAN_create_association_request(access_point_info *ap);
|
||||
struct mac80211_frame *Esp32_WLAN_create_association_response(access_point_info *ap);
|
||||
struct mac80211_frame *Esp32_WLAN_create_disassociation(void);
|
||||
struct mac80211_frame *Esp32_WLAN_create_data_reply(Esp32WifiState *s, struct mac80211_frame *incoming);
|
||||
struct mac80211_frame *Esp32_WLAN_create_data_packet(Esp32WifiState *s, const uint8_t *buf, int size);
|
||||
struct mac80211_frame *Esp32_WLAN_create_ack(void);
|
||||
struct mac80211_frame *Esp32_WLAN_create_dhcp_discover(Esp32WifiState *s);
|
||||
struct mac80211_frame *Esp32_WLAN_create_dhcp_request(Esp32WifiState *s, uint8_t *ip);
|
||||
void insertCRC(mac80211_frame *frame);
|
||||
|
||||
#endif // esp32_wlan_packet_h
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/esp32c3_ana.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
int esp32_wifi_channel = 0;
|
||||
|
||||
static uint64_t esp32c3_ana_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
Esp32C3AnaState *s = ESP32C3_ANA(opaque);
|
||||
uint32_t r = s->mem[addr/4];
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
case 0x48:
|
||||
r= 0x00FFFFFF;
|
||||
break;
|
||||
case 0x50:
|
||||
r=0x07000000 | s->mem[addr/4];
|
||||
break;
|
||||
case 0x04:
|
||||
r= 0xFDFFFFFF;
|
||||
break;
|
||||
case 0x44:
|
||||
case 0x4C:
|
||||
case 0xC4:
|
||||
r=0xFFFFFFFF;
|
||||
break;
|
||||
}
|
||||
if(DEBUG) printf("esp32c3_ana_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void esp32c3_ana_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned int size) {
|
||||
Esp32C3AnaState *s = ESP32C3_ANA(opaque);
|
||||
|
||||
if(DEBUG) printf("esp32c3_ana_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
|
||||
|
||||
if(addr == 0x150) {
|
||||
int v= (value & 0x0FF00000) >> 0x14;
|
||||
esp32_wifi_channel=(v-7)/5;
|
||||
if(esp32_wifi_channel > 14) esp32_wifi_channel = 14;
|
||||
//printf("wifi channel:0x%08x ",(int)value);
|
||||
//printf("===========> esp32_wifi_channel %i \n", esp32_wifi_channel);
|
||||
}
|
||||
|
||||
s->mem[addr/4]=value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps esp32c3_ana_ops = {
|
||||
.read = esp32c3_ana_read,
|
||||
.write = esp32c3_ana_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void esp32c3_ana_init(Object *obj)
|
||||
{
|
||||
Esp32C3AnaState *s = ESP32C3_ANA(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &esp32c3_ana_ops, s,
|
||||
TYPE_ESP32C3_ANA, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
memset(s->mem,0,sizeof(s->mem));
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo esp32c3_ana_info = {
|
||||
.name = TYPE_ESP32C3_ANA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Esp32C3AnaState),
|
||||
.instance_init = esp32c3_ana_init,
|
||||
};
|
||||
|
||||
static void esp32c3_ana_register_types(void)
|
||||
{
|
||||
type_register_static(&esp32c3_ana_info);
|
||||
}
|
||||
|
||||
type_init(esp32c3_ana_register_types)
|
||||
@@ -0,0 +1,84 @@
|
||||
/* ESP32C3 unimp/dummy peripheral handler
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/misc/esp32c3_pwrmng.h"
|
||||
#include "hw/misc/esp32c3_reg.h"
|
||||
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static uint64_t esp32c3_pwrmng_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
static bool init = false;
|
||||
Esp32c3PwrMngState *s = ESP32C3_PWR_MANAGER(opaque);
|
||||
|
||||
uint32_t r = s->mem[addr/4];
|
||||
|
||||
switch(addr){
|
||||
case 0x07C:
|
||||
/* Return a random 32-bit value */
|
||||
if (!init) {
|
||||
srand(time(NULL));
|
||||
init = true;
|
||||
}
|
||||
r = rand();
|
||||
break;
|
||||
case 0x128: //DMA enabled
|
||||
r = 0 ;
|
||||
break;
|
||||
case 0x118: //PWR int events
|
||||
r = 0 ;
|
||||
break;
|
||||
}
|
||||
|
||||
if(DEBUG) printf("esp32_pwrmng_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void esp32c3_pwrmng_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned int size)
|
||||
{
|
||||
Esp32c3PwrMngState *s = ESP32C3_PWR_MANAGER(opaque);
|
||||
|
||||
if(DEBUG) printf("esp32_pwrmng_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
|
||||
|
||||
s->mem[addr/4]=value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps esp32c3_pwrmng_ops = {
|
||||
.read = esp32c3_pwrmng_read,
|
||||
.write = esp32c3_pwrmng_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void esp32c3_pwrmng_init(Object *obj)
|
||||
{
|
||||
Esp32c3PwrMngState *s = ESP32C3_PWR_MANAGER(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &esp32c3_pwrmng_ops, s, TYPE_ESP32C3_PWR_MANAGER, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static const TypeInfo esp32c3_pwrmng_info = {
|
||||
.name = TYPE_ESP32C3_PWR_MANAGER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Esp32c3PwrMngState),
|
||||
.instance_init = esp32c3_pwrmng_init,
|
||||
};
|
||||
|
||||
static void esp32c3_pwrmng_register_types(void)
|
||||
{
|
||||
type_register_static(&esp32c3_pwrmng_info);
|
||||
}
|
||||
|
||||
type_init(esp32c3_pwrmng_register_types)
|
||||
@@ -0,0 +1,245 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/esp32c3_wifi.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "esp32_wlan_packet.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/misc/esp32c3_reg.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
extern access_point_info access_points[];
|
||||
extern int nb_aps;
|
||||
|
||||
static uint64_t esp32C3_wifi_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
|
||||
Esp32WifiState *s = ESP32_WIFI(opaque);
|
||||
uint32_t r = s->mem[addr/4];
|
||||
|
||||
switch(addr) {
|
||||
case A_C3_WIFI_DMA_IN_STATUS:
|
||||
r = 0;
|
||||
break;
|
||||
case A_C3_WIFI_DMA_INT_STATUS:
|
||||
case A_C3_WIFI_DMA_INT_CLR:
|
||||
r = s->raw_interrupt;
|
||||
break;
|
||||
case A_C3_WIFI_STATUS:
|
||||
case A_C3_WIFI_DMA_OUT_STATUS:
|
||||
r = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (DEBUG) printf("esp32C3_wifi_read 0x%04lx= 0x%08x\n",(unsigned long) addr,r);
|
||||
|
||||
return r;
|
||||
}
|
||||
static void set_interrupt(Esp32WifiState *s,int e) {
|
||||
s->raw_interrupt |= e;
|
||||
qemu_set_irq(s->irq, 1);
|
||||
}
|
||||
|
||||
void Esp32_WLAN_frame_delivered(Esp32WifiState *s){
|
||||
s->raw_interrupt |= 0x80;
|
||||
qemu_set_irq(s->irq, 1);
|
||||
}
|
||||
|
||||
static void esp32C3_wifi_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned int size) {
|
||||
Esp32WifiState *s = ESP32_WIFI(opaque);
|
||||
if(DEBUG) printf("esp32C3_wifi_write 0x%04lx= 0x%08lx\n",(unsigned long) addr, (unsigned long) value);
|
||||
|
||||
switch (addr) {
|
||||
case A_C3_WIFI_DMA_INLINK: {
|
||||
uint32_t offset = value & 0xfffff;
|
||||
s->dma_inlink_address = offset ? 0x3fc00000 | offset : 0;
|
||||
s->mem[0x90 / sizeof(uint32_t)] = s->dma_inlink_address;
|
||||
break;
|
||||
}
|
||||
case A_C3_WIFI_DMA_INT_CLR:
|
||||
s->raw_interrupt &= ~value;
|
||||
if (s->raw_interrupt == 0) {
|
||||
qemu_set_irq(s->irq, 0);
|
||||
}
|
||||
break;
|
||||
case A_C3_WIFI_DMA_OUTLINK:
|
||||
if ((value & 0xc0000000) && (value & 0xfffff)) {
|
||||
mac80211_frame frame;
|
||||
dma_list_item item;
|
||||
unsigned memaddr = 0x3fc00000 | (value & 0xfffff);
|
||||
address_space_read(&address_space_memory, memaddr,
|
||||
MEMTXATTRS_UNSPECIFIED, &item, sizeof(item));
|
||||
if (item.length > sizeof(frame)) {
|
||||
break;
|
||||
}
|
||||
address_space_read(&address_space_memory, item.address,
|
||||
MEMTXATTRS_UNSPECIFIED, &frame, item.length);
|
||||
frame.frame_length = item.length;
|
||||
frame.next_frame = NULL;
|
||||
Esp32_WLAN_handle_frame(s, &frame);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s->mem[addr/4]=value;
|
||||
}
|
||||
|
||||
static int match_mac_address(uint8_t *a1,uint8_t *a2) {
|
||||
if(!memcmp(a1,a2,6)) return 1;
|
||||
if(!memcmp(a1,BROADCAST,6)) return 1;
|
||||
return 0;
|
||||
}
|
||||
// frame from ap to esp32
|
||||
void Esp32_sendFrame(Esp32WifiState *s, mac80211_frame *frame,int length, int signal_strength) {
|
||||
int packet_channel = esp32_wifi_channel;
|
||||
|
||||
if (s->dma_inlink_address == 0) {
|
||||
return;
|
||||
}
|
||||
if (frame->frame_control.type == IEEE80211_TYPE_MGT &&
|
||||
frame->frame_control.sub_type == IEEE80211_TYPE_MGT_SUBTYPE_BEACON) {
|
||||
int pos = 12;
|
||||
int data_length = length - IEEE80211_HEADER_SIZE;
|
||||
|
||||
while (pos + 2 <= data_length) {
|
||||
uint8_t tag = frame->data_and_fcs[pos];
|
||||
uint8_t tag_length = frame->data_and_fcs[pos + 1];
|
||||
|
||||
if (tag == IEEE80211_BEACON_PARAM_CHANNEL && tag_length) {
|
||||
packet_channel = frame->data_and_fcs[pos + 2];
|
||||
break;
|
||||
}
|
||||
pos += 2 + tag_length;
|
||||
}
|
||||
}
|
||||
if (packet_channel == 0) {
|
||||
const uint8_t *address = frame->frame_control.type == IEEE80211_TYPE_DATA
|
||||
? frame->bssid_address : frame->source_address;
|
||||
|
||||
for (int i = 0; i < nb_aps; i++) {
|
||||
if (memcmp(access_points[i].mac_address, address, 6) == 0) {
|
||||
packet_channel = access_points[i].channel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t header[sizeof(wifi_pkt_rx_ctrl_c3_t)+length];
|
||||
memset(header,0,sizeof(header));
|
||||
wifi_pkt_rx_ctrl_c3_t *pkt=(wifi_pkt_rx_ctrl_c3_t *)header;
|
||||
*pkt=(wifi_pkt_rx_ctrl_c3_t){
|
||||
.rssi=(signal_strength+(rand()%10)+96),
|
||||
.rate=11,
|
||||
.sig_len=length,
|
||||
.sig_len_copy=length,
|
||||
.legacy_length=length,
|
||||
.noise_floor=-97,
|
||||
.channel=packet_channel,
|
||||
.timestamp=qemu_clock_get_ns(QEMU_CLOCK_REALTIME)/1000,
|
||||
};
|
||||
// These 4 bits are set if the mac addresses previously stored at 0x40 and 0x48
|
||||
// match the destination or bssid addresses in the frame
|
||||
if(match_mac_address(frame->destination_address,(uint8_t *)s->mem+0x40))
|
||||
pkt->damatch0=1;
|
||||
if(match_mac_address(frame->destination_address,(uint8_t *)s->mem+0x48))
|
||||
pkt->damatch1=1;
|
||||
if(match_mac_address(frame->bssid_address,(uint8_t *)s->mem+0x40))
|
||||
pkt->bssidmatch0=1;
|
||||
if(match_mac_address(frame->bssid_address,(uint8_t *)s->mem+0x48))
|
||||
pkt->bssidmatch1=1;
|
||||
pkt->damatch0 = 1;
|
||||
pkt->bssidmatch0 = 1;
|
||||
|
||||
memcpy(header+sizeof(wifi_pkt_rx_ctrl_c3_t),frame,length);
|
||||
length+=sizeof(wifi_pkt_rx_ctrl_c3_t);
|
||||
// do a DMA transfer from the hardware to esp32 memory
|
||||
dma_list_item item;
|
||||
address_space_read(&address_space_memory, s->dma_inlink_address,
|
||||
MEMTXATTRS_UNSPECIFIED, &item, sizeof(item));
|
||||
address_space_write(&address_space_memory, item.address,
|
||||
MEMTXATTRS_UNSPECIFIED, header, length);
|
||||
item.length = length;
|
||||
item.eof = 1;
|
||||
address_space_write(&address_space_memory, s->dma_inlink_address,
|
||||
MEMTXATTRS_UNSPECIFIED, &item, sizeof(uint32_t));
|
||||
s->mem[0x8c / sizeof(uint32_t)] = item.next;
|
||||
s->mem[0x90 / sizeof(uint32_t)] = s->dma_inlink_address;
|
||||
if (item.next) {
|
||||
s->dma_inlink_address = item.next;
|
||||
} else {
|
||||
uint32_t base = s->mem[A_C3_WIFI_DMA_INLINK / sizeof(uint32_t)];
|
||||
uint32_t offset = base & 0xfffff;
|
||||
s->dma_inlink_address = offset ? 0x3fc00000 | offset : 0;
|
||||
}
|
||||
set_interrupt(s, 0x1004024);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps esp32C3_wifi_ops = {
|
||||
.read = esp32C3_wifi_read,
|
||||
.write = esp32C3_wifi_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void esp32c3_wifi_reset(DeviceState *dev)
|
||||
{
|
||||
Esp32WifiState *s = ESP32_WIFI(dev);
|
||||
|
||||
s->dma_inlink_address=0;
|
||||
memset(s->mem,0,sizeof(s->mem));
|
||||
Esp32_WLAN_reset_ap(s);
|
||||
}
|
||||
|
||||
static void esp32C3_wifi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Esp32WifiState *s = ESP32_WIFI(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
s->dma_inlink_address=0;
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &esp32C3_wifi_ops, s,
|
||||
TYPE_ESP32_WIFI, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
memset(s->mem,0,sizeof(s->mem));
|
||||
Esp32_WLAN_setup_ap(dev, s);
|
||||
|
||||
}
|
||||
static Property esp32C3_wifi_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(Esp32WifiState, conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void esp32C3_wifi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = esp32C3_wifi_realize;
|
||||
device_class_set_legacy_reset(dc, esp32c3_wifi_reset);
|
||||
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||
dc->desc = "Esp32C3 WiFi";
|
||||
device_class_set_props(dc, esp32C3_wifi_properties);
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo esp32C3_wifi_info = {
|
||||
.name = TYPE_ESP32_WIFI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Esp32WifiState),
|
||||
.class_init = esp32C3_wifi_class_init,
|
||||
};
|
||||
|
||||
static void esp32C3_wifi_register_types(void)
|
||||
{
|
||||
type_register_static(&esp32C3_wifi_info);
|
||||
}
|
||||
|
||||
type_init(esp32C3_wifi_register_types)
|
||||
+8
-1
@@ -155,7 +155,14 @@ system_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files(
|
||||
'esp32c3_jtag.c',
|
||||
'esp32c3_rtc_cntl.c',
|
||||
'esp_hmac.c',
|
||||
'esp32c3_hmac.c'
|
||||
'esp32c3_hmac.c',
|
||||
'esp32c3_wifi.c',
|
||||
'esp32_wifi_ap.c',
|
||||
'esp32_wlan_packet.c',
|
||||
'esp32c3_ana.c',
|
||||
'esp32_phya.c',
|
||||
'esp32_fe.c',
|
||||
'esp32c3_pwrmng.c'
|
||||
))
|
||||
|
||||
system_ss.add(when: 'CONFIG_XTENSA_ESP32S3', if_true: files(
|
||||
|
||||
+77
-26
@@ -51,6 +51,11 @@
|
||||
#include "hw/misc/esp32c3_ds.h"
|
||||
#include "hw/misc/esp32c3_xts_aes.h"
|
||||
#include "hw/misc/esp32c3_jtag.h"
|
||||
#include "hw/misc/esp32c3_wifi.h"
|
||||
#include "hw/misc/esp32c3_ana.h"
|
||||
#include "hw/misc/esp32_phya.h"
|
||||
#include "hw/misc/esp32_fe.h"
|
||||
#include "hw/misc/esp32c3_pwrmng.h"
|
||||
#include "hw/dma/esp32c3_gdma.h"
|
||||
#include "hw/display/esp_rgb.h"
|
||||
#include "hw/display/xteink_x3_eink.h"
|
||||
@@ -76,6 +81,7 @@ struct Esp32C3MachineState {
|
||||
EspRISCVCPU soc;
|
||||
BusState periph_bus;
|
||||
MemoryRegion iomem;
|
||||
uint32_t syscon[0x1000 / sizeof(uint32_t)];
|
||||
bool xteink;
|
||||
bool x4;
|
||||
|
||||
@@ -183,12 +189,19 @@ static bool addr_in_range(hwaddr addr, hwaddr start, hwaddr end)
|
||||
|
||||
static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
if (addr_in_range(addr + ESP32C3_IO_START_ADDR, DR_REG_RTC_I2C_BASE, DR_REG_RTC_I2C_BASE + 0x100)) {
|
||||
return (uint32_t) 0xffffff;
|
||||
} else if (addr + ESP32C3_IO_START_ADDR == DR_REG_SYSCON_BASE + A_SYSCON_ORIGIN_REG) {
|
||||
Esp32C3MachineState *ms = opaque;
|
||||
hwaddr absolute = addr + ESP32C3_IO_START_ADDR;
|
||||
|
||||
if (addr_in_range(absolute, DR_REG_NRX_BASE - 0xc00,
|
||||
DR_REG_BB_BASE + 0x1000)) {
|
||||
return UINT32_MAX;
|
||||
} else if (addr_in_range(absolute, DR_REG_RTC_I2C_BASE,
|
||||
DR_REG_RTC_I2C_BASE + 0x100)) {
|
||||
return 0xffffff;
|
||||
} else if (absolute == DR_REG_SYSCON_BASE + A_SYSCON_ORIGIN_REG) {
|
||||
/* Return "QEMU" as a 32-bit value */
|
||||
return 0x51454d55;
|
||||
} else if (addr + ESP32C3_IO_START_ADDR == DR_REG_SYSCON_BASE + A_SYSCON_RND_DATA_REG) {
|
||||
} else if (absolute == DR_REG_SYSCON_BASE + A_SYSCON_RND_DATA_REG) {
|
||||
/* Return a random 32-bit value */
|
||||
static bool init = false;
|
||||
if (!init) {
|
||||
@@ -196,8 +209,11 @@ static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
init = true;
|
||||
}
|
||||
return rand();
|
||||
} else if (addr + ESP32C3_IO_START_ADDR == DR_REG_ASSIST_DEBUG_BASE + A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG) {
|
||||
} else if (absolute == DR_REG_ASSIST_DEBUG_BASE + A_ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG) {
|
||||
return 0;
|
||||
} else if (addr_in_range(absolute, DR_REG_SYSCON_BASE,
|
||||
DR_REG_SYSCON_BASE + sizeof(ms->syscon))) {
|
||||
return ms->syscon[(absolute - DR_REG_SYSCON_BASE) / sizeof(uint32_t)];
|
||||
} else {
|
||||
#if ESP32C3_IO_WARNING
|
||||
warn_report("[ESP32-C3] Unsupported read to $%08lx\n", ESP32C3_IO_START_ADDR + addr);
|
||||
@@ -208,8 +224,16 @@ static uint64_t esp32c3_io_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
|
||||
static void esp32c3_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
|
||||
{
|
||||
Esp32C3MachineState *ms = opaque;
|
||||
hwaddr absolute = addr + ESP32C3_IO_START_ADDR;
|
||||
|
||||
if (addr_in_range(absolute, DR_REG_SYSCON_BASE,
|
||||
DR_REG_SYSCON_BASE + sizeof(ms->syscon))) {
|
||||
ms->syscon[(absolute - DR_REG_SYSCON_BASE) / sizeof(uint32_t)] = value;
|
||||
return;
|
||||
}
|
||||
#if ESP32C3_IO_WARNING
|
||||
warn_report("[ESP32-C3] Unsupported write $%08lx = %08lx\n", ESP32C3_IO_START_ADDR + addr, value);
|
||||
warn_report("[ESP32-C3] Unsupported write $%08lx = %08lx\n", absolute, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -271,34 +295,60 @@ static void esp32c3_init_spi_flash(Esp32C3MachineState *ms, BlockBackend* blk)
|
||||
}
|
||||
|
||||
|
||||
static void esp32c3_map_radio_device(const char *type, hwaddr address)
|
||||
{
|
||||
DeviceState *device = qdev_new(type);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(device);
|
||||
|
||||
sysbus_realize_and_unref(sbd, &error_fatal);
|
||||
memory_region_add_subregion_overlap(get_system_memory(), address,
|
||||
sysbus_mmio_get_region(sbd, 0), 0);
|
||||
}
|
||||
|
||||
static bool esp32c3_init_wifi(Esp32C3MachineState *ms)
|
||||
{
|
||||
DeviceState *wifi = qemu_create_nic_device(TYPE_ESP32C3_WIFI, false, NULL);
|
||||
SysBusDevice *sbd;
|
||||
|
||||
if (!wifi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
esp32c3_map_radio_device(TYPE_ESP32C3_ANA, DR_REG_RTC_I2C_BASE);
|
||||
esp32c3_map_radio_device(TYPE_ESP32_PHYA, DR_REG_PHYA_BASE);
|
||||
esp32c3_map_radio_device(TYPE_ESP32_FE, DR_REG_FE_BASE);
|
||||
esp32c3_map_radio_device(TYPE_ESP32C3_PWR_MANAGER, DR_REG_PWR_MANAGER_BASE);
|
||||
|
||||
sbd = SYS_BUS_DEVICE(wifi);
|
||||
sysbus_realize_and_unref(sbd, &error_fatal);
|
||||
memory_region_add_subregion_overlap(get_system_memory(), DR_REG_WIFI_BASE,
|
||||
sysbus_mmio_get_region(sbd, 0), 0);
|
||||
sysbus_connect_irq(sbd, 0,
|
||||
qdev_get_gpio_in(DEVICE(&ms->intmatrix),
|
||||
ETS_WIFI_MAC_INTR_SOURCE));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void esp32c3_init_openeth(Esp32C3MachineState *ms)
|
||||
{
|
||||
MemoryRegion* mr = NULL;
|
||||
SysBusDevice* sbd = NULL;
|
||||
DeviceState *open_eth_dev = qemu_create_nic_device("open_eth", true, NULL);
|
||||
SysBusDevice *sbd;
|
||||
|
||||
MemoryRegion* sys_mem = get_system_memory();
|
||||
|
||||
/* Create a new OpenCores Ethernet component */
|
||||
DeviceState* open_eth_dev = qemu_create_nic_device("open_eth", true, NULL);
|
||||
if (!open_eth_dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
ms->eth = open_eth_dev;
|
||||
|
||||
sbd = SYS_BUS_DEVICE(open_eth_dev);
|
||||
sysbus_realize(sbd, &error_fatal);
|
||||
|
||||
/* OpenCores Ethernet has two memory regions: one for registers and one for descriptors,
|
||||
* we need to provide one I/O range for each of them */
|
||||
mr = sysbus_mmio_get_region(sbd, 0);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_EMAC_BASE, mr, 0);
|
||||
mr = sysbus_mmio_get_region(sbd, 1);
|
||||
memory_region_add_subregion_overlap(sys_mem, DR_REG_EMAC_BASE + 0x400, mr, 0);
|
||||
|
||||
memory_region_add_subregion_overlap(get_system_memory(), DR_REG_EMAC_BASE,
|
||||
sysbus_mmio_get_region(sbd, 0), 0);
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
DR_REG_EMAC_BASE + 0x400,
|
||||
sysbus_mmio_get_region(sbd, 1), 0);
|
||||
sysbus_connect_irq(sbd, 0,
|
||||
qdev_get_gpio_in(DEVICE(&ms->intmatrix), ETS_ETH_MAC_INTR_SOURCE));
|
||||
|
||||
qdev_get_gpio_in(DEVICE(&ms->intmatrix),
|
||||
ETS_ETH_MAC_INTR_SOURCE));
|
||||
}
|
||||
|
||||
|
||||
@@ -420,7 +470,7 @@ static void esp32c3_machine_init(MachineState *machine)
|
||||
qdev_realize(DEVICE(&ms->soc), NULL, &error_fatal);
|
||||
|
||||
memory_region_init_io(&ms->iomem, OBJECT(&ms->soc), &esp32c3_io_ops,
|
||||
NULL, "esp32c3.iomem", 0xd1000);
|
||||
ms, "esp32c3.iomem", 0xd1000);
|
||||
memory_region_add_subregion(sys_mem, ESP32C3_IO_START_ADDR, &ms->iomem);
|
||||
|
||||
|
||||
@@ -495,8 +545,9 @@ static void esp32c3_machine_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize OpenCores Ethernet controller now sicne it requires the interrupt matrix */
|
||||
esp32c3_init_openeth(ms);
|
||||
if (!esp32c3_init_wifi(ms)) {
|
||||
esp32c3_init_openeth(ms);
|
||||
}
|
||||
|
||||
/* USB Serial JTAG realization */
|
||||
{
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
|
||||
#define TYPE_ESP32_FE "misc.esp32.fe"
|
||||
#define ESP32_FE(obj) OBJECT_CHECK(Esp32FeState, (obj), TYPE_ESP32_FE)
|
||||
//OBJECT_CHECK(Esp32FeState, (obj), TYPE_ESP32_FE)
|
||||
//(Esp32FeState *)(obj)
|
||||
|
||||
typedef struct Esp32FeState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
uint32_t mem[1024];
|
||||
} Esp32FeState;
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
|
||||
#define TYPE_ESP32_PHYA "misc.esp32.phya"
|
||||
#define ESP32_PHYA(obj) OBJECT_CHECK(Esp32PhyaState, (obj), TYPE_ESP32_PHYA)
|
||||
|
||||
typedef struct Esp32PhyaState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
uint32_t mem[1024];
|
||||
} Esp32PhyaState;
|
||||
|
||||
#define ESP32_PHYA_NACK 0x00002300
|
||||
#define ESP32_PHYA_ACK 0x0
|
||||
|
||||
void Esp32_WLAN_Set_Packet_Status(const uint32_t state);
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/sysbus.h"
|
||||
//#include "hw/misc/esp32_reg.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "net/net.h"
|
||||
|
||||
#define TYPE_ESP32_WIFI "esp32c3_wifi"
|
||||
#define ESP32_WIFI(obj) OBJECT_CHECK(Esp32WifiState, (obj), TYPE_ESP32_WIFI)
|
||||
|
||||
typedef struct dma_list_item {
|
||||
unsigned size:12;
|
||||
unsigned length:12;
|
||||
unsigned :6;
|
||||
unsigned eof:1;
|
||||
unsigned owner:1;
|
||||
uint32_t address;
|
||||
uint32_t next;
|
||||
} QEMU_PACKED dma_list_item;
|
||||
|
||||
typedef struct Esp32WifiState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
int raw_interrupt;
|
||||
qemu_irq irq;
|
||||
uint32_t mem[1024];
|
||||
int dma_inlink_address;
|
||||
uint32_t ap_state;
|
||||
int inject_queue_size;
|
||||
struct mac80211_frame *inject_queue;
|
||||
int inject_timer_running;
|
||||
unsigned int inject_sequence_number;
|
||||
int beacon_ap;
|
||||
|
||||
hwaddr receive_queue_address;
|
||||
uint32_t receive_queue_count;
|
||||
NICConf conf;
|
||||
NICState *nic;
|
||||
// various timers
|
||||
QEMUTimer *beacon_timer;
|
||||
QEMUTimer *inject_timer;
|
||||
QEMUTimer *wait_ack_timer;
|
||||
uint8_t ipaddr[4];
|
||||
uint8_t macaddr[6];
|
||||
|
||||
uint8_t ap_ipaddr[4];
|
||||
uint8_t ap_macaddr[6];
|
||||
|
||||
uint8_t associated_ap_macaddr[6];
|
||||
|
||||
uint8_t softap_macaddr[6];
|
||||
|
||||
uint8_t mode;
|
||||
|
||||
} Esp32WifiState;
|
||||
|
||||
#define Esp32_Mode_Station 0
|
||||
#define Esp32_Mode_SoftAP 1
|
||||
|
||||
|
||||
void Esp32_WLAN_handle_frame(Esp32WifiState *s, struct mac80211_frame *frame);
|
||||
void Esp32_WLAN_setup_ap(DeviceState *dev,Esp32WifiState *s);
|
||||
void Esp32_WLAN_reset_ap(Esp32WifiState *s);
|
||||
void Esp32_sendFrame(Esp32WifiState *s, struct mac80211_frame *frame,int length, int signal_strength);
|
||||
void Esp32_WLAN_frame_delivered(Esp32WifiState *s);
|
||||
|
||||
REG32(WIFI_DMA_IN_STATUS, 0x84);
|
||||
REG32(WIFI_DMA_INLINK, 0x88);
|
||||
REG32(WIFI_DMA_INT_STATUS, 0xc48);
|
||||
REG32(WIFI_DMA_INT_CLR, 0xc4c);
|
||||
REG32(WIFI_STATUS, 0xcc8);
|
||||
REG32(WIFI_DMA_OUTLINK, 0xd20);
|
||||
REG32(WIFI_DMA_OUT_STATUS, 0xd24);
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
|
||||
#define TYPE_ESP32C3_ANA "misc.esp32c3.ana"
|
||||
#define ESP32C3_ANA(obj) OBJECT_CHECK(Esp32C3AnaState, (obj), TYPE_ESP32C3_ANA)
|
||||
|
||||
typedef struct Esp32C3AnaState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
uint32_t mem[1024];
|
||||
} Esp32C3AnaState;
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/registerfields.h"
|
||||
|
||||
#define TYPE_ESP32C3_PWR_MANAGER "misc.esp32c3.pwrmng"
|
||||
#define ESP32C3_PWR_MANAGER(obj) OBJECT_CHECK(Esp32c3PwrMngState, (obj), TYPE_ESP32C3_PWR_MANAGER)
|
||||
|
||||
|
||||
typedef struct Esp32c3PwrMngState {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
uint32_t mem[1024];
|
||||
} Esp32c3PwrMngState;
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
#define DR_REG_APB_CTRL_BASE 0x60026000 /* Old name for SYSCON, to be removed */
|
||||
#define DR_REG_TWAI_BASE 0x6002B000
|
||||
#define DR_REG_I2S0_BASE 0x6002D000
|
||||
#define DR_REG_WIFI_BASE 0x60033000
|
||||
#define DR_REG_PHYA_BASE 0x60034000
|
||||
#define DR_REG_PWR_MANAGER_BASE 0x60035000
|
||||
#define DR_REG_APB_SARADC_BASE 0x60040000
|
||||
#define DR_REG_USB_SERIAL_JTAG_BASE 0x60043000
|
||||
#define DR_REG_AES_XTS_BASE 0x600CC000
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "net/net.h"
|
||||
#include "esp32_wifi.h"
|
||||
|
||||
#define TYPE_ESP32C3_WIFI TYPE_ESP32_WIFI
|
||||
|
||||
|
||||
REG32(C3_WIFI_DMA_IN_STATUS, 0x84);
|
||||
REG32(C3_WIFI_DMA_INLINK, 0x88);
|
||||
REG32(C3_WIFI_DMA_INT_STATUS, 0xc3C);
|
||||
REG32(C3_WIFI_DMA_INT_CLR, 0xc40);
|
||||
REG32(C3_WIFI_STATUS, 0xcb0);
|
||||
REG32(C3_WIFI_DMA_OUTLINK, 0xd08);
|
||||
REG32(C3_WIFI_DMA_OUT_STATUS, 0xd14);
|
||||
@@ -136,6 +136,10 @@ def start(args):
|
||||
(state / "wait.offset").write_text("0\n")
|
||||
flash = state / "flash.bin"
|
||||
build_flash(firmware, flash)
|
||||
efuse = bytearray(1024)
|
||||
efuse[0x18:0x1E] = bytes.fromhex("563412005452")
|
||||
efuse[0x26] = 0x0C
|
||||
(state / "efuse.bin").write_bytes(efuse)
|
||||
|
||||
command = [
|
||||
str(require_env("XTEINK_QEMU")),
|
||||
@@ -146,8 +150,10 @@ def start(args):
|
||||
"-serial", f"file:{state / 'serial.log'}",
|
||||
"-monitor", "none",
|
||||
"-qmp", f"unix:{state / 'qmp.sock'},server=on,wait=off",
|
||||
"-nic", "none",
|
||||
"-nic", "user,model=esp32c3_wifi,mac=52:54:00:12:34:56,net=192.168.4.0/24",
|
||||
"-drive", f"file={flash},if=mtd,format=raw",
|
||||
"-drive", f"file={state / 'efuse.bin'},if=none,format=raw,id=efuse",
|
||||
"-global", "driver=nvram.esp32c3.efuse,property=drive,value=efuse",
|
||||
"-drive", f"file={sdcard},if=sd,format=raw",
|
||||
]
|
||||
qemu_log = (state / "qemu.log").open("ab")
|
||||
|
||||
Reference in New Issue
Block a user