From 6e8850c90304360cbfcb1129f6527fc6de3e485c Mon Sep 17 00:00:00 2001
From: luigi__ <luigi__@users.sf.net>
Date: Sun, 23 Aug 2009 22:01:54 +0000
Subject: [PATCH] Wifi: more work on packet reception. NSMB two-card
 multiplayer now half-works. Luigi sees Mario, but Mario doesn't see Luigi :(

---
 desmume/src/wifi.cpp | 152 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 113 insertions(+), 39 deletions(-)

diff --git a/desmume/src/wifi.cpp b/desmume/src/wifi.cpp
index 96e419062..66c2d2ba3 100644
--- a/desmume/src/wifi.cpp
+++ b/desmume/src/wifi.cpp
@@ -54,6 +54,8 @@ socket_t wifi_socket = INVALID_SOCKET;
 sockaddr_t sendAddr;
 pcap_t *wifi_bridge = NULL;
 
+const u8 BroadcastMAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
 #endif
 
 wifimac_t wifiMac;
@@ -68,6 +70,7 @@ wifimac_t wifiMac;
  *******************************************************************************/
 
 u8 FW_Mac[6] 			= { 0x00, 0x09, 0xBF, 0x12, 0x34, 0x56 } ;
+
 const u8 FW_WIFIInit[32] 		= { 0x02,0x00,  0x17,0x00,  0x26,0x00,  0x18,0x18,
 							0x48,0x00,  0x40,0x48,  0x58,0x00,  0x42,0x00,
 							0x40,0x01,  0x64,0x80,  0xE0,0xE0,  0x43,0x24,
@@ -677,10 +680,59 @@ void WIFI_Reset()
 	wifiCom->Reset();
 }
 
+
+INLINE u16 WIFI_GetRXFlags(u8* packet)
+{
+	u16 ret = 0x0010;
+	u16 frameCtl = *(u16*)&packet[0];
+
+	switch(frameCtl & 0x000C)
+	{
+	case 0x0000:
+		if ((frameCtl & 0x00F0) == 0x0080)
+			ret |= 0x0001;
+		break;
+
+	case 0x0004:
+		ret |= 0x0005;
+		break;
+
+	case 0x0008:
+		ret |= 0x0008;
+		break;
+	}
+
+	if (frameCtl & 0x0400)
+		ret |= 0x0100;
+
+	if (!memcmp(&packet[16], &wifiMac.bss.bytes[0], 6))
+		ret |= 0x8000;
+
+	return ret;
+}
+
+INLINE void WIFI_MakeRXHeader(u8* buf, u16 flags, u16 xferRate, u16 len, u8 maxRSSI, u8 minRSSI)
+{
+	*(u16*)&buf[0] = flags;
+
+	// Unknown (usually 0x0400)
+	buf[2] = 0x40;
+	buf[3] = 0x00;
+
+	// Time since last packet??? Random??? Left unchanged???
+	buf[4] = 0x01;
+	buf[5] = 0x00;
+
+	*(u16*)&buf[6] = xferRate;
+
+	*(u16*)&buf[8] = WIFI_alignedLen(len);
+
+	buf[10] = maxRSSI;
+	buf[11] = minRSSI;
+}
+
 static void WIFI_RXPutWord(u16 val)
 {
-//	printf("wifi: rx circbuf write attempt: rxcnt=%04X, rxread=%04X, rxwrite=%04X\n", 
-//		wifiMac.RXCnt, wifiMac.RXReadCursor, wifiMac.RXHWWriteCursor);
 	/* abort when RX data queuing is not enabled */
 	if (!(wifiMac.RXCnt & 0x8000)) return ;
 	/* abort when ringbuffer is full */
@@ -731,6 +783,10 @@ static void WIFI_TXStart(u8 slot)
 				slot);
 			return;
 		}
+
+		// Align packet length
+		txLen = WIFI_alignedLen(txLen);
+
 		// unsupported txRate
 		switch (wifiMac.circularBuffer[address+4] & 0xFF)
 		{
@@ -743,7 +799,9 @@ static void WIFI_TXStart(u8 slot)
 				return;
 		}
 
-		// FIXME: calculate FCS
+		// Calculate and set FCS
+		u32 crc32 = WIFI_calcCRC32((u8*)&wifiMac.circularBuffer[address + 6], txLen - 4);
+		*(u32*)&wifiMac.circularBuffer[address + 6 + ((txLen-4) >> 1)] = crc32;
 
 		WIFI_triggerIRQ(WIFI_IRQ_SENDSTART) ;
 
@@ -788,6 +846,9 @@ static void WIFI_BeaconTXStart()
 			return;
 		}
 
+		// Align packet length
+		txLen = WIFI_alignedLen(txLen);
+
 		// unsupported txRate
 		switch (wifiMac.circularBuffer[address+4] & 0xFF)
 		{
@@ -798,7 +859,9 @@ static void WIFI_BeaconTXStart()
 				return;
 		}
 
