Skip to content
Marza4Public

About

Rust Odin protocol implementation for Samsung download mode. Based on Thor and odin4.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rodin — Rust Odin Protocol Implementation

A Rust implementation of the Samsung Odin/LOKE download mode protocol. Based on Thor (C#) and odin4 (C), with full feature parity and additional capabilities.

Overview

rodin communicates with Samsung devices in download mode (04e8:685d) using the Odin/LOKE protocol over USB bulk transfers. It provides a command-line interface for all standard Odin operations plus advanced features like multi-command sessions, device info dumps, and LZ4 support detection.

Key Features

  • Full Odin protocol: Handshake, session management, PIT operations, flashing, reboot
  • Multi-command sessions: Run multiple commands in a single session (Thor-style)
  • Flash + reboot: Atomic flash → reboot in one command
  • Device info dump: Model, serial, region, carrier
  • LZ4 support detection: Detects bootloader LZ4 compression support
  • LZ4 decompression: Automatic decompression of .lz4 files
  • MD5 verification: Verify tar.md5 checksums before flashing
  • Progress display: Real-time progress with speed and ETA
  • Pre-handshake commands: RESET, DVIF (work without session)
  • Recovery mechanism: Automatic recovery for stuck bootloader state

Building

cargo build --release

The binary is at target/release/rodin.

Prerequisites

  • Rust toolchain (rustc, cargo)
  • USBFS mounted at /dev/bus/usb
  • udev rule for Samsung devices:
    SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666"
    
  • cdc_acm kernel module unloaded (or device not auto-claimed)

Usage

Device Discovery

# List all Samsung USB devices
./rodin list

Single Commands

Each command opens a session, executes, and closes the session automatically. After execution, the device reboots to Android mode — use adb reboot download to return to download mode.

# Connect and verify handshake
./rodin connect

# Dump and print PIT table
./rodin pit

# Dump device information (model, serial, region, carrier)
./rodin device-info

# Dump PIT to file
./rodin dump-pit pit.bin

# Flash a PIT file to device
./rodin flash-pit pit.bin

# Flash a file (auto-detect partition from filename)
./rodin flash vbmeta.img

# Flash a file to a specific partition
./rodin flash vbmeta.img --partition VBMETA

# Flash a file with LZ4 decompression
./rodin flash vbmeta.img.lz4 --lz4

# Flash a tar archive
./rodin flash-tar package.tar

# Flash a tar.md5 archive (with MD5 verification)
./rodin flash-tar-md5 BL_G991U1.tar.md5

# Erase a partition
./rodin erase vbmeta 65536

# Factory reset (erase userdata)
./rodin factory-reset

# Reboot device
./rodin reboot

# Reboot to download mode (reboots to Android, use adb reboot download)
./rodin reboot-odin

# Shutdown device
./rodin shutdown

Flash + Reboot

Flash a file and reboot in a single atomic operation:

./rodin flash-reboot vbmeta.img --partition VBMETA

Multi-Command Sessions

Run multiple commands in a single session (Thor-style). The session stays open across all commands, avoiding the bootloader stuck state:

# Dump device info and PIT in one session
./rodin session -c device-info -c pit

# Flash and reboot in one session
./rodin session -c "flash?file=vbmeta.img&partition=VBMETA" -c reboot-odin

# Flash tar and reboot
./rodin session -c "flash-tar?tar=package.tar" -c reboot

# Multiple commands with options
./rodin session \
  -c "option?name=efsclear&value=true" \
  -c "flash?file=vbmeta.img&partition=VBMETA" \
  -c reboot-odin

Session action formats:

Action Format
pit pit
device-info device-info
dump-pit dump-pit?output=pit.bin
flash flash?file=path&partition=name&lz4=true
flash-tar flash-tar?tar=path&lz4=true
flash-tar-md5 flash-tar-md5?tar=path&lz4=true
erase erase?partition=name&size=65536
factory-reset factory-reset
reboot reboot
reboot-odin reboot-odin
shutdown shutdown
option option?name=efsclear&value=true
set-region set-region?code=XYZ

Flash Options

# Set EFS clear
./rodin options efsclear true

# Set bootloader update
./rodin options blupdate true

# Enable T-Flash
./rodin options tflash true

# Disable reset flash count
./rodin options resetfc false

# Show current value
./rodin options efsclear

Region Code

# Set 3-character region code
./rodin set-region XYZ

Raw I/O

# Raw write (string)
./rodin raw-write string "ODIN"

# Raw write (integers)
./rodin raw-write int 0x64 0x00

# Raw write (hex bytes)
./rodin raw-write bytes 64 00 00 00

# Raw read
./rodin raw-read 1024

Pre-Handshake Commands

These commands work without a session (before ODIN/LOKE handshake):

# Send RESET command (device may reboot)
./rodin pre-cmd reset

# Send DVIF command (device info)
./rodin pre-cmd dvif

Device Path

All commands accept an optional --device flag to specify the USB device path:

./rodin flash vbmeta.img --device /dev/bus/usb/003/009

If omitted, the first Samsung device found is used.

Session Lifecycle

Open USB → Claim Interface → Clear Halt → Handshake (ODIN/LOKE)
  → BeginSession (0x64/0x00) → SendFilePartSize (0x64/0x05, v2+)
  → Commands (PIT, Flash, Options, etc.)
  → EndSession (0x67/0x00) → RebootToOdin (0x67/0x02)
  → Release Interface → Close FD

Session cleanup: After each command, EndSession + RebootToOdin is sent automatically via Drop. This properly closes the session on the bootloader side and reboots the device to Android mode. Use adb reboot download to return to download mode.

Terminal commands (reboot, reboot-odin, shutdown) call EndSession internally before sending the reboot command.

Multi-command sessions (session) keep the session open across all commands. EndSession + RebootToOdin is sent when the session ends (or when a terminal command is executed).

Protocol Reference

The Odin/LOKE protocol uses USB bulk transfers on the CDC-Data interface (class 0x0a). All commands are sent as 1024-byte packets with a 4-byte region code and 4-byte sub-command at the start. Responses are 8 bytes: [0x00..0xFE, 0x00, 0x00, 0x00, <data...>] on success, or [0xFF, 0x00, 0x00, 0x00, <error_code>] on failure.

Handshake

  1. Host sends ODIN (4 bytes) via bulk write
  2. Device responds with LOKE (4 bytes) via bulk read

Session Commands (Region 0x64)

Sub-command Name Description
0x00 BeginSession Start session, returns bootloader version
0x01 ResetFlashCount Reset flash counter
0x02 SetTotalBytes Set total bytes to flash (8-byte LE value at offset 8)
0x05 SetPacketSize Set packet size (4-byte LE value at offset 8)
0x07 EraseUserData Erase userdata partition (factory reset)
0x08 EnableTFlash Enable T-Flash mode
0x08 SetRegionCode Set region code (3-char ASCII at offset 8)

Flash Commands (Region 0x66)

Sub-command Name Description
0x00 RequestFileFlash Initialize file flash operation
0x02 RequestSequence Request sequence flash (4-byte LE size at offset 8)
0x03 EndSequence Complete sequence flash

EndSequence payload (offset 8+):

  • Bytes 8-11: 0x00 (phone firmware) or 0x01 (modem firmware)
  • Bytes 12-15: Real data size (LE)
  • Bytes 16-19: Binary type (from PIT)
  • Bytes 20-23: Device type (from PIT)
  • Bytes 24-27: Partition ID (from PIT, phone only)
  • Bytes 28-31: Is last sequence (0 or 1, phone only)
  • Bytes 32-35: EFS clear (0 or 1, phone only)
  • Bytes 36-39: Bootloader update (0 or 1, phone only)

PIT Commands (Region 0x65)

Sub-command Name Description
0x00 RequestPitFlash Initialize PIT flash
0x01 RequestPitDump Request PIT dump, returns size
0x02 ReadPitBlock Read 500-byte block (block index at offset 8)
0x02 BeginPitFlash Begin PIT flash (size at offset 8)
0x03 EndPitDump Complete PIT dump
0x03 EndPitFlash Complete PIT flash

Device Info Commands (Region 0x69)

Sub-command Name Description
0x00 RequestDevInfo Request device info dump, returns size
0x01 ReadDevInfoBlock Read 500-byte block (block index at offset 8)
0x02 EndDevInfo Complete device info dump

Device info response format:

  • Header: magic (0x12345678), entry count, location array, data array
  • Location entry: type (4), offset (4), size (4)
  • Data entry: type (4), size (4), raw data
  • Types: 0x00=Model, 0x01=Serial, 0x02=Region Code, 0x03=Carrier ID

Session End Commands (Region 0x67)

Sub-command Name Description
0x00 EndSession End session
0x01 Reboot Reboot device
0x02 RebootToOdin Reboot to download mode (reboots to Android)
0x03 Shutdown Shutdown device

Error Codes

Code Meaning
-2 Write Protect
-3 Erase
-4 Write
-5 Auth
-6 Size
-7 Ext4

Architecture

rodin
├── USB Device Layer (usb.rs)
│   ├── Device discovery (scans /dev/bus/usb)
│   ├── Descriptor parsing (finds CDC-Data interface)
│   ├── Interface claiming (ioctl USBDEVFS_CLAIMINTERFACE)
│   ├── Bulk write/read (ioctl USBDEVFS_BULK)
│   ├── Control transfer (ioctl USBDEVFS_CONTROL)
│   └── Clear halt (ioctl USBDEVFS_CLEAR_HALT)
│
├── Odin Protocol Layer (odin.rs)
│   ├── Handshake (ODIN/LOKE)
│   ├── Session management (begin/end)
│   ├── LZ4 support detection (bit 0x8000 of version)
│   ├── Device info dump (model, serial, region, carrier)
│   ├── PIT dump/parse/flash
│   ├── File flashing (sequences, packets, progress)
│   ├── Partition erase (zero-fill flash)
│   ├── Factory reset (erase userdata)
│   ├── Flash options (EFS clear, BL update, T-Flash)
│   ├── Region code (set region)
│   ├── Raw I/O (raw write/read)
│   ├── LZ4 decompression (automatic for .lz4 files)
│   ├── MD5 verification (tar.md5 packages)
│   ├── Reboot/shutdown
│   └── Recovery (EndSession + RebootToOdin)
│
├── PIT Parser (pit.rs)
│   ├── Magic number validation (0x12349876)
│   ├── Entry parsing (partition info)
│   └── Lookup by filename/partition
│
├── Progress Tracking (progress.rs)
│   ├── Real-time progress display
│   ├── Transfer speed calculation
│   └── ETA estimation
│
└── CLI (main.rs)
    ├── list, connect, device-info, pit, dump-pit, flash-pit
    ├── flash, flash-tar, flash-tar-md5, flash-reboot
    ├── erase, factory-reset, options, set-region
    ├── raw-write, raw-read, reboot, reboot-odin, shutdown
    ├── session (multi-command, Thor-style)
    └── pre-cmd (pre-handshake: reset, dvif)

Feature Comparison

Feature Thor odin4 rodin
Handshake (ODIN/LOKE) ✅ ✅ ✅
Session management ✅ ✅ ✅
PIT dump/print ✅ ✅ ✅
PIT dump to file ✅ ❌ ✅
PIT flash ✅ ❌ ✅
Flash file ✅ ✅ ✅
Flash tar ✅ ✅ ✅
Flash tar.md5 ✅ ✅ ✅
LZ4 decompression ✅ ✅ ✅
MD5 verification ❌ ✅ ✅
Erase partition ✅ ✅ ✅
Factory reset ✅ ❌ ✅
Flash options ✅ ✅ ✅
EFS clear ✅ ✅ ✅
Bootloader update ✅ ✅ ✅
T-Flash ✅ ❌ ✅
Reset flash count ✅ ❌ ✅
Set region code ✅ ❌ ✅
Raw write ✅ ❌ ✅
Raw read ✅ ❌ ✅
Progress display ✅ ✅ ✅
Reboot ✅ ✅ ✅
Reboot to download mode ✅ ✅ ✅
Flash + reboot (single session) ❌ ❌ ✅
Multi-command session (Thor-style) ✅ ❌ ✅
Shutdown ❌ ❌ ✅
MODEM EndSequence layout ✅ ✅ ✅
EraseUserData timeout (10 min) ✅ ✅ ✅
Device listing ❌ ✅ ✅
Device info dump ❌ ❌ ✅
LZ4 support detection implicit ❌ ✅
Pre-handshake commands (RESET, DVIF) ❌ ❌ ✅
Automatic session cleanup implicit ❌ ✅
Stuck bootloader recovery ❌ ❌ ✅

USBFS Struct Layout (64-bit)

rodin uses Linux USBFS ioctls directly. On 64-bit systems, usbdevfs_bulktransfer and usbdevfs_ctrltransfer are 24 bytes due to pointer alignment padding:

struct usbdevfs_bulktransfer {
    __u32 ep;           // offset 0
    __u32 len;          // offset 4
    __u32 timeout;      // offset 8
    __u32 actual_length; // offset 12 (kernel returns via ioctl retval)
    void *data;         // offset 16 (8-byte aligned, 4 bytes padding before)
};
// Total: 24 bytes (not 20)

rodin includes compile-time assertions to prevent future drift:

assert!(std::mem::size_of::<usb_bulk_transfer>() == 24);
assert!(std::mem::size_of::<usb_control_transfer>() == 24);

USBFS Test Utility

A companion Python script is available at ../usbfs_test.py for low-level USBFS testing:

# Get device descriptor
python3 usbfs_test.py /dev/bus/usb/003/009 get-descriptor

# ODIN/LOKE handshake
python3 usbfs_test.py /dev/bus/usb/003/009 handshake

# Full session (handshake + begin + end + reboot)
python3 usbfs_test.py /dev/bus/usb/003/009 full

# Pre-handshake commands
python3 usbfs_test.py /dev/bus/usb/003/009 dvif
python3 usbfs_test.py /dev/bus/usb/003/009 reset-cmd

License

MIT

About

Rust Odin protocol implementation for Samsung download mode. Based on Thor and odin4.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages