HDLC-Daemon
FrameParser.cpp
Go to the documentation of this file.
1 
37 #include "FrameParser.h"
38 #include "ProtocolState.h"
39 #include "FCS16.h"
40 
41 FrameParser::FrameParser(ProtocolState& a_ProtocolState): m_ProtocolState(a_ProtocolState) {
42  Reset();
43 }
44 
46  // Prepare assembly buffer
47  m_Buffer.clear();
48  m_Buffer.reserve(max_length);
49  m_Buffer.emplace_back(0x7E);
50  m_bStartTokenSeen = false;
51 }
52 
53 void FrameParser::AddReceivedRawBytes(const unsigned char* a_Buffer, size_t a_Bytes) {
54  while (a_Bytes) {
55  size_t l_ConsumedBytes = AddChunk(a_Buffer, a_Bytes);
56  a_Buffer += l_ConsumedBytes;
57  a_Bytes -= l_ConsumedBytes;
58  } // while
59 }
60 
61 size_t FrameParser::AddChunk(const unsigned char* a_Buffer, size_t a_Bytes) {
62  if (m_bStartTokenSeen == false) {
63  // No start token seen yet. Check if there is the start token available in the input buffer.
64  const void* l_pStartTokenPtr = memchr((const void*)a_Buffer, 0x7E, a_Bytes);
65  if (l_pStartTokenPtr) {
66  // The start token was found in the input buffer.
67  m_bStartTokenSeen = true;
68  if (l_pStartTokenPtr == a_Buffer) {
69  // The start token is at the beginning of the buffer. Clip it.
70  return 1;
71  } else {
72  // Clip front of buffer containing junk, including the start token.
73  return ((const unsigned char*)l_pStartTokenPtr - a_Buffer + 1);
74  } // else
75  } else {
76  // No token found, and no token was seen yet. Dropping received buffer now.
77  return a_Bytes;
78  } // else
79  } else {
80  // We already have seen the start token. Check if there is the end token available in the input buffer.
81  const void* l_pEndTokenPtr = memchr((const void*)a_Buffer, 0x7E, a_Bytes);
82  if (l_pEndTokenPtr) {
83  // The end token was found in the input buffer. At first, check if we receive to much data.
84  size_t l_NbrOfBytes = ((const unsigned char*)l_pEndTokenPtr - a_Buffer + 1);
85  if ((m_Buffer.size() + l_NbrOfBytes) <= (2 * max_length)) {
86  // We did not exceed the maximum frame size yet. Copy all bytes including the end token.
87  m_Buffer.insert(m_Buffer.end(), a_Buffer, a_Buffer + l_NbrOfBytes);
88  if (RemoveEscapeCharacters()) {
89  // The complete frame was valid and was consumed.
90  m_bStartTokenSeen = false;
91  } // if
92  } // else
93 
94  m_Buffer.resize(1); // Already contains start token 0x7E
95  return (l_NbrOfBytes);
96  } else {
97  // No end token found. Copy all bytes if we do not exceed the maximum frame size.
98  if ((m_Buffer.size() + a_Bytes) > (2 * max_length)) {
99  // Even if all these bytes were escaped, we have exceeded the maximum frame size.
100  m_bStartTokenSeen = false;
101  m_Buffer.resize(1); // Already contains start token 0x7E
102  } else {
103  // Add all bytes
104  m_Buffer.insert(m_Buffer.end(), a_Buffer, a_Buffer + a_Bytes);
105  } // else
106 
107  return a_Bytes;
108  } // else
109  } // else
110 }
111 
112 bool FrameParser::RemoveEscapeCharacters() {
113  // Checks
114  assert(m_Buffer.front() == 0x7E);
115  assert(m_Buffer.back() == 0x7E);
116  assert(m_Buffer.size() >= 2);
117  assert(m_bStartTokenSeen == true);
118 
119  if (m_Buffer.size() == 2) {
120  // Remove junk, start again
121  return false;
122  } // if
123 
124  // Check for illegal escape sequence at the end of the buffer
125  bool l_bMessageInvalid = false;
126  if (m_Buffer[m_Buffer.size() - 2] == 0x7D) {
127  l_bMessageInvalid = true;
128  } else {
129  // Remove escape sequences
130  std::vector<unsigned char> l_UnescapedBuffer;
131  l_UnescapedBuffer.reserve(m_Buffer.size());
132  for (auto it = m_Buffer.begin(); it != m_Buffer.end(); ++it) {
133  if (*it == 0x7D) {
134  // This was the escape character
135  ++it;
136  if (*it == 0x5E) {
137  l_UnescapedBuffer.emplace_back(0x7E);
138  } else if (*it == 0x5D) {
139  l_UnescapedBuffer.emplace_back(0x7D);
140  } else {
141  // Invalid character. Go ahead with an invalid frame.
142  l_bMessageInvalid = true;
143  l_UnescapedBuffer.emplace_back(*it);
144  } // else
145  } else {
146  // Normal non-escaped character, or one of the frame delimiters
147  l_UnescapedBuffer.emplace_back(*it);
148  } // else
149  } // while
150 
151  // Go ahead with the unescaped buffer
152  m_Buffer = std::move(l_UnescapedBuffer);
153  } // if
154 
155  // We now have the unescaped frame at hand.
156  if ((m_Buffer.size() < 6) || (m_Buffer.size() > max_length)) {
157  // To short or too long for a valid HDLC frame. We consider it as junk.
158  return false;
159  } // if
160 
161  if (l_bMessageInvalid == false) {
162  // Check FCS
163  l_bMessageInvalid = (pppfcs16(PPPINITFCS16, (m_Buffer.data() + 1), (m_Buffer.size() - 2)) != PPPGOODFCS16);
164  } // if
165 
166  m_ProtocolState.InterpretDeserializedFrame(m_Buffer, DeserializeFrame(m_Buffer), l_bMessageInvalid);
167  return (l_bMessageInvalid == false);
168 }
169 
170 HdlcFrame FrameParser::DeserializeFrame(const std::vector<unsigned char> &a_UnescapedBuffer) const {
171  // Parse byte buffer to get the HDLC frame
172  HdlcFrame l_HdlcFrame;
173  l_HdlcFrame.SetAddress(a_UnescapedBuffer[1]);
174  unsigned char l_ucCtrl = a_UnescapedBuffer[2];
175  l_HdlcFrame.SetPF((l_ucCtrl & 0x10) >> 4);
176  bool l_bAppendPayload = false;
177  if ((l_ucCtrl & 0x01) == 0) {
178  // I-Frame
180  l_HdlcFrame.SetSSeq((l_ucCtrl & 0x0E) >> 1);
181  l_HdlcFrame.SetRSeq((l_ucCtrl & 0xE0) >> 5);
182  l_bAppendPayload = true;
183  } else {
184  // S-Frame or U-Frame
185  if ((l_ucCtrl & 0x02) == 0x00) {
186  // S-Frame
187  l_HdlcFrame.SetRSeq((l_ucCtrl & 0xE0) >> 5);
188  unsigned char l_ucType = ((l_ucCtrl & 0x0c) >> 2);
189  if (l_ucType == 0x00) {
190  // Receive-Ready (RR)
192  } else if (l_ucType == 0x01) {
193  // Receive-Not-Ready (RNR)
195  } else if (l_ucType == 0x02) {
196  // Reject (REJ)
198  } else {
199  // Selective Reject (SREJ)
201  } // else
202  } else {
203  // U-Frame
204  unsigned char l_ucType = (((l_ucCtrl & 0x0c) >> 2) | ((l_ucCtrl & 0xe0) >> 3));
205  switch (l_ucType) {
206  case 0b00000: {
207  // Unnumbered information (UI)
209  l_bAppendPayload = true;
210  break;
211  }
212  case 0b00001: {
213  // Set Init. Mode (SIM)
215  break;
216  }
217  case 0b00011: {
218  // Set Async. Response Mode (SARM)
220  break;
221  }
222  case 0b00100: {
223  // Unnumbered Poll (UP)
225  break;
226  }
227  case 0b00111: {
228  // Set Async. Balance Mode (SABM)
230  break;
231  }
232  case 0b01000: {
233  // Disconnect (DISC)
235  break;
236  }
237  case 0b01100: {
238  // Unnumbered Ack. (UA)
240  break;
241  }
242  case 0b10000: {
243  // Set normal response mode (SNRM)
245  break;
246  }
247  case 0b10001: {
248  // Command reject (FRMR / CMDR)
250  l_bAppendPayload = true;
251  break;
252  }
253  case 0b11100: {
254  // Test (TEST)
256  l_bAppendPayload = true;
257  break;
258  }
259  case 0b11101: {
260  // Exchange Identification (XID)
262  l_bAppendPayload = true;
263  break;
264  }
265  default: {
267  break;
268  }
269  } // switch
270  } // else
271  } // else
272 
273  if (l_bAppendPayload) {
274  // I-Frames and UI-Frames have additional payload
275  std::vector<unsigned char> l_Payload;
276  l_Payload.assign(&a_UnescapedBuffer[3], (&a_UnescapedBuffer[3] + (a_UnescapedBuffer.size() - 6)));
277  l_HdlcFrame.SetPayload(std::move(l_Payload));
278  } // if
279 
280  return l_HdlcFrame;
281 }
void SetRSeq(unsigned char a_RSeq)
Definition: HdlcFrame.h:79
#define PPPGOODFCS16
Definition: FCS16.h:44
void SetHDLCFrameType(E_HDLC_FRAMETYPE a_eHDLCFrameType)
Definition: HdlcFrame.h:69
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
void SetPayload(const std::vector< unsigned char > &a_Payload)
Definition: HdlcFrame.h:85
uint16_t pppfcs16(uint16_t fcs, unsigned char *cp, size_t len)
Definition: FCS16.cpp:74
FrameParser(ProtocolState &a_ProtocolState)
Definition: FrameParser.cpp:41
void AddReceivedRawBytes(const unsigned char *a_Buffer, size_t a_Bytes)
Definition: FrameParser.cpp:53
void SetAddress(unsigned char a_Address)
Definition: HdlcFrame.h:47
void InterpretDeserializedFrame(const std::vector< unsigned char > &a_Payload, const HdlcFrame &a_HdlcFrame, bool a_bMessageInvalid)
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
void Reset()
Definition: FrameParser.cpp:45
void SetSSeq(unsigned char a_SSeq)
Definition: HdlcFrame.h:82
void SetPF(bool a_PF)
Definition: HdlcFrame.h:76
#define PPPINITFCS16
Definition: FCS16.h:43
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.