// // MARK: ATT_WRITE_REQUEST 0x12 static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint8_t * response_buffer, uint16_t response_buffer_size){ uint8_t request_type = ATT_WRITE_REQUEST; uint16_t handle = READ_BT_16(request_buffer, 1); att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok) { return setup_error_invalid_handle(response_buffer, request_type, handle); } if (!att_write_callback) { return setup_error_write_not_permitted(response_buffer, request_type, handle); } if ((it.flags & ATT_PROPERTY_WRITE) == 0) { return setup_error_write_not_permitted(response_buffer, request_type, handle); } if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { return setup_error_write_not_permitted(response_buffer, request_type, handle); } // check security requirements uint8_t error_code = att_validate_security(att_connection, &it); if (error_code) { return setup_error(response_buffer, request_type, handle, error_code); } error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); if (error_code) { return setup_error(response_buffer, request_type, handle, error_code); } response_buffer[0] = ATT_WRITE_RESPONSE; return 1; }
void setup_error::throw_(const char* file, std::size_t line, std::string const& descr) { boost::throw_exception(boost::enable_error_info(setup_error(descr)) << boost::throw_file(file) << boost::throw_line(line) ); }
void tester_util::setup(const ProcessPointer &process, const problem::single::process::Settings &settings) { try { process::setup(m_process_group, process, settings.resource_limits()); } catch (std::exception &) { BOOST_THROW_EXCEPTION(setup_error() << bunsan::enable_nested_current()); } }
// // MARK: ATT_PREPARE_WRITE_REQUEST 0x16 static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint8_t * response_buffer, uint16_t response_buffer_size){ uint8_t request_type = ATT_PREPARE_WRITE_REQUEST; uint16_t handle = READ_BT_16(request_buffer, 1); uint16_t offset = READ_BT_16(request_buffer, 3); if (!att_write_callback) { return setup_error_write_not_permitted(response_buffer, request_type, handle); } att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok) { return setup_error_invalid_handle(response_buffer, request_type, handle); } if ((it.flags & ATT_PROPERTY_WRITE) == 0) { return setup_error_write_not_permitted(response_buffer, request_type, handle); } if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { return setup_error_write_not_permitted(response_buffer, request_type, handle); } // check security requirements uint8_t error_code = att_validate_security(att_connection, &it); if (error_code) { return setup_error(response_buffer, request_type, handle, error_code); } error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5); switch (error_code){ case 0: break; case ATT_ERROR_INVALID_OFFSET: case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: // postpone to execute write request att_prepare_write_update_errors(error_code, handle); break; default: return setup_error(response_buffer, request_type, handle, error_code); } // response: echo request memcpy(response_buffer, request_buffer, request_len); response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE; return request_len; }
// // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e // static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint8_t * handles){ log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles); uint8_t request_type = ATT_READ_MULTIPLE_REQUEST; // TODO: figure out which error to respond with // if (num_handles < 2){ // return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???); // } uint16_t offset = 1; int i; uint8_t error_code = 0; uint16_t handle = 0; for (i=0;i<num_handles;i++){ handle = READ_BT_16(handles, i << 1); if (handle == 0){ return setup_error_invalid_handle(response_buffer, request_type, handle); } att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_invalid_handle(response_buffer, request_type, handle); } // check if handle can be read if ((it.flags & ATT_PROPERTY_READ) == 0) { error_code = ATT_ERROR_READ_NOT_PERMITTED; break; } // check security requirements error_code = att_validate_security(att_connection, &it); if (error_code) break; att_update_value_len(&it, att_connection->con_handle); // limit data if (offset + it.value_len > response_buffer_size) { it.value_len = response_buffer_size - 1; } // store uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); offset += bytes_copied; } if (error_code){ return setup_error(response_buffer, request_type, handle, error_code); } response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; return offset; }
// // MARK: ATT_READ_BLOB_REQUEST 0x0c // static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){ log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset); uint8_t request_type = ATT_READ_BLOB_REQUEST; att_iterator_t it; int ok = att_find_handle(&it, handle); if (!ok){ return setup_error_invalid_handle(response_buffer, request_type, handle); } // check if handle can be read if ((it.flags & ATT_PROPERTY_READ) == 0) { return setup_error_read_not_permitted(response_buffer, request_type, handle); } // check security requirements uint8_t error_code = att_validate_security(att_connection, &it); if (error_code) { return setup_error(response_buffer, request_type, handle, error_code); } att_update_value_len(&it, att_connection->con_handle); if (value_offset > it.value_len){ return setup_error_invalid_offset(response_buffer, request_type, handle); } // limit data uint16_t offset = 1; if (offset + it.value_len - value_offset > response_buffer_size) { it.value_len = response_buffer_size - 1 + value_offset; } // store uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset, att_connection->con_handle); offset += bytes_copied; response_buffer[0] = ATT_READ_BLOB_RESPONSE; return offset; }
// MARK: ATT_EXECUTE_WRITE_REQUEST 0x18 // NOTE: security has been verified by handle_prepare_write_request static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint8_t * response_buffer, uint16_t response_buffer_size){ uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST; if (!att_write_callback) { return setup_error_write_not_permitted(response_buffer, request_type, 0); } if (request_buffer[1]) { // deliver queued errors if (att_prepare_write_error_code){ att_clear_transaction_queue(att_connection); uint8_t error_code = att_prepare_write_error_code; uint16_t handle = att_prepare_write_error_handle; att_prepare_write_reset(); return setup_error(response_buffer, request_type, handle, error_code); } (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0); } else { att_clear_transaction_queue(att_connection); } response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE; return 1; }
static int __init wd7000_setup(char *str) { static short wd7000_card_num; /* .bss will zero this */ short i; int ints[6]; (void) get_options(str, ARRAY_SIZE(ints), ints); if (wd7000_card_num >= NUM_CONFIGS) { printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__); return 0; } if ((ints[0] < 3) || (ints[0] > 5)) { printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __func__); } else { for (i = 0; i < NUM_IRQS; i++) if (ints[1] == wd7000_irq[i]) break; if (i == NUM_IRQS) { setup_error("invalid IRQ.", ints); return 0; } else configs[wd7000_card_num].irq = ints[1]; for (i = 0; i < NUM_DMAS; i++) if (ints[2] == wd7000_dma[i]) break; if (i == NUM_DMAS) { setup_error("invalid DMA channel.", ints); return 0; } else configs[wd7000_card_num].dma = ints[2]; for (i = 0; i < NUM_IOPORTS; i++) if (ints[3] == wd7000_iobase[i]) break; if (i == NUM_IOPORTS) { setup_error("invalid I/O base address.", ints); return 0; } else configs[wd7000_card_num].iobase = ints[3]; if (ints[0] > 3) { if ((ints[4] < 500) || (ints[4] > 31875)) { setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints); configs[wd7000_card_num].bus_on = BUS_ON; } else configs[wd7000_card_num].bus_on = ints[4] / 125; } else configs[wd7000_card_num].bus_on = BUS_ON; if (ints[0] > 4) { if ((ints[5] < 500) || (ints[5] > 31875)) { setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints); configs[wd7000_card_num].bus_off = BUS_OFF; } else configs[wd7000_card_num].bus_off = ints[5] / 125; } else configs[wd7000_card_num].bus_off = BUS_OFF; if (wd7000_card_num) { for (i = 0; i < (wd7000_card_num - 1); i++) { int j = i + 1; for (; j < wd7000_card_num; j++) if (configs[i].irq == configs[j].irq) { setup_error("duplicated IRQ!", ints); return 0; } if (configs[i].dma == configs[j].dma) { setup_error("duplicated DMA " "channel!", ints); return 0; } if (configs[i].iobase == configs[j].iobase) { setup_error("duplicated I/O " "base address!", ints); return 0; } } } dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, " "BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125); wd7000_card_num++; } return 1; }
// // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 // // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID // Core v4.0, vol 3, part g, 2.5.3 // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request. // The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request." // // NOTE: doesn't handle DYNAMIC values // // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected // Core 4.0, vol 3, part g, 8.1 // "The list of services and characteristics that a device supports is not considered private or // confidential information, and therefore the Service and Characteristic Discovery procedures // shall always be permitted. " // static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t start_handle, uint16_t end_handle, uint16_t attribute_type_len, uint8_t * attribute_type){ log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); hexdump(attribute_type, attribute_type_len); uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST; if (start_handle > end_handle || start_handle == 0){ return setup_error_invalid_handle(response_buffer, request_type, start_handle); } // assert UUID is primary or secondary service uuid uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type); if (uuid16 != GATT_PRIMARY_SERVICE_UUID && uuid16 != GATT_SECONDARY_SERVICE_UUID){ return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE); } uint16_t offset = 1; uint16_t pair_len = 0; uint16_t in_group = 0; uint16_t group_start_handle = 0; uint8_t const * group_start_value = NULL; uint16_t prev_handle = 0; att_iterator_t it; att_iterator_init(&it); while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (it.handle && it.handle < start_handle) continue; if (it.handle > end_handle) break; // (1) // log_info("Handle 0x%04x", it.handle); // close current tag, if within a group and a new service definition starts or we reach end of att db if (in_group && (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4); bt_store_16(response_buffer, offset, group_start_handle); offset += 2; bt_store_16(response_buffer, offset, prev_handle); offset += 2; memcpy(response_buffer + offset, group_start_value, pair_len - 4); offset += pair_len - 4; in_group = 0; // check if space for another handle pair available if (offset + pair_len > response_buffer_size){ break; } } // keep track of previous handle prev_handle = it.handle; // does current attribute match // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { // check if value has same len as last one uint16_t this_pair_len = 4 + it.value_len; if (offset > 1){ if (this_pair_len != pair_len) { break; } } // log_info("Begin of group, handle 0x%04x", it.handle); // first if (offset == 1) { pair_len = this_pair_len; response_buffer[offset] = this_pair_len; offset++; } group_start_handle = it.handle; group_start_value = it.value; in_group = 1; } } if (offset == 1){ return setup_error_atribute_not_found(response_buffer, request_type, start_handle); } response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; return offset; }
// // MARK: ATT_READ_BY_TYPE_REQUEST // static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t start_handle, uint16_t end_handle, uint16_t attribute_type_len, uint8_t * attribute_type){ log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); hexdump(attribute_type, attribute_type_len); uint8_t request_type = ATT_READ_BY_TYPE_REQUEST; if (start_handle > end_handle || start_handle == 0){ return setup_error_invalid_handle(response_buffer, request_type, start_handle); } uint16_t offset = 1; uint16_t pair_len = 0; att_iterator_t it; att_iterator_init(&it); uint8_t error_code = 0; uint16_t first_matching_but_unreadable_handle = 0; while (att_iterator_has_next(&it)){ att_iterator_fetch_next(&it); if (!it.handle) break; if (it.handle < start_handle) continue; if (it.handle > end_handle) break; // (1) // does current attribute match if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; // skip handles that cannot be read but rembember that there has been at least one if ((it.flags & ATT_PROPERTY_READ) == 0) { if (first_matching_but_unreadable_handle == 0) { first_matching_but_unreadable_handle = it.handle; } continue; } // check security requirements error_code = att_validate_security(att_connection, &it); if (error_code) break; att_update_value_len(&it, att_connection->con_handle); // check if value has same len as last one uint16_t this_pair_len = 2 + it.value_len; if (offset > 1){ if (pair_len != this_pair_len) { break; } } // first if (offset == 1) { pair_len = this_pair_len; response_buffer[offset] = pair_len; offset++; } // space? if (offset + pair_len > response_buffer_size) { if (offset > 2) break; it.value_len = response_buffer_size - 4; response_buffer[1] = 2 + it.value_len; } // store bt_store_16(response_buffer, offset, it.handle); offset += 2; uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); offset += bytes_copied; } // at least one attribute could be read if (offset > 1){ response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; return offset; } // first attribute had an error if (error_code){ return setup_error(response_buffer, request_type, start_handle, error_code); } // no other errors, but all found attributes had been non-readable if (first_matching_but_unreadable_handle){ return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle); } // attribute not found return setup_error_atribute_not_found(response_buffer, request_type, start_handle); }
static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){ return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET); }
static inline uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND); }
static inline uint16_t setup_error_write_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ return setup_error(response_buffer, request, start_handle, ATT_ERROR_WRITE_NOT_PERMITTED); }
static uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){ return setup_error(response_buffer, request, handle, ATT_ERROR_ATTRIBUTE_INVALID); }