diff options
Diffstat (limited to 'src/osd/modules/netdev/taptun.cpp')
-rw-r--r-- | src/osd/modules/netdev/taptun.cpp | 170 |
1 files changed, 104 insertions, 66 deletions
diff --git a/src/osd/modules/netdev/taptun.cpp b/src/osd/modules/netdev/taptun.cpp index 91ca323a178..b765a667ae7 100644 --- a/src/osd/modules/netdev/taptun.cpp +++ b/src/osd/modules/netdev/taptun.cpp @@ -1,8 +1,23 @@ // license:BSD-3-Clause // copyright-holders:Carl +#include "netdev_module.h" + +#include "modules/osdmodule.h" + #if defined(OSD_NET_USE_TAPTUN) -#if defined(WIN32) +#include "netdev_common.h" + +#include "osdcore.h" // osd_printf_verbose +#include "osdfile.h" // PATH_SEPARATOR + +#include "util/hashing.h" // crc32_creator +#include "util/unicode.h" + +#include <memory> +#include <vector> + +#if defined(_WIN32) #include <windows.h> #include <winioctl.h> #else @@ -10,19 +25,14 @@ #include <fcntl.h> #include <sys/ioctl.h> #include <net/if.h> -#include <errno.h> +#include <cerrno> #endif -#include "emu.h" -#include "osdnet.h" -#include "modules/osdmodule.h" -#include "netdev_module.h" - #ifdef __linux__ #define IFF_TAP 0x0002 #define IFF_NO_PI 0x1000 #define TUNSETIFF _IOW('T', 202, int) -#elif defined(WIN32) +#elif defined(_WIN32) #include "tap-windows6/tap-windows.h" // for some reason this isn't defined in the header, and presumably it changes @@ -30,6 +40,10 @@ #define PRODUCT_TAP_WIN_COMPONENT_ID "tap0901" #endif +namespace osd { + +namespace { + // Ethernet minimum frame length static constexpr int ETHERNET_MIN_FRAME = 64; @@ -42,26 +56,39 @@ public: } virtual ~taptun_module() { } - virtual int init(const osd_options &options); - virtual void exit(); + virtual int init(osd_interface &osd, const osd_options &options) override; + virtual void exit() override; + + virtual bool probe() override { return true; } + + virtual std::unique_ptr<network_device> open_device(int id, network_handler &handler) override; + virtual std::vector<network_device_info> list_devices() override; + +private: + struct device_info + { + std::string name; + std::string description; + }; - virtual bool probe() { return true; } + std::vector<device_info> m_devices; }; -class netdev_tap : public osd_netdev +class netdev_tap : public network_device_base { public: - netdev_tap(const char *name, class device_network_interface *ifdev, int rate); + netdev_tap(const char *name, network_handler &handler); ~netdev_tap(); - int send(uint8_t *buf, int len) override; - void set_mac(const char *mac) override; + int send(void const *buf, int len) override; + protected: int recv_dev(uint8_t **buf) override; + private: -#if defined(WIN32) +#if defined(_WIN32) HANDLE m_handle = INVALID_HANDLE_VALUE; OVERLAPPED m_overlapped; bool m_receive_pending; @@ -69,22 +96,20 @@ private: int m_fd = -1; char m_ifname[10]; #endif - char m_mac[6]; uint8_t m_buf[2048]; }; -netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev, int rate) - : osd_netdev(ifdev, rate) +netdev_tap::netdev_tap(const char *name, network_handler &handler) + : network_device_base(handler) { -#ifdef __linux__ - struct ifreq ifr; - +#if defined(__linux__) m_fd = -1; if((m_fd = open("/dev/net/tun", O_RDWR)) == -1) { osd_printf_verbose("tap: open failed %d\n", errno); return; } + struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; sprintf(ifr.ifr_name, "tap-mess-%d-0", getuid()); @@ -97,7 +122,7 @@ netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev, osd_printf_verbose("netdev_tap: network up!\n"); strncpy(m_ifname, ifr.ifr_name, 10); fcntl(m_fd, F_SETFL, O_NONBLOCK); -#elif defined(WIN32) +#elif defined(_WIN32) std::wstring device_path(L"" USERMODEDEVICEDIR); device_path.append(wstring_from_utf8(name)); device_path.append(L"" TAP_WIN_SUFFIX); @@ -120,7 +145,7 @@ netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev, netdev_tap::~netdev_tap() { -#if defined(WIN32) +#if defined(_WIN32) if (m_handle != INVALID_HANDLE_VALUE) { if (m_receive_pending) @@ -133,11 +158,6 @@ netdev_tap::~netdev_tap() #endif } -void netdev_tap::set_mac(const char *mac) -{ - memcpy(m_mac, mac, 6); -} - static u32 finalise_frame(u8 buf[], u32 length) { /* @@ -168,8 +188,8 @@ static u32 finalise_frame(u8 buf[], u32 length) return length; } -#if defined(WIN32) -int netdev_tap::send(uint8_t *buf, int len) +#if defined(_WIN32) +int netdev_tap::send(void const *buf, int len) { OVERLAPPED overlapped = {}; @@ -233,7 +253,7 @@ static std::wstring safe_string(WCHAR value[], int length) } // find the friendly name for an adapter in the registry -static std::wstring get_connection_name(std::wstring &id) +static std::wstring get_connection_name(std::wstring const &id) { std::wstring result; @@ -285,16 +305,21 @@ static std::vector<std::wstring> get_tap_adapters() // check if the ComponentId value indicates a TAP-Windows adapter if (RegQueryValueExW(unit_key, L"ComponentId", NULL, &data_type, LPBYTE(component_id), &component_id_len) == ERROR_SUCCESS - && data_type == REG_SZ - && safe_string(component_id, component_id_len) == L"" PRODUCT_TAP_WIN_COMPONENT_ID) + && data_type == REG_SZ) { - WCHAR net_cfg_instance_id[MAX_PATH]; - DWORD net_cfg_instance_id_len = sizeof(net_cfg_instance_id); - - // add the adapter to the result - if (RegQueryValueExW(unit_key, L"NetCfgInstanceId", NULL, &data_type, LPBYTE(net_cfg_instance_id), &net_cfg_instance_id_len) == ERROR_SUCCESS - && data_type == REG_SZ) - result.push_back(safe_string(net_cfg_instance_id, net_cfg_instance_id_len)); + std::wstring const value(safe_string(component_id, component_id_len)); + + // some older versions may not set the "root\" prefix + if (value == L"root\\" PRODUCT_TAP_WIN_COMPONENT_ID || value == L"" PRODUCT_TAP_WIN_COMPONENT_ID) + { + WCHAR net_cfg_instance_id[MAX_PATH]; + DWORD net_cfg_instance_id_len = sizeof(net_cfg_instance_id); + + // add the adapter to the result + if (RegQueryValueExW(unit_key, L"NetCfgInstanceId", NULL, &data_type, LPBYTE(net_cfg_instance_id), &net_cfg_instance_id_len) == ERROR_SUCCESS + && data_type == REG_SZ) + result.push_back(safe_string(net_cfg_instance_id, net_cfg_instance_id_len)); + } } RegCloseKey(unit_key); @@ -310,7 +335,7 @@ static std::vector<std::wstring> get_tap_adapters() return result; } #else -int netdev_tap::send(uint8_t *buf, int len) +int netdev_tap::send(void const *buf, int len) { if(m_fd == -1) return 0; len = write(m_fd, buf, len); @@ -319,51 +344,64 @@ int netdev_tap::send(uint8_t *buf, int len) int netdev_tap::recv_dev(uint8_t **buf) { - int len; - if(m_fd == -1) return 0; - // exit if we didn't receive anything, got an error, got a broadcast or multicast packet, - // are in promiscuous mode or got a packet with our mac. - do { - len = read(m_fd, m_buf, sizeof(m_buf)); - } while((len > 0) && memcmp(get_mac(), m_buf, 6) && !get_promisc() && !(m_buf[0] & 1)); + if (0 > m_fd) + return 0; + + int len = read(m_fd, m_buf, sizeof(m_buf)); if (len > 0) len = finalise_frame(m_buf, len); *buf = m_buf; - return (len == -1)?0:len; + return (len == -1) ? 0 : len; } #endif -static CREATE_NETDEV(create_tap) -{ - class netdev_tap *dev = global_alloc(netdev_tap(ifname, ifdev, rate)); - return dynamic_cast<osd_netdev *>(dev); -} - -int taptun_module::init(const osd_options &options) +int taptun_module::init(osd_interface &osd, const osd_options &options) { -#if defined(WIN32) - for (std::wstring &id : get_tap_adapters()) - add_netdev(utf8_from_wstring(id).c_str(), utf8_from_wstring(get_connection_name(id)).c_str(), create_tap); +#if defined(_WIN32) + auto const adapters = get_tap_adapters(); + m_devices.reserve(adapters.size()); + for (std::wstring const &id : adapters) + m_devices.emplace_back(device_info{ utf8_from_wstring(id), utf8_from_wstring(get_connection_name(id)) }); #else - add_netdev("tap", "TAP/TUN Device", create_tap); + m_devices.emplace_back(device_info{ "tap", "TUN/TAP Device" }); #endif return 0; } void taptun_module::exit() { - clear_netdev(); + m_devices.clear(); } +std::unique_ptr<network_device> taptun_module::open_device(int id, network_handler &handler) +{ + if ((0 > id) || (m_devices.size() <= id)) + return nullptr; + + return std::make_unique<netdev_tap>(m_devices[id].name.c_str(), handler); +} + +std::vector<network_device_info> taptun_module::list_devices() +{ + std::vector<network_device_info> result; + result.reserve(m_devices.size()); + for (int id = 0; m_devices.size() > id; ++id) + result.emplace_back(network_device_info{ id, m_devices[id].description }); + return result; +} + +} // anonymous namespace + +} // namespace osd + #else - #include "modules/osdmodule.h" - #include "netdev_module.h" - MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun") +namespace osd { namespace { MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun") } } + #endif -MODULE_DEFINITION(NETDEV_TAPTUN, taptun_module) +MODULE_DEFINITION(NETDEV_TAPTUN, osd::taptun_module) |