Implemented EoE Set IP parameter request via command-line tool.
authorFlorian Pose <fp@igh-essen.com>
Wed, 12 Nov 2014 14:42:17 +0100
changeset 2597 0e145bb05859
parent 2596 d71acfbd7319
child 2598 19ff84bbbcb3
Implemented EoE Set IP parameter request via command-line tool.
master/Kbuild.in
master/Makefile.am
master/eoe_request.c
master/eoe_request.h
master/fsm_eoe.c
master/fsm_eoe.h
master/fsm_slave.c
master/fsm_slave.h
master/globals.h
master/ioctl.c
master/ioctl.h
master/slave.c
master/slave.h
tool/CommandIp.cpp
tool/CommandIp.h
tool/Makefile.am
tool/MasterDevice.cpp
tool/MasterDevice.h
tool/main.cpp
--- a/master/Kbuild.in	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/Kbuild.in	Wed Nov 12 14:42:17 2014 +0100
@@ -40,10 +40,12 @@
 	datagram_pair.o \
 	device.o \
 	domain.o \
+	eoe_request.o \
 	fmmu_config.o \
 	foe_request.o \
 	fsm_change.o \
 	fsm_coe.o \
+	fsm_eoe.o \
 	fsm_foe.o \
 	fsm_master.o \
 	fsm_pdo.o \
--- a/master/Makefile.am	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/Makefile.am	Wed Nov 12 14:42:17 2014 +0100
@@ -37,12 +37,14 @@
 	device.c device.h \
 	domain.c domain.h \
 	doxygen.c \
+	eoe_request.c eoe_request.h \
 	ethernet.c ethernet.h \
 	fmmu_config.c fmmu_config.h \
 	foe.h \
 	foe_request.c foe_request.h \
 	fsm_change.c fsm_change.h \
 	fsm_coe.c fsm_coe.h \
