diff --git a/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-common.c b/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-common.c index b5d48fa15..04ce9523f 100644 --- a/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-common.c +++ b/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-common.c @@ -31,11 +31,10 @@ proto_manager_generate_get_device_info_request(void) Logi__Device__Proto__Header header_msg = LOGI__DEVICE__PROTO__HEADER__INIT; Logi__Device__Proto__GetDeviceInfoRequest get_deviceinfo_msg = LOGI__DEVICE__PROTO__GET_DEVICE_INFO_REQUEST__INIT; - Logi__Device__Proto__Request request_msg = { - PROTOBUF_C_MESSAGE_INIT(&logi__device__proto__request__descriptor), - LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_GET_DEVICE_INFO_REQUEST, - {&get_deviceinfo_msg}}; Logi__Device__Proto__UsbMsg usb_msg = LOGI__DEVICE__PROTO__USB_MSG__INIT; + Logi__Device__Proto__Request request_msg = LOGI__DEVICE__PROTO__REQUEST__INIT; + request_msg.payload_case = LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_GET_DEVICE_INFO_REQUEST; + request_msg.get_device_info_request = &get_deviceinfo_msg; proto_manager_set_header(&header_msg); usb_msg.header = &header_msg; @@ -54,11 +53,11 @@ proto_manager_generate_transition_to_device_mode_request(void) Logi__Device__Proto__Header header_msg = LOGI__DEVICE__PROTO__HEADER__INIT; Logi__Device__Proto__TransitionToDeviceModeRequest transition_to_device_mode_msg = LOGI__DEVICE__PROTO__TRANSITION_TO_DEVICE_MODE_REQUEST__INIT; - Logi__Device__Proto__Request request_msg = { - PROTOBUF_C_MESSAGE_INIT(&logi__device__proto__request__descriptor), - LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_TRANSITION_TO_DEVICEMODE_REQUEST, - {(Logi__Device__Proto__GetDeviceInfoRequest *)&transition_to_device_mode_msg}}; Logi__Device__Proto__UsbMsg usb_msg = LOGI__DEVICE__PROTO__USB_MSG__INIT; + Logi__Device__Proto__Request request_msg = LOGI__DEVICE__PROTO__REQUEST__INIT; + request_msg.payload_case = + LOGI__DEVICE__PROTO__REQUEST__PAYLOAD_TRANSITION_TO_DEVICEMODE_REQUEST; + request_msg.transition_to_devicemode_request = &transition_to_device_mode_msg; proto_manager_set_header(&header_msg); usb_msg.header = &header_msg; @@ -77,7 +76,8 @@ proto_manager_decode_message(const guint8 *data, GError **error) { g_autoptr(GByteArray) buf_decoded = g_byte_array_new(); - + guint32 success = 0; + guint32 error_code = 0; Logi__Device__Proto__UsbMsg *usb_msg = logi__device__proto__usb_msg__unpack(NULL, len, (const unsigned char *)data); if (usb_msg == NULL) { @@ -115,9 +115,16 @@ proto_manager_decode_message(const guint8 *data, case LOGI__DEVICE__PROTO__RESPONSE__PAYLOAD_TRANSITION_TO_DEVICEMODE_RESPONSE: if (usb_msg->response->transition_to_devicemode_response) { *proto_id = kProtoId_TransitionToDeviceModeResponse; - fu_byte_array_append_uint8( - buf_decoded, - usb_msg->response->transition_to_devicemode_response->success); + success = + usb_msg->response->transition_to_devicemode_response->success + ? 1 + : 0; + error_code = + usb_msg->response->transition_to_devicemode_response->error; + fu_byte_array_append_uint32(buf_decoded, success, G_LITTLE_ENDIAN); + fu_byte_array_append_uint32(buf_decoded, + error_code, + G_LITTLE_ENDIAN); } break; default: diff --git a/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-device.c b/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-device.c index cbf9028a0..48be6bccb 100644 --- a/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-device.c +++ b/plugins/logitech-bulkcontroller/fu-logitech-bulkcontroller-device.c @@ -234,7 +234,7 @@ fu_logitech_bulkcontroller_device_send_upd_cmd(FuLogitechBulkcontrollerDevice *s /* receiving INIT ACK */ fu_byte_array_set_size(buf_ack, MAX_DATA_SIZE); - /* Extending the bulk transfer timeout value, as android device takes some time to + /* extending the bulk transfer timeout value, as android device takes some time to calculate Hash and respond */ if (CMD_END_TRANSFER == cmd) timeout = HASH_TIMEOUT; @@ -423,6 +423,148 @@ fu_logitech_bulkcontroller_device_compute_hash(GBytes *data) return g_base64_encode(md5buf, sizeof(md5buf)); } +static gboolean +fu_logitech_bulkcontroller_device_json_parser(FuDevice *device, + GByteArray *decoded_pkt, + GError **error) +{ + FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device); + JsonArray *json_devices; + JsonNode *json_root; + JsonObject *json_device; + JsonObject *json_object; + JsonObject *json_payload; + g_autoptr(JsonParser) json_parser = json_parser_new(); + + /* parse JSON reply */ + if (!json_parser_load_from_data(json_parser, + (const gchar *)decoded_pkt->data, + decoded_pkt->len, + error)) { + g_prefix_error(error, "failed to parse json data: "); + return FALSE; + } + json_root = json_parser_get_root(json_parser); + if (json_root == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "did not get JSON root"); + return FALSE; + } + json_object = json_node_get_object(json_root); + json_payload = json_object_get_object_member(json_object, "payload"); + if (json_payload == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "did not get JSON payload"); + return FALSE; + } + json_devices = json_object_get_array_member(json_payload, "devices"); + if (json_devices == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "did not get JSON devices"); + return FALSE; + } + json_device = json_array_get_object_element(json_devices, 0); + if (json_device == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "did not get JSON device"); + return FALSE; + } + if (json_object_has_member(json_device, "name")) + fu_device_set_name(device, json_object_get_string_member(json_device, "name")); + if (json_object_has_member(json_device, "sw")) + fu_device_set_version(device, json_object_get_string_member(json_device, "sw")); + if (json_object_has_member(json_device, "type")) + fu_device_add_instance_id(device, + json_object_get_string_member(json_device, "type")); + if (json_object_has_member(json_device, "status")) + self->status = json_object_get_int_member(json_device, "status"); + if (json_object_has_member(json_device, "updateStatus")) + self->update_status = json_object_get_int_member(json_device, "updateStatus"); + + return TRUE; +} + +static gboolean +fu_logitech_bulkcontroller_device_get_data(FuDevice *device, GError **error) +{ + FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device); + g_autoptr(GByteArray) device_request = g_byte_array_new(); + g_autoptr(GByteArray) decoded_pkt = g_byte_array_new(); + g_autoptr(GByteArray) device_response = g_byte_array_new(); + FuLogitechBulkcontrollerProtoId proto_id = kProtoId_UnknownId; + + /* sending GetDeviceInfoRequest. Device reports quite a few matrix, including status, + * progress etc */ + device_request = proto_manager_generate_get_device_info_request(); + if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self, + CMD_BUFFER_WRITE, + device_request, + error)) { + g_prefix_error(error, + "failed to send write buffer packet for device info request: "); + return FALSE; + } + + /* wait for the GetDeviceInfoResponse */ + if (!fu_logitech_bulkcontroller_device_recv_sync_cmd(self, + CMD_BUFFER_READ, + device_response, + error)) { + g_prefix_error(error, "failed to read buffer packet for device info request: "); + return FALSE; + } + if (!fu_logitech_bulkcontroller_device_recv_sync_cmd(self, + CMD_UNINIT_BUFFER, + NULL, + error)) { + g_prefix_error(error, + "failed to read uninit buffer packet for device info request: "); + return FALSE; + } + if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self, + CMD_UNINIT_BUFFER, + NULL, + error)) { + g_prefix_error( + error, + "failed to send buffer uninitialize packet for device info request: "); + return FALSE; + } + decoded_pkt = proto_manager_decode_message(device_response->data, + device_response->len, + &proto_id, + error); + if (decoded_pkt == NULL) { + g_prefix_error(error, "failed to unpack packet for device info request: "); + return FALSE; + } + if (g_getenv("FWUPD_LOGITECH_BULKCONTROLLER_VERBOSE") != NULL) { + g_autofree gchar *strsafe = + fu_common_strsafe((const gchar *)decoded_pkt->data, decoded_pkt->len); + g_debug("Received device response: %s", strsafe); + } + if (proto_id != kProtoId_GetDeviceInfoResponse) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "incorrect response for device info request"); + return FALSE; + } + if (!fu_logitech_bulkcontroller_device_json_parser(device, decoded_pkt, error)) + return FALSE; + + /* success */ + return TRUE; +} + static gboolean fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device, FuFirmware *firmware, @@ -449,9 +591,9 @@ fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device, if (fw == NULL) return FALSE; - /* Sending INIT */ + /* sending INIT */ if (!fu_logitech_bulkcontroller_device_send_upd_cmd(self, CMD_INIT, NULL, error)) { - g_prefix_error(error, "error in writing init transfer packet: "); + g_prefix_error(error, "failed to write init transfer packet: "); return FALSE; } @@ -461,7 +603,7 @@ fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device, CMD_START_TRANSFER, start_pkt, error)) { - g_prefix_error(error, "error in writing start transfer packet: "); + g_prefix_error(error, "failed to write start transfer packet: "); return FALSE; } fu_progress_step_done(progress); @@ -495,13 +637,13 @@ fu_logitech_bulkcontroller_device_write_firmware(FuDevice *device, CMD_END_TRANSFER, end_pkt, error)) { - g_prefix_error(error, "error in writing end transfer transfer packet: "); + g_prefix_error(error, "failed to write end transfer transfer packet: "); return FALSE; } /* send uninit */ if (!fu_logitech_bulkcontroller_device_send_upd_cmd(self, CMD_UNINIT, NULL, error)) { - g_prefix_error(error, "error in writing finish transfer packet: "); + g_prefix_error(error, "failed to write finish transfer packet: "); return FALSE; } fu_progress_step_done(progress); @@ -566,104 +708,43 @@ fu_logitech_bulkcontroller_device_close(FuDevice *device, GError **error) ->close(device, error); } -static gboolean -fu_logitech_bulkcontroller_device_json_parser(FuDevice *device, - GByteArray *decoded_pkt, - GError **error) -{ - FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device); - JsonArray *json_devices; - JsonNode *json_root; - JsonObject *json_device; - JsonObject *json_object; - JsonObject *json_payload; - g_autoptr(JsonParser) json_parser = json_parser_new(); - - /* parse JSON reply */ - if (!json_parser_load_from_data(json_parser, - (const gchar *)decoded_pkt->data, - decoded_pkt->len, - error)) { - g_prefix_error(error, "error in parsing json data: "); - return FALSE; - } - json_root = json_parser_get_root(json_parser); - if (json_root == NULL) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "did not get JSON root"); - return FALSE; - } - json_object = json_node_get_object(json_root); - json_payload = json_object_get_object_member(json_object, "payload"); - if (json_payload == NULL) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "did not get JSON payload"); - return FALSE; - } - json_devices = json_object_get_array_member(json_payload, "devices"); - if (json_devices == NULL) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "did not get JSON devices"); - return FALSE; - } - json_device = json_array_get_object_element(json_devices, 0); - if (json_device == NULL) { - g_set_error_literal(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "did not get JSON device"); - return FALSE; - } - if (json_object_has_member(json_device, "name")) - fu_device_set_name(device, json_object_get_string_member(json_device, "name")); - if (json_object_has_member(json_device, "sw")) - fu_device_set_version(device, json_object_get_string_member(json_device, "sw")); - if (json_object_has_member(json_device, "type")) - fu_device_add_instance_id(device, - json_object_get_string_member(json_device, "type")); - if (json_object_has_member(json_device, "status")) - self->status = json_object_get_int_member(json_device, "status"); - if (json_object_has_member(json_device, "updateStatus")) - self->update_status = json_object_get_int_member(json_device, "updateStatus"); - - return TRUE; -} - static gboolean fu_logitech_bulkcontroller_device_setup(FuDevice *device, GError **error) { FuLogitechBulkcontrollerDevice *self = FU_LOGITECH_BULKCONTROLLER_DEVICE(device); - g_autoptr(GByteArray) device_info_request = g_byte_array_new(); + g_autoptr(GByteArray) device_request = g_byte_array_new(); g_autoptr(GByteArray) decoded_pkt = g_byte_array_new(); - g_autoptr(GByteArray) device_info_response = g_byte_array_new(); + g_autoptr(GByteArray) device_response = g_byte_array_new(); FuLogitechBulkcontrollerProtoId proto_id = kProtoId_UnknownId; + guint32 success = 0; + guint32 error_code = 0; /* FuUsbDevice->setup */ if (!FU_DEVICE_CLASS(fu_logitech_bulkcontroller_device_parent_class)->setup(device, error)) return FALSE; - /* sending GetDeviceInfoRequest */ - device_info_request = proto_manager_generate_get_device_info_request(); + /* + * device supports USB_Device mode, Appliance mode and BYOD mode. + * Only USB_Device mode is supported here. + * Ensure it is running in USB_Device mode + * Response has two data: Request succeeded or failed, and error code in case of failure + */ + device_request = proto_manager_generate_transition_to_device_mode_request(); if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self, CMD_BUFFER_WRITE, - device_info_request, + device_request, error)) { - g_prefix_error(error, "error in sending buffer write packet: "); + g_prefix_error(error, + "failed to send buffer write packet for transition mode request: "); return FALSE; } - /* wait for the GetDeviceInfoResponse */ + /* wait for the TransitionToDeviceModeResponse */ if (!fu_logitech_bulkcontroller_device_recv_sync_cmd(self, CMD_BUFFER_READ, - device_info_response, + device_response, error)) { - g_prefix_error(error, "error in buffer read packet: "); + g_prefix_error(error, "failed to read buffer packet for transition mode request: "); return FALSE; } @@ -671,32 +752,63 @@ fu_logitech_bulkcontroller_device_setup(FuDevice *device, GError **error) CMD_UNINIT_BUFFER, NULL, error)) { - g_prefix_error(error, "error in buffer read packet: "); + g_prefix_error(error, + "failed to read uninit buffer packet for transition mode request: "); return FALSE; } if (!fu_logitech_bulkcontroller_device_send_sync_cmd(self, CMD_UNINIT_BUFFER, NULL, error)) { - g_prefix_error(error, "error in sending buffer uninitialize packet: "); + g_prefix_error( + error, + "failed to send buffer uninitialize packet for transition mode request: "); return FALSE; } - decoded_pkt = proto_manager_decode_message(device_info_response->data, - device_info_response->len, + decoded_pkt = proto_manager_decode_message(device_response->data, + device_response->len, &proto_id, error); if (decoded_pkt == NULL) { - g_prefix_error(error, "error in unpacking packet: "); + g_prefix_error(error, "failed to unpack packet for transition mode request: "); return FALSE; } - if (proto_id != kProtoId_GetDeviceInfoResponse) { + if (proto_id != kProtoId_TransitionToDeviceModeResponse) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, - "did not get kProtoId_GetDeviceInfoResponse"); + "incorrect response for transition mode request"); return FALSE; } - if (!fu_logitech_bulkcontroller_device_json_parser(device, decoded_pkt, error)) + if (!fu_common_read_uint32_safe(decoded_pkt->data, + decoded_pkt->len, + COMMAND_OFFSET, + &success, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (!fu_common_read_uint32_safe(decoded_pkt->data, + decoded_pkt->len, + LENGTH_OFFSET, + &error_code, + G_LITTLE_ENDIAN, + error)) + return FALSE; + if (g_getenv("FWUPD_LOGITECH_BULKCONTROLLER_VERBOSE") != NULL) + g_debug("Received transition mode response. Success: %u, Error: %u", + success, + error_code); + if (!success) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "transition mode request failed. error: %u", + error_code); + return FALSE; + } + + /* load current device data */ + if (!fu_logitech_bulkcontroller_device_get_data(device, error)) return FALSE; /* success */