Installing LEDE-Project on a Cisco Meraki MR24

RussellSenior purchased 9 of these total so far, 8 of them in a batch. The following is a description of how to get a LEDE Project image on them as of 2016-09-18, 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.

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. This method requires a tailored TFTP server (I used a Buffalo WZR600DHP with atftpd installed), along with some customized blobs (three required: an kernel-initramfs.bin, a device tree dtb, and an initramfs blob which isn't actually used but needs to be present to satisfy u-boot). The bootstrap image is configured with sufficient ssh credentials to reach a machine on the network to save copies of the original flash, but otherwise trimmed down to just ethernet and enough tools to manipulated the u-boot environment and the ubi volumes. It also requires a modified device tree to allow the u-boot environment partitions to be written to.

The second version of MR24 firmware is a recovery kernel-initramfs.bin to be written to a recovery ubi volume.

A third version of the MR24 firmware is a regular OpenWrt build that boots from flash normally (i.e. without the reset button held). The second and third firmware images can be stored on the same machine that hosts the flash backups, so that the same ssh credentials can be used to fetch the images.

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. Unfortunately, the package does not come with an init script, so I wrote a simple one:

    # Copyright (C) 2008 OpenWrt.org
    
    START=95
    PIDFILE=/tmp/run/atftpd.pid
    
    start() {
            atftpd --pidfile $PIDFILE --daemon /srv/tftp
    }
    
    stop() {
            kill $(cat $PIDFILE)
    }
    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 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. Minimally, you need three blobs:
    1. uImage -- this can be a regular kernel-initramfs.bin file generated by the OpenWrt build system, including a kernel, embedded initramfs, and device tree binary. The initramfs is actually the one that gets used, not the one described further down in the list. I am not sure which device tree is used. A uImage header is expected.

    2. bluestone.dtb -- this can be extracted from a kernel-initramfs.bin. Before building, the device tree source needs to be modified to allow writing the the two u-boot-env partitions. After building, find the dtb magic number in a resulting kernel-initramfs.bin:
      # hexdump -C /srv/tftp/openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin | grep 'd0 0d fe ed'
      for me, this was at an offset of 0x003f7c0c, the 64512 byte dtd blob was extracted like this:
      # dd if=openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin bs=$((0x003f7c0c)) skip=1 count=1 | dd bs=64512 count=1 of=/tmp/dtb.img
    3. uRamdisk -- this 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 > /tmp/uRamdisk

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_DRIVER_11N_SUPPORT is not set
    # CONFIG_DRIVER_11W_SUPPORT is not set
    CONFIG_PACKAGE_diffutils=y
    # CONFIG_PACKAGE_dnsmasq is not set
    # CONFIG_PACKAGE_firewall is not set
    # CONFIG_PACKAGE_hostapd-common is not set
    # CONFIG_PACKAGE_ip6tables is not set
    # CONFIG_PACKAGE_iptables is not set
    # CONFIG_PACKAGE_iw 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-ip6tables is not set
    # CONFIG_PACKAGE_kmod-ipt-conntrack is not set
    # CONFIG_PACKAGE_kmod-ipt-core is not set
    # CONFIG_PACKAGE_kmod-ipt-nat is not set
    # CONFIG_PACKAGE_kmod-ipt-offload is not set
    # CONFIG_PACKAGE_kmod-lib-crc-ccitt is not set
    # CONFIG_PACKAGE_kmod-mac80211 is not set
    # CONFIG_PACKAGE_kmod-nf-conntrack is not set
    # CONFIG_PACKAGE_kmod-nf-conntrack6 is not set
    # CONFIG_PACKAGE_kmod-nf-flow is not set
    # CONFIG_PACKAGE_kmod-nf-ipt is not set
    # CONFIG_PACKAGE_kmod-nf-ipt6 is not set
    # CONFIG_PACKAGE_kmod-nf-nat is not set
    # CONFIG_PACKAGE_kmod-nf-reject is not set
    # CONFIG_PACKAGE_kmod-nf-reject6 is not set
    # CONFIG_PACKAGE_kmod-ppp is not set
    # CONFIG_PACKAGE_libip4tc is not set
    # CONFIG_PACKAGE_libip6tc is not set
    # CONFIG_PACKAGE_libxtables is not set
    # CONFIG_PACKAGE_odhcp6c is not set
    # CONFIG_PACKAGE_odhcpd-ipv6only is not set
    # CONFIG_PACKAGE_ppp is not set
    CONFIG_PACKAGE_uboot-envtools=y
    # CONFIG_PACKAGE_wpad-basic is not set
    CONFIG_PACKAGE_wireless-regdb=y
  3. Prepare a files overlay:
    1. files/etc/uci-defaults/ptp.defaults
      uci batch <<EOF
      
      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 A stable host key so that ssh'ing to the "bootstrap" device won't trigger a balk from ssh when connecting over the network.
    3. 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)
    4. files/etc/combined.ubootenv Concatenation of files/etc/meraki.ubootenv and files/etc/openwrt.ubootenv
    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/config/system This is the default /etc/config/system with the exception of the hostname, which is changed to "bootstrap". This could probably be moved to the uci-defaults script.
    7. 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
    8. 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/
    9. 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
    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.

