diff --git a/src/frontend/qt_sdl/LANDialog.cpp b/src/frontend/qt_sdl/LANDialog.cpp
index 0a5c7449..58baf908 100644
--- a/src/frontend/qt_sdl/LANDialog.cpp
+++ b/src/frontend/qt_sdl/LANDialog.cpp
@@ -49,7 +49,7 @@ LANStartHostDialog::LANStartHostDialog(QWidget* parent) : QDialog(parent), ui(ne
     ui->setupUi(this);
     setAttribute(Qt::WA_DeleteOnClose);
 
-    MPInterface::Set(MPInterface_LAN);
+    setMPInterface(MPInterface_LAN);
 
     // TODO: remember the last setting? so this doesn't suck massively
     // we could also remember the player name (and auto-init it from the firmware name or whatever)
@@ -85,7 +85,7 @@ void LANStartHostDialog::done(int r)
     }
     else
     {
-        MPInterface::Set(MPInterface_Local);
+        setMPInterface(MPInterface_Local);
     }
 
     QDialog::done(r);
@@ -97,7 +97,7 @@ LANStartClientDialog::LANStartClientDialog(QWidget* parent) : QDialog(parent), u
     ui->setupUi(this);
     setAttribute(Qt::WA_DeleteOnClose);
 
-    MPInterface::Set(MPInterface_LAN);
+    setMPInterface(MPInterface_LAN);
 
     QStandardItemModel* model = new QStandardItemModel();
     ui->tvAvailableGames->setModel(model);
@@ -213,7 +213,7 @@ void LANStartClientDialog::done(int r)
     else
     {
         lan().EndDiscovery();
-        MPInterface::Set(MPInterface_Local);
+        setMPInterface(MPInterface_Local);
     }
 
     QDialog::done(r);
@@ -293,10 +293,26 @@ LANDialog::~LANDialog()
     delete ui;
 }
 
+void LANDialog::on_btnLeaveGame_clicked()
+{
+    done(QDialog::Accepted);
+}
+
 void LANDialog::done(int r)
 {
-    // ???
-    // TODO handle this situation, and provide the user a way to reopen this dialog
+    bool showwarning = true;
+    if (lan().GetNumPlayers() < 2)
+        showwarning = false;
+
+    if (showwarning)
+    {
+        if (QMessageBox::warning(this, "melonDS", "Really leave this LAN game?",
+                                 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
+            return;
+    }
+
+    lan().EndSession();
+    setMPInterface(MPInterface_Local);
 
     QDialog::done(r);
 }
diff --git a/src/frontend/qt_sdl/LANDialog.h b/src/frontend/qt_sdl/LANDialog.h
index c4b6255e..03857d79 100644
--- a/src/frontend/qt_sdl/LANDialog.h
+++ b/src/frontend/qt_sdl/LANDialog.h
@@ -104,6 +104,7 @@ protected:
     void timerEvent(QTimerEvent* event) override;
 
 private slots:
+    void on_btnLeaveGame_clicked();
     void done(int r);
 
     void doUpdatePlayerList();
diff --git a/src/frontend/qt_sdl/LANDialog.ui b/src/frontend/qt_sdl/LANDialog.ui
index e99000e4..88e9718f 100644
--- a/src/frontend/qt_sdl/LANDialog.ui
+++ b/src/frontend/qt_sdl/LANDialog.ui
@@ -11,15 +11,35 @@
    </rect>
   </property>
   <property name="windowTitle">
-   <string>LAN SHITO</string>
+   <string>LAN game - melonDS</string>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout_2">
+  <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <widget class="QLabel" name="lblStatus">
-     <property name="text">
-      <string>STATUS PLACEHOLDER</string>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="leftMargin">
+      <number>0</number>
      </property>
-    </widget>
+     <item>
+      <widget class="QPushButton" name="btnLeaveGame">
+       <property name="text">
+        <string>Leave game</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Orientation::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
    </item>
    <item>
     <widget class="QTreeView" name="tvPlayerList"/>
diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp
index 84cc7222..e0b76d19 100644
--- a/src/frontend/qt_sdl/Window.cpp
+++ b/src/frontend/qt_sdl/Window.cpp
@@ -749,6 +749,8 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
 
     QObject::connect(qApp, &QApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged);
     onUpdateInterfaceSettings();
+
+    updateMPInterface(MPInterface::GetType());
 }
 
 MainWindow::~MainWindow()
@@ -1712,6 +1714,19 @@ void MainWindow::onNPTest()
     //Netplay::StartGame();
 }
 
