From f7f34e0ea3796113fd77f839e77f63f83e5bdaf6 Mon Sep 17 00:00:00 2001 From: faragher Date: Wed, 8 May 2024 02:14:29 -0500 Subject: [PATCH 1/6] Windows DTR timing adjustments --- RNS/Utilities/rnodeconf.py | 214 ++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 98 deletions(-) diff --git a/RNS/Utilities/rnodeconf.py b/RNS/Utilities/rnodeconf.py index 0cca1cb..6a49049 100755 --- a/RNS/Utilities/rnodeconf.py +++ b/RNS/Utilities/rnodeconf.py @@ -283,7 +283,7 @@ except Exception as e: print("No access to directory "+str(CNF_DIR)+". This utility needs file system access to store firmware and data files. Cannot continue.") print("The contained exception was:") print(str(e)) - exit(99) + graceful_exit(99) squashvw = False @@ -572,7 +572,7 @@ class RNode(): except Exception as e: raise e - exit() + graceful_exit() def updateBitrate(self): try: @@ -598,6 +598,7 @@ class RNode(): written = self.serial.write(kiss_command) if written != len(kiss_command): raise IOError("An IO error occurred while sending host left command to device") + sleep(1) def set_display_intensity(self, intensity): data = bytes([intensity & 0xFF]) @@ -761,7 +762,7 @@ class RNode(): sleep(0.6) if self.eeprom == None: RNS.log("Could not download EEPROM from device. Is a valid firmware installed?") - exit() + graceful_exit() else: self.parse_eeprom() @@ -807,7 +808,7 @@ class RNode(): if self.checksum != checksum: self.provisioned = False RNS.log("EEPROM checksum mismatch") - exit() + graceful_exit() else: RNS.log("EEPROM checksum correct") @@ -988,7 +989,7 @@ def ensure_firmware_file(fw_filename): RNS.log("One or more required firmware files are missing from the extracted RNode") RNS.log("Firmware archive. Installation cannot continue. Please try extracting the") RNS.log("firmware again with the --extract-firmware option.") - exit(184) + graceful_exit(184) vf = open(vfpath, "rb") release_info = vf.read().decode("utf-8").strip() @@ -998,7 +999,7 @@ def ensure_firmware_file(fw_filename): else: RNS.log("No extracted firmware is available, cannot continue.") RNS.log("Extract a firmware from an existing RNode first, using the --extract-firmware option.") - exit(183) + graceful_exit(183) else: try: @@ -1032,7 +1033,7 @@ def ensure_firmware_file(fw_filename): RNS.log("Check your internet connection and try again.") RNS.log("If you don't have Internet access currently, use the --fw-version option to manually specify a version.") RNS.log("You can also use --extract to copy the firmware from a known-good RNode of the same model.") - exit() + graceful_exit() except Exception as e: # if custom firmware url, don't fallback if fw_url != None: @@ -1040,7 +1041,7 @@ def ensure_firmware_file(fw_filename): RNS.log("Check your internet connection and try again.") RNS.log("If you don't have Internet access currently, use the --fw-version option to manually specify a version.") RNS.log("You can also use --extract to copy the firmware from a known-good RNode of the same model.") - exit() + graceful_exit() RNS.log("") RNS.log("WARNING!") @@ -1069,7 +1070,7 @@ def ensure_firmware_file(fw_filename): selected_version = release_info.split()[0] if selected_version == "not": RNS.log("No valid version found for this board, exiting.") - exit(199) + graceful_exit(199) selected_hash = release_info.split()[1] if not os.path.isdir(UPD_DIR+"/"+selected_version): @@ -1080,7 +1081,7 @@ def ensure_firmware_file(fw_filename): else: RNS.log("Online firmware version check was disabled, but no firmware version specified for install.") RNS.log("use the --fw-version option to manually specify a version.") - exit(98) + graceful_exit(98) # if custom firmware url, use it if fw_url != None: @@ -1114,7 +1115,7 @@ def ensure_firmware_file(fw_filename): if selected_hash == None: RNS.log("No release hash found for "+fw_filename+". The firmware integrity could not be verified.") - exit(97) + graceful_exit(97) RNS.log("Verifying firmware integrity...") fw_file = open(UPD_DIR+"/"+selected_version+"/"+fw_filename, "rb") @@ -1125,24 +1126,24 @@ def ensure_firmware_file(fw_filename): else: RNS.log("") RNS.log("Firmware corrupt. Try clearing the local firmware cache with: rnodeconf --clear-cache") - exit(96) + graceful_exit(96) except Exception as e: RNS.log("An error occurred while checking firmware file integrity. The contained exception was:") RNS.log(str(e)) - exit(95) + graceful_exit(95) except Exception as e: RNS.log("Could not download required firmware file: ") RNS.log(str(update_target_url)) RNS.log("The contained exception was:") RNS.log(str(e)) - exit() + graceful_exit() except Exception as e: RNS.log("An error occurred while reading version information for "+str(fw_filename)+". The contained exception was:") RNS.log(str(e)) - exit() + graceful_exit() def rnode_open_serial(port): import serial @@ -1159,6 +1160,21 @@ def rnode_open_serial(port): write_timeout = None, dsrdtr = False ) + + +def graceful_exit(C=0): + if RNS.vendor.platformutils.is_windows(): + RNS.log("Windows detected; delaying DTR")# ,RNS.LOG_VERBOSE + if rnode: + RNS.log("Sending \"Leave\" to Rnode") + rnode.leave() # Leave has wait built in + elif rnode_serial: + RNS.log("Closing raw serial") + sleep(1) # Wait for MCU to complete operation before DTR goes false + rnode_serial.close() + RNS.log("Exiting: Code "+str(C)) + exit(C) + device_signer = None force_update = False @@ -1174,7 +1190,7 @@ def main(): print("RNode Config Utility needs pyserial to work.") print("You can install it with: pip3 install pyserial") print("") - exit() + graceful_exit() try: if not util.find_spec("cryptography"): @@ -1184,7 +1200,7 @@ def main(): print("RNode Config Utility needs the cryptography module to work.") print("You can install it with: pip3 install cryptography") print("") - exit() + graceful_exit() import serial from serial.tools import list_ports @@ -1252,14 +1268,14 @@ def main(): if args.version: print("rnodeconf "+program_version) - exit(0) + graceful_exit(0) if args.clear_cache: RNS.log("Clearing local firmware cache...") import shutil shutil.rmtree(UPD_DIR) RNS.log("Done") - exit(0) + graceful_exit(0) if args.fw_version != None: selected_version = args.fw_version @@ -1267,7 +1283,7 @@ def main(): check_float = float(selected_version) except ValueError: RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.") - exit() + graceful_exit() if args.fw_url != None: fw_url = args.fw_url @@ -1306,7 +1322,7 @@ def main(): except Exception as e: RNS.log("Invalid key data supplied") - exit(0) + graceful_exit(0) if args.use_extracted and ((args.update and args.port != None) or args.autoinstall): print("") @@ -1345,11 +1361,11 @@ def main(): selected_port = portlist[c_port-1] except Exception as e: print("That port does not exist, exiting now.") - exit() + graceful_exit() if selected_port == None: print("Could not select port, exiting now.") - exit() + graceful_exit() port_path = selected_port.device port_product = selected_port.product @@ -1366,7 +1382,7 @@ def main(): if selected_port == None: print("Could not find specified port "+str(args.port)+", exiting now") - exit() + graceful_exit() port_path = selected_port.device port_product = selected_port.product @@ -1381,7 +1397,7 @@ def main(): except Exception as e: RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log(str(e)) - exit() + graceful_exit() rnode = RNode(rnode_serial) thread = threading.Thread(target=rnode.readLoop, daemon=True).start() @@ -1434,16 +1450,16 @@ def main(): print("Extracting "+part+"...") if subprocess.call(shlex.split(command), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) != 0: print("The extraction failed, the following command did not complete successfully:\n"+command) - exit(182) + graceful_exit(182) print("\nFirmware successfully extracted!") print("\nYou can now use this firmware to update or autoinstall other RNodes") - exit() + graceful_exit() else: print("Could not read firmware information from device") print("\nRNode firmware extraction failed") - exit(180) + graceful_exit(180) if args.autoinstall: clear() @@ -1477,11 +1493,11 @@ def main(): selected_port = portlist[c_port-1] except Exception as e: print("That port does not exist, exiting now.") - exit() + graceful_exit() if selected_port == None: print("Could not select port, exiting now.") - exit() + graceful_exit() port_path = selected_port.device port_product = selected_port.product @@ -1499,7 +1515,7 @@ def main(): if selected_port == None: print("Could not find specified port "+str(args.port)+", exiting now") - exit() + graceful_exit() port_path = selected_port.device port_product = selected_port.product @@ -1514,7 +1530,7 @@ def main(): except Exception as e: RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log(str(e)) - exit() + graceful_exit() rnode = RNode(rnode_serial) thread = threading.Thread(target=rnode.readLoop, daemon=True).start() @@ -1531,7 +1547,7 @@ def main(): print("\nThis device is already installed and provisioned. No further action will") print("be taken. If you wish to completely reinstall this device, you must first") print("wipe the current EEPROM. See the help for more info.\n\nExiting now.") - exit() + graceful_exit() print("\n---------------------------------------------------------------------------") print(" Device Selection") @@ -1707,7 +1723,7 @@ def main(): input() except Exception as e: print("That device type does not exist, exiting now.") - exit() + graceful_exit() selected_platform = None selected_model = None @@ -1736,7 +1752,7 @@ def main(): except Exception as e: print("That MCU type does not exist, exiting now.") - exit() + graceful_exit() print("\nWhat transceiver module does your board use?\n") print("[1] SX1276/SX1278 with antenna port on PA_BOOST pin") @@ -1753,7 +1769,7 @@ def main(): except Exception as e: print("That transceiver type does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_RNODE: @@ -1805,7 +1821,7 @@ def main(): # selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That model does not exist, exiting now.") - exit() + graceful_exit() else: print("\nWhat model is this T3S3?\n") print("[1] 410 - 525 MHz (with SX1268 chip)") @@ -1825,7 +1841,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That model does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_TBEAM: selected_mcu = ROM.MCU_ESP32 @@ -1854,7 +1870,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That band does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_T32_10: selected_mcu = ROM.MCU_ESP32 @@ -1876,7 +1892,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That band does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_T32_20: selected_mcu = ROM.MCU_ESP32 @@ -1898,7 +1914,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That band does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_T32_21: selected_mcu = ROM.MCU_ESP32 @@ -1926,7 +1942,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That band does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_H32_V2: selected_mcu = ROM.MCU_ESP32 @@ -1948,7 +1964,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That band does not exist, exiting now.") - exit() + graceful_exit() elif selected_product == ROM.PRODUCT_H32_V3: selected_mcu = ROM.MCU_ESP32 @@ -1970,7 +1986,7 @@ def main(): selected_platform = ROM.PLATFORM_ESP32 except Exception as e: print("That band does not exist, exiting now.") - exit() + graceful_exit() if selected_model != ROM.MODEL_FF and selected_model != ROM.MODEL_FE: fw_filename = models[selected_model][4] @@ -1998,7 +2014,7 @@ def main(): fw_filename = "rnode_firmware_esp32_generic.zip" except Exception as e: print("That ESP32 board does not exist, exiting now.") - exit() + graceful_exit() if fw_filename == None: print("") @@ -2008,7 +2024,7 @@ def main(): print("") print_donation_block() print("") - exit() + graceful_exit() if args.use_extracted: fw_filename = "extracted_rnode_firmware.zip" @@ -2038,7 +2054,7 @@ def main(): raise ValueError() except Exception as e: print("OK, aborting now.") - exit() + graceful_exit() args.key = True args.port = selected_port.device @@ -2055,7 +2071,7 @@ def main(): except Exception as e: RNS.log("Could not obain firmware package for your board") RNS.log("The contained exception was: "+str(e)) - exit() + graceful_exit() rnode.disconnect() @@ -2096,7 +2112,7 @@ def main(): RNS.log("Could not load device signing key") - exit() + graceful_exit() if args.key: if not os.path.isfile(FWD_DIR+"/device.key"): @@ -2109,7 +2125,7 @@ def main(): RNS.log("Could not create new device signing key at "+str(FWD_DIR+"/device.key")+". The contained exception was:") RNS.log(str(e)) RNS.log("Please ensure filesystem access and try again.") - exit(81) + graceful_exit(81) else: try: device_signer = RNS.Identity.from_file(FWD_DIR+"/device.key") @@ -2117,7 +2133,7 @@ def main(): RNS.log("Could not load device signing key from "+str(FWD_DIR+"/device.key")+". The contained exception was:") RNS.log(str(e)) RNS.log("Please restore or clear the key and try again.") - exit(82) + graceful_exit(82) if not os.path.isfile(FWD_DIR+"/signing.key"): RNS.log("Generating a new EEPROM signing key...") @@ -2155,7 +2171,7 @@ def main(): RNS.log("The firmware directory does not exist, can't write key!") if not args.autoinstall: - exit() + graceful_exit() def get_partition_hash(partition_file): try: @@ -2187,7 +2203,7 @@ def main(): RNS.log(" sudo apt install "+flasher) RNS.log("") RNS.log("Please install \""+flasher+"\" and try again.") - exit() + graceful_exit() elif platform == ROM.PLATFORM_AVR: flasher = "avrdude" if which(flasher) is not None: @@ -2206,7 +2222,7 @@ def main(): RNS.log(" sudo apt install avrdude") RNS.log("") RNS.log("Please install \""+flasher+"\" and try again.") - exit() + graceful_exit() elif platform == ROM.PLATFORM_ESP32: numeric_version = float(selected_version) flasher_dir = UPD_DIR+"/"+selected_version @@ -2666,7 +2682,7 @@ def main(): RNS.log(" sudo apt install esptool") RNS.log("") RNS.log("Please install \""+flasher+"\" and try again.") - exit() + graceful_exit() if args.port: wants_fw_provision = False @@ -2681,7 +2697,7 @@ def main(): if selected_version == None: RNS.log("Missing parameters, cannot continue") - exit(68) + graceful_exit(68) if fw_filename == "extracted_rnode_firmware.zip": try: @@ -2697,12 +2713,12 @@ def main(): RNS.log("Waiting for ESP32 reset...") time.sleep(7) else: - exit() + graceful_exit() except Exception as e: RNS.log("Error while flashing") RNS.log(str(e)) - exit(1) + graceful_exit(1) else: fw_src = UPD_DIR+"/"+selected_version+"/" @@ -2715,7 +2731,7 @@ def main(): zip.extractall(fw_src) except Exception as e: RNS.log("Could not decompress firmware from downloaded zip file") - exit() + graceful_exit() RNS.log("Firmware decompressed") RNS.log("Flashing RNode firmware to device on "+args.port) @@ -2734,15 +2750,15 @@ def main(): RNS.log("Some boards have trouble flashing at high speeds, and you can") RNS.log("try flashing with a lower baud rate, as in this example:") RNS.log("rnodeconf --autoinstall --baud-flash 115200") - exit() + graceful_exit() except Exception as e: RNS.log("Error while flashing") RNS.log(str(e)) - exit(1) + graceful_exit(1) else: RNS.log("Firmware file not found") - exit() + graceful_exit() RNS.log("Opening serial port "+args.port+"...") try: @@ -2751,7 +2767,7 @@ def main(): except Exception as e: RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log(str(e)) - exit() + graceful_exit() rnode = RNode(rnode_serial) thread = threading.Thread(target=rnode.readLoop, daemon=True).start() @@ -2761,7 +2777,7 @@ def main(): except Exception as e: RNS.log("Serial port opened, but RNode did not respond. Is a valid firmware installed?") print(e) - exit() + graceful_exit() if rnode.detected: if rnode.platform == None or rnode.mcu == None: @@ -2773,7 +2789,7 @@ def main(): RNS.log("WARNING: EEPROM is being wiped! Power down device NOW if you do not want this!") rnode.wipe_eeprom() rnode.hard_reset() - exit() + graceful_exit() RNS.log("Reading EEPROM...") rnode.download_eeprom() @@ -2799,12 +2815,12 @@ def main(): fw_filename = None if args.update: RNS.log("ERROR: No firmware found for this board. Cannot update.") - exit() + graceful_exit() if args.update: if not rnode.provisioned: RNS.log("Device not provisioned. Cannot update device firmware.") - exit(1) + graceful_exit(1) if args.use_extracted: fw_filename = "extracted_rnode_firmware.zip" @@ -2823,21 +2839,21 @@ def main(): if args.fw_version != None: RNS.log("Specified firmware version ("+selected_version+") is already installed on this device") RNS.log("Override with -U option to install anyway") - exit(0) + graceful_exit(0) else: RNS.log("Latest firmware version ("+selected_version+") is already installed on this device") RNS.log("Override with -U option to install anyway") - exit(0) + graceful_exit(0) if rnode.version > selected_version: if args.fw_version != None: RNS.log("Specified firmware version ("+selected_version+") is older than firmware already installed on this device") RNS.log("Override with -U option to install anyway") - exit(0) + graceful_exit(0) else: RNS.log("Latest firmware version ("+selected_version+") is older than firmware already installed on this device") RNS.log("Override with -U option to install anyway") - exit(0) + graceful_exit(0) if not fw_file_ensured and selected_version != None: ensure_firmware_file(fw_filename) @@ -2850,13 +2866,13 @@ def main(): zip.extractall(fw_src) except Exception as e: RNS.log("Could not decompress firmware from downloaded zip file") - exit() + graceful_exit() RNS.log("Firmware decompressed") except Exception as e: RNS.log("Could not obtain firmware package for your board") RNS.log("The contained exception was: "+str(e)) - exit() + graceful_exit() if fw_filename == "extracted_rnode_firmware.zip": update_full_path = EXT_DIR+"/extracted_rnode_firmware.version" @@ -2894,7 +2910,7 @@ def main(): except Exception as e: RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log(str(e)) - exit() + graceful_exit() rnode = RNode(rnode_serial) thread = threading.Thread(target=rnode.readLoop, daemon=True).start() @@ -2904,7 +2920,7 @@ def main(): except Exception as e: RNS.log("Serial port opened, but RNode did not respond. Is a valid firmware installed?") print(e) - exit() + graceful_exit() if rnode.detected: if rnode.platform == None or rnode.mcu == None: @@ -2928,19 +2944,19 @@ def main(): RNS.log("Firmware update completed successfully") else: RNS.log("An error occurred while flashing the new firmware, exiting now.") - exit() + graceful_exit() except Exception as e: RNS.log("Error while updating firmware") RNS.log(str(e)) else: RNS.log("Firmware update file not found") - exit() + graceful_exit() if args.eeprom_dump: RNS.log("EEPROM contents:") RNS.log(RNS.hexrep(rnode.eeprom)) - exit() + graceful_exit() if args.eeprom_backup: try: @@ -2954,7 +2970,7 @@ def main(): except Exception as e: RNS.log("EEPROM was successfully downloaded from device,") RNS.log("but file could not be written to disk.") - exit() + graceful_exit() if isinstance(args.display, int): di = args.display @@ -2979,7 +2995,7 @@ def main(): RNS.log("Setting display address to "+RNS.hexrep(da, delimit=False)) rnode.set_display_address(ord(da)) rnode.hard_reset() - exit() + graceful_exit() else: RNS.log("Invalid display address specified") @@ -3049,23 +3065,23 @@ def main(): print("") rnode.disconnect() - exit() + graceful_exit() else: RNS.log("EEPROM is invalid, no further information available") - exit() + egraceful_xit() if args.rom: if rnode.provisioned and not args.autoinstall: RNS.log("EEPROM bootstrap was requested, but a valid EEPROM was already present.") RNS.log("No changes are being made.") - exit() + graceful_exit() else: if rnode.signature_valid: RNS.log("EEPROM bootstrap was requested, but a valid EEPROM was already present.") RNS.log("No changes are being made.") - exit() + graceful_exit() else: if args.autoinstall: RNS.log("Clearing old EEPROM, this will take about 15 seconds...") @@ -3090,7 +3106,7 @@ def main(): except Exception as e: RNS.log("Could not create device serial number, exiting") RNS.log(str(e)) - exit() + graceful_exit() serialno = counter+1 model = None @@ -3186,7 +3202,7 @@ def main(): RNS.log(str(e)) else: RNS.log("No signing key found") - exit() + graceful_exit() if model == ROM.MODEL_A1 or model == ROM.MODEL_A6: rnode.hard_reset() @@ -3300,10 +3316,10 @@ def main(): file.close() except Exception as e: RNS.log("WARNING: Could not backup device EEPROM to disk") - exit() + graceful_exit() else: RNS.log("EEPROM was written, but validation failed. Check your settings.") - exit() + graceful_exit() except Exception as e: RNS.log("An error occurred while writing EEPROM. The contained exception was:") RNS.log(str(e)) @@ -3311,7 +3327,7 @@ def main(): else: RNS.log("Invalid data specified, cancelling EEPROM write") - exit() + graceful_exit() if args.sign: if rnode.provisioned: @@ -3325,14 +3341,14 @@ def main(): else: if device_signer == None: RNS.log("No device signer loaded, cannot sign device") - exit(78) + graceful_exit(78) else: new_device_signature = device_signer.sign(rnode.device_hash) rnode.store_signature(new_device_signature) RNS.log("Device signed") else: RNS.log("This device has not been provisioned yet, cannot create device signature") - exit(79) + graceful_exit(79) if args.firmware_hash != None: if rnode.provisioned: @@ -3345,17 +3361,17 @@ def main(): RNS.log("Firmware hash set") except Exception as e: RNS.log("The provided value was not a valid SHA256 hash") - exit(78) + graceful_exit(78) else: RNS.log("This device has not been provisioned yet, cannot set firmware hash") - exit(77) + graceful_exit(77) if rnode.provisioned: if args.normal: rnode.setNormalMode() RNS.log("Device set to normal (host-controlled) operating mode") - exit() + graceful_exit() if args.tnc: if not (args.freq and args.bw and args.txp and args.sf and args.cr): RNS.log("Please input startup configuration:") @@ -3400,7 +3416,7 @@ def main(): RNS.log("Device set to TNC operating mode") sleep(1.0) - exit() + graceful_exit() else: RNS.log("This device contains a valid firmware, but EEPROM is invalid.") RNS.log("Probably the device has not been initialised, or the EEPROM has been erased.") @@ -3410,12 +3426,14 @@ def main(): print("") parser.print_help() print("") - exit() + graceful_exit() except KeyboardInterrupt: print("") - exit() + graceful_exit() + + graceful_exit() def extract_recovery_esptool(): if not os.path.isfile(RT_PATH): @@ -3429,7 +3447,7 @@ def extract_recovery_esptool(): except Exception as e: RNS.log("Error: Could not extract recovery ESP-Tool. The contained exception was:") RNS.log(str(e)) - exit(181) + graceful_exit(181) if __name__ == "__main__": main() From 3551662187006edae247ba820b38c90b1836a493 Mon Sep 17 00:00:00 2001 From: faragher Date: Wed, 8 May 2024 02:19:59 -0500 Subject: [PATCH 2/6] Changing log levels --- RNS/Utilities/rnodeconf.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RNS/Utilities/rnodeconf.py b/RNS/Utilities/rnodeconf.py index 6a49049..ea8e8fc 100755 --- a/RNS/Utilities/rnodeconf.py +++ b/RNS/Utilities/rnodeconf.py @@ -1164,15 +1164,15 @@ def rnode_open_serial(port): def graceful_exit(C=0): if RNS.vendor.platformutils.is_windows(): - RNS.log("Windows detected; delaying DTR")# ,RNS.LOG_VERBOSE + RNS.log("Windows detected; delaying DTR",RNS.LOG_VERBOSE) if rnode: - RNS.log("Sending \"Leave\" to Rnode") + RNS.log("Sending \"Leave\" to Rnode",RNS.LOG_VERBOSE) rnode.leave() # Leave has wait built in elif rnode_serial: - RNS.log("Closing raw serial") + RNS.log("Closing raw serial",RNS.LOG_VERBOSE) sleep(1) # Wait for MCU to complete operation before DTR goes false rnode_serial.close() - RNS.log("Exiting: Code "+str(C)) + RNS.log("Exiting: Code "+str(C),RNS.LOG_INFO) exit(C) From 746a38f818803aa63ff87418dfa883b1fc7a7aaa Mon Sep 17 00:00:00 2001 From: "jacob.eva" Date: Mon, 13 May 2024 22:55:49 +0100 Subject: [PATCH 3/6] Add ability to get target and calculated firmware hash from device --- RNS/Utilities/rnodeconf.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/RNS/Utilities/rnodeconf.py b/RNS/Utilities/rnodeconf.py index 0cca1cb..aa5f401 100755 --- a/RNS/Utilities/rnodeconf.py +++ b/RNS/Utilities/rnodeconf.py @@ -324,6 +324,7 @@ class RNode(): self.checksum = None self.device_hash = None self.firmware_hash = None + self.firmware_hash_target = None self.signature = None self.signature_valid = False self.locally_signed = False @@ -471,6 +472,8 @@ class RNode(): escape = False command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 33): + if command_buffer[0] == 0x01: + self.firmware_hash_target = command_buffer[1:] if command_buffer[0] == 0x02: self.firmware_hash = command_buffer[1:] @@ -588,7 +591,7 @@ class RNode(): self.version = str(self.major_version)+"."+minstr def detect(self): - kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND, KISS.CMD_BOARD, 0x00, KISS.FEND, KISS.CMD_DEV_HASH, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x02, KISS.FEND]) + kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND, KISS.CMD_BOARD, 0x00, KISS.FEND, KISS.CMD_DEV_HASH, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x02, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): raise IOError("An IO error occurred while detecting hardware for "+self(str)) @@ -1233,6 +1236,8 @@ def main(): parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") # parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key") parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash") + parser.add_argument("-K", "--get-target-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get target firmware hash from device + parser.add_argument("-L", "--get-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get calculated firmware hash from device parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap") parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") # parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap") @@ -3351,6 +3356,22 @@ def main(): RNS.log("This device has not been provisioned yet, cannot set firmware hash") exit(77) + if args.get_target_firmware_hash: + if rnode.provisioned: + RNS.log(f"The target firmware hash is: {rnode.firmware_hash_target.hex()}") + + else: + RNS.log("This device has not been provisioned yet, cannot get firmware hash") + exit(77) + + if args.get_firmware_hash: + if rnode.provisioned: + RNS.log(f"The actual firmware hash is: {rnode.firmware_hash.hex()}") + + else: + RNS.log("This device has not been provisioned yet, cannot get firmware hash") + exit(77) + if rnode.provisioned: if args.normal: rnode.setNormalMode() From 1564930a512c5ab6d5e41fecda8d12c1ed3cc4c2 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Fri, 17 May 2024 04:09:11 +1200 Subject: [PATCH 4/6] auto interface working on windows --- RNS/Interfaces/AutoInterface.py | 38 +++++++++++++----- RNS/Reticulum.py | 68 +++++++++++++++------------------ RNS/vendor/ifaddr/niwrapper.py | 7 ++++ 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/RNS/Interfaces/AutoInterface.py b/RNS/Interfaces/AutoInterface.py index 0c86184..f3f6496 100644 --- a/RNS/Interfaces/AutoInterface.py +++ b/RNS/Interfaces/AutoInterface.py @@ -77,6 +77,15 @@ class AutoInterface(Interface): ifas = self.netinfo.ifaddresses(ifname) return ifas + def interface_name_to_index(self, ifname): + + # socket.if_nametoindex doesn't work with uuid interface names on windows, it wants the ethernet_0 style + # we will just get the index from netinfo instead as it seems to work + if RNS.vendor.platformutils.is_windows(): + return self.netinfo.interface_names_to_indexes()[ifname] + + return socket.if_nametoindex(ifname) + def __init__(self, owner, name, group_id=None, discovery_scope=None, discovery_port=None, multicast_address_type=None, data_port=None, allowed_interfaces=None, ignored_interfaces=None, configured_bitrate=None): from RNS.vendor.ifaddr import niwrapper super().__init__() @@ -205,7 +214,7 @@ class AutoInterface(Interface): RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME) # Struct with interface index - if_struct = struct.pack("I", socket.if_nametoindex(ifname)) + if_struct = struct.pack("I", self.interface_name_to_index(ifname)) # Set up multicast socket discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) @@ -219,12 +228,21 @@ class AutoInterface(Interface): discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group) # Bind socket - if self.discovery_scope == AutoInterface.SCOPE_LINK: - addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) - else: - addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + if RNS.vendor.platformutils.is_windows(): - discovery_socket.bind(addr_info[0][4]) + # window throws "[WinError 10049] The requested address is not valid in its context" + # when trying to use the multicast address as host, or when providing interface index + # passing an empty host appears to work, but probably not exactly how we want it to... + discovery_socket.bind(('', self.discovery_port)) + + else: + + if self.discovery_scope == AutoInterface.SCOPE_LINK: + addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + else: + addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + + discovery_socket.bind(addr_info[0][4]) # Set up thread for discovery packets def discovery_loop(): @@ -253,7 +271,7 @@ class AutoInterface(Interface): socketserver.UDPServer.address_family = socket.AF_INET6 for ifname in self.adopted_interfaces: - local_addr = self.adopted_interfaces[ifname]+"%"+ifname + local_addr = self.adopted_interfaces[ifname]+"%"+str(self.interface_name_to_index(ifname)) addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) address = addr_info[0][4] @@ -380,7 +398,7 @@ class AutoInterface(Interface): announce_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) addr_info = socket.getaddrinfo(self.mcast_discovery_address, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) - ifis = struct.pack("I", socket.if_nametoindex(ifname)) + ifis = struct.pack("I", self.interface_name_to_index(ifname)) announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis) announce_socket.sendto(discovery_token, addr_info[0][4]) announce_socket.close() @@ -433,8 +451,8 @@ class AutoInterface(Interface): try: if self.outbound_udp_socket == None: self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - - peer_addr = str(peer)+"%"+str(self.peers[peer][0]) + + peer_addr = str(peer)+"%"+str(self.interface_name_to_index(self.peers[peer][0])) addr_info = socket.getaddrinfo(peer_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) self.outbound_udp_socket.sendto(data, addr_info[0][4]) diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 44d9028..4a9bb9b 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -536,46 +536,40 @@ class Reticulum: if (("interface_enabled" in c) and c.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True): if c["type"] == "AutoInterface": - if not RNS.vendor.platformutils.is_windows(): - group_id = c["group_id"] if "group_id" in c else None - discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None - discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None - multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None - data_port = int(c["data_port"]) if "data_port" in c else None - allowed_interfaces = c.as_list("devices") if "devices" in c else None - ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None + group_id = c["group_id"] if "group_id" in c else None + discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None + discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None + multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None + data_port = int(c["data_port"]) if "data_port" in c else None + allowed_interfaces = c.as_list("devices") if "devices" in c else None + ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None - interface = AutoInterface.AutoInterface( - RNS.Transport, - name, - group_id, - discovery_scope, - discovery_port, - multicast_address_type, - data_port, - allowed_interfaces, - ignored_interfaces - ) - - if "outgoing" in c and c.as_bool("outgoing") == False: - interface.OUT = False - else: - interface.OUT = True - - interface.mode = interface_mode - - interface.announce_cap = announce_cap - if configured_bitrate: - interface.bitrate = configured_bitrate - if ifac_size != None: - interface.ifac_size = ifac_size - else: - interface.ifac_size = 16 + interface = AutoInterface.AutoInterface( + RNS.Transport, + name, + group_id, + discovery_scope, + discovery_port, + multicast_address_type, + data_port, + allowed_interfaces, + ignored_interfaces + ) + if "outgoing" in c and c.as_bool("outgoing") == False: + interface.OUT = False else: - RNS.log("AutoInterface is not currently supported on Windows, disabling interface.", RNS.LOG_ERROR); - RNS.log("Please remove this AutoInterface instance from your configuration file.", RNS.LOG_ERROR); - RNS.log("You will have to manually configure other interfaces for connectivity.", RNS.LOG_ERROR); + interface.OUT = True + + interface.mode = interface_mode + + interface.announce_cap = announce_cap + if configured_bitrate: + interface.bitrate = configured_bitrate + if ifac_size != None: + interface.ifac_size = ifac_size + else: + interface.ifac_size = 16 if c["type"] == "UDPInterface": device = c["device"] if "device" in c else None diff --git a/RNS/vendor/ifaddr/niwrapper.py b/RNS/vendor/ifaddr/niwrapper.py index bd44c72..e6c8b96 100644 --- a/RNS/vendor/ifaddr/niwrapper.py +++ b/RNS/vendor/ifaddr/niwrapper.py @@ -11,6 +11,13 @@ def interfaces() -> List[str]: adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) return [a.name for a in adapters] +def interface_names_to_indexes() -> dict: + adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) + results = {} + for adapter in adapters: + results[adapter.name] = adapter.index + return results + def ifaddresses(ifname) -> dict: adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) ifa = {} From 4b07e30b9d47e5d183b54f9d55a1f0b9234eeaf0 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Fri, 17 May 2024 23:54:04 +0200 Subject: [PATCH 5/6] Updated version --- RNS/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNS/_version.py b/RNS/_version.py index ed9d4d8..ab55bb1 100644 --- a/RNS/_version.py +++ b/RNS/_version.py @@ -1 +1 @@ -__version__ = "0.7.4" +__version__ = "0.7.5" From 444ae0206b9f2121a865308c16a9cc8229b6fc36 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Fri, 17 May 2024 23:54:48 +0200 Subject: [PATCH 6/6] Added better handling on Windows of interfaces that are non-adoptable for AutoInterface --- RNS/Interfaces/AutoInterface.py | 138 +++++++++++++++++--------------- RNS/vendor/ifaddr/niwrapper.py | 12 +++ 2 files changed, 87 insertions(+), 63 deletions(-) diff --git a/RNS/Interfaces/AutoInterface.py b/RNS/Interfaces/AutoInterface.py index f3f6496..75c52d2 100644 --- a/RNS/Interfaces/AutoInterface.py +++ b/RNS/Interfaces/AutoInterface.py @@ -181,78 +181,90 @@ class AutoInterface(Interface): suitable_interfaces = 0 for ifname in self.list_interfaces(): - if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" skipping Darwin AWDL or tethering interface "+str(ifname), RNS.LOG_EXTREME) - elif RNS.vendor.platformutils.is_darwin() and ifname == "lo0": - RNS.log(str(self)+" skipping Darwin loopback interface "+str(ifname), RNS.LOG_EXTREME) - elif RNS.vendor.platformutils.is_android() and ifname in AutoInterface.ANDROID_IGNORE_IFS and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" skipping Android system interface "+str(ifname), RNS.LOG_EXTREME) - elif ifname in self.ignored_interfaces: - RNS.log(str(self)+" ignoring disallowed interface "+str(ifname), RNS.LOG_EXTREME) - elif ifname in AutoInterface.ALL_IGNORE_IFS: - RNS.log(str(self)+" skipping interface "+str(ifname), RNS.LOG_EXTREME) - else: - if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" ignoring interface "+str(ifname)+" since it was not allowed", RNS.LOG_EXTREME) + try: + if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces: + RNS.log(str(self)+" skipping Darwin AWDL or tethering interface "+str(ifname), RNS.LOG_EXTREME) + elif RNS.vendor.platformutils.is_darwin() and ifname == "lo0": + RNS.log(str(self)+" skipping Darwin loopback interface "+str(ifname), RNS.LOG_EXTREME) + elif RNS.vendor.platformutils.is_android() and ifname in AutoInterface.ANDROID_IGNORE_IFS and not ifname in self.allowed_interfaces: + RNS.log(str(self)+" skipping Android system interface "+str(ifname), RNS.LOG_EXTREME) + elif ifname in self.ignored_interfaces: + RNS.log(str(self)+" ignoring disallowed interface "+str(ifname), RNS.LOG_EXTREME) + elif ifname in AutoInterface.ALL_IGNORE_IFS: + RNS.log(str(self)+" skipping interface "+str(ifname), RNS.LOG_EXTREME) else: - addresses = self.list_addresses(ifname) - if self.netinfo.AF_INET6 in addresses: - link_local_addr = None - for address in addresses[self.netinfo.AF_INET6]: - if "addr" in address: - if address["addr"].startswith("fe80:"): - link_local_addr = self.descope_linklocal(address["addr"]) - self.link_local_addresses.append(link_local_addr) - self.adopted_interfaces[ifname] = link_local_addr - self.multicast_echoes[ifname] = time.time() - RNS.log(str(self)+" Selecting link-local address "+str(link_local_addr)+" for interface "+str(ifname), RNS.LOG_EXTREME) - - if link_local_addr == None: - RNS.log(str(self)+" No link-local IPv6 address configured for "+str(ifname)+", skipping interface", RNS.LOG_EXTREME) - else: - mcast_addr = self.mcast_discovery_address - RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME) - - # Struct with interface index - if_struct = struct.pack("I", self.interface_name_to_index(ifname)) - - # Set up multicast socket - discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if hasattr(socket, "SO_REUSEPORT"): - discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, if_struct) - - # Join multicast group - mcast_group = socket.inet_pton(socket.AF_INET6, mcast_addr) + if_struct - discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group) - - # Bind socket - if RNS.vendor.platformutils.is_windows(): - - # window throws "[WinError 10049] The requested address is not valid in its context" - # when trying to use the multicast address as host, or when providing interface index - # passing an empty host appears to work, but probably not exactly how we want it to... - discovery_socket.bind(('', self.discovery_port)) + if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces: + RNS.log(str(self)+" ignoring interface "+str(ifname)+" since it was not allowed", RNS.LOG_EXTREME) + else: + addresses = self.list_addresses(ifname) + if self.netinfo.AF_INET6 in addresses: + link_local_addr = None + for address in addresses[self.netinfo.AF_INET6]: + if "addr" in address: + if address["addr"].startswith("fe80:"): + link_local_addr = self.descope_linklocal(address["addr"]) + self.link_local_addresses.append(link_local_addr) + self.adopted_interfaces[ifname] = link_local_addr + self.multicast_echoes[ifname] = time.time() + nice_name = self.netinfo.interface_name_to_nice_name(ifname) + if nice_name != None and nice_name != ifname: + RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {nice_name} / {ifname}", RNS.LOG_EXTREME) + else: + RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {ifname}", RNS.LOG_EXTREME) + if link_local_addr == None: + RNS.log(str(self)+" No link-local IPv6 address configured for "+str(ifname)+", skipping interface", RNS.LOG_EXTREME) else: + mcast_addr = self.mcast_discovery_address + RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME) + + # Struct with interface index + if_struct = struct.pack("I", self.interface_name_to_index(ifname)) + + # Set up multicast socket + discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if hasattr(socket, "SO_REUSEPORT"): + discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, if_struct) + + # Join multicast group + mcast_group = socket.inet_pton(socket.AF_INET6, mcast_addr) + if_struct + discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group) + + # Bind socket + if RNS.vendor.platformutils.is_windows(): + + # window throws "[WinError 10049] The requested address is not valid in its context" + # when trying to use the multicast address as host, or when providing interface index + # passing an empty host appears to work, but probably not exactly how we want it to... + discovery_socket.bind(('', self.discovery_port)) - if self.discovery_scope == AutoInterface.SCOPE_LINK: - addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) else: - addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) - discovery_socket.bind(addr_info[0][4]) + if self.discovery_scope == AutoInterface.SCOPE_LINK: + addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + else: + addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) - # Set up thread for discovery packets - def discovery_loop(): - self.discovery_handler(discovery_socket, ifname) + discovery_socket.bind(addr_info[0][4]) - thread = threading.Thread(target=discovery_loop) - thread.daemon = True - thread.start() + # Set up thread for discovery packets + def discovery_loop(): + self.discovery_handler(discovery_socket, ifname) - suitable_interfaces += 1 + thread = threading.Thread(target=discovery_loop) + thread.daemon = True + thread.start() + + suitable_interfaces += 1 + + except Exception as e: + nice_name = self.netinfo.interface_name_to_nice_name(ifname) + if nice_name != None and nice_name != ifname: + RNS.log(f"Could not configure the system interface {nice_name} / {ifname} for use with {self}, skipping it. The contained exception was: {e}", RNS.LOG_ERROR) + else: + RNS.log(f"Could not configure the system interface {ifname} for use with {self}, skipping it. The contained exception was: {e}", RNS.LOG_ERROR) if suitable_interfaces == 0: RNS.log(str(self)+" could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING) diff --git a/RNS/vendor/ifaddr/niwrapper.py b/RNS/vendor/ifaddr/niwrapper.py index e6c8b96..8167dc4 100644 --- a/RNS/vendor/ifaddr/niwrapper.py +++ b/RNS/vendor/ifaddr/niwrapper.py @@ -18,6 +18,18 @@ def interface_names_to_indexes() -> dict: results[adapter.name] = adapter.index return results +def interface_name_to_nice_name(ifname) -> str: + try: + adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) + for adapter in adapters: + if adapter.name == ifname: + if hasattr(adapter, "nice_name"): + return adapter.nice_name + except: + return None + + return None + def ifaddresses(ifname) -> dict: adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) ifa = {}