From c4c36e5c34a1ed8f3604612db7406c18b994e3fd Mon Sep 17 00:00:00 2001 From: Bignaux Ronan Date: Tue, 11 May 2021 12:51:41 +0200 Subject: [PATCH] lwNBD: a NBD soon compliant server for hard drive --- Makefile | 12 +- include/extern_irx.h | 4 +- include/lang.h | 10 +- include/opl.h | 2 +- labs/{hdldsvrlab => lwnbdsvr}/Makefile | 14 +- .../hdldsvrlab.c => lwnbdsvr/lwnbdsvrlab.c} | 8 +- modules/hdd/hdldsvr/Makefile | 10 - modules/hdd/hdldsvr/hdldsvr.c | 471 ------------------ modules/hdd/hdldsvr/smsutils.h | 26 - modules/network/lwnbdsvr/Makefile | 13 + modules/network/lwnbdsvr/drivers/atad.c | 26 + modules/network/lwnbdsvr/drivers/atad.h | 21 + modules/network/lwnbdsvr/drivers/drivers.h | 34 ++ .../hdldsvr => network/lwnbdsvr}/exports.tab | 2 +- .../hdldsvr => network/lwnbdsvr}/imports.lst | 31 +- .../lwnbdsvr}/irx_imports.h | 5 +- modules/network/lwnbdsvr/lwNBD/LICENSE | 23 + modules/network/lwnbdsvr/lwNBD/README.md | 21 + modules/network/lwnbdsvr/lwNBD/nbd-protocol.h | 295 +++++++++++ modules/network/lwnbdsvr/lwNBD/nbd_opts.h | 109 ++++ modules/network/lwnbdsvr/lwNBD/nbd_server.c | 415 +++++++++++++++ modules/network/lwnbdsvr/lwNBD/nbd_server.h | 146 ++++++ modules/network/lwnbdsvr/lwnbdsvr.c | 38 ++ src/lang.c | 10 +- src/menusys.c | 8 +- src/opl.c | 31 +- 26 files changed, 1203 insertions(+), 582 deletions(-) rename labs/{hdldsvrlab => lwnbdsvr}/Makefile (83%) rename labs/{hdldsvrlab/hdldsvrlab.c => lwnbdsvr/lwnbdsvrlab.c} (95%) delete mode 100644 modules/hdd/hdldsvr/Makefile delete mode 100644 modules/hdd/hdldsvr/hdldsvr.c delete mode 100644 modules/hdd/hdldsvr/smsutils.h create mode 100644 modules/network/lwnbdsvr/Makefile create mode 100644 modules/network/lwnbdsvr/drivers/atad.c create mode 100644 modules/network/lwnbdsvr/drivers/atad.h create mode 100644 modules/network/lwnbdsvr/drivers/drivers.h rename modules/{hdd/hdldsvr => network/lwnbdsvr}/exports.tab (82%) rename modules/{hdd/hdldsvr => network/lwnbdsvr}/imports.lst (59%) rename modules/{hdd/hdldsvr => network/lwnbdsvr}/irx_imports.h (76%) create mode 100644 modules/network/lwnbdsvr/lwNBD/LICENSE create mode 100644 modules/network/lwnbdsvr/lwNBD/README.md create mode 100644 modules/network/lwnbdsvr/lwNBD/nbd-protocol.h create mode 100644 modules/network/lwnbdsvr/lwNBD/nbd_opts.h create mode 100644 modules/network/lwnbdsvr/lwNBD/nbd_server.c create mode 100644 modules/network/lwnbdsvr/lwNBD/nbd_server.h create mode 100644 modules/network/lwnbdsvr/lwnbdsvr.c diff --git a/Makefile b/Makefile index 83a8afb42..68e81f6fc 100644 --- a/Makefile +++ b/Makefile @@ -85,7 +85,7 @@ MISC_OBJS = icon_sys_A.o icon_sys_J.o icon_sys_C.o conf_theme_OPL.o \ IOP_OBJS = iomanx.o filexio.o ps2fs.o usbd.o bdmevent.o \ bdm.o bdmfs_vfat.o usbmass_bd.o iLinkman.o IEEE1394_bd.o \ - ps2atad.o hdpro_atad.o poweroff.o ps2hdd.o xhdd.o genvmc.o hdldsvr.o \ + ps2atad.o hdpro_atad.o poweroff.o ps2hdd.o xhdd.o genvmc.o lwnbdsvr.o \ ps2dev9.o smsutils.o ps2ip.o smap.o isofs.o nbns-iop.o \ sio2man.o padman.o mcman.o mcserv.o \ httpclient-iop.o netman.o ps2ips.o \ @@ -284,8 +284,8 @@ clean: $(MAKE) -C modules/mcemu USE_SMB=1 clean echo " -genvmc" $(MAKE) -C modules/vmc/genvmc clean - echo " -hdldsvr" - $(MAKE) -C modules/hdd/hdldsvr clean + echo " -lwnbdsvr" + $(MAKE) -C modules/network/lwnbdsvr clean echo " -udptty-ingame" $(MAKE) -C modules/debug/udptty-ingame clean echo " -ioptrap" @@ -611,11 +611,11 @@ modules/vmc/genvmc/genvmc.irx: modules/vmc/genvmc $(EE_ASM_DIR)genvmc.s: modules/vmc/genvmc/genvmc.irx | $(EE_ASM_DIR) $(BIN2S) $< $@ genvmc_irx -modules/hdd/hdldsvr/hdldsvr.irx: modules/hdd/hdldsvr +modules/network/lwnbdsvr/lwnbdsvr.irx: modules/network/lwnbdsvr $(MAKE) -C $< -$(EE_ASM_DIR)hdldsvr.s: modules/hdd/hdldsvr/hdldsvr.irx | $(EE_ASM_DIR) - $(BIN2S) $< $@ hdldsvr_irx +$(EE_ASM_DIR)lwnbdsvr.s: modules/network/lwnbdsvr/lwnbdsvr.irx | $(EE_ASM_DIR) + $(BIN2S) $< $@ lwnbdsvr_irx $(EE_ASM_DIR)udptty.s: $(PS2SDK)/iop/irx/udptty.irx | $(EE_ASM_DIR) $(BIN2S) $< $@ udptty_irx diff --git a/include/extern_irx.h b/include/extern_irx.h index bb2b0f464..c82d27a57 100644 --- a/include/extern_irx.h +++ b/include/extern_irx.h @@ -61,8 +61,8 @@ extern int size_hdd_cdvdman_irx; extern void *hdd_hdpro_cdvdman_irx; extern int size_hdd_hdpro_cdvdman_irx; -extern void *hdldsvr_irx; -extern int size_hdldsvr_irx; +extern void *lwnbdsvr_irx; +extern int size_lwnbdsvr_irx; extern void *hdd_mcemu_irx; extern int size_hdd_mcemu_irx; diff --git a/include/lang.h b/include/lang.h index d7c2d7dd1..8acf2cd6b 100644 --- a/include/lang.h +++ b/include/lang.h @@ -71,11 +71,11 @@ enum _STR_IDS { _STR_APPMODE, _STR_AUTO, _STR_MANUAL, - _STR_STARTHDL, - _STR_STARTINGHDL, - _STR_RUNNINGHDL, - _STR_STARTFAILHDL, - _STR_UNLOADHDL, + _STR_STARTNBD, + _STR_STARTINGNBD, + _STR_RUNNINGNBD, + _STR_STARTFAILNBD, + _STR_UNLOADNBD, _STR_EXITTO, _STR_BGCOLOR, _STR_TXTCOLOR, diff --git a/include/opl.h b/include/opl.h index 7ba40c1f1..023ada2cf 100644 --- a/include/opl.h +++ b/include/opl.h @@ -73,7 +73,7 @@ int saveConfig(int types, int showUI); void applyConfig(int themeID, int langID); void menuDeferredUpdate(void *data); void moduleUpdateMenu(int mode, int themeChanged, int langChanged); -void handleHdlSrv(); +void handleLwnbdSrv(); void deinit(int exception, int modeSelected); extern char *gBaseMCDir; diff --git a/labs/hdldsvrlab/Makefile b/labs/lwnbdsvr/Makefile similarity index 83% rename from labs/hdldsvrlab/Makefile rename to labs/lwnbdsvr/Makefile index 34a3c284d..4b02970c2 100644 --- a/labs/hdldsvrlab/Makefile +++ b/labs/lwnbdsvr/Makefile @@ -1,6 +1,6 @@ -EE_BIN = hdldsvrlab.elf -EE_OBJS = hdldsvrlab.o discid.o poweroff.o ps2dev9.o smsutils.o smstcpip.o smsmap.o ps2atad.o ps2hdd.o hdldsvr.o iomanx.o filexio.o +EE_BIN = lwnbdsvrlab.elf +EE_OBJS = lwnbdsvrlab.o discid.o poweroff.o ps2dev9.o smsutils.o smstcpip.o smsmap.o ps2atad.o ps2hdd.o lwnbdsvr.o iomanx.o filexio.o EE_LIBS = -lfileXio -lpatches -ldebug -lc -lkernel EE_CFLAGS = -g @@ -19,7 +19,7 @@ clean: $(MAKE) -C ../../modules/network/SMSMAP clean $(MAKE) -C ../../modules/hdd/atad clean $(MAKE) -C ../../modules/hdd/ps2hdd clean - $(MAKE) -C ../../modules/hdd/hdldsvr clean + $(MAKE) -C ../../modules/network/lwnbdsvr clean rm -f *.elf *.o *.a *.s rebuild: clean all @@ -42,7 +42,7 @@ smsutils.s: smstcpip.s: $(MAKE) -C ../../modules/network/SMSTCPIP -f Makefile rebuild $(BIN2S) ../../modules/network/SMSTCPIP/SMSTCPIP.irx smstcpip.s smstcpip_irx - + smsmap.s: $(MAKE) -C ../../modules/network/SMSMAP $(BIN2S) ../../modules/network/SMSMAP/SMSMAP.irx smsmap.s smsmap_irx @@ -55,9 +55,9 @@ ps2hdd.s: $(MAKE) -C ../../modules/hdd/ps2hdd $(BIN2S) ../../modules/hdd/ps2hdd/ps2hdd.irx ps2hdd.s ps2hdd_irx -hdldsvr.s: - $(MAKE) -C ../../modules/hdd/hdldsvr - $(BIN2S) ../../modules/hdd/hdldsvr/hdldsvr.irx hdldsvr.s hdldsvr_irx +lwnbdsvr.s: + $(MAKE) -C ../../modules/network/lwnbdsvr + $(BIN2S) ../../modules/network/lwnbdsvr/lwnbdsvr.irx lwnbdsvr.s lwnbdsvr_irx iomanx.s: $(BIN2S) $(PS2SDK)/iop/irx/iomanX.irx iomanx.s iomanx_irx diff --git a/labs/hdldsvrlab/hdldsvrlab.c b/labs/lwnbdsvr/lwnbdsvrlab.c similarity index 95% rename from labs/hdldsvrlab/hdldsvrlab.c rename to labs/lwnbdsvr/lwnbdsvrlab.c index 869ec3b28..0d66b6e10 100644 --- a/labs/hdldsvrlab/hdldsvrlab.c +++ b/labs/lwnbdsvr/lwnbdsvrlab.c @@ -35,8 +35,8 @@ extern void ps2atad_irx; extern int size_ps2atad_irx; extern void ps2hdd_irx; extern int size_ps2hdd_irx; -extern void hdldsvr_irx; -extern int size_hdldsvr_irx; +extern void lwnbdsvr_irx; +extern int size_lwnbdsvr_irx; extern void iomanx_irx; extern int size_iomanx_irx; extern void filexio_irx; @@ -76,7 +76,7 @@ int main(int argc, char *argv[2]) init_scr(); scr_clear(); - scr_printf("\t hdldsvrlab\n\n"); + scr_printf("\t lwnbdsvrlab\n\n"); SifInitRpc(0); @@ -122,7 +122,7 @@ int main(int argc, char *argv[2]) id = SifExecModuleBuffer(&smsmap_irx, size_smsmap_irx, g_ipconfig_len, g_ipconfig, &ret); id = SifExecModuleBuffer(&ps2atad_irx, size_ps2atad_irx, 0, NULL, &ret); id = SifExecModuleBuffer(&ps2hdd_irx, size_ps2hdd_irx, sizeof(hddarg), hddarg, &ret); - id = SifExecModuleBuffer(&hdldsvr_irx, size_hdldsvr_irx, 0, NULL, &ret); + id = SifExecModuleBuffer(&lwnbdsvr_irx, size_lwnbdsvr_irx, 0, NULL, &ret); scr_printf("OK\n"); diff --git a/modules/hdd/hdldsvr/Makefile b/modules/hdd/hdldsvr/Makefile deleted file mode 100644 index b338c83cc..000000000 --- a/modules/hdd/hdldsvr/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -IOP_BIN = hdldsvr.irx -IOP_OBJS = hdldsvr.o imports.o exports.o - -ifeq ($(DEBUG),1) -IOP_CFLAGS += -DDEBUG -endif - -include $(PS2SDK)/Defs.make -include ../../Rules.bin.make -include ../../Rules.make diff --git a/modules/hdd/hdldsvr/hdldsvr.c b/modules/hdd/hdldsvr/hdldsvr.c deleted file mode 100644 index 570ab6e14..000000000 --- a/modules/hdd/hdldsvr/hdldsvr.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - Copyright 2010, jimmikaelkael - Licenced under Academic Free License version 3.0 - Review OpenUsbLd README & LICENSE files for further details. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "smsutils.h" - -//#define FAKE_WRITES - -#define MODNAME "hdldsvr" -IRX_ID(MODNAME, 1, 1); - -struct irx_export_table _exp_hdldsvr; - -#define TCP_SERVER_PORT 45233 -#define UDP_SERVER_PORT 45233 - -#define CMD_SIZE 16 -#define CMD_STAT 0x73746174 // 'stat'; get HDD size in KB -#define CMD_READ 0x72656164 // 'read'; read sectors from HDD -#define CMD_WRIT 0x77726974 // 'writ'; write sectors to HDD -#define CMD_WRIS 0x77726973 // 'wris'; get last write status -#define CMD_FLSH 0x666c7368 // 'flsh'; flush write buff -#define CMD_POWX 0x706f7778 // 'powx'; poweroff system - -#define HDD_SECTOR_SIZE 512 // HDD sector size in bytes -#define NET_NUM_SECTORS 2048 // max # of sectors to move via network - -#define STATUS_AVAIL 0 // expecting command -#define STATUS_BUSY_RESPOND 1 // sending back response (and readen data) -#define STATUS_BUSY_WRITE 2 // expecting write data -#define STATUS_WRITE_STAT 3 // sending back write stat response - -#define SETBIT(mask, bit) (mask)[(bit) / 32] |= 1 << ((bit) % 32) -#define GETBIT(mask, bit) ((mask)[(bit) / 32] & (1 << ((bit) % 32))) - -void tcp_server_thread(void *args); -void udp_server_thread(void *args); - -static int tcp_server_tid, udp_server_tid; -static int udp_mutex = -1; - -static u8 tcp_buf[CMD_SIZE + HDD_SECTOR_SIZE * 2] __attribute__((aligned(64))); -static u8 udp_buf[8 + HDD_SECTOR_SIZE * 2] __attribute__((aligned(64))); - -struct tcp_packet_header -{ - u32 command; - u32 start_sector; - u32 num_sectors; - u32 result; -} __attribute__((packed)); - -typedef struct -{ - struct tcp_packet_header hdr; - u8 data[HDD_SECTOR_SIZE * 2]; -} tcp_packet_t __attribute__((packed)); - -typedef struct -{ - u8 data[HDD_SECTOR_SIZE * 2]; - u32 command; - u32 start_sector; -} udp_packet_t __attribute__((packed)); - -struct stats -{ - int status; - u32 command; - u32 start_sector; - u32 num_sectors; - u8 *data; - u32 bitmask[(NET_NUM_SECTORS + 31) / 32]; - u32 bitmask_copy[(NET_NUM_SECTORS + 31) / 32]; // endian-neutral - u8 buffer[HDD_SECTOR_SIZE * (NET_NUM_SECTORS + 1)]; // 1MB on IOP !!! Huge ! -}; - -static struct stats gstats __attribute__((aligned(64))); - -//------------------------------------------------------------------------- -int _start(int argc, char **argv) -{ - iop_thread_t thread_param; - - // register exports - RegisterLibraryEntries(&_exp_hdldsvr); - - // create a locked udp mutex - udp_mutex = CreateMutex(IOP_MUTEX_LOCKED); - - // create & start the tcp thread - thread_param.attr = TH_C; - thread_param.thread = (void *)tcp_server_thread; - thread_param.priority = 0x10; - thread_param.stacksize = 0x1000; - thread_param.option = 0; - - tcp_server_tid = CreateThread(&thread_param); - - StartThread(tcp_server_tid, 0); - - // create & start the udp thread - thread_param.attr = TH_C; - thread_param.thread = (void *)udp_server_thread; - thread_param.priority = 0x10; - thread_param.stacksize = 0x1000; - thread_param.option = 0; - - udp_server_tid = CreateThread(&thread_param); - - StartThread(udp_server_tid, 0); - - return MODULE_RESIDENT_END; -} - -//------------------------------------------------------------------------- -int _shutdown(void) -{ - // delete threads - DeleteThread(tcp_server_tid); - DeleteThread(udp_server_tid); - - // delete udp mutex - DeleteSema(udp_mutex); - - return 0; -} - -//------------------------------------------------------------------------- -static int ack_tcp_command(int sock, void *buf, int bsize) -{ - register int r; - - // acknowledge a received command - - gstats.status = STATUS_BUSY_RESPOND; - - r = lwip_send(sock, buf, bsize, 0); - - gstats.status = STATUS_AVAIL; - - return r; -} - -//------------------------------------------------------------------------- -static void reject_tcp_command(int sock, char *error_string) -{ - // reject a received command - - gstats.status = STATUS_BUSY_RESPOND; - - lwip_send(sock, error_string, strlen(error_string), 0); - - gstats.status = STATUS_AVAIL; - - ata_device_flush_cache(0); -} - -//------------------------------------------------------------------------- -static int check_datas(u32 command, u32 start_sector, u32 num_sectors) -{ - // check if all write data is here - - register int i, got_all_datas = 1; - - // wait that udp mutex is unlocked - WaitSema(udp_mutex); - - for (i = 0; i < num_sectors; ++i) { - if (!GETBIT(gstats.bitmask, i)) { - got_all_datas = 0; - break; - } - } - - if (!got_all_datas) // some parts are missing; should ask for retransmit - return -1; - - // all data here -- we can commit - gstats.command = command; - return 0; -} - -//------------------------------------------------------------------------- -static int handle_tcp_client(int tcp_client_socket) -{ - register int r, i, size; - ata_devinfo_t *devinfo; - tcp_packet_t *pkt = (tcp_packet_t *)tcp_buf; - - while (1) { - - // receive incoming packets - size = lwip_recv(tcp_client_socket, &tcp_buf[0], sizeof(tcp_buf), 0); - if (size < 0) - goto error; - - // check if valid command size - if (size != CMD_SIZE) { - reject_tcp_command(tcp_client_socket, "handle_recv: invalid packet received"); - goto error; - } - - // don't accept 'wris' without previous 'writ' - if ((gstats.status == STATUS_AVAIL) && (pkt->hdr.command == CMD_WRIS)) { - reject_tcp_command(tcp_client_socket, "write stat denied"); - goto error; - } else if ((!(gstats.status == STATUS_BUSY_WRITE) && (pkt->hdr.command == CMD_WRIS))) { - reject_tcp_command(tcp_client_socket, "busy"); - goto error; - } - - switch (pkt->hdr.command) { - - // ------------------------------------------------ - // 'writ' command - // ------------------------------------------------ - case CMD_WRIT: - // confirm write - pkt->hdr.result = 0; - r = ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header)); - if (r < 0) { - reject_tcp_command(tcp_client_socket, "init_write b0rked"); - goto error; - } - - gstats.status = STATUS_BUSY_WRITE; - gstats.command = pkt->hdr.command; - gstats.start_sector = pkt->hdr.start_sector; - gstats.num_sectors = pkt->hdr.num_sectors; - - // set-up buffer and clear bitmask - gstats.data = (u8 *)(((long)&gstats.buffer[HDD_SECTOR_SIZE - 1]) & ~(HDD_SECTOR_SIZE - 1)); - mips_memset(gstats.bitmask, 0, sizeof(gstats.bitmask)); - - break; - - - // ------------------------------------------------ - // 'wris' command - // ------------------------------------------------ - case CMD_WRIS: - if ((pkt->hdr.start_sector != gstats.start_sector) || (pkt->hdr.num_sectors != gstats.num_sectors)) { - reject_tcp_command(tcp_client_socket, "invalid write stat"); - goto error; - } - r = check_datas(pkt->hdr.command, pkt->hdr.start_sector, pkt->hdr.num_sectors); - if (r < 0) { - - // means we need retransmission of some datas so we send bitmask stats to the client - u32 *out = gstats.bitmask_copy; - for (i = 0; i < (NET_NUM_SECTORS + 31) / 32; ++i) - out[i] = gstats.bitmask[i]; - - mips_memcpy(pkt->data, (void *)out, sizeof(gstats.bitmask_copy)); - - pkt->hdr.result = 0; - r = ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header) + sizeof(gstats.bitmask)); - if (r < 0) { - reject_tcp_command(tcp_client_socket, "init_write_stat failed"); - goto error; - } - - gstats.status = STATUS_BUSY_WRITE; - } else { - pkt->hdr.result = pkt->hdr.num_sectors; - -#ifdef FAKE_WRITES - // fake write, we read instead - ata_device_sector_io(0, gstats.data, pkt->hdr.start_sector, pkt->hdr.num_sectors, ATA_DIR_READ); -#else - // !!! real writes !!! - ata_device_sector_io(0, gstats.data, pkt->hdr.start_sector, pkt->hdr.num_sectors, ATA_DIR_WRITE); -#endif - ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header)); - } - break; - - - // ------------------------------------------------ - // 'stat' command - // ------------------------------------------------ - case CMD_STAT: - if ((devinfo = ata_get_devinfo(0)) == NULL) - pkt->hdr.result = -1; - else - pkt->hdr.result = devinfo->total_sectors >> 1; - ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header)); - - break; - - - // ------------------------------------------------ - // 'read' command - // ------------------------------------------------ - case CMD_READ: - // set up buffer - gstats.data = (u8 *)(((long)&gstats.buffer + HDD_SECTOR_SIZE - 1) & ~(HDD_SECTOR_SIZE - 1)); - - if (pkt->hdr.num_sectors > 2) { - r = ata_device_sector_io(0, gstats.data, pkt->hdr.start_sector, pkt->hdr.num_sectors, ATA_DIR_READ); - if (r != 0) - pkt->hdr.result = -1; - else - pkt->hdr.result = pkt->hdr.num_sectors; - - ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(struct tcp_packet_header)); - if (r == 0) - ack_tcp_command(tcp_client_socket, gstats.data, pkt->hdr.num_sectors * HDD_SECTOR_SIZE); - } else { - r = ata_device_sector_io(0, pkt->data, pkt->hdr.start_sector, pkt->hdr.num_sectors, ATA_DIR_READ); - if (r != 0) - pkt->hdr.result = -1; - else - pkt->hdr.result = pkt->hdr.num_sectors; - - ack_tcp_command(tcp_client_socket, &tcp_buf[0], sizeof(tcp_packet_t)); - } - - break; - - - // ------------------------------------------------ - // 'flsh' command - // ------------------------------------------------ - case CMD_FLSH: - ata_device_flush_cache(0); - - break; - - - // ------------------------------------------------ - // 'powx' command - // ------------------------------------------------ - case CMD_POWX: - ata_device_flush_cache(0); - dev9Shutdown(); - PoweroffShutdown(); - - break; - - - - default: - reject_tcp_command(tcp_client_socket, "handle_recv: unknown command"); - goto error; - } - } - - return 0; - -error: - return -1; -} - -//------------------------------------------------------------------------- -void tcp_server_thread(void *args) -{ - int tcp_socket, client_socket = -1; - struct sockaddr_in peer; - int peerlen; - register int r; - - while (1) { - - peer.sin_family = AF_INET; - peer.sin_port = htons(TCP_SERVER_PORT); - peer.sin_addr.s_addr = htonl(INADDR_ANY); - - // create the socket - tcp_socket = lwip_socket(AF_INET, SOCK_STREAM, 0); - if (tcp_socket < 0) - goto error; - - // bind the socket - r = lwip_bind(tcp_socket, (struct sockaddr *)&peer, sizeof(peer)); - if (r < 0) - goto error; - - // we want to listen - r = lwip_listen(tcp_socket, 3); - if (r < 0) - goto error; - - while (1) { - peerlen = sizeof(peer); - // wait for incoming connection - client_socket = lwip_accept(tcp_socket, (struct sockaddr *)&peer, &peerlen); - if (client_socket < 0) - goto error; - - // got connection, handle the client - r = handle_tcp_client(client_socket); - if (r < 0) - lwip_close(client_socket); - } - - error: - // close the socket - lwip_close(tcp_socket); - } -} - -//------------------------------------------------------------------------- -void udp_server_thread(void *args) -{ - int udp_socket; - struct sockaddr_in peer; - register int r; - udp_packet_t *pkt = (udp_packet_t *)udp_buf; - - while (1) { - - peer.sin_family = AF_INET; - peer.sin_port = htons(UDP_SERVER_PORT); - peer.sin_addr.s_addr = htonl(INADDR_ANY); - - // create the socket - udp_socket = lwip_socket(AF_INET, SOCK_DGRAM, 0); - if (udp_socket < 0) - goto error; - - // bind the socket - r = lwip_bind(udp_socket, (struct sockaddr *)&peer, sizeof(peer)); - if (r < 0) - goto error; - - while (1) { - - // wait for packet - r = lwip_recv(udp_socket, udp_buf, sizeof(udp_buf), 0); - - // check to see if it's the command we're expecting - if ((r == sizeof(udp_packet_t)) && (pkt->command == gstats.command)) { - - // check the start sector is valid - if ((gstats.start_sector <= pkt->start_sector) && (pkt->start_sector < gstats.start_sector + gstats.num_sectors)) { - - u32 start_sector = pkt->start_sector - gstats.start_sector; - - if (!GETBIT(gstats.bitmask, start_sector)) { - mips_memcpy(gstats.data + start_sector * HDD_SECTOR_SIZE, pkt, HDD_SECTOR_SIZE * 2); - - SETBIT(gstats.bitmask, start_sector); - SETBIT(gstats.bitmask, start_sector + 1); - - // unlock udp mutex - SignalSema(udp_mutex); - } - } - } - } - - error: - // close the socket - lwip_close(udp_socket); - } -} diff --git a/modules/hdd/hdldsvr/smsutils.h b/modules/hdd/hdldsvr/smsutils.h deleted file mode 100644 index 6c210a739..000000000 --- a/modules/hdd/hdldsvr/smsutils.h +++ /dev/null @@ -1,26 +0,0 @@ -/* -# ___ _ _ ___ -# | | | | | -# ___| | | ___| PS2DEV Open Source Project. -#---------------------------------------------------------- -# (c) 2005 by Eugene Plotnikov -# -# Licensed under Academic Free License version 2.0 -# Review ps2sdk README & LICENSE files for further details. -*/ -#ifndef __SMSUTILS_H -#define __SMSUTILS_H - -#include - -#define smsutils_IMPORTS_start DECLARE_IMPORT_TABLE(smsutils, 1, 1) - -extern void mips_memcpy(void *, const void *, unsigned); -#define I_mips_memcpy DECLARE_IMPORT(4, mips_memcpy) - -extern void mips_memset(void *, int, unsigned); -#define I_mips_memset DECLARE_IMPORT(5, mips_memset) - -#define smsutils_IMPORTS_end END_IMPORT_TABLE - -#endif /* __SMSUTILS_H */ diff --git a/modules/network/lwnbdsvr/Makefile b/modules/network/lwnbdsvr/Makefile new file mode 100644 index 000000000..5b12ce081 --- /dev/null +++ b/modules/network/lwnbdsvr/Makefile @@ -0,0 +1,13 @@ +IOP_BIN = lwnbdsvr.irx +IOP_OBJS = lwnbdsvr.o imports.o exports.o drivers/atad.o lwNBD/nbd_server.o + +IOP_CFLAGS += -DPS2SDK +IOP_INCS += -I../../iopcore/common -I../../../include/ + +ifeq ($(DEBUG),1) +IOP_CFLAGS += -DDEBUG -DNBD_DEBUG +endif + +include $(PS2SDK)/Defs.make +include ../../Rules.bin.make +include ../../Rules.make diff --git a/modules/network/lwnbdsvr/drivers/atad.c b/modules/network/lwnbdsvr/drivers/atad.c new file mode 100644 index 000000000..c95cde23e --- /dev/null +++ b/modules/network/lwnbdsvr/drivers/atad.c @@ -0,0 +1,26 @@ +#include "atad.h" + +int hdd_atad_init(struct nbd_context *me) +{ + ata_devinfo_t *dev_info = ata_get_devinfo(0); + if (dev_info != NULL && dev_info->exists) { + me->export_size = (uint64_t)dev_info->total_sectors << me->blockshift; + return 0; + } + return 1; +} + +int hdd_atad_read(struct nbd_context *me, void *buffer, uint64_t offset, uint32_t length) +{ + return ata_device_sector_io(0, buffer, (uint32_t)offset, length, ATA_DIR_READ); +} + +int hdd_atad_write(struct nbd_context *me, void *buffer, uint64_t offset, uint32_t length) +{ + return ata_device_sector_io(0, buffer, (uint32_t)offset, length, ATA_DIR_WRITE); +} + +int hdd_atad_flush(struct nbd_context *me) +{ + return ata_device_flush_cache(0); +} diff --git a/modules/network/lwnbdsvr/drivers/atad.h b/modules/network/lwnbdsvr/drivers/atad.h new file mode 100644 index 000000000..e52fb4440 --- /dev/null +++ b/modules/network/lwnbdsvr/drivers/atad.h @@ -0,0 +1,21 @@ + + +#ifndef ATAD_DRIVERS_NBD_H +#define ATAD_DRIVERS_NBD_H + +#include "../irx_imports.h" +#include "../lwNBD/nbd_server.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int hdd_atad_init(struct nbd_context *me); +int hdd_atad_read(struct nbd_context *me, void *buffer, uint64_t offset, uint32_t length); +int hdd_atad_write(struct nbd_context *me, void *buffer, uint64_t offset, uint32_t length); +int hdd_atad_flush(struct nbd_context *me); + +#ifdef __cplusplus +} +#endif +#endif /* ATAD_DRIVERS_NBD_H */ diff --git a/modules/network/lwnbdsvr/drivers/drivers.h b/modules/network/lwnbdsvr/drivers/drivers.h new file mode 100644 index 000000000..0da6c8804 --- /dev/null +++ b/modules/network/lwnbdsvr/drivers/drivers.h @@ -0,0 +1,34 @@ + + +#ifndef DRIVERS_NBD_H +#define DRIVERS_NBD_H + +#include "../irx_imports.h" +#include "../lwNBD/nbd_server.h" +#include "atad.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static struct nbd_context hdd_atad = + { + .export_name = "hdd", + .export_desc = "PlayStation 2 HDD via ATAD", + .blockshift = 9, + .buffer = nbd_buffer, + .export_init = hdd_atad_init, + .read = hdd_atad_read, + .write = hdd_atad_write, + .flush = hdd_atad_flush, +}; + +struct nbd_context *nbd_contexts[] = { + &hdd_atad, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_NBD_H */ diff --git a/modules/hdd/hdldsvr/exports.tab b/modules/network/lwnbdsvr/exports.tab similarity index 82% rename from modules/hdd/hdldsvr/exports.tab rename to modules/network/lwnbdsvr/exports.tab index 2d3c4280d..9985e0e56 100644 --- a/modules/hdd/hdldsvr/exports.tab +++ b/modules/network/lwnbdsvr/exports.tab @@ -1,6 +1,6 @@ void _retonly(void) {} -DECLARE_EXPORT_TABLE(hdldsvr, 1, 1) +DECLARE_EXPORT_TABLE(lwnbdsvr, 1, 1) DECLARE_EXPORT(_start) DECLARE_EXPORT(_retonly) DECLARE_EXPORT(_shutdown) diff --git a/modules/hdd/hdldsvr/imports.lst b/modules/network/lwnbdsvr/imports.lst similarity index 59% rename from modules/hdd/hdldsvr/imports.lst rename to modules/network/lwnbdsvr/imports.lst index 4f65b804d..cd3385ad6 100644 --- a/modules/hdd/hdldsvr/imports.lst +++ b/modules/network/lwnbdsvr/imports.lst @@ -5,18 +5,10 @@ I_ata_device_sector_io I_ata_device_flush_cache atad_IMPORTS_end -dev9_IMPORTS_start -I_dev9Shutdown -dev9_IMPORTS_end - loadcore_IMPORTS_start I_RegisterLibraryEntries loadcore_IMPORTS_end -poweroff_IMPORTS_start -I_PoweroffShutdown -poweroff_IMPORTS_end - ps2ip_IMPORTS_start I_lwip_recv I_lwip_send @@ -29,11 +21,6 @@ I_lwip_select I_inet_addr ps2ip_IMPORTS_end -smsutils_IMPORTS_start -I_mips_memset -I_mips_memcpy -smsutils_IMPORTS_end - thbase_IMPORTS_start I_DelayThread I_CreateThread @@ -41,17 +28,15 @@ I_StartThread I_DeleteThread thbase_IMPORTS_end -thsemap_IMPORTS_start -I_CreateSema -I_WaitSema -I_SignalSema -I_DeleteSema -thsemap_IMPORTS_end - sysclib_IMPORTS_start +I_strcpy I_strlen +I_memcpy +I_memset sysclib_IMPORTS_end -//stdio_IMPORTS_start -//I_printf -//stdio_IMPORTS_end +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + + diff --git a/modules/hdd/hdldsvr/irx_imports.h b/modules/network/lwnbdsvr/irx_imports.h similarity index 76% rename from modules/hdd/hdldsvr/irx_imports.h rename to modules/network/lwnbdsvr/irx_imports.h index 7d0edf855..2ac7338af 100644 --- a/modules/hdd/hdldsvr/irx_imports.h +++ b/modules/network/lwnbdsvr/irx_imports.h @@ -4,13 +4,12 @@ #include #include -#include #include -#include #include -#include "smsutils.h" +#include #include #include #include +#include #endif diff --git a/modules/network/lwnbdsvr/lwNBD/LICENSE b/modules/network/lwnbdsvr/lwNBD/LICENSE new file mode 100644 index 000000000..43aabb22a --- /dev/null +++ b/modules/network/lwnbdsvr/lwNBD/LICENSE @@ -0,0 +1,23 @@ +BSD 2 - Clause License + + Copyright(c) 2021, + Bignaux Ronan + All rights reserved. + + Redistribution and use in source and binary forms, + with or without + modification, + are permitted provided that the following conditions are met : + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / + or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules/network/lwnbdsvr/lwNBD/README.md b/modules/network/lwnbdsvr/lwNBD/README.md new file mode 100644 index 000000000..73d12305b --- /dev/null +++ b/modules/network/lwnbdsvr/lwNBD/README.md @@ -0,0 +1,21 @@ +#lwNBD + +* Description : A Lightweight NBD server based on lwIP stack +* Official repository : https://github.com/bignaux/lwNBD +* Author : Ronan Bignaux +* Licence : BSD +* lwIP 2.0.0 Socket API + +#History + +On Playstation 2, there is no standardised central partition table like GPT for hard disk partitioning, nor is there a standard file system but PFS and HDLoader. In fact, there are few tools capable of handling hard disks, especially under Linux, and the servers developed in the past to handle these disks via the network did not use a standard protocol, which required each software wishing to handle the disks to include a specific client part, which were broken when the toolchain was updated. The same goes for the memory cards and other block devices on this console, which is why I decided to implement NBD on this target first. + +lwNBD is developed on MIPS R3000 IOP in [my OPL nbd branch](https://github.com/bignaux/Open-PS2-Loader/tree/nbd/modules/network/lwnbdsvr), that provides a good uptodate use case. + +#Status + +Although this server is not yet complete in respect of the minimal requirements defined by the [NBD protocol](https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md#baseline), it is nevertheless usable with certain clients, in particular nbdfuse (provided by libnbd), the client I am using for this development. In a [RERO spirit](https://en.wikipedia.org/wiki/Release_early,_release_often) i publish this "AS-IS". + +#TODO: +* fix NBD_FLAG_FIXED_NEWSTYLE negotiation +* NBD_OPT_INFO/NBD_OPT_GO, the server is not yet able to serve many export. Currently, the server takes the first on the list. \ No newline at end of file diff --git a/modules/network/lwnbdsvr/lwNBD/nbd-protocol.h b/modules/network/lwnbdsvr/lwNBD/nbd-protocol.h new file mode 100644 index 000000000..628bc3b87 --- /dev/null +++ b/modules/network/lwnbdsvr/lwNBD/nbd-protocol.h @@ -0,0 +1,295 @@ +/* nbdkit + * Copyright (C) 2013-2020 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Red Hat nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef NBD_PROTOCOL_H +#define NBD_PROTOCOL_H + +#include + +/* Note that all NBD fields are sent on the wire in network byte + * order, so you must use beXXtoh or htobeXX when reading or writing + * these structures. + */ + +#if defined(__GNUC__) || defined(__clang__) +#define NBD_ATTRIBUTE_PACKED __attribute__((__packed__)) +#else +#error "Please port to your compiler's notion of a packed struct" +#endif + +#define NBD_MAX_STRING 4096 /* Maximum length of a string field */ + +/* Old-style handshake. */ +struct nbd_old_handshake +{ + uint64_t nbdmagic; /* NBD_MAGIC */ + uint64_t version; /* NBD_OLD_VERSION */ + uint64_t exportsize; + uint16_t gflags; /* global flags */ + uint16_t eflags; /* per-export flags */ + char zeroes[124]; /* must be sent as zero bytes */ +} NBD_ATTRIBUTE_PACKED; + +#define NBD_MAGIC UINT64_C(0x4e42444d41474943) /* ASCII "NBDMAGIC" */ +#define NBD_OLD_VERSION UINT64_C(0x0000420281861253) + +/* New-style handshake. */ +struct nbd_new_handshake +{ + uint64_t nbdmagic; /* NBD_MAGIC */ + uint64_t version; /* NBD_NEW_VERSION */ + uint16_t gflags; /* global flags */ +} NBD_ATTRIBUTE_PACKED; + +#define NBD_NEW_VERSION UINT64_C(0x49484156454F5054) /* ASCII "IHAVEOPT" */ + +/* New-style handshake option (sent by the client to us). */ +struct nbd_new_option +{ + uint64_t version; /* NBD_NEW_VERSION */ + uint32_t option; /* NBD_OPT_* */ + uint32_t optlen; /* option data length */ + /* option data follows */ +} NBD_ATTRIBUTE_PACKED; + +/* Newstyle handshake OPT_EXPORT_NAME reply message. + * Modern clients use NBD_OPT_GO instead of this. + */ +struct nbd_export_name_option_reply +{ + uint64_t exportsize; /* size of export */ + uint16_t eflags; /* per-export flags */ + char zeroes[124]; /* optional zeroes, unless NBD_FLAG_NO_ZEROES */ +} NBD_ATTRIBUTE_PACKED; + +/* Fixed newstyle handshake reply message. */ +struct nbd_fixed_new_option_reply +{ + uint64_t magic; /* NBD_REP_MAGIC */ + uint32_t option; /* option we are replying to */ + uint32_t reply; /* NBD_REP_* */ + uint32_t replylen; +} NBD_ATTRIBUTE_PACKED; + +#define NBD_REP_MAGIC UINT64_C(0x3e889045565a9) + +/* Global flags. */ +#define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) +#define NBD_FLAG_NO_ZEROES (1 << 1) + +/* Per-export flags. */ +#define NBD_FLAG_HAS_FLAGS (1 << 0) +#define NBD_FLAG_READ_ONLY (1 << 1) +#define NBD_FLAG_SEND_FLUSH (1 << 2) +#define NBD_FLAG_SEND_FUA (1 << 3) +#define NBD_FLAG_ROTATIONAL (1 << 4) +#define NBD_FLAG_SEND_TRIM (1 << 5) +#define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) +#define NBD_FLAG_SEND_DF (1 << 7) +#define NBD_FLAG_CAN_MULTI_CONN (1 << 8) +#define NBD_FLAG_SEND_CACHE (1 << 10) +#define NBD_FLAG_SEND_FAST_ZERO (1 << 11) + +/* NBD options (new style handshake only). */ +#define NBD_OPT_EXPORT_NAME 1 +#define NBD_OPT_ABORT 2 +#define NBD_OPT_LIST 3 +#define NBD_OPT_STARTTLS 5 +#define NBD_OPT_INFO 6 +#define NBD_OPT_GO 7 +#define NBD_OPT_STRUCTURED_REPLY 8 +#define NBD_OPT_LIST_META_CONTEXT 9 +#define NBD_OPT_SET_META_CONTEXT 10 + +#define NBD_REP_ERR(val) (0x80000000 | (val)) +#define NBD_REP_IS_ERR(val) (!!((val)&0x80000000)) + +#define NBD_REP_ACK 1 +#define NBD_REP_SERVER 2 +#define NBD_REP_INFO 3 +#define NBD_REP_META_CONTEXT 4 +#define NBD_REP_ERR_UNSUP NBD_REP_ERR(1) +#define NBD_REP_ERR_POLICY NBD_REP_ERR(2) +#define NBD_REP_ERR_INVALID NBD_REP_ERR(3) +#define NBD_REP_ERR_PLATFORM NBD_REP_ERR(4) +#define NBD_REP_ERR_TLS_REQD NBD_REP_ERR(5) +#define NBD_REP_ERR_UNKNOWN NBD_REP_ERR(6) +#define NBD_REP_ERR_SHUTDOWN NBD_REP_ERR(7) +#define NBD_REP_ERR_BLOCK_SIZE_REQD NBD_REP_ERR(8) +#define NBD_REP_ERR_TOO_BIG NBD_REP_ERR(9) + +#define NBD_INFO_EXPORT 0 +#define NBD_INFO_NAME 1 +#define NBD_INFO_DESCRIPTION 2 +#define NBD_INFO_BLOCK_SIZE 3 + +/* NBD_INFO_EXPORT reply (follows fixed_new_option_reply). */ +struct nbd_fixed_new_option_reply_info_export +{ + uint16_t info; /* NBD_INFO_EXPORT */ + uint64_t exportsize; /* size of export */ + uint16_t eflags; /* per-export flags */ +} NBD_ATTRIBUTE_PACKED; + +/* NBD_INFO_NAME or NBD_INFO_DESCRIPTION reply (follows + * fixed_new_option_reply). + */ +struct nbd_fixed_new_option_reply_info_name_or_desc +{ + uint16_t info; /* NBD_INFO_NAME, NBD_INFO_DESCRIPTION */ + /* followed by a string name or description */ +} NBD_ATTRIBUTE_PACKED; + +/* NBD_INFO_BLOCK_SIZE reply (follows fixed_new_option_reply). */ +struct nbd_fixed_new_option_reply_info_block_size +{ + uint16_t info; /* NBD_INFO_BLOCK_SIZE */ + uint32_t minimum; /* minimum block size */ + uint32_t preferred; /* preferred block size */ + uint32_t maximum; /* maximum block size */ +} NBD_ATTRIBUTE_PACKED; + +/* NBD_REP_SERVER reply (follows fixed_new_option_reply). */ +struct nbd_fixed_new_option_reply_server +{ + uint32_t export_name_len; /* length of export name */ + /* followed by a string export name and description */ +} NBD_ATTRIBUTE_PACKED; + +/* NBD_REP_META_CONTEXT reply (follows fixed_new_option_reply). */ +struct nbd_fixed_new_option_reply_meta_context +{ + uint32_t context_id; /* metadata context ID */ + /* followed by a string */ +} NBD_ATTRIBUTE_PACKED; + +/* NBD_REPLY_TYPE_BLOCK_STATUS block descriptor. */ +struct nbd_block_descriptor +{ + uint32_t length; /* length of block */ + uint32_t status_flags; /* block type (hole etc) */ +} NBD_ATTRIBUTE_PACKED; + +/* Request (client -> server). */ +struct nbd_request +{ + uint32_t magic; /* NBD_REQUEST_MAGIC. */ + uint16_t flags; /* Request flags. */ + uint16_t type; /* Request type. */ + uint64_t handle; /* Opaque handle. */ + uint64_t offset; /* Request offset. */ + uint32_t count; /* Request length. */ +} NBD_ATTRIBUTE_PACKED; + +/* Simple reply (server -> client). */ +struct nbd_simple_reply +{ + uint32_t magic; /* NBD_SIMPLE_REPLY_MAGIC. */ + uint32_t error; /* NBD_SUCCESS or one of NBD_E*. */ + uint64_t handle; /* Opaque handle. */ +} NBD_ATTRIBUTE_PACKED; + +/* Structured reply (server -> client). */ +struct nbd_structured_reply +{ + uint32_t magic; /* NBD_STRUCTURED_REPLY_MAGIC. */ + uint16_t flags; /* NBD_REPLY_FLAG_* */ + uint16_t type; /* NBD_REPLY_TYPE_* */ + uint64_t handle; /* Opaque handle. */ + uint32_t length; /* Length of payload which follows. */ +} NBD_ATTRIBUTE_PACKED; + +struct nbd_structured_reply_offset_data +{ + uint64_t offset; /* offset */ + /* Followed by data. */ +} NBD_ATTRIBUTE_PACKED; + +struct nbd_structured_reply_offset_hole +{ + uint64_t offset; + uint32_t length; /* Length of hole. */ +} NBD_ATTRIBUTE_PACKED; + +struct nbd_structured_reply_error +{ + uint32_t error; /* NBD_E* error number */ + uint16_t len; /* Length of human readable error. */ + /* Followed by human readable error string, and possibly more structure. */ +} NBD_ATTRIBUTE_PACKED; + +#define NBD_REQUEST_MAGIC 0x25609513 +#define NBD_SIMPLE_REPLY_MAGIC 0x67446698 +#define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef + +/* Structured reply flags. */ +#define NBD_REPLY_FLAG_DONE (1 << 0) + +#define NBD_REPLY_TYPE_ERR(val) ((1 << 15) | (val)) +#define NBD_REPLY_TYPE_IS_ERR(val) (!!((val) & (1 << 15))) + +/* Structured reply types. */ +#define NBD_REPLY_TYPE_NONE 0 +#define NBD_REPLY_TYPE_OFFSET_DATA 1 +#define NBD_REPLY_TYPE_OFFSET_HOLE 2 +#define NBD_REPLY_TYPE_BLOCK_STATUS 5 +#define NBD_REPLY_TYPE_ERROR NBD_REPLY_TYPE_ERR(1) +#define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_TYPE_ERR(2) + +/* NBD commands. */ +#define NBD_CMD_READ 0 +#define NBD_CMD_WRITE 1 +#define NBD_CMD_DISC 2 /* Disconnect. */ +#define NBD_CMD_FLUSH 3 +#define NBD_CMD_TRIM 4 +#define NBD_CMD_CACHE 5 +#define NBD_CMD_WRITE_ZEROES 6 +#define NBD_CMD_BLOCK_STATUS 7 + +#define NBD_CMD_FLAG_FUA (1 << 0) +#define NBD_CMD_FLAG_NO_HOLE (1 << 1) +#define NBD_CMD_FLAG_DF (1 << 2) +#define NBD_CMD_FLAG_REQ_ONE (1 << 3) +#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) + +/* NBD error codes. */ +#define NBD_SUCCESS 0 +#define NBD_EPERM 1 +#define NBD_EIO 5 +#define NBD_ENOMEM 12 +#define NBD_EINVAL 22 +#define NBD_ENOSPC 28 +#define NBD_EOVERFLOW 75 +#define NBD_ENOTSUP 95 +#define NBD_ESHUTDOWN 108 + +#endif /* NBD_PROTOCOL_H */ diff --git a/modules/network/lwnbdsvr/lwNBD/nbd_opts.h b/modules/network/lwnbdsvr/lwNBD/nbd_opts.h new file mode 100644 index 000000000..a574b950e --- /dev/null +++ b/modules/network/lwnbdsvr/lwNBD/nbd_opts.h @@ -0,0 +1,109 @@ +/****************************************************************/ /** + * + * @file nbd_opts.h + * + * @author Ronan Bignaux + * + * @brief Network Block Device Protocol implementation options + * + * Copyright (c) Ronan Bignaux. 2021 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Ronan Bignaux + * + */ + +#ifndef LWIP_HDR_APPS_NBD_OPTS_H +#define LWIP_HDR_APPS_NBD_OPTS_H + +#ifndef PS2SDK +#include "lwip/opt.h" +#else +#include "tcpip.h" +#endif + +/** + * @defgroup NBD_opts Options + * @ingroup NBD + * @{ + */ + +/** + * Enable NBD debug messages + */ +#if !defined NBD_DEBUG || defined __DOXYGEN__ +#define NBD_DEBUG LWIP_DBG_ON +#endif + +/** + * NBD server port + */ +#if !defined NBD_SERVER_PORT || defined __DOXYGEN__ +#define NBD_SERVER_PORT 10809 +#endif + +/** + * NBD timeout + */ +#if !defined NBD_TIMEOUT_MSECS || defined __DOXYGEN__ +#define NBD_TIMEOUT_MSECS 10000 +#endif + +/** + * Max. number of retries when a file is read from server + */ +#if !defined NBD_MAX_RETRIES || defined __DOXYGEN__ +#define NBD_MAX_RETRIES 5 +#endif + +/** + * NBD timer cyclic interval + */ +#if !defined NBD_TIMER_MSECS || defined __DOXYGEN__ +#define NBD_TIMER_MSECS 50 +#endif + +/** + * Max. length of NBD buffer : NBD_MAX_STRING is minimal size for the buffer + */ +#if !defined NBD_BUFFER_LEN || defined __DOXYGEN__ +#define NBD_BUFFER_LEN 512 * 256 +#endif + +/** + * Max. length of NBD mode + */ +#if !defined NBD_MAX_MODE_LEN || defined __DOXYGEN__ +#define NBD_MAX_MODE_LEN 7 +#endif + +/** + * @} + */ + +#endif /* LWIP_HDR_APPS_NBD_OPTS_H */ diff --git a/modules/network/lwnbdsvr/lwNBD/nbd_server.c b/modules/network/lwnbdsvr/lwNBD/nbd_server.c new file mode 100644 index 000000000..a8377ea84 --- /dev/null +++ b/modules/network/lwnbdsvr/lwNBD/nbd_server.c @@ -0,0 +1,415 @@ +/****************************************************************/ /** + * + * @file nbd_server.c + * + * @author Ronan Bignaux + * + * @brief Network Block Device Protocol server + * + * Copyright (c) Ronan Bignaux. 2021 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Ronan Bignaux + * + */ + +/** + * @defgroup nbd NBD server + * @ingroup apps + * + * This is simple NBD server for the lwIP Socket API. + */ + +#include "nbd_server.h" + +/* + * https://lwip.fandom.com/wiki/Receiving_data_with_LWIP + */ +static int nbd_recv(int s, void *mem, size_t len, int flags) +{ + uint32_t bytesRead = 0; + uint32_t left = len; + uint32_t totalRead = 0; + + // LWIP_DEBUGF(NBD_DEBUG | LWIP_DBG_STATE("nbd_recv(-, 0x%X, %d)\n", (int)mem, size); + do { + bytesRead = recv(s, mem + totalRead, left, flags); + // LWIP_DEBUGF(NBD_DEBUG | LWIP_DBG_STATE("bytesRead = %d\n", bytesRead); + if (bytesRead <= 0) + break; + + left -= bytesRead; + totalRead += bytesRead; + + } while (left); + return totalRead; +} + +/** @ingroup nbd + * Fixed newstyle negotiation. + * @param client_socket + * @param ctx NBD callback struct + */ +struct nbd_context *negotiation_phase(int client_socket, struct nbd_context **ctxs) +{ + register int size; + uint32_t cflags, name_len, desc_len, len; + struct nbd_new_option new_opt; + struct nbd_export_name_option_reply handshake_finish; + struct nbd_fixed_new_option_reply fixed_new_option_reply; + struct nbd_new_handshake new_hs; + + //temporary workaround + struct nbd_context *ctx = ctxs[0]; + + /*** handshake ***/ + + new_hs.nbdmagic = htonll(NBD_MAGIC); + new_hs.version = htonll(NBD_NEW_VERSION); + new_hs.gflags = 0; //htons(NBD_FLAG_FIXED_NEWSTYLE); + size = send(client_socket, &new_hs, sizeof(struct nbd_new_handshake), + 0); + if (size < sizeof(struct nbd_new_handshake)) + goto error; + + size = recv(client_socket, &cflags, sizeof(cflags), 0); + if (size < sizeof(cflags)) + goto error; + cflags = htonl(cflags); + /* TODO: manage cflags + * https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md#client-flags + */ + + ctx->eflags = NBD_FLAG_HAS_FLAGS; + + while (1) { + + /*** options haggling ***/ + + size = recv(client_socket, &new_opt, sizeof(struct nbd_new_option), + 0); + if (size < sizeof(struct nbd_new_option)) + goto error; + + new_opt.version = ntohll(new_opt.version); + if (new_opt.version != NBD_NEW_VERSION) + goto error; + + new_opt.option = htonl(new_opt.option); + new_opt.optlen = htonl(new_opt.optlen); + + if (new_opt.optlen > 0) { + size = recv(client_socket, &nbd_buffer, new_opt.optlen, 0); + nbd_buffer[new_opt.optlen] = '\0'; + } + + switch (new_opt.option) { + + case NBD_OPT_EXPORT_NAME: + + handshake_finish.exportsize = htonll(ctx->export_size); + handshake_finish.eflags = htons(ctx->eflags); + // TODO if NBD_FLAG_NO_ZEROES / NBD_FLAG_C_NO_ZEROES + memset(handshake_finish.zeroes, 0, sizeof(handshake_finish.zeroes)); + size = send(client_socket, &handshake_finish, + sizeof(struct nbd_export_name_option_reply), 0); + goto abort; + + case NBD_OPT_ABORT: + //TODO : test + fixed_new_option_reply.magic = htonll(NBD_REP_MAGIC); + fixed_new_option_reply.option = htonl(new_opt.option); + fixed_new_option_reply.reply = htonl(NBD_REP_ACK); + fixed_new_option_reply.replylen = 0; + size = send(client_socket, &fixed_new_option_reply, + sizeof(struct nbd_fixed_new_option_reply), 0); + goto soft_disconnect; + break; + // see nbdkit send_newstyle_option_reply_exportnames() + case NBD_OPT_LIST: + + name_len = strlen(ctx->export_name); + desc_len = ctx->export_desc ? strlen(ctx->export_desc) : 0; + len = htonl(name_len); + + //TODO : many export in a loop + fixed_new_option_reply.magic = htonll(NBD_REP_MAGIC); + fixed_new_option_reply.option = htonl(new_opt.option); + fixed_new_option_reply.reply = htonl(NBD_REP_SERVER); + fixed_new_option_reply.replylen = htonl(name_len + sizeof(len) + + desc_len); + + size = send(client_socket, &fixed_new_option_reply, + sizeof(struct nbd_fixed_new_option_reply), MSG_MORE); + size = send(client_socket, &len, sizeof len, MSG_MORE); + size = send(client_socket, ctx->export_name, name_len, MSG_MORE); + size = send(client_socket, ctx->export_desc, desc_len, 0); + break; + //TODO + // break; + // case NBD_OPT_STARTTLS: + // break; + // see nbdkit send_newstyle_option_reply_info_export() + case NBD_OPT_INFO: + case NBD_OPT_GO: + + + // if (new_opt.option == NBD_OPT_GO) + // goto abort; + // break; + case NBD_OPT_STRUCTURED_REPLY: + case NBD_OPT_LIST_META_CONTEXT: + case NBD_OPT_SET_META_CONTEXT: + default: + //TODO: test + fixed_new_option_reply.magic = htonll(NBD_REP_MAGIC); + fixed_new_option_reply.option = htonl(new_opt.option); + fixed_new_option_reply.reply = htonl(NBD_REP_ERR_UNSUP); + fixed_new_option_reply.replylen = 0; + size = send(client_socket, &fixed_new_option_reply, + sizeof(struct nbd_fixed_new_option_reply), 0); + break; + } + } + +abort: + return ctx; +soft_disconnect: +error: + return NULL; +} + +/** @ingroup nbd + * Transmission phase. + * @param client_socket + * @param ctx NBD callback struct + */ +static int transmission_phase(int client_socket, struct nbd_context *ctx) +{ + register int r, size, error, retry = NBD_MAX_RETRIES, sendflag = 0; + register uint32_t blkremains = 0, byteread = 0, bufbklsz = 0; + register uint64_t offset = 0; + struct nbd_simple_reply reply; + struct nbd_request request; + + reply.magic = htonl(NBD_SIMPLE_REPLY_MAGIC); + + while (1) { + + /*** requests handling ***/ + + // TODO : blocking here if no proper NBD_CMD_DISC, bad threading design ? + size = recv(client_socket, &request, sizeof(struct nbd_request), 0); + if (size < sizeof(struct nbd_request)) + goto error; + + request.magic = ntohl(request.magic); + if (request.magic != NBD_REQUEST_MAGIC) + goto error; + + request.flags = ntohs(request.flags); + request.type = ntohs(request.type); + request.offset = ntohll(request.offset); + request.count = ntohl(request.count); + + reply.handle = request.handle; + + switch (request.type) { + + case NBD_CMD_READ: + + if (request.offset + request.count > ctx->export_size) + error = NBD_EIO; + else { + error = NBD_SUCCESS; + sendflag = MSG_MORE; + bufbklsz = NBD_BUFFER_LEN >> ctx->blockshift; + blkremains = request.count >> ctx->blockshift; + offset = request.offset >> ctx->blockshift; + byteread = bufbklsz << ctx->blockshift; + } + + reply.error = ntohl(error); + r = send(client_socket, &reply, sizeof(struct nbd_simple_reply), + sendflag); + + while (sendflag) { + + if (blkremains < bufbklsz) { + bufbklsz = blkremains; + byteread = bufbklsz << ctx->blockshift; + } + + if (blkremains <= bufbklsz) + sendflag = 0; + + r = ctx->read(ctx, ctx->buffer, offset, bufbklsz); + + if (r == 0) { + r = send(client_socket, ctx->buffer, byteread, sendflag); + if (r != byteread) + break; + offset += bufbklsz; + blkremains -= bufbklsz; + retry = NBD_MAX_RETRIES; + } else if (retry) { + retry--; + sendflag = 1; + } else { + goto error; // -EIO + // LWIP_DEBUGF(NBD_DEBUG | LWIP_DBG_STATE, ("nbd: error read\n")); + } + } + + break; + + case NBD_CMD_WRITE: + + if (ctx->eflags & NBD_FLAG_READ_ONLY) + error = NBD_EPERM; + else if (request.offset + request.count > ctx->export_size) + error = NBD_ENOSPC; + else { + error = NBD_SUCCESS; + sendflag = MSG_MORE; + bufbklsz = NBD_BUFFER_LEN >> ctx->blockshift; + blkremains = request.count >> ctx->blockshift; + offset = request.offset >> ctx->blockshift; + byteread = bufbklsz << ctx->blockshift; + } + + while (sendflag) { + + if (blkremains < bufbklsz) { + bufbklsz = blkremains; + byteread = bufbklsz << ctx->blockshift; + } + + if (blkremains <= bufbklsz) + sendflag = 0; + + r = nbd_recv(client_socket, ctx->buffer, byteread, 0); + + if (r == byteread) { + r = ctx->write(ctx, ctx->buffer, offset, bufbklsz); + if (r != 0) { + error = NBD_EIO; + sendflag = 0; + // LWIP_DEBUGF(NBD_DEBUG | LWIP_DBG_STATE, ("nbd: error read\n")); + } + offset += bufbklsz; + blkremains -= bufbklsz; + retry = NBD_MAX_RETRIES; + } else { + error = NBD_EOVERFLOW; //TODO + sendflag = 0; + // LWIP_DEBUGF(NBD_DEBUG | LWIP_DBG_STATE, ("nbd: error read\n")); + } + } + + reply.error = ntohl(error); + r = send(client_socket, &reply, sizeof(struct nbd_simple_reply), + 0); + + break; + + case NBD_CMD_DISC: + //TODO + goto soft_disconnect; + break; + + case NBD_CMD_FLUSH: + ctx->flush(ctx); + break; + + case NBD_CMD_TRIM: + case NBD_CMD_CACHE: + case NBD_CMD_WRITE_ZEROES: + case NBD_CMD_BLOCK_STATUS: + default: + /* NBD_REP_ERR_INVALID */ + goto error; + } + } + +soft_disconnect: + return 0; +error: + return -1; +} + +/** @ingroup nbd + * Initialize NBD server. + * @param ctx NBD callback struct + */ +int nbd_init(struct nbd_context **ctx) +{ + int tcp_socket, client_socket = -1; + struct sockaddr_in peer; + socklen_t addrlen; + register int r; + struct nbd_context *ctxt; + + peer.sin_family = AF_INET; + peer.sin_port = htons(NBD_SERVER_PORT); + peer.sin_addr.s_addr = htonl(INADDR_ANY); + + while (1) { + + tcp_socket = socket(AF_INET, SOCK_STREAM, 0); + if (tcp_socket < 0) + goto error; + + r = bind(tcp_socket, (struct sockaddr *)&peer, sizeof(peer)); + if (r < 0) + goto error; + + r = listen(tcp_socket, 3); + if (r < 0) + goto error; + + while (1) { + + addrlen = sizeof(peer); + client_socket = accept(tcp_socket, (struct sockaddr *)&peer, + &addrlen); + if (client_socket < 0) + goto error; + + ctxt = negotiation_phase(client_socket, ctx); + if (ctxt != NULL) + transmission_phase(client_socket, ctxt); + + closesocket(client_socket); + } + + error: + printf("Error: failed to nbd_init"); + closesocket(tcp_socket); + } +} diff --git a/modules/network/lwnbdsvr/lwNBD/nbd_server.h b/modules/network/lwnbdsvr/lwNBD/nbd_server.h new file mode 100644 index 000000000..e0387163e --- /dev/null +++ b/modules/network/lwnbdsvr/lwNBD/nbd_server.h @@ -0,0 +1,146 @@ +/****************************************************************/ /** + * + * @file nbd_server.h + * + * @author Ronan Bignaux + * + * @brief Network Block Device Protocol implementation options + * + * Copyright (c) Ronan Bignaux. 2021 + * All rights reserved. + * + ********************************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification,are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Ronan Bignaux + * + */ + +#ifndef LWIP_HDR_APPS_NBD_SERVER_H +#define LWIP_HDR_APPS_NBD_SERVER_H + +#include "nbd-protocol.h" +#include "nbd_opts.h" + +//#include "lwip/apps/nbd_opts.h" +//#include "lwip/err.h" +//#include "lwip/pbuf.h" +//#include "lwip/mem.h" + +#ifdef PS2SDK +#include +#include +#include +#include +//#include +//#include + +//TODO: Missing in PS2SDK +// pickup from https://gist.github.com/jtbr/7a43e6281e6cca353b33ee501421860c +static inline uint64_t bswap64(uint64_t x) +{ + return (((x & 0xff00000000000000ull) >> 56) | ((x & 0x00ff000000000000ull) >> 40) | ((x & 0x0000ff0000000000ull) >> 24) | ((x & 0x000000ff00000000ull) >> 8) | ((x & 0x00000000ff000000ull) << 8) | ((x & 0x0000000000ff0000ull) << 24) | ((x & 0x000000000000ff00ull) << 40) | ((x & 0x00000000000000ffull) << 56)); +} + +//TODO: Missing in PS2SK's "common/include/tcpip.h" +#if __BIG_ENDIAN__ +#define htonll(x) (x) +#define ntohll(x) (x) +#else +#define htonll(x) bswap64(x) +#define ntohll(x) bswap64(x) +#endif + +//TODO: Missing in PS2SK's , needed for "nbd-protocol.h" +// https://en.cppreference.com/w/c/types/integer +#define UINT64_MAX 0xffffffffffffffff +#define UINT64_C(x) ((x) + (UINT64_MAX - UINT64_MAX)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +//extern uint8_t buffer[]; +uint8_t nbd_buffer[NBD_BUFFER_LEN] __attribute__((aligned(64))); + +/** @ingroup nbd + * NBD context containing callback functions for NBD transfers + * https://github.com/QuantumLeaps/OOP-in-C/blob/master/AN_OOP_in_C.pdf + */ + +struct nbd_context +{ + + char export_name[32]; + char export_desc[64]; + uint64_t export_size; /* size of export in byte */ + uint16_t eflags; /* per-export flags */ + uint8_t blockshift; /* in power of 2 for bit shifting - log2(blocksize) */ + uint8_t *buffer; + /** + * block device + * @param + * @returns + */ + int (*export_init)(struct nbd_context *me); + /** + * Close block device handle + * @param handle File handle returned by open() + */ + // void (*close)(struct nbd_context *me); + /** + * Read from block device + * @param + * @param buffer Target buffer to copy read data to + * @param offset Offset in block to copy read data to + * @param length Number of blocks to copy to buffer + * @returns >= 0: Success; < 0: Error + */ + int (*read)(struct nbd_context *me, void *buffer, uint64_t offset, uint32_t length); + /** + * Write to block device + * @param me () + * @param buffer Target buffer to copy write data to + * @param offset Offset in block to copy write data to + * @param length Number of blocks to copy to buffer + * @returns >= 0: Success; < 0: Error + */ + int (*write)(struct nbd_context *me, void *buffer, uint64_t offset, uint32_t length); + /** + * Flush to block device + * @param me () + * @returns >= 0: Success; < 0: Error + */ + int (*flush)(struct nbd_context *me); +}; + +int nbd_init(struct nbd_context **ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_APPS_NBD_SERVER_H */ diff --git a/modules/network/lwnbdsvr/lwnbdsvr.c b/modules/network/lwnbdsvr/lwnbdsvr.c new file mode 100644 index 000000000..3e52afd39 --- /dev/null +++ b/modules/network/lwnbdsvr/lwnbdsvr.c @@ -0,0 +1,38 @@ + +#include "irx_imports.h" +#include "lwNBD/nbd_server.h" +#include "drivers/drivers.h" + +#define MODNAME "lwnbdsvr" +IRX_ID(MODNAME, 1, 1); +static int nbd_tid; +struct irx_export_table _exp_lwnbdsvr; + +int _start(int argc, char **argv) +{ + iop_thread_t nbd_thread; + + //TODO : platform specific block device detection then nbd_context initialization go here + //TODO : many export in a loop + if (nbd_contexts[0]->export_init(nbd_contexts[0]) != 0) + return -1; + + // register exports + RegisterLibraryEntries(&_exp_lwnbdsvr); + + nbd_thread.attr = TH_C; + nbd_thread.thread = (void *)nbd_init; + nbd_thread.priority = 0x10; + nbd_thread.stacksize = 0x800; + nbd_thread.option = 0; + nbd_tid = CreateThread(&nbd_thread); + + StartThread(nbd_tid, (struct nbd_context **)nbd_contexts); + return MODULE_RESIDENT_END; +} + +int _shutdown(void) +{ + DeleteThread(nbd_tid); + return 0; +} diff --git a/src/lang.c b/src/lang.c index 88da2da41..ef24911f7 100644 --- a/src/lang.c +++ b/src/lang.c @@ -75,11 +75,11 @@ static char *internalEnglish[LANG_STR_COUNT] = { "Applications Start Mode", "Auto", "Manual", - "Start HDL Server", - "HDL Server starting...", - "HDL Server running...", - "Failed to start HDL Server.", - "HDL Server unloading...", + "Start NBD Server", + "NBD Server starting...", + "NBD Server running...", + "Failed to start NBD Server.", + "NBD Server unloading...", "IGR Path", "Background Color", "Text Color", diff --git a/src/menusys.c b/src/menusys.c index 6f830afd5..1048e01a7 100644 --- a/src/menusys.c +++ b/src/menusys.c @@ -26,7 +26,7 @@ enum MENU_IDs { MENU_PARENTAL_LOCK, MENU_NET_CONFIG, MENU_NET_UPDATE, - MENU_START_HDL, + MENU_START_NBD, MENU_ABOUT, MENU_SAVE_CHANGES, MENU_EXIT, @@ -209,7 +209,7 @@ static void menuInitMainMenu(void) submenuAppendItem(&mainMenu, -1, NULL, MENU_NET_CONFIG, _STR_NETCONFIG); submenuAppendItem(&mainMenu, -1, NULL, MENU_NET_UPDATE, _STR_NET_UPDATE); if (gHDDStartMode && gEnableWrite) // enabled at all? - submenuAppendItem(&mainMenu, -1, NULL, MENU_START_HDL, _STR_STARTHDL); + submenuAppendItem(&mainMenu, -1, NULL, MENU_START_NBD, _STR_STARTNBD); submenuAppendItem(&mainMenu, -1, NULL, MENU_ABOUT, _STR_ABOUT); submenuAppendItem(&mainMenu, -1, NULL, MENU_SAVE_CHANGES, _STR_SAVE_CHANGES); submenuAppendItem(&mainMenu, -1, NULL, MENU_EXIT, _STR_EXIT); @@ -839,9 +839,9 @@ void menuHandleInputMenu() } else if (id == MENU_NET_UPDATE) { if (menuCheckParentalLock() == 0) guiShowNetCompatUpdate(); - } else if (id == MENU_START_HDL) { + } else if (id == MENU_START_NBD) { if (menuCheckParentalLock() == 0) - handleHdlSrv(); + handleLwnbdSrv(); } else if (id == MENU_ABOUT) { guiShowAbout(); } else if (id == MENU_SAVE_CHANGES) { diff --git a/src/opl.c b/src/opl.c index 12388b9b0..2074a2e5a 100644 --- a/src/opl.c +++ b/src/opl.c @@ -1360,13 +1360,13 @@ int oplUpdateGameCompatSingle(int id, item_list_t *support, config_set_t *config } // ---------------------------------------------------------- -// -------------------- HD SRV Support ---------------------- +// -------------------- NBD SRV Support --------------------- // ---------------------------------------------------------- -static int loadHdldSvr(void) +static int loadLwnbdSvr(void) { int ret, padStatus; - // deint audio lib while hdl server is running + // deint audio lib while nbd server is running sfxEnd(); // block all io ops, wait for the ones still running to finish @@ -1385,7 +1385,7 @@ static int loadHdldSvr(void) if (ret == 0) { ret = sysLoadModuleBuffer(&ps2atad_irx, size_ps2atad_irx, 0, NULL); if (ret >= 0) { - ret = sysLoadModuleBuffer(&hdldsvr_irx, size_hdldsvr_irx, 0, NULL); + ret = sysLoadModuleBuffer(&lwnbdsvr_irx, size_lwnbdsvr_irx, 0, NULL); if (ret >= 0) ret = 0; } @@ -1403,7 +1403,7 @@ static int loadHdldSvr(void) return ret; } -static void unloadHdldSvr(void) +static void unloadLwnbdSvr(void) { ethDeinitModules(); unloadPads(); @@ -1430,18 +1430,21 @@ static void unloadHdldSvr(void) ioPutRequest(IO_CUSTOM_SIMPLEACTION, &deferredAudioInit); } -void handleHdlSrv() +void handleLwnbdSrv() { - // prepare for hdl, display screen with info - guiRenderTextScreen(_l(_STR_STARTINGHDL)); - if (loadHdldSvr() == 0) - guiMsgBox(_l(_STR_RUNNINGHDL), 0, NULL); - else - guiMsgBox(_l(_STR_STARTFAILHDL), 0, NULL); + char temp[256]; + // prepare for lwnbd, display screen with info + guiRenderTextScreen(_l(_STR_STARTINGNBD)); + if (loadLwnbdSvr() == 0) { + snprintf(temp, sizeof(temp), "%s\nIP: %d.%d.%d.%d %s", _l(_STR_RUNNINGNBD), + ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3], ps2_ip_use_dhcp ? "DHCP" : ""); + guiMsgBox(temp, 0, NULL); + } else + guiMsgBox(_l(_STR_STARTFAILNBD), 0, NULL); // restore normal functionality again - guiRenderTextScreen(_l(_STR_UNLOADHDL)); - unloadHdldSvr(); + guiRenderTextScreen(_l(_STR_UNLOADNBD)); + unloadLwnbdSvr(); } // ----------------------------------------------------------