nimbuscontrols / EIPScanner

Free implementation of EtherNet/IP in C++
https://eipscanner.readthedocs.io/en/latest/
MIT License
233 stars 93 forks source link

Implicit Messaging with Siemens not working #48

Open jwhitman1-lmco opened 3 years ago

jwhitman1-lmco commented 3 years ago

Apologies for marking this as a bug, it should probably be a 'question', but Git doesn't want to let me switch the labels

I'm new to EIP and I'm trying to open an implicit messaging loop with a Siemens drive device using this eds. I thought I understood things, but when I tried to establish the connection using my understanding of the parameters, I got a 0x13 "not enough data supplied" error from the stack. Thought that was a little strange so I opened up the ImplicitMessagingExample and updated the path with the one on line 371 of that file, or-equaled the t2o network connection parameters to indicate multicast support, and switched the IP address for the one our device is using (and confirmed via ping). Unfortunately, even the example code (with my updates) is returning a 0x13 error.

I don't understand what's going on here...am I missing a nuance in how EIP is supposed to work? Is the stack incompatible with Siemens devices? Do I just need to update some other parameters because something is being finicky under the hood?

Can you shed some light on any of this?

Thanks!

jwhitman1-lmco commented 3 years ago

Oh, possibly relevant: Epath class ID is 6, object ID is 1.

jadamroth commented 3 years ago

Hi,

Sorry for not reaching out sooner. Did you resolve this

jadamroth commented 3 years ago

After reading this once more, if you're working with Implicit messaging, then EPath shouldn't apply, as EPath is only used to handle data in CIP Objects via explicit messaging.

Please read this response and issue for better understanding about the differences - https://github.com/nimbuscontrols/EIPScanner/issues/36#issuecomment-747524312

jwhitman1-lmco commented 3 years ago

This is not resolved at this time, no.

if you're working with Implicit messaging, then EPath shouldn't apply, as EPath is only used to handle data in CIP Objects via explicit messaging.