Preparing the recovery firmware

Preparing the OpenWrt firmware

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:
    # backup-mtd
    The script is as follows:
    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

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

Instructions for serial console install

WARNING: Currently broken due to a change in the initramfs image construction ... see the OpenWrt wiki page for Meraki MR24 for updated instructions ... will come back and fix this later

  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 investigate PoE (Russell hasn't yet, it's believed to be standard IEEE 802.3at or whatever the modern gigabit compatible version is, but CHECK FIRST). 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 LEDE Project 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 LEDE .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 LEDE 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 LEDE, 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 "lede-apm821xx-nand-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 lede version:
    setenv lede_loadaddr c00000
    setenv lede_loadaddr_kernel c10000
    setenv lede_loadaddr_ramdisk e00000
    setenv lede_loadaddr_fdt c00400
    setenv lede_ubi ubi part ubi
    setenv lede_checkpart meraki checkpart \${lede_loadaddr}
    setenv lede_bootlinux bootm \${lede_loadaddr_kernel} \${lede_loadaddr_ramdisk} \${lede_loadaddr_fdt}
    setenv lede_load1 ubi read \${lede_loadaddr} kernel
    setenv lede_load2 ubi read \${lede_loadaddr} recovery
    setenv lede_bootkernel bootm \${lede_loadaddr_kernel} - \${lede_loadaddr_fdt}
    setenv lede_bootargs setenv bootargs console=ttyS0,\${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
    setenv lede_boot run lede_ubi lede_bootargs\; run lede_load1 lede_checkpart lede_bootkernel\; run lede_load2 lede_checkpart lede_bootlinux
    setenv bootcmd run lede_boot
    setenv ipaddr 192.168.80.49
    setenv serverip 192.168.80.7
    setenv lede_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin
    setenv tftpboot_lede run lede_bootargs\; tftpboot \${lede_loadaddr} \${serverpath}\${lede_bootfile}\; run lede_checkpart lede_bootlinux
    setenv factory_boot run lede_bootargs lede_ubi\; ubi read \${lede_loadaddr} recovery\; run lede_checkpart lede_bootlinux
    saveenv
    or, in fewer lines:
    setenv lede_loadaddr c00000; setenv lede_loadaddr_kernel c10000; setenv lede_loadaddr_ramdisk e00000; setenv lede_loadaddr_fdt c00400; setenv lede_ubi ubi part ubi; setenv lede_checkpart meraki checkpart \${lede_loadaddr}
    setenv lede_bootlinux bootm \${lede_loadaddr_kernel} \${lede_loadaddr_ramdisk} \${lede_loadaddr_fdt}; setenv lede_load1 ubi read \${lede_loadaddr} kernel; setenv lede_load2 ubi read \${lede_loadaddr} recovery 
    setenv lede_bootkernel bootm \${lede_loadaddr_kernel} - \${lede_loadaddr_fdt}; setenv lede_bootargs setenv bootargs console=ttyS0,\${baudrate} rootfstype=squashfs mtdoops.mtddev=oops
    setenv lede_boot run lede_ubi lede_bootargs\; run lede_load1 lede_checkpart lede_bootkernel\; run lede_load2 lede_checkpart lede_bootlinux; setenv bootcmd run lede_boot; setenv ipaddr 192.168.80.49; setenv serverip 192.168.80.7
    setenv lede_bootfile openwrt-apm821xx-nand-meraki_mr24-initramfs-kernel.bin; setenv tftpboot_lede run lede_bootargs\; tftpboot \${lede_loadaddr} \${serverpath}\${lede_bootfile}\; run lede_checkpart lede_bootlinux
    setenv factory_boot run lede_bootargs lede_ubi\; ubi read \${lede_loadaddr} recovery\; run lede_checkpart lede_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_lede
  15. At the lede 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 LEDE boot, this time from flash. You might want to reboot a few times to make sure things went okay.

Tada! You may have succeeded!

Recovery

  1. In order to exploit the recovery partition, from u-boot, run the following command:
    run lede_bootargs lede_ubi; ubi read ${lede_loadaddr} recovery; run lede_checkpart lede_bootlinux
  2. Or, just hold the reset button for a few seconds while powering on


[CategoryHardware] [CategoryVendor]

MerakiMR24 (last edited 2019-09-19 02:47:30 by RussellSenior)