Chromium Code Reviews| 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 #include "components/proximity_auth/logging/logging.h" | |
| 8 | |
| 9 using proximity_auth::BluetoothLowEnergyWeavePacketGenerator; | |
| 10 | |
| 11 namespace { | |
| 12 typedef BluetoothLowEnergyWeavePacketGenerator::PacketType PacketType; | |
| 13 typedef BluetoothLowEnergyWeavePacketGenerator::ControlCommand ControlCommand; | |
| 14 typedef BluetoothLowEnergyWeavePacketGenerator::ReasonForClose ReasonForClose; | |
| 15 | |
| 16 const uint8_t kMaxPacketCounter = 8; | |
| 17 const uint16_t kMaxControlPacketSize = 20; | |
| 18 const uint16_t kMinPacketSize = 20; | |
|
Kyle Horimoto
2016/06/20 23:25:40
nit: Please word this constant differently. It's n
jingxuy
2016/06/21 01:19:14
Done.
Kyle Horimoto
2016/06/21 02:10:26
Haha, MinMax is also very confusing. Can you think
Kyle Horimoto
2016/06/21 18:13:37
Ping.
jingxuy
2016/06/22 01:42:23
Done.
| |
| 19 const uint16_t kMinConnectionRequestSize = 7; | |
| 20 const uint16_t kMinConnectionResponseSize = 5; | |
| 21 const uint16_t kMinConnectionCloseSize = 3; | |
| 22 const uint16_t kSupportedWeaveVersion = 1; | |
| 23 | |
| 24 } // namespace | |
| 25 | |
| 26 namespace proximity_auth { | |
| 27 | |
| 28 BluetoothLowEnergyWeavePacketReceiver::Factory* | |
| 29 BluetoothLowEnergyWeavePacketReceiver::Factory::factory_instance_ = nullptr; | |
| 30 | |
| 31 std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver> | |
| 32 BluetoothLowEnergyWeavePacketReceiver::Factory::NewInstance( | |
| 33 ReceiverType receiver_type) { | |
| 34 if (factory_instance_ == nullptr) { | |
| 35 factory_instance_ = new Factory(); | |
| 36 } | |
| 37 return std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver>( | |
| 38 factory_instance_->BuildInstance(receiver_type)); | |
| 39 } | |
| 40 | |
| 41 void BluetoothLowEnergyWeavePacketReceiver::Factory::SetInstanceForTesting( | |
| 42 Factory* factory) { | |
| 43 factory_instance_ = factory; | |
| 44 } | |
| 45 | |
| 46 BluetoothLowEnergyWeavePacketReceiver* | |
| 47 BluetoothLowEnergyWeavePacketReceiver::Factory::BuildInstance( | |
| 48 ReceiverType receiver_type) { | |
| 49 return new BluetoothLowEnergyWeavePacketReceiver(receiver_type); | |
| 50 } | |
| 51 | |
| 52 BluetoothLowEnergyWeavePacketReceiver::BluetoothLowEnergyWeavePacketReceiver( | |
| 53 ReceiverType receiver_type) | |
| 54 : receiver_type_(receiver_type), | |
| 55 packet_number_(0), | |
| 56 state_(State::CONNECTING), | |
| 57 reason_for_close_(ReasonForClose::CLOSE_WITHOUT_ERROR), | |
| 58 reason_to_close_(ReasonForClose::CLOSE_WITHOUT_ERROR) { | |
| 59 SetMaxPacketSize(kMinPacketSize); | |
| 60 } | |
| 61 | |
| 62 BluetoothLowEnergyWeavePacketReceiver:: | |
| 63 ~BluetoothLowEnergyWeavePacketReceiver() {} | |
| 64 | |
| 65 BluetoothLowEnergyWeavePacketReceiver::State | |
| 66 BluetoothLowEnergyWeavePacketReceiver::GetState() { | |
| 67 return state_; | |
| 68 } | |
| 69 | |
| 70 uint16_t BluetoothLowEnergyWeavePacketReceiver::GetMaxPacketSize() { | |
| 71 // max_packet_size_ is well defined in every state. | |
|
Kyle Horimoto
2016/06/20 23:25:40
It doesn't seem like this is true. max_packet_size
jingxuy
2016/06/21 01:19:14
It's default to 20 in the SetMaxPacketSize in the
| |
| 72 return max_packet_size_; | |
| 73 } | |
| 74 | |
| 75 ReasonForClose BluetoothLowEnergyWeavePacketReceiver::GetReasonForClose() { | |
| 76 DCHECK(state_ == State::CONNECTION_CLOSED); | |
| 77 return reason_for_close_; | |
| 78 } | |
| 79 | |
| 80 ReasonForClose BluetoothLowEnergyWeavePacketReceiver::GetReasonToClose() { | |
| 81 DCHECK(state_ == State::ERROR); | |
| 82 return reason_to_close_; | |
| 83 } | |
| 84 | |
| 85 std::string BluetoothLowEnergyWeavePacketReceiver::GetDataMessage() { | |
| 86 DCHECK(state_ == State::DATA_READY); | |
| 87 return std::string(data_message_.begin(), data_message_.end()); | |
| 88 } | |
| 89 | |
| 90 BluetoothLowEnergyWeavePacketReceiver::State | |
| 91 BluetoothLowEnergyWeavePacketReceiver::ReceivePacket(const Packet& packet) { | |
| 92 if (packet.empty()) { | |
| 93 Error("Empty packet is not a valid uWeave packet.", | |
|
Kyle Horimoto
2016/06/20 23:25:39
For these error messages, please make them declara
jingxuy
2016/06/21 01:19:14
Done.
| |
| 94 ReasonForClose::UNKNOWN_ERROR); | |
| 95 } else if (packet.size() > GetConceptualMaxPacketSize()) { | |
| 96 Error("Can't receive packet greater than maximum packet size", | |
| 97 ReasonForClose::UNKNOWN_ERROR); | |
| 98 } else { | |
| 99 VerifyPacketCounter(packet); | |
|
Kyle Horimoto
2016/06/20 23:25:40
If the packet counter is not verified correctly, y
jingxuy
2016/06/21 01:19:14
this is caught on the case ERROR:
Kyle Horimoto
2016/06/21 02:10:26
I realize that, but that case will cause "Received
Kyle Horimoto
2016/06/21 18:13:37
Ping.
jingxuy
2016/06/22 01:42:23
Done.
| |
| 100 | |
| 101 switch (state_) { | |
| 102 case State::CONNECTING: | |
| 103 ReceiveFirstPacket(packet); | |
| 104 break; | |
| 105 case State::WAITING: | |
| 106 ReceiveNonFirstPacket(packet, true); | |
| 107 break; | |
| 108 case State::RECEIVING_DATA: | |
| 109 ReceiveNonFirstPacket(packet, false); | |
| 110 break; | |
| 111 case State::DATA_READY: | |
| 112 data_message_.clear(); | |
| 113 ReceiveNonFirstPacket(packet, true); | |
| 114 break; | |
| 115 case State::CONNECTION_CLOSED: | |
| 116 Error("Receiving message in ConnectionClosed state.", | |
| 117 ReasonForClose::UNKNOWN_ERROR); | |
| 118 break; | |
| 119 case State::ERROR: | |
| 120 PA_LOG(ERROR) << "Receiving message in ERROR state."; | |
| 121 break; | |
| 122 default: | |
| 123 // Receiving an message in connection close or error state is not valid. | |
|
Kyle Horimoto
2016/06/20 23:25:39
This should just be NOTREACHED();
We shouldn't ev
jingxuy
2016/06/21 01:19:14
Done.
| |
| 124 Error("Receiving message in invalid state.", | |
| 125 ReasonForClose::UNKNOWN_ERROR); | |
| 126 break; | |
| 127 } | |
| 128 } | |
| 129 return state_; | |
| 130 } | |
| 131 | |
| 132 void BluetoothLowEnergyWeavePacketReceiver::ReceiveFirstPacket( | |
| 133 const Packet& packet) { | |
| 134 DCHECK(!packet.empty()); | |
| 135 DCHECK(state_ == State::CONNECTING); | |
| 136 | |
| 137 if (GetPacketType(packet) != PacketType::CONTROL) { | |
| 138 Error("Can't receive data packets when not connected.", | |
| 139 ReasonForClose::UNKNOWN_ERROR); | |
| 140 return; | |
| 141 } | |
| 142 | |
| 143 uint8_t command = GetControlCommand(packet); | |
| 144 switch (command) { | |
| 145 case ControlCommand::CONNECTION_REQUEST: | |
| 146 if (receiver_type_ == ReceiverType::SERVER) { | |
| 147 ReceiveConnectionRequest(packet); | |
| 148 } else { | |
| 149 Error("Server couldn't process connection response.", | |
| 150 ReasonForClose::UNKNOWN_ERROR); | |
| 151 } | |
| 152 break; | |
| 153 case ControlCommand::CONNECTION_RESPONSE: | |
| 154 if (receiver_type_ == ReceiverType::CLIENT) { | |
| 155 ReceiveConnectionResponse(packet); | |
| 156 } else { | |
| 157 Error("Client couldn't process connection request.", | |
| 158 ReasonForClose::UNKNOWN_ERROR); | |
| 159 } | |
| 160 break; | |
| 161 case ControlCommand::CONNECTION_CLOSE: | |
| 162 Error("Shouldn't receive close without a connection.", | |
| 163 ReasonForClose::UNKNOWN_ERROR); | |
| 164 break; | |
| 165 default: | |
| 166 Error("Unrecognized control packet command.", | |
| 167 ReasonForClose::UNKNOWN_ERROR); | |
| 168 break; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 void BluetoothLowEnergyWeavePacketReceiver::ReceiveNonFirstPacket( | |
| 173 const Packet& packet, | |
| 174 bool expect_first_packet) { | |
|
Kyle Horimoto
2016/06/20 23:25:39
There should be no need to pass this parameter. We
jingxuy
2016/06/21 01:19:14
I was trying to avoid switching on the state twice
Kyle Horimoto
2016/06/21 02:10:26
I'm not sure what you mean. You can just use:
boo
jingxuy
2016/06/21 06:19:26
It's more of a code style issue. I was trying to t
Kyle Horimoto
2016/06/21 18:13:37
In general, you should strive to make functions en
jingxuy
2016/06/22 01:42:23
I don't really think DCHECK count as part of the l
| |
| 175 DCHECK(!packet.empty()); | |
| 176 DCHECK(((state_ == State::WAITING || state_ == State::DATA_READY) && | |
| 177 expect_first_packet) || | |
| 178 (state_ == State::RECEIVING_DATA && !expect_first_packet)); | |
| 179 | |
| 180 switch (GetPacketType(packet)) { | |
| 181 case PacketType::CONTROL: | |
| 182 if (GetControlCommand(packet) == ControlCommand::CONNECTION_CLOSE) { | |
| 183 ReceiveConnectionClose(packet); | |
| 184 } else { | |
| 185 Error("Can only receive connection close during data transaction", | |
| 186 ReasonForClose::UNKNOWN_ERROR); | |
| 187 } | |
| 188 break; | |
| 189 case PacketType::DATA: | |
| 190 if (!IsLowerTwoBitsCleared(packet)) { | |
| 191 Error("Lower two bits of data packet header are not clear.", | |
| 192 ReasonForClose::UNKNOWN_ERROR); | |
| 193 } else if (expect_first_packet ^ IsFirstDataPacket(packet)) { | |
|
Kyle Horimoto
2016/06/20 23:25:39
Why xor? If we expect that this is the first packe
jingxuy
2016/06/21 01:19:14
I think true and true are suppose to be false for
| |
| 194 // This means that expectation of whether a packet would be a | |
| 195 // first packet and what we actually got are different. | |
| 196 Error("First bit of data packet is not set correctly.", | |
| 197 ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE); | |
| 198 } else { | |
| 199 AppendData(packet, 1); | |
| 200 if (IsLastDataPacket(packet)) { | |
| 201 state_ = State::DATA_READY; | |
| 202 } else { | |
| 203 state_ = State::RECEIVING_DATA; | |
| 204 } | |
| 205 } | |
| 206 break; | |
| 207 default: | |
| 208 Error("Invalid packet type.", ReasonForClose::UNKNOWN_ERROR); | |
| 209 break; | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 void BluetoothLowEnergyWeavePacketReceiver::ReceiveConnectionRequest( | |
| 214 const Packet& packet) { | |
| 215 DCHECK(!packet.empty()); | |
| 216 DCHECK(state_ == State::CONNECTING); | |
| 217 | |
| 218 if (packet.size() < kMinConnectionRequestSize || | |
| 219 packet.size() > kMaxControlPacketSize) { | |
| 220 Error("Invalid connection request packet size.", | |
| 221 ReasonForClose::UNKNOWN_ERROR); | |
| 222 return; | |
| 223 } | |
| 224 | |
| 225 uint16_t packet_size = GetShortField(packet, 5); | |
| 226 // Packet size of 0 means the server can observe the ATT_MTU and selecte an | |
|
Kyle Horimoto
2016/06/20 23:25:39
Please use a constant instead of using 0 directly.
Kyle Horimoto
2016/06/20 23:25:39
nit: s/selecte/select/
jingxuy
2016/06/21 01:19:14
Done.
| |
| 227 // appropriate packet size; | |
| 228 if (packet_size > 0 && packet_size < kMinPacketSize) { | |
| 229 Error("Client must support at least 20 bytes per packet.", | |
| 230 ReasonForClose::UNKNOWN_ERROR); | |
| 231 return; | |
| 232 } | |
| 233 SetMaxPacketSize(packet_size); | |
| 234 | |
| 235 uint16_t min_version = GetShortField(packet, 1); | |
| 236 uint16_t max_version = GetShortField(packet, 3); | |
| 237 if (kSupportedWeaveVersion < min_version || | |
| 238 kSupportedWeaveVersion > max_version) { | |
| 239 Error("Server does not support client version range.", | |
| 240 ReasonForClose::NO_COMMON_VERSION_SUPPORTED); | |
| 241 return; | |
| 242 } | |
| 243 | |
| 244 if (packet.size() > kMinConnectionRequestSize) { | |
| 245 AppendData(packet, kMinConnectionRequestSize); | |
| 246 state_ = State::DATA_READY; | |
| 247 } else { | |
| 248 state_ = State::WAITING; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 void BluetoothLowEnergyWeavePacketReceiver::ReceiveConnectionResponse( | |
| 253 const Packet& packet) { | |
| 254 DCHECK(!packet.empty()); | |
| 255 DCHECK(state_ == State::CONNECTING); | |
| 256 | |
| 257 if (packet.size() < kMinConnectionResponseSize || | |
| 258 packet.size() > kMaxControlPacketSize) { | |
| 259 Error("Invalid connection response packet size.", | |
| 260 ReasonForClose::UNKNOWN_ERROR); | |
| 261 return; | |
| 262 } | |
| 263 | |
| 264 uint16_t selected_packet_size = GetShortField(packet, 3); | |
| 265 if (selected_packet_size < kMinPacketSize) { | |
| 266 Error("Server must support at least 20 bytes per packet.", | |
|
Kyle Horimoto
2016/06/20 23:25:39
nit: Don't hard-code 20 in your error message. Use
jingxuy
2016/06/21 01:19:14
Done.
Kyle Horimoto
2016/06/21 02:10:26
Use a std::stringstream instead of this.
Kyle Horimoto
2016/06/21 18:13:37
Ping.
jingxuy
2016/06/22 01:42:23
Done.
| |
| 267 ReasonForClose::UNKNOWN_ERROR); | |
| 268 return; | |
| 269 } | |
| 270 SetMaxPacketSize(selected_packet_size); | |
| 271 | |
| 272 uint16_t selected_version = GetShortField(packet, 1); | |
| 273 if (selected_version != kSupportedWeaveVersion) { | |
| 274 Error("Client does not support server selected version.", | |
| 275 ReasonForClose::NO_COMMON_VERSION_SUPPORTED); | |
| 276 return; | |
| 277 } | |
| 278 | |
| 279 if (packet.size() > kMinConnectionResponseSize) { | |
| 280 AppendData(packet, kMinConnectionResponseSize); | |
| 281 state_ = State::DATA_READY; | |
| 282 } else { | |
| 283 state_ = State::WAITING; | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 void BluetoothLowEnergyWeavePacketReceiver::ReceiveConnectionClose( | |
| 288 const Packet& packet) { | |
| 289 DCHECK(!packet.empty()); | |
| 290 | |
| 291 if (packet.size() > kMaxControlPacketSize) { | |
| 292 Error("Invalid connection close packet size.", | |
| 293 ReasonForClose::UNKNOWN_ERROR); | |
| 294 return; | |
| 295 } | |
| 296 | |
| 297 if (packet.size() < kMinConnectionCloseSize) { | |
| 298 reason_for_close_ = ReasonForClose::UNKNOWN_ERROR; | |
| 299 return; | |
| 300 } | |
| 301 | |
| 302 uint16_t reason = GetShortField(packet, 1); | |
| 303 | |
| 304 switch (reason) { | |
| 305 case ReasonForClose::CLOSE_WITHOUT_ERROR: | |
| 306 case ReasonForClose::UNKNOWN_ERROR: | |
| 307 case ReasonForClose::NO_COMMON_VERSION_SUPPORTED: | |
| 308 case ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE: | |
| 309 case ReasonForClose::APPLICATION_ERROR: | |
| 310 reason_for_close_ = static_cast<ReasonForClose>(reason); | |
| 311 state_ = State::CONNECTION_CLOSED; | |
| 312 break; | |
| 313 default: | |
| 314 Error("Invalid reason for close.", ReasonForClose::UNKNOWN_ERROR); | |
| 315 break; | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 void BluetoothLowEnergyWeavePacketReceiver::AppendData(const Packet& packet, | |
| 320 uint32_t byte_offset) { | |
| 321 DCHECK(!packet.empty()); | |
| 322 | |
| 323 // Append to data_message_ bytes 1 through end of the packet. | |
| 324 data_message_.insert(data_message_.end(), packet.begin() + byte_offset, | |
| 325 packet.end()); | |
| 326 } | |
| 327 | |
| 328 uint16_t BluetoothLowEnergyWeavePacketReceiver::GetShortField( | |
| 329 const Packet& packet, | |
| 330 uint32_t byte_offset) { | |
| 331 DCHECK_LT(byte_offset, packet.size()); | |
| 332 DCHECK_LT(byte_offset + 1, packet.size()); | |
| 333 | |
| 334 // packet[byte_offset + 1] is the upper byte and packet[byte_offset] is the | |
|
Kyle Horimoto
2016/06/20 23:25:39
As I mentioned in https://codereview.chromium.org/
jingxuy
2016/06/21 01:19:14
I think Gustavo already replied and resolved this.
Kyle Horimoto
2016/06/21 02:10:26
You are correct that the packet is guaranteed to b
jingxuy
2016/06/21 06:19:26
I was referring to Gustavo's comment on writing or
Kyle Horimoto
2016/06/21 18:13:37
I think the misunderstanding is that the direct 2-
jingxuy
2016/06/22 01:42:23
This is resolved in the generator as a correct imp
| |
| 335 // lower byte. | |
| 336 return (packet[byte_offset + 1] << 8) | packet[byte_offset]; | |
| 337 } | |
| 338 | |
| 339 uint8_t BluetoothLowEnergyWeavePacketReceiver::GetPacketType( | |
| 340 const Packet& packet) { | |
| 341 DCHECK(!packet.empty()); | |
| 342 // Packet type is stored in the highest bit of the first byte. | |
| 343 return (packet[0] >> 7) & 1; | |
| 344 } | |
| 345 | |
| 346 uint8_t BluetoothLowEnergyWeavePacketReceiver::GetControlCommand( | |
| 347 const Packet& packet) { | |
| 348 DCHECK(!packet.empty()); | |
| 349 // Control command is stored in the lower 4 bits of the first byte. | |
| 350 return packet[0] & 0x0F; | |
| 351 } | |
| 352 | |
| 353 void BluetoothLowEnergyWeavePacketReceiver::VerifyPacketCounter( | |
| 354 const Packet& packet) { | |
| 355 if (state_ == State::ERROR) | |
| 356 return; | |
| 357 | |
| 358 DCHECK(!packet.empty()); | |
| 359 // Packet counter is bits 4, 5, and 6 of the first byte. | |
| 360 uint8_t count = (packet[0] >> 4) & 7; | |
| 361 | |
| 362 if (count == (packet_number_ % kMaxPacketCounter)) { | |
| 363 packet_number_++; | |
| 364 } else { | |
| 365 Error("Invalid packet counter.", | |
| 366 ReasonForClose::RECEIVED_PACKET_OUT_OF_SEQUENCE); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 bool BluetoothLowEnergyWeavePacketReceiver::IsFirstDataPacket( | |
| 371 const Packet& packet) { | |
| 372 DCHECK(!packet.empty()); | |
| 373 // Bit 3 determines whether the packet is the first packet of the message. | |
| 374 return (packet[0] >> 3) & 1; | |
| 375 } | |
| 376 | |
| 377 bool BluetoothLowEnergyWeavePacketReceiver::IsLastDataPacket( | |
| 378 const Packet& packet) { | |
| 379 DCHECK(!packet.empty()); | |
| 380 // Bit 2 determines whether the packet is the last packet of the message. | |
| 381 return (packet[0] >> 2) & 1; | |
| 382 } | |
| 383 | |
| 384 bool BluetoothLowEnergyWeavePacketReceiver::IsLowerTwoBitsCleared( | |
| 385 const Packet& packet) { | |
| 386 DCHECK(!packet.empty()); | |
| 387 return (packet[0] & 3) == 0; | |
| 388 } | |
| 389 | |
| 390 void BluetoothLowEnergyWeavePacketReceiver::Error( | |
| 391 std::string error_message, | |
| 392 ReasonForClose reason_to_close) { | |
| 393 PA_LOG(ERROR) << error_message; | |
| 394 state_ = State::ERROR; | |
| 395 reason_to_close_ = reason_to_close; | |
| 396 } | |
| 397 | |
| 398 void BluetoothLowEnergyWeavePacketReceiver::SetMaxPacketSize( | |
| 399 uint16_t packet_size) { | |
| 400 DCHECK(packet_size == 0 || packet_size >= kMinPacketSize); | |
| 401 max_packet_size_ = packet_size; | |
| 402 } | |
| 403 | |
| 404 uint16_t BluetoothLowEnergyWeavePacketReceiver::GetConceptualMaxPacketSize() { | |
| 405 if (!max_packet_size_) | |
| 406 return 20; | |
| 407 return max_packet_size_; | |
| 408 } | |
| 409 | |
| 410 } // namespace proximity_auth | |
| OLD | NEW |