+	fsm_eoe.c fsm_eoe.h \
 	fsm_foe.c fsm_foe.h \
 	fsm_master.c fsm_master.h \
 	fsm_pdo.c fsm_pdo.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/eoe_request.c	Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/** \file
+ * Ethernet-over-EtherCAT request functions.
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+
+#include "eoe_request.h"
+
+/*****************************************************************************/
+
+/** EoE request constructor.
+ */
+void ec_eoe_request_init(
+        ec_eoe_request_t *req /**< EoE request. */
+        )
+{
+    INIT_LIST_HEAD(&req->list);
+    req->state = EC_INT_REQUEST_INIT;
+    req->jiffies_sent = 0U;
+
+    req->mac_address_included = 0;
+    req->ip_address_included = 0;
+    req->subnet_mask_included = 0;
+    req->gateway_included = 0;
+    req->dns_included = 0;
+    req->name_included = 0;
+
+    memset(req->mac_address, 0x00, ETH_ALEN);
+    req->ip_address = 0;
+    req->subnet_mask = 0;
+    req->gateway = 0;
+    req->dns = 0;
+    req->name[0] = 0x00;
+
+    req->result = 0x0000;
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/eoe_request.h	Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT EoE request structure.
+*/
+
+/*****************************************************************************/
+
+#ifndef __EC_EOE_REQUEST_H__
+#define __EC_EOE_REQUEST_H__
+
+#include <linux/list.h>
+#include <linux/etherdevice.h> // ETH_ALEN
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/** Ethernet-over-EtherCAT set IP parameter request.
+ */
+typedef struct {
+    struct list_head list; /**< List item. */
+    ec_internal_request_state_t state; /**< Request state. */
+    unsigned long jiffies_sent; /**< Jiffies, when the request was sent. */
+
+    uint8_t mac_address_included;
+    uint8_t ip_address_included;
+    uint8_t subnet_mask_included;
+    uint8_t gateway_included;
+    uint8_t dns_included;
+    uint8_t name_included;
+
+    unsigned char mac_address[ETH_ALEN];
+    uint32_t ip_address;
+    uint32_t subnet_mask;
+    uint32_t gateway;
+    uint32_t dns;
+    char name[EC_MAX_HOSTNAME_SIZE];
+
+    uint16_t result;
+} ec_eoe_request_t;
+
+/*****************************************************************************/
+
+void ec_eoe_request_init(ec_eoe_request_t *);
+
+/*****************************************************************************/
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fsm_eoe.c	Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,485 @@
+/******************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/**
+   \file
+   EtherCAT EoE state machines.
+*/
+
+/*****************************************************************************/
+
+#include "globals.h"
+#include "master.h"
+#include "mailbox.h"
+#include "fsm_eoe.h"
+
+/*****************************************************************************/
+
+/** Maximum time to wait for a set IP parameter response.
+ */
+#define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms]
+
+/*****************************************************************************/
+
+void ec_fsm_eoe_set_ip_start(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_set_ip_request(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_set_ip_check(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_set_ip_response(ec_fsm_eoe_t *, ec_datagram_t *);
+
+void ec_fsm_eoe_end(ec_fsm_eoe_t *, ec_datagram_t *);
+void ec_fsm_eoe_error(ec_fsm_eoe_t *, ec_datagram_t *);
+
+/*****************************************************************************/
+
+/** Constructor.
+ */
+void ec_fsm_eoe_init(
+        ec_fsm_eoe_t *fsm /**< finite state machine */
+        )
+{
+    fsm->slave = NULL;
+    fsm->retries = 0;
+    fsm->state = NULL;
+    fsm->datagram = NULL;
+    fsm->jiffies_start = 0;
+    fsm->request = NULL;
+}
+
+/*****************************************************************************/
+
+/** Destructor.
+ */
+void ec_fsm_eoe_clear(
+        ec_fsm_eoe_t *fsm /**< finite state machine */
+        )
+{
+}
+
+/*****************************************************************************/
+
+/** Starts to set the EoE IP partameters of a slave.
+ */
+void ec_fsm_eoe_set_ip_param(
+        ec_fsm_eoe_t *fsm, /**< State machine. */
+        ec_slave_t *slave, /**< EtherCAT slave. */
+        ec_eoe_request_t *request /**< EoE request. */
+        )
+{
+    fsm->slave = slave;
+    fsm->request = request;
+    fsm->state = ec_fsm_eoe_set_ip_start;
+}
+
+/*****************************************************************************/
+
+/** Executes the current state of the state machine.
+ *
+ * \return 1 if the datagram was used, else 0.
+ */
+int ec_fsm_eoe_exec(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    int datagram_used = 0;
+
+    if (fsm->datagram &&
+            (fsm->datagram->state == EC_DATAGRAM_INIT ||
+             fsm->datagram->state == EC_DATAGRAM_QUEUED ||
+             fsm->datagram->state == EC_DATAGRAM_SENT)) {
+        // datagram not received yet
+        return datagram_used;
+    }
+
+    fsm->state(fsm, datagram);
+
+    datagram_used =
+        fsm->state != ec_fsm_eoe_end && fsm->state != ec_fsm_eoe_error;
+
+    if (datagram_used) {
+        fsm->datagram = datagram;
+    } else {
+        fsm->datagram = NULL;
+    }
+
+    return datagram_used;
+}
+
+/*****************************************************************************/
+
+/** Returns, if the state machine terminated with success.
+ *
+ * \return non-zero if successful.
+ */
+int ec_fsm_eoe_success(const ec_fsm_eoe_t *fsm /**< Finite state machine */)
+{
+    return fsm->state == ec_fsm_eoe_end;
+}
+
+/******************************************************************************
+ * EoE set IP parameter state machine
+ *****************************************************************************/
+
+/** Prepare a set IP parameters operation.
+ *
+ * \return 0 on success, otherwise a negative error code.
+ */
+int ec_fsm_eoe_prepare_set(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    uint8_t *data, *cur;
+    ec_slave_t *slave = fsm->slave;
+    ec_master_t *master = slave->master;
+    ec_eoe_request_t *req = fsm->request;
+    size_t size = 8;
+
+    if (req->mac_address_included) {
+        size += ETH_ALEN;
+    }
+
+    if (req->ip_address_included) {
+        size += 4;
+    }
+
+    if (req->subnet_mask_included) {
+        size += 4;
+    }
+
+    if (req->gateway_included) {
+        size += 4;
+    }
+
+    if (req->dns_included) {
+        size += 4;
+    }
+
+    if (req->name_included) {
+        size += EC_MAX_HOSTNAME_SIZE;
+    }
+
+    data = ec_slave_mbox_prepare_send(slave, datagram, EC_MBOX_TYPE_EOE,
+            size);
+    if (IS_ERR(data)) {
+        return PTR_ERR(data);
+    }
+
+    EC_WRITE_U8(data, EC_EOE_FRAMETYPE_SET_IP_REQ); // Set IP parameter req.
+    EC_WRITE_U8(data + 1, 0x01); // last fragment, no timestamps
+    EC_WRITE_U16(data + 2, 0x0000); // fragment no., offset, frame no.
+
+    EC_WRITE_U32(data + 4,
+            ((req->mac_address_included != 0) << 0) |
+            ((req->ip_address_included != 0) << 1) |
+            ((req->subnet_mask_included != 0) << 2) |
+            ((req->gateway_included != 0) << 3) |
+            ((req->dns_included != 0) << 4) |
+            ((req->name_included != 0) << 5)
+            );
+
+    cur = data + 8;
+
+    if (req->mac_address_included) {
+        memcpy(cur, req->mac_address, ETH_ALEN);
+        cur += ETH_ALEN;
+    }
+
+    if (req->ip_address_included) {
+        memcpy(cur, &req->ip_address, 4);
+        cur += 4;
+    }
+
+    if (req->subnet_mask_included) {
+        memcpy(cur, &req->subnet_mask, 4);
+        cur += 4;
+    }
+
+    if (req->gateway_included) {
+        memcpy(cur, &req->gateway, 4);
+        cur += 4;
+    }
+
+    if (req->dns_included) {
+        memcpy(cur, &req->dns, 4);
+        cur += 4;
+    }
+
+    if (req->name_included) {
+        memcpy(cur, req->name, EC_MAX_HOSTNAME_SIZE);
+        cur += EC_MAX_HOSTNAME_SIZE;
+    }
+
+    if (master->debug_level) {
+        EC_SLAVE_DBG(slave, 0, "Set IP parameter request:\n");
+        ec_print_data(data, cur - data);
+    }
+
+    fsm->request->jiffies_sent = jiffies;
+
+    return 0;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP START.
+ */
+void ec_fsm_eoe_set_ip_start(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+
+    EC_SLAVE_DBG(slave, 1, "Setting IP parameters.\n");
+
+    if (!(slave->sii.mailbox_protocols & EC_MBOX_EOE)) {
+        EC_SLAVE_ERR(slave, "Slave does not support EoE!\n");
+        fsm->state = ec_fsm_eoe_error;
+        return;
+    }
+
+    if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
+        fsm->state = ec_fsm_eoe_error;
+        return;
+    }
+
+    fsm->retries = EC_FSM_RETRIES;
+    fsm->state = ec_fsm_eoe_set_ip_request;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP REQUEST.
+ */
+void ec_fsm_eoe_set_ip_request(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+
+    if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
+        if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
+            fsm->state = ec_fsm_eoe_error;
+        }
+        return;
+    }
+
+    if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Failed to receive EoE set IP parameter"
+                " request: ");
+        ec_datagram_print_state(fsm->datagram);
+        return;
+    }
+
+    if (fsm->datagram->working_counter != 1) {
+        unsigned long diff_ms =
+            (jiffies - fsm->request->jiffies_sent) * 1000 / HZ;
+
+        if (!fsm->datagram->working_counter) {
+            if (diff_ms < EC_EOE_RESPONSE_TIMEOUT) {
+                // no response; send request datagram again
+                if (ec_fsm_eoe_prepare_set(fsm, datagram)) {
+                    fsm->state = ec_fsm_eoe_error;
+                }
+                return;
+            }
+        }
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Reception of EoE set IP parameter request"
+                " failed after %lu ms: ", diff_ms);
+        ec_datagram_print_wc_error(fsm->datagram);
+        return;
+    }
+
+    fsm->jiffies_start = fsm->datagram->jiffies_sent;
+    ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+    fsm->retries = EC_FSM_RETRIES;
+    fsm->state = ec_fsm_eoe_set_ip_check;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP CHECK.
+ */
+void ec_fsm_eoe_set_ip_check(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+
+    if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
+        ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+        return;
+    }
+
+    if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Failed to receive EoE mailbox check datagram: ");
+        ec_datagram_print_state(fsm->datagram);
+        return;
+    }
+
+    if (fsm->datagram->working_counter != 1) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Reception of EoE mailbox check"
+                " datagram failed: ");
+        ec_datagram_print_wc_error(fsm->datagram);
+        return;
+    }
+
+    if (!ec_slave_mbox_check(fsm->datagram)) {
+        unsigned long diff_ms =
+            (fsm->datagram->jiffies_received - fsm->jiffies_start) *
+            1000 / HZ;
+        if (diff_ms >= EC_EOE_RESPONSE_TIMEOUT) {
+            fsm->state = ec_fsm_eoe_error;
+            EC_SLAVE_ERR(slave, "Timeout after %lu ms while waiting for"
+                    " set IP parameter response.\n", diff_ms);
+            return;
+        }
+
+        ec_slave_mbox_prepare_check(slave, datagram); // can not fail.
+        fsm->retries = EC_FSM_RETRIES;
+        return;
+    }
+
+    // fetch response
+    ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
+    fsm->retries = EC_FSM_RETRIES;
+    fsm->state = ec_fsm_eoe_set_ip_response;
+}
+
+/*****************************************************************************/
+
+/** EoE state: SET IP RESPONSE.
+ */
+void ec_fsm_eoe_set_ip_response(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+    ec_master_t *master = slave->master;
+    uint8_t *data, mbox_prot, frame_type;
+    size_t rec_size;
+    ec_eoe_request_t *req = fsm->request;
+
+    if (fsm->datagram->state == EC_DATAGRAM_TIMED_OUT && fsm->retries--) {
+        ec_slave_mbox_prepare_fetch(slave, datagram); // can not fail.
+        return;
+    }
+
+    if (fsm->datagram->state != EC_DATAGRAM_RECEIVED) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Failed to receive EoE read response datagram: ");
+        ec_datagram_print_state(fsm->datagram);
+        return;
+    }
+
+    if (fsm->datagram->working_counter != 1) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Reception of EoE read response failed: ");
+        ec_datagram_print_wc_error(fsm->datagram);
+        return;
+    }
+
+    data = ec_slave_mbox_fetch(slave, fsm->datagram, &mbox_prot, &rec_size);
+    if (IS_ERR(data)) {
+        fsm->state = ec_fsm_eoe_error;
+        return;
+    }
+
+    if (master->debug_level) {
+        EC_SLAVE_DBG(slave, 0, "Set IP parameter response:\n");
+        ec_print_data(data, rec_size);
+    }
+
+    if (mbox_prot != EC_MBOX_TYPE_EOE) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Received mailbox protocol 0x%02X as response.\n",
+                mbox_prot);
+        return;
+    }
+
+    if (rec_size < 4) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_ERR(slave, "Received currupted EoE set IP parameter response"
+                " (%zu bytes)!\n", rec_size);
+        ec_print_data(data, rec_size);
+        return;
+    }
+
+    frame_type = EC_READ_U8(data) & 0x0f;
+
+    if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) {
+        EC_SLAVE_ERR(slave, "Received no set IP parameter response"
+                " (frame type %x).\n", frame_type);
+        ec_print_data(data, rec_size);
+        fsm->state = ec_fsm_eoe_error;
+        return;
+    }
+
+    req->result = EC_READ_U16(data + 2);
+
+    if (req->result) {
+        fsm->state = ec_fsm_eoe_error;
+        EC_SLAVE_DBG(slave, 1, "EoE set IP parameters failed with result code"
+                " 0x%04X.\n", req->result);
+    } else {
+        fsm->state = ec_fsm_eoe_end; // success
+    }
+}
+
+/*****************************************************************************/
+
+/** State: ERROR.
+ */
+void ec_fsm_eoe_error(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+}
+
+/*****************************************************************************/
+
+/** State: END.
+ */
+void ec_fsm_eoe_end(
+        ec_fsm_eoe_t *fsm, /**< finite state machine */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+}
+
+/*****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/master/fsm_eoe.h	Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+/**
+   \file
+   EtherCAT EoE set IP parameter state machines.
+*/
+
+/****************************************************************************/
+
+#ifndef __EC_FSM_EOE_H__
+#define __EC_FSM_EOE_H__
+
+#include "globals.h"
+#include "datagram.h"
+#include "slave.h"
+#include "eoe_request.h"
+
+/****************************************************************************/
+
+typedef struct ec_fsm_eoe ec_fsm_eoe_t; /**< \see ec_fsm_eoe */
+
+/** Finite state machines for the Ethernet over EtherCAT protocol.
+ */
+struct ec_fsm_eoe {
+    ec_slave_t *slave; /**< slave the FSM runs on */
+    unsigned int retries; /**< retries upon datagram timeout */
+
+    void (*state)(ec_fsm_eoe_t *, ec_datagram_t *); /**< EoE state function */
+    ec_datagram_t *datagram; /**< Datagram used in the previous step. */
+    unsigned long jiffies_start; /**< Timestamp. */
+    ec_eoe_request_t *request; /**< EoE request */
+};
+
+/****************************************************************************/
+
+void ec_fsm_eoe_init(ec_fsm_eoe_t *);
+void ec_fsm_eoe_clear(ec_fsm_eoe_t *);
+
+void ec_fsm_eoe_set_ip_param(ec_fsm_eoe_t *, ec_slave_t *,
+        ec_eoe_request_t *);
+
+int ec_fsm_eoe_exec(ec_fsm_eoe_t *, ec_datagram_t *);
+int ec_fsm_eoe_success(const ec_fsm_eoe_t *);
+
+/****************************************************************************/
+
+#endif
--- a/master/fsm_slave.c	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/fsm_slave.c	Wed Nov 12 14:42:17 2014 +0100
@@ -52,6 +52,8 @@
 void ec_fsm_slave_state_foe_request(ec_fsm_slave_t *, ec_datagram_t *);
 int ec_fsm_slave_action_process_soe(ec_fsm_slave_t *, ec_datagram_t *);
 void ec_fsm_slave_state_soe_request(ec_fsm_slave_t *, ec_datagram_t *);
