Routeur Linksys WRT350N V2

Après un gros mois de travail acharné, je suis parvenu à faire revivre un vieux routeur Linksys WRT350N V2 que j’avais brické en voulant faire des tests pour une application domotique. Le détail de ce débrickage est ici.

Photo Linksys WRT350N

Linksys WRT350N v2

Photo Linksys WRT350N

On peut trouver les caractéristiques de ce routeur ici : https://wikidevi.com/wiki/Linksys_WRT350N_v2. C’est un routeur WiFi antérieur à 2010 mais qui présente l’intérêt d’avoir un port USB ce qui peut être intéressant notamment pour y mettre un téléphone en partage de connexion et le transformer en modem 4G.

Le firmware d’origine ne laisser pas beaucoup de possibilité d’usage à un vieux routeur comme celui-ci mais avec une distribution OpenWRT les applications pour redonner vie à cet équipement sont multiples : NAS, tethering 4G, firewall customisable, etc. Toutes les infos pour installer cette distribution sur ce routeur sont disponibles sur la page du WRT350N V2 d’OpenWRT.

Le firmware OpenWRT officiellement compatible est disponible ici : Attitude Adjustment 12.09. Je m’en suis servi pendant des années avec satisfaction. Comme ce matériel commence à être ancien, vous trouverez une copie sur cette page de tous les fichiers disponibles sur OpenWRT correspondant à cette release.

Un projet plus récent existe visant à poursuivre le support du WRT350NV2 avec OpenWRT et LEDE. On peut le trouver ici.

La dernière version du firmware officiel Linksys est disponible ici. Une copie est aussi disponible sur cette page.

Bricking 🙁

Lorsque vous jouez avec un firmware, des erreurs sont possibles et vous pouvez bricker votre routeur. FAITES-LE A VOS RISQUES ET PÉRILS !

Si votre routeur n’est plus capable de basculer en mode de secours TFTP et qu’il ne s’allume plus, vous l’avez probablement brické comme moi en jouant dans la mémoire flash où vous n’êtiez pas sensé jouer. La partie la plus sensible de la mémoire est le bootloader (U-Boot) et certaines chaînes de caractères (ErCoMm, page OpenWRT WRT350NV2).

Dans le cas du Linksys WRT350N V2, grâce au travail de DirkNL, Maddes.b, StrickerNL et Relghuar sur le forum de OpenWRT, il est possible de le faire revivre en utilisant une interface de bas niveau nommée JTAG : https://forum.archive.openwrt.org/viewtopic.php?id=12358&p=42 (post #1031). Comme ce fil est ancien, certains liens et pages sont morts, j’ai donc passé beaucoup de temps à collecter des informations (un grand merci à DirkNL pour ses archives) afin de faire revivre mon WRT350NV2. C’est pour cela que je vais essayer de refaire un HOWTO complet ici.

Debricking 🙂

Il n’est pas possible de debricker ce routeur en programmant directement une image dans la mémoire flash à l’aide d’un JTAG. Plusieurs personnes sur Internet ont essayé ces dernières années sans succès. En réalité, le seul moyen efficace est de mettre une image dans la RAM qui permettra à un serveur NFS d’obtenir un rootfs, puis d’utiliser le terminal qu’on obtiendra pour programmer la mémoire flash du routeur.

Pour débricker et suivre ce HOWTO, vous devez avoir une interface JTAG compatible avec OpenOCD. Personnellement, j’ai utilisé un BlackHawk USB100v2 également appelée XDS100V2 de TI.

Vous avez également besoin d’un convertisseur USB vers série-TTL 3V3. Connectez-le à J5 sur la carte mère WRT350nV2. Le brochage est le suivant :

  1. VCC
  2. RX
  3. TX
  4. GND

