Table of Contents

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.

TP-Link MR6400 Case Rear

Istall the OpenWRT firmware via TFTP protocol

Following the OpenWRT Firmware Selector and choosing the option TFTP-RECOVERY, I downloaded the firmware file openwrt-22.03.3-ramips-mt76x8-tplink_tl-mr6400- v5-squashfs-tftp-recovery.bin.

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: 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:

Once the network device is created, you must add it to the WAN firewall zone: InterfacesLTE4GFirewall SettingsCreate/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
}
RSSI Usability
-60 Good
-70 Acceptable
-90 Barely usable

The uqmi can be used to get several info about the current connection, e.g. the MCC (Mobile Country Code), MNC (Mobile Network Code), TAC (Tracking Area Code, knwon also as LAC, Local Area Code):

uqmi --device=/dev/cdc-wdm0 --get-system-info
{
        "wcdma": {
                "service_status": "none",
                "true_service_status": "none",
                "preferred_data_path": false
        },
        "lte": {
                "service_status": "available",
                "true_service_status": "available",
                "preferred_data_path": false,
                "domain": "cs-ps",
                "service": "cs-ps",
                "roaming_status": "off",
                "forbidden": false,
                "mcc": "222",
                "mnc": "50",
                "tracking_area_code": 36035,
                "enodeb_id": 344505,
                "cell_id": 7,
                "voice_support": false,
                "ims_voice_support": false,
                "cell_access_status": "all calls",
                "registration_restriction": 0,
                "registration_domain": 0
        }
}

:!: NOTICE: Some services - like www.opencellid.org - identify the cells using the Cell ID, which is actually the ECI (E-UTRAN Cell Identifier). That identifier is composed by the enodeb_id (20 bits) and the cell_id (8 bits), using the following formula:

ECI = enodeb_id * 256 + cell_id

So, in the example above, we have that the Cell ID is:

ECI = 344505 * 256 + 7 = 88193287

Configuring the LEDs

The TL-MR6400 router has seven LEDs:

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 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 ServicesSNMP 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 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 SystemBackup / 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 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:

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:

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