1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
package linux
import (
"errors"
"log"
"sync"
"syscall"
"unsafe"
"github.com/bettercap/gatt/linux/gioctl"
"github.com/bettercap/gatt/linux/socket"
"golang.org/x/sys/unix"
)
type device struct {
fd int
fds []unix.PollFd
dev int
name string
rmu *sync.Mutex
wmu *sync.Mutex
}
func newDevice(n int, chk bool) (*device, error) {
fd, err := socket.Socket(socket.AF_BLUETOOTH, syscall.SOCK_RAW, socket.BTPROTO_HCI)
if err != nil {
log.Printf("could not create AF_BLUETOOTH raw socket")
return nil, err
}
if n != -1 {
return newSocket(fd, n, chk)
}
req := devListRequest{devNum: hciMaxDevices}
if err := gioctl.Ioctl(uintptr(fd), hciGetDeviceList, uintptr(unsafe.Pointer(&req))); err != nil {
log.Printf("hciGetDeviceList failed")
return nil, err
}
log.Printf("got %d devices", req.devNum)
for i := 0; i < int(req.devNum); i++ {
d, err := newSocket(fd, i, chk)
if err == nil {
log.Printf("dev: %s opened", d.name)
return d, err
} else {
log.Printf("error while opening device %d: %v", i, err)
}
}
return nil, errors.New("no supported devices available")
}
func newSocket(fd, n int, chk bool) (*device, error) {
i := hciDevInfo{id: uint16(n)}
if err := gioctl.Ioctl(uintptr(fd), hciGetDeviceInfo, uintptr(unsafe.Pointer(&i))); err != nil {
log.Printf("hciGetDeviceInfo failed")
return nil, err
}
name := string(i.name[:])
// Check the feature list returned feature list.
if chk && i.features[4]&0x40 == 0 {
err := errors.New("does not support LE")
log.Printf("dev: %s %s", name, err)
return nil, err
}
log.Printf("dev: %s up", name)
if err := gioctl.Ioctl(uintptr(fd), hciUpDevice, uintptr(n)); err != nil {
if err != syscall.EALREADY {
return nil, err
}
log.Printf("dev: %s reset", name)
if err := gioctl.Ioctl(uintptr(fd), hciResetDevice, uintptr(n)); err != nil {
log.Printf("hciResetDevice failed")
return nil, err
}
}
log.Printf("dev: %s down", name)
if err := gioctl.Ioctl(uintptr(fd), hciDownDevice, uintptr(n)); err != nil {
return nil, err
}
// Attempt to use the linux 3.14 feature, if this fails with EINVAL fall back to raw access
// on older kernels.
sa := socket.SockaddrHCI{Dev: n, Channel: socket.HCI_CHANNEL_USER}
if err := socket.Bind(fd, &sa); err != nil {
if err != syscall.EINVAL {
return nil, err
}
log.Printf("dev: %s can't bind to hci user channel, err: %s.", name, err)
sa := socket.SockaddrHCI{Dev: n, Channel: socket.HCI_CHANNEL_RAW}
if err := socket.Bind(fd, &sa); err != nil {
log.Printf("dev: %s can't bind to hci raw channel, err: %s.", name, err)
return nil, err
}
}
fds := make([]unix.PollFd, 1)
fds[0].Fd = int32(fd)
fds[0].Events = unix.POLLIN
return &device{
fd: fd,
fds: fds,
dev: n,
name: name,
rmu: &sync.Mutex{},
wmu: &sync.Mutex{},
}, nil
}
func (d device) Read(b []byte) (int, error) {
d.rmu.Lock()
defer d.rmu.Unlock()
// Use poll to avoid blocking on Read
n, err := unix.Poll(d.fds, 100)
if n == 0 || err != nil {
return 0, err
}
return syscall.Read(d.fd, b)
}
func (d device) Write(b []byte) (int, error) {
d.wmu.Lock()
defer d.wmu.Unlock()
return syscall.Write(d.fd, b)
}
func (d device) Close() error {
log.Printf("linux.device.Close()")
return syscall.Close(d.fd)
}
|