Exemplo n.º 1
0
        private void HicWorker(object o)
        {
            var token = (CancellationToken)o;
            var nameList = new SortedDictionary<string, string>();

            var bStarted = false;
            var bd = string.Empty;

            var Buffer = new byte[512];
            var BD_Addr = new byte[6];
            var BD_Link = new byte[16];

            var Transfered = 0;
            HCI.Event Event;
            var Command = HCI.Command.HCI_Null;
            var Connection = new BthConnection();

            Log.InfoFormat("-- Bluetooth  : HCI_Worker_Thread Starting (IN: {0:X2})", IntIn);

            HCI_Reset();

            while (!token.IsCancellationRequested)
            {
                try
                {
                    if (ReadIntPipe(Buffer, Buffer.Length, ref Transfered) && Transfered > 0)
                    {
                        if (Enum.IsDefined(typeof(HCI.Event), Buffer[0]))
                        {
                            Event = (HCI.Event)Buffer[0];

                            switch (Event)
                            {
                                case HCI.Event.HCI_Command_Complete_EV:

                                    Command = (HCI.Command)(ushort)(Buffer[3] | Buffer[4] << 8);
                                    Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, Buffer[0], Buffer[5],
                                        Command);
                                    break;

                                case HCI.Event.HCI_Command_Status_EV:

                                    Command = (HCI.Command)(ushort)(Buffer[4] | Buffer[5] << 8);
                                    Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, Buffer[0], Buffer[2],
                                        Command);

                                    if (Buffer[2] != 0)
                                    {
                                        switch (Command)
                                        {
                                            case HCI.Command.HCI_Write_Simple_Pairing_Mode:
                                            case HCI.Command.HCI_Write_Authentication_Enable:
                                            case HCI.Command.HCI_Set_Event_Mask:

                                                GlobalConfiguration.Instance.DisableSSP = true;
                                                Log.Warn(
                                                    "-- Simple Pairing not supported on this device. [SSP Disabled]");
                                                Transfered = HCI_Write_Scan_Enable();
                                                break;
                                        }
                                    }
                                    break;

                                case HCI.Event.HCI_Number_Of_Completed_Packets_EV:
                                    break;

                                default:
                                    Log.DebugFormat(">> {0} [{1:X2}]", Event, Buffer[0]);
                                    break;
                            }

                            switch (Event)
                            {
                                case HCI.Event.HCI_Command_Complete_EV:

                                    if (Command == HCI.Command.HCI_Reset && Buffer[5] == 0 && !bStarted)
                                    {
                                        bStarted = true;
                                        Thread.Sleep(250);

                                        Transfered = HCI_Read_BD_Addr();
                                    }

                                    if (Command == HCI.Command.HCI_Read_BD_ADDR && Buffer[5] == 0)
                                    {
                                        _localMac = new[] { Buffer[6], Buffer[7], Buffer[8], Buffer[9], Buffer[10], Buffer[11] };

                                        Transfered = HCI_Read_Buffer_Size();
                                    }

                                    if (Command == HCI.Command.HCI_Read_Buffer_Size && Buffer[5] == 0)
                                    {
                                        Log.DebugFormat("-- {0:X2}{1:X2}, {2:X2}, {3:X2}{4:X2}, {5:X2}{6:X2}", Buffer[7],
                                            Buffer[6], Buffer[8], Buffer[10], Buffer[9], Buffer[12], Buffer[11]);

                                        Transfered = HCI_Read_Local_Version_Info();
                                    }

                                    if (Command == HCI.Command.HCI_Read_Local_Version_Info && Buffer[5] == 0)
                                    {
                                        HciVersion = string.Format("{0}.{1:X4}", Buffer[6], Buffer[8] << 8 | Buffer[7]);
                                        LmpVersion = string.Format("{0}.{1:X4}", Buffer[9],
                                            Buffer[13] << 8 | Buffer[12]);

                                        Log.InfoFormat("-- Master {0}, HCI_Version {1}, LMP_Version {2}", Local,
                                            HciVersion, LmpVersion);

                                        if (GlobalConfiguration.Instance.DisableSSP)
                                        {
                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                        else
                                        {
                                            Transfered = HCI_Write_Simple_Pairing_Mode();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Write_Simple_Pairing_Mode)
                                    {
                                        if (Buffer[5] == 0)
                                        {
                                            Transfered = HCI_Write_Simple_Pairing_Debug_Mode();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Write_Simple_Pairing_Debug_Mode)
                                    {
                                        Transfered = HCI_Write_Authentication_Enable();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Authentication_Enable)
                                    {
                                        if (Buffer[5] == 0)
                                        {
                                            Transfered = HCI_Set_Event_Mask();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Set_Event_Mask)
                                    {
                                        if (Buffer[5] == 0)
                                        {
                                            Transfered = HCI_Write_Page_Timeout();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Write_Page_Timeout && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Page_Scan_Activity();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Page_Scan_Activity && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Page_Scan_Type();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Page_Scan_Type && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Inquiry_Scan_Activity();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Inquiry_Scan_Activity && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Inquiry_Scan_Type();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Inquiry_Scan_Type && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Inquiry_Mode();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Inquiry_Mode && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Class_of_Device();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Class_of_Device && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Extended_Inquiry_Response();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Extended_Inquiry_Response && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Local_Name();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Local_Name && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Scan_Enable();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Scan_Enable && Buffer[5] == 0)
                                    {
                                        Initialised = true;
                                    }
                                    break;

                                case HCI.Event.HCI_Connection_Request_EV:

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 2];

                                    Transfered = HCI_Delete_Stored_Link_Key(BD_Addr);
                                    Transfered = HCI_Remote_Name_Request(BD_Addr);
                                    break;

                                case HCI.Event.HCI_Connection_Complete_EV:

                                    bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", Buffer[10],
                                        Buffer[9], Buffer[8], Buffer[7], Buffer[6], Buffer[5]);

                                    if (!nameList.Any())
                                        break;

                                    Connection = Add(Buffer[3], (byte)(Buffer[4] | 0x20), nameList[bd]);

                                    // TODO: fix workaround, breaks my controller
                                    if (Buffer[10] != 0x00 || Buffer[9] != 0x07 || Buffer[8] != 0x04)
                                    {
                                        //Connection.IsFake = true;
                                        //Log.Info("-- Fake DualShock3 found, workaround applied");
                                        Log.Info("-- Fake DualShock3 found");
                                    }
                                    else
                                    {
                                        //Connection.IsFake = false;
                                        Log.Info("-- Genuine Sony DualShock3 found");
                                    }

                                    // fetch configuration from .INI
                                    var bdc = IniConfig.Instance.BthDongle;

                                    // check if current device matches names or MACs
                                    if (bdc.SupportedNames.Any(n => nameList[bd].Contains(n))
                                        || bdc.SupportedMacs.Any(m => bd.StartsWith(m)))
                                    {
                                        Connection.ServiceByPass = true;
                                    }

                                    Connection.RemoteName = nameList[bd];
                                    nameList.Remove(bd);
                                    Connection.BdAddress = new[] { Buffer[10], Buffer[9], Buffer[8], Buffer[7], Buffer[6], Buffer[5] };
                                    break;

                                case HCI.Event.HCI_Disconnection_Complete_EV:

                                    Remove(Buffer[3], (byte)(Buffer[4] | 0x20));
                                    break;

                                case HCI.Event.HCI_Number_Of_Completed_Packets_EV:

                                    for (byte Index = 0, Ptr = 3; Index < Buffer[2]; Index++, Ptr += 4)
                                    {
                                        OnCompletedCount(Buffer[Ptr], (byte)(Buffer[Ptr + 1] | 0x20),
                                            (ushort)(Buffer[Ptr + 2] | Buffer[Ptr + 3] << 8));
                                    }
                                    break;

                                case HCI.Event.HCI_Remote_Name_Request_Complete_EV:

                                    bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", Buffer[8], Buffer[7],
                                        Buffer[6], Buffer[5], Buffer[4], Buffer[3]);
                                    var nm = new StringBuilder();

                                    for (var Index = 9; Index < Buffer.Length; Index++)
                                    {
                                        if (Buffer[Index] > 0) nm.Append((char)Buffer[Index]);
                                        else break;
                                    }

                                    var Name = nm.ToString();

                                    Log.InfoFormat("-- Remote Name : {0} - {1}", bd, Name);

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 3];

                                    var hci = IniConfig.Instance.Hci;

                                    if (hci.SupportedNames.Any(n => Name.StartsWith(n))
                                        || hci.SupportedNames.Any(n => Name == n))
                                    {
                                        nameList.Add(bd, nm.ToString());

                                        Transfered = HCI_Accept_Connection_Request(BD_Addr, 0x00);
                                    }
                                    else
                                    {
                                        Transfered = HCI_Reject_Connection_Request(BD_Addr, 0x0F);
                                    }
                                    break;

                                case HCI.Event.HCI_Link_Key_Request_EV:

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 2];

                                    Transfered = HCI_Link_Key_Request_Reply(BD_Addr);
                                    Transfered = HCI_Set_Connection_Encryption(Connection.HciHandle);
                                    break;

                                case HCI.Event.HCI_PIN_Code_Request_EV:

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 2];

                                    Transfered = HCI_PIN_Code_Request_Negative_Reply(BD_Addr);
                                    break;

                                case HCI.Event.HCI_IO_Capability_Request_EV:

                                    Transfered = HCI_IO_Capability_Request_Reply(BD_Addr);
                                    break;

                                case HCI.Event.HCI_User_Confirmation_Request_EV:

                                    Transfered = HCI_User_Confirmation_Request_Reply(BD_Addr);
                                    break;

                                case HCI.Event.HCI_Link_Key_Notification_EV:

                                    for (var Index = 0; Index < 6; Index++) BD_Addr[Index] = Buffer[Index + 2];
                                    for (var Index = 0; Index < 16; Index++) BD_Link[Index] = Buffer[Index + 8];

                                    Transfered = HCI_Set_Connection_Encryption(Connection.HciHandle);
                                    break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in HCI_Worker_Thread: {0}", ex);
                }
            }

            HCI_Reset();

            Log.Info("-- Bluetooth  : HCI_Worker_Thread Exiting");
        }
