====== OpenWRT on the TP-Link MR6400 ====== I purchased the **TP-Link MR6400** router (**v.5** hardware revision) to manage an LTE connection provided by the Iliad operator, in Italy. The price was about **67 €** in January 2023. {{.:tplink:tl-mr6400_case_rear.jpg?320|TP-Link MR6400 Case Rear}} ===== Istall the OpenWRT firmware via TFTP protocol ===== Following the **[[https://firmware-selector.openwrt.org/|OpenWRT Firmware Selector]]** and choosing the option **TFTP-RECOVERY**, I downloaded the firmware file **{{https://downloads.openwrt.org/releases/22.03.3/targets/ramips/mt76x8/openwrt-22.03.3-ramips-mt76x8-tplink_tl-mr6400-v5-squashfs-tftp-recovery.bin|openwrt-22.03.3-ramips-mt76x8-tplink_tl-mr6400- v5-squashfs-tftp-recovery.bin}}**. * Configure your PC as a **TFTP server**. On a Debian GNU/Linux PC you can: - Install the **tftpd** Debian package. - Verify in **/etc/inetd.conf** that the document root of the service is **/srv/tftp/**. - Rename and copy the firmware file to **/srv/tftp/tp_recovery.bin**, with mode **644**. - Configure the Ethernet interface of the PC with address **192.168.0.225/255.255.255.0**. - Restart the inetd service with ''systemctl restart inetd.service''. * Connect the TFTP server with an **Ethernet** cable to the **LAN1** port of the router. * Power on the device while **holding the reset button** (waiting 8 seconds should suffice). * Check the **/var/log/syslog** of the TFTP server: the router will request the **tp_recovery.bin** file and and install it. Once the firmware is installed, the router will reboot and it will start with an IP address of **192.168.1.1** on the **LAN ports 1 to 3**. You can connect using **HTTP** or **SSH**, default setting have **no password** for the **root** user. ===== Istall other OpenWRT packages ===== The default OpenWRT configuration uses the **LAN port 4** as **WAN** (i.e. connection to the Internet). If a DHCP server is found on the LAN, the IP address, DNS and default gateway will be aquired automatically. Connect to the router via SSH and install the following packages (I use OpenVPN to make a VPN between two offices and I use ''tcpdump'' as a debug tool): opkg update opkg install luci-proto-qmi opkg install openvpn opkg install luci-app-openvpn opkg install tcpdump-mini The repository used during the installation is the following:\\ **[[https://downloads.openwrt.org/releases/22.03.3/packages/mipsel_24kc/]]**. After the installation of the above packages, this is the free space on the filesystems: root@OpenWrt:~# df Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 3840 3840 0 100% /rom tmpfs 28800 976 27824 3% /tmp tmpfs 28800 60 28740 0% /tmp/root tmpfs 512 0 512 0% /dev /dev/mtdblock4 1920 912 1008 48% /overlay overlayfs:/overlay 1920 912 1008 48% / ===== Upgrade the uqmi package ===== Using the stock **uqmi** package provided by OpenWRT 22.03.2 I was not able to bring up the LTE interface. The error message shown by **logread** was: daemon.notice netifd: lte4g (2329): Command failed: ubus call network.interface notify_proto { "action": 0, "link-up": false, "keep": false, "interface": "lte4g" } (Permission denied) daemon.notice netifd: Interface 'lte4g' is now down daemon.notice netifd: Interface 'lte4g' is setting up now daemon.notice netifd: lte4g (2343): Waiting for SIM initialization I downloaded a custom **uqmi** packages for OpenWRT 22.03.2 here: **[[https://github.com/mrhaav/openwrt/raw/master/22.03.2/uqmi_2022-11-29-0.10_mipsel_24kc.ipk|uqmi_2022-11-29-0.10_mipsel_24kc.ipk]]**. The **uqmi** depends upon **libubox** and **libblobmsg-json**, these are the exact versions that satisfied the dependency in my installation: ^ uqmi | 2022-11-29-0.10 | ^ libubox20220515 | 2022-05-15-d2223ef9-1 | ^ libblobmsg-json20220515 | 2022-05-15-d2223ef9-1 | Now the ''logread'' output is OK, except that IPv6 is not negotiated (may be a fault by the Iliad provider): kern.info kernel: qmi_wwan 1-1:1.4: cdc-wdm0: USB WDM device kern.info kernel: qmi_wwan 1-1:1.4 wwan0: register 'qmi_wwan' at usb-101c0000.ehci-1, WWAN/QMI device, 1a:45:b9:77:47:66 kern.info kernel: usbcore: registered new interface driver qmi_wwan kern.info kernel: usbcore: registered new interface driver option kern.info kernel: usbserial: USB Serial support registered for GSM modem (1-port) daemon.notice netifd: Interface 'lte4g' is setting up now daemon.notice netifd: lte4g (1900): PINcode disabled daemon.notice netifd: lte4g (1900): Data format set to raw-ip daemon.notice netifd: lte4g (1900): Default profile: 1 daemon.notice netifd: lte4g (1900): Change default profile daemon.notice netifd: lte4g (1900): apn: to iliad daemon.notice netifd: lte4g (1900): authentication: none to both daemon.notice netifd: lte4g (1900): Airplane mode off daemon.notice netifd: lte4g (1900): registered on 22250 daemon.notice netifd: lte4g (1900): Registered to Iliad on LTE daemon.notice netifd: lte4g (1900): Connected with IPv4 daemon.notice netifd: lte4g (1900): Unable to connect with IPv6 daemon.notice netifd: lte4g (1900): Setting up wwan0 daemon.notice netifd: Interface 'lte4g' is now up ===== Configure the LTE connection ===== Edit the **/etc/config/network** file and add a section like this: config interface 'lte4g' option proto 'qmi' option apn 'iliad' option autoconnect '1' option device '/dev/cdc-wdm0' option delay '1' option auth 'both' option pdptype 'ipv4v6' option default_profile '1' You can now verify that the new interface is shown into the **LuCI** web interface, into the //**Interfaces**// page. Click over //LTE4G// and check the //**General Settings**//: * Protocol: QMI Cellular * Bring on boot: [x] * Modem device: /dev/cdc-wdm0 * APN: iliad * PIN: * Authentication Type: PAP/CHAP * PAP/CHAP username: * PAP/CHAP password: * PDP Type: IPv4/IPv6 Once the network device is created, you must add it to the WAN firewall zone: **//Interfaces//** => //LTE4G// => //Firewall Settings// => //Create/Assign firewall-zone//: **WAN**. When the LTE connection is established you will see an **wwan0** interface up and configured. It is possibile to query the status of the connection using the **uqmi** tool. **SNR** (Signal to Noise Ratio) and **RSSI** (Received Signal Strength Indication) should both give you an indication of your signal strength: uqmi --device=/dev/cdc-wdm0 --get-signal-info { "type": "lte", "rssi": -58, "rsrq": -8, "rsrp": -94, "snr": 16.600000 } ===== Configuring the LEDs ===== The TL-MR6400 router has **seven LEDs**: {{.:tplink:tl-mr6400-led.jpg?400|The TP-Link MR6400 LEDs}} Once you installed the OpenWRT operating system, you can control them accessing the pseudo files into the **/sys/class/leds/** directory. Each LED have its name (actually a subdirectory): ^ white:power | Power | ^ white:wan | Internet connection | ^ white:wlan | WiFi connection | ^ white:lan | LAN connection | ^ white:signal1 | Signal strenght #1 | ^ white:signal2 | Signal strenght #2 | ^ white:signal3 | Signal strenght #3 | You can manually test the on/off operation sending a specific string to the **trigger** pseudo file: echo "default-on" > /sys/class/leds/white:signal1/trigger echo "none" > /sys/class/leds/white:signal1/trigger Reading the same pseudo file you can get the options supperted by the //trigger//, the current state is highlighted by the square brackets: cat /sys/class/leds/white:wlan/trigger [none] switch0 timer heartbeat default-on netdev usbport phy0rx phy0tx phy0assoc phy0radio phy0tpt The trigger **netdev** can be used to connect the LED status to a network device status (link, activity, etc.). It seems to be integrated into OpenWRT 22.03.3; the package **kmod-ledtrig-netdev** does not exists and it is not actually required. The default LED configuration is found into the **/etc/config/system** file. It binds the LAN LED to the carrier status of **ports 1 to 3** of **switch0** and the WAN LED to the carrier status of **port 3** of **switch0** (the //port_mask// option is a binary mask of ports position: 0x07 = 0b0111, 0x08 = 0b1000): config led 'led_lan' option name 'lan' option sysfs 'white:lan' option trigger 'switch0' option port_mask '0x07' config led 'led_wan' option name 'wan' option sysfs 'white:wan' option trigger 'switch0' option port_mask '0x08' I want to use alle the four ports as LAN ports and I want to bind the WAN LED to the LTE connection, so I have changed the configuration as follow: config led 'led_lan' option name 'lan' option sysfs 'white:lan' option trigger 'switch0' option port_mask '0x0f' config led 'led_wan' option name 'wan' option sysfs 'white:wan' option trigger 'netdev' option dev 'wwan0' option mode 'link tx' config led 'led_wifi' option name 'wifi' option sysfs 'white:wlan' option trigger 'phy0tpt' For the WiFi LED the **phy0tpt** trigger seems to be the most adequate, I tried to use the **phy0radio**, hoping that it will reflect the on/off status of the radio transmitter, but it is not the case: sometimes the LED remained off even if the WiFi signal was active. ===== LTE signal strenght LEDs ===== The **uqmi_d.sh** daemon provided by the custom **uqmi** package contains an hook to update the LEDs of the LTE connection. Every 30 seconds it calls the script **/usr/bin/uqmi_led.sh**, which **is not provided**, you have to create your own. This is mine: #!/bin/sh RSSI="$1" if ! echo "$RSSI" | egrep -q '^[+-]?\d+$'; then echo "Usage: uqmi_led.sh [RSSI]" exit fi echo "$RSSI" > '/tmp/lte-rssi' LED1=$(readlink -f /sys/class/leds/white:signal1) LED2=$(readlink -f /sys/class/leds/white:signal2) LED3=$(readlink -f /sys/class/leds/white:signal3) if [ "$RSSI" -eq -200 ]; then echo none > $LED1/trigger echo none > $LED2/trigger echo none > $LED3/trigger elif [ "$RSSI" -le -90 ]; then echo default-on > $LED1/trigger echo none > $LED2/trigger echo none > $LED3/trigger elif [ "$RSSI" -le -60 ]; then echo default-on > $LED1/trigger echo default-on > $LED2/trigger echo none > $LED3/trigger else echo default-on > $LED1/trigger echo default-on > $LED2/trigger echo default-on > $LED3/trigger fi The script is based on the [[https://github.com/mrhaav/openwrt|uqmi_led.sh example]], but I added some syntax check and the creation of a cache file where to store the RSSI (Received Signal Strength Indication) value. That cached value is used to make the value available via the SNMP service (see below). ===== The SNMP Daemon ===== Installing the full snmpd daemon and the relative LuCI web interface requires about **548 kb** of storage space on the **/overlay** partition. The required packages are: opkg install snmpd opkg install luci-app-snmpd You have to restart the LuCI service to see the new //Services// => //SNMP page//. Unfortunately the web interface is rather useless: to add an **extend** OID it is necessary to edit manually the configuration file. The following example adds an OID to read the current RSSI value of the LTE connection; add this section to **/etc/config/snmpd**: config extend option name 'lte_rssi' option prog '/usr/local/bin/snmp-lte-rssi' Restart the SNMP service with **/etc/init.d/snmpd restart** and verify that the configuration file **/etc/snmp/snmpd.conf** created on the fly is correct. The script that will serve the OID value is **/usr/local/bin/snmp-lte-rssi**: #!/bin/ash # If the file RSSI is fresh, return its content, otherwise return an empty line. RSSI="/tmp/lte-rssi" if [ -f "$RSSI" ]; then NOW="$(date +%s)" FILE_MTIME="$(date +%s -r "$RSSI")" FILE_AGE="$((NOW - FILE_MTIME))" if [ "$FILE_AGE" -le "60" ]; then cat "$RSSI" exit fi fi echo It is possibile to query the SNMP service using the **snmpwalk** command line tool: snmpwalk -v 2c -c public 192.168.1.1 'NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."lte_rssi"' NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."lte_rssi" = STRING: -65 ===== Wake-on-LAN ===== I was not able to instal the **wakeonlan** package because it depends upon Perl (not enough space on flash memory). Fortunately I was able to install **etherwake**, which requires only **4 kb**. ===== Upgrade to OpenWRT 22.05.0 ===== To upgrade from OpenWRT **22.03.3** to **22.05.0** we used the **sysupgrade** option, which preserves the existing configuration, at least partially. Download the new firmware **[[https://downloads.openwrt.org/releases/23.05.0/targets/ramips/mt76x8/openwrt-23.05.0-ramips-mt76x8-tplink_tl-mr6400-v5-squashfs-sysupgrade.bin|openwrt-23.05.0-ramips-mt76x8-tplink_tl-mr6400-v5-squashfs-sysupgrade.bin]]** to your PC. Connect the PC to one of the Ethernet ports of the router and point your browser to the LuCI web interface. Click the **System** => **Backup / Flash Firmware** page and then upload the firmware file to the router by clicking **Flash new firmware image**. Once the router reboots, you can access it via SSH or LuCI web, the network configuration should have been preserved. Beware that all the extra packages must be installed again, notably the **uqmi** package, required to drive the LTE modem for internet access, must be upgraded to version **[[https://raw.githubusercontent.com/mrhaav/openwrt/master/23.05.0/uqmi_2022-11-29-0.11_mipsel_24kc.ipk|uqmi_2022-11-29-0.11_mipsel_24kc.ipk]]**. That version is not included into the official repository and thus must be downloaded from the GitHub repository. The repository roots are: * https://downloads.openwrt.org/releases/23.05.0/targets/ramips/mt76x8/ * https://downloads.openwrt.org/releases/23.05.0/packages/mipsel_24kc/ This is the list of all the extra packages installed: ^ Package ^ Space ^ | uqmi_2022-11-29-0.11_mipsel_24kc.ipk | 92K | | openvpn | 228K | | luci-app-openvpn | 320K | | tcpdump-mini | 314K | | snmpd | 540K | | luci-app-snmpd | 8K | | etherwake | 8K | | coreutils-base64 | | ===== Sending and receiving SMS ===== Once installed the **uqmi** package, there is a daemon process **/usr/bin/uqmi_d.sh** which is responsible for sending and receiving SMS messages. The program will check every 30 seconds if there is a file into the **send** directory and eventually save received SMS messages from the modem memory to the **received** directory: * **/var/sms/send/** * **/var/sms/received/** To send a message just create a text file into the **/var/sms/send/** directory; the first line must contain the recipient phone number, the following lines are the text message. E.g. +393274445556 Hello, World! Received messages will be saved automatically into **/var/sms/received/**, in files named something like **sms_20240426T150933**. The content will be something like: [Phone Number|CallerID] Tex message. If you stop the running uqmi_d.sh daemon, it is possibile to retrieve received messages from **sim** or from **me** (memory). Get first the list of messages availables and then retrieve one: uqmi -d /dev/cdc-wdm0 --list-messages --storage me uqmi -s -d /dev/cdc-wdm0 --get-message 0 --storage me ===== Web References ===== * **[[https://openwrt.org/toh/tp-link/tl-mr6400_v5|OpenWRT - TP-Link TL-MR6400 v5]]** * **[[https://github.com/mrhaav/openwrt|Customized OpenWRT uqmi package by Mrhaav]]** * **[[https://openwrt.org/docs/guide-user/base-system/led_configuration|OpenWRT - LED Configuration]]** * **[[https://forum.openwrt.org/t/tl-mr6400-v5-lte-disconnect-after-six-hours/125468|[TL-MR6400 v5] LTE “disconnect” after six hours]]**