From 3ac37d71641c79ff4ea98c8c54227d50756bbc82 Mon Sep 17 00:00:00 2001 From: paulober <44974737+paulober@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:02:51 +0100 Subject: [PATCH 01/10] Add USB Ethernet Gadget toggle Signed-off-by: paulober <44974737+paulober@users.noreply.github.com> --- src/CMakeLists.txt | 5 +- src/OptionsPopup.qml | 42 ++++++- src/cli.cpp | 4 +- .../zlib-1.3.1/{zconf.h => zconf.h.included} | 0 src/downloadthread.cpp | 22 +++- src/downloadthread.h | 3 +- src/extraFiles.qrc | 7 ++ src/extraFiles/10-usb.network | 33 +++++ .../configure-usb-ether-gadget-once.sh | 115 ++++++++++++++++++ src/extraFiles/usb-ether-gadget-once.service | 17 +++ src/imagewriter.cpp | 6 +- src/imagewriter.h | 5 +- 12 files changed, 248 insertions(+), 11 deletions(-) rename src/dependencies/zlib-1.3.1/{zconf.h => zconf.h.included} (100%) create mode 100644 src/extraFiles.qrc create mode 100644 src/extraFiles/10-usb.network create mode 100644 src/extraFiles/configure-usb-ether-gadget-once.sh create mode 100644 src/extraFiles/usb-ether-gadget-once.service diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a266380b2..3c0600959 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -278,7 +278,8 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc ${QM_FILES}) if (WIN32) # Adding WIN32 prevents a console window being opened on Windows - add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${DEPENDENCIES}) + add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${DEPENDENCIES} + extraFiles.qrc) else() add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${DEPENDENCIES}) endif() @@ -495,4 +496,4 @@ else() endif() include_directories(${CURL_INCLUDE_DIR} ${LibArchive_INCLUDE_DIR} ${LIBLZMA_INCLUDE_DIRS} ${LIBDRM_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${ZSTD_INCLUDE_DIR}) -target_link_libraries(${PROJECT_NAME} PRIVATE ${QT}::Core ${QT}::Quick ${QT}::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${ZSTD_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBLZMA_LIBRARIES} ${LIBDRM_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS}) \ No newline at end of file +target_link_libraries(${PROJECT_NAME} PRIVATE ${QT}::Core ${QT}::Quick ${QT}::Svg ${CURL_LIBRARIES} ${LibArchive_LIBRARIES} ${ZSTD_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBLZMA_LIBRARIES} ${LIBDRM_LIBRARIES} ${ATOMIC_LIBRARY} ${EXTRALIBS}) diff --git a/src/OptionsPopup.qml b/src/OptionsPopup.qml index 88f5410da..b770e57b9 100644 --- a/src/OptionsPopup.qml +++ b/src/OptionsPopup.qml @@ -34,6 +34,7 @@ Window { property string cloudinitrun property string cloudinitwrite property string cloudinitnetwork + property bool enableEtherGadget signal saveSettingsSignal(var settings) @@ -355,6 +356,11 @@ Window { ColumnLayout { // Remote access tab + ImCheckBox { + id: chkUSBEther + text: qsTr("Enable USB Ethernet Gadget") + } + ImCheckBox { id: chkSSH text: qsTr("Enable SSH") @@ -826,6 +832,40 @@ Window { addCmdline("cfg80211.ieee80211_regdom="+fieldWifiCountry.editText) } + if (chkUSBEther.checked) { + addConfig("dtoverlay=dwc2,dr_mode=peripheral") + // only required if no conf is used to load modules + // g_ether must not be loaded when using manual config + // with sh script + addCmdline("modules-load=dwc2,g_ether") + // TODO: generate mac addresses if there are issues with DHCP + //addCmdline("g_ether.dev_addr=8A:89:6a:8d:14:22") + //addCmdline("g_ether.host_addr=6A:89:6a:8d:14:22") + addCmdline("g_ether.idVendor=0x04b3") + addCmdline("g_ether.idProduct=0x4010") + addCmdline("g_ether.iManufacturer=\"Raspberry Pi\"") + addCmdline("g_ether.bcdDevice=0x0100") + addCmdline("g_ether.iProduct=\"USB Ethernet Gadget\"") + // TODO: maybe set device serial + //addCmdline("g_ether.iSerialNumber=8c1aceb07269b131") + + enableEtherGadget = true; + + // manual config with this script requires not to load g_ether + //addFirstRun("mv /boot/firmware/etherSet.sh /usr/sbin/configure-usb-ether-gadget-once") + //addFirstRun("chmod +x /usr/sbin/configure-usb-ether-gadget-once") + //addFirstRun("mv /boot/firmware/sysdEth.srv /etc/systemd/system/usb-ether-gadget-once.service") + //addFirstRun("mkdir -p /etc/systemd/system/usb-gadget.target.wants") + //addFirstRun("ln -s /etc/systemd/system/usb-ether-gadget-once.service /etc/systemd/system/usb-gadget.target.wants/usb-ether-gadget-once.service") + addFirstRun("mv /boot/firmware/10usb.net /etc/systemd/network/10-usb.network\n") + // enable stuff + //addFirstRun("systemctl daemon-reload") + //addFirstRun("systemctl enable usb-ether-gadget-once.service") + //addFirstRun("systemctl start usb-ether-gadget-once.service\n") + // enable networkd as I don't have NetworkManager config + addFirstRun("systemctl enable systemd-networkd\n") + } + if (chkLocale.checked) { var kbdconfig = "XKBMODEL=\"pc105\"\n" kbdconfig += "XKBLAYOUT=\""+fieldKeyboardLayout.editText+"\"\n" @@ -870,7 +910,7 @@ Window { addCloudInit("runcmd:\n"+cloudinitrun+"\n") } - imageWriter.setImageCustomization(config, cmdline, firstrun, cloudinit, cloudinitnetwork) + imageWriter.setImageCustomization(config, cmdline, firstrun, cloudinit, cloudinitnetwork, enableEtherGadget) } function saveSettings() diff --git a/src/cli.cpp b/src/cli.cpp index ed5aa062e..bb0e88c19 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -186,7 +186,7 @@ int Cli::run() return 1; } - _imageWriter->setImageCustomization("", "", "", userData, networkConfig); + _imageWriter->setImageCustomization("", "", "", userData, networkConfig, false); } else if (!parser.value("first-run-script").isEmpty()) { @@ -208,7 +208,7 @@ int Cli::run() return 1; } - _imageWriter->setImageCustomization("", "", firstRunScript, "", ""); + _imageWriter->setImageCustomization("", "", firstRunScript, "", "", false); } _imageWriter->setDst(args[1]); diff --git a/src/dependencies/zlib-1.3.1/zconf.h b/src/dependencies/zlib-1.3.1/zconf.h.included similarity index 100% rename from src/dependencies/zlib-1.3.1/zconf.h rename to src/dependencies/zlib-1.3.1/zconf.h.included diff --git a/src/downloadthread.cpp b/src/downloadthread.cpp index 3db9c2384..4e488e609 100644 --- a/src/downloadthread.cpp +++ b/src/downloadthread.cpp @@ -885,7 +885,7 @@ qint64 DownloadThread::_sectorsWritten() return -1; } -void DownloadThread::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudInitNetwork, const QByteArray &initFormat) +void DownloadThread::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudInitNetwork, const QByteArray &initFormat, const bool enableEtherGadget) { _config = config; _cmdline = cmdline; @@ -893,6 +893,7 @@ void DownloadThread::setImageCustomization(const QByteArray &config, const QByte _cloudinit = cloudinit; _cloudinitNetwork = cloudInitNetwork; _initFormat = initFormat; + _enableEtherGadget = enableEtherGadget; } bool DownloadThread::_customizeImage() @@ -974,6 +975,25 @@ bool DownloadThread::_customizeImage() _cmdline += " systemd.run=/boot/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target"; } + if (_enableEtherGadget) { + // load files from disk and write + QByteArray networkConfig = _fileGetContentsTrimmed("://extraFiles/10-usb.network"); + fat->writeFile("10usb.net", networkConfig); + // little optimization for memory constraint systems - add if more files are loaded in this scope + //networkConfig.clear(); + + // only needed for manual config without g_ether + //QByteArray script = _fileGetContentsTrimmed("://extraFiles/configure-usb-ether-gadget-once.sh"); + //fat->writeFile("etherSet.sh", script); + // little optimization for memory constraint systems - add if more files are loaded in this scope + //script.clear(); + + //QByteArray serviceFile = _fileGetContentsTrimmed("://extraFiles/usb-ether-gadget-once.service"); + //fat->writeFile("sysdEth.srv", serviceFile); + // not needed anymore, because auto cleanup after out of scope + //serviceFile.clear(); + } + if (!_cloudinit.isEmpty() && _initFormat == "cloudinit") { _cloudinit = "#cloud-config\n"+_cloudinit; diff --git a/src/downloadthread.h b/src/downloadthread.h index 3fb954255..a8f3483a7 100644 --- a/src/downloadthread.h +++ b/src/downloadthread.h @@ -116,7 +116,7 @@ class DownloadThread : public QThread /* * Enable image customization */ - void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const QByteArray &initFormat); + void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const QByteArray &initFormat, const bool enableEtherGadget); /* * Thread safe download progress query functions @@ -171,6 +171,7 @@ class DownloadThread : public QThread std::uint64_t _lastFailureOffset; qint64 _sectorsStart; QByteArray _url, _useragent, _buf, _filename, _lastError, _expectedHash, _config, _cmdline, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat; + bool _enableEtherGadget; char *_firstBlock; size_t _firstBlockSize; static QByteArray _proxy; diff --git a/src/extraFiles.qrc b/src/extraFiles.qrc new file mode 100644 index 000000000..df02268f7 --- /dev/null +++ b/src/extraFiles.qrc @@ -0,0 +1,7 @@ + + + extraFiles/10-usb.network + extraFiles/configure-usb-ether-gadget-once.sh + extraFiles/usb-ether-gadget-once.service + + diff --git a/src/extraFiles/10-usb.network b/src/extraFiles/10-usb.network new file mode 100644 index 000000000..8223e446b --- /dev/null +++ b/src/extraFiles/10-usb.network @@ -0,0 +1,33 @@ +[Match] +Name=usb* + +[Link] +RequiredForOnline=no + +[Network] +# Configure Subnet for USB Ethernet Gadget +# - IP Range: 10.12.194.1 to 10.12.194.14 +# - Total IPs: 16 +# - Usable IPs: 14 +# - Network Address: 10.12.194.0 +# - Broadcast Address: 10.12.194.15 +# - Subnet Mask: 255.255.255.240 (/28) +# | 10 - private +# | 12 - 2012 founding of Raspberry Pi Ltd. +# | 194 - address of Raspberry Pi Ltd. in the Science Park, Cambridge +# | 1 - first device +# TODO: maybe only static hostname to not conflict when multiple devices are connected +# to the same computer +Address=10.12.194.1/28 +DHCPServer=yes + +[DHCPServer] +# Configure DHCP settings +PoolSize=16 # Number of IP addresses available for lease +DefaultLeaseTimeSec=60 # Default lease time for DHCP clients +MaxLeaseTimeSec=60 # Maximum lease time for DHCP clients + +# Network isolation settings (no internet) +EmitDNS=no # Do not provide DNS information +EmitNTP=no # Do not provide NTP information +EmitRouter=no # Do not provide router information diff --git a/src/extraFiles/configure-usb-ether-gadget-once.sh b/src/extraFiles/configure-usb-ether-gadget-once.sh new file mode 100644 index 000000000..199c799dc --- /dev/null +++ b/src/extraFiles/configure-usb-ether-gadget-once.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +###################### +## Config variables ## +###################### +# required for RNDIS (Windows compatibility) +# Acer Incorporated. - Other hardware - Acer USB Ethernet/RNDIS Gadget +# did not work correctly +#VID="0x0502" +#PID="0x3230" +# Did work correctly with IBM driver +VID="0x04b3" +PID="0x4010" +SERIAL=$(grep Serial /proc/cpuinfo | awk '{print $3}') +# Compute the SHA256 hash of the serial number +sha=$(echo -n "$SERIAL" | sha256sum | cut -d ' ' -f 1) +config_path=g_ether +########################## +## END Config variables ## +########################## + +############################### +## Setup basic configuration ## +############################### +mkdir -p ${config_path} +cd ${config_path} || exit 1 + +echo "${VID}" > idVendor # Custom Vendor ID +echo "${PID}" > idProduct # Custom Product ID +echo 0x0100 > bcdDevice # v1.0.0 +echo 0x0200 > bcdUSB # USB2 +# setup appearance +mkdir -p strings/0x409 +echo "${SERIAL}" > strings/0x409/serialnumber +echo "Raspberry Pi" > strings/0x409/manufacturer +echo "USB Ethernet Gadget" > strings/0x409/product +################################### +## END Setup basic configuration ## +################################### + +#################################################### +## ECM (Ethernet Control Model) for Mac and Linux ## +#################################################### +mkdir -p configs/c.1/strings/0x409 +mkdir -p functions/ecm.usb0 + +# max possible stable USB 2.0 power +echo 250 > configs/c.1/MaxPower +echo "ECM" > configs/c.1/strings/0x409/configuration +######################################################## +## END ECM (Ethernet Control Model) for Mac and Linux ## +######################################################## + +##################################### +## RNDIS for Windows compatibility ## +##################################### +mkdir -p configs/c.2/strings/0x409 +mkdir -p functions/rndis.usb0 +# not allowed +#mkdir -p os_desc/interface.rndis + +echo "RNDIS" > configs/c.2/strings/0x409/configuration +#echo "RNDIS" > os_desc/interface.rndis/compatibility_id +#echo "5162001" > os_desc/interface.rndis/sub_compatibility_id +######################################### +## END RNDIS for Windows compatibility ## +######################################### + +######################### +## Setup MAC addresses ## +######################### +# Generate MAC addresses using slices of the hash +# TODO: maybe change prefix +mac0=6A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} +mac1=7A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} +mac2=8A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} +mac3=9A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} + +echo "${mac1}" > functions/ecm.usb0/host_addr +echo "${mac3}" > functions/ecm.usb0/dev_addr + +echo "${mac0}" > functions/rndis.usb0/host_addr +echo "${mac2}" > functions/rndis.usb0/dev_addr +############################# +## END Setup MAC addresses ## +############################# + +###################################### +## Link functions to configurations ## +###################################### +ln -s functions/ecm.usb0 configs/c.1/ +ln -s functions/rndis.usb0 configs/c.2/ +########################################## + +###################################### +## Link the UDC to start the gadget ## +###################################### +count=0 +while [ ${count} -lt 15 ]; do + udc="$(ls /sys/class/udc)" + if [ -n "${udc}" ]; then + echo "Found UDC ${udc}" + echo "${udc}" > UDC + break + fi + count=$((count + 1)) + sleep 1 +done +########################################## +## END Link the UDC to start the gadget ## +########################################## + +systemctl restart getty@ttyGS0 + +echo "Ethernet USB OTG gadget init complete - $(cat UDC)" diff --git a/src/extraFiles/usb-ether-gadget-once.service b/src/extraFiles/usb-ether-gadget-once.service new file mode 100644 index 000000000..941f4930a --- /dev/null +++ b/src/extraFiles/usb-ether-gadget-once.service @@ -0,0 +1,17 @@ +[Unit] +Description=Configure USB Ethernet Gadget +Requires=sys-kernel-config.mount +After=sys-kernel-config.mount +Requires=systemd-modules-load.service +After=systemd-modules-load.service + +[Service] +Type=oneshot +WorkingDirectory=/sys/kernel/config/usb_gadget +ExecStart=/usr/sbin/configure-usb-ether-gadget-once +StandardOutput=journal+console +# TODO: remove +User=root + +[Install] +WantedBy=usb-gadget.target diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp index c538b0970..55bc39ff2 100644 --- a/src/imagewriter.cpp +++ b/src/imagewriter.cpp @@ -296,7 +296,7 @@ void ImageWriter::startWrite() connect(_thread, SIGNAL(preparationStatusUpdate(QString)), SLOT(onPreparationStatusUpdate(QString))); _thread->setVerifyEnabled(_verifyEnabled); _thread->setUserAgent(QString("Mozilla/5.0 rpi-imager/%1").arg(constantVersion()).toUtf8()); - _thread->setImageCustomization(_config, _cmdline, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat); + _thread->setImageCustomization(_config, _cmdline, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat, _enableEtherGadget); if (!_expectedHash.isEmpty() && _cachedFileHash != _expectedHash && _cachingEnabled) { @@ -1184,18 +1184,20 @@ void ImageWriter::setSetting(const QString &key, const QVariant &value) _settings.sync(); } -void ImageWriter::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork) +void ImageWriter::setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget) { _config = config; _cmdline = cmdline; _firstrun = firstrun; _cloudinit = cloudinit; _cloudinitNetwork = cloudinitNetwork; + _enableEtherGadget = enableEtherGadget; qDebug() << "Custom config.txt entries:" << config; qDebug() << "Custom cmdline.txt entries:" << cmdline; qDebug() << "Custom firstuse.sh:" << firstrun; qDebug() << "Cloudinit:" << cloudinit; + qDebug() << "Enable USB Ethernet gadget:" << enableEtherGadget; } QString ImageWriter::crypt(const QByteArray &password) diff --git a/src/imagewriter.h b/src/imagewriter.h index 843ed539b..166c241aa 100644 --- a/src/imagewriter.h +++ b/src/imagewriter.h @@ -122,8 +122,8 @@ class ImageWriter : public QObject Q_INVOKABLE QString getPSK(); Q_INVOKABLE bool getBoolSetting(const QString &key); - Q_INVOKABLE void setSetting(const QString &key, const QVariant &value); - Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork); + Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);//, const QVariantList + Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget); Q_INVOKABLE void setSavedCustomizationSettings(const QVariantMap &map); Q_INVOKABLE QVariantMap getSavedCustomizationSettings(); Q_INVOKABLE void clearSavedCustomizationSettings(); @@ -191,6 +191,7 @@ protected slots: QUrl _src, _repo; QString _dst, _cacheFileName, _parentCategory, _osName, _currentLang, _currentLangcode, _currentKeyboard; QByteArray _expectedHash, _cachedFileHash, _cmdline, _config, _firstrun, _cloudinit, _cloudinitNetwork, _initFormat; + bool _enableEtherGadget; quint64 _downloadLen, _extrLen, _devLen, _dlnow, _verifynow; DriveListModel _drivelist; QQmlApplicationEngine *_engine; From a2223c1e9d90783d7f301a78b62570b6f7ab61c5 Mon Sep 17 00:00:00 2001 From: paulober <44974737+paulober@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:56:31 +0100 Subject: [PATCH 02/10] Implemented requested changes and switched to auto g_ether Signed-off-by: paulober <44974737+paulober@users.noreply.github.com> --- src/CMakeLists.txt | 3 +- src/OptionsPopup.qml | 45 +++---- src/downloadthread.cpp | 18 +-- src/extraFiles.qrc | 4 +- .../configure-usb-ether-gadget-once.sh | 115 ------------------ src/extraFiles/g_ether.conf | 1 + src/extraFiles/usb-ether-gadget-once.service | 17 --- src/extraFiles/usb-ether-gadget.conf | 2 + src/imagewriter.cpp | 15 ++- src/imagewriter.h | 17 ++- src/main.qml | 2 +- 11 files changed, 64 insertions(+), 175 deletions(-) delete mode 100644 src/extraFiles/configure-usb-ether-gadget-once.sh create mode 100644 src/extraFiles/g_ether.conf delete mode 100644 src/extraFiles/usb-ether-gadget-once.service create mode 100644 src/extraFiles/usb-ether-gadget.conf diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c0600959..628d5a626 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -281,7 +281,8 @@ if (WIN32) add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${DEPENDENCIES} extraFiles.qrc) else() - add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${DEPENDENCIES}) + add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${DEPENDENCIES} + extraFiles.qrc) endif() set_property(TARGET ${PROJECT_NAME} PROPERTY AUTOMOC ON) diff --git a/src/OptionsPopup.qml b/src/OptionsPopup.qml index b770e57b9..11fc379da 100644 --- a/src/OptionsPopup.qml +++ b/src/OptionsPopup.qml @@ -34,6 +34,7 @@ Window { property string cloudinitrun property string cloudinitwrite property string cloudinitnetwork + property bool deviceUsbOtgSupport property bool enableEtherGadget signal saveSettingsSignal(var settings) @@ -359,6 +360,7 @@ Window { ImCheckBox { id: chkUSBEther text: qsTr("Enable USB Ethernet Gadget") + enabled: deviceUsbOtgSupport } ImCheckBox { @@ -635,6 +637,18 @@ Window { } } + var hwFilterList = imageWriter.getHWFilterList() + var hwFilterIsModelZero = imageWriter.getHWFilterIsModelZero() + + if (hwFilterList) { + var targetTags = ["pi5-64bit", "pi4-64bit", "pi5-32bit", "pi4-32bit"] + deviceUsbOtgSupport = targetTags.some(tag => hwFilterList.includes(tag)) || hwFilterIsModelZero + if (!deviceUsbOtgSupport) { + // make sure it isn't disabled and selected + chkUSBEther = false; + } + } + //open() show() raise() @@ -834,35 +848,14 @@ Window { } if (chkUSBEther.checked) { addConfig("dtoverlay=dwc2,dr_mode=peripheral") - // only required if no conf is used to load modules - // g_ether must not be loaded when using manual config - // with sh script - addCmdline("modules-load=dwc2,g_ether") - // TODO: generate mac addresses if there are issues with DHCP - //addCmdline("g_ether.dev_addr=8A:89:6a:8d:14:22") - //addCmdline("g_ether.host_addr=6A:89:6a:8d:14:22") - addCmdline("g_ether.idVendor=0x04b3") - addCmdline("g_ether.idProduct=0x4010") - addCmdline("g_ether.iManufacturer=\"Raspberry Pi\"") - addCmdline("g_ether.bcdDevice=0x0100") - addCmdline("g_ether.iProduct=\"USB Ethernet Gadget\"") - // TODO: maybe set device serial - //addCmdline("g_ether.iSerialNumber=8c1aceb07269b131") enableEtherGadget = true; - // manual config with this script requires not to load g_ether - //addFirstRun("mv /boot/firmware/etherSet.sh /usr/sbin/configure-usb-ether-gadget-once") - //addFirstRun("chmod +x /usr/sbin/configure-usb-ether-gadget-once") - //addFirstRun("mv /boot/firmware/sysdEth.srv /etc/systemd/system/usb-ether-gadget-once.service") - //addFirstRun("mkdir -p /etc/systemd/system/usb-gadget.target.wants") - //addFirstRun("ln -s /etc/systemd/system/usb-ether-gadget-once.service /etc/systemd/system/usb-gadget.target.wants/usb-ether-gadget-once.service") - addFirstRun("mv /boot/firmware/10usb.net /etc/systemd/network/10-usb.network\n") - // enable stuff - //addFirstRun("systemctl daemon-reload") - //addFirstRun("systemctl enable usb-ether-gadget-once.service") - //addFirstRun("systemctl start usb-ether-gadget-once.service\n") - // enable networkd as I don't have NetworkManager config + addFirstRun("\nmv /boot/firmware/10usb.net /etc/systemd/network/10-usb.network") + addFirstRun("mv /boot/firmware/geth.cnf /etc/modprobe.d/g_ether.conf") + addFirstRun("mv /boot/firmware/gemod.cnf /etc/modules-load.d/usb-ether-gadget.conf\n") + addFirstRun("SERIAL=$(grep Serial /proc/cpuinfo | awk '{print $3}')") + addFirstRun("sed -i \"s//$SERIAL/g\" /etc/modprobe.d/g_ether.conf") addFirstRun("systemctl enable systemd-networkd\n") } diff --git a/src/downloadthread.cpp b/src/downloadthread.cpp index 4e488e609..ca64d5718 100644 --- a/src/downloadthread.cpp +++ b/src/downloadthread.cpp @@ -979,19 +979,19 @@ bool DownloadThread::_customizeImage() // load files from disk and write QByteArray networkConfig = _fileGetContentsTrimmed("://extraFiles/10-usb.network"); fat->writeFile("10usb.net", networkConfig); - // little optimization for memory constraint systems - add if more files are loaded in this scope - //networkConfig.clear(); + // little optimization for memory constraint systems + networkConfig.clear(); // only needed for manual config without g_ether - //QByteArray script = _fileGetContentsTrimmed("://extraFiles/configure-usb-ether-gadget-once.sh"); - //fat->writeFile("etherSet.sh", script); - // little optimization for memory constraint systems - add if more files are loaded in this scope - //script.clear(); + QByteArray modprobeConf = _fileGetContentsTrimmed("://extraFiles/g_ether.conf"); + fat->writeFile("geth.cnf", modprobeConf); + // little optimization for memory constraint systems + modprobeConf.clear(); - //QByteArray serviceFile = _fileGetContentsTrimmed("://extraFiles/usb-ether-gadget-once.service"); - //fat->writeFile("sysdEth.srv", serviceFile); + QByteArray modulesConf = _fileGetContentsTrimmed("://extraFiles/usb-ether-gadget.conf"); + fat->writeFile("gemod.cnf", modulesConf); // not needed anymore, because auto cleanup after out of scope - //serviceFile.clear(); + //modulesConf.clear(); } if (!_cloudinit.isEmpty() && _initFormat == "cloudinit") diff --git a/src/extraFiles.qrc b/src/extraFiles.qrc index df02268f7..bf056b740 100644 --- a/src/extraFiles.qrc +++ b/src/extraFiles.qrc @@ -1,7 +1,7 @@ extraFiles/10-usb.network - extraFiles/configure-usb-ether-gadget-once.sh - extraFiles/usb-ether-gadget-once.service + extraFiles/g_ether.conf + extraFiles/usb-ether-gadget.conf diff --git a/src/extraFiles/configure-usb-ether-gadget-once.sh b/src/extraFiles/configure-usb-ether-gadget-once.sh deleted file mode 100644 index 199c799dc..000000000 --- a/src/extraFiles/configure-usb-ether-gadget-once.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash - -###################### -## Config variables ## -###################### -# required for RNDIS (Windows compatibility) -# Acer Incorporated. - Other hardware - Acer USB Ethernet/RNDIS Gadget -# did not work correctly -#VID="0x0502" -#PID="0x3230" -# Did work correctly with IBM driver -VID="0x04b3" -PID="0x4010" -SERIAL=$(grep Serial /proc/cpuinfo | awk '{print $3}') -# Compute the SHA256 hash of the serial number -sha=$(echo -n "$SERIAL" | sha256sum | cut -d ' ' -f 1) -config_path=g_ether -########################## -## END Config variables ## -########################## - -############################### -## Setup basic configuration ## -############################### -mkdir -p ${config_path} -cd ${config_path} || exit 1 - -echo "${VID}" > idVendor # Custom Vendor ID -echo "${PID}" > idProduct # Custom Product ID -echo 0x0100 > bcdDevice # v1.0.0 -echo 0x0200 > bcdUSB # USB2 -# setup appearance -mkdir -p strings/0x409 -echo "${SERIAL}" > strings/0x409/serialnumber -echo "Raspberry Pi" > strings/0x409/manufacturer -echo "USB Ethernet Gadget" > strings/0x409/product -################################### -## END Setup basic configuration ## -################################### - -#################################################### -## ECM (Ethernet Control Model) for Mac and Linux ## -#################################################### -mkdir -p configs/c.1/strings/0x409 -mkdir -p functions/ecm.usb0 - -# max possible stable USB 2.0 power -echo 250 > configs/c.1/MaxPower -echo "ECM" > configs/c.1/strings/0x409/configuration -######################################################## -## END ECM (Ethernet Control Model) for Mac and Linux ## -######################################################## - -##################################### -## RNDIS for Windows compatibility ## -##################################### -mkdir -p configs/c.2/strings/0x409 -mkdir -p functions/rndis.usb0 -# not allowed -#mkdir -p os_desc/interface.rndis - -echo "RNDIS" > configs/c.2/strings/0x409/configuration -#echo "RNDIS" > os_desc/interface.rndis/compatibility_id -#echo "5162001" > os_desc/interface.rndis/sub_compatibility_id -######################################### -## END RNDIS for Windows compatibility ## -######################################### - -######################### -## Setup MAC addresses ## -######################### -# Generate MAC addresses using slices of the hash -# TODO: maybe change prefix -mac0=6A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} -mac1=7A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} -mac2=8A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} -mac3=9A:${sha:2:2}:${sha:4:2}:${sha:6:2}:${sha:8:2}:${sha:10:2} - -echo "${mac1}" > functions/ecm.usb0/host_addr -echo "${mac3}" > functions/ecm.usb0/dev_addr - -echo "${mac0}" > functions/rndis.usb0/host_addr -echo "${mac2}" > functions/rndis.usb0/dev_addr -############################# -## END Setup MAC addresses ## -############################# - -###################################### -## Link functions to configurations ## -###################################### -ln -s functions/ecm.usb0 configs/c.1/ -ln -s functions/rndis.usb0 configs/c.2/ -########################################## - -###################################### -## Link the UDC to start the gadget ## -###################################### -count=0 -while [ ${count} -lt 15 ]; do - udc="$(ls /sys/class/udc)" - if [ -n "${udc}" ]; then - echo "Found UDC ${udc}" - echo "${udc}" > UDC - break - fi - count=$((count + 1)) - sleep 1 -done -########################################## -## END Link the UDC to start the gadget ## -########################################## - -systemctl restart getty@ttyGS0 - -echo "Ethernet USB OTG gadget init complete - $(cat UDC)" diff --git a/src/extraFiles/g_ether.conf b/src/extraFiles/g_ether.conf new file mode 100644 index 000000000..0e9f090ab --- /dev/null +++ b/src/extraFiles/g_ether.conf @@ -0,0 +1 @@ +options g_ether idVendor=0x04b3 idProduct=0x4010 iManufacturer="Raspberry Pi" bcdDevice=0x0100 iProduct="USB Ethernet Gadget" iSerialNumber= diff --git a/src/extraFiles/usb-ether-gadget-once.service b/src/extraFiles/usb-ether-gadget-once.service deleted file mode 100644 index 941f4930a..000000000 --- a/src/extraFiles/usb-ether-gadget-once.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Configure USB Ethernet Gadget -Requires=sys-kernel-config.mount -After=sys-kernel-config.mount -Requires=systemd-modules-load.service -After=systemd-modules-load.service - -[Service] -Type=oneshot -WorkingDirectory=/sys/kernel/config/usb_gadget -ExecStart=/usr/sbin/configure-usb-ether-gadget-once -StandardOutput=journal+console -# TODO: remove -User=root - -[Install] -WantedBy=usb-gadget.target diff --git a/src/extraFiles/usb-ether-gadget.conf b/src/extraFiles/usb-ether-gadget.conf new file mode 100644 index 000000000..b79e76045 --- /dev/null +++ b/src/extraFiles/usb-ether-gadget.conf @@ -0,0 +1,2 @@ +dwc2 +g_ether diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp index 55bc39ff2..dd1289061 100644 --- a/src/imagewriter.cpp +++ b/src/imagewriter.cpp @@ -477,10 +477,23 @@ namespace { } // namespace anonymous -void ImageWriter::setHWFilterList(const QByteArray &json, const bool &inclusive) { +void ImageWriter::setHWFilterList(const QByteArray &json, const bool &inclusive, const bool &isModelZero) { QJsonDocument json_document = QJsonDocument::fromJson(json); _deviceFilter = json_document.array(); _deviceFilterIsInclusive = inclusive; + _isModelZero = isModelZero; +} + +QJsonArray ImageWriter::getHWFilterList() { + return _deviceFilter; +} + +bool ImageWriter::getHWFilterListInclusive() { + return _deviceFilterIsInclusive; +} + +bool ImageWriter::getHWFilterIsModelZero() { + return _isModelZero; } void ImageWriter::handleNetworkRequestFinished(QNetworkReply *data) { diff --git a/src/imagewriter.h b/src/imagewriter.h index 166c241aa..251ed25cd 100644 --- a/src/imagewriter.h +++ b/src/imagewriter.h @@ -85,7 +85,16 @@ class ImageWriter : public QObject Q_INVOKABLE void beginOSListFetch(); /** Set the HW filter, for a filtered view of the OS list */ - Q_INVOKABLE void setHWFilterList(const QByteArray &json, const bool &inclusive); + Q_INVOKABLE void setHWFilterList(const QByteArray &json, const bool &inclusive, const bool &isModelZero); + + /* Get the HW filter list */ + Q_INVOKABLE QJsonArray getHWFilterList(); + + /* Get if the HW filter is in inclusive mode */ + Q_INVOKABLE bool getHWFilterListInclusive(); + + /* Get if HW filter tags are from a Pi Zero model */ + Q_INVOKABLE bool getHWFilterIsModelZero(); /* Set custom cache file */ void setCustomCacheFile(const QString &cacheFile, const QByteArray &sha256); @@ -122,8 +131,8 @@ class ImageWriter : public QObject Q_INVOKABLE QString getPSK(); Q_INVOKABLE bool getBoolSetting(const QString &key); - Q_INVOKABLE void setSetting(const QString &key, const QVariant &value);//, const QVariantList - Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget); + Q_INVOKABLE void setSetting(const QString &key, const QVariant &value); + Q_INVOKABLE void setImageCustomization(const QByteArray &config, const QByteArray &cmdline, const QByteArray &firstrun, const QByteArray &cloudinit, const QByteArray &cloudinitNetwork, const bool enableEtherGadget); Q_INVOKABLE void setSavedCustomizationSettings(const QVariantMap &map); Q_INVOKABLE QVariantMap getSavedCustomizationSettings(); Q_INVOKABLE void clearSavedCustomizationSettings(); @@ -186,6 +195,8 @@ protected slots: QJsonDocument _completeOsList; QJsonArray _deviceFilter; bool _deviceFilterIsInclusive; + /* As there is no distinction between normal pi models and zeros (in the tags), this flag can be used to differenciate */ + bool _isModelZero; protected: QUrl _src, _repo; diff --git a/src/main.qml b/src/main.qml index f89e95541..6894b4a0f 100644 --- a/src/main.qml +++ b/src/main.qml @@ -1614,7 +1614,7 @@ ApplicationWindow { } } - imageWriter.setHWFilterList(hwmodel.tags, inclusive) + imageWriter.setHWFilterList(hwmodel.tags, inclusive, hwmodel.name.toLowerCase().includes("zero")) /* Reload list */ var oslist_json = imageWriter.getFilteredOSlist(); From 38ee1031e719ad40fc464b35acb6aa5f83922e8a Mon Sep 17 00:00:00 2001 From: paulober <44974737+paulober@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:32:26 +0100 Subject: [PATCH 03/10] Added CLI support for enable usb ether gadget mode config + CLI version and help arguments Signed-off-by: paulober <44974737+paulober@users.noreply.github.com> --- src/OptionsPopup.qml | 1 + src/cli.cpp | 28 +++++++++++++++++++++++++--- src/downloadthread.cpp | 4 ++++ src/downloadthread.h | 5 +++++ src/imagewriter.cpp | 8 +++++++- src/imagewriter.h | 3 +++ 6 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/OptionsPopup.qml b/src/OptionsPopup.qml index 11fc379da..99e83fd29 100644 --- a/src/OptionsPopup.qml +++ b/src/OptionsPopup.qml @@ -847,6 +847,7 @@ Window { addCmdline("cfg80211.ieee80211_regdom="+fieldWifiCountry.editText) } if (chkUSBEther.checked) { + // keep parity with cli.cpp addConfig("dtoverlay=dwc2,dr_mode=peripheral") enableEtherGadget = true; diff --git a/src/cli.cpp b/src/cli.cpp index bb0e88c19..44d0a8b61 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -58,11 +58,14 @@ int Cli::run() {"first-run-script", "Add firstrun.sh to image", "first-run-script", ""}, {"cloudinit-userdata", "Add cloud-init user-data file to image", "cloudinit-userdata", ""}, {"cloudinit-networkconfig", "Add cloud-init network-config file to image", "cloudinit-networkconfig", ""}, + {"usb-ether-gadget", "Enable USB Ethernet Gadget mode"}, {"disable-eject", "Disable automatic ejection of storage media after verification"}, {"debug", "Output debug messages to console"}, {"quiet", "Only write to console on error"}, }); + parser.addVersionOption(); + parser.addHelpOption(); parser.addPositionalArgument("src", "Image file/URL"); parser.addPositionalArgument("dst", "Destination device"); parser.process(*_app); @@ -70,7 +73,7 @@ int Cli::run() const QStringList args = parser.positionalArguments(); if (args.count() != 2) { - std::cerr << "Usage: --cli [--disable-verify] [--disable-eject] [--sha256 [--cache-file ]] [--first-run-script