+void MainWindow::updateMPInterface(MPInterfaceType type)
+{
+    // MP interface was changed, reflect it in the UI
+
+    bool enable = (type == MPInterface_Local);
+    actMPNewInstance->setEnabled(enable);
+    actLANStartHost->setEnabled(enable);
+    actLANStartClient->setEnabled(enable);
+    actNPStartHost->setEnabled(enable);
+    actNPStartClient->setEnabled(enable);
+    actNPTest->setEnabled(enable);
+}
+
 bool MainWindow::lanWarning(bool host)
 {
     if (numEmuInstances() < 2)
diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h
index 67a16ae5..1dfd680c 100644
--- a/src/frontend/qt_sdl/Window.h
+++ b/src/frontend/qt_sdl/Window.h
@@ -35,6 +35,7 @@
 
 #include "Screen.h"
 #include "Config.h"
+#include "MPInterface.h"
 
 
 class EmuInstance;
@@ -125,6 +126,9 @@ public:
 
     void osdAddMessage(unsigned int color, const char* msg);
 
+    // called when the MP interface is changed
+    void updateMPInterface(melonDS::MPInterfaceType type);
+
 protected:
     void keyPressEvent(QKeyEvent* event) override;
     void keyReleaseEvent(QKeyEvent* event) override;
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index 001d0f4f..9a9c93cb 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -205,6 +205,28 @@ void pathInit()
 }
 
 
+void setMPInterface(MPInterfaceType type)
+{
+    // switch to the requested MP interface
+    MPInterface::Set(type);
+
+    // set receive timeout
+    // TODO: different settings per interface?
+    MPInterface::Get().SetRecvTimeout(Config::GetGlobalTable().GetInt("MP.RecvTimeout"));
+
+    // update UI appropriately
+    // TODO: decide how to deal with multi-window when it becomes a thing
+    for (int i = 0; i < kMaxEmuInstances; i++)
+    {
+        EmuInstance* inst = emuInstances[i];
+        if (!inst) continue;
+
+        MainWindow* win = inst->getMainWindow();
+        if (win) win->updateMPInterface(type);
+    }
+}
+
+
 
 MelonApplication::MelonApplication(int& argc, char** argv)
     : QApplication(argc, argv)
@@ -313,8 +335,7 @@ int main(int argc, char** argv)
 
     // default MP interface type is local MP
     // this will be changed if a LAN or netplay session is initiated
-    MPInterface::Set(MPInterface_Local);
-    MPInterface::Get().SetRecvTimeout(Config::GetGlobalTable().GetInt("MP.RecvTimeout"));
+    setMPInterface(MPInterface_Local);
 
     NetInit();
 
diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h
index 6bd07d75..77cdf4ee 100644
--- a/src/frontend/qt_sdl/main.h
+++ b/src/frontend/qt_sdl/main.h
@@ -29,6 +29,7 @@
 #include "Window.h"
 #include "EmuThread.h"
 #include "ScreenLayout.h"
