#include #include "saprotocol.h" #include "wmspeer.h" #include "crc16.h" #include "sapsocket.h" #include "sapbtpeer.h" #define PROTO_DEBUG 0 SAPBTPeer::SAPBTPeer(SAProtocol::Role role, QBluetoothSocket *socket, QObject *parent) : SAPPeer(role, socket->localAddress().toString(), socket->peerAddress().toString(), parent), _socket(socket), _curFrameLength(0), _peerDescriptionExchangeDone(false), _authenticationDone(false) { connect(_socket, SIGNAL(readyRead()), SLOT(handleSocketData())); connect(_socket, SIGNAL(disconnected()), SLOT(handleSocketDisconnected())); } void SAPBTPeer::handleSocketData() { uint bytes = _socket->bytesAvailable(); const bool need_crc = _peerDescriptionExchangeDone && _authenticationDone; const uint header_size = need_crc ? 2 * sizeof(quint16) : 1 * sizeof(quint16); const uint footer_size = need_crc ? sizeof(quint16) : 0; while ((_curFrameLength == 0 && bytes >= header_size) || (_curFrameLength > 0 && bytes >= _curFrameLength + footer_size)) { if (_curFrameLength > 0) { // We are waiting for a full frame of known length QByteArray frame = _socket->read(_curFrameLength); Q_ASSERT(frame.size() == (int)_curFrameLength); _curFrameLength = 0; if (need_crc) { quint16 computed_crc = crc16(0, reinterpret_cast(frame.constData()), frame.size()); quint16 crc; _socket->read(reinterpret_cast(&crc), sizeof(quint16)); crc = qFromBigEndian(crc); if (crc != computed_crc) { qWarning() << "CRC data failure"; _socket->close(); // Drop the connection, no provision for resync. return; } } handleFrame(frame); } else { quint16 frame_length; bytes = _socket->read(reinterpret_cast(&frame_length), sizeof(quint16)); Q_ASSERT(bytes == sizeof(quint16)); _curFrameLength = qFromBigEndian(frame_length); Q_ASSERT(_curFrameLength > 0); if (need_crc) { // Compute the checksum of the BIG ENDIAN frame length. quint16 computed_crc = crc16(0, reinterpret_cast(&frame_length), sizeof(quint16)); quint16 crc; _socket->read(reinterpret_cast(&crc), sizeof(quint16)); crc = qFromBigEndian(crc); if (crc != computed_crc) { qWarning() << "CRC length failure"; _curFrameLength = 0; _socket->close(); // Drop the connection, no provision for resync. return; } } } bytes = _socket->bytesAvailable(); } } void SAPBTPeer::handleSocketDisconnected() { qDebug() << "Socket disconnected"; handleDisconnected(); } void SAPBTPeer::sendFrame(const QByteArray &data) { const bool need_crc = _peerDescriptionExchangeDone && _authenticationDone; quint16 frame_length = qToBigEndian(data.length()); _socket->write(reinterpret_cast(&frame_length), sizeof(quint16)); // Compute the checksum of the BIG ENDIAN frame length. if (need_crc) { quint16 crc = qToBigEndian(crc16(0, reinterpret_cast(&frame_length), sizeof(quint16))); _socket->write(reinterpret_cast(&crc), sizeof(quint16)); } _socket->write(data.constData(), data.size()); if (need_crc) { quint16 crc = qToBigEndian(crc16(0, reinterpret_cast(data.constData()), data.size())); _socket->write(reinterpret_cast(&crc), sizeof(quint16)); } #if PROTO_DEBUG qDebug() << "Sent:" << data.toHex(); #endif } void SAPBTPeer::handleFrame(const QByteArray &data) { #if PROTO_DEBUG qDebug() << "Recv:" << data.toHex(); #endif if (!_peerDescriptionExchangeDone) { // This must be a peer description frame! SAProtocol::PeerDescription peerDesc = SAProtocol::unpackPeerDescription(data); qDebug() << peerDesc.product << peerDesc.manufacturer << peerDesc.name; qDebug() << "apdu=" << peerDesc.APDUSize << "ssdu=" << peerDesc.SSDUSize << "sessions=" << peerDesc.sessions << "timeout=" << peerDesc.timeout; SAProtocol::PeerDescription myDesc = peerDesc; myDesc.messageType = 6; // Why? myDesc.status = 0; // This seems to be "accepted" myDesc.product = "RandomPhone"; myDesc.manufacturer = "me"; myDesc.name = "gearbttest"; myDesc.profile = "SWatch"; // This is what Gear manager sends sendFrame(SAProtocol::packPeerDescription(myDesc)); _peerDescriptionExchangeDone = true; } else if (!_authenticationDone) { // This must be a authentication frame... handleAuthenticationFrame(data); } else { SAProtocol::Frame frame = SAProtocol::unpackFrame(data); switch (frame.type) { case SAProtocol::FrameData: handleDataFrame(frame); break; case SAProtocol::FrameControl: handleControlFrame(frame); break; default: qWarning() << "Unknown frame type" << frame.type; break; } } } void SAPBTPeer::handleDataFrame(const SAProtocol::Frame &frame) { Q_ASSERT(frame.type == SAProtocol::FrameData); handleSessionData(frame.sessionId, frame.data); } void SAPBTPeer::handleControlFrame(const SAProtocol::Frame &frame) { Q_ASSERT(frame.type == SAProtocol::FrameControl); handleSessionControl(frame.sessionId, frame.data); } void SAPBTPeer::handleAuthenticationFrame(const QByteArray &data) { SAProtocol::SecurityFrame sframe = SAProtocol::unpackSecurityFrame(data); switch (sframe.type) { case SAProtocol::SecurityAuthenticateRequest: { qDebug() << "Starting authorization..."; SAProtocol::SecurityFrame response = _wms->respondToServerChallenge(sframe); if (!response.data.isEmpty()) { sendFrame(SAProtocol::packSecurityFrame(response)); } break; } case SAProtocol::SecurityAuthenticateConfirm: { _authenticationDone = _wms->verifyServerResponse(sframe); if (_authenticationDone) { qDebug() << "Authentication confirmed"; handleConnected(); } else { qWarning() << "Authentication failure, closing connection"; _socket->close(); // Will call "handleDisconnected" and emit disconnected signals. } break; } default: qWarning() << "Unknown security frame type" << sframe.type; break; } }