Automatyczny restart połączenia LTE na routerze WiFi z OpenWRT

Spis treści

Od już dłuższego czasu (będzie parę lat) korzystam z internetu LTE zamiast tradycyjnego połączenia przewodowego. Głównie ze względu na fakt, że w mojej okolicy nie ma praktycznie żadnych szanujących się ISP, z którymi warto by wejść w interakcję i podpisać z nimi jakąś sensową umowę. Poza tym, dla osób mojego pokroju, które cenią sobie mobilność, internet stacjonarny i tak jest mało praktyczny. Dlatego w moim domowym routerze mam wgrany firmware OpenWRT umożliwiający zainstalowanie na tym urządzeniu odpowiedniego oprogramowania obsługującego modemy LTE podłączane przez port USB. Połączenie sieciowe ze światem zwykle działa prawidłowo ale z jakiegoś powodu jest ono zrywane. Zwykle taka sytuacja ma miejsce w środku nocy (czasami parokrotnie), zwłaszcza gdy przekroczę limit danych i do końca okresu rozliczeniowego muszę przemęczyć się z lejkiem 1 mbit/s. Gdy ten lejek jest aplikowany, to zwykle odpalam sobie torrent'a, tak by pobrać najnowsze obrazy ISO tej czy innej dystrybucji linux'a. Niemniej jednak, jak mi net rozłączą, to nie załączy się on ponownie sam z siebie. Modem Huawei E3372s-153 w wersji NON-HiLink zdaje się pracować poprawnie, bo świeci się na nim dioda sugerująca, że połączenie z internetem jest nawiązane. Dlatego też postanowiłem w końcu ten problem rozwiązać raz na zawsze i mieć przy tym nieco spokojniejszy sen.

Problemy z modemem LTE przy restarcie interfejsu WAN

Na necie można spotkać wiele rozwiązań, które umożliwiają monitorowanie połączenia sieciowego pod kątem jego aktywności czy sprawności. Zwykle jednak te sposoby radzenia sobie z zanikiem internetu dotyczą przewodowych połączeń, gdzie zresetowaniu podlega interfejs WAN w przypadku wykrycia utraty odpowiedzi na zapytania ping . Nie byłoby w zasadzie żadnego problemu, gdyby to rozwiązanie przedstawione w powyżej podlinkowanym artykule działało ale rzecz w tym, że nie działa.

Ja u siebie na OpenWRT mam skonfigurowany interfejs LTE obok interfejsu WAN i te dwa interfejsy mogą działać niezależnie, w zależności od tego czy chcę wykorzystywać router do połączenia przewodowego lub LTE. Generalnie to ten interfejs jest konfigurowany w poniższy sposób:

uci set network.lte=interface
uci set network.lte.proto='ncm'
uci set network.lte.device='/dev/cdc-wdm0'
uci set network.lte.service='preferlte'
uci set network.lte.pdptype='IP'
uci set network.lte.apn='internet'
uci set network.lte.pincode='internet'
uci set network.lte.ipv6='auto'
uci set network.lte.peerdns='0'
uci add_list network.lte.dns='127.0.0.1'

uci del firewall.@zone[1].network
uci set firewall.@zone[1].network='wan wan6 lte'

uci commit

Niestety w przypadku mojego modemu Huawei E3372s-153 w wersji NON-HiLink przy próbie zresetowania połączenia za sprawą polecenia ifup lte , w logu systemowym routera można zaobserwować poniższe komunikaty:

...
netifd: lte_4 (10284): udhcpc: received SIGTERM
netifd: lte_4 (10284): udhcpc: unicasting a release of 10.73.3.94 to 10.73.3.93
netifd: lte_4 (10284): udhcpc: sending release
netifd: lte_4 (10284): udhcpc: entering released state
netifd: lte (11278): Stopping network lte
netifd: lte_4 (10284): Command failed: Permission denied
netifd: Interface 'lte_4' is now down
netifd: Network alias '' link is down
netifd: Interface 'lte_4' has link connectivity loss
netifd: Interface 'lte_4' is disabled

Czyli interfejs został rozłączony poprawnie ale dalej w logu mamy coś takiego:

netifd: lte (11278): sending -> AT^NDISDUP=1,0
netifd: lte (11278): Command failed: Permission denied
netifd: Interface 'lte' is now down
netifd: Interface 'lte' is setting up now
netifd: lte (11340): Failed to get modem information
netifd: lte (11449): Stopping network lte
netifd: lte (11449): Failed to get modem information
netifd: Interface 'lte' is now down
netifd: Interface 'lte' is setting up now
netifd: lte (11508): Failed to get modem information
netifd: lte (11585): Stopping network lte
netifd: lte (11585): Failed to get modem information
...

