Adhoc wifi notes

From DeSmuME
Revision as of 14:36, 15 August 2011 by Luigi (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

The Ultimate Goal

- Getting adhoc wifi working. AKA NSMB multiplayer, pictochat, and many others.

The Issue

NSMB goes through the following sequence to connect two players together:
- Mario configures the wifi hardware as to send beacons every ~200ms. The beacons are 802.11 standard with extra data (tag DDh as GBATek puts it)
- Luigi receives the beacons and asks "Mario found - want to play?", let's assume the player says Yes
- Luigi associates with Mario, they exchange a few 802.11 standard authentication/association packets
- Mario sends a data frame every 1660µs. Luigi is given 478µs to reply.
- Luigi never replies for some reason. Connection fails.


Luigi does processing on the received data frame before it is fully received (aka between IRQ6 and IRQ0). Once it is fully received it's too late.
That's what we can call tight timing. :P

Some disassembling

NSMB's wifi IRQ handler (pseudocode)
(located at 0x037F9504)

u16 flags;
do
{
flags = IF & IE;
if (flags & 0x0080 /* TXSTART */) call 0x037FA528;
if (flags & 0x0040 /* RXSTART */) call 0x037FA5E4;
if (flags & 0x8000 /* PREBEACON */) call 0x037F95E8;
if (flags & 0x4000 /* BEACON */) call 0x037F9674;
if (flags & 0x2000 /* POSTBEACON */) call 0x037F9970;
if (flags & 0x0800 /* RFWAKEUP */) call 0x027EBC08;
if (flags & 0x0008 /* TXERR INC */) call 0x037F9A28;
if (flags & 0x0004 /* RXEVT INC */) call 0x037F9B54;
if (flags & 0x0001 /* RXEND */) call 0x037F9F88;
if (flags & 0x0030 /* TXERR/RXEVT HOVF */) call 0x037F99EC;
if (flags & 0x0002 /* TXEND */) call 0x037F9D18;
if (flags & 0x1000 /* IRQ12 */) call 0x037FA418;
}
while (flags);
/* clear wifi IRQ flag in main IF */
return;


IRQ12 (0x037FA418):
/* clear IRQ flags, blah blah */
/* R2 = txbusy; */
/* R0 = rfstatus; */
if (rfstatus != 3)
{
if (rfstatus != 5) goto 4f8;
}
if (txbusy != 0) goto 4f8;
call 0x027E9550;
goto 504;
4f8:
call 0x037F85F8;
504:
return;


TXSTART (0x037FA528):
/* clear TXSTART irq flag */
R3 = rxtxaddr;
status = rfstatus & 0xFF;
if (status < 3) return;
if (status > 5) return;
/* rxtxaddr range checks */
unk244 |= 0x0080;
unk244 &= ~0x0080;
return;


TXEND (0x037F9D18):
/* clear TXEND irq flag */
/* todo some shit */
R2 = txstat;
whosent = txstat & 0x0F00;
if (whosent == 0x0300) goto d80;
if (whosent == 0x0800) goto db4;
if (whosent == 0x0B00) goto df4;
goto ebc;
d80:
todo


RXSTART (0x037FA5E4):
/* clear RXSTART irq flag */
if ((rfpins & 0x0003) != 0x0003) goto bad;
if (rxtxaddr < rxbufbegin>>1) goto bad;
addr = wrcsr<<1 + 12; /* with wraparound */
framectl = wifiram[addr] & 0xE7FF;
if (framectl != 0x0228) goto bad;
addr += 2;
duration = wifiram[addr];
lastcount = us_count_0;
6ac:
numreceived = rxtxaddr - wrcsr;
if (numreceived <= 14) { if ((us_count_0 - lastcount)<=64) goto 6ac; else goto bad };
addr += 8; /* advance to mac2 */
/* compare mac2 against something in memory*/
addr += 6;
addr += 10; /* advance to body+2, aka slave bits */
R3 = &us_count_0;
73c: numreceived = rxtxaddr - wrcsr/*R6*/;
if (numreceived <= 20) { if ((us_count_0 - lastcount)<=112) goto 73c; else goto bad };
slavebits = wifiram[addr];
if (slavebits & (1 << aid_low)) goto bad;
memory[somewhere] = txbuf_reply2;
txbuf_reset = 0x0040; /* disable reply2 */
memory[somewhereelse]++;
while ((rfpins & 0x0003) == 0x0003);
unk244 |= 0x0040;
unk244 &= ~0x0040;
unk228 = 0x0008;
unk228 = 0x0000;
/* store something into txbuf_reply1, latch into txbuf_reply2 */
bad:
return;

So yeah. Not only it analyzes the packet before it is fully received, but it also replies before the packet is fully received! Nintendo coding sure rhymes with madness :P


RXEND:
todo

Update

With the latest work on wifi, Luigi tries to reply to the packet sent by Mario. He uses txbuf_reply1/2, however those registers are always set to zero for whatever reason.

Personal tools