diff --git a/src/classic/hid_device.c b/src/classic/hid_device.c index 2e7abb97c..e338ad804 100644 --- a/src/classic/hid_device.c +++ b/src/classic/hid_device.c @@ -122,7 +122,7 @@ static uint16_t hid_device_get_next_cid(void){ // TODO: store hid device connection into list static hid_device_t * hid_device_get_instance_for_cid(uint16_t cid){ - printf("control_cid 0x%02x, interrupt_cid 0x%02x, query_cid 0x%02x \n", _hid_device.control_cid, _hid_device.interrupt_cid, cid); + // printf("control_cid 0x%02x, interrupt_cid 0x%02x, query_cid 0x%02x \n", _hid_device.control_cid, _hid_device.interrupt_cid, cid); if (_hid_device.cid == cid || _hid_device.control_cid == cid || _hid_device.interrupt_cid == cid){ return &_hid_device; } @@ -371,8 +371,6 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack } hid_message_type_t message_type = packet[0] >> 4; // printf("L2CAP_DATA_PACKET message_type %d, packet_size %d \n", message_type, packet_size); - printf_hexdump(packet, packet_size); - switch (message_type){ case HID_MESSAGE_TYPE_GET_REPORT: device->report_type = packet[0] & 0x03; @@ -413,6 +411,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack case HID_MESSAGE_TYPE_SET_REPORT: device->state = HID_DEVICE_W2_SET_REPORT; device->max_packet_size = l2cap_max_mtu(); + device->report_type = packet[0] & 0x03; if (packet_size < 1){ device->report_status = HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER; break; @@ -426,15 +425,15 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * pack break; } device->report_id = packet[1]; - device->report_status = (*hci_device_set_report)(device->cid, device->report_type, device->max_packet_size-1, &packet[1]); + device->report_status = (*hci_device_set_report)(device->cid, device->report_type, packet_size-1, &packet[1]); break; case HID_PROTOCOL_MODE_REPORT: // printf("HID_PROTOCOL_MODE_REPORT \n"); if (packet_size >= 2){ - device->report_status = (*hci_device_set_report)(device->cid, device->report_type, device->max_packet_size-1, &packet[1]); + device->report_status = (*hci_device_set_report)(device->cid, device->report_type, packet_size-1, &packet[1]); } else { uint8_t payload[] = {0}; - device->report_status = (*hci_device_set_report)(device->cid, device->report_type, device->max_packet_size-1, payload); + device->report_status = (*hci_device_set_report)(device->cid, device->report_type, 1, payload); } break; } diff --git a/src/classic/hid_device.h b/src/classic/hid_device.h index be6ed1f19..059cf8fa3 100644 --- a/src/classic/hid_device.h +++ b/src/classic/hid_device.h @@ -96,6 +96,11 @@ typedef enum { HID_PROTOCOL_MODE_REPORT } hid_protocol_mode_t; +typedef enum { + HID_REPORT_ID_UNDECLARED, + HID_REPORT_ID_VALID, + HID_REPORT_ID_INVALID +} hid_report_id_status_t; /** * @brief Create HID Device SDP service record. diff --git a/test/pts/hid_device_test.c b/test/pts/hid_device_test.c index a8abfffc2..d98250d35 100644 --- a/test/pts/hid_device_test.c +++ b/test/pts/hid_device_test.c @@ -119,6 +119,7 @@ const uint8_t hid_descriptor_keyboard_boot_mode[] = { }; + // #define CHAR_ILLEGAL 0xff #define CHAR_RETURN '\n' @@ -280,6 +281,53 @@ static int prepare_keyboard_report(hid_report_type_t report_type, int modifier, return pos; } +static int hid_report_size_valid(uint16_t cid, int report_id, hid_report_type_t report_type, int report_size){ + printf("report size %d, report type %d, report id %d\n", report_size, report_type, report_id); + if (!report_size) return 0; + if (hid_device_in_boot_protocol_mode(cid)){ + switch (report_id){ + case HID_BOOT_MODE_KEYBOARD_ID: + if (report_size < 8) return 0; + break; + case HID_BOOT_MODE_MOUSE_ID: + if (report_size < 1) return 0; + break; + default: + return 0; + } + } else { + switch (report_type){ + case HID_REPORT_TYPE_INPUT: + if (report_size < 8) return 0; + break; + case HID_REPORT_TYPE_OUTPUT: + if (report_size < 1) return 0; + break; + default: + return 0; + } + } + return 1; +} + +static hid_report_id_status_t hid_report_id_status(uint16_t cid, uint16_t report_id){ + if (hid_device_in_boot_protocol_mode(cid)){ + switch (report_id){ + case HID_BOOT_MODE_KEYBOARD_ID: + case HID_BOOT_MODE_MOUSE_ID: + return HID_REPORT_ID_VALID; + default: + return HID_REPORT_ID_INVALID; + } + } else { +#ifdef REPORT_ID_DECLARED + if (report_id != 1) return HID_REPORT_ID_INVALID; + return HID_REPORT_ID_VALID; +#endif + return HID_REPORT_ID_UNDECLARED; + } +} + static hid_handshake_param_type_t hid_get_report_callback(uint16_t cid, hid_report_type_t report_type, uint16_t report_id, uint8_t report_max_size, int * out_report_size, uint8_t * out_report){ UNUSED(cid); UNUSED(report_max_size); @@ -292,8 +340,18 @@ static hid_handshake_param_type_t hid_get_report_callback(uint16_t cid, hid_repo int report_size = 0; int pos = 0; + hid_report_id_status_t report_id_status = hid_report_id_status(cid, report_id); + switch (report_id_status){ + case HID_REPORT_ID_VALID: + report_data[pos++] = report_id; + break; + case HID_REPORT_ID_INVALID: + return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID; + default: + break; + } + if (hid_device_in_boot_protocol_mode(cid)){ - report_data[pos++] = report_id; switch (report_id){ case HID_BOOT_MODE_KEYBOARD_ID: report_size = prepare_keyboard_report(report_type, send_modifier, send_keycode, &report_data[pos], sizeof(report_data) - pos); @@ -304,13 +362,6 @@ static hid_handshake_param_type_t hid_get_report_callback(uint16_t cid, hid_repo break; } } else { -#ifdef REPORT_ID_DECLARED - if (report_id != 1){ - printf("wrong ID, received %d\n", report_id); - return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID; - } - report_data[pos++] = report_id; -#endif report_size = prepare_keyboard_report(report_type, send_modifier, send_keycode, &report_data[pos], sizeof(report_data) - pos); } if (!report_size) return HID_HANDSHAKE_PARAM_TYPE_ERR_UNSUPPORTED_REQUEST; @@ -323,75 +374,42 @@ static hid_handshake_param_type_t hid_get_report_callback(uint16_t cid, hid_repo static hid_handshake_param_type_t hid_set_report_callback(uint16_t cid, hid_report_type_t report_type, int report_size, uint8_t * report){ UNUSED(cid); - UNUSED(report_type); - UNUSED(report_size); UNUSED(report); int pos = 0; -#ifdef REPORT_ID_DECLARED - int report_id = report[pos++]; - if (report_id != 1) { - return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID; - } -#endif - printf("check report size %d\n", report_size); - switch (report_type){ - case HID_REPORT_TYPE_INPUT: - if (report_size < 9) { - return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER; - } - break; - case HID_REPORT_TYPE_OUTPUT: - if (report_size < 2) { - return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER; - } - break; - default: - return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER; - } + printf("set report, size %d\n", report_size); + printf_hexdump(report, report_size); + printf("\n"); + + int report_id = report[0]; + hid_report_id_status_t report_id_status = hid_report_id_status(cid, report_id); + switch (report_id_status){ + case HID_REPORT_ID_VALID: + pos++; + break; + case HID_REPORT_ID_INVALID: + printf("invalid id\n"); + return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_REPORT_ID; + default: + report_id = 0; + break; + } + printf(" report_id %d \n", report_id); + + if (!hid_report_size_valid(cid, report_id, report_type, report_size-pos)){ + printf("invalid report size\n"); + return HID_HANDSHAKE_PARAM_TYPE_ERR_INVALID_PARAMETER; + } return HID_HANDSHAKE_PARAM_TYPE_SUCCESSFUL; } static void hid_report_data_callback(uint16_t cid, hid_report_type_t report_type, uint16_t report_id, int report_size, uint8_t * report){ - UNUSED(cid); - UNUSED(report_type); - UNUSED(report_size); UNUSED(report); - UNUSED(report_id); - printf("hid_report_data_callback\n"); - printf_hexdump(report, report_size); - if (!report_size){ + if ( hid_report_id_status(cid, report_id) == HID_REPORT_ID_INVALID || + !hid_report_size_valid(cid, report_id, report_type, report_size)){ printf("ignore data packet\n"); return; - } - - printf("received report data, type %d, size %d\n", report_type, report_size); - printf_hexdump(report, report_size); - printf("\n"); - - if (hid_device_in_boot_protocol_mode(cid)){ - printf("Boot protocol mode\n"); - - if ( report_id < 2 || - (report_id == HID_BOOT_MODE_KEYBOARD_ID && report_size < 8) || - (report_id == HID_BOOT_MODE_MOUSE_ID && report_size < 1)) { - printf("ignore data packet\n"); - return; - } - } else { - printf("Report protocol mode\n"); -#ifdef REPORT_ID_DECLARED - if (report_id != 1){ - printf("ignore data packet\n"); - return; - } -#endif - if ((report_type == HID_REPORT_TYPE_INPUT && report_size < 8) || - (report_type == HID_REPORT_TYPE_OUTPUT && report_size < 1)) { - printf("ignore data packet\n"); - return; - } } printf("do smth with report\n"); }