-		// FIXME: calculate FCS
+		// Calculate and set FCS
+		u32 crc32 = WIFI_calcCRC32((u8*)&wifiMac.circularBuffer[address + 6], txLen - 4);
+		*(u32*)&wifiMac.circularBuffer[address + 6 + ((txLen-4) >> 1)] = crc32;
 
 		WIFI_triggerIRQ(WIFI_IRQ_SENDSTART);
 		wifiCom->SendPacket((u8*)&wifiMac.circularBuffer[address+6], txLen);
@@ -1328,7 +1391,7 @@ void WIFI_usTrigger()
 	}
 	if ((wifiMac.ucmpEnable) && (wifiMac.ucmp == wifiMac.usec))
 	{
-			WIFI_triggerIRQ(WIFI_IRQ_TIMEBEACON) ;
+		WIFI_triggerIRQ(WIFI_IRQ_TIMEBEACON) ;
 	}
 
 	if((wifiMac.usec & 3) == 0)
@@ -1447,7 +1510,7 @@ void Adhoc_Reset()
 
 void Adhoc_SendPacket(u8* packet, u32 len)
 {
-	u32 packetLen = 12 + WIFI_alignedLen(len);
+	u32 packetLen = 12 + len;
 	u32 frameLen = sizeof(Adhoc_FrameHeader) + packetLen;
 
 	u8* frame = new u8[frameLen];
@@ -1473,7 +1536,7 @@ void Adhoc_usTrigger()
 {
 	wifiMac.Adhoc.usecCounter++;
 
-	// Check every millisecond (approx.) if we received a packet
+	// Check every millisecond if we received a packet
 	if (!(wifiMac.Adhoc.usecCounter & 1023))
 	{
 		fd_set fd;
@@ -1489,6 +1552,9 @@ void Adhoc_usTrigger()
 			sockaddr_t fromAddr;
 			int fromLen = sizeof(sockaddr_t);
 			u8 buf[1536];
+			u8* ptr;
+			u16 packetLen;
+
 			int nbytes = recvfrom(wifi_socket, (char*)buf, 1536, 0, &fromAddr, &fromLen);
 
 			// No packet arrived (or there was an error)
@@ -1501,7 +1567,8 @@ void Adhoc_usTrigger()
 				(u8)fromAddr.sa_data[4], (u8)fromAddr.sa_data[5],
 				ntohs(*(u16*)&fromAddr.sa_data[0]));
 
-			Adhoc_FrameHeader header = *(Adhoc_FrameHeader*)&buf[0];
+			ptr = buf;
+			Adhoc_FrameHeader header = *(Adhoc_FrameHeader*)&ptr[0];
 			
 			// Check the magic string in header
 			if (strncmp(header.magic, ADHOC_MAGIC, 8) != 0)
@@ -1511,8 +1578,36 @@ void Adhoc_usTrigger()
 			if (header.version != ADHOC_PROTOCOL_VERSION)
 				return;
 
-			// TODO: handle the packet!
-			//WIFI_LOG(3, "Ad-hoc: packet is interesting!\n");
+			packetLen = header.packetLen;
+			ptr += sizeof(Adhoc_FrameHeader);
+
+			// If the packet is for us, send it to the wifi core
+			if (memcmp(&ptr[10], &wifiMac.mac.bytes[0], 6))
+			{
+				if ((!memcmp(&ptr[16], &BroadcastMAC[0], 6)) ||
+					(!memcmp(&ptr[16], &wifiMac.bss.bytes[0], 6)) ||
+					(!memcmp(&wifiMac.bss.bytes[0], &BroadcastMAC[0], 6)))
+				{
+					WIFI_triggerIRQ(WIFI_IRQ_RECVSTART);
+
+					u8* packet = new u8[12 + packetLen];
+
+					WIFI_MakeRXHeader(packet, WIFI_GetRXFlags(ptr), 20, packetLen, 255, 2);
+					memcpy(&packet[12], &ptr[0], packetLen);
+
+				//	u32 crc32 = WIFI_calcCRC32(ptr, packetLen - 4);
+				//	*(u32*)&ptr[packetLen - 4] = crc32;
+
+					for (int i = 0; i < (12 + packetLen); i += 2)
+					{
+						u16 word = *(u16*)&packet[i];
+						WIFI_RXPutWord(word);
+					}
+
+					wifiMac.RXHWWriteCursorReg = ((wifiMac.RXHWWriteCursor + 1) & (~1));
+					WIFI_triggerIRQ(WIFI_IRQ_RECVCOMPLETE);
+				}
+			}
 		}
 	}
 }
@@ -1665,33 +1760,12 @@ void SoftAP_Reset()
 	wifiMac.SoftAP.curPacketSending = FALSE;
 }
 
