diff --git a/doc/rascsi.1 b/doc/rascsi.1 index d287b791..8954e32b 100644 --- a/doc/rascsi.1 +++ b/doc/rascsi.1 @@ -84,7 +84,7 @@ Overrides the default locale for client-faces error messages. The client can ove .BR \-ID\fIn[:u] " " \fIFILE n is the SCSI ID number (0-7). u (0-31) is the optional LUN (logical unit). The default LUN is 0. .IP -FILE is the name of the image file to use for the SCSI device. For devices that do not support an image file (SCBR, SCDP, SCLP, SCHS) the filename may have a special meaning or a dummy name can be provided. For SCBR and SCDP it is an optioinal prioritized list of network interfaces, e.g. "interfaces=eth0,eth1,wlan0". For SCLP it is the print command to be used and a reservation timeout in seconds, e.g. "cmd=lp -oraw:timeout=60". +FILE is the name of the image file to use for the SCSI device. For devices that do not support an image file (SCBR, SCDP, SCLP, SCHS) the filename may have a special meaning or a dummy name can be provided. For SCBR and SCDP it is an optioinal prioritized list of network interfaces, an optional IP address and netmask, e.g. "interfaces=eth0,eth1,wlan0:inet=10.10.20.1/24". For SCLP it is the print command to be used and a reservation timeout in seconds, e.g. "cmd=lp -oraw %f:timeout=60". .TP .BR \-HD\fIn[:u] " " \fIFILE n is the SASI ID number (0-15). The effective SASI ID is calculated as n/2, the effective SASI LUN is calculated is the remainder of n/2. Alternatively the n:u syntax can be used, where ns is the SASI ID (0-7) and u the LUN (0-1). diff --git a/doc/rascsi_man_page.txt b/doc/rascsi_man_page.txt index 359c738d..12bbb4c4 100644 --- a/doc/rascsi_man_page.txt +++ b/doc/rascsi_man_page.txt @@ -111,10 +111,10 @@ OPTIONS For devices that do not support an image file (SCBR, SCDP, SCLP, SCHS) the filename may have a special meaning or a dummy name can be provided. For SCBR and SCDP it is an optioinal priori‐ - tized list of network interfaces, e.g. "inter‐ - faces=eth0,eth1,wlan0". For SCLP it is the print command to be - used and a reservation timeout in seconds, e.g. "cmd=lp - -oraw:timeout=60". + tized list of network interfaces, an optional IP address and + netmask, e.g. "interfaces=eth0,eth1,wlan0:inet=10.10.20.1/24". + For SCLP it is the print command to be used and a reservation + timeout in seconds, e.g. "cmd=lp -oraw %f:timeout=60". -HDn[:u] FILE n is the SASI ID number (0-15). The effective SASI ID is calcu‐ diff --git a/src/raspberrypi/controllers/scsidev_ctrl.h b/src/raspberrypi/controllers/scsidev_ctrl.h index 55c4ca15..9a3621cd 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.h +++ b/src/raspberrypi/controllers/scsidev_ctrl.h @@ -70,7 +70,7 @@ public: ERROR_CODES::asc asc = ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION, ERROR_CODES::status status = ERROR_CODES::status::CHECK_CONDITION) override; - void ShutDown(rascsi_shutdown_mode shutdown_mode) { this->shutdown_mode = shutdown_mode; } + void ScheduleShutDown(rascsi_shutdown_mode shutdown_mode) { this->shutdown_mode = shutdown_mode; } int GetInitiatorId() const { return scsi.initiator_id; } bool IsByteTransfer() const { return scsi.is_byte_transfer; } diff --git a/src/raspberrypi/devices/ctapdriver.cpp b/src/raspberrypi/devices/ctapdriver.cpp index 06c0664d..0b9de36e 100644 --- a/src/raspberrypi/devices/ctapdriver.cpp +++ b/src/raspberrypi/devices/ctapdriver.cpp @@ -20,25 +20,22 @@ #include #include #endif +// TODO Try to get rid of zlib, there is only one operation using it #include // For crc32() #include "os.h" #include "ctapdriver.h" #include "log.h" +#include "rasutil.h" #include "exceptions.h" #include +#define BRIDGE_NAME "rascsi_bridge" + using namespace std; +using namespace ras_util; -CTapDriver::CTapDriver(const string& interfaces) +CTapDriver::CTapDriver() { - stringstream s(interfaces); - string interface; - while (getline(s, interface, ',')) { - this->interfaces.push_back(interface); - } - - // Initialization - m_bTxValid = FALSE; m_hTAP = -1; memset(&m_MacAddr, 0, sizeof(m_MacAddr)); m_pcap = NULL; @@ -52,28 +49,28 @@ CTapDriver::CTapDriver(const string& interfaces) //--------------------------------------------------------------------------- #ifdef __linux__ -static BOOL br_setif(int br_socket_fd, const char* bridgename, const char* ifname, BOOL add) { +static bool br_setif(int br_socket_fd, const char* bridgename, const char* ifname, bool add) { struct ifreq ifr; ifr.ifr_ifindex = if_nametoindex(ifname); if (ifr.ifr_ifindex == 0) { - LOGERROR("Error: can't if_nametoindex. Errno: %d %s", errno, strerror(errno)); - return FALSE; + LOGERROR("Can't if_nametoindex: %s", strerror(errno)); + return false; } strncpy(ifr.ifr_name, bridgename, IFNAMSIZ); if (ioctl(br_socket_fd, add ? SIOCBRADDIF : SIOCBRDELIF, &ifr) < 0) { - LOGERROR("Error: can't ioctl %s. Errno: %d %s", add ? "SIOCBRADDIF" : "SIOCBRDELIF", errno, strerror(errno)); - return FALSE; + LOGERROR("Can't ioctl %s: %s", add ? "SIOCBRADDIF" : "SIOCBRDELIF", strerror(errno)); + return false; } - return TRUE; + return true; } -static BOOL ip_link(int fd, const char* ifname, BOOL up) { +static bool ip_link(int fd, const char* ifname, bool up) { struct ifreq ifr; strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); // Need to save room for null terminator int err = ioctl(fd, SIOCGIFFLAGS, &ifr); if (err) { - LOGERROR("Error: can't ioctl SIOCGIFFLAGS. Errno: %d %s", errno, strerror(errno)); - return FALSE; + LOGERROR("Can't ioctl SIOCGIFFLAGS: %s", strerror(errno)); + return false; } ifr.ifr_flags &= ~IFF_UP; if (up) { @@ -81,10 +78,10 @@ static BOOL ip_link(int fd, const char* ifname, BOOL up) { } err = ioctl(fd, SIOCSIFFLAGS, &ifr); if (err) { - LOGERROR("Error: can't ioctl SIOCSIFFLAGS. Errno: %d %s", errno, strerror(errno)); - return FALSE; + LOGERROR("Can't ioctl SIOCSIFFLAGS: %s", strerror(errno)); + return false; } - return TRUE; + return true; } static bool is_interface_up(const string& interface) { @@ -105,12 +102,33 @@ static bool is_interface_up(const string& interface) { return status; } -bool CTapDriver::Init() +bool CTapDriver::Init(const map& const_params) { + map params = const_params; + if (params.count("interfaces")) { + LOGWARN("You are using the deprecated 'interfaces' parameter. " + "Provide the interface list and the IP address/netmask with the 'interface' and 'inet' parameters"); + + // TODO Remove the deprecated syntax in a future version + const string& interfaces = params["interfaces"]; + size_t separatorPos = interfaces.find(':'); + if (separatorPos != string::npos) { + params["interface"] = interfaces.substr(0, separatorPos); + params["inet"] = interfaces.substr(separatorPos + 1); + } + } + + stringstream s(params["interface"]); + string interface; + while (getline(s, interface, ',')) { + this->interfaces.push_back(interface); + } + this->inet = params["inet"]; + LOGTRACE("Opening Tap device"); // TAP device initilization if ((m_hTAP = open("/dev/net/tun", O_RDWR)) < 0) { - LOGERROR("Error: can't open tun. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't open tun: %s", strerror(errno)); return false; } @@ -127,17 +145,17 @@ bool CTapDriver::Init() int ret = ioctl(m_hTAP, TUNSETIFF, (void *)&ifr); if (ret < 0) { - LOGERROR("Error: can't ioctl TUNSETIFF. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't ioctl TUNSETIFF: %s", strerror(errno)); close(m_hTAP); return false; } - LOGTRACE("return code from ioctl was %d", ret); + LOGTRACE("Return code from ioctl was %d", ret); int ip_fd = socket(PF_INET, SOCK_DGRAM, 0); if (ip_fd < 0) { - LOGERROR("Error: can't open ip socket. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't open ip socket: %s", strerror(errno)); close(m_hTAP); return false; @@ -145,7 +163,7 @@ bool CTapDriver::Init() int br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (br_socket_fd < 0) { - LOGERROR("Error: can't open bridge socket. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't open bridge socket: %s", strerror(errno)); close(m_hTAP); close(ip_fd); @@ -153,36 +171,23 @@ bool CTapDriver::Init() } // Check if the bridge has already been created - if (access("/sys/class/net/rascsi_bridge", F_OK)) { - LOGINFO("rascsi_bridge is not yet available"); + string sys_file = "/sys/class/net/"; + sys_file += BRIDGE_NAME; + if (access(sys_file.c_str(), F_OK)) { + LOGINFO("%s is not yet available", BRIDGE_NAME); LOGTRACE("Checking which interface is available for creating the bridge"); string bridge_interface; - string bridge_ip; - for (const string& iface : interfaces) { - string interface; - size_t separatorPos = iface.find(':'); - if (separatorPos != string::npos) { - interface = iface.substr(0, separatorPos); - bridge_ip = iface.substr(separatorPos + 1); - } - else { - interface = iface; - bridge_ip = "10.10.20.1/24"; - } - - ostringstream msg; + for (const string& interface : interfaces) { if (is_interface_up(interface)) { - msg << "Interface " << interface << " is up"; - LOGTRACE("%s", msg.str().c_str()); + LOGTRACE("%s", string("Interface " + interface + " is up").c_str()); bridge_interface = interface; break; } else { - msg << "Interface " << interface << " is not available or is not up"; - LOGTRACE("%s", msg.str().c_str()); + LOGTRACE("%s", string("Interface " + interface + " is not available or is not up").c_str()); } } @@ -191,13 +196,13 @@ bool CTapDriver::Init() return false; } - LOGINFO("Creating rascsi_bridge for interface %s", bridge_interface.c_str()); + LOGINFO("Creating %s for interface %s", BRIDGE_NAME, bridge_interface.c_str()); if (bridge_interface == "eth0") { - LOGDEBUG("brctl addbr rascsi_bridge"); + LOGTRACE("brctl addbr %s", BRIDGE_NAME); - if ((ret = ioctl(br_socket_fd, SIOCBRADDBR, "rascsi_bridge")) < 0) { - LOGERROR("Error: can't ioctl SIOCBRADDBR. Errno: %d %s", errno, strerror(errno)); + if ((ret = ioctl(br_socket_fd, SIOCBRADDBR, BRIDGE_NAME)) < 0) { + LOGERROR("Can't ioctl SIOCBRADDBR: %s", strerror(errno)); close(m_hTAP); close(ip_fd); @@ -205,9 +210,9 @@ bool CTapDriver::Init() return false; } - LOGDEBUG("brctl addif rascsi_bridge %s", bridge_interface.c_str()); + LOGTRACE("brctl addif %s %s", BRIDGE_NAME, bridge_interface.c_str()); - if (!br_setif(br_socket_fd, "rascsi_bridge", bridge_interface.c_str(), TRUE)) { + if (!br_setif(br_socket_fd, BRIDGE_NAME, bridge_interface.c_str(), true)) { close(m_hTAP); close(ip_fd); close(br_socket_fd); @@ -215,38 +220,34 @@ bool CTapDriver::Init() } } else { - LOGDEBUG("ip address add %s dev rascsi_bridge", bridge_ip.c_str()); - - string address = bridge_ip; + string address = inet; string netmask = "255.255.255.0"; - size_t separatorPos = bridge_ip.find('/'); + size_t separatorPos = inet.find('/'); if (separatorPos != string::npos) { - address = bridge_ip.substr(0, separatorPos); + address = inet.substr(0, separatorPos); - string mask = bridge_ip.substr(separatorPos + 1); - if (mask == "8") { - netmask = "255.0.0.0"; - } - else if (mask == "16") { - netmask = "255.255.0.0"; - } - else if (mask == "24") { - netmask = "255.255.255.0"; - } - else { - LOGERROR("Error: Invalid netmask in %s", bridge_ip.c_str()); + int m; + if (!GetAsInt(inet.substr(separatorPos + 1), m) || m < 8 || m > 32) { + LOGERROR("Invalid CIDR netmask notation '%s'", inet.substr(separatorPos + 1).c_str()); close(m_hTAP); close(ip_fd); close(br_socket_fd); return false; } + + // long long is required for compatibility with 32 bit platforms + long long mask = pow(2, 32) - (1 << (32 - m)); + char buf[16]; + sprintf(buf, "%lld.%lld.%lld.%lld", (mask >> 24) & 0xff, (mask >> 16) & 0xff, (mask >> 8) & 0xff, + mask & 0xff); + netmask = buf; } - LOGDEBUG("brctl addbr rascsi_bridge"); + LOGTRACE("brctl addbr %s", BRIDGE_NAME); - if ((ret = ioctl(br_socket_fd, SIOCBRADDBR, "rascsi_bridge")) < 0) { - LOGERROR("Error: can't ioctl SIOCBRADDBR. Errno: %d %s", errno, strerror(errno)); + if ((ret = ioctl(br_socket_fd, SIOCBRADDBR, BRIDGE_NAME)) < 0) { + LOGERROR("Can't ioctl SIOCBRADDBR: %s", strerror(errno)); close(m_hTAP); close(ip_fd); @@ -254,20 +255,36 @@ bool CTapDriver::Init() return false; } - LOGDEBUG("ip address add %s dev rascsi_bridge", bridge_ip.c_str()); - struct ifreq ifr_a; ifr_a.ifr_addr.sa_family = AF_INET; - strncpy(ifr_a.ifr_name, "rascsi_bridge", IFNAMSIZ); + strncpy(ifr_a.ifr_name, BRIDGE_NAME, IFNAMSIZ); struct sockaddr_in* addr = (struct sockaddr_in*)&ifr_a.ifr_addr; - inet_pton(AF_INET, address.c_str(), &addr->sin_addr); + if (inet_pton(AF_INET, address.c_str(), &addr->sin_addr) != 1) { + LOGERROR("Can't convert '%s' into a network address: %s", address.c_str(), strerror(errno)); + + close(m_hTAP); + close(ip_fd); + close(br_socket_fd); + return false; + } + struct ifreq ifr_n; ifr_n.ifr_addr.sa_family = AF_INET; - strncpy(ifr_n.ifr_name, "rascsi_bridge", IFNAMSIZ); + strncpy(ifr_n.ifr_name, BRIDGE_NAME, IFNAMSIZ); struct sockaddr_in* mask = (struct sockaddr_in*)&ifr_n.ifr_addr; - inet_pton(AF_INET, netmask.c_str(), &mask->sin_addr); + if (inet_pton(AF_INET, netmask.c_str(), &mask->sin_addr) != 1) { + LOGERROR("Can't convert '%s' into a netmask: %s", netmask.c_str(), strerror(errno)); + + close(m_hTAP); + close(ip_fd); + close(br_socket_fd); + return false; + } + + LOGTRACE("ip address add %s dev %s", inet.c_str(), BRIDGE_NAME); + if (ioctl(ip_fd, SIOCSIFADDR, &ifr_a) < 0 || ioctl(ip_fd, SIOCSIFNETMASK, &ifr_n) < 0) { - LOGERROR("Error: can't ioctl SIOCSIFADDR or SIOCSIFNETMASK. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't ioctl SIOCSIFADDR or SIOCSIFNETMASK: %s", strerror(errno)); close(m_hTAP); close(ip_fd); @@ -276,9 +293,9 @@ bool CTapDriver::Init() } } - LOGDEBUG("ip link set dev rascsi_bridge up"); + LOGTRACE("ip link set dev %s up", BRIDGE_NAME); - if (!ip_link(ip_fd, "rascsi_bridge", TRUE)) { + if (!ip_link(ip_fd, BRIDGE_NAME, true)) { close(m_hTAP); close(ip_fd); close(br_socket_fd); @@ -287,21 +304,21 @@ bool CTapDriver::Init() } else { - LOGINFO("rascsi_bridge is already available"); + LOGINFO("%s is already available", BRIDGE_NAME); } - LOGDEBUG("ip link set ras0 up"); + LOGTRACE("ip link set ras0 up"); - if (!ip_link(ip_fd, "ras0", TRUE)) { + if (!ip_link(ip_fd, "ras0", true)) { close(m_hTAP); close(ip_fd); close(br_socket_fd); return false; } - LOGDEBUG("brctl addif rascsi_bridge ras0"); + LOGTRACE("brctl addif %s ras0", BRIDGE_NAME); - if (!br_setif(br_socket_fd, "rascsi_bridge", "ras0", TRUE)) { + if (!br_setif(br_socket_fd, BRIDGE_NAME, "ras0", true)) { close(m_hTAP); close(ip_fd); close(br_socket_fd); @@ -313,7 +330,7 @@ bool CTapDriver::Init() ifr.ifr_addr.sa_family = AF_INET; if ((ret = ioctl(m_hTAP, SIOCGIFHWADDR, &ifr)) < 0) { - LOGERROR("Error: can't ioctl SIOCGIFHWADDR. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't ioctl SIOCGIFHWADDR: %s", strerror(errno)); close(m_hTAP); close(ip_fd); @@ -335,27 +352,27 @@ bool CTapDriver::Init() #endif // __linux__ #ifdef __NetBSD__ -BOOL CTapDriver::Init() +bool CTapDriver::Init(const map&) { struct ifreq ifr; struct ifaddrs *ifa, *a; // TAP Device Initialization if ((m_hTAP = open("/dev/tap", O_RDWR)) < 0) { - LOGERROR("Error: can't open tap. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't open tap: %s", strerror(errno)); return false; } // Get device name if (ioctl(m_hTAP, TAPGIFNAME, (void *)&ifr) < 0) { - LOGERROR("Error: can't ioctl TAPGIFNAME. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't ioctl TAPGIFNAME: %s", strerror(errno)); close(m_hTAP); return false; } // Get MAC address if (getifaddrs(&ifa) == -1) { - LOGERROR("Error: can't getifaddrs. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't getifaddrs: %s", strerror(errno)); close(m_hTAP); return false; } @@ -364,7 +381,7 @@ BOOL CTapDriver::Init() a->ifa_addr->sa_family == AF_LINK) break; if (a == NULL) { - LOGERROR("Error: can't get MAC addressErrno: %d %s", errno, strerror(errno)); + LOGERROR("Can't get MAC address: %s", strerror(errno)); close(m_hTAP); return false; } @@ -374,7 +391,7 @@ BOOL CTapDriver::Init() sizeof(m_MacAddr)); freeifaddrs(ifa); - LOGINFO("Tap device : %s\n", ifr.ifr_name); + LOGINFO("Tap device: %s\n", ifr.ifr_name); return true; } @@ -389,26 +406,21 @@ void CTapDriver::OpenDump(const Filepath& path) { } m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath()); if (m_pcap_dumper == NULL) { - LOGERROR("Error: can't open pcap file: %s", pcap_geterr(m_pcap)); + LOGERROR("Can't open pcap file: %s", pcap_geterr(m_pcap)); throw io_exception("Can't open pcap file"); } LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.GetPath()); } -//--------------------------------------------------------------------------- -// -// Cleanup -// -//--------------------------------------------------------------------------- void CTapDriver::Cleanup() { int br_socket_fd = -1; if ((br_socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { - LOGERROR("Error: can't open bridge socket. Errno: %d %s", errno, strerror(errno)); + LOGERROR("Can't open bridge socket: %s", strerror(errno)); } else { - LOGDEBUG("brctl delif rascsi_bridge ras0"); - if (!br_setif(br_socket_fd, "rascsi_bridge", "ras0", FALSE)) { + LOGDEBUG("brctl delif %s ras0", BRIDGE_NAME); + if (!br_setif(br_socket_fd, BRIDGE_NAME, "ras0", false)) { LOGWARN("Warning: Removing ras0 from the bridge failed."); LOGWARN("You may need to manually remove the ras0 tap device from the bridge"); } @@ -432,50 +444,29 @@ void CTapDriver::Cleanup() } } -//--------------------------------------------------------------------------- -// -// Enable -// -//--------------------------------------------------------------------------- bool CTapDriver::Enable(){ int fd = socket(PF_INET, SOCK_DGRAM, 0); LOGDEBUG("%s: ip link set ras0 up", __PRETTY_FUNCTION__); - bool result = ip_link(fd, "ras0", TRUE); + bool result = ip_link(fd, "ras0", true); close(fd); return result; } -//--------------------------------------------------------------------------- -// -// Disable -// -//--------------------------------------------------------------------------- bool CTapDriver::Disable(){ int fd = socket(PF_INET, SOCK_DGRAM, 0); LOGDEBUG("%s: ip link set ras0 down", __PRETTY_FUNCTION__); - bool result = ip_link(fd, "ras0", FALSE); + bool result = ip_link(fd, "ras0", false); close(fd); return result; } -//--------------------------------------------------------------------------- -// -// Flush -// -//--------------------------------------------------------------------------- -BOOL CTapDriver::Flush(){ +void CTapDriver::Flush(){ LOGTRACE("%s", __PRETTY_FUNCTION__); while(PendingPackets()){ (void)Rx(m_garbage_buffer); } - return TRUE; } -//--------------------------------------------------------------------------- -// -// MGet MAC Address -// -//--------------------------------------------------------------------------- void CTapDriver::GetMacAddr(BYTE *mac) { ASSERT(mac); @@ -488,7 +479,7 @@ void CTapDriver::GetMacAddr(BYTE *mac) // Receive // //--------------------------------------------------------------------------- -BOOL CTapDriver::PendingPackets() +bool CTapDriver::PendingPackets() { struct pollfd fds; @@ -501,9 +492,9 @@ BOOL CTapDriver::PendingPackets() poll(&fds, 1, 0); LOGTRACE("%s %u revents", __PRETTY_FUNCTION__, fds.revents); if (!(fds.revents & POLLIN)) { - return FALSE; + return false; }else { - return TRUE; + return true; } } diff --git a/src/raspberrypi/devices/ctapdriver.h b/src/raspberrypi/devices/ctapdriver.h index 1d4f4c6f..0d55dc1f 100644 --- a/src/raspberrypi/devices/ctapdriver.h +++ b/src/raspberrypi/devices/ctapdriver.h @@ -17,6 +17,7 @@ #include #include "filepath.h" +#include #include #include @@ -24,6 +25,8 @@ #define ETH_FRAME_LEN 1514 #endif +using namespace std; + //=========================================================================== // // Linux Tap Driver @@ -31,25 +34,31 @@ //=========================================================================== class CTapDriver { -public: - CTapDriver(const std::string&); - ~CTapDriver() {}; +private: + + friend class SCSIDaynaPort; + friend class SCSIBR; + + CTapDriver(); + ~CTapDriver() {} + + bool Init(const map&); + +public: - bool Init(); void OpenDump(const Filepath& path); // Capture packets void Cleanup(); // Cleanup void GetMacAddr(BYTE *mac); // Get Mac Address int Rx(BYTE *buf); // Receive int Tx(const BYTE *buf, int len); // Send - BOOL PendingPackets(); // Check if there are IP packets available + bool PendingPackets(); // Check if there are IP packets available bool Enable(); // Enable the ras0 interface bool Disable(); // Disable the ras0 interface - BOOL Flush(); // Purge all of the packets that are waiting to be processed + void Flush(); // Purge all of the packets that are waiting to be processed private: BYTE m_MacAddr[6]; // MAC Address - BOOL m_bTxValid; // Send Valid Flag int m_hTAP; // File handle BYTE m_garbage_buffer[ETH_FRAME_LEN]; @@ -58,6 +67,8 @@ private: pcap_dumper_t *m_pcap_dumper; // Prioritized comma-separated list of interfaces to create the bridge for - std::vector interfaces; + vector interfaces; + + string inet; }; diff --git a/src/raspberrypi/devices/device.cpp b/src/raspberrypi/devices/device.cpp index 8e194967..83658f4a 100644 --- a/src/raspberrypi/devices/device.cpp +++ b/src/raspberrypi/devices/device.cpp @@ -121,6 +121,15 @@ const string Device::GetParam(const string& key) return params.find(key) != params.end() ? params[key] : ""; } +void Device::SetParams(const map& params) +{ + this->params = GetDefaultParams(); + + for (const auto& param : params) { + this->params[param.first] = param.second; + } +} + void Device::SetStatusCode(int status_code) { if (status_code) { diff --git a/src/raspberrypi/devices/device.h b/src/raspberrypi/devices/device.h index 3978eec0..aeb94d9d 100644 --- a/src/raspberrypi/devices/device.h +++ b/src/raspberrypi/devices/device.h @@ -171,7 +171,7 @@ public: void SupportsParams(bool supports_paams) { this->supports_params = supports_paams; } const map GetParams() const { return params; } const string GetParam(const string&); - void SetParams(const map& params) { this->params = params; } + void SetParams(const map&); const map GetDefaultParams() const { return default_params; } void SetDefaultParams(const map& default_params) { this->default_params = default_params; } diff --git a/src/raspberrypi/devices/device_factory.cpp b/src/raspberrypi/devices/device_factory.cpp index 2cd3eeac..86da4c23 100644 --- a/src/raspberrypi/devices/device_factory.cpp +++ b/src/raspberrypi/devices/device_factory.cpp @@ -51,8 +51,10 @@ DeviceFactory::DeviceFactory() network_interfaces += network_interface; } - default_params[SCBR]["interfaces"] = network_interfaces; - default_params[SCDP]["interfaces"] = network_interfaces; + default_params[SCBR]["interface"] = network_interfaces; + default_params[SCBR]["inet"] = "10.10.20.1/24"; + default_params[SCDP]["interface"] = network_interfaces; + default_params[SCDP]["inet"] = "10.10.20.1/24"; default_params[SCLP]["cmd"] = "lp -oraw %f"; default_params[SCLP]["timeout"] = "30"; diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index 0585ce44..2a444b76 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -67,9 +67,7 @@ Disk::~Disk() // Save disk cache if (IsReady()) { // Only if ready... - if (disk.dcache) { - disk.dcache->Save(); - } + FlushCache(); } // Clear disk cache @@ -118,6 +116,13 @@ void Disk::Open(const Filepath& path) SetLocked(false); } +void Disk::FlushCache() +{ + if (disk.dcache) { + disk.dcache->Save(); + } +} + void Disk::Rezero(SASIDEV *controller) { if (!CheckReady()) { @@ -369,8 +374,7 @@ void Disk::PreventAllowMediumRemoval(SASIDEV *controller) void Disk::SynchronizeCache10(SASIDEV *controller) { - // Flush the RaSCSI cache - disk.dcache->Save(); + FlushCache(); controller->Status(); } @@ -395,8 +399,7 @@ bool Disk::Eject(bool force) { bool status = Device::Eject(force); if (status) { - // Remove disk cache - disk.dcache->Save(); + FlushCache(); delete disk.dcache; disk.dcache = NULL; @@ -1030,8 +1033,7 @@ bool Disk::StartStop(const DWORD *cdb) } if (!start) { - // Flush the cache when stopping - disk.dcache->Save(); + FlushCache(); // Look at the eject bit and eject if necessary if (load) { diff --git a/src/raspberrypi/devices/disk.h b/src/raspberrypi/devices/disk.h index 84af03b5..68dd1d50 100644 --- a/src/raspberrypi/devices/disk.h +++ b/src/raspberrypi/devices/disk.h @@ -132,6 +132,7 @@ public: void SetBlockCount(uint32_t); bool CheckBlockAddress(SASIDEV *, access_mode); bool GetStartAndCount(SASIDEV *, uint64_t&, uint32_t&, access_mode); + void FlushCache(); protected: int ModeSense6(const DWORD *cdb, BYTE *buf); diff --git a/src/raspberrypi/devices/disk_track_cache.h b/src/raspberrypi/devices/disk_track_cache.h index 9154b534..846adacf 100644 --- a/src/raspberrypi/devices/disk_track_cache.h +++ b/src/raspberrypi/devices/disk_track_cache.h @@ -43,6 +43,9 @@ public: DiskTrack(); ~DiskTrack(); +private: + friend class DiskCache; + void Init(int track, int size, int sectors, BOOL raw = FALSE, off_t imgoff = 0); bool Load(const Filepath& path); bool Save(const Filepath& path); diff --git a/src/raspberrypi/devices/host_services.cpp b/src/raspberrypi/devices/host_services.cpp index 22852f85..f825e197 100644 --- a/src/raspberrypi/devices/host_services.cpp +++ b/src/raspberrypi/devices/host_services.cpp @@ -33,6 +33,7 @@ // #include "controllers/scsidev_ctrl.h" +#include "disk.h" #include "host_services.h" using namespace scsi_defs; @@ -67,18 +68,19 @@ void HostServices::StartStopUnit(SCSIDEV *controller) bool load = ctrl->cmd[4] & 0x02; if (!start) { - // Delete all other devices. This will also flush any caches. - for (const Device *device : devices) { - if (device != this) { - delete device; + // Flush any caches + for (Device *device : devices) { + Disk *disk = dynamic_cast(device); + if (disk) { + disk->FlushCache(); } } if (load) { - ((SCSIDEV *)controller)->ShutDown(SCSIDEV::rascsi_shutdown_mode::PI); + controller->ScheduleShutDown(SCSIDEV::rascsi_shutdown_mode::PI); } else { - ((SCSIDEV *)controller)->ShutDown(SCSIDEV::rascsi_shutdown_mode::RASCSI); + controller->ScheduleShutDown(SCSIDEV::rascsi_shutdown_mode::RASCSI); } controller->Status(); diff --git a/src/raspberrypi/devices/scsi_daynaport.cpp b/src/raspberrypi/devices/scsi_daynaport.cpp index b4d8ea8e..4c0aeaf7 100644 --- a/src/raspberrypi/devices/scsi_daynaport.cpp +++ b/src/raspberrypi/devices/scsi_daynaport.cpp @@ -66,12 +66,12 @@ bool SCSIDaynaPort::Dispatch(SCSIDEV *controller) bool SCSIDaynaPort::Init(const map& params) { - SetParams(params.empty() ? GetDefaultParams() : params); + SetParams(params); #ifdef __linux__ // TAP Driver Generation - m_tap = new CTapDriver(GetParam("interfaces")); - m_bTapEnable = m_tap->Init(); + m_tap = new CTapDriver(); + m_bTapEnable = m_tap->Init(GetParams()); if(!m_bTapEnable){ LOGERROR("Unable to open the TAP interface"); diff --git a/src/raspberrypi/devices/scsi_host_bridge.cpp b/src/raspberrypi/devices/scsi_host_bridge.cpp index e490f6a2..d9be4579 100644 --- a/src/raspberrypi/devices/scsi_host_bridge.cpp +++ b/src/raspberrypi/devices/scsi_host_bridge.cpp @@ -61,13 +61,12 @@ SCSIBR::~SCSIBR() bool SCSIBR::Init(const map& params) { - // Use default parameters if no parameters were provided - SetParams(params.empty() ? GetDefaultParams() : params); + SetParams(params); #ifdef __linux__ // TAP Driver Generation - tap = new CTapDriver(GetParam("interfaces")); - m_bTapEnable = tap->Init(); + tap = new CTapDriver(); + m_bTapEnable = tap->Init(GetParams()); if (!m_bTapEnable){ LOGERROR("Unable to open the TAP interface"); return false; diff --git a/src/raspberrypi/devices/scsi_printer.cpp b/src/raspberrypi/devices/scsi_printer.cpp index ba2e3f65..1c2b1409 100644 --- a/src/raspberrypi/devices/scsi_printer.cpp +++ b/src/raspberrypi/devices/scsi_printer.cpp @@ -29,6 +29,7 @@ // requires that the client uses a printer driver compatible with the respective printer, or that the // printing service on the Pi is configured to do any necessary conversions, or that the print command // applies any conversions on the file to be printed (%f) before passing it to the printing service. +// 'enscript' is an example for a conversion tool. // By attaching different devices/LUNs multiple printers (i.e. different print commands) are possible. // Note that the print command is not executed by root but with the permissions of the lp user. // @@ -60,7 +61,7 @@ SCSIPrinter::SCSIPrinter() : PrimaryDevice("SCLP"), ScsiPrinterCommands() dispatcher.AddCommand(eCmdReserve6, "ReserveUnit", &SCSIPrinter::ReserveUnit); dispatcher.AddCommand(eCmdRelease6, "ReleaseUnit", &SCSIPrinter::ReleaseUnit); dispatcher.AddCommand(eCmdWrite6, "Print", &SCSIPrinter::Print); - dispatcher.AddCommand(eCmdReadCapacity10, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer); + dispatcher.AddCommand(eCmdSynchronizeBuffer, "SynchronizeBuffer", &SCSIPrinter::SynchronizeBuffer); dispatcher.AddCommand(eCmdSendDiag, "SendDiagnostic", &SCSIPrinter::SendDiagnostic); dispatcher.AddCommand(eCmdStartStop, "StopPrint", &SCSIPrinter::StopPrint); } @@ -72,8 +73,7 @@ SCSIPrinter::~SCSIPrinter() bool SCSIPrinter::Init(const map& params) { - // Use default parameters if no parameters were provided - SetParams(params.empty() ? GetDefaultParams() : params); + SetParams(params); if (GetParam("cmd").find("%f") == string::npos) { LOGERROR("Missing filename specifier %s", "%f"); @@ -169,6 +169,8 @@ void SCSIPrinter::Print(SCSIDEV *controller) // TODO This device suffers from the statically allocated buffer size, // see https://github.com/akuker/RASCSI/issues/669 if (length > (uint32_t)controller->DEFAULT_BUFFER_SIZE) { + LOGERROR("Transfer buffer overflow"); + controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB); return; } @@ -236,7 +238,7 @@ void SCSIPrinter::StopPrint(SCSIDEV *controller) return; } - Cleanup(); + // Nothing to do, printing has not yet been started controller->Status(); } diff --git a/src/raspberrypi/devices/scsicd.cpp b/src/raspberrypi/devices/scsicd.cpp index a250c443..c2658dff 100644 --- a/src/raspberrypi/devices/scsicd.cpp +++ b/src/raspberrypi/devices/scsicd.cpp @@ -22,15 +22,10 @@ using namespace scsi_defs; //=========================================================================== // -// CD Track +// CD Track // //=========================================================================== -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- CDTrack::CDTrack(SCSICD *scsicd) { ASSERT(scsicd); @@ -49,20 +44,6 @@ CDTrack::CDTrack(SCSICD *scsicd) raw = false; } -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -CDTrack::~CDTrack() -{ -} - -//--------------------------------------------------------------------------- -// -// Init -// -//--------------------------------------------------------------------------- void CDTrack::Init(int track, DWORD first, DWORD last) { ASSERT(!valid); @@ -78,11 +59,6 @@ void CDTrack::Init(int track, DWORD first, DWORD last) last_lba = last; } -//--------------------------------------------------------------------------- -// -// Set Path -// -//--------------------------------------------------------------------------- void CDTrack::SetPath(bool cdda, const Filepath& path) { ASSERT(valid); @@ -94,11 +70,6 @@ void CDTrack::SetPath(bool cdda, const Filepath& path) imgpath = path; } -//--------------------------------------------------------------------------- -// -// Get Path -// -//--------------------------------------------------------------------------- void CDTrack::GetPath(Filepath& path) const { ASSERT(valid); @@ -107,11 +78,6 @@ void CDTrack::GetPath(Filepath& path) const path = imgpath; } -//--------------------------------------------------------------------------- -// -// Add Index -// -//--------------------------------------------------------------------------- void CDTrack::AddIndex(int index, DWORD lba) { ASSERT(valid); @@ -149,11 +115,6 @@ DWORD CDTrack::GetLast() const return last_lba; } -//--------------------------------------------------------------------------- -// -// Get the number of blocks -// -//--------------------------------------------------------------------------- DWORD CDTrack::GetBlocks() const { ASSERT(valid); @@ -163,11 +124,6 @@ DWORD CDTrack::GetBlocks() const return (DWORD)(last_lba - first_lba + 1); } -//--------------------------------------------------------------------------- -// -// Get track number -// -//--------------------------------------------------------------------------- int CDTrack::GetTrackNo() const { ASSERT(valid); @@ -220,11 +176,6 @@ bool CDTrack::IsAudio() const // //=========================================================================== -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- SCSICD::SCSICD() : Disk("SCCD"), ScsiMmcCommands(), FileSupport() { // NOT in raw format @@ -245,11 +196,6 @@ SCSICD::SCSICD() : Disk("SCCD"), ScsiMmcCommands(), FileSupport() dispatcher.AddCommand(eCmdGetEventStatusNotification, "GetEventStatusNotification", &SCSICD::GetEventStatusNotification); } -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- SCSICD::~SCSICD() { // Clear track @@ -262,11 +208,6 @@ bool SCSICD::Dispatch(SCSIDEV *controller) return dispatcher.Dispatch(this, controller) ? true : super::Dispatch(controller); } -//--------------------------------------------------------------------------- -// -// Open -// -//--------------------------------------------------------------------------- void SCSICD::Open(const Filepath& path) { off_t size; @@ -334,21 +275,11 @@ void SCSICD::Open(const Filepath& path) } } -//--------------------------------------------------------------------------- -// -// Open (CUE) -// -//--------------------------------------------------------------------------- void SCSICD::OpenCue(const Filepath& /*path*/) { throw io_exception("Opening CUE CD-ROM files is not supported"); } -//--------------------------------------------------------------------------- -// -// Open (ISO) -// -//--------------------------------------------------------------------------- void SCSICD::OpenIso(const Filepath& path) { // Open as read-only @@ -419,11 +350,6 @@ void SCSICD::OpenIso(const Filepath& path) dataindex = 0; } -//--------------------------------------------------------------------------- -// -// Open (Physical) -// -//--------------------------------------------------------------------------- void SCSICD::OpenPhysical(const Filepath& path) { // Open as read-only @@ -469,11 +395,6 @@ void SCSICD::ReadToc(SASIDEV *controller) controller->DataIn(); } -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf) { // EVPD check @@ -535,11 +456,6 @@ int SCSICD::Inquiry(const DWORD *cdb, BYTE *buf) return size; } -//--------------------------------------------------------------------------- -// -// READ -// -//--------------------------------------------------------------------------- int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block) { ASSERT(buf); @@ -584,11 +500,6 @@ int SCSICD::Read(const DWORD *cdb, BYTE *buf, uint64_t block) return Disk::Read(cdb, buf, block); } -//--------------------------------------------------------------------------- -// -// READ TOC -// -//--------------------------------------------------------------------------- int SCSICD::ReadToc(const DWORD *cdb, BYTE *buf) { ASSERT(cdb); @@ -741,11 +652,6 @@ void SCSICD::LBAtoMSF(DWORD lba, BYTE *msf) const msf[3] = (BYTE)f; } -//--------------------------------------------------------------------------- -// -// Clear Track -// -//--------------------------------------------------------------------------- void SCSICD::ClearTrack() { // delete the track object diff --git a/src/raspberrypi/devices/scsicd.h b/src/raspberrypi/devices/scsicd.h index fb87d47a..42150b5c 100644 --- a/src/raspberrypi/devices/scsicd.h +++ b/src/raspberrypi/devices/scsicd.h @@ -10,7 +10,7 @@ // Licensed under the BSD 3-Clause License. // See LICENSE file in the project root folder. // -// [ SCSI CD-ROM for Apple Macintosh ] +// [ SCSI CD-ROM ] // //--------------------------------------------------------------------------- #pragma once @@ -21,12 +21,6 @@ #include "interfaces/scsi_mmc_commands.h" #include "interfaces/scsi_primary_commands.h" - -//--------------------------------------------------------------------------- -// -// Class precedence definition -// -//--------------------------------------------------------------------------- class SCSICD; //=========================================================================== @@ -36,9 +30,14 @@ class SCSICD; //=========================================================================== class CDTrack { -public: +private: + + friend class SCSICD; + CDTrack(SCSICD *scsicd); - virtual ~CDTrack(); + virtual ~CDTrack() {} + +public: void Init(int track, DWORD first, DWORD last); diff --git a/src/raspberrypi/devices/scsihd.cpp b/src/raspberrypi/devices/scsihd.cpp index 58981a05..4451c0dc 100644 --- a/src/raspberrypi/devices/scsihd.cpp +++ b/src/raspberrypi/devices/scsihd.cpp @@ -26,11 +26,6 @@ // //=========================================================================== -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- SCSIHD::SCSIHD(bool removable) : Disk(removable ? "SCRM" : "SCHD") { } @@ -67,11 +62,6 @@ void SCSIHD::FinalizeSetup(const Filepath &path, off_t size) FileSupport::SetPath(path); } -//--------------------------------------------------------------------------- -// -// Reset -// -//--------------------------------------------------------------------------- void SCSIHD::Reset() { // Unlock and release attention @@ -83,11 +73,6 @@ void SCSIHD::Reset() SetStatusCode(STATUS_NOERROR); } -//--------------------------------------------------------------------------- -// -// Open -// -//--------------------------------------------------------------------------- void SCSIHD::Open(const Filepath& path) { ASSERT(!IsReady()); @@ -112,11 +97,6 @@ void SCSIHD::Open(const Filepath& path) FinalizeSetup(path, size); } -//--------------------------------------------------------------------------- -// -// INQUIRY -// -//--------------------------------------------------------------------------- int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf) { // EVPD check @@ -157,11 +137,6 @@ int SCSIHD::Inquiry(const DWORD *cdb, BYTE *buf) return size; } -//--------------------------------------------------------------------------- -// -// MODE SELECT -// -//--------------------------------------------------------------------------- bool SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length) { int size; diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index 16a4672c..5207b7a2 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -41,7 +41,8 @@ enum PbOperation { // Attach devices and return the new device list (PbDevicesInfo) // Parameters (depending on the device type): // "file": The filename relative to the default image folder - // "interfaces": A prioritized comma-separated list of interfaces to create a network bridge for + // "interface": A prioritized comma-separated list of interfaces to create a network bridge for + // "inet": The IP address and netmask for the network bridge // "cmd": The command to be used for printing, with "%f" as file placeholder // "timeout": The timeout for printer reservations in seconds ATTACH = 1; diff --git a/src/raspberrypi/rascsi_response.cpp b/src/raspberrypi/rascsi_response.cpp index 6bb9e4ae..8cda4412 100644 --- a/src/raspberrypi/rascsi_response.cpp +++ b/src/raspberrypi/rascsi_response.cpp @@ -369,8 +369,9 @@ PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result, int depth) PbOperationMetaData *meta_data = new PbOperationMetaData(); AddOperationParameter(meta_data, "name", "Image file name in case of a mass storage device"); - AddOperationParameter(meta_data, "interfaces", "Comma-separated prioritized network interface list"); - AddOperationParameter(meta_data, "cmd", "print command for the printer device"); + AddOperationParameter(meta_data, "interface", "Comma-separated prioritized network interface list"); + AddOperationParameter(meta_data, "inet", "IP address and netmask of the network bridge"); + AddOperationParameter(meta_data, "cmd", "Print command for the printer device"); AddOperationParameter(meta_data, "timeout", "Reservation timeout for the printer device in seconds"); CreateOperation(operation_info, meta_data, ATTACH, "Attach device, device-specific parameters are required"); diff --git a/src/raspberrypi/rasctl_display.cpp b/src/raspberrypi/rasctl_display.cpp index a7258e45..92172589 100644 --- a/src/raspberrypi/rasctl_display.cpp +++ b/src/raspberrypi/rasctl_display.cpp @@ -173,13 +173,12 @@ void RasctlDisplay::DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types bool isFirst = true; for (const auto& param : params) { if (!isFirst) { - cout << ":"; + cout << " "; } - cout << param.first << "=" << param.second; + cout << param.first << "=" << param.second << endl; isFirst = false; } - cout << endl; } if (properties.block_sizes_size()) { diff --git a/src/raspberrypi/scsi.h b/src/raspberrypi/scsi.h index e5e1e947..699dd15b 100644 --- a/src/raspberrypi/scsi.h +++ b/src/raspberrypi/scsi.h @@ -184,6 +184,7 @@ namespace scsi_defs { eCmdSetMcastAddr = 0x0D, // DaynaPort specific command eCmdEnableInterface = 0x0E, + eCmdSynchronizeBuffer = 0x10, eCmdInquiry = 0x12, eCmdModeSelect6 = 0x15, eCmdReserve6 = 0x16,