Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver.cc

Issue 2053013002: Weave Packet Receiver (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@proximity_auth_weave_migration
Patch Set: added receiver error code and some test along the waywq Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/proximity_auth/ble/bluetooth_low_energy_weave_packet_receiv er.h"
6
7 #include <netinet/in.h>
8
9 #include "components/proximity_auth/logging/logging.h"
10
11 using proximity_auth::BluetoothLowEnergyWeavePacketGenerator;
12
13 namespace {
14 typedef BluetoothLowEnergyWeavePacketGenerator::PacketType PacketType;
15 typedef BluetoothLowEnergyWeavePacketGenerator::ControlCommand ControlCommand;
16 typedef BluetoothLowEnergyWeavePacketGenerator::ReasonForClose ReasonForClose;
17
18 const uint8_t kMaxPacketCounter = 8;
19 const uint16_t kMaxInitControlPacketSize = 20;
20 const uint16_t kMaxPacketSizeLowerBound = 20;
21 const uint16_t kSelectDefaultPacketSize = 0;
22 const uint16_t kMinConnectionRequestSize = 7;
23 const uint16_t kMinConnectionResponseSize = 5;
24 const uint16_t kMaxConnectionCloseSize = 3;
25 const uint16_t kSupportedWeaveVersion = 1;
26
27 } // namespace
28
29 namespace proximity_auth {
30
31 BluetoothLowEnergyWeavePacketReceiver::Factory*
32 BluetoothLowEnergyWeavePacketReceiver::Factory::factory_instance_ = nullptr;
33
34 std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver>
35 BluetoothLowEnergyWeavePacketReceiver::Factory::NewInstance(
36 ReceiverType receiver_type) {
37 if (factory_instance_ == nullptr) {
38 factory_instance_ = new Factory();
39 }
40 return std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver>(
41 factory_instance_->BuildInstance(receiver_type));
42 }
43
44 void BluetoothLowEnergyWeavePacketReceiver::Factory::SetInstanceForTesting(
45 Factory* factory) {
46 factory_instance_ = factory;
47 }
48
49 BluetoothLowEnergyWeavePacketReceiver*
50 BluetoothLowEnergyWeavePacketReceiver::Factory::BuildInstance(
51 ReceiverType receiver_type) {
52 return new BluetoothLowEnergyWeavePacketReceiver(receiver_type);
53 }
54
55 BluetoothLowEnergyWeavePacketReceiver::BluetoothLowEnergyWeavePacketReceiver(
56 ReceiverType receiver_type)
57 : receiver_type_(receiver_type),
58 next_packet_number_(0),
59 state_(State::CONNECTING),
60 reason_for_close_(ReasonForClose::CLOSE_WITHOUT_ERROR),
61 reason_to_close_(ReasonForClose::CLOSE_WITHOUT_ERROR),
62 receiver_error_(ReceiverError::NO_ERROR) {
63 SetMaxPacketSize(kMaxPacketSizeLowerBound);
64 }
65
66 BluetoothLowEnergyWeavePacketReceiver::
67 ~BluetoothLowEnergyWeavePacketReceiver() {}
68
69 BluetoothLowEnergyWeavePacketReceiver::State
70 BluetoothLowEnergyWeavePacketReceiver::GetState() {
71 return state_;
72 }
73
74 uint16_t BluetoothLowEnergyWeavePacketReceiver::GetMaxPacketSize() {
75 // max_packet_size_ is well defined in every state.
76 return max_packet_size_;
77 }
78
79 ReasonForClose BluetoothLowEnergyWeavePacketReceiver::GetReasonForClose() {
80 DCHECK(state_ == State::CONNECTION_CLOSED);
81 return reason_for_close_;
82 }
83
84 ReasonForClose BluetoothLowEnergyWeavePacketReceiver::GetReasonToClose() {
85 DCHECK(state_ == State::ERROR);
86 return reason_to_close_;
87 }
88
89 std::string BluetoothLowEnergyWeavePacketReceiver::GetDataMessage() {
90 DCHECK(state_ == State::DATA_READY);
91 return std::string(data_message_.begin(), data_message_.end());
92 }
93
94 BluetoothLowEnergyWeavePacketReceiver::ReceiverError
95 BluetoothLowEnergyWeavePacketReceiver::GetReceiverError() {
Tim Song 2016/06/23 01:19:47 DCHECK for State::ERROR?
sacomoto 2016/06/23 16:09:19 The |ReceiverError| enum has a |NO_ERROR| value, s
jingxuy 2016/06/23 21:16:13 Yes, I added a comment in the .h file to say this
96 return receiver_error_;
97 }
98
99 BluetoothLowEnergyWeavePacketReceiver::State
100 BluetoothLowEnergyWeavePacketReceiver::ReceivePacket(const Packet& packet) {
101 if (packet.empty()) {
102 PA_LOG(ERROR) << "Received empty packet. Empty packet is not a valid uWeave"
103 << " packet.";
104 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
105 ReceiverError::EMPTY_PACKET);
106 } else if (state_ == State::ERROR) {
Tim Song 2016/06/23 01:19:47 This should be the first condition before doing an
jingxuy 2016/06/23 21:16:13 Done.
107 PA_LOG(ERROR) << "Received message in ERROR state.";
108 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
Tim Song 2016/06/23 01:19:46 If we're in the error state, we shouldn't override
jingxuy 2016/06/23 21:16:14 Done.
109 ReceiverError::RECEIVED_PACKET_IN_ERROR);
110 } else {
111 VerifyPacketCounter(packet);
112
113 switch (state_) {
114 case State::CONNECTING:
115 ReceiveFirstPacket(packet);
116 break;
117 case State::WAITING:
118 ReceiveNonFirstPacket(packet);
119 break;
120 case State::RECEIVING_DATA:
Tim Song 2016/06/23 01:19:47 You can merge this case with the WAITING case.
jingxuy 2016/06/23 21:16:13 Done.
121 ReceiveNonFirstPacket(packet);
122 break;
123 case State::DATA_READY:
124 data_message_.clear();
125 ReceiveNonFirstPacket(packet);
126 break;
127 case State::CONNECTION_CLOSED:
128 PA_LOG(ERROR) << "Received message in ConnectionClosed state.";
129 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
130 ReceiverError::RECEIVED_PACKET_IN_CONNECTION_CLOSED);
131 break;
132 case State::ERROR:
133 // Counter not verified.
134 break;
135 default:
136 NOTREACHED();
137 }
138 }
139 return state_;
140 }
141
142 void BluetoothLowEnergyWeavePacketReceiver::ReceiveFirstPacket(
143 const Packet& packet) {
144 DCHECK(!packet.empty());
145 DCHECK(state_ == State::CONNECTING);
146
147 if (GetPacketType(packet) != PacketType::CONTROL) {
148 PA_LOG(ERROR) << "Received data packets when not connected.";
149 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
150 ReceiverError::RECEIVED_DATA_IN_CONNECTING);
151 return;
152 }
153
154 uint8_t command = GetControlCommand(packet);
155 switch (command) {
156 case ControlCommand::CONNECTION_REQUEST:
157 if (receiver_type_ == ReceiverType::SERVER) {
158 ReceiveConnectionRequest(packet);
159 } else {
160 PA_LOG(ERROR) << "Server received connection response instead of "
161 << "request.";
162 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
163 ReceiverError::SERVER_RECEIVED_CONNECTION_RESPONSE);
164 }
165 break;
166 case ControlCommand::CONNECTION_RESPONSE:
167 if (receiver_type_ == ReceiverType::CLIENT) {
168 ReceiveConnectionResponse(packet);
169 } else {
170 PA_LOG(ERROR) << "Client received connection request instead of "
171 << "response.";
172 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
173 ReceiverError::CLIENT_RECEIVED_CONNECTION_REQUEST);
174 }
175 break;
176 case ControlCommand::CONNECTION_CLOSE:
177 PA_LOG(ERROR) << "Received connection close when not even connected.";
178 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
179 ReceiverError::RECEIVED_CONNECTION_CLOSE_IN_CONNECTING);
180 break;
181 default:
182 PA_LOG(ERROR) << "Received unrecognized control packet command: "
183 << std::to_string(command);
184 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
185 ReceiverError::UNRECOGNIZED_CONTROL_COMMAND);
186 break;
187 }
188 }
189
190 void BluetoothLowEnergyWeavePacketReceiver::ReceiveNonFirstPacket(
191 const Packet& packet) {
192 DCHECK(!packet.empty());
193
194 uint8_t command;
195 bool expect_first_packet = state_ != State::RECEIVING_DATA;
196
197 switch (GetPacketType(packet)) {
198 case PacketType::CONTROL:
199 command = GetControlCommand(packet);
200 if (command == ControlCommand::CONNECTION_CLOSE) {
201 ReceiveConnectionClose(packet);
202 } else {
203 PA_LOG(ERROR) << "Received invalid command " << std::to_string(command)
204 << " during data transaction";
205 MoveToErrorState(
206 ReasonForClose::UNKNOWN_ERROR,
207 ReceiverError::INVALID_CONTROL_COMMAND_IN_DATA_TRANSACTION);
208 }
209 break;
210 case PacketType::DATA:
211 if (packet.size() > GetConceptualMaxPacketSize()) {
212 PA_LOG(ERROR) << "Received packet with size: " << packet.size()
213 << ". It is greater than maximum packet size "
214 << GetConceptualMaxPacketSize();
215 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
216 ReceiverError::INVALID_DATA_PACKET_SIZE);
217 } else if (!AreLowerTwoBitsCleared(packet)) {
218 PA_LOG(ERROR) << "Lower two bits of data packet header are not clear "
219 << "as expected.";
220 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
221 ReceiverError::DATA_HEADER_LOW_BITS_NOT_CLEARED);
222 } else if (expect_first_packet != IsFirstDataPacket(packet)) {
223 PA_LOG(ERROR) << "First bit of data packet is set incorrectly to: "
224 << IsFirstDataPacket(packet);
225 MoveToErrorState(ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE,
226 ReceiverError::INCORRECT_DATA_FIRST_BIT);
227 } else {
228 AppendData(packet, 1);
229 if (IsLastDataPacket(packet)) {
230 state_ = State::DATA_READY;
231 } else {
232 state_ = State::RECEIVING_DATA;
233 }
234 }
235 break;
236 default:
237 NOTREACHED();
238 }
239 }
240
241 void BluetoothLowEnergyWeavePacketReceiver::ReceiveConnectionRequest(
242 const Packet& packet) {
243 DCHECK(!packet.empty());
244 DCHECK(state_ == State::CONNECTING);
245
246 if (packet.size() < kMinConnectionRequestSize ||
247 packet.size() > kMaxInitControlPacketSize) {
248 PA_LOG(ERROR) << "Received invalid connection request packet size: "
249 << packet.size();
250 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
251 ReceiverError::INVALID_CONNECTION_REQUEST_SIZE);
252 return;
253 }
254
255 uint16_t packet_size = GetShortField(packet, 5);
256 // Packet size of 0 means the server can observe the ATT_MTU and select an
257 // appropriate packet size;
258 if (packet_size != kSelectDefaultPacketSize &&
259 packet_size < kMaxPacketSizeLowerBound) {
260 PA_LOG(ERROR) << "Received requested max packet size of: " << packet_size
261 << ". Client must support at least "
262 << kMaxPacketSizeLowerBound << " bytes per packet.";
263 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
264 ReceiverError::INVALID_REQUESTED_MAX_PACKET_SIZE);
265 return;
266 }
267 SetMaxPacketSize(packet_size);
268
269 uint16_t min_version = GetShortField(packet, 1);
270 uint16_t max_version = GetShortField(packet, 3);
271 if (kSupportedWeaveVersion < min_version ||
272 kSupportedWeaveVersion > max_version) {
273 PA_LOG(ERROR) << "Server does not support client version range.";
274 MoveToErrorState(ReasonForClose::NO_COMMON_VERSION_SUPPORTED,
275 ReceiverError::NOT_SUPPORTED_REQUESTED_VERSION);
276 return;
277 }
278
279 if (packet.size() > kMinConnectionRequestSize) {
280 AppendData(packet, kMinConnectionRequestSize);
281 state_ = State::DATA_READY;
282 } else {
283 state_ = State::WAITING;
284 }
285 }
286
287 void BluetoothLowEnergyWeavePacketReceiver::ReceiveConnectionResponse(
288 const Packet& packet) {
289 DCHECK(!packet.empty());
290 DCHECK(state_ == State::CONNECTING);
291
292 if (packet.size() < kMinConnectionResponseSize ||
293 packet.size() > kMaxInitControlPacketSize) {
294 PA_LOG(ERROR) << "Received invalid connection response packet size: "
295 << packet.size();
296 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
297 ReceiverError::INVALID_CONNECTION_RESPONSE_SIZE);
298 return;
299 }
300
301 uint16_t selected_packet_size = GetShortField(packet, 3);
302 if (selected_packet_size < kMaxPacketSizeLowerBound) {
303 PA_LOG(ERROR) << "Received selected max packet size of: "
304 << selected_packet_size << ". Server must support at least "
305 << kMaxPacketSizeLowerBound << " bytes per packet.";
306 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
307 ReceiverError::INVALID_SELECTED_MAX_PACKET_SIZE);
308 return;
309 }
310 SetMaxPacketSize(selected_packet_size);
311
312 uint16_t selected_version = GetShortField(packet, 1);
313 if (selected_version != kSupportedWeaveVersion) {
314 PA_LOG(ERROR) << "Client does not support server selected version.";
315 MoveToErrorState(ReasonForClose::NO_COMMON_VERSION_SUPPORTED,
316 ReceiverError::NOT_SUPPORTED_SELECTED_VERSION);
317 return;
318 }
319
320 if (packet.size() > kMinConnectionResponseSize) {
321 AppendData(packet, kMinConnectionResponseSize);
322 state_ = State::DATA_READY;
323 } else {
324 state_ = State::WAITING;
325 }
326 }
327
328 void BluetoothLowEnergyWeavePacketReceiver::ReceiveConnectionClose(
329 const Packet& packet) {
330 DCHECK(!packet.empty());
331
332 uint16_t reason;
333
334 if (packet.size() > kMaxConnectionCloseSize) {
335 PA_LOG(ERROR) << "Received invalid connection close packet size: "
336 << packet.size();
337 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
338 ReceiverError::INVALID_CONNECTION_CLOSE_SIZE);
339 return;
340 } else if (packet.size() < kMaxConnectionCloseSize) {
Tim Song 2016/06/23 01:19:46 You can merge this range check case with the one a
jingxuy 2016/06/23 21:16:14 They are different cases. The greater than connect
341 reason = ReasonForClose::UNKNOWN_ERROR;
342 } else {
343 reason = GetShortField(packet, 1);
344 }
345
346 switch (reason) {
347 case ReasonForClose::CLOSE_WITHOUT_ERROR:
348 case ReasonForClose::UNKNOWN_ERROR:
349 case ReasonForClose::NO_COMMON_VERSION_SUPPORTED:
350 case ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE:
351 case ReasonForClose::APPLICATION_ERROR:
352 reason_for_close_ = static_cast<ReasonForClose>(reason);
353 state_ = State::CONNECTION_CLOSED;
354 break;
355 default:
356 PA_LOG(ERROR) << "Received invalid reason for close: " << reason;
357 MoveToErrorState(ReasonForClose::UNKNOWN_ERROR,
358 ReceiverError::UNRECOGNIZED_REASON_FOR_CLOSE);
359 break;
360 }
361 }
362
363 void BluetoothLowEnergyWeavePacketReceiver::AppendData(const Packet& packet,
364 uint32_t byte_offset) {
365 DCHECK(!packet.empty());
366
367 // Append to data_message_ bytes 1 through end of the packet.
368 data_message_.insert(data_message_.end(), packet.begin() + byte_offset,
369 packet.end());
370 }
371
372 uint16_t BluetoothLowEnergyWeavePacketReceiver::GetShortField(
373 const Packet& packet,
374 uint32_t byte_offset) {
375 DCHECK_LT(byte_offset, packet.size());
376 DCHECK_LT(byte_offset + 1, packet.size());
377
378 uint16_t received;
379 uint8_t* received_ptr = (uint8_t*)(&received);
Tim Song 2016/06/23 01:19:46 Use a reinterp_cast rather than a C cast
jingxuy 2016/06/23 21:16:13 Done.
380 received_ptr[0] = packet[byte_offset];
381 received_ptr[1] = packet[byte_offset + 1];
382
383 return ntohs(received);
384 }
385
386 uint8_t BluetoothLowEnergyWeavePacketReceiver::GetPacketType(
387 const Packet& packet) {
388 DCHECK(!packet.empty());
389 // Packet type is stored in the highest bit of the first byte.
390 return (packet[0] >> 7) & 1;
391 }
392
393 uint8_t BluetoothLowEnergyWeavePacketReceiver::GetControlCommand(
394 const Packet& packet) {
395 DCHECK(!packet.empty());
396 // Control command is stored in the lower 4 bits of the first byte.
397 return packet[0] & 0x0F;
398 }
399
400 void BluetoothLowEnergyWeavePacketReceiver::VerifyPacketCounter(
401 const Packet& packet) {
402 DCHECK(!packet.empty());
403 DCHECK(state_ != State::ERROR);
404
405 // Packet counter is bits 4, 5, and 6 of the first byte.
406 uint8_t count = (packet[0] >> 4) & 7;
407
408 if (count == (next_packet_number_ % kMaxPacketCounter)) {
409 next_packet_number_++;
410 } else {
411 PA_LOG(ERROR) << "Received invalid packet counter: "
412 << std::to_string(count);
413 MoveToErrorState(ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE,
414 ReceiverError::PACKET_OUT_OF_SEQUENCE);
415 }
416 }
417
418 bool BluetoothLowEnergyWeavePacketReceiver::IsFirstDataPacket(
419 const Packet& packet) {
420 DCHECK(!packet.empty());
421 // Bit 3 determines whether the packet is the first packet of the message.
422 return (packet[0] >> 3) & 1;
423 }
424
425 bool BluetoothLowEnergyWeavePacketReceiver::IsLastDataPacket(
426 const Packet& packet) {
427 DCHECK(!packet.empty());
428 // Bit 2 determines whether the packet is the last packet of the message.
429 return (packet[0] >> 2) & 1;
430 }
431
432 bool BluetoothLowEnergyWeavePacketReceiver::AreLowerTwoBitsCleared(
433 const Packet& packet) {
434 DCHECK(!packet.empty());
435 return (packet[0] & 3) == 0;
436 }
437
438 void BluetoothLowEnergyWeavePacketReceiver::MoveToErrorState(
439 ReasonForClose reason_to_close,
440 ReceiverError receiver_error) {
441 state_ = State::ERROR;
442 reason_to_close_ = reason_to_close;
443 receiver_error_ = receiver_error;
444 }
445
446 void BluetoothLowEnergyWeavePacketReceiver::SetMaxPacketSize(
447 uint16_t packet_size) {
448 DCHECK(packet_size == kSelectDefaultPacketSize ||
449 packet_size >= kMaxPacketSizeLowerBound);
450 max_packet_size_ = packet_size;
451 }
452
453 uint16_t BluetoothLowEnergyWeavePacketReceiver::GetConceptualMaxPacketSize() {
454 if (!max_packet_size_)
455 return 20;
Tim Song 2016/06/23 01:19:47 return kMaxPacketSizeLowerBound instead?
jingxuy 2016/06/23 21:16:14 Done.
456 return max_packet_size_;
457 }
458
459 } // namespace proximity_auth
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698