+int ec_fsm_slave_action_process_eoe(ec_fsm_slave_t *, ec_datagram_t *);
+void ec_fsm_slave_state_eoe_request(ec_fsm_slave_t *, ec_datagram_t *);
 
 /*****************************************************************************/
 
@@ -71,11 +73,13 @@
     fsm->reg_request = NULL;
     fsm->foe_request = NULL;
     fsm->soe_request = NULL;
+    fsm->eoe_request = NULL;
 
     // Init sub-state-machines
     ec_fsm_coe_init(&fsm->fsm_coe);
     ec_fsm_foe_init(&fsm->fsm_foe);
     ec_fsm_soe_init(&fsm->fsm_soe);
+    ec_fsm_eoe_init(&fsm->fsm_eoe);
 }
 
 /*****************************************************************************/
@@ -108,10 +112,16 @@
         wake_up_all(&fsm->slave->master->request_queue);
     }
 
+    if (fsm->eoe_request) {
+        fsm->soe_request->state = EC_INT_REQUEST_FAILURE;
+        wake_up_all(&fsm->slave->master->request_queue);
+    }
+
     // clear sub-state machines
     ec_fsm_coe_clear(&fsm->fsm_coe);
     ec_fsm_foe_clear(&fsm->fsm_foe);
     ec_fsm_soe_clear(&fsm->fsm_soe);
+    ec_fsm_eoe_clear(&fsm->fsm_eoe);
 }
 
 /*****************************************************************************/
@@ -210,6 +220,11 @@
     if (ec_fsm_slave_action_process_soe(fsm, datagram)) {
         return;
     }
+
+    // Check for pending EoE IP parameter requests
+    if (ec_fsm_slave_action_process_eoe(fsm, datagram)) {
+        return;
+    }
 }
 
 /*****************************************************************************/
@@ -240,7 +255,7 @@
         request->state = EC_INT_REQUEST_FAILURE;
         wake_up_all(&slave->master->request_queue);
         fsm->state = ec_fsm_slave_state_idle;
