-------------------------------- PS2LINK OPERATION AND PROTOCOL Dan Peori (peori@oopo.net) Current as of: ps2link v1.22 -------------------------------- Communication with ps2link takes place on three ports. I'm not entirely sure why, but it does. One udp port is used to send commands to ps2link in the form of command packets. A tcp port is used to receive requests and send responses during program runtime. And another udp port is used to receive log text from ps2link for debug or informational purposes. PS2LINK PORT NUMBERS Command (UDP) 0x4712 - One way communication to send commands. Request (TCP) 0x4711 - Two way communication to serve requests. Log (UDP) 0x4712 - One way communication to receive log text. Typical operation is to send a command, then enter a loop that waits for requests and log text from ps2link. If at any time contact is lost with ps2link, close and exit. Extra points are given if you close the command port during the loop to allow other commands to be sent to ps2link while your client is handling requests. ------------------------- PS2LINK COMMAND PACKETS ------------------------- When ps2link is finished booting, it waits for a command from a client to tell it what to do. These are simple commands sent as single packets for executing programs, resetting ps2link or other things. This list may grow as time goes on and new functionality is added to ps2link. ---------------------------- 0xBABE0201 (reset command) ---------------------------- Tell ps2link to reset and reload back to its information screen. PACKET STRUCTURE struct { int number; short length; } command; PACKET CONTENTS command.number = htonl(0xBABE0201); command.length = htons(sizeof(command)); ------------------------------ 0xBABE0202 (execiop command) ------------------------------ Tell ps2link to load and run the given program (IRX) on the IOP. PACKET STRUCTURE struct { int number; short length; int argc; char argv[256]; } command; PACKET CONTENTS command.number = htonl(0xBABE0202); command.length = htons(sizeof(command)); command.argc = htonl(argc); if (argv) { memcpy(command.argv, argv, 256); } ----------------------------- 0xBABE0203 (execee command) ----------------------------- Tell ps2link to load and run the given program (ELF) on the EE. PACKET STRUCTURE struct { int number; short length; int argc; char argv[256]; } command; PACKET CONTENTS command.number = htonl(0xBABE0203); command.length = htons(sizeof(command)); command.argc = htonl(argc); if (argv) { memcpy(command.argv, argv, 256); } ------------------------------- 0xBABE0204 (poweroff command) ------------------------------- Tell ps2link to power off the PS2. PACKET STRUCTURE struct { int number; short length; } command; PACKET CONTENTS command.number = htonl(0xBABE0204); command.length = htons(sizeof(command)); ------------------------------ 0xBABE0207 (dumpmem command) ------------------------------ Tell ps2link to dump memory starting at offset and of size bytes into the file specified by pathname. PACKET STRUCTURE struct { int number; short length; int offset, size; char pathname[256]; } command; PACKET CONTENTS command.number = htonl(0xBABE0207); command.length = htons(sizeof(command)); command.offset = htonl(offset); command.size = htonl(size); if (pathname) { strncpy(command.pathname, pathname, 256); } ------------------------------ 0xBABE0208 (startvu command) ------------------------------ Tell the specified vector unit to start operation. PACKET STRUCTURE struct { int number; short length; int vu; } command; PACKET CONTENTS command.number = htonl(0xBABE0208); command.length = htons(sizeof(command)); command.vu = htonl(vu); ----------------------------- 0xBABE0209 (stopvu command) ----------------------------- Tell the specified vector unit to stop operation. PACKET STRUCTURE struct { int number; short length; int vu; } command; PACKET CONTENTS command.number = htonl(0xBABE0209); command.length = htons(sizeof(command)); command.vu = htonl(vu); ------------------------------ 0xBABE020A (dumpreg command) ------------------------------ Tell ps2link to dump the specified register type into the file specified by pathname. PACKET STRUCTURE struct { int number; short length; int type; char pathname[256]; } command; REGISTER TYPES DMAC (0), INTC (1), Timer (2), GS (3), SIF (4), FIFO (5), GIF (6), VIF0 (7), VIF1 (8) IPU (9), all registers (10), VU0 (11), VU1 (12) PACKET CONTENTS command.number = htonl(0xBABE020A); command.length = htons(sizeof(command)); command.type = htonl(type); if (pathname) { strncpy(command.pathname, pathname, 256); } ----------------------------- 0xBABE020B (gsexec command) ----------------------------- Tell ps2link to load and send the file specified by pathname to the GS. PACKET STRUCTURE struct { int number; short length; int size; char pathname[256]; } command; PACKET CONTENTS command.number = htonl(0xBABE020B); command.length = htons(sizeof(command)); command.size = htonl(size); if (pathname) { strncpy(command.pathname, pathname, 256); } -------------------------------------- PS2LINK REQUEST AND RESPONSE PACKETS -------------------------------------- During runtime, ps2link will send requests to the client for various things, usually to manipulate data on the 'host:' device. These requests are a single packet with a command number, the packet length, and its arguments. A single response packet is sent with the result of the operation. ---------------------------- 0xBABE0111 (open request) 0xBABE0112 (open response) ---------------------------- A request from ps2link to open the file specified by pathname with the given flags. Note that the flags are similar but not the same as the standard unix command open() and need to be converted before passing them on. The resulting file descriptor is returned as the result in the response packet. PACKET STRUCTURES struct { int number; short length; int flags; char pathname[256]; } request; struct { int number; short length; int result; } response; FLAG VALUES #define OPEN_READ 0x0001 #define OPEN_WRITE 0x0002 #define OPEN_NONBLOCK 0x0010 #define OPEN_APPEND 0x0100 #define OPEN_CREATE 0x0200 #define OPEN_TRUNCATE 0x0400 RESPONSE VALUES response.number = htonl(0xBABE0112); response.length = htons(sizeof(response)); response.result = htonl(open(request.pathname, converted_flags, 0644)); ----------------------------- 0xBABE0121 (close request) 0xBABE0122 (close response) ----------------------------- A request from ps2link to close the file specified by the file descriptor, fd. The result of the close() call is returned in the response packet. PACKET STRUCTURES struct { int number; short length; int fd; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE0122); response.length = htons(sizeof(response)); response.result = htonl(close(ntohl(request->fd))); ---------------------------- 0xBABE0131 (read request) 0xBABE0132 (read response) ---------------------------- A request from ps2link to read size bytes from the file specified by the file descriptor, fd. The result of the read() call is returned in the response packet, followed by the read data itself in the next packet. The current maximum size for any given read is 64k. PACKET STRUCTURES char buffer[65536]; struct { int number; short length; int fd, size; } request; struct { int number; short length; int result, size; } response; RESPONSE VALUES response.number = htonl(0xBABE0132); response.length = htons(sizeof(response)); response.result = htonl(read(ntohl(request->fd), buffer, ntohl(request->size))); response.size = response.result; ----------------------------- 0xBABE0141 (write request) 0xBABE0142 (write response) ----------------------------- A request from ps2link to write size bytes to the file specified by the file descriptor, fd. The data to be written immediately follows the request packet itself. The result of the write() call is returned in the response packet. The current maximum size for any given write is 64k. PACKET STRUCTURES struct { int number; short length; int fd, size; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE0142); response.length = htons(sizeof(response)); response.result = htonl(write(ntohl(request->fd), request->data, ntohl(request->size))); ----------------------------- 0xBABE0151 (lseek request) 0xBABE0152 (lseek response) ----------------------------- A request from ps2link to perform a lseek on the file specified by the file descriptor, fd. The result of the lseek() call is returned in the response packet. Note that unlike the open request, the values in this lseek request are the same as in the unix lseek(). PACKET STRUCTURES struct { int number; short length; int fd, offset, whence; } request; struct { int number; short length; int result; } response; WHENCE VALUES #define LSEEK_SET 0x0000 #define LSEEK_CURRENT 0x0001 #define LSEEK_END 0x0002 RESPONSE VALUES response.number = htonl(0xBABE0152); response.length = htons(sizeof(response)); response.result = htonl(lseek(ntohl(request->fd), ntohl(request->offset), ntohl(request->whence))); ----------------------------- 0xBABE0161 (dopen request) 0xBABE0162 (dopen response) ----------------------------- A request from ps2link to open the directory specified by the pathname with with the given flags. The resulting directory descriptor is returned as the result in the response packet. PACKET STRUCTURES struct { int number; short length; int flags; char pathname[256]; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE0162); response.length = htons(sizeof(response)); response.dd = htonl((int)opendir(request->pathname)); ------------------------------ 0xBABE0171 (dread request) 0xBABE0172 (dread response) ------------------------------ A request from ps2link to read the next directory entry specified by the directory descriptor, dd. The result of the readdir() call is returned in the response packet, along with the actual entry information. To maintain compatibility with existing PS2 directory functions, this data must be almost entirely converted to a different format. PACKET STRUCTURES struct tm timem; struct stat stats; struct dirent *direptr; struct { int number; short length; int dd; } request; struct { int number; short length; int ret; u32 mode, attr, size; u08 ctime[8], atime[8], mtime[8]; u32 hisize; u08 name[256]; } reponse; RESPONSE VALUES response.number = htonl(0xBABE0182); response.length = htons(sizeof(packet)); response.result = htonl((int)direptr = readdir((DIR *)ntohl(request->dd))); // Fetch the stats for the entry. stat(direptr->d_name, &stats); // Convert and add the mode. response.mode = (stats.st_mode & 0x07); if (S_ISDIR(stats.st_mode)) { response.mode |= 0x20; } if (S_ISLNK(stats.st_mode)) { response.mode |= 0x08; } if (S_ISREG(stats.st_mode)) { response.mode |= 0x10; } response.mode = htonl(response.mode); // Add the attributes. response.attr = htonl(0); // Add the size. response.size = htonl(stats.st_size); // Convert and add the creation time. if (localtime_r(&(stats.st_ctime), &timem)) { response.ctime[6] = (u08)loctime.tm_year; response.ctime[5] = (u08)loctime.tm_mon + 1; response.ctime[4] = (u08)loctime.tm_mday; response.ctime[3] = (u08)loctime.tm_hour; response.ctime[2] = (u08)loctime.tm_min; response.ctime[1] = (u08)loctime.tm_sec; } // Convert and add the access time. if (localtime_r(&(stats.st_atime), &timem)) { response.atime[6] = (u08)loctime.tm_year; response.atime[5] = (u08)loctime.tm_mon + 1; response.atime[4] = (u08)loctime.tm_mday; response.atime[3] = (u08)loctime.tm_hour; response.atime[2] = (u08)loctime.tm_min; response.atime[1] = (u08)loctime.tm_sec; } // Convert and add the modification time. if (localtime_r(&(stats.st_mtime), &timem)) { response.mtime[6] = (u08)loctime.tm_year; response.mtime[5] = (u08)loctime.tm_mon + 1; response.mtime[4] = (u08)loctime.tm_mday; response.mtime[3] = (u08)loctime.tm_hour; response.mtime[2] = (u08)loctime.tm_min; response.mtime[1] = (u08)loctime.tm_sec; } // Add the hsize. (what is this?) response.hisize = htonl(0); ------------------------------ 0xBABE0181 (dclose request) 0xBABE0182 (dclose response) ------------------------------ A request from ps2link to close the directory specified by the directory descriptor, dd. The result of the closedir() call is returned in the response packet. PACKET STRUCTURES struct { int number; short length; int dd; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE0172); response.length = htons(sizeof(reponse)); response.result = htonl(closedir((DIR *)ntohl(request->dd))); ----------------------------- 0xBABE0191 (remove request) 0xBABE0192 (remove response) ----------------------------- A request from ps2link to remove the file specified by the given filename 'name'. The result of the remove() call is returned in the response packet. PACKET STRUCTURES struct { int number; short length; int flags; char name[256]; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE0192); response.length = htons(sizeof(response)); response.result = htonl(remove(request->name)); ----------------------------- 0xBABE01a1 (mkdir request) 0xBABE01a2 (mkdir response) ----------------------------- A request from ps2link to make a directory with the dirname 'name'. The result of the mkdir() call is returned in the response packet. PACKET STRUCTURES struct { int number; short length; int flags; char name[256]; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE01a2); response.length = htons(sizeof(response)); response.result = htonl(mkdir(request->name)); ----------------------------- 0xBABE01b1 (rmdir request) 0xBABE01b2 (rmdir response) ----------------------------- A request from ps2link to remove a directory with the dirname 'name'. The result of the rmdir() call is returned in the response packet. PACKET STRUCTURES struct { int number; short length; int flags; char name[256]; } request; struct { int number; short length; int result; } response; RESPONSE VALUES response.number = htonl(0xBABE01b2); response.length = htons(sizeof(response)); response.result = htonl(rmdir(request->name)); --------------------- PS2LINK LOG PACKETS --------------------- Any data received from the log port from ps2link is meant to be displayed to the user via a simple printf. There is no special processing required or any packet format - just output to the screen.