I tak w nieskończoność, czego efektem jest brak możliwości skonfigurowania modemu LTE do pracy, co oczywiście przekłada się na brak internetu.

Jedyną opcją by wybrnąć z tej sytuacji jest fizyczne odłączenie modemu LTE od portu USB routera i podłączenie go ponownie. Można też naturalnie zrestartować router ale czas jego gotowości do pracy zawsze będzie sporo dłuższy niż samo skonfigurowanie modemu LTE po podpięciu go do portu USB.

Restart modemu LTE bez wyciągania go z portu USB

Pojawiło się zatem zapytanie na temat tego w jaki sposób rozłączyć modem LTE bez wyciągania go z portu USB? Okazało się, że nie jest to jakoś specjalnie trudne i można do tego celu skorzystać z mechanizmu autoryzacji urządzeń USB, który jest wbudowany bezpośrednio w kernel linux'a. To jest dokładnie ten sam mechanizm, który jest wykorzystywany np. przez usbguard. Można także wykorzystać do tego celu mechanizm manualnego przypisania sterowników do urządzeń ( bind/unbind ). Postanowiłem zatem przerobić nieco skrypt watchdog'a, który był podany na stronie eko.one.pl .

Skrypt watchdog'a (wersja z plikiem authorized)

Poniżej znajduje się wersja skryptu watchdog'a wykorzystująca mechanizm autoryzacji urządzeń USB:

#!/bin/sh

if ! ping -q -c 1 -W 15 8.8.8.8 > /dev/null
then
    logger "*************************************************"
    logger "**** Brak internetu. Restartuje modem LTE... ****"
    logger "*************************************************"

    echo 0 > /sys/bus/usb/devices/usb3/authorized
    sleep 5
    echo 1 > /sys/bus/usb/devices/usb3/authorized
fi

Gdy wykorzystujemy mechanizm autoryzacji urządzeń USB, to skrypt prześle wartość 0 do pliku authorized hub'a usb3 (bo to tutaj został wpięty modem LTE). Można by odszukać ścieżkę do samego modemu LTE ale ta może ulec zmianie po rozłączeniu modemu, co skomplikowałoby nam nieco życie. Z racji, że odłączymy cały hub, to wszystkie urządzenia podłączone do usb3 zostaną zresetowane.

Warto też zaznaczyć, że mój router ma 2 fizyczne porty USB ale hub'ów dostępnych w systemie jest 4, z czego 2 wewnętrzne. Akurat w przypadku mojego routera jest tak, że każdy port USB jest wpięty do innego hub'a ale nie jest to regułą. Jeśli mamy problem z ustaleniem, który hub jest od którego portu USB, to trzeba metodą prób i błędów przesłać wartość 0 do każdego z nich i w końcu ten prawidłowy ujawni się rozłączając modem LTE.

W skrypcie watchdog'a mamy jeszcze przesłanie wartości 1 do pliku authorized , co efektywnie włączy modem mniej więcej w taki sposób gdybyśmy go fizycznie podłączyli do portu USB.

Przesłanie wartości 0 i 1 trzeba też nieco opóźnić, bo inaczej mogą pojawić się problemy z ponownym włączeniem modemu LTE.

W poleceniu ping zostały użyte poniższe flagi:

  • -q -- odpowiada za ciche wyjście, tj. nic poza podsumowaniem nie zostanie wydrukowane w terminalu.
  • -c 1 -- odpowiada za przesłanie do serwera tylko jednego pakietu.
  • -W 15 -- odpowiada za czas oczekiwania na odpowiedź od serwera, który w tym przypadku został ustawiony na 15 sekund.
  • 8.8.8.8 -- to adres IP, na który mają zostać posłane zapytania. Można także skorzystać z domeny, choć wiarygodniejsze jest podanie tutaj adresu IP.

Zatem jeśli to powyższe polecenie ping nie otrzyma odpowiedzi od serwera w ciągu 15 sekund, to zostaną zainicjowane instrukcje zawarte dalej w skrypcie watchdog'a.

Skrypt watchdog'a (wersja z plikami bind/unbind)

Poniżej znajduje się wersja skryptu watchdog'a wykorzystująca mechanizm manualnego przypisywania sterowników do urządzeń:

