Installing OpenWrt on a Cisco Meraki MR24

RussellSenior and PersonalTelco have separately purchased a bunch of these. The following is a description of how to get an OpenWrt image on them as of 2022-08-01, using Russell's method. The instructions here are mostly derived from here, but adapted and refined a little bit.



Description

The Meraki MR24 is a dual-band, single-ethernet router using a PPC cpu and two ath9k radios with 3x3 MIMO channels. It draws about 7.4 watts, 0.156 amps, at 48V PoE. The MR24 is intended for wall mounting and has a steel backing plate.

Overview

The Meraki MR24 has 32MB of NAND flash. It is formatted as follows:

The general idea is to install two different operating systems:

Two methods for accomplishing this goal ("serial console" and "factory_boot" ) are now presented.

Instructions for serial console install

In this process, the case is opened and u-boot is manipulated from the serial console.

Two MR24 firmwares need to be built:

Two machines are needed:

Preparing the recovery firmware

  1. Pare down a .config to a minimum:
    CONFIG_TARGET_apm821xx=y
    CONFIG_TARGET_apm821xx_nand=y
    CONFIG_TARGET_apm821xx_nand_DEVICE_meraki_mr24=y
    CONFIG_DEVEL=y
    CONFIG_BUILD_LOG=y
    # CONFIG_PACKAGE_ppp is not set
    # CONFIG_PACKAGE_firewall4 is not set
    # CONFIG_PACKAGE_kmod-nft-offload is not set
    CONFIG_PACKAGE_uboot-envtools=y
  2. Prepare a files overlay:
    1. files/etc/uci-defaults/ptp.defaults
      uci batch <<EOF
      set dhcp.@dnsmasq[0].domainneeded=0
      set dhcp.@dnsmasq[0].boguspriv=0
      set dhcp.@dnsmasq[0].localise_queries=0
      set dhcp.@dnsmasq[0].expandhosts=0
      set dhcp.@dnsmasq[0].nohosts=0
      add_list dhcp.@dnsmasq[0].notinterface=eth0
      commit dhcp
      
      delete network.globals
      del_list network.@device[0].ports=eth0
      set network.lan.ipaddr=192.168.11.1
      set network.lan.ip6assign=64
      
      set network.wan=interface
      set network.wan.proto=dhcp
      set network.wan.device=eth0
      
      set network.wan6=interface
      set network.wan6.device='@wan'
      set network.wan6.proto='dhcpv6'
      set network.wan6.reqprefix='60'
      commit network
      
      set system.@system[0].hostname=recovery
      set system.@system[0].timezone='PST8PDT,M3.2.0,M11.1.0'
      commit system
      
      set wireless.radio0.disabled=0
      set wireless.radio1.disabled=0
      set wireless.default_radio0.ssid=RECOVERY
      set wireless.default_radio1.ssid=RECOVERY
      commit wireless
      EOF
    2. files/etc/dropbear/dropbear_rsa_host_key
    3. files/etc/dropbear/dropbear_ed25519_host_key
      • Stable host keys (rsa and ed25519) so that ssh'ing to the "bootstrap" device won't trigger a balk from ssh when connecting over the network.
    4. files/usr/bin/fetch_image.sh
      user=grabber
      dest=dest.mr24
      fname=openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.bin
      
      scp ${user}@${dest}:mr24/images/${fname} /tmp/
    5. files/root/.ssh/known_hosts
      • This is the host public key for dest.mr24 so that we aren't queried on every device
    6. files/root/.ssh/id_dropbear
      • A dropbear ssh private key to allow access a remote server "dest.mr24" without needing a password (add the public key to the remote server's user grabber's .ssh/authorized_keys.

Preparing the OpenWrt firmware

This part depends on the intention for the device, PTP gateway or Dumb AP, or whatever. This is up to you to figure out and, naturally, can change as your needs change.

Installation steps

  1. To open an MR24, first remove 6 screws from around the circumference of the plastic case. The screws are T-6 torx head screws, pretty small, don't lose them ;-). It is a little tricky to free the plastic covers, there are three catches on each long edge and two on each short edge. Starting near the ethernet connector on the long edge with a guitar pick or something similar eventually worked for me.
  2. Once the plastic is removed, you need to remove 4 phillips head screws holding the circuit board to the steel backing plate. Once freed, you will want to rest the board with the antenna down, but suspended in a way that the delicate antenna bits are not bent.
  3. So that the devices do not succeed in phoning home to Meraki World Headquarters, it is recommended to not connect ethernet to the device until you have managed to stop the device at a u-boot prompt.
  4. With the antenna down, and the ethernet jack facing you, the serial console (3.3V TTL) 4 pin header is located at J2 on the right edge about 2/3 of the way to the back, also labelled UART. Only the three closest pins should be connected (from nearest: BLACK (GND), GREEN (board's RX, cable's TX), WHITE (board's TX, cable's RX), NC. Do NOT connect the red wire (it is the 5V USB supply voltage, the NC pin will probably have 3.3V supplied by the board. Again DO NOT connect the red wire from the serial cable.
  5. Configure your serial console software. Russell uses GNU Screen from linux. Plug in your USB-serial 3.3V TTL console cable to your computer, and check "dmesg | tail" to see how the usb-serial device enumerated itself. If it's the only one, it will probably be ttyUSB0. In that case, you can start a console session with: screen /dev/ttyUSB0 115200. It is nice to keep a record of your doings, so turn on logging with: C-a H (if this is your only screen window, your log file will appear in screenlog.0.
  6. Attach a 12V power supply to the barrel jack or 48V PoE. Watch the device begin to boot.
  7. To stop at a u-boot prompt, start pressing the space bar very early. It only pauses for 1 second, but it will recognize a space hit a bit early. You should see something like this:
    U-Boot 2010.06-00036-g4e1a276 Meraki MR24 (May 11 2012 - 16:57:49)
    
    CPU:   AMCC PowerPC  UNKNOWN (PVR=12c41c82) at 800 MHz (PLB=200 OPB=100 EBC=100)
           Bootstrap Option H - Boot ROM Location I2C (Addr 0x52), booting from NAND
           32 kB I-Cache 32 kB D-Cache
    Board: MR24 - Meraki MR24 Cloud Managed Access Point
    ============================
    BoardID: 0 0
    POE-PWR_DET Status: 0
    ADAPTER_DET Status: 1
    Reset Button Status: 1
    ============================
    SDR0_PERCLK=0x40000300
    I2C:   ready
    DRAM:  128 MiB
    I2C write: failed 4
    NAND:  32 MiB
    Configure Max Payload 256B 
    PCIE0: successfully set as root-complex
            03  00  168c  0030  0280  ff
            02  02  111d  8039  0604  00
            04  00  168c  0030  0280  ff
            02  03  111d  8039  0604  00
            01  00  111d  8039  0604  00
    I2C read: failed 4
    I2C write: failed 4
    I2C read: failed 4
    I2C read: failed 4
    I2C write: failed 4
    Net:   ppc_4xx_eth0
    RESET is un-pushed
    
    Set serverpath and run meraki_netboot to netboot
    
    Hit any key to stop autoboot:  0 
  8. For your own reference, type the commands:
    help
    and
    printenv
    If you mess anything up, you can probably restore things by re-entering some of the u-boot environment variables.
  9. You will need two images, an initramfs image and a squashfs-sysupgrade image. You can either obtain these from Russell or perhaps the OpenWrt snapshots, or you can build them yourself. The initramfs image needs to be relatively small in order to fit within some size constraints. It is also used as a recovery image, so something small and simple is preferred. Russell built his vanilla images with the following starting OpenWrt .config file.

    CONFIG_TARGET_apm821xx=y
    CONFIG_TARGET_apm821xx_nand=y
    CONFIG_TARGET_apm821xx_nand_DEVICE_meraki_mr24=y
    CONFIG_DEVEL=y
    CONFIG_BUILD_LOG=y
    # CONFIG_PACKAGE_kmod-lib-crc-ccitt is not set
    # CONFIG_PACKAGE_kmod-ppp is not set
    # CONFIG_PACKAGE_ppp is not set

    Also, you can obtain a files overlay to go with it (recommended) here. The tarball should be unpacked from the OpenWrt build tree at $TOPDIR, so that you get files like $TOPDIR/files/etc/uci-defaults/ptp.defaults. Once unpacked, you can look at the files and modify them as desired. For more details on how to build OpenWrt, see the appropriate documentation or ask Russell lots of questions.

  10. You will need a TFTP server to provide the initramfs image to the device. Russell uses the hpa-tftpd package on a Debian/Ubuntu box. Put your initramfs image, which is named "openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin" in the TFTP servers directory.
  11. From the u-boot prompt, do a test boot of the initramfs image. First, plug in the ethernet cable in such a way that the TFTP server will be reachable. Then apply the following temporary changes to the u-boot environment (they won't be saved until you give u-boot the command: "saveenv"). Substitute IP addresses that make sense for you. The "ipaddr" variable is for the MR24, "serverip" is for your TFTP server.
    setenv ipaddr 192.168.80.49
    setenv serverip 192.168.80.7
    setenv meraki_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
    You can do another printenv to make sure they were set properly. Now try booting your initramfs image like so:
    setenv netloadmethod tftpboot; setenv bootargs console=ttyS0,${baudrate} rootfstype=squashfs mtdoops.mtddev=oops; run meraki_load_net meraki_checkpart meraki_bootlinux
    or the whole thing as two lines:
    setenv ipaddr 192.168.80.49; setenv serverip 192.168.80.7; setenv meraki_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin; setenv netloadmethod tftpboot; setenv bootargs console=ttyS0,${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
    run meraki_load_net meraki_checkpart meraki_bootlinux
    You should see something like this:
    Waiting for PHY auto negotiation to complete.... done
    ENET Speed is 1000 Mbps - FULL duplex connection (EMAC0)
    Using ppc_4xx_eth0 device
    TFTP from server 192.168.80.7; our IP address is 192.168.80.49
    Filename 'openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin'.
    Load address: 0xc00000
    Loading: #################################################################
             #################################################################
             #################################################################
             #################################################################
             #######################################################
    done
    Bytes transferred = 4613120 (466400 hex)
    ## Booting kernel from Legacy Image at 00c10000 ...
       Image Name:   POWERPC OpenWrt Linux-4.14.20
       Created:      2018-02-22  22:40:16 UTC
       Image Type:   PowerPC Linux Kernel Image (lzma compressed)
       Data Size:    1751563 Bytes = 1.7 MiB
       Load Address: 00000000
       Entry Point:  00000000
       Verifying Checksum ... OK
    ## Loading init Ramdisk from Legacy Image at 00e00000 ...
       Image Name:   DEVICE_meraki_mr24 rootfs
       Created:      2018-02-22  22:40:16 UTC
       Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
       Data Size:    2484765 Bytes = 2.4 MiB
       Load Address: 00000000
       Entry Point:  00000000
       Verifying Checksum ... OK
    ## Flattened Device Tree blob at 00c00400
       Booting using the fdt blob at 0xc00400
       Uncompressing Kernel Image ... OK
       Loading Ramdisk to 07910000, end 07b6ea1d ... OK
    [    0.000000] Linux version 4.14.20 (openwrt@hawg) (gcc version 5.5.0 (OpenWrt GCC 5.5.0 r6156-6873cf4f63)) #0 Thu Feb 22 22:40:16 2018
    [    0.000000] Found initrd at 0xc7910000:0xc7b6ea1d
    [    0.000000] Using PowerPC 44x Platform machine description
    [    0.000000] bootconsole [udbg0] enabled
    [    0.000000] -----------------------------------------------------
    [    0.000000] phys_mem_size     = 0x8000000
    [    0.000000] dcache_bsize      = 0x20
    [    0.000000] icache_bsize      = 0x20
    [    0.000000] cpu_features      = 0x0000000010100040
    [    0.000000]   possible        = 0x0000000030100040
    [    0.000000]   always          = 0x0000000000100000
    [    0.000000] cpu_user_features = 0x8c008000 0x00000000
    [    0.000000] mmu_features      = 0x00000008
    [    0.000000] -----------------------------------------------------
    [    0.000000] Zone ranges:
    [    0.000000]   DMA      [mem 0x0000000000000000-0x0000000007ffffff]
    [    0.000000]   Normal   empty
    [    0.000000] Movable zone start for each node
    [    0.000000] Early memory node ranges
    [    0.000000]   node   0: [mem 0x0000000000000000-0x0000000007ffffff]
    [    0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x0000000007ffffff]
    [    0.000000] MMU: Allocated 1088 bytes of context maps for 255 contexts
    [    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 32512
    [    0.000000] Kernel command line: console=ttyS0,115200 rootfstype=squashfs mtdoops.mtddev=oops
    [    0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
    [    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
    [    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
    [    0.000000] Memory: 122080K/131072K available (3708K kernel code, 192K rwdata, 976K rodata, 176K init, 234K bss, 8992K reserved, 0K cma-reserved)
    [...]
  12. Press enter to get a shell prompt, then grab some images and write them off to a persistent storage somewhere to preserve the original state, should you ever want to compare or restore.
    for i in 0 1 2 ; do dd if=/dev/mtdblock$i of=/tmp/mtdblock$i.img ; done
    scp /tmp/mtdblock*.img <myusername>@<myhost>:<mypath>/mr24/stock01/
    rm /tmp/mtdblock*.img
    ubinfo -a > /tmp/ubinfo.txt
    for i in 0 1 2 3 ; do dd if=/dev/ubi0_$i of=/tmp/ubi0_$i.img ; done
    scp /tmp/ubi* <myusername>@<myhost>:<mypath>/mr24/stock01/
  13. Now reboot to a u-boot prompt again (you might want to disconnect ethernet until you are sure you have a u-boot prompt). You may want to do a power cycle too, in order to clear the previous setenv's you have done. Make sure you've got your initramfs and squashfs-sysupgrade images ready. At the u-boot prompt, you are going to create some new environment variables and to repoint the regular boot command at the openwrt version:
    setenv openwrt_loadaddr c00000
    setenv openwrt_loadaddr_kernel c10000
    setenv openwrt_loadaddr_ramdisk e00000
    setenv openwrt_loadaddr_fdt c00400
    setenv openwrt_ubi ubi part ubi
    setenv openwrt_checkpart meraki checkpart \${openwrt_loadaddr}
    setenv openwrt_bootlinux bootm \${openwrt_loadaddr_kernel} \${openwrt_loadaddr_ramdisk} \${openwrt_loadaddr_fdt}
    setenv openwrt_load1 ubi read \${openwrt_loadaddr} kernel
    setenv openwrt_load2 ubi read \${openwrt_loadaddr} recovery
    setenv openwrt_bootkernel bootm \${openwrt_loadaddr_kernel} - \${openwrt_loadaddr_fdt}
    setenv openwrt_bootargs setenv bootargs console=ttyS0,\${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
    setenv openwrt_boot run openwrt_ubi openwrt_bootargs\; run openwrt_load1 openwrt_checkpart openwrt_bootkernel\; run openwrt_load2 openwrt_checkpart openwrt_bootlinux
    setenv bootcmd run openwrt_boot
    setenv ipaddr 192.168.80.49
    setenv serverip 192.168.80.7
    setenv openwrt_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
    setenv tftpboot_openwrt run openwrt_bootargs\; tftpboot \${openwrt_loadaddr} \${serverpath}\${openwrt_bootfile}\; run openwrt_checkpart openwrt_bootlinux
    setenv factory_boot run openwrt_bootargs openwrt_ubi\; ubi read \${openwrt_loadaddr} recovery\; run openwrt_checkpart openwrt_bootlinux
    saveenv
    or, in fewer lines:
    setenv openwrt_loadaddr c00000; setenv openwrt_loadaddr_kernel c10000; setenv openwrt_loadaddr_ramdisk e00000; setenv openwrt_loadaddr_fdt c00400; setenv openwrt_ubi ubi part ubi; setenv openwrt_checkpart meraki checkpart \${openwrt_loadaddr}
    setenv openwrt_bootlinux bootm \${openwrt_loadaddr_kernel} \${openwrt_loadaddr_ramdisk} \${openwrt_loadaddr_fdt}; setenv openwrt_load1 ubi read \${openwrt_loadaddr} kernel; setenv openwrt_load2 ubi read \${openwrt_loadaddr} recovery 
    setenv openwrt_bootkernel bootm \${openwrt_loadaddr_kernel} - \${openwrt_loadaddr_fdt}; setenv openwrt_bootargs setenv bootargs console=ttyS0,\${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
    setenv openwrt_boot run openwrt_ubi openwrt_bootargs\; run openwrt_load1 openwrt_checkpart openwrt_bootkernel\; run openwrt_load2 openwrt_checkpart openwrt_bootlinux; setenv bootcmd run openwrt_boot; setenv ipaddr 192.168.80.49; setenv serverip 192.168.80.7
    setenv openwrt_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin; setenv tftpboot_openwrt run openwrt_bootargs\; tftpboot \${openwrt_loadaddr} \${serverpath}\${openwrt_bootfile}\; run openwrt_checkpart openwrt_bootlinux
    setenv factory_boot run openwrt_bootargs openwrt_ubi\; ubi read \${openwrt_loadaddr} recovery\; run openwrt_checkpart openwrt_bootlinux; saveenv
    Up to now, you have not changed anything on flash, but the change in "bootcmd" means you won't boot the meraki firmware anymore. We are about to change things substantially, so hold tight.
  14. Boot into the initramfs again:
    run tftpboot_openwrt
  15. At the OpenWrt shell prompt, carefully do the following:

    ubinfo /dev/ubi0 -N board-config
    Check to make sure that the Volume ID for board-config is 2. If so, first make a copy of the board-config partition to a file in /tmp/, then remove all the ubi volumes, then create a new one and write the board-config image back:
    dd if=/dev/ubi0_2 of=/tmp/board-config.img
    ubirmvol /dev/ubi0 -N part1
    ubirmvol /dev/ubi0 -N part2
    ubirmvol /dev/ubi0 -N storage
    ubirmvol /dev/ubi0 -N board-config
    ubimkvol /dev/ubi0 -s 24KiB -N board-config
    ubiupdatevol /dev/ubi0_0 /tmp/board-config.img
  16. Copy an initramfs image and the sysupgrade image to the MR24's /tmp/ directory (using scp, either pushing or pulling), e.g., from your build machine:
    scp bin/targets/apm821xx/nand/openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin root@<mr24-ipaddr>:/tmp/
    scp bin/targets/apm821xx/nand/openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.tar root@<mr24-ipaddr>:/tmp/

    Note that the squashfs-sysupgrade image does not need to be the same vanilla build as the initramfs, and can be a full FooCab build. You can use the vanilla version as a proof of concept, and then sysupgrade from that to arbitrary other sysupgrade images. Obviously, this doesn't replace the "recovery" image, flashed in the next step, but that's okay.

  17. On the MR24, check the size of the initramfs image, then if less than 5MB, you can create a recovery ubi partition:
    ls -alh /tmp/openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
    ubimkvol /dev/ubi0 -s 5MiB -N recovery
    ubiupdatevol /dev/ubi0_1 /tmp/openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
  18. Now do a sysupgrade from the initramfs, using the squashfs image:
    sysupgrade -v -n /tmp/openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.tar

    When it is done, it will reboot and hopefully boot back to a familiar looking OpenWrt, this time from flash. You might want to reboot a few times to make sure things went okay.

Instructions for factory_boot install

This method exploits the Meraki MR24 out-of-the-box uboot environment variables to enable a TFTP boot into a bootstrap OpenWrt image, from which the uboot environment can be modified, and the ubi volumes updated over an ssh session without the need to open the case, thus substantially speeding up the operation.

Three MR24 firmwares need to be built:

Two machines are needed:

Preparing the bootstrap firmware

  1. Disable read-only on the u-boot-env partitions (both of them!) in the device tree source in: target/linux/apm821xx/dts/meraki-mr24.dts
  2. Pare down a .config to a minimum:
    CONFIG_TARGET_apm821xx=y
    CONFIG_TARGET_apm821xx_nand=y
    CONFIG_TARGET_apm821xx_nand_DEVICE_meraki_mr24=y
    CONFIG_DEVEL=y
    CONFIG_BUILD_LOG=y
    # CONFIG_BUSYBOX_DEFAULT_FEATURE_IPV6 is not set
    # CONFIG_DRIVER_11N_SUPPORT is not set
    # CONFIG_IPV6 is not set
    # CONFIG_KERNEL_IPV6 is not set
    # CONFIG_LUCI_CSSTIDY is not set
    # CONFIG_LUCI_JSMIN is not set
    # CONFIG_PACKAGE_dnsmasq is not set
    # CONFIG_PACKAGE_hostapd-common is not set
    # CONFIG_PACKAGE_iw is not set
    # CONFIG_PACKAGE_iwinfo is not set
    # CONFIG_PACKAGE_jansson is not set
    # CONFIG_PACKAGE_kmod-ath is not set
    # CONFIG_PACKAGE_kmod-ath9k is not set
    # CONFIG_PACKAGE_kmod-cfg80211 is not set
    # CONFIG_PACKAGE_kmod-crypto-aead is not set
    # CONFIG_PACKAGE_kmod-crypto-ccm is not set
    # CONFIG_PACKAGE_kmod-crypto-cmac is not set
    # CONFIG_PACKAGE_kmod-crypto-crc32c is not set
    # CONFIG_PACKAGE_kmod-crypto-ctr is not set
    # CONFIG_PACKAGE_kmod-crypto-gcm is not set
    # CONFIG_PACKAGE_kmod-crypto-gf128 is not set
    # CONFIG_PACKAGE_kmod-crypto-ghash is not set
    # CONFIG_PACKAGE_kmod-crypto-hash is not set
    # CONFIG_PACKAGE_kmod-crypto-hmac is not set
    # CONFIG_PACKAGE_kmod-crypto-manager is not set
    # CONFIG_PACKAGE_kmod-crypto-null is not set
    # CONFIG_PACKAGE_kmod-crypto-rng is not set
    # CONFIG_PACKAGE_kmod-crypto-seqiv is not set
    # CONFIG_PACKAGE_kmod-crypto-sha256 is not set
    # CONFIG_PACKAGE_kmod-gpio-button-hotplug is not set
    # CONFIG_PACKAGE_kmod-i2c-core is not set
    # CONFIG_PACKAGE_kmod-lib-crc-ccitt is not set
    # CONFIG_PACKAGE_kmod-lib-crc32c is not set
    # CONFIG_PACKAGE_kmod-mac80211 is not set
    # CONFIG_PACKAGE_kmod-nf-conntrack is not set
    # CONFIG_PACKAGE_kmod-nf-flow is not set
    # CONFIG_PACKAGE_kmod-nf-log is not set
    # CONFIG_PACKAGE_kmod-nf-nat is not set
    # CONFIG_PACKAGE_kmod-nf-reject is not set
    # CONFIG_PACKAGE_kmod-nfnetlink is not set
    # CONFIG_PACKAGE_kmod-nft-core is not set
    # CONFIG_PACKAGE_kmod-nft-fib is not set
    # CONFIG_PACKAGE_kmod-nft-nat is not set
    # CONFIG_PACKAGE_kmod-ppp is not set
    # CONFIG_PACKAGE_libiwinfo is not set
    # CONFIG_PACKAGE_libmnl is not set
    # CONFIG_PACKAGE_libnftnl is not set
    # CONFIG_PACKAGE_libucode is not set
    # CONFIG_PACKAGE_libustream-wolfssl is not set
    # CONFIG_PACKAGE_libwolfssl is not set
    # CONFIG_PACKAGE_nftables-json is not set
    # CONFIG_PACKAGE_ppp is not set
    # CONFIG_PACKAGE_ucode is not set
    # CONFIG_PACKAGE_wireless-regdb is not set
    # CONFIG_PACKAGE_wpad-basic-wolfssl is not set
    CONFIG_TARGET_ROOTFS_CPIOGZ=y
    # CONFIG_TARGET_ROOTFS_SQUASHFS is not set
    # CONFIG_WPA_WOLFSSL is not set
  3. Prepare a files overlay:
    1. files/etc/uci-defaults/ptp.defaults
      uci batch <<EOF
      
      set system.@system[0].hostname=bootstrap
      
      commit system 
      
      delete network.globals
      delete network.lan
      
      set network.pub=interface
      set network.pub.ifname=eth0
      set network.pub.proto=dhcp
      
      commit network
      
      EOF
    2. files/etc/dropbear/dropbear_rsa_host_key
    3. files/etc/dropbear/dropbear_ed25519_host_key
      • Stable host keys (rsa and ed25519) so that ssh'ing to the "bootstrap" device won't trigger a balk from ssh when connecting over the network.
    4. files/etc/meraki.ubootenv
      bootdelay 1
      baudrate 115200
      loads_echo 
      preboot echo;echo Set serverpath and run meraki_netboot to netboot;echo
      nload ${netloadmethod} 600000 ${serverpath}u-boot-nand.bin
      nupdate nand erase 0 0x00170000 ;nand write 600000 0 0x00100000
      nupd run nload nupdate
      kernel_addr fc000000
      fdt_addr fc1e0000
      ramdisk_addr fc200000
      pciconfighost 1
      pcie_mode RP:RP
      netdev eth0
      netloadmethod dhcp
      ethact ppc_4xx_eth0
      ethaddr 00:01:73:01:23:41
      boardtype pcie
      mtd_addr_r 0x4000000
      kernel_size 0x400000
      fdt_size 0x25000
      bootcmd run meraki_boot
      meraki_bootargs setenv bootargs root=/dev/ram console=ttyS0,${baudrate} ubi.mtd=ubi MERAKI_BOARD=mr24 mtdoops.mtddev=oops ${extra_bootargs}
      meraki_bootfile mr24.bin
      meraki_bootlinux bootm ${meraki_loadaddr_kernel} ${meraki_loadaddr_ramdisk} ${meraki_loadaddr_fdt}
      meraki_boot run meraki_ubi meraki_bootargs ; run meraki_load1 meraki_checkpart meraki_bootlinux; run meraki_load2 meraki_bootlinux
      meraki_checkpart meraki checkpart ${meraki_loadaddr}
      meraki_netboot run meraki_load_net meraki_bootargs meraki_bootlinux
      meraki_loadaddr c00000
      meraki_loadaddr_kernel c10000
      meraki_loadaddr_fdt c00400
      meraki_loadaddr_ramdisk e00000
      meraki_load1 ubi read ${meraki_loadaddr} part1
      meraki_load2 ubi read ${meraki_loadaddr} part2
      meraki_load_net ${netloadmethod} ${meraki_loadaddr} ${serverpath}${meraki_bootfile}
      meraki_ubi ubi part ubi
      meraki_ubifile mr24-ubi.bin
      meraki_ubi_loadfile ${netloadmethod} 600000 ${serverpath}${meraki_ubifile}
      meraki_ubi_update_nand nand erase 0x00180000 0x01e80000 ; nand write 600000 0x00180000 ${filesize}
      meraki_ubi_update run meraki_ubi_loadfile meraki_ubi_update_nand
      meraki_update_part1 run meraki_ubi meraki_load_net meraki_write1
      meraki_update_part2 run meraki_ubi meraki_load_net meraki_write2
      meraki_write1 ubi write ${meraki_loadaddr} part1 ${filesize}
      meraki_write2 ubi write ${meraki_loadaddr} part2 ${filesize}
      mtdids nand0=nand0
      mtdparts mtdparts=nand0:0x00170000@0(firmware),0x00010000@0x00170000(panic),0x01e80000@0x00180000(ubi)
      ipaddr 192.168.1.1
      serverip 192.168.1.101
      gatewayip 192.168.1.1
      netmask 255.255.255.0
      factory_cmdline setenv bootargs root=/dev/ram ramdisk_size=${factory_ramdisk_size} rw ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off panic=1 console=ttyS1,${baudrate}
      factory_ramdisk_file uRamdisk
      factory_bootfile uImage
      factory_fdt_file bluestone.dtb
      factory_kernel_addr_r 0x600000
      factory_fdt_addr_r 0xa00000
      factory_mtd_addr_r 0x4000000
      factory_ramdisk_size 0x200000
      factory_boot tftp ${factory_kernel_addr_r} ${factory_bootfile};tftp ${factory_fdt_addr_r} ${factory_fdt_file};tftp ${factory_mtd_addr_r} ${factory_ramdisk_file};run factory_cmdline;bootm ${factory_kernel_addr_r} ${factory_mtd_addr_r} ${factory_fdt_addr_r}
      ver U-Boot 2010.06-00036-g4e1a276 Meraki MR24 (May 11 2012 - 16:57:49)
    5. files/etc/openwrt.ubootenv
      openwrt_load ubi read ${meraki_loadaddr} kernel
      openwrt_recovery ubi read ${meraki_loadaddr} recovery;bootm ${meraki_loadaddr}
      openwrt_bootkernel bootm ${meraki_loadaddr_kernel} - ${meraki_loadaddr_fdt}
      openwrt_bootargs setenv bootargs console=ttyS0,${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
      openwrt_boot run meraki_ubi openwrt_bootargs;run openwrt_load meraki_checkpart openwrt_bootkernel;run openwrt_recovery
      openwrt_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
      openwrt_tftp tftpboot ${meraki_loadaddr} ${openwrt_bootfile};run openwrt_bootargs;bootm ${fileaddr}
      bootcmd run openwrt_boot
      factory_boot_orig tftp ${factory_kernel_addr_r} ${factory_bootfile};tftp ${factory_fdt_addr_r} ${factory_fdt_file};tftp ${factory_mtd_addr_r} ${factory_ramdisk_file};run factory_cmdline;bootm ${factory_kernel_addr_r} ${factory_mtd_addr_r} ${factory_fdt_addr_r}
      factory_boot run meraki_ubi;run openwrt_bootargs;run openwrt_recovery
    6. files/etc/combined.ubootenv
      • Concatenation of files/etc/meraki.ubootenv and files/etc/openwrt.ubootenv
    7. files/usr/bin/backup-mtd
      macaddr=$(cat /sys/class/net/eth0/address | tr -d ':')
      user=grabber
      dest=dest.mr24
      
      ssh ${user}@${dest} mkdir mr24/$macaddr
      fw_printenv | sed 's/=/ /' > /tmp/ubootenv.txt
      scp /tmp/ubootenv.txt ${user}@${dest}:mr24/$macaddr/
      for i in 0 1 2 3 4 ; do
              dd if=/dev/mtdblock$i of=/tmp/mtdblock$i.img bs=16k conv=noerror
              scp /tmp/mtdblock$i.img ${user}@${dest}:mr24/$macaddr/
              rm /tmp/mtdblock$i.img
      done
      ubinfo -a > /tmp/ubinfo.txt
      scp /tmp/ubinfo.txt ${user}@${dest}:mr24/$macaddr/
      for i in 0 1 2 3 ; do 
              dd if=/dev/ubi0_$i of=/tmp/ubi0_$i.img bs=15872
              scp /tmp/ubi0_$i.img ${user}@${dest}:mr24/$macaddr/
              rm /tmp/ubi0_$i.img
      done
    8. files/usr/bin/install-recovery
      user=grabber
      dest=dest.mr24
      fname=openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
      
      scp ${user}@${dest}:mr24/images/${fname} /tmp/
      
      if [ -f "/tmp/${fname}" ]; then
              size=$(ls -l /tmp/${fname} | awk '{ print $5 }')
      
              ubirmvol /dev/ubi0 -N part1
              ubirmvol /dev/ubi0 -N part2
              ubirmvol /dev/ubi0 -N storage
              
              if ! ubinfo /dev/ubi0 -N recovery 2>/dev/null > /dev/null ; then 
                      ubimkvol /dev/ubi0 -s ${size} -N recovery
              fi
      
              volid=$(ubinfo /dev/ubi0 -N recovery | awk '$0 ~ /Volume ID/ { print $3 }')
              volsz=$(cat /sys/devices/virtual/ubi/ubi0/ubi0_${volid}/data_bytes)
      
              if [ "$size" -gt "$volsz" ]; then
                      ubirsvol /dev/ubi0 -N recovery -s ${size}
              fi      
      
              ubiupdatevol /dev/ubi0_${volid} /tmp/${fname}
              sync 
              exit 0
      else
              exit 1
      fi
    9. files/usr/bin/fetch_image.sh
      user=grabber
      dest=dest.mr24
      fname=openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.bin
      
      scp ${user}@${dest}:mr24/images/${fname} /tmp/
    10. files/root/.ssh/known_hosts This is the host public key for dest.mr24 so that we aren't queried on every device
    11. files/root/.ssh/id_dropbear A dropbear ssh private key to allow access a remote server "dest.mr24" without needing a password (add the public key to the remote server's user grabber's .ssh/authorized_keys.
  4. After the bootstrap image is created, you will need to prepare the three files that will be served to the MR24 over TFTP:
    1. uImage -- this is just the renamed initramfs binary that OpenWrt builds for you

      $ ln bin/targets/apm821xx/nand/openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin bin/targets/apm821xx/nand/uImage
    2. bluestone.dtb -- this can be extracted from a initramfs.bin. Find the dtb magic number in a resulting initramfs:
      $ binwalk bin/targets/apm821xx/nand/uImage
      
      DECIMAL       HEXADECIMAL     DESCRIPTION
      --------------------------------------------------------------------------------
      0             0x0             uImage header, header size: 64 bytes, header CRC: 0x767534D2, created: 2022-08-08 07:17:37, image size: 3840204 bytes, Data Address: 0x0, Entry Point: 0x0, data CRC: 0x7C3D55D1, OS: Linux, CPU: PowerPC, image type: Multi-File Image, compression type: lzma, image name: "mr24 initramfs"
      80            0x50            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 9385248 bytes
      3775756       0x399D0C        Flattened device tree, size: 64512 bytes, version: 17
      for me, this was at an offset of 3775756 bytes, the 64512 byte dtd blob was extracted like this:
      $ dd if=bin/targets/apm821xx/nand/uImage bs=3775756 skip=1 count=1 | dd bs=64512 count=1 of=bin/targets/apm821xx/nand/bluestone.dtb
    3. uRamdisk -- Due to limitations of the vendor u-boot-env, uRamdisk needs to be 2MB or less. The uRamdisk file needs a uImage header, which can be generated something like this:
      $ staging_dir/host/bin/mkimage -A powerpc -T ramdisk -O linux -d bin/targets/apm821xx/nand/openwrt-apm821xx-nand-rootfs.cpio.gz bin/targets/apm821xx/nand/uRamdisk

Setting up the TFTP server

  1. I used a Buffalo WZR600DHP router, partly because it has a prodigious amount of NOR flash (32MB) that would allow holding the payloads without extra or external storage.
  2. On top of standard OpenWrt, I installed the package atftpd. If you build it into your Buffalo firmware, this init script should be enabled automatically, but if you install from a package repository, you'll need to manually enable it, e.g.:

    # /etc/init.d/atftpd enable
  3. The Meraki u-boot environment assumes a serverip of 192.168.1.101, and an ipaddr of 192.168.1.1. The ipaddr isn't important to the TFTP server, but the server address most definitely is. You can set the LAN ip address of your OpenWrt TFTP server with a command like:

    # uci set network.lan.ipaddr=192.168.1.101
    # uci commit network
    Make sure the network the TFTP server's WAN port is plugged into has a different network than 192.168.1.0/24 or your routing won't work.
  4. Create the directory that will house the TFTP blobs:
    # mkdir -p /srv/tftp
  5. Place the three files:
    1. uImage
    2. bluestone.dtb
    3. uRamdisk into /srv/tftp

Set up the backup/firmware host

To make the process run smoothly, we need an ssh host that can install the public key corresponding to the one installed in the bootstrap and recovery MR24 images. We create a temporary account on the ssh host "grabber", where we can write backups and fetch the recovery image during the bootstrap phase, and where we can fetch the firmware (of your choice) that is installed on the MR24. On an Ubuntu 20.04 machine:

  1. sudo adduser grabber

  2. sudo su - grabber

  3. ssh-keygen -t ed25519 -- this is mainly just to create the .ssh directory with the correct permissions

  4. vi .ssh/authorized_keys --- and insert the public key corresponding to the dropbear private key included in the bootstrap and recovery images. You can obtain the public key using dropbearkey -f /root/.ssh/id_dropbear -y and you'll see a line that looks like: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHDHgF0DNo9+ykxaTcF2KCItlco75qa6yGFJHlaBaDo4 root@recovery

  5. mkdir -p mr24/images

  6. Place the recovery firmware openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin and the final firmware openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.bin in mr24/images

Installation steps

  1. Attach an ethernet cable from the TFTP server to the MR24 to be installed.
  2. With a straightened paper clip or similar device, press and hold the reset button.
  3. Plug in 12V power to the MR24 and continue holding the reset button for approximately 8-10 seconds.
  4. The MR24 should fetch the kernel, dtb and initramfs from the TFTP server and boot. If doing this for the first time, it is wise to disassemble the device and attach a serial console to enable intervention at the u-boot console, if needed. However, note that with the default u-boot environment, the serial console will not function after the tftp'd kernel boots.
  5. Examine the DHCP leases on the network where the MR24 was plugged in. The MR24 uses a preconfigured ipaddr while in u-boot and tftp'ing, but the booted operating system will used DHCP to request a lease. The DHCP leases will indicate which address it was allocated.
  6. Ssh to the indicated address:
    # ssh root@${ipaddr}
    No password is required at this stage.
  7. Save backups of the flash using the backup-mtd script (see above):
    # backup-mtd

    Check to make sure the results make sense. This is your only chance to preserve the original configuration, you may need this later down the road to reconstruct state. It is a REALLY GOOD IDEA to keep these copies and to make sure they are complete.

  8. Examine the ubi, it will look something like this:
    # ubinfo -a
    UBI version:                    1
    Count of UBI devices:           1
    UBI control device major/minor: 10:59
    Present UBI devices:            ubi0
    
    ubi0
    Volumes count:                           4
    Logical eraseblock size:                 15872 bytes, 15.5 KiB
    Total amount of logical eraseblocks:     1952 (30982144 bytes, 29.5 MiB)
    Amount of available logical eraseblocks: 243 (3856896 bytes, 3.6 MiB)
    Maximum count of volumes                 92
    Count of bad physical eraseblocks:       0
    Count of reserved physical eraseblocks:  40
    Current maximum erase counter value:     2976
    Minimum input/output unit size:          512 bytes
    Character device major/minor:            251:0
    Present volumes:                         0, 1, 2, 3
    
    Volume ID:   0 (on ubi0)
    Type:        dynamic
    Alignment:   1
    Size:        567 LEBs (8999424 bytes, 8.5 MiB)
    State:       OK
    Name:        part1
    Character device major/minor: 251:1
    -----------------------------------
    Volume ID:   1 (on ubi0)
    Type:        dynamic
    Alignment:   1
    Size:        567 LEBs (8999424 bytes, 8.5 MiB)
    State:       OK
    Name:        part2
    Character device major/minor: 251:2
    -----------------------------------
    Volume ID:   2 (on ubi0)
    Type:        dynamic
    Alignment:   1
    Size:        2 LEBs (31744 bytes, 31.0 KiB)
    State:       OK
    Name:        board-config
    Character device major/minor: 251:3
    -----------------------------------
    Volume ID:   3 (on ubi0)
    Type:        dynamic
    Alignment:   1
    Size:        529 LEBs (8396288 bytes, 8.0 MiB)
    State:       OK
    Name:        storage
    Character device major/minor: 251:4
  9. Fetch the recovery firmware and prepare the ubi with the /usr/bin/install-recovery script (see above):
  10. Check the state of the u-boot environment:
    # fw_printenv
    Warning: Bad CRC, using default environment
    bootcmd=bootp; setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; bootm
    bootdelay=5
    baudrate=115200
    If you see the "Bad CRC", then use the combined.ubootenv you prepared earlier, to write a full u-boot environment:
    # fw_setenv -s /etc/combined.ubootenv
    Warning: Bad CRC, using default environment
    and then check the result:
    # fw_printenv
    bootdelay=1
    baudrate=115200
    preboot=echo;echo Set serverpath and run meraki_netboot to netboot;echo
    nload=${netloadmethod} 600000 ${serverpath}u-boot-nand.bin
    nupdate=nand erase 0 0x00170000 ;nand write 600000 0 0x00100000
    nupd=run nload nupdate
    kernel_addr=fc000000
    fdt_addr=fc1e0000
    ramdisk_addr=fc200000
    pciconfighost=1
    pcie_mode=RP:RP
    netdev=eth0
    netloadmethod=dhcp
    ethact=ppc_4xx_eth0
    ethaddr=00:01:73:01:23:41
    boardtype=pcie
    mtd_addr_r=0x4000000
    kernel_size=0x400000
    fdt_size=0x25000
    meraki_bootargs=setenv bootargs root=/dev/ram console=ttyS0,${baudrate} ubi.mtd=ubi MERAKI_BOARD=mr24 mtdoops.mtddev=oops ${extra_bootargs}
    meraki_bootfile=mr24.bin
    meraki_bootlinux=bootm ${meraki_loadaddr_kernel} ${meraki_loadaddr_ramdisk} ${meraki_loadaddr_fdt}
    meraki_boot=run meraki_ubi meraki_bootargs ; run meraki_load1 meraki_checkpart meraki_bootlinux; run meraki_load2 meraki_bootlinux
    meraki_checkpart=meraki checkpart ${meraki_loadaddr}
    meraki_netboot=run meraki_load_net meraki_bootargs meraki_bootlinux
    meraki_loadaddr=c00000
    meraki_loadaddr_kernel=c10000
    meraki_loadaddr_fdt=c00400
    meraki_loadaddr_ramdisk=e00000
    meraki_load1=ubi read ${meraki_loadaddr} part1
    meraki_load2=ubi read ${meraki_loadaddr} part2
    meraki_load_net=${netloadmethod} ${meraki_loadaddr} ${serverpath}${meraki_bootfile}
    meraki_ubi=ubi part ubi
    meraki_ubifile=mr24-ubi.bin
    meraki_ubi_loadfile=${netloadmethod} 600000 ${serverpath}${meraki_ubifile}
    meraki_ubi_update_nand=nand erase 0x00180000 0x01e80000 ; nand write 600000 0x00180000 ${filesize}
    meraki_ubi_update=run meraki_ubi_loadfile meraki_ubi_update_nand
    meraki_update_part1=run meraki_ubi meraki_load_net meraki_write1
    meraki_update_part2=run meraki_ubi meraki_load_net meraki_write2
    meraki_write1=ubi write ${meraki_loadaddr} part1 ${filesize}
    meraki_write2=ubi write ${meraki_loadaddr} part2 ${filesize}
    mtdids=nand0=nand0
    mtdparts=mtdparts=nand0:0x00170000@0(firmware),0x00010000@0x00170000(panic),0x01e80000@0x00180000(ubi)
    ipaddr=192.168.1.1
    serverip=192.168.1.101
    gatewayip=192.168.1.1
    netmask=255.255.255.0
    factory_cmdline=setenv bootargs root=/dev/ram ramdisk_size=${factory_ramdisk_size} rw ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off panic=1 console=ttyS1,${baudrate}
    factory_ramdisk_file=uRamdisk
    factory_bootfile=uImage
    factory_fdt_file=bluestone.dtb
    factory_kernel_addr_r=0x600000
    factory_fdt_addr_r=0xa00000
    factory_mtd_addr_r=0x4000000
    factory_ramdisk_size=0x200000
    ver=U-Boot 2010.06-00036-g4e1a276 Meraki MR24 (May 11 2012 - 16:57:49)
    openwrt_load=ubi read ${meraki_loadaddr} kernel
    openwrt_recovery=ubi read ${meraki_loadaddr} recovery;bootm ${meraki_loadaddr}
    openwrt_bootkernel=bootm ${meraki_loadaddr_kernel} - ${meraki_loadaddr_fdt}
    openwrt_bootargs=setenv bootargs console=ttyS0,${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
    openwrt_boot=run meraki_ubi openwrt_bootargs;run openwrt_load meraki_checkpart openwrt_bootkernel;run openwrt_recovery
    openwrt_bootfile=openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
    openwrt_tftp=tftpboot ${meraki_loadaddr} ${openwrt_bootfile};run openwrt_bootargs;bootm ${fileaddr}
    bootcmd=run openwrt_boot
    factory_boot_orig=tftp ${factory_kernel_addr_r} ${factory_bootfile};tftp ${factory_fdt_addr_r} ${factory_fdt_file};tftp ${factory_mtd_addr_r} ${factory_ramdisk_file};run factory_cmdline;bootm ${factory_kernel_addr_r} ${factory_mtd_addr_r} ${factory_fdt_addr_r}
    factory_boot=run meraki_ubi;run openwrt_bootargs;run openwrt_recovery
  11. Reboot into recovery firmware:
    # reboot
  12. Look for the DHCP lease of the device and log in to the recover firmware, and fetch the sysupgrade.bin firmware. For some reason the DNS lookup for the name dest.mr24 which works in the bootstrap firmware does not work in the recovery firmware, so add a line to /etc/hosts with the appropriate ip address, e.g.:
    echo 192.168.80.12 dest.mr24 >> /etc/hosts
    and then run fetch_image2.sh:
    user=grabber
    dest=dest.mr24
    fname=openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.bin
    
    scp ${user}@${dest}:mr24/images/${fname} /tmp/
  13. Use sysupgrade to install the normal OpenWrt firmware:

    # sysupgrade -v -n /tmp/openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.bin
  14. The MR24 will install the firmware and reboot. Look for dhcp leases again and try ssh'ing into the device to confirm success. Try a "factory_boot" with the reset button pressed at power-on to confirm the recovery firmware works as well.
  15. If something went wrong and you can't get access to the device, you will need to open the device to get access to the u-boot prompt. Recovery should be possible from there, though that is left as an exercise for the reader. Hopefully, enough artifacts have been collected to recover. If the u-boot environment is lost or hopelessly mangled, you might be able to erase the blocks where the u-boot environment usually lives to recover (note the address ranges, from dmesg):
    [    1.493402] nand: device found, Manufacturer ID: 0xad, Chip ID: 0x75
    [    1.602330] 0x000000000000-0x000000150000 : "u-boot"
    [    1.603070] 0x000000150000-0x000000160000 : "u-boot-env"
    [    1.603622] 0x000000160000-0x000000170000 : "u-boot-env-redundant"
    [    1.604132] 0x000000170000-0x000000180000 : "oops"
    [    1.604680] 0x000000180000-0x000002000000 : "ubi"

    DO NOT ERASE THE WRONG THINGS.

  16. Having completed the installation of MR24's, disable logins to the grabber account and move the backups somewhere safe for longterm storage.

Updating Recovery Firmware

Over the course of acquiring MR24's, a variety of recovery firmwares have been installed.

  1. (A) kernel 4.4.21 : Sat Sep 17 19:43:29 2016 -- LEDE (old u-boot-env variables);
  2. (B) kernel 4.9.20 : Tue Apr 04 13:06:14 2017 -- LEDE (old u-boot-env variables);
  3. (C) kernel 4.14.20 : Thu Feb 22 22:40:16 2018 -- OpenWrt (old u-boot-env variables);

  4. (D) kernel 4.19.72 : Sat Sep 14 17:38:48 2019 -- OpenWrt (SSID: OpenWrt currrent u-boot-env variables, includes a firewall which makes it unreachable from ethernet side);

As time has passed, shortcomings have been observed in older Recovery Firmware, and corrected in a new Recovery Firmware. The following instructions provide a guide for updating the Recovery Firmware to on MR24s based on the peculiarites in the exsting versions. It assumes that the factory_boot router is available, you are logged into it, and that two firmwares: the replacement recovery.bin and a full featured (including fw_printenv/fw_setenv) normal squashfs-sysupgrade final.bin, and a uboot.env (the combined.ubootenv) are located on the factory_boot router in its /tmp directory.

  1. With power off, hold reset button, apply power, after 5 seconds release.
    1. Alternative if you can't reach the reset button:
      1. Log in to the normal firmware
      2. Check ubi volumes: ubinfo -a

      3. Remove the kernel ubi volume, which should force booting from the Recovery Firmware: ubirmvol /dev/ubi0 -N kernel

  2. Watch for the DHCP lease request from the MR24 with logread -f

  3. If you notice no hostname is advertised on the DHCP lease, you may have firmware (C), in which case you have additional problems, including the firewall is active and won't allow connections from the ethernet side and the LAN side of the MR24 configuration has a conflicting network (192.168.1.0/24). To work around:
    1. Connect wirelessly to the "OpenWrt" network

    2. SSH to the MR24 over wifi: ssh root@192.168.1.1

    3. Stop the firewall: /etc/init.d/firewall stop

    4. To avoid conflicting networks, change the MR24's LAN: uci set network.lan.ipaddr=192.168.2.1

    5. Restart the network: /etc/init.d/network restart

  4. From the factory_boot router, copy all the potentially required files (you may need to adapt the hostname depending on the Recovery Firmware version):
    scp /tmp/recovery.bin /tmp/final.bin /tmp/uboot.env recovery:/tmp/
  5. Log in to the MR24's Recovery Firmware
  6. Check version using uname -a, try running fw_printenv, and check the SSID with iwinfo to held identify what is running, you will need this information soon.

  7. Check the ubi volumes with ubinfo -a, and note the index of the existing "recovery" volume, we will call it: M

  8. Apply the following changes:
    ubirmvol /dev/ubi0 -N rootfs_data
    ubirmvol /dev/ubi0 -N rootfs
    ubirmvol /dev/ubi0 -N kernel
    ubirsvol /dev/ubi0 -S 345 -N recovery
    ubiupdatevol /dev/ubi0_M /tmp/recovery.bin
    Note ubi0_M where M is the ubi volume index.
  9. If the Recovery Firmware is (A) or (B) or possibly (C), the u-boot environment won't successfully boot the new recovery.bin without changes and we need to work around that. The key thing is whether fw_printenv/fw_setenv works and whether there are any "lede" items in the u-boot environment. If there are lede items in the u-boot environment (or if, like (A) and (B), you can't tell), then rebooting now will lead to a brick. Instead:
    1. Flash a regular firmware you login to and run fw_printenv/fw_setenv, with: sysupgrade -v -n /tmp/final.bin, and the MR24 should reboot into the "final.bin" firmware

    2. Watch for the DHCP lease request from the MR24 with logread -f

    3. Copy the clean environment "script" onto the MR24: scp /tmp/uboot.env cat:/tmp/ where "cat" is placeholder name of the rebooted MR24

    4. Login to "cat": ssh cat

    5. Find the lede environment variables you want to remove: fw_printenv | grep lede | cut -d= -f1 > /tmp/lede.env

    6. Concatenate the lede environment variables (since we remove the assignment value from each line, they'll be deleted in the next step) with the desired environment: cat /tmp/lede.env /tmp/uboot-env > /tmp/final.env

    7. Apply the final.env: fw_setenv -s /tmp/final.env

    8. Check the resulting u-boot environment with fw_printenv

    9. Force booting the new Recovery Firmware by removing the "kernel" ubi volume: ubirmvol /dev/ubi0 -N kernel

    10. Now continue with the normal steps
  10. Reboot the MR24 and close the ssh session: reboot ; exit

  11. Watch for the DHCP lease from the newly flashed firmware with logread -f

  12. Login to the new Recovery Firmware: ssh recovery (note, no password is needed)

  13. For some reason, at this stage, DNS resolution doesn't work for the firmware hosting machine (dest.mr24, from the earlier instructions, so setup a /etc/hosts record: echo 192.168.80.12 dest.mr24 >> /etc/hosts

  14. Use the script builtin to the new Recovery Firmware to fetch the new final firmware from dest.mr24: fetch_image2.sh (you will need to accept the host key of the dest.mr24)

  15. Use sysupgrade to flash to final firmware: sysupgrade -v -n /tmp/openwrt-apm821xx-nand-meraki_mr24-squashfs-sysupgrade.bin

  16. Watch for the DHCP lease from the newly flashed firmware with logread -f

  17. You are done!

If you are super careful, you may be able to replace the Recovery Firmware without touching the device, but you will need the MR24 to be accessible over the network. If the MR24 is the gateway device, the Recovery Firmware is not going to have a VPN tunnel, so you will at least need to be on-site.


[CategoryHardware] [CategoryVendor]

MerakiMR24 (last edited 2022-08-10 01:25:44 by RussellSenior)