HP MSM Support

Would anyone be interested in running OpenWRT on HP Enterprise Access Points? I could try to port it if more people are interested

I managed to get access to the internal shell (busybox) (Protected access to shell) (script will follow if people need it) and to decode a firmware package from HP (not sure this is needed (CIM file format)) as well as having a solution to get the AP in recovery mode that will allow us to add OpenWRT to the hardware.

The hardware that I have around is a MSM422 and it has 128MB RAM and 128MB Flash. I still have to find a way to get uboot and see if I can enable the default console to output to the hardware serial port

3 Likes

Count me in.
I have MSC-5100 which I obtained some time ago, didn't have yet much time to poke at it. I assume that this one is similar to Your MSM422 (or at least same architecture: Freescale MPC83xx). If It has CFI flash and NAND flash, the U-Boot resides in CFI and the rest in NAND. You can use pin2pwn trick (https://carvesystems.com/news/pin2pwn-how-to-root-an-embedded-linux-box-with-a-sewing-needle) to enter recovery process. Before powering on, short with needle Address Latch (AL) and Control Latch (CL) pins. You'll enter U-Boot which starts TFTP server waiting for an image. Unfortunately no interaction is possible. As I don't have any resources available (no flash image or flash backup), I didn't check what images it accepts.
I would be interested in the script to access the shell, this will allow me to make flash backup and allow to experiment further.
The CIM format spec would also be important, as maybe that's what U-Boot is expecting to be uploaded to its TFTP server. Also that way the installation of OpenWrt would be easier.

Can you please post your U-Boot (from CF card) somewhere so I can take a look at it? As well it would be great if you can post a bootlog so I can see what goes on in uboot. My device does not respond to serial commands (except a 1 sec window at the beginning of the boot sequence) at all and I am thinking there is a interrupt sequence string that can be found in the u-boot itself

The format for a file that is uploaded via tftp is this:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x30A145D5, created: 1971-03-16 16:53:20, image size: 40011928 bytes, Data Address: 0x500000, Entry Point: 0x500000, data CRC: 0x90D9868A, OS: Linux, CPU: PowerPC, image type: OS Kernel Image, compression type: gzip, image name: "6.5.0.1-19720"
64            0x40            gzip compressed data, maximum compression, has original file name: "dtbImage.nanaimo", from Unix, last modified: 2014-12-06 00:11:03
2021592       0x1ED8D8        Squashfs filesystem, little endian, version 4.0, compression:gzip, size: 37989789 bytes, 31 inodes, blocksize: 131072 bytes, created: 2014-12-06 00:56:26

The cim file is different from the file that is to be uploaded via TFTP in order to do a rescua via tftp.

Below you can find the python script to decode the cim files (at least version 5) (v6 uses AES and I still have to find the key) and using this script you can also generate responses to access the shell via ssh

./script.py --action cim --infile v5.cim --outfile v5.tar
./script.py --action shell --challenge 123456
import argparse
import hashlib

class File:
    def __init__(self):
        pass

    def read(self, path):
        strg = b""
        with open(path, "rb") as f:
            header = f.read(12)
            if header == b"CIM\xc1\x06\xad\xb0\x15\x00\x00\x00\x00":
                print('[*] CIM Header version 6')
                print('[*] AES Encryption not supported ATM')
                exit()
            else:
                print('[*] CIM Header version 5')
                f.seek(0, 0)

                while byte := f.read():
                    strg += byte
        return strg

    def write(self, path, data):
        f = open(path, "wb")
        f.write(data)
        f.close()

class ShellAccess:
    def __init__(self):
        self.challenge_static = b'\xa7\x25\x57\xd1\x90\x0e\x3d\x6b'
        self.sha = hashlib.sha1()

    def generate(self, challenge):
        self.sha.update(bytes(challenge[:3], 'utf-8'))
        self.sha.update(self.challenge_static)
        self.sha.update(bytes(challenge[3:], 'utf-8'))
        digest = self.sha.digest()
        return "%05u" % (digest[3] * digest[13])