-        return 1;
+        return 0;
     }
 
     if (slave->current_state == EC_SLAVE_STATE_INIT) {
@@ -248,7 +263,7 @@
         request->state = EC_INT_REQUEST_FAILURE;
         wake_up_all(&slave->master->request_queue);
         fsm->state = ec_fsm_slave_state_idle;
-        return 1;
+        return 0;
     }
 
     fsm->sdo_request = request;
@@ -342,7 +357,7 @@
         wake_up_all(&slave->master->request_queue);
         fsm->reg_request = NULL;
         fsm->state = ec_fsm_slave_state_idle;
-        return 1;
+        return 0;
     }
 
     // Found pending register request. Execute it!
@@ -444,7 +459,7 @@
         request->state = EC_INT_REQUEST_FAILURE;
         wake_up_all(&slave->master->request_queue);
         fsm->state = ec_fsm_slave_state_idle;
-        return 1;
+        return 0;
     }
 
     request->state = EC_INT_REQUEST_BUSY;
@@ -521,7 +536,7 @@
         req->state = EC_INT_REQUEST_FAILURE;
         wake_up_all(&slave->master->request_queue);
         fsm->state = ec_fsm_slave_state_idle;
-        return 1;
+        return 0;
     }
 
     if (slave->current_state == EC_SLAVE_STATE_INIT) {
@@ -580,3 +595,85 @@
 }
 
 /*****************************************************************************/
+
+/** Check for pending EoE IP parameter requests and process one.
+ *
+ * \return non-zero, if a request is processed.
+ */
+int ec_fsm_slave_action_process_eoe(
+        ec_fsm_slave_t *fsm, /**< Slave state machine. */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+    ec_eoe_request_t *request;
+
+    if (list_empty(&slave->eoe_requests)) {
+        return 0;
+    }
+
+    // take the first request to be processed
+    request = list_entry(slave->eoe_requests.next, ec_eoe_request_t, list);
+    list_del_init(&request->list); // dequeue
+
+    if (slave->current_state & EC_SLAVE_STATE_ACK_ERR) {
+        EC_SLAVE_WARN(slave, "Aborting EoE request,"
+                " slave has error flag set.\n");
+        request->state = EC_INT_REQUEST_FAILURE;
+        wake_up_all(&slave->master->request_queue);
+        fsm->state = ec_fsm_slave_state_idle;
+        return 0;
+    }
+
+    if (slave->current_state == EC_SLAVE_STATE_INIT) {
+        EC_SLAVE_WARN(slave, "Aborting EoE request, slave is in INIT.\n");
+        request->state = EC_INT_REQUEST_FAILURE;
+        wake_up_all(&slave->master->request_queue);
+        fsm->state = ec_fsm_slave_state_idle;
+        return 0;
+    }
+
+    fsm->eoe_request = request;
+    request->state = EC_INT_REQUEST_BUSY;
+
+    // Found pending request. Execute it!
+    EC_SLAVE_DBG(slave, 1, "Processing EoE request...\n");
+
+    // Start EoE command
+    fsm->state = ec_fsm_slave_state_eoe_request;
+    ec_fsm_eoe_set_ip_param(&fsm->fsm_eoe, slave, request);
+    ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram); // execute immediately
+    return 1;
+}
+
+/*****************************************************************************/
+
+/** Slave state: EOE_REQUEST.
+ */
+void ec_fsm_slave_state_eoe_request(
+        ec_fsm_slave_t *fsm, /**< Slave state machine. */
+        ec_datagram_t *datagram /**< Datagram to use. */
+        )
+{
+    ec_slave_t *slave = fsm->slave;
+    ec_eoe_request_t *req = fsm->eoe_request;
+
+    if (ec_fsm_eoe_exec(&fsm->fsm_eoe, datagram)) {
+        return;
+    }
+
+    if (ec_fsm_eoe_success(&fsm->fsm_eoe)) {
+		req->state = EC_INT_REQUEST_SUCCESS;
+		EC_SLAVE_DBG(slave, 1, "Finished EoE request.\n");
+    }
+	else {
+        req->state = EC_INT_REQUEST_FAILURE;
+        EC_SLAVE_ERR(slave, "Failed to process EoE request.\n");
+	}
+
+    wake_up_all(&slave->master->request_queue);
+    fsm->eoe_request = NULL;
+    fsm->state = ec_fsm_slave_state_ready;
+}
+
+/*****************************************************************************/
--- a/master/fsm_slave.h	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/fsm_slave.h	Wed Nov 12 14:42:17 2014 +0100
@@ -41,9 +41,11 @@
 #include "datagram.h"
 #include "sdo_request.h"
 #include "reg_request.h"
+#include "eoe_request.h"
 #include "fsm_coe.h"
 #include "fsm_foe.h"
 #include "fsm_soe.h"
+#include "fsm_eoe.h"
 
 /*****************************************************************************/
 
@@ -62,10 +64,12 @@
     ec_foe_request_t *foe_request; /**< FoE request to process. */
     off_t foe_index; /**< Index to FoE write request data. */
     ec_soe_request_t *soe_request; /**< SoE request to process. */
+    ec_eoe_request_t *eoe_request; /**< SoE request to process. */
 
     ec_fsm_coe_t fsm_coe; /**< CoE state machine. */
     ec_fsm_foe_t fsm_foe; /**< FoE state machine. */
     ec_fsm_soe_t fsm_soe; /**< SoE state machine. */
+    ec_fsm_eoe_t fsm_eoe; /**< EoE state machine. */
 };
 
 /*****************************************************************************/
--- a/master/globals.h	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/globals.h	Wed Nov 12 14:42:17 2014 +0100
@@ -115,6 +115,12 @@
  **/
 #define EC_DATAGRAM_NAME_SIZE 20
 
+/** Maximum hostname size.
+ *
+ * Used inside the EoE set IP parameter request.
+ */
+#define EC_MAX_HOSTNAME_SIZE 32
+
 /** Slave state mask.
  *
  * Apply this mask to a slave state byte to get the slave state without
--- a/master/ioctl.c	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/ioctl.c	Wed Nov 12 14:42:17 2014 +0100
@@ -1550,6 +1550,89 @@
 
 /*****************************************************************************/
 
+/** Request EoE IP parameter setting.
+ *
+ * \return Zero on success, otherwise a negative error code.
+ */
+static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param(
+        ec_master_t *master, /**< EtherCAT master. */
+        void *arg /**< ioctl() argument. */
+        )
+{
+    ec_ioctl_slave_eoe_ip_t io;
+    ec_eoe_request_t req;
+    ec_slave_t *slave;
+
+    if (copy_from_user(&io, (void __user *) arg, sizeof(io))) {
+        return -EFAULT;
+    }
+
+    // init EoE request
+    ec_eoe_request_init(&req);
+
+    req.mac_address_included = io.mac_address_included;
+    req.ip_address_included = io.ip_address_included;
+    req.subnet_mask_included = io.subnet_mask_included;
+    req.gateway_included = io.gateway_included;
+    req.dns_included = io.dns_included;
+    req.name_included = io.name_included;
+
+    memcpy(req.mac_address, io.mac_address, ETH_ALEN);
+    req.ip_address = io.ip_address;
+    req.subnet_mask = io.subnet_mask;
+    req.gateway = io.gateway;
+    req.dns = io.dns;
+    memcpy(req.name, io.name, EC_MAX_HOSTNAME_SIZE);
+
+    req.state = EC_INT_REQUEST_QUEUED;
+
+    if (down_interruptible(&master->master_sem)) {
+        return -EINTR;
+    }
+
+    if (!(slave = ec_master_find_slave(
+                    master, 0, io.slave_position))) {
+        up(&master->master_sem);
+        EC_MASTER_ERR(master, "Slave %u does not exist!\n",
+                io.slave_position);
+        return -EINVAL;
+    }
+
+    EC_MASTER_DBG(master, 1, "Scheduling EoE request.\n");
+
+    // schedule request.
+    list_add_tail(&req.list, &slave->eoe_requests);
+
+    up(&master->master_sem);
+
+    // wait for processing through FSM
+    if (wait_event_interruptible(master->request_queue,
+                req.state != EC_INT_REQUEST_QUEUED)) {
+        // interrupted by signal
+        down(&master->master_sem);
+        if (req.state == EC_INT_REQUEST_QUEUED) {
+            // abort request
+            list_del(&req.list);
+            up(&master->master_sem);
+            return -EINTR;
+        }
+        up(&master->master_sem);
+    }
+
+    // wait until master FSM has finished processing
+    wait_event(master->request_queue, req.state != EC_INT_REQUEST_BUSY);
+
+    io.result = req.result;
+
+    if (copy_to_user((void __user *) arg, &io, sizeof(io))) {
+        return -EFAULT;
+    }
+
+    return req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
+}
+
+/*****************************************************************************/
+
 /** Request the master from userspace.
  *
  * \return Zero on success, otherwise a negative error code.
@@ -4205,6 +4288,13 @@
         case EC_IOCTL_SLAVE_SOE_READ:
             ret = ec_ioctl_slave_soe_read(master, arg);
             break;
+        case EC_IOCTL_SLAVE_EOE_IP_PARAM:
+            if (!ctx->writable) {
+                ret = -EPERM;
+                break;
+            }
+            ret = ec_ioctl_slave_eoe_ip_param(master, arg);
+            break;
         case EC_IOCTL_SLAVE_SOE_WRITE:
             if (!ctx->writable) {
                 ret = -EPERM;
--- a/master/ioctl.h	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/ioctl.h	Wed Nov 12 14:42:17 2014 +0100
@@ -56,7 +56,7 @@
  *
  * Increment this when changing the ioctl interface!
  */
-#define EC_IOCTL_VERSION_MAGIC 28
+#define EC_IOCTL_VERSION_MAGIC 29
 
 // Command-line tool
 #define EC_IOCTL_MODULE                EC_IOR(0x00, ec_ioctl_module_t)
@@ -83,75 +83,76 @@
 #define EC_IOCTL_SLAVE_FOE_WRITE       EC_IOW(0x15, ec_ioctl_slave_foe_t)
 #define EC_IOCTL_SLAVE_SOE_READ       EC_IOWR(0x16, ec_ioctl_slave_soe_read_t)
 #define EC_IOCTL_SLAVE_SOE_WRITE      EC_IOWR(0x17, ec_ioctl_slave_soe_write_t)
-#define EC_IOCTL_CONFIG               EC_IOWR(0x18, ec_ioctl_config_t)
-#define EC_IOCTL_CONFIG_PDO           EC_IOWR(0x19, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_CONFIG_PDO_ENTRY     EC_IOWR(0x1a, ec_ioctl_config_pdo_entry_t)
-#define EC_IOCTL_CONFIG_SDO           EC_IOWR(0x1b, ec_ioctl_config_sdo_t)
-#define EC_IOCTL_CONFIG_IDN           EC_IOWR(0x1c, ec_ioctl_config_idn_t)
+#define EC_IOCTL_SLAVE_EOE_IP_PARAM    EC_IOW(0x18, ec_ioctl_slave_eoe_ip_t)
+#define EC_IOCTL_CONFIG               EC_IOWR(0x19, ec_ioctl_config_t)
+#define EC_IOCTL_CONFIG_PDO           EC_IOWR(0x1a, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_CONFIG_PDO_ENTRY     EC_IOWR(0x1b, ec_ioctl_config_pdo_entry_t)
+#define EC_IOCTL_CONFIG_SDO           EC_IOWR(0x1c, ec_ioctl_config_sdo_t)
+#define EC_IOCTL_CONFIG_IDN           EC_IOWR(0x1d, ec_ioctl_config_idn_t)
 #ifdef EC_EOE
-#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x1d, ec_ioctl_eoe_handler_t)
+#define EC_IOCTL_EOE_HANDLER          EC_IOWR(0x1e, ec_ioctl_eoe_handler_t)
 #endif
 
 // Application interface
