lglaf/protocol.md
Peter Wu 8f35f2f5b5 More protocol details, add property parser
Example output for parse-props.py:

    download cable             = 'USER'
    battery level              = 100
    download type              = ' '
    download speed             = 0
    usb version                = ' '
    hardware revision          = 'rev_10'
    download sw version        = ' '
    device sw version          = 'D85520t'
    secure device              = 'S'
    laf sw version             = '1.1'
    device factory version     = 'LGD855AT-00-V20t-EUR-XX-AUG-18-2015-16G+0'
    device factory out version = 'LGD855AT-00-V20t-GLOBAL-COM-AUG-18-2015-16G+0'
    pid                        = 'YE01S151002002500'
    imei                       = (redacted)
    model name                 = 'LG-D855'
    device build type          = 'U'
    chipset platform           = 'msm8974'
    target_operator            = 'GLOBAL'
    target_country             = 'COM'
    ap_factory_reset_status    = 3
    cp_factory_reset_status    = 0
    isDownloadNotFinish        = 0
    qem                        = 0
    cupss swfv                 = 'A1439892730-M1439892730-C1439940554-U1439940554-0'
    is one binary dual plan    = 0
    memory size                = 30777344
    memory_id                  = 'SDW16G\n'
    bootloader_ver             = 'MiniOS 3.0'
2015-12-25 15:16:42 +01:00

147 lines
4.5 KiB
Markdown

# LG LAF Protocol
This document is a reverse-engineered protocol description for "LG LAG", the
download mode offered by various LG models. It is based on analysis on the
`Send_Command.exe` utility and `LGD855_20140526_LGFLASHv160.dll` file and a USB
trace using Wireshark and usbmon on Linux. Some commands were found in the
`/sbin/lafd` binary.
## Overview
LAF is a simple request/response protocol operating over USB. The USB details
are described at the end of the document, the messages are described below.
Each message consists of a header, followed by an optional body. The header
contains 32-bit DWORDs, integers are encoded in little-endian form:
| Offset (hex) | Offset (dec) | Type | Description
| ----:| --:| ---
| 0x00 | 0 | char[4] | Command
| 0x04 | 4 | var | Argument 1
| 0x08 | 8 | var | Argument 2
| 0x0c | 12 | var | Argument 3
| 0x10 | 16 | var | Argument 4 (not encountered)
| 0x14 | 20 | int | Body length
| 0x18 | 24 | int | CRC-16
| 0x1c | 28 | char[4] | Bit-wise invertion of command at offset 0
Arguments can be integers or character sequences depending on the command.
The CRC field is the CRC-16-CCITT calculation (LSB-first) over the header and
the body with zeroes in place of CRC.
Each request is followed by a response with a matching command field. If an
error occurs, the response contains command is `FAIL` with argument 1 being the
error code and the original request header as body.
## Commands
### OPEN - Open File
Opens a file path.
Arguments:
- arg1 (response): DWORD file descriptor.
Request body: NUL-terminated file path that should be opened for reading or an
empty string to open `/dev/block/mmcblk0` in read/write mode.
(at most 276 (0x114) bytes?)
Non-existing files result in FAIL with error code 0x80000001.
### CLSE - Close File
Closes a file descriptor which was returned by the `OPEN` command.
Arguments:
- arg1: DWORD file descriptor (same in request and response).
Note: this allows you to close any file descriptor that are in use by the `lafd`
process, not just the one returned by `OPEN`. You can discover the current file
descriptors via `ls -l /proc/$pid/fd` where `$pid` is found by `ps | grep lafd`.
### HELO - Hello
Arguments:
- arg1: DWORD Protocol Version (`\1\0\0\1`) (resp must match req.)
- arg2 (response): Minimum Protocol Version (`\0\0\x80\0` was observed)
### CTRL - Control
Arguments:
- arg1: "RSET" or "ONRS"
Note: `CTRL(RSET)` with no body is sent by the `Send_Command.exe` utility for
the `LEAVE` command.
### WRTE - Write File
Writes to a file descriptor.
Arguments:
- arg1: file descriptor (must be open for writing!)
- arg2: offset in **blocks** (multiple of 512 bytes).
Request body: the data to be written. Can be of any size (including 1 or 513).
Note: writing to a file descriptor which was opened for reading results in FAIL
with code 0x82000002. This command is likely used for writing to partitions.
### READ - Read File
Reads from a file descriptor.
Arguments:
- arg1: file descriptor
- arg2: offset in **blocks** (multiple of 512 bytes).
- arg3: requested length in bytes.
Response body: data in file at given offset and requested length.
Note: be sure not to read past the end of the file (512 * offset + length), this
will hang the communication, requiring a reset (pull out battery)!
### ERSE - Erase
Arguments:
- arg1: ?
- arg2: ?
- arg3: ?
### EXEC - Execute Command
Arguments: none
Request body: NUL-terminated command.
Response body: standard output of the command.
The command is probably split on space and then passes to `execve`. In order to
see standard error, use variables and globbing, use a command such as:
sh -c "$@" -- eval 2>&1 echo $PATH
### INFO
Arguments:
- arg1: action (`GPRO` - Get Properties, `SPRO` - Set Properties)
Request body: must begin with two bytes (`08 0b`).
Response body: 2824 (0xb08) bytes of binary info.
See [scripts/parse-props.py](scripts/parse-props.py) for the structure of the
property body.
### UNLK - Unlock
Arguments: none
### RSVD - Reserved
Arguments: none
### IOCT
Unknown.
### MISC
Unknown.
### KILO
Unknown.
### DIFF
Unknown.
## USB layer
The LG Windows driver (via `LGMobileDriver_WHQL_Ver_4.0.3.exe`) exposes two
serial ports, `LGANDNETMDM0` and `LGANDNETDIAG1`. The `LGANDNETDIAG1` port is
used for LAF.
The LG G3 (D855) has Vendor ID 0x1004 and Product ID 0x633e.
There is only one configuration descriptor and LAF uses bulk transfers over
endpoints 5 (for input from the device) and endpoint 3 (for output to the
device).
For other descriptors, see [info/lsusb.txt](info/lsusb.txt).