Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mass_storage/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ App(
],
stack_size=2 * 1024,
fap_description="Implements a mass storage device over USB for disk images",
fap_version="1.4",
fap_version="1.5",
fap_icon="assets/floppydisk_10px.png",
fap_icon_assets="assets",
fap_category="USB",
Expand Down
52 changes: 46 additions & 6 deletions mass_storage/helpers/mass_storage_scsi.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "mass_storage_scsi.h"

#include <core/log.h>
#include <string.h>

#define TAG "MassStorageSCSI"

Expand All @@ -15,6 +16,8 @@
#define SCSI_START_STOP_UNIT (0x1B)
#define SCSI_WRITE_10 (0x2A)

#define SCSI_MIN(a, b) ((a) < (b) ? (a) : (b))

bool scsi_cmd_start(SCSISession* scsi, uint8_t* cmd, uint8_t len) {
if(!len) {
scsi->sk = SCSI_SK_ILLEGAL_REQUEST;
Expand Down Expand Up @@ -121,9 +124,36 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t
data[5] = 0; // flags
data[6] = 0; // flags
data[7] = 0; // flags
memcpy(data + 8, "Flipper ", 8); // vendor id
memcpy(data + 16, "Mass Storage ", 16); // product id
memcpy(data + 32, "0001", 4); // product revision level

// Clear fields with spaces (SCSI standard padding)
memset(data + 8, ' ', 8); // vendor id
memset(data + 16, ' ', 16); // product id
memset(data + 32, ' ', 4); // revision

// Use configurable vendor ID
if(scsi->config && scsi->config->scsi_vendor_id) {
size_t vendor_len = SCSI_MIN(strlen(scsi->config->scsi_vendor_id), 8);
memcpy(data + 8, scsi->config->scsi_vendor_id, vendor_len);
} else {
memcpy(data + 8, "Flipper ", 8); // default
}

// Use configurable product ID
if(scsi->config && scsi->config->scsi_product_id) {
size_t product_len = SCSI_MIN(strlen(scsi->config->scsi_product_id), 16);
memcpy(data + 16, scsi->config->scsi_product_id, product_len);
} else {
memcpy(data + 16, "Mass Storage ", 16); // default
}

// Use configurable revision
if(scsi->config && scsi->config->scsi_revision) {
size_t revision_len = SCSI_MIN(strlen(scsi->config->scsi_revision), 4);
memcpy(data + 32, scsi->config->scsi_revision, revision_len);
} else {
memcpy(data + 32, "0001", 4); // default
}

*len = 36;
scsi->tx_done = true;
return true;
Expand All @@ -135,9 +165,19 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t
data[0] = 0x00;
data[1] = 0x80;
data[2] = 0x00;
data[3] = 0x01; // Serial len
data[4] = '0';
*len = 5;

// Use configurable serial number
if(scsi->config && scsi->config->scsi_serial) {
size_t serial_len = strlen(scsi->config->scsi_serial);
data[3] = serial_len; // Serial len
memcpy(data + 4, scsi->config->scsi_serial, serial_len);
*len = 4 + serial_len;
} else {
data[3] = 0x01; // Serial len
data[4] = '0'; // default serial
*len = 5;
}

scsi->tx_done = true;
return true;
}
Expand Down
13 changes: 13 additions & 0 deletions mass_storage/helpers/mass_storage_scsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
#define SCSI_ASC_LBA_OOB (0x21)
#define SCSI_ASC_INVALID_FIELD_IN_CDB (0x24)

typedef struct {
char* scsi_vendor_id; // 8 chars max
char* scsi_product_id; // 16 chars max
char* scsi_revision; // 4 chars max
char* scsi_serial; // Variable length
char* usb_manufacturer; // Variable length
char* usb_product; // Variable length
char* usb_serial; // Variable length
uint16_t usb_vendor_id; // USB VID
uint16_t usb_product_id; // USB PID
} MassStorageConfig;

typedef struct {
void* ctx;
bool (*read)(
Expand All @@ -27,6 +39,7 @@ typedef struct {
typedef struct {
SCSIDeviceFunc fn;

const MassStorageConfig* config;
uint8_t* cmd;
uint8_t cmd_len;
bool rx_done;
Expand Down
123 changes: 99 additions & 24 deletions mass_storage/helpers/mass_storage_usb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "mass_storage_usb.h"
#include <furi_hal.h>
#include <string.h>
#include <stdlib.h>

#define TAG "MassStorageUsb"

Expand Down Expand Up @@ -59,13 +61,19 @@ struct MassStorageUsb {
FuriThread* thread;
usbd_device* dev;
SCSIDeviceFunc fn;
const MassStorageConfig* config;

// Dynamically allocated descriptors
struct usb_device_descriptor* dev_descr;
struct usb_string_descriptor* str_manuf_descr;
};

static int32_t mass_thread_worker(void* context) {
MassStorageUsb* mass = context;
usbd_device* dev = mass->dev;
SCSISession scsi = {
.fn = mass->fn,
.config = mass->config,
};
CBW cbw = {0};
CSW csw = {0};
Expand Down Expand Up @@ -298,10 +306,14 @@ static void usb_deinit(usbd_device* dev) {
furi_thread_free(mass->thread);
mass->thread = NULL;

free(mass->usb.str_manuf_descr);
mass->usb.str_manuf_descr = NULL;
free(mass->usb.str_prod_descr);
mass->usb.str_prod_descr = NULL;
free(mass->usb.str_serial_descr);
mass->usb.str_serial_descr = NULL;
free(mass->dev_descr);
mass->dev_descr = NULL;
free(mass);
}

Expand Down Expand Up @@ -366,16 +378,14 @@ static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal
return usbd_fail;
}

static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc.");

struct MassStorageDescriptor {
struct usb_config_descriptor config;
struct usb_interface_descriptor intf;
struct usb_endpoint_descriptor ep_rx;
struct usb_endpoint_descriptor ep_tx;
} __attribute__((packed));

static const struct usb_device_descriptor usb_mass_dev_descr = {
static const struct usb_device_descriptor usb_mass_dev_descr_template = {
.bLength = sizeof(struct usb_device_descriptor),
.bDescriptorType = USB_DTYPE_DEVICE,
.bcdUSB = VERSION_BCD(2, 0, 0),
Expand Down Expand Up @@ -436,42 +446,107 @@ static const struct MassStorageDescriptor usb_mass_cfg_descr = {
},
};

MassStorageUsb* mass_storage_usb_start(const char* filename, SCSIDeviceFunc fn) {
static struct usb_string_descriptor* create_string_descriptor(const char* str) {
if(!str) return NULL;

size_t len = strlen(str);
struct usb_string_descriptor* desc = malloc(len * 2 + 2);
if(!desc) return NULL;

desc->bLength = len * 2 + 2;
desc->bDescriptorType = USB_DTYPE_STRING;
for(size_t i = 0; i < len; i++) {
desc->wString[i] = str[i];
}
return desc;
}

MassStorageUsb* mass_storage_usb_start(
const char* filename,
SCSIDeviceFunc fn,
const MassStorageConfig* config) {
MassStorageUsb* mass = malloc(sizeof(MassStorageUsb));
if(!mass) return NULL;

mass->config = config;
mass->usb_prev = furi_hal_usb_get_config();

// Create a copy of the device descriptor template that we can modify
mass->dev_descr = malloc(sizeof(struct usb_device_descriptor));
if(!mass->dev_descr) {
free(mass);
return NULL;
}
memcpy(mass->dev_descr, &usb_mass_dev_descr_template, sizeof(struct usb_device_descriptor));

// Update USB VID/PID from config
if(config) {
if(config->usb_vendor_id != 0) {
mass->dev_descr->idVendor = config->usb_vendor_id;
}
if(config->usb_product_id != 0) {
mass->dev_descr->idProduct = config->usb_product_id;
}
}

mass->usb.init = usb_init;
mass->usb.deinit = usb_deinit;
mass->usb.wakeup = usb_wakeup;
mass->usb.suspend = usb_suspend;
mass->usb.dev_descr = (struct usb_device_descriptor*)&usb_mass_dev_descr;
mass->usb.str_manuf_descr = (void*)&dev_manuf_desc;
mass->usb.dev_descr = mass->dev_descr;
mass->usb.str_manuf_descr = NULL;
mass->usb.str_prod_descr = NULL;
mass->usb.str_serial_descr = NULL;
mass->usb.cfg_descr = (void*)&usb_mass_cfg_descr;

const char* name = furi_hal_version_get_device_name_ptr();
if(!name) name = "Flipper Zero";
size_t len = strlen(name);
struct usb_string_descriptor* str_prod_descr = malloc(len * 2 + 2);
str_prod_descr->bLength = len * 2 + 2;
str_prod_descr->bDescriptorType = USB_DTYPE_STRING;
for(uint8_t i = 0; i < len; i++)
str_prod_descr->wString[i] = name[i];
mass->usb.str_prod_descr = str_prod_descr;

len = strlen(filename);
struct usb_string_descriptor* str_serial_descr = malloc(len * 2 + 2);
str_serial_descr->bLength = len * 2 + 2;
str_serial_descr->bDescriptorType = USB_DTYPE_STRING;
for(uint8_t i = 0; i < len; i++)
str_serial_descr->wString[i] = filename[i];
mass->usb.str_serial_descr = str_serial_descr;
// Create manufacturer string descriptor
const char* manufacturer = NULL;
if(config && config->usb_manufacturer) {
manufacturer = config->usb_manufacturer;
} else {
manufacturer = "Flipper Devices Inc.";
}
mass->usb.str_manuf_descr = create_string_descriptor(manufacturer);
if(!mass->usb.str_manuf_descr) {
free(mass->dev_descr);
free(mass);
return NULL;
}

// Create product string descriptor
const char* product_name = NULL;
if(config && config->usb_product) {
product_name = config->usb_product;
} else {
product_name = furi_hal_version_get_device_name_ptr();
if(!product_name) product_name = "Flipper Zero";
}
mass->usb.str_prod_descr = create_string_descriptor(product_name);
if(!mass->usb.str_prod_descr) {
free(mass->usb.str_manuf_descr);
free(mass->dev_descr);
free(mass);
return NULL;
}

// Create serial string descriptor
const char* usb_serial = (config && config->usb_serial) ? config->usb_serial : filename;
mass->usb.str_serial_descr = create_string_descriptor(usb_serial);
if(!mass->usb.str_serial_descr) {
free(mass->usb.str_prod_descr);
free(mass->usb.str_manuf_descr);
free(mass->dev_descr);
free(mass);
return NULL;
}

mass->fn = fn;
if(!furi_hal_usb_set_config(&mass->usb, mass)) {
FURI_LOG_E(TAG, "USB locked, cannot start Mass Storage");
free(mass->usb.str_prod_descr);
free(mass->usb.str_serial_descr);
free(mass->usb.str_prod_descr);
free(mass->usb.str_manuf_descr);
free(mass->dev_descr);
free(mass);
return NULL;
}
Expand Down
5 changes: 4 additions & 1 deletion mass_storage/helpers/mass_storage_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@

typedef struct MassStorageUsb MassStorageUsb;

MassStorageUsb* mass_storage_usb_start(const char* filename, SCSIDeviceFunc fn);
MassStorageUsb* mass_storage_usb_start(
const char* filename,
SCSIDeviceFunc fn,
const MassStorageConfig* config);
void mass_storage_usb_stop(MassStorageUsb* mass);
11 changes: 8 additions & 3 deletions mass_storage/mass_storage_app_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
#include "views/mass_storage_view.h"
#include <mass_storage_icons.h>

#define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX
#define MASS_STORAGE_APP_EXTENSION ".img"
#define MASS_STORAGE_FILE_NAME_LEN 40
#define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX
#define MASS_STORAGE_APP_EXTENSION ".img"
#define MASS_STORAGE_FILE_NAME_LEN 40
#define MASS_STORAGE_CONFIG_FILE_PATH MASS_STORAGE_APP_PATH_FOLDER "/usbconf.txt"

#define TEXT_BUFFER_SIZE 128

struct MassStorageApp {
Gui* gui;
Expand All @@ -32,12 +35,14 @@ struct MassStorageApp {
Popup* popup;
DialogsApp* dialogs;
TextInput* text_input;
char text_buffer[TEXT_BUFFER_SIZE];
VariableItemList* variable_item_list;
Loading* loading;

FuriString* file_path;
File* file;
MassStorage* mass_storage_view;
void* mass_storage_config_ptr;

FuriMutex* usb_mutex;
MassStorageUsb* usb;
Expand Down
1 change: 1 addition & 0 deletions mass_storage/scenes/mass_storage_scene_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ ADD_SCENE(mass_storage, file_select, FileSelect)
ADD_SCENE(mass_storage, work, Work)
ADD_SCENE(mass_storage, create_image, CreateImage)
ADD_SCENE(mass_storage, create_image_name, CreateImageName)
ADD_SCENE(mass_storage, usb_config, USBConfig)
ADD_SCENE(mass_storage, usb_locked, UsbLocked)
5 changes: 5 additions & 0 deletions mass_storage/scenes/mass_storage_scene_start.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
enum VarItemListIndex {
VarItemListIndexSelectDiskImage,
VarItemListIndexCreateDiskImage,
VarItemListIndexEditUSBConfig,
};

static void mass_storage_scene_start_variable_item_list_callback(void* context, uint32_t index) {
Expand All @@ -17,6 +18,7 @@ void mass_storage_scene_start_on_enter(void* context) {
variable_item_list_add(variable_item_list, "Select Disk Image", 0, NULL, app);

variable_item_list_add(variable_item_list, "Create Disk Image", 0, NULL, app);
variable_item_list_add(variable_item_list, "Spoof USB Identity", 0, NULL, app);

variable_item_list_set_enter_callback(
variable_item_list, mass_storage_scene_start_variable_item_list_callback, app);
Expand Down Expand Up @@ -48,6 +50,9 @@ bool mass_storage_scene_start_on_event(void* context, SceneManagerEvent event) {
scene_manager_set_scene_state(app->scene_manager, MassStorageSceneCreateImage, 0);
scene_manager_next_scene(app->scene_manager, MassStorageSceneCreateImage);
break;
case VarItemListIndexEditUSBConfig:
scene_manager_next_scene(app->scene_manager, MassStorageSceneUSBConfig);
break;
default:
break;
}
Expand Down
Loading