-INLINE void SoftAP_MakeRXHeader(u16 flags, u16 xferRate, u16 len, u8 maxRSSI, u8 minRSSI)
-{
-	*(u16*)&wifiMac.SoftAP.curPacket[0] = flags;
-
-	// Unknown (usually 0x0400)
-	wifiMac.SoftAP.curPacket[2] = 0x40;
-	wifiMac.SoftAP.curPacket[3] = 0x00;
-
-	// Time since last packet??? Random??? Left unchanged???
-	wifiMac.SoftAP.curPacket[4] = 0x01;
-	wifiMac.SoftAP.curPacket[5] = 0x00;
-
-	*(u16*)&wifiMac.SoftAP.curPacket[6] = xferRate;
-
-	*(u16*)&wifiMac.SoftAP.curPacket[8] = WIFI_alignedLen(len);
-
-	wifiMac.SoftAP.curPacket[10] = maxRSSI;
-	wifiMac.SoftAP.curPacket[11] = minRSSI;
-}
-
 void SoftAP_SendPacket(u8 *packet, u32 len)
 {
-	u32 alignedLen = WIFI_alignedLen(len);
 	u16 frameCtl = *(u16*)&packet[12];
 
-	WIFI_LOG(3, "SoftAP: Received a packet of length %i bytes (%i aligned). Frame control = %04X\n",
-		len, alignedLen, frameCtl);
+	WIFI_LOG(3, "SoftAP: Received a packet of length %i bytes. Frame control = %04X\n",
+		len, frameCtl);
 
 	switch((frameCtl >> 2) & 0x3)
 	{
@@ -1711,7 +1785,7 @@ void SoftAP_SendPacket(u8 *packet, u32 len)
 					// config util expects this length to be the length of the IEEE header and
 					// the frame body AND the FCS. Actually, it expects WRCSR to be equal to
 					// (READCSR + 12 + packet_length).
-					SoftAP_MakeRXHeader(0x0010, 20, packetLen, 0, 0);
+					WIFI_MakeRXHeader(wifiMac.SoftAP.curPacket, 0x0010, 20, packetLen, 0, 0);
 
 					// Copy the probe response template
 					memcpy(&wifiMac.SoftAP.curPacket[12], SoftAP_ProbeResponse, packetLen);
@@ -1740,7 +1814,7 @@ void SoftAP_SendPacket(u8 *packet, u32 len)
 					u32 totalLen = (packetLen + 12);
 
 					// Make the RX header
-					SoftAP_MakeRXHeader(0x0010, 20, packetLen, 0, 0);
+					WIFI_MakeRXHeader(wifiMac.SoftAP.curPacket, 0x0010, 20, packetLen, 0, 0);
 
 					// Copy the authentication frame template
 					memcpy(&wifiMac.SoftAP.curPacket[12], SoftAP_AuthFrame, packetLen);
@@ -1765,7 +1839,7 @@ void SoftAP_SendPacket(u8 *packet, u32 len)
 					u32 totalLen = (packetLen + 12);
 
 					// Make the RX header
-					SoftAP_MakeRXHeader(0x0010, 20, packetLen, 0, 0);
+					WIFI_MakeRXHeader(wifiMac.SoftAP.curPacket, 0x0010, 20, packetLen, 0, 0);
 
 					// Copy the association response template
 					memcpy(&wifiMac.SoftAP.curPacket[12], SoftAP_AssocResponse, packetLen);
@@ -1791,7 +1865,7 @@ void SoftAP_SendPacket(u8 *packet, u32 len)
 		{
 			// We convert the packet into an Ethernet packet
 
-			u32 eflen = (alignedLen - 4 - 30 + 14);
+			u32 eflen = (len - 4 - 30 + 14);
 			u8 *ethernetframe = new u8[eflen];
 
 			// Destination address
@@ -1815,7 +1889,7 @@ void SoftAP_SendPacket(u8 *packet, u32 len)
 			ethernetframe[13] = packet[43];
 
 			// Frame body
-			memcpy((ethernetframe + 14), (packet + 44), (alignedLen - 30 - 4));
+			memcpy((ethernetframe + 14), (packet + 44), (len - 30 - 4));
 
 			// Checksum 
 			// TODO ?
@@ -1835,7 +1909,7 @@ INLINE void SoftAP_SendBeacon()
 	u32 totalLen = (packetLen + 12);
 
 	// Make the RX header
-	SoftAP_MakeRXHeader(0x0011, 20, packetLen, 0, 0);
+	WIFI_MakeRXHeader(wifiMac.SoftAP.curPacket, 0x0011, 20, packetLen, 0, 0);
 
 	// Copy the beacon template
 	memcpy(&wifiMac.SoftAP.curPacket[12], SoftAP_Beacon, packetLen);