#!/bin/sh

if ! ping -q -c 1 -W 15 8.8.8.8 > /dev/null
then
    logger "*************************************************"
    logger "**** Brak internetu. Restartuje modem LTE... ****"
    logger "*************************************************"

    echo "usb1" > /sys/bus/usb/drivers/usb/unbind
    sleep 1
    echo "usb1" > /sys/bus/usb/drivers/usb/bind

fi

W tym przypadku, do plików unbind i bind zostaje przesłany numerek urządzenia USB, które zostanie rozłączone i ponownie podłączone. Reszta skryptu się nie zmienia.

Praca dla cron

By całość nam jeszcze zadziałała i modem się faktycznie zresetował, gdy połączenie z internetem zaniknie, musimy stworzyć zadanie dla cron'a, które będzie cyklicznie wykonywane. Tworzymy zatem plik /etc/crontabs/root (jeśli nie istnieje) i dodajemy do niego poniższą zawartość:

*/2 * * * * /etc/skrypty/watchdog

Ta powyższa linijka ma za zadanie wykonywać skrypt watchdog'a co dwie minuty. W przypadku braku internetu, modem LTE powinien zostać zresetowany, a połączenie z siecią odzyskane.

Test internetowego watchdog'a

Gdy już wszystko mamy na swoim miejscu, symulujemy brak internetu, np. przez wysłanie zapytania ping pod adres IP, który wiemy, że nie odpowie, np. jakiś lokalny (do ustawienia w skrypcie watchdog'a). Odpalamy terminal i wpisujemy logread -f , po czym obserwujemy co tam system nam wypisze.

Najpierw pojawia się poniższy komunikat:

root: *************************************************
root: **** Brak internetu. Restartuje modem LTE... ****
root: *************************************************

Zatem wiemy, że skrypt został wykonany. Później mamy zaś takie oto wiadomości:

kernel: [90294.008064] usb 3-1: USB disconnect, device number 12
kernel: [90294.008506] option1 ttyUSB0: GSM modem (1-port) converter now disconnected from ttyUSB0
kernel: [90294.012306] option 3-1:1.0: device disconnected
kernel: [90294.020559] option1 ttyUSB1: GSM modem (1-port) converter now disconnected from ttyUSB1
kernel: [90294.024582] option 3-1:1.1: device disconnected
kernel: [90294.033280] huawei_cdc_ncm 3-1:1.2 wwan0: unregister 'huawei_cdc_ncm' usb-xhci-hcd.1.auto-1, Huawei CDC NCM device
netifd: Network device 'wwan0' link is down
netifd: Network alias 'wwan0' link is down
netifd: Interface 'lte_4' has link connectivity loss
netifd: lte_4 (26465): udhcpc: SIOCGIFINDEX: No such device
netifd: lte_4 (26465): udhcpc: received SIGTERM
netifd: lte_4 (26465): udhcpc: unicasting a release of 10.70.8.81 to 10.70.8.82
netifd: lte_4 (26465): udhcpc: sending release
netifd: lte_4 (26465): udhcpc: can't bind to interface wwan0: No such device
netifd: lte_4 (26465): udhcpc: bindtodevice: No such device
netifd: lte_4 (26465): udhcpc: entering released state
netifd: lte_4 (26465): Command failed: Permission denied
netifd: Interface 'lte_4' is now down
netifd: Interface 'lte_4' is disabled
netifd: lte (27037): Control device not valid
netifd: Interface 'lte' is now down

Widać wyraźnie, że urządzenie USB zostało rozłączone i to mniej więcej w taki sam sposób, gdybyśmy je fizycznie wyciągnęli z portu USB. Znika nam też z systemu interfejs LTE ( wwan0 ) i nie będzie go nawet na liście w wyjściu polecenia ip .

Po chwili pojawiają się w logu poniższe komunikaty:

kernel: [90299.492540] hub 3-0:1.0: USB hub found
kernel: [90299.492644] hub 3-0:1.0: 1 port detected
kernel: [90299.495628] usb usb3: authorized to connect
kernel: [90299.675996] usb 3-1: new high-speed USB device number 13 using xhci-hcd
kernel: [90299.961386] option 3-1:1.0: GSM modem (1-port) converter detected
kernel: [90299.961563] usb 3-1: GSM modem (1-port) converter now attached to ttyUSB0
kernel: [90299.966896] option 3-1:1.1: GSM modem (1-port) converter detected
kernel: [90299.973418] usb 3-1: GSM modem (1-port) converter now attached to ttyUSB1
kernel: [90300.151756] huawei_cdc_ncm 3-1:1.2: MAC-Address: 00:1e:10:1f:00:00
kernel: [90300.151784] huawei_cdc_ncm 3-1:1.2: setting rx_max = 16384
kernel: [90300.162721] huawei_cdc_ncm 3-1:1.2: NDP will be placed at end of frame for this device.
kernel: [90300.162874] huawei_cdc_ncm 3-1:1.2: cdc-wdm0: USB WDM device
kernel: [90300.170843] huawei_cdc_ncm 3-1:1.2 wwan0: register 'huawei_cdc_ncm' at usb-xhci-hcd.1.auto-1, Huawei CDC NCM device, 00:1e:10:1f:00:00
kernel: [90300.176571] usb-storage 3-1:1.3: USB Mass Storage device detected
kernel: [90300.188928] scsi host0: usb-storage 3-1:1.3
kernel: [90301.222184] scsi 0:0:0:0: Direct-Access     HUAWEI   TF CARD Storage  2.31 PQ: 0 ANSI: 2
kernel: [90301.224138] sd 0:0:0:0: Power-on or device reset occurred
kernel: [90301.232048] sd 0:0:0:0: [sda] Attached SCSI removable disk

Zatem modem LTE został ponownie wykryty. Pojawił się także fizyczny interfejs sieciowy wwan0 .

Po chwili modem zostaje przygotowany do pracy:

netifd: Interface 'lte' is setting up now
netifd: lte (28012): sending -> AT
netifd: lte (28012): sending -> ATZ
netifd: lte (28012): sending -> ATQ0
netifd: lte (28012): sending -> ATV1
netifd: lte (28012): sending -> ATE1
netifd: lte (28012): sending -> ATS0=0
netifd: lte (28012): sending -> AT+CGDCONT=1,"IP","internet"
netifd: lte (28012): SIM ready
netifd: lte (28012): PIN set successfully
netifd: lte (28012): Configuring modem
netifd: lte (28012): Starting network lte
netifd: lte (28012): Connecting modem
netifd: lte (28012): sending -> AT^NDISDUP=1,1,"internet"
netifd: lte (28012): Setting up wwan0
netifd: Interface 'lte' is now up

Następnie interfejs LTE, pod który podlega fizyczny interfejs wwan0 , zostaje skonfigurowany:

netifd: Network device 'wwan0' link is up
netifd: Network alias 'wwan0' link is up
netifd: Interface 'lte_4' is enabled
netifd: Interface 'lte_4' has link connectivity
netifd: Interface 'lte_4' is setting up now
netifd: lte_4 (28300): udhcpc: started, v1.33.1
firewall: Reloading firewall due to ifup of lte (wwan0)
netifd: lte_4 (28300): udhcpc: sending discover
netifd: lte_4 (28300): udhcpc: sending select for 10.70.8.81
netifd: lte_4 (28300): udhcpc: lease of 10.70.8.81 obtained, lease time 518400
netifd: Interface 'lte_4' is now up
firewall: Reloading firewall due to ifup of lte_4 (wwan0)

I jak widzimy adresacja IP na interfejsie LTE ( wwan0 ) zostaje uzyskana od serwera DHCP mojego ISP, czego efektem jest przywrócenie połączenia sieciowego do pełnej sprawności.

Podsumowanie

W taki oto dość prosty sposób, kawałek skryptu oraz odpowiednie wykorzystanie mechanizmu autoryzacji podłączanych do portów USB urządzeń (ewentualnie też mechanizmu manualnego przypisywania sterowników do urządzeń) umożliwiły nam zaimplementowanie watchdog'a na routerze z wgranym firmware OpenWRT. Ilekroć tylko połączenie LTE nam zaniknie z jakiegoś powodu, nasz watchdog zresetuje modem LTE i przywróci je do pełnej sprawności. Nie musimy już się obawiać, że w środku nocy internet nam po cichu zdechnie, a obrazy ISO różnych dystrybucji linux'a nie pobiorą się nam przez torrent'a. No i oczywiście też nasz komputer nie będzie pracował całą noc na marne. Z moich obserwacji wynika też, że watchdog oparty o mechanizm przypisywania sterowników do urządzeń działa nieco lepiej niż ten, w którym wykorzystywana jest autoryzacja urządzeń USB.

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.