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)
|
||||
enable_language(OBJC C)
|
||||
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)
|
||||
if(ZLIB_FOUND)
|
||||
set(EXTRALIBS ${EXTRALIBS} ZLIB::ZLIB)
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#ifndef QT_NO_WIDGETS
|
||||
#include <QFileDialog>
|
||||
#include <QApplication>
|
||||
#else
|
||||
#include <QtPlatformHeaders/QEglFSFunctions>
|
||||
#endif
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <QMessageBox>
|
||||
|
@ -49,8 +51,8 @@
|
|||
#include <QProcessEnvironment>
|
||||
#endif
|
||||
|
||||
#ifdef QT_NO_WIDGETS
|
||||
#include <QtPlatformHeaders/QEglFSFunctions>
|
||||
#ifdef Q_OS_LINUX
|
||||
#include "linux/stpanalyzer.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
@ -75,6 +77,7 @@ ImageWriter::ImageWriter(QObject *parent)
|
|||
platform = "cli";
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
if (platform == "eglfs" || platform == "linuxfb")
|
||||
{
|
||||
_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
|
||||
_taskbarButton = nullptr;
|
||||
|
@ -923,7 +931,7 @@ void ImageWriter::pollNetwork()
|
|||
if (!a.isLoopback() && a.scopeId().isEmpty())
|
||||
{
|
||||
/* Not a loopback or IPv6 link-local address, so online */
|
||||
qDebug() << "IP:" << a;
|
||||
emit networkInfo(QString("IP: %1").arg(a.toString()));
|
||||
_online = true;
|
||||
break;
|
||||
}
|
||||
|
@ -961,11 +969,12 @@ void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
|||
};
|
||||
::settimeofday(&tv, NULL);
|
||||
|
||||
beginOSListFetch();
|
||||
emit networkOnline();
|
||||
}
|
||||
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()));
|
||||
}
|
||||
|
||||
|
@ -975,6 +984,11 @@ void ImageWriter::onTimeSyncReply(QNetworkReply *reply)
|
|||
#endif
|
||||
}
|
||||
|
||||
void ImageWriter::onSTPdetected()
|
||||
{
|
||||
emit networkInfo(tr("STP is enabled on your Ethernet switch. Getting IP will take long time."));
|
||||
}
|
||||
|
||||
bool ImageWriter::isEmbeddedMode()
|
||||
{
|
||||
return _embeddedMode;
|
||||
|
|
|
@ -159,6 +159,7 @@ signals:
|
|||
void networkOnline();
|
||||
void preparationStatusUpdate(QVariant msg);
|
||||
void osListPrepared();
|
||||
void networkInfo(QVariant msg);
|
||||
|
||||
protected slots:
|
||||
|
||||
|
@ -176,6 +177,7 @@ protected slots:
|
|||
void onTimeSyncReply(QNetworkReply *reply);
|
||||
void onPreparationStatusUpdate(QString msg);
|
||||
void handleNetworkRequestFinished(QNetworkReply *data);
|
||||
void onSTPdetected();
|
||||
|
||||
private:
|
||||
// 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(networkOnline()), qmlwindow, SLOT(fetchOSlist()));
|
||||
qmlwindow->connect(&imageWriter, SIGNAL(osListPrepared()), qmlwindow, SLOT(onOsListPrepared()));
|
||||
qmlwindow->connect(&imageWriter, SIGNAL(networkInfo(QVariant)), qmlwindow, SLOT(onNetworkInfo(QVariant)));
|
||||
|
||||
#ifndef QT_NO_WIDGETS
|
||||
/* Set window position */
|
||||
|
@ -375,7 +376,8 @@ int main(int argc, char *argv[])
|
|||
qmlwindow->setProperty("y", y);
|
||||
#endif
|
||||
|
||||
imageWriter.beginOSListFetch();
|
||||
if (imageWriter.isOnline())
|
||||
imageWriter.beginOSListFetch();
|
||||
|
||||
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 {
|
||||
id: networkInfo
|
||||
Layout.columnSpan: 3
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 18
|
||||
font.family: roboto.name
|
||||
visible: imageWriter.isEmbeddedMode()
|
||||
text: qsTr("Network not ready yet")
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.columnSpan: 3
|
||||
color: "#ffffff"
|
||||
|
@ -1316,6 +1326,10 @@ ApplicationWindow {
|
|||
progressText.text = qsTr("Finalizing...")
|
||||
}
|
||||
|
||||
function onNetworkInfo(msg) {
|
||||
networkInfo.text = msg
|
||||
}
|
||||
|
||||
function shuffle(arr) {
|
||||
for (var i = 0; i < arr.length - 1; i++) {
|
||||
var j = i + Math.floor(Math.random() * (arr.length - i));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue