xref: /aosp_15_r20/external/pigweed/pw_hdlc/decoder.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_hdlc/decoder.h"
16 
17 #include "pw_assert/check.h"
18 #include "pw_bytes/endian.h"
19 #include "pw_hdlc/internal/protocol.h"
20 #include "pw_log/log.h"
21 #include "pw_varint/varint.h"
22 
23 using std::byte;
24 
25 namespace pw::hdlc {
26 
Parse(ConstByteSpan frame)27 Result<Frame> Frame::Parse(ConstByteSpan frame) {
28   uint64_t address;
29   size_t address_size = varint::Decode(frame, &address, kAddressFormat);
30   int data_size =
31       static_cast<int>(frame.size() - address_size - kControlSize - kFcsSize);
32 
33   if (address_size == 0 || data_size < 0) {
34     return Status::DataLoss();
35   }
36 
37   return Frame(
38       address, frame[address_size], frame.subspan(address_size + 1, data_size));
39 }
40 
Process(const byte new_byte)41 Result<Frame> Decoder::Process(const byte new_byte) {
42   switch (state_) {
43     case State::kInterFrame: {
44       if (new_byte == kFlag) {
45         state_ = State::kFrame;
46 
47         // Report an error if non-flag bytes were read between frames.
48         if (current_frame_size_ != 0u) {
49           Reset();
50           return Status::DataLoss();
51         }
52       } else {
53         // Count bytes to track how many are discarded.
54         current_frame_size_ += 1;
55       }
56       return Status::Unavailable();  // Report error when starting a new frame.
57     }
58     case State::kFrame: {
59       if (new_byte == kFlag) {
60         const Status status = CheckFrame();
61 
62         const size_t completed_frame_size = current_frame_size_;
63         Reset();
64 
65         if (status.ok()) {
66           return Frame::Parse(buffer_.first(completed_frame_size));
67         }
68         return status;
69       }
70 
71       if (new_byte == kEscape) {
72         state_ = State::kFrameEscape;
73       } else {
74         AppendByte(new_byte);
75       }
76       return Status::Unavailable();
77     }
78     case State::kFrameEscape: {
79       // The flag character cannot be escaped; return an error.
80       if (new_byte == kFlag) {
81         state_ = State::kFrame;
82         Reset();
83         return Status::DataLoss();
84       }
85 
86       if (new_byte == kEscape) {
87         // Two escape characters in a row is illegal -- invalidate this frame.
88         // The frame is reported abandoned when the next flag byte appears.
89         state_ = State::kInterFrame;
90 
91         // Count the escape byte so that the inter-frame state detects an error.
92         current_frame_size_ += 1;
93       } else {
94         state_ = State::kFrame;
95         AppendByte(Escape(new_byte));
96       }
97       return Status::Unavailable();
98     }
99   }
100   PW_CRASH("Bad decoder state");
101 }
102 
AppendByte(byte new_byte)103 void Decoder::AppendByte(byte new_byte) {
104   if (current_frame_size_ < max_size()) {
105     buffer_[current_frame_size_] = new_byte;
106   }
107 
108   if (current_frame_size_ >= last_read_bytes_.size()) {
109     // A byte will be ejected. Add it to the running checksum.
110     fcs_.Update(last_read_bytes_[last_read_bytes_index_]);
111   }
112 
113   last_read_bytes_[last_read_bytes_index_] = new_byte;
114   last_read_bytes_index_ =
115       (last_read_bytes_index_ + 1) % last_read_bytes_.size();
116 
117   // Always increase size: if it is larger than the buffer, overflow occurred.
118   current_frame_size_ += 1;
119 }
120 
CheckFrame() const121 Status Decoder::CheckFrame() const {
122   // Empty frames are not an error; repeated flag characters are okay.
123   if (current_frame_size_ == 0u) {
124     return Status::Unavailable();
125   }
126 
127   if (current_frame_size_ < Frame::kMinContentSizeBytes) {
128     PW_LOG_ERROR("Received %lu-byte frame; frame must be at least 6 bytes",
129                  static_cast<unsigned long>(current_frame_size_));
130     return Status::DataLoss();
131   }
132 
133   if (!VerifyFrameCheckSequence()) {
134     PW_LOG_ERROR("Frame check sequence verification failed");
135     return Status::DataLoss();
136   }
137 
138   if (current_frame_size_ > max_size()) {
139     // Frame does not fit into the provided buffer; indicate this to the caller.
140     // This may not be considered an error if the caller is doing a partial
141     // decode.
142     return Status::ResourceExhausted();
143   }
144 
145   return OkStatus();
146 }
147 
VerifyFrameCheckSequence() const148 bool Decoder::VerifyFrameCheckSequence() const {
149   // De-ring the last four bytes read, which at this point contain the FCS.
150   std::array<std::byte, sizeof(uint32_t)> fcs_buffer;
151   size_t index = last_read_bytes_index_;
152 
153   for (size_t i = 0; i < fcs_buffer.size(); ++i) {
154     fcs_buffer[i] = last_read_bytes_[index];
155     index = (index + 1) % last_read_bytes_.size();
156   }
157 
158   uint32_t actual_fcs =
159       bytes::ReadInOrder<uint32_t>(endian::little, fcs_buffer);
160   return actual_fcs == fcs_.value();
161 }
162 
163 }  // namespace pw::hdlc
164