-#define EC_IOCTL_REQUEST                EC_IO(0x1e)
-#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x1f)
-#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x20, ec_ioctl_config_t)
-#define EC_IOCTL_SELECT_REF_CLOCK      EC_IOW(0x21, uint32_t)
-#define EC_IOCTL_ACTIVATE              EC_IOR(0x22, ec_ioctl_master_activate_t)
-#define EC_IOCTL_DEACTIVATE             EC_IO(0x23)
-#define EC_IOCTL_SEND                   EC_IO(0x24)
-#define EC_IOCTL_RECEIVE                EC_IO(0x25)
-#define EC_IOCTL_MASTER_STATE          EC_IOR(0x26, ec_master_state_t)
-#define EC_IOCTL_MASTER_LINK_STATE    EC_IOWR(0x27, ec_ioctl_link_state_t)
-#define EC_IOCTL_APP_TIME              EC_IOW(0x28, ec_ioctl_app_time_t)
-#define EC_IOCTL_SYNC_REF               EC_IO(0x29)
-#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x2a)
-#define EC_IOCTL_REF_CLOCK_TIME        EC_IOR(0x2b, uint32_t)
-#define EC_IOCTL_SYNC_MON_QUEUE         EC_IO(0x2c)
-#define EC_IOCTL_SYNC_MON_PROCESS      EC_IOR(0x2d, uint32_t)
-#define EC_IOCTL_RESET                  EC_IO(0x2e)
-#define EC_IOCTL_SC_SYNC               EC_IOW(0x2f, ec_ioctl_config_t)
-#define EC_IOCTL_SC_WATCHDOG           EC_IOW(0x30, ec_ioctl_config_t)
-#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x31, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x32, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x33, ec_ioctl_add_pdo_entry_t)
-#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x34, ec_ioctl_config_pdo_t)
-#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x35, ec_ioctl_reg_pdo_entry_t)
-#define EC_IOCTL_SC_REG_PDO_POS       EC_IOWR(0x36, ec_ioctl_reg_pdo_pos_t)
-#define EC_IOCTL_SC_DC                 EC_IOW(0x37, ec_ioctl_config_t)
-#define EC_IOCTL_SC_SDO                EC_IOW(0x38, ec_ioctl_sc_sdo_t)
-#define EC_IOCTL_SC_EMERG_SIZE         EC_IOW(0x39, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_POP         EC_IOWR(0x3a, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_CLEAR        EC_IOW(0x3b, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_EMERG_OVERRUNS    EC_IOWR(0x3c, ec_ioctl_sc_emerg_t)
-#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x3d, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SC_REG_REQUEST       EC_IOWR(0x3e, ec_ioctl_reg_request_t)
-#define EC_IOCTL_SC_VOE               EC_IOWR(0x3f, ec_ioctl_voe_t)
-#define EC_IOCTL_SC_STATE             EC_IOWR(0x40, ec_ioctl_sc_state_t)
-#define EC_IOCTL_SC_IDN                EC_IOW(0x41, ec_ioctl_sc_idn_t)
-#define EC_IOCTL_DOMAIN_SIZE            EC_IO(0x42)
-#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x43)
-#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x44)
-#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x45)
-#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x46, ec_ioctl_domain_state_t)
-#define EC_IOCTL_SDO_REQUEST_INDEX    EC_IOWR(0x47, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x48, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x49, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
-#define EC_IOCTL_REG_REQUEST_DATA     EC_IOWR(0x4d, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_STATE    EC_IOWR(0x4e, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_WRITE    EC_IOWR(0x4f, ec_ioctl_reg_request_t)
-#define EC_IOCTL_REG_REQUEST_READ     EC_IOWR(0x50, ec_ioctl_reg_request_t)
-#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x51, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x52, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ              EC_IOW(0x53, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x54, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x55, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x56, ec_ioctl_voe_t)
-#define EC_IOCTL_VOE_DATA             EC_IOWR(0x57, ec_ioctl_voe_t)
-#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x58, size_t)
+#define EC_IOCTL_REQUEST                EC_IO(0x1f)
+#define EC_IOCTL_CREATE_DOMAIN          EC_IO(0x20)
+#define EC_IOCTL_CREATE_SLAVE_CONFIG  EC_IOWR(0x21, ec_ioctl_config_t)
+#define EC_IOCTL_SELECT_REF_CLOCK      EC_IOW(0x22, uint32_t)
+#define EC_IOCTL_ACTIVATE              EC_IOR(0x23, ec_ioctl_master_activate_t)
+#define EC_IOCTL_DEACTIVATE             EC_IO(0x24)
+#define EC_IOCTL_SEND                   EC_IO(0x25)
+#define EC_IOCTL_RECEIVE                EC_IO(0x26)
+#define EC_IOCTL_MASTER_STATE          EC_IOR(0x27, ec_master_state_t)
+#define EC_IOCTL_MASTER_LINK_STATE    EC_IOWR(0x28, ec_ioctl_link_state_t)
+#define EC_IOCTL_APP_TIME              EC_IOW(0x29, ec_ioctl_app_time_t)
+#define EC_IOCTL_SYNC_REF               EC_IO(0x2a)
+#define EC_IOCTL_SYNC_SLAVES            EC_IO(0x2b)
+#define EC_IOCTL_REF_CLOCK_TIME        EC_IOR(0x2c, uint32_t)
+#define EC_IOCTL_SYNC_MON_QUEUE         EC_IO(0x2d)
+#define EC_IOCTL_SYNC_MON_PROCESS      EC_IOR(0x2e, uint32_t)
+#define EC_IOCTL_RESET                  EC_IO(0x2f)
+#define EC_IOCTL_SC_SYNC               EC_IOW(0x30, ec_ioctl_config_t)
+#define EC_IOCTL_SC_WATCHDOG           EC_IOW(0x31, ec_ioctl_config_t)
+#define EC_IOCTL_SC_ADD_PDO            EC_IOW(0x32, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_CLEAR_PDOS         EC_IOW(0x33, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_ADD_ENTRY          EC_IOW(0x34, ec_ioctl_add_pdo_entry_t)
+#define EC_IOCTL_SC_CLEAR_ENTRIES      EC_IOW(0x35, ec_ioctl_config_pdo_t)
+#define EC_IOCTL_SC_REG_PDO_ENTRY     EC_IOWR(0x36, ec_ioctl_reg_pdo_entry_t)
+#define EC_IOCTL_SC_REG_PDO_POS       EC_IOWR(0x37, ec_ioctl_reg_pdo_pos_t)
+#define EC_IOCTL_SC_DC                 EC_IOW(0x38, ec_ioctl_config_t)
+#define EC_IOCTL_SC_SDO                EC_IOW(0x39, ec_ioctl_sc_sdo_t)
+#define EC_IOCTL_SC_EMERG_SIZE         EC_IOW(0x3a, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_POP         EC_IOWR(0x3b, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_CLEAR        EC_IOW(0x3c, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_EMERG_OVERRUNS    EC_IOWR(0x3d, ec_ioctl_sc_emerg_t)
+#define EC_IOCTL_SC_SDO_REQUEST       EC_IOWR(0x3e, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SC_REG_REQUEST       EC_IOWR(0x3f, ec_ioctl_reg_request_t)
+#define EC_IOCTL_SC_VOE               EC_IOWR(0x40, ec_ioctl_voe_t)
+#define EC_IOCTL_SC_STATE             EC_IOWR(0x41, ec_ioctl_sc_state_t)
+#define EC_IOCTL_SC_IDN                EC_IOW(0x42, ec_ioctl_sc_idn_t)
+#define EC_IOCTL_DOMAIN_SIZE            EC_IO(0x43)
+#define EC_IOCTL_DOMAIN_OFFSET          EC_IO(0x44)
+#define EC_IOCTL_DOMAIN_PROCESS         EC_IO(0x45)
+#define EC_IOCTL_DOMAIN_QUEUE           EC_IO(0x46)
+#define EC_IOCTL_DOMAIN_STATE         EC_IOWR(0x47, ec_ioctl_domain_state_t)
+#define EC_IOCTL_SDO_REQUEST_INDEX    EC_IOWR(0x48, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_TIMEOUT  EC_IOWR(0x49, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_STATE    EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_READ     EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_WRITE    EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_SDO_REQUEST_DATA     EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
+#define EC_IOCTL_REG_REQUEST_DATA     EC_IOWR(0x4e, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_STATE    EC_IOWR(0x4f, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_WRITE    EC_IOWR(0x50, ec_ioctl_reg_request_t)
+#define EC_IOCTL_REG_REQUEST_READ     EC_IOWR(0x51, ec_ioctl_reg_request_t)
+#define EC_IOCTL_VOE_SEND_HEADER       EC_IOW(0x52, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_REC_HEADER       EC_IOWR(0x53, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ              EC_IOW(0x54, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_READ_NOSYNC       EC_IOW(0x55, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_WRITE            EC_IOWR(0x56, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_EXEC             EC_IOWR(0x57, ec_ioctl_voe_t)
+#define EC_IOCTL_VOE_DATA             EC_IOWR(0x58, ec_ioctl_voe_t)
+#define EC_IOCTL_SET_SEND_INTERVAL     EC_IOW(0x59, size_t)
 
 /*****************************************************************************/
 
