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