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.
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.
- 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: 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: <blank>
- Authentication Type: PAP/CHAP
- PAP/CHAP username: <blank>
- PAP/CHAP password: <blank>
- 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 }
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:
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 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 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 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:
- /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