Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion avf/qemu-scfb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
# env: MEMG (default 4), EXTRA (more boot-args), HMP (monitor port, 4454), QMP (4455)
# CAM=1: and the camera region (SCCAM, avf/CAMERA.md) 16 MB below the framebuffer's, with guest RAM a
# shared file (RAMFILE, default a temporary one) that avf/sccam-host.py serves a test pattern into
# NET=1: a virtio-net-pci card on QEMU's user network, as Scion's Network setting gives one under
# AVF; with virtio_net_wifi=1, which this adds, iOS sees it as Wi-Fi. NET=wired: the same card as a cable
# Note: under hvf, an extra virtio-tablet-pci made QEMU abort ("!s1ptw" in hvf.c); keep the device set as is.
set -u
HERE=$(cd "$(dirname "$0")" && pwd)
Expand All @@ -18,6 +20,12 @@ MEMG=${MEMG:-4}
IMAGE=$HERE/shim/out/Image
[ -f "$IMAGE" ] || "$HERE/shim/build.sh"
REGION=$(( 0x40000000 + (MEMG << 30) - (36 << 20) ))
NETARGS=()
case "${NET:-}" in
'' | 0) ;;
wired) NETARGS=(-netdev user,id=net0 -device virtio-net-pci,netdev=net0) ;;
*) NETARGS=(-netdev user,id=net0 -device virtio-net-pci,netdev=net0); EXTRA="virtio_net_wifi=1 ${EXTRA:-}" ;;
esac
PARAMS="scfb.addr=$(printf 0x%x $REGION) scfb.size=0x2000000 scfb.w=1125 scfb.h=2436 md0=rvblk0 ${EXTRA:-} -v"
RAM=(-m "${MEMG}G")
if [ "${CAM:-0}" = 1 ]; then
Expand All @@ -36,6 +44,6 @@ echo "scfb region $(printf 0x%x $REGION); boot-args: $PARAMS" >&2
timeout "$SECS" qemu-system-aarch64 -M virt,gic-version=3 -accel "${ACCEL:-hvf}" -cpu "${CPU:-host}" -smp 1 "${RAM[@]}" \
-kernel "$IMAGE" -initrd "$PAYLOAD" -append "$PARAMS" \
-drive "file=$SYSTEM,format=raw,if=none,id=sys,readonly=on" -device virtio-blk-pci,drive=sys \
-device virtio-multitouch-pci \
-device virtio-multitouch-pci ${NETARGS[@]+"${NETARGS[@]}"} \
-nographic -serial stdio -no-reboot \
-monitor "tcp:127.0.0.1:${HMP:-4454},server,nowait" -qmp "tcp:127.0.0.1:${QMP:-4455},server,nowait"
5 changes: 4 additions & 1 deletion avf/scion/avf.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
kernel=Image
initrd=payload.bin
disk.0=system.apfs
params=md0=rvblk0
# virtio_net_wifi=1: with Scion's "Network" setting on, AVF adds a virtio-net card (Android's VM
# tethering behind it) and iOS sees it as Wi-Fi, joined to the open network "Scion"
# (bsd/dev/redwood_virtio_net.c). Without the setting there is no card and it does nothing.
params=md0=rvblk0 virtio_net_wifi=1
memory_mib=4096
cpus=1
12 changes: 10 additions & 2 deletions xnu/files/bsd/dev/redwood_apple80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,10 +436,18 @@ get(struct apple80211req *request)
case 103: /* all of it, as a scan's result */
error = state->phase != REDWOOD_STA_JOINED ? ENXIO : give_network(request, &state->bss);
break;
case 2: { /* how it was joined: open system, then WPA2 with a passphrase */
struct {
case 2: { /* how it was joined: open system, then WPA2 with a passphrase -- or */
struct { /* nothing more, for a network whose beacon has no RSN element (48) */
uint32_t version, lower, upper, extended;
} answer = { .version = 1, .lower = 1, .upper = 8 };
bool secured = false;

for (unsigned at = 0; at + 2 <= state->bss.elements_length; at += 2 + state->bss.elements[at + 1]) {
secured |= state->bss.elements[at] == 48;
}
if (!secured && state->bss.elements_length != 0) {
answer.upper = 0;
}

error = state->phase != REDWOOD_STA_JOINED ? ENXIO : give(request, &answer, sizeof(answer));
break;
Expand Down
180 changes: 179 additions & 1 deletion xnu/files/bsd/dev/redwood_virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
* Nothing of what the device offers is taken (no checksums or segmentation left to it, no
* merged receive buffers): a 12-byte header nobody reads, then the frame, one buffer each.
* No interrupt is used; the interface's thread asks (virtio_poll()).
*
* Boot-arg virtio_net_wifi=1: iOS is told that en0 is a radio, the way the phone's is
* (redwood_net.c, RedwoodWLAN.cpp, redwood_apple80211.c), and a station of this file's stands
* behind it (the station boundary, sys/redwood_sta.h). It hears one open network, "Scion" (or
* virtio_net_ssid=NAME), joins it at the start and whenever iOS asks, and then lets frames
* pass. So Settings shows Wi-Fi on and that network joined, configd configures the interface
* by itself (a "Wi-Fi" network service, DHCP), and the status bar has the Wi-Fi bars. Under
* AVF (Scion's "Network" setting) the cable behind it is Android's VM tethering.
*/
#include <kern/thread.h>
#include <libkern/libkern.h>
Expand All @@ -17,7 +25,9 @@
#include <net/ethernet.h>
#include <pexpert/pexpert.h>
#include <sys/kpi_mbuf.h>
#include <sys/errno.h>
#include <sys/redwood_net.h>
#include <sys/redwood_sta.h>
#include <sys/redwood_virtio.h>
#include <sys/systm.h>

Expand Down Expand Up @@ -169,18 +179,186 @@ static struct redwood_net_link virtio_link = {
.poll = virtio_poll,
};

/* ---- virtio_net_wifi=1: a station with one network, always in reach ------------------------------------- */

#define VSTA_FREQUENCY 2437 /* channel 6 */
#define VSTA_RSSI (-45)

static struct redwood_sta_bss vsta_bss;
static enum redwood_sta_phase vsta_phase = REDWOOD_STA_IDLE;
static int vsta_error;

static void
vsta_link(bool up)
{
redwood_net_link_state(up);
}

static int
vsta_power(bool on)
{
if (!on && vsta_phase == REDWOOD_STA_JOINED) {
vsta_link(false);
}
vsta_phase = on ? REDWOOD_STA_IDLE : REDWOOD_STA_OFF;
return 0;
}

static int
vsta_scan(__unused const struct redwood_sta_scan *what)
{
return vsta_phase == REDWOOD_STA_OFF ? ENETDOWN : 0;
}

static void
vsta_heard(void (*each)(const struct redwood_sta_bss *bss, void *context), void *context)
{
each(&vsta_bss, context);
}

static int
vsta_join(const struct redwood_sta_join *what)
{
bool ours = what->ssid_length == vsta_bss.ssid_length && memcmp(what->ssid, vsta_bss.ssid, what->ssid_length) == 0;

if (vsta_phase == REDWOOD_STA_OFF) {
return ENETDOWN;
}
if (!ours) {
vsta_error = ENOENT; /* (nothing else is in reach) */
return ENOENT;
}
if (what->security != REDWOOD_STA_OPEN) {
vsta_error = EAUTH; /* (it is an open network: a key is the wrong one) */
return EAUTH;
}
vsta_error = 0;
if (vsta_phase != REDWOOD_STA_JOINED) {
vsta_phase = REDWOOD_STA_JOINED;
vsta_link(true);
}
return 0;
}

static int
vsta_leave(void)
{
if (vsta_phase == REDWOOD_STA_JOINED) {
vsta_link(false);
vsta_phase = REDWOOD_STA_IDLE;
}
return 0;
}

static void
vsta_state(struct redwood_sta_state *state)
{
state->phase = vsta_phase;
state->bss = vsta_bss;
state->last_error = vsta_error;
}

static unsigned
vsta_channels(struct redwood_sta_channel *channels, unsigned most)
{
static const uint16_t frequencies[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 5180, 5200, 5220, 5240 };
unsigned count = 0;

for (unsigned i = 0; i < sizeof(frequencies) / sizeof(frequencies[0]) && count < most; i++) {
channels[count++] = (struct redwood_sta_channel){ .frequency = frequencies[i] };
}
return count;
}

static struct redwood_sta_ops vsta_ops = {
.power = vsta_power,
.scan = vsta_scan,
.heard = vsta_heard,
.join = vsta_join,
.leave = vsta_leave,
.state = vsta_state,
.channels = vsta_channels,
};

/* The network: what a beacon of an open 802.11g access point on channel 6 would say. */
static void
vsta_start(const uint8_t address[ETHER_ADDR_LEN])
{
static const uint8_t rates[] = { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24 }; /* 1 2 5.5 11 basic; 6 9 12 18 */
static const uint8_t more_rates[] = { 0x30, 0x48, 0x60, 0x6c }; /* 24 36 48 54 */
static struct redwood_sta_join join;
char name[33] = "Scion";
struct redwood_sta_bss *b = &vsta_bss;
uint8_t *e = b->elements;
size_t length;

PE_parse_boot_argn("virtio_net_ssid", name, sizeof(name));
name[32] = 0;
length = strlen(name);
if (length == 0) {
strlcpy(name, "Scion", sizeof(name));
length = 5;
}
memcpy(b->ssid, name, length);
b->ssid_length = (uint8_t)length;
/* the access point's address: ours with another last byte, and "locally administered" */
memcpy(b->bssid, address, ETHER_ADDR_LEN);
b->bssid[0] = (uint8_t)((b->bssid[0] | 0x02) & ~0x01);
b->bssid[5] ^= 0x01;
b->frequency = VSTA_FREQUENCY;
b->rssi = VSTA_RSSI;
b->beacon_interval = 100;
b->capability = 0x0421; /* an access point (ESS), short preamble, short slot time; no privacy */
*e++ = 0; /* SSID */
*e++ = (uint8_t)length;
memcpy(e, name, length);
e += length;
*e++ = 1; /* supported rates */
*e++ = sizeof(rates);
memcpy(e, rates, sizeof(rates));
e += sizeof(rates);
*e++ = 3; /* the channel */
*e++ = 1;
*e++ = 6;
*e++ = 50; /* extended rates */
*e++ = sizeof(more_rates);
memcpy(e, more_rates, sizeof(more_rates));
e += sizeof(more_rates);
b->elements_length = (uint16_t)(e - b->elements);

memcpy(vsta_ops.address, address, ETHER_ADDR_LEN);
redwood_sta_attach(&vsta_ops);
/* joined at the start, and again whenever iOS turns Wi-Fi back on (as the phone joins the network of its file) */
bzero(&join, sizeof(join));
memcpy(join.ssid, b->ssid, length);
join.ssid_length = b->ssid_length;
join.security = REDWOOD_STA_OPEN;
if (redwood_sta_ask_join_standing(&join) != 0) {
printf("net: the virtual station did not take the standing join\n");
}
printf("net: en0 is a radio (virtio_net_wifi=1): one open network, \"%s\", joined at the start\n", name);
}

void
redwood_virtio_net_init(void)
{
uint32_t enabled = 1;
uint32_t enabled = 1, wifi = 0;

if (PE_parse_boot_argn("virtio_net", &enabled, sizeof(enabled)) && !enabled) {
return;
}
if (vio_find(VIRTIO_ID_NET, 0) == NULL) {
return; /* quietly: most machines have none */
}
if (PE_parse_boot_argn("virtio_net_wifi", &wifi, sizeof(wifi)) && wifi) {
virtio_link.wireless = true;
virtio_link.up = false; /* until the station has joined its network */
}
if (!virtio_net_start(virtio_link.address) || !redwood_net_attach(&virtio_link)) {
printf("net: no network interface\n");
return;
}
if (virtio_link.wireless) {
vsta_start(virtio_link.address);
}
}
Loading