hci.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Package ble provides BLE scanning via raw HCI sockets
  2. package ble
  3. import (
  4. "encoding/binary"
  5. "fmt"
  6. "syscall"
  7. "unsafe"
  8. )
  9. // HCI constants
  10. const (
  11. AF_BLUETOOTH = 31
  12. BTPROTO_HCI = 1
  13. SOL_HCI = 0
  14. HCI_FILTER = 2
  15. // HCI packet types
  16. HCI_COMMAND_PKT = 0x01
  17. HCI_EVENT_PKT = 0x04
  18. // HCI events
  19. EVT_LE_META = 0x3E
  20. EVT_CMD_COMPLETE = 0x0E
  21. // LE Meta sub-events
  22. EVT_LE_ADVERTISING_REPORT = 0x02
  23. // OGF (Opcode Group Field)
  24. OGF_LE_CTL = 0x08
  25. // OCF (Opcode Command Field)
  26. OCF_LE_SET_SCAN_PARAMETERS = 0x000B
  27. OCF_LE_SET_SCAN_ENABLE = 0x000C
  28. // Scan types
  29. SCAN_TYPE_PASSIVE = 0x00
  30. SCAN_TYPE_ACTIVE = 0x01
  31. )
  32. // sockaddrHCI is the HCI socket address
  33. type sockaddrHCI struct {
  34. Family uint16
  35. Dev uint16
  36. Channel uint16
  37. }
  38. // hciFilter is the HCI event filter
  39. type hciFilter struct {
  40. TypeMask uint32
  41. EventMask [2]uint32
  42. Opcode uint16
  43. }
  44. // HCISocket represents a raw HCI socket
  45. type HCISocket struct {
  46. fd int
  47. devID int
  48. }
  49. // NewHCISocket creates a new HCI socket for the given device
  50. func NewHCISocket(devID int) (*HCISocket, error) {
  51. fd, err := syscall.Socket(AF_BLUETOOTH, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, BTPROTO_HCI)
  52. if err != nil {
  53. return nil, fmt.Errorf("socket: %w", err)
  54. }
  55. // Bind to device
  56. addr := sockaddrHCI{
  57. Family: AF_BLUETOOTH,
  58. Dev: uint16(devID),
  59. Channel: 0, // HCI_CHANNEL_RAW
  60. }
  61. _, _, errno := syscall.Syscall(
  62. syscall.SYS_BIND,
  63. uintptr(fd),
  64. uintptr(unsafe.Pointer(&addr)),
  65. unsafe.Sizeof(addr),
  66. )
  67. if errno != 0 {
  68. syscall.Close(fd)
  69. return nil, fmt.Errorf("bind: %v", errno)
  70. }
  71. return &HCISocket{fd: fd, devID: devID}, nil
  72. }
  73. // SetEventFilter sets the HCI event filter to receive LE Meta events
  74. func (h *HCISocket) SetEventFilter() error {
  75. var filter hciFilter
  76. // Enable HCI_EVENT_PKT
  77. filter.TypeMask = 1 << HCI_EVENT_PKT
  78. // Enable EVT_LE_META (0x3E = 62) and EVT_CMD_COMPLETE (0x0E = 14) events
  79. // EventMask is split: [0] = events 0-31, [1] = events 32-63
  80. filter.EventMask[0] = 1 << EVT_CMD_COMPLETE // bit 14
  81. filter.EventMask[1] = 1 << (EVT_LE_META - 32) // bit 30 in second word (62-32=30)
  82. _, _, errno := syscall.Syscall6(
  83. syscall.SYS_SETSOCKOPT,
  84. uintptr(h.fd),
  85. SOL_HCI,
  86. HCI_FILTER,
  87. uintptr(unsafe.Pointer(&filter)),
  88. unsafe.Sizeof(filter),
  89. 0,
  90. )
  91. if errno != 0 {
  92. return fmt.Errorf("setsockopt HCI_FILTER: %v", errno)
  93. }
  94. return nil
  95. }
  96. // SendCommand sends an HCI command
  97. func (h *HCISocket) SendCommand(ogf, ocf uint16, params []byte) error {
  98. opcode := uint16(ocf) | (uint16(ogf) << 10)
  99. buf := make([]byte, 4+len(params))
  100. buf[0] = HCI_COMMAND_PKT
  101. binary.LittleEndian.PutUint16(buf[1:3], opcode)
  102. buf[3] = byte(len(params))
  103. copy(buf[4:], params)
  104. _, err := syscall.Write(h.fd, buf)
  105. return err
  106. }
  107. // SetScanParameters sets LE scan parameters
  108. func (h *HCISocket) SetScanParameters(scanType byte, interval, window uint16) error {
  109. params := make([]byte, 7)
  110. params[0] = scanType
  111. binary.LittleEndian.PutUint16(params[1:3], interval) // interval (units of 0.625ms)
  112. binary.LittleEndian.PutUint16(params[3:5], window) // window (units of 0.625ms)
  113. params[5] = 0x00 // own address type: public
  114. params[6] = 0x00 // filter policy: accept all
  115. return h.SendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, params)
  116. }
  117. // SetScanEnable enables or disables LE scanning
  118. func (h *HCISocket) SetScanEnable(enable bool, filterDuplicates bool) error {
  119. params := make([]byte, 2)
  120. if enable {
  121. params[0] = 0x01
  122. }
  123. if filterDuplicates {
  124. params[1] = 0x01
  125. }
  126. return h.SendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, params)
  127. }
  128. // Read reads an HCI event packet
  129. func (h *HCISocket) Read(buf []byte) (int, error) {
  130. return syscall.Read(h.fd, buf)
  131. }
  132. // Close closes the HCI socket
  133. func (h *HCISocket) Close() error {
  134. return syscall.Close(h.fd)
  135. }
  136. // Fd returns the file descriptor
  137. func (h *HCISocket) Fd() int {
  138. return h.fd
  139. }