summaryrefslogtreecommitdiffstats
path: root/xbmc/platform/freebsd
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/platform/freebsd')
-rw-r--r--xbmc/platform/freebsd/CMakeLists.txt28
-rw-r--r--xbmc/platform/freebsd/CPUInfoFreebsd.cpp268
-rw-r--r--xbmc/platform/freebsd/CPUInfoFreebsd.h24
-rw-r--r--xbmc/platform/freebsd/MemUtils.cpp83
-rw-r--r--xbmc/platform/freebsd/OptionalsReg.cpp23
-rw-r--r--xbmc/platform/freebsd/OptionalsReg.h18
-rw-r--r--xbmc/platform/freebsd/PlatformFreebsd.cpp124
-rw-r--r--xbmc/platform/freebsd/PlatformFreebsd.h26
-rw-r--r--xbmc/platform/freebsd/network/CMakeLists.txt4
-rw-r--r--xbmc/platform/freebsd/network/NetworkFreebsd.cpp247
-rw-r--r--xbmc/platform/freebsd/network/NetworkFreebsd.h40
11 files changed, 885 insertions, 0 deletions
diff --git a/xbmc/platform/freebsd/CMakeLists.txt b/xbmc/platform/freebsd/CMakeLists.txt
new file mode 100644
index 0000000..9b8782f
--- /dev/null
+++ b/xbmc/platform/freebsd/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(SOURCES ../linux/AppParamParserLinux.cpp
+ CPUInfoFreebsd.cpp
+ OptionalsReg.cpp
+ ../linux/OptionalsReg.cpp
+ ../linux/TimeUtils.cpp
+ MemUtils.cpp
+ PlatformFreebsd.cpp)
+
+set(HEADERS ../linux/AppParamParserLinux.cpp
+ CPUInfoFreebsd.h
+ OptionalsReg.h
+ ../linux/OptionalsReg.h
+ ../linux/TimeUtils.h
+ PlatformFreebsd.h)
+
+if(ALSA_FOUND)
+ list(APPEND SOURCES ../linux/FDEventMonitor.cpp)
+ list(APPEND HEADERS ../linux/FDEventMonitor.h)
+endif()
+
+if(DBUS_FOUND)
+ list(APPEND SOURCES ../linux/DBusMessage.cpp
+ ../linux/DBusUtil.cpp)
+ list(APPEND HEADERS ../linux/DBusMessage.h
+ ../linux/DBusUtil.h)
+endif()
+
+core_add_library(freebsdsupport)
diff --git a/xbmc/platform/freebsd/CPUInfoFreebsd.cpp b/xbmc/platform/freebsd/CPUInfoFreebsd.cpp
new file mode 100644
index 0000000..5128a72
--- /dev/null
+++ b/xbmc/platform/freebsd/CPUInfoFreebsd.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "CPUInfoFreebsd.h"
+
+#include "utils/Temperature.h"
+#include "utils/log.h"
+
+#include <array>
+#include <vector>
+
+// clang-format off
+/* sys/types.h must be included early, esp. before sysy/systl.h, otherwise:
+ /usr/include/sys/sysctl.h:1117:25: error: unknown type name 'u_int' */
+
+#include <sys/types.h>
+// clang-format on
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <cpuid.h>
+#elif __has_include(<sys/auxv.h>)
+#include <sys/auxv.h>
+#endif
+
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+
+namespace
+{
+
+struct CpuData
+{
+public:
+ std::size_t GetActiveTime() const { return state[CP_USER] + state[CP_NICE] + state[CP_SYS]; }
+
+ std::size_t GetIdleTime() const { return state[CP_INTR] + state[CP_IDLE]; }
+
+ std::size_t GetTotalTime() const { return GetActiveTime() + GetIdleTime(); }
+
+ std::size_t state[CPUSTATES];
+};
+
+} // namespace
+
+std::shared_ptr<CCPUInfo> CCPUInfo::GetCPUInfo()
+{
+ return std::make_shared<CCPUInfoFreebsd>();
+}
+
+CCPUInfoFreebsd::CCPUInfoFreebsd()
+{
+ int count = 0;
+ size_t countLength = sizeof(count);
+ if (sysctlbyname("hw.ncpu", &count, &countLength, nullptr, 0) == 0)
+ m_cpuCount = count;
+ else
+ m_cpuCount = 1;
+
+ std::array<char, 512> cpuModel;
+ size_t length = cpuModel.size();
+ if (sysctlbyname("hw.model", cpuModel.data(), &length, nullptr, 0) == 0)
+ m_cpuModel = cpuModel.data();
+
+ for (int i = 0; i < m_cpuCount; i++)
+ {
+ CoreInfo core;
+ core.m_id = i;
+ m_cores.emplace_back(core);
+ }
+#if defined(__i386__) || defined(__x86_64__)
+ uint32_t eax, ebx, ecx, edx;
+
+ m_cpuVendor.clear();
+
+ if (__get_cpuid(CPUID_INFOTYPE_MANUFACTURER, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuVendor.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuVendor.append(reinterpret_cast<const char*>(&edx), 4);
+ m_cpuVendor.append(reinterpret_cast<const char*>(&ecx), 4);
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &ebx, &ecx, &edx))
+ {
+ if (eax >= CPUID_INFOTYPE_PROCESSOR_3)
+ {
+ m_cpuModel.clear();
+
+ if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_1, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_2, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_3, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
+ }
+ }
+ }
+
+ m_cpuModel = m_cpuModel.substr(0, m_cpuModel.find(char(0))); // remove extra null terminations
+
+ if (__get_cpuid(CPUID_INFOTYPE_STANDARD, &eax, &eax, &ecx, &edx))
+ {
+ if (edx & CPUID_00000001_EDX_MMX)
+ m_cpuFeatures |= CPU_FEATURE_MMX;
+
+ // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap
+ if (edx & CPUID_00000001_EDX_SSE)
+ m_cpuFeatures |= (CPU_FEATURE_SSE | CPU_FEATURE_MMX2);
+
+ if (edx & CPUID_00000001_EDX_SSE2)
+ m_cpuFeatures |= CPU_FEATURE_SSE2;
+
+ if (ecx & CPUID_00000001_ECX_SSE3)
+ m_cpuFeatures |= CPU_FEATURE_SSE3;
+
+ if (ecx & CPUID_00000001_ECX_SSSE3)
+ m_cpuFeatures |= CPU_FEATURE_SSSE3;
+
+ if (ecx & CPUID_00000001_ECX_SSE4)
+ m_cpuFeatures |= CPU_FEATURE_SSE4;
+
+ if (ecx & CPUID_00000001_ECX_SSE42)
+ m_cpuFeatures |= CPU_FEATURE_SSE42;
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &eax, &ecx, &edx))
+ {
+ if (eax >= CPUID_INFOTYPE_EXTENDED)
+ {
+ if (edx & CPUID_80000001_EDX_MMX)
+ m_cpuFeatures |= CPU_FEATURE_MMX;
+
+ if (edx & CPUID_80000001_EDX_MMX2)
+ m_cpuFeatures |= CPU_FEATURE_MMX2;
+
+ if (edx & CPUID_80000001_EDX_3DNOW)
+ m_cpuFeatures |= CPU_FEATURE_3DNOW;
+
+ if (edx & CPUID_80000001_EDX_3DNOWEXT)
+ m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
+ }
+ }
+#endif
+
+#if defined(HAS_NEON)
+#if defined(__ARM_NEON)
+ m_cpuFeatures |= CPU_FEATURE_NEON;
+#elif __has_include(<sys/auxv.h>)
+ unsigned long hwcap = 0;
+ elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
+ if (hwcap & HWCAP_NEON)
+ m_cpuFeatures |= CPU_FEATURE_NEON;
+#endif
+#endif
+}
+
+int CCPUInfoFreebsd::GetUsedPercentage()
+{
+ if (!m_nextUsedReadTime.IsTimePast())
+ return m_lastUsedPercentage;
+
+ size_t len = sizeof(long);
+
+ if (sysctlbyname("kern.cp_times", nullptr, &len, nullptr, 0) != 0)
+ return false;
+
+ std::vector<long> cptimes(len);
+ size_t cptimesLength = cptimes.size();
+ if (sysctlbyname("kern.cp_times", cptimes.data(), &cptimesLength, nullptr, 0) != 0)
+ return false;
+
+ size_t activeTime{0};
+ size_t idleTime{0};
+ size_t totalTime{0};
+
+ std::vector<CpuData> cpuData;
+
+ for (int i = 0; i < m_cpuCount; i++)
+ {
+ CpuData info;
+
+ for (size_t state = 0; state < CPUSTATES; state++)
+ {
+ info.state[state] = cptimes[i * CPUSTATES + state];
+ }
+
+ activeTime += info.GetActiveTime();
+ idleTime += info.GetIdleTime();
+ totalTime += info.GetTotalTime();
+
+ cpuData.emplace_back(info);
+ }
+
+ activeTime -= m_activeTime;
+ idleTime -= m_idleTime;
+ totalTime -= m_totalTime;
+
+ m_activeTime += activeTime;
+ m_idleTime += idleTime;
+ m_totalTime += totalTime;
+
+ m_lastUsedPercentage = activeTime * 100.0f / totalTime;
+ m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
+
+ for (size_t core = 0; core < cpuData.size(); core++)
+ {
+ auto activeTime = cpuData[core].GetActiveTime() - m_cores[core].m_activeTime;
+ auto idleTime = cpuData[core].GetIdleTime() - m_cores[core].m_idleTime;
+ auto totalTime = cpuData[core].GetTotalTime() - m_cores[core].m_totalTime;
+
+ m_cores[core].m_usagePercent = activeTime * 100.0 / totalTime;
+
+ m_cores[core].m_activeTime += activeTime;
+ m_cores[core].m_idleTime += idleTime;
+ m_cores[core].m_totalTime += totalTime;
+ }
+
+ return static_cast<int>(m_lastUsedPercentage);
+}
+
+float CCPUInfoFreebsd::GetCPUFrequency()
+{
+ int hz = 0;
+ size_t len = sizeof(hz);
+ if (sysctlbyname("dev.cpu.0.freq", &hz, &len, nullptr, 0) != 0)
+ hz = 0;
+
+ return static_cast<float>(hz);
+}
+
+
+bool CCPUInfoFreebsd::GetTemperature(CTemperature& temperature)
+{
+ if (CheckUserTemperatureCommand(temperature))
+ return true;
+
+ int value;
+ size_t len = sizeof(value);
+
+ /* Temperature is in Kelvin * 10 */
+ if (sysctlbyname("dev.cpu.0.temperature", &value, &len, nullptr, 0) != 0)
+ return false;
+
+ temperature = CTemperature::CreateFromKelvin(static_cast<double>(value) / 10.0);
+ temperature.SetValid(true);
+
+ return true;
+}
diff --git a/xbmc/platform/freebsd/CPUInfoFreebsd.h b/xbmc/platform/freebsd/CPUInfoFreebsd.h
new file mode 100644
index 0000000..f1743ce
--- /dev/null
+++ b/xbmc/platform/freebsd/CPUInfoFreebsd.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "utils/Temperature.h"
+
+#include "platform/posix/CPUInfoPosix.h"
+
+class CCPUInfoFreebsd : public CCPUInfoPosix
+{
+public:
+ CCPUInfoFreebsd();
+ ~CCPUInfoFreebsd() = default;
+
+ int GetUsedPercentage() override;
+ float GetCPUFrequency() override;
+ bool GetTemperature(CTemperature& temperature) override;
+};
diff --git a/xbmc/platform/freebsd/MemUtils.cpp b/xbmc/platform/freebsd/MemUtils.cpp
new file mode 100644
index 0000000..de3e42c
--- /dev/null
+++ b/xbmc/platform/freebsd/MemUtils.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "utils/MemUtils.h"
+
+#include <array>
+#include <cstdlib>
+#include <cstring>
+#include <stdio.h>
+
+#include <unistd.h> /* FreeBSD can't write standalone headers */
+#include <sys/sysctl.h> /* FreeBSD can't write standalone headers */
+#include <sys/types.h>
+
+namespace KODI
+{
+namespace MEMORY
+{
+
+void* AlignedMalloc(size_t s, size_t alignTo)
+{
+ void* p;
+ posix_memalign(&p, alignTo, s);
+
+ return p;
+}
+
+void AlignedFree(void* p)
+{
+ free(p);
+}
+
+void GetMemoryStatus(MemoryStatus* buffer)
+{
+ if (!buffer)
+ return;
+
+ /* sysctl hw.physmem */
+ size_t len = 0;
+
+ /* physmem */
+ size_t physmem = 0;
+ len = sizeof(physmem);
+ if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) == 0)
+ {
+ buffer->totalPhys = physmem;
+ }
+
+ /* pagesize */
+ size_t pagesize = 0;
+ len = sizeof(pagesize);
+ if (sysctlbyname("hw.pagesize", &pagesize, &len, NULL, 0) != 0)
+ pagesize = 4096;
+
+ /* mem_inactive */
+ size_t mem_inactive = 0;
+ len = sizeof(mem_inactive);
+ if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &len, NULL, 0) == 0)
+ mem_inactive *= pagesize;
+
+ /* mem_cache */
+ size_t mem_cache = 0;
+ len = sizeof(mem_cache);
+ if (sysctlbyname("vm.stats.vm.v_cache_count", &mem_cache, &len, NULL, 0) == 0)
+ mem_cache *= pagesize;
+
+ /* mem_free */
+ size_t mem_free = 0;
+ len = sizeof(mem_free);
+ if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &len, NULL, 0) == 0)
+ mem_free *= pagesize;
+
+ /* mem_avail = mem_inactive + mem_cache + mem_free */
+ buffer->availPhys = mem_inactive + mem_cache + mem_free;
+}
+
+}
+}
diff --git a/xbmc/platform/freebsd/OptionalsReg.cpp b/xbmc/platform/freebsd/OptionalsReg.cpp
new file mode 100644
index 0000000..ed414f1
--- /dev/null
+++ b/xbmc/platform/freebsd/OptionalsReg.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "OptionalsReg.h"
+
+
+//-----------------------------------------------------------------------------
+// OSS
+//-----------------------------------------------------------------------------
+
+#ifdef HAS_OSS
+#include "cores/AudioEngine/Sinks/AESinkOSS.h"
+bool OPTIONALS::OSSRegister()
+{
+ CAESinkOSS::Register();
+ return true;
+}
+#endif
diff --git a/xbmc/platform/freebsd/OptionalsReg.h b/xbmc/platform/freebsd/OptionalsReg.h
new file mode 100644
index 0000000..36837d0
--- /dev/null
+++ b/xbmc/platform/freebsd/OptionalsReg.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2005-2019 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+//-----------------------------------------------------------------------------
+// OSS
+//-----------------------------------------------------------------------------
+
+namespace OPTIONALS
+{
+bool OSSRegister();
+}
diff --git a/xbmc/platform/freebsd/PlatformFreebsd.cpp b/xbmc/platform/freebsd/PlatformFreebsd.cpp
new file mode 100644
index 0000000..b65501b
--- /dev/null
+++ b/xbmc/platform/freebsd/PlatformFreebsd.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "PlatformFreebsd.h"
+
+#include "utils/StringUtils.h"
+
+#include "platform/freebsd/OptionalsReg.h"
+#include "platform/linux/powermanagement/LinuxPowerSyscall.h"
+
+// clang-format off
+#if defined(HAS_GLES)
+#if defined(HAVE_WAYLAND)
+#include "windowing/wayland/WinSystemWaylandEGLContextGLES.h"
+#endif
+#if defined(HAVE_X11)
+#include "windowing/X11/WinSystemX11GLESContext.h"
+#endif
+#if defined(HAVE_GBM)
+#include "windowing/gbm/WinSystemGbmGLESContext.h"
+#endif
+#endif
+
+#if defined(HAS_GL)
+#if defined(HAVE_WAYLAND)
+#include "windowing/wayland/WinSystemWaylandEGLContextGL.h"
+#endif
+#if defined(HAVE_X11)
+#include "windowing/X11/WinSystemX11GLContext.h"
+#endif
+#if defined(HAVE_GBM)
+#include "windowing/gbm/WinSystemGbmGLContext.h"
+#endif
+#endif
+// clang-format on
+
+#include <cstdlib>
+
+CPlatform* CPlatform::CreateInstance()
+{
+ return new CPlatformFreebsd();
+}
+
+bool CPlatformFreebsd::InitStageOne()
+{
+ if (!CPlatformPosix::InitStageOne())
+ return false;
+
+ setenv("OS", "Linux", true); // for python scripts that check the OS
+
+#if defined(HAS_GLES)
+#if defined(HAVE_WAYLAND)
+ KODI::WINDOWING::WAYLAND::CWinSystemWaylandEGLContextGLES::Register();
+#endif
+#if defined(HAVE_X11)
+ KODI::WINDOWING::X11::CWinSystemX11GLESContext::Register();
+#endif
+#if defined(HAVE_GBM)
+ KODI::WINDOWING::GBM::CWinSystemGbmGLESContext::Register();
+#endif
+#endif
+
+#if defined(HAS_GL)
+#if defined(HAVE_WAYLAND)
+ KODI::WINDOWING::WAYLAND::CWinSystemWaylandEGLContextGL::Register();
+#endif
+#if defined(HAVE_X11)
+ KODI::WINDOWING::X11::CWinSystemX11GLContext::Register();
+#endif
+#if defined(HAVE_GBM)
+ KODI::WINDOWING::GBM::CWinSystemGbmGLContext::Register();
+#endif
+#endif
+
+ CLinuxPowerSyscall::Register();
+
+ std::string envSink;
+ if (getenv("KODI_AE_SINK"))
+ envSink = getenv("KODI_AE_SINK");
+
+ if (StringUtils::EqualsNoCase(envSink, "ALSA"))
+ {
+ OPTIONALS::ALSARegister();
+ }
+ else if (StringUtils::EqualsNoCase(envSink, "PULSE"))
+ {
+ OPTIONALS::PulseAudioRegister();
+ }
+ else if (StringUtils::EqualsNoCase(envSink, "OSS"))
+ {
+ OPTIONALS::OSSRegister();
+ }
+ else if (StringUtils::EqualsNoCase(envSink, "SNDIO"))
+ {
+ OPTIONALS::SndioRegister();
+ }
+ else if (StringUtils::EqualsNoCase(envSink, "ALSA+PULSE"))
+ {
+ OPTIONALS::ALSARegister();
+ OPTIONALS::PulseAudioRegister();
+ }
+ else
+ {
+ if (!OPTIONALS::PulseAudioRegister())
+ {
+ if (!OPTIONALS::ALSARegister())
+ {
+ if (!OPTIONALS::SndioRegister())
+ {
+ OPTIONALS::OSSRegister();
+ }
+ }
+ }
+ }
+
+ m_lirc.reset(OPTIONALS::LircRegister());
+
+ return true;
+}
diff --git a/xbmc/platform/freebsd/PlatformFreebsd.h b/xbmc/platform/freebsd/PlatformFreebsd.h
new file mode 100644
index 0000000..48a4151
--- /dev/null
+++ b/xbmc/platform/freebsd/PlatformFreebsd.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "platform/linux/OptionalsReg.h"
+#include "platform/posix/PlatformPosix.h"
+
+#include <memory>
+
+class CPlatformFreebsd : public CPlatformPosix
+{
+public:
+ CPlatformFreebsd() = default;
+ ~CPlatformFreebsd() override = default;
+
+ bool InitStageOne() override;
+
+private:
+ std::unique_ptr<OPTIONALS::CLircContainer, OPTIONALS::delete_CLircContainer> m_lirc;
+};
diff --git a/xbmc/platform/freebsd/network/CMakeLists.txt b/xbmc/platform/freebsd/network/CMakeLists.txt
new file mode 100644
index 0000000..25d8ee8
--- /dev/null
+++ b/xbmc/platform/freebsd/network/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(SOURCES NetworkFreebsd.cpp)
+set(HEADERS NetworkFreebsd.h)
+
+core_add_library(platform_freebsd_network)
diff --git a/xbmc/platform/freebsd/network/NetworkFreebsd.cpp b/xbmc/platform/freebsd/network/NetworkFreebsd.cpp
new file mode 100644
index 0000000..94a0a41
--- /dev/null
+++ b/xbmc/platform/freebsd/network/NetworkFreebsd.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "NetworkFreebsd.h"
+
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include <array>
+#include <errno.h>
+
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <sys/sockio.h>
+#include <sys/wait.h>
+
+CNetworkInterfaceFreebsd::CNetworkInterfaceFreebsd(CNetworkPosix* network,
+ std::string interfaceName,
+ char interfaceMacAddrRaw[6])
+ : CNetworkInterfacePosix(network, interfaceName, interfaceMacAddrRaw)
+{
+}
+
+std::string CNetworkInterfaceFreebsd::GetCurrentDefaultGateway() const
+{
+ std::string result;
+
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ char line[16];
+ struct rt_msghdr* rtm;
+ struct sockaddr* sa;
+ struct sockaddr_in* sockin;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return result;
+
+ if ((buf = (char*)malloc(needed)) == NULL)
+ return result;
+
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ {
+ free(buf);
+ return result;
+ }
+
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen)
+ {
+ rtm = (struct rt_msghdr*)next;
+ sa = (struct sockaddr*)(rtm + 1);
+ sa = (struct sockaddr*)(SA_SIZE(sa) + (char*)sa);
+ sockin = (struct sockaddr_in*)sa;
+ if (inet_ntop(AF_INET, &sockin->sin_addr.s_addr, line, sizeof(line)) == NULL)
+ {
+ free(buf);
+ return result;
+ }
+ result = line;
+ break;
+ }
+ free(buf);
+
+ return result;
+}
+
+bool CNetworkInterfaceFreebsd::GetHostMacAddress(unsigned long host_ip, std::string& mac) const
+{
+ bool ret = false;
+ size_t needed;
+ char *buf, *next;
+ struct rt_msghdr* rtm;
+ struct sockaddr_inarp* sin;
+ struct sockaddr_dl* sdl;
+ constexpr std::array<int, 6> mib = {
+ CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO,
+ };
+
+ mac = "";
+
+ if (sysctl(mib.data(), mib.size(), nullptr, &needed, nullptr, 0) == 0)
+ {
+ buf = (char*)malloc(needed);
+ if (buf)
+ {
+ if (sysctl(mib.data(), mib.size(), buf, &needed, nullptr, 0) == 0)
+ {
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen)
+ {
+
+ rtm = (struct rt_msghdr*)next;
+ sin = (struct sockaddr_inarp*)(rtm + 1);
+ sdl = (struct sockaddr_dl*)(sin + 1);
+
+ if (host_ip != sin->sin_addr.s_addr || sdl->sdl_alen < 6)
+ continue;
+
+ u_char* cp = (u_char*)LLADDR(sdl);
+
+ mac = StringUtils::Format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", cp[0], cp[1],
+ cp[2], cp[3], cp[4], cp[5]);
+ ret = true;
+ break;
+ }
+ }
+ free(buf);
+ }
+ }
+ return ret;
+}
+
+std::unique_ptr<CNetworkBase> CNetworkBase::GetNetwork()
+{
+ return std::make_unique<CNetworkFreebsd>();
+}
+
+CNetworkFreebsd::CNetworkFreebsd() : CNetworkPosix()
+{
+ queryInterfaceList();
+}
+
+void CNetworkFreebsd::GetMacAddress(const std::string& interfaceName, char rawMac[6])
+{
+ memset(rawMac, 0, 6);
+
+#if !defined(IFT_ETHER)
+#define IFT_ETHER 0x6 /* Ethernet CSMACD */
+#endif
+ const struct sockaddr_dl* dlAddr = NULL;
+ const uint8_t* base = NULL;
+ // Query the list of interfaces.
+ struct ifaddrs* list;
+ struct ifaddrs* interface;
+
+ if (getifaddrs(&list) < 0)
+ {
+ return;
+ }
+
+ for (interface = list; interface != NULL; interface = interface->ifa_next)
+ {
+ if (interfaceName == interface->ifa_name)
+ {
+ if ((interface->ifa_addr->sa_family == AF_LINK) &&
+ (((const struct sockaddr_dl*)interface->ifa_addr)->sdl_type == IFT_ETHER))
+ {
+ dlAddr = (const struct sockaddr_dl*)interface->ifa_addr;
+ base = (const uint8_t*)&dlAddr->sdl_data[dlAddr->sdl_nlen];
+
+ if (dlAddr->sdl_alen > 5)
+ {
+ memcpy(rawMac, base, 6);
+ }
+ }
+ break;
+ }
+ }
+
+ freeifaddrs(list);
+}
+
+void CNetworkFreebsd::queryInterfaceList()
+{
+ char macAddrRaw[6];
+ m_interfaces.clear();
+
+ // Query the list of interfaces.
+ struct ifaddrs* list;
+ if (getifaddrs(&list) < 0)
+ return;
+
+ struct ifaddrs* cur;
+ for (cur = list; cur != NULL; cur = cur->ifa_next)
+ {
+ if (cur->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ GetMacAddress(cur->ifa_name, macAddrRaw);
+
+ // only add interfaces with non-zero mac addresses
+ if (macAddrRaw[0] || macAddrRaw[1] || macAddrRaw[2] || macAddrRaw[3] || macAddrRaw[4] ||
+ macAddrRaw[5])
+ // Add the interface.
+ m_interfaces.push_back(new CNetworkInterfaceFreebsd(this, cur->ifa_name, macAddrRaw));
+ }
+
+ freeifaddrs(list);
+}
+
+std::vector<std::string> CNetworkFreebsd::GetNameServers()
+{
+ std::vector<std::string> result;
+
+ res_init();
+
+ for (int i = 0; i < _res.nscount; i++)
+ {
+ std::string ns = inet_ntoa(_res.nsaddr_list[i].sin_addr);
+ result.push_back(ns);
+ }
+
+ return result;
+}
+
+bool CNetworkFreebsd::PingHost(unsigned long remote_ip, unsigned int timeout_ms)
+{
+ char cmd_line[64];
+
+ struct in_addr host_ip;
+ host_ip.s_addr = remote_ip;
+
+ sprintf(cmd_line, "ping -c 1 -t %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0,
+ inet_ntoa(host_ip));
+
+ int status = -1;
+ status = system(cmd_line);
+ int result = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+
+ // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ;
+ // 0 reply
+ // 1 no reply
+ // else some error
+
+ if (result < 0 || result > 1)
+ CLog::Log(LOGERROR, "Ping fail : status = {}, errno = {} : '{}'", status, errno, cmd_line);
+
+ return result == 0;
+}
diff --git a/xbmc/platform/freebsd/network/NetworkFreebsd.h b/xbmc/platform/freebsd/network/NetworkFreebsd.h
new file mode 100644
index 0000000..92b00d7
--- /dev/null
+++ b/xbmc/platform/freebsd/network/NetworkFreebsd.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "platform/posix/network/NetworkPosix.h"
+
+#include <string>
+#include <vector>
+
+class CNetworkInterfaceFreebsd : public CNetworkInterfacePosix
+{
+public:
+ CNetworkInterfaceFreebsd(CNetworkPosix* network,
+ std::string interfaceName,
+ char interfaceMacAddrRaw[6]);
+ ~CNetworkInterfaceFreebsd() override = default;
+
+ std::string GetCurrentDefaultGateway() const override;
+ bool GetHostMacAddress(unsigned long host, std::string& mac) const override;
+};
+
+class CNetworkFreebsd : public CNetworkPosix
+{
+public:
+ CNetworkFreebsd();
+ ~CNetworkFreebsd() override = default;
+
+ bool PingHost(unsigned long host, unsigned int timeout_ms = 2000) override;
+ std::vector<std::string> GetNameServers() override;
+
+private:
+ void GetMacAddress(const std::string& interfaceName, char macAddrRaw[6]) override;
+ void queryInterfaceList() override;
+};