I do understand this, and was referring to the EPath displayed when using a ConnectionManager that failed to make a good connection. I think my error may be somewhat consistent with the one haellingsen mentioned though. The 0x13 error shows up during the ForwardOpen command (and mentions there's others that aren't being displayed, but I don't have WireShark to see what they are). I'm using the Connection Path shown for the first (and only) connection in the EDS file I attached in my original post, "20 04 24 67 2C 66 2C 65".

I'm not sure what I'm missing, since there's no explicit reference to either of the assembly objects in the implicit messaging example....

Broekman commented 3 years ago

Hi @jwhitman1-lmco,

Can you share all your "eipScanner::cip::connectionManager::ConnectionParameters" as setup in your code?

"I don't have WireShark to see what they are" Any reasons as to why this is not possible? In general Wireshark will tell you exactly what's wrong (i.e. what you send and what was expected).

jwhitman1-lmco commented 3 years ago

Hi @Broekman,

Can you share all your "eipScanner::cip::connectionManager::ConnectionParameters" as setup in your code?

Sure thing; here they are!

parameters.connectionPath = {0x20, 0x04, 0x24, 0x67, 0x2c, 0x66, 0x2c, 0x65};
parameters.o2tRealTimeFromat = true;
parameters.originatorVendorId = 42;  /* This was edited; this is the Siemens VID value */
parameters.originatorSerialNumber = 32423;
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::MULTICAST; /* Added this */
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
parameters.t2oNetworkConnectionParams |= 32;  /* I think this is correct....*/
parameters.o2tNetworkConnectionParams |= NetworkConnectinParams::P2P;
parameters.o2tNetworkConnectionParams |= NetworkConnectinParams::SCHEDULED_PRIORITY;
parameters.o2tNetworkConnectionParams |= 32;  /* I think this is also correct */
parameters.originatorSerialNumber = 0x12345;
parameters.o2tRPI= 1000000;
parameters.t2oRPI= 1000000;
parameters.transportTypeTrigger |= NetworkConnectionParams::CLASS1;

Does this help?

One thing I note is that I'm not absolutely certain about the size of the network connection parameters. Like I said, I'm very new to this. Do they match with the eds that I attached above?

Any reasons as to why this is not possible? In general Wireshark will tell you exactly what's wrong (i.e. what you send and what was expected).

Because unfortunately the Powers That Be have yet to authorize its use. Getting that authorization will likely take an awful lot of time and migraines on my end.

jadamroth commented 3 years ago

I strongly, strongly agree with @Broekman regarding debugging with wireshark, and I almost consider it as a necessity with implicit messaging.

Without seeing the packets and errors, it will make debugging infinitely more difficult, especially for people who are trying to solve the issue remotely. It very well could be an error with the library as much as it could be an error with the parameters.

jwhitman1-lmco commented 3 years ago

Understood. I'll see if I can get special permission or something. Maybe I'll get lucky for a change, who knows?

UPDATE: Managed to get approval accelerated. I'll be able to post packet capture tomorrow morning (28 APR 2021).

jwhitman1-lmco commented 3 years ago

Had to change the extension to upload this, but this is a capture of my creating the object, establishing the explicit connection, then trying ten times to open an implicit connection. Any help would be appreciated...nothing sticks out as obviously erroneous to me, but that could be a lack of familiarity with what 'good' looks like here.

Remove the .txt and this should be a .pcapng file.

EIP_10ImplicitOpens.pcapng.txt

Thank you!

jwhitman1-lmco commented 3 years ago

Any chance you guys have some insight on this? Not to jostle your elbow, just checking so I can answer my boss when he asks.

jadamroth commented 3 years ago

Sorry I haven't had time to look at this as I've been extremely busy with my main work.

I'll try to get to it before the weekend.

jwhitman1-lmco commented 3 years ago

Understood, thank you so much. Knowing that will keep a bunch of flak off me.

jwhitman1-lmco commented 3 years ago

Just checking, has there been any chance to look at this?

johnfarrell commented 3 years ago

Thought I'd pop in as I encountered a similar issue as above. Hope this helps resolve your issue if you're still having it.

Issue

Like @jwhitman1-lmco, I was unable to get implicit connections working with my device. For my situation, I am trying to connect to an IFM AL1320 IO-Link hub to read sensor status. When I tried to follow the guide to connect, I received the same error:

[INFO] Registered session 352518144
[INFO] Send request: service=0x1 epath=[classId=1 objectId=1]
[INFO] Send request: service=0x54 epath=[classId=6 objectId=1]
[ERROR] Message Router error=0x13 additional statuses

Here's a screenshot of the wireshark capture of the request as well. image

At this point my parameters setup looked like this:

eipScanner::cip::connectionManager::ConnectionParameters params;
params.connectionPath = {0x20, 0x04, 0x24, 0xC7, 0x2C, 0x96, 0x2C, 0x64 };

params.o2tRealTimeFormat = true;

params.originatorVendorId = 322;

{
    using namespace eipScanner::cip::connectionManager;

    params.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;
    params.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
    params.t2oNetworkConnectionParams |= NetworkConnectionParams::FIXED;
    params.t2oNetworkConnectionParams |= 140;
    params.o2tNetworkConnectionParams |= NetworkConnectionParams::P2P;
    params.o2tNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
    params.o2tNetworkConnectionParams |= NetworkConnectionParams::FIXED;
    params.o2tNetworkConnectionParams |= 130;

    params.t2oRPI = 10000;
    params.o2tRPI = 10000;

    params.transportTypeTrigger |= NetworkConnectionParams::CLASS1;
}

implicit_data_connection = conn_man->forwardOpen(session, params);

The excerpt from the EDS file for this connection is as follows:

        Connection1 =
                0x04010002,             $ Trigger and Transport
                0x44640405,             $ Connnection Parameters
                Param19,Param2,Assem150,$ O->T RPI, size, format
                Param19,Param1,Assem100,$ T->O RPI, size, format
                ,,                      $ proxy config size, format
                50,Assem199,            $ target config size, format
                "Exclusive Owner IO-Acyc-Diag",    $ Connection Name
                " In/Out Data",         $ help string
                "20 04 24 C7 2C 96 2C 64";    $ Path

In my parameters, the o2t connection size is specified with Param2 and evaluates to 140, and t2o is Param1 evaluating to 130. I just used the default values of the parameters for these values. Changing these didn't seem to have an affect on whether or not the connection was able to be made.

Solution

The issue I was having is from the config specified by Assem199. My device was looking for more data to be passed through in the connection path because of this. In Chapter 7 of the CIP spec, the details of the configuration option states that these specify the size of the data segment to be passed through appended to the connection path in the Forward_Open call. Elswhere in the CIP spec it details the bytes of the connection path, and through that I was able to change my connection path to the following:

    params.connectionPath = {0x20, 0x04, 0x24, 0xC7, 0x2C, 0x96, 0x2C, 0x64,
                                  0x80, 0x19,                                        // 0x80 specifies the beginning of the data
                                                                                            // segment, 0x19 specifies the number of words in the
                                                                                            // data section. This is equivalent to 25 words (50 bytes).
                                  // This is just a large empty buffer. This is the extra
                                  // data that the device was expecting that caused it to throw error 0x13
                                  0x00, 0x00, 0x00, 0x00, 0x00,        
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00 
                            };

Since I see your EDS file doesn't specify any extra configurations I don't know if this is your exact problem, but I would guess that you have a similar issue in that your device is expecting some more data passed through the connection path in the data field.

After changing my connection path to the above, I get the following output when configuring the messaging:

[INFO] Send request: service=0x1 epath=[classId=1 objectId=1]
[INFO] Send request: service=0x54 epath=[classId=6 objectId=1]
[INFO] Open IO connection O2T_ID=4231659531 T2O_ID=1671561217 SerialNumber 1
[INFO] Open UDP socket to send data to 192.168.1.250:2222

Normally you would read the assembly specified in the EDS to figure out what each value should be set to, but in my case all zeroes pretty much turned it into a useless device. The configuration values would be used to set up each device that is connected to the IO hub for me.

I am extremely new to the EthernetIP protocol so I don't know how necessary a lot of this stuff is, but this is what I was able to get working after a couple days of banging my head around.

TWhite-Canvas commented 2 years ago

Hi, I would like to chime in on this thread to request more information on the library. I would like to preface this with the fact that I only have a cursory knowledge of CIP-E/IP.

Question: Is there any explicit definition within the library of the formatting of "conectionPath"? All I see is the header file definition of it being a vector<uint8> within struct ConnectionParameters{} Is this defined in the CIP manual? Because the random hex numbers contained within the example code make no sense to me. I can decipher what is the Assm ID, but I don't know what the other elements mean.

Any help here would be greatly appreciated!

EDIT: For context, I am trying to migrate to using this library from a Python implementation we were using before. I am currently getting a Path segment error. I am using wireshark and looking at the differences between the Python library's Forward Open request vs. this implementation, I get the following differences:

GOOD: good_CIP_request_path

BAD: bad_CIP_request_path

It appears the good implementation is has two 8-bit path segments (0x20 and 0x24) while the bad one has two 16-bit (0x21and 0x25)

This is my setup:

`
parameters.connectionPath = {0x20, 0x04, 0x24, 2, 0x2C, 102, 0x2C, 103};   
parameters.o2tRealTimeFormat = true;
parameters.connectionSerialNumber = 0x017a;
parameters.originatorVendorId = 0x00ff;
parameters.originatorSerialNumber = 0xffffffff; 
parameters.timeoutTicks = 250;
parameters.o2tNetworkConnectionId = 0x002be2bd;
parameters.t2oNetworkConnectionId = 0x00630a04;

parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
parameters.t2oNetworkConnectionParams |= 178; //size of Assm103 = 32
parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
parameters.o2tNetworkConnectionParams |= 8; //size of Assm102 = 32

//parameters.originatorSerialNumber = 0x12345;
parameters.o2tRPI = 100000;
parameters.t2oRPI = 100000;
parameters.transportTypeTrigger |= NetworkConnectionParams::CLASS1;

`

TWhite-Canvas commented 2 years ago

Update: I resolved my issue. The issue was that the library was by default constructing 16-bit path segments when my PLC expected 8-bit. I found the following example in 8-bit_path_segments.rst on how to resolve this (set to 8-bit):

   #include "MessageRouter.h"
    #include "ConnectionManager.h"

    using eipScanner::ConnectionManager;
    using eipScanner::MessageRouter;

    int main()
    {
        MessageRouter::SPtr mr_ptr = std::make_shared<MessageRouter>(MessageRouter::USE_8_BIT_PATH_SEGMENTS);
        ConnectionManager _connectionManager = ConnectionManager(mr_ptr);

        /* ConnectionManager now uses 8-bit path segments */

        return 0;
    }

This did not work. Could have been that I did something wrong, but I doubt it. So instead I hard-coded the MessageRouter constructor to 8-bit segments by default:

class MessageRouter {
    public:
        using SPtr = std::shared_ptr<MessageRouter>;

        static constexpr bool USE_8_BIT_PATH_SEGMENTS = true;

        /**
         * @brief Default constructor
         */
        MessageRouter(bool use_8_bit_path_segments=true); // TW: edited this to default to true

Data is now streaming to/from PLC

tpcorrea commented 1 year ago

Hi, everyone. I tried to set the 8-bit path as described in https://eipscanner.readthedocs.io/en/latest/misc/8-bit_path_segments.html, but I get this link error:

'''/usr/bin/ld: CMakeFiles/eip2mqqt.dir/main.cpp.o: warning: relocation against _ZN10eipScanner13MessageRouter23USE_8_BIT_PATH_SEGMENTSE' in read-only section.text' /usr/bin/ld: CMakeFiles/eip2mqqt.dir/main.cpp.o: in function main': main.cpp:(.text+0x35f): undefined reference toeipScanner::MessageRouter::USE_8_BIT_PATH_SEGMENTS' /usr/bin/ld: warning: creating DT_TEXTREL in a PIE collect2: error: ld returned 1 exit status make[2]: [CMakeFiles/eip2mqqt.dir/build.make:97: eip2mqqt] Error 1 make[1]: [CMakeFiles/Makefile2:83: CMakeFiles/eip2mqqt.dir/all] Error 2 make: *** [Makefile:91: all] Error 2'''

What could be the reason?

1193851719 commented 5 months ago

Thought I'd pop in as I encountered a similar issue as above. Hope this helps resolve your issue if you're still having it.

Issue

Like @jwhitman1-lmco, I was unable to get implicit connections working with my device. For my situation, I am trying to connect to an IFM AL1320 IO-Link hub to read sensor status. When I tried to follow the guide to connect, I received the same error:

[INFO] Registered session 352518144
[INFO] Send request: service=0x1 epath=[classId=1 objectId=1]
[INFO] Send request: service=0x54 epath=[classId=6 objectId=1]
[ERROR] Message Router error=0x13 additional statuses

Here's a screenshot of the wireshark capture of the request as well. image

At this point my parameters setup looked like this:

eipScanner::cip::connectionManager::ConnectionParameters params;
params.connectionPath = {0x20, 0x04, 0x24, 0xC7, 0x2C, 0x96, 0x2C, 0x64 };

params.o2tRealTimeFormat = true;

params.originatorVendorId = 322;

{
    using namespace eipScanner::cip::connectionManager;

    params.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;
    params.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
    params.t2oNetworkConnectionParams |= NetworkConnectionParams::FIXED;
    params.t2oNetworkConnectionParams |= 140;
    params.o2tNetworkConnectionParams |= NetworkConnectionParams::P2P;
    params.o2tNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
    params.o2tNetworkConnectionParams |= NetworkConnectionParams::FIXED;
    params.o2tNetworkConnectionParams |= 130;

    params.t2oRPI = 10000;
    params.o2tRPI = 10000;

    params.transportTypeTrigger |= NetworkConnectionParams::CLASS1;
}

implicit_data_connection = conn_man->forwardOpen(session, params);

The excerpt from the EDS file for this connection is as follows:

        Connection1 =
                0x04010002,             $ Trigger and Transport
                0x44640405,             $ Connnection Parameters
                Param19,Param2,Assem150,$ O->T RPI, size, format
                Param19,Param1,Assem100,$ T->O RPI, size, format
                ,,                      $ proxy config size, format
                50,Assem199,            $ target config size, format
                "Exclusive Owner IO-Acyc-Diag",    $ Connection Name
                " In/Out Data",         $ help string
                "20 04 24 C7 2C 96 2C 64";    $ Path

In my parameters, the o2t connection size is specified with Param2 and evaluates to 140, and t2o is Param1 evaluating to 130. I just used the default values of the parameters for these values. Changing these didn't seem to have an affect on whether or not the connection was able to be made.

Solution

The issue I was having is from the config specified by Assem199. My device was looking for more data to be passed through in the connection path because of this. In Chapter 7 of the CIP spec, the details of the configuration option states that these specify the size of the data segment to be passed through appended to the connection path in the Forward_Open call. Elswhere in the CIP spec it details the bytes of the connection path, and through that I was able to change my connection path to the following:

    params.connectionPath = {0x20, 0x04, 0x24, 0xC7, 0x2C, 0x96, 0x2C, 0x64,
                                  0x80, 0x19,                                        // 0x80 specifies the beginning of the data
                                                                                            // segment, 0x19 specifies the number of words in the
                                                                                            // data section. This is equivalent to 25 words (50 bytes).
                                  // This is just a large empty buffer. This is the extra
                                  // data that the device was expecting that caused it to throw error 0x13
                                  0x00, 0x00, 0x00, 0x00, 0x00,        
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00, 
                                  0x00, 0x00, 0x00, 0x00, 0x00 
                            };

Since I see your EDS file doesn't specify any extra configurations I don't know if this is your exact problem, but I would guess that you have a similar issue in that your device is expecting some more data passed through the connection path in the data field.

After changing my connection path to the above, I get the following output when configuring the messaging:

[INFO] Send request: service=0x1 epath=[classId=1 objectId=1]
[INFO] Send request: service=0x54 epath=[classId=6 objectId=1]
[INFO] Open IO connection O2T_ID=4231659531 T2O_ID=1671561217 SerialNumber 1
[INFO] Open UDP socket to send data to 192.168.1.250:2222

Normally you would read the assembly specified in the EDS to figure out what each value should be set to, but in my case all zeroes pretty much turned it into a useless device. The configuration values would be used to set up each device that is connected to the IO hub for me.

I am extremely new to the EthernetIP protocol so I don't know how necessary a lot of this stuff is, but this is what I was able to get working after a couple days of banging my head around.

Hi,I have the same problem now.I modified it with your advice, but the routing information threw an exception, it seems that I can't modify it. ST15_EIP_Ethernet_IP CPU_IO64.eds.txt Param3 = 0, $ first field shall equal 0 ,, $ path size,path 0x0000, $ descriptor 0xDC, $ data type : Path , $ data size in bytes "Data Configuration Size", $ name "", $ units "Configuration buffer added to the path. Example of the format: 20 0C 21 01", $ help string ,400,"", $ min,max,default data values ,,,, $ mult,dev,base,offset scaling not used ,,,, $ mult,dev,base,offset link not used ; $ decimal places not used I tried two modifications in the code, but the route threw an exception. The first kind: `// Implicit messaging ConnectionManager connectionManager;

ConnectionParameters parameters;
parameters.connectionPath = { 0x20, 0x04, 0x24, 0x00, 0x2C, 0x01,0X2C,0X00 ,
                                0x20, 0x0c ,0x21 ,0x01};
parameters.o2tRealTimeFormat = true;
parameters.originatorVendorId = 1;
//parameters.originatorSerialNumber = 32423;  
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;

parameters.t2oNetworkConnectionParams |= 64; //size of Assm100 =32
parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
parameters.o2tNetworkConnectionParams |= 64; //size of Assm150 = 32

parameters.originatorSerialNumber = 123456789;
parameters.o2tRPI = 50000;//1000000;
parameters.t2oRPI = 50000;//1000000;

parameters.transportTypeTrigger |= NetworkConnectionParams::CLASS1; The second type: // Implicit messaging ConnectionManager connectionManager;

ConnectionParameters parameters;
parameters.connectionPath = { 0x20, 0x04, 0x24, 0x00, 0x2C, 0x01,0X2C,0X00 ,
                                0x80, 0x01 ,0x01};
parameters.o2tRealTimeFormat = true;
parameters.originatorVendorId = 1;
//parameters.originatorSerialNumber = 32423;  
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.t2oNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;

parameters.t2oNetworkConnectionParams |= 64; //size of Assm100 =32
parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::P2P;
parameters.o2tNetworkConnectionParams |= NetworkConnectionParams::SCHEDULED_PRIORITY;
parameters.o2tNetworkConnectionParams |= 64; //size of Assm150 = 32

parameters.originatorSerialNumber = 123456789;
parameters.o2tRPI = 50000;//1000000;
parameters.t2oRPI = 50000;//1000000;

parameters.transportTypeTrigger |= NetworkConnectionParams::CLASS1;`

I'd be most grateful if you could help.