mirror of
https://gitlab.com/etherlab.org/ethercat.git
synced 2026-08-17 16:51:44 +08:00
Merge branch 'protect-datagram-fields' into 'stable-1.6'
Re-ordering protection for datagram fields See merge request etherlab.org/ethercat!203
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
# Version History
|
||||
|
||||
- Protect datagram receiving mechanism against re-ordering.
|
||||
|
||||
## Version 1.6.10
|
||||
|
||||
- Added RasPi 5 macb (Cadence GEM / RP1) driver for kernel 6.18.
|
||||
|
||||
@@ -67,6 +67,7 @@ noinst_HEADERS = \
|
||||
sdo_request.c sdo_request.h \
|
||||
slave.c slave.h \
|
||||
slave_config.c slave_config.h \
|
||||
smp.h \
|
||||
soe_errors.c \
|
||||
soe_request.c soe_request.h \
|
||||
sync.c sync.h \
|
||||
|
||||
+15
-18
@@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2026 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -32,6 +32,7 @@
|
||||
#ifdef EC_EOE
|
||||
#include "ethernet.h"
|
||||
#endif
|
||||
#include "smp.h"
|
||||
|
||||
#include "fsm_master.h"
|
||||
#include "fsm_foe.h"
|
||||
@@ -174,8 +175,9 @@ int ec_fsm_master_exec(
|
||||
ec_fsm_master_t *fsm /**< Master state machine. */
|
||||
)
|
||||
{
|
||||
if (fsm->datagram->state == EC_DATAGRAM_SENT
|
||||
|| fsm->datagram->state == EC_DATAGRAM_QUEUED) {
|
||||
ec_datagram_state_t state = smp_load_acquire(&fsm->datagram->state);
|
||||
|
||||
if (state == EC_DATAGRAM_SENT || state == EC_DATAGRAM_QUEUED) {
|
||||
// datagram was not sent or received yet.
|
||||
return 0;
|
||||
}
|
||||
@@ -315,8 +317,8 @@ void ec_fsm_master_state_broadcast(
|
||||
for (dev_idx = EC_DEVICE_MAIN;
|
||||
dev_idx < ec_master_num_devices(master); dev_idx++) {
|
||||
fsm->slave_states[dev_idx] = 0x00;
|
||||
fsm->slaves_responding[dev_idx] = 0; /* Reset to trigger rescan on
|
||||
next link up. */
|
||||
/* Reset to trigger rescan on next link up. */
|
||||
fsm->slaves_responding[dev_idx] = 0;
|
||||
}
|
||||
}
|
||||
fsm->link_state[fsm->dev_idx] = master->devices[fsm->dev_idx].link_state;
|
||||
@@ -429,7 +431,6 @@ void ec_fsm_master_state_broadcast(
|
||||
}
|
||||
|
||||
if (master->slave_count) {
|
||||
|
||||
// application applied configurations
|
||||
if (master->config_changed) {
|
||||
master->config_changed = 0;
|
||||
@@ -438,8 +439,8 @@ void ec_fsm_master_state_broadcast(
|
||||
|
||||
fsm->slave = master->slaves; // begin with first slave
|
||||
ec_fsm_master_enter_write_system_times(fsm);
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// fetch state from first slave
|
||||
fsm->slave = master->slaves;
|
||||
ec_datagram_fprd(fsm->datagram, fsm->slave->station_address,
|
||||
@@ -535,14 +536,12 @@ int ec_fsm_master_action_process_int_request(
|
||||
for (slave = master->slaves;
|
||||
slave < master->slaves + master->slave_count;
|
||||
slave++) {
|
||||
|
||||
if (!slave->config) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdo_req, &slave->config->sdo_requests, list) {
|
||||
if (sdo_req->state == EC_INT_REQUEST_QUEUED) {
|
||||
|
||||
if (ec_sdo_request_timed_out(sdo_req)) {
|
||||
sdo_req->state = EC_INT_REQUEST_FAILURE;
|
||||
EC_SLAVE_DBG(slave, 1, "Internal SDO request"
|
||||
@@ -570,7 +569,6 @@ int ec_fsm_master_action_process_int_request(
|
||||
|
||||
list_for_each_entry(soe_req, &slave->config->soe_requests, list) {
|
||||
if (soe_req->state == EC_INT_REQUEST_QUEUED) {
|
||||
|
||||
if (ec_soe_request_timed_out(soe_req)) {
|
||||
soe_req->state = EC_INT_REQUEST_FAILURE;
|
||||
EC_SLAVE_DBG(slave, 1, "Internal SoE request"
|
||||
@@ -634,8 +632,9 @@ void ec_fsm_master_action_idle(
|
||||
|| slave->sdo_dictionary_fetched
|
||||
|| slave->current_state == EC_SLAVE_STATE_INIT
|
||||
|| slave->current_state == EC_SLAVE_STATE_UNKNOWN
|
||||
|| jiffies - slave->jiffies_preop < EC_WAIT_SDO_DICT * HZ
|
||||
) continue;
|
||||
|| jiffies - slave->jiffies_preop < EC_WAIT_SDO_DICT * HZ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EC_SLAVE_DBG(slave, 1, "Fetching SDO dictionary.\n");
|
||||
|
||||
@@ -715,7 +714,6 @@ void ec_fsm_master_action_configure(
|
||||
// Does the slave have to be configured?
|
||||
if ((slave->current_state != slave->requested_state
|
||||
|| slave->force_config) && !slave->error_flag) {
|
||||
|
||||
// Start slave configuration
|
||||
down(&master->config_sem);
|
||||
master->config_busy = 1;
|
||||
@@ -1033,7 +1031,7 @@ void ec_fsm_master_state_configure_slave(
|
||||
wake_up_interruptible(&master->config_queue);
|
||||
|
||||
if (!ec_fsm_slave_config_success(&fsm->fsm_slave_config)) {
|
||||
// TODO: mark slave_config as failed.
|
||||
// TODO(fp): mark slave_config as failed.
|
||||
}
|
||||
|
||||
fsm->idle = 1;
|
||||
@@ -1051,7 +1049,6 @@ void ec_fsm_master_enter_write_system_times(
|
||||
ec_master_t *master = fsm->master;
|
||||
|
||||
if (master->dc_ref_time) {
|
||||
|
||||
while (fsm->slave < master->slaves + master->slave_count) {
|
||||
if (!fsm->slave->base_dc_supported
|
||||
|| !fsm->slave->has_dc_system_time) {
|
||||
@@ -1334,10 +1331,10 @@ void ec_fsm_master_state_write_sii(
|
||||
if (request->offset <= 4 && request->offset + request->nwords > 4) {
|
||||
// alias was written
|
||||
slave->sii.alias = EC_READ_U16(request->words + 4);
|
||||
// TODO: read alias from register 0x0012
|
||||
// TODO(fp): read alias from register 0x0012
|
||||
slave->effective_alias = slave->sii.alias;
|
||||
}
|
||||
// TODO: Evaluate other SII contents!
|
||||
// TODO(fp): Evaluate other SII contents!
|
||||
|
||||
request->state = EC_INT_REQUEST_SUCCESS;
|
||||
wake_up_all(&master->request_queue);
|
||||
|
||||
@@ -121,10 +121,10 @@ void ec_fsm_slave_config_reconfigure(ec_fsm_slave_config_t *);
|
||||
void ec_fsm_slave_config_init(
|
||||
ec_fsm_slave_config_t *fsm, /**< slave state machine */
|
||||
ec_datagram_t *datagram, /**< datagram structure to use */
|
||||
ec_fsm_change_t *fsm_change, /**< State change state machine to use. */
|
||||
ec_fsm_change_t *fsm_change, /**< State machine to use. */
|
||||
ec_fsm_coe_t *fsm_coe, /**< CoE state machine to use. */
|
||||
ec_fsm_soe_t *fsm_soe, /**< SoE state machine to use. */
|
||||
ec_fsm_pdo_t *fsm_pdo, /**< PDO configuration state machine to use. */
|
||||
ec_fsm_pdo_t *fsm_pdo, /**< PDO config. state machine to use. */
|
||||
ec_fsm_eoe_t *fsm_eoe /**< EoE state machine to use. */
|
||||
)
|
||||
{
|
||||
@@ -1030,7 +1030,7 @@ void ec_fsm_slave_config_state_pdo_conf(
|
||||
ec_fsm_slave_config_t *fsm /**< slave state machine */
|
||||
)
|
||||
{
|
||||
// TODO check for config here
|
||||
// TODO(fp) check for config here
|
||||
|
||||
if (ec_fsm_pdo_exec(fsm->fsm_pdo, fsm->datagram)) {
|
||||
return;
|
||||
@@ -1476,7 +1476,6 @@ void ec_fsm_slave_config_state_dc_sync_check(
|
||||
diff_ms = (datagram->jiffies_received - fsm->jiffies_start) * 1000 / HZ;
|
||||
|
||||
if (abs_sync_diff > EC_DC_MAX_SYNC_DIFF_NS) {
|
||||
|
||||
if (diff_ms >= EC_DC_SYNC_WAIT_MS) {
|
||||
EC_SLAVE_WARN(slave, "Slave did not sync after %lu ms.\n",
|
||||
diff_ms);
|
||||
|
||||
+4
-5
@@ -24,8 +24,8 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef __EC_MASTER_GLOBALS_H__
|
||||
#define __EC_MASTER_GLOBALS_H__
|
||||
#ifndef MASTER_GLOBALS_H_
|
||||
#define MASTER_GLOBALS_H_
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../include/ecrt.h"
|
||||
@@ -171,8 +171,7 @@ typedef struct {
|
||||
*/
|
||||
typedef enum {
|
||||
EC_DC_32, /**< 32 bit. */
|
||||
EC_DC_64 /*< 64 bit for system time, system time offset and
|
||||
port 0 receive time. */
|
||||
EC_DC_64 /*< 64 bit for system time, time offset and port receive time. */
|
||||
} ec_slave_dc_range_t;
|
||||
|
||||
/** EtherCAT slave sync signal configuration.
|
||||
@@ -311,4 +310,4 @@ typedef struct ec_slave ec_slave_t; /**< \see ec_slave. */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#endif
|
||||
#endif // MASTER_GLOBALS_H_
|
||||
|
||||
+16
-28
@@ -1,6 +1,6 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006-2020 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
* Copyright (C) 2006-2026 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT Master.
|
||||
*
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "slave_config.h"
|
||||
#include "device.h"
|
||||
#include "datagram.h"
|
||||
#include "smp.h"
|
||||
|
||||
#ifdef EC_EOE
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
@@ -62,23 +63,6 @@
|
||||
rt_mutex_lock_interruptible(lock, 0)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 47)
|
||||
|
||||
#define smp_store_release(p, v) \
|
||||
do { \
|
||||
smp_mb(); \
|
||||
ACCESS_ONCE(*p) = (v); \
|
||||
} while (0)
|
||||
|
||||
#define smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
|
||||
smp_mb(); \
|
||||
___p1; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
#include "master.h"
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -863,7 +847,7 @@ void ec_master_inject_external_datagrams(
|
||||
queue_size = new_queue_size;
|
||||
}
|
||||
else if (datagram->data_size > master->max_queue_size) {
|
||||
datagram->state = EC_DATAGRAM_ERROR;
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_ERROR);
|
||||
EC_MASTER_ERR(master, "External datagram %s is too large,"
|
||||
" size=%zu, max_queue_size=%zu\n",
|
||||
datagram->name, datagram->data_size,
|
||||
@@ -884,7 +868,7 @@ void ec_master_inject_external_datagrams(
|
||||
unsigned int time_us;
|
||||
#endif
|
||||
|
||||
datagram->state = EC_DATAGRAM_ERROR;
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_ERROR);
|
||||
|
||||
#if defined EC_RT_SYSLOG || DEBUG_INJECT
|
||||
#ifdef EC_HAVE_CYCLES
|
||||
@@ -981,13 +965,13 @@ void ec_master_queue_datagram(
|
||||
EC_MASTER_DBG(master, 1,
|
||||
"Datagram %p already queued (skipping).\n", datagram);
|
||||
#endif
|
||||
datagram->state = EC_DATAGRAM_QUEUED;
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_QUEUED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&datagram->queue, &master->datagram_queue);
|
||||
datagram->state = EC_DATAGRAM_QUEUED;
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_QUEUED);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -1116,12 +1100,12 @@ void ec_master_send_datagrams(
|
||||
|
||||
// set datagram states and sending timestamps
|
||||
list_for_each_entry_safe(datagram, next, &sent_datagrams, sent) {
|
||||
datagram->state = EC_DATAGRAM_SENT;
|
||||
#ifdef EC_HAVE_CYCLES
|
||||
datagram->cycles_sent = cycles_sent;
|
||||
#endif
|
||||
datagram->jiffies_sent = jiffies_sent;
|
||||
list_del_init(&datagram->sent); // empty list of sent datagrams
|
||||
list_del_init(&datagram->sent); // remove from sent queue
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_SENT);
|
||||
}
|
||||
|
||||
frame_count++;
|
||||
@@ -1265,15 +1249,19 @@ void ec_master_receive_datagrams(
|
||||
datagram->working_counter = EC_READ_U16(cur_data);
|
||||
cur_data += EC_DATAGRAM_FOOTER_SIZE;
|
||||
|
||||
// dequeue the received datagram
|
||||
datagram->state = EC_DATAGRAM_RECEIVED;
|
||||
// set the receive time
|
||||
#ifdef EC_HAVE_CYCLES
|
||||
datagram->cycles_received =
|
||||
master->devices[EC_DEVICE_MAIN].cycles_poll;
|
||||
#endif
|
||||
datagram->jiffies_received =
|
||||
master->devices[EC_DEVICE_MAIN].jiffies_poll;
|
||||
|
||||
// dequeue the received datagram
|
||||
list_del_init(&datagram->queue);
|
||||
|
||||
// set the state (with a barrier)
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_RECEIVED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2478,8 +2466,8 @@ int ecrt_master_send(ec_master_t *master)
|
||||
list_for_each_entry_safe(datagram, n,
|
||||
&master->datagram_queue, queue) {
|
||||
if (datagram->device_index == dev_idx) {
|
||||
datagram->state = EC_DATAGRAM_ERROR;
|
||||
list_del_init(&datagram->queue);
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2527,7 +2515,7 @@ int ecrt_master_receive(ec_master_t *master)
|
||||
datagram->jiffies_sent > timeout_jiffies) {
|
||||
#endif
|
||||
list_del_init(&datagram->queue);
|
||||
datagram->state = EC_DATAGRAM_TIMED_OUT;
|
||||
smp_store_release(&datagram->state, EC_DATAGRAM_TIMED_OUT);
|
||||
master->stats.timeouts++;
|
||||
|
||||
#ifdef EC_RT_SYSLOG
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006-2026 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
*
|
||||
* This file is part of the IgH EtherCAT master.
|
||||
*
|
||||
* The file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation; version 2.1 of the License.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/** \file
|
||||
* Definitions of Kernel SMP macros.
|
||||
*/
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef MASTER_SMP_H_
|
||||
#define MASTER_SMP_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Define SMP macros on kernel versions where they did not exist yet.
|
||||
*/
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 47)
|
||||
|
||||
#define smp_store_release(p, v) \
|
||||
do { \
|
||||
smp_mb(); \
|
||||
ACCESS_ONCE(*p) = (v); \
|
||||
} while (0)
|
||||
|
||||
#define smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
|
||||
smp_mb(); \
|
||||
___p1; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#endif // MASTER_SMP_H_
|
||||
Reference in New Issue
Block a user