-
Notifications
You must be signed in to change notification settings - Fork 673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
create S7COMM protocol and tests #1185
Conversation
Codecov Report
@@ Coverage Diff @@
## dev #1185 +/- ##
==========================================
+ Coverage 82.66% 82.73% +0.06%
==========================================
Files 157 159 +2
Lines 20180 20290 +110
Branches 7626 7667 +41
==========================================
+ Hits 16682 16786 +104
- Misses 2877 2886 +9
+ Partials 621 618 -3
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Packet++/src/S7commLayer.cpp
Outdated
} | ||
|
||
std::string S7commLayer::toString() const { | ||
std::ostringstream msgTypeStream; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we have only one ostringstream
, there is no need to have four here.
@wivien19 I read a little bit about S7COMM (I didn't know this protocol before), mostly here: http://gmiru.com/article/s7comm/ Apparently this protocol has 3 parts: Header, Parameters and Data. |
I have read the articles on this blog. |
@wivien19 it looks like the Parameter section doesn't have a fixed structure, and so as the Data section. Maybe we can have methods to at least read them as byte arrays? By the way, even the header structure can change per message:
|
If I want optional parameters (error code), do I need to create another header that I can fit to? Where should I read the Parameters and the Data values as a byte array? I get its size from fitting it to the header, then I know that it takes up so many bytes. Should I extract a value of variable size from the payload like this? |
I'm not sure I understand your question - do you mean you'd like to extract the error code from the Parameter data? As far as I know, not all Parameter types have an error code. Some of them have, some don't...
I think we can have a structure like this, please let me know what you think: // S7commLayer.h
class S7commLayer : public Layer
{
public:
...
...
class S7CommParameter
{
friend class S7commLayer;
public:
S7CommParameter(
uint8_t* getData() { return m_Data; }
size_t getDataLength() const { return m_DataLen; }
private:
S7CommParameter(uint8_t* data, size_t dataLen) : m_Data(data), m_DataLen(dataLen) {}
uint8_t* m_Data;
size_t m_DataLen;
};
S7CommParameter* getParameter() const;
...
private:
S7CommParameter* m_Parameter;
};
// S7commLayer.cpp
S7commLayer::getParameter() const
{
// If m_Parameter is still nullptr - get the parameter data and index and create it
// m_Parameter = new S7CommParameter(...);
return m_Parameter;
} |
I think about this error class and error code. These are optional in header and I cannot parse always. I would like to know, that I should create another header to this option or something else. I have no idea to
I think, it seems to be ok. |
My understanding based on this: http://gmiru.com/article/s7comm/#21-header is that only Ack-Data messages will have these extra bytes. In that case I think we can create 2 methods inside #pragma pack(push, 1)
typedef struct s7comm_ack_data_hdr : s7comm_hdr
{
uint8_t errorClass;
uint8_t errorCode;
}
#pragma pack(pop)
class S7commLayer : public Layer
{
public:
s7comm_hdr* getS7commHeader() const { return (s7commhdr *)m_Data; } // this method already exists
s7comm_ack_data_hdr *getS7commAckDataHeader() const; // this method will return `nullptr` if the message is not of type `Ack-Data`, otherwise it will return the struct
} This solution might not be the cleanest, but I think it's good enough since there is only one message type with a different header structure. Please notice that you need to take the header length into account when implementing the |
In this commit (c2f1f2c) I have some problem with get parameter values. I have implemented some of the functions, but it does not work good. Can you help me what i am doing wrong? |
I think the S7commLayer* myLayer = ...;
S7CommParameter* param = myLayer->getParameter();
... |
I moved the getParameter() method to the other class. It seems to me that I am returning a completely wrong value. How can such a sequence of bytes be returned? I could tell from its size that it was not good, but its value was empty. I tried to change the size, but the value of the data data member was still not correct. Can you see where I went wrong? Thank you in advance for your help. |
I'm not sure what you mean by wrong size and empty value. Can you please elaborate? |
@wivien19 is this PR ready for review? |
Yes |
Packet++/src/S7commLayer.cpp
Outdated
std::string S7commLayer::toString() const | ||
{ | ||
std::ostringstream str; | ||
std::string error; | ||
if (getMsgType() == 0x03) | ||
{ | ||
error = | ||
", error class: " + std::to_string(getErrorClass()) + ", error code: " + std::to_string(getErrorCode()); | ||
} | ||
str << "S7comm Layer, " | ||
<< "msg_type: " << std::to_string(getMsgType()) << ", pdu_ref: " << std::to_string(getPduRef()) | ||
<< ", param_length: " << std::to_string(getParamLength()) | ||
<< ", data_length: " << std::to_string(getDataLength()) << error; | ||
|
||
return str.str(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string is a bit long... maybe it should be shorter, like:
S7Comm Layer, Job Request
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wivien19 I think you misunderstood what I meant. I think the at string should represent the message type. For example:
- If the message is of type
0x01 Job Request
the string should be:S7Comm Layer, Job Request
- If the message is of type
0x02 Ack
the string should be:S7Comm Layer, Ack
- If the message is of type
0x03 Ack-Data
the string should be:S7Comm Layer, Ack-Data
- If the message is of type
0x07 Userdata
the string should be:S7Comm Layer, Userdata
- Else the string could be:
S7Comm Layer, Unknown message
@wivien19 the Visual Studio build fails in CI: https://github.com/seladb/PcapPlusPlus/actions/runs/6558348298/job/17811739778?pr=1185 |
PTF_ASSERT_EQUAL(S7CommLayer->getParamLength(), 12); | ||
PTF_ASSERT_EQUAL(S7CommLayer->getDataLength(), 212); | ||
PTF_ASSERT_EQUAL(S7CommLayer->getHeaderLen(), 0xea); | ||
PTF_ASSERT_EQUAL(S7CommLayer->toString(), "S7Comm Layer, Job Request"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This packet is not of type Job Request
, it's Userdata
@wivien19 here are the remaining unresolved comments, can you please address them so we can merge this PR: |
Sorry, I overlooked them. It was my mistake. |
Thank you @wivien19 for working on this, much appreciated! 🙏 🙏 |
I did not add it to the readme, because I do not know exactly, where to put it.