class Firmware():
    def __init__(self):
        self.key = '379AeAB93l550g80'

    def crypt_rc4(self, data):
        return self.crypt_rc4_pp(data)

    def crypt_rc4_pp(self, data):
        S = list(range(256))
        j = 0
        key = self.key

        for i in list(range(256)):
            j = (j + S[i] + ord(key[i % len(key)])) % 256
            S[i], S[j] = S[j], S[i]

        j, y = (0, 0)
        out = bytearray()

        for char in data:
            j = (j + 1) % 256
            y = (y + S[j]) % 256
            S[j], S[y] = S[y], S[j]

            out.append(char ^ S[(S[j] + S[y]) % 256])

        return out


parser = argparse.ArgumentParser(description='Colubris/HPE Helper')
parser.add_argument('--action', help='[cim|shell]')
parser.add_argument('--infile', help='input file to decrypt/encrypt')
parser.add_argument('--outfile', help='output file to decrypt/encrypt')
parser.add_argument('--challenge', help='challenge issues by en->sh')
args = parser.parse_args()
if not args.action:
    print('[*] No action given.')
    exit()

if args.action == 'cim':
    if not args.infile or not args.outfile:
        print('[*] Both infile and outfile are needed')
        exit()
    fl = File()
    fw = Firmware()
    data = fw.crypt_rc4(fl.read(args.infile))
    fl.write(args.outfile, data)

if args.action == 'shell':
    sa = ShellAccess()
    print( 'Response: %s' % sa.generate(args.challenge) )

Sorry... not CF card.. CFI Flash. Are you able to read the CFI Contents?
On my MSM422 U-Boot resides on a S29AL004D (4 Megabit CMOS Boot Sector Flash Memory) and I still have to find the adapter for my reader in order to read the memory. If anyone can send me a dump, I can take a look at it and see if there is a way to activate the console at boot time

Yeah, not CF card, although the pin description in datasheet look similar (mines also S29AL004D).
I'm not experienced much in that regard (reading SPI chip with flashrom is easy), so reading out the U-Boot with that kind of chip would be difficult. The best option would be preparing simple kernel initramfs with defined MTD devices, so that would allow us to read it. BTW, have You seen this page: https://oldwiki.archive.openwrt.org/toh/colubris/cn3200? There's an U-Boot dump which have strings which are very similar with the ones U-Boot outputs on my device. I wouldn't be surprised if they used same access methods. For reference this is U-Boot output from my device (sensitive data censored):

^^GO:


Boot 6.5 (Oct 17 2006 - 15:59:22)

NAND: Nandflash_init PPCBOOT 
NAND: Detecting NAND ...
NAND: Device id 00.00
NAND: *** NAND Flash not detected !!!

***** Nand Flash not detected ***** 
Clock configuration:
  Coherent System Bus:  128 MHz
  Core:                 384 MHz
  Local Bus Controller: 128 MHz
  Local Bus:             32 MHz
  DDR:                  256 MHz
  I2C:                  128 MHz
  TSEC1:                128 MHz
  TSEC2:                128 MHz
  USB MPH:               42 MHz
  USB DR:                42 MHz
CPU: MPC83xx,  (43) Rev: 1.1 at 384 MHz
Rev: 11 at 384 MHz
Board: Colubris DragonFly-128
malloc area 7f30000 to 7fc0000, len 90000
bd: 7f2f780
gd: 7f2f724
sp: 7f2f6a8
DRAM:  128 MB
FLASH: 512 kB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
hw_flag=0, bss=7ff3000 (29592 bytes), code=7fc0000 (192512 bytes)
sys_clk=64000000
TSEC0: PHY is Broadcomm 5461S (2060c1)
TSEC1: PHY is Broadcomm 5461S (2060c1)
TSEC0, TSEC1

TSEC0: Link down, half duplex, 0 Mbps
TSEC0: No link.
TSEC0 configured

  Protocol Supported: ARP, ICMP, IP, TCP, UDP, TFTP, DHCP
  Server Ready
