/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.HLE.modules; import static jpcsp.HLE.Modules.sceNetIfhandleModule; import static jpcsp.HLE.kernel.managers.SceUidManager.INVALID_ID; import static jpcsp.HLE.kernel.types.SceNetWlanMessage.WLAN_PROTOCOL_SUBTYPE_CONTROL; import static jpcsp.HLE.kernel.types.SceNetWlanMessage.WLAN_PROTOCOL_SUBTYPE_DATA; import static jpcsp.HLE.kernel.types.SceNetWlanMessage.WLAN_PROTOCOL_TYPE_SONY; import static jpcsp.HLE.modules.SysMemUserForUser.KERNEL_PARTITION_ID; import static jpcsp.hardware.Wlan.MAC_ADDRESS_LENGTH; import java.io.IOException; import java.net.BindException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.LinkedList; import java.util.List; import jpcsp.Emulator; import jpcsp.Memory; import jpcsp.NIDMapper; import jpcsp.Allegrex.compiler.RuntimeContext; import jpcsp.HLE.BufferInfo; import jpcsp.HLE.BufferInfo.LengthInfo; import jpcsp.HLE.BufferInfo.Usage; import jpcsp.HLE.CanBeNull; import jpcsp.HLE.HLEFunction; import jpcsp.HLE.HLEModule; import jpcsp.HLE.HLEUnimplemented; import jpcsp.HLE.TPointer; import jpcsp.HLE.TPointer16; import jpcsp.HLE.TPointer32; import jpcsp.HLE.kernel.Managers; import jpcsp.HLE.kernel.managers.SystemTimeManager; import jpcsp.HLE.kernel.types.IAction; import jpcsp.HLE.kernel.types.SceKernelErrors; import jpcsp.HLE.kernel.types.SceKernelThreadInfo; import jpcsp.HLE.kernel.types.SceKernelVplInfo; import jpcsp.HLE.kernel.types.SceNetIfHandle; import jpcsp.HLE.kernel.types.SceNetIfMessage; import jpcsp.HLE.kernel.types.SceNetWlanMessage; import jpcsp.HLE.kernel.types.SceNetWlanScanInfo; import jpcsp.HLE.kernel.types.pspNetMacAddress; import jpcsp.HLE.Modules; import jpcsp.hardware.Wlan; import jpcsp.network.accesspoint.AccessPoint; import jpcsp.scheduler.Scheduler; import jpcsp.util.Utilities; import org.apache.log4j.Logger; public class sceWlan extends HLEModule { public static Logger log = Modules.getLogger("sceWlan"); public static final int IOCTL_CMD_UNKNOWN_0x2 = 0x2; public static final int IOCTL_CMD_START_SCANNING = 0x34; public static final int IOCTL_CMD_CREATE = 0x35; public static final int IOCTL_CMD_CONNECT = 0x36; public static final int IOCTL_CMD_GET_INFO = 0x37; public static final int IOCTL_CMD_DISCONNECT = 0x38; public static final int IOCTL_CMD_UNKNOWN_0x42 = 0x42; public static final int IOCTL_CMD_ENTER_GAME_MODE = 0x44; public static final int IOCTL_CMD_SET_WEP_KEY = 0x47; public static final int WLAN_MODE_INFRASTRUCTURE = 1; public static final int WLAN_MODE_ADHOC = 2; private static int wlanSocketPort = 30010; private static final int wlanThreadPollingDelayUs = 12000; // 12ms private static final int wlanScanActionDelayUs = 50000; // 50ms private static final int wlanConnectActionDelayUs = 50000; // 50ms private static final int wlanCreateActionDelayUs = 50000; // 50ms private static final int wlanDisconnectActionDelayUs = 50000; // 50ms public static final byte WLAN_CMD_DATA = (byte) 0; public static final byte WLAN_CMD_SCAN_REQUEST = (byte) 1; public static final byte WLAN_CMD_SCAN_RESPONSE = (byte) 2; static private final byte[] dummyOtherMacAddress = new byte[] { 0x10, 0x22, 0x33, 0x44, 0x55, 0x66 }; private static final int[] channels = new int[] { 1, 6, 11 }; private int joinedChannel; private int dummyMessageStep; private TPointer dummyMessageHandleAddr; private DatagramSocket wlanSocket; private TPointer wlanHandleAddr; private int wlanThreadUid; private int unknownValue1; private int unknownValue2; private int unknownValue3; private boolean isGameMode; private List<pspNetMacAddress> activeMacAddresses; private List<GameModeState> gameModeStates; private int gameModeDataLength; private String[] channelSSIDs; private int[] channelModes; private int wlanDropRate; private int wlanDropDuration; private static class GameModeState { public long timeStamp; public boolean updated; public pspNetMacAddress macAddress; public byte[] data; public int dataLength; public GameModeState(pspNetMacAddress macAddress) { this.macAddress = macAddress; dataLength = Modules.sceWlanModule.gameModeDataLength; data = new byte[dataLength]; } public void doUpdate() { updated = true; timeStamp = SystemTimeManager.getSystemTime(); } @Override public String toString() { return String.format("macAddress=%s, updated=%b, timeStamp=%d, dataLength=0x%X, data=%s", macAddress, updated, timeStamp, dataLength, Utilities.getMemoryDump(data, 0, dataLength)); } } private class WlanScanAction implements IAction { private TPointer handleAddr; private TPointer inputAddr; private TPointer outputAddr; private int callCount; public WlanScanAction(TPointer handleAddr, int inputAddr, int outputAddr) { this.handleAddr = handleAddr; this.inputAddr = new TPointer(handleAddr.getMemory(), inputAddr); this.outputAddr = new TPointer(handleAddr.getMemory(), outputAddr); } @Override public void execute() { hleWlanScanAction(handleAddr, inputAddr, outputAddr, this, callCount); callCount++; } } private class WlanConnectAction implements IAction { private TPointer handleAddr; public WlanConnectAction(TPointer handleAddr) { this.handleAddr = handleAddr; } @Override public void execute() { hleWlanConnectAction(handleAddr); } } private class WlanCreateAction implements IAction { private TPointer handleAddr; public WlanCreateAction(TPointer handleAddr) { this.handleAddr = handleAddr; } @Override public void execute() { hleWlanCreateAction(handleAddr); } } private class WlanDisconnectAction implements IAction { private TPointer handleAddr; public WlanDisconnectAction(TPointer handleAddr) { this.handleAddr = handleAddr; } @Override public void execute() { hleWlanDisconnectAction(handleAddr); } } @Override public void start() { wlanThreadUid = INVALID_ID; dummyMessageStep = -1; activeMacAddresses = new LinkedList<pspNetMacAddress>(); gameModeStates = new LinkedList<GameModeState>(); gameModeDataLength = 256; int maxChannel = -1; for (int i = 0; i < channels.length; i++) { maxChannel = Math.max(maxChannel, channels[i]); } channelSSIDs = new String[maxChannel + 1]; channelModes = new int[maxChannel + 1]; joinedChannel = -1; super.start(); } public void hleWlanThread() { if (log.isTraceEnabled()) { log.trace(String.format("hleWlanThread isGameMode=%b", isGameMode)); } if (wlanThreadMustExit()) { if (log.isDebugEnabled()) { log.debug(String.format("Exiting hleWlanThread %s", Modules.ThreadManForUserModule.getCurrentThread())); } Modules.ThreadManForUserModule.hleKernelExitDeleteThread(0); return; } if (isGameMode) { hleWlanSendGameMode(); } while (!wlanThreadMustExit() && hleWlanReceive()) { // Receive all available messages } if (dummyMessageStep > 0) { sendDummyMessage(dummyMessageStep, dummyMessageHandleAddr); dummyMessageStep = 0; } Modules.ThreadManForUserModule.hleKernelDelayThread(wlanThreadPollingDelayUs, true); } private boolean wlanThreadMustExit() { return wlanThreadUid != Modules.ThreadManForUserModule.getCurrentThreadID(); } private void hleWlanScanAction(TPointer handleAddr, TPointer inputAddr, TPointer outputAddr, WlanScanAction action, int callCount) { // Send a scan request packet byte[] scanRequestPacket = new byte[1 + MAC_ADDRESS_LENGTH]; scanRequestPacket[0] = WLAN_CMD_SCAN_REQUEST; System.arraycopy(Wlan.getMacAddress(), 0, scanRequestPacket, 1, MAC_ADDRESS_LENGTH); sendPacket(scanRequestPacket, scanRequestPacket.length); while (hleWlanReceive()) { // Process all pending messages } if (callCount < 20) { // Schedule this action for 20 times (1 second) // before terminating the scan action Emulator.getScheduler().addAction(Scheduler.getNow() + wlanScanActionDelayUs, action); } else { if (log.isDebugEnabled()) { log.debug(String.format("End of scan action:")); for (int ch : channels) { log.debug(String.format("Scan result channel#%d, ssid='%s', mode=%d", ch, channelSSIDs[ch], channelModes[ch])); } } TPointer addr = new TPointer(outputAddr); for (int i = 0; i < 14; i++) { int channel = inputAddr.getValue8(10 + i); if (channel == 0) { break; } if (log.isDebugEnabled()) { log.debug(String.format("Scan on channel %d", channel)); } if (isValidChannel(channel)) { String ssid = channelSSIDs[channel]; if (ssid != null && ssid.length() > 0) { SceNetWlanScanInfo scanInfo = new SceNetWlanScanInfo(); scanInfo.bssid = "Jpcsp"; scanInfo.channel = channel; scanInfo.ssid = ssid; scanInfo.mode = channelModes[channel]; scanInfo.unknown44 = 1000; // Unknown value, need to be != 0 scanInfo.write(addr.getMemory(), addr.getAddress() + 4); addr.setValue32(0, addr.getAddress() + 4 + scanInfo.sizeof()); // Link to next SSID addr.add(4 + scanInfo.sizeof()); } } } if (addr.getAddress() > outputAddr.getAddress()) { addr.setValue32(-96, 0); // Last SSID, no next one } // Signal the sema when the scan has completed SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); } } private void hleWlanConnectAction(TPointer handleAddr) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanConnectAction handleAddr=%s", handleAddr)); } // Signal the sema that the connect/join has completed SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); } private void hleWlanCreateAction(TPointer handleAddr) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanCreateAction handleAddr=%s", handleAddr)); } // Signal the sema that the create has completed SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); } private void hleWlanDisconnectAction(TPointer handleAddr) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanDisconnectAction handleAddr=%s", handleAddr)); } // Signal the sema that the disconnect has completed SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); } private boolean hleWlanReceive() { if (isGameMode) { return hleWlanReceiveGameMode(); } return hleWlanReceiveMessage(); } private boolean createWlanSocket() { if (wlanSocket == null) { boolean retry; do { retry = false; try { wlanSocket = new DatagramSocket(wlanSocketPort); // For broadcast wlanSocket.setBroadcast(true); // Non-blocking (timeout = 0 would mean blocking) wlanSocket.setSoTimeout(1); } catch (BindException e) { if (log.isDebugEnabled()) { log.debug(String.format("createWlanSocket port %d already in use (%s) - retrying with port %d", wlanSocketPort, e, wlanSocketPort + 1)); } // The port is already busy, retrying with another port wlanSocketPort++; retry = true; } catch (SocketException e) { log.error("createWlanSocket", e); } } while (retry); } return wlanSocket != null; } public static int getSocketPort() { return wlanSocketPort; } private int getBroadcastPort(int channel) { if (channel >= 0 && channelModes[channel] == WLAN_MODE_INFRASTRUCTURE) { return AccessPoint.getInstance().getPort(); } return wlanSocketPort ^ 1; } protected void sendPacket(byte[] buffer, int bufferLength) { if (log.isDebugEnabled()) { log.debug(String.format("sendPacket %s", Utilities.getMemoryDump(buffer, 0, bufferLength))); } try { InetSocketAddress broadcastAddress[] = sceNetInet.getBroadcastInetSocketAddress(getBroadcastPort(joinedChannel)); if (broadcastAddress != null) { for (int i = 0; i < broadcastAddress.length; i++) { DatagramPacket packet = new DatagramPacket(buffer, bufferLength, broadcastAddress[i]); wlanSocket.send(packet); } } } catch (UnknownHostException e) { log.error("sendPacket", e); } catch (IOException e) { log.error("sendPacket", e); } } protected void sendDataPacket(byte[] buffer, int bufferLength) { byte[] packetBuffer = new byte[bufferLength + 1 + 32]; int offset = 0; // Add the cmd in front of the data packetBuffer[offset] = WLAN_CMD_DATA; offset++; // Add the joined SSID in front of the data if (joinedChannel >= 0) { Utilities.writeStringNZ(packetBuffer, offset, 32, channelSSIDs[joinedChannel]); } offset += 32; // Add the data System.arraycopy(buffer, 0, packetBuffer, offset, bufferLength); offset += bufferLength; sendPacket(packetBuffer, offset); } private GameModeState getGameModeStat(byte[] macAddress) { GameModeState myGameModeState = null; for (GameModeState gameModeState : gameModeStates) { if (gameModeState.macAddress.equals(macAddress)) { myGameModeState = gameModeState; break; } } return myGameModeState; } private GameModeState getMyGameModeState() { return getGameModeStat(Wlan.getMacAddress()); } private void addActiveMacAddress(pspNetMacAddress macAddress) { if (!sceNetAdhoc.isAnyMacAddress(macAddress.macAddress)) { if (!activeMacAddresses.contains(macAddress)) { activeMacAddresses.add(macAddress); gameModeStates.add(new GameModeState(macAddress)); } } } private boolean isValidChannel(int channel) { for (int i = 0; i < channels.length; i++) { if (channels[i] == channel) { return true; } } return false; } private void setChannelSSID(int channel, String ssid, int mode) { if (ssid != null && ssid.length() > 0 && isValidChannel(channel)) { channelSSIDs[channel] = ssid; channelModes[channel] = mode; } } private void joinChannelSSID(int channel, String ssid, int mode) { setChannelSSID(channel, ssid, mode); joinedChannel = channel; } private void processCmd(byte cmd, byte[] buffer, int offset, int length) { byte[] packetMacAddress = new byte[MAC_ADDRESS_LENGTH]; System.arraycopy(buffer, offset, packetMacAddress, 0, MAC_ADDRESS_LENGTH); offset += MAC_ADDRESS_LENGTH; length -= MAC_ADDRESS_LENGTH; byte[] myMacAddress = Wlan.getMacAddress(); boolean macAddressEqual = true; for (int i = 0; i < MAC_ADDRESS_LENGTH; i++) { if (packetMacAddress[i] != myMacAddress[i]) { macAddressEqual = false; break; } } if (macAddressEqual) { // This packet is coming from myself, ignore it if (log.isDebugEnabled()) { log.debug(String.format("Ignoring packet coming from myself")); } return; } if (cmd == WLAN_CMD_SCAN_REQUEST) { byte[] scanResponse = new byte[1 + MAC_ADDRESS_LENGTH + (32 + 2) * channels.length]; int responseOffset = 0; scanResponse[responseOffset] = WLAN_CMD_SCAN_RESPONSE; responseOffset++; System.arraycopy(Wlan.getMacAddress(), 0, scanResponse, responseOffset, MAC_ADDRESS_LENGTH); responseOffset += MAC_ADDRESS_LENGTH; for (int channel : channels) { scanResponse[responseOffset] = (byte) channel; responseOffset++; scanResponse[responseOffset] = (byte) channelModes[channel]; responseOffset++; Utilities.writeStringNZ(scanResponse, responseOffset, 32, channelSSIDs[channel]); responseOffset += 32; } sendPacket(scanResponse, responseOffset); } else if (cmd == WLAN_CMD_SCAN_RESPONSE) { while (length >= 34) { int channel = buffer[offset]; offset++; length--; int mode = buffer[offset]; offset++; length--; String ssid = Utilities.readStringNZ(buffer, offset, 32); if (ssid != null && ssid.length() > 0) { // Do not overwrite the information for our joined channel if (channel != joinedChannel) { setChannelSSID(channel, ssid, mode); } } offset += 32; length -= 32; } } else { if (log.isInfoEnabled()) { log.info(String.format("processCmd unknown cmd=0x%X, buffer=%s", cmd, Utilities.getMemoryDump(buffer, offset, length))); } } } private boolean hleWlanReceiveMessage() { boolean packetReceived = false; if (!createWlanSocket()) { return packetReceived; } byte[] bytes = new byte[10000]; DatagramPacket packet = new DatagramPacket(bytes, bytes.length); try { wlanSocket.receive(packet); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanReceiveMessage message: %s", Utilities.getMemoryDump(packet.getData(), packet.getOffset(), packet.getLength()))); } packetReceived = true; byte[] dataBytes = packet.getData(); int dataOffset = packet.getOffset(); int dataLength = packet.getLength(); byte cmd = dataBytes[dataOffset]; dataOffset++; dataLength--; if (cmd != WLAN_CMD_DATA) { processCmd(cmd, dataBytes, dataOffset, dataLength); return packetReceived; } String ssid = Utilities.readStringNZ(dataBytes, dataOffset, 32); dataOffset += 32; dataLength -= 32; if (joinedChannel >= 0 && !ssid.equals(channelSSIDs[joinedChannel])) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanReceiveMessage message SSID('%s') not matching the joined SSID('%s')", ssid, channelSSIDs[joinedChannel])); } return packetReceived; } SceNetIfMessage message = new SceNetIfMessage(); final int size = message.sizeof() + dataLength; int allocatedAddr; SceKernelVplInfo vplInfo = Managers.vpl.getVplInfoByName("SceNet"); if (vplInfo != null) { allocatedAddr = Managers.vpl.tryAllocateVpl(vplInfo, size); } else { allocatedAddr = Modules.sceNetIfhandleModule.sceNetMallocInternal(size); } if (allocatedAddr > 0) { Memory mem = Memory.getInstance(); mem.memset(allocatedAddr, (byte) 0, size); RuntimeContext.debugMemory(allocatedAddr, size); TPointer messageAddr = new TPointer(mem, allocatedAddr); TPointer data = new TPointer(mem, messageAddr.getAddress() + message.sizeof()); // Write the received bytes to memory Utilities.writeBytes(data.getAddress(), dataLength, dataBytes, dataOffset); // Write the message header message.dataAddr = data.getAddress(); message.dataLength = dataLength; message.unknown16 = 1; message.unknown18 = 2; message.unknown24 = dataLength; message.write(messageAddr); SceNetWlanMessage wlanMessage = new SceNetWlanMessage(); wlanMessage.read(data); addActiveMacAddress(wlanMessage.srcMacAddress); addActiveMacAddress(wlanMessage.dstMacAddress); if (dataLength > 0) { if (log.isDebugEnabled()) { log.debug(String.format("Notifying received message: %s", message)); log.debug(String.format("Message WLAN: %s", wlanMessage)); log.debug(String.format("Message data: %s", Utilities.getMemoryDump(data.getAddress(), dataLength))); } int sceNetIfEnqueue = NIDMapper.getInstance().getAddressByName("sceNetIfEnqueue"); if (sceNetIfEnqueue != 0) { SceKernelThreadInfo thread = Modules.ThreadManForUserModule.getCurrentThread(); Modules.ThreadManForUserModule.executeCallback(thread, sceNetIfEnqueue, null, true, wlanHandleAddr.getAddress(), messageAddr.getAddress()); } } } } catch (SocketTimeoutException e) { // Timeout can be ignored as we are polling } catch (IOException e) { log.error("hleWlanReceiveMessage", e); } return packetReceived; } private void hleWlanSendGameMode() { GameModeState myGameModeState = getMyGameModeState(); if (myGameModeState == null) { return; } byte[] buffer = new byte[myGameModeState.dataLength + myGameModeState.macAddress.sizeof()]; int offset = 0; System.arraycopy(myGameModeState.macAddress.macAddress, 0, buffer, offset, myGameModeState.macAddress.sizeof()); offset += myGameModeState.macAddress.sizeof(); System.arraycopy(myGameModeState.data, 0, buffer, offset, myGameModeState.dataLength); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanSendGameMode sending packet: %s", Utilities.getMemoryDump(buffer, 0, buffer.length))); } sendDataPacket(buffer, buffer.length); myGameModeState.updated = false; } private boolean hleWlanReceiveGameMode() { boolean packetReceived = false; if (!createWlanSocket()) { return packetReceived; } pspNetMacAddress macAddress = new pspNetMacAddress(); byte[] bytes = new byte[gameModeDataLength + macAddress.sizeof() + 1 + 8]; DatagramPacket packet = new DatagramPacket(bytes, bytes.length); try { wlanSocket.receive(packet); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanReceiveGameMode message: %s", Utilities.getMemoryDump(packet.getData(), packet.getOffset(), packet.getLength()))); } packetReceived = true; byte[] dataBytes = packet.getData(); int dataOffset = packet.getOffset(); int dataLength = packet.getLength(); byte cmd = dataBytes[dataOffset]; dataOffset++; dataLength--; if (cmd != WLAN_CMD_DATA) { processCmd(cmd, dataBytes, dataOffset, dataLength); return packetReceived; } String ssid = Utilities.readStringNZ(dataBytes, dataOffset, 32); dataOffset += 32; dataLength -= 32; if (joinedChannel >= 0 && !ssid.equals(channelSSIDs[joinedChannel])) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanReceiveGameMode message SSID('%s') not matching the joined SSID('%s')", ssid, channelSSIDs[joinedChannel])); } return packetReceived; } macAddress.setMacAddress(dataBytes, dataOffset); dataOffset += macAddress.sizeof(); dataLength -= macAddress.sizeof(); GameModeState gameModeState = getGameModeStat(macAddress.macAddress); if (gameModeState != null) { int length = Math.min(dataLength, gameModeState.dataLength); System.arraycopy(dataBytes, dataOffset, gameModeState.data, 0, length); gameModeState.doUpdate(); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanReceiveGameMode updated GameModeState %s", gameModeState)); } } else { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanReceiveGameMode could not find GameModeState for MAC address %s", macAddress)); } } } catch (SocketTimeoutException e) { // Timeout can be ignored as we are polling } catch (IOException e) { log.error("hleWlanReceiveMessage", e); } return packetReceived; } protected void hleWlanSendMessage(TPointer handleAddr, SceNetIfMessage message) { Memory mem = handleAddr.getMemory(); SceNetWlanMessage wlanMessage = new SceNetWlanMessage(); wlanMessage.read(mem, message.dataAddr); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanSendMessage message: %s: %s", message, Utilities.getMemoryDump(message.getBaseAddress(), message.sizeof()))); log.debug(String.format("hleWlanSendMessage WLAN message : %s", wlanMessage)); log.debug(String.format("hleWlanSendMessage message data: %s", Utilities.getMemoryDump(message.dataAddr + wlanMessage.sizeof(), message.dataLength - wlanMessage.sizeof()))); } if (!createWlanSocket()) { return; } byte[] messageBytes = null; while (true) { if (message.dataLength > 0) { int messageBytesOffset = messageBytes == null ? 0 : messageBytes.length; messageBytes = Utilities.extendArray(messageBytes, message.dataLength); Utilities.readBytes(message.dataAddr, message.dataLength, messageBytes, messageBytesOffset); } if (message.nextDataAddr == 0) { break; } message.read(mem, message.nextDataAddr); } if (messageBytes != null) { sendDataPacket(messageBytes, messageBytes.length); } if (false) { sendDummyMessage(handleAddr, message, wlanMessage); } } public int hleWlanSendCallback(TPointer handleAddr) { SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); Memory mem = handleAddr.getMemory(); TPointer firstMessageAddr = new TPointer(mem, handle.addrFirstMessageToBeSent); SceNetIfMessage message = new SceNetIfMessage(); message.read(firstMessageAddr); RuntimeContext.debugMemory(firstMessageAddr.getAddress(), message.sizeof()); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanSendCallback handleAddr=%s: %s", handleAddr, handle)); } hleWlanSendMessage(handleAddr, message); // Unlink the message from the handle handle.addrFirstMessageToBeSent = message.nextMessageAddr; handle.numberOfMessagesToBeSent--; if (handle.addrFirstMessageToBeSent == 0) { handle.addrLastMessageToBeSent = 0; } handle.write(handleAddr); // Call sceNetMFreem to free the received message int sceNetMFreem = NIDMapper.getInstance().getAddressByName("sceNetMFreem"); if (sceNetMFreem != 0) { Modules.ThreadManForUserModule.executeCallback(null, sceNetMFreem, null, true, firstMessageAddr.getAddress()); } else { Modules.sceNetIfhandleModule.sceNetMFreem(firstMessageAddr); } return 0; } // Called by sceNetIfhandleIfUp public int hleWlanUpCallback(TPointer handleAddr) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanUpCallback handleAddr: %s", Utilities.getMemoryDump(handleAddr.getAddress(), 44))); int handleInternalAddr = handleAddr.getValue32(); if (handleInternalAddr != 0) { log.debug(String.format("hleWlanUpCallback handleInternalAddr: %s", Utilities.getMemoryDump(handleInternalAddr, 320))); } } SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanUpCallback handleAddr=%s: %s", handleAddr, handle)); } wlanHandleAddr = handleAddr; // Add my own MAC address to the active list addActiveMacAddress(new pspNetMacAddress(Wlan.getMacAddress())); // This thread will call hleWlanThread() in a loop SceKernelThreadInfo thread = Modules.ThreadManForUserModule.hleKernelCreateThread("SceWlanHal", ThreadManForUser.WLAN_LOOP_ADDRESS, 39, 2048, 0, 0, KERNEL_PARTITION_ID); if (thread != null) { wlanThreadUid = thread.uid; Modules.ThreadManForUserModule.hleKernelStartThread(thread, 0, 0, 0); } Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); return 0; } // Called by sceNetIfhandleIfDown public int hleWlanDownCallback(TPointer handleAddr) { if (log.isDebugEnabled()) { log.debug(String.format("hleWlanDownCallback handleAddr: %s", Utilities.getMemoryDump(handleAddr.getAddress(), 44))); int handleInternalAddr = handleAddr.getValue32(); if (handleInternalAddr != 0) { log.debug(String.format("hleWlanDownCallback handleInternalAddr: %s", Utilities.getMemoryDump(handleInternalAddr, 320))); } } SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanDownCallback handleAddr=%s: %s", handleAddr, handle)); } // This will force the current wlan thread to exit wlanThreadUid = INVALID_ID; Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); return 0; } public int hleWlanIoctlCallback(TPointer handleAddr, int cmd, TPointer unknown, TPointer32 buffersAddr) { SceNetIfHandle handle = new SceNetIfHandle(); handle.read(handleAddr); Memory mem = Memory.getInstance(); int inputAddr = buffersAddr.getValue(0); int outputAddr = buffersAddr.getValue(4); if (log.isDebugEnabled()) { int inputLength = 0x80; int outputLength = 0x80; switch (cmd) { case IOCTL_CMD_START_SCANNING: inputLength = 0x4C; outputLength = 0x600; break; case IOCTL_CMD_CREATE: inputLength = 0x70; break; case IOCTL_CMD_CONNECT: inputLength = 0x70; break; case IOCTL_CMD_GET_INFO: inputLength = 0x60; break; case IOCTL_CMD_ENTER_GAME_MODE: inputLength = 0x50; outputLength = 0x6; break; case IOCTL_CMD_SET_WEP_KEY: inputLength = 0xA0; break; case IOCTL_CMD_UNKNOWN_0x42: // Has no input and no output parameters break; case IOCTL_CMD_UNKNOWN_0x2: // Has no input and no output parameters break; } log.debug(String.format("hleWlanIoctlCallback cmd=0x%X, handleAddr=%s: %s", cmd, handleAddr, handle)); if (inputAddr != 0 && Memory.isAddressGood(inputAddr) && inputLength > 0) { log.debug(String.format("hleWlanIoctlCallback inputAddr: %s", Utilities.getMemoryDump(inputAddr, inputLength))); RuntimeContext.debugMemory(inputAddr, inputLength); } if (outputAddr != 0 && Memory.isAddressGood(outputAddr) && outputLength > 0) { log.debug(String.format("hleWlanIoctlCallback outputAddr: %s", Utilities.getMemoryDump(outputAddr, outputLength))); RuntimeContext.debugMemory(outputAddr, outputLength); } RuntimeContext.debugMemory(unknown.getAddress(), 32); } boolean signalSema = true; int errorCode = 0; String ssid; String bssid; int ssidLength; int mode; int channel; switch (cmd) { case IOCTL_CMD_START_SCANNING: // Start scanning mode = mem.read32(inputAddr + 0); channel = mem.read8(inputAddr + 10); // If scanning only the joined channel, it seems no // scan is really started as all information are available if (channel == joinedChannel && mem.read8(inputAddr + 11) == 0) { SceNetWlanScanInfo scanInfo = new SceNetWlanScanInfo(); scanInfo.bssid = "Jpcsp"; scanInfo.channel = channel; scanInfo.ssid = channelSSIDs[channel]; scanInfo.mode = channelModes[channel]; scanInfo.unknown44 = 1000; // Unknown value, need to be != 0 scanInfo.write(handleAddr.getMemory(), outputAddr + 4); mem.write32(outputAddr, 0); // Link to next SSID } else { if (channel != joinedChannel) { // When called by sceNetAdhocctlCreate() or sceNetAdhocctlConnect(), // the SSID is available in the inputAddr structure. // When called by sceNetAdhocctlScan(), no SSID is available // in the inputAddr structure. ssidLength = mem.read8(inputAddr + 24); ssid = Utilities.readStringNZ(mem, inputAddr + 28, ssidLength); setChannelSSID(channel, ssid, mode); } if (createWlanSocket()) { signalSema = false; Emulator.getScheduler().addAction(Scheduler.getNow(), new WlanScanAction(handleAddr, inputAddr, outputAddr)); } } break; case IOCTL_CMD_CREATE: // Called by sceNetAdhocctlCreate() channel = mem.read8(inputAddr + 6); ssidLength = mem.read8(inputAddr + 7); ssid = Utilities.readStringNZ(mem, inputAddr + 8, ssidLength); mode = mem.read32(inputAddr + 40); int unknown44 = mem.read32(inputAddr + 44); // 0x64 int unknown62 = mem.read16(inputAddr + 62); // 0x22 if (log.isDebugEnabled()) { log.debug(String.format("hleWlanIoctlCallback cmd=0x%X, channel=%d, ssid='%s', mode=0x%X, unknown44=0x%X, unknown62=0x%X", cmd, channel, ssid, mode, unknown44, unknown62)); } joinChannelSSID(channel, ssid, mode); signalSema = false; Emulator.getScheduler().addAction(Scheduler.getNow() + wlanCreateActionDelayUs, new WlanCreateAction(handleAddr)); break; case IOCTL_CMD_CONNECT: // Called by sceNetAdhocctlConnect() and sceNetAdhocctlJoin() // Receiving as input the SSID structure returned by cmd=0x34 SceNetWlanScanInfo scanInfo = new SceNetWlanScanInfo(); scanInfo.read(mem, inputAddr); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanIoctlCallback cmd=0x%X, channel=%d, ssid='%s', mode=0x%X", cmd, scanInfo.channel, scanInfo.ssid, scanInfo.mode)); } joinChannelSSID(scanInfo.channel, scanInfo.ssid, scanInfo.mode); signalSema = false; Emulator.getScheduler().addAction(Scheduler.getNow() + wlanConnectActionDelayUs, new WlanConnectAction(handleAddr)); break; case IOCTL_CMD_GET_INFO: // Get joined SSID // Remark: returning the joined SSID in the inputAddr! mem.memset(inputAddr, (byte) 0, 40); if (joinedChannel >= 0) { bssid = "Jpcsp"; Utilities.writeStringNZ(mem, inputAddr + 0, 6, bssid); mem.write8(inputAddr + 6, (byte) joinedChannel); mem.write8(inputAddr + 7, (byte) channelSSIDs[joinedChannel].length()); Utilities.writeStringNZ(mem, inputAddr + 8, 32, channelSSIDs[joinedChannel]); } break; case IOCTL_CMD_DISCONNECT: // Disconnect isGameMode = false; joinedChannel = -1; signalSema = false; Emulator.getScheduler().addAction(Scheduler.getNow() + wlanDisconnectActionDelayUs, new WlanDisconnectAction(handleAddr)); break; case IOCTL_CMD_ENTER_GAME_MODE: // Enter Game Mode pspNetMacAddress multicastMacAddress = new pspNetMacAddress(); multicastMacAddress.read(mem, inputAddr + 6); ssidLength = mem.read8(inputAddr + 12); ssid = Utilities.readStringNZ(mem, inputAddr + 14, ssidLength); pspNetMacAddress macAddress = new pspNetMacAddress(); macAddress.read(mem, outputAddr + 0); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanIoctlCallback cmd=0x%X, ssid='%s', multicastMacAddress=%s, macAddress=%s", cmd, ssid, multicastMacAddress, macAddress)); } isGameMode = true; break; case IOCTL_CMD_SET_WEP_KEY: int unknown1 = mem.read32(inputAddr + 0); // Always 0 int unknown2 = mem.read32(inputAddr + 4); // Always 1 if (log.isDebugEnabled()) { log.debug(String.format("hleWlanIoctlCallback unknown1=0x%X, unknown2=0x%X", unknown1, unknown2)); } int wepKeyAddr = inputAddr + 12; // 4 times the same data... for (int i = 0; i < 4; i++) { mode = mem.read32(wepKeyAddr + 0); String wepKey = Utilities.readStringNZ(wepKeyAddr + 4, 13); if (log.isDebugEnabled()) { log.debug(String.format("hleWlanIoctlCallback cmd=0x%X, wekKey#%d: mode=0x%X, wepKey='%s'", cmd, i, mode, wepKey)); } wepKeyAddr += 20; } break; default: log.warn(String.format("hleWlanIoctlCallback unknown cmd=0x%X", cmd)); break; } handle.handleInternal.errorCode = errorCode; handle.write(handleAddr); if (signalSema) { Modules.ThreadManForUserModule.sceKernelSignalSema(handle.handleInternal.ioctlSemaId, 1); } return 0; } static private void sendDummyMessage(int step, TPointer handleAddr) { if (log.isDebugEnabled()) { log.debug(String.format("sendDummyMessage step=%d", step)); } Memory mem = Memory.getInstance(); SceNetIfMessage message = new SceNetIfMessage(); SceNetWlanMessage wlanMessage = new SceNetWlanMessage(); final int size = message.sizeof() + wlanMessage.sizeof() + SceNetWlanMessage.maxContentLength + 0x12; int allocatedAddr; SceKernelVplInfo vplInfo = Managers.vpl.getVplInfoByName("SceNet"); if (vplInfo != null) { allocatedAddr = Managers.vpl.tryAllocateVpl(vplInfo, size); } else { allocatedAddr = Modules.sceNetIfhandleModule.sceNetMallocInternal(size); } if (allocatedAddr <= 0) { return; } RuntimeContext.debugMemory(allocatedAddr, size); mem.memset(allocatedAddr, (byte) 0, size); TPointer messageAddr = new TPointer(mem, allocatedAddr); TPointer data = new TPointer(mem, messageAddr.getAddress() + message.sizeof()); TPointer header = new TPointer(mem, data.getAddress()); TPointer content = new TPointer(mem, header.getAddress() + wlanMessage.sizeof()); int dataLength; int controlType; int contentLength; switch (step) { case 1: controlType = 2; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength; wlanMessage.dstMacAddress = new pspNetMacAddress(Wlan.getMacAddress()); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.clear(contentLength); break; case 2: controlType = 0; contentLength = 0x4C; dataLength = wlanMessage.sizeof() + contentLength; wlanMessage.dstMacAddress = new pspNetMacAddress(new byte[] { -1, -1, -1, -1, -1, -1}); // Broadcast MAC address wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_DATA; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 0; wlanMessage.controlType = controlType; wlanMessage.contentLength = contentLength; content.clear(contentLength); content.setStringNZ(0x34, 5, "Jpcsp"); break; case 3: controlType = 2; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength + 0x12; wlanMessage.dstMacAddress = new pspNetMacAddress(new byte[] { -1, -1, -1, -1, -1, -1}); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.setStringNZ(0, 0x80, "JpcspOther"); content.setValue8(0x80, (byte) 1); content.setValue8(0x81, (byte) 4); content.setUnalignedValue32(0x82, Modules.SysMemUserForUserModule.sceKernelDevkitVersion()); content.setValue8(0x86, (byte) 2); content.setValue8(0x87, (byte) 4); content.setUnalignedValue32(0x88, Modules.SysMemUserForUserModule.sceKernelGetCompiledSdkVersion()); content.setValue8(0x8C, (byte) 3); content.setValue8(0x8D, (byte) 4); content.setUnalignedValue32(0x8E, Modules.SysMemForKernelModule.sceKernelGetModel()); break; case 4: controlType = 3; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength + 0x12; wlanMessage.dstMacAddress = new pspNetMacAddress(Wlan.getMacAddress()); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.clear(contentLength); content.setStringNZ(0xA0, 0x80, "JpcspOther"); content.setValue8(0x120, (byte) 1); content.setValue8(0x121, (byte) 4); content.setUnalignedValue32(0x82, Modules.SysMemUserForUserModule.sceKernelDevkitVersion()); content.setValue8(0x126, (byte) 2); content.setValue8(0x127, (byte) 4); content.setUnalignedValue32(0x88, Modules.SysMemUserForUserModule.sceKernelGetCompiledSdkVersion()); content.setValue8(0x12C, (byte) 3); content.setValue8(0x12D, (byte) 4); content.setUnalignedValue32(0x12E, Modules.SysMemForKernelModule.sceKernelGetModel()); break; case 5: controlType = 4; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength; wlanMessage.dstMacAddress = new pspNetMacAddress(Wlan.getMacAddress()); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.clear(contentLength); break; case 6: controlType = 5; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength; wlanMessage.dstMacAddress = new pspNetMacAddress(Wlan.getMacAddress()); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.clear(contentLength); break; case 7: controlType = 6; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength; wlanMessage.dstMacAddress = new pspNetMacAddress(Wlan.getMacAddress()); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.clear(contentLength); break; case 8: controlType = 8; // possible values: [1..8] contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; dataLength = wlanMessage.sizeof() + contentLength; wlanMessage.dstMacAddress = new pspNetMacAddress(Wlan.getMacAddress()); wlanMessage.srcMacAddress = new pspNetMacAddress(dummyOtherMacAddress); wlanMessage.protocolType = WLAN_PROTOCOL_TYPE_SONY; wlanMessage.protocolSubType = WLAN_PROTOCOL_SUBTYPE_CONTROL; // 1 or 2 -> 1 will trigger sceNetIfhandleModule.unknownCallback3, 2 will trigger sceNetIfhandleModule.unknownCallback1 wlanMessage.unknown16 = 1; // possible value: only 1 wlanMessage.controlType = controlType; wlanMessage.contentLength = SceNetWlanMessage.contentLengthFromMessageType[controlType]; content.clear(contentLength); break; default: dataLength = 0; break; } wlanMessage.write(header); message.dataAddr = data.getAddress(); message.dataLength = dataLength; message.unknown18 = 0; message.unknown24 = dataLength; message.write(messageAddr); if (dataLength > 0) { if (log.isDebugEnabled()) { log.debug(String.format("Sending dummy message: %s", message)); log.debug(String.format("Dummy message data: %s", Utilities.getMemoryDump(data.getAddress(), dataLength))); } int sceNetIfEnqueue = NIDMapper.getInstance().getAddressByName("sceNetIfEnqueue"); if (sceNetIfEnqueue != 0) { SceKernelThreadInfo thread = Modules.ThreadManForUserModule.getCurrentThread(); Modules.ThreadManForUserModule.executeCallback(thread, sceNetIfEnqueue, null, true, handleAddr.getAddress(), messageAddr.getAddress()); } } } private void sendDummyMessage(TPointer handleAddr, SceNetIfMessage sentMessage, SceNetWlanMessage sentWlanMessage) { int step = 0; if (false) { step = 1; } else if (false) { step = 2; } else if (dummyMessageStep < 0 && !sentWlanMessage.dstMacAddress.equals(dummyOtherMacAddress)) { step = 3; } else if (sentWlanMessage.controlType == 3) { step = 5; } else if (sentWlanMessage.controlType == 4) { step = 5; } else if (sentWlanMessage.controlType == 5) { step = 7; } else if (sentWlanMessage.controlType == 7) { step = 8; } else { step = 0; } if (log.isDebugEnabled()) { log.debug(String.format("Adding action step=%d for sending dummy message", step)); } dummyMessageStep = step; dummyMessageHandleAddr = handleAddr; } private class AfterNetCreateIfhandleEtherAction implements IAction { private SceKernelThreadInfo thread; private TPointer handleAddr; public AfterNetCreateIfhandleEtherAction(SceKernelThreadInfo thread, TPointer handleAddr) { this.thread = thread; this.handleAddr = handleAddr; } @Override public void execute() { afterNetCreateIfhandleEtherAction(thread, handleAddr); } } private void afterNetCreateIfhandleEtherAction(SceKernelThreadInfo thread, TPointer handleAddr) { int tempMem = sceNetIfhandleModule.sceNetMallocInternal(32); if (tempMem <= 0) { return; } int macAddressAddr = tempMem; int interfaceNameAddr = tempMem + 8; pspNetMacAddress macAddress = new pspNetMacAddress(Wlan.getMacAddress()); macAddress.write(handleAddr.getMemory(), macAddressAddr); Utilities.writeStringZ(handleAddr.getMemory(), interfaceNameAddr, "wlan"); int sceNetAttachIfhandleEther = NIDMapper.getInstance().getAddressByName("sceNetAttachIfhandleEther"); if (sceNetAttachIfhandleEther == 0) { return; } Modules.ThreadManForUserModule.executeCallback(thread, sceNetAttachIfhandleEther, null, true, handleAddr.getAddress(), macAddressAddr, interfaceNameAddr); } private int createWlanInterface() { SceNetIfHandle handle = new SceNetIfHandle(); handle.callbackArg4 = 0x11040404; // dummy callback value handle.upCallbackAddr = ThreadManForUser.WLAN_UP_CALLBACK_ADDRESS; handle.downCallbackAddr = ThreadManForUser.WLAN_DOWN_CALLBACK_ADDRESS; handle.sendCallbackAddr = ThreadManForUser.WLAN_SEND_CALLBACK_ADDRESS; handle.ioctlCallbackAddr = ThreadManForUser.WLAN_IOCTL_CALLBACK_ADDRESS; int handleMem = sceNetIfhandleModule.sceNetMallocInternal(handle.sizeof()); if (handleMem < 0) { return handleMem; } TPointer handleAddr = new TPointer(Memory.getInstance(), handleMem); handle.write(handleAddr); RuntimeContext.debugMemory(handleAddr.getAddress(), handle.sizeof()); int sceNetCreateIfhandleEther = NIDMapper.getInstance().getAddressByName("sceNetCreateIfhandleEther"); if (sceNetCreateIfhandleEther == 0) { int result = sceNetIfhandleModule.hleNetCreateIfhandleEther(handleAddr); if (result < 0) { return result; } result = sceNetIfhandleModule.hleNetAttachIfhandleEther(handleAddr, new pspNetMacAddress(Wlan.getMacAddress()), "wlan"); if (result < 0) { return result; } } else { SceKernelThreadInfo thread = Modules.ThreadManForUserModule.getCurrentThread(); Modules.ThreadManForUserModule.executeCallback(thread, sceNetCreateIfhandleEther, new AfterNetCreateIfhandleEtherAction(thread, handleAddr), false, handleAddr.getAddress()); } return 0; } /** * Get the Ethernet Address of the wlan controller * * @param etherAddr - pointer to a buffer of u8 (NOTE: it only writes to 6 bytes, but * requests 8 so pass it 8 bytes just in case) * @return 0 on success, < 0 on error */ @HLEFunction(nid = 0x0C622081, version = 150, checkInsideInterrupt = true) public int sceWlanGetEtherAddr(@BufferInfo(lengthInfo=LengthInfo.fixedLength, length=6, usage=Usage.out) TPointer etherAddr) { pspNetMacAddress macAddress = new pspNetMacAddress(); macAddress.setMacAddress(Wlan.getMacAddress()); macAddress.write(etherAddr); if (log.isDebugEnabled()) { log.debug(String.format("sceWlanGetEtherAddr returning %s", macAddress)); } return 0; } /** * Determine the state of the Wlan power switch * * @return 0 if off, 1 if on */ @HLEFunction(nid = 0xD7763699, version = 150) public int sceWlanGetSwitchState() { return Wlan.getSwitchState(); } /** * Determine if the wlan device is currently powered on * * @return 0 if off, 1 if on */ @HLEFunction(nid = 0x93440B11, version = 150) public int sceWlanDevIsPowerOn() { return Wlan.getSwitchState(); } @HLEUnimplemented @HLEFunction(nid = 0x482CAE9A, version = 150) public int sceWlanDevAttach() { // Has no parameters int result = createWlanInterface(); if (result < 0) { log.error(String.format("Cannot create the WLAN Interface: 0x%08X", result)); return result; } return 0; } @HLEUnimplemented @HLEFunction(nid = 0xC9A8CAB7, version = 150) public int sceWlanDevDetach() { // Has no parameters return 0; } @HLEUnimplemented @HLEFunction(nid = 0x8D5F551B, version = 150) public int sceWlanDrv_lib_8D5F551B(int unknown) { return 0; } @HLEUnimplemented @HLEFunction(nid = 0x749B813A, version = 150) public int sceWlanSetHostDiscover(int unknown1, @CanBeNull @BufferInfo(lengthInfo=LengthInfo.fixedLength, length=40, usage=Usage.in) TPointer unknown2) { return 0; } @HLEUnimplemented @HLEFunction(nid = 0xFE8A0B46, version = 150) public int sceWlanSetWakeUp(int unknown1, @CanBeNull @BufferInfo(lengthInfo=LengthInfo.fixedLength, length=40, usage=Usage.in) TPointer unknown2) { return 0; } @HLEFunction(nid = 0x5E7C8D94, version = 150) public boolean sceWlanDevIsGameMode() { return isGameMode; } @HLEFunction(nid = 0x5ED4049A, version = 150) public int sceWlanGPPrevEstablishActive(pspNetMacAddress macAddress) { int index = 0; for (pspNetMacAddress activeMacAddress : activeMacAddresses) { if (activeMacAddress.equals(macAddress.macAddress)) { return index; } index++; } return -1; } /* * Called by sceNetAdhocGameModeUpdateReplica() */ @HLEFunction(nid = 0xA447103A, version = 150) public int sceWlanGPRecv(int id, @BufferInfo(lengthInfo=LengthInfo.nextParameter, usage=Usage.out) TPointer buffer, int bufferLength, @CanBeNull @BufferInfo(lengthInfo=LengthInfo.variableLength, usage=Usage.out) TPointer updateInfoAddr) { if (!isGameMode) { return SceKernelErrors.ERROR_WLAN_NOT_IN_GAMEMODE; } if (id < 0 || id >= gameModeStates.size()) { return SceKernelErrors.ERROR_WLAN_BAD_PARAMS; } if (bufferLength < 0 || bufferLength > gameModeDataLength) { return SceKernelErrors.ERROR_WLAN_BAD_PARAMS; } GameModeState gameModeState = gameModeStates.get(id); int size = Math.min(gameModeState.dataLength, bufferLength); Utilities.writeBytes(buffer.getAddress(), size, gameModeState.data, 0); if (updateInfoAddr.isNotNull()) { sceNetAdhoc.GameModeUpdateInfo updateInfo = new sceNetAdhoc.GameModeUpdateInfo(); updateInfo.read(updateInfoAddr); updateInfo.updated = gameModeState.updated ? 1 : 0; updateInfo.timeStamp = gameModeState.timeStamp; updateInfo.write(updateInfoAddr); } return 0; } /* * Called by sceNetAdhocGameModeUpdateMaster() */ @HLEFunction(nid = 0xB4D7CB74, version = 150) public int sceWlanGPSend(int unknown, @BufferInfo(lengthInfo=LengthInfo.nextParameter, usage=Usage.in) TPointer buffer, int bufferLength) { if (!isGameMode) { return SceKernelErrors.ERROR_WLAN_NOT_IN_GAMEMODE; } if (bufferLength < 0 || bufferLength > gameModeDataLength) { return SceKernelErrors.ERROR_WLAN_BAD_PARAMS; } GameModeState myGameModeState = getMyGameModeState(); if (myGameModeState == null) { log.error(String.format("sceWlanGPSend not found my GameModeState!")); return -1; } Utilities.readBytes(buffer.getAddress(), bufferLength, myGameModeState.data, 0); myGameModeState.doUpdate(); return 0; } @HLEUnimplemented @HLEFunction(nid = 0x2D0FAE4E, version = 150) public int sceWlanDrv_lib_2D0FAE4E(@BufferInfo(lengthInfo=LengthInfo.fixedLength, length=6, usage=Usage.in) TPointer16 unknown) { unknownValue1 = unknown.getValue(0); unknownValue2 = unknown.getValue(2); unknownValue3 = unknown.getValue(4); return 0; } @HLEUnimplemented @HLEFunction(nid = 0x56F467CA, version = 150) public int sceWlanDrv_lib_56F467CA(@BufferInfo(lengthInfo=LengthInfo.fixedLength, length=6, usage=Usage.out) TPointer16 unknown) { unknown.setValue(0, unknownValue1); unknown.setValue(2, unknownValue2); unknown.setValue(4, unknownValue3); return 0; } @HLEUnimplemented @HLEFunction(nid = 0x5BAA1FE5, version = 150) public int sceWlanDrv_lib_5BAA1FE5(int unknown1, int unknown2) { return 0; } /** * Checks if a packet has to be dropped according * to the parameters defined by sceNetSetDropRate. * * @return true if the packet should be dropped * false if the packet should be processed */ @HLEFunction(nid = 0x2519EAA7, version = 150) public boolean sceWlanIsPacketToBeDropped() { // Has no parameters return false; } @HLEFunction(nid = 0x325F7172, version = 150) public int sceWlanSetDropRate(int dropRate, int dropDuration) { wlanDropRate = dropRate; wlanDropDuration = dropDuration; return 0; } @HLEFunction(nid = 0xB6A9700D, version = 150) public int sceWlanGetDropRate(@CanBeNull TPointer32 dropRateAddr, @CanBeNull TPointer32 dropDurationAddr) { dropRateAddr.setValue(wlanDropRate); dropDurationAddr.setValue(wlanDropDuration); return 0; } }