From c3943b29ec57721ee21d332d4f3bdf9bf5e28a1d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 27 Jul 2023 21:11:30 +0200 Subject: [PATCH] wifi: * rework and clean up frame transfer code * disable melonAP during local multiplayer comm --- src/Wifi.cpp | 191 ++++++++++++++++++++++++--------------------------- 1 file changed, 88 insertions(+), 103 deletions(-) diff --git a/src/Wifi.cpp b/src/Wifi.cpp index 482802e0c6..a1c8267535 100644 --- a/src/Wifi.cpp +++ b/src/Wifi.cpp @@ -85,6 +85,7 @@ struct TXSlot }; TXSlot TXSlots[6]; +u8 TXBuffer[0x2000]; u8 RXBuffer[2048]; u32 RXBufferPtr; @@ -107,6 +108,7 @@ int USUntilPowerOn; bool ForcePowerOn; // MULTIPLAYER SYNC APPARATUS +bool IsMP; bool IsMPClient; u64 NextSync; // for clients: timestamp for next sync point u64 RXTimestamp; @@ -242,6 +244,7 @@ void Reset() BlockBeaconIRQ14 = false; memset(TXSlots, 0, sizeof(TXSlots)); + memset(TXBuffer, 0, sizeof(TXBuffer)); ComStatus = 0; TXCurSlot = -1; RXCounter = 0; @@ -261,6 +264,7 @@ void Reset() USUntilPowerOn = 0; ForcePowerOn = false; + IsMP = false; IsMPClient = false; NextSync = 0; RXTimestamp = 0; @@ -314,6 +318,8 @@ void DoSavestate(Savestate* file) file->Var32(&slot->HalfwordTimeMask); } + file->VarArray(TXBuffer, sizeof(TXBuffer)); + file->VarArray(RXBuffer, sizeof(RXBuffer)); file->Var32(&RXBufferPtr); file->Var32((u32*)&RXTime); @@ -332,6 +338,7 @@ void DoSavestate(Savestate* file) file->Var32((u32*)&USUntilPowerOn); file->Bool32(&ForcePowerOn); + file->Bool32(&IsMP); file->Bool32(&IsMPClient); file->Var64(&NextSync); file->Var64(&RXTimestamp); @@ -530,16 +537,73 @@ void ReportMPReplyErrors(u16 clientfail) } } -void PreTXAdjust(TXSlot* slot, int num) +void TXSendFrame(TXSlot* slot, int num) { u32 noseqno = 0; - if (num == 1) noseqno = (IOPORT(W_TXSlotCmd) & 0x4000); + + if (RAM[slot->Addr + 0x4]) + { + noseqno = 2; + } + else + { + if (num == 1) noseqno = (IOPORT(W_TXSlotCmd) & 0x4000) ? 1:0; + } if (!noseqno) { - *(u16*)&RAM[slot->Addr + 0xC + 22] = IOPORT(W_TXSeqNo) << 4; + if (!(IOPORT(W_TXHeaderCnt) & (1<<2))) + *(u16*)&RAM[slot->Addr + 0xC + 22] = IOPORT(W_TXSeqNo) << 4; IOPORT(W_TXSeqNo) = (IOPORT(W_TXSeqNo) + 1) & 0x0FFF; } + + u16 framectl = *(u16*)&RAM[slot->Addr + 0xC]; + if (framectl & (1<<14)) + { + // WEP frame + // TODO: what happens when sending a WEP frame while WEP processing is off? + // TODO: some form of actual WEP processing? + // for now we just set the WEP FCS to a nonzero value, because some games require it + + if (IOPORT(W_WEPCnt) & (1<<15)) + { + u32 wep_fcs = (slot->Addr + 0xC + slot->Length - 7) & ~0x1; + *(u32*)&RAM[wep_fcs] = 0x22334466; + } + } + + int len = slot->Length; + if ((slot->Addr + len) > 0x1FF4) + len = 0x1FF4 - slot->Addr; + + memcpy(TXBuffer, &RAM[slot->Addr], 12+len); + + if (noseqno == 2) + *(u16*)&TXBuffer[0xC] |= (1<<11); + + switch (num) + { + case 0: + case 2: + case 3: + Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp); + if (!IsMP) WifiAP::SendPacket(TXBuffer, 12+len); + break; + + case 1: + Platform::MP_SendCmd(TXBuffer, 12+len, USTimestamp); + break; + + case 5: + IncrementTXCount(slot); + Platform::MP_SendReply(TXBuffer, 12+len, USTimestamp, IOPORT(W_AIDLow)); + break; + + case 4: + *(u64*)&TXBuffer[0xC + 24] = USCounter; + Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp); + break; + } } void StartTX_LocN(int nslot, int loc) @@ -549,6 +613,8 @@ void StartTX_LocN(int nslot, int loc) if (IOPORT(W_TXSlotLoc1 + (loc*4)) & 0x7000) Log(LogLevel::Warn, "wifi: unusual loc%d bits set %04X\n", loc, IOPORT(W_TXSlotLoc1 + (loc*4))); + slot->Valid = true; + slot->Addr = (IOPORT(W_TXSlotLoc1 + (loc*4)) & 0x0FFF) << 1; slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF; @@ -567,6 +633,8 @@ void StartTX_Cmd() if (IOPORT(W_TXSlotCmd) & 0x3000) Log(LogLevel::Warn,"wifi: !! unusual TXSLOT_CMD bits set %04X\n", IOPORT(W_TXSlotCmd)); + slot->Valid = true; + slot->Addr = (IOPORT(W_TXSlotCmd) & 0x0FFF) << 1; slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF; @@ -595,6 +663,8 @@ void StartTX_Beacon() { TXSlot* slot = &TXSlots[4]; + slot->Valid = true; + slot->Addr = (IOPORT(W_TXSlotBeacon) & 0x0FFF) << 1; slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF; @@ -716,21 +786,13 @@ void SendMPReply(u16 clienttime, u16 clientmask) slot->Valid = false; } - //if (RAM[slot->Addr+4] > 0) - // printf("REPLY RETRY COUNTER %d (%04X)\n", RAM[slot->Addr+4], IOPORT(W_TXSlotReply2)); - // this seems to be set upon IRQ0 // TODO: how does it behave if the packet addr is changed before it gets sent? (maybe just not possible) if (slot->Valid) { - //*(u16*)&RAM[slot->Addr + 0x4] = 0x0001; - IncrementTXCount(slot); - slot->CurPhase = 0; - PreTXAdjust(slot, 5); - int txlen = Platform::MP_SendReply(&RAM[slot->Addr], 12 + slot->Length, USTimestamp, IOPORT(W_AIDLow)); - WIFI_LOG("wifi: sent %d/%d bytes of MP reply\n", txlen, 12 + slot->Length); + TXSendFrame(slot, 5); } else { @@ -804,15 +866,6 @@ bool ProcessTX(TXSlot* slot, int num) u32 curclient = 1 << nclient; - /*if (CheckRX(1)) - { - // we received a reply, mark it as such - // TODO: is any received packet considered a good reply? - // hardware probably requires a specific frame-control and/or destination MAC - - MPClientFail &= ~curclient; - } - else printf("REPLY %04X NOT RECEIVED\n");*/ if (!(MPClientFail & curclient)) MPClientReplyRX(nclient); @@ -831,23 +884,7 @@ bool ProcessTX(TXSlot* slot, int num) SetIRQ(7); if (num == 5) - { - // MP reply slot - // setup needs to be done now as port 098 can get changed in the meantime - SetStatus(8); - - //slot->Addr = (IOPORT(W_TXSlotReply2) & 0x0FFF) << 1; - //slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF; - - /*u8 rate = RAM[slot->Addr + 0x8]; - if (rate == 0x14) slot->Rate = 2; - else slot->Rate = 1;*/ - - // TODO: duration should be set by hardware - // doesn't seem to be important - //RAM[slot->Addr + 0xC + 2] = 0x00F0; - } else SetStatus(3); @@ -866,68 +903,19 @@ bool ProcessTX(TXSlot* slot, int num) slot->CurPhase = 1; slot->CurPhaseTime = len; - u16 framectl = *(u16*)&RAM[slot->Addr + 0xC]; - if (framectl & (1<<14)) - { - // WEP frame - // TODO: what happens when sending a WEP frame while WEP processing is off? - // TODO: some form of actual WEP processing? - // for now we just set the WEP FCS to a nonzero value, because some games require it - - if (IOPORT(W_WEPCnt) & (1<<15)) - { - u32 wep_fcs = (slot->Addr + 0xC + slot->Length - 7) & ~0x1; - *(u32*)&RAM[wep_fcs] = 0x22334466; - } - } - - u64 oldts; - if (num == 4) - { - // beacon timestamp - oldts = *(u64*)&RAM[slot->Addr + 0xC + 24]; - *(u64*)&RAM[slot->Addr + 0xC + 24] = USCounter; - } - - if ((num != 5) && (RAM[slot->Addr+4] > 0)) - Log(LogLevel::Debug, "SLOT %d RETRY COUNTER %d\n", num, RAM[slot->Addr+4]); - // set TX addr IOPORT(W_RXTXAddr) = slot->Addr >> 1; - if (num == 1) + if (num != 5) { - PreTXAdjust(slot, num); - - // send - int txlen = Platform::MP_SendCmd(&RAM[slot->Addr], 12 + slot->Length, USTimestamp); - WIFI_LOG("wifi: sent %d/%d bytes of slot%d packet, addr=%04X, framectl=%04X, %04X %04X\n", - txlen, slot->Length+12, num, slot->Addr, *(u16*)&RAM[slot->Addr + 0xC], - *(u16*)&RAM[slot->Addr + 0x24], *(u16*)&RAM[slot->Addr + 0x26]); - } - else if (num == 5) - { - // send - /*int txlen = Platform::MP_SendReply(&RAM[slot->Addr], 12 + slot->Length, USTimestamp, IOPORT(W_AIDLow)); - WIFI_LOG("wifi: sent %d/%d bytes of slot%d packet, addr=%04X, framectl=%04X, %04X %04X\n", - txlen, slot->Length+12, num, slot->Addr, *(u16*)&RAM[slot->Addr + 0xC], - *(u16*)&RAM[slot->Addr + 0x24], *(u16*)&RAM[slot->Addr + 0x26]);*/ - } - else //if (num != 5) - { - PreTXAdjust(slot, num); - - // send - int txlen = Platform::MP_SendPacket(&RAM[slot->Addr], 12 + slot->Length, USTimestamp); - WIFI_LOG("wifi: sent %d/%d bytes of slot%d packet, addr=%04X, framectl=%04X, %04X %04X\n", - txlen, slot->Length+12, num, slot->Addr, *(u16*)&RAM[slot->Addr + 0xC], - *(u16*)&RAM[slot->Addr + 0x24], *(u16*)&RAM[slot->Addr + 0x26]); + TXSendFrame(slot, num); } // if the packet is being sent via LOC1..3, send it to the AP // any packet sent via CMD/REPLY/BEACON isn't going to have much use outside of local MP if (num == 0 || num == 2 || num == 3) { + u16 framectl = *(u16*)&RAM[slot->Addr + 0xC]; if ((framectl & 0x00FF) == 0x0010) { u16 aid = *(u16*)&RAM[slot->Addr + 0xC + 24 + 4]; @@ -938,16 +926,10 @@ bool ProcessTX(TXSlot* slot, int num) if (IsMPClient) { Log(LogLevel::Info, "[CLIENT] deauth\n"); + IsMP = false; IsMPClient = false; } } - - WifiAP::SendPacket(&RAM[slot->Addr], 12 + slot->Length); - } - - if (num == 4) - { - *(u64*)&RAM[slot->Addr + 0xC + 24] = oldts; } } break; @@ -957,10 +939,6 @@ bool ProcessTX(TXSlot* slot, int num) SetIRQ(7); SetStatus(8); - //SendMPDefaultReply(); - - //slot->Addr = 0; - //slot->Length = 28; slot->CurPhase = 11; slot->CurPhaseTime = 28*4; slot->HalfwordTimeMask = 0xFFFFFFFF; @@ -984,7 +962,6 @@ bool ProcessTX(TXSlot* slot, int num) SetStatus(5); u16 clientmask = *(u16*)&RAM[slot->Addr + 12 + 24 + 2] & 0xFFFE; - //MPNumReplies = NumClients(clientmask); MPReplyTimer = 16 + PreambleLen(slot->Rate); MPClientMask = clientmask; MPClientFail = clientmask; @@ -1085,7 +1062,8 @@ bool ProcessTX(TXSlot* slot, int num) // this is set to indicate which clients failed to reply *(u16*)&RAM[slot->Addr + 0x2] = MPClientFail; - IncrementTXCount(slot); + if (!MPClientFail) + IncrementTXCount(slot); IOPORT(W_TXSeqNo) = (IOPORT(W_TXSeqNo) + 1) & 0x0FFF; @@ -1497,7 +1475,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames if (type == 0) { rxlen = Platform::MP_RecvPacket(RXBuffer, ×tamp); - if (rxlen <= 0) + if ((rxlen <= 0) && (!IsMP)) rxlen = WifiAP::RecvPacket(RXBuffer); } else @@ -1507,6 +1485,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames { // host is gone // TODO: make this more resilient + IsMP = false; IsMPClient = false; } } @@ -1556,6 +1535,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames { Log(LogLevel::Debug, "[CLIENT %01X] host sync=%016llX\n", aid&0xF, timestamp); + IsMP = true; IsMPClient = true; USTimestamp = timestamp; NextSync = RXTimestamp + (framelen * (txrate==0x14 ? 4:8)); @@ -1566,6 +1546,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames } else if (((framectl & 0x00FF) == 0x00C0) && timestamp && macgood && IsMPClient) { + IsMP = false; IsMPClient = false; NextSync = 0; @@ -2251,6 +2232,10 @@ void Write(u32 addr, u16 val) val &= 0x0FFF; break; + case W_TXSlotBeacon: + IsMP = (val & 0x8000) != 0; + break; + case W_TXSlotCmd: if (CmdCounter == 0) val = (val & 0x7FFF) | (IOPORT(W_TXSlotCmd) & 0x8000);