@@ -590,6 +591,37 @@
 
 /*****************************************************************************/
 
+#define EC_ETH_ALEN 6
+#ifdef ETH_ALEN
+#if ETH_ALEN != EC_ETH_ALEN
+#error Ethernet address length mismatch
+#endif
+#endif
+
+typedef struct {
+    // input
+    uint16_t slave_position;
+
+    uint8_t mac_address_included;
+    uint8_t ip_address_included;
+    uint8_t subnet_mask_included;
+    uint8_t gateway_included;
+    uint8_t dns_included;
+    uint8_t name_included;
+
+    unsigned char mac_address[EC_ETH_ALEN];
+    uint32_t ip_address;
+    uint32_t subnet_mask;
+    uint32_t gateway;
+    uint32_t dns;
+    char name[EC_MAX_HOSTNAME_SIZE];
+
+	// output
+	uint16_t result;
+} ec_ioctl_slave_eoe_ip_t;
+
+/*****************************************************************************/
+
 typedef struct {
     // outputs
     void *process_data;
--- a/master/slave.c	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/slave.c	Wed Nov 12 14:42:17 2014 +0100
@@ -155,6 +155,7 @@
     INIT_LIST_HEAD(&slave->reg_requests);
     INIT_LIST_HEAD(&slave->foe_requests);
     INIT_LIST_HEAD(&slave->soe_requests);
+    INIT_LIST_HEAD(&slave->eoe_requests);
 
     // create state machine object
     ec_fsm_slave_init(&slave->fsm, slave);
@@ -211,6 +212,15 @@
         request->state = EC_INT_REQUEST_FAILURE;
     }
 
+    while (!list_empty(&slave->eoe_requests)) {
+        ec_eoe_request_t *request =
+            list_entry(slave->eoe_requests.next, ec_eoe_request_t, list);
+        list_del_init(&request->list); // dequeue
+        EC_SLAVE_WARN(slave, "Discarding EoE request,"
+                " slave about to be deleted.\n");
+        request->state = EC_INT_REQUEST_FAILURE;
+    }
+
     wake_up_all(&slave->master->request_queue);
 
     if (slave->config) {
--- a/master/slave.h	Thu Nov 06 08:55:35 2014 +0100
+++ b/master/slave.h	Wed Nov 12 14:42:17 2014 +0100
@@ -228,8 +228,9 @@
 
     struct list_head sdo_requests; /**< SDO access requests. */
     struct list_head reg_requests; /**< Register access requests. */
-    struct list_head foe_requests; /**< FoE write requests. */
-    struct list_head soe_requests; /**< SoE write requests. */
+    struct list_head foe_requests; /**< FoE requests. */
+    struct list_head soe_requests; /**< SoE requests. */
+    struct list_head eoe_requests; /**< EoE set IP parameter requests. */
 
     ec_fsm_slave_t fsm; /**< Slave state machine. */
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandIp.cpp	Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,258 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *  vim: expandtab
+ *
+ ****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <iostream>
+#include <algorithm>
+using namespace std;
+
+#include "CommandIp.h"
+#include "MasterDevice.h"
+
+/*****************************************************************************/
+
+CommandIp::CommandIp():
+    Command("ip", "Set EoE IP parameters.")
+{
+}
+
+/*****************************************************************************/
+
+string CommandIp::helpString(const string &binaryBaseName) const
+{
+    stringstream str;
+
+    str << binaryBaseName << " " << getName() << " [OPTIONS] <ARGS>" << endl
+        << endl
+        << getBriefDescription() << endl
+        << endl
+        << "This command requires a single slave to be selected." << endl
+        << endl
+        << "IP parameters can be appended as argument pairs:" << endl
+        << endl
+        << "  addr <IPv4>[/prefix]  IP address (optionally with" << endl
+        << "                        decimal subnet prefix)" << endl
+        << "  link <MAC>            Link-layer address (may contain" << endl
+        << "                        colons or hyphens)" << endl
+        << "  default <IPv4>        Default gateway" << endl
+        << "  dns <IPv4>            DNS server" << endl
+        << "  name <hostname>       Host name (max. 32 byte)" << endl
+        << endl
+        << "IPv4 adresses can be given either in dot notation or as" << endl
+        << "hostnames, which will be automatically resolved." << endl
+        << endl
+        << "Command-specific options:" << endl
+        << "  --alias    -a <alias>" << endl
+        << "  --position -p <pos>    Slave selection. See the help of" << endl
+        << "                         the 'slaves' command." << endl
+        << endl
+        << numericInfo();
+
+    return str.str();
+}
+
+/****************************************************************************/
+
+void CommandIp::execute(const StringVector &args)
+{
+    if (args.size() <= 0) {
+        return;
+    }
+
+    if (args.size() % 2) {
+        stringstream err;
+        err << "'" << getName() << "' needs an even number of arguments!";
+        throwInvalidUsageException(err);
+    }
+
+    ec_ioctl_slave_eoe_ip_t io = {};
+
+    for (unsigned int argIdx = 0; argIdx < args.size(); argIdx += 2) {
+        string arg = args[argIdx];
+        string val = args[argIdx + 1];
+        std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
+
+        if (arg == "link") {
+            parseMac(io.mac_address, val);
+            io.mac_address_included = 1;
+        }
+        else if (arg == "addr") {
+            parseIpv4Prefix(&io, val);
+            io.ip_address_included = 1;
+        }
+        else if (arg == "default") {
+            resolveIpv4(&io.gateway, val);
+            io.gateway_included = 1;
+        }
+        else if (arg == "dns") {
+            resolveIpv4(&io.dns, val);
+            io.dns_included = 1;
+        }
+        else if (arg == "name") {
+            if (val.size() > EC_MAX_HOSTNAME_SIZE - 1) {
+                stringstream err;
+                err << "Name too long!";
+                throwInvalidUsageException(err);
+            }
+            unsigned int i;
+            for (i = 0; i < val.size(); i++) {
+                io.name[i] = val[i];
+            }
+            io.name[i] = 0;
+            io.name_included = 1;
+        }
+        else {
+            stringstream err;
+            err << "Unknown argument '" << args[argIdx] << "'!";
+            throwInvalidUsageException(err);
+        }
+    }
+
+    MasterDevice m(getSingleMasterIndex());
+    m.open(MasterDevice::ReadWrite);
+    SlaveList slaves = selectedSlaves(m);
+    if (slaves.size() != 1) {
+        throwSingleSlaveRequired(slaves.size());
+    }
+    io.slave_position = slaves.front().position;
+
+    // execute actual request
+    try {
+        m.setIpParam(&io);
+    } catch (MasterDeviceException &e) {
+        throw e;
+    }
+}
+
+/*****************************************************************************/
+
+void CommandIp::parseMac(unsigned char mac[EC_ETH_ALEN], const string &str)
+{
+    unsigned int pos = 0;
+
+    for (unsigned int i = 0; i < EC_ETH_ALEN; i++) {
+        if (pos + 2 > str.size()) {
+            stringstream err;
+            err << "Incomplete MAC address!";
+            throwInvalidUsageException(err);
+        }
+
+        string byteStr = str.substr(pos, 2);
+        pos += 2;
+
+        stringstream s;
+        s << byteStr;
+        unsigned int byteValue;
+        s >> hex >> byteValue;
+        if (s.fail() || !s.eof() || byteValue > 0xff) {
+            stringstream err;
+            err << "Invalid MAC address!";
+            throwInvalidUsageException(err);
+        }
+        mac[i] = byteValue;
+
+        while (pos < str.size() && (str[pos] == ':' || str[pos] == '-')) {
+            pos++;
+        }
+    }
+}
+
+/*****************************************************************************/
+
+void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io,
+        const string &str)
+{
+    size_t pos = str.find('/');
+    string host;
+
+    io->subnet_mask_included = pos != string::npos;
+
+    if (pos == string::npos) { // no prefix found
+        host = str;
+    }
+    else {
+        host = str.substr(0, pos);
+        string prefixStr = str.substr(pos + 1, string::npos);
+        stringstream s;
+        s << prefixStr;
+        unsigned int prefix;
+        s >> prefix;
+        if (s.fail() || !s.eof() || prefix > 32) {
+            stringstream err;
+            err << "Invalid prefix '" << prefixStr << "'!";
+            throwInvalidUsageException(err);
+        }
+        uint32_t mask = 0;
+        for (unsigned int bit = 0; bit < prefix; bit++) {
+            mask |= (1 << (31 - bit));
+        }
+        io->subnet_mask = htonl(mask);
+    }
+
+    resolveIpv4(&io->ip_address, host);
+}
+
+/*****************************************************************************/
+
+void CommandIp::resolveIpv4(uint32_t *addr, const string &str)
+{
+    struct addrinfo hints = {};
+    struct addrinfo *res;
+
+    hints.ai_family = AF_INET; // only IPv4
+
+    int ret = getaddrinfo(str.c_str(), NULL, &hints, &res);
+    if (ret) {
+        stringstream err;
+        err << "Lookup of '" << str << "' failed: "
+            << gai_strerror(ret) << endl;
+        throwCommandException(err.str());
+    }
+
+    if (!res) { // returned list is empty
+        stringstream err;
+        err << "Lookup of '" << str << "' failed." << endl;
+        throwCommandException(err.str());
+    }
+
+    sockaddr_in *sin = (sockaddr_in *) res->ai_addr;
+    for (unsigned int i = 0; i < 4; i++) {
+        ((unsigned char *) addr)[i] =
+            ((unsigned char *) &sin->sin_addr.s_addr)[i];
+    }
+
+    freeaddrinfo(res);
+}
+
+/****************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool/CommandIp.h	Wed Nov 12 14:42:17 2014 +0100
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 General
+ *  Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#ifndef __COMMANDIP_H__
+#define __COMMANDIP_H__
+
+#include "Command.h"
+
+/****************************************************************************/
+
+class CommandIp:
+    public Command
+{
+    public:
+        CommandIp();
+
+        string helpString(const string &) const;
+        void execute(const StringVector &);
+
+    protected:
+        static void parseMac(unsigned char [6], const string &);
+        static void parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *,
+                const string &);
+        static void resolveIpv4(uint32_t *, const string &);
+};
+
+/****************************************************************************/
+
+#endif
--- a/tool/Makefile.am	Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/Makefile.am	Wed Nov 12 14:42:17 2014 +0100
@@ -48,6 +48,7 @@
 	CommandFoeRead.cpp \
 	CommandFoeWrite.cpp \
 	CommandGraph.cpp \
