mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 16:05:21 +01:00
Embedded: fix network detection
This commit is contained in:
parent
ebe72a4b16
commit
8c9de2d78c
7 changed files with 188 additions and 6 deletions
|
@ -29,7 +29,7 @@ if (APPLE)
|
||||||
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
dependencies/drivelist/src/darwin/list.mm dependencies/drivelist/src/darwin/REDiskList.m icons/rpi-imager.icns)
|
||||||
enable_language(OBJC C)
|
enable_language(OBJC C)
|
||||||
elseif (UNIX)
|
elseif (UNIX)
|
||||||
set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp linux/networkmanagerapi.h linux/networkmanagerapi.cpp)
|
set(DEPENDENCIES dependencies/mountutils/src/linux/functions.cpp linux/linuxdrivelist.cpp linux/networkmanagerapi.h linux/networkmanagerapi.cpp linux/stpanalyzer.h linux/stpanalyzer.cpp)
|
||||||
find_package(ZLIB)
|
find_package(ZLIB)
|
||||||
if(ZLIB_FOUND)
|
if(ZLIB_FOUND)
|
||||||
set(EXTRALIBS ${EXTRALIBS} ZLIB::ZLIB)
|
set(EXTRALIBS ${EXTRALIBS} ZLIB::ZLIB)
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
#ifndef QT_NO_WIDGETS
|
#ifndef QT_NO_WIDGETS
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#else
|
||||||
|
#include <QtPlatformHeaders/QEglFSFunctions>
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -49,8 +51,8 @@
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef QT_NO_WIDGETS
|
#ifdef Q_OS_LINUX
|
||||||
#include <QtPlatformHeaders/QEglFSFunctions>
|
#include "linux/stpanalyzer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -75,6 +77,7 @@ ImageWriter::ImageWriter(QObject *parent)
|
||||||
platform = "cli";
|
platform = "cli";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
if (platform == "eglfs" || platform == "linuxfb")
|
if (platform == "eglfs" || platform == "linuxfb")
|
||||||
{
|
{
|
||||||
_embeddedMode = true;
|
_embeddedMode = true;
|
||||||
|
@ -98,7 +101,12 @@ ImageWriter::ImageWriter(QObject *parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StpAnalyzer *stpAnalyzer = new StpAnalyzer(5, this);
|
||||||
|
connect(stpAnalyzer, SIGNAL(detected()), SLOT(onSTPdetected()));
|
||||||
|
stpAnalyzer->startListening("eth0");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
_taskbarButton = nullptr;
|
_taskbarButton = nullptr;
|
||||||
|
@ -923,7 +931,7 @@ void ImageWriter::pollNetwork()
|
||||||
if (!a.isLoopback() && a.scopeId().isEmpty())
|
if (!a.isLoopback() && a.scopeId().isEmpty())
|
||||||
{
|
{
|
||||||
/* Not a loopback or IPv6 link-local address, so online */
|
/* Not a loopback or IPv6 link-local address, so online */
|
||||||
qDebug() << "IP:" << a;
|
emit networkInfo(QString("IP: %1").arg(a.toString()));
|
||||||
_online = true;
|
_online = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -961,11 +969,12 @@ void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
||||||
};
|
};
|
||||||
::settimeofday(&tv, NULL);
|
::settimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
beginOSListFetch();
|
||||||
emit networkOnline();
|
emit networkOnline();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "Error synchronizing time. Trying again in 3 seconds";
|
emit networkInfo(tr("Error synchronizing time. Trying again in 3 seconds"));
|
||||||
QTimer::singleShot(3000, this, SLOT(syncTime()));
|
QTimer::singleShot(3000, this, SLOT(syncTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,6 +984,11 @@ void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageWriter::onSTPdetected()
|
||||||
|
{
|
||||||
|
emit networkInfo(tr("STP is enabled on your Ethernet switch. Getting IP will take long time."));
|
||||||
|
}
|
||||||
|
|
||||||
bool ImageWriter::isEmbeddedMode()
|
bool ImageWriter::isEmbeddedMode()
|
||||||
{
|
{
|
||||||
return _embeddedMode;
|
return _embeddedMode;
|
||||||
|
|
|
@ -159,6 +159,7 @@ signals:
|
||||||
void networkOnline();
|
void networkOnline();
|
||||||
void preparationStatusUpdate(QVariant msg);
|
void preparationStatusUpdate(QVariant msg);
|
||||||
void osListPrepared();
|
void osListPrepared();
|
||||||
|
void networkInfo(QVariant msg);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
||||||
|
@ -176,6 +177,7 @@ protected slots:
|
||||||
void onTimeSyncReply(QNetworkReply *reply);
|
void onTimeSyncReply(QNetworkReply *reply);
|
||||||
void onPreparationStatusUpdate(QString msg);
|
void onPreparationStatusUpdate(QString msg);
|
||||||
void handleNetworkRequestFinished(QNetworkReply *data);
|
void handleNetworkRequestFinished(QNetworkReply *data);
|
||||||
|
void onSTPdetected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Recursively walk all the entries with subitems and, for any which
|
// Recursively walk all the entries with subitems and, for any which
|
||||||
|
|
118
src/linux/stpanalyzer.cpp
Normal file
118
src/linux/stpanalyzer.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/**
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
* Copyright (C) 2024 Raspberry Pi Ltd
|
||||||
|
*
|
||||||
|
* Class to detect if the Spanning-Tree-Protocol
|
||||||
|
* is enabled on the Ethernet switch (which can
|
||||||
|
* cause a long delay in getting an IP-address)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stpanalyzer.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QtEndian>
|
||||||
|
|
||||||
|
struct stp_packet {
|
||||||
|
/* Ethernet header */
|
||||||
|
struct ethhdr eth;
|
||||||
|
/* 802.2 LLC header */
|
||||||
|
uint8_t dsap, ssap, control;
|
||||||
|
/* STP fields */
|
||||||
|
uint16_t protocol;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t msgtype;
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t rootpriority;
|
||||||
|
unsigned char rootmac[6];
|
||||||
|
uint32_t rootpathcost;
|
||||||
|
uint16_t bridgepriority;
|
||||||
|
unsigned char bridgemac[6];
|
||||||
|
uint16_t portid;
|
||||||
|
uint16_t msgage;
|
||||||
|
uint16_t maxage;
|
||||||
|
uint16_t hellotime;
|
||||||
|
uint16_t forwarddelay;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#define LSAP_BDPU 0x42
|
||||||
|
#define MULTICAST_MAC_BDPU {0x1, 0x80, 0xC2, 0, 0, 0}
|
||||||
|
#define MULTICAST_MAC_BDPUPV {0x1, 0, 0x0C, 0xCC, 0xCC, 0xCD}
|
||||||
|
|
||||||
|
StpAnalyzer::StpAnalyzer(int onlyReportIfForwardDelayIsAbove, QObject *parent)
|
||||||
|
: QObject(parent), _s(-1), _minForwardDelay(onlyReportIfForwardDelayIsAbove), _qsn(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StpAnalyzer::~StpAnalyzer()
|
||||||
|
{
|
||||||
|
stopListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StpAnalyzer::startListening(const QByteArray &ifname)
|
||||||
|
{
|
||||||
|
int iface;
|
||||||
|
|
||||||
|
if (_s != -1)
|
||||||
|
return; /* Already listening */
|
||||||
|
|
||||||
|
_s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_802_2));
|
||||||
|
if (_s < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iface = if_nametoindex(ifname.constData());
|
||||||
|
if (!iface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct packet_mreq mreq = { iface, PACKET_MR_MULTICAST, ETH_ALEN, MULTICAST_MAC_BDPU };
|
||||||
|
setsockopt(_s, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||||
|
struct packet_mreq mreq2 = { iface, PACKET_MR_MULTICAST, ETH_ALEN, MULTICAST_MAC_BDPUPV };
|
||||||
|
setsockopt(_s, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq2, sizeof(mreq2));
|
||||||
|
|
||||||
|
_qsn = new QSocketNotifier(_s, QSocketNotifier::Read, this);
|
||||||
|
connect(_qsn, SIGNAL(activated(QSocketDescriptor,QSocketNotifier::Type)), SLOT(onPacket(QSocketDescriptor,QSocketNotifier::Type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StpAnalyzer::stopListening()
|
||||||
|
{
|
||||||
|
if (_s != -1)
|
||||||
|
{
|
||||||
|
_qsn->setEnabled(false);
|
||||||
|
_qsn->deleteLater();
|
||||||
|
_qsn = nullptr;
|
||||||
|
close(_s);
|
||||||
|
_s = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StpAnalyzer::onPacket(QSocketDescriptor socket, QSocketNotifier::Type type)
|
||||||
|
{
|
||||||
|
struct stp_packet packet = { 0 };
|
||||||
|
|
||||||
|
int len = recvfrom(_s, &packet, sizeof(packet), 0, NULL, 0);
|
||||||
|
|
||||||
|
if (len == sizeof(packet)
|
||||||
|
&& packet.dsap == LSAP_BDPU
|
||||||
|
&& packet.ssap == LSAP_BDPU
|
||||||
|
&& packet.protocol == 0)
|
||||||
|
{
|
||||||
|
/* It is a STP packet */
|
||||||
|
int forwardDelay = qFromLittleEndian(packet.forwarddelay);
|
||||||
|
if (forwardDelay > _minForwardDelay)
|
||||||
|
{
|
||||||
|
emit detected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only analyze first packet */
|
||||||
|
stopListening();
|
||||||
|
}
|
||||||
|
}
|
32
src/linux/stpanalyzer.h
Normal file
32
src/linux/stpanalyzer.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef STPANALYZER_H
|
||||||
|
#define STPANALYZER_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
* Copyright (C) 2024 Raspberry Pi Ltd
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
|
||||||
|
class StpAnalyzer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
StpAnalyzer(int onlyReportIfForwardDelayIsAbove = 5, QObject *parent = nullptr);
|
||||||
|
virtual ~StpAnalyzer();
|
||||||
|
void startListening(const QByteArray &ifname);
|
||||||
|
void stopListening();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void detected();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _s, _minForwardDelay;
|
||||||
|
QSocketNotifier *_qsn;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void onPacket(QSocketDescriptor socket, QSocketNotifier::Type type);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STPANALYZER_H
|
|
@ -347,6 +347,7 @@ int main(int argc, char *argv[])
|
||||||
qmlwindow->connect(&imageWriter, SIGNAL(finalizing()), qmlwindow, SLOT(onFinalizing()));
|
qmlwindow->connect(&imageWriter, SIGNAL(finalizing()), qmlwindow, SLOT(onFinalizing()));
|
||||||
qmlwindow->connect(&imageWriter, SIGNAL(networkOnline()), qmlwindow, SLOT(fetchOSlist()));
|
qmlwindow->connect(&imageWriter, SIGNAL(networkOnline()), qmlwindow, SLOT(fetchOSlist()));
|
||||||
qmlwindow->connect(&imageWriter, SIGNAL(osListPrepared()), qmlwindow, SLOT(onOsListPrepared()));
|
qmlwindow->connect(&imageWriter, SIGNAL(osListPrepared()), qmlwindow, SLOT(onOsListPrepared()));
|
||||||
|
qmlwindow->connect(&imageWriter, SIGNAL(networkInfo(QVariant)), qmlwindow, SLOT(onNetworkInfo(QVariant)));
|
||||||
|
|
||||||
#ifndef QT_NO_WIDGETS
|
#ifndef QT_NO_WIDGETS
|
||||||
/* Set window position */
|
/* Set window position */
|
||||||
|
@ -375,7 +376,8 @@ int main(int argc, char *argv[])
|
||||||
qmlwindow->setProperty("y", y);
|
qmlwindow->setProperty("y", y);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
imageWriter.beginOSListFetch();
|
if (imageWriter.isOnline())
|
||||||
|
imageWriter.beginOSListFetch();
|
||||||
|
|
||||||
int rc = app.exec();
|
int rc = app.exec();
|
||||||
|
|
||||||
|
|
14
src/main.qml
14
src/main.qml
|
@ -320,6 +320,16 @@ ApplicationWindow {
|
||||||
text: qsTr("Using custom repository: %1").arg(imageWriter.constantOsListUrl())
|
text: qsTr("Using custom repository: %1").arg(imageWriter.constantOsListUrl())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: networkInfo
|
||||||
|
Layout.columnSpan: 3
|
||||||
|
color: "#ffffff"
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.family: roboto.name
|
||||||
|
visible: imageWriter.isEmbeddedMode()
|
||||||
|
text: qsTr("Network not ready yet")
|
||||||
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
Layout.columnSpan: 3
|
Layout.columnSpan: 3
|
||||||
color: "#ffffff"
|
color: "#ffffff"
|
||||||
|
@ -1316,6 +1326,10 @@ ApplicationWindow {
|
||||||
progressText.text = qsTr("Finalizing...")
|
progressText.text = qsTr("Finalizing...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onNetworkInfo(msg) {
|
||||||
|
networkInfo.text = msg
|
||||||
|
}
|
||||||
|
|
||||||
function shuffle(arr) {
|
function shuffle(arr) {
|
||||||
for (var i = 0; i < arr.length - 1; i++) {
|
for (var i = 0; i < arr.length - 1; i++) {
|
||||||
var j = i + Math.floor(Math.random() * (arr.length - i));
|
var j = i + Math.floor(Math.random() * (arr.length - i));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue