# HG changeset patch # User Florian Pose # Date 1190279547 0 # Node ID 03d2fe3d4a9371a9d8cd4f2c2d9d8acdb3e34d73 # Parent aece53f82df3852639fa0bbce5820110114662c9 Improved checking of EEPROM data while reading. diff -r aece53f82df3 -r 03d2fe3d4a93 master/fsm_slave.c --- a/master/fsm_slave.c Wed Sep 19 17:44:28 2007 +0000 +++ b/master/fsm_slave.c Thu Sep 20 09:12:27 2007 +0000 @@ -431,7 +431,7 @@ slave->eeprom_size = 0; slave->error_flag = 1; fsm->state = ec_fsm_slave_state_error; - EC_ERR("Failed to allocate EEPROM data on slave %i.\n", + EC_ERR("Failed to allocate EEPROM data for slave %u.\n", slave->ring_position); return; } @@ -453,7 +453,7 @@ void ec_fsm_slave_scan_state_eeprom_data(ec_fsm_slave_t *fsm /**< slave state machine */) { ec_slave_t *slave = fsm->slave; - uint16_t *cat_word, cat_type, cat_size; + uint16_t *cat_word, cat_type, cat_size, eeprom_word_size = slave->eeprom_size / 2; if (ec_fsm_sii_exec(&fsm->fsm_sii)) return; @@ -467,7 +467,7 @@ // 2 words fetched - if (fsm->sii_offset + 2 <= slave->eeprom_size / 2) { // 2 words fit + if (fsm->sii_offset + 2 <= eeprom_word_size) { // 2 words fit memcpy(slave->eeprom_data + fsm->sii_offset * 2, fsm->fsm_sii.value, 4); } @@ -476,7 +476,7 @@ fsm->fsm_sii.value, 2); } - if (fsm->sii_offset + 2 < slave->eeprom_size / 2) { + if (fsm->sii_offset + 2 < eeprom_word_size) { // fetch the next 2 words fsm->sii_offset += 2; ec_fsm_sii_read(&fsm->fsm_sii, slave, fsm->sii_offset, @@ -508,39 +508,62 @@ slave->sii_mailbox_protocols = EC_READ_U16(slave->eeprom_data + 2 * 0x001C); + if (eeprom_word_size < EC_FIRST_EEPROM_CATEGORY_OFFSET + 1) { + EC_ERR("Unexpected end of EEPROM data in slave %u.\n", + slave->ring_position); + goto end; + } + // evaluate category data - cat_word = (uint16_t *) slave->eeprom_data + EC_FIRST_EEPROM_CATEGORY_OFFSET; + cat_word = + (uint16_t *) slave->eeprom_data + EC_FIRST_EEPROM_CATEGORY_OFFSET; while (EC_READ_U16(cat_word) != 0xFFFF) { + + // type and size words must fit + if (cat_word + 2 - (uint16_t *) slave->eeprom_data + > eeprom_word_size) { + EC_ERR("Unexpected end of EEPROM data in slave %u.\n", + slave->ring_position); + goto end; + } + cat_type = EC_READ_U16(cat_word) & 0x7FFF; cat_size = EC_READ_U16(cat_word + 1); + cat_word += 2; + + if (cat_word + cat_size - (uint16_t *) slave->eeprom_data + > eeprom_word_size) { + EC_WARN("Unexpected end of EEPROM data in slave %u.\n", + slave->ring_position); + goto end; + } switch (cat_type) { case 0x000A: - if (ec_slave_fetch_sii_strings( - slave, (uint8_t *) (cat_word + 2))) + if (ec_slave_fetch_sii_strings(slave, (uint8_t *) cat_word, + cat_size * 2)) goto end; break; case 0x001E: - ec_slave_fetch_sii_general( - slave, (uint8_t *) (cat_word + 2)); + if (ec_slave_fetch_sii_general(slave, (uint8_t *) cat_word, + cat_size * 2)) + goto end; break; case 0x0028: break; case 0x0029: - if (ec_slave_fetch_sii_syncs( - slave, (uint8_t *) (cat_word + 2), cat_size)) + if (ec_slave_fetch_sii_syncs(slave, (uint8_t *) cat_word, + cat_size * 2)) goto end; break; case 0x0032: - if (ec_slave_fetch_sii_pdos( - slave, (uint8_t *) (cat_word + 2), - cat_size, EC_TX_PDO)) + if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word, + cat_size * 2, EC_TX_PDO)) goto end; break; case 0x0033: - if (ec_slave_fetch_sii_pdos( - slave, (uint8_t *) (cat_word + 2), - cat_size, EC_RX_PDO)) + if (ec_slave_fetch_sii_pdos( slave, (uint8_t *) cat_word, + cat_size * 2, EC_RX_PDO)) goto end; break; default: @@ -549,7 +572,12 @@ cat_type, slave->ring_position); } - cat_word += cat_size + 2; + cat_word += cat_size; + if (cat_word - (uint16_t *) slave->eeprom_data >= eeprom_word_size) { + EC_WARN("Unexpected end of EEPROM data in slave %u.\n", + slave->ring_position); + goto end; + } } fsm->state = ec_fsm_slave_state_end; diff -r aece53f82df3 -r 03d2fe3d4a93 master/slave.c --- a/master/slave.c Wed Sep 19 17:44:28 2007 +0000 +++ b/master/slave.c Thu Sep 20 09:12:27 2007 +0000 @@ -388,12 +388,14 @@ /** Fetches data from a STRING category. + \todo range checking \return 0 in case of success, else < 0 */ int ec_slave_fetch_sii_strings( ec_slave_t *slave, /**< EtherCAT slave */ - const uint8_t *data /**< category data */ + const uint8_t *data, /**< category data */ + size_t data_size /**< number of bytes */ ) { int i; @@ -444,13 +446,20 @@ \return 0 in case of success, else < 0 */ -void ec_slave_fetch_sii_general( +int ec_slave_fetch_sii_general( ec_slave_t *slave, /**< EtherCAT slave */ - const uint8_t *data /**< category data */ + const uint8_t *data, /**< category data */ + size_t data_size /**< size in bytes */ ) { unsigned int i; + if (data_size != 32) { + EC_ERR("Wrong size of general category (%u/32) in slave %u.\n", + data_size, slave->ring_position); + return -1; + } + slave->sii_group = ec_slave_sii_string(slave, data[0]); slave->sii_image = ec_slave_sii_string(slave, data[1]); slave->sii_order = ec_slave_sii_string(slave, data[2]); @@ -461,6 +470,8 @@ (data[4] & (0x03 << (i * 2))) >> (i * 2); slave->sii_current_on_ebus = EC_READ_S16(data + 0x0C); + + return 0; } /*****************************************************************************/ @@ -473,19 +484,26 @@ int ec_slave_fetch_sii_syncs( ec_slave_t *slave, /**< EtherCAT slave */ const uint8_t *data, /**< category data */ - size_t word_count /**< number of words */ + size_t data_size /**< number of bytes */ ) { unsigned int i; ec_sync_t *sync; - - // sync manager struct is 4 words long - slave->sii_sync_count = word_count / 4; - - if (!(slave->sii_syncs = - kmalloc(sizeof(ec_sync_t) * slave->sii_sync_count, - GFP_KERNEL))) { - EC_ERR("Failed to allocate memory for sync managers.\n"); + size_t memsize; + + // one sync manager struct is 4 words long + if (data_size % 8) { + EC_ERR("Invalid SII sync manager size %u in slave %u.\n", + data_size, slave->ring_position); + return -1; + } + + slave->sii_sync_count = data_size / 8; + + memsize = sizeof(ec_sync_t) * slave->sii_sync_count; + if (!(slave->sii_syncs = kmalloc(memsize, GFP_KERNEL))) { + EC_ERR("Failed to allocate %u bytes for sync managers.\n", + memsize); slave->sii_sync_count = 0; return -1; } @@ -513,7 +531,7 @@ int ec_slave_fetch_sii_pdos( ec_slave_t *slave, /**< EtherCAT slave */ const uint8_t *data, /**< category data */ - size_t word_count, /**< number of words */ + size_t data_size, /**< number of bytes */ ec_pdo_type_t pdo_type /**< PDO type */ ) { @@ -521,7 +539,7 @@ ec_pdo_entry_t *entry; unsigned int entry_count, i; - while (word_count >= 4) { + while (data_size >= 8) { if (!(pdo = kmalloc(sizeof(ec_pdo_t), GFP_KERNEL))) { EC_ERR("Failed to allocate PDO memory.\n"); return -1; @@ -535,7 +553,7 @@ pdo->name = ec_slave_sii_string(slave, EC_READ_U8(data + 5)); list_add_tail(&pdo->list, &slave->sii_pdos); - word_count -= 4; + data_size -= 8; data += 8; for (i = 0; i < entry_count; i++) { @@ -550,7 +568,7 @@ entry->bit_length = EC_READ_U8(data + 5); list_add_tail(&entry->list, &pdo->entries); - word_count -= 4; + data_size -= 8; data += 8; } diff -r aece53f82df3 -r 03d2fe3d4a93 master/slave.h --- a/master/slave.h Wed Sep 19 17:44:28 2007 +0000 +++ b/master/slave.h Thu Sep 20 09:12:27 2007 +0000 @@ -175,8 +175,9 @@ struct list_head sdo_dictionary; /**< SDO dictionary list */ struct list_head sdo_confs; /**< list of SDO configurations */ uint8_t sdo_dictionary_fetched; /**< dictionary has been fetched */ + unsigned long jiffies_preop; /**< time, the slave went to PREOP */ + uint8_t pdo_mapping_fetched; /**< PDO mapping has been fetched */ - unsigned long jiffies_preop; /**< time, the slave went to PREOP */ }; /*****************************************************************************/ @@ -195,8 +196,8 @@ void ec_slave_set_online_state(ec_slave_t *, ec_slave_online_state_t); // SII categories -int ec_slave_fetch_sii_strings(ec_slave_t *, const uint8_t *); -void ec_slave_fetch_sii_general(ec_slave_t *, const uint8_t *); +int ec_slave_fetch_sii_strings(ec_slave_t *, const uint8_t *, size_t); +int ec_slave_fetch_sii_general(ec_slave_t *, const uint8_t *, size_t); int ec_slave_fetch_sii_syncs(ec_slave_t *, const uint8_t *, size_t); int ec_slave_fetch_sii_pdos(ec_slave_t *, const uint8_t *, size_t, ec_pdo_type_t);