+	CommandIp.cpp \
 	CommandMaster.cpp \
 	CommandPdos.cpp \
 	CommandRegRead.cpp \
@@ -90,6 +91,7 @@
 	CommandFoeRead.h \
 	CommandFoeWrite.h \
 	CommandGraph.h \
+	CommandIp.h \
 	CommandMaster.h \
 	CommandPdos.h \
 	CommandRegRead.h \
--- a/tool/MasterDevice.cpp	Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/MasterDevice.cpp	Wed Nov 12 14:42:17 2014 +0100
@@ -585,4 +585,19 @@
     }
 }
 
+/****************************************************************************/
+
+void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data)
+{
+    if (ioctl(fd, EC_IOCTL_SLAVE_EOE_IP_PARAM, data) < 0) {
+        if (errno == EIO && data->result) {
+            throw MasterDeviceEoeException(data->result);
+        } else {
+            stringstream err;
+            err << "Failed to set IP parameters: " << strerror(errno);
+            throw MasterDeviceException(err);
+        }
+    }
+}
+
 /*****************************************************************************/
--- a/tool/MasterDevice.h	Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/MasterDevice.h	Wed Nov 12 14:42:17 2014 +0100
@@ -94,6 +94,23 @@
 
 /****************************************************************************/
 
+class MasterDeviceEoeException:
+    public MasterDeviceException
+{
+    friend class MasterDevice;
+
+    public:
+        uint16_t result;
+
+    protected:
+        /** Constructor with error code parameter. */
+        MasterDeviceEoeException(uint16_t result):
+            MasterDeviceException("EoE set IP parameter failed."),
+            result(result) {};
+};
+
+/****************************************************************************/
+
 class MasterDevice
 {
     public:
@@ -144,6 +161,7 @@
 #endif
         void readSoe(ec_ioctl_slave_soe_read_t *);
         void writeSoe(ec_ioctl_slave_soe_write_t *);
+        void setIpParam(ec_ioctl_slave_eoe_ip_t *);
 
         unsigned int getMasterCount() const {return masterCount;}
 
--- a/tool/main.cpp	Thu Nov 06 08:55:35 2014 +0100
+++ b/tool/main.cpp	Wed Nov 12 14:42:17 2014 +0100
@@ -48,6 +48,7 @@
 #include "CommandFoeRead.h"
 #include "CommandFoeWrite.h"
 #include "CommandGraph.h"
+#include "CommandIp.h"
 #include "CommandMaster.h"
 #include "CommandPdos.h"
 #include "CommandRegRead.h"
@@ -288,6 +289,7 @@
     commandList.push_back(new CommandFoeRead());
     commandList.push_back(new CommandFoeWrite());
     commandList.push_back(new CommandGraph());
+    commandList.push_back(new CommandIp());
     commandList.push_back(new CommandMaster());
     commandList.push_back(new CommandPdos());
     commandList.push_back(new CommandRegRead());