+#include "MPInterface.h"
 
 class MelonApplication : public QApplication
 {
@@ -49,4 +50,6 @@ void deleteEmuInstance(int id);
 void deleteAllEmuInstances(int first = 0);
 int numEmuInstances();
 
+void setMPInterface(melonDS::MPInterfaceType type);
+
 #endif // MAIN_H
diff --git a/src/net/LAN.cpp b/src/net/LAN.cpp
index 358bb92a..ebc66fd8 100644
--- a/src/net/LAN.cpp
+++ b/src/net/LAN.cpp
@@ -17,10 +17,7 @@
 */
 
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <queue>
-#include <vector>
 
 #ifdef __WIN32__
     #include <winsock2.h>
@@ -107,46 +104,25 @@ LAN::LAN() noexcept : Inited(false)
     // TODO make this somewhat nicer
     if (enet_initialize() != 0)
     {
-        printf("enet shat itself :(\n");
+        Platform::Log(Platform::LogLevel::Error, "LAN: failed to initialize enet\n");
         return;
     }
 
-    printf("enet init OK\n");
+    Platform::Log(Platform::LogLevel::Info, "LAN: enet initialized\n");
     Inited = true;
 }
 
 LAN::~LAN() noexcept
 {
-    if (DiscoverySocket)
-    {
-        closesocket(DiscoverySocket);
-        DiscoverySocket = INVALID_SOCKET;
-    }
-
-    while (!RXQueue.empty())
-    {
-        ENetPacket* packet = RXQueue.front();
-        RXQueue.pop();
-        enet_packet_destroy(packet);
-    }
-
-    for (int i = 0; i < 16; i++)
-    {
-        if (i == MyPlayer.ID) continue;
-
-        if (RemotePeers[i])
-            enet_peer_disconnect(RemotePeers[i], 0);
-
-        RemotePeers[i] = nullptr;
-    }
-
-    enet_host_destroy(Host);
-    Host = nullptr;
+    EndSession();
 
+    Inited = false;
     enet_deinitialize();
 
     Platform::Mutex_Free(DiscoveryMutex);
     Platform::Mutex_Free(PlayersMutex);
+
+    Platform::Log(Platform::LogLevel::Info, "LAN: enet deinitialized\n");
 }
 
 
@@ -281,9 +257,6 @@ bool LAN::StartHost(const char* playername, int numplayers)
     Active = true;
     IsHost = true;
 
-    //if (lanDlg)
-    //    lanDlg->updatePlayerList();
-
     StartDiscovery();
     return true;
 }
@@ -398,6 +371,35 @@ bool LAN::StartClient(const char* playername, const char* host)
     return true;
 }
 