watchDogSetup: enabled swcrr:0xffff0007 at ff400204 swcnr:0xffff at ff400208 HW_FLAG  0 
Boot: No valid bid: stay in boot
SENDING DHCP DISCOVER
SENDING DHCP DISCOVER
SENDING DHCP DISCOVER
SENDING DHCP DISCOVER
SENDING DHCP DISCOVER
TSEC0: Link up, full duplex, 1000 Mbps
TSEC0: Link down, half duplex, 0 Mbps
SENDING DHCP DISCOVER
TSEC0: Link up, full duplex, 1000 Mbps
SENDING DHCP DISCOVER
ARP RX  1 source: mac 00:24:be:xx:xx:xx ip 10.42.0.1
ARP       target: mac 00:00:00:00:00:00 ip 10.42.0.121
ARP Packet Dropped: wrong target ip address
ARP RX  1 source: mac 00:24:be:xx:xx:xx ip 10.42.0.1
ARP       target: mac 00:00:00:00:00:00 ip 10.42.0.121
ARP Packet Dropped: wrong target ip address
ARP RX  1 source: mac 00:24:be:xx:xx:xx ip 10.42.0.1
ARP       target: mac 00:00:00:00:00:00 ip 10.42.0.121
ARP Packet Dropped: wrong target ip address
ICMP PACKET RECEIVED
IP Packet Dropped: wrong ip address.10.42.0.121
DHCP PACKET RECEIVED, state=2
DHCP OFFER: ip address.10.42.0.121
DHCP PACKET RECEIVED, state=5
DHCP ACK
ARP RX  1 source: mac 00:24:be:xx:xx:xx ip 10.42.0.1
ARP       target: mac 00:00:00:00:00:00 ip 10.42.0.121

I did try to get U-Boot via it's default linux, but dd segfaults on both v5 and v6 firmware. so either I desolder the s29al004d and find a adapter for my tl866 that can read it or try to get a initramfs that would work. The issue with sending a initramfs would be (at least for me) that I cannot see anything on the console during normal operation, so I would need to redirect the output to serial

CN3200 does not have the strings with In: Out: Err:
I do have a initramfs image but I am still reluctant to try it out :slight_smile: I need to be sure that I can finish everything before I upload it to my AP

So I have some good news. There are two u-boot dumps (of sorts) in the firmware file https://filebin.ca/5mtDbmcblMgi/dfboot-128-ap.bin and https://filebin.ca/5mtDl9Lapm35/dfboot-128-ap-11n.bin
I will take a look at the u-boot files and come back as soon as I have something

I also raised a support ticket with HP for the patches they applied to linux kernel source code and u-boot. If I don't get any response does anyone know where should I send the GPL violation?

So I did debug the u-boot and my problem is that I cannot see anything on my serial output as the serial console I have available is ttyS1 and U-Boot outputs to ttyS0 (which I was not able to find on the board). I would need to get a device that outputs u-boot to serial port that way I can start building openwrt for the device and than port it to MSM422.

I also requested the GPL code from HP but they refused to give it away, and I sent a email attn to their legal department regarding this. I will update this as soon as I have something.

There is a way to activate ash instead of cli at boot time, but I still need to find out how. If the following condition is true, than the serial console is activated instead of cli

"`getbootinfo -x 28 0x80000000`" = "80 00 00 00"
1 Like

