1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/mac/bluetooth_utility.h" 6 7#import <Foundation/Foundation.h> 8#include <IOKit/IOKitLib.h> 9 10#include "base/mac/foundation_util.h" 11#include "base/mac/mac_util.h" 12#include "base/mac/scoped_ioobject.h" 13#include "base/mac/sdk_forward_declarations.h" 14 15namespace bluetooth_utility { 16 17BluetoothAvailability GetBluetoothAvailability() { 18 base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( 19 IOServiceMatching("IOBluetoothHCIController")); 20 if (!matching_dict) 21 return BLUETOOTH_AVAILABILITY_ERROR; 22 23 // IOServiceGetMatchingServices takes ownership of matching_dict. 24 io_iterator_t iter; 25 int kr = IOServiceGetMatchingServices( 26 kIOMasterPortDefault, matching_dict.release(), &iter); 27 if (kr != KERN_SUCCESS) 28 return BLUETOOTH_NOT_AVAILABLE; 29 base::mac::ScopedIOObject<io_iterator_t> scoped_iter(iter); 30 31 int bluetooth_available = false; 32 base::mac::ScopedIOObject<io_service_t> device; 33 while (device.reset(IOIteratorNext(scoped_iter.get())), device) { 34 bluetooth_available = true; 35 36 CFMutableDictionaryRef dict; 37 kr = IORegistryEntryCreateCFProperties( 38 device, &dict, kCFAllocatorDefault, kNilOptions); 39 if (kr != KERN_SUCCESS) 40 continue; 41 base::ScopedCFTypeRef<CFMutableDictionaryRef> scoped_dict(dict); 42 43 NSDictionary* objc_dict = base::mac::CFToNSCast(scoped_dict.get()); 44 NSNumber* lmp_version = 45 base::mac::ObjCCast<NSNumber>([objc_dict objectForKey:@"LMPVersion"]); 46 if (!lmp_version) 47 continue; 48 49 // The LMP version is too low to support Bluetooth LE. 50 if ([lmp_version intValue] < 6) 51 continue; 52 53 // Check the supported features registry entry for Bluetooth LE 54 // availability. The relevant bit has a different meaning on OSX 10.6, and 55 // could change again in the future. 56 if (base::mac::IsOSSnowLeopard()) 57 return BLUETOOTH_AVAILABLE_LE_UNKNOWN; 58 59 NSData* data = base::mac::ObjCCast<NSData>( 60 [objc_dict objectForKey:@"HCISupportedFeatures"]); 61 62 NSUInteger supported_features_index = 4; 63 NSUInteger length = [data length]; 64 if (length < supported_features_index + 1) 65 continue; 66 67 // The bytes are indexed in reverse order. 68 NSUInteger index = length - supported_features_index - 1; 69 70 const unsigned char* bytes = 71 static_cast<const unsigned char*>([data bytes]); 72 const unsigned char byte = bytes[index]; 73 bool le_supported = byte & kBluetoothFeatureLESupportedController; 74 if (le_supported) 75 return BLUETOOTH_AVAILABLE_WITH_LE; 76 } 77 78 return bluetooth_available ? BLUETOOTH_AVAILABLE_WITHOUT_LE 79 : BLUETOOTH_AVAILABILITY_ERROR; 80} 81 82} // namespace bluetooth_utility 83