+void LAN::EndSession()
+{
+    if (!Active) return;
+    if (IsHost) EndDiscovery();
+
+    Active = false;
+
+    while (!RXQueue.empty())
+    {
+        ENetPacket* packet = RXQueue.front();
+        RXQueue.pop();
+        enet_packet_destroy(packet);
+    }
+
+    for (int i = 0; i < 16; i++)
+    {
+        if (i == MyPlayer.ID) continue;
+
+        if (RemotePeers[i])
+            enet_peer_disconnect(RemotePeers[i], 0);
+
+        RemotePeers[i] = nullptr;
+    }
+
+    enet_host_destroy(Host);
+    Host = nullptr;
+    IsHost = false;
+}
+
 
 void LAN::ProcessDiscovery()
 {
@@ -631,7 +633,6 @@ void LAN::ProcessHostEvent(ENetEvent& event)
                 {
                     if (event.packet->dataLength != 1) break;
                     Player* player = (Player*)event.peer->data;
-                    //printf("HOST: PLAYER CONNECT %p\n", player);
                     if (!player) break;
 
                     ConnectedBitmask |= (1 << player->ID);
@@ -642,7 +643,6 @@ void LAN::ProcessHostEvent(ENetEvent& event)
                 {
                     if (event.packet->dataLength != 1) break;
                     Player* player = (Player*)event.peer->data;
-                    //printf("HOST: PLAYER DISCONNECT %p\n", player);
                     if (!player) break;
 
                     ConnectedBitmask &= ~(1 << player->ID);
@@ -757,7 +757,6 @@ void LAN::ProcessClientEvent(ENetEvent& event)
                 {
                     if (event.packet->dataLength != 1) break;
                     Player* player = (Player*)event.peer->data;
-                    //printf("CLIENT: PLAYER CONNECT %p\n", player);
                     if (!player) break;
 
                     ConnectedBitmask |= (1 << player->ID);
@@ -768,7 +767,6 @@ void LAN::ProcessClientEvent(ENetEvent& event)
                 {
                     if (event.packet->dataLength != 1) break;
                     Player* player = (Player*)event.peer->data;
-                    //printf("CLIENT: PLAYER DISCONNECT %p\n", player);
                     if (!player) break;
 
                     ConnectedBitmask &= ~(1 << player->ID);
@@ -796,7 +794,6 @@ void LAN::ProcessEvent(ENetEvent& event)
 void LAN::ProcessLAN(int type)
 {
     if (!Host) return;
-    //printf("Process(%d): %d %d\n", type, RXQueue.empty(), RXQueue.size());
 
     u32 time_last = (u32)Platform::GetMSCount();
 
@@ -842,7 +839,7 @@ void LAN::ProcessLAN(int type)
         if (event.type == ENET_EVENT_TYPE_RECEIVE && event.channelID == Chan_MP)
         {
             MPPacketHeader* header = (MPPacketHeader*)&event.packet->data[0];
-            //printf("- enet_host_service: (%d) got MP frame, len=%d type=%08X fc=%04X\n", type, event.packet->dataLength, header->Type, *(u16*)&event.packet->data[sizeof(MPPacketHeader)+12]);
+
             bool good = true;
             if (event.packet->dataLength < sizeof(MPPacketHeader))
                 good = false;
@@ -870,7 +867,6 @@ void LAN::ProcessLAN(int type)
         }
         else
         {
-            //printf("- enet_host_service: got something else, time=%d\n", SDL_GetTicks()-time_last);
             ProcessEvent(event);
         }
 
@@ -1053,7 +1049,6 @@ u16 LAN::RecvReplies(int inst, u8* packets, u64 timestamp, u16 aidmask)
         if (RXQueue.empty())
         {
             // no more replies available
-            //printf("RecvMPReplies timeout, ret=%04X myinstmask=%04X conn=%04X aidmask=%04X\n", ret, myinstmask, ConnectedBitmask, aidmask);
             return ret;
         }
 
diff --git a/src/net/LAN.h b/src/net/LAN.h
index d507e04d..87282539 100644
--- a/src/net/LAN.h
+++ b/src/net/LAN.h
@@ -87,6 +87,7 @@ public:
     void EndDiscovery();
     bool StartHost(const char* player, int numplayers);
     bool StartClient(const char* player, const char* host);
+    void EndSession();
 
     std::map<u32, DiscoveryData> GetDiscoveryList();
     std::vector<Player> GetPlayerList();
diff --git a/src/net/MPInterface.cpp b/src/net/MPInterface.cpp
index c92ac4fd..39d1915d 100644
--- a/src/net/MPInterface.cpp
+++ b/src/net/MPInterface.cpp
@@ -42,6 +42,7 @@ public:
 
 
 std::unique_ptr<MPInterface> MPInterface::Current(std::make_unique<DummyMP>());
+MPInterfaceType MPInterface::CurrentType = MPInterface_Dummy;
 
 
 void MPInterface::Set(MPInterfaceType type)
@@ -60,6 +61,8 @@ void MPInterface::Set(MPInterfaceType type)
         Current = std::make_unique<DummyMP>();
         break;
     }
+
+    CurrentType = type;
 }
 
 }
diff --git a/src/net/MPInterface.h b/src/net/MPInterface.h
index 5900a97a..eb5bef88 100644
--- a/src/net/MPInterface.h
+++ b/src/net/MPInterface.h
@@ -46,7 +46,10 @@ struct MPPacketHeader
 class MPInterface
 {
 public:
+    virtual ~MPInterface() = default;
+
     static MPInterface& Get() { return *Current; }
+    static MPInterfaceType GetType() { return CurrentType; }
     static void Set(MPInterfaceType type);
 
     [[nodiscard]] int GetRecvTimeout() const noexcept { return RecvTimeout; }
@@ -70,6 +73,7 @@ protected:
     int RecvTimeout = 25;
 
 private:
+    static MPInterfaceType CurrentType;
     static std::unique_ptr<MPInterface> Current;
 };