Voici le HOWTO pas à pas pour débricker ce routeur en utilisant l’interface JTAG :

  1. Ouvrez le WRT350N V2 en panne et soudez sur J4 un connecteur CMS de 2,54 mm à 20 broches. Voici le pinout pour connecter plus loin le programmateur JTAG :
  2. Téléchargez et décompressez OpenOCD 0.10.0 : http://www.freddiechopin.info/en/download/category/4-openocd
  3. Téléchargez MobaXterm Home Edition et installez-le : https://mobaxterm.mobatek.net/download.html
  4. Installez la dernière version de VirtualBox et téléchargez la machine virtuel Ubuntu 14.04 LTS.
  5. Avant d’exécuter la machine virtuelle Ubuntu, assurez-vous qu’elle est configurée pour utiliser l’interface réseau en mode pont :
  6. Dans la machine virtuelle, nous devons disposer d’un serveur NFS opérationnel et d’un serveur DHCP. Pour cela, lancez la machine virtuelle et installez les packages suivants :
    sudo apt-get install nfs-kernel-server
    sudo apt-get install isc-dhcp-server
  7. Connectez l’interface Ethernet de votre PC directement sur le port 4 du WRT350N V2.
  8. Modifiez l’adresse IP de l’interface Ethernet de la machine virtuelle pour être avec l’IP statique 192.168.20.254.
  9. Configurons maintenant le serveur DHCP. Dans mon exemple, la machine virtuelle est le serveur DHCP avec l’adresse IP 192.168.20.254, l’hôte Windows OS a l’adresse IP 192.168.20.10 (la première valeur disponible puisque c’est le 1e à ce connecter) et le routeur WRT350N V2 obtiendra l’adresse suivante : 192.168.20.11. Pour ce faire, configurez le fichier /etc/dhcp/dhcpd.conf avec les lignes suivantes :
    ddns-update-style none;

    default-lease-time 600;
    max-lease-time 7200;

    option subnet-mask 255.255.255.0;
    option broadcast-address 192.168.20.255;
    option routers 192.168.20.254;
    option domain-name-servers 192.168.20.254;
    option domain-name "mydomain";

    log-facility local7;

    subnet 192.168.20.0 netmask 255.255.255.0 {
        range 192.168.20.10 192.168.20.100;
    }
  10. L’image que nous allons placer dans la RAM du routeur accédera au serveur NFS de la machine virtuelle pour obtenir son rootfs. Elle devra se trouver sur le disque de la machine virtuelle dans un répertoire nommé /tftpboot/xxx.xxx.xxx.xxx, où xxx.xxx. xxx.xxx est l’adresse IP fournie par le serveur DHCP. Dans mon cas, l’adresse IP du routeur est 192.168.20.11. Configurons le serveur NFS :
    1. Créez le répertoire /tftpboot/192.168.20.11
    2. Ajoutez les lignes suivantes au fichier /etc/exports :
      /tftpboot/192.168.20.11     *(rw,sync,no_subtree_check,no_root_squash)
    3. Mettez à jour le serveur NFS avec ces nouveaux paramètres :
      sudo exportfs -ra

      sudo service nfs-kernel-server restart
    4. J’ai préparé un RootFS avec tous les fichiers binaires de la dernière version du firmware d’origineprêt à être programmé. Téléchargez le fichier « nfs_rootfs_jtag.tar.gz » qui est sur le côté droit de cette page. Décompressez le dans le répertoire « /home/osboxes/TEST ».
    5. Ajoutez les lines suivantes dans le fichier /etc/fstab pour monter le dossier RootFS dans le répertoire partagé à travers le serveur NFS :
      /home/osboxes/TEST/192.168.20.11    /tftpboot/192.168.20.11 none bind,rw 0 0
    6. Pour être sure qu’il n’y aura pas de problème de droit d’accès et comme nous sommes dans une machine virtuelle sur un réseau fermé, ouvrons tous les droits à tout le monde dans le répertoire NFS et faisons qu’il appartienne à root :
      sudo chown -R root:root /tftpboot

      sudo chmod -R 777 /tftpboot
    7. Redémarrez la VM, authentifiez vous et vérifiez que les services nfs-kernel-server et isc-dhcp-server fonctionnent correctement :
      sudo service --status-all
    8. Vérifiez que le répertoire partagé par le serveur NFS est bien partagé :
      ll /tftpboot/192.168.20.11
    9. Maintenant, la VM est prête.
  11. Téléchargez le fichier « zImage_jtag_wrt350n.zip » (milles mercis à DirkNL) qui est disponible sur cette page et décompressez le fichier « zImage.jtag.wrt350n » dans le même répertoire que openocd.exe (dans « bin-x64 » en ce qui me concerne puisque j’utilise Win10 64bits).
  12. Dans le répertoire « ./scripts/board » dans le dossier d’openOCD, créez un fichier texte contenant les lignes suivantes :
    # Linksys WRT350Nv2

    # SoC: Marvell Orion 88F5181 with Feroceon CPU (ARMv5TE)
    #      Documentation at http://www.embeddedarm.com/
    #      under Support -> Documentation -> Third-Party manuals
    #                    -> MV88F5182 files (sister SoC with SATA)

    set CPUTAPID 0x07926041
    source [find target/feroceon.cfg]

    # use RCLK (adaptive clock speed), fallback 3 MHz = 3000KHz
    # (otherwise use "adapter_khz", before 0.5.0 use "jtag_khz", before 0.2.0 use "jtag_speed")
    adapter_khz 1000

    arm7_9 dcc_downloads enable
    arm7_9 fast_memory_access enable

    # define NOR flash bank
    # (TODO: can not be written to, seems some register values are missing in init)
    set _FLASHNAME $_CHIPNAME.flash
    flash bank $_FLASHNAME cfi 0xff800000 0x00800000 1 2 $_TARGETNAME jedec_probe

    init
    ftdi_set_signal PWR_RST 1
    jtag arp_init
  13. Maintenant ouvrez MobaXterm et démarrez une session terminal. Ensuite, allez dans le répertoire de l’exécutable d’openOCD.
  14. Branchez le connecteur JTAG (pas en USB3) et allumez votre routeur. Envoyez cette commande dans le terminal (remplacez l’interface par la vôtre) :
    ./openocd.exe -f "interface/ftdi/xds100v2.cfg" -f "board/wrt350nv2.cfg"
  15. Dans mon cas, j’ai toujours des erreursà la première exécution. Tapez CRTL+C pour terminer le processus et renvoyez la commande. Cela fonctionne sans erreur toujours à la deuxième tentative :
  16. Dans MobaXterm, démarrez une session Telnet sur localhost avec le port 4444 pour se connecter à la ligne de commande d’OpenOCD :
  17. Toujours dans MobaXterm, démarrez une session port série sur le convertisseur USB-série à la vitesse 115200bds.
  18. Maintenant, après toutes ces étapes préparatoires, nous allons charger dans la RAM du WRT350N V2 la zImage pour le faire booter. Tout d’abord, nous devons faire un reset sur le routeur à l’aide du terminal d’OpenOCD pour être dans un état connu :
    reset init
  19. Ensuite, envoyez toutes les commandes suivantes (attention à bien remplacer AABBCCDDEEFF par l’adresse MAC du routeur visible sur l’étiquette de sa face inféireure) dans le terminal d’OpenOCD pour charger la zImage en RAM (MobaXterm accepte de coller du texte, c’est plus rapide). Regardez dans le terminal de MobaXterm : vous devriez voir « 01234 »puis le boot du routeur à partir de sa RAM et du système de fichiers du serveur NFS. A la fin, vous obtenez le prompt.
    #ram latency settings
    feroceon.cpu mww 0xD0001400 0x03148400
    feroceon.cpu mww 0xD0001404 0x04041000
    feroceon.cpu mww 0xD0001408 0x11602220
    feroceon.cpu mww 0xD000140C 0x0000040C
    feroceon.cpu mww 0xD0001410 0x00000000
    feroceon.cpu mww 0xD0001414 0x00000000
    feroceon.cpu mww 0xD0001418 0x00000000
    feroceon.cpu mww 0xD000141C 0x00000062
    feroceon.cpu mww 0xD0001420 0x00000000

    #additional SDRAM settings
    feroceon.cpu mww 0xF10014C0 0x071F128A
    feroceon.cpu mww 0xF10014C4 0x071F128A

    #ram size register settings
    feroceon.cpu mww 0xD0001504 0x01FF0001
    feroceon.cpu mww 0xD000150C 0x00000000
    feroceon.cpu mww 0xD0001510 0x20000000
    feroceon.cpu mww 0xD0001514 0x00000000
    feroceon.cpu mww 0xD000151C 0x00000000

    #ram init
    feroceon.cpu mww 0xD0001480 0x00000001

    #serial setup
    feroceon.cpu mww 0xD001200C 0x83
    feroceon.cpu mww 0xD0012000 0x5A
    feroceon.cpu mww 0xD001200C 0x03

    #serial test
    feroceon.cpu mww 0xD0012000 0x30
    feroceon.cpu mww 0xD0012000 0x31
    feroceon.cpu mww 0xD0012000 0x32
    feroceon.cpu mww 0xD0012000 0x33
    feroceon.cpu mww 0xD0012000 0x34

    #CPU map registers
    feroceon.cpu mww 0xD0020060 0x00FF7941
    feroceon.cpu mww 0xD0020064 0xF0000000

    #cpu pci-e
    feroceon.cpu mww 0xD0020100 0x00000003
    feroceon.cpu mww 0xD0020104 0x00000000

    #interrupt
    feroceon.cpu mww 0xD0020204 0x106203C9

    #mac (NOTE: use value from label on your device for replacing the AABBCCDDEEFF value)
    feroceon.cpu mww 0xD0072418 0xAABBCCDD
    feroceon.cpu mww 0xD0072414 0x0000EEFF

    #gpio
    feroceon.cpu mww 0xD0010100 0x0000006E
    feroceon.cpu mww 0xD0010104 0xFFFFF21C
    feroceon.cpu mww 0xD0010108 0x00000000
    feroceon.cpu mww 0xD001010C 0x00000530
    feroceon.cpu mww 0xD0010110 0x0000054E
    feroceon.cpu mww 0xD0010114 0x00000591
    feroceon.cpu mww 0xD0010118 0x00000000
    feroceon.cpu mww 0xD001011C 0x00000010

    #PCI-e
    feroceon.cpu mww 0xD0041804 0x01FF0001
    feroceon.cpu mww 0xD0041808 0x00000000
    feroceon.cpu mww 0xD004180C 0x00000000
    feroceon.cpu mww 0xD00418F8 0x8000003C
    feroceon.cpu mww 0xD00418FC 0x0000010B

    #PCI
    feroceon.cpu mww 0xD0030D3C 0x00000009
    feroceon.cpu mww 0xD0030C00 0x2107E371
    feroceon.cpu mww 0xD0030C78 0x8001380C
    feroceon.cpu mww 0xD0031D58 0x00000100
    feroceon.cpu mww 0xD004 0x3F2A3B0B

    #PCI/MPP
    feroceon.cpu mww 0xD0031D1C 0x03F3FFFF

    #MPP
    feroceon.cpu mww 0xD0010000 0x00000003
    feroceon.cpu mww 0xD0010004 0x11110010
    feroceon.cpu mww 0xD0010050 0x00001111
    feroceon.cpu mww 0xD0010008 0x03FF0000
    feroceon.cpu mww 0xD0010010 0x10410636

    #NAND flash control register
    feroceon.cpu mww 0xD00104E8 0xFFFF0000

    #register move
    feroceon.cpu mww 0xD0020080 0xF1000000

    load_image ./zImage.jtag.wrt350n 0x00400000 bin
    resume 0x00400000
  20. Dans le terminal du port série, on va vous demander d’appuyer sur « Entrée » et vous obtiendrez le prompt :
  21. Dans le système de fichiers que vous utilisez avec NFS, j’ai préparé dans le dossier « /root » tout le nécessaire pour flasher la mémoire flash du routeur WRT350N V2 avec la dernière version du firmware d’origine de Linksys :
    • Les 4 fichiers binaires dans le dossier « /root/Linksys » pour les partitions rootfs + kernel, lang, nvram et u-boot.
    • Quelques scripts dans « /root » qui permettent de lancer la séquence de programmation (rien de particulier, seulement les commandes « dd » avec les bons mtdblock).

    La seule chose à faire avant de flasher est de modifier le fichier « wrt350_official2.00.20_uboot.bin » dans le dossier « /root/Linksys » pour y écrire l’adresse MAC de votre routeur. Pour ce faire, utilisez votre éditeur HEX préféré (HxD dans mon cas) et allez à l’offset 0x3FFA0 pour écrire les 6 octets écrits sur la plaque signalétique sous votre routeur :

  22. Dès que c’est fait, vous pouvez lancer les scripts de programmation les uns après les autres dans le terminal du port série (ne vous inquiétez pas si vous ne voyez pas de réponse sur le terminal du port série pendant un certain temps, soyez patient):
    cd /root

    ./flash.rootfs
    ./flash.lang
    ./flash.nvram
    ./flash.uboot
  23. Débranchez le JTAG, le port serie, éteignez le routeur, redémarrez-le : votre routeur est de nouveau vivant !
  24. Enjoy !