Exemplo n.º 2
0
        private void HicWorker(object o)
        {
            var token    = (CancellationToken)o;
            var nameList = new SortedDictionary <string, string>();

            var bStarted = false;
            var bd       = string.Empty;

            var Buffer  = new byte[512];
            var BD_Addr = new byte[6];
            var BD_Link = new byte[16];

            var Transfered = 0;

            HCI.Event Event;
            var       Command    = HCI.Command.HCI_Null;
            var       Connection = new BthConnection();

            Log.InfoFormat("-- Bluetooth  : HCI_Worker_Thread Starting (IN: {0:X2})", m_IntIn);

            HCI_Reset();

            while (!token.IsCancellationRequested)
            {
                try
                {
                    if (ReadIntPipe(Buffer, Buffer.Length, ref Transfered) && Transfered > 0)
                    {
                        if (Enum.IsDefined(typeof(HCI.Event), Buffer[0]))
                        {
                            Event = (HCI.Event)Buffer[0];

                            switch (Event)
                            {
                            case HCI.Event.HCI_Command_Complete_EV:

                                Command = (HCI.Command)(ushort)(Buffer[3] | Buffer[4] << 8);
                                Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, Buffer[0], Buffer[5],
                                                Command);
                                break;

                            case HCI.Event.HCI_Command_Status_EV:

                                Command = (HCI.Command)(ushort)(Buffer[4] | Buffer[5] << 8);
                                Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, Buffer[0], Buffer[2],
                                                Command);

                                if (Buffer[2] != 0)
                                {
                                    switch (Command)
                                    {
                                    case HCI.Command.HCI_Write_Simple_Pairing_Mode:
                                    case HCI.Command.HCI_Write_Authentication_Enable:
                                    case HCI.Command.HCI_Set_Event_Mask:

                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn(
                                            "-- Simple Pairing not supported on this device. [SSP Disabled]");
                                        Transfered = HCI_Write_Scan_Enable();
                                        break;
                                    }
                                }
                                break;

                            case HCI.Event.HCI_Number_Of_Completed_Packets_EV:
                                break;

                            default:
                                Log.DebugFormat(">> {0} [{1:X2}]", Event, Buffer[0]);
                                break;
                            }

                            switch (Event)
                            {
                            case HCI.Event.HCI_Command_Complete_EV:

                                if (Command == HCI.Command.HCI_Reset && Buffer[5] == 0 && !bStarted)
                                {
                                    bStarted = true;
                                    Thread.Sleep(250);

                                    Transfered = HCI_Read_BD_Addr();
                                }

                                if (Command == HCI.Command.HCI_Read_BD_ADDR && Buffer[5] == 0)
                                {
                                    _localMac = new[] { Buffer[6], Buffer[7], Buffer[8], Buffer[9], Buffer[10], Buffer[11] };

                                    Transfered = HCI_Read_Buffer_Size();
                                }

                                if (Command == HCI.Command.HCI_Read_Buffer_Size && Buffer[5] == 0)
                                {
                                    Log.DebugFormat("-- {0:X2}{1:X2}, {2:X2}, {3:X2}{4:X2}, {5:X2}{6:X2}", Buffer[7],
                                                    Buffer[6], Buffer[8], Buffer[10], Buffer[9], Buffer[12], Buffer[11]);

                                    Transfered = HCI_Read_Local_Version_Info();
                                }

                                if (Command == HCI.Command.HCI_Read_Local_Version_Info && Buffer[5] == 0)
                                {
                                    HciVersion = string.Format("{0}.{1:X4}", Buffer[6], Buffer[8] << 8 | Buffer[7]);
                                    LmpVersion = string.Format("{0}.{1:X4}", Buffer[9],
                                                               Buffer[13] << 8 | Buffer[12]);

                                    Log.InfoFormat("-- Master {0}, HCI_Version {1}, LMP_Version {2}", Local,
                                                   HciVersion, LmpVersion);

                                    if (GlobalConfiguration.Instance.DisableSSP)
                                    {
                                        Transfered = HCI_Write_Scan_Enable();
                                    }
                                    else
                                    {
                                        Transfered = HCI_Write_Simple_Pairing_Mode();
                                    }
                                }

                                if (Command == HCI.Command.HCI_Write_Simple_Pairing_Mode)
                                {
                                    if (Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Simple_Pairing_Debug_Mode();
                                    }
                                    else
                                    {
                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                        Transfered = HCI_Write_Scan_Enable();
                                    }
                                }

                                if (Command == HCI.Command.HCI_Write_Simple_Pairing_Debug_Mode)
                                {
                                    Transfered = HCI_Write_Authentication_Enable();
                                }

                                if (Command == HCI.Command.HCI_Write_Authentication_Enable)
                                {
                                    if (Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Set_Event_Mask();
                                    }
                                    else
                                    {
                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                        Transfered = HCI_Write_Scan_Enable();
                                    }
                                }

                                if (Command == HCI.Command.HCI_Set_Event_Mask)
                                {
                                    if (Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Page_Timeout();
                                    }
                                    else
                                    {
                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                        Transfered = HCI_Write_Scan_Enable();
                                    }
                                }

                                if (Command == HCI.Command.HCI_Write_Page_Timeout && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Page_Scan_Activity();
                                }

                                if (Command == HCI.Command.HCI_Write_Page_Scan_Activity && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Page_Scan_Type();
                                }

                                if (Command == HCI.Command.HCI_Write_Page_Scan_Type && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Inquiry_Scan_Activity();
                                }

                                if (Command == HCI.Command.HCI_Write_Inquiry_Scan_Activity && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Inquiry_Scan_Type();
                                }

                                if (Command == HCI.Command.HCI_Write_Inquiry_Scan_Type && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Inquiry_Mode();
                                }

                                if (Command == HCI.Command.HCI_Write_Inquiry_Mode && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Class_of_Device();
                                }

                                if (Command == HCI.Command.HCI_Write_Class_of_Device && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Extended_Inquiry_Response();
                                }

                                if (Command == HCI.Command.HCI_Write_Extended_Inquiry_Response && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Local_Name();
                                }

                                if (Command == HCI.Command.HCI_Write_Local_Name && Buffer[5] == 0)
                                {
                                    Transfered = HCI_Write_Scan_Enable();
                                }

                                if (Command == HCI.Command.HCI_Write_Scan_Enable && Buffer[5] == 0)
                                {
                                    Initialised = true;
                                }
                                break;

                            case HCI.Event.HCI_Connection_Request_EV:

                                for (var i = 0; i < 6; i++)
                                {
                                    BD_Addr[i] = Buffer[i + 2];
                                }

                                Transfered = HCI_Delete_Stored_Link_Key(BD_Addr);
                                Transfered = HCI_Remote_Name_Request(BD_Addr);
                                break;

                            case HCI.Event.HCI_Connection_Complete_EV:

                                bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", Buffer[10],
                                                   Buffer[9], Buffer[8], Buffer[7], Buffer[6], Buffer[5]);

                                if (!nameList.Any())
                                {
                                    break;
                                }

                                Connection = Add(Buffer[3], (byte)(Buffer[4] | 0x20), nameList[bd]);

                                // TODO: fix workaround, breaks my controller

                                /* if (Buffer[10] != 0x00 || Buffer[9] != 0x07 || Buffer[8] != 0x04)
                                 * {
                                 *  Connection.IsFake = true;
                                 *  Log.Info("-- Fake DualShock3 found, workaround applied");
                                 * }
                                 * else
                                 * {
                                 *  Connection.IsFake = false;
                                 *  Log.Info("-- Genuine Sony DualShock3 found");
                                 * } */

                                // fetch configuration from .INI
                                var bdc = IniConfig.Instance.BthDongle;

                                // check if current device matches names or MACs
                                if (bdc.SupportedNames.Any(n => nameList[bd].Contains(n)) ||
                                    bdc.SupportedMacs.Any(m => bd.StartsWith(m)))
                                {
                                    Connection.ServiceByPass = true;
                                }

                                Connection.RemoteName = nameList[bd];
                                nameList.Remove(bd);
                                Connection.BdAddress = new[] { Buffer[10], Buffer[9], Buffer[8], Buffer[7], Buffer[6], Buffer[5] };
                                break;

                            case HCI.Event.HCI_Disconnection_Complete_EV:

                                Remove(Buffer[3], (byte)(Buffer[4] | 0x20));
                                break;

                            case HCI.Event.HCI_Number_Of_Completed_Packets_EV:

                                for (byte Index = 0, Ptr = 3; Index < Buffer[2]; Index++, Ptr += 4)
                                {
                                    OnCompletedCount(Buffer[Ptr], (byte)(Buffer[Ptr + 1] | 0x20),
                                                     (ushort)(Buffer[Ptr + 2] | Buffer[Ptr + 3] << 8));
                                }
                                break;

                            case HCI.Event.HCI_Remote_Name_Request_Complete_EV:

                                bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", Buffer[8], Buffer[7],
                                                   Buffer[6], Buffer[5], Buffer[4], Buffer[3]);
                                var nm = new StringBuilder();

                                for (var Index = 9; Index < Buffer.Length; Index++)
                                {
                                    if (Buffer[Index] > 0)
                                    {
                                        nm.Append((char)Buffer[Index]);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }

                                var Name = nm.ToString();

                                Log.InfoFormat("-- Remote Name : {0} - {1}", bd, Name);

                                for (var i = 0; i < 6; i++)
                                {
                                    BD_Addr[i] = Buffer[i + 3];
                                }

                                var hci = IniConfig.Instance.Hci;

                                if (hci.SupportedNames.Any(n => Name.StartsWith(n)) ||
                                    hci.SupportedNames.Any(n => Name == n))
                                {
                                    nameList.Add(bd, nm.ToString());

                                    Transfered = HCI_Accept_Connection_Request(BD_Addr, 0x00);
                                }
                                else
                                {
                                    Transfered = HCI_Reject_Connection_Request(BD_Addr, 0x0F);
                                }
                                break;

                            case HCI.Event.HCI_Link_Key_Request_EV:

                                for (var i = 0; i < 6; i++)
                                {
                                    BD_Addr[i] = Buffer[i + 2];
                                }

                                Transfered = HCI_Link_Key_Request_Reply(BD_Addr);
                                Transfered = HCI_Set_Connection_Encryption(Connection.HciHandle);
                                break;

                            case HCI.Event.HCI_PIN_Code_Request_EV:

                                for (var i = 0; i < 6; i++)
                                {
                                    BD_Addr[i] = Buffer[i + 2];
                                }

                                Transfered = HCI_PIN_Code_Request_Negative_Reply(BD_Addr);
                                break;

                            case HCI.Event.HCI_IO_Capability_Request_EV:

                                Transfered = HCI_IO_Capability_Request_Reply(BD_Addr);
                                break;

                            case HCI.Event.HCI_User_Confirmation_Request_EV:

                                Transfered = HCI_User_Confirmation_Request_Reply(BD_Addr);
                                break;

                            case HCI.Event.HCI_Link_Key_Notification_EV:

                                for (var Index = 0; Index < 6; Index++)
                                {
                                    BD_Addr[Index] = Buffer[Index + 2];
                                }
                                for (var Index = 0; Index < 16; Index++)
                                {
                                    BD_Link[Index] = Buffer[Index + 8];
                                }

                                Transfered = HCI_Set_Connection_Encryption(Connection.HciHandle);
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in HCI_Worker_Thread: {0}", ex);
                }
            }

            HCI_Reset();

            Log.Info("-- Bluetooth  : HCI_Worker_Thread Exiting");
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Processes communication with the Bluetooth host device.
        /// </summary>
        /// <param name="o">The cancellation token to request task abortion.</param>
        private void HicWorker(object o)
        {
            var token    = (CancellationToken)o;
            var nameList = new SortedDictionary <string, string>();
            var hci      = IniConfig.Instance.Hci;

            var bStarted = false;
            var bd       = string.Empty;

            var buffer   = new byte[512];
            var bdAddr   = new byte[6];
            var bdLink   = new byte[16];
            var bdHandle = new byte[2];

            var transfered = 0;
            var command    = HCI.Command.HCI_Null;
            var connection = new BthConnection();

            Log.DebugFormat("Bluetooth Host Controller Interface Task starting on Interrupt Input Pipe: {0:X2}", IntIn);

            HCI_Reset();

            while (!token.IsCancellationRequested)
            {
                try
                {
                    // HCI traffic using the interrupt pipe
                    if (ReadIntPipe(buffer, buffer.Length, ref transfered) && transfered > 0)
                    {
                        if (Enum.IsDefined(typeof(HCI.Event), buffer[0]))
                        {
                            var Event = (HCI.Event)buffer[0];

                            switch (Event)
                            {
                            case HCI.Event.HCI_Command_Complete_EV:

                                command = (HCI.Command)(ushort) (buffer[3] | buffer[4] << 8);
                                Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, buffer[0], buffer[5],
                                                command);
                                break;

                            case HCI.Event.HCI_Command_Status_EV:

                                command = (HCI.Command)(ushort) (buffer[4] | buffer[5] << 8);
                                Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, buffer[0], buffer[2],
                                                command);

                                if (buffer[2] != 0)
                                {
                                    switch (command)
                                    {
                                    case HCI.Command.HCI_Write_Simple_Pairing_Mode:
                                    case HCI.Command.HCI_Write_Authentication_Enable:
                                    case HCI.Command.HCI_Set_Event_Mask:

                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn(
                                            "-- Simple Pairing not supported on this device. [SSP Disabled]");
                                        transfered = HCI_Write_Scan_Enable();
                                        break;
                                    }
                                }
                                break;

                            case HCI.Event.HCI_Number_Of_Completed_Packets_EV:
                                break;

                            default:
                                Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[0]);
                                break;
                            }

                            switch (Event)
                            {
                                #region HCI_Command_Complete_EV

                            case HCI.Event.HCI_Command_Complete_EV:

                                if (command == HCI.Command.HCI_Reset && buffer[5] == 0 && !bStarted)
                                {
                                    bStarted = true;
                                    // TODO: do we really need this?
                                    Thread.Sleep(250);

                                    transfered = HCI_Read_BD_Addr();
                                }

                                if (command == HCI.Command.HCI_Read_BD_ADDR && buffer[5] == 0)
                                {
                                    BluetoothHostAddress =
                                        new PhysicalAddress(new[]
                                                            { buffer[11], buffer[10], buffer[9], buffer[8], buffer[7], buffer[6] });

                                    transfered = HCI_Read_Buffer_Size();
                                }

                                if (command == HCI.Command.HCI_Read_Buffer_Size && buffer[5] == 0)
                                {
                                    Log.DebugFormat("-- {0:X2}{1:X2}, {2:X2}, {3:X2}{4:X2}, {5:X2}{6:X2}", buffer[7],
                                                    buffer[6], buffer[8], buffer[10], buffer[9], buffer[12], buffer[11]);

                                    transfered = HCI_Read_Local_Version_Info();
                                }

                                #region Host version

                                // incoming HCI firmware version information
                                if (command == HCI.Command.HCI_Read_Local_Version_Info && buffer[5] == 0)
                                {
                                    var hciMajor = buffer[6];
                                    var lmpMajor = buffer[9];

                                    HciVersion = string.Format("{0}.{1:X4}", buffer[6], buffer[8] << 8 | buffer[7]);
                                    LmpVersion = string.Format("{0}.{1:X4}", buffer[9],
                                                               buffer[13] << 8 | buffer[12]);

                                    Log.InfoFormat(
                                        "Initializing Bluetooth host {0} (HCI-Version: {1}, LMP-Version: {2})",
                                        BluetoothHostAddress.AsFriendlyName(),
                                        HciVersion, LmpVersion);

                                    /* analyzes Host Controller Interface (HCI) major version
                                     * see https://www.bluetooth.org/en-us/specification/assigned-numbers/host-controller-interface
                                     * */
                                    switch (hciMajor)
                                    {
                                    case 0:
                                        Log.DebugFormat("HCI_Version: Bluetooth® Core Specification 1.0b");
                                        break;

                                    case 1:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 1.1");
                                        break;

                                    case 2:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 1.2");
                                        break;

                                    case 3:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 2.0 + EDR");
                                        break;

                                    case 4:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 2.1 + EDR");
                                        break;

                                    case 5:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 3.0 + HS");
                                        break;

                                    case 6:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.0");
                                        break;

                                    case 7:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.1");
                                        break;

                                    case 8:
                                        Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.2");
                                        break;

                                    default:
                                        // this should not happen
                                        Log.ErrorFormat("HCI_Version: Specification unknown");
                                        break;
                                    }

                                    /* analyzes Link Manager Protocol (LMP) major version
                                     * see https://www.bluetooth.org/en-us/specification/assigned-numbers/link-manager
                                     * */
                                    switch (lmpMajor)
                                    {
                                    case 0:
                                        Log.DebugFormat("LMP_Version: Bluetooth® Core Specification 1.0b");
                                        break;

                                    case 1:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 1.1");
                                        break;

                                    case 2:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 1.2");
                                        break;

                                    case 3:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 2.0 + EDR");
                                        break;

                                    case 4:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 2.1 + EDR");
                                        break;

                                    case 5:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 3.0 + HS");
                                        break;

                                    case 6:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.0");
                                        break;

                                    case 7:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.1");
                                        break;

                                    case 8:
                                        Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.2");
                                        break;

                                    default:
                                        // this should not happen
                                        Log.ErrorFormat("LMP_Version: Specification unknown");
                                        break;
                                    }

                                    // Bluetooth v2.0 + EDR
                                    if (hciMajor >= 3 && lmpMajor >= 3)
                                    {
                                        Log.InfoFormat(
                                            "Bluetooth host supports communication with DualShock 3 controllers");
                                    }

                                    // Bluetooth v2.1 + EDR
                                    if (hciMajor >= 4 && lmpMajor >= 4)
                                    {
                                        Log.InfoFormat(
                                            "Bluetooth host supports communication with DualShock 4 controllers");
                                    }

                                    // dongle effectively too old/unsupported
                                    if (hciMajor < 3 || lmpMajor < 3)
                                    {
                                        Log.FatalFormat(
                                            "Unsupported Bluetooth Specification, aborting communication");
                                        transfered = HCI_Reset();
                                        break;
                                    }

                                    // use simple pairing?
                                    if (GlobalConfiguration.Instance.DisableSSP)
                                    {
                                        transfered = HCI_Write_Scan_Enable();
                                    }
                                    else
                                    {
                                        transfered = HCI_Write_Simple_Pairing_Mode();
                                    }
                                }

                                #endregion

                                if (command == HCI.Command.HCI_Write_Simple_Pairing_Mode)
                                {
                                    if (buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Simple_Pairing_Debug_Mode();
                                    }
                                    else
                                    {
                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                        transfered = HCI_Write_Scan_Enable();
                                    }
                                }

                                if (command == HCI.Command.HCI_Write_Simple_Pairing_Debug_Mode)
                                {
                                    transfered = HCI_Write_Authentication_Enable();
                                }

                                if (command == HCI.Command.HCI_Write_Authentication_Enable)
                                {
                                    if (buffer[5] == 0)
                                    {
                                        transfered = HCI_Set_Event_Mask();
                                    }
                                    else
                                    {
                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                        transfered = HCI_Write_Scan_Enable();
                                    }
                                }

                                if (command == HCI.Command.HCI_Set_Event_Mask)
                                {
                                    if (buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Page_Timeout();
                                    }
                                    else
                                    {
                                        GlobalConfiguration.Instance.DisableSSP = true;
                                        Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                        transfered = HCI_Write_Scan_Enable();
                                    }
                                }

                                if (command == HCI.Command.HCI_Write_Page_Timeout && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Page_Scan_Activity();
                                }

                                if (command == HCI.Command.HCI_Write_Page_Scan_Activity && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Page_Scan_Type();
                                }

                                if (command == HCI.Command.HCI_Write_Page_Scan_Type && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Inquiry_Scan_Activity();
                                }

                                if (command == HCI.Command.HCI_Write_Inquiry_Scan_Activity && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Inquiry_Scan_Type();
                                }

                                if (command == HCI.Command.HCI_Write_Inquiry_Scan_Type && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Inquiry_Mode();
                                }

                                if (command == HCI.Command.HCI_Write_Inquiry_Mode && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Class_of_Device();
                                }

                                if (command == HCI.Command.HCI_Write_Class_of_Device && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Extended_Inquiry_Response();
                                }

                                if (command == HCI.Command.HCI_Write_Extended_Inquiry_Response && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Local_Name();
                                }

                                if (command == HCI.Command.HCI_Write_Local_Name && buffer[5] == 0)
                                {
                                    transfered = HCI_Write_Scan_Enable();
                                }

                                if (command == HCI.Command.HCI_Write_Scan_Enable && buffer[5] == 0)
                                {
                                    Initialised = true;
                                }
                                break;

                                #endregion

                                #region HCI_Connection_Request_EV

                            case HCI.Event.HCI_Connection_Request_EV:

                                Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);

                                transfered = HCI_Delete_Stored_Link_Key(bdAddr);
                                transfered = HCI_Accept_Connection_Request(bdAddr, 0x00);

                                break;

                                #endregion

                                #region HCI_Connection_Complete_EV

                            case HCI.Event.HCI_Connection_Complete_EV:

                                //buffer[2] contains the status of connection_complete_ev. it's always 0 if succeed
                                if (buffer[2] == 0x00)
                                {
                                    Log.DebugFormat("-- HCI_Connection_Complete_EV OK, status: {0:X2}", buffer[2]);

                                    //saving the handle for later usage
                                    bdHandle[0] = buffer[3];
                                    bdHandle[1] = buffer[4];

                                    _connectionPendingEvent.Reset();

                                    //only after connection completed with status 0 we request for controller's name.
                                    transfered = HCI_Remote_Name_Request(bdAddr);
                                }
                                else
                                {
                                    Log.WarnFormat(
                                        "-- HCI_Connection_Complete_EV failed with status: {0:X2}. Connection handle:0x{1:X2}{2:X2}",
                                        buffer[2], buffer[4], buffer[3]);
                                    // TODO: you might want to add some other command here to break or retry.
                                }

                                break;

                                #endregion

                                #region HCI_Disconnection_Complete_EV

                            case HCI.Event.HCI_Disconnection_Complete_EV:

                                Remove(buffer[3], (byte)(buffer[4] | 0x20));
                                break;

                                #endregion

                                #region HCI_Number_Of_Completed_Packets_EV

                            case HCI.Event.HCI_Number_Of_Completed_Packets_EV:

                                for (byte index = 0, ptr = 3; index < buffer[2]; index++, ptr += 4)
                                {
                                    OnCompletedCount(buffer[ptr], (byte)(buffer[ptr + 1] | 0x20),
                                                     (ushort)(buffer[ptr + 2] | buffer[ptr + 3] << 8));
                                }
                                break;

                                #endregion

                                #region HCI_Remote_Name_Request_Complete_EV

                            case HCI.Event.HCI_Remote_Name_Request_Complete_EV:

                                bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", buffer[8], buffer[7],
                                                   buffer[6], buffer[5], buffer[4], buffer[3]);
                                var nm = new StringBuilder();

                                // extract product name
                                for (var index = 9; index < buffer.Length; index++)
                                {
                                    if (buffer[index] > 0)
                                    {
                                        nm.Append((char)buffer[index]);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }

                                var name = nm.ToString();

                                Log.DebugFormat("-- Remote Name : {0} - {1}", bd, name);

                                // extract MAC address
                                Buffer.BlockCopy(buffer, 3, bdAddr, 0, 6);

                                if (hci.SupportedNames.Any(n => name.StartsWith(n)) ||
                                    hci.SupportedNames.Any(n => name == n))
                                {
                                    nameList.Add(bd, name);

                                    // the code below is just cut-paste from "case HCI.Event.HCI_Connection_Complete_EV"
                                    // just some adjustments made in the buffer variables

                                    if (!nameList.Any())
                                    {
                                        break;
                                    }

                                    //using there the handles saved earlier
                                    connection = Add(bdHandle[0], (byte)(bdHandle[1] | 0x20), nameList[bd]);

                                    #region Fake DS3 workaround

                                    // skip fake check for version 4 controllers
                                    if (!name.Equals(BthDs4.GenuineProductName, StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (!hci.GenuineMacAddresses.Any(m => bd.StartsWith(m)))
                                        {
                                            connection.IsFake = true;
                                            Log.Warn("Fake DualShock 3 found. Trying Workarounds...");
                                        }
                                        else
                                        {
                                            connection.IsFake = false;
                                            Log.Info("Genuine Sony DualShock 3 found");
                                        }
                                    }
                                    else
                                    {
                                        Log.Info("Sony DualShock 4 found");
                                    }

                                    #endregion

                                    connection.RemoteName = nameList[bd];
                                    nameList.Remove(bd);

                                    connection.DeviceAddress =
                                        new PhysicalAddress(new[]
                                                            { buffer[8], buffer[7], buffer[6], buffer[5], buffer[4], buffer[3] });

                                    _connectionPendingEvent.Set();
                                }
                                else
                                {
                                    transfered = HCI_Reject_Connection_Request(bdAddr, 0x0F);
                                }
                                break;

                                #endregion

                                #region HCI_Link_Key_Request_EV

                            case HCI.Event.HCI_Link_Key_Request_EV:

                                Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);

                                transfered = HCI_Link_Key_Request_Reply(bdAddr);
                                transfered = HCI_Set_Connection_Encryption(connection.HciHandle);
                                break;

                                #endregion

                                #region HCI_PIN_Code_Request_EV

                            case HCI.Event.HCI_PIN_Code_Request_EV:

                                Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);

                                transfered = HCI_PIN_Code_Request_Negative_Reply(bdAddr);
                                break;

                                #endregion

                                #region HCI_IO_Capability_Request_EV

                            case HCI.Event.HCI_IO_Capability_Request_EV:

                                transfered = HCI_IO_Capability_Request_Reply(bdAddr);
                                break;

                                #endregion

                                #region HCI_User_Confirmation_Request_EV

                            case HCI.Event.HCI_User_Confirmation_Request_EV:

                                transfered = HCI_User_Confirmation_Request_Reply(bdAddr);
                                break;

                                #endregion

                                #region HCI_Link_Key_Notification_EV

                            case HCI.Event.HCI_Link_Key_Notification_EV:

                                Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);
                                Buffer.BlockCopy(buffer, 8, bdLink, 0, 16);

                                transfered = HCI_Set_Connection_Encryption(connection.HciHandle);
                                break;

                                #endregion
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in HCI_Worker_Thread: {0}", ex);
                }
            }

            HCI_Reset();

            Log.Debug("-- Bluetooth  : HCI_Worker_Thread Exiting");
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Processes communication with the Bluetooth host device.
        /// </summary>
        /// <param name="o">The cancellation token to request task abortion.</param>
        private void HicWorker(object o)
        {
            var token = (CancellationToken) o;
            var nameList = new SortedDictionary<string, string>();
            var hci = IniConfig.Instance.Hci;

            var bStarted = false;
            var bd = string.Empty;

            var buffer = new byte[512];
            var bdAddr = new byte[6];
            var bdLink = new byte[16];
            var bdHandle = new byte[2];

            var transfered = 0;
            var command = HCI.Command.HCI_Null;
            var connection = new BthConnection();

            Log.InfoFormat("-- Bluetooth  : HCI_Worker_Thread Starting (IN: {0:X2})", IntIn);

            HCI_Reset();

            while (!token.IsCancellationRequested)
            {
                try
                {
                    // HCI traffic using the interrupt pipe
                    if (ReadIntPipe(buffer, buffer.Length, ref transfered) && transfered > 0)
                    {
                        if (Enum.IsDefined(typeof (HCI.Event), buffer[0]))
                        {
                            var Event = (HCI.Event) buffer[0];

                            switch (Event)
                            {
                                case HCI.Event.HCI_Command_Complete_EV:

                                    command = (HCI.Command) (ushort) (buffer[3] | buffer[4] << 8);
                                    Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, buffer[0], buffer[5],
                                        command);
                                    break;

                                case HCI.Event.HCI_Command_Status_EV:

                                    command = (HCI.Command) (ushort) (buffer[4] | buffer[5] << 8);
                                    Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, buffer[0], buffer[2],
                                        command);

                                    if (buffer[2] != 0)
                                    {
                                        switch (command)
                                        {
                                            case HCI.Command.HCI_Write_Simple_Pairing_Mode:
                                            case HCI.Command.HCI_Write_Authentication_Enable:
                                            case HCI.Command.HCI_Set_Event_Mask:

                                                GlobalConfiguration.Instance.DisableSSP = true;
                                                Log.Warn(
                                                    "-- Simple Pairing not supported on this device. [SSP Disabled]");
                                                transfered = HCI_Write_Scan_Enable();
                                                break;
                                        }
                                    }
                                    break;

                                case HCI.Event.HCI_Number_Of_Completed_Packets_EV:
                                    break;

                                default:
                                    Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[0]);
                                    break;
                            }

                            switch (Event)
                            {
                                    #region HCI_Command_Complete_EV

                                case HCI.Event.HCI_Command_Complete_EV:

                                    if (command == HCI.Command.HCI_Reset && buffer[5] == 0 && !bStarted)
                                    {
                                        bStarted = true;
                                        // TODO: do we really need this?
                                        Thread.Sleep(250);

                                        transfered = HCI_Read_BD_Addr();
                                    }

                                    if (command == HCI.Command.HCI_Read_BD_ADDR && buffer[5] == 0)
                                    {
                                        _localMac = new[]
                                        {buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]};

                                        transfered = HCI_Read_Buffer_Size();
                                    }

                                    if (command == HCI.Command.HCI_Read_Buffer_Size && buffer[5] == 0)
                                    {
                                        Log.DebugFormat("-- {0:X2}{1:X2}, {2:X2}, {3:X2}{4:X2}, {5:X2}{6:X2}", buffer[7],
                                            buffer[6], buffer[8], buffer[10], buffer[9], buffer[12], buffer[11]);

                                        transfered = HCI_Read_Local_Version_Info();
                                    }

                                    #region Host version

                                    // incoming HCI firmware version information
                                    if (command == HCI.Command.HCI_Read_Local_Version_Info && buffer[5] == 0)
                                    {
                                        var hciMajor = buffer[6];
                                        var lmpMajor = buffer[9];

                                        HciVersion = string.Format("{0}.{1:X4}", buffer[6], buffer[8] << 8 | buffer[7]);
                                        LmpVersion = string.Format("{0}.{1:X4}", buffer[9],
                                            buffer[13] << 8 | buffer[12]);

                                        Log.InfoFormat("-- Master {0}, HCI_Version {1}, LMP_Version {2}", Local,
                                            HciVersion, LmpVersion);

                                        /* analyzes Host Controller Interface (HCI) major version
                                         * see https://www.bluetooth.org/en-us/specification/assigned-numbers/host-controller-interface
                                         * */
                                        switch (hciMajor)
                                        {
                                            case 0:
                                                Log.DebugFormat("HCI_Version: Bluetooth® Core Specification 1.0b");
                                                break;
                                            case 1:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 1.1");
                                                break;
                                            case 2:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 1.2");
                                                break;
                                            case 3:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 2.0 + EDR");
                                                break;
                                            case 4:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 2.1 + EDR");
                                                break;
                                            case 5:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 3.0 + HS");
                                                break;
                                            case 6:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.0");
                                                break;
                                            case 7:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.1");
                                                break;
                                            case 8:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.2");
                                                break;
                                            default:
                                                // this should not happen
                                                Log.ErrorFormat("HCI_Version: Specification unknown");
                                                break;
                                        }

                                        /* analyzes Link Manager Protocol (LMP) major version
                                         * see https://www.bluetooth.org/en-us/specification/assigned-numbers/link-manager
                                         * */
                                        switch (lmpMajor)
                                        {
                                            case 0:
                                                Log.DebugFormat("LMP_Version: Bluetooth® Core Specification 1.0b");
                                                break;
                                            case 1:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 1.1");
                                                break;
                                            case 2:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 1.2");
                                                break;
                                            case 3:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 2.0 + EDR");
                                                break;
                                            case 4:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 2.1 + EDR");
                                                break;
                                            case 5:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 3.0 + HS");
                                                break;
                                            case 6:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.0");
                                                break;
                                            case 7:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.1");
                                                break;
                                            case 8:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.2");
                                                break;
                                            default:
                                                // this should not happen
                                                Log.ErrorFormat("LMP_Version: Specification unknown");
                                                break;
                                        }

                                        // Bluetooth v2.0 + EDR
                                        if (hciMajor >= 3 && lmpMajor >= 3)
                                        {
                                            Log.InfoFormat(
                                                "Bluetooth host supports communication with DualShock 3 controllers");
                                        }

                                        // Bluetooth v2.1 + EDR
                                        if (hciMajor >= 4 && lmpMajor >= 4)
                                        {
                                            Log.InfoFormat(
                                                "Bluetooth host supports communication with DualShock 4 controllers");
                                        }

                                        // dongle effectively too old/unsupported
                                        if (hciMajor < 3 || lmpMajor < 3)
                                        {
                                            Log.FatalFormat(
                                                "Unsupported Bluetooth Specification, aborting communication");
                                            transfered = HCI_Reset();
                                            break;
                                        }

                                        // use simple pairing?
                                        if (GlobalConfiguration.Instance.DisableSSP)
                                        {
                                            transfered = HCI_Write_Scan_Enable();
                                        }
                                        else
                                        {
                                            transfered = HCI_Write_Simple_Pairing_Mode();
                                        }
                                    }

                                    #endregion

                                    if (command == HCI.Command.HCI_Write_Simple_Pairing_Mode)
                                    {
                                        if (buffer[5] == 0)
                                        {
                                            transfered = HCI_Write_Simple_Pairing_Debug_Mode();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (command == HCI.Command.HCI_Write_Simple_Pairing_Debug_Mode)
                                    {
                                        transfered = HCI_Write_Authentication_Enable();
                                    }

                                    if (command == HCI.Command.HCI_Write_Authentication_Enable)
                                    {
                                        if (buffer[5] == 0)
                                        {
                                            transfered = HCI_Set_Event_Mask();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (command == HCI.Command.HCI_Set_Event_Mask)
                                    {
                                        if (buffer[5] == 0)
                                        {
                                            transfered = HCI_Write_Page_Timeout();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (command == HCI.Command.HCI_Write_Page_Timeout && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Page_Scan_Activity();
                                    }

                                    if (command == HCI.Command.HCI_Write_Page_Scan_Activity && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Page_Scan_Type();
                                    }

                                    if (command == HCI.Command.HCI_Write_Page_Scan_Type && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Inquiry_Scan_Activity();
                                    }

                                    if (command == HCI.Command.HCI_Write_Inquiry_Scan_Activity && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Inquiry_Scan_Type();
                                    }

                                    if (command == HCI.Command.HCI_Write_Inquiry_Scan_Type && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Inquiry_Mode();
                                    }

                                    if (command == HCI.Command.HCI_Write_Inquiry_Mode && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Class_of_Device();
                                    }

                                    if (command == HCI.Command.HCI_Write_Class_of_Device && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Extended_Inquiry_Response();
                                    }

                                    if (command == HCI.Command.HCI_Write_Extended_Inquiry_Response && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Local_Name();
                                    }

                                    if (command == HCI.Command.HCI_Write_Local_Name && buffer[5] == 0)
                                    {
                                        transfered = HCI_Write_Scan_Enable();
                                    }

                                    if (command == HCI.Command.HCI_Write_Scan_Enable && buffer[5] == 0)
                                    {
                                        Initialised = true;
                                    }
                                    break;

                                    #endregion

                                    #region HCI_Connection_Request_EV

                                case HCI.Event.HCI_Connection_Request_EV:

                                    Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);

                                    transfered = HCI_Delete_Stored_Link_Key(bdAddr);
                                    transfered = HCI_Accept_Connection_Request(bdAddr, 0x00);

                                    _waitForConnectionComplete.Reset();
                                    break;

                                    #endregion

                                    #region HCI_Connection_Complete_EV

                                case HCI.Event.HCI_Connection_Complete_EV:

                                    //buffer[2] contains the status of connection_complete_ev. it's always 0 if succeed
                                    if (buffer[2] == 0x00)
                                    {
                                        Log.InfoFormat("-- HCI_Connection_Complete_EV OK, status: {0:X2}", buffer[2]);

                                        //saving the handle for later usage
                                        bdHandle[0] = buffer[3];
                                        bdHandle[1] = buffer[4];

                                        //only after connection completed with status 0 we request for controller's name.
                                        transfered = HCI_Remote_Name_Request(bdAddr);
                                    }
                                    else
                                    {
                                        Log.WarnFormat(
                                            "-- HCI_Connection_Complete_EV failed with status: {0:X2}. Connection handle:0x{1:X2}{2:X2}",
                                            buffer[2], buffer[4], buffer[3]);
                                        // TODO: you might want to add some other command here to break or retry.
                                    }

                                    break;

                                    #endregion

                                    #region HCI_Disconnection_Complete_EV

                                case HCI.Event.HCI_Disconnection_Complete_EV:

                                    Remove(buffer[3], (byte) (buffer[4] | 0x20));
                                    break;

                                    #endregion

                                    #region HCI_Number_Of_Completed_Packets_EV

                                case HCI.Event.HCI_Number_Of_Completed_Packets_EV:

                                    for (byte index = 0, ptr = 3; index < buffer[2]; index++, ptr += 4)
                                    {
                                        OnCompletedCount(buffer[ptr], (byte) (buffer[ptr + 1] | 0x20),
                                            (ushort) (buffer[ptr + 2] | buffer[ptr + 3] << 8));
                                    }
                                    break;

                                    #endregion

                                    #region HCI_Remote_Name_Request_Complete_EV

                                case HCI.Event.HCI_Remote_Name_Request_Complete_EV:

                                    bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", buffer[8], buffer[7],
                                        buffer[6], buffer[5], buffer[4], buffer[3]);
                                    var nm = new StringBuilder();

                                    // extract product name
                                    for (var index = 9; index < buffer.Length; index++)
                                    {
                                        if (buffer[index] > 0) nm.Append((char) buffer[index]);
                                        else break;
                                    }

                                    var name = nm.ToString();

                                    Log.InfoFormat("-- Remote Name : {0} - {1}", bd, name);

                                    // extract MAC address
                                    Buffer.BlockCopy(buffer, 3, bdAddr, 0, 6);

                                    if (hci.SupportedNames.Any(n => name.StartsWith(n))
                                        || hci.SupportedNames.Any(n => name == n))
                                    {
                                        nameList.Add(bd, nm.ToString());

                                        // the code below is just cut-paste from "case HCI.Event.HCI_Connection_Complete_EV"
                                        // just some adjustments made in the buffer variables

                                        if (!nameList.Any())
                                            break;

                                        connection = Add(bdHandle[0], (byte) (bdHandle[1] | 0x20), nameList[bd]);
                                        //using there the handles saved earlier

                                        // signal L2CAP task to continue
                                        _waitForConnectionComplete.Set();

                                        #region Fake DS3 workaround

                                        if (GlobalConfiguration.Instance.UseDs3CounterfeitWorkarounds &&
                                            !hci.GenuineMacAddresses.Any(m => bd.StartsWith(m)))
                                        {
                                            connection.IsFake = true;
                                            Log.Warn("-- Fake DualShock 3 found. Workaround applied");
                                        }
                                        else
                                        {
                                            connection.IsFake = false;
                                            Log.Info("-- Genuine Sony DualShock 3 found");
                                        }

                                        #endregion

                                        connection.RemoteName = nameList[bd];
                                        nameList.Remove(bd);
                                        connection.BdAddress = new[]
                                        {buffer[8], buffer[7], buffer[6], buffer[5], buffer[4], buffer[3]};
                                    }
                                    else
                                    {
                                        transfered = HCI_Reject_Connection_Request(bdAddr, 0x0F);
                                    }
                                    break;

                                    #endregion

                                    #region HCI_Link_Key_Request_EV

                                case HCI.Event.HCI_Link_Key_Request_EV:

                                    Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);

                                    transfered = HCI_Link_Key_Request_Reply(bdAddr);
                                    transfered = HCI_Set_Connection_Encryption(connection.HciHandle);
                                    break;

                                    #endregion

                                    #region HCI_PIN_Code_Request_EV

                                case HCI.Event.HCI_PIN_Code_Request_EV:

                                    Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);

                                    transfered = HCI_PIN_Code_Request_Negative_Reply(bdAddr);
                                    break;

                                    #endregion

                                    #region HCI_IO_Capability_Request_EV

                                case HCI.Event.HCI_IO_Capability_Request_EV:

                                    transfered = HCI_IO_Capability_Request_Reply(bdAddr);
                                    break;

                                    #endregion

                                    #region HCI_User_Confirmation_Request_EV

                                case HCI.Event.HCI_User_Confirmation_Request_EV:

                                    transfered = HCI_User_Confirmation_Request_Reply(bdAddr);
                                    break;

                                    #endregion

                                    #region HCI_Link_Key_Notification_EV

                                case HCI.Event.HCI_Link_Key_Notification_EV:

                                    Buffer.BlockCopy(buffer, 2, bdAddr, 0, 6);
                                    Buffer.BlockCopy(buffer, 8, bdLink, 0, 16);

                                    transfered = HCI_Set_Connection_Encryption(connection.HciHandle);
                                    break;

                                    #endregion
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in HCI_Worker_Thread: {0}", ex);
                }
            }

            HCI_Reset();

            Log.Info("-- Bluetooth  : HCI_Worker_Thread Exiting");
        }
Exemplo n.º 5
0
        private void HicWorker(object o)
        {
            var token = (CancellationToken)o;
            var nameList = new SortedDictionary<string, string>();
            var hci = IniConfig.Instance.Hci;

            var bStarted = false;
            var bd = string.Empty;

            var Buffer = new byte[512];
            var BD_Addr = new byte[6];
            var BD_Link = new byte[16];

            var Transfered = 0;
            HCI.Event Event;
            var Command = HCI.Command.HCI_Null;
            var Connection = new BthConnection();

            Log.InfoFormat("-- Bluetooth  : HCI_Worker_Thread Starting (IN: {0:X2})", IntIn);

            HCI_Reset();

            while (!token.IsCancellationRequested)
            {
                try
                {
                    if (ReadIntPipe(Buffer, Buffer.Length, ref Transfered) && Transfered > 0)
                    {
                        if (Enum.IsDefined(typeof(HCI.Event), Buffer[0]))
                        {
                            Event = (HCI.Event)Buffer[0];

                            switch (Event)
                            {
                                case HCI.Event.HCI_Command_Complete_EV:

                                    Command = (HCI.Command)(ushort)(Buffer[3] | Buffer[4] << 8);
                                    Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, Buffer[0], Buffer[5],
                                        Command);
                                    break;

                                case HCI.Event.HCI_Command_Status_EV:

                                    Command = (HCI.Command)(ushort)(Buffer[4] | Buffer[5] << 8);
                                    Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}] [{3}]", Event, Buffer[0], Buffer[2],
                                        Command);

                                    if (Buffer[2] != 0)
                                    {
                                        switch (Command)
                                        {
                                            case HCI.Command.HCI_Write_Simple_Pairing_Mode:
                                            case HCI.Command.HCI_Write_Authentication_Enable:
                                            case HCI.Command.HCI_Set_Event_Mask:

                                                GlobalConfiguration.Instance.DisableSSP = true;
                                                Log.Warn(
                                                    "-- Simple Pairing not supported on this device. [SSP Disabled]");
                                                Transfered = HCI_Write_Scan_Enable();
                                                break;
                                        }
                                    }
                                    break;

                                case HCI.Event.HCI_Number_Of_Completed_Packets_EV:
                                    break;

                                default:
                                    Log.DebugFormat(">> {0} [{1:X2}]", Event, Buffer[0]);
                                    break;
                            }

                            switch (Event)
                            {
                                case HCI.Event.HCI_Command_Complete_EV:

                                    if (Command == HCI.Command.HCI_Reset && Buffer[5] == 0 && !bStarted)
                                    {
                                        bStarted = true;
                                        Thread.Sleep(250);

                                        Transfered = HCI_Read_BD_Addr();
                                    }

                                    if (Command == HCI.Command.HCI_Read_BD_ADDR && Buffer[5] == 0)
                                    {
                                        _localMac = new[] { Buffer[6], Buffer[7], Buffer[8], Buffer[9], Buffer[10], Buffer[11] };

                                        Transfered = HCI_Read_Buffer_Size();
                                    }

                                    if (Command == HCI.Command.HCI_Read_Buffer_Size && Buffer[5] == 0)
                                    {
                                        Log.DebugFormat("-- {0:X2}{1:X2}, {2:X2}, {3:X2}{4:X2}, {5:X2}{6:X2}", Buffer[7],
                                            Buffer[6], Buffer[8], Buffer[10], Buffer[9], Buffer[12], Buffer[11]);

                                        Transfered = HCI_Read_Local_Version_Info();
                                    }

                                    // incoming HCI firmware version information
                                    if (Command == HCI.Command.HCI_Read_Local_Version_Info && Buffer[5] == 0)
                                    {
                                        var hciMajor = Buffer[6];
                                        var lmpMajor = Buffer[9];

                                        HciVersion = string.Format("{0}.{1:X4}", Buffer[6], Buffer[8] << 8 | Buffer[7]);
                                        LmpVersion = string.Format("{0}.{1:X4}", Buffer[9],
                                            Buffer[13] << 8 | Buffer[12]);

                                        Log.InfoFormat("-- Master {0}, HCI_Version {1}, LMP_Version {2}", Local,
                                            HciVersion, LmpVersion);

                                        /* analyzes Host Controller Interface (HCI) major version
                                         * see https://www.bluetooth.org/en-us/specification/assigned-numbers/host-controller-interface
                                         * */
                                        switch (hciMajor)
                                        {
                                            case 0:
                                                Log.DebugFormat("HCI_Version: Bluetooth® Core Specification 1.0b");
                                                break;
                                            case 1:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 1.1");
                                                break;
                                            case 2:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 1.2");
                                                break;
                                            case 3:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 2.0 + EDR");
                                                break;
                                            case 4:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 2.1 + EDR");
                                                break;
                                            case 5:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 3.0 + HS");
                                                break;
                                            case 6:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.0");
                                                break;
                                            case 7:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.1");
                                                break;
                                            case 8:
                                                Log.DebugFormat("HCI_Version: Bluetooth Core Specification 4.2");
                                                break;
                                            default:
                                                // this should not happen
                                                Log.ErrorFormat("HCI_Version: Specification unknown");
                                                break;
                                        }

                                        /* analyzes Link Manager Protocol (LMP) major version
                                         * see https://www.bluetooth.org/en-us/specification/assigned-numbers/link-manager
                                         * */
                                        switch (lmpMajor)
                                        {
                                            case 0:
                                                Log.DebugFormat("LMP_Version: Bluetooth® Core Specification 1.0b");
                                                break;
                                            case 1:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 1.1");
                                                break;
                                            case 2:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 1.2");
                                                break;
                                            case 3:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 2.0 + EDR");
                                                break;
                                            case 4:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 2.1 + EDR");
                                                break;
                                            case 5:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 3.0 + HS");
                                                break;
                                            case 6:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.0");
                                                break;
                                            case 7:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.1");
                                                break;
                                            case 8:
                                                Log.DebugFormat("LMP_Version: Bluetooth Core Specification 4.2");
                                                break;
                                            default:
                                                // this should not happen
                                                Log.ErrorFormat("LMP_Version: Specification unknown");
                                                break;
                                        }

                                        // Bluetooth v2.0 + EDR
                                        if (hciMajor >= 3 && lmpMajor >= 3)
                                        {
                                            Log.InfoFormat("Bluetooth host supports communication with DualShock 3 controllers");
                                        }

                                        // Bluetooth v2.1 + EDR
                                        if (hciMajor >= 4 && lmpMajor >= 4)
                                        {
                                            Log.InfoFormat("Bluetooth host supports communication with DualShock 4 controllers");
                                        }

                                        // dongle effectively too old/unsupported
                                        if (hciMajor < 3 || lmpMajor < 3)
                                        {
                                            Log.FatalFormat("Unsupported Bluetooth Specification, aborting communication");
                                            Transfered = HCI_Reset();
                                            break;
                                        }

                                        // use simple pairing?
                                        if (GlobalConfiguration.Instance.DisableSSP)
                                        {
                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                        else
                                        {
                                            Transfered = HCI_Write_Simple_Pairing_Mode();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Write_Simple_Pairing_Mode)
                                    {
                                        if (Buffer[5] == 0)
                                        {
                                            Transfered = HCI_Write_Simple_Pairing_Debug_Mode();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Write_Simple_Pairing_Debug_Mode)
                                    {
                                        Transfered = HCI_Write_Authentication_Enable();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Authentication_Enable)
                                    {
                                        if (Buffer[5] == 0)
                                        {
                                            Transfered = HCI_Set_Event_Mask();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Set_Event_Mask)
                                    {
                                        if (Buffer[5] == 0)
                                        {
                                            Transfered = HCI_Write_Page_Timeout();
                                        }
                                        else
                                        {
                                            GlobalConfiguration.Instance.DisableSSP = true;
                                            Log.Warn("-- Simple Pairing not supported on this device. [SSP Disabled]");

                                            Transfered = HCI_Write_Scan_Enable();
                                        }
                                    }

                                    if (Command == HCI.Command.HCI_Write_Page_Timeout && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Page_Scan_Activity();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Page_Scan_Activity && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Page_Scan_Type();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Page_Scan_Type && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Inquiry_Scan_Activity();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Inquiry_Scan_Activity && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Inquiry_Scan_Type();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Inquiry_Scan_Type && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Inquiry_Mode();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Inquiry_Mode && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Class_of_Device();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Class_of_Device && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Extended_Inquiry_Response();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Extended_Inquiry_Response && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Local_Name();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Local_Name && Buffer[5] == 0)
                                    {
                                        Transfered = HCI_Write_Scan_Enable();
                                    }

                                    if (Command == HCI.Command.HCI_Write_Scan_Enable && Buffer[5] == 0)
                                    {
                                        Initialised = true;
                                    }
                                    break;

                                case HCI.Event.HCI_Connection_Request_EV:

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 2];

                                    Transfered = HCI_Delete_Stored_Link_Key(BD_Addr);
                                    Transfered = HCI_Remote_Name_Request(BD_Addr);
                                    break;

                                case HCI.Event.HCI_Connection_Complete_EV:

                                    bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", Buffer[10],
                                        Buffer[9], Buffer[8], Buffer[7], Buffer[6], Buffer[5]);

                                    if (!nameList.Any())
                                        break;

                                    Connection = Add(Buffer[3], (byte)(Buffer[4] | 0x20), nameList[bd]);

                                    #region Fake DS3 workaround

                                    if (!hci.GenuineMacAddresses.Any(m => bd.StartsWith(m)))
                                    {
                                        Connection.IsFake = true;
                                        Log.Warn("-- Fake DualShock 3 found. Workaround applied");
                                    }
                                    else
                                    {
                                        Connection.IsFake = false;
                                        Log.Info("-- Genuine Sony DualShock 3 found");
                                    }

                                    #endregion

                                    Connection.RemoteName = nameList[bd];
                                    nameList.Remove(bd);
                                    Connection.BdAddress = new[] { Buffer[10], Buffer[9], Buffer[8], Buffer[7], Buffer[6], Buffer[5] };
                                    break;

                                case HCI.Event.HCI_Disconnection_Complete_EV:

                                    Remove(Buffer[3], (byte)(Buffer[4] | 0x20));
                                    break;

                                case HCI.Event.HCI_Number_Of_Completed_Packets_EV:

                                    for (byte Index = 0, Ptr = 3; Index < Buffer[2]; Index++, Ptr += 4)
                                    {
                                        OnCompletedCount(Buffer[Ptr], (byte)(Buffer[Ptr + 1] | 0x20),
                                            (ushort)(Buffer[Ptr + 2] | Buffer[Ptr + 3] << 8));
                                    }
                                    break;

                                case HCI.Event.HCI_Remote_Name_Request_Complete_EV:

                                    bd = string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", Buffer[8], Buffer[7],
                                        Buffer[6], Buffer[5], Buffer[4], Buffer[3]);
                                    var nm = new StringBuilder();

                                    for (var Index = 9; Index < Buffer.Length; Index++)
                                    {
                                        if (Buffer[Index] > 0) nm.Append((char)Buffer[Index]);
                                        else break;
                                    }

                                    var Name = nm.ToString();

                                    Log.InfoFormat("-- Remote Name : {0} - {1}", bd, Name);

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 3];

                                    if (hci.SupportedNames.Any(n => Name.StartsWith(n))
                                        || hci.SupportedNames.Any(n => Name == n))
                                    {
                                        nameList.Add(bd, nm.ToString());

                                        Transfered = HCI_Accept_Connection_Request(BD_Addr, 0x00);
                                    }
                                    else
                                    {
                                        Transfered = HCI_Reject_Connection_Request(BD_Addr, 0x0F);
                                    }
                                    break;

                                case HCI.Event.HCI_Link_Key_Request_EV:

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 2];

                                    Transfered = HCI_Link_Key_Request_Reply(BD_Addr);
                                    Transfered = HCI_Set_Connection_Encryption(Connection.HciHandle);
                                    break;

                                case HCI.Event.HCI_PIN_Code_Request_EV:

                                    for (var i = 0; i < 6; i++) BD_Addr[i] = Buffer[i + 2];

                                    Transfered = HCI_PIN_Code_Request_Negative_Reply(BD_Addr);
                                    break;

                                case HCI.Event.HCI_IO_Capability_Request_EV:

                                    Transfered = HCI_IO_Capability_Request_Reply(BD_Addr);
                                    break;

                                case HCI.Event.HCI_User_Confirmation_Request_EV:

                                    Transfered = HCI_User_Confirmation_Request_Reply(BD_Addr);
                                    break;

                                case HCI.Event.HCI_Link_Key_Notification_EV:

                                    for (var Index = 0; Index < 6; Index++) BD_Addr[Index] = Buffer[Index + 2];
                                    for (var Index = 0; Index < 16; Index++) BD_Link[Index] = Buffer[Index + 8];

                                    Transfered = HCI_Set_Connection_Encryption(Connection.HciHandle);
                                    break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in HCI_Worker_Thread: {0}", ex);
                }
            }

            HCI_Reset();

            Log.Info("-- Bluetooth  : HCI_Worker_Thread Exiting");
        }