So to get u-boot showing stuff and activate the console instead of cli on a MSM422 here are the steps to follow:

  1. login to router via console or ssh
  2. en -> sh -> (and enter the challenge to the script in the posts above)
  3. getbootinfo -x 28 -> you need the output , so write it down
  4. dd if=/dev/bidio of=/ram/bidio
  5. on your machine start a ftp server (on win I use indiftpd.exe as it's portable and small and no user/pass)
  6. curl -T /ram/bidio ftp://ip-of-machine-running-ftp/
  7. hexedit bidio file on your machine and instead of the string you have at step for (for me was 00 00 00 01) it needs to be (80 00 00 00) (on my bid the hex location was starting at 0x54)
  8. copy the file back (curl ftp://ip-of-machine-running-ftp/modified_bidio -o /ram/bidio_new
  9. dd if=/ram/bidio_new of=/dev/bidio
  10. reboot

Yes, that works. Unfortunately in my case U-Boot still doesn't accept any key input, seems like there's either some magic key or the bid file needs altering.

My latest discoveries so far regarding u-boot and hw settings:
80 00 00 00 = 10000000 00000000 00000000 00000000
ab?????? ???????? ???????? ??????cd

a = enable console in linux
b = unknown
c = unknown
d = disable u-boot console
? = have not tested as I have already bricked a board

I have a script that stops autoboot and will post it later on today

Thanks for this information. I've had a MSM460 around since last year which required overwriting the bootloader to install OpenWrt (hence I never submit it upstream).

This works like a charm (autobooting can be interrupted without any additonal step).

Here is the script that is used to interrupt autoboot (it includes the shell access and cim decoder)

python script.py --action stopboot --serial_port COM5

Start the script before powering on the device. At least on MSM422 this is the interrupt sequence that is used here. After the script exists you can connect to the serial port and just hit enter and the U-Boot console will pop up

import argparse
import hashlib
import re
import serial
import serial.tools.list_ports as port_list
import struct

#from Cryptodome.Cipher import AES

class Serial:
    def __init__(self):
        pass

    def list_serial_ports(self):
        ports = list(port_list.comports())
        for p in ports:
            print (p)

    def stop_autoboot(self, serial_port):
        import serial
        import struct
        import re

        s = serial.Serial(serial_port, 115200, xonxoff=False, rtscts=False, dsrdtr=False)
        s.flushInput()
        s.flushOutput()
        read_data = ''
        found_autoboot = False
        print('[*] Looking for Autoboot countdown string on "'+ serial_port +'"')
        while True:
            bytesToRead = s.inWaiting()
            data_raw = s.read(bytesToRead)
            if len(data_raw) > 0:
                read_data += str(data_raw, 'utf-8', 'ignore')
                if re.findall('Autoboot countdown', read_data):
                    if not found_autoboot:
                        print('[*] Found Autoboot countdown string')
                        found_autoboot = True
                if found_autoboot:
                    print('[*] Sending interrupt string')
                    s.write(b'\x01\x0A')

                if re.findall('INTERRUPT', read_data):
                    break
                if re.findall('Unknown command', read_data):
                    break
        print('[*] U-Boot command prompt available. Connect to serial port "' + serial_port + '" using 115200 baud rate')


class File:
    def __init__(self):
        pass

    def read(self, path):
        strg = b""
        with open(path, "rb") as f:
            header = f.read(8)
            if header == b"CIM\xc1\x06\xad\xb0\x15":
                print('[*] CIM Header version 6 (AES)')
                print('[*] AES Encryption not supported ATM')
                exit()

                return decipher.decrypt(strg)
            else:
                print('[*] CIM Header version 5 (RC4)')
                f.seek(0, 0)

                while byte := f.read():
                    strg += byte
        return strg

    def write(self, path, data):
        f = open(path, "wb")
        f.write(data)
        f.close()

class ShellAccess:
    def __init__(self):
        self.challenge_static = b'\xa7\x25\x57\xd1\x90\x0e\x3d\x6b'
        self.sha = hashlib.sha1()

    def generate(self, challenge):
        self.sha.update(bytes(challenge[:3], 'utf-8'))
        self.sha.update(self.challenge_static)
        self.sha.update(bytes(challenge[3:], 'utf-8'))
        digest = self.sha.digest()
        return "%05u" % (digest[3] * digest[13])


class Firmware():
    def __init__(self):
        self.key = '379AeAB93l550g80'

    def crypt_rc4(self, data):
        return self.crypt_rc4_pp(data)

    def crypt_rc4_pp(self, data):
        S = list(range(256))
        j = 0
        key = self.key

        for i in list(range(256)):
            j = (j + S[i] + ord(key[i % len(key)])) % 256
            S[i], S[j] = S[j], S[i]

        j, y = (0, 0)
        out = bytearray()

        for char in data:
            j = (j + 1) % 256
            y = (y + S[j]) % 256
            S[j], S[y] = S[y], S[j]

            out.append(char ^ S[(S[j] + S[y]) % 256])

        return out


parser = argparse.ArgumentParser(description='Colubris/HPE Helper')
parser.add_argument('--action', help='[cim|shell|stopboot]')
parser.add_argument('--infile', help='input file to decrypt/encrypt')
parser.add_argument('--outfile', help='output file to decrypt/encrypt')
parser.add_argument('--challenge', help='challenge issues by en->sh')
parser.add_argument('--serial_port', help='serial port that is used to stop autoboot')

args = parser.parse_args()
if not args.action:
    print('[*] No action given.')
    exit()

if args.action == 'cim':
    if not args.infile or not args.outfile:
        print('[*] Both infile and outfile are needed')
        exit()
    fl = File()
    fw = Firmware()
    data = fw.crypt_rc4(fl.read(args.infile))
    fl.write(args.outfile, data)
elif args.action == 'shell':
    sa = ShellAccess()
    print( 'Response: %s' % sa.generate(args.challenge) )
elif args.action == 'stopboot':
    s = Serial()
    s.stop_autoboot(args.serial_port)

Latest version of the script (I will be waiting for some input if I should go further with this script/openwrt):

To decode CIM v5:

python script.py --action cim --infile cim_v5.cim --outfile cim_v5.tar

To access the shell:

python script.py --action shell --challenge 123456

To stop u-boot (start this before you start the device):

python script.py --action stopboot --serial-port COM5

To stop patch uimage (so that it's accepted by u-boot): (supported devices msm422|msm710|msm430|msm460)

python script.py --action patchheader --infile uImage.img --outfile uImage-patch.img --board-type msm422
import argparse
import hashlib
import re
import serial
import serial.tools.list_ports as port_list
import struct
import zlib
from struct import *

class UBoot:
    def __init__(self):
        self.header_format = '!7L4B32s'
        self.header_size = calcsize(self.header_format)

    def update_header(self, indata, sign_as):
        mx = 32
        indata = bytearray(indata)
        indata[mx:mx+32] = b'\x00' * 32
        indata[mx:mx+16] = b'5.0.0.0-sr9-007'
        if sign_as == 'msm422' or sign_as == 'msm710':
            indata[mx+16:mx+17] = b'\x81\xFF'
            indata[mx+21:mx+22] = b'\x20'
            indata[mx+25:mx+26] = b'\x40'
            indata[mx+28:mx+32] = b'\x51\x2D\x37\x9E'
        elif sign_as == 'msm430':
            indata[mx+16:mx+17] = b'\x82\xFF'
            indata[mx+21:mx+22] = b'\x20'
            indata[mx+25:mx+26] = b'\x40'
            indata[mx+28:mx+32] = b'\x59\xC3\xC9\x8E'
        elif sign_as == 'msm460':
            indata[mx+16:mx+17] = b'\x83\x01'
            indata[mx+21:mx+22] = b'\x20'
            indata[mx+25:mx+26] = b'\x40'
            indata[mx+28:mx+32] = b'\x59\xC3\xC9\xC1'

        hd = self.parse_header(indata[0:64])
        indata[4:8] = self.int_to_bytes(self.calculate_crc(hd), 4)
        print(self.int_to_bytes(self.calculate_crc(hd), 4))
        print(indata[0:64])
        return indata

    def parse_header(self, header_data):
        keys = ['magic', 'headerCrc', 'time', 'size', 'loadAddr', 'entryAddr', 'dataCrc', 'osType', 'arch', 'imageType', 'compression', 'name']

        values = unpack(self.header_format, header_data)
        hd = dict(zip(keys, values))

        if hd['imageType'] == 4:
            hd['files'] = getMultiFileLengths(fh, fh.tell())

        return hd

    def calculate_crc(self, hd):
        header = pack(self.header_format, hd['magic'], 0, hd['time'], hd['size'], hd['loadAddr'], hd['entryAddr'],
            hd['dataCrc'], hd['osType'], hd['arch'], hd['imageType'], hd['compression'], hd['name'])
        return (zlib.crc32(header) & 0xffffffff)

    def int_to_bytes(self, n, minlen=0):
        if n > 0:
            arr = []
            while n:
                n, rem = n >> 8, n & 0xff
                arr.append(rem)
            b = bytearray(reversed(arr))
        elif n == 0:
            b = bytearray(b'\x00')
        else:
            raise ValueError('Only non-negative values supported')

        if minlen > 0 and len(b) < minlen:
            b = (minlen-len(b)) * '\x00' + b
        return b

class Serial:
    def __init__(self):
        pass

    def list_serial_ports(self):
        ports = list(port_list.comports())
        for p in ports:
            print (p)

    def stop_autoboot(self, serial_port):
        s = serial.Serial(serial_port, 115200, xonxoff=False, rtscts=False, dsrdtr=False)
        s.flushInput()
        s.flushOutput()
        read_data = ''
        found_autoboot = False
        print('[*] Looking for Autoboot countdown string on "'+ serial_port +'"')
        while True:
            bytesToRead = s.inWaiting()
            data_raw = s.read(bytesToRead)
            if len(data_raw) > 0:
                read_data += str(data_raw, 'utf-8', 'ignore')
                if re.findall('Autoboot countdown', read_data):
                    if not found_autoboot:
                        print('[*] Found Autoboot countdown string')
                        found_autoboot = True
                if found_autoboot:
                    print('[*] Sending interrupt string')
                    s.write(b'\x01\x0A')

                if re.findall('INTERRUPT', read_data):
                    break
                if re.findall('Unknown command', read_data):
                    break
        print('[*] U-Boot command prompt available. Connect to serial port "' + serial_port + '" using 115200 baud rate')


class File:
    def __init__(self):
        pass

    def simple_read(self, path):
        strg = b""
        with open(path, "rb") as f:
            while byte := f.read():
                strg += byte
        return strg

    def read(self, path):
        strg = b""
        with open(path, "rb") as f:
            header = f.read(8)
            if header == b"CIM\xc1\x06\xad\xb0\x15":
                print('[*] CIM Header version 6 (AES)')
                print('[*] AES Encryption not supported ATM')
                exit()

                return
            else:
                print('[*] CIM Header version 5 (RC4)')
                f.seek(0, 0)

                while byte := f.read():
                    strg += byte
        return strg

    def write(self, path, data):
        f = open(path, "wb")
        f.write(data)
        f.close()

class ShellAccess:
    def __init__(self):
        self.challenge_static = b'\xa7\x25\x57\xd1\x90\x0e\x3d\x6b'
        self.sha = hashlib.sha1()

    def generate(self, challenge):
        self.sha.update(bytes(challenge[:3], 'utf-8'))
        self.sha.update(self.challenge_static)
        self.sha.update(bytes(challenge[3:], 'utf-8'))
        digest = self.sha.digest()
        return "%05u" % (digest[3] * digest[13])


class Firmware():
    def __init__(self):
        self.key = '379AeAB93l550g80'

    def crypt_rc4(self, data):
        return self.crypt_rc4_pp(data)

    def crypt_rc4_pp(self, data):
        S = list(range(256))
        j = 0
        key = self.key

        for i in list(range(256)):
            j = (j + S[i] + ord(key[i % len(key)])) % 256
            S[i], S[j] = S[j], S[i]

        j, y = (0, 0)
        out = bytearray()

        for char in data:
            j = (j + 1) % 256
            y = (y + S[j]) % 256
            S[j], S[y] = S[y], S[j]

            out.append(char ^ S[(S[j] + S[y]) % 256])

        return out


parser = argparse.ArgumentParser(description='Colubris/HPE Helper')
parser.add_argument('--action', help='[cim|shell|stopboot|patchheader]')
parser.add_argument('--infile', help='input file to decrypt/encrypt')
parser.add_argument('--outfile', help='output file to decrypt/encrypt')
parser.add_argument('--challenge', help='challenge issues by en->sh')
parser.add_argument('--serial-port', help='serial port that is used to stop autoboot')
parser.add_argument('--board-type', help='[msm422|msm710|msm430|msm460]')

args = parser.parse_args()
if not args.action:
    print('[*] No action given.')
    exit()

if args.action == 'cim':
    if not args.infile or not args.outfile:
        print('[*] Both infile and outfile are needed')
        exit()
    fl = File()
    fw = Firmware()
    data = fw.crypt_rc4(fl.read(args.infile))
    fl.write(args.outfile, data)
elif args.action == 'shell':
    sa = ShellAccess()
    print( 'Response: %s' % sa.generate(args.challenge) )
elif args.action == 'stopboot':
    s = Serial()
    s.stop_autoboot(args.serial_port)
elif args.action == 'patchheader':
    u = UBoot()
    fl = File()
    fc = fl.simple_read(args.infile)
    lfc = u.update_header(fc, args.board_type)
    fl.write(args.outfile, lfc)

Hi, This is a very interesting project.

I recently got a HP 425 Wireless Dual Radio 802.11n Access Point (JG654A).

The script works for the challenge.

The following command gives the same output:

getbootinfo -x 28
00 00 00 01

EDIT:

I dumped all mtd partitions as well as the bidio.

And the patching worked, too:


Changed it it:

Now this commands all give this answer (before it was 1):

# getbootinfo -x 28
80 00 00 00
# getbootinfo -x 28 0x80000000
80 00 00 00
# getbootinfo -d 29 8
8
# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00400000 00020000 "bw-kernel"
mtd1: 00400000 00020000 "kernel"
mtd2: 01400000 00020000 "bw-slash"
mtd3: 01600000 00020000 "flash"
mtd4: 00100000 00020000 "unused"
mtd5: 048c0000 00020000 "slash"
mtd6: 00010000 00010000 "pf"
mtd7: 000e0000 00010000 "boot"
mtd8: 00020000 00010000 "caldata"
mtd9: 000a0000 00010000 "bootware"
uname -a
Linux 127.0.0.1 2.6.34.1-colubris #1 Thu Jul 2 17:04:25 UTC 2015 mips unknown
# cat /proc/cpuinfo
system type             : Atheros AR934x
processor               : 0
cpu model               : MIPS 74Kc V4.12
BogoMIPS                : 279.55
wait instruction        : yes
microsecond timers      : yes
tlb_entries             : 32
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 4, address/irw mask: [0x0000, 0x0ff8, 0x0ff8, 0x0ff8]
ASEs implemented        : mips16 dsp
shadow register sets    : 1
core                    : 0
VCED exceptions         : not available
VCEI exceptions         : not available

I just haven't figured out how to access the Serial ....

And I just discovered the Warranty is in effect, too, which is great, if I brick it, I can take it to HP.

Any news on this project?

I surfed the internals of this access point, and most if not all of the scripts are referring to MSM series. Seems this model is compatible.

Hi All,

Did anyone manage to flash OpenWRT onto the HP JG654A 425?

I happen to have access to a decent number of decommissioned MSM422 AP's J9359B's and am very interested in getting OpenWRT running on them, I'd be happy to hook up someone doing the serious work towards that goal with a good number of them for the cost of postage.
Needs to be someone capable of actually building and documenting a method of replacing the manufacturer firmware with OpenWRT... Not just someone wanting to score a bunch of free AP's. Reach out if that's you, these are located in QLD, Australia. Thanks.

Unfortunately I cannot continue working on this as I have bricked all 5 MSM422's that I had so until I can find some a bargain on some I won't be able to do anything. And shipping from Australia to Europe is kind of expensive :wink:

I have gotten my hands on 7 of these: https://fccid.io/RTP-MRLBB1003S

I'll be hacking on them in the other HP MSM thread once I receive them.

I had some old HP access points (V-M200 / J9467A / RSVLC-1001) laying around from my old WiFi deployment. I was able to open them up and connect to the UART and poke around. This trick of writing a patched bidio with the updated key worked on this model as well, and now I have access to UBoot. Happy to post any output if it would help anyone.