mirror of https://github.com/labapart/gattlib
Compare commits
396 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
f99558d9b8 | |
![]() |
b3c5d2d1ed | |
![]() |
9fb48aacb6 | |
![]() |
dbe599dbfb | |
![]() |
f79e90ce02 | |
![]() |
35566d198a | |
![]() |
f4ed88eb31 | |
![]() |
aaab2dc74e | |
![]() |
880f1d2cd0 | |
![]() |
8a108495a1 | |
![]() |
880ff269e5 | |
![]() |
76353f8659 | |
![]() |
db04a0eb5c | |
![]() |
2d771d9390 | |
![]() |
5406a97e57 | |
![]() |
4acf4aa0ab | |
![]() |
f609f7d507 | |
![]() |
dc009029fa | |
![]() |
cdd62f6d35 | |
![]() |
0e34df58e5 | |
![]() |
014c2802ee | |
![]() |
22dca4511c | |
![]() |
5049443704 | |
![]() |
a587aa9dfa | |
![]() |
67ff1de69b | |
![]() |
53e6c2c7ae | |
![]() |
fcedfb9e85 | |
![]() |
b57d9546df | |
![]() |
2e99c4f1b6 | |
![]() |
709b76019e | |
![]() |
0c1334c5b4 | |
![]() |
aa6a7b79bb | |
![]() |
fab0e8fa67 | |
![]() |
ce52533f39 | |
![]() |
2861549a80 | |
![]() |
7758bae7d4 | |
![]() |
42c97d4767 | |
![]() |
aac4e069c9 | |
![]() |
8f17232216 | |
![]() |
86f9a742f3 | |
![]() |
50dca02e97 | |
![]() |
6cdbe58e7b | |
![]() |
db629448fd | |
![]() |
5f43addb8f | |
![]() |
a85dd83015 | |
![]() |
5ca46ad208 | |
![]() |
f3f6bb37bb | |
![]() |
5d9a36f1d1 | |
![]() |
6e6436ceb3 | |
![]() |
5ba3eda6f5 | |
![]() |
8e351e746c | |
![]() |
6cea2d37db | |
![]() |
2a46780e96 | |
![]() |
b2c4094cb6 | |
![]() |
d2fb01d85e | |
![]() |
98833bf7ce | |
![]() |
6823c02892 | |
![]() |
7925aa6a38 | |
![]() |
2edc8f2620 | |
![]() |
36e0cb4934 | |
![]() |
24ab0ea95f | |
![]() |
e26e9f0b7a | |
![]() |
6e718253b0 | |
![]() |
ea1fe15857 | |
![]() |
00cbc1ab87 | |
![]() |
d2702050ec | |
![]() |
f4cc321a90 | |
![]() |
6321d28d25 | |
![]() |
f0426ae3e3 | |
![]() |
ebd163f1dc | |
![]() |
01ea87aa16 | |
![]() |
f38f73a9a4 | |
![]() |
e554dec3dc | |
![]() |
100c5d5f69 | |
![]() |
860f7f5b61 | |
![]() |
13bd692bb4 | |
![]() |
18e1658d6f | |
![]() |
d3d9600114 | |
![]() |
5f5cb5bd12 | |
![]() |
6751a17cee | |
![]() |
57c99c6038 | |
![]() |
b8268c4cb5 | |
![]() |
fbd65421d0 | |
![]() |
61043afd98 | |
![]() |
aacc53c511 | |
![]() |
7d5748cb0d | |
![]() |
33a634a535 | |
![]() |
2f83e85eee | |
![]() |
1530184776 | |
![]() |
b28a0422f0 | |
![]() |
b193543fb0 | |
![]() |
7a8d53d817 | |
![]() |
7922810016 | |
![]() |
8e5412a1a9 | |
![]() |
c4e4b8fa5a | |
![]() |
76fb44643f | |
![]() |
0a868a506b | |
![]() |
4c5f35f15f | |
![]() |
ad7aa1899e | |
![]() |
f894c8e23a | |
![]() |
7f6979c82b | |
![]() |
db8aee543b | |
![]() |
8065d12dac | |
![]() |
011f4e4c4a | |
![]() |
0fde4ff82d | |
![]() |
9a9e49edcd | |
![]() |
959ee55b61 | |
![]() |
118dc961d6 | |
![]() |
2518348023 | |
![]() |
884904a3c0 | |
![]() |
1d80061bf2 | |
![]() |
ec9e5cd38a | |
![]() |
d5aa8d6468 | |
![]() |
306acf8483 | |
![]() |
3c9b0eaa1c | |
![]() |
028dfef5fc | |
![]() |
a41061c1d4 | |
![]() |
642556f8b9 | |
![]() |
96407ad763 | |
![]() |
6d271f98b6 | |
![]() |
33a8a27592 | |
![]() |
0369342fd4 | |
![]() |
3ac5707c95 | |
![]() |
c1a3c02154 | |
![]() |
20f2d5facf | |
![]() |
59820e2cad | |
![]() |
ac1f3d44d5 | |
![]() |
bae7df3ee0 | |
![]() |
b5a785e4b6 | |
![]() |
75fda5df84 | |
![]() |
2570850046 | |
![]() |
d9c18b93a3 | |
![]() |
0719dcc31d | |
![]() |
5c87eda925 | |
![]() |
bdc273fe0a | |
![]() |
b82be455b4 | |
![]() |
5badee94b9 | |
![]() |
2448da5410 | |
![]() |
85acbd8c88 | |
![]() |
5b8893c647 | |
![]() |
c2c6b2f17b | |
![]() |
deee3766e1 | |
![]() |
bb90b55dde | |
![]() |
1afaa8b460 | |
![]() |
809a10a289 | |
![]() |
e93504b91f | |
![]() |
e2b189d226 | |
![]() |
f90a95bcff | |
![]() |
fa54ae42cc | |
![]() |
c3abb7eb6c | |
![]() |
f4ecc64d29 | |
![]() |
2c38df5f30 | |
![]() |
db44d7a99d | |
![]() |
d66e268865 | |
![]() |
f3b5b295bc | |
![]() |
edb5862f96 | |
![]() |
15210d1c35 | |
![]() |
3f85abd606 | |
![]() |
b137160afc | |
![]() |
9451e19426 | |
![]() |
321c37dc57 | |
![]() |
49790a92bf | |
![]() |
fee6603fa3 | |
![]() |
3c917fe683 | |
![]() |
d63b7ccb27 | |
![]() |
b8f60de4e5 | |
![]() |
acf3df7da6 | |
![]() |
6dcf6b904e | |
![]() |
bef872c588 | |
![]() |
989483acdb | |
![]() |
c6c29ad9fe | |
![]() |
054f64e115 | |
![]() |
f5c2fcc906 | |
![]() |
d4bd91ad1e | |
![]() |
b63dc0f23e | |
![]() |
0bbe347daf | |
![]() |
7056103e6a | |
![]() |
b61c03ae25 | |
![]() |
3dfaa875b6 | |
![]() |
a34a2d2a21 | |
![]() |
f18dd02530 | |
![]() |
8cb7f01104 | |
![]() |
9315ecfa54 | |
![]() |
eb70896c98 | |
![]() |
825fc4d07c | |
![]() |
c0215ee4ce | |
![]() |
4ebc640ddd | |
![]() |
d40ac8e743 | |
![]() |
a8a06114e2 | |
![]() |
ddc790358f | |
![]() |
504ee7d1a7 | |
![]() |
46da1ee50c | |
![]() |
6f3ad714a2 | |
![]() |
71c4e71952 | |
![]() |
7107d9f5b4 | |
![]() |
52f195f5c2 | |
![]() |
6df99eadbe | |
![]() |
d26065d6ad | |
![]() |
0ef32af289 | |
![]() |
51bbc0242b | |
![]() |
392d9d5eb3 | |
![]() |
1779c75062 | |
![]() |
efc656ca52 | |
![]() |
80d26d702d | |
![]() |
cfc47a0c0d | |
![]() |
9663984e9d | |
![]() |
26d288613d | |
![]() |
6a4d00b43c | |
![]() |
08ce1b3303 | |
![]() |
3d656b1e19 | |
![]() |
5c7ee43bd7 | |
![]() |
c6a3325222 | |
![]() |
d300b66ebd | |
![]() |
1f6c89f0bf | |
![]() |
55d875438b | |
![]() |
a5a45a9fad | |
![]() |
42c9f2667d | |
![]() |
6a770e4349 | |
![]() |
6ace06d3c5 | |
![]() |
3b495609ed | |
![]() |
53bb794a7d | |
![]() |
967b46bb99 | |
![]() |
51c6cbeee2 | |
![]() |
3d433e3551 | |
![]() |
e342e292fd | |
![]() |
3dd0ab40b4 | |
![]() |
193c86590e | |
![]() |
50129fe753 | |
![]() |
69fb243fe7 | |
![]() |
bcf0596abe | |
![]() |
c956a5b151 | |
![]() |
fef6659af0 | |
![]() |
3f829b806c | |
![]() |
2e6cc4c381 | |
![]() |
e9b98f6dd7 | |
![]() |
4e9b1094d4 | |
![]() |
e5daed3484 | |
![]() |
4f8625cedf | |
![]() |
2831cdf765 | |
![]() |
ca92375558 | |
![]() |
4b9252bad1 | |
![]() |
0142c33dd8 | |
![]() |
ebf3cc80fb | |
![]() |
d7a323ccd7 | |
![]() |
a42f76aa7d | |
![]() |
a52f66834a | |
![]() |
a9cd2d3c1a | |
![]() |
d55898276d | |
![]() |
bca923366e | |
![]() |
40eec80170 | |
![]() |
2ae549f9d6 | |
![]() |
eca8415fd6 | |
![]() |
531477b941 | |
![]() |
43b5d9a113 | |
![]() |
2b9d932792 | |
![]() |
e74543fa56 | |
![]() |
a1ad48f20c | |
![]() |
046f077085 | |
![]() |
8438cd5c0d | |
![]() |
1db0ab51a6 | |
![]() |
8020503ab6 | |
![]() |
1e0e57070f | |
![]() |
2accddb3c7 | |
![]() |
9a665239a1 | |
![]() |
50401ad1c5 | |
![]() |
028004a8a1 | |
![]() |
120f6e0886 | |
![]() |
2d81b253da | |
![]() |
ceaa8a17e4 | |
![]() |
683efaaca4 | |
![]() |
e3ff819872 | |
![]() |
54f06b64f5 | |
![]() |
c479cec21f | |
![]() |
9bed1e17c8 | |
![]() |
d4e0c22792 | |
![]() |
c2a07a9139 | |
![]() |
e822d3268a | |
![]() |
d8fb10906b | |
![]() |
3a1e92ae5d | |
![]() |
ca9725f806 | |
![]() |
510d650b85 | |
![]() |
58d5dac125 | |
![]() |
9db483bdcc | |
![]() |
60f3bc1c5a | |
![]() |
98ac9e5d2b | |
![]() |
bcac05a811 | |
![]() |
71f33207c7 | |
![]() |
f9b92018f1 | |
![]() |
c2e48c3fd6 | |
![]() |
10af2f1971 | |
![]() |
cbeca9d6c0 | |
![]() |
62022bdab9 | |
![]() |
ff07ac89f1 | |
![]() |
532c405323 | |
![]() |
846261120c | |
![]() |
7ad64704cb | |
![]() |
3ce4632d1c | |
![]() |
60b813a770 | |
![]() |
5a31a00871 | |
![]() |
1402183edd | |
![]() |
f0b1f7c5ef | |
![]() |
7a2fdbd062 | |
![]() |
0f8c02c6a6 | |
![]() |
096acbe837 | |
![]() |
647f3d3c10 | |
![]() |
a370ea5f02 | |
![]() |
d6a87e47a9 | |
![]() |
5b08f051d8 | |
![]() |
f4e09c0fd6 | |
![]() |
72a13512a0 | |
![]() |
2a8fee224d | |
![]() |
91f9e93522 | |
![]() |
3d7802af21 | |
![]() |
6ab868245e | |
![]() |
56a8b24153 | |
![]() |
01d5c51a0c | |
![]() |
4af454d026 | |
![]() |
82684b107e | |
![]() |
ce6e6a687d | |
![]() |
cd6701dc08 | |
![]() |
3751fd3587 | |
![]() |
8e159b683d | |
![]() |
6332cb807c | |
![]() |
d3ca083826 | |
![]() |
a8ff524171 | |
![]() |
6361b818e5 | |
![]() |
c890f64dd9 | |
![]() |
2e88aec8e1 | |
![]() |
f7a5ced9d5 | |
![]() |
a5df534400 | |
![]() |
7c40bad040 | |
![]() |
6d90fa4d48 | |
![]() |
ecc627cb8a | |
![]() |
0ee021f531 | |
![]() |
a40b8f9724 | |
![]() |
c702d74b23 | |
![]() |
cfe5613d0d | |
![]() |
beed53a6ba | |
![]() |
80f9884ae0 | |
![]() |
d0b18d5409 | |
![]() |
4dde0c3698 | |
![]() |
5391388201 | |
![]() |
1655e8c329 | |
![]() |
ee2fabaf3f | |
![]() |
74972ae011 | |
![]() |
e880df8e01 | |
![]() |
d998e0072a | |
![]() |
076067a2d7 | |
![]() |
ebe4e57591 | |
![]() |
6a083a8496 | |
![]() |
5b76fada47 | |
![]() |
15ab7a84d2 | |
![]() |
1434b741ec | |
![]() |
7417102e12 | |
![]() |
180f7dff54 | |
![]() |
e11618bdeb | |
![]() |
4ab4cddfba | |
![]() |
dfba6f53ec | |
![]() |
ecad887c2e | |
![]() |
698561a25a | |
![]() |
07a4e011da | |
![]() |
ed3ff0627f | |
![]() |
a5d4655922 | |
![]() |
671267e266 | |
![]() |
45e7a8066c | |
![]() |
bd5d8daa92 | |
![]() |
4a0b3903fb | |
![]() |
ece340a193 | |
![]() |
21541e755c | |
![]() |
751ea82bda | |
![]() |
f1aa5b0ede | |
![]() |
98eca71225 | |
![]() |
f152b8d04e | |
![]() |
e802d4ab50 | |
![]() |
9c43746ec6 | |
![]() |
48f3ab4e5f | |
![]() |
58c547fe9e | |
![]() |
1e68512f3b | |
![]() |
9c7382b215 | |
![]() |
7f32f5c346 | |
![]() |
3bce76b270 | |
![]() |
427bad8904 | |
![]() |
411dc8633f | |
![]() |
d9e67b829b | |
![]() |
4db0060a3b | |
![]() |
f9adbe5b09 | |
![]() |
ee58e4cb64 | |
![]() |
36ff478c3e | |
![]() |
69da222e3a | |
![]() |
36a267bfa7 | |
![]() |
db5ffbf47d | |
![]() |
15defc8f7d | |
![]() |
183bf5015a | |
![]() |
c5622cc385 | |
![]() |
ccea65dbae | |
![]() |
0c77aec7c9 |
|
@ -0,0 +1,118 @@
|
|||
name: gattlib
|
||||
on: [push]
|
||||
jobs:
|
||||
build-debug:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt install libbluetooth-dev
|
||||
- run: mkdir build && pushd build && cmake -DCMAKE_BUILD_TYPE=Debug -DGATTLIB_PYTHON_INTERFACE=ON .. && make
|
||||
|
||||
build-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt install libbluetooth-dev doxygen
|
||||
- run: mkdir build && pushd build && cmake -DCMAKE_BUILD_TYPE=Release -DGATTLIB_BUILD_DOCS=ON -DGATTLIB_PYTHON_INTERFACE=ON .. && make
|
||||
- run: pushd build && cpack ..
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
PACKAGE_VERSION: '${{github.ref_name}}'
|
||||
- name: Archive Distribution packages
|
||||
uses: actions/upload-artifact@v4
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
name: distribution-packages
|
||||
path: |
|
||||
build/*.deb
|
||||
build/*.rpm
|
||||
build/*.zip
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: |
|
||||
build/*.deb
|
||||
build/*.rpm
|
||||
build/*.zip
|
||||
|
||||
build-release-force-dbus:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt install libbluetooth-dev
|
||||
- run: mkdir build && pushd build && cmake -DGATTLIB_FORCE_DBUS=TRUE -DCMAKE_BUILD_TYPE=Release -DGATTLIB_PYTHON_INTERFACE=ON .. && make
|
||||
|
||||
build-release-without-python-support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt install libbluetooth-dev
|
||||
- run: mkdir build && pushd build && cmake -DCMAKE_BUILD_TYPE=Release -DGATTLIB_PYTHON_INTERFACE=OFF .. && make
|
||||
|
||||
test-pylint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: python3 -m pip install PyGObject>=3.44.0
|
||||
- run: python3 -m pip install pylint
|
||||
- run: python3 -m pylint gattlib-py/gattlib --rcfile gattlib-py/.pylintrc
|
||||
|
||||
generate-python-binary-packages:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt install -y libbluetooth-dev
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
- run: ./ci/generate-python-package.sh
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
CIBW_BEFORE_BUILD_LINUX: "sh ci/install-bluez.sh"
|
||||
GATTLIB_PY_VERSION: '${{github.ref_name}}'
|
||||
CIBW_ENVIRONMENT_PASS_LINUX: "GATTLIB_PY_VERSION"
|
||||
#TODO: To support 'musllinux', we need to replace 'yum install' by 'apk install' - and detect which platform we are
|
||||
CIBW_SKIP: "*-musllinux_*"
|
||||
- run: ./ci/generate-python-package.sh
|
||||
if: ${{ ! startsWith(github.ref, 'refs/tags/') }}
|
||||
env:
|
||||
CIBW_BEFORE_BUILD_LINUX: "sh ci/install-bluez.sh"
|
||||
GATTLIB_PY_VERSION: '0.0.1'
|
||||
CIBW_ENVIRONMENT_PASS_LINUX: "GATTLIB_PY_VERSION"
|
||||
#TODO: To support 'musllinux', we need to replace 'yum install' by 'apk install' - and detect which platform we are
|
||||
CIBW_SKIP: "*-musllinux_*"
|
||||
- name: Archive Python packages
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: python-binary-packages
|
||||
path: dist/*
|
||||
|
||||
# publish-python-packages:
|
||||
# needs:
|
||||
# - generate-python-binary-packages
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/download-artifact@master
|
||||
# - run: ls *
|
||||
|
||||
publish-to-pypi:
|
||||
name: >-
|
||||
Publish Python 🐍 distribution 📦 to PyPI
|
||||
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
|
||||
needs:
|
||||
- generate-python-binary-packages
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: pypi
|
||||
url: https://pypi.org/p/gattlib-py # Replace <package-name> with your PyPI project name
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: mandatory for trusted publishing
|
||||
steps:
|
||||
- uses: actions/download-artifact@master
|
||||
- run: |
|
||||
mkdir dist/
|
||||
mv python-binary-packages/*.tar.gz dist/
|
||||
mv python-binary-packages/*.whl dist/
|
||||
ls dist/*
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@ -0,0 +1,9 @@
|
|||
# IDE files
|
||||
.vscode/
|
||||
|
||||
# Generated files
|
||||
build
|
||||
__pycache__
|
||||
MANIFEST.in
|
||||
dist
|
||||
gattlib-py/gattlib_py.egg-info/
|
|
@ -0,0 +1,111 @@
|
|||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
#Disable Clang for now until we support ARM cross-toolchain - clang
|
||||
|
||||
dist: xenial
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-aarch64-linux-gnu
|
||||
- g++-aarch64-linux-gnu
|
||||
- libbluetooth-dev
|
||||
- rpm
|
||||
- python3-pip
|
||||
- python3-setuptools
|
||||
- doxygen
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ ! -f $PWD/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf ]; then
|
||||
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz
|
||||
tar xf gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz
|
||||
fi
|
||||
- pip3 install --upgrade cross-sysroot
|
||||
- pip3 install Sphinx
|
||||
- pip3 install breathe
|
||||
|
||||
script:
|
||||
# Build default Gattlib - Debug
|
||||
- mkdir build-debug && pushd build-debug
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug .. && make
|
||||
- popd
|
||||
|
||||
# Build and Package default Gattlib - Release
|
||||
- mkdir build-release && pushd build-release
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release .. && make && cpack ..
|
||||
- popd
|
||||
|
||||
# Build Gattlib with DBus support - Debug
|
||||
- mkdir build-dbus-debug && pushd build-dbus-debug
|
||||
- cmake -DGATTLIB_FORCE_DBUS=TRUE -DCMAKE_BUILD_TYPE=Debug .. && make
|
||||
- popd
|
||||
|
||||
# Build and Package Gattlib with DBus support - Release
|
||||
- mkdir build-dbus-release && pushd build-dbus-release
|
||||
- cmake -DGATTLIB_FORCE_DBUS=TRUE -DCMAKE_BUILD_TYPE=Release .. && make && cpack ..
|
||||
- popd
|
||||
|
||||
#
|
||||
# Setup build for ARM 32-bit
|
||||
#
|
||||
# Set environment variables
|
||||
- export SYSROOT=$PWD/debian-stable-arm
|
||||
- export CROSS_COMPILE=$PWD/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
|
||||
|
||||
# Ensure folder is empty
|
||||
- rm -Rf $PWD/debian-stable-arm/*
|
||||
- cross-sysroot --distribution debian --distribution-version stable --architecture armhf --cross-gcc ${CROSS_COMPILE}gcc --build-root $PWD/debian-stable-arm requirements.dep
|
||||
|
||||
# Build and Package Gattlib with DBus support - Release - ARM32
|
||||
- mkdir build-dbus-release-arm32 && pushd build-dbus-release-arm32
|
||||
- cmake -DGATTLIB_FORCE_DBUS=TRUE -DCMAKE_BUILD_TYPE=Release .. && make VERBOSE=1 && cpack ..
|
||||
- popd
|
||||
|
||||
#
|
||||
# Setup build for ARM 64-bit
|
||||
#
|
||||
# Ensure folder is empty
|
||||
- rm -Rf $PWD/debian-stable-arm64/*
|
||||
- cross-sysroot --distribution debian --distribution-version stable --architecture arm64 --build-root $PWD/debian-stable-arm64 requirements.dep
|
||||
|
||||
# Set environment variables
|
||||
- export SYSROOT=$PWD/debian-stable-arm64
|
||||
- export CROSS_COMPILE=aarch64-linux-gnu-
|
||||
|
||||
# Build and Package Gattlib with DBus support - Release - ARM64
|
||||
- mkdir build-dbus-release-arm64 && pushd build-dbus-release-arm64
|
||||
- cmake -DGATTLIB_FORCE_DBUS=TRUE -DCMAKE_BUILD_TYPE=Release .. && make VERBOSE=1 && cpack ..
|
||||
- popd
|
||||
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then ./update-dev-tag.sh; fi
|
||||
|
||||
before_deploy:
|
||||
# Create directory to store the artifacts we want to deploy
|
||||
- mkdir artifacts
|
||||
|
||||
# Copy packages to artifacts
|
||||
- cp build-release/gattlib_*_x86_64.deb artifacts/
|
||||
- cp build-release/gattlib_*_x86_64.rpm artifacts/
|
||||
- cp build-release/gattlib_*_x86_64.zip artifacts/
|
||||
# Copy DBUS packages to artifacts
|
||||
- for f in build-dbus-release/gattlib_*; do cp "$f" "`echo $f | sed 's/build-dbus-release\/gattlib_/artifacts\/gattlib_dbus_/'`"; done
|
||||
# Copy DBUS ARM packages to artifacts
|
||||
- cp build-dbus-release-arm32/gattlib_*_armhf.deb artifacts/
|
||||
- cp build-dbus-release-arm32/gattlib_*_armhf.zip artifacts/
|
||||
# Copy DBUS ARM64 packages to artifacts
|
||||
- cp build-dbus-release-arm64/gattlib_*_arm64.deb artifacts/
|
||||
- cp build-dbus-release-arm64/gattlib_*_arm64.zip artifacts/
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api-key: ${GITHUB_OAUTH_TOKEN}
|
||||
file_glob: true
|
||||
file: artifacts/*
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
on:
|
||||
tags: true
|
||||
|
200
CMakeLists.txt
200
CMakeLists.txt
|
@ -1,90 +1,178 @@
|
|||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
|
||||
#
|
||||
# GattLib - GATT Library
|
||||
#
|
||||
# Copyright (C) 2016 Olivier Martin <olivier@labapart.org>
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
# Copyright (c) 2016-2024, Olivier Martin <olivier@labapart.org>
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_minimum_required(VERSION 3.22.0)
|
||||
|
||||
# Add Cross-Compilation support when the environment variables
|
||||
# CROSS_COMPILE and SYSROOT are defined
|
||||
include(CrossCompilation.cmake)
|
||||
|
||||
project(gattlib)
|
||||
|
||||
#TODO: Gattlib examples must be ported to new gattlib_connect()
|
||||
option(GATTLIB_BUILD_EXAMPLES "Build GattLib examples" YES)
|
||||
option(GATTLIB_SHARED_LIB "Build GattLib as a shared library" YES)
|
||||
option(GATTLIB_BUILD_DOCS "Build GattLib docs" NO)
|
||||
option(GATTLIB_PYTHON_INTERFACE "Build GattLib Python Interface" NO)
|
||||
option(GATTLIB_ENABLE_ADDRESS_SANITIZER "Enable address sanitizer" NO)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Doxygen)
|
||||
|
||||
include_directories(include bluez/attrib bluez/btio bluez/src)
|
||||
# Define 'Debug' as the default build type
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Debug")
|
||||
endif()
|
||||
|
||||
# Bluez specific files
|
||||
set(gattlib_SRCS bluez/attrib/att.c
|
||||
bluez/attrib/gatt.c
|
||||
bluez/attrib/gattrib.c
|
||||
bluez/btio/btio.c
|
||||
bluez/lib/bluetooth.c
|
||||
bluez/lib/hci.c
|
||||
bluez/lib/sdp.c
|
||||
bluez/lib/uuid.c
|
||||
bluez/src/log.c)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DDEBUG)
|
||||
endif()
|
||||
|
||||
add_definitions(-DVERSION="4.101")
|
||||
# Show all the warnings
|
||||
if (MSVC)
|
||||
# warning level 4
|
||||
add_compile_options(/W4)
|
||||
else()
|
||||
# additional warnings
|
||||
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-variadic-macros)
|
||||
endif()
|
||||
# Add stack protector
|
||||
add_compile_options(-fstack-protector-strong)
|
||||
|
||||
# Gattlib files
|
||||
list(APPEND gattlib_SRCS src/gattlib_connect.c
|
||||
src/gattlib_discover.c
|
||||
src/gattlib_read_write.c)
|
||||
if (GATTLIB_ENABLE_ADDRESS_SANITIZER)
|
||||
add_compile_options(-fsanitize=address -fsanitize=bounds -fsanitize=undefined -fsanitize-recover=address)
|
||||
add_link_options(-fsanitize=address -fsanitize=bounds -fsanitize=undefined -fsanitize-recover=address -static-libasan)
|
||||
endif()
|
||||
|
||||
# Added Glib support
|
||||
pkg_search_module(GLIB REQUIRED glib-2.0)
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
list(APPEND gattlib_LIBS ${GLIB_LIBRARIES})
|
||||
# Expose 'gattlib.h' to all sub-directories
|
||||
include_directories(include)
|
||||
|
||||
# gattlib
|
||||
add_library(gattlib SHARED ${gattlib_SRCS})
|
||||
target_link_libraries(gattlib ${gattlib_LIBS})
|
||||
if (NOT BLUEZ_VERSION)
|
||||
# Check version of Bluez to know which backend we use (ie: Bluez code or DBus)
|
||||
pkg_search_module(BLUEZ bluez)
|
||||
if (NOT BLUEZ_FOUND)
|
||||
message(FATAL_ERROR "Please install 'libbluetooth-dev'")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Examples
|
||||
add_subdirectory(examples/discover)
|
||||
add_subdirectory(examples/read_write)
|
||||
add_subdirectory(examples/gatttool)
|
||||
# Extract Bluez version
|
||||
string(REPLACE "." ";" BLUEZ_VERSIONS "${BLUEZ_VERSION}")
|
||||
list(GET BLUEZ_VERSIONS 0 BLUEZ_VERSION_MAJOR)
|
||||
list(GET BLUEZ_VERSIONS 1 BLUEZ_VERSION_MINOR)
|
||||
add_definitions(-DBLUEZ_VERSION_MAJOR=${BLUEZ_VERSION_MAJOR} -DBLUEZ_VERSION_MINOR=${BLUEZ_VERSION_MINOR})
|
||||
|
||||
set(GATTLIB_FORCE_DBUS OFF CACHE BOOL "Build gattlib with D-Bus support on Bluez version < v5.42")
|
||||
|
||||
if (BLUEZ_VERSION_MAJOR LESS 5)
|
||||
set(GATTLIB_DBUS FALSE)
|
||||
elseif (BLUEZ_VERSION_MINOR LESS 42)
|
||||
if (GATTLIB_FORCE_DBUS)
|
||||
set(GATTLIB_DBUS TRUE)
|
||||
else()
|
||||
set(GATTLIB_DBUS FALSE)
|
||||
endif()
|
||||
else()
|
||||
set(GATTLIB_DBUS TRUE)
|
||||
endif()
|
||||
|
||||
# With 'syslog' backend, we enable all logs (ie: up to level debug) and we leave the
|
||||
# application to set the level using 'setlogmask()'
|
||||
set(GATTLIB_LOG_LEVEL 3 CACHE STRING "Define the minimum logging level for Gattlib (0=error, 1=warning, 2=info, 3=debug)")
|
||||
set(GATTLIB_LOG_BACKEND syslog CACHE STRING "Define logging backend: syslog, printf, python (default: syslog)")
|
||||
|
||||
if (GATTLIB_DBUS)
|
||||
# Build dbus-based gattlib
|
||||
add_subdirectory(dbus)
|
||||
|
||||
# Add the Gattlib build directory for the examples
|
||||
link_directories(${PROJECT_BINARY_DIR}/dbus)
|
||||
else()
|
||||
# Build bluez-based gattlib
|
||||
add_subdirectory(bluez)
|
||||
|
||||
# Add the Gattlib build directory for the examples
|
||||
link_directories(${PROJECT_BINARY_DIR}/bluez)
|
||||
endif()
|
||||
|
||||
if(GATTLIB_BUILD_DOCS)
|
||||
if (NOT Doxygen_FOUND)
|
||||
message(FATAL_ERROR "Gattlib documentation requires Doxygen. Or disable doc generation with '-DGATTLIB_BUILD_DOCS=OFF'")
|
||||
endif()
|
||||
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
# Generate pkg-config file before building the examples
|
||||
configure_file(dbus/gattlib.pc.in ${PROJECT_BINARY_DIR}/gattlib.pc @ONLY)
|
||||
|
||||
# Add the build directory to PKG_CONFIG_PATH
|
||||
set(ENV{PKG_CONFIG_PATH} "${PROJECT_BINARY_DIR}:$ENV{PKG_CONFIG_PATH}")
|
||||
|
||||
if(GATTLIB_BUILD_EXAMPLES)
|
||||
# Examples
|
||||
add_subdirectory(examples/advertisement_data)
|
||||
add_subdirectory(examples/ble_scan)
|
||||
add_subdirectory(examples/discover)
|
||||
add_subdirectory(examples/find_eddystone)
|
||||
add_subdirectory(examples/read_write)
|
||||
#add_subdirectory(examples/read_write_memory)
|
||||
add_subdirectory(examples/notification)
|
||||
#add_subdirectory(examples/nordic_uart)
|
||||
add_subdirectory(tests/test_continuous_connection)
|
||||
|
||||
# Some examples require Bluez code and other DBus support
|
||||
if (NOT GATTLIB_DBUS)
|
||||
add_subdirectory(examples/gatttool)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# Packaging
|
||||
#
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY /usr CACHE STRING "Install directory (default: /usr).")
|
||||
set(CPACK_PACKAGE_VERSION 0.1)
|
||||
if (ENV{PACKAGE_VERSION} AND (NOT "ENV{PACKAGE_VERSION}" STREQUAL "dev"))
|
||||
message("Package Gattlib for tagged version $ENV{PACKAGE_VERSION}")
|
||||
|
||||
# Transform 'v0.3' into '0.3' and 'v0.3-rc1' into '0.3-rc1'
|
||||
string(REGEX REPLACE "v([0-9]+).([0-9]+)(.*)" "\\1.\\2\\3" CPACK_PACKAGE_VERSION $ENV{PACKAGE_VERSION})
|
||||
else()
|
||||
set(CPACK_PACKAGE_VERSION 0.4-dev)
|
||||
message("Package Gattlib for development version $ENV{CPACK_PACKAGE_VERSION}")
|
||||
endif()
|
||||
set(CPACK_PACKAGE_CONTACT "Olivier Martin <olivier@labapart.com>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Library to access GATT information from Bluetooth Low Power devices")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Library to access GATT information from Bluetooth Low Energy (BLE) devices")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
|
||||
|
||||
#
|
||||
# Debian package
|
||||
# Debian, RPM and ZIP packages
|
||||
#
|
||||
set(CPACK_GENERATOR "DEB;RPM;ZIP")
|
||||
if (CMAKE_SYSROOT)
|
||||
# CPack does like RPM package in a cross-toolchain context
|
||||
set(CPACK_GENERATOR "DEB;ZIP")
|
||||
else()
|
||||
set(CPACK_GENERATOR "DEB;RPM;ZIP")
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_SYSROOT)
|
||||
# Detect platform architecture to use it for the Debian package
|
||||
execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_QUIET)
|
||||
execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_QUIET)
|
||||
endif()
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libglib2.0-0")
|
||||
|
||||
# Bluez DBus API changed from v5.40
|
||||
if (GATTLIB_DBUS AND (BLUEZ_VERSION_MAJOR EQUAL 5) AND (BLUEZ_VERSION_MINOR GREATER 39))
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, bluez (>= 5.40)")
|
||||
endif()
|
||||
|
||||
#
|
||||
# List of file to install
|
||||
#
|
||||
configure_file(gattlib.pc.in gattlib.pc @ONLY)
|
||||
install(TARGETS gattlib LIBRARY DESTINATION lib)
|
||||
install(FILES include/gattlib.h DESTINATION include)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/gattlib.pc DESTINATION lib/pkgconfig)
|
||||
include(GNUInstallDirs)
|
||||
install(FILES include/gattlib.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${PROJECT_BINARY_DIR}/gattlib.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
include(CPack)
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (c) 2016-2021, Olivier Martin <olivier@labapart.org>
|
||||
#
|
||||
#
|
||||
# Version: 1.0
|
||||
# Repository: https://gist.github.com/oliviermartin/
|
||||
# Description:
|
||||
#
|
||||
# Add Cross-Compilation support when the environment variables
|
||||
# CROSS_COMPILE and SYSROOT are defined
|
||||
|
||||
#
|
||||
# Check required environment variables
|
||||
#
|
||||
if ("$ENV{CROSS_COMPILE}" STREQUAL "")
|
||||
# Cross compilation is not needed
|
||||
|
||||
# We still set CPACK_PACKAGE_ARCHITECTURE
|
||||
if (NOT DEFINED CPACK_PACKAGE_ARCHITECTURE)
|
||||
execute_process(COMMAND uname -m OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
|
||||
return()
|
||||
endif()
|
||||
if ("$ENV{SYSROOT}" STREQUAL "")
|
||||
message(WARNING "Environment variable SYSROOT is not defined.")
|
||||
endif()
|
||||
|
||||
# Trigger cross-compilation in CMake
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
|
||||
# Specify the cross compiler
|
||||
set(CMAKE_C_COMPILER $ENV{CROSS_COMPILE}gcc)
|
||||
set(CMAKE_CXX_COMPILER $ENV{CROSS_COMPILE}g++)
|
||||
|
||||
# Specify the target environment
|
||||
set(CMAKE_FIND_ROOT_PATH $ENV{SYSROOT})
|
||||
set(CMAKE_SYSROOT $ENV{SYSROOT})
|
||||
|
||||
# Retrieve the machine supported by the toolchain
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpmachine OUTPUT_VARIABLE TOOLCHAIN_MACHINE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
# Add '--sysroot' to the compiler flags
|
||||
set(ENV{CFLAGS} "--sysroot=$ENV{SYSROOT} $ENV{CFLAGS}")
|
||||
|
||||
# Add '-rpath' to the linker flags
|
||||
set(ENV{LDFLAGS} "--sysroot=$ENV{SYSROOT} -Wl,-rpath,$ENV{SYSROOT}/lib/${TOOLCHAIN_MACHINE} $ENV{LDFLAGS}")
|
||||
|
||||
#
|
||||
# Configure pkg-config for cross-compilation
|
||||
#
|
||||
if(IS_DIRECTORY "$ENV{SYSROOT}/usr/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} $ENV{SYSROOT}/usr/lib/pkgconfig)
|
||||
endif()
|
||||
if(IS_DIRECTORY "$ENV{SYSROOT}/usr/lib/${TOOLCHAIN_MACHINE}/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} $ENV{SYSROOT}/usr/lib/${TOOLCHAIN_MACHINE}/pkgconfig)
|
||||
endif()
|
||||
if (NOT "$ENV{PKG_CONFIG_PATH}" STREQUAL "")
|
||||
set(ENV{PKG_CONFIG_SYSROOT_DIR} $ENV{SYSROOT})
|
||||
# Don't strip -I/usr/include out of cflags
|
||||
set(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS} 1)
|
||||
# Don't strip -L/usr/lib out of libs
|
||||
set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 1)
|
||||
endif()
|
||||
|
||||
# Workaround as some pkgconfig file forgot to add the architecture specific include folder
|
||||
# such as openssl.pc
|
||||
include_directories($ENV{SYSROOT}/usr/include $ENV{SYSROOT}/usr/include/${TOOLCHAIN_MACHINE})
|
||||
|
||||
# Workaround as some library are installed in $ENV{SYSROOT}/lib/${TOOLCHAIN_MACHINE}
|
||||
# such as libpcre.so (required by glib-2.0)
|
||||
link_directories($ENV{SYSROOT}/lib/${TOOLCHAIN_MACHINE})
|
||||
link_directories($ENV{SYSROOT}/usr/lib/${TOOLCHAIN_MACHINE})
|
||||
|
||||
# search for programs in the build host directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
# for libraries and headers in the target directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
#
|
||||
# Set architecture for CPack
|
||||
#
|
||||
if ("${TOOLCHAIN_MACHINE}" STREQUAL "arm-linux-gnueabihf")
|
||||
set(CPACK_PACKAGE_ARCHITECTURE armhf)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE armhf)
|
||||
set(CPACK_RPM_PACKAGE_ARCHITECTURE armv7hl)
|
||||
endif()
|
||||
if ("${TOOLCHAIN_MACHINE}" STREQUAL "aarch64-linux-gnu")
|
||||
set(CPACK_PACKAGE_ARCHITECTURE arm64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64)
|
||||
set(CPACK_RPM_PACKAGE_ARCHITECTURE aarch64)
|
||||
endif()
|
100
README.md
100
README.md
|
@ -1,14 +1,25 @@
|
|||
GattLib is a library used to access Generic Attribute Profile (GATT) protocol of BLE (Bluetooth Low Energy) devices.
|
||||
It has been introduced to allow to build applications that could easily communicate with BLE devices.
|
||||
|
||||
It is based on Bluez 4.101 GATT code (prior to Bluez D-BUS API).
|
||||
It supports Bluez v4 and v5.
|
||||
|
||||
It has been introduced to allow to build applications hosted on platform with a version of Bluez prior to v5.x that could easily communicate with BLE devices.
|
||||
Latest GattLib Release packages
|
||||
===============================
|
||||
|
||||
Potentially, D-BUS API could also be added to GattLib to provide an abstraction layer between different versions of BlueZ.
|
||||
* The latest release can be found [here](https://github.com/labapart/gattlib/releases/latest). It contains:
|
||||
|
||||
- Prebuilt Debian, RPM and ZIP packages for x86_64 and Bluez v5.x
|
||||
- Packages for ARM 32bit and 64bit would have to be built by the developer - see section [Package GattLib](#package-gattlib).
|
||||
|
||||
- Prebuilt Python packages are available on [Pypi repository](https://pypi.org/project/gattlib-py/).
|
||||
|
||||
Build GattLib
|
||||
=============
|
||||
|
||||
* Gattlib requires the following packages: `libbluetooth-dev`, `libreadline-dev`.
|
||||
On Debian based system (such as Ubuntu), you can installed these packages with the
|
||||
following command: `sudo apt install libbluetooth-dev libreadline-dev`
|
||||
|
||||
```
|
||||
cd <gattlib-src-root>
|
||||
mkdir build && cd build
|
||||
|
@ -16,6 +27,42 @@ cmake ..
|
|||
make
|
||||
```
|
||||
|
||||
* Gattlib can also be built for a specific version of Bluez by specifying its version at build time:
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake -DBLUEZ_VERSION=5.50 ..
|
||||
make
|
||||
```
|
||||
|
||||
|
||||
* **On Bluez versions prior to v5.42**, gattlib used Bluez source code while it uses D-Bus API
|
||||
from v5.42. D-Bus API can be used on version prior to Bluez v5.42 by using the CMake flag `-DGATTLIB_FORCE_DBUS=TRUE`:
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake -DGATTLIB_FORCE_DBUS=TRUE ..
|
||||
make
|
||||
```
|
||||
|
||||
### Cross-Compilation
|
||||
|
||||
To cross-compile GattLib, you must provide the following environment variables:
|
||||
|
||||
- `CROSS_COMPILE`: prefix of your cross-compile toolchain
|
||||
- `SYSROOT`: an existing system root that contains the libraries and include files required by your application
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
cd <gattlib-src-root>
|
||||
mkdir build && cd build
|
||||
export CROSS_COMPILE=~/Toolchains/gcc-linaro-4.9-2015.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
|
||||
export SYSROOT=~/Distributions/debian-wheezy
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
Package GattLib
|
||||
===============
|
||||
|
||||
|
@ -31,24 +78,40 @@ To change the install directory to `/usr/local` run: `cpack -DCPACK_PACKAGE_INST
|
|||
Examples
|
||||
========
|
||||
|
||||
* Demonstrate discovering of primary services and characteristics:
|
||||
* [Demonstrate discovering of primary services and characteristics](/examples/discover/discover.c):
|
||||
|
||||
./examples/discover/discover 78:A5:04:22:45:4F
|
||||
|
||||
* Demonstrate characteristic read/write:
|
||||
* [Demonstrate characteristic read/write](/examples/read_write/read_write.c):
|
||||
|
||||
./examples/read_write/read_write 78:A5:04:22:45:4F read 00002a29-0000-1000-8000-00805f9b34fb
|
||||
./examples/read_write/read_write 78:A5:04:22:45:4F write 00002a6b-0000-1000-8000-00805f9b34fb 0x1234
|
||||
|
||||
**Note:** `examples/gatttool` has been partially ported to gattlib. There are two reasons the laziness
|
||||
* [Demonstrate BLE scanning and connection](/examples/ble_scan/ble_scan.c):
|
||||
|
||||
./examples/ble_scan/ble_scan
|
||||
|
||||
* [Demonstrate GATT notification using GATT Battery service](/examples/notification/notification.c):
|
||||
|
||||
./examples/notification/notification
|
||||
|
||||
* [Demonstrate GATT Write Without Response](/examples/nordic_uart/nordic_uart.c):
|
||||
|
||||
./examples/nordic_uart/nordic_uart
|
||||
|
||||
**Note 1:** [The example 'read/write mem'](/examples/read_write_mem/read_write.c) is similar to
|
||||
[the example 'read/write'](/examples/read_write/read_write.c) except a GLib loop is used to allows
|
||||
the memory to be freed by Glib. Without this loop, some memory could be locked.
|
||||
|
||||
**Note 2:** `examples/gatttool` has been partially ported to gattlib. There are two reasons: the laziness
|
||||
(some of the GATT functions could be replaced by their gattlib equivalent) and the completeness (there
|
||||
are still some missing functions in gattlib).
|
||||
|
||||
* Notification is also supported. Example:
|
||||
|
||||
```
|
||||
void notification_cb(uint16_t handle, const uint8_t* data, size_t data_length) {
|
||||
printf("Notification on handle 0x%02x : ", handle);
|
||||
void notification_cb(uint16_t handle, const uint8_t* data, size_t data_length, void* user_data) {
|
||||
printf("Notification on handle 0x%02x\n", handle);
|
||||
}
|
||||
|
||||
main() {
|
||||
|
@ -58,13 +121,30 @@ main() {
|
|||
// Enable Status Notification
|
||||
gattlib_write_char_by_handle(connection, status_handle + 1, &enable_notification, sizeof(enable_notification));
|
||||
// Register notification handler
|
||||
gattlib_register_notification(notification_cb);
|
||||
gattlib_register_notification(connection, notification_cb, NULL);
|
||||
}
|
||||
```
|
||||
|
||||
Known limitations
|
||||
-----------------
|
||||
|
||||
* **gattlib and BLE**: gattlib requires at least Bluez v4.100 to work with Bluetooth Low Energy (BLE) devices. Bluez does not allow to connect to BLE device prior to this version. But gattlib can still work with Bluetooth Classic (BR/EDR) prior to Bluez v4.100.
|
||||
Debian 7 "Wheezy" (supported until 31st of May 2018) relies on Bluez v4.99 while Debian 8 "Jessie" (supported until April/May 2020) uses Bluez v5.23.
|
||||
|
||||
TODO List
|
||||
=========
|
||||
|
||||
- Complete `examples/gatttool` port to GattLib to demonstrate the completeness of GattLib.
|
||||
- Support Bluez v5.x GATT D-BUS API in addition to the current Bluez v4.101 support.
|
||||
- Remove GLib dependencies to GattLib (mainly replacing GLib IO Channels by Unix Domain Socket).
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Gattlib with Bluez Legacy support (for Bluez v4) has a GPL v2.0 or later license.
|
||||
While Gattlib for recent version of Bluez (v5.40+) has a BSD-3-Clause license - except `dbus/bluez5/lib/uuid.c`
|
||||
and `dbus/bluez5/lib/uuid.h` that have a GPL v2.0 or later license.
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
Commercial Support can be obtained through [Lab A Part](https://labapart.com). Please contact us: [https://labapart.com/about/](https://labapart.com/about/).
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
#
|
||||
# GattLib - GATT Library
|
||||
#
|
||||
# Copyright (C) 2016-2024 Olivier Martin <olivier@labapart.org>
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.22.0)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
message("Build gattlib for Bluez v${BLUEZ_VERSION_MAJOR}.${BLUEZ_VERSION_MINOR}")
|
||||
|
||||
set(bluez4_DIR bluez4)
|
||||
set(bluez5_DIR bluez5)
|
||||
|
||||
# Bluez specific files
|
||||
set(bluez4_SRCS ${bluez4_DIR}/attrib/att.c
|
||||
${bluez4_DIR}/attrib/gatt.c
|
||||
${bluez4_DIR}/attrib/gattrib.c
|
||||
${bluez4_DIR}/btio/btio.c
|
||||
${bluez4_DIR}/lib/bluetooth.c
|
||||
${bluez4_DIR}/lib/hci.c
|
||||
${bluez4_DIR}/lib/sdp.c
|
||||
${bluez4_DIR}/lib/uuid.c
|
||||
${bluez4_DIR}/src/log.c)
|
||||
|
||||
set(bluez5_SRCS ${bluez5_DIR}/attrib/att.c
|
||||
${bluez5_DIR}/attrib/gatt.c
|
||||
${bluez5_DIR}/attrib/gattrib.c
|
||||
${bluez5_DIR}/btio/btio.c
|
||||
${bluez5_DIR}/lib/bluetooth.c
|
||||
${bluez5_DIR}/lib/hci.c
|
||||
${bluez5_DIR}/lib/sdp.c
|
||||
${bluez5_DIR}/lib/uuid.c
|
||||
${bluez5_DIR}/src/log.c
|
||||
${bluez5_DIR}/src/shared/queue.c
|
||||
${bluez5_DIR}/src/shared/util.c
|
||||
${bluez5_DIR}/src/shared/mgmt.c
|
||||
${bluez5_DIR}/src/shared/crypto.c
|
||||
${bluez5_DIR}/src/shared/ecc.c
|
||||
${bluez5_DIR}/src/shared/ringbuf.c
|
||||
${bluez5_DIR}/src/shared/tester.c
|
||||
${bluez5_DIR}/src/shared/hci.c
|
||||
${bluez5_DIR}/src/shared/hci-crypto.c
|
||||
${bluez5_DIR}/src/shared/hfp.c
|
||||
${bluez5_DIR}/src/shared/uhid.c
|
||||
${bluez5_DIR}/src/shared/pcap.c
|
||||
${bluez5_DIR}/src/shared/btsnoop.c
|
||||
${bluez5_DIR}/src/shared/ad.c
|
||||
${bluez5_DIR}/src/shared/att.c
|
||||
${bluez5_DIR}/src/shared/gatt-helpers.c
|
||||
${bluez5_DIR}/src/shared/gatt-client.c
|
||||
${bluez5_DIR}/src/shared/gatt-server.c
|
||||
${bluez5_DIR}/src/shared/gatt-db.c
|
||||
${bluez5_DIR}/src/shared/gap.c
|
||||
${bluez5_DIR}/src/shared/io-glib.c
|
||||
${bluez5_DIR}/src/shared/timeout-glib.c)
|
||||
|
||||
# Gattlib files
|
||||
set(gattlib_SRCS gattlib_adapter.c
|
||||
gattlib_connect.c
|
||||
gattlib_discover.c
|
||||
gattlib_read_write.c
|
||||
${CMAKE_SOURCE_DIR}/common/gattlib_common.c
|
||||
${CMAKE_SOURCE_DIR}/common/gattlib_eddystone.c
|
||||
${CMAKE_SOURCE_DIR}/common/logging_backend/${GATTLIB_LOG_BACKEND}/gattlib_logging.c)
|
||||
|
||||
# Added Glib support
|
||||
pkg_search_module(GLIB REQUIRED glib-2.0)
|
||||
include_directories(${GLIB_INCLUDE_DIRS})
|
||||
list(APPEND gattlib_LIBS ${GLIB_LDFLAGS})
|
||||
|
||||
# Added Bluetooth support
|
||||
include_directories(${BLUEZ_INCLUDE_DIRS})
|
||||
list(APPEND gattlib_LIBS ${BLUEZ_LDFLAGS})
|
||||
|
||||
include_directories(. ${CMAKE_SOURCE_DIR}/common)
|
||||
if(BLUEZ_VERSION_MAJOR STREQUAL "4")
|
||||
list(APPEND gattlib_SRCS ${bluez4_SRCS})
|
||||
include_directories(${bluez4_DIR}/attrib ${bluez4_DIR}/btio ${bluez4_DIR}/src ${bluez4_DIR}/lib)
|
||||
else()
|
||||
list(APPEND gattlib_SRCS ${bluez5_SRCS})
|
||||
include_directories(${bluez5_DIR} ${bluez5_DIR}/attrib ${bluez5_DIR}/btio ${bluez5_DIR}/lib)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
endif()
|
||||
|
||||
# gattlib
|
||||
target_compile_definitions(gattlib PUBLIC -DGATTLIB_LOG_LEVEL=${GATTLIB_LOG_LEVEL})
|
||||
if (GATTLIB_LOG_BACKEND STREQUAL "syslog")
|
||||
target_compile_definitions(gattlib PUBLIC -DGATTLIB_LOG_BACKEND_SYSLOG)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
if(GATTLIB_SHARED_LIB)
|
||||
add_library(gattlib SHARED ${gattlib_SRCS})
|
||||
target_link_libraries(gattlib ${gattlib_LIBS})
|
||||
|
||||
install(TARGETS gattlib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
else()
|
||||
add_library(gattlib ${gattlib_SRCS})
|
||||
target_include_directories(gattlib INTERFACE ../include)
|
||||
target_link_libraries(gattlib ${gattlib_LIBS})
|
||||
|
||||
install(TARGETS gattlib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
|
@ -27,7 +27,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/uuid.h>
|
||||
#include "uuid.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <bluetooth/uuid.h>
|
||||
#include "uuid.h"
|
||||
#include <bluetooth/sdp.h>
|
||||
#include <bluetooth/sdp_lib.h>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/uuid.h>
|
||||
#include "uuid.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "att.h"
|
|
@ -65,6 +65,7 @@ struct set_opts {
|
|||
uint8_t mode;
|
||||
int flushable;
|
||||
uint32_t priority;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
struct connect {
|
||||
|
@ -172,11 +173,27 @@ static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm,
|
|||
}
|
||||
|
||||
static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
|
||||
uint16_t psm, uint16_t cid)
|
||||
uint16_t psm, uint16_t cid, uint16_t timeout)
|
||||
{
|
||||
int err;
|
||||
struct sockaddr_l2 addr;
|
||||
|
||||
if (timeout > 0) {
|
||||
struct timeval timeval;
|
||||
timeval.tv_sec = timeout;
|
||||
timeval.tv_usec = 0;
|
||||
|
||||
if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeval, sizeof(timeval)) < 0) {
|
||||
fprintf(stderr, "l2cap_connect: Failed to setsockopt for receive timeout.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeval, sizeof(timeval)) < 0) {
|
||||
fprintf(stderr, "l2cap_connect: Failed to setsockopt for sending timeout.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.l2_family = AF_BLUETOOTH;
|
||||
bacpy(&addr.l2_bdaddr, dst);
|
||||
|
@ -185,7 +202,14 @@ static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
|
|||
else
|
||||
addr.l2_psm = htobs(psm);
|
||||
|
||||
#if BLUEZ_VERSION < BLUEZ_VERSIONS(4, 100)
|
||||
if (dst_type != BDADDR_BREDR) {
|
||||
fprintf(stderr, "Require Bluez >= 4.100 to support BLE connections.\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
addr.l2_bdaddr_type = dst_type;
|
||||
#endif
|
||||
|
||||
err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
|
||||
if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
|
||||
|
@ -592,6 +616,7 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
|
|||
opts->flushable = -1;
|
||||
opts->priority = 0;
|
||||
opts->dst_type = BDADDR_BREDR;
|
||||
opts->timeout = 0;
|
||||
|
||||
while (opt != BT_IO_OPT_INVALID) {
|
||||
switch (opt) {
|
||||
|
@ -653,6 +678,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
|
|||
case BT_IO_OPT_PRIORITY:
|
||||
opts->priority = va_arg(args, int);
|
||||
break;
|
||||
case BT_IO_OPT_TIMEOUT:
|
||||
opts->timeout = va_arg(args, int);
|
||||
break;
|
||||
default:
|
||||
g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
|
||||
"Unknown option %d", opt);
|
||||
|
@ -1238,12 +1266,12 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
|
|||
switch (type) {
|
||||
case BT_IO_L2RAW:
|
||||
err = l2cap_connect(sock, &opts.dst, opts.dst_type, 0,
|
||||
opts.cid);
|
||||
opts.cid, opts.timeout);
|
||||
break;
|
||||
case BT_IO_L2CAP:
|
||||
case BT_IO_L2ERTM:
|
||||
err = l2cap_connect(sock, &opts.dst, opts.dst_type,
|
||||
opts.psm, opts.cid);
|
||||
opts.psm, opts.cid, opts.timeout);
|
||||
break;
|
||||
case BT_IO_RFCOMM:
|
||||
err = rfcomm_connect(sock, &opts.dst, opts.channel);
|
|
@ -70,8 +70,16 @@ typedef enum {
|
|||
BT_IO_OPT_MODE,
|
||||
BT_IO_OPT_FLUSHABLE,
|
||||
BT_IO_OPT_PRIORITY,
|
||||
BT_IO_OPT_TIMEOUT
|
||||
} BtIOOption;
|
||||
|
||||
typedef enum {
|
||||
BT_IO_SEC_SDP = 0,
|
||||
BT_IO_SEC_LOW,
|
||||
BT_IO_SEC_MEDIUM,
|
||||
BT_IO_SEC_HIGH,
|
||||
} BtIOSecLevel;
|
||||
|
||||
typedef enum {
|
||||
BT_IO_MODE_BASIC = 0,
|
||||
BT_IO_MODE_RETRANS,
|
|
@ -1383,14 +1383,16 @@ static void attr_print_func(void *value, void *userData)
|
|||
{
|
||||
sdp_data_t *d = (sdp_data_t *)value;
|
||||
|
||||
SDPDBG("=====================================\n");
|
||||
SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x\n", d->attrId);
|
||||
SDPDBG("ATTRIBUTE VALUE PTR : %p\n", value);
|
||||
if (d)
|
||||
if (d) {
|
||||
SDPDBG("=====================================\n");
|
||||
SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x\n", d->attrId);
|
||||
SDPDBG("ATTRIBUTE VALUE PTR : %p\n", value);
|
||||
sdp_data_print(d);
|
||||
else
|
||||
}
|
||||
else {
|
||||
SDPDBG("NULL value\n");
|
||||
SDPDBG("=====================================\n");
|
||||
SDPDBG("=====================================\n");
|
||||
}
|
||||
}
|
||||
|
||||
void sdp_print_service_attr(sdp_list_t *svcAttrList)
|
|
@ -133,7 +133,7 @@ void __btd_log_init(const char *debug, int detach)
|
|||
|
||||
openlog("bluetoothd", option, LOG_DAEMON);
|
||||
|
||||
syslog(LOG_INFO, "Bluetooth daemon %s", VERSION);
|
||||
syslog(LOG_INFO, "Bluetooth daemon %d.%d", BLUEZ_VERSION_MAJOR, BLUEZ_VERSION_MINOR);
|
||||
}
|
||||
|
||||
void __btd_log_cleanup(void)
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* Requirements for read/write operations */
|
||||
enum {
|
||||
ATT_NONE, /* No restrictions */
|
||||
ATT_AUTHENTICATION, /* Authentication required */
|
||||
ATT_AUTHORIZATION, /* Authorization required */
|
||||
ATT_NOT_PERMITTED, /* Operation not permitted */
|
||||
};
|
||||
|
||||
struct attribute {
|
||||
uint16_t handle;
|
||||
bt_uuid_t uuid;
|
||||
int read_req; /* Read requirement */
|
||||
int write_req; /* Write requirement */
|
||||
uint8_t (*read_cb)(struct attribute *a, struct btd_device *device,
|
||||
gpointer user_data);
|
||||
uint8_t (*write_cb)(struct attribute *a, struct btd_device *device,
|
||||
gpointer user_data);
|
||||
gpointer cb_user_data;
|
||||
size_t len;
|
||||
uint8_t *data;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "src/shared/crypto.h"
|
||||
|
||||
/* Len of signature in write signed packet */
|
||||
#define ATT_SIGNATURE_LEN 12
|
||||
|
||||
/* Attribute Protocol Opcodes */
|
||||
#define ATT_OP_ERROR 0x01
|
||||
#define ATT_OP_MTU_REQ 0x02
|
||||
#define ATT_OP_MTU_RESP 0x03
|
||||
#define ATT_OP_FIND_INFO_REQ 0x04
|
||||
#define ATT_OP_FIND_INFO_RESP 0x05
|
||||
#define ATT_OP_FIND_BY_TYPE_REQ 0x06
|
||||
#define ATT_OP_FIND_BY_TYPE_RESP 0x07
|
||||
#define ATT_OP_READ_BY_TYPE_REQ 0x08
|
||||
#define ATT_OP_READ_BY_TYPE_RESP 0x09
|
||||
#define ATT_OP_READ_REQ 0x0A
|
||||
#define ATT_OP_READ_RESP 0x0B
|
||||
#define ATT_OP_READ_BLOB_REQ 0x0C
|
||||
#define ATT_OP_READ_BLOB_RESP 0x0D
|
||||
#define ATT_OP_READ_MULTI_REQ 0x0E
|
||||
#define ATT_OP_READ_MULTI_RESP 0x0F
|
||||
#define ATT_OP_READ_BY_GROUP_REQ 0x10
|
||||
#define ATT_OP_READ_BY_GROUP_RESP 0x11
|
||||
#define ATT_OP_WRITE_REQ 0x12
|
||||
#define ATT_OP_WRITE_RESP 0x13
|
||||
#define ATT_OP_WRITE_CMD 0x52
|
||||
#define ATT_OP_PREP_WRITE_REQ 0x16
|
||||
#define ATT_OP_PREP_WRITE_RESP 0x17
|
||||
#define ATT_OP_EXEC_WRITE_REQ 0x18
|
||||
#define ATT_OP_EXEC_WRITE_RESP 0x19
|
||||
#define ATT_OP_HANDLE_NOTIFY 0x1B
|
||||
#define ATT_OP_HANDLE_IND 0x1D
|
||||
#define ATT_OP_HANDLE_CNF 0x1E
|
||||
#define ATT_OP_SIGNED_WRITE_CMD 0xD2
|
||||
|
||||
/* Error codes for Error response PDU */
|
||||
#define ATT_ECODE_INVALID_HANDLE 0x01
|
||||
#define ATT_ECODE_READ_NOT_PERM 0x02
|
||||
#define ATT_ECODE_WRITE_NOT_PERM 0x03
|
||||
#define ATT_ECODE_INVALID_PDU 0x04
|
||||
#define ATT_ECODE_AUTHENTICATION 0x05
|
||||
#define ATT_ECODE_REQ_NOT_SUPP 0x06
|
||||
#define ATT_ECODE_INVALID_OFFSET 0x07
|
||||
#define ATT_ECODE_AUTHORIZATION 0x08
|
||||
#define ATT_ECODE_PREP_QUEUE_FULL 0x09
|
||||
#define ATT_ECODE_ATTR_NOT_FOUND 0x0A
|
||||
#define ATT_ECODE_ATTR_NOT_LONG 0x0B
|
||||
#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C
|
||||
#define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D
|
||||
#define ATT_ECODE_UNLIKELY 0x0E
|
||||
#define ATT_ECODE_INSUFF_ENC 0x0F
|
||||
#define ATT_ECODE_UNSUPP_GRP_TYPE 0x10
|
||||
#define ATT_ECODE_INSUFF_RESOURCES 0x11
|
||||
/* Application error */
|
||||
#define ATT_ECODE_IO 0x80
|
||||
#define ATT_ECODE_TIMEOUT 0x81
|
||||
#define ATT_ECODE_ABORTED 0x82
|
||||
|
||||
#define ATT_MAX_VALUE_LEN 512
|
||||
#define ATT_DEFAULT_L2CAP_MTU 48
|
||||
#define ATT_DEFAULT_LE_MTU 23
|
||||
|
||||
#define ATT_CID 4
|
||||
#define ATT_PSM 31
|
||||
|
||||
/* Flags for Execute Write Request Operation */
|
||||
#define ATT_CANCEL_ALL_PREP_WRITES 0x00
|
||||
#define ATT_WRITE_ALL_PREP_WRITES 0x01
|
||||
|
||||
/* Find Information Response Formats */
|
||||
#define ATT_FIND_INFO_RESP_FMT_16BIT 0x01
|
||||
#define ATT_FIND_INFO_RESP_FMT_128BIT 0x02
|
||||
|
||||
struct att_data_list {
|
||||
uint16_t num;
|
||||
uint16_t len;
|
||||
uint8_t **data;
|
||||
};
|
||||
|
||||
struct att_range {
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
};
|
||||
|
||||
struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len);
|
||||
void att_data_list_free(struct att_data_list *list);
|
||||
|
||||
const char *att_ecode2str(uint8_t status);
|
||||
uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start,
|
||||
uint16_t *end, bt_uuid_t *uuid);
|
||||
uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
|
||||
size_t len);
|
||||
uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
|
||||
const uint8_t *value, size_t vlen, uint8_t *pdu,
|
||||
size_t len);
|
||||
uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
|
||||
uint16_t *end, bt_uuid_t *uuid, uint8_t *value, size_t *vlen);
|
||||
uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, size_t len);
|
||||
GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len);
|
||||
struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len);
|
||||
uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
|
||||
uint16_t *end, bt_uuid_t *uuid);
|
||||
uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu,
|
||||
size_t len);
|
||||
uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle,
|
||||
uint8_t *value, size_t *vlen);
|
||||
uint16_t enc_signed_write_cmd(uint16_t handle,
|
||||
const uint8_t *value, size_t vlen,
|
||||
struct bt_crypto *crypto,
|
||||
const uint8_t csrk[16],
|
||||
uint32_t sign_cnt,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_signed_write_cmd(const uint8_t *pdu, size_t len,
|
||||
uint16_t *handle,
|
||||
uint8_t *value, size_t *vlen,
|
||||
uint8_t signature[12]);
|
||||
struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len);
|
||||
uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle,
|
||||
uint8_t *value, size_t *vlen);
|
||||
uint16_t enc_write_resp(uint8_t *pdu);
|
||||
uint16_t dec_write_resp(const uint8_t *pdu, size_t len);
|
||||
uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len);
|
||||
uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu,
|
||||
size_t len);
|
||||
uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle);
|
||||
uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle,
|
||||
uint16_t *offset);
|
||||
uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len);
|
||||
uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset,
|
||||
uint8_t *pdu, size_t len);
|
||||
ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value,
|
||||
size_t vlen);
|
||||
uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu,
|
||||
size_t len);
|
||||
uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start,
|
||||
uint16_t *end);
|
||||
uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
|
||||
uint8_t *pdu, size_t len);
|
||||
struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len,
|
||||
uint8_t *format);
|
||||
uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle,
|
||||
uint8_t *value, size_t vlen);
|
||||
uint16_t enc_confirmation(uint8_t *pdu, size_t len);
|
||||
|
||||
uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len);
|
||||
uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu);
|
||||
uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len);
|
||||
uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu);
|
||||
|
||||
uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset,
|
||||
const uint8_t *value, size_t vlen,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_prep_write_req(const uint8_t *pdu, size_t len, uint16_t *handle,
|
||||
uint16_t *offset, uint8_t *value, size_t *vlen);
|
||||
uint16_t enc_prep_write_resp(uint16_t handle, uint16_t offset,
|
||||
const uint8_t *value, size_t vlen,
|
||||
uint8_t *pdu, size_t len);
|
||||
uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle,
|
||||
uint16_t *offset, uint8_t *value,
|
||||
size_t *vlen);
|
||||
uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len);
|
||||
uint16_t dec_exec_write_req(const uint8_t *pdu, size_t len, uint8_t *flags);
|
||||
uint16_t enc_exec_write_resp(uint8_t *pdu);
|
||||
uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len);
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
GATT_OPT_INVALID = 0,
|
||||
|
||||
/* bt_uuid_t* value */
|
||||
GATT_OPT_CHR_UUID,
|
||||
|
||||
/* a uint16 value */
|
||||
GATT_OPT_CHR_UUID16,
|
||||
|
||||
GATT_OPT_CHR_PROPS,
|
||||
GATT_OPT_CHR_VALUE_CB,
|
||||
GATT_OPT_CHR_AUTHENTICATION,
|
||||
GATT_OPT_CHR_AUTHORIZATION,
|
||||
|
||||
/* Get attribute handle for characteristic value */
|
||||
GATT_OPT_CHR_VALUE_GET_HANDLE,
|
||||
|
||||
/* Get handle for ccc attribute */
|
||||
GATT_OPT_CCC_GET_HANDLE,
|
||||
|
||||
/* arguments for authentication/authorization */
|
||||
GATT_CHR_VALUE_READ,
|
||||
GATT_CHR_VALUE_WRITE,
|
||||
GATT_CHR_VALUE_BOTH,
|
||||
} gatt_option;
|
||||
|
||||
typedef enum {
|
||||
ATTRIB_READ,
|
||||
ATTRIB_WRITE,
|
||||
} attrib_event_t;
|
||||
|
||||
gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
|
||||
bt_uuid_t *svc_uuid, gatt_option opt1, ...);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* GATT Characteristic Property bit field
|
||||
* Reference: Core SPEC 4.1 page 2183 (Table 3.5: Characteristic Properties
|
||||
* bit field) defines how the Characteristic Value can be used, or how the
|
||||
* characteristic descriptors (see Section 3.3.3 - page 2184) can be accessed.
|
||||
* In the core spec, regular properties are included in the characteristic
|
||||
* declaration, and the extended properties are defined as descriptor.
|
||||
*/
|
||||
|
||||
#define GATT_CHR_PROP_BROADCAST 0x01
|
||||
#define GATT_CHR_PROP_READ 0x02
|
||||
#define GATT_CHR_PROP_WRITE_WITHOUT_RESP 0x04
|
||||
#define GATT_CHR_PROP_WRITE 0x08
|
||||
#define GATT_CHR_PROP_NOTIFY 0x10
|
||||
#define GATT_CHR_PROP_INDICATE 0x20
|
||||
#define GATT_CHR_PROP_AUTH 0x40
|
||||
#define GATT_CHR_PROP_EXT_PROP 0x80
|
||||
|
||||
/* Client Characteristic Configuration bit field */
|
||||
#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
|
||||
#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002
|
||||
|
||||
typedef void (*gatt_cb_t) (uint8_t status, GSList *l, void *user_data);
|
||||
|
||||
struct gatt_primary {
|
||||
char uuid[MAX_LEN_UUID_STR + 1];
|
||||
gboolean changed;
|
||||
struct att_range range;
|
||||
};
|
||||
|
||||
struct gatt_included {
|
||||
char uuid[MAX_LEN_UUID_STR + 1];
|
||||
uint16_t handle;
|
||||
struct att_range range;
|
||||
};
|
||||
|
||||
struct gatt_char {
|
||||
char uuid[MAX_LEN_UUID_STR + 1];
|
||||
uint16_t handle;
|
||||
uint8_t properties;
|
||||
uint16_t value_handle;
|
||||
};
|
||||
|
||||
struct gatt_desc {
|
||||
char uuid[MAX_LEN_UUID_STR + 1];
|
||||
uint16_t handle;
|
||||
uint16_t uuid16;
|
||||
};
|
||||
|
||||
guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
|
||||
gpointer user_data);
|
||||
|
||||
unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
|
||||
gatt_cb_t func, gpointer user_data);
|
||||
|
||||
guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
|
||||
bt_uuid_t *uuid, gatt_cb_t func,
|
||||
gpointer user_data);
|
||||
|
||||
guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
guint gatt_write_char(GAttrib *attrib, uint16_t handle, const uint8_t *value,
|
||||
size_t vlen, GAttribResultFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
|
||||
bt_uuid_t *uuid, gatt_cb_t func,
|
||||
gpointer user_data);
|
||||
|
||||
guint gatt_reliable_write_char(GAttrib *attrib, uint16_t handle,
|
||||
const uint8_t *value, size_t vlen,
|
||||
GAttribResultFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
guint gatt_execute_write(GAttrib *attrib, uint8_t flags,
|
||||
GAttribResultFunc func, gpointer user_data);
|
||||
|
||||
guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
|
||||
int vlen, GDestroyNotify notify, gpointer user_data);
|
||||
|
||||
guint gatt_signed_write_cmd(GAttrib *attrib, uint16_t handle,
|
||||
const uint8_t *value, int vlen,
|
||||
struct bt_crypto *crypto,
|
||||
const uint8_t csrk[16],
|
||||
uint32_t sign_cnt,
|
||||
GDestroyNotify notify,
|
||||
gpointer user_data);
|
||||
guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
|
||||
bt_uuid_t *uuid, GAttribResultFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
gboolean gatt_parse_record(const sdp_record_t *rec,
|
||||
uuid_t *prim_uuid, uint16_t *psm,
|
||||
uint16_t *start, uint16_t *end);
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
|
||||
#include "btio/btio.h"
|
||||
#include "src/log.h"
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/att.h"
|
||||
#include "src/shared/queue.h"
|
||||
#include "attrib/gattrib.h"
|
||||
|
||||
struct _GAttrib {
|
||||
int ref_count;
|
||||
struct bt_att *att;
|
||||
GIOChannel *io;
|
||||
GDestroyNotify destroy;
|
||||
gpointer destroy_user_data;
|
||||
struct queue *callbacks;
|
||||
uint8_t *buf;
|
||||
int buflen;
|
||||
struct queue *track_ids;
|
||||
};
|
||||
|
||||
struct id_pair {
|
||||
unsigned int org_id;
|
||||
unsigned int pend_id;
|
||||
};
|
||||
|
||||
struct attrib_callbacks {
|
||||
struct id_pair *id;
|
||||
GAttribResultFunc result_func;
|
||||
GAttribNotifyFunc notify_func;
|
||||
GDestroyNotify destroy_func;
|
||||
gpointer user_data;
|
||||
GAttrib *parent;
|
||||
uint16_t notify_handle;
|
||||
};
|
||||
|
||||
static bool find_with_org_id(const void *data, const void *user_data)
|
||||
{
|
||||
const struct id_pair *p = data;
|
||||
unsigned int orig_id = PTR_TO_UINT(user_data);
|
||||
|
||||
return (p->org_id == orig_id);
|
||||
}
|
||||
|
||||
static struct id_pair *store_id(GAttrib *attrib, unsigned int org_id,
|
||||
unsigned int pend_id)
|
||||
{
|
||||
struct id_pair *t;
|
||||
|
||||
t = new0(struct id_pair, 1);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
t->org_id = org_id;
|
||||
t->pend_id = pend_id;
|
||||
|
||||
if (queue_push_tail(attrib->track_ids, t))
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed)
|
||||
{
|
||||
gint fd;
|
||||
GAttrib *attr;
|
||||
|
||||
if (!io)
|
||||
return NULL;
|
||||
|
||||
fd = g_io_channel_unix_get_fd(io);
|
||||
attr = new0(GAttrib, 1);
|
||||
if (!attr)
|
||||
return NULL;
|
||||
|
||||
g_io_channel_ref(io);
|
||||
attr->io = io;
|
||||
|
||||
attr->att = bt_att_new(fd, ext_signed);
|
||||
if (!attr->att)
|
||||
goto fail;
|
||||
|
||||
bt_att_set_close_on_unref(attr->att, true);
|
||||
g_io_channel_set_close_on_unref(io, FALSE);
|
||||
|
||||
if (!bt_att_set_mtu(attr->att, mtu))
|
||||
goto fail;
|
||||
|
||||
attr->buf = malloc0(mtu);
|
||||
attr->buflen = mtu;
|
||||
if (!attr->buf)
|
||||
goto fail;
|
||||
|
||||
attr->callbacks = queue_new();
|
||||
if (!attr->callbacks)
|
||||
goto fail;
|
||||
|
||||
attr->track_ids = queue_new();
|
||||
if (!attr->track_ids)
|
||||
goto fail;
|
||||
|
||||
return g_attrib_ref(attr);
|
||||
|
||||
fail:
|
||||
free(attr->buf);
|
||||
bt_att_unref(attr->att);
|
||||
g_io_channel_unref(io);
|
||||
free(attr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GAttrib *g_attrib_ref(GAttrib *attrib)
|
||||
{
|
||||
if (!attrib)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&attrib->ref_count, 1);
|
||||
|
||||
DBG("%p: g_attrib_ref=%d ", attrib, attrib->ref_count);
|
||||
|
||||
return attrib;
|
||||
}
|
||||
|
||||
static void attrib_callbacks_destroy(void *data)
|
||||
{
|
||||
struct attrib_callbacks *cb = data;
|
||||
|
||||
if (cb->destroy_func)
|
||||
cb->destroy_func(cb->user_data);
|
||||
|
||||
if (queue_remove(cb->parent->track_ids, cb->id))
|
||||
free(cb->id);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void attrib_callbacks_remove(void *data)
|
||||
{
|
||||
struct attrib_callbacks *cb = data;
|
||||
|
||||
if (!data || !queue_remove(cb->parent->callbacks, data))
|
||||
return;
|
||||
|
||||
attrib_callbacks_destroy(data);
|
||||
}
|
||||
|
||||
void g_attrib_unref(GAttrib *attrib)
|
||||
{
|
||||
if (!attrib)
|
||||
return;
|
||||
|
||||
DBG("%p: g_attrib_unref=%d ", attrib, attrib->ref_count - 1);
|
||||
|
||||
if (__sync_sub_and_fetch(&attrib->ref_count, 1))
|
||||
return;
|
||||
|
||||
if (attrib->destroy)
|
||||
attrib->destroy(attrib->destroy_user_data);
|
||||
|
||||
bt_att_unref(attrib->att);
|
||||
|
||||
queue_destroy(attrib->callbacks, attrib_callbacks_destroy);
|
||||
queue_destroy(attrib->track_ids, free);
|
||||
|
||||
free(attrib->buf);
|
||||
|
||||
g_io_channel_unref(attrib->io);
|
||||
|
||||
free(attrib);
|
||||
}
|
||||
|
||||
GIOChannel *g_attrib_get_channel(GAttrib *attrib)
|
||||
{
|
||||
if (!attrib)
|
||||
return NULL;
|
||||
|
||||
return attrib->io;
|
||||
}
|
||||
|
||||
struct bt_att *g_attrib_get_att(GAttrib *attrib)
|
||||
{
|
||||
if (!attrib)
|
||||
return NULL;
|
||||
|
||||
return attrib->att;
|
||||
}
|
||||
|
||||
gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!attrib)
|
||||
return FALSE;
|
||||
|
||||
attrib->destroy = destroy;
|
||||
attrib->destroy_user_data = user_data;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t *construct_full_pdu(uint8_t opcode, const void *pdu,
|
||||
uint16_t length)
|
||||
{
|
||||
uint8_t *buf = malloc0(length + 1);
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
buf[0] = opcode;
|
||||
memcpy(buf + 1, pdu, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void attrib_callback_result(uint8_t opcode, const void *pdu,
|
||||
uint16_t length, void *user_data)
|
||||
{
|
||||
uint8_t *buf;
|
||||
struct attrib_callbacks *cb = user_data;
|
||||
guint8 status = 0;
|
||||
|
||||
if (!cb)
|
||||
return;
|
||||
|
||||
buf = construct_full_pdu(opcode, pdu, length);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
if (opcode == BT_ATT_OP_ERROR_RSP) {
|
||||
/* Error code is the third byte of the PDU data */
|
||||
if (length < 4)
|
||||
status = BT_ATT_ERROR_UNLIKELY;
|
||||
else
|
||||
status = ((guint8 *)pdu)[3];
|
||||
}
|
||||
|
||||
if (cb->result_func)
|
||||
cb->result_func(status, buf, length + 1, cb->user_data);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void attrib_callback_notify(uint8_t opcode, const void *pdu,
|
||||
uint16_t length, void *user_data)
|
||||
{
|
||||
uint8_t *buf;
|
||||
struct attrib_callbacks *cb = user_data;
|
||||
|
||||
if (!cb || !cb->notify_func)
|
||||
return;
|
||||
|
||||
if (cb->notify_handle != GATTRIB_ALL_HANDLES && length < 2)
|
||||
return;
|
||||
|
||||
if (cb->notify_handle != GATTRIB_ALL_HANDLES &&
|
||||
cb->notify_handle != get_le16(pdu))
|
||||
return;
|
||||
|
||||
buf = construct_full_pdu(opcode, pdu, length);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
cb->notify_func(buf, length + 1, cb->user_data);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
|
||||
GAttribResultFunc func, gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
struct attrib_callbacks *cb = NULL;
|
||||
bt_att_response_func_t response_cb = NULL;
|
||||
bt_att_destroy_func_t destroy_cb = NULL;
|
||||
unsigned int pend_id;
|
||||
|
||||
if (!attrib)
|
||||
return 0;
|
||||
|
||||
if (!pdu || !len)
|
||||
return 0;
|
||||
|
||||
if (func || notify) {
|
||||
cb = new0(struct attrib_callbacks, 1);
|
||||
if (!cb)
|
||||
return 0;
|
||||
cb->result_func = func;
|
||||
cb->user_data = user_data;
|
||||
cb->destroy_func = notify;
|
||||
cb->parent = attrib;
|
||||
queue_push_head(attrib->callbacks, cb);
|
||||
response_cb = attrib_callback_result;
|
||||
destroy_cb = attrib_callbacks_remove;
|
||||
|
||||
}
|
||||
|
||||
pend_id = bt_att_send(attrib->att, pdu[0], (void *) pdu + 1, len - 1,
|
||||
response_cb, cb, destroy_cb);
|
||||
|
||||
/*
|
||||
* We store here pair as it is easier to handle it in response and in
|
||||
* case where user request us to use specific id request - see below.
|
||||
*/
|
||||
if (id == 0)
|
||||
id = pend_id;
|
||||
|
||||
/*
|
||||
* If user what us to use given id, lets keep track on that so we give
|
||||
* user a possibility to cancel ongoing request.
|
||||
*/
|
||||
if (cb)
|
||||
cb->id = store_id(attrib, id, pend_id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
gboolean g_attrib_cancel(GAttrib *attrib, guint id)
|
||||
{
|
||||
struct id_pair *p;
|
||||
|
||||
if (!attrib)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* If request belongs to gattrib and is not yet done it has to be on
|
||||
* the tracking id queue
|
||||
*
|
||||
* FIXME: It can happen that on the queue there is id_pair with
|
||||
* given id which was provided by the user. In the same time it might
|
||||
* happen that other attrib user got dynamic allocated req_id with same
|
||||
* value as the one provided by the other user.
|
||||
* In such case there are two clients having same request id and in
|
||||
* this point of time we don't know which one calls cancel. For
|
||||
* now we cancel request in which id was specified by the user.
|
||||
*/
|
||||
p = queue_remove_if(attrib->track_ids, find_with_org_id,
|
||||
UINT_TO_PTR(id));
|
||||
if (!p)
|
||||
return FALSE;
|
||||
|
||||
id = p->pend_id;
|
||||
free(p);
|
||||
|
||||
return bt_att_cancel(attrib->att, id);
|
||||
}
|
||||
|
||||
static void cancel_request(void *data, void *user_data)
|
||||
{
|
||||
struct id_pair *p = data;
|
||||
GAttrib *attrib = user_data;
|
||||
|
||||
bt_att_cancel(attrib->att, p->pend_id);
|
||||
}
|
||||
|
||||
gboolean g_attrib_cancel_all(GAttrib *attrib)
|
||||
{
|
||||
if (!attrib)
|
||||
return FALSE;
|
||||
|
||||
/* Cancel only request which belongs to gattrib */
|
||||
queue_foreach(attrib->track_ids, cancel_request, attrib);
|
||||
queue_remove_all(attrib->track_ids, NULL, NULL, free);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
|
||||
GAttribNotifyFunc func, gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
struct attrib_callbacks *cb = NULL;
|
||||
|
||||
if (!attrib)
|
||||
return 0;
|
||||
|
||||
if (func || notify) {
|
||||
cb = new0(struct attrib_callbacks, 1);
|
||||
if (!cb)
|
||||
return 0;
|
||||
cb->notify_func = func;
|
||||
cb->notify_handle = handle;
|
||||
cb->user_data = user_data;
|
||||
cb->destroy_func = notify;
|
||||
cb->parent = attrib;
|
||||
queue_push_head(attrib->callbacks, cb);
|
||||
}
|
||||
|
||||
if (opcode == GATTRIB_ALL_REQS)
|
||||
opcode = BT_ATT_ALL_REQUESTS;
|
||||
|
||||
return bt_att_register(attrib->att, opcode, attrib_callback_notify,
|
||||
cb, attrib_callbacks_remove);
|
||||
}
|
||||
|
||||
uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
|
||||
{
|
||||
uint16_t mtu;
|
||||
|
||||
if (!attrib || !len)
|
||||
return NULL;
|
||||
|
||||
mtu = bt_att_get_mtu(attrib->att);
|
||||
|
||||
/*
|
||||
* Clients of this expect a buffer to use.
|
||||
*
|
||||
* Pdu encoding in shared/att verifies if whole buffer fits the mtu,
|
||||
* thus we should set the buflen also when mtu is reduced. But we
|
||||
* need to reallocate the buffer only if mtu is larger.
|
||||
*/
|
||||
if (mtu > attrib->buflen)
|
||||
attrib->buf = g_realloc(attrib->buf, mtu);
|
||||
|
||||
attrib->buflen = mtu;
|
||||
*len = attrib->buflen;
|
||||
return attrib->buf;
|
||||
}
|
||||
|
||||
gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
|
||||
{
|
||||
if (!attrib)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Clients of this expect a buffer to use.
|
||||
*
|
||||
* Pdu encoding in sharred/att verifies if whole buffer fits the mtu,
|
||||
* thus we should set the buflen also when mtu is reduced. But we
|
||||
* need to reallocate the buffer only if mtu is larger.
|
||||
*/
|
||||
if (mtu > attrib->buflen)
|
||||
attrib->buf = g_realloc(attrib->buf, mtu);
|
||||
|
||||
attrib->buflen = mtu;
|
||||
|
||||
return bt_att_set_mtu(attrib->att, mtu);
|
||||
}
|
||||
|
||||
gboolean g_attrib_unregister(GAttrib *attrib, guint id)
|
||||
{
|
||||
if (!attrib)
|
||||
return FALSE;
|
||||
|
||||
return bt_att_unregister(attrib->att, id);
|
||||
}
|
||||
|
||||
gboolean g_attrib_unregister_all(GAttrib *attrib)
|
||||
{
|
||||
if (!attrib)
|
||||
return false;
|
||||
|
||||
return bt_att_unregister_all(attrib->att);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __GATTRIB_H
|
||||
#define __GATTRIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define GATTRIB_ALL_REQS 0xFE
|
||||
#define GATTRIB_ALL_HANDLES 0x0000
|
||||
|
||||
struct bt_att; /* Forward declaration for compatibility */
|
||||
struct _GAttrib;
|
||||
typedef struct _GAttrib GAttrib;
|
||||
|
||||
typedef void (*GAttribResultFunc) (guint8 status, const guint8 *pdu,
|
||||
guint16 len, gpointer user_data);
|
||||
typedef void (*GAttribDisconnectFunc)(gpointer user_data);
|
||||
typedef void (*GAttribDebugFunc)(const char *str, gpointer user_data);
|
||||
typedef void (*GAttribNotifyFunc)(const guint8 *pdu, guint16 len,
|
||||
gpointer user_data);
|
||||
|
||||
GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed);
|
||||
GAttrib *g_attrib_ref(GAttrib *attrib);
|
||||
void g_attrib_unref(GAttrib *attrib);
|
||||
|
||||
GIOChannel *g_attrib_get_channel(GAttrib *attrib);
|
||||
|
||||
struct bt_att *g_attrib_get_att(GAttrib *attrib);
|
||||
|
||||
gboolean g_attrib_set_destroy_function(GAttrib *attrib,
|
||||
GDestroyNotify destroy, gpointer user_data);
|
||||
|
||||
guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
|
||||
GAttribResultFunc func, gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
gboolean g_attrib_cancel(GAttrib *attrib, guint id);
|
||||
gboolean g_attrib_cancel_all(GAttrib *attrib);
|
||||
|
||||
guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
|
||||
GAttribNotifyFunc func, gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len);
|
||||
gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu);
|
||||
|
||||
gboolean g_attrib_unregister(GAttrib *attrib, guint id);
|
||||
gboolean g_attrib_unregister_all(GAttrib *attrib);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
int interactive(const char *src, const char *dst, const char *dst_type,
|
||||
int psm);
|
||||
GIOChannel *gatt_connect(const char *src, const char *dst,
|
||||
const char *dst_type, const char *sec_level,
|
||||
int psm, int mtu, BtIOConnect connect_cb,
|
||||
GError **gerr);
|
||||
size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2009-2010 Nokia Corporation
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifndef BT_IO_H
|
||||
#define BT_IO_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define BT_IO_ERROR bt_io_error_quark()
|
||||
|
||||
GQuark bt_io_error_quark(void);
|
||||
|
||||
typedef enum {
|
||||
BT_IO_OPT_INVALID = 0,
|
||||
BT_IO_OPT_SOURCE,
|
||||
BT_IO_OPT_SOURCE_BDADDR,
|
||||
BT_IO_OPT_SOURCE_TYPE,
|
||||
BT_IO_OPT_DEST,
|
||||
BT_IO_OPT_DEST_BDADDR,
|
||||
BT_IO_OPT_DEST_TYPE,
|
||||
BT_IO_OPT_DEFER_TIMEOUT,
|
||||
BT_IO_OPT_SEC_LEVEL,
|
||||
BT_IO_OPT_KEY_SIZE,
|
||||
BT_IO_OPT_CHANNEL,
|
||||
BT_IO_OPT_SOURCE_CHANNEL,
|
||||
BT_IO_OPT_DEST_CHANNEL,
|
||||
BT_IO_OPT_PSM,
|
||||
BT_IO_OPT_CID,
|
||||
BT_IO_OPT_MTU,
|
||||
BT_IO_OPT_OMTU,
|
||||
BT_IO_OPT_IMTU,
|
||||
BT_IO_OPT_MASTER,
|
||||
BT_IO_OPT_HANDLE,
|
||||
BT_IO_OPT_CLASS,
|
||||
BT_IO_OPT_MODE,
|
||||
BT_IO_OPT_FLUSHABLE,
|
||||
BT_IO_OPT_PRIORITY,
|
||||
BT_IO_OPT_VOICE,
|
||||
BT_IO_OPT_TIMEOUT,
|
||||
} BtIOOption;
|
||||
|
||||
typedef enum {
|
||||
BT_IO_SEC_SDP = 0,
|
||||
BT_IO_SEC_LOW,
|
||||
BT_IO_SEC_MEDIUM,
|
||||
BT_IO_SEC_HIGH,
|
||||
} BtIOSecLevel;
|
||||
|
||||
typedef enum {
|
||||
BT_IO_MODE_BASIC = 0,
|
||||
BT_IO_MODE_RETRANS,
|
||||
BT_IO_MODE_FLOWCTL,
|
||||
BT_IO_MODE_ERTM,
|
||||
BT_IO_MODE_STREAMING
|
||||
} BtIOMode;
|
||||
|
||||
typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
|
||||
|
||||
typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
|
||||
|
||||
gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
|
||||
GDestroyNotify destroy, GError **err);
|
||||
|
||||
gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...);
|
||||
|
||||
gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...);
|
||||
|
||||
GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
|
||||
GDestroyNotify destroy, GError **gerr,
|
||||
BtIOOption opt1, ...);
|
||||
|
||||
GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
|
||||
gpointer user_data, GDestroyNotify destroy,
|
||||
GError **err, BtIOOption opt1, ...);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __A2MP_H
|
||||
#define __A2MP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* A2MP Protocol */
|
||||
|
||||
/* A2MP command codes */
|
||||
|
||||
#define A2MP_COMMAND_REJ 0x01
|
||||
#define A2MP_DISCOVER_REQ 0x02
|
||||
#define A2MP_DISCOVER_RSP 0x03
|
||||
#define A2MP_CHANGE_NOTIFY 0x04
|
||||
#define A2MP_CHANGE_RSP 0x05
|
||||
#define A2MP_INFO_REQ 0x06
|
||||
#define A2MP_INFO_RSP 0x07
|
||||
#define A2MP_ASSOC_REQ 0x08
|
||||
#define A2MP_ASSOC_RSP 0x09
|
||||
#define A2MP_CREATE_REQ 0x0a
|
||||
#define A2MP_CREATE_RSP 0x0b
|
||||
#define A2MP_DISCONN_REQ 0x0c
|
||||
#define A2MP_DISCONN_RSP 0x0d
|
||||
|
||||
struct a2mp_hdr {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed));
|
||||
#define A2MP_HDR_SIZE 4
|
||||
|
||||
struct a2mp_command_rej {
|
||||
uint16_t reason;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_discover_req {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_ctrl {
|
||||
uint8_t id;
|
||||
uint8_t type;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_discover_rsp {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
struct a2mp_ctrl ctrl_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_info_req {
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_info_rsp {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
uint32_t total_bw;
|
||||
uint32_t max_bw;
|
||||
uint32_t min_latency;
|
||||
uint16_t pal_caps;
|
||||
uint16_t assoc_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_assoc_req {
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_assoc_rsp {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
uint8_t assoc_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_create_req {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t assoc_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_create_rsp {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_disconn_req {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_disconn_rsp {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define A2MP_COMMAND_NOT_RECOGNIZED 0x0000
|
||||
|
||||
/* AMP controller status */
|
||||
#define AMP_CTRL_POWERED_DOWN 0x00
|
||||
#define AMP_CTRL_BLUETOOTH_ONLY 0x01
|
||||
#define AMP_CTRL_NO_CAPACITY 0x02
|
||||
#define AMP_CTRL_LOW_CAPACITY 0x03
|
||||
#define AMP_CTRL_MEDIUM_CAPACITY 0x04
|
||||
#define AMP_CTRL_HIGH_CAPACITY 0x05
|
||||
#define AMP_CTRL_FULL_CAPACITY 0x06
|
||||
|
||||
/* A2MP response status */
|
||||
#define A2MP_STATUS_SUCCESS 0x00
|
||||
#define A2MP_STATUS_INVALID_CTRL_ID 0x01
|
||||
#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
|
||||
#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
|
||||
#define A2MP_STATUS_COLLISION_OCCURED 0x03
|
||||
#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04
|
||||
#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
|
||||
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __A2MP_H */
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010-2011 Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2012 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMP_H
|
||||
#define __AMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AMP_MGR_CID 0x03
|
||||
|
||||
/* AMP manager codes */
|
||||
#define AMP_COMMAND_REJ 0x01
|
||||
#define AMP_DISCOVER_REQ 0x02
|
||||
#define AMP_DISCOVER_RSP 0x03
|
||||
#define AMP_CHANGE_NOTIFY 0x04
|
||||
#define AMP_CHANGE_RSP 0x05
|
||||
#define AMP_INFO_REQ 0x06
|
||||
#define AMP_INFO_RSP 0x07
|
||||
#define AMP_ASSOC_REQ 0x08
|
||||
#define AMP_ASSOC_RSP 0x09
|
||||
#define AMP_LINK_REQ 0x0a
|
||||
#define AMP_LINK_RSP 0x0b
|
||||
#define AMP_DISCONN_REQ 0x0c
|
||||
#define AMP_DISCONN_RSP 0x0d
|
||||
|
||||
typedef struct {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed)) amp_mgr_hdr;
|
||||
#define AMP_MGR_HDR_SIZE 4
|
||||
|
||||
/* AMP ASSOC structure */
|
||||
typedef struct {
|
||||
uint8_t type_id;
|
||||
uint16_t len;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) amp_assoc_tlv;
|
||||
|
||||
typedef struct {
|
||||
uint16_t reason;
|
||||
} __attribute__ ((packed)) amp_cmd_rej_parms;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
} __attribute__ ((packed)) amp_discover_req_parms;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
uint8_t controller_list[0];
|
||||
} __attribute__ ((packed)) amp_discover_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed)) amp_info_req_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
uint32_t total_bandwidth;
|
||||
uint32_t max_bandwidth;
|
||||
uint32_t min_latency;
|
||||
uint16_t pal_caps;
|
||||
uint16_t assoc_size;
|
||||
} __attribute__ ((packed)) amp_info_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
amp_assoc_tlv assoc;
|
||||
} __attribute__ ((packed)) amp_assoc_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
amp_assoc_tlv assoc;
|
||||
} __attribute__ ((packed)) amp_link_req_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed)) amp_link_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
} __attribute__ ((packed)) amp_disconn_req_parms;
|
||||
|
||||
#define A2MP_MAC_ADDR_TYPE 1
|
||||
#define A2MP_PREF_CHANLIST_TYPE 2
|
||||
#define A2MP_CONNECTED_CHAN 3
|
||||
#define A2MP_PAL_CAP_TYPE 4
|
||||
#define A2MP_PAL_VER_INFO 5
|
||||
|
||||
struct amp_tlv {
|
||||
uint8_t type;
|
||||
uint16_t len;
|
||||
uint8_t val[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct amp_pal_ver {
|
||||
uint8_t ver;
|
||||
uint16_t company_id;
|
||||
uint16_t sub_ver;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct amp_country_triplet {
|
||||
union {
|
||||
struct {
|
||||
uint8_t first_channel;
|
||||
uint8_t num_channels;
|
||||
int8_t max_power;
|
||||
} __attribute__ ((packed)) chans;
|
||||
struct {
|
||||
uint8_t reg_extension_id;
|
||||
uint8_t reg_class;
|
||||
uint8_t coverage_class;
|
||||
} __attribute__ ((packed)) ext;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct amp_chan_list {
|
||||
uint8_t country_code[3];
|
||||
struct amp_country_triplet triplets[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define AMP_COMMAND_NOT_RECOGNIZED 0x0000
|
||||
|
||||
/* AMP controller status */
|
||||
#define AMP_CT_POWERED_DOWN 0x00
|
||||
#define AMP_CT_BLUETOOTH_ONLY 0x01
|
||||
#define AMP_CT_NO_CAPACITY 0x02
|
||||
#define AMP_CT_LOW_CAPACITY 0x03
|
||||
#define AMP_CT_MEDIUM_CAPACITY 0x04
|
||||
#define AMP_CT_HIGH_CAPACITY 0x05
|
||||
#define AMP_CT_FULL_CAPACITY 0x06
|
||||
|
||||
/* AMP response status */
|
||||
#define AMP_STATUS_SUCCESS 0x00
|
||||
#define AMP_STATUS_INVALID_CTRL_ID 0x01
|
||||
#define AMP_STATUS_UNABLE_START_LINK_CREATION 0x02
|
||||
#define AMP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
|
||||
#define AMP_STATUS_COLLISION_OCCURED 0x03
|
||||
#define AMP_STATUS_DISCONN_REQ_RECVD 0x04
|
||||
#define AMP_STATUS_PHYS_LINK_EXISTS 0x05
|
||||
#define AMP_STATUS_SECURITY_VIOLATION 0x06
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AMP_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BLUETOOTH_H
|
||||
#define __BLUETOOTH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifndef AF_BLUETOOTH
|
||||
#define AF_BLUETOOTH 31
|
||||
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||
#endif
|
||||
|
||||
#define BTPROTO_L2CAP 0
|
||||
#define BTPROTO_HCI 1
|
||||
#define BTPROTO_SCO 2
|
||||
#define BTPROTO_RFCOMM 3
|
||||
#define BTPROTO_BNEP 4
|
||||
#define BTPROTO_CMTP 5
|
||||
#define BTPROTO_HIDP 6
|
||||
#define BTPROTO_AVDTP 7
|
||||
|
||||
#define SOL_HCI 0
|
||||
#define SOL_L2CAP 6
|
||||
#define SOL_SCO 17
|
||||
#define SOL_RFCOMM 18
|
||||
|
||||
#ifndef SOL_BLUETOOTH
|
||||
#define SOL_BLUETOOTH 274
|
||||
#endif
|
||||
|
||||
#define BT_SECURITY 4
|
||||
struct bt_security {
|
||||
uint8_t level;
|
||||
uint8_t key_size;
|
||||
};
|
||||
#define BT_SECURITY_SDP 0
|
||||
#define BT_SECURITY_LOW 1
|
||||
#define BT_SECURITY_MEDIUM 2
|
||||
#define BT_SECURITY_HIGH 3
|
||||
#define BT_SECURITY_FIPS 4
|
||||
|
||||
#define BT_DEFER_SETUP 7
|
||||
|
||||
#define BT_FLUSHABLE 8
|
||||
|
||||
#define BT_FLUSHABLE_OFF 0
|
||||
#define BT_FLUSHABLE_ON 1
|
||||
|
||||
#define BT_POWER 9
|
||||
struct bt_power {
|
||||
uint8_t force_active;
|
||||
};
|
||||
#define BT_POWER_FORCE_ACTIVE_OFF 0
|
||||
#define BT_POWER_FORCE_ACTIVE_ON 1
|
||||
|
||||
#define BT_CHANNEL_POLICY 10
|
||||
|
||||
/* BR/EDR only (default policy)
|
||||
* AMP controllers cannot be used.
|
||||
* Channel move requests from the remote device are denied.
|
||||
* If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_BREDR_ONLY 0
|
||||
|
||||
/* BR/EDR Preferred
|
||||
* Allow use of AMP controllers.
|
||||
* If the L2CAP channel is currently on AMP, move it to BR/EDR.
|
||||
* Channel move requests from the remote device are allowed.
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_BREDR_PREFERRED 1
|
||||
|
||||
/* AMP Preferred
|
||||
* Allow use of AMP controllers
|
||||
* If the L2CAP channel is currently on BR/EDR and AMP controller
|
||||
* resources are available, initiate a channel move to AMP.
|
||||
* Channel move requests from the remote device are allowed.
|
||||
* If the L2CAP socket has not been connected yet, try to create
|
||||
* and configure the channel directly on an AMP controller rather
|
||||
* than BR/EDR.
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_AMP_PREFERRED 2
|
||||
|
||||
#define BT_VOICE 11
|
||||
struct bt_voice {
|
||||
uint16_t setting;
|
||||
};
|
||||
|
||||
#define BT_SNDMTU 12
|
||||
#define BT_RCVMTU 13
|
||||
|
||||
#define BT_VOICE_TRANSPARENT 0x0003
|
||||
#define BT_VOICE_CVSD_16BIT 0x0060
|
||||
|
||||
/* Connection and socket states */
|
||||
enum {
|
||||
BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
|
||||
BT_OPEN,
|
||||
BT_BOUND,
|
||||
BT_LISTEN,
|
||||
BT_CONNECT,
|
||||
BT_CONNECT2,
|
||||
BT_CONFIG,
|
||||
BT_DISCONN,
|
||||
BT_CLOSED
|
||||
};
|
||||
|
||||
/* Byte order conversions */
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define htobs(d) (d)
|
||||
#define htobl(d) (d)
|
||||
#define htobll(d) (d)
|
||||
#define btohs(d) (d)
|
||||
#define btohl(d) (d)
|
||||
#define btohll(d) (d)
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define htobs(d) bswap_16(d)
|
||||
#define htobl(d) bswap_32(d)
|
||||
#define htobll(d) bswap_64(d)
|
||||
#define btohs(d) bswap_16(d)
|
||||
#define btohl(d) bswap_32(d)
|
||||
#define btohll(d) bswap_64(d)
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
/* Bluetooth unaligned access */
|
||||
#define bt_get_unaligned(ptr) \
|
||||
__extension__ ({ \
|
||||
struct __attribute__((packed)) { \
|
||||
__typeof__(*(ptr)) __v; \
|
||||
} *__p = (__typeof__(__p)) (ptr); \
|
||||
__p->__v; \
|
||||
})
|
||||
|
||||
#define bt_put_unaligned(val, ptr) \
|
||||
do { \
|
||||
struct __attribute__((packed)) { \
|
||||
__typeof__(*(ptr)) __v; \
|
||||
} *__p = (__typeof__(__p)) (ptr); \
|
||||
__p->__v = (val); \
|
||||
} while(0)
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
static inline uint64_t bt_get_le64(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint64_t bt_get_be64(const void *ptr)
|
||||
{
|
||||
return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_le32(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_be32(const void *ptr)
|
||||
{
|
||||
return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_le16(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_be16(const void *ptr)
|
||||
{
|
||||
return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
|
||||
}
|
||||
|
||||
static inline void bt_put_le64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
|
||||
}
|
||||
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
static inline uint64_t bt_get_le64(const void *ptr)
|
||||
{
|
||||
return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint64_t bt_get_be64(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_le32(const void *ptr)
|
||||
{
|
||||
return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_be32(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_le16(const void *ptr)
|
||||
{
|
||||
return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_be16(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint16_t *) ptr);
|
||||
}
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
/* BD Address */
|
||||
typedef struct {
|
||||
uint8_t b[6];
|
||||
} __attribute__((packed)) bdaddr_t;
|
||||
|
||||
/* BD Address type */
|
||||
#define BDADDR_BREDR 0x00
|
||||
#define BDADDR_LE_PUBLIC 0x01
|
||||
#define BDADDR_LE_RANDOM 0x02
|
||||
|
||||
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
|
||||
#define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
|
||||
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
|
||||
|
||||
/* Copy, swap, convert BD Address */
|
||||
static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
|
||||
{
|
||||
return memcmp(ba1, ba2, sizeof(bdaddr_t));
|
||||
}
|
||||
static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(bdaddr_t));
|
||||
}
|
||||
|
||||
void baswap(bdaddr_t *dst, const bdaddr_t *src);
|
||||
bdaddr_t *strtoba(const char *str);
|
||||
char *batostr(const bdaddr_t *ba);
|
||||
int ba2str(const bdaddr_t *ba, char *str);
|
||||
int str2ba(const char *str, bdaddr_t *ba);
|
||||
int ba2oui(const bdaddr_t *ba, char *oui);
|
||||
int bachk(const char *str);
|
||||
|
||||
int baprintf(const char *format, ...);
|
||||
int bafprintf(FILE *stream, const char *format, ...);
|
||||
int basprintf(char *str, const char *format, ...);
|
||||
int basnprintf(char *str, size_t size, const char *format, ...);
|
||||
|
||||
void *bt_malloc(size_t size);
|
||||
void bt_free(void *ptr);
|
||||
|
||||
int bt_error(uint16_t code);
|
||||
const char *bt_compidtostr(int id);
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[16];
|
||||
} uint128_t;
|
||||
|
||||
static inline void bswap_128(const void *src, void *dst)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *) src;
|
||||
uint8_t *d = (uint8_t *) dst;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
d[15 - i] = s[i];
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
||||
#define ntoh64(x) (x)
|
||||
|
||||
static inline void ntoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
memcpy(dst, src, sizeof(uint128_t));
|
||||
}
|
||||
|
||||
static inline void btoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
bswap_128(src, dst);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint64_t ntoh64(uint64_t n)
|
||||
{
|
||||
uint64_t h;
|
||||
uint64_t tmp = ntohl(n & 0x00000000ffffffff);
|
||||
|
||||
h = ntohl(n >> 32);
|
||||
h |= tmp << 32;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline void ntoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
bswap_128(src, dst);
|
||||
}
|
||||
|
||||
static inline void btoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
memcpy(dst, src, sizeof(uint128_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define hton64(x) ntoh64(x)
|
||||
#define hton128(x, y) ntoh128(x, y)
|
||||
#define htob128(x, y) btoh128(x, y)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BLUETOOTH_H */
|
|
@ -0,0 +1,10 @@
|
|||
prefix=/usr
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: BlueZ
|
||||
Description: Bluetooth protocol stack for Linux
|
||||
Version: 5.43
|
||||
Libs: -L${libdir} -lbluetooth
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,10 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: BlueZ
|
||||
Description: Bluetooth protocol stack for Linux
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lbluetooth
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BNEP_H
|
||||
#define __BNEP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6 /* from <net/ethernet.h> */
|
||||
#endif
|
||||
|
||||
/* BNEP UUIDs */
|
||||
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
|
||||
#define BNEP_UUID16 0x02
|
||||
#define BNEP_UUID32 0x04
|
||||
#define BNEP_UUID128 0x16
|
||||
|
||||
#define BNEP_SVC_PANU 0x1115
|
||||
#define BNEP_SVC_NAP 0x1116
|
||||
#define BNEP_SVC_GN 0x1117
|
||||
|
||||
/* BNEP packet types */
|
||||
#define BNEP_GENERAL 0x00
|
||||
#define BNEP_CONTROL 0x01
|
||||
#define BNEP_COMPRESSED 0x02
|
||||
#define BNEP_COMPRESSED_SRC_ONLY 0x03
|
||||
#define BNEP_COMPRESSED_DST_ONLY 0x04
|
||||
|
||||
/* BNEP control types */
|
||||
#define BNEP_CMD_NOT_UNDERSTOOD 0x00
|
||||
#define BNEP_SETUP_CONN_REQ 0x01
|
||||
#define BNEP_SETUP_CONN_RSP 0x02
|
||||
#define BNEP_FILTER_NET_TYPE_SET 0x03
|
||||
#define BNEP_FILTER_NET_TYPE_RSP 0x04
|
||||
#define BNEP_FILTER_MULT_ADDR_SET 0x05
|
||||
#define BNEP_FILTER_MULT_ADDR_RSP 0x06
|
||||
|
||||
/* BNEP response messages */
|
||||
#define BNEP_SUCCESS 0x00
|
||||
|
||||
#define BNEP_CONN_INVALID_DST 0x01
|
||||
#define BNEP_CONN_INVALID_SRC 0x02
|
||||
#define BNEP_CONN_INVALID_SVC 0x03
|
||||
#define BNEP_CONN_NOT_ALLOWED 0x04
|
||||
|
||||
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
|
||||
#define BNEP_FILTER_INVALID_RANGE 0x02
|
||||
#define BNEP_FILTER_INVALID_MCADDR 0x02
|
||||
#define BNEP_FILTER_LIMIT_REACHED 0x03
|
||||
#define BNEP_FILTER_DENIED_SECURITY 0x04
|
||||
|
||||
/* L2CAP settings */
|
||||
#define BNEP_MTU 1691
|
||||
#define BNEP_FLUSH_TO 0xffff
|
||||
#define BNEP_CONNECT_TO 15
|
||||
#define BNEP_FILTER_TO 15
|
||||
|
||||
#ifndef BNEP_PSM
|
||||
#define BNEP_PSM 0x0f
|
||||
#endif
|
||||
|
||||
/* BNEP headers */
|
||||
#define BNEP_TYPE_MASK 0x7f
|
||||
#define BNEP_EXT_HEADER 0x80
|
||||
|
||||
struct bnep_setup_conn_req {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint8_t uuid_size;
|
||||
uint8_t service[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_set_filter_req {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint16_t len;
|
||||
uint8_t list[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_ctrl_cmd_not_understood_cmd {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint8_t unkn_ctrl;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_control_rsp {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint16_t resp;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_ext_hdr {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* BNEP ioctl defines */
|
||||
#define BNEPCONNADD _IOW('B', 200, int)
|
||||
#define BNEPCONNDEL _IOW('B', 201, int)
|
||||
#define BNEPGETCONNLIST _IOR('B', 210, int)
|
||||
#define BNEPGETCONNINFO _IOR('B', 211, int)
|
||||
#define BNEPGETSUPPFEAT _IOR('B', 212, int)
|
||||
|
||||
#define BNEP_SETUP_RESPONSE 0
|
||||
|
||||
struct bnep_connadd_req {
|
||||
int sock; /* Connected socket */
|
||||
uint32_t flags;
|
||||
uint16_t role;
|
||||
char device[16]; /* Name of the Ethernet device */
|
||||
};
|
||||
|
||||
struct bnep_conndel_req {
|
||||
uint32_t flags;
|
||||
uint8_t dst[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct bnep_conninfo {
|
||||
uint32_t flags;
|
||||
uint16_t role;
|
||||
uint16_t state;
|
||||
uint8_t dst[ETH_ALEN];
|
||||
char device[16];
|
||||
};
|
||||
|
||||
struct bnep_connlist_req {
|
||||
uint32_t cnum;
|
||||
struct bnep_conninfo *ci;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BNEP_H */
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CMTP_H
|
||||
#define __CMTP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* CMTP defaults */
|
||||
#define CMTP_MINIMUM_MTU 152
|
||||
#define CMTP_DEFAULT_MTU 672
|
||||
|
||||
/* CMTP ioctl defines */
|
||||
#define CMTPCONNADD _IOW('C', 200, int)
|
||||
#define CMTPCONNDEL _IOW('C', 201, int)
|
||||
#define CMTPGETCONNLIST _IOR('C', 210, int)
|
||||
#define CMTPGETCONNINFO _IOR('C', 211, int)
|
||||
|
||||
#define CMTP_LOOPBACK 0
|
||||
|
||||
struct cmtp_connadd_req {
|
||||
int sock; /* Connected socket */
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct cmtp_conndel_req {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct cmtp_conninfo {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
uint16_t state;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct cmtp_connlist_req {
|
||||
uint32_t cnum;
|
||||
struct cmtp_conninfo *ci;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CMTP_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HCI_LIB_H
|
||||
#define __HCI_LIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hci_request {
|
||||
uint16_t ogf;
|
||||
uint16_t ocf;
|
||||
int event;
|
||||
void *cparam;
|
||||
int clen;
|
||||
void *rparam;
|
||||
int rlen;
|
||||
};
|
||||
|
||||
struct hci_version {
|
||||
uint16_t manufacturer;
|
||||
uint8_t hci_ver;
|
||||
uint16_t hci_rev;
|
||||
uint8_t lmp_ver;
|
||||
uint16_t lmp_subver;
|
||||
};
|
||||
|
||||
int hci_open_dev(int dev_id);
|
||||
int hci_close_dev(int dd);
|
||||
int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param);
|
||||
int hci_send_req(int dd, struct hci_request *req, int timeout);
|
||||
|
||||
int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to);
|
||||
int hci_disconnect(int dd, uint16_t handle, uint8_t reason, int to);
|
||||
|
||||
int hci_inquiry(int dev_id, int len, int num_rsp, const uint8_t *lap, inquiry_info **ii, long flags);
|
||||
int hci_devinfo(int dev_id, struct hci_dev_info *di);
|
||||
int hci_devba(int dev_id, bdaddr_t *bdaddr);
|
||||
int hci_devid(const char *str);
|
||||
|
||||
int hci_read_local_name(int dd, int len, char *name, int to);
|
||||
int hci_write_local_name(int dd, const char *name, int to);
|
||||
int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to);
|
||||
int hci_read_remote_name_with_clock_offset(int dd, const bdaddr_t *bdaddr, uint8_t pscan_rep_mode, uint16_t clkoffset, int len, char *name, int to);
|
||||
int hci_read_remote_name_cancel(int dd, const bdaddr_t *bdaddr, int to);
|
||||
int hci_read_remote_version(int dd, uint16_t handle, struct hci_version *ver, int to);
|
||||
int hci_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to);
|
||||
int hci_read_remote_ext_features(int dd, uint16_t handle, uint8_t page, uint8_t *max_page, uint8_t *features, int to);
|
||||
int hci_read_clock_offset(int dd, uint16_t handle, uint16_t *clkoffset, int to);
|
||||
int hci_read_local_version(int dd, struct hci_version *ver, int to);
|
||||
int hci_read_local_commands(int dd, uint8_t *commands, int to);
|
||||
int hci_read_local_features(int dd, uint8_t *features, int to);
|
||||
int hci_read_local_ext_features(int dd, uint8_t page, uint8_t *max_page, uint8_t *features, int to);
|
||||
int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to);
|
||||
int hci_read_class_of_dev(int dd, uint8_t *cls, int to);
|
||||
int hci_write_class_of_dev(int dd, uint32_t cls, int to);
|
||||
int hci_read_voice_setting(int dd, uint16_t *vs, int to);
|
||||
int hci_write_voice_setting(int dd, uint16_t vs, int to);
|
||||
int hci_read_current_iac_lap(int dd, uint8_t *num_iac, uint8_t *lap, int to);
|
||||
int hci_write_current_iac_lap(int dd, uint8_t num_iac, uint8_t *lap, int to);
|
||||
int hci_read_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to);
|
||||
int hci_write_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t *key, int to);
|
||||
int hci_delete_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to);
|
||||
int hci_authenticate_link(int dd, uint16_t handle, int to);
|
||||
int hci_encrypt_link(int dd, uint16_t handle, uint8_t encrypt, int to);
|
||||
int hci_change_link_key(int dd, uint16_t handle, int to);
|
||||
int hci_switch_role(int dd, bdaddr_t *bdaddr, uint8_t role, int to);
|
||||
int hci_park_mode(int dd, uint16_t handle, uint16_t max_interval, uint16_t min_interval, int to);
|
||||
int hci_exit_park_mode(int dd, uint16_t handle, int to);
|
||||
int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to);
|
||||
int hci_write_inquiry_scan_type(int dd, uint8_t type, int to);
|
||||
int hci_read_inquiry_mode(int dd, uint8_t *mode, int to);
|
||||
int hci_write_inquiry_mode(int dd, uint8_t mode, int to);
|
||||
int hci_read_afh_mode(int dd, uint8_t *mode, int to);
|
||||
int hci_write_afh_mode(int dd, uint8_t mode, int to);
|
||||
int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to);
|
||||
int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to);
|
||||
int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to);
|
||||
int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to);
|
||||
int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to);
|
||||
int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to);
|
||||
int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to);
|
||||
int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to);
|
||||
int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to);
|
||||
int hci_read_link_policy(int dd, uint16_t handle, uint16_t *policy, int to);
|
||||
int hci_write_link_policy(int dd, uint16_t handle, uint16_t policy, int to);
|
||||
int hci_read_link_supervision_timeout(int dd, uint16_t handle, uint16_t *timeout, int to);
|
||||
int hci_write_link_supervision_timeout(int dd, uint16_t handle, uint16_t timeout, int to);
|
||||
int hci_set_afh_classification(int dd, uint8_t *map, int to);
|
||||
int hci_read_link_quality(int dd, uint16_t handle, uint8_t *link_quality, int to);
|
||||
int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to);
|
||||
int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to);
|
||||
int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to);
|
||||
|
||||
int hci_le_set_scan_enable(int dev_id, uint8_t enable, uint8_t filter_dup, int to);
|
||||
int hci_le_set_scan_parameters(int dev_id, uint8_t type, uint16_t interval,
|
||||
uint16_t window, uint8_t own_type,
|
||||
uint8_t filter, int to);
|
||||
int hci_le_set_advertise_enable(int dev_id, uint8_t enable, int to);
|
||||
int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
|
||||
uint8_t initiator_filter, uint8_t peer_bdaddr_type,
|
||||
bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
|
||||
uint16_t min_interval, uint16_t max_interval,
|
||||
uint16_t latency, uint16_t supervision_timeout,
|
||||
uint16_t min_ce_length, uint16_t max_ce_length,
|
||||
uint16_t *handle, int to);
|
||||
int hci_le_conn_update(int dd, uint16_t handle, uint16_t min_interval,
|
||||
uint16_t max_interval, uint16_t latency,
|
||||
uint16_t supervision_timeout, int to);
|
||||
int hci_le_add_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
|
||||
int hci_le_rm_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
|
||||
int hci_le_read_white_list_size(int dd, uint8_t *size, int to);
|
||||
int hci_le_clear_white_list(int dd, int to);
|
||||
int hci_le_add_resolving_list(int dd, const bdaddr_t *bdaddr, uint8_t type,
|
||||
uint8_t *peer_irk, uint8_t *local_irk, int to);
|
||||
int hci_le_rm_resolving_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
|
||||
int hci_le_clear_resolving_list(int dd, int to);
|
||||
int hci_le_read_resolving_list_size(int dd, uint8_t *size, int to);
|
||||
int hci_le_set_address_resolution_enable(int dev_id, uint8_t enable, int to);
|
||||
int hci_le_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to);
|
||||
|
||||
int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg);
|
||||
int hci_get_route(bdaddr_t *bdaddr);
|
||||
|
||||
char *hci_bustostr(int bus);
|
||||
char *hci_typetostr(int type);
|
||||
char *hci_dtypetostr(int type);
|
||||
char *hci_dflagstostr(uint32_t flags);
|
||||
char *hci_ptypetostr(unsigned int ptype);
|
||||
int hci_strtoptype(char *str, unsigned int *val);
|
||||
char *hci_scoptypetostr(unsigned int ptype);
|
||||
int hci_strtoscoptype(char *str, unsigned int *val);
|
||||
char *hci_lptostr(unsigned int ptype);
|
||||
int hci_strtolp(char *str, unsigned int *val);
|
||||
char *hci_lmtostr(unsigned int ptype);
|
||||
int hci_strtolm(char *str, unsigned int *val);
|
||||
|
||||
char *hci_cmdtostr(unsigned int cmd);
|
||||
char *hci_commandstostr(uint8_t *commands, char *pref, int width);
|
||||
|
||||
char *hci_vertostr(unsigned int ver);
|
||||
int hci_strtover(char *str, unsigned int *ver);
|
||||
char *lmp_vertostr(unsigned int ver);
|
||||
int lmp_strtover(char *str, unsigned int *ver);
|
||||
char *pal_vertostr(unsigned int ver);
|
||||
int pal_strtover(char *str, unsigned int *ver);
|
||||
|
||||
char *lmp_featurestostr(uint8_t *features, char *pref, int width);
|
||||
|
||||
static inline void hci_set_bit(int nr, void *addr)
|
||||
{
|
||||
*((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31));
|
||||
}
|
||||
|
||||
static inline void hci_clear_bit(int nr, void *addr)
|
||||
{
|
||||
*((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31));
|
||||
}
|
||||
|
||||
static inline int hci_test_bit(int nr, void *addr)
|
||||
{
|
||||
return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31));
|
||||
}
|
||||
|
||||
/* HCI filter tools */
|
||||
static inline void hci_filter_clear(struct hci_filter *f)
|
||||
{
|
||||
memset(f, 0, sizeof(*f));
|
||||
}
|
||||
static inline void hci_filter_set_ptype(int t, struct hci_filter *f)
|
||||
{
|
||||
hci_set_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
|
||||
}
|
||||
static inline void hci_filter_clear_ptype(int t, struct hci_filter *f)
|
||||
{
|
||||
hci_clear_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
|
||||
}
|
||||
static inline int hci_filter_test_ptype(int t, struct hci_filter *f)
|
||||
{
|
||||
return hci_test_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
|
||||
}
|
||||
static inline void hci_filter_all_ptypes(struct hci_filter *f)
|
||||
{
|
||||
memset((void *) &f->type_mask, 0xff, sizeof(f->type_mask));
|
||||
}
|
||||
static inline void hci_filter_set_event(int e, struct hci_filter *f)
|
||||
{
|
||||
hci_set_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
|
||||
}
|
||||
static inline void hci_filter_clear_event(int e, struct hci_filter *f)
|
||||
{
|
||||
hci_clear_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
|
||||
}
|
||||
static inline int hci_filter_test_event(int e, struct hci_filter *f)
|
||||
{
|
||||
return hci_test_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
|
||||
}
|
||||
static inline void hci_filter_all_events(struct hci_filter *f)
|
||||
{
|
||||
memset((void *) f->event_mask, 0xff, sizeof(f->event_mask));
|
||||
}
|
||||
static inline void hci_filter_set_opcode(int opcode, struct hci_filter *f)
|
||||
{
|
||||
f->opcode = opcode;
|
||||
}
|
||||
static inline void hci_filter_clear_opcode(struct hci_filter *f)
|
||||
{
|
||||
f->opcode = 0;
|
||||
}
|
||||
static inline int hci_filter_test_opcode(int opcode, struct hci_filter *f)
|
||||
{
|
||||
return (f->opcode == opcode);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HCI_LIB_H */
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HIDP_H
|
||||
#define __HIDP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* HIDP defaults */
|
||||
#define HIDP_MINIMUM_MTU 48
|
||||
#define HIDP_DEFAULT_MTU 48
|
||||
|
||||
/* HIDP ioctl defines */
|
||||
#define HIDPCONNADD _IOW('H', 200, int)
|
||||
#define HIDPCONNDEL _IOW('H', 201, int)
|
||||
#define HIDPGETCONNLIST _IOR('H', 210, int)
|
||||
#define HIDPGETCONNINFO _IOR('H', 211, int)
|
||||
|
||||
#define HIDP_VIRTUAL_CABLE_UNPLUG 0
|
||||
#define HIDP_BOOT_PROTOCOL_MODE 1
|
||||
#define HIDP_BLUETOOTH_VENDOR_ID 9
|
||||
|
||||
struct hidp_connadd_req {
|
||||
int ctrl_sock; /* Connected control socket */
|
||||
int intr_sock; /* Connected interrupt socket */
|
||||
uint16_t parser; /* Parser version */
|
||||
uint16_t rd_size; /* Report descriptor size */
|
||||
uint8_t *rd_data; /* Report descriptor data */
|
||||
uint8_t country;
|
||||
uint8_t subclass;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
uint32_t flags;
|
||||
uint32_t idle_to;
|
||||
char name[128]; /* Device name */
|
||||
};
|
||||
|
||||
struct hidp_conndel_req {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct hidp_conninfo {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
uint16_t state;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
char name[128];
|
||||
};
|
||||
|
||||
struct hidp_connlist_req {
|
||||
uint32_t cnum;
|
||||
struct hidp_conninfo *ci;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HIDP_H */
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __L2CAP_H
|
||||
#define __L2CAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* L2CAP defaults */
|
||||
#define L2CAP_DEFAULT_MTU 672
|
||||
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
|
||||
|
||||
/* L2CAP socket address */
|
||||
struct sockaddr_l2 {
|
||||
sa_family_t l2_family;
|
||||
unsigned short l2_psm;
|
||||
bdaddr_t l2_bdaddr;
|
||||
unsigned short l2_cid;
|
||||
uint8_t l2_bdaddr_type;
|
||||
};
|
||||
|
||||
/* L2CAP socket options */
|
||||
#define L2CAP_OPTIONS 0x01
|
||||
struct l2cap_options {
|
||||
uint16_t omtu;
|
||||
uint16_t imtu;
|
||||
uint16_t flush_to;
|
||||
uint8_t mode;
|
||||
uint8_t fcs;
|
||||
uint8_t max_tx;
|
||||
uint16_t txwin_size;
|
||||
};
|
||||
|
||||
#define L2CAP_CONNINFO 0x02
|
||||
struct l2cap_conninfo {
|
||||
uint16_t hci_handle;
|
||||
uint8_t dev_class[3];
|
||||
};
|
||||
|
||||
#define L2CAP_LM 0x03
|
||||
#define L2CAP_LM_MASTER 0x0001
|
||||
#define L2CAP_LM_AUTH 0x0002
|
||||
#define L2CAP_LM_ENCRYPT 0x0004
|
||||
#define L2CAP_LM_TRUSTED 0x0008
|
||||
#define L2CAP_LM_RELIABLE 0x0010
|
||||
#define L2CAP_LM_SECURE 0x0020
|
||||
|
||||
/* L2CAP command codes */
|
||||
#define L2CAP_COMMAND_REJ 0x01
|
||||
#define L2CAP_CONN_REQ 0x02
|
||||
#define L2CAP_CONN_RSP 0x03
|
||||
#define L2CAP_CONF_REQ 0x04
|
||||
#define L2CAP_CONF_RSP 0x05
|
||||
#define L2CAP_DISCONN_REQ 0x06
|
||||
#define L2CAP_DISCONN_RSP 0x07
|
||||
#define L2CAP_ECHO_REQ 0x08
|
||||
#define L2CAP_ECHO_RSP 0x09
|
||||
#define L2CAP_INFO_REQ 0x0a
|
||||
#define L2CAP_INFO_RSP 0x0b
|
||||
#define L2CAP_CREATE_REQ 0x0c
|
||||
#define L2CAP_CREATE_RSP 0x0d
|
||||
#define L2CAP_MOVE_REQ 0x0e
|
||||
#define L2CAP_MOVE_RSP 0x0f
|
||||
#define L2CAP_MOVE_CFM 0x10
|
||||
#define L2CAP_MOVE_CFM_RSP 0x11
|
||||
|
||||
/* L2CAP extended feature mask */
|
||||
#define L2CAP_FEAT_FLOWCTL 0x00000001
|
||||
#define L2CAP_FEAT_RETRANS 0x00000002
|
||||
#define L2CAP_FEAT_BIDIR_QOS 0x00000004
|
||||
#define L2CAP_FEAT_ERTM 0x00000008
|
||||
#define L2CAP_FEAT_STREAMING 0x00000010
|
||||
#define L2CAP_FEAT_FCS 0x00000020
|
||||
#define L2CAP_FEAT_EXT_FLOW 0x00000040
|
||||
#define L2CAP_FEAT_FIXED_CHAN 0x00000080
|
||||
#define L2CAP_FEAT_EXT_WINDOW 0x00000100
|
||||
#define L2CAP_FEAT_UCD 0x00000200
|
||||
|
||||
/* L2CAP fixed channels */
|
||||
#define L2CAP_FC_L2CAP 0x02
|
||||
#define L2CAP_FC_CONNLESS 0x04
|
||||
#define L2CAP_FC_A2MP 0x08
|
||||
|
||||
/* L2CAP structures */
|
||||
typedef struct {
|
||||
uint16_t len;
|
||||
uint16_t cid;
|
||||
} __attribute__ ((packed)) l2cap_hdr;
|
||||
#define L2CAP_HDR_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed)) l2cap_cmd_hdr;
|
||||
#define L2CAP_CMD_HDR_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t reason;
|
||||
} __attribute__ ((packed)) l2cap_cmd_rej;
|
||||
#define L2CAP_CMD_REJ_SIZE 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t psm;
|
||||
uint16_t scid;
|
||||
} __attribute__ ((packed)) l2cap_conn_req;
|
||||
#define L2CAP_CONN_REQ_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint16_t result;
|
||||
uint16_t status;
|
||||
} __attribute__ ((packed)) l2cap_conn_rsp;
|
||||
#define L2CAP_CONN_RSP_SIZE 8
|
||||
|
||||
/* connect result */
|
||||
#define L2CAP_CR_SUCCESS 0x0000
|
||||
#define L2CAP_CR_PEND 0x0001
|
||||
#define L2CAP_CR_BAD_PSM 0x0002
|
||||
#define L2CAP_CR_SEC_BLOCK 0x0003
|
||||
#define L2CAP_CR_NO_MEM 0x0004
|
||||
|
||||
/* connect status */
|
||||
#define L2CAP_CS_NO_INFO 0x0000
|
||||
#define L2CAP_CS_AUTHEN_PEND 0x0001
|
||||
#define L2CAP_CS_AUTHOR_PEND 0x0002
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t flags;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) l2cap_conf_req;
|
||||
#define L2CAP_CONF_REQ_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t scid;
|
||||
uint16_t flags;
|
||||
uint16_t result;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) l2cap_conf_rsp;
|
||||
#define L2CAP_CONF_RSP_SIZE 6
|
||||
|
||||
#define L2CAP_CONF_SUCCESS 0x0000
|
||||
#define L2CAP_CONF_UNACCEPT 0x0001
|
||||
#define L2CAP_CONF_REJECT 0x0002
|
||||
#define L2CAP_CONF_UNKNOWN 0x0003
|
||||
#define L2CAP_CONF_PENDING 0x0004
|
||||
#define L2CAP_CONF_EFS_REJECT 0x0005
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t val[0];
|
||||
} __attribute__ ((packed)) l2cap_conf_opt;
|
||||
#define L2CAP_CONF_OPT_SIZE 2
|
||||
|
||||
#define L2CAP_CONF_MTU 0x01
|
||||
#define L2CAP_CONF_FLUSH_TO 0x02
|
||||
#define L2CAP_CONF_QOS 0x03
|
||||
#define L2CAP_CONF_RFC 0x04
|
||||
#define L2CAP_CONF_FCS 0x05
|
||||
#define L2CAP_CONF_EFS 0x06
|
||||
#define L2CAP_CONF_EWS 0x07
|
||||
|
||||
#define L2CAP_CONF_MAX_SIZE 22
|
||||
|
||||
#define L2CAP_MODE_BASIC 0x00
|
||||
#define L2CAP_MODE_RETRANS 0x01
|
||||
#define L2CAP_MODE_FLOWCTL 0x02
|
||||
#define L2CAP_MODE_ERTM 0x03
|
||||
#define L2CAP_MODE_STREAMING 0x04
|
||||
|
||||
#define L2CAP_SERVTYPE_NOTRAFFIC 0x00
|
||||
#define L2CAP_SERVTYPE_BESTEFFORT 0x01
|
||||
#define L2CAP_SERVTYPE_GUARANTEED 0x02
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
} __attribute__ ((packed)) l2cap_disconn_req;
|
||||
#define L2CAP_DISCONN_REQ_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
} __attribute__ ((packed)) l2cap_disconn_rsp;
|
||||
#define L2CAP_DISCONN_RSP_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
} __attribute__ ((packed)) l2cap_info_req;
|
||||
#define L2CAP_INFO_REQ_SIZE 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t result;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) l2cap_info_rsp;
|
||||
#define L2CAP_INFO_RSP_SIZE 4
|
||||
|
||||
/* info type */
|
||||
#define L2CAP_IT_CL_MTU 0x0001
|
||||
#define L2CAP_IT_FEAT_MASK 0x0002
|
||||
|
||||
/* info result */
|
||||
#define L2CAP_IR_SUCCESS 0x0000
|
||||
#define L2CAP_IR_NOTSUPP 0x0001
|
||||
|
||||
typedef struct {
|
||||
uint16_t psm;
|
||||
uint16_t scid;
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed)) l2cap_create_req;
|
||||
#define L2CAP_CREATE_REQ_SIZE 5
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint16_t result;
|
||||
uint16_t status;
|
||||
} __attribute__ ((packed)) l2cap_create_rsp;
|
||||
#define L2CAP_CREATE_RSP_SIZE 8
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed)) l2cap_move_req;
|
||||
#define L2CAP_MOVE_REQ_SIZE 3
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
uint16_t result;
|
||||
} __attribute__ ((packed)) l2cap_move_rsp;
|
||||
#define L2CAP_MOVE_RSP_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
uint16_t result;
|
||||
} __attribute__ ((packed)) l2cap_move_cfm;
|
||||
#define L2CAP_MOVE_CFM_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
} __attribute__ ((packed)) l2cap_move_cfm_rsp;
|
||||
#define L2CAP_MOVE_CFM_RSP_SIZE 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __L2CAP_H */
|
|
@ -0,0 +1,41 @@
|
|||
# libbluetooth-internal.la - a libtool library file
|
||||
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-0.1
|
||||
#
|
||||
# Please DO NOT delete this file!
|
||||
# It is necessary for linking the library.
|
||||
|
||||
# The name that we can dlopen(3).
|
||||
dlname=''
|
||||
|
||||
# Names of this library.
|
||||
library_names=''
|
||||
|
||||
# The name of the static archive.
|
||||
old_library='libbluetooth-internal.a'
|
||||
|
||||
# Linker flags that cannot go in dependency_libs.
|
||||
inherited_linker_flags=''
|
||||
|
||||
# Libraries that this one depends upon.
|
||||
dependency_libs=''
|
||||
|
||||
# Names of additional weak libraries provided by this library
|
||||
weak_library_names=''
|
||||
|
||||
# Version information for libbluetooth-internal.
|
||||
current=
|
||||
age=
|
||||
revision=
|
||||
|
||||
# Is this an already installed library?
|
||||
installed=no
|
||||
|
||||
# Should we warn about portability when linking against -modules?
|
||||
shouldnotlink=no
|
||||
|
||||
# Files to dlopen/dlpreopen
|
||||
dlopen=''
|
||||
dlpreopen=''
|
||||
|
||||
# Directory that this library needs to be installed in:
|
||||
libdir=''
|
|
@ -0,0 +1,926 @@
|
|||
/*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#define MGMT_INDEX_NONE 0xFFFF
|
||||
|
||||
#define MGMT_STATUS_SUCCESS 0x00
|
||||
#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
|
||||
#define MGMT_STATUS_NOT_CONNECTED 0x02
|
||||
#define MGMT_STATUS_FAILED 0x03
|
||||
#define MGMT_STATUS_CONNECT_FAILED 0x04
|
||||
#define MGMT_STATUS_AUTH_FAILED 0x05
|
||||
#define MGMT_STATUS_NOT_PAIRED 0x06
|
||||
#define MGMT_STATUS_NO_RESOURCES 0x07
|
||||
#define MGMT_STATUS_TIMEOUT 0x08
|
||||
#define MGMT_STATUS_ALREADY_CONNECTED 0x09
|
||||
#define MGMT_STATUS_BUSY 0x0a
|
||||
#define MGMT_STATUS_REJECTED 0x0b
|
||||
#define MGMT_STATUS_NOT_SUPPORTED 0x0c
|
||||
#define MGMT_STATUS_INVALID_PARAMS 0x0d
|
||||
#define MGMT_STATUS_DISCONNECTED 0x0e
|
||||
#define MGMT_STATUS_NOT_POWERED 0x0f
|
||||
#define MGMT_STATUS_CANCELLED 0x10
|
||||
#define MGMT_STATUS_INVALID_INDEX 0x11
|
||||
#define MGMT_STATUS_RFKILLED 0x12
|
||||
#define MGMT_STATUS_ALREADY_PAIRED 0x13
|
||||
#define MGMT_STATUS_PERMISSION_DENIED 0x14
|
||||
|
||||
struct mgmt_hdr {
|
||||
uint16_t opcode;
|
||||
uint16_t index;
|
||||
uint16_t len;
|
||||
} __packed;
|
||||
#define MGMT_HDR_SIZE 6
|
||||
|
||||
struct mgmt_addr_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_VERSION 0x0001
|
||||
struct mgmt_rp_read_version {
|
||||
uint8_t version;
|
||||
uint16_t revision;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_COMMANDS 0x0002
|
||||
struct mgmt_rp_read_commands {
|
||||
uint16_t num_commands;
|
||||
uint16_t num_events;
|
||||
uint16_t opcodes[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_INDEX_LIST 0x0003
|
||||
struct mgmt_rp_read_index_list {
|
||||
uint16_t num_controllers;
|
||||
uint16_t index[0];
|
||||
} __packed;
|
||||
|
||||
/* Reserve one extra byte for names in management messages so that they
|
||||
* are always guaranteed to be nul-terminated */
|
||||
#define MGMT_MAX_NAME_LENGTH (248 + 1)
|
||||
#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
|
||||
|
||||
#define MGMT_SETTING_POWERED 0x00000001
|
||||
#define MGMT_SETTING_CONNECTABLE 0x00000002
|
||||
#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
|
||||
#define MGMT_SETTING_DISCOVERABLE 0x00000008
|
||||
#define MGMT_SETTING_BONDABLE 0x00000010
|
||||
#define MGMT_SETTING_LINK_SECURITY 0x00000020
|
||||
#define MGMT_SETTING_SSP 0x00000040
|
||||
#define MGMT_SETTING_BREDR 0x00000080
|
||||
#define MGMT_SETTING_HS 0x00000100
|
||||
#define MGMT_SETTING_LE 0x00000200
|
||||
#define MGMT_SETTING_ADVERTISING 0x00000400
|
||||
#define MGMT_SETTING_SECURE_CONN 0x00000800
|
||||
#define MGMT_SETTING_DEBUG_KEYS 0x00001000
|
||||
#define MGMT_SETTING_PRIVACY 0x00002000
|
||||
#define MGMT_SETTING_CONFIGURATION 0x00004000
|
||||
#define MGMT_SETTING_STATIC_ADDRESS 0x00008000
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
struct mgmt_rp_read_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t version;
|
||||
uint16_t manufacturer;
|
||||
uint32_t supported_settings;
|
||||
uint32_t current_settings;
|
||||
uint8_t dev_class[3];
|
||||
uint8_t name[MGMT_MAX_NAME_LENGTH];
|
||||
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_mode {
|
||||
uint8_t val;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_cod {
|
||||
uint8_t val[3];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_POWERED 0x0005
|
||||
|
||||
#define MGMT_OP_SET_DISCOVERABLE 0x0006
|
||||
struct mgmt_cp_set_discoverable {
|
||||
uint8_t val;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_CONNECTABLE 0x0007
|
||||
|
||||
#define MGMT_OP_SET_FAST_CONNECTABLE 0x0008
|
||||
|
||||
#define MGMT_OP_SET_BONDABLE 0x0009
|
||||
|
||||
#define MGMT_OP_SET_LINK_SECURITY 0x000A
|
||||
|
||||
#define MGMT_OP_SET_SSP 0x000B
|
||||
|
||||
#define MGMT_OP_SET_HS 0x000C
|
||||
|
||||
#define MGMT_OP_SET_LE 0x000D
|
||||
|
||||
#define MGMT_OP_SET_DEV_CLASS 0x000E
|
||||
struct mgmt_cp_set_dev_class {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_LOCAL_NAME 0x000F
|
||||
struct mgmt_cp_set_local_name {
|
||||
uint8_t name[MGMT_MAX_NAME_LENGTH];
|
||||
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_UUID 0x0010
|
||||
struct mgmt_cp_add_uuid {
|
||||
uint8_t uuid[16];
|
||||
uint8_t svc_hint;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_UUID 0x0011
|
||||
struct mgmt_cp_remove_uuid {
|
||||
uint8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_link_key_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t type;
|
||||
uint8_t val[16];
|
||||
uint8_t pin_len;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_LINK_KEYS 0x0012
|
||||
struct mgmt_cp_load_link_keys {
|
||||
uint8_t debug_keys;
|
||||
uint16_t key_count;
|
||||
struct mgmt_link_key_info keys[0];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_ltk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t type;
|
||||
uint8_t master;
|
||||
uint8_t enc_size;
|
||||
uint16_t ediv;
|
||||
uint64_t rand;
|
||||
uint8_t val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0013
|
||||
struct mgmt_cp_load_long_term_keys {
|
||||
uint16_t key_count;
|
||||
struct mgmt_ltk_info keys[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_DISCONNECT 0x0014
|
||||
struct mgmt_cp_disconnect {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_disconnect {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CONNECTIONS 0x0015
|
||||
struct mgmt_rp_get_connections {
|
||||
uint16_t conn_count;
|
||||
struct mgmt_addr_info addr[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_REPLY 0x0016
|
||||
struct mgmt_cp_pin_code_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t pin_len;
|
||||
uint8_t pin_code[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017
|
||||
struct mgmt_cp_pin_code_neg_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_IO_CAPABILITY 0x0018
|
||||
struct mgmt_cp_set_io_capability {
|
||||
uint8_t io_capability;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PAIR_DEVICE 0x0019
|
||||
struct mgmt_cp_pair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t io_cap;
|
||||
} __packed;
|
||||
struct mgmt_rp_pair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A
|
||||
|
||||
#define MGMT_OP_UNPAIR_DEVICE 0x001B
|
||||
struct mgmt_cp_unpair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t disconnect;
|
||||
} __packed;
|
||||
struct mgmt_rp_unpair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_REPLY 0x001C
|
||||
struct mgmt_cp_user_confirm_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_user_confirm_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_REPLY 0x001E
|
||||
struct mgmt_cp_user_passkey_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t passkey;
|
||||
} __packed;
|
||||
struct mgmt_rp_user_passkey_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
|
||||
struct mgmt_cp_user_passkey_neg_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020
|
||||
struct mgmt_rp_read_local_oob_data {
|
||||
uint8_t hash192[16];
|
||||
uint8_t rand192[16];
|
||||
uint8_t hash256[16];
|
||||
uint8_t rand256[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021
|
||||
struct mgmt_cp_add_remote_oob_data {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t hash192[16];
|
||||
uint8_t rand192[16];
|
||||
uint8_t hash256[16];
|
||||
uint8_t rand256[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
|
||||
struct mgmt_cp_remove_remote_oob_data {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_DISCOVERY 0x0023
|
||||
struct mgmt_cp_start_discovery {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x0024
|
||||
struct mgmt_cp_stop_discovery {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_CONFIRM_NAME 0x0025
|
||||
struct mgmt_cp_confirm_name {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t name_known;
|
||||
} __packed;
|
||||
struct mgmt_rp_confirm_name {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_BLOCK_DEVICE 0x0026
|
||||
struct mgmt_cp_block_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_UNBLOCK_DEVICE 0x0027
|
||||
struct mgmt_cp_unblock_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_DEVICE_ID 0x0028
|
||||
struct mgmt_cp_set_device_id {
|
||||
uint16_t source;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_ADVERTISING 0x0029
|
||||
|
||||
#define MGMT_OP_SET_BREDR 0x002A
|
||||
|
||||
#define MGMT_OP_SET_STATIC_ADDRESS 0x002B
|
||||
struct mgmt_cp_set_static_address {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_SCAN_PARAMS 0x002C
|
||||
struct mgmt_cp_set_scan_params {
|
||||
uint16_t interval;
|
||||
uint16_t window;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_SECURE_CONN 0x002D
|
||||
|
||||
#define MGMT_OP_SET_DEBUG_KEYS 0x002E
|
||||
|
||||
struct mgmt_irk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_PRIVACY 0x002F
|
||||
struct mgmt_cp_set_privacy {
|
||||
uint8_t privacy;
|
||||
uint8_t irk[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_IRKS 0x0030
|
||||
struct mgmt_cp_load_irks {
|
||||
uint16_t irk_count;
|
||||
struct mgmt_irk_info irks[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CONN_INFO 0x0031
|
||||
struct mgmt_cp_get_conn_info {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_get_conn_info {
|
||||
struct mgmt_addr_info addr;
|
||||
int8_t rssi;
|
||||
int8_t tx_power;
|
||||
int8_t max_tx_power;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CLOCK_INFO 0x0032
|
||||
struct mgmt_cp_get_clock_info {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_get_clock_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t local_clock;
|
||||
uint32_t piconet_clock;
|
||||
uint16_t accuracy;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_DEVICE 0x0033
|
||||
struct mgmt_cp_add_device {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t action;
|
||||
} __packed;
|
||||
struct mgmt_rp_add_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_DEVICE 0x0034
|
||||
struct mgmt_cp_remove_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_remove_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_conn_param {
|
||||
struct mgmt_addr_info addr;
|
||||
uint16_t min_interval;
|
||||
uint16_t max_interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_CONN_PARAM 0x0035
|
||||
struct mgmt_cp_load_conn_param {
|
||||
uint16_t param_count;
|
||||
struct mgmt_conn_param params[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_UNCONF_INDEX_LIST 0x0036
|
||||
struct mgmt_rp_read_unconf_index_list {
|
||||
uint16_t num_controllers;
|
||||
uint16_t index[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OPTION_EXTERNAL_CONFIG 0x00000001
|
||||
#define MGMT_OPTION_PUBLIC_ADDRESS 0x00000002
|
||||
|
||||
#define MGMT_OP_READ_CONFIG_INFO 0x0037
|
||||
struct mgmt_rp_read_config_info {
|
||||
uint16_t manufacturer;
|
||||
uint32_t supported_options;
|
||||
uint32_t missing_options;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_EXTERNAL_CONFIG 0x0038
|
||||
struct mgmt_cp_set_external_config {
|
||||
uint8_t config;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_PUBLIC_ADDRESS 0x0039
|
||||
struct mgmt_cp_set_public_address {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_SERVICE_DISCOVERY 0x003A
|
||||
struct mgmt_cp_start_service_discovery {
|
||||
uint8_t type;
|
||||
int8_t rssi;
|
||||
uint16_t uuid_count;
|
||||
uint8_t uuids[0][16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_LOCAL_OOB_EXT_DATA 0x003B
|
||||
struct mgmt_cp_read_local_oob_ext_data {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
struct mgmt_rp_read_local_oob_ext_data {
|
||||
uint8_t type;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_EXT_INDEX_LIST 0x003C
|
||||
struct mgmt_rp_read_ext_index_list {
|
||||
uint16_t num_controllers;
|
||||
struct {
|
||||
uint16_t index;
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
} entry[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_ADV_FEATURES 0x003D
|
||||
struct mgmt_rp_read_adv_features {
|
||||
uint32_t supported_flags;
|
||||
uint8_t max_adv_data_len;
|
||||
uint8_t max_scan_rsp_len;
|
||||
uint8_t max_instances;
|
||||
uint8_t num_instances;
|
||||
uint8_t instance[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_ADVERTISING 0x003E
|
||||
struct mgmt_cp_add_advertising {
|
||||
uint8_t instance;
|
||||
uint32_t flags;
|
||||
uint16_t duration;
|
||||
uint16_t timeout;
|
||||
uint8_t adv_data_len;
|
||||
uint8_t scan_rsp_len;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
struct mgmt_rp_add_advertising {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_ADV_FLAG_CONNECTABLE (1 << 0)
|
||||
#define MGMT_ADV_FLAG_DISCOV (1 << 1)
|
||||
#define MGMT_ADV_FLAG_LIMITED_DISCOV (1 << 2)
|
||||
#define MGMT_ADV_FLAG_MANAGED_FLAGS (1 << 3)
|
||||
#define MGMT_ADV_FLAG_TX_POWER (1 << 4)
|
||||
#define MGMT_ADV_FLAG_APPEARANCE (1 << 5)
|
||||
#define MGMT_ADV_FLAG_LOCAL_NAME (1 << 6)
|
||||
|
||||
#define MGMT_OP_REMOVE_ADVERTISING 0x003F
|
||||
struct mgmt_cp_remove_advertising {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
#define MGMT_REMOVE_ADVERTISING_SIZE 1
|
||||
struct mgmt_rp_remove_advertising {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_ADV_SIZE_INFO 0x0040
|
||||
struct mgmt_cp_get_adv_size_info {
|
||||
uint8_t instance;
|
||||
uint32_t flags;
|
||||
} __packed;
|
||||
#define MGMT_GET_ADV_SIZE_INFO_SIZE 5
|
||||
struct mgmt_rp_get_adv_size_info {
|
||||
uint8_t instance;
|
||||
uint32_t flags;
|
||||
uint8_t max_adv_data_len;
|
||||
uint8_t max_scan_rsp_len;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_LIMITED_DISCOVERY 0x0041
|
||||
|
||||
#define MGMT_OP_READ_EXT_INFO 0x0042
|
||||
struct mgmt_rp_read_ext_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t version;
|
||||
uint16_t manufacturer;
|
||||
uint32_t supported_settings;
|
||||
uint32_t current_settings;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_APPEARANCE 0x0043
|
||||
struct mgmt_cp_set_appearance {
|
||||
uint16_t appearance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_STATUS 0x0002
|
||||
struct mgmt_ev_cmd_status {
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONTROLLER_ERROR 0x0003
|
||||
struct mgmt_ev_controller_error {
|
||||
uint8_t error_code;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_INDEX_ADDED 0x0004
|
||||
|
||||
#define MGMT_EV_INDEX_REMOVED 0x0005
|
||||
|
||||
#define MGMT_EV_NEW_SETTINGS 0x0006
|
||||
|
||||
#define MGMT_EV_CLASS_OF_DEV_CHANGED 0x0007
|
||||
struct mgmt_ev_class_of_dev_changed {
|
||||
uint8_t dev_class[3];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0008
|
||||
struct mgmt_ev_local_name_changed {
|
||||
uint8_t name[MGMT_MAX_NAME_LENGTH];
|
||||
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_LINK_KEY 0x0009
|
||||
struct mgmt_ev_new_link_key {
|
||||
uint8_t store_hint;
|
||||
struct mgmt_link_key_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_LONG_TERM_KEY 0x000A
|
||||
struct mgmt_ev_new_long_term_key {
|
||||
uint8_t store_hint;
|
||||
struct mgmt_ltk_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_CONNECTED 0x000B
|
||||
struct mgmt_ev_device_connected {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t flags;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_DEV_DISCONN_UNKNOWN 0x00
|
||||
#define MGMT_DEV_DISCONN_TIMEOUT 0x01
|
||||
#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
|
||||
#define MGMT_DEV_DISCONN_REMOTE 0x03
|
||||
|
||||
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
|
||||
struct mgmt_ev_device_disconnected {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t reason;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONNECT_FAILED 0x000D
|
||||
struct mgmt_ev_connect_failed {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
|
||||
struct mgmt_ev_pin_code_request {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t secure;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
|
||||
struct mgmt_ev_user_confirm_request {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t confirm_hint;
|
||||
uint32_t value;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0010
|
||||
struct mgmt_ev_user_passkey_request {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_AUTH_FAILED 0x0011
|
||||
struct mgmt_ev_auth_failed {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01
|
||||
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
|
||||
#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04
|
||||
|
||||
#define MGMT_EV_DEVICE_FOUND 0x0012
|
||||
struct mgmt_ev_device_found {
|
||||
struct mgmt_addr_info addr;
|
||||
int8_t rssi;
|
||||
uint32_t flags;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DISCOVERING 0x0013
|
||||
struct mgmt_ev_discovering {
|
||||
uint8_t type;
|
||||
uint8_t discovering;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_BLOCKED 0x0014
|
||||
struct mgmt_ev_device_blocked {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_UNBLOCKED 0x0015
|
||||
struct mgmt_ev_device_unblocked {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_UNPAIRED 0x0016
|
||||
struct mgmt_ev_device_unpaired {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PASSKEY_NOTIFY 0x0017
|
||||
struct mgmt_ev_passkey_notify {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t passkey;
|
||||
uint8_t entered;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_IRK 0x0018
|
||||
struct mgmt_ev_new_irk {
|
||||
uint8_t store_hint;
|
||||
bdaddr_t rpa;
|
||||
struct mgmt_irk_info key;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_csrk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t type;
|
||||
uint8_t val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_CSRK 0x0019
|
||||
struct mgmt_ev_new_csrk {
|
||||
uint8_t store_hint;
|
||||
struct mgmt_csrk_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_ADDED 0x001a
|
||||
struct mgmt_ev_device_added {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t action;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_REMOVED 0x001b
|
||||
struct mgmt_ev_device_removed {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_CONN_PARAM 0x001c
|
||||
struct mgmt_ev_new_conn_param {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t store_hint;
|
||||
uint16_t min_interval;
|
||||
uint16_t max_interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_UNCONF_INDEX_ADDED 0x001d
|
||||
|
||||
#define MGMT_EV_UNCONF_INDEX_REMOVED 0x001e
|
||||
|
||||
#define MGMT_EV_NEW_CONFIG_OPTIONS 0x001f
|
||||
|
||||
#define MGMT_EV_EXT_INDEX_ADDED 0x0020
|
||||
struct mgmt_ev_ext_index_added {
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_EXT_INDEX_REMOVED 0x0021
|
||||
struct mgmt_ev_ext_index_removed {
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_LOCAL_OOB_DATA_UPDATED 0x0022
|
||||
struct mgmt_ev_local_oob_data_updated {
|
||||
uint8_t type;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADVERTISING_ADDED 0x0023
|
||||
struct mgmt_ev_advertising_added {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADVERTISING_REMOVED 0x0024
|
||||
struct mgmt_ev_advertising_removed {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_EXT_INFO_CHANGED 0x0025
|
||||
struct mgmt_ev_ext_info_changed {
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
static const char *mgmt_op[] = {
|
||||
"<0x0000>",
|
||||
"Read Version",
|
||||
"Read Commands",
|
||||
"Read Index List",
|
||||
"Read Controller Info",
|
||||
"Set Powered",
|
||||
"Set Discoverable",
|
||||
"Set Connectable",
|
||||
"Set Fast Connectable", /* 0x0008 */
|
||||
"Set Bondable",
|
||||
"Set Link Security",
|
||||
"Set Secure Simple Pairing",
|
||||
"Set High Speed",
|
||||
"Set Low Energy",
|
||||
"Set Dev Class",
|
||||
"Set Local Name",
|
||||
"Add UUID", /* 0x0010 */
|
||||
"Remove UUID",
|
||||
"Load Link Keys",
|
||||
"Load Long Term Keys",
|
||||
"Disconnect",
|
||||
"Get Connections",
|
||||
"PIN Code Reply",
|
||||
"PIN Code Neg Reply",
|
||||
"Set IO Capability", /* 0x0018 */
|
||||
"Pair Device",
|
||||
"Cancel Pair Device",
|
||||
"Unpair Device",
|
||||
"User Confirm Reply",
|
||||
"User Confirm Neg Reply",
|
||||
"User Passkey Reply",
|
||||
"User Passkey Neg Reply",
|
||||
"Read Local OOB Data", /* 0x0020 */
|
||||
"Add Remote OOB Data",
|
||||
"Remove Remove OOB Data",
|
||||
"Start Discovery",
|
||||
"Stop Discovery",
|
||||
"Confirm Name",
|
||||
"Block Device",
|
||||
"Unblock Device",
|
||||
"Set Device ID", /* 0x0028 */
|
||||
"Set Advertising",
|
||||
"Set BR/EDR",
|
||||
"Set Static Address",
|
||||
"Set Scan Parameters",
|
||||
"Set Secure Connections",
|
||||
"Set Debug Keys",
|
||||
"Set Privacy",
|
||||
"Load Identity Resolving Keys", /* 0x0030 */
|
||||
"Get Connection Information",
|
||||
"Get Clock Information",
|
||||
"Add Device",
|
||||
"Remove Device",
|
||||
"Load Connection Parameters",
|
||||
"Read Unconfigured Index List",
|
||||
"Read Controller Configuration Information",
|
||||
"Set External Configuration", /* 0x0038 */
|
||||
"Set Public Address",
|
||||
"Start Service Discovery",
|
||||
"Read Local Out Of Band Extended Data",
|
||||
"Read Extended Controller Index List",
|
||||
"Read Advertising Features",
|
||||
"Add Advertising",
|
||||
"Remove Advertising",
|
||||
"Get Advertising Size Information", /* 0x0040 */
|
||||
"Start Limited Discovery",
|
||||
"Read Extended Controller Information",
|
||||
"Set Appearance",
|
||||
};
|
||||
|
||||
static const char *mgmt_ev[] = {
|
||||
"<0x0000>",
|
||||
"Command Complete",
|
||||
"Command Status",
|
||||
"Controller Error",
|
||||
"Index Added",
|
||||
"Index Removed",
|
||||
"New Settings",
|
||||
"Class of Device Changed",
|
||||
"Local Name Changed", /* 0x0008 */
|
||||
"New Link Key",
|
||||
"New Long Term Key",
|
||||
"Device Connected",
|
||||
"Device Disconnected",
|
||||
"Connect Failed",
|
||||
"PIN Code Request",
|
||||
"User Confirm Request",
|
||||
"User Passkey Request", /* 0x0010 */
|
||||
"Authentication Failed",
|
||||
"Device Found",
|
||||
"Discovering",
|
||||
"Device Blocked",
|
||||
"Device Unblocked",
|
||||
"Device Unpaired",
|
||||
"Passkey Notify",
|
||||
"New Identity Resolving Key", /* 0x0018 */
|
||||
"New Signature Resolving Key",
|
||||
"Device Added",
|
||||
"Device Removed",
|
||||
"New Connection Parameter",
|
||||
"Unconfigured Index Added",
|
||||
"Unconfigured Index Removed",
|
||||
"New Configuration Options",
|
||||
"Extended Index Added", /* 0x0020 */
|
||||
"Extended Index Removed",
|
||||
"Local Out Of Band Extended Data Updated",
|
||||
"Advertising Added",
|
||||
"Advertising Removed",
|
||||
"Extended Controller Information Changed",
|
||||
};
|
||||
|
||||
static const char *mgmt_status[] = {
|
||||
"Success",
|
||||
"Unknown Command",
|
||||
"Not Connected",
|
||||
"Failed",
|
||||
"Connect Failed",
|
||||
"Authentication Failed",
|
||||
"Not Paired",
|
||||
"No Resources",
|
||||
"Timeout",
|
||||
"Already Connected",
|
||||
"Busy",
|
||||
"Rejected",
|
||||
"Not Supported",
|
||||
"Invalid Parameters",
|
||||
"Disconnected",
|
||||
"Not Powered",
|
||||
"Cancelled",
|
||||
"Invalid Index",
|
||||
"Blocked through rfkill",
|
||||
"Already Paired",
|
||||
"Permission Denied",
|
||||
};
|
||||
|
||||
#ifndef NELEM
|
||||
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
static inline const char *mgmt_opstr(uint16_t op)
|
||||
{
|
||||
if (op >= NELEM(mgmt_op))
|
||||
return "<unknown opcode>";
|
||||
return mgmt_op[op];
|
||||
}
|
||||
|
||||
static inline const char *mgmt_evstr(uint16_t ev)
|
||||
{
|
||||
if (ev >= NELEM(mgmt_ev))
|
||||
return "<unknown event>";
|
||||
return mgmt_ev[ev];
|
||||
}
|
||||
|
||||
static inline const char *mgmt_errstr(uint8_t status)
|
||||
{
|
||||
if (status >= NELEM(mgmt_status))
|
||||
return "<unknown status>";
|
||||
return mgmt_status[status];
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RFCOMM_H
|
||||
#define __RFCOMM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* RFCOMM defaults */
|
||||
#define RFCOMM_DEFAULT_MTU 127
|
||||
|
||||
#define RFCOMM_PSM 3
|
||||
|
||||
/* RFCOMM socket address */
|
||||
struct sockaddr_rc {
|
||||
sa_family_t rc_family;
|
||||
bdaddr_t rc_bdaddr;
|
||||
uint8_t rc_channel;
|
||||
};
|
||||
|
||||
/* RFCOMM socket options */
|
||||
#define RFCOMM_CONNINFO 0x02
|
||||
struct rfcomm_conninfo {
|
||||
uint16_t hci_handle;
|
||||
uint8_t dev_class[3];
|
||||
};
|
||||
|
||||
#define RFCOMM_LM 0x03
|
||||
#define RFCOMM_LM_MASTER 0x0001
|
||||
#define RFCOMM_LM_AUTH 0x0002
|
||||
#define RFCOMM_LM_ENCRYPT 0x0004
|
||||
#define RFCOMM_LM_TRUSTED 0x0008
|
||||
#define RFCOMM_LM_RELIABLE 0x0010
|
||||
#define RFCOMM_LM_SECURE 0x0020
|
||||
|
||||
/* RFCOMM TTY support */
|
||||
#define RFCOMM_MAX_DEV 256
|
||||
|
||||
#define RFCOMMCREATEDEV _IOW('R', 200, int)
|
||||
#define RFCOMMRELEASEDEV _IOW('R', 201, int)
|
||||
#define RFCOMMGETDEVLIST _IOR('R', 210, int)
|
||||
#define RFCOMMGETDEVINFO _IOR('R', 211, int)
|
||||
|
||||
struct rfcomm_dev_req {
|
||||
int16_t dev_id;
|
||||
uint32_t flags;
|
||||
bdaddr_t src;
|
||||
bdaddr_t dst;
|
||||
uint8_t channel;
|
||||
};
|
||||
#define RFCOMM_REUSE_DLC 0
|
||||
#define RFCOMM_RELEASE_ONHUP 1
|
||||
#define RFCOMM_HANGUP_NOW 2
|
||||
#define RFCOMM_TTY_ATTACHED 3
|
||||
|
||||
struct rfcomm_dev_info {
|
||||
int16_t id;
|
||||
uint32_t flags;
|
||||
uint16_t state;
|
||||
bdaddr_t src;
|
||||
bdaddr_t dst;
|
||||
uint8_t channel;
|
||||
};
|
||||
|
||||
struct rfcomm_dev_list_req {
|
||||
uint16_t dev_num;
|
||||
struct rfcomm_dev_info dev_info[0];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RFCOMM_H */
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SCO_H
|
||||
#define __SCO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SCO defaults */
|
||||
#define SCO_DEFAULT_MTU 500
|
||||
#define SCO_DEFAULT_FLUSH_TO 0xFFFF
|
||||
|
||||
#define SCO_CONN_TIMEOUT (HZ * 40)
|
||||
#define SCO_DISCONN_TIMEOUT (HZ * 2)
|
||||
#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
|
||||
|
||||
/* SCO socket address */
|
||||
struct sockaddr_sco {
|
||||
sa_family_t sco_family;
|
||||
bdaddr_t sco_bdaddr;
|
||||
};
|
||||
|
||||
/* set/get sockopt defines */
|
||||
#define SCO_OPTIONS 0x01
|
||||
struct sco_options {
|
||||
uint16_t mtu;
|
||||
};
|
||||
|
||||
#define SCO_CONNINFO 0x02
|
||||
struct sco_conninfo {
|
||||
uint16_t hci_handle;
|
||||
uint8_t dev_class[3];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SCO_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2001-2002 Nokia Corporation
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SDP_H
|
||||
#define __SDP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
|
||||
#define SDP_UNIX_PATH "/var/run/sdp"
|
||||
#define SDP_RESPONSE_TIMEOUT 20
|
||||
#define SDP_REQ_BUFFER_SIZE 2048
|
||||
#define SDP_RSP_BUFFER_SIZE 65535
|
||||
#define SDP_PDU_CHUNK_SIZE 1024
|
||||
|
||||
/*
|
||||
* All definitions are based on Bluetooth Assigned Numbers
|
||||
* of the Bluetooth Specification
|
||||
*/
|
||||
#define SDP_PSM 0x0001
|
||||
|
||||
/*
|
||||
* Protocol UUIDs
|
||||
*/
|
||||
#define SDP_UUID 0x0001
|
||||
#define UDP_UUID 0x0002
|
||||
#define RFCOMM_UUID 0x0003
|
||||
#define TCP_UUID 0x0004
|
||||
#define TCS_BIN_UUID 0x0005
|
||||
#define TCS_AT_UUID 0x0006
|
||||
#define ATT_UUID 0x0007
|
||||
#define OBEX_UUID 0x0008
|
||||
#define IP_UUID 0x0009
|
||||
#define FTP_UUID 0x000a
|
||||
#define HTTP_UUID 0x000c
|
||||
#define WSP_UUID 0x000e
|
||||
#define BNEP_UUID 0x000f
|
||||
#define UPNP_UUID 0x0010
|
||||
#define HIDP_UUID 0x0011
|
||||
#define HCRP_CTRL_UUID 0x0012
|
||||
#define HCRP_DATA_UUID 0x0014
|
||||
#define HCRP_NOTE_UUID 0x0016
|
||||
#define AVCTP_UUID 0x0017
|
||||
#define AVDTP_UUID 0x0019
|
||||
#define CMTP_UUID 0x001b
|
||||
#define UDI_UUID 0x001d
|
||||
#define MCAP_CTRL_UUID 0x001e
|
||||
#define MCAP_DATA_UUID 0x001f
|
||||
#define L2CAP_UUID 0x0100
|
||||
|
||||
/*
|
||||
* Service class identifiers of standard services and service groups
|
||||
*/
|
||||
#define SDP_SERVER_SVCLASS_ID 0x1000
|
||||
#define BROWSE_GRP_DESC_SVCLASS_ID 0x1001
|
||||
#define PUBLIC_BROWSE_GROUP 0x1002
|
||||
#define SERIAL_PORT_SVCLASS_ID 0x1101
|
||||
#define LAN_ACCESS_SVCLASS_ID 0x1102
|
||||
#define DIALUP_NET_SVCLASS_ID 0x1103
|
||||
#define IRMC_SYNC_SVCLASS_ID 0x1104
|
||||
#define OBEX_OBJPUSH_SVCLASS_ID 0x1105
|
||||
#define OBEX_FILETRANS_SVCLASS_ID 0x1106
|
||||
#define IRMC_SYNC_CMD_SVCLASS_ID 0x1107
|
||||
#define HEADSET_SVCLASS_ID 0x1108
|
||||
#define CORDLESS_TELEPHONY_SVCLASS_ID 0x1109
|
||||
#define AUDIO_SOURCE_SVCLASS_ID 0x110a
|
||||
#define AUDIO_SINK_SVCLASS_ID 0x110b
|
||||
#define AV_REMOTE_TARGET_SVCLASS_ID 0x110c
|
||||
#define ADVANCED_AUDIO_SVCLASS_ID 0x110d
|
||||
#define AV_REMOTE_SVCLASS_ID 0x110e
|
||||
#define AV_REMOTE_CONTROLLER_SVCLASS_ID 0x110f
|
||||
#define INTERCOM_SVCLASS_ID 0x1110
|
||||
#define FAX_SVCLASS_ID 0x1111
|
||||
#define HEADSET_AGW_SVCLASS_ID 0x1112
|
||||
#define WAP_SVCLASS_ID 0x1113
|
||||
#define WAP_CLIENT_SVCLASS_ID 0x1114
|
||||
#define PANU_SVCLASS_ID 0x1115
|
||||
#define NAP_SVCLASS_ID 0x1116
|
||||
#define GN_SVCLASS_ID 0x1117
|
||||
#define DIRECT_PRINTING_SVCLASS_ID 0x1118
|
||||
#define REFERENCE_PRINTING_SVCLASS_ID 0x1119
|
||||
#define IMAGING_SVCLASS_ID 0x111a
|
||||
#define IMAGING_RESPONDER_SVCLASS_ID 0x111b
|
||||
#define IMAGING_ARCHIVE_SVCLASS_ID 0x111c
|
||||
#define IMAGING_REFOBJS_SVCLASS_ID 0x111d
|
||||
#define HANDSFREE_SVCLASS_ID 0x111e
|
||||
#define HANDSFREE_AGW_SVCLASS_ID 0x111f
|
||||
#define DIRECT_PRT_REFOBJS_SVCLASS_ID 0x1120
|
||||
#define REFLECTED_UI_SVCLASS_ID 0x1121
|
||||
#define BASIC_PRINTING_SVCLASS_ID 0x1122
|
||||
#define PRINTING_STATUS_SVCLASS_ID 0x1123
|
||||
#define HID_SVCLASS_ID 0x1124
|
||||
#define HCR_SVCLASS_ID 0x1125
|
||||
#define HCR_PRINT_SVCLASS_ID 0x1126
|
||||
#define HCR_SCAN_SVCLASS_ID 0x1127
|
||||
#define CIP_SVCLASS_ID 0x1128
|
||||
#define VIDEO_CONF_GW_SVCLASS_ID 0x1129
|
||||
#define UDI_MT_SVCLASS_ID 0x112a
|
||||
#define UDI_TA_SVCLASS_ID 0x112b
|
||||
#define AV_SVCLASS_ID 0x112c
|
||||
#define SAP_SVCLASS_ID 0x112d
|
||||
#define PBAP_PCE_SVCLASS_ID 0x112e
|
||||
#define PBAP_PSE_SVCLASS_ID 0x112f
|
||||
#define PBAP_SVCLASS_ID 0x1130
|
||||
#define MAP_MSE_SVCLASS_ID 0x1132
|
||||
#define MAP_MCE_SVCLASS_ID 0x1133
|
||||
#define MAP_SVCLASS_ID 0x1134
|
||||
#define GNSS_SVCLASS_ID 0x1135
|
||||
#define GNSS_SERVER_SVCLASS_ID 0x1136
|
||||
#define MPS_SC_SVCLASS_ID 0x113A
|
||||
#define MPS_SVCLASS_ID 0x113B
|
||||
#define PNP_INFO_SVCLASS_ID 0x1200
|
||||
#define GENERIC_NETWORKING_SVCLASS_ID 0x1201
|
||||
#define GENERIC_FILETRANS_SVCLASS_ID 0x1202
|
||||
#define GENERIC_AUDIO_SVCLASS_ID 0x1203
|
||||
#define GENERIC_TELEPHONY_SVCLASS_ID 0x1204
|
||||
#define UPNP_SVCLASS_ID 0x1205
|
||||
#define UPNP_IP_SVCLASS_ID 0x1206
|
||||
#define UPNP_PAN_SVCLASS_ID 0x1300
|
||||
#define UPNP_LAP_SVCLASS_ID 0x1301
|
||||
#define UPNP_L2CAP_SVCLASS_ID 0x1302
|
||||
#define VIDEO_SOURCE_SVCLASS_ID 0x1303
|
||||
#define VIDEO_SINK_SVCLASS_ID 0x1304
|
||||
#define VIDEO_DISTRIBUTION_SVCLASS_ID 0x1305
|
||||
#define HDP_SVCLASS_ID 0x1400
|
||||
#define HDP_SOURCE_SVCLASS_ID 0x1401
|
||||
#define HDP_SINK_SVCLASS_ID 0x1402
|
||||
#define GENERIC_ACCESS_SVCLASS_ID 0x1800
|
||||
#define GENERIC_ATTRIB_SVCLASS_ID 0x1801
|
||||
#define APPLE_AGENT_SVCLASS_ID 0x2112
|
||||
|
||||
/*
|
||||
* Standard profile descriptor identifiers; note these
|
||||
* may be identical to some of the service classes defined above
|
||||
*/
|
||||
#define SDP_SERVER_PROFILE_ID SDP_SERVER_SVCLASS_ID
|
||||
#define BROWSE_GRP_DESC_PROFILE_ID BROWSE_GRP_DESC_SVCLASS_ID
|
||||
#define SERIAL_PORT_PROFILE_ID SERIAL_PORT_SVCLASS_ID
|
||||
#define LAN_ACCESS_PROFILE_ID LAN_ACCESS_SVCLASS_ID
|
||||
#define DIALUP_NET_PROFILE_ID DIALUP_NET_SVCLASS_ID
|
||||
#define IRMC_SYNC_PROFILE_ID IRMC_SYNC_SVCLASS_ID
|
||||
#define OBEX_OBJPUSH_PROFILE_ID OBEX_OBJPUSH_SVCLASS_ID
|
||||
#define OBEX_FILETRANS_PROFILE_ID OBEX_FILETRANS_SVCLASS_ID
|
||||
#define IRMC_SYNC_CMD_PROFILE_ID IRMC_SYNC_CMD_SVCLASS_ID
|
||||
#define HEADSET_PROFILE_ID HEADSET_SVCLASS_ID
|
||||
#define CORDLESS_TELEPHONY_PROFILE_ID CORDLESS_TELEPHONY_SVCLASS_ID
|
||||
#define AUDIO_SOURCE_PROFILE_ID AUDIO_SOURCE_SVCLASS_ID
|
||||
#define AUDIO_SINK_PROFILE_ID AUDIO_SINK_SVCLASS_ID
|
||||
#define AV_REMOTE_TARGET_PROFILE_ID AV_REMOTE_TARGET_SVCLASS_ID
|
||||
#define ADVANCED_AUDIO_PROFILE_ID ADVANCED_AUDIO_SVCLASS_ID
|
||||
#define AV_REMOTE_PROFILE_ID AV_REMOTE_SVCLASS_ID
|
||||
#define VIDEO_CONF_PROFILE_ID VIDEO_CONF_SVCLASS_ID
|
||||
#define INTERCOM_PROFILE_ID INTERCOM_SVCLASS_ID
|
||||
#define FAX_PROFILE_ID FAX_SVCLASS_ID
|
||||
#define HEADSET_AGW_PROFILE_ID HEADSET_AGW_SVCLASS_ID
|
||||
#define WAP_PROFILE_ID WAP_SVCLASS_ID
|
||||
#define WAP_CLIENT_PROFILE_ID WAP_CLIENT_SVCLASS_ID
|
||||
#define PANU_PROFILE_ID PANU_SVCLASS_ID
|
||||
#define NAP_PROFILE_ID NAP_SVCLASS_ID
|
||||
#define GN_PROFILE_ID GN_SVCLASS_ID
|
||||
#define DIRECT_PRINTING_PROFILE_ID DIRECT_PRINTING_SVCLASS_ID
|
||||
#define REFERENCE_PRINTING_PROFILE_ID REFERENCE_PRINTING_SVCLASS_ID
|
||||
#define IMAGING_PROFILE_ID IMAGING_SVCLASS_ID
|
||||
#define IMAGING_RESPONDER_PROFILE_ID IMAGING_RESPONDER_SVCLASS_ID
|
||||
#define IMAGING_ARCHIVE_PROFILE_ID IMAGING_ARCHIVE_SVCLASS_ID
|
||||
#define IMAGING_REFOBJS_PROFILE_ID IMAGING_REFOBJS_SVCLASS_ID
|
||||
#define HANDSFREE_PROFILE_ID HANDSFREE_SVCLASS_ID
|
||||
#define HANDSFREE_AGW_PROFILE_ID HANDSFREE_AGW_SVCLASS_ID
|
||||
#define DIRECT_PRT_REFOBJS_PROFILE_ID DIRECT_PRT_REFOBJS_SVCLASS_ID
|
||||
#define REFLECTED_UI_PROFILE_ID REFLECTED_UI_SVCLASS_ID
|
||||
#define BASIC_PRINTING_PROFILE_ID BASIC_PRINTING_SVCLASS_ID
|
||||
#define PRINTING_STATUS_PROFILE_ID PRINTING_STATUS_SVCLASS_ID
|
||||
#define HID_PROFILE_ID HID_SVCLASS_ID
|
||||
#define HCR_PROFILE_ID HCR_SCAN_SVCLASS_ID
|
||||
#define HCR_PRINT_PROFILE_ID HCR_PRINT_SVCLASS_ID
|
||||
#define HCR_SCAN_PROFILE_ID HCR_SCAN_SVCLASS_ID
|
||||
#define CIP_PROFILE_ID CIP_SVCLASS_ID
|
||||
#define VIDEO_CONF_GW_PROFILE_ID VIDEO_CONF_GW_SVCLASS_ID
|
||||
#define UDI_MT_PROFILE_ID UDI_MT_SVCLASS_ID
|
||||
#define UDI_TA_PROFILE_ID UDI_TA_SVCLASS_ID
|
||||
#define AV_PROFILE_ID AV_SVCLASS_ID
|
||||
#define SAP_PROFILE_ID SAP_SVCLASS_ID
|
||||
#define PBAP_PCE_PROFILE_ID PBAP_PCE_SVCLASS_ID
|
||||
#define PBAP_PSE_PROFILE_ID PBAP_PSE_SVCLASS_ID
|
||||
#define PBAP_PROFILE_ID PBAP_SVCLASS_ID
|
||||
#define MAP_PROFILE_ID MAP_SVCLASS_ID
|
||||
#define PNP_INFO_PROFILE_ID PNP_INFO_SVCLASS_ID
|
||||
#define GENERIC_NETWORKING_PROFILE_ID GENERIC_NETWORKING_SVCLASS_ID
|
||||
#define GENERIC_FILETRANS_PROFILE_ID GENERIC_FILETRANS_SVCLASS_ID
|
||||
#define GENERIC_AUDIO_PROFILE_ID GENERIC_AUDIO_SVCLASS_ID
|
||||
#define GENERIC_TELEPHONY_PROFILE_ID GENERIC_TELEPHONY_SVCLASS_ID
|
||||
#define UPNP_PROFILE_ID UPNP_SVCLASS_ID
|
||||
#define UPNP_IP_PROFILE_ID UPNP_IP_SVCLASS_ID
|
||||
#define UPNP_PAN_PROFILE_ID UPNP_PAN_SVCLASS_ID
|
||||
#define UPNP_LAP_PROFILE_ID UPNP_LAP_SVCLASS_ID
|
||||
#define UPNP_L2CAP_PROFILE_ID UPNP_L2CAP_SVCLASS_ID
|
||||
#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID
|
||||
#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID
|
||||
#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID
|
||||
#define HDP_PROFILE_ID HDP_SVCLASS_ID
|
||||
#define HDP_SOURCE_PROFILE_ID HDP_SOURCE_SVCLASS_ID
|
||||
#define HDP_SINK_PROFILE_ID HDP_SINK_SVCLASS_ID
|
||||
#define GENERIC_ACCESS_PROFILE_ID GENERIC_ACCESS_SVCLASS_ID
|
||||
#define GENERIC_ATTRIB_PROFILE_ID GENERIC_ATTRIB_SVCLASS_ID
|
||||
#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID
|
||||
#define MPS_PROFILE_ID MPS_SC_SVCLASS_ID
|
||||
|
||||
/*
|
||||
* Compatibility macros for the old MDP acronym
|
||||
*/
|
||||
#define MDP_SVCLASS_ID HDP_SVCLASS_ID
|
||||
#define MDP_SOURCE_SVCLASS_ID HDP_SOURCE_SVCLASS_ID
|
||||
#define MDP_SINK_SVCLASS_ID HDP_SINK_SVCLASS_ID
|
||||
#define MDP_PROFILE_ID HDP_PROFILE_ID
|
||||
#define MDP_SOURCE_PROFILE_ID HDP_SOURCE_PROFILE_ID
|
||||
#define MDP_SINK_PROFILE_ID HDP_SINK_PROFILE_ID
|
||||
|
||||
/*
|
||||
* Attribute identifier codes
|
||||
*/
|
||||
#define SDP_SERVER_RECORD_HANDLE 0x0000
|
||||
|
||||
/*
|
||||
* Possible values for attribute-id are listed below.
|
||||
* See SDP Spec, section "Service Attribute Definitions" for more details.
|
||||
*/
|
||||
#define SDP_ATTR_RECORD_HANDLE 0x0000
|
||||
#define SDP_ATTR_SVCLASS_ID_LIST 0x0001
|
||||
#define SDP_ATTR_RECORD_STATE 0x0002
|
||||
#define SDP_ATTR_SERVICE_ID 0x0003
|
||||
#define SDP_ATTR_PROTO_DESC_LIST 0x0004
|
||||
#define SDP_ATTR_BROWSE_GRP_LIST 0x0005
|
||||
#define SDP_ATTR_LANG_BASE_ATTR_ID_LIST 0x0006
|
||||
#define SDP_ATTR_SVCINFO_TTL 0x0007
|
||||
#define SDP_ATTR_SERVICE_AVAILABILITY 0x0008
|
||||
#define SDP_ATTR_PFILE_DESC_LIST 0x0009
|
||||
#define SDP_ATTR_DOC_URL 0x000a
|
||||
#define SDP_ATTR_CLNT_EXEC_URL 0x000b
|
||||
#define SDP_ATTR_ICON_URL 0x000c
|
||||
#define SDP_ATTR_ADD_PROTO_DESC_LIST 0x000d
|
||||
|
||||
#define SDP_ATTR_GROUP_ID 0x0200
|
||||
#define SDP_ATTR_IP_SUBNET 0x0200
|
||||
#define SDP_ATTR_VERSION_NUM_LIST 0x0200
|
||||
#define SDP_ATTR_SUPPORTED_FEATURES_LIST 0x0200
|
||||
#define SDP_ATTR_GOEP_L2CAP_PSM 0x0200
|
||||
#define SDP_ATTR_SVCDB_STATE 0x0201
|
||||
|
||||
#define SDP_ATTR_MPSD_SCENARIOS 0x0200
|
||||
#define SDP_ATTR_MPMD_SCENARIOS 0x0201
|
||||
#define SDP_ATTR_MPS_DEPENDENCIES 0x0202
|
||||
|
||||
#define SDP_ATTR_SERVICE_VERSION 0x0300
|
||||
#define SDP_ATTR_EXTERNAL_NETWORK 0x0301
|
||||
#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301
|
||||
#define SDP_ATTR_DATA_EXCHANGE_SPEC 0x0301
|
||||
#define SDP_ATTR_NETWORK 0x0301
|
||||
#define SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302
|
||||
#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
|
||||
#define SDP_ATTR_MCAP_SUPPORTED_PROCEDURES 0x0302
|
||||
#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303
|
||||
#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303
|
||||
#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304
|
||||
#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305
|
||||
#define SDP_ATTR_NETWORK_ADDRESS 0x0306
|
||||
#define SDP_ATTR_WAP_GATEWAY 0x0307
|
||||
#define SDP_ATTR_HOMEPAGE_URL 0x0308
|
||||
#define SDP_ATTR_WAP_STACK_TYPE 0x0309
|
||||
#define SDP_ATTR_SECURITY_DESC 0x030a
|
||||
#define SDP_ATTR_NET_ACCESS_TYPE 0x030b
|
||||
#define SDP_ATTR_MAX_NET_ACCESSRATE 0x030c
|
||||
#define SDP_ATTR_IP4_SUBNET 0x030d
|
||||
#define SDP_ATTR_IP6_SUBNET 0x030e
|
||||
#define SDP_ATTR_SUPPORTED_CAPABILITIES 0x0310
|
||||
#define SDP_ATTR_SUPPORTED_FEATURES 0x0311
|
||||
#define SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312
|
||||
#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313
|
||||
#define SDP_ATTR_SUPPORTED_REPOSITORIES 0x0314
|
||||
#define SDP_ATTR_MAS_INSTANCE_ID 0x0315
|
||||
#define SDP_ATTR_SUPPORTED_MESSAGE_TYPES 0x0316
|
||||
#define SDP_ATTR_PBAP_SUPPORTED_FEATURES 0x0317
|
||||
#define SDP_ATTR_MAP_SUPPORTED_FEATURES 0x0317
|
||||
|
||||
#define SDP_ATTR_SPECIFICATION_ID 0x0200
|
||||
#define SDP_ATTR_VENDOR_ID 0x0201
|
||||
#define SDP_ATTR_PRODUCT_ID 0x0202
|
||||
#define SDP_ATTR_VERSION 0x0203
|
||||
#define SDP_ATTR_PRIMARY_RECORD 0x0204
|
||||
#define SDP_ATTR_VENDOR_ID_SOURCE 0x0205
|
||||
|
||||
#define SDP_ATTR_HID_DEVICE_RELEASE_NUMBER 0x0200
|
||||
#define SDP_ATTR_HID_PARSER_VERSION 0x0201
|
||||
#define SDP_ATTR_HID_DEVICE_SUBCLASS 0x0202
|
||||
#define SDP_ATTR_HID_COUNTRY_CODE 0x0203
|
||||
#define SDP_ATTR_HID_VIRTUAL_CABLE 0x0204
|
||||
#define SDP_ATTR_HID_RECONNECT_INITIATE 0x0205
|
||||
#define SDP_ATTR_HID_DESCRIPTOR_LIST 0x0206
|
||||
#define SDP_ATTR_HID_LANG_ID_BASE_LIST 0x0207
|
||||
#define SDP_ATTR_HID_SDP_DISABLE 0x0208
|
||||
#define SDP_ATTR_HID_BATTERY_POWER 0x0209
|
||||
#define SDP_ATTR_HID_REMOTE_WAKEUP 0x020a
|
||||
#define SDP_ATTR_HID_PROFILE_VERSION 0x020b
|
||||
#define SDP_ATTR_HID_SUPERVISION_TIMEOUT 0x020c
|
||||
#define SDP_ATTR_HID_NORMALLY_CONNECTABLE 0x020d
|
||||
#define SDP_ATTR_HID_BOOT_DEVICE 0x020e
|
||||
|
||||
/*
|
||||
* These identifiers are based on the SDP spec stating that
|
||||
* "base attribute id of the primary (universal) language must be 0x0100"
|
||||
*
|
||||
* Other languages should have their own offset; e.g.:
|
||||
* #define XXXLangBase yyyy
|
||||
* #define AttrServiceName_XXX 0x0000+XXXLangBase
|
||||
*/
|
||||
#define SDP_PRIMARY_LANG_BASE 0x0100
|
||||
|
||||
#define SDP_ATTR_SVCNAME_PRIMARY 0x0000 + SDP_PRIMARY_LANG_BASE
|
||||
#define SDP_ATTR_SVCDESC_PRIMARY 0x0001 + SDP_PRIMARY_LANG_BASE
|
||||
#define SDP_ATTR_PROVNAME_PRIMARY 0x0002 + SDP_PRIMARY_LANG_BASE
|
||||
|
||||
/*
|
||||
* The Data representation in SDP PDUs (pps 339, 340 of BT SDP Spec)
|
||||
* These are the exact data type+size descriptor values
|
||||
* that go into the PDU buffer.
|
||||
*
|
||||
* The datatype (leading 5bits) + size descriptor (last 3 bits)
|
||||
* is 8 bits. The size descriptor is critical to extract the
|
||||
* right number of bytes for the data value from the PDU.
|
||||
*
|
||||
* For most basic types, the datatype+size descriptor is
|
||||
* straightforward. However for constructed types and strings,
|
||||
* the size of the data is in the next "n" bytes following the
|
||||
* 8 bits (datatype+size) descriptor. Exactly what the "n" is
|
||||
* specified in the 3 bits of the data size descriptor.
|
||||
*
|
||||
* TextString and URLString can be of size 2^{8, 16, 32} bytes
|
||||
* DataSequence and DataSequenceAlternates can be of size 2^{8, 16, 32}
|
||||
* The size are computed post-facto in the API and are not known apriori
|
||||
*/
|
||||
#define SDP_DATA_NIL 0x00
|
||||
#define SDP_UINT8 0x08
|
||||
#define SDP_UINT16 0x09
|
||||
#define SDP_UINT32 0x0A
|
||||
#define SDP_UINT64 0x0B
|
||||
#define SDP_UINT128 0x0C
|
||||
#define SDP_INT8 0x10
|
||||
#define SDP_INT16 0x11
|
||||
#define SDP_INT32 0x12
|
||||
#define SDP_INT64 0x13
|
||||
#define SDP_INT128 0x14
|
||||
#define SDP_UUID_UNSPEC 0x18
|
||||
#define SDP_UUID16 0x19
|
||||
#define SDP_UUID32 0x1A
|
||||
#define SDP_UUID128 0x1C
|
||||
#define SDP_TEXT_STR_UNSPEC 0x20
|
||||
#define SDP_TEXT_STR8 0x25
|
||||
#define SDP_TEXT_STR16 0x26
|
||||
#define SDP_TEXT_STR32 0x27
|
||||
#define SDP_BOOL 0x28
|
||||
#define SDP_SEQ_UNSPEC 0x30
|
||||
#define SDP_SEQ8 0x35
|
||||
#define SDP_SEQ16 0x36
|
||||
#define SDP_SEQ32 0x37
|
||||
#define SDP_ALT_UNSPEC 0x38
|
||||
#define SDP_ALT8 0x3D
|
||||
#define SDP_ALT16 0x3E
|
||||
#define SDP_ALT32 0x3F
|
||||
#define SDP_URL_STR_UNSPEC 0x40
|
||||
#define SDP_URL_STR8 0x45
|
||||
#define SDP_URL_STR16 0x46
|
||||
#define SDP_URL_STR32 0x47
|
||||
|
||||
/*
|
||||
* The PDU identifiers of SDP packets between client and server
|
||||
*/
|
||||
#define SDP_ERROR_RSP 0x01
|
||||
#define SDP_SVC_SEARCH_REQ 0x02
|
||||
#define SDP_SVC_SEARCH_RSP 0x03
|
||||
#define SDP_SVC_ATTR_REQ 0x04
|
||||
#define SDP_SVC_ATTR_RSP 0x05
|
||||
#define SDP_SVC_SEARCH_ATTR_REQ 0x06
|
||||
#define SDP_SVC_SEARCH_ATTR_RSP 0x07
|
||||
|
||||
/*
|
||||
* Some additions to support service registration.
|
||||
* These are outside the scope of the Bluetooth specification
|
||||
*/
|
||||
#define SDP_SVC_REGISTER_REQ 0x75
|
||||
#define SDP_SVC_REGISTER_RSP 0x76
|
||||
#define SDP_SVC_UPDATE_REQ 0x77
|
||||
#define SDP_SVC_UPDATE_RSP 0x78
|
||||
#define SDP_SVC_REMOVE_REQ 0x79
|
||||
#define SDP_SVC_REMOVE_RSP 0x80
|
||||
|
||||
/*
|
||||
* SDP Error codes
|
||||
*/
|
||||
#define SDP_INVALID_VERSION 0x0001
|
||||
#define SDP_INVALID_RECORD_HANDLE 0x0002
|
||||
#define SDP_INVALID_SYNTAX 0x0003
|
||||
#define SDP_INVALID_PDU_SIZE 0x0004
|
||||
#define SDP_INVALID_CSTATE 0x0005
|
||||
|
||||
/*
|
||||
* SDP PDU
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t pdu_id;
|
||||
uint16_t tid;
|
||||
uint16_t plen;
|
||||
} __attribute__ ((packed)) sdp_pdu_hdr_t;
|
||||
|
||||
/*
|
||||
* Common definitions for attributes in the SDP.
|
||||
* Should the type of any of these change, you need only make a change here.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
union {
|
||||
uint16_t uuid16;
|
||||
uint32_t uuid32;
|
||||
uint128_t uuid128;
|
||||
} value;
|
||||
} uuid_t;
|
||||
|
||||
#define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || \
|
||||
(x) == SDP_UUID128)
|
||||
#define SDP_IS_ALT(x) ((x) == SDP_ALT8 || (x) == SDP_ALT16 || (x) == SDP_ALT32)
|
||||
#define SDP_IS_SEQ(x) ((x) == SDP_SEQ8 || (x) == SDP_SEQ16 || (x) == SDP_SEQ32)
|
||||
#define SDP_IS_TEXT_STR(x) ((x) == SDP_TEXT_STR8 || (x) == SDP_TEXT_STR16 || \
|
||||
(x) == SDP_TEXT_STR32)
|
||||
|
||||
typedef struct _sdp_list sdp_list_t;
|
||||
struct _sdp_list {
|
||||
sdp_list_t *next;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* User-visible strings can be in many languages
|
||||
* in addition to the universal language.
|
||||
*
|
||||
* Language meta-data includes language code in ISO639
|
||||
* followed by the encoding format. The third field in this
|
||||
* structure is the attribute offset for the language.
|
||||
* User-visible strings in the specified language can be
|
||||
* obtained at this offset.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t code_ISO639;
|
||||
uint16_t encoding;
|
||||
uint16_t base_offset;
|
||||
} sdp_lang_attr_t;
|
||||
|
||||
/*
|
||||
* Profile descriptor is the Bluetooth profile metadata. If a
|
||||
* service conforms to a well-known profile, then its profile
|
||||
* identifier (UUID) is an attribute of the service. In addition,
|
||||
* if the profile has a version number it is specified here.
|
||||
*/
|
||||
typedef struct {
|
||||
uuid_t uuid;
|
||||
uint16_t version;
|
||||
} sdp_profile_desc_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} sdp_version_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
uint32_t data_size;
|
||||
uint32_t buf_size;
|
||||
} sdp_buf_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t handle;
|
||||
|
||||
/* Search pattern: a sequence of all UUIDs seen in this record */
|
||||
sdp_list_t *pattern;
|
||||
sdp_list_t *attrlist;
|
||||
|
||||
/* Main service class for Extended Inquiry Response */
|
||||
uuid_t svclass;
|
||||
} sdp_record_t;
|
||||
|
||||
typedef struct sdp_data_struct sdp_data_t;
|
||||
struct sdp_data_struct {
|
||||
uint8_t dtd;
|
||||
uint16_t attrId;
|
||||
union {
|
||||
int8_t int8;
|
||||
int16_t int16;
|
||||
int32_t int32;
|
||||
int64_t int64;
|
||||
uint128_t int128;
|
||||
uint8_t uint8;
|
||||
uint16_t uint16;
|
||||
uint32_t uint32;
|
||||
uint64_t uint64;
|
||||
uint128_t uint128;
|
||||
uuid_t uuid;
|
||||
char *str;
|
||||
sdp_data_t *dataseq;
|
||||
} val;
|
||||
sdp_data_t *next;
|
||||
int unitSize;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SDP_H */
|
|
@ -0,0 +1,634 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2001-2002 Nokia Corporation
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SDP_LIB_H
|
||||
#define __SDP_LIB_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SDP lists
|
||||
*/
|
||||
typedef void(*sdp_list_func_t)(void *, void *);
|
||||
typedef void(*sdp_free_func_t)(void *);
|
||||
typedef int (*sdp_comp_func_t)(const void *, const void *);
|
||||
|
||||
sdp_list_t *sdp_list_append(sdp_list_t *list, void *d);
|
||||
sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d);
|
||||
sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *data, sdp_comp_func_t f);
|
||||
void sdp_list_free(sdp_list_t *list, sdp_free_func_t f);
|
||||
|
||||
static inline int sdp_list_len(const sdp_list_t *list)
|
||||
{
|
||||
int n = 0;
|
||||
for (; list; list = list->next)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline sdp_list_t *sdp_list_find(sdp_list_t *list, void *u, sdp_comp_func_t f)
|
||||
{
|
||||
for (; list; list = list->next)
|
||||
if (f(list->data, u) == 0)
|
||||
return list;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void sdp_list_foreach(sdp_list_t *list, sdp_list_func_t f, void *u)
|
||||
{
|
||||
for (; list; list = list->next)
|
||||
f(list->data, u);
|
||||
}
|
||||
|
||||
/*
|
||||
* Values of the flags parameter to sdp_record_register
|
||||
*/
|
||||
#define SDP_RECORD_PERSIST 0x01
|
||||
#define SDP_DEVICE_RECORD 0x02
|
||||
|
||||
/*
|
||||
* Values of the flags parameter to sdp_connect
|
||||
*/
|
||||
#define SDP_RETRY_IF_BUSY 0x01
|
||||
#define SDP_WAIT_ON_CLOSE 0x02
|
||||
#define SDP_NON_BLOCKING 0x04
|
||||
#define SDP_LARGE_MTU 0x08
|
||||
|
||||
/*
|
||||
* a session with an SDP server
|
||||
*/
|
||||
typedef struct {
|
||||
int sock;
|
||||
int state;
|
||||
int local;
|
||||
int flags;
|
||||
uint16_t tid; /* Current transaction ID */
|
||||
void *priv;
|
||||
} sdp_session_t;
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* Attributes are specified as individual elements
|
||||
*/
|
||||
SDP_ATTR_REQ_INDIVIDUAL = 1,
|
||||
/*
|
||||
* Attributes are specified as a range
|
||||
*/
|
||||
SDP_ATTR_REQ_RANGE
|
||||
} sdp_attrreq_type_t;
|
||||
|
||||
/*
|
||||
* When the pdu_id(type) is a sdp error response, check the status value
|
||||
* to figure out the error reason. For status values 0x0001-0x0006 check
|
||||
* Bluetooth SPEC. If the status is 0xffff, call sdp_get_error function
|
||||
* to get the real reason:
|
||||
* - wrong transaction ID(EPROTO)
|
||||
* - wrong PDU id or(EPROTO)
|
||||
* - I/O error
|
||||
*/
|
||||
typedef void sdp_callback_t(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *udata);
|
||||
|
||||
/*
|
||||
* create an L2CAP connection to a Bluetooth device
|
||||
*
|
||||
* INPUT:
|
||||
*
|
||||
* bdaddr_t *src:
|
||||
* Address of the local device to use to make the connection
|
||||
* (or BDADDR_ANY)
|
||||
*
|
||||
* bdaddr_t *dst:
|
||||
* Address of the SDP server device
|
||||
*/
|
||||
sdp_session_t *sdp_connect(const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags);
|
||||
int sdp_close(sdp_session_t *session);
|
||||
int sdp_get_socket(const sdp_session_t *session);
|
||||
|
||||
/*
|
||||
* SDP transaction: functions for asynchronous search.
|
||||
*/
|
||||
sdp_session_t *sdp_create(int sk, uint32_t flags);
|
||||
int sdp_get_error(sdp_session_t *session);
|
||||
int sdp_process(sdp_session_t *session);
|
||||
int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata);
|
||||
|
||||
int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num);
|
||||
int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
|
||||
int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
|
||||
|
||||
uint16_t sdp_gen_tid(sdp_session_t *session);
|
||||
|
||||
/*
|
||||
* find all devices in the piconet
|
||||
*/
|
||||
int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *found);
|
||||
|
||||
/* flexible extraction of basic attributes - Jean II */
|
||||
int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value);
|
||||
int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen);
|
||||
|
||||
/*
|
||||
* Basic sdp data functions
|
||||
*/
|
||||
sdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value);
|
||||
sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value, uint32_t length);
|
||||
void sdp_data_free(sdp_data_t *data);
|
||||
sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attr_id);
|
||||
|
||||
sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len);
|
||||
sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, int len);
|
||||
sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *data);
|
||||
|
||||
int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
|
||||
void sdp_attr_remove(sdp_record_t *rec, uint16_t attr);
|
||||
void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
|
||||
int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t attr, sdp_list_t *seq);
|
||||
int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp);
|
||||
|
||||
/*
|
||||
* NOTE that none of the functions below will update the SDP server,
|
||||
* unless the {register, update}sdp_record_t() function is invoked.
|
||||
* All functions which return an integer value, return 0 on success
|
||||
* or -1 on failure.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create an attribute and add it to the service record's attribute list.
|
||||
* This consists of the data type descriptor of the attribute,
|
||||
* the value of the attribute and the attribute identifier.
|
||||
*/
|
||||
int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *p);
|
||||
|
||||
/*
|
||||
* Set the information attributes of the service record.
|
||||
* The set of attributes comprises service name, description
|
||||
* and provider name
|
||||
*/
|
||||
void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc);
|
||||
|
||||
/*
|
||||
* Set the ServiceClassID attribute to the sequence specified by seq.
|
||||
* Note that the identifiers need to be in sorted order from the most
|
||||
* specific to the most generic service class that this service
|
||||
* conforms to.
|
||||
*/
|
||||
static inline int sdp_set_service_classes(sdp_record_t *rec, sdp_list_t *seq)
|
||||
{
|
||||
return sdp_set_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the service classes to which the service conforms.
|
||||
*
|
||||
* When set, the list contains elements of ServiceClassIdentifer(uint16_t)
|
||||
* ordered from most specific to most generic
|
||||
*/
|
||||
static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp)
|
||||
{
|
||||
return sdp_get_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seqp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the BrowseGroupList attribute to the list specified by seq.
|
||||
*
|
||||
* A service can belong to one or more service groups
|
||||
* and the list comprises such group identifiers (UUIDs)
|
||||
*/
|
||||
static inline int sdp_set_browse_groups(sdp_record_t *rec, sdp_list_t *seq)
|
||||
{
|
||||
return sdp_set_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the access protocols of the record to those specified in proto
|
||||
*/
|
||||
int sdp_set_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
|
||||
|
||||
/*
|
||||
* Set the additional access protocols of the record to those specified in proto
|
||||
*/
|
||||
int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
|
||||
|
||||
/*
|
||||
* Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)
|
||||
*/
|
||||
int sdp_get_proto_port(const sdp_list_t *list, int proto);
|
||||
|
||||
/*
|
||||
* Get protocol descriptor.
|
||||
*/
|
||||
sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto);
|
||||
|
||||
/*
|
||||
* Set the LanguageBase attributes to the values specified in list
|
||||
* (a linked list of sdp_lang_attr_t objects, one for each language in
|
||||
* which user-visible attributes are present).
|
||||
*/
|
||||
int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *list);
|
||||
|
||||
/*
|
||||
* Set the ServiceInfoTimeToLive attribute of the service.
|
||||
* This is the number of seconds that this record is guaranteed
|
||||
* not to change after being obtained by a client.
|
||||
*/
|
||||
static inline int sdp_set_service_ttl(sdp_record_t *rec, uint32_t ttl)
|
||||
{
|
||||
return sdp_attr_add_new(rec, SDP_ATTR_SVCINFO_TTL, SDP_UINT32, &ttl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the ServiceRecordState attribute of a service. This is
|
||||
* guaranteed to change if there is any kind of modification to
|
||||
* the record.
|
||||
*/
|
||||
static inline int sdp_set_record_state(sdp_record_t *rec, uint32_t state)
|
||||
{
|
||||
return sdp_attr_add_new(rec, SDP_ATTR_RECORD_STATE, SDP_UINT32, &state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the ServiceID attribute of a service.
|
||||
*/
|
||||
void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid);
|
||||
|
||||
/*
|
||||
* Set the GroupID attribute of a service
|
||||
*/
|
||||
void sdp_set_group_id(sdp_record_t *rec, uuid_t grouuuid);
|
||||
|
||||
/*
|
||||
* Set the ServiceAvailability attribute of a service.
|
||||
*
|
||||
* Note that this represents the relative availability
|
||||
* of the service: 0x00 means completely unavailable;
|
||||
* 0xFF means maximum availability.
|
||||
*/
|
||||
static inline int sdp_set_service_avail(sdp_record_t *rec, uint8_t avail)
|
||||
{
|
||||
return sdp_attr_add_new(rec, SDP_ATTR_SERVICE_AVAILABILITY, SDP_UINT8, &avail);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the profile descriptor list attribute of a record.
|
||||
*
|
||||
* Each element in the list is an object of type
|
||||
* sdp_profile_desc_t which is a definition of the
|
||||
* Bluetooth profile that this service conforms to.
|
||||
*/
|
||||
int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *desc);
|
||||
|
||||
/*
|
||||
* Set URL attributes of a record.
|
||||
*
|
||||
* ClientExecutableURL: a URL to a client's platform specific (WinCE,
|
||||
* PalmOS) executable code that can be used to access this service.
|
||||
*
|
||||
* DocumentationURL: a URL pointing to service documentation
|
||||
*
|
||||
* IconURL: a URL to an icon that can be used to represent this service.
|
||||
*
|
||||
* Note: pass NULL for any URLs that you don't want to set or remove
|
||||
*/
|
||||
void sdp_set_url_attr(sdp_record_t *rec, const char *clientExecURL, const char *docURL, const char *iconURL);
|
||||
|
||||
/*
|
||||
* a service search request.
|
||||
*
|
||||
* INPUT :
|
||||
*
|
||||
* sdp_list_t *search
|
||||
* list containing elements of the search
|
||||
* pattern. Each entry in the list is a UUID
|
||||
* of the service to be searched
|
||||
*
|
||||
* uint16_t max_rec_num
|
||||
* An integer specifying the maximum number of
|
||||
* entries that the client can handle in the response.
|
||||
*
|
||||
* OUTPUT :
|
||||
*
|
||||
* int return value
|
||||
* 0
|
||||
* The request completed successfully. This does not
|
||||
* mean the requested services were found
|
||||
* -1
|
||||
* The request completed unsuccessfully
|
||||
*
|
||||
* sdp_list_t *rsp_list
|
||||
* This variable is set on a successful return if there are
|
||||
* non-zero service handles. It is a singly linked list of
|
||||
* service record handles (uint16_t)
|
||||
*/
|
||||
int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list);
|
||||
|
||||
/*
|
||||
* a service attribute request.
|
||||
*
|
||||
* INPUT :
|
||||
*
|
||||
* uint32_t handle
|
||||
* The handle of the service for which the attribute(s) are
|
||||
* requested
|
||||
*
|
||||
* sdp_attrreq_type_t reqtype
|
||||
* Attribute identifiers are 16 bit unsigned integers specified
|
||||
* in one of 2 ways described below :
|
||||
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
|
||||
* They are the actual attribute identifiers in ascending order
|
||||
*
|
||||
* SDP_ATTR_REQ_RANGE - 32bit identifier range
|
||||
* The high-order 16bits is the start of range
|
||||
* the low-order 16bits are the end of range
|
||||
* 0x0000 to 0xFFFF gets all attributes
|
||||
*
|
||||
* sdp_list_t *attrid_list
|
||||
* Singly linked list containing attribute identifiers desired.
|
||||
* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
|
||||
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
|
||||
*
|
||||
* OUTPUT :
|
||||
* int return value
|
||||
* 0
|
||||
* The request completed successfully. This does not
|
||||
* mean the requested services were found
|
||||
* -1
|
||||
* The request completed unsuccessfully due to a timeout
|
||||
*/
|
||||
sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
|
||||
|
||||
/*
|
||||
* This is a service search request combined with the service
|
||||
* attribute request. First a service class match is done and
|
||||
* for matching service, requested attributes are extracted
|
||||
*
|
||||
* INPUT :
|
||||
*
|
||||
* sdp_list_t *search
|
||||
* Singly linked list containing elements of the search
|
||||
* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
|
||||
* of the service to be searched
|
||||
*
|
||||
* AttributeSpecification attrSpec
|
||||
* Attribute identifiers are 16 bit unsigned integers specified
|
||||
* in one of 2 ways described below :
|
||||
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
|
||||
* They are the actual attribute identifiers in ascending order
|
||||
*
|
||||
* SDP_ATTR_REQ_RANGE - 32bit identifier range
|
||||
* The high-order 16bits is the start of range
|
||||
* the low-order 16bits are the end of range
|
||||
* 0x0000 to 0xFFFF gets all attributes
|
||||
*
|
||||
* sdp_list_t *attrid_list
|
||||
* Singly linked list containing attribute identifiers desired.
|
||||
* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
|
||||
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
|
||||
*
|
||||
* OUTPUT :
|
||||
* int return value
|
||||
* 0
|
||||
* The request completed successfully. This does not
|
||||
* mean the requested services were found
|
||||
* -1
|
||||
* The request completed unsuccessfully due to a timeout
|
||||
*
|
||||
* sdp_list_t *rsp_list
|
||||
* This variable is set on a successful return to point to
|
||||
* service(s) found. Each element of this list is of type
|
||||
* sdp_record_t *.
|
||||
*/
|
||||
int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list);
|
||||
|
||||
/*
|
||||
* Allocate/free a service record and its attributes
|
||||
*/
|
||||
sdp_record_t *sdp_record_alloc(void);
|
||||
void sdp_record_free(sdp_record_t *rec);
|
||||
|
||||
/*
|
||||
* Register a service record.
|
||||
*
|
||||
* Note: It is the responsbility of the Service Provider to create the
|
||||
* record first and set its attributes using setXXX() methods.
|
||||
*
|
||||
* The service provider must then call sdp_record_register() to make
|
||||
* the service record visible to SDP clients. This function returns 0
|
||||
* on success or -1 on failure (and sets errno).
|
||||
*/
|
||||
int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device, uint8_t *data, uint32_t size, uint8_t flags, uint32_t *handle);
|
||||
int sdp_device_record_register(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec, uint8_t flags);
|
||||
int sdp_record_register(sdp_session_t *session, sdp_record_t *rec, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Unregister a service record.
|
||||
*/
|
||||
int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle);
|
||||
int sdp_device_record_unregister(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec);
|
||||
int sdp_record_unregister(sdp_session_t *session, sdp_record_t *rec);
|
||||
|
||||
/*
|
||||
* Update an existing service record. (Calling this function
|
||||
* before a previous call to sdp_record_register() will result
|
||||
* in an error.)
|
||||
*/
|
||||
int sdp_device_record_update_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle, uint8_t *data, uint32_t size);
|
||||
int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp_record_t *rec);
|
||||
int sdp_record_update(sdp_session_t *sess, const sdp_record_t *rec);
|
||||
|
||||
void sdp_record_print(const sdp_record_t *rec);
|
||||
|
||||
/*
|
||||
* UUID functions
|
||||
*/
|
||||
uuid_t *sdp_uuid16_create(uuid_t *uuid, uint16_t data);
|
||||
uuid_t *sdp_uuid32_create(uuid_t *uuid, uint32_t data);
|
||||
uuid_t *sdp_uuid128_create(uuid_t *uuid, const void *data);
|
||||
int sdp_uuid16_cmp(const void *p1, const void *p2);
|
||||
int sdp_uuid128_cmp(const void *p1, const void *p2);
|
||||
int sdp_uuid_cmp(const void *p1, const void *p2);
|
||||
uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid);
|
||||
void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16);
|
||||
void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32);
|
||||
int sdp_uuid128_to_uuid(uuid_t *uuid);
|
||||
int sdp_uuid_to_proto(uuid_t *uuid);
|
||||
int sdp_uuid_extract(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned);
|
||||
void sdp_uuid_print(const uuid_t *uuid);
|
||||
|
||||
#define MAX_LEN_UUID_STR 37
|
||||
#define MAX_LEN_PROTOCOL_UUID_STR 8
|
||||
#define MAX_LEN_SERVICECLASS_UUID_STR 28
|
||||
#define MAX_LEN_PROFILEDESCRIPTOR_UUID_STR 28
|
||||
|
||||
int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
|
||||
/*
|
||||
* In all the sdp_get_XXX(handle, XXX *xxx) functions below,
|
||||
* the XXX * is set to point to the value, should it exist
|
||||
* and 0 is returned. If the value does not exist, -1 is
|
||||
* returned and errno set to ENODATA.
|
||||
*
|
||||
* In all the methods below, the memory management rules are
|
||||
* simple. Don't free anything! The pointer returned, in the
|
||||
* case of constructed types, is a pointer to the contents
|
||||
* of the sdp_record_t.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the access protocols from the service record
|
||||
*/
|
||||
int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **protos);
|
||||
|
||||
/*
|
||||
* Get the additional access protocols from the service record
|
||||
*/
|
||||
int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **protos);
|
||||
|
||||
/*
|
||||
* Extract the list of browse groups to which the service belongs.
|
||||
* When set, seqp contains elements of GroupID (uint16_t)
|
||||
*/
|
||||
static inline int sdp_get_browse_groups(const sdp_record_t *rec, sdp_list_t **seqp)
|
||||
{
|
||||
return sdp_get_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seqp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract language attribute meta-data of the service record.
|
||||
* For each language in the service record, LangSeq has a struct of type
|
||||
* sdp_lang_attr_t.
|
||||
*/
|
||||
int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq);
|
||||
|
||||
/*
|
||||
* Extract the Bluetooth profile descriptor sequence from a record.
|
||||
* Each element in the list is of type sdp_profile_desc_t
|
||||
* which contains the UUID of the profile and its version number
|
||||
* (encoded as major and minor in the high-order 8bits
|
||||
* and low-order 8bits respectively of the uint16_t)
|
||||
*/
|
||||
int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDesc);
|
||||
|
||||
/*
|
||||
* Extract SDP server version numbers
|
||||
*
|
||||
* Note: that this is an attribute of the SDP server only and
|
||||
* contains a list of uint16_t each of which represent the
|
||||
* major and minor SDP version numbers supported by this server
|
||||
*/
|
||||
int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **pVnumList);
|
||||
|
||||
int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid);
|
||||
int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid);
|
||||
int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState);
|
||||
int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail);
|
||||
int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo);
|
||||
int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState);
|
||||
|
||||
static inline int sdp_get_service_name(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_SVCNAME_PRIMARY, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_service_desc(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_SVCDESC_PRIMARY, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_provider_name(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_PROVNAME_PRIMARY, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_doc_url(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_DOC_URL, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_clnt_exec_url(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_CLNT_EXEC_URL, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_icon_url(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the supported features
|
||||
* sf should be a list of list with each feature data
|
||||
* Returns 0 on success -1 on fail
|
||||
*/
|
||||
int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf);
|
||||
|
||||
/*
|
||||
* Get the supported features
|
||||
* seqp is set to a list of list with each feature data
|
||||
* Returns 0 on success, if an error occurred -1 is returned and errno is set
|
||||
*/
|
||||
int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp);
|
||||
|
||||
sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int bufsize, int *scanned);
|
||||
sdp_record_t *sdp_copy_record(sdp_record_t *rec);
|
||||
|
||||
void sdp_data_print(sdp_data_t *data);
|
||||
void sdp_print_service_attr(sdp_list_t *alist);
|
||||
|
||||
int sdp_attrid_comp_func(const void *key1, const void *key2);
|
||||
|
||||
void sdp_set_seq_len(uint8_t *ptr, uint32_t length);
|
||||
void sdp_set_attrid(sdp_buf_t *pdu, uint16_t id);
|
||||
void sdp_append_to_pdu(sdp_buf_t *dst, sdp_data_t *d);
|
||||
void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len);
|
||||
|
||||
int sdp_gen_pdu(sdp_buf_t *pdu, sdp_data_t *data);
|
||||
int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *pdu);
|
||||
|
||||
int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size);
|
||||
|
||||
sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int bufsize, int *extractedLength, sdp_record_t *rec);
|
||||
|
||||
void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid);
|
||||
void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq);
|
||||
|
||||
int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *req, uint8_t *rsp, uint32_t reqsize, uint32_t *rspsize);
|
||||
|
||||
void sdp_add_lang_attr(sdp_record_t *rec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SDP_LIB_H */
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib/bluetooth.h"
|
||||
#include "uuid.h"
|
||||
|
||||
static uint128_t bluetooth_base_uuid = {
|
||||
.data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
|
||||
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
|
||||
};
|
||||
|
||||
#define BASE_UUID16_OFFSET 2
|
||||
#define BASE_UUID32_OFFSET 0
|
||||
|
||||
static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
|
||||
{
|
||||
uint16_t be16;
|
||||
|
||||
dst->value.u128 = bluetooth_base_uuid;
|
||||
dst->type = BT_UUID128;
|
||||
|
||||
/*
|
||||
* No matter the system: 128-bit UUIDs should be stored
|
||||
* as big-endian. 16-bit UUIDs are stored on host order.
|
||||
*/
|
||||
|
||||
be16 = htons(src->value.u16);
|
||||
memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET], &be16, sizeof(be16));
|
||||
}
|
||||
|
||||
static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
|
||||
{
|
||||
uint32_t be32;
|
||||
|
||||
dst->value.u128 = bluetooth_base_uuid;
|
||||
dst->type = BT_UUID128;
|
||||
|
||||
/*
|
||||
* No matter the system: 128-bit UUIDs should be stored
|
||||
* as big-endian. 32-bit UUIDs are stored on host order.
|
||||
*/
|
||||
|
||||
be32 = htonl(src->value.u32);
|
||||
memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET], &be32, sizeof(be32));
|
||||
}
|
||||
|
||||
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
|
||||
{
|
||||
switch (src->type) {
|
||||
case BT_UUID128:
|
||||
*dst = *src;
|
||||
break;
|
||||
case BT_UUID32:
|
||||
bt_uuid32_to_uuid128(src, dst);
|
||||
break;
|
||||
case BT_UUID16:
|
||||
bt_uuid16_to_uuid128(src, dst);
|
||||
break;
|
||||
case BT_UUID_UNSPEC:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
|
||||
{
|
||||
return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
|
||||
}
|
||||
|
||||
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
|
||||
{
|
||||
memset(btuuid, 0, sizeof(bt_uuid_t));
|
||||
btuuid->type = BT_UUID16;
|
||||
btuuid->value.u16 = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
|
||||
{
|
||||
memset(btuuid, 0, sizeof(bt_uuid_t));
|
||||
btuuid->type = BT_UUID32;
|
||||
btuuid->value.u32 = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
|
||||
{
|
||||
memset(btuuid, 0, sizeof(bt_uuid_t));
|
||||
btuuid->type = BT_UUID128;
|
||||
btuuid->value.u128 = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
|
||||
{
|
||||
bt_uuid_t u1, u2;
|
||||
|
||||
bt_uuid_to_uuid128(uuid1, &u1);
|
||||
bt_uuid_to_uuid128(uuid2, &u2);
|
||||
|
||||
return bt_uuid128_cmp(&u1, &u2);
|
||||
}
|
||||
|
||||
/*
|
||||
* convert the UUID to string, copying a maximum of n characters.
|
||||
*/
|
||||
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
|
||||
{
|
||||
bt_uuid_t tmp;
|
||||
unsigned int data0;
|
||||
unsigned short data1;
|
||||
unsigned short data2;
|
||||
unsigned short data3;
|
||||
unsigned int data4;
|
||||
unsigned short data5;
|
||||
const uint8_t *data;
|
||||
|
||||
if (!uuid || uuid->type == BT_UUID_UNSPEC) {
|
||||
snprintf(str, n, "NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Convert to 128 Bit format */
|
||||
bt_uuid_to_uuid128(uuid, &tmp);
|
||||
data = (uint8_t *) &tmp.value.u128;
|
||||
|
||||
memcpy(&data0, &data[0], 4);
|
||||
memcpy(&data1, &data[4], 2);
|
||||
memcpy(&data2, &data[6], 2);
|
||||
memcpy(&data3, &data[8], 2);
|
||||
memcpy(&data4, &data[10], 4);
|
||||
memcpy(&data5, &data[14], 2);
|
||||
|
||||
snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
|
||||
ntohl(data0), ntohs(data1),
|
||||
ntohs(data2), ntohs(data3),
|
||||
ntohl(data4), ntohs(data5));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int is_uuid128(const char *string)
|
||||
{
|
||||
return (strlen(string) == 36 &&
|
||||
string[8] == '-' &&
|
||||
string[13] == '-' &&
|
||||
string[18] == '-' &&
|
||||
string[23] == '-');
|
||||
}
|
||||
|
||||
static inline int is_base_uuid128(const char *string)
|
||||
{
|
||||
uint16_t uuid;
|
||||
char dummy[2];
|
||||
|
||||
if (!is_uuid128(string))
|
||||
return 0;
|
||||
|
||||
return sscanf(string,
|
||||
"0000%04hx-0000-1000-8000-00805%1[fF]9%1[bB]34%1[fF]%1[bB]",
|
||||
&uuid, dummy, dummy, dummy, dummy) == 5;
|
||||
}
|
||||
|
||||
static inline int is_uuid32(const char *string)
|
||||
{
|
||||
return (strlen(string) == 8 || strlen(string) == 10);
|
||||
}
|
||||
|
||||
static inline int is_uuid16(const char *string)
|
||||
{
|
||||
return (strlen(string) == 4 || strlen(string) == 6);
|
||||
}
|
||||
|
||||
static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string)
|
||||
{
|
||||
uint16_t u16;
|
||||
char *endptr = NULL;
|
||||
|
||||
u16 = strtol(string, &endptr, 16);
|
||||
if (endptr && (*endptr == '\0' || *endptr == '-')) {
|
||||
bt_uuid16_create(uuid, u16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string)
|
||||
{
|
||||
uint32_t u32;
|
||||
char *endptr = NULL;
|
||||
|
||||
u32 = strtol(string, &endptr, 16);
|
||||
if (endptr && *endptr == '\0') {
|
||||
bt_uuid32_create(uuid, u32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string)
|
||||
{
|
||||
uint32_t data0, data4;
|
||||
uint16_t data1, data2, data3, data5;
|
||||
uint128_t u128;
|
||||
uint8_t *val = (uint8_t *) &u128;
|
||||
|
||||
if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
|
||||
&data0, &data1, &data2,
|
||||
&data3, &data4, &data5) != 6)
|
||||
return -EINVAL;
|
||||
|
||||
data0 = htonl(data0);
|
||||
data1 = htons(data1);
|
||||
data2 = htons(data2);
|
||||
data3 = htons(data3);
|
||||
data4 = htonl(data4);
|
||||
data5 = htons(data5);
|
||||
|
||||
memcpy(&val[0], &data0, 4);
|
||||
memcpy(&val[4], &data1, 2);
|
||||
memcpy(&val[6], &data2, 2);
|
||||
memcpy(&val[8], &data3, 2);
|
||||
memcpy(&val[10], &data4, 4);
|
||||
memcpy(&val[14], &data5, 2);
|
||||
|
||||
bt_uuid128_create(uuid, u128);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
|
||||
{
|
||||
if (is_base_uuid128(string))
|
||||
return bt_string_to_uuid16(uuid, string + 4);
|
||||
else if (is_uuid128(string))
|
||||
return bt_string_to_uuid128(uuid, string);
|
||||
else if (is_uuid32(string))
|
||||
return bt_string_to_uuid32(uuid, string);
|
||||
else if (is_uuid16(string))
|
||||
return bt_string_to_uuid16(uuid, string);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int bt_uuid_strcmp(const void *a, const void *b)
|
||||
{
|
||||
bt_uuid_t u1, u2;
|
||||
|
||||
if (bt_string_to_uuid(&u1, a) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (bt_string_to_uuid(&u2, b) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return bt_uuid_cmp(&u1, &u2);
|
||||
}
|
||||
|
||||
int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
|
||||
{
|
||||
bt_uuid_t uuid;
|
||||
|
||||
switch (src->type) {
|
||||
case BT_UUID16:
|
||||
bt_put_le16(src->value.u16, dst);
|
||||
return 0;
|
||||
case BT_UUID32:
|
||||
bt_uuid32_to_uuid128(src, &uuid);
|
||||
src = &uuid;
|
||||
/* Fallthrough */
|
||||
case BT_UUID128:
|
||||
/* Convert from 128-bit BE to LE */
|
||||
bswap_128(&src->value.u128, dst);
|
||||
return 0;
|
||||
case BT_UUID_UNSPEC:
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BLUETOOTH_UUID_H
|
||||
#define __BLUETOOTH_UUID_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb"
|
||||
#define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb"
|
||||
#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb"
|
||||
#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define AVRCP_REMOTE_UUID "0000110e-0000-1000-8000-00805f9b34fb"
|
||||
#define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb"
|
||||
#define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
|
||||
#define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
|
||||
#define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb"
|
||||
#define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb"
|
||||
#define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb"
|
||||
#define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb"
|
||||
#define TX_POWER_UUID "00001804-0000-1000-8000-00805f9b34fb"
|
||||
#define BATTERY_UUID "0000180f-0000-1000-8000-00805f9b34fb"
|
||||
#define SCAN_PARAMETERS_UUID "00001813-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
|
||||
#define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb"
|
||||
#define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb"
|
||||
#define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb"
|
||||
#define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb"
|
||||
#define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb"
|
||||
#define INTERMEDIATE_TEMPERATURE_UUID "00002a1e-0000-1000-8000-00805f9b34fb"
|
||||
#define MEASUREMENT_INTERVAL_UUID "00002a21-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define CYCLING_SC_UUID "00001816-0000-1000-8000-00805f9b34fb"
|
||||
#define CSC_MEASUREMENT_UUID "00002a5b-0000-1000-8000-00805f9b34fb"
|
||||
#define CSC_FEATURE_UUID "00002a5c-0000-1000-8000-00805f9b34fb"
|
||||
#define SENSOR_LOCATION_UUID "00002a5d-0000-1000-8000-00805f9b34fb"
|
||||
#define SC_CONTROL_POINT_UUID "00002a55-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HDP_UUID "00001400-0000-1000-8000-00805f9b34fb"
|
||||
#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805f9b34fb"
|
||||
#define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define GAP_UUID "00001800-0000-1000-8000-00805f9b34fb"
|
||||
#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define OBEX_SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_PSE_UUID "0000112f-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_PBAP_UUID "00001130-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
/* GATT UUIDs section */
|
||||
#define GATT_PRIM_SVC_UUID 0x2800
|
||||
#define GATT_SND_SVC_UUID 0x2801
|
||||
#define GATT_INCLUDE_UUID 0x2802
|
||||
#define GATT_CHARAC_UUID 0x2803
|
||||
|
||||
/* GATT Characteristic Types */
|
||||
#define GATT_CHARAC_DEVICE_NAME 0x2A00
|
||||
#define GATT_CHARAC_APPEARANCE 0x2A01
|
||||
#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
|
||||
#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
|
||||
#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
|
||||
#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
|
||||
#define GATT_CHARAC_SYSTEM_ID 0x2A23
|
||||
#define GATT_CHARAC_MODEL_NUMBER_STRING 0x2A24
|
||||
#define GATT_CHARAC_SERIAL_NUMBER_STRING 0x2A25
|
||||
#define GATT_CHARAC_FIRMWARE_REVISION_STRING 0x2A26
|
||||
#define GATT_CHARAC_HARDWARE_REVISION_STRING 0x2A27
|
||||
#define GATT_CHARAC_SOFTWARE_REVISION_STRING 0x2A28
|
||||
#define GATT_CHARAC_MANUFACTURER_NAME_STRING 0x2A29
|
||||
#define GATT_CHARAC_PNP_ID 0x2A50
|
||||
|
||||
/* GATT Characteristic Descriptors */
|
||||
#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
|
||||
#define GATT_CHARAC_USER_DESC_UUID 0x2901
|
||||
#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
|
||||
#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
|
||||
#define GATT_CHARAC_FMT_UUID 0x2904
|
||||
#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
|
||||
#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
|
||||
#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
|
||||
#define GATT_REPORT_REFERENCE 0x2908
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
BT_UUID_UNSPEC = 0,
|
||||
BT_UUID16 = 16,
|
||||
BT_UUID32 = 32,
|
||||
BT_UUID128 = 128,
|
||||
} type;
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint128_t u128;
|
||||
} value;
|
||||
} bt_uuid_t;
|
||||
|
||||
int bt_uuid_strcmp(const void *a, const void *b);
|
||||
|
||||
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value);
|
||||
int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value);
|
||||
int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value);
|
||||
|
||||
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2);
|
||||
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
|
||||
|
||||
#define MAX_LEN_UUID_STR 37
|
||||
|
||||
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
|
||||
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
|
||||
|
||||
int bt_uuid_to_le(const bt_uuid_t *uuid, void *dst);
|
||||
|
||||
static inline int bt_uuid_len(const bt_uuid_t *uuid)
|
||||
{
|
||||
return uuid->type / 8;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BLUETOOTH_UUID_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,199 @@
|
|||
#ifndef __UHID_H_
|
||||
#define __UHID_H_
|
||||
|
||||
/*
|
||||
* User-space I/O driver support for HID subsystem
|
||||
* Copyright (c) 2012 David Herrmann
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Public header for user-space communication. We try to keep every structure
|
||||
* aligned but to be safe we also use __attribute__((__packed__)). Therefore,
|
||||
* the communication should be ABI compatible even between architectures.
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
enum uhid_event_type {
|
||||
__UHID_LEGACY_CREATE,
|
||||
UHID_DESTROY,
|
||||
UHID_START,
|
||||
UHID_STOP,
|
||||
UHID_OPEN,
|
||||
UHID_CLOSE,
|
||||
UHID_OUTPUT,
|
||||
__UHID_LEGACY_OUTPUT_EV,
|
||||
__UHID_LEGACY_INPUT,
|
||||
UHID_GET_REPORT,
|
||||
UHID_GET_REPORT_REPLY,
|
||||
UHID_CREATE2,
|
||||
UHID_INPUT2,
|
||||
UHID_SET_REPORT,
|
||||
UHID_SET_REPORT_REPLY,
|
||||
};
|
||||
|
||||
struct uhid_create2_req {
|
||||
__u8 name[128];
|
||||
__u8 phys[64];
|
||||
__u8 uniq[64];
|
||||
__u16 rd_size;
|
||||
__u16 bus;
|
||||
__u32 vendor;
|
||||
__u32 product;
|
||||
__u32 version;
|
||||
__u32 country;
|
||||
__u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
enum uhid_dev_flag {
|
||||
UHID_DEV_NUMBERED_FEATURE_REPORTS = (1ULL << 0),
|
||||
UHID_DEV_NUMBERED_OUTPUT_REPORTS = (1ULL << 1),
|
||||
UHID_DEV_NUMBERED_INPUT_REPORTS = (1ULL << 2),
|
||||
};
|
||||
|
||||
struct uhid_start_req {
|
||||
__u64 dev_flags;
|
||||
};
|
||||
|
||||
#define UHID_DATA_MAX 4096
|
||||
|
||||
enum uhid_report_type {
|
||||
UHID_FEATURE_REPORT,
|
||||
UHID_OUTPUT_REPORT,
|
||||
UHID_INPUT_REPORT,
|
||||
};
|
||||
|
||||
struct uhid_input2_req {
|
||||
__u16 size;
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_output_req {
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
__u16 size;
|
||||
__u8 rtype;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_get_report_req {
|
||||
__u32 id;
|
||||
__u8 rnum;
|
||||
__u8 rtype;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_get_report_reply_req {
|
||||
__u32 id;
|
||||
__u16 err;
|
||||
__u16 size;
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_set_report_req {
|
||||
__u32 id;
|
||||
__u8 rnum;
|
||||
__u8 rtype;
|
||||
__u16 size;
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_set_report_reply_req {
|
||||
__u32 id;
|
||||
__u16 err;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/*
|
||||
* Compat Layer
|
||||
* All these commands and requests are obsolete. You should avoid using them in
|
||||
* new code. We support them for backwards-compatibility, but you might not get
|
||||
* access to new feature in case you use them.
|
||||
*/
|
||||
|
||||
enum uhid_legacy_event_type {
|
||||
UHID_CREATE = __UHID_LEGACY_CREATE,
|
||||
UHID_OUTPUT_EV = __UHID_LEGACY_OUTPUT_EV,
|
||||
UHID_INPUT = __UHID_LEGACY_INPUT,
|
||||
UHID_FEATURE = UHID_GET_REPORT,
|
||||
UHID_FEATURE_ANSWER = UHID_GET_REPORT_REPLY,
|
||||
};
|
||||
|
||||
/* Obsolete! Use UHID_CREATE2. */
|
||||
struct uhid_create_req {
|
||||
__u8 name[128];
|
||||
__u8 phys[64];
|
||||
__u8 uniq[64];
|
||||
__u8 *rd_data;
|
||||
__u16 rd_size;
|
||||
|
||||
__u16 bus;
|
||||
__u32 vendor;
|
||||
__u32 product;
|
||||
__u32 version;
|
||||
__u32 country;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Obsolete! Use UHID_INPUT2. */
|
||||
struct uhid_input_req {
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
__u16 size;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Obsolete! Kernel uses UHID_OUTPUT exclusively now. */
|
||||
struct uhid_output_ev_req {
|
||||
__u16 type;
|
||||
__u16 code;
|
||||
__s32 value;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Obsolete! Kernel uses ABI compatible UHID_GET_REPORT. */
|
||||
struct uhid_feature_req {
|
||||
__u32 id;
|
||||
__u8 rnum;
|
||||
__u8 rtype;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Obsolete! Use ABI compatible UHID_GET_REPORT_REPLY. */
|
||||
struct uhid_feature_answer_req {
|
||||
__u32 id;
|
||||
__u16 err;
|
||||
__u16 size;
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/*
|
||||
* UHID Events
|
||||
* All UHID events from and to the kernel are encoded as "struct uhid_event".
|
||||
* The "type" field contains a UHID_* type identifier. All payload depends on
|
||||
* that type and can be accessed via ev->u.XYZ accordingly.
|
||||
* If user-space writes short events, they're extended with 0s by the kernel. If
|
||||
* the kernel writes short events, user-space shall extend them with 0s.
|
||||
*/
|
||||
|
||||
struct uhid_event {
|
||||
__u32 type;
|
||||
|
||||
union {
|
||||
struct uhid_create_req create;
|
||||
struct uhid_input_req input;
|
||||
struct uhid_output_req output;
|
||||
struct uhid_output_ev_req output_ev;
|
||||
struct uhid_feature_req feature;
|
||||
struct uhid_get_report_req get_report;
|
||||
struct uhid_feature_answer_req feature_answer;
|
||||
struct uhid_get_report_reply_req get_report_reply;
|
||||
struct uhid_create2_req create2;
|
||||
struct uhid_input2_req input2;
|
||||
struct uhid_set_report_req set_report;
|
||||
struct uhid_set_report_reply_req set_report_reply;
|
||||
struct uhid_start_req start;
|
||||
} u;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#endif /* __UHID_H_ */
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "lib/sdp.h"
|
||||
|
||||
#define EIR_FLAGS 0x01 /* flags */
|
||||
#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
|
||||
#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
|
||||
#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
|
||||
#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
|
||||
#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
|
||||
#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
|
||||
#define EIR_NAME_SHORT 0x08 /* shortened local name */
|
||||
#define EIR_NAME_COMPLETE 0x09 /* complete local name */
|
||||
#define EIR_TX_POWER 0x0A /* transmit power level */
|
||||
#define EIR_CLASS_OF_DEV 0x0D /* Class of Device */
|
||||
#define EIR_SSP_HASH 0x0E /* SSP Hash */
|
||||
#define EIR_SSP_RANDOMIZER 0x0F /* SSP Randomizer */
|
||||
#define EIR_DEVICE_ID 0x10 /* device ID */
|
||||
#define EIR_SOLICIT16 0x14 /* LE: Solicit UUIDs, 16-bit */
|
||||
#define EIR_SOLICIT128 0x15 /* LE: Solicit UUIDs, 128-bit */
|
||||
#define EIR_SVC_DATA16 0x16 /* LE: Service data, 16-bit UUID */
|
||||
#define EIR_PUB_TRGT_ADDR 0x17 /* LE: Public Target Address */
|
||||
#define EIR_RND_TRGT_ADDR 0x18 /* LE: Random Target Address */
|
||||
#define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */
|
||||
#define EIR_SOLICIT32 0x1F /* LE: Solicit UUIDs, 32-bit */
|
||||
#define EIR_SVC_DATA32 0x20 /* LE: Service data, 32-bit UUID */
|
||||
#define EIR_SVC_DATA128 0x21 /* LE: Service data, 128-bit UUID */
|
||||
#define EIR_MANUFACTURER_DATA 0xFF /* Manufacturer Specific Data */
|
||||
|
||||
/* Flags Descriptions */
|
||||
#define EIR_LIM_DISC 0x01 /* LE Limited Discoverable Mode */
|
||||
#define EIR_GEN_DISC 0x02 /* LE General Discoverable Mode */
|
||||
#define EIR_BREDR_UNSUP 0x04 /* BR/EDR Not Supported */
|
||||
#define EIR_CONTROLLER 0x08 /* Simultaneous LE and BR/EDR to Same
|
||||
Device Capable (Controller) */
|
||||
#define EIR_SIM_HOST 0x10 /* Simultaneous LE and BR/EDR to Same
|
||||
Device Capable (Host) */
|
||||
|
||||
#define EIR_SD_MAX_LEN 238 /* 240 (EIR) - 2 (len) */
|
||||
#define EIR_MSD_MAX_LEN 236 /* 240 (EIR) - 2 (len & type) - 2 */
|
||||
|
||||
struct eir_msd {
|
||||
uint16_t company;
|
||||
uint8_t data[EIR_MSD_MAX_LEN];
|
||||
uint8_t data_len;
|
||||
};
|
||||
|
||||
struct eir_sd {
|
||||
char *uuid;
|
||||
uint8_t data[EIR_SD_MAX_LEN];
|
||||
uint8_t data_len;
|
||||
};
|
||||
|
||||
struct eir_data {
|
||||
GSList *services;
|
||||
unsigned int flags;
|
||||
char *name;
|
||||
uint32_t class;
|
||||
uint16_t appearance;
|
||||
bool name_complete;
|
||||
int8_t tx_power;
|
||||
uint8_t *hash;
|
||||
uint8_t *randomizer;
|
||||
bdaddr_t addr;
|
||||
uint16_t did_vendor;
|
||||
uint16_t did_product;
|
||||
uint16_t did_version;
|
||||
uint16_t did_source;
|
||||
GSList *msd_list;
|
||||
GSList *sd_list;
|
||||
};
|
||||
|
||||
void eir_data_free(struct eir_data *eir);
|
||||
void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len);
|
||||
int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len);
|
||||
int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod,
|
||||
const uint8_t *hash, const uint8_t *randomizer,
|
||||
uint16_t did_vendor, uint16_t did_product,
|
||||
uint16_t did_version, uint16_t did_source,
|
||||
sdp_list_t *uuids, uint8_t *data);
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "lib/bluetooth.h"
|
||||
#include "lib/hci.h"
|
||||
|
||||
#include "src/shared/util.h"
|
||||
#include "log.h"
|
||||
|
||||
#define LOG_IDENT "bluetoothd"
|
||||
#define LOG_IDENT_LEN sizeof(LOG_IDENT)
|
||||
|
||||
struct log_hdr {
|
||||
uint16_t opcode;
|
||||
uint16_t index;
|
||||
uint16_t len;
|
||||
uint8_t priority;
|
||||
uint8_t ident_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
static int logging_fd = -1;
|
||||
|
||||
static void logging_open(void)
|
||||
{
|
||||
struct sockaddr_hci addr;
|
||||
int fd;
|
||||
|
||||
if (logging_fd >= 0)
|
||||
return;
|
||||
|
||||
fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = HCI_DEV_NONE;
|
||||
addr.hci_channel = HCI_CHANNEL_LOGGING;
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
logging_fd = fd;
|
||||
}
|
||||
|
||||
static void logging_close(void)
|
||||
{
|
||||
if (logging_fd >= 0) {
|
||||
close(logging_fd);
|
||||
logging_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void logging_log(uint16_t index, int priority,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
struct log_hdr hdr;
|
||||
struct msghdr msg;
|
||||
struct iovec iov[3];
|
||||
uint16_t len;
|
||||
char *str;
|
||||
|
||||
if (vasprintf(&str, format, ap) < 0)
|
||||
return;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
|
||||
hdr.opcode = cpu_to_le16(0x0000);
|
||||
hdr.index = cpu_to_le16(index);
|
||||
hdr.len = cpu_to_le16(2 + LOG_IDENT_LEN + len);
|
||||
hdr.priority = priority;
|
||||
hdr.ident_len = LOG_IDENT_LEN;
|
||||
|
||||
iov[0].iov_base = &hdr;
|
||||
iov[0].iov_len = sizeof(hdr);
|
||||
|
||||
iov[1].iov_base = LOG_IDENT;
|
||||
iov[1].iov_len = LOG_IDENT_LEN;
|
||||
|
||||
iov[2].iov_base = str;
|
||||
iov[2].iov_len = len;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 3;
|
||||
|
||||
if (sendmsg(logging_fd, &msg, 0) < 0) {
|
||||
if (errno != ENODEV) {
|
||||
close(logging_fd);
|
||||
logging_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(str);
|
||||
}
|
||||
|
||||
void error(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_ERR, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(HCI_DEV_NONE, LOG_ERR, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void warn(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_WARNING, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(HCI_DEV_NONE, LOG_WARNING, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void info(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_INFO, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(HCI_DEV_NONE, LOG_INFO, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void btd_log(uint16_t index, int priority, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(index, priority, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void btd_error(uint16_t index, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_ERR, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(index, LOG_ERR, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void btd_warn(uint16_t index, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_WARNING, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(index, LOG_WARNING, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void btd_info(uint16_t index, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_INFO, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(index, LOG_INFO, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void btd_debug(uint16_t index, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsyslog(LOG_DEBUG, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (logging_fd < 0)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
logging_log(index, LOG_DEBUG, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
extern struct btd_debug_desc __start___debug[];
|
||||
extern struct btd_debug_desc __stop___debug[];
|
||||
|
||||
static char **enabled = NULL;
|
||||
|
||||
static gboolean is_enabled(struct btd_debug_desc *desc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (enabled == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; enabled[i] != NULL; i++)
|
||||
if (desc->file != NULL && g_pattern_match_simple(enabled[i],
|
||||
desc->file) == TRUE)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __btd_enable_debug(struct btd_debug_desc *start,
|
||||
struct btd_debug_desc *stop)
|
||||
{
|
||||
struct btd_debug_desc *desc;
|
||||
|
||||
if (start == NULL || stop == NULL)
|
||||
return;
|
||||
|
||||
for (desc = start; desc < stop; desc++) {
|
||||
if (is_enabled(desc))
|
||||
desc->flags |= BTD_DEBUG_FLAG_PRINT;
|
||||
}
|
||||
}
|
||||
|
||||
void __btd_toggle_debug(void)
|
||||
{
|
||||
struct btd_debug_desc *desc;
|
||||
|
||||
for (desc = __start___debug; desc < __stop___debug; desc++)
|
||||
desc->flags |= BTD_DEBUG_FLAG_PRINT;
|
||||
}
|
||||
|
||||
void __btd_log_init(const char *debug, int detach)
|
||||
{
|
||||
int option = LOG_NDELAY | LOG_PID;
|
||||
|
||||
if (debug != NULL)
|
||||
enabled = g_strsplit_set(debug, ":, ", 0);
|
||||
|
||||
__btd_enable_debug(__start___debug, __stop___debug);
|
||||
|
||||
logging_open();
|
||||
|
||||
if (!detach)
|
||||
option |= LOG_PERROR;
|
||||
|
||||
openlog(LOG_IDENT, option, LOG_DAEMON);
|
||||
|
||||
info("Bluetooth daemon %d.%d", BLUEZ_VERSION_MAJOR, BLUEZ_VERSION_MINOR);
|
||||
}
|
||||
|
||||
void __btd_log_cleanup(void)
|
||||
{
|
||||
closelog();
|
||||
|
||||
logging_close();
|
||||
|
||||
g_strfreev(enabled);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
void warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
void btd_log(uint16_t index, int priority, const char *format, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
void btd_error(uint16_t index, const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void btd_warn(uint16_t index, const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void btd_info(uint16_t index, const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void btd_debug(uint16_t index, const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
void __btd_log_init(const char *debug, int detach);
|
||||
void __btd_log_cleanup(void);
|
||||
void __btd_toggle_debug(void);
|
||||
|
||||
struct btd_debug_desc {
|
||||
const char *file;
|
||||
#define BTD_DEBUG_FLAG_DEFAULT (0)
|
||||
#define BTD_DEBUG_FLAG_PRINT (1 << 0)
|
||||
unsigned int flags;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
void __btd_enable_debug(struct btd_debug_desc *start,
|
||||
struct btd_debug_desc *stop);
|
||||
|
||||
/**
|
||||
* DBG:
|
||||
* @fmt: format string
|
||||
* @arg...: list of arguments
|
||||
*
|
||||
* Simple macro around btd_debug() which also include the function
|
||||
* name it is called in.
|
||||
*/
|
||||
#define DBG_IDX(idx, fmt, arg...) do { \
|
||||
static struct btd_debug_desc __btd_debug_desc \
|
||||
__attribute__((used, section("__debug"), aligned(8))) = { \
|
||||
.file = __FILE__, .flags = BTD_DEBUG_FLAG_DEFAULT, \
|
||||
}; \
|
||||
if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \
|
||||
btd_debug(idx, "%s:%s() " fmt, __FILE__, __func__ , ## arg); \
|
||||
} while (0)
|
||||
|
||||
#define DBG(fmt, arg...) DBG_IDX(0xffff, fmt, ## arg)
|
|
@ -0,0 +1,658 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2015 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "src/shared/ad.h"
|
||||
|
||||
#include "src/eir.h"
|
||||
#include "src/shared/queue.h"
|
||||
#include "src/shared/util.h"
|
||||
|
||||
#define MAX_ADV_DATA_LEN 31
|
||||
|
||||
struct bt_ad {
|
||||
int ref_count;
|
||||
struct queue *service_uuids;
|
||||
struct queue *manufacturer_data;
|
||||
struct queue *solicit_uuids;
|
||||
struct queue *service_data;
|
||||
};
|
||||
|
||||
struct bt_ad *bt_ad_new(void)
|
||||
{
|
||||
struct bt_ad *ad;
|
||||
|
||||
ad = new0(struct bt_ad, 1);
|
||||
ad->service_uuids = queue_new();
|
||||
ad->manufacturer_data = queue_new();
|
||||
ad->solicit_uuids = queue_new();
|
||||
ad->service_data = queue_new();
|
||||
|
||||
return bt_ad_ref(ad);
|
||||
}
|
||||
|
||||
struct bt_ad *bt_ad_ref(struct bt_ad *ad)
|
||||
{
|
||||
if (!ad)
|
||||
return NULL;
|
||||
|
||||
ad->ref_count++;
|
||||
return ad;
|
||||
}
|
||||
|
||||
static void uuid_destroy(void *data)
|
||||
{
|
||||
struct bt_ad_service_data *uuid_data = data;
|
||||
|
||||
free(uuid_data->data);
|
||||
free(uuid_data);
|
||||
}
|
||||
|
||||
static bool uuid_data_match(const void *data, const void *elem)
|
||||
{
|
||||
const struct bt_ad_service_data *uuid_data = elem;
|
||||
const bt_uuid_t *uuid = data;
|
||||
|
||||
return !bt_uuid_cmp(&uuid_data->uuid, uuid);
|
||||
}
|
||||
|
||||
static void manuf_destroy(void *data)
|
||||
{
|
||||
struct bt_ad_manufacturer_data *manuf = data;
|
||||
|
||||
free(manuf->data);
|
||||
free(manuf);
|
||||
}
|
||||
|
||||
static bool manuf_match(const void *data, const void *elem)
|
||||
{
|
||||
const struct bt_ad_manufacturer_data *manuf = elem;
|
||||
uint16_t manuf_id = PTR_TO_UINT(elem);
|
||||
|
||||
return manuf->manufacturer_id == manuf_id;
|
||||
}
|
||||
|
||||
void bt_ad_unref(struct bt_ad *ad)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&ad->ref_count, 1))
|
||||
return;
|
||||
|
||||
queue_destroy(ad->service_uuids, free);
|
||||
|
||||
queue_destroy(ad->manufacturer_data, manuf_destroy);
|
||||
|
||||
queue_destroy(ad->solicit_uuids, free);
|
||||
|
||||
queue_destroy(ad->service_data, uuid_destroy);
|
||||
|
||||
free(ad);
|
||||
}
|
||||
|
||||
static size_t uuid_list_length(struct queue *uuid_queue)
|
||||
{
|
||||
bool uuid16_included = false;
|
||||
bool uuid32_included = false;
|
||||
bool uuid128_included = false;
|
||||
size_t length = 0;
|
||||
const struct queue_entry *entry;
|
||||
|
||||
entry = queue_get_entries(uuid_queue);
|
||||
|
||||
while (entry) {
|
||||
bt_uuid_t *uuid = entry->data;
|
||||
|
||||
length += bt_uuid_len(uuid);
|
||||
|
||||
if (uuid->type == BT_UUID16)
|
||||
uuid16_included = true;
|
||||
else if (uuid->type == BT_UUID32)
|
||||
uuid32_included = true;
|
||||
else
|
||||
uuid128_included = true;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
if (uuid16_included)
|
||||
length += 2;
|
||||
|
||||
if (uuid32_included)
|
||||
length += 2;
|
||||
|
||||
if (uuid128_included)
|
||||
length += 2;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static size_t mfg_data_length(struct queue *manuf_data)
|
||||
{
|
||||
size_t length = 0;
|
||||
const struct queue_entry *entry;
|
||||
|
||||
entry = queue_get_entries(manuf_data);
|
||||
|
||||
while (entry) {
|
||||
struct bt_ad_manufacturer_data *data = entry->data;
|
||||
|
||||
length += 2 + sizeof(uint16_t) + data->len;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static size_t uuid_data_length(struct queue *uuid_data)
|
||||
{
|
||||
size_t length = 0;
|
||||
const struct queue_entry *entry;
|
||||
|
||||
entry = queue_get_entries(uuid_data);
|
||||
|
||||
while (entry) {
|
||||
struct bt_ad_service_data *data = entry->data;
|
||||
|
||||
length += 2 + bt_uuid_len(&data->uuid) + data->len;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static size_t calculate_length(struct bt_ad *ad)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
length += uuid_list_length(ad->service_uuids);
|
||||
|
||||
length += uuid_list_length(ad->solicit_uuids);
|
||||
|
||||
length += mfg_data_length(ad->manufacturer_data);
|
||||
|
||||
length += uuid_data_length(ad->service_data);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static void serialize_uuids(struct queue *uuids, uint8_t uuid_type,
|
||||
uint8_t ad_type, uint8_t *buf,
|
||||
uint8_t *pos)
|
||||
{
|
||||
const struct queue_entry *entry = queue_get_entries(uuids);
|
||||
bool added = false;
|
||||
uint8_t length_pos = 0;
|
||||
|
||||
while (entry) {
|
||||
bt_uuid_t *uuid = entry->data;
|
||||
|
||||
if (uuid->type == uuid_type) {
|
||||
if (!added) {
|
||||
length_pos = (*pos)++;
|
||||
buf[(*pos)++] = ad_type;
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (uuid_type != BT_UUID32)
|
||||
bt_uuid_to_le(uuid, buf + *pos);
|
||||
else
|
||||
bt_put_le32(uuid->value.u32, buf + *pos);
|
||||
|
||||
*pos += bt_uuid_len(uuid);
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
if (added)
|
||||
buf[length_pos] = *pos - length_pos - 1;
|
||||
}
|
||||
|
||||
static void serialize_service_uuids(struct queue *uuids, uint8_t *buf,
|
||||
uint8_t *pos)
|
||||
{
|
||||
serialize_uuids(uuids, BT_UUID16, EIR_UUID16_ALL, buf, pos);
|
||||
|
||||
serialize_uuids(uuids, BT_UUID32, EIR_UUID32_ALL, buf, pos);
|
||||
|
||||
serialize_uuids(uuids, BT_UUID128, EIR_UUID128_ALL, buf, pos);
|
||||
}
|
||||
|
||||
static void serialize_solicit_uuids(struct queue *uuids, uint8_t *buf,
|
||||
uint8_t *pos)
|
||||
{
|
||||
serialize_uuids(uuids, BT_UUID16, EIR_SOLICIT16, buf, pos);
|
||||
|
||||
serialize_uuids(uuids, BT_UUID32, EIR_SOLICIT32, buf, pos);
|
||||
|
||||
serialize_uuids(uuids, BT_UUID128, EIR_SOLICIT128, buf, pos);
|
||||
}
|
||||
|
||||
static void serialize_manuf_data(struct queue *manuf_data, uint8_t *buf,
|
||||
uint8_t *pos)
|
||||
{
|
||||
const struct queue_entry *entry = queue_get_entries(manuf_data);
|
||||
|
||||
while (entry) {
|
||||
struct bt_ad_manufacturer_data *data = entry->data;
|
||||
|
||||
buf[(*pos)++] = data->len + 2 + 1;
|
||||
|
||||
buf[(*pos)++] = EIR_MANUFACTURER_DATA;
|
||||
|
||||
bt_put_le16(data->manufacturer_id, buf + (*pos));
|
||||
|
||||
*pos += 2;
|
||||
|
||||
memcpy(buf + *pos, data->data, data->len);
|
||||
|
||||
*pos += data->len;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void serialize_service_data(struct queue *service_data, uint8_t *buf,
|
||||
uint8_t *pos)
|
||||
{
|
||||
const struct queue_entry *entry = queue_get_entries(service_data);
|
||||
|
||||
while (entry) {
|
||||
struct bt_ad_service_data *data = entry->data;
|
||||
int uuid_len = bt_uuid_len(&data->uuid);
|
||||
|
||||
buf[(*pos)++] = uuid_len + data->len + 1;
|
||||
|
||||
switch (uuid_len) {
|
||||
case 2:
|
||||
buf[(*pos)++] = EIR_SVC_DATA16;
|
||||
break;
|
||||
case 4:
|
||||
buf[(*pos)++] = EIR_SVC_DATA32;
|
||||
break;
|
||||
case 16:
|
||||
buf[(*pos)++] = EIR_SVC_DATA128;
|
||||
break;
|
||||
}
|
||||
|
||||
if (uuid_len != 4)
|
||||
bt_uuid_to_le(&data->uuid, buf + *pos);
|
||||
else
|
||||
bt_put_le32(data->uuid.value.u32, buf + *pos);
|
||||
|
||||
*pos += uuid_len;
|
||||
|
||||
memcpy(buf + *pos, data->data, data->len);
|
||||
|
||||
*pos += data->len;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length)
|
||||
{
|
||||
uint8_t *adv_data;
|
||||
uint8_t pos = 0;
|
||||
|
||||
if (!ad)
|
||||
return NULL;
|
||||
|
||||
*length = calculate_length(ad);
|
||||
|
||||
if (*length > MAX_ADV_DATA_LEN)
|
||||
return NULL;
|
||||
|
||||
adv_data = malloc0(*length);
|
||||
if (!adv_data)
|
||||
return NULL;
|
||||
|
||||
serialize_service_uuids(ad->service_uuids, adv_data, &pos);
|
||||
|
||||
serialize_solicit_uuids(ad->solicit_uuids, adv_data, &pos);
|
||||
|
||||
serialize_manuf_data(ad->manufacturer_data, adv_data, &pos);
|
||||
|
||||
serialize_service_data(ad->service_data, adv_data, &pos);
|
||||
|
||||
return adv_data;
|
||||
}
|
||||
|
||||
static bool queue_add_uuid(struct queue *queue, const bt_uuid_t *uuid)
|
||||
{
|
||||
bt_uuid_t *new_uuid;
|
||||
|
||||
if (!queue)
|
||||
return false;
|
||||
|
||||
new_uuid = new0(bt_uuid_t, 1);
|
||||
|
||||
*new_uuid = *uuid;
|
||||
|
||||
if (queue_push_tail(queue, new_uuid))
|
||||
return true;
|
||||
|
||||
free(new_uuid);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool uuid_match(const void *data, const void *elem)
|
||||
{
|
||||
const bt_uuid_t *match_uuid = data;
|
||||
const bt_uuid_t *uuid = elem;
|
||||
|
||||
return bt_uuid_cmp(match_uuid, uuid);
|
||||
}
|
||||
|
||||
static bool queue_remove_uuid(struct queue *queue, bt_uuid_t *uuid)
|
||||
{
|
||||
bt_uuid_t *removed;
|
||||
|
||||
if (!queue || !uuid)
|
||||
return false;
|
||||
|
||||
removed = queue_remove_if(queue, uuid_match, uuid);
|
||||
|
||||
if (removed) {
|
||||
free(removed);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid)
|
||||
{
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
return queue_add_uuid(ad->service_uuids, uuid);
|
||||
}
|
||||
|
||||
bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid)
|
||||
{
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
return queue_remove_uuid(ad->service_uuids, uuid);
|
||||
}
|
||||
|
||||
void bt_ad_clear_service_uuid(struct bt_ad *ad)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
queue_remove_all(ad->service_uuids, NULL, NULL, free);
|
||||
}
|
||||
|
||||
static bool manufacturer_id_data_match(const void *data, const void *user_data)
|
||||
{
|
||||
const struct bt_ad_manufacturer_data *m = data;
|
||||
uint16_t id = PTR_TO_UINT(user_data);
|
||||
|
||||
return m->manufacturer_id == id;
|
||||
}
|
||||
|
||||
bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id,
|
||||
void *data, size_t len)
|
||||
{
|
||||
struct bt_ad_manufacturer_data *new_data;
|
||||
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
if (len > (MAX_ADV_DATA_LEN - 2 - sizeof(uint16_t)))
|
||||
return false;
|
||||
|
||||
new_data = queue_find(ad->manufacturer_data, manufacturer_id_data_match,
|
||||
UINT_TO_PTR(manufacturer_id));
|
||||
if (new_data) {
|
||||
if (new_data->len == len && !memcmp(new_data->data, data, len))
|
||||
return false;
|
||||
new_data->data = realloc(new_data->data, len);
|
||||
memcpy(new_data->data, data, len);
|
||||
new_data->len = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
new_data = new0(struct bt_ad_manufacturer_data, 1);
|
||||
new_data->manufacturer_id = manufacturer_id;
|
||||
|
||||
new_data->data = malloc(len);
|
||||
if (!new_data->data) {
|
||||
free(new_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(new_data->data, data, len);
|
||||
|
||||
new_data->len = len;
|
||||
|
||||
if (queue_push_tail(ad->manufacturer_data, new_data))
|
||||
return true;
|
||||
|
||||
manuf_destroy(new_data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool manufacturer_data_match(const void *data, const void *user_data)
|
||||
{
|
||||
const struct bt_ad_manufacturer_data *m1 = data;
|
||||
const struct bt_ad_manufacturer_data *m2 = user_data;
|
||||
|
||||
if (m1->manufacturer_id != m2->manufacturer_id)
|
||||
return false;
|
||||
|
||||
if (m1->len != m2->len)
|
||||
return false;
|
||||
|
||||
return !memcmp(m1->data, m2->data, m1->len);
|
||||
}
|
||||
|
||||
bool bt_ad_has_manufacturer_data(struct bt_ad *ad,
|
||||
const struct bt_ad_manufacturer_data *data)
|
||||
{
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
if (!data)
|
||||
return !queue_isempty(ad->manufacturer_data);
|
||||
|
||||
return queue_find(ad->manufacturer_data, manufacturer_data_match, data);
|
||||
}
|
||||
|
||||
void bt_ad_foreach_manufacturer_data(struct bt_ad *ad, bt_ad_func_t func,
|
||||
void *user_data)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
queue_foreach(ad->manufacturer_data, func, user_data);
|
||||
}
|
||||
|
||||
bool bt_ad_remove_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id)
|
||||
{
|
||||
struct bt_ad_manufacturer_data *data;
|
||||
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
data = queue_remove_if(ad->manufacturer_data, manuf_match,
|
||||
UINT_TO_PTR(manufacturer_id));
|
||||
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
manuf_destroy(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bt_ad_clear_manufacturer_data(struct bt_ad *ad)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
queue_remove_all(ad->manufacturer_data, NULL, NULL, manuf_destroy);
|
||||
}
|
||||
|
||||
bool bt_ad_add_solicit_uuid(struct bt_ad *ad, const bt_uuid_t *uuid)
|
||||
{
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
return queue_add_uuid(ad->solicit_uuids, uuid);
|
||||
}
|
||||
|
||||
bool bt_ad_remove_solicit_uuid(struct bt_ad *ad, bt_uuid_t *uuid)
|
||||
{
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
return queue_remove_uuid(ad->solicit_uuids, uuid);
|
||||
}
|
||||
|
||||
void bt_ad_clear_solicit_uuid(struct bt_ad *ad)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
queue_remove_all(ad->solicit_uuids, NULL, NULL, free);
|
||||
}
|
||||
|
||||
|
||||
static bool service_uuid_match(const void *data, const void *user_data)
|
||||
{
|
||||
const struct bt_ad_service_data *s = data;
|
||||
const bt_uuid_t *uuid = user_data;
|
||||
|
||||
return !bt_uuid_cmp(&s->uuid, uuid);
|
||||
}
|
||||
|
||||
bool bt_ad_add_service_data(struct bt_ad *ad, const bt_uuid_t *uuid, void *data,
|
||||
size_t len)
|
||||
{
|
||||
struct bt_ad_service_data *new_data;
|
||||
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
if (len > (MAX_ADV_DATA_LEN - 2 - (size_t)bt_uuid_len(uuid)))
|
||||
return false;
|
||||
|
||||
new_data = queue_find(ad->service_data, service_uuid_match, uuid);
|
||||
if (new_data) {
|
||||
if (new_data->len == len && !memcmp(new_data->data, data, len))
|
||||
return false;
|
||||
new_data->data = realloc(new_data->data, len);
|
||||
memcpy(new_data->data, data, len);
|
||||
new_data->len = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
new_data = new0(struct bt_ad_service_data, 1);
|
||||
|
||||
new_data->uuid = *uuid;
|
||||
|
||||
new_data->data = malloc(len);
|
||||
if (!new_data->data) {
|
||||
free(new_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(new_data->data, data, len);
|
||||
|
||||
new_data->len = len;
|
||||
|
||||
if (queue_push_tail(ad->service_data, new_data))
|
||||
return true;
|
||||
|
||||
uuid_destroy(new_data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool service_data_match(const void *data, const void *user_data)
|
||||
{
|
||||
const struct bt_ad_service_data *s1 = data;
|
||||
const struct bt_ad_service_data *s2 = user_data;
|
||||
|
||||
if (bt_uuid_cmp(&s1->uuid, &s2->uuid))
|
||||
return false;
|
||||
|
||||
if (s1->len != s2->len)
|
||||
return false;
|
||||
|
||||
return !memcmp(s1->data, s2->data, s1->len);
|
||||
}
|
||||
|
||||
bool bt_ad_has_service_data(struct bt_ad *ad,
|
||||
const struct bt_ad_service_data *data)
|
||||
{
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
if (!data)
|
||||
return !queue_isempty(ad->service_data);
|
||||
|
||||
return queue_find(ad->service_data, service_data_match, data);
|
||||
}
|
||||
|
||||
void bt_ad_foreach_service_data(struct bt_ad *ad, bt_ad_func_t func,
|
||||
void *user_data)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
queue_foreach(ad->service_data, func, user_data);
|
||||
}
|
||||
|
||||
bool bt_ad_remove_service_data(struct bt_ad *ad, bt_uuid_t *uuid)
|
||||
{
|
||||
struct bt_ad_service_data *data;
|
||||
|
||||
if (!ad)
|
||||
return false;
|
||||
|
||||
data = queue_remove_if(ad->service_data, uuid_data_match, uuid);
|
||||
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
uuid_destroy(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bt_ad_clear_service_data(struct bt_ad *ad)
|
||||
{
|
||||
if (!ad)
|
||||
return;
|
||||
|
||||
queue_remove_all(ad->service_data, NULL, NULL, uuid_destroy);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2015 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lib/bluetooth.h"
|
||||
#include "lib/uuid.h"
|
||||
|
||||
typedef void (*bt_ad_func_t)(void *data, void *user_data);
|
||||
|
||||
struct bt_ad;
|
||||
|
||||
struct bt_ad_manufacturer_data {
|
||||
uint16_t manufacturer_id;
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct bt_ad_service_data {
|
||||
bt_uuid_t uuid;
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct bt_ad *bt_ad_new(void);
|
||||
|
||||
struct bt_ad *bt_ad_ref(struct bt_ad *ad);
|
||||
|
||||
void bt_ad_unref(struct bt_ad *ad);
|
||||
|
||||
uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length);
|
||||
|
||||
bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid);
|
||||
|
||||
bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid);
|
||||
|
||||
void bt_ad_clear_service_uuid(struct bt_ad *ad);
|
||||
|
||||
bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_data,
|
||||
void *data, size_t len);
|
||||
|
||||
bool bt_ad_has_manufacturer_data(struct bt_ad *ad,
|
||||
const struct bt_ad_manufacturer_data *data);
|
||||
|
||||
void bt_ad_foreach_manufacturer_data(struct bt_ad *ad, bt_ad_func_t func,
|
||||
void *user_data);
|
||||
|
||||
bool bt_ad_remove_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id);
|
||||
|
||||
void bt_ad_clear_manufacturer_data(struct bt_ad *ad);
|
||||
|
||||
bool bt_ad_add_solicit_uuid(struct bt_ad *ad, const bt_uuid_t *uuid);
|
||||
|
||||
bool bt_ad_remove_solicit_uuid(struct bt_ad *ad, bt_uuid_t *uuid);
|
||||
|
||||
void bt_ad_clear_solicit_uuid(struct bt_ad *ad);
|
||||
|
||||
bool bt_ad_add_service_data(struct bt_ad *ad, const bt_uuid_t *uuid, void *data,
|
||||
size_t len);
|
||||
|
||||
bool bt_ad_has_service_data(struct bt_ad *ad,
|
||||
const struct bt_ad_service_data *data);
|
||||
|
||||
void bt_ad_foreach_service_data(struct bt_ad *ad, bt_ad_func_t func,
|
||||
void *user_data);
|
||||
|
||||
bool bt_ad_remove_service_data(struct bt_ad *ad, bt_uuid_t *uuid);
|
||||
|
||||
void bt_ad_clear_service_data(struct bt_ad *ad);
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#define BT_ATT_SECURITY_AUTO 0
|
||||
#define BT_ATT_SECURITY_LOW 1
|
||||
#define BT_ATT_SECURITY_MEDIUM 2
|
||||
#define BT_ATT_SECURITY_HIGH 3
|
||||
#define BT_ATT_SECURITY_FIPS 4
|
||||
|
||||
#define BT_ATT_DEFAULT_LE_MTU 23
|
||||
#define BT_ATT_MAX_LE_MTU 517
|
||||
#define BT_ATT_MAX_VALUE_LEN 512
|
||||
|
||||
#define BT_ATT_LINK_BREDR 0x00
|
||||
#define BT_ATT_LINK_LE 0x01
|
||||
#define BT_ATT_LINK_LOCAL 0xff
|
||||
|
||||
/* ATT protocol opcodes */
|
||||
#define BT_ATT_OP_ERROR_RSP 0x01
|
||||
#define BT_ATT_OP_MTU_REQ 0x02
|
||||
#define BT_ATT_OP_MTU_RSP 0x03
|
||||
#define BT_ATT_OP_FIND_INFO_REQ 0x04
|
||||
#define BT_ATT_OP_FIND_INFO_RSP 0x05
|
||||
#define BT_ATT_OP_FIND_BY_TYPE_REQ 0x06
|
||||
#define BT_ATT_OP_FIND_BY_TYPE_RSP 0x07
|
||||
#define BT_ATT_OP_READ_BY_TYPE_REQ 0x08
|
||||
#define BT_ATT_OP_READ_BY_TYPE_RSP 0x09
|
||||
#define BT_ATT_OP_READ_REQ 0x0a
|
||||
#define BT_ATT_OP_READ_RSP 0x0b
|
||||
#define BT_ATT_OP_READ_BLOB_REQ 0x0c
|
||||
#define BT_ATT_OP_READ_BLOB_RSP 0x0d
|
||||
#define BT_ATT_OP_READ_MULT_REQ 0x0e
|
||||
#define BT_ATT_OP_READ_MULT_RSP 0x0f
|
||||
#define BT_ATT_OP_READ_BY_GRP_TYPE_REQ 0x10
|
||||
#define BT_ATT_OP_READ_BY_GRP_TYPE_RSP 0x11
|
||||
#define BT_ATT_OP_WRITE_REQ 0x12
|
||||
#define BT_ATT_OP_WRITE_RSP 0x13
|
||||
#define BT_ATT_OP_WRITE_CMD 0x52
|
||||
#define BT_ATT_OP_SIGNED_WRITE_CMD 0xD2
|
||||
#define BT_ATT_OP_PREP_WRITE_REQ 0x16
|
||||
#define BT_ATT_OP_PREP_WRITE_RSP 0x17
|
||||
#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
|
||||
#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
|
||||
#define BT_ATT_OP_HANDLE_VAL_NOT 0x1B
|
||||
#define BT_ATT_OP_HANDLE_VAL_IND 0x1D
|
||||
#define BT_ATT_OP_HANDLE_VAL_CONF 0x1E
|
||||
|
||||
/* Packed struct definitions for ATT protocol PDUs */
|
||||
/* TODO: Complete these definitions for all opcodes */
|
||||
struct bt_att_pdu_error_rsp {
|
||||
uint8_t opcode;
|
||||
uint16_t handle;
|
||||
uint8_t ecode;
|
||||
} __packed;
|
||||
|
||||
/* Special opcode to receive all requests (legacy servers) */
|
||||
#define BT_ATT_ALL_REQUESTS 0x00
|
||||
|
||||
/* Error codes for Error response PDU */
|
||||
#define BT_ATT_ERROR_INVALID_HANDLE 0x01
|
||||
#define BT_ATT_ERROR_READ_NOT_PERMITTED 0x02
|
||||
#define BT_ATT_ERROR_WRITE_NOT_PERMITTED 0x03
|
||||
#define BT_ATT_ERROR_INVALID_PDU 0x04
|
||||
#define BT_ATT_ERROR_AUTHENTICATION 0x05
|
||||
#define BT_ATT_ERROR_REQUEST_NOT_SUPPORTED 0x06
|
||||
#define BT_ATT_ERROR_INVALID_OFFSET 0x07
|
||||
#define BT_ATT_ERROR_AUTHORIZATION 0x08
|
||||
#define BT_ATT_ERROR_PREPARE_QUEUE_FULL 0x09
|
||||
#define BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND 0x0A
|
||||
#define BT_ATT_ERROR_ATTRIBUTE_NOT_LONG 0x0B
|
||||
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE 0x0C
|
||||
#define BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN 0x0D
|
||||
#define BT_ATT_ERROR_UNLIKELY 0x0E
|
||||
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION 0x0F
|
||||
#define BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE 0x10
|
||||
#define BT_ATT_ERROR_INSUFFICIENT_RESOURCES 0x11
|
||||
|
||||
/*
|
||||
* Common Profile and Service Error Code descriptions (see Supplement to the
|
||||
* Bluetooth Core Specification, sections 1.2 and 2). The error codes within
|
||||
* 0xE0-0xFC are reserved for future use. The remaining 3 are defined as the
|
||||
* following:
|
||||
*/
|
||||
#define BT_ERROR_CCC_IMPROPERLY_CONFIGURED 0xfd
|
||||
#define BT_ERROR_ALREADY_IN_PROGRESS 0xfe
|
||||
#define BT_ERROR_OUT_OF_RANGE 0xff
|
||||
|
||||
/*
|
||||
* ATT attribute permission bitfield values. Permissions are grouped as
|
||||
* "Access", "Encryption", "Authentication", and "Authorization". A bitmask of
|
||||
* permissions is a byte that encodes a combination of these.
|
||||
*/
|
||||
#define BT_ATT_PERM_READ 0x01
|
||||
#define BT_ATT_PERM_WRITE 0x02
|
||||
#define BT_ATT_PERM_READ_ENCRYPT 0x04
|
||||
#define BT_ATT_PERM_WRITE_ENCRYPT 0x08
|
||||
#define BT_ATT_PERM_ENCRYPT (BT_ATT_PERM_READ_ENCRYPT | \
|
||||
BT_ATT_PERM_WRITE_ENCRYPT)
|
||||
#define BT_ATT_PERM_READ_AUTHEN 0x10
|
||||
#define BT_ATT_PERM_WRITE_AUTHEN 0x20
|
||||
#define BT_ATT_PERM_AUTHEN (BT_ATT_PERM_READ_AUTHEN | \
|
||||
BT_ATT_PERM_WRITE_AUTHEN)
|
||||
#define BT_ATT_PERM_AUTHOR 0x40
|
||||
#define BT_ATT_PERM_NONE 0x80
|
||||
#define BT_ATT_PERM_READ_SECURE 0x0100
|
||||
#define BT_ATT_PERM_WRITE_SECURE 0x0200
|
||||
#define BT_ATT_PERM_SECURE (BT_ATT_PERM_READ_SECURE | \
|
||||
BT_ATT_PERM_WRITE_SECURE)
|
||||
|
||||
/* GATT Characteristic Properties Bitfield values */
|
||||
#define BT_GATT_CHRC_PROP_BROADCAST 0x01
|
||||
#define BT_GATT_CHRC_PROP_READ 0x02
|
||||
#define BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP 0x04
|
||||
#define BT_GATT_CHRC_PROP_WRITE 0x08
|
||||
#define BT_GATT_CHRC_PROP_NOTIFY 0x10
|
||||
#define BT_GATT_CHRC_PROP_INDICATE 0x20
|
||||
#define BT_GATT_CHRC_PROP_AUTH 0x40
|
||||
#define BT_GATT_CHRC_PROP_EXT_PROP 0x80
|
||||
|
||||
/* GATT Characteristic Extended Properties Bitfield values */
|
||||
#define BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE 0x01
|
||||
#define BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX 0x02
|
||||
#define BT_GATT_CHRC_EXT_PROP_ENC_READ 0x04
|
||||
#define BT_GATT_CHRC_EXT_PROP_ENC_WRITE 0x08
|
||||
#define BT_GATT_CHRC_EXT_PROP_ENC (BT_GATT_CHRC_EXT_PROP_ENC_READ | \
|
||||
BT_GATT_CHRC_EXT_PROP_ENC_WRITE)
|
||||
#define BT_GATT_CHRC_EXT_PROP_AUTH_READ 0x10
|
||||
#define BT_GATT_CHRC_EXT_PROP_AUTH_WRITE 0x20
|
||||
#define BT_GATT_CHRC_EXT_PROP_AUTH (BT_GATT_CHRC_EXT_PROP_AUTH_READ | \
|
||||
BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "src/shared/att-types.h"
|
||||
|
||||
struct bt_att;
|
||||
|
||||
struct bt_att *bt_att_new(int fd, bool ext_signed);
|
||||
|
||||
struct bt_att *bt_att_ref(struct bt_att *att);
|
||||
void bt_att_unref(struct bt_att *att);
|
||||
|
||||
bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close);
|
||||
|
||||
int bt_att_get_fd(struct bt_att *att);
|
||||
|
||||
typedef void (*bt_att_response_func_t)(uint8_t opcode, const void *pdu,
|
||||
uint16_t length, void *user_data);
|
||||
typedef void (*bt_att_notify_func_t)(uint8_t opcode, const void *pdu,
|
||||
uint16_t length, void *user_data);
|
||||
typedef void (*bt_att_destroy_func_t)(void *user_data);
|
||||
typedef void (*bt_att_debug_func_t)(const char *str, void *user_data);
|
||||
typedef void (*bt_att_timeout_func_t)(unsigned int id, uint8_t opcode,
|
||||
void *user_data);
|
||||
typedef void (*bt_att_disconnect_func_t)(int err, void *user_data);
|
||||
typedef bool (*bt_att_counter_func_t)(uint32_t *sign_cnt, void *user_data);
|
||||
|
||||
bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback,
|
||||
void *user_data, bt_att_destroy_func_t destroy);
|
||||
|
||||
uint16_t bt_att_get_mtu(struct bt_att *att);
|
||||
bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu);
|
||||
uint8_t bt_att_get_link_type(struct bt_att *att);
|
||||
|
||||
bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
|
||||
void *user_data,
|
||||
bt_att_destroy_func_t destroy);
|
||||
|
||||
unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
|
||||
const void *pdu, uint16_t length,
|
||||
bt_att_response_func_t callback,
|
||||
void *user_data,
|
||||
bt_att_destroy_func_t destroy);
|
||||
bool bt_att_cancel(struct bt_att *att, unsigned int id);
|
||||
bool bt_att_cancel_all(struct bt_att *att);
|
||||
|
||||
unsigned int bt_att_send_error_rsp(struct bt_att *att, uint8_t opcode,
|
||||
uint16_t handle, int error);
|
||||
|
||||
unsigned int bt_att_register(struct bt_att *att, uint8_t opcode,
|
||||
bt_att_notify_func_t callback,
|
||||
void *user_data,
|
||||
bt_att_destroy_func_t destroy);
|
||||
bool bt_att_unregister(struct bt_att *att, unsigned int id);
|
||||
|
||||
unsigned int bt_att_register_disconnect(struct bt_att *att,
|
||||
bt_att_disconnect_func_t callback,
|
||||
void *user_data,
|
||||
bt_att_destroy_func_t destroy);
|
||||
bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);
|
||||
|
||||
bool bt_att_unregister_all(struct bt_att *att);
|
||||
|
||||
int bt_att_get_security(struct bt_att *att);
|
||||
bool bt_att_set_security(struct bt_att *att, int level);
|
||||
|
||||
bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
|
||||
bt_att_counter_func_t func, void *user_data);
|
||||
bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
|
||||
bt_att_counter_func_t func, void *user_data);
|
||||
bool bt_att_has_crypto(struct bt_att *att);
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "src/shared/btsnoop.h"
|
||||
|
||||
struct btsnoop_hdr {
|
||||
uint8_t id[8]; /* Identification Pattern */
|
||||
uint32_t version; /* Version Number = 1 */
|
||||
uint32_t type; /* Datalink Type */
|
||||
} __attribute__ ((packed));
|
||||
#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
|
||||
|
||||
struct btsnoop_pkt {
|
||||
uint32_t size; /* Original Length */
|
||||
uint32_t len; /* Included Length */
|
||||
uint32_t flags; /* Packet Flags */
|
||||
uint32_t drops; /* Cumulative Drops */
|
||||
uint64_t ts; /* Timestamp microseconds */
|
||||
uint8_t data[0]; /* Packet Data */
|
||||
} __attribute__ ((packed));
|
||||
#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
|
||||
|
||||
static const uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e,
|
||||
0x6f, 0x6f, 0x70, 0x00 };
|
||||
|
||||
static const uint32_t btsnoop_version = 1;
|
||||
|
||||
struct pklg_pkt {
|
||||
uint32_t len;
|
||||
uint64_t ts;
|
||||
uint8_t type;
|
||||
} __attribute__ ((packed));
|
||||
#define PKLG_PKT_SIZE (sizeof(struct pklg_pkt))
|
||||
|
||||
struct btsnoop {
|
||||
int ref_count;
|
||||
int fd;
|
||||
unsigned long flags;
|
||||
uint32_t format;
|
||||
uint16_t index;
|
||||
bool aborted;
|
||||
bool pklg_format;
|
||||
bool pklg_v2;
|
||||
};
|
||||
|
||||
struct btsnoop *btsnoop_open(const char *path, unsigned long flags)
|
||||
{
|
||||
struct btsnoop *btsnoop;
|
||||
struct btsnoop_hdr hdr;
|
||||
ssize_t len;
|
||||
|
||||
btsnoop = calloc(1, sizeof(*btsnoop));
|
||||
if (!btsnoop)
|
||||
return NULL;
|
||||
|
||||
btsnoop->fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (btsnoop->fd < 0) {
|
||||
free(btsnoop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
btsnoop->flags = flags;
|
||||
|
||||
len = read(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
|
||||
if (len < 0 || len != BTSNOOP_HDR_SIZE)
|
||||
goto failed;
|
||||
|
||||
if (!memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
|
||||
/* Check for BTSnoop version 1 format */
|
||||
if (be32toh(hdr.version) != btsnoop_version)
|
||||
goto failed;
|
||||
|
||||
btsnoop->format = be32toh(hdr.type);
|
||||
btsnoop->index = 0xffff;
|
||||
} else {
|
||||
if (!(btsnoop->flags & BTSNOOP_FLAG_PKLG_SUPPORT))
|
||||
goto failed;
|
||||
|
||||
/* Check for Apple Packet Logger format */
|
||||
if (hdr.id[0] != 0x00 ||
|
||||
(hdr.id[1] != 0x00 && hdr.id[1] != 0x01))
|
||||
goto failed;
|
||||
|
||||
btsnoop->format = BTSNOOP_FORMAT_MONITOR;
|
||||
btsnoop->index = 0xffff;
|
||||
btsnoop->pklg_format = true;
|
||||
btsnoop->pklg_v2 = (hdr.id[1] == 0x01);
|
||||
|
||||
/* Apple Packet Logger format has no header */
|
||||
lseek(btsnoop->fd, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
return btsnoop_ref(btsnoop);
|
||||
|
||||
failed:
|
||||
close(btsnoop->fd);
|
||||
free(btsnoop);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct btsnoop *btsnoop_create(const char *path, uint32_t format)
|
||||
{
|
||||
struct btsnoop *btsnoop;
|
||||
struct btsnoop_hdr hdr;
|
||||
ssize_t written;
|
||||
|
||||
btsnoop = calloc(1, sizeof(*btsnoop));
|
||||
if (!btsnoop)
|
||||
return NULL;
|
||||
|
||||
btsnoop->fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (btsnoop->fd < 0) {
|
||||
free(btsnoop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
btsnoop->format = format;
|
||||
btsnoop->index = 0xffff;
|
||||
|
||||
memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
|
||||
hdr.version = htobe32(btsnoop_version);
|
||||
hdr.type = htobe32(btsnoop->format);
|
||||
|
||||
written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
|
||||
if (written < 0) {
|
||||
close(btsnoop->fd);
|
||||
free(btsnoop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return btsnoop_ref(btsnoop);
|
||||
}
|
||||
|
||||
struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop)
|
||||
{
|
||||
if (!btsnoop)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&btsnoop->ref_count, 1);
|
||||
|
||||
return btsnoop;
|
||||
}
|
||||
|
||||
void btsnoop_unref(struct btsnoop *btsnoop)
|
||||
{
|
||||
if (!btsnoop)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&btsnoop->ref_count, 1))
|
||||
return;
|
||||
|
||||
if (btsnoop->fd >= 0)
|
||||
close(btsnoop->fd);
|
||||
|
||||
free(btsnoop);
|
||||
}
|
||||
|
||||
uint32_t btsnoop_get_format(struct btsnoop *btsnoop)
|
||||
{
|
||||
if (!btsnoop)
|
||||
return BTSNOOP_FORMAT_INVALID;
|
||||
|
||||
return btsnoop->format;
|
||||
}
|
||||
|
||||
bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint32_t flags, uint32_t drops, const void *data,
|
||||
uint16_t size)
|
||||
{
|
||||
struct btsnoop_pkt pkt;
|
||||
uint64_t ts;
|
||||
ssize_t written;
|
||||
|
||||
if (!btsnoop || !tv)
|
||||
return false;
|
||||
|
||||
ts = (tv->tv_sec - 946684800ll) * 1000000ll + tv->tv_usec;
|
||||
|
||||
pkt.size = htobe32(size);
|
||||
pkt.len = htobe32(size);
|
||||
pkt.flags = htobe32(flags);
|
||||
pkt.drops = htobe32(drops);
|
||||
pkt.ts = htobe64(ts + 0x00E03AB44A676000ll);
|
||||
|
||||
written = write(btsnoop->fd, &pkt, BTSNOOP_PKT_SIZE);
|
||||
if (written < 0)
|
||||
return false;
|
||||
|
||||
if (data && size > 0) {
|
||||
written = write(btsnoop->fd, data, size);
|
||||
if (written < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t get_flags_from_opcode(uint16_t opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
case BTSNOOP_OPCODE_NEW_INDEX:
|
||||
case BTSNOOP_OPCODE_DEL_INDEX:
|
||||
break;
|
||||
case BTSNOOP_OPCODE_COMMAND_PKT:
|
||||
return 0x02;
|
||||
case BTSNOOP_OPCODE_EVENT_PKT:
|
||||
return 0x03;
|
||||
case BTSNOOP_OPCODE_ACL_TX_PKT:
|
||||
return 0x00;
|
||||
case BTSNOOP_OPCODE_ACL_RX_PKT:
|
||||
return 0x01;
|
||||
case BTSNOOP_OPCODE_SCO_TX_PKT:
|
||||
case BTSNOOP_OPCODE_SCO_RX_PKT:
|
||||
break;
|
||||
case BTSNOOP_OPCODE_OPEN_INDEX:
|
||||
case BTSNOOP_OPCODE_CLOSE_INDEX:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
bool btsnoop_write_hci(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t index, uint16_t opcode, uint32_t drops,
|
||||
const void *data, uint16_t size)
|
||||
{
|
||||
uint32_t flags;
|
||||
|
||||
if (!btsnoop)
|
||||
return false;
|
||||
|
||||
switch (btsnoop->format) {
|
||||
case BTSNOOP_FORMAT_HCI:
|
||||
if (btsnoop->index == 0xffff)
|
||||
btsnoop->index = index;
|
||||
|
||||
if (index != btsnoop->index)
|
||||
return false;
|
||||
|
||||
flags = get_flags_from_opcode(opcode);
|
||||
if (flags == 0xff)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case BTSNOOP_FORMAT_MONITOR:
|
||||
flags = (index << 16) | opcode;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return btsnoop_write(btsnoop, tv, flags, drops, data, size);
|
||||
}
|
||||
|
||||
bool btsnoop_write_phy(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t frequency, const void *data, uint16_t size)
|
||||
{
|
||||
uint32_t flags;
|
||||
|
||||
if (!btsnoop)
|
||||
return false;
|
||||
|
||||
switch (btsnoop->format) {
|
||||
case BTSNOOP_FORMAT_SIMULATOR:
|
||||
flags = (1 << 16) | frequency;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return btsnoop_write(btsnoop, tv, flags, 0, data, size);
|
||||
}
|
||||
|
||||
static bool pklg_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t *index, uint16_t *opcode,
|
||||
void *data, uint16_t *size)
|
||||
{
|
||||
struct pklg_pkt pkt;
|
||||
uint32_t toread;
|
||||
uint64_t ts;
|
||||
ssize_t len;
|
||||
|
||||
len = read(btsnoop->fd, &pkt, PKLG_PKT_SIZE);
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
if (len < 0 || len != PKLG_PKT_SIZE) {
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (btsnoop->pklg_v2) {
|
||||
toread = le32toh(pkt.len) - (PKLG_PKT_SIZE - 4);
|
||||
|
||||
ts = le64toh(pkt.ts);
|
||||
tv->tv_sec = ts & 0xffffffff;
|
||||
tv->tv_usec = ts >> 32;
|
||||
} else {
|
||||
toread = be32toh(pkt.len) - (PKLG_PKT_SIZE - 4);
|
||||
|
||||
ts = be64toh(pkt.ts);
|
||||
tv->tv_sec = ts >> 32;
|
||||
tv->tv_usec = ts & 0xffffffff;
|
||||
}
|
||||
|
||||
switch (pkt.type) {
|
||||
case 0x00:
|
||||
*index = 0x0000;
|
||||
*opcode = BTSNOOP_OPCODE_COMMAND_PKT;
|
||||
break;
|
||||
case 0x01:
|
||||
*index = 0x0000;
|
||||
*opcode = BTSNOOP_OPCODE_EVENT_PKT;
|
||||
break;
|
||||
case 0x02:
|
||||
*index = 0x0000;
|
||||
*opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
|
||||
break;
|
||||
case 0x03:
|
||||
*index = 0x0000;
|
||||
*opcode = BTSNOOP_OPCODE_ACL_RX_PKT;
|
||||
break;
|
||||
case 0x0b:
|
||||
*index = 0x0000;
|
||||
*opcode = BTSNOOP_OPCODE_VENDOR_DIAG;
|
||||
break;
|
||||
case 0xfc:
|
||||
*index = 0xffff;
|
||||
*opcode = BTSNOOP_OPCODE_SYSTEM_NOTE;
|
||||
break;
|
||||
default:
|
||||
*index = 0xffff;
|
||||
*opcode = 0xffff;
|
||||
break;
|
||||
}
|
||||
|
||||
len = read(btsnoop->fd, data, toread);
|
||||
if (len < 0) {
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
*size = toread;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint16_t get_opcode_from_flags(uint8_t type, uint32_t flags)
|
||||
{
|
||||
switch (type) {
|
||||
case 0x01:
|
||||
return BTSNOOP_OPCODE_COMMAND_PKT;
|
||||
case 0x02:
|
||||
if (flags & 0x01)
|
||||
return BTSNOOP_OPCODE_ACL_RX_PKT;
|
||||
else
|
||||
return BTSNOOP_OPCODE_ACL_TX_PKT;
|
||||
case 0x03:
|
||||
if (flags & 0x01)
|
||||
return BTSNOOP_OPCODE_SCO_RX_PKT;
|
||||
else
|
||||
return BTSNOOP_OPCODE_SCO_TX_PKT;
|
||||
case 0x04:
|
||||
return BTSNOOP_OPCODE_EVENT_PKT;
|
||||
case 0xff:
|
||||
if (flags & 0x02) {
|
||||
if (flags & 0x01)
|
||||
return BTSNOOP_OPCODE_EVENT_PKT;
|
||||
else
|
||||
return BTSNOOP_OPCODE_COMMAND_PKT;
|
||||
} else {
|
||||
if (flags & 0x01)
|
||||
return BTSNOOP_OPCODE_ACL_RX_PKT;
|
||||
else
|
||||
return BTSNOOP_OPCODE_ACL_TX_PKT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
bool btsnoop_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t *index, uint16_t *opcode,
|
||||
void *data, uint16_t *size)
|
||||
{
|
||||
struct btsnoop_pkt pkt;
|
||||
uint32_t toread, flags;
|
||||
uint64_t ts;
|
||||
uint8_t pkt_type;
|
||||
ssize_t len;
|
||||
|
||||
if (!btsnoop || btsnoop->aborted)
|
||||
return false;
|
||||
|
||||
if (btsnoop->pklg_format)
|
||||
return pklg_read_hci(btsnoop, tv, index, opcode, data, size);
|
||||
|
||||
len = read(btsnoop->fd, &pkt, BTSNOOP_PKT_SIZE);
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
if (len < 0 || len != BTSNOOP_PKT_SIZE) {
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
toread = be32toh(pkt.size);
|
||||
if (toread > BTSNOOP_MAX_PACKET_SIZE) {
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
flags = be32toh(pkt.flags);
|
||||
|
||||
ts = be64toh(pkt.ts) - 0x00E03AB44A676000ll;
|
||||
tv->tv_sec = (ts / 1000000ll) + 946684800ll;
|
||||
tv->tv_usec = ts % 1000000ll;
|
||||
|
||||
switch (btsnoop->format) {
|
||||
case BTSNOOP_FORMAT_HCI:
|
||||
*index = 0;
|
||||
*opcode = get_opcode_from_flags(0xff, flags);
|
||||
break;
|
||||
|
||||
case BTSNOOP_FORMAT_UART:
|
||||
len = read(btsnoop->fd, &pkt_type, 1);
|
||||
if (len < 0) {
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
toread--;
|
||||
|
||||
*index = 0;
|
||||
*opcode = get_opcode_from_flags(pkt_type, flags);
|
||||
break;
|
||||
|
||||
case BTSNOOP_FORMAT_MONITOR:
|
||||
*index = flags >> 16;
|
||||
*opcode = flags & 0xffff;
|
||||
break;
|
||||
|
||||
default:
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
len = read(btsnoop->fd, data, toread);
|
||||
if (len < 0) {
|
||||
btsnoop->aborted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
*size = toread;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool btsnoop_read_phy(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t *frequency, void *data, uint16_t *size)
|
||||
{
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define BTSNOOP_FORMAT_INVALID 0
|
||||
#define BTSNOOP_FORMAT_HCI 1001
|
||||
#define BTSNOOP_FORMAT_UART 1002
|
||||
#define BTSNOOP_FORMAT_BCSP 1003
|
||||
#define BTSNOOP_FORMAT_3WIRE 1004
|
||||
#define BTSNOOP_FORMAT_MONITOR 2001
|
||||
#define BTSNOOP_FORMAT_SIMULATOR 2002
|
||||
|
||||
#define BTSNOOP_FLAG_PKLG_SUPPORT (1 << 0)
|
||||
|
||||
#define BTSNOOP_OPCODE_NEW_INDEX 0
|
||||
#define BTSNOOP_OPCODE_DEL_INDEX 1
|
||||
#define BTSNOOP_OPCODE_COMMAND_PKT 2
|
||||
#define BTSNOOP_OPCODE_EVENT_PKT 3
|
||||
#define BTSNOOP_OPCODE_ACL_TX_PKT 4
|
||||
#define BTSNOOP_OPCODE_ACL_RX_PKT 5
|
||||
#define BTSNOOP_OPCODE_SCO_TX_PKT 6
|
||||
#define BTSNOOP_OPCODE_SCO_RX_PKT 7
|
||||
#define BTSNOOP_OPCODE_OPEN_INDEX 8
|
||||
#define BTSNOOP_OPCODE_CLOSE_INDEX 9
|
||||
#define BTSNOOP_OPCODE_INDEX_INFO 10
|
||||
#define BTSNOOP_OPCODE_VENDOR_DIAG 11
|
||||
#define BTSNOOP_OPCODE_SYSTEM_NOTE 12
|
||||
#define BTSNOOP_OPCODE_USER_LOGGING 13
|
||||
#define BTSNOOP_OPCODE_CTRL_OPEN 14
|
||||
#define BTSNOOP_OPCODE_CTRL_CLOSE 15
|
||||
#define BTSNOOP_OPCODE_CTRL_COMMAND 16
|
||||
#define BTSNOOP_OPCODE_CTRL_EVENT 17
|
||||
|
||||
#define BTSNOOP_MAX_PACKET_SIZE (1486 + 4)
|
||||
|
||||
#define BTSNOOP_TYPE_PRIMARY 0
|
||||
#define BTSNOOP_TYPE_AMP 1
|
||||
|
||||
#define BTSNOOP_BUS_VIRTUAL 0
|
||||
#define BTSNOOP_BUS_USB 1
|
||||
#define BTSNOOP_BUS_PCCARD 2
|
||||
#define BTSNOOP_BUS_UART 3
|
||||
#define BTSNOOP_BUS_RS232 4
|
||||
#define BTSNOOP_BUS_PCI 5
|
||||
#define BTSNOOP_BUS_SDIO 6
|
||||
#define BTSNOOP_BUS_SPI 7
|
||||
#define BTSNOOP_BUS_I2C 8
|
||||
#define BTSNOOP_BUS_SMD 9
|
||||
|
||||
struct btsnoop_opcode_new_index {
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
uint8_t bdaddr[6];
|
||||
char name[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct btsnoop_opcode_index_info {
|
||||
uint8_t bdaddr[6];
|
||||
uint16_t manufacturer;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define BTSNOOP_PRIORITY_EMERG 0
|
||||
#define BTSNOOP_PRIORITY_ALERT 1
|
||||
#define BTSNOOP_PRIORITY_CRIT 2
|
||||
#define BTSNOOP_PRIORITY_ERR 3
|
||||
#define BTSNOOP_PRIORITY_WARNING 4
|
||||
#define BTSNOOP_PRIORITY_NOTICE 5
|
||||
#define BTSNOOP_PRIORITY_INFO 6
|
||||
#define BTSNOOP_PRIORITY_DEBUG 7
|
||||
|
||||
struct btsnoop_opcode_user_logging {
|
||||
uint8_t priority;
|
||||
uint8_t ident_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct btsnoop;
|
||||
|
||||
struct btsnoop *btsnoop_open(const char *path, unsigned long flags);
|
||||
struct btsnoop *btsnoop_create(const char *path, uint32_t format);
|
||||
|
||||
struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop);
|
||||
void btsnoop_unref(struct btsnoop *btsnoop);
|
||||
|
||||
uint32_t btsnoop_get_format(struct btsnoop *btsnoop);
|
||||
|
||||
bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv, uint32_t flags,
|
||||
uint32_t drops, const void *data, uint16_t size);
|
||||
bool btsnoop_write_hci(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t index, uint16_t opcode, uint32_t drops,
|
||||
const void *data, uint16_t size);
|
||||
bool btsnoop_write_phy(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t frequency, const void *data, uint16_t size);
|
||||
|
||||
bool btsnoop_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t *index, uint16_t *opcode,
|
||||
void *data, uint16_t *size);
|
||||
bool btsnoop_read_phy(struct btsnoop *btsnoop, struct timeval *tv,
|
||||
uint16_t *frequency, void *data, uint16_t *size);
|
|
@ -0,0 +1,690 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/crypto.h"
|
||||
|
||||
#ifndef HAVE_LINUX_IF_ALG_H
|
||||
#ifndef HAVE_LINUX_TYPES_H
|
||||
typedef uint8_t __u8;
|
||||
typedef uint16_t __u16;
|
||||
typedef uint32_t __u32;
|
||||
#else
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
|
||||
struct sockaddr_alg {
|
||||
__u16 salg_family;
|
||||
__u8 salg_type[14];
|
||||
__u32 salg_feat;
|
||||
__u32 salg_mask;
|
||||
__u8 salg_name[64];
|
||||
};
|
||||
|
||||
struct af_alg_iv {
|
||||
__u32 ivlen;
|
||||
__u8 iv[0];
|
||||
};
|
||||
|
||||
#define ALG_SET_KEY 1
|
||||
#define ALG_SET_IV 2
|
||||
#define ALG_SET_OP 3
|
||||
|
||||
#define ALG_OP_DECRYPT 0
|
||||
#define ALG_OP_ENCRYPT 1
|
||||
|
||||
#define PF_ALG 38 /* Algorithm sockets. */
|
||||
#define AF_ALG PF_ALG
|
||||
#else
|
||||
#include <linux/if_alg.h>
|
||||
#endif
|
||||
|
||||
#ifndef SOL_ALG
|
||||
#define SOL_ALG 279
|
||||
#endif
|
||||
|
||||
/* Maximum message length that can be passed to aes_cmac */
|
||||
#define CMAC_MSG_MAX 80
|
||||
|
||||
struct bt_crypto {
|
||||
int ref_count;
|
||||
int ecb_aes;
|
||||
int urandom;
|
||||
int cmac_aes;
|
||||
};
|
||||
|
||||
static int urandom_setup(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int ecb_aes_setup(void)
|
||||
{
|
||||
struct sockaddr_alg salg;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&salg, 0, sizeof(salg));
|
||||
salg.salg_family = AF_ALG;
|
||||
strcpy((char *) salg.salg_type, "skcipher");
|
||||
strcpy((char *) salg.salg_name, "ecb(aes)");
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int cmac_aes_setup(void)
|
||||
{
|
||||
struct sockaddr_alg salg;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&salg, 0, sizeof(salg));
|
||||
salg.salg_family = AF_ALG;
|
||||
strcpy((char *) salg.salg_type, "hash");
|
||||
strcpy((char *) salg.salg_name, "cmac(aes)");
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct bt_crypto *bt_crypto_new(void)
|
||||
{
|
||||
struct bt_crypto *crypto;
|
||||
|
||||
crypto = new0(struct bt_crypto, 1);
|
||||
|
||||
crypto->ecb_aes = ecb_aes_setup();
|
||||
if (crypto->ecb_aes < 0) {
|
||||
free(crypto);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crypto->urandom = urandom_setup();
|
||||
if (crypto->urandom < 0) {
|
||||
close(crypto->ecb_aes);
|
||||
free(crypto);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crypto->cmac_aes = cmac_aes_setup();
|
||||
if (crypto->cmac_aes < 0) {
|
||||
close(crypto->urandom);
|
||||
close(crypto->ecb_aes);
|
||||
free(crypto);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bt_crypto_ref(crypto);
|
||||
}
|
||||
|
||||
struct bt_crypto *bt_crypto_ref(struct bt_crypto *crypto)
|
||||
{
|
||||
if (!crypto)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&crypto->ref_count, 1);
|
||||
|
||||
return crypto;
|
||||
}
|
||||
|
||||
void bt_crypto_unref(struct bt_crypto *crypto)
|
||||
{
|
||||
if (!crypto)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&crypto->ref_count, 1))
|
||||
return;
|
||||
|
||||
close(crypto->urandom);
|
||||
close(crypto->ecb_aes);
|
||||
close(crypto->cmac_aes);
|
||||
|
||||
free(crypto);
|
||||
}
|
||||
|
||||
bool bt_crypto_random_bytes(struct bt_crypto *crypto,
|
||||
uint8_t *buf, uint8_t num_bytes)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
if (!crypto)
|
||||
return false;
|
||||
|
||||
len = read(crypto->urandom, buf, num_bytes);
|
||||
if (len < num_bytes)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int alg_new(int fd, const void *keyval, socklen_t keylen)
|
||||
{
|
||||
if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, keyval, keylen) < 0)
|
||||
return -1;
|
||||
|
||||
/* FIXME: This should use accept4() with SOCK_CLOEXEC */
|
||||
return accept(fd, NULL, 0);
|
||||
}
|
||||
|
||||
static bool alg_encrypt(int fd, const void *inbuf, size_t inlen,
|
||||
void *outbuf, size_t outlen)
|
||||
{
|
||||
__u32 alg_op = ALG_OP_ENCRYPT;
|
||||
char cbuf[CMSG_SPACE(sizeof(alg_op))];
|
||||
struct cmsghdr *cmsg;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
ssize_t len;
|
||||
|
||||
memset(cbuf, 0, sizeof(cbuf));
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_control = cbuf;
|
||||
msg.msg_controllen = sizeof(cbuf);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_ALG;
|
||||
cmsg->cmsg_type = ALG_SET_OP;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(alg_op));
|
||||
memcpy(CMSG_DATA(cmsg), &alg_op, sizeof(alg_op));
|
||||
|
||||
iov.iov_base = (void *) inbuf;
|
||||
iov.iov_len = inlen;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
len = sendmsg(fd, &msg, 0);
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
len = read(fd, outbuf, outlen);
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void swap_buf(const uint8_t *src, uint8_t *dst, uint16_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
dst[len - 1 - i] = src[i];
|
||||
}
|
||||
|
||||
bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
|
||||
const uint8_t *m, uint16_t m_len,
|
||||
uint32_t sign_cnt, uint8_t signature[12])
|
||||
{
|
||||
int fd;
|
||||
int len;
|
||||
uint8_t tmp[16], out[16];
|
||||
uint16_t msg_len = m_len + sizeof(uint32_t);
|
||||
uint8_t msg[msg_len];
|
||||
uint8_t msg_s[msg_len];
|
||||
|
||||
if (!crypto)
|
||||
return false;
|
||||
|
||||
memset(msg, 0, msg_len);
|
||||
memcpy(msg, m, m_len);
|
||||
|
||||
/* Add sign_counter to the message */
|
||||
put_le32(sign_cnt, msg + m_len);
|
||||
|
||||
/* The most significant octet of key corresponds to key[0] */
|
||||
swap_buf(key, tmp, 16);
|
||||
|
||||
fd = alg_new(crypto->cmac_aes, tmp, 16);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
/* Swap msg before signing */
|
||||
swap_buf(msg, msg_s, msg_len);
|
||||
|
||||
len = send(fd, msg_s, msg_len, 0);
|
||||
if (len < 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
len = read(fd, out, 16);
|
||||
if (len < 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/*
|
||||
* As to BT spec. 4.1 Vol[3], Part C, chapter 10.4.1 sign counter should
|
||||
* be placed in the signature
|
||||
*/
|
||||
put_be32(sign_cnt, out + 8);
|
||||
|
||||
/*
|
||||
* The most significant octet of hash corresponds to out[0] - swap it.
|
||||
* Then truncate in most significant bit first order to a length of
|
||||
* 12 octets
|
||||
*/
|
||||
swap_buf(out, tmp, 16);
|
||||
memcpy(signature, tmp + 4, 12);
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Security function e
|
||||
*
|
||||
* Security function e generates 128-bit encryptedData from a 128-bit key
|
||||
* and 128-bit plaintextData using the AES-128-bit block cypher:
|
||||
*
|
||||
* encryptedData = e(key, plaintextData)
|
||||
*
|
||||
* The most significant octet of key corresponds to key[0], the most
|
||||
* significant octet of plaintextData corresponds to in[0] and the
|
||||
* most significant octet of encryptedData corresponds to out[0].
|
||||
*
|
||||
*/
|
||||
bool bt_crypto_e(struct bt_crypto *crypto, const uint8_t key[16],
|
||||
const uint8_t plaintext[16], uint8_t encrypted[16])
|
||||
{
|
||||
uint8_t tmp[16], in[16], out[16];
|
||||
int fd;
|
||||
|
||||
if (!crypto)
|
||||
return false;
|
||||
|
||||
/* The most significant octet of key corresponds to key[0] */
|
||||
swap_buf(key, tmp, 16);
|
||||
|
||||
fd = alg_new(crypto->ecb_aes, tmp, 16);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
|
||||
/* Most significant octet of plaintextData corresponds to in[0] */
|
||||
swap_buf(plaintext, in, 16);
|
||||
|
||||
if (!alg_encrypt(fd, in, 16, out, 16)) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Most significant octet of encryptedData corresponds to out[0] */
|
||||
swap_buf(out, encrypted, 16);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Random Address Hash function ah
|
||||
*
|
||||
* The random address hash function ah is used to generate a hash value
|
||||
* that is used in resolvable private addresses.
|
||||
*
|
||||
* The following are inputs to the random address hash function ah:
|
||||
*
|
||||
* k is 128 bits
|
||||
* r is 24 bits
|
||||
* padding is 104 bits
|
||||
*
|
||||
* r is concatenated with padding to generate r' which is used as the
|
||||
* 128-bit input parameter plaintextData to security function e:
|
||||
*
|
||||
* r' = padding || r
|
||||
*
|
||||
* The least significant octet of r becomes the least significant octet
|
||||
* of r’ and the most significant octet of padding becomes the most
|
||||
* significant octet of r'.
|
||||
*
|
||||
* For example, if the 24-bit value r is 0x423456 then r' is
|
||||
* 0x00000000000000000000000000423456.
|
||||
*
|
||||
* The output of the random address function ah is:
|
||||
*
|
||||
* ah(k, r) = e(k, r') mod 2^24
|
||||
*
|
||||
* The output of the security function e is then truncated to 24 bits by
|
||||
* taking the least significant 24 bits of the output of e as the result
|
||||
* of ah.
|
||||
*/
|
||||
bool bt_crypto_ah(struct bt_crypto *crypto, const uint8_t k[16],
|
||||
const uint8_t r[3], uint8_t hash[3])
|
||||
{
|
||||
uint8_t rp[16];
|
||||
uint8_t encrypted[16];
|
||||
|
||||
if (!crypto)
|
||||
return false;
|
||||
|
||||
/* r' = padding || r */
|
||||
memcpy(rp, r, 3);
|
||||
memset(rp + 3, 0, 13);
|
||||
|
||||
/* e(k, r') */
|
||||
if (!bt_crypto_e(crypto, k, rp, encrypted))
|
||||
return false;
|
||||
|
||||
/* ah(k, r) = e(k, r') mod 2^24 */
|
||||
memcpy(hash, encrypted, 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint64_t a, b;
|
||||
} u128;
|
||||
|
||||
static inline void u128_xor(const uint8_t p[16], const uint8_t q[16],
|
||||
uint8_t r[16])
|
||||
{
|
||||
u128 pp, qq, rr;
|
||||
|
||||
memcpy(&pp, p, 16);
|
||||
memcpy(&qq, q, 16);
|
||||
|
||||
rr.a = pp.a ^ qq.a;
|
||||
rr.b = pp.b ^ qq.b;
|
||||
|
||||
memcpy(r, &rr, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Confirm value generation function c1
|
||||
*
|
||||
* During the pairing process confirm values are exchanged. This confirm
|
||||
* value generation function c1 is used to generate the confirm values.
|
||||
*
|
||||
* The following are inputs to the confirm value generation function c1:
|
||||
*
|
||||
* k is 128 bits
|
||||
* r is 128 bits
|
||||
* pres is 56 bits
|
||||
* preq is 56 bits
|
||||
* iat is 1 bit
|
||||
* ia is 48 bits
|
||||
* rat is 1 bit
|
||||
* ra is 48 bits
|
||||
* padding is 32 bits of 0
|
||||
*
|
||||
* iat is concatenated with 7-bits of 0 to create iat' which is 8 bits
|
||||
* in length. iat is the least significant bit of iat'
|
||||
*
|
||||
* rat is concatenated with 7-bits of 0 to create rat' which is 8 bits
|
||||
* in length. rat is the least significant bit of rat'
|
||||
*
|
||||
* pres, preq, rat' and iat' are concatenated to generate p1 which is
|
||||
* XORed with r and used as 128-bit input parameter plaintextData to
|
||||
* security function e:
|
||||
*
|
||||
* p1 = pres || preq || rat' || iat'
|
||||
*
|
||||
* The octet of iat' becomes the least significant octet of p1 and the
|
||||
* most significant octet of pres becomes the most significant octet of
|
||||
* p1.
|
||||
*
|
||||
* ra is concatenated with ia and padding to generate p2 which is XORed
|
||||
* with the result of the security function e using p1 as the input
|
||||
* paremter plaintextData and is then used as the 128-bit input
|
||||
* parameter plaintextData to security function e:
|
||||
*
|
||||
* p2 = padding || ia || ra
|
||||
*
|
||||
* The least significant octet of ra becomes the least significant octet
|
||||
* of p2 and the most significant octet of padding becomes the most
|
||||
* significant octet of p2.
|
||||
*
|
||||
* The output of the confirm value generation function c1 is:
|
||||
*
|
||||
* c1(k, r, preq, pres, iat, rat, ia, ra) = e(k, e(k, r XOR p1) XOR p2)
|
||||
*
|
||||
* The 128-bit output of the security function e is used as the result
|
||||
* of confirm value generation function c1.
|
||||
*/
|
||||
bool bt_crypto_c1(struct bt_crypto *crypto, const uint8_t k[16],
|
||||
const uint8_t r[16], const uint8_t pres[7],
|
||||
const uint8_t preq[7], uint8_t iat,
|
||||
const uint8_t ia[6], uint8_t rat,
|
||||
const uint8_t ra[6], uint8_t res[16])
|
||||
{
|
||||
uint8_t p1[16], p2[16];
|
||||
|
||||
/* p1 = pres || preq || _rat || _iat */
|
||||
p1[0] = iat;
|
||||
p1[1] = rat;
|
||||
memcpy(p1 + 2, preq, 7);
|
||||
memcpy(p1 + 9, pres, 7);
|
||||
|
||||
/* p2 = padding || ia || ra */
|
||||
memcpy(p2, ra, 6);
|
||||
memcpy(p2 + 6, ia, 6);
|
||||
memset(p2 + 12, 0, 4);
|
||||
|
||||
/* res = r XOR p1 */
|
||||
u128_xor(r, p1, res);
|
||||
|
||||
/* res = e(k, res) */
|
||||
if (!bt_crypto_e(crypto, k, res, res))
|
||||
return false;
|
||||
|
||||
/* res = res XOR p2 */
|
||||
u128_xor(res, p2, res);
|
||||
|
||||
/* res = e(k, res) */
|
||||
return bt_crypto_e(crypto, k, res, res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Key generation function s1
|
||||
*
|
||||
* The key generation function s1 is used to generate the STK during the
|
||||
* pairing process.
|
||||
*
|
||||
* The following are inputs to the key generation function s1:
|
||||
*
|
||||
* k is 128 bits
|
||||
* r1 is 128 bits
|
||||
* r2 is 128 bits
|
||||
*
|
||||
* The most significant 64-bits of r1 are discarded to generate r1' and
|
||||
* the most significant 64-bits of r2 are discarded to generate r2'.
|
||||
*
|
||||
* r1' is concatenated with r2' to generate r' which is used as the
|
||||
* 128-bit input parameter plaintextData to security function e:
|
||||
*
|
||||
* r' = r1' || r2'
|
||||
*
|
||||
* The least significant octet of r2' becomes the least significant
|
||||
* octet of r' and the most significant octet of r1' becomes the most
|
||||
* significant octet of r'.
|
||||
*
|
||||
* The output of the key generation function s1 is:
|
||||
*
|
||||
* s1(k, r1, r2) = e(k, r')
|
||||
*
|
||||
* The 128-bit output of the security function e is used as the result
|
||||
* of key generation function s1.
|
||||
*/
|
||||
bool bt_crypto_s1(struct bt_crypto *crypto, const uint8_t k[16],
|
||||
const uint8_t r1[16], const uint8_t r2[16],
|
||||
uint8_t res[16])
|
||||
{
|
||||
memcpy(res, r2, 8);
|
||||
memcpy(res + 8, r1, 8);
|
||||
|
||||
return bt_crypto_e(crypto, k, res, res);
|
||||
}
|
||||
|
||||
static bool aes_cmac(struct bt_crypto *crypto, const uint8_t key[16],
|
||||
const uint8_t *msg, size_t msg_len, uint8_t res[16])
|
||||
{
|
||||
uint8_t key_msb[16], out[16], msg_msb[CMAC_MSG_MAX];
|
||||
ssize_t len;
|
||||
int fd;
|
||||
|
||||
if (msg_len > CMAC_MSG_MAX)
|
||||
return false;
|
||||
|
||||
swap_buf(key, key_msb, 16);
|
||||
fd = alg_new(crypto->cmac_aes, key_msb, 16);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
swap_buf(msg, msg_msb, msg_len);
|
||||
len = send(fd, msg_msb, msg_len, 0);
|
||||
if (len < 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
len = read(fd, out, 16);
|
||||
if (len < 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
swap_buf(out, res, 16);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_crypto_f4(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32],
|
||||
uint8_t x[16], uint8_t z, uint8_t res[16])
|
||||
{
|
||||
uint8_t m[65];
|
||||
|
||||
if (!crypto)
|
||||
return false;
|
||||
|
||||
m[0] = z;
|
||||
memcpy(&m[1], v, 32);
|
||||
memcpy(&m[33], u, 32);
|
||||
|
||||
return aes_cmac(crypto, x, m, sizeof(m), res);
|
||||
}
|
||||
|
||||
bool bt_crypto_f5(struct bt_crypto *crypto, uint8_t w[32], uint8_t n1[16],
|
||||
uint8_t n2[16], uint8_t a1[7], uint8_t a2[7],
|
||||
uint8_t mackey[16], uint8_t ltk[16])
|
||||
{
|
||||
uint8_t btle[4] = { 0x65, 0x6c, 0x74, 0x62 };
|
||||
uint8_t salt[16] = { 0xbe, 0x83, 0x60, 0x5a, 0xdb, 0x0b, 0x37, 0x60,
|
||||
0x38, 0xa5, 0xf5, 0xaa, 0x91, 0x83, 0x88, 0x6c };
|
||||
uint8_t length[2] = { 0x00, 0x01 };
|
||||
uint8_t m[53], t[16];
|
||||
|
||||
if (!aes_cmac(crypto, salt, w, 32, t))
|
||||
return false;
|
||||
|
||||
memcpy(&m[0], length, 2);
|
||||
memcpy(&m[2], a2, 7);
|
||||
memcpy(&m[9], a1, 7);
|
||||
memcpy(&m[16], n2, 16);
|
||||
memcpy(&m[32], n1, 16);
|
||||
memcpy(&m[48], btle, 4);
|
||||
|
||||
m[52] = 0; /* Counter */
|
||||
if (!aes_cmac(crypto, t, m, sizeof(m), mackey))
|
||||
return false;
|
||||
|
||||
m[52] = 1; /* Counter */
|
||||
return aes_cmac(crypto, t, m, sizeof(m), ltk);
|
||||
}
|
||||
|
||||
bool bt_crypto_f6(struct bt_crypto *crypto, uint8_t w[16], uint8_t n1[16],
|
||||
uint8_t n2[16], uint8_t r[16], uint8_t io_cap[3],
|
||||
uint8_t a1[7], uint8_t a2[7], uint8_t res[16])
|
||||
{
|
||||
uint8_t m[65];
|
||||
|
||||
memcpy(&m[0], a2, 7);
|
||||
memcpy(&m[7], a1, 7);
|
||||
memcpy(&m[14], io_cap, 3);
|
||||
memcpy(&m[17], r, 16);
|
||||
memcpy(&m[33], n2, 16);
|
||||
memcpy(&m[49], n1, 16);
|
||||
|
||||
return aes_cmac(crypto, w, m, sizeof(m), res);
|
||||
}
|
||||
|
||||
bool bt_crypto_g2(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32],
|
||||
uint8_t x[16], uint8_t y[16], uint32_t *val)
|
||||
{
|
||||
uint8_t m[80], tmp[16];
|
||||
|
||||
memcpy(&m[0], y, 16);
|
||||
memcpy(&m[16], v, 32);
|
||||
memcpy(&m[48], u, 32);
|
||||
|
||||
if (!aes_cmac(crypto, x, m, sizeof(m), tmp))
|
||||
return false;
|
||||
|
||||
*val = get_le32(tmp);
|
||||
*val %= 1000000;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_crypto_h6(struct bt_crypto *crypto, const uint8_t w[16],
|
||||
const uint8_t keyid[4], uint8_t res[16])
|
||||
{
|
||||
if (!aes_cmac(crypto, w, keyid, 4, res))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct bt_crypto;
|
||||
|
||||
struct bt_crypto *bt_crypto_new(void);
|
||||
|
||||
struct bt_crypto *bt_crypto_ref(struct bt_crypto *crypto);
|
||||
void bt_crypto_unref(struct bt_crypto *crypto);
|
||||
|
||||
bool bt_crypto_random_bytes(struct bt_crypto *crypto,
|
||||
uint8_t *buf, uint8_t num_bytes);
|
||||
|
||||
bool bt_crypto_e(struct bt_crypto *crypto, const uint8_t key[16],
|
||||
const uint8_t plaintext[16], uint8_t encrypted[16]);
|
||||
bool bt_crypto_ah(struct bt_crypto *crypto, const uint8_t k[16],
|
||||
const uint8_t r[3], uint8_t hash[3]);
|
||||
bool bt_crypto_c1(struct bt_crypto *crypto, const uint8_t k[16],
|
||||
const uint8_t r[16], const uint8_t pres[7],
|
||||
const uint8_t preq[7], uint8_t iat,
|
||||
const uint8_t ia[6], uint8_t rat,
|
||||
const uint8_t ra[6], uint8_t res[16]);
|
||||
bool bt_crypto_s1(struct bt_crypto *crypto, const uint8_t k[16],
|
||||
const uint8_t r1[16], const uint8_t r2[16],
|
||||
uint8_t res[16]);
|
||||
bool bt_crypto_f4(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32],
|
||||
uint8_t x[16], uint8_t z, uint8_t res[16]);
|
||||
bool bt_crypto_f5(struct bt_crypto *crypto, uint8_t w[32], uint8_t n1[16],
|
||||
uint8_t n2[16], uint8_t a1[7], uint8_t a2[7],
|
||||
uint8_t mackey[16], uint8_t ltk[16]);
|
||||
bool bt_crypto_f6(struct bt_crypto *crypto, uint8_t w[16], uint8_t n1[16],
|
||||
uint8_t n2[16], uint8_t r[16], uint8_t io_cap[3],
|
||||
uint8_t a1[7], uint8_t a2[7], uint8_t res[16]);
|
||||
bool bt_crypto_g2(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32],
|
||||
uint8_t x[16], uint8_t y[16], uint32_t *val);
|
||||
bool bt_crypto_h6(struct bt_crypto *crypto, const uint8_t w[16],
|
||||
const uint8_t keyid[4], uint8_t res[16]);
|
||||
bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
|
||||
const uint8_t *m, uint16_t m_len,
|
||||
uint32_t sign_cnt, uint8_t signature[12]);
|
|
@ -0,0 +1,861 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ecc.h"
|
||||
|
||||
/* 256-bit curve */
|
||||
#define ECC_BYTES 32
|
||||
|
||||
/* Number of uint64_t's needed */
|
||||
#define NUM_ECC_DIGITS (ECC_BYTES / 8)
|
||||
|
||||
struct ecc_point {
|
||||
uint64_t x[NUM_ECC_DIGITS];
|
||||
uint64_t y[NUM_ECC_DIGITS];
|
||||
};
|
||||
|
||||
#define MAX_TRIES 16
|
||||
|
||||
typedef struct {
|
||||
uint64_t m_low;
|
||||
uint64_t m_high;
|
||||
} uint128_t;
|
||||
|
||||
#define CURVE_P_32 { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \
|
||||
0x0000000000000000ull, 0xFFFFFFFF00000001ull }
|
||||
|
||||
#define CURVE_G_32 { \
|
||||
{ 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, \
|
||||
0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull }, \
|
||||
{ 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, \
|
||||
0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull } \
|
||||
}
|
||||
|
||||
#define CURVE_N_32 { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \
|
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }
|
||||
|
||||
static uint64_t curve_p[NUM_ECC_DIGITS] = CURVE_P_32;
|
||||
static struct ecc_point curve_g = CURVE_G_32;
|
||||
static uint64_t curve_n[NUM_ECC_DIGITS] = CURVE_N_32;
|
||||
|
||||
static bool get_random_number(uint64_t *vli)
|
||||
{
|
||||
char *ptr = (char *) vli;
|
||||
size_t left = ECC_BYTES;
|
||||
int fd;
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (left > 0) {
|
||||
ssize_t ret;
|
||||
|
||||
ret = read(fd, ptr, left);
|
||||
if (ret <= 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
left -= ret;
|
||||
ptr += ret;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vli_clear(uint64_t *vli)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++)
|
||||
vli[i] = 0;
|
||||
}
|
||||
|
||||
/* Returns true if vli == 0, false otherwise. */
|
||||
static bool vli_is_zero(const uint64_t *vli)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
if (vli[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns nonzero if bit bit of vli is set. */
|
||||
static uint64_t vli_test_bit(const uint64_t *vli, unsigned int bit)
|
||||
{
|
||||
return (vli[bit / 64] & ((uint64_t) 1 << (bit % 64)));
|
||||
}
|
||||
|
||||
/* Counts the number of 64-bit "digits" in vli. */
|
||||
static unsigned int vli_num_digits(const uint64_t *vli)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Search from the end until we find a non-zero digit.
|
||||
* We do it in reverse because we expect that most digits will
|
||||
* be nonzero.
|
||||
*/
|
||||
for (i = NUM_ECC_DIGITS - 1; i >= 0 && vli[i] == 0; i--);
|
||||
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
/* Counts the number of bits required for vli. */
|
||||
static unsigned int vli_num_bits(const uint64_t *vli)
|
||||
{
|
||||
unsigned int i, num_digits;
|
||||
uint64_t digit;
|
||||
|
||||
num_digits = vli_num_digits(vli);
|
||||
if (num_digits == 0)
|
||||
return 0;
|
||||
|
||||
digit = vli[num_digits - 1];
|
||||
for (i = 0; digit; i++)
|
||||
digit >>= 1;
|
||||
|
||||
return ((num_digits - 1) * 64 + i);
|
||||
}
|
||||
|
||||
/* Sets dest = src. */
|
||||
static void vli_set(uint64_t *dest, const uint64_t *src)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++)
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
/* Returns sign of left - right. */
|
||||
static int vli_cmp(const uint64_t *left, const uint64_t *right)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = NUM_ECC_DIGITS - 1; i >= 0; i--) {
|
||||
if (left[i] > right[i])
|
||||
return 1;
|
||||
else if (left[i] < right[i])
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Computes result = in << c, returning carry. Can modify in place
|
||||
* (if result == in). 0 < shift < 64.
|
||||
*/
|
||||
static uint64_t vli_lshift(uint64_t *result, const uint64_t *in,
|
||||
unsigned int shift)
|
||||
{
|
||||
uint64_t carry = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
uint64_t temp = in[i];
|
||||
|
||||
result[i] = (temp << shift) | carry;
|
||||
carry = temp >> (64 - shift);
|
||||
}
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
/* Computes vli = vli >> 1. */
|
||||
static void vli_rshift1(uint64_t *vli)
|
||||
{
|
||||
uint64_t *end = vli;
|
||||
uint64_t carry = 0;
|
||||
|
||||
vli += NUM_ECC_DIGITS;
|
||||
|
||||
while (vli-- > end) {
|
||||
uint64_t temp = *vli;
|
||||
*vli = (temp >> 1) | carry;
|
||||
carry = temp << 63;
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes result = left + right, returning carry. Can modify in place. */
|
||||
static uint64_t vli_add(uint64_t *result, const uint64_t *left,
|
||||
const uint64_t *right)
|
||||
{
|
||||
uint64_t carry = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
uint64_t sum;
|
||||
|
||||
sum = left[i] + right[i] + carry;
|
||||
if (sum != left[i])
|
||||
carry = (sum < left[i]);
|
||||
|
||||
result[i] = sum;
|
||||
}
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
/* Computes result = left - right, returning borrow. Can modify in place. */
|
||||
static uint64_t vli_sub(uint64_t *result, const uint64_t *left,
|
||||
const uint64_t *right)
|
||||
{
|
||||
uint64_t borrow = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
uint64_t diff;
|
||||
|
||||
diff = left[i] - right[i] - borrow;
|
||||
if (diff != left[i])
|
||||
borrow = (diff > left[i]);
|
||||
|
||||
result[i] = diff;
|
||||
}
|
||||
|
||||
return borrow;
|
||||
}
|
||||
|
||||
static uint128_t mul_64_64(uint64_t left, uint64_t right)
|
||||
{
|
||||
uint64_t a0 = left & 0xffffffffull;
|
||||
uint64_t a1 = left >> 32;
|
||||
uint64_t b0 = right & 0xffffffffull;
|
||||
uint64_t b1 = right >> 32;
|
||||
uint64_t m0 = a0 * b0;
|
||||
uint64_t m1 = a0 * b1;
|
||||
uint64_t m2 = a1 * b0;
|
||||
uint64_t m3 = a1 * b1;
|
||||
uint128_t result;
|
||||
|
||||
m2 += (m0 >> 32);
|
||||
m2 += m1;
|
||||
|
||||
/* Overflow */
|
||||
if (m2 < m1)
|
||||
m3 += 0x100000000ull;
|
||||
|
||||
result.m_low = (m0 & 0xffffffffull) | (m2 << 32);
|
||||
result.m_high = m3 + (m2 >> 32);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint128_t add_128_128(uint128_t a, uint128_t b)
|
||||
{
|
||||
uint128_t result;
|
||||
|
||||
result.m_low = a.m_low + b.m_low;
|
||||
result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void vli_mult(uint64_t *result, const uint64_t *left,
|
||||
const uint64_t *right)
|
||||
{
|
||||
uint128_t r01 = { 0, 0 };
|
||||
uint64_t r2 = 0;
|
||||
unsigned int i, k;
|
||||
|
||||
/* Compute each digit of result in sequence, maintaining the
|
||||
* carries.
|
||||
*/
|
||||
for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; k++) {
|
||||
unsigned int min;
|
||||
|
||||
if (k < NUM_ECC_DIGITS)
|
||||
min = 0;
|
||||
else
|
||||
min = (k + 1) - NUM_ECC_DIGITS;
|
||||
|
||||
for (i = min; i <= k && i < NUM_ECC_DIGITS; i++) {
|
||||
uint128_t product;
|
||||
|
||||
product = mul_64_64(left[i], right[k - i]);
|
||||
|
||||
r01 = add_128_128(r01, product);
|
||||
r2 += (r01.m_high < product.m_high);
|
||||
}
|
||||
|
||||
result[k] = r01.m_low;
|
||||
r01.m_low = r01.m_high;
|
||||
r01.m_high = r2;
|
||||
r2 = 0;
|
||||
}
|
||||
|
||||
result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
|
||||
}
|
||||
|
||||
static void vli_square(uint64_t *result, const uint64_t *left)
|
||||
{
|
||||
uint128_t r01 = { 0, 0 };
|
||||
uint64_t r2 = 0;
|
||||
int i, k;
|
||||
|
||||
for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; k++) {
|
||||
unsigned int min;
|
||||
|
||||
if (k < NUM_ECC_DIGITS)
|
||||
min = 0;
|
||||
else
|
||||
min = (k + 1) - NUM_ECC_DIGITS;
|
||||
|
||||
for (i = min; i <= k && i <= k - i; i++) {
|
||||
uint128_t product;
|
||||
|
||||
product = mul_64_64(left[i], left[k - i]);
|
||||
|
||||
if (i < k - i) {
|
||||
r2 += product.m_high >> 63;
|
||||
product.m_high = (product.m_high << 1) |
|
||||
(product.m_low >> 63);
|
||||
product.m_low <<= 1;
|
||||
}
|
||||
|
||||
r01 = add_128_128(r01, product);
|
||||
r2 += (r01.m_high < product.m_high);
|
||||
}
|
||||
|
||||
result[k] = r01.m_low;
|
||||
r01.m_low = r01.m_high;
|
||||
r01.m_high = r2;
|
||||
r2 = 0;
|
||||
}
|
||||
|
||||
result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
|
||||
}
|
||||
|
||||
/* Computes result = (left + right) % mod.
|
||||
* Assumes that left < mod and right < mod, result != mod.
|
||||
*/
|
||||
static void vli_mod_add(uint64_t *result, const uint64_t *left,
|
||||
const uint64_t *right, const uint64_t *mod)
|
||||
{
|
||||
uint64_t carry;
|
||||
|
||||
carry = vli_add(result, left, right);
|
||||
|
||||
/* result > mod (result = mod + remainder), so subtract mod to
|
||||
* get remainder.
|
||||
*/
|
||||
if (carry || vli_cmp(result, mod) >= 0)
|
||||
vli_sub(result, result, mod);
|
||||
}
|
||||
|
||||
/* Computes result = (left - right) % mod.
|
||||
* Assumes that left < mod and right < mod, result != mod.
|
||||
*/
|
||||
static void vli_mod_sub(uint64_t *result, const uint64_t *left,
|
||||
const uint64_t *right, const uint64_t *mod)
|
||||
{
|
||||
uint64_t borrow = vli_sub(result, left, right);
|
||||
|
||||
/* In this case, p_result == -diff == (max int) - diff.
|
||||
* Since -x % d == d - x, we can get the correct result from
|
||||
* result + mod (with overflow).
|
||||
*/
|
||||
if (borrow)
|
||||
vli_add(result, result, mod);
|
||||
}
|
||||
|
||||
/* Computes result = product % curve_p
|
||||
from http://www.nsa.gov/ia/_files/nist-routines.pdf */
|
||||
static void vli_mmod_fast(uint64_t *result, const uint64_t *product)
|
||||
{
|
||||
uint64_t tmp[NUM_ECC_DIGITS];
|
||||
int carry;
|
||||
|
||||
/* t */
|
||||
vli_set(result, product);
|
||||
|
||||
/* s1 */
|
||||
tmp[0] = 0;
|
||||
tmp[1] = product[5] & 0xffffffff00000000ull;
|
||||
tmp[2] = product[6];
|
||||
tmp[3] = product[7];
|
||||
carry = vli_lshift(tmp, tmp, 1);
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* s2 */
|
||||
tmp[1] = product[6] << 32;
|
||||
tmp[2] = (product[6] >> 32) | (product[7] << 32);
|
||||
tmp[3] = product[7] >> 32;
|
||||
carry += vli_lshift(tmp, tmp, 1);
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* s3 */
|
||||
tmp[0] = product[4];
|
||||
tmp[1] = product[5] & 0xffffffff;
|
||||
tmp[2] = 0;
|
||||
tmp[3] = product[7];
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* s4 */
|
||||
tmp[0] = (product[4] >> 32) | (product[5] << 32);
|
||||
tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
|
||||
tmp[2] = product[7];
|
||||
tmp[3] = (product[6] >> 32) | (product[4] << 32);
|
||||
carry += vli_add(result, result, tmp);
|
||||
|
||||
/* d1 */
|
||||
tmp[0] = (product[5] >> 32) | (product[6] << 32);
|
||||
tmp[1] = (product[6] >> 32);
|
||||
tmp[2] = 0;
|
||||
tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
/* d2 */
|
||||
tmp[0] = product[6];
|
||||
tmp[1] = product[7];
|
||||
tmp[2] = 0;
|
||||
tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
/* d3 */
|
||||
tmp[0] = (product[6] >> 32) | (product[7] << 32);
|
||||
tmp[1] = (product[7] >> 32) | (product[4] << 32);
|
||||
tmp[2] = (product[4] >> 32) | (product[5] << 32);
|
||||
tmp[3] = (product[6] << 32);
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
/* d4 */
|
||||
tmp[0] = product[7];
|
||||
tmp[1] = product[4] & 0xffffffff00000000ull;
|
||||
tmp[2] = product[5];
|
||||
tmp[3] = product[6] & 0xffffffff00000000ull;
|
||||
carry -= vli_sub(result, result, tmp);
|
||||
|
||||
if (carry < 0) {
|
||||
do {
|
||||
carry += vli_add(result, result, curve_p);
|
||||
} while (carry < 0);
|
||||
} else {
|
||||
while (carry || vli_cmp(curve_p, result) != 1)
|
||||
carry -= vli_sub(result, result, curve_p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes result = (left * right) % curve_p. */
|
||||
static void vli_mod_mult_fast(uint64_t *result, const uint64_t *left,
|
||||
const uint64_t *right)
|
||||
{
|
||||
uint64_t product[2 * NUM_ECC_DIGITS];
|
||||
|
||||
vli_mult(product, left, right);
|
||||
vli_mmod_fast(result, product);
|
||||
}
|
||||
|
||||
/* Computes result = left^2 % curve_p. */
|
||||
static void vli_mod_square_fast(uint64_t *result, const uint64_t *left)
|
||||
{
|
||||
uint64_t product[2 * NUM_ECC_DIGITS];
|
||||
|
||||
vli_square(product, left);
|
||||
vli_mmod_fast(result, product);
|
||||
}
|
||||
|
||||
#define EVEN(vli) (!(vli[0] & 1))
|
||||
/* Computes result = (1 / p_input) % mod. All VLIs are the same size.
|
||||
* See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
|
||||
* https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
|
||||
*/
|
||||
static void vli_mod_inv(uint64_t *result, const uint64_t *input,
|
||||
const uint64_t *mod)
|
||||
{
|
||||
uint64_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS];
|
||||
uint64_t u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS];
|
||||
uint64_t carry;
|
||||
int cmp_result;
|
||||
|
||||
if (vli_is_zero(input)) {
|
||||
vli_clear(result);
|
||||
return;
|
||||
}
|
||||
|
||||
vli_set(a, input);
|
||||
vli_set(b, mod);
|
||||
vli_clear(u);
|
||||
u[0] = 1;
|
||||
vli_clear(v);
|
||||
|
||||
while ((cmp_result = vli_cmp(a, b)) != 0) {
|
||||
carry = 0;
|
||||
|
||||
if (EVEN(a)) {
|
||||
vli_rshift1(a);
|
||||
|
||||
if (!EVEN(u))
|
||||
carry = vli_add(u, u, mod);
|
||||
|
||||
vli_rshift1(u);
|
||||
if (carry)
|
||||
u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
} else if (EVEN(b)) {
|
||||
vli_rshift1(b);
|
||||
|
||||
if (!EVEN(v))
|
||||
carry = vli_add(v, v, mod);
|
||||
|
||||
vli_rshift1(v);
|
||||
if (carry)
|
||||
v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
} else if (cmp_result > 0) {
|
||||
vli_sub(a, a, b);
|
||||
vli_rshift1(a);
|
||||
|
||||
if (vli_cmp(u, v) < 0)
|
||||
vli_add(u, u, mod);
|
||||
|
||||
vli_sub(u, u, v);
|
||||
if (!EVEN(u))
|
||||
carry = vli_add(u, u, mod);
|
||||
|
||||
vli_rshift1(u);
|
||||
if (carry)
|
||||
u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
} else {
|
||||
vli_sub(b, b, a);
|
||||
vli_rshift1(b);
|
||||
|
||||
if (vli_cmp(v, u) < 0)
|
||||
vli_add(v, v, mod);
|
||||
|
||||
vli_sub(v, v, u);
|
||||
if (!EVEN(v))
|
||||
carry = vli_add(v, v, mod);
|
||||
|
||||
vli_rshift1(v);
|
||||
if (carry)
|
||||
v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
|
||||
}
|
||||
}
|
||||
|
||||
vli_set(result, u);
|
||||
}
|
||||
|
||||
/* ------ Point operations ------ */
|
||||
|
||||
/* Returns true if p_point is the point at infinity, false otherwise. */
|
||||
static bool ecc_point_is_zero(const struct ecc_point *point)
|
||||
{
|
||||
return (vli_is_zero(point->x) && vli_is_zero(point->y));
|
||||
}
|
||||
|
||||
/* Point multiplication algorithm using Montgomery's ladder with co-Z
|
||||
* coordinates. From http://eprint.iacr.org/2011/338.pdf
|
||||
*/
|
||||
|
||||
/* Double in place */
|
||||
static void ecc_point_double_jacobian(uint64_t *x1, uint64_t *y1, uint64_t *z1)
|
||||
{
|
||||
/* t1 = x, t2 = y, t3 = z */
|
||||
uint64_t t4[NUM_ECC_DIGITS];
|
||||
uint64_t t5[NUM_ECC_DIGITS];
|
||||
|
||||
if (vli_is_zero(z1))
|
||||
return;
|
||||
|
||||
vli_mod_square_fast(t4, y1); /* t4 = y1^2 */
|
||||
vli_mod_mult_fast(t5, x1, t4); /* t5 = x1*y1^2 = A */
|
||||
vli_mod_square_fast(t4, t4); /* t4 = y1^4 */
|
||||
vli_mod_mult_fast(y1, y1, z1); /* t2 = y1*z1 = z3 */
|
||||
vli_mod_square_fast(z1, z1); /* t3 = z1^2 */
|
||||
|
||||
vli_mod_add(x1, x1, z1, curve_p); /* t1 = x1 + z1^2 */
|
||||
vli_mod_add(z1, z1, z1, curve_p); /* t3 = 2*z1^2 */
|
||||
vli_mod_sub(z1, x1, z1, curve_p); /* t3 = x1 - z1^2 */
|
||||
vli_mod_mult_fast(x1, x1, z1); /* t1 = x1^2 - z1^4 */
|
||||
|
||||
vli_mod_add(z1, x1, x1, curve_p); /* t3 = 2*(x1^2 - z1^4) */
|
||||
vli_mod_add(x1, x1, z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */
|
||||
if (vli_test_bit(x1, 0)) {
|
||||
uint64_t carry = vli_add(x1, x1, curve_p);
|
||||
vli_rshift1(x1);
|
||||
x1[NUM_ECC_DIGITS - 1] |= carry << 63;
|
||||
} else {
|
||||
vli_rshift1(x1);
|
||||
}
|
||||
/* t1 = 3/2*(x1^2 - z1^4) = B */
|
||||
|
||||
vli_mod_square_fast(z1, x1); /* t3 = B^2 */
|
||||
vli_mod_sub(z1, z1, t5, curve_p); /* t3 = B^2 - A */
|
||||
vli_mod_sub(z1, z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */
|
||||
vli_mod_sub(t5, t5, z1, curve_p); /* t5 = A - x3 */
|
||||
vli_mod_mult_fast(x1, x1, t5); /* t1 = B * (A - x3) */
|
||||
vli_mod_sub(t4, x1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */
|
||||
|
||||
vli_set(x1, z1);
|
||||
vli_set(z1, y1);
|
||||
vli_set(y1, t4);
|
||||
}
|
||||
|
||||
/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
|
||||
static void apply_z(uint64_t *x1, uint64_t *y1, uint64_t *z)
|
||||
{
|
||||
uint64_t t1[NUM_ECC_DIGITS];
|
||||
|
||||
vli_mod_square_fast(t1, z); /* z^2 */
|
||||
vli_mod_mult_fast(x1, x1, t1); /* x1 * z^2 */
|
||||
vli_mod_mult_fast(t1, t1, z); /* z^3 */
|
||||
vli_mod_mult_fast(y1, y1, t1); /* y1 * z^3 */
|
||||
}
|
||||
|
||||
/* P = (x1, y1) => 2P, (x2, y2) => P' */
|
||||
static void xycz_initial_double(uint64_t *x1, uint64_t *y1, uint64_t *x2,
|
||||
uint64_t *y2, uint64_t *p_initial_z)
|
||||
{
|
||||
uint64_t z[NUM_ECC_DIGITS];
|
||||
|
||||
vli_set(x2, x1);
|
||||
vli_set(y2, y1);
|
||||
|
||||
vli_clear(z);
|
||||
z[0] = 1;
|
||||
|
||||
if (p_initial_z)
|
||||
vli_set(z, p_initial_z);
|
||||
|
||||
apply_z(x1, y1, z);
|
||||
|
||||
ecc_point_double_jacobian(x1, y1, z);
|
||||
|
||||
apply_z(x2, y2, z);
|
||||
}
|
||||
|
||||
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||
* Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
|
||||
* or P => P', Q => P + Q
|
||||
*/
|
||||
static void xycz_add(uint64_t *x1, uint64_t *y1, uint64_t *x2, uint64_t *y2)
|
||||
{
|
||||
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||
uint64_t t5[NUM_ECC_DIGITS];
|
||||
|
||||
vli_mod_sub(t5, x2, x1, curve_p); /* t5 = x2 - x1 */
|
||||
vli_mod_square_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */
|
||||
vli_mod_mult_fast(x1, x1, t5); /* t1 = x1*A = B */
|
||||
vli_mod_mult_fast(x2, x2, t5); /* t3 = x2*A = C */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y2 - y1 */
|
||||
vli_mod_square_fast(t5, y2); /* t5 = (y2 - y1)^2 = D */
|
||||
|
||||
vli_mod_sub(t5, t5, x1, curve_p); /* t5 = D - B */
|
||||
vli_mod_sub(t5, t5, x2, curve_p); /* t5 = D - B - C = x3 */
|
||||
vli_mod_sub(x2, x2, x1, curve_p); /* t3 = C - B */
|
||||
vli_mod_mult_fast(y1, y1, x2); /* t2 = y1*(C - B) */
|
||||
vli_mod_sub(x2, x1, t5, curve_p); /* t3 = B - x3 */
|
||||
vli_mod_mult_fast(y2, y2, x2); /* t4 = (y2 - y1)*(B - x3) */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y3 */
|
||||
|
||||
vli_set(x2, t5);
|
||||
}
|
||||
|
||||
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||
* Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
|
||||
* or P => P - Q, Q => P + Q
|
||||
*/
|
||||
static void xycz_add_c(uint64_t *x1, uint64_t *y1, uint64_t *x2, uint64_t *y2)
|
||||
{
|
||||
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||
uint64_t t5[NUM_ECC_DIGITS];
|
||||
uint64_t t6[NUM_ECC_DIGITS];
|
||||
uint64_t t7[NUM_ECC_DIGITS];
|
||||
|
||||
vli_mod_sub(t5, x2, x1, curve_p); /* t5 = x2 - x1 */
|
||||
vli_mod_square_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */
|
||||
vli_mod_mult_fast(x1, x1, t5); /* t1 = x1*A = B */
|
||||
vli_mod_mult_fast(x2, x2, t5); /* t3 = x2*A = C */
|
||||
vli_mod_add(t5, y2, y1, curve_p); /* t4 = y2 + y1 */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y2 - y1 */
|
||||
|
||||
vli_mod_sub(t6, x2, x1, curve_p); /* t6 = C - B */
|
||||
vli_mod_mult_fast(y1, y1, t6); /* t2 = y1 * (C - B) */
|
||||
vli_mod_add(t6, x1, x2, curve_p); /* t6 = B + C */
|
||||
vli_mod_square_fast(x2, y2); /* t3 = (y2 - y1)^2 */
|
||||
vli_mod_sub(x2, x2, t6, curve_p); /* t3 = x3 */
|
||||
|
||||
vli_mod_sub(t7, x1, x2, curve_p); /* t7 = B - x3 */
|
||||
vli_mod_mult_fast(y2, y2, t7); /* t4 = (y2 - y1)*(B - x3) */
|
||||
vli_mod_sub(y2, y2, y1, curve_p); /* t4 = y3 */
|
||||
|
||||
vli_mod_square_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */
|
||||
vli_mod_sub(t7, t7, t6, curve_p); /* t7 = x3' */
|
||||
vli_mod_sub(t6, t7, x1, curve_p); /* t6 = x3' - B */
|
||||
vli_mod_mult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */
|
||||
vli_mod_sub(y1, t6, y1, curve_p); /* t2 = y3' */
|
||||
|
||||
vli_set(x1, t7);
|
||||
}
|
||||
|
||||
static void ecc_point_mult(struct ecc_point *result,
|
||||
const struct ecc_point *point,
|
||||
uint64_t *scalar, uint64_t *initial_z,
|
||||
int num_bits)
|
||||
{
|
||||
/* R0 and R1 */
|
||||
uint64_t rx[2][NUM_ECC_DIGITS];
|
||||
uint64_t ry[2][NUM_ECC_DIGITS];
|
||||
uint64_t z[NUM_ECC_DIGITS];
|
||||
int i, nb;
|
||||
|
||||
vli_set(rx[1], point->x);
|
||||
vli_set(ry[1], point->y);
|
||||
|
||||
xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z);
|
||||
|
||||
for (i = num_bits - 2; i > 0; i--) {
|
||||
nb = !vli_test_bit(scalar, i);
|
||||
xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb]);
|
||||
xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb]);
|
||||
}
|
||||
|
||||
nb = !vli_test_bit(scalar, 0);
|
||||
xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb]);
|
||||
|
||||
/* Find final 1/Z value. */
|
||||
vli_mod_sub(z, rx[1], rx[0], curve_p); /* X1 - X0 */
|
||||
vli_mod_mult_fast(z, z, ry[1 - nb]); /* Yb * (X1 - X0) */
|
||||
vli_mod_mult_fast(z, z, point->x); /* xP * Yb * (X1 - X0) */
|
||||
vli_mod_inv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0)) */
|
||||
vli_mod_mult_fast(z, z, point->y); /* yP / (xP * Yb * (X1 - X0)) */
|
||||
vli_mod_mult_fast(z, z, rx[1 - nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */
|
||||
/* End 1/Z calculation */
|
||||
|
||||
xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb]);
|
||||
|
||||
apply_z(rx[0], ry[0], z);
|
||||
|
||||
vli_set(result->x, rx[0]);
|
||||
vli_set(result->y, ry[0]);
|
||||
}
|
||||
|
||||
/* Little endian byte-array to native conversion */
|
||||
static void ecc_bytes2native(const uint8_t bytes[ECC_BYTES],
|
||||
uint64_t native[NUM_ECC_DIGITS])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
const uint8_t *digit = bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
|
||||
|
||||
native[NUM_ECC_DIGITS - 1 - i] =
|
||||
((uint64_t) digit[0] << 0) |
|
||||
((uint64_t) digit[1] << 8) |
|
||||
((uint64_t) digit[2] << 16) |
|
||||
((uint64_t) digit[3] << 24) |
|
||||
((uint64_t) digit[4] << 32) |
|
||||
((uint64_t) digit[5] << 40) |
|
||||
((uint64_t) digit[6] << 48) |
|
||||
((uint64_t) digit[7] << 56);
|
||||
}
|
||||
}
|
||||
|
||||
/* Native to little endian byte-array conversion */
|
||||
static void ecc_native2bytes(const uint64_t native[NUM_ECC_DIGITS],
|
||||
uint8_t bytes[ECC_BYTES])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ECC_DIGITS; i++) {
|
||||
uint8_t *digit = bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
|
||||
|
||||
digit[0] = native[NUM_ECC_DIGITS - 1 - i] >> 0;
|
||||
digit[1] = native[NUM_ECC_DIGITS - 1 - i] >> 8;
|
||||
digit[2] = native[NUM_ECC_DIGITS - 1 - i] >> 16;
|
||||
digit[3] = native[NUM_ECC_DIGITS - 1 - i] >> 24;
|
||||
digit[4] = native[NUM_ECC_DIGITS - 1 - i] >> 32;
|
||||
digit[5] = native[NUM_ECC_DIGITS - 1 - i] >> 40;
|
||||
digit[6] = native[NUM_ECC_DIGITS - 1 - i] >> 48;
|
||||
digit[7] = native[NUM_ECC_DIGITS - 1 - i] >> 56;
|
||||
}
|
||||
}
|
||||
|
||||
bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32])
|
||||
{
|
||||
struct ecc_point pk;
|
||||
uint64_t priv[NUM_ECC_DIGITS];
|
||||
unsigned tries = 0;
|
||||
|
||||
do {
|
||||
if (!get_random_number(priv) || (tries++ >= MAX_TRIES))
|
||||
return false;
|
||||
|
||||
if (vli_is_zero(priv))
|
||||
continue;
|
||||
|
||||
/* Make sure the private key is in the range [1, n-1]. */
|
||||
if (vli_cmp(curve_n, priv) != 1)
|
||||
continue;
|
||||
|
||||
ecc_point_mult(&pk, &curve_g, priv, NULL, vli_num_bits(priv));
|
||||
} while (ecc_point_is_zero(&pk));
|
||||
|
||||
ecc_native2bytes(priv, private_key);
|
||||
ecc_native2bytes(pk.x, public_key);
|
||||
ecc_native2bytes(pk.y, &public_key[32]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdh_shared_secret(const uint8_t public_key[64],
|
||||
const uint8_t private_key[32],
|
||||
uint8_t secret[32])
|
||||
{
|
||||
uint64_t priv[NUM_ECC_DIGITS];
|
||||
uint64_t rand[NUM_ECC_DIGITS];
|
||||
struct ecc_point product, pk;
|
||||
|
||||
if (!get_random_number(rand))
|
||||
return false;
|
||||
|
||||
ecc_bytes2native(public_key, pk.x);
|
||||
ecc_bytes2native(&public_key[32], pk.y);
|
||||
ecc_bytes2native(private_key, priv);
|
||||
|
||||
ecc_point_mult(&product, &pk, priv, rand, vli_num_bits(priv));
|
||||
|
||||
ecc_native2bytes(product.x, secret);
|
||||
|
||||
return !ecc_point_is_zero(&product);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Create a public/private key pair.
|
||||
* Outputs:
|
||||
* public_key - Will be filled in with the public key.
|
||||
* private_Key - Will be filled in with the private key.
|
||||
*
|
||||
* Returns true if the key pair was generated successfully, false
|
||||
* if an error occurred. They keys are with the LSB first.
|
||||
*/
|
||||
bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]);
|
||||
|
||||
/* Compute a shared secret given your secret key and someone else's
|
||||
* public key.
|
||||
* Note: It is recommended that you hash the result of ecdh_shared_secret
|
||||
* before using it for symmetric encryption or HMAC.
|
||||
*
|
||||
* Inputs:
|
||||
* public_key - The public key of the remote party.
|
||||
* private_Key - Your private key.
|
||||
*
|
||||
* Outputs:
|
||||
* secret - Will be filled in with the shared secret value.
|
||||
*
|
||||
* Returns true if the shared secret was generated successfully, false
|
||||
* if an error occurred. Both input and output parameters are with the
|
||||
* LSB first.
|
||||
*/
|
||||
bool ecdh_shared_secret(const uint8_t public_key[64],
|
||||
const uint8_t private_key[32],
|
||||
uint8_t secret[32]);
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lib/bluetooth.h"
|
||||
#include "lib/mgmt.h"
|
||||
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/queue.h"
|
||||
#include "src/shared/mgmt.h"
|
||||
#include "src/shared/gap.h"
|
||||
|
||||
#define FLAG_MGMT_CONN_CONTROL (0 << 1)
|
||||
|
||||
struct bt_gap {
|
||||
int ref_count;
|
||||
uint16_t index;
|
||||
struct mgmt *mgmt;
|
||||
|
||||
uint8_t mgmt_version;
|
||||
uint16_t mgmt_revision;
|
||||
bool mgmt_ready;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
bt_gap_ready_func_t ready_handler;
|
||||
bt_gap_destroy_func_t ready_destroy;
|
||||
void *ready_data;
|
||||
|
||||
uint8_t static_addr[6];
|
||||
uint8_t local_irk[16];
|
||||
struct queue *irk_list;
|
||||
};
|
||||
|
||||
struct irk_entry {
|
||||
uint8_t addr_type;
|
||||
uint8_t addr[6];
|
||||
uint8_t key[16];
|
||||
};
|
||||
|
||||
static void irk_entry_free(void *data)
|
||||
{
|
||||
struct irk_entry *irk = data;
|
||||
|
||||
free(irk);
|
||||
}
|
||||
|
||||
static void ready_status(struct bt_gap *gap, bool status)
|
||||
{
|
||||
gap->mgmt_ready = status;
|
||||
|
||||
if (gap->ready_handler)
|
||||
gap->ready_handler(status, gap->ready_data);
|
||||
}
|
||||
|
||||
static void read_commands_complete(uint8_t status, uint16_t length,
|
||||
const void *param, void *user_data)
|
||||
{
|
||||
struct bt_gap *gap = user_data;
|
||||
const struct mgmt_rp_read_commands *rp = param;
|
||||
uint16_t num_commands, num_events;
|
||||
const uint16_t *opcode;
|
||||
size_t expected_len;
|
||||
int i;
|
||||
|
||||
if (status != MGMT_STATUS_SUCCESS) {
|
||||
ready_status(gap, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length < sizeof(*rp)) {
|
||||
ready_status(gap, false);
|
||||
return;
|
||||
}
|
||||
|
||||
num_commands = le16_to_cpu(rp->num_commands);
|
||||
num_events = le16_to_cpu(rp->num_events);
|
||||
|
||||
expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
|
||||
num_events * sizeof(uint16_t);
|
||||
|
||||
if (length < expected_len) {
|
||||
ready_status(gap, false);
|
||||
return;
|
||||
}
|
||||
|
||||
opcode = rp->opcodes;
|
||||
|
||||
for (i = 0; i < num_commands; i++) {
|
||||
uint16_t op = get_le16(opcode++);
|
||||
|
||||
if (op == MGMT_OP_ADD_DEVICE)
|
||||
gap->flags |= FLAG_MGMT_CONN_CONTROL;
|
||||
}
|
||||
|
||||
ready_status(gap, true);
|
||||
}
|
||||
|
||||
static void read_version_complete(uint8_t status, uint16_t length,
|
||||
const void *param, void *user_data)
|
||||
{
|
||||
struct bt_gap *gap = user_data;
|
||||
const struct mgmt_rp_read_version *rp = param;
|
||||
|
||||
if (status != MGMT_STATUS_SUCCESS) {
|
||||
ready_status(gap, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (length < sizeof(*rp)) {
|
||||
ready_status(gap, false);
|
||||
return;
|
||||
}
|
||||
|
||||
gap->mgmt_version = rp->version;
|
||||
gap->mgmt_revision = le16_to_cpu(rp->revision);
|
||||
|
||||
if (!mgmt_send(gap->mgmt, MGMT_OP_READ_COMMANDS,
|
||||
MGMT_INDEX_NONE, 0, NULL,
|
||||
read_commands_complete, gap, NULL)) {
|
||||
ready_status(gap, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct bt_gap *bt_gap_new_default(void)
|
||||
{
|
||||
return bt_gap_new_index(0x0000);
|
||||
}
|
||||
|
||||
struct bt_gap *bt_gap_new_index(uint16_t index)
|
||||
{
|
||||
struct bt_gap *gap;
|
||||
|
||||
if (index == MGMT_INDEX_NONE)
|
||||
return NULL;
|
||||
|
||||
gap = new0(struct bt_gap, 1);
|
||||
gap->index = index;
|
||||
|
||||
gap->mgmt = mgmt_new_default();
|
||||
if (!gap->mgmt) {
|
||||
free(gap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gap->irk_list = queue_new();
|
||||
gap->mgmt_ready = false;
|
||||
|
||||
if (!mgmt_send(gap->mgmt, MGMT_OP_READ_VERSION,
|
||||
MGMT_INDEX_NONE, 0, NULL,
|
||||
read_version_complete, gap, NULL)) {
|
||||
mgmt_unref(gap->mgmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bt_gap_ref(gap);
|
||||
}
|
||||
|
||||
struct bt_gap *bt_gap_ref(struct bt_gap *gap)
|
||||
{
|
||||
if (!gap)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&gap->ref_count, 1);
|
||||
|
||||
return gap;
|
||||
}
|
||||
|
||||
void bt_gap_unref(struct bt_gap *gap)
|
||||
{
|
||||
if (!gap)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&gap->ref_count, 1))
|
||||
return;
|
||||
|
||||
gap->mgmt_ready = false;
|
||||
|
||||
mgmt_cancel_all(gap->mgmt);
|
||||
mgmt_unregister_all(gap->mgmt);
|
||||
|
||||
if (gap->ready_destroy)
|
||||
gap->ready_destroy(gap->ready_data);
|
||||
|
||||
queue_destroy(gap->irk_list, irk_entry_free);
|
||||
|
||||
mgmt_unref(gap->mgmt);
|
||||
|
||||
free(gap);
|
||||
}
|
||||
|
||||
bool bt_gap_set_ready_handler(struct bt_gap *gap,
|
||||
bt_gap_ready_func_t handler, void *user_data,
|
||||
bt_gap_destroy_func_t destroy)
|
||||
{
|
||||
if (!gap)
|
||||
return false;
|
||||
|
||||
if (gap->ready_destroy)
|
||||
gap->ready_destroy(gap->ready_data);
|
||||
|
||||
gap->ready_handler = handler;
|
||||
gap->ready_destroy = destroy;
|
||||
gap->ready_data = user_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_gap_set_static_addr(struct bt_gap *gap, uint8_t addr[6])
|
||||
{
|
||||
if (!gap)
|
||||
return false;
|
||||
|
||||
memcpy(gap->static_addr, addr, 6);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_gap_set_local_irk(struct bt_gap *gap, uint8_t key[16])
|
||||
{
|
||||
if (!gap)
|
||||
return false;
|
||||
|
||||
memcpy(gap->local_irk, key, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_gap_add_peer_irk(struct bt_gap *gap, uint8_t addr_type,
|
||||
uint8_t addr[6], uint8_t key[16])
|
||||
{
|
||||
struct irk_entry *irk;
|
||||
|
||||
if (!gap)
|
||||
return false;
|
||||
|
||||
if (addr_type > BT_GAP_ADDR_TYPE_LE_RANDOM)
|
||||
return false;
|
||||
|
||||
irk = new0(struct irk_entry, 1);
|
||||
irk->addr_type = addr_type;
|
||||
memcpy(irk->addr, addr, 6);
|
||||
memcpy(irk->key, key, 16);
|
||||
|
||||
if (!queue_push_tail(gap->irk_list, irk)) {
|
||||
free(irk);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BT_GAP_ADDR_TYPE_BREDR 0x00
|
||||
#define BT_GAP_ADDR_TYPE_LE_PUBLIC 0x01
|
||||
#define BT_GAP_ADDR_TYPE_LE_RANDOM 0x02
|
||||
|
||||
struct bt_gap;
|
||||
|
||||
struct bt_gap *bt_gap_new_default(void);
|
||||
struct bt_gap *bt_gap_new_index(uint16_t index);
|
||||
|
||||
struct bt_gap *bt_gap_ref(struct bt_gap *gap);
|
||||
void bt_gap_unref(struct bt_gap *gap);
|
||||
|
||||
typedef void (*bt_gap_destroy_func_t)(void *user_data);
|
||||
typedef void (*bt_gap_ready_func_t)(bool success, void *user_data);
|
||||
|
||||
bool bt_gap_set_ready_handler(struct bt_gap *gap,
|
||||
bt_gap_ready_func_t handler, void *user_data,
|
||||
bt_gap_destroy_func_t destroy);
|
||||
|
||||
bool bt_gap_set_static_addr(struct bt_gap *gap, uint8_t addr[6]);
|
||||
bool bt_gap_set_local_irk(struct bt_gap *gap, uint8_t key[16]);
|
||||
bool bt_gap_add_peer_irk(struct bt_gap *gap, uint8_t addr_type,
|
||||
uint8_t addr[6], uint8_t key[16]);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define BT_GATT_UUID_SIZE 16
|
||||
|
||||
struct bt_gatt_client;
|
||||
|
||||
struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
|
||||
struct bt_att *att,
|
||||
uint16_t mtu);
|
||||
struct bt_gatt_client *bt_gatt_client_clone(struct bt_gatt_client *client);
|
||||
|
||||
struct bt_gatt_client *bt_gatt_client_ref(struct bt_gatt_client *client);
|
||||
void bt_gatt_client_unref(struct bt_gatt_client *client);
|
||||
|
||||
typedef void (*bt_gatt_client_destroy_func_t)(void *user_data);
|
||||
typedef void (*bt_gatt_client_callback_t)(bool success, uint8_t att_ecode,
|
||||
void *user_data);
|
||||
typedef void (*bt_gatt_client_debug_func_t)(const char *str, void *user_data);
|
||||
typedef void (*bt_gatt_client_read_callback_t)(bool success, uint8_t att_ecode,
|
||||
const uint8_t *value, uint16_t length,
|
||||
void *user_data);
|
||||
typedef void (*bt_gatt_client_write_long_callback_t)(bool success,
|
||||
bool reliable_error, uint8_t att_ecode,
|
||||
void *user_data);
|
||||
typedef void (*bt_gatt_client_notify_callback_t)(uint16_t value_handle,
|
||||
const uint8_t *value, uint16_t length,
|
||||
void *user_data);
|
||||
typedef void (*bt_gatt_client_register_callback_t)(uint16_t att_ecode,
|
||||
void *user_data);
|
||||
typedef void (*bt_gatt_client_service_changed_callback_t)(uint16_t start_handle,
|
||||
uint16_t end_handle,
|
||||
void *user_data);
|
||||
|
||||
bool bt_gatt_client_is_ready(struct bt_gatt_client *client);
|
||||
bool bt_gatt_client_set_ready_handler(struct bt_gatt_client *client,
|
||||
bt_gatt_client_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
bool bt_gatt_client_set_service_changed(struct bt_gatt_client *client,
|
||||
bt_gatt_client_service_changed_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
bool bt_gatt_client_set_debug(struct bt_gatt_client *client,
|
||||
bt_gatt_client_debug_func_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
|
||||
uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client);
|
||||
struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client);
|
||||
|
||||
bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id);
|
||||
bool bt_gatt_client_cancel_all(struct bt_gatt_client *client);
|
||||
|
||||
unsigned int bt_gatt_client_read_value(struct bt_gatt_client *client,
|
||||
uint16_t value_handle,
|
||||
bt_gatt_client_read_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client,
|
||||
uint16_t value_handle, uint16_t offset,
|
||||
bt_gatt_client_read_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
|
||||
uint16_t *handles, uint8_t num_handles,
|
||||
bt_gatt_client_read_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
|
||||
unsigned int bt_gatt_client_write_without_response(
|
||||
struct bt_gatt_client *client,
|
||||
uint16_t value_handle,
|
||||
bool signed_write,
|
||||
const uint8_t *value, uint16_t length);
|
||||
unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client,
|
||||
uint16_t value_handle,
|
||||
const uint8_t *value, uint16_t length,
|
||||
bt_gatt_client_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
|
||||
bool reliable,
|
||||
uint16_t value_handle, uint16_t offset,
|
||||
const uint8_t *value, uint16_t length,
|
||||
bt_gatt_client_write_long_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
unsigned int bt_gatt_client_prepare_write(struct bt_gatt_client *client,
|
||||
unsigned int id,
|
||||
uint16_t value_handle, uint16_t offset,
|
||||
const uint8_t *value, uint16_t length,
|
||||
bt_gatt_client_write_long_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
unsigned int bt_gatt_client_write_execute(struct bt_gatt_client *client,
|
||||
unsigned int id,
|
||||
bt_gatt_client_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
|
||||
unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
|
||||
uint16_t chrc_value_handle,
|
||||
bt_gatt_client_register_callback_t callback,
|
||||
bt_gatt_client_notify_callback_t notify,
|
||||
void *user_data,
|
||||
bt_gatt_client_destroy_func_t destroy);
|
||||
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
|
||||
unsigned int id);
|
||||
|
||||
bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level);
|
||||
int bt_gatt_client_get_security(struct bt_gatt_client *client);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
struct gatt_db;
|
||||
struct gatt_db_attribute;
|
||||
|
||||
struct gatt_db *gatt_db_new(void);
|
||||
|
||||
struct gatt_db *gatt_db_ref(struct gatt_db *db);
|
||||
void gatt_db_unref(struct gatt_db *db);
|
||||
|
||||
bool gatt_db_isempty(struct gatt_db *db);
|
||||
|
||||
struct gatt_db_attribute *gatt_db_add_service(struct gatt_db *db,
|
||||
const bt_uuid_t *uuid,
|
||||
bool primary,
|
||||
uint16_t num_handles);
|
||||
|
||||
bool gatt_db_remove_service(struct gatt_db *db,
|
||||
struct gatt_db_attribute *attrib);
|
||||
bool gatt_db_clear(struct gatt_db *db);
|
||||
bool gatt_db_clear_range(struct gatt_db *db, uint16_t start_handle,
|
||||
uint16_t end_handle);
|
||||
|
||||
struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
|
||||
uint16_t handle,
|
||||
const bt_uuid_t *uuid,
|
||||
bool primary,
|
||||
uint16_t num_handles);
|
||||
|
||||
typedef void (*gatt_db_read_t) (struct gatt_db_attribute *attrib,
|
||||
unsigned int id, uint16_t offset,
|
||||
uint8_t opcode, struct bt_att *att,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*gatt_db_write_t) (struct gatt_db_attribute *attrib,
|
||||
unsigned int id, uint16_t offset,
|
||||
const uint8_t *value, size_t len,
|
||||
uint8_t opcode, struct bt_att *att,
|
||||
void *user_data);
|
||||
|
||||
struct gatt_db_attribute *
|
||||
gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
|
||||
const bt_uuid_t *uuid,
|
||||
uint32_t permissions,
|
||||
uint8_t properties,
|
||||
gatt_db_read_t read_func,
|
||||
gatt_db_write_t write_func,
|
||||
void *user_data);
|
||||
struct gatt_db_attribute *
|
||||
gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
|
||||
uint16_t handle,
|
||||
const bt_uuid_t *uuid,
|
||||
uint32_t permissions,
|
||||
uint8_t properties,
|
||||
gatt_db_read_t read_func,
|
||||
gatt_db_write_t write_func,
|
||||
void *user_data);
|
||||
|
||||
struct gatt_db_attribute *
|
||||
gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
|
||||
const bt_uuid_t *uuid,
|
||||
uint32_t permissions,
|
||||
gatt_db_read_t read_func,
|
||||
gatt_db_write_t write_func,
|
||||
void *user_data);
|
||||
struct gatt_db_attribute *
|
||||
gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
|
||||
uint16_t handle,
|
||||
const bt_uuid_t *uuid,
|
||||
uint32_t permissions,
|
||||
gatt_db_read_t read_func,
|
||||
gatt_db_write_t write_func,
|
||||
void *user_data);
|
||||
|
||||
struct gatt_db_attribute *
|
||||
gatt_db_service_add_included(struct gatt_db_attribute *attrib,
|
||||
struct gatt_db_attribute *include);
|
||||
|
||||
bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active);
|
||||
bool gatt_db_service_get_active(struct gatt_db_attribute *attrib);
|
||||
|
||||
bool gatt_db_service_set_claimed(struct gatt_db_attribute *attrib,
|
||||
bool claimed);
|
||||
bool gatt_db_service_get_claimed(struct gatt_db_attribute *attrib);
|
||||
|
||||
typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
|
||||
void *user_data);
|
||||
|
||||
void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
|
||||
uint16_t end_handle,
|
||||
const bt_uuid_t type,
|
||||
struct queue *queue);
|
||||
|
||||
unsigned int gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
|
||||
uint16_t end_handle,
|
||||
const bt_uuid_t *type,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
|
||||
unsigned int gatt_db_find_by_type_value(struct gatt_db *db,
|
||||
uint16_t start_handle,
|
||||
uint16_t end_handle,
|
||||
const bt_uuid_t *type,
|
||||
const void *value,
|
||||
size_t value_len,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
|
||||
void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
|
||||
uint16_t end_handle,
|
||||
const bt_uuid_t type,
|
||||
struct queue *queue);
|
||||
|
||||
void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
|
||||
uint16_t end_handle,
|
||||
struct queue *queue);
|
||||
|
||||
|
||||
void gatt_db_foreach_service(struct gatt_db *db, const bt_uuid_t *uuid,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
void gatt_db_foreach_service_in_range(struct gatt_db *db,
|
||||
const bt_uuid_t *uuid,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data,
|
||||
uint16_t start_handle,
|
||||
uint16_t end_handle);
|
||||
|
||||
void gatt_db_service_foreach(struct gatt_db_attribute *attrib,
|
||||
const bt_uuid_t *uuid,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
void gatt_db_service_foreach_char(struct gatt_db_attribute *attrib,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
void gatt_db_service_foreach_incl(struct gatt_db_attribute *attrib,
|
||||
gatt_db_attribute_cb_t func,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*gatt_db_destroy_func_t)(void *user_data);
|
||||
|
||||
unsigned int gatt_db_register(struct gatt_db *db,
|
||||
gatt_db_attribute_cb_t service_added,
|
||||
gatt_db_attribute_cb_t service_removed,
|
||||
void *user_data,
|
||||
gatt_db_destroy_func_t destroy);
|
||||
bool gatt_db_unregister(struct gatt_db *db, unsigned int id);
|
||||
|
||||
struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
|
||||
uint16_t handle);
|
||||
|
||||
struct gatt_db_attribute *gatt_db_get_service_with_uuid(struct gatt_db *db,
|
||||
const bt_uuid_t *uuid);
|
||||
|
||||
const bt_uuid_t *gatt_db_attribute_get_type(
|
||||
const struct gatt_db_attribute *attrib);
|
||||
|
||||
uint16_t gatt_db_attribute_get_handle(const struct gatt_db_attribute *attrib);
|
||||
|
||||
bool gatt_db_attribute_get_service_uuid(const struct gatt_db_attribute *attrib,
|
||||
bt_uuid_t *uuid);
|
||||
|
||||
bool gatt_db_attribute_get_service_handles(
|
||||
const struct gatt_db_attribute *attrib,
|
||||
uint16_t *start_handle,
|
||||
uint16_t *end_handle);
|
||||
|
||||
bool gatt_db_attribute_get_service_data(const struct gatt_db_attribute *attrib,
|
||||
uint16_t *start_handle,
|
||||
uint16_t *end_handle,
|
||||
bool *primary,
|
||||
bt_uuid_t *uuid);
|
||||
|
||||
bool gatt_db_attribute_get_char_data(const struct gatt_db_attribute *attrib,
|
||||
uint16_t *handle,
|
||||
uint16_t *value_handle,
|
||||
uint8_t *properties,
|
||||
uint16_t *ext_prop,
|
||||
bt_uuid_t *uuid);
|
||||
|
||||
bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
|
||||
uint16_t *handle,
|
||||
uint16_t *start_handle,
|
||||
uint16_t *end_handle);
|
||||
|
||||
uint32_t
|
||||
gatt_db_attribute_get_permissions(const struct gatt_db_attribute *attrib);
|
||||
|
||||
typedef void (*gatt_db_attribute_read_t) (struct gatt_db_attribute *attrib,
|
||||
int err, const uint8_t *value,
|
||||
size_t length, void *user_data);
|
||||
|
||||
bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
|
||||
uint8_t opcode, struct bt_att *att,
|
||||
gatt_db_attribute_read_t func, void *user_data);
|
||||
|
||||
bool gatt_db_attribute_read_result(struct gatt_db_attribute *attrib,
|
||||
unsigned int id, int err,
|
||||
const uint8_t *value, size_t length);
|
||||
|
||||
typedef void (*gatt_db_attribute_write_t) (struct gatt_db_attribute *attrib,
|
||||
int err, void *user_data);
|
||||
|
||||
bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
|
||||
const uint8_t *value, size_t len,
|
||||
uint8_t opcode, struct bt_att *att,
|
||||
gatt_db_attribute_write_t func,
|
||||
void *user_data);
|
||||
|
||||
bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib,
|
||||
unsigned int id, int err);
|
||||
|
||||
bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* This file defines helpers for performing client-side procedures defined by
|
||||
* the Generic Attribute Profile.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct bt_gatt_result;
|
||||
|
||||
struct bt_gatt_iter {
|
||||
struct bt_gatt_result *result;
|
||||
uint16_t pos;
|
||||
};
|
||||
|
||||
unsigned int bt_gatt_result_service_count(struct bt_gatt_result *result);
|
||||
unsigned int bt_gatt_result_characteristic_count(struct bt_gatt_result *result);
|
||||
unsigned int bt_gatt_result_descriptor_count(struct bt_gatt_result *result);
|
||||
unsigned int bt_gatt_result_included_count(struct bt_gatt_result *result);
|
||||
|
||||
bool bt_gatt_iter_init(struct bt_gatt_iter *iter, struct bt_gatt_result *result);
|
||||
bool bt_gatt_iter_next_service(struct bt_gatt_iter *iter,
|
||||
uint16_t *start_handle, uint16_t *end_handle,
|
||||
uint8_t uuid[16]);
|
||||
bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter,
|
||||
uint16_t *start_handle, uint16_t *end_handle,
|
||||
uint16_t *value_handle, uint8_t *properties,
|
||||
uint8_t uuid[16]);
|
||||
bool bt_gatt_iter_next_descriptor(struct bt_gatt_iter *iter, uint16_t *handle,
|
||||
uint8_t uuid[16]);
|
||||
bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
|
||||
uint16_t *handle, uint16_t *start_handle,
|
||||
uint16_t *end_handle, uint8_t uuid[16]);
|
||||
bool bt_gatt_iter_next_read_by_type(struct bt_gatt_iter *iter,
|
||||
uint16_t *handle, uint16_t *length,
|
||||
const uint8_t **value);
|
||||
|
||||
typedef void (*bt_gatt_destroy_func_t)(void *user_data);
|
||||
|
||||
typedef void (*bt_gatt_result_callback_t)(bool success, uint8_t att_ecode,
|
||||
void *user_data);
|
||||
typedef void (*bt_gatt_request_callback_t)(bool success, uint8_t att_ecode,
|
||||
struct bt_gatt_result *result,
|
||||
void *user_data);
|
||||
|
||||
struct bt_gatt_request;
|
||||
|
||||
struct bt_gatt_request *bt_gatt_request_ref(struct bt_gatt_request *req);
|
||||
void bt_gatt_request_unref(struct bt_gatt_request *req);
|
||||
void bt_gatt_request_cancel(struct bt_gatt_request *req);
|
||||
|
||||
unsigned int bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
|
||||
bt_gatt_result_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
|
||||
struct bt_gatt_request *bt_gatt_discover_all_primary_services(
|
||||
struct bt_att *att, bt_uuid_t *uuid,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
struct bt_gatt_request *bt_gatt_discover_primary_services(
|
||||
struct bt_att *att, bt_uuid_t *uuid,
|
||||
uint16_t start, uint16_t end,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
struct bt_gatt_request *bt_gatt_discover_secondary_services(
|
||||
struct bt_att *att, bt_uuid_t *uuid,
|
||||
uint16_t start, uint16_t end,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
struct bt_gatt_request *bt_gatt_discover_included_services(struct bt_att *att,
|
||||
uint16_t start, uint16_t end,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
struct bt_gatt_request *bt_gatt_discover_characteristics(struct bt_att *att,
|
||||
uint16_t start, uint16_t end,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
struct bt_gatt_request *bt_gatt_discover_descriptors(struct bt_att *att,
|
||||
uint16_t start, uint16_t end,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
||||
|
||||
bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
|
||||
const bt_uuid_t *uuid,
|
||||
bt_gatt_request_callback_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_destroy_func_t destroy);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2014 Google Inc.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct bt_gatt_server;
|
||||
|
||||
struct bt_gatt_server *bt_gatt_server_new(struct gatt_db *db,
|
||||
struct bt_att *att, uint16_t mtu);
|
||||
|
||||
struct bt_gatt_server *bt_gatt_server_ref(struct bt_gatt_server *server);
|
||||
void bt_gatt_server_unref(struct bt_gatt_server *server);
|
||||
|
||||
typedef void (*bt_gatt_server_destroy_func_t)(void *user_data);
|
||||
typedef void (*bt_gatt_server_debug_func_t)(const char *str, void *user_data);
|
||||
typedef void (*bt_gatt_server_conf_func_t)(void *user_data);
|
||||
|
||||
bool bt_gatt_server_set_debug(struct bt_gatt_server *server,
|
||||
bt_gatt_server_debug_func_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_server_destroy_func_t destroy);
|
||||
|
||||
bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
|
||||
uint16_t handle, const uint8_t *value,
|
||||
uint16_t length);
|
||||
|
||||
bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
|
||||
uint16_t handle, const uint8_t *value,
|
||||
uint16_t length,
|
||||
bt_gatt_server_conf_func_t callback,
|
||||
void *user_data,
|
||||
bt_gatt_server_destroy_func_t destroy);
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013-2014 Intel Corporation
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "monitor/bt.h"
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/hci.h"
|
||||
#include "src/shared/hci-crypto.h"
|
||||
|
||||
struct crypto_data {
|
||||
uint8_t size;
|
||||
bt_hci_crypto_func_t callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void le_encrypt_callback(const void *response, uint8_t size,
|
||||
void *user_data)
|
||||
{
|
||||
struct crypto_data *data = user_data;
|
||||
const struct bt_hci_rsp_le_encrypt *rsp = response;
|
||||
|
||||
if (rsp->status) {
|
||||
data->callback(NULL, 0, data->user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
data->callback(rsp->data, data->size, data->user_data);
|
||||
}
|
||||
|
||||
static bool le_encrypt(struct bt_hci *hci, uint8_t size,
|
||||
const uint8_t key[16], const uint8_t plaintext[16],
|
||||
bt_hci_crypto_func_t callback, void *user_data)
|
||||
{
|
||||
struct crypto_data *data;
|
||||
struct bt_hci_cmd_le_encrypt cmd;
|
||||
|
||||
if (!callback || !size || size > 16)
|
||||
return false;
|
||||
|
||||
memcpy(cmd.key, key, 16);
|
||||
memcpy(cmd.plaintext, plaintext, 16);
|
||||
|
||||
data = new0(struct crypto_data, 1);
|
||||
data->size = size;
|
||||
data->callback = callback;
|
||||
data->user_data = user_data;
|
||||
|
||||
if (!bt_hci_send(hci, BT_HCI_CMD_LE_ENCRYPT, &cmd, sizeof(cmd),
|
||||
le_encrypt_callback, data, free)) {
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void prand_callback(const void *response, uint8_t size,
|
||||
void *user_data)
|
||||
{
|
||||
struct crypto_data *data = user_data;
|
||||
const struct bt_hci_rsp_le_rand *rsp = response;
|
||||
uint8_t prand[3];
|
||||
|
||||
if (rsp->status) {
|
||||
data->callback(NULL, 0, data->user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
prand[0] = (rsp->number & 0xff0000) >> 16;
|
||||
prand[1] = (rsp->number & 0x00ff00) >> 8;
|
||||
prand[2] = (rsp->number & 0x00003f) | 0x40;
|
||||
|
||||
data->callback(prand, 3, data->user_data);
|
||||
}
|
||||
|
||||
bool bt_hci_crypto_prand(struct bt_hci *hci,
|
||||
bt_hci_crypto_func_t callback, void *user_data)
|
||||
{
|
||||
struct crypto_data *data;
|
||||
|
||||
if (!callback)
|
||||
return false;
|
||||
|
||||
data = new0(struct crypto_data, 1);
|
||||
data->callback = callback;
|
||||
data->user_data = user_data;
|
||||
|
||||
if (!bt_hci_send(hci, BT_HCI_CMD_LE_RAND, NULL, 0,
|
||||
prand_callback, data, free)) {
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_hci_crypto_e(struct bt_hci *hci,
|
||||
const uint8_t key[16], const uint8_t plaintext[16],
|
||||
bt_hci_crypto_func_t callback, void *user_data)
|
||||
{
|
||||
return le_encrypt(hci, 16, key, plaintext, callback, user_data);
|
||||
}
|
||||
|
||||
bool bt_hci_crypto_d1(struct bt_hci *hci,
|
||||
const uint8_t k[16], uint16_t d, uint16_t r,
|
||||
bt_hci_crypto_func_t callback, void *user_data)
|
||||
{
|
||||
uint8_t dp[16];
|
||||
|
||||
/* d' = padding || r || d */
|
||||
dp[0] = d & 0xff;
|
||||
dp[1] = d >> 8;
|
||||
dp[2] = r & 0xff;
|
||||
dp[3] = r >> 8;
|
||||
memset(dp + 4, 0, 12);
|
||||
|
||||
/* d1(k, d, r) = e(k, d') */
|
||||
return le_encrypt(hci, 16, k, dp, callback, user_data);
|
||||
}
|
||||
|
||||
bool bt_hci_crypto_dm(struct bt_hci *hci,
|
||||
const uint8_t k[16], const uint8_t r[8],
|
||||
bt_hci_crypto_func_t callback, void *user_data)
|
||||
{
|
||||
uint8_t rp[16];
|
||||
|
||||
/* r' = padding || r */
|
||||
memcpy(rp, r, 8);
|
||||
memset(rp + 8, 0, 8);
|
||||
|
||||
/* dm(k, r) = e(k, r') mod 2^16 */
|
||||
return le_encrypt(hci, 8, k, rp, callback, user_data);
|
||||
}
|
||||
|
||||
bool bt_hci_crypto_ah(struct bt_hci *hci,
|
||||
const uint8_t k[16], const uint8_t r[3],
|
||||
bt_hci_crypto_func_t callback, void *user_data)
|
||||
{
|
||||
uint8_t rp[16];
|
||||
|
||||
/* r' = padding || r */
|
||||
memcpy(rp, r, 3);
|
||||
memset(rp + 3, 0, 13);
|
||||
|
||||
/* ah(k, r) = e(k, r') mod 2^24 */
|
||||
return le_encrypt(hci, 3, k, rp, callback, user_data);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2013-2014 Intel Corporation
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct bt_hci;
|
||||
|
||||
typedef void (*bt_hci_crypto_func_t)(const void *data, uint8_t size,
|
||||
void *user_data);
|
||||
|
||||
bool bt_hci_crypto_prand(struct bt_hci *hci,
|
||||
bt_hci_crypto_func_t callback, void *user_data);
|
||||
bool bt_hci_crypto_e(struct bt_hci *hci,
|
||||
const uint8_t key[16], const uint8_t plaintext[16],
|
||||
bt_hci_crypto_func_t callback, void *user_data);
|
||||
bool bt_hci_crypto_d1(struct bt_hci *hci,
|
||||
const uint8_t k[16], uint16_t d, uint16_t r,
|
||||
bt_hci_crypto_func_t callback, void *user_data);
|
||||
bool bt_hci_crypto_dm(struct bt_hci *hci,
|
||||
const uint8_t k[16], const uint8_t r[8],
|
||||
bt_hci_crypto_func_t callback, void *user_data);
|
||||
bool bt_hci_crypto_ah(struct bt_hci *hci,
|
||||
const uint8_t k[16], const uint8_t r[3],
|
||||
bt_hci_crypto_func_t callback, void *user_data);
|
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "monitor/bt.h"
|
||||
#include "src/shared/mainloop.h"
|
||||
#include "src/shared/io.h"
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/queue.h"
|
||||
#include "src/shared/hci.h"
|
||||
|
||||
#define BTPROTO_HCI 1
|
||||
struct sockaddr_hci {
|
||||
sa_family_t hci_family;
|
||||
unsigned short hci_dev;
|
||||
unsigned short hci_channel;
|
||||
};
|
||||
#define HCI_CHANNEL_RAW 0
|
||||
#define HCI_CHANNEL_USER 1
|
||||
|
||||
#define SOL_HCI 0
|
||||
#define HCI_FILTER 2
|
||||
struct hci_filter {
|
||||
uint32_t type_mask;
|
||||
uint32_t event_mask[2];
|
||||
uint16_t opcode;
|
||||
};
|
||||
|
||||
struct bt_hci {
|
||||
int ref_count;
|
||||
struct io *io;
|
||||
bool is_stream;
|
||||
bool writer_active;
|
||||
uint8_t num_cmds;
|
||||
unsigned int next_cmd_id;
|
||||
unsigned int next_evt_id;
|
||||
struct queue *cmd_queue;
|
||||
struct queue *rsp_queue;
|
||||
struct queue *evt_list;
|
||||
};
|
||||
|
||||
struct cmd {
|
||||
unsigned int id;
|
||||
uint16_t opcode;
|
||||
void *data;
|
||||
uint8_t size;
|
||||
bt_hci_callback_func_t callback;
|
||||
bt_hci_destroy_func_t destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct evt {
|
||||
unsigned int id;
|
||||
uint8_t event;
|
||||
bt_hci_callback_func_t callback;
|
||||
bt_hci_destroy_func_t destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void cmd_free(void *data)
|
||||
{
|
||||
struct cmd *cmd = data;
|
||||
|
||||
if (cmd->destroy)
|
||||
cmd->destroy(cmd->user_data);
|
||||
|
||||
free(cmd->data);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
static void evt_free(void *data)
|
||||
{
|
||||
struct evt *evt = data;
|
||||
|
||||
if (evt->destroy)
|
||||
evt->destroy(evt->user_data);
|
||||
|
||||
free(evt);
|
||||
}
|
||||
|
||||
static void send_command(struct bt_hci *hci, uint16_t opcode,
|
||||
void *data, uint8_t size)
|
||||
{
|
||||
uint8_t type = BT_H4_CMD_PKT;
|
||||
struct bt_hci_cmd_hdr hdr;
|
||||
struct iovec iov[3];
|
||||
int iovcnt;
|
||||
|
||||
if (hci->num_cmds < 1)
|
||||
return;
|
||||
|
||||
hdr.opcode = cpu_to_le16(opcode);
|
||||
hdr.plen = size;
|
||||
|
||||
iov[0].iov_base = &type;
|
||||
iov[0].iov_len = 1;
|
||||
iov[1].iov_base = &hdr;
|
||||
iov[1].iov_len = sizeof(hdr);
|
||||
|
||||
if (size > 0) {
|
||||
iov[2].iov_base = data;
|
||||
iov[2].iov_len = size;
|
||||
iovcnt = 3;
|
||||
} else
|
||||
iovcnt = 2;
|
||||
|
||||
if (io_send(hci->io, iov, iovcnt) < 0)
|
||||
return;
|
||||
|
||||
hci->num_cmds--;
|
||||
}
|
||||
|
||||
static bool io_write_callback(struct io *io, void *user_data)
|
||||
{
|
||||
struct bt_hci *hci = user_data;
|
||||
struct cmd *cmd;
|
||||
|
||||
cmd = queue_pop_head(hci->cmd_queue);
|
||||
if (cmd) {
|
||||
send_command(hci, cmd->opcode, cmd->data, cmd->size);
|
||||
queue_push_tail(hci->rsp_queue, cmd);
|
||||
}
|
||||
|
||||
hci->writer_active = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wakeup_writer(struct bt_hci *hci)
|
||||
{
|
||||
if (hci->writer_active)
|
||||
return;
|
||||
|
||||
if (hci->num_cmds < 1)
|
||||
return;
|
||||
|
||||
if (queue_isempty(hci->cmd_queue))
|
||||
return;
|
||||
|
||||
if (!io_set_write_handler(hci->io, io_write_callback, hci, NULL))
|
||||
return;
|
||||
|
||||
hci->writer_active = true;
|
||||
}
|
||||
|
||||
static bool match_cmd_opcode(const void *a, const void *b)
|
||||
{
|
||||
const struct cmd *cmd = a;
|
||||
uint16_t opcode = PTR_TO_UINT(b);
|
||||
|
||||
return cmd->opcode == opcode;
|
||||
}
|
||||
|
||||
static void process_response(struct bt_hci *hci, uint16_t opcode,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
if (opcode == BT_HCI_CMD_NOP)
|
||||
goto done;
|
||||
|
||||
cmd = queue_remove_if(hci->rsp_queue, match_cmd_opcode,
|
||||
UINT_TO_PTR(opcode));
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
if (cmd->callback)
|
||||
cmd->callback(data, size, cmd->user_data);
|
||||
|
||||
cmd_free(cmd);
|
||||
|
||||
done:
|
||||
wakeup_writer(hci);
|
||||
}
|
||||
|
||||
static void process_notify(void *data, void *user_data)
|
||||
{
|
||||
struct bt_hci_evt_hdr *hdr = user_data;
|
||||
struct evt *evt = data;
|
||||
|
||||
if (evt->event == hdr->evt)
|
||||
evt->callback(user_data + sizeof(struct bt_hci_evt_hdr),
|
||||
hdr->plen, evt->user_data);
|
||||
}
|
||||
|
||||
static void process_event(struct bt_hci *hci, const void *data, size_t size)
|
||||
{
|
||||
const struct bt_hci_evt_hdr *hdr = data;
|
||||
const struct bt_hci_evt_cmd_complete *cc;
|
||||
const struct bt_hci_evt_cmd_status *cs;
|
||||
|
||||
if (size < sizeof(struct bt_hci_evt_hdr))
|
||||
return;
|
||||
|
||||
data += sizeof(struct bt_hci_evt_hdr);
|
||||
size -= sizeof(struct bt_hci_evt_hdr);
|
||||
|
||||
if (hdr->plen != size)
|
||||
return;
|
||||
|
||||
switch (hdr->evt) {
|
||||
case BT_HCI_EVT_CMD_COMPLETE:
|
||||
if (size < sizeof(*cc))
|
||||
return;
|
||||
cc = data;
|
||||
hci->num_cmds = cc->ncmd;
|
||||
process_response(hci, le16_to_cpu(cc->opcode),
|
||||
data + sizeof(*cc),
|
||||
size - sizeof(*cc));
|
||||
break;
|
||||
|
||||
case BT_HCI_EVT_CMD_STATUS:
|
||||
if (size < sizeof(*cs))
|
||||
return;
|
||||
cs = data;
|
||||
hci->num_cmds = cs->ncmd;
|
||||
process_response(hci, le16_to_cpu(cs->opcode), &cs->status, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
queue_foreach(hci->evt_list, process_notify, (void *) hdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool io_read_callback(struct io *io, void *user_data)
|
||||
{
|
||||
struct bt_hci *hci = user_data;
|
||||
uint8_t buf[512];
|
||||
ssize_t len;
|
||||
int fd;
|
||||
|
||||
fd = io_get_fd(hci->io);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
if (hci->is_stream)
|
||||
return false;
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
if (len < 0)
|
||||
return false;
|
||||
|
||||
if (len < 1)
|
||||
return true;
|
||||
|
||||
switch (buf[0]) {
|
||||
case BT_H4_EVT_PKT:
|
||||
process_event(hci, buf + 1, len - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct bt_hci *create_hci(int fd)
|
||||
{
|
||||
struct bt_hci *hci;
|
||||
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
hci = new0(struct bt_hci, 1);
|
||||
hci->io = io_new(fd);
|
||||
if (!hci->io) {
|
||||
free(hci);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hci->is_stream = true;
|
||||
hci->writer_active = false;
|
||||
hci->num_cmds = 1;
|
||||
hci->next_cmd_id = 1;
|
||||
hci->next_evt_id = 1;
|
||||
|
||||
hci->cmd_queue = queue_new();
|
||||
hci->rsp_queue = queue_new();
|
||||
hci->evt_list = queue_new();
|
||||
|
||||
if (!io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
|
||||
queue_destroy(hci->evt_list, NULL);
|
||||
queue_destroy(hci->rsp_queue, NULL);
|
||||
queue_destroy(hci->cmd_queue, NULL);
|
||||
io_destroy(hci->io);
|
||||
free(hci);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bt_hci_ref(hci);
|
||||
}
|
||||
|
||||
struct bt_hci *bt_hci_new(int fd)
|
||||
{
|
||||
struct bt_hci *hci;
|
||||
|
||||
hci = create_hci(fd);
|
||||
if (!hci)
|
||||
return NULL;
|
||||
|
||||
return hci;
|
||||
}
|
||||
|
||||
static int create_socket(uint16_t index, uint16_t channel)
|
||||
{
|
||||
struct sockaddr_hci addr;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
BTPROTO_HCI);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = index;
|
||||
addr.hci_channel = channel;
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct bt_hci *bt_hci_new_user_channel(uint16_t index)
|
||||
{
|
||||
struct bt_hci *hci;
|
||||
int fd;
|
||||
|
||||
fd = create_socket(index, HCI_CHANNEL_USER);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
hci = create_hci(fd);
|
||||
if (!hci) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hci->is_stream = false;
|
||||
|
||||
bt_hci_set_close_on_unref(hci, true);
|
||||
|
||||
return hci;
|
||||
}
|
||||
|
||||
struct bt_hci *bt_hci_new_raw_device(uint16_t index)
|
||||
{
|
||||
struct bt_hci *hci;
|
||||
struct hci_filter flt;
|
||||
int fd;
|
||||
|
||||
fd = create_socket(index, HCI_CHANNEL_RAW);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
memset(&flt, 0, sizeof(flt));
|
||||
flt.type_mask = 1 << BT_H4_EVT_PKT;
|
||||
flt.event_mask[0] = 0xffffffff;
|
||||
flt.event_mask[1] = 0xffffffff;
|
||||
|
||||
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hci = create_hci(fd);
|
||||
if (!hci) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hci->is_stream = false;
|
||||
|
||||
bt_hci_set_close_on_unref(hci, true);
|
||||
|
||||
return hci;
|
||||
}
|
||||
|
||||
struct bt_hci *bt_hci_ref(struct bt_hci *hci)
|
||||
{
|
||||
if (!hci)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&hci->ref_count, 1);
|
||||
|
||||
return hci;
|
||||
}
|
||||
|
||||
void bt_hci_unref(struct bt_hci *hci)
|
||||
{
|
||||
if (!hci)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&hci->ref_count, 1))
|
||||
return;
|
||||
|
||||
queue_destroy(hci->evt_list, evt_free);
|
||||
queue_destroy(hci->cmd_queue, cmd_free);
|
||||
queue_destroy(hci->rsp_queue, cmd_free);
|
||||
|
||||
io_destroy(hci->io);
|
||||
|
||||
free(hci);
|
||||
}
|
||||
|
||||
bool bt_hci_set_close_on_unref(struct bt_hci *hci, bool do_close)
|
||||
{
|
||||
if (!hci)
|
||||
return false;
|
||||
|
||||
return io_set_close_on_destroy(hci->io, do_close);
|
||||
}
|
||||
|
||||
unsigned int bt_hci_send(struct bt_hci *hci, uint16_t opcode,
|
||||
const void *data, uint8_t size,
|
||||
bt_hci_callback_func_t callback,
|
||||
void *user_data, bt_hci_destroy_func_t destroy)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
if (!hci)
|
||||
return 0;
|
||||
|
||||
cmd = new0(struct cmd, 1);
|
||||
cmd->opcode = opcode;
|
||||
cmd->size = size;
|
||||
|
||||
if (cmd->size > 0) {
|
||||
cmd->data = malloc(cmd->size);
|
||||
if (!cmd->data) {
|
||||
free(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(cmd->data, data, cmd->size);
|
||||
}
|
||||
|
||||
if (hci->next_cmd_id < 1)
|
||||
hci->next_cmd_id = 1;
|
||||
|
||||
cmd->id = hci->next_cmd_id++;
|
||||
|
||||
cmd->callback = callback;
|
||||
cmd->destroy = destroy;
|
||||
cmd->user_data = user_data;
|
||||
|
||||
if (!queue_push_tail(hci->cmd_queue, cmd)) {
|
||||
free(cmd->data);
|
||||
free(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wakeup_writer(hci);
|
||||
|
||||
return cmd->id;
|
||||
}
|
||||
|
||||
static bool match_cmd_id(const void *a, const void *b)
|
||||
{
|
||||
const struct cmd *cmd = a;
|
||||
unsigned int id = PTR_TO_UINT(b);
|
||||
|
||||
return cmd->id == id;
|
||||
}
|
||||
|
||||
bool bt_hci_cancel(struct bt_hci *hci, unsigned int id)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
|
||||
if (!hci || !id)
|
||||
return false;
|
||||
|
||||
cmd = queue_remove_if(hci->cmd_queue, match_cmd_id, UINT_TO_PTR(id));
|
||||
if (!cmd) {
|
||||
cmd = queue_remove_if(hci->rsp_queue, match_cmd_id,
|
||||
UINT_TO_PTR(id));
|
||||
if (!cmd)
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd_free(cmd);
|
||||
|
||||
wakeup_writer(hci);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bt_hci_flush(struct bt_hci *hci)
|
||||
{
|
||||
if (!hci)
|
||||
return false;
|
||||
|
||||
if (hci->writer_active) {
|
||||
io_set_write_handler(hci->io, NULL, NULL, NULL);
|
||||
hci->writer_active = false;
|
||||
}
|
||||
|
||||
queue_remove_all(hci->cmd_queue, NULL, NULL, cmd_free);
|
||||
queue_remove_all(hci->rsp_queue, NULL, NULL, cmd_free);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
|
||||
bt_hci_callback_func_t callback,
|
||||
void *user_data, bt_hci_destroy_func_t destroy)
|
||||
{
|
||||
struct evt *evt;
|
||||
|
||||
if (!hci)
|
||||
return 0;
|
||||
|
||||
evt = new0(struct evt, 1);
|
||||
evt->event = event;
|
||||
|
||||
if (hci->next_evt_id < 1)
|
||||
hci->next_evt_id = 1;
|
||||
|
||||
evt->id = hci->next_evt_id++;
|
||||
|
||||
evt->callback = callback;
|
||||
evt->destroy = destroy;
|
||||
evt->user_data = user_data;
|
||||
|
||||
if (!queue_push_tail(hci->evt_list, evt)) {
|
||||
free(evt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return evt->id;
|
||||
}
|
||||
|
||||
static bool match_evt_id(const void *a, const void *b)
|
||||
{
|
||||
const struct evt *evt = a;
|
||||
unsigned int id = PTR_TO_UINT(b);
|
||||
|
||||
return evt->id == id;
|
||||
}
|
||||
|
||||
bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
|
||||
{
|
||||
struct evt *evt;
|
||||
|
||||
if (!hci || !id)
|
||||
return false;
|
||||
|
||||
evt = queue_remove_if(hci->evt_list, match_evt_id, UINT_TO_PTR(id));
|
||||
if (!evt)
|
||||
return false;
|
||||
|
||||
evt_free(evt);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*bt_hci_destroy_func_t)(void *user_data);
|
||||
|
||||
struct bt_hci;
|
||||
|
||||
struct bt_hci *bt_hci_new(int fd);
|
||||
struct bt_hci *bt_hci_new_user_channel(uint16_t index);
|
||||
struct bt_hci *bt_hci_new_raw_device(uint16_t index);
|
||||
|
||||
struct bt_hci *bt_hci_ref(struct bt_hci *hci);
|
||||
void bt_hci_unref(struct bt_hci *hci);
|
||||
|
||||
bool bt_hci_set_close_on_unref(struct bt_hci *hci, bool do_close);
|
||||
|
||||
typedef void (*bt_hci_callback_func_t)(const void *data, uint8_t size,
|
||||
void *user_data);
|
||||
|
||||
unsigned int bt_hci_send(struct bt_hci *hci, uint16_t opcode,
|
||||
const void *data, uint8_t size,
|
||||
bt_hci_callback_func_t callback,
|
||||
void *user_data, bt_hci_destroy_func_t destroy);
|
||||
bool bt_hci_cancel(struct bt_hci *hci, unsigned int id);
|
||||
bool bt_hci_flush(struct bt_hci *hci);
|
||||
|
||||
unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
|
||||
bt_hci_callback_func_t callback,
|
||||
void *user_data, bt_hci_destroy_func_t destroy);
|
||||
bool bt_hci_unregister(struct bt_hci *hci, unsigned int id);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
enum hfp_result {
|
||||
HFP_RESULT_OK = 0,
|
||||
HFP_RESULT_CONNECT = 1,
|
||||
HFP_RESULT_RING = 2,
|
||||
HFP_RESULT_NO_CARRIER = 3,
|
||||
HFP_RESULT_ERROR = 4,
|
||||
HFP_RESULT_NO_DIALTONE = 6,
|
||||
HFP_RESULT_BUSY = 7,
|
||||
HFP_RESULT_NO_ANSWER = 8,
|
||||
HFP_RESULT_DELAYED = 9,
|
||||
HFP_RESULT_BLACKLISTED = 10,
|
||||
HFP_RESULT_CME_ERROR = 11,
|
||||
};
|
||||
|
||||
enum hfp_error {
|
||||
HFP_ERROR_AG_FAILURE = 0,
|
||||
HFP_ERROR_NO_CONNECTION_TO_PHONE = 1,
|
||||
HFP_ERROR_OPERATION_NOT_ALLOWED = 3,
|
||||
HFP_ERROR_OPERATION_NOT_SUPPORTED = 4,
|
||||
HFP_ERROR_PH_SIM_PIN_REQUIRED = 5,
|
||||
HFP_ERROR_SIM_NOT_INSERTED = 10,
|
||||
HFP_ERROR_SIM_PIN_REQUIRED = 11,
|
||||
HFP_ERROR_SIM_PUK_REQUIRED = 12,
|
||||
HFP_ERROR_SIM_FAILURE = 13,
|
||||
HFP_ERROR_SIM_BUSY = 14,
|
||||
HFP_ERROR_INCORRECT_PASSWORD = 16,
|
||||
HFP_ERROR_SIM_PIN2_REQUIRED = 17,
|
||||
HFP_ERROR_SIM_PUK2_REQUIRED = 18,
|
||||
HFP_ERROR_MEMORY_FULL = 20,
|
||||
HFP_ERROR_INVALID_INDEX = 21,
|
||||
HFP_ERROR_MEMORY_FAILURE = 23,
|
||||
HFP_ERROR_TEXT_STRING_TOO_LONG = 24,
|
||||
HFP_ERROR_INVALID_CHARS_IN_TEXT_STRING = 25,
|
||||
HFP_ERROR_DIAL_STRING_TO_LONG = 26,
|
||||
HFP_ERROR_INVALID_CHARS_IN_DIAL_STRING = 27,
|
||||
HFP_ERROR_NO_NETWORK_SERVICE = 30,
|
||||
HFP_ERROR_NETWORK_TIMEOUT = 31,
|
||||
HFP_ERROR_NETWORK_NOT_ALLOWED = 32,
|
||||
};
|
||||
|
||||
enum hfp_gw_cmd_type {
|
||||
HFP_GW_CMD_TYPE_READ,
|
||||
HFP_GW_CMD_TYPE_SET,
|
||||
HFP_GW_CMD_TYPE_TEST,
|
||||
HFP_GW_CMD_TYPE_COMMAND
|
||||
};
|
||||
|
||||
struct hfp_context;
|
||||
|
||||
typedef void (*hfp_result_func_t)(struct hfp_context *context,
|
||||
enum hfp_gw_cmd_type type, void *user_data);
|
||||
|
||||
typedef void (*hfp_destroy_func_t)(void *user_data);
|
||||
typedef void (*hfp_debug_func_t)(const char *str, void *user_data);
|
||||
|
||||
typedef void (*hfp_command_func_t)(const char *command, void *user_data);
|
||||
typedef void (*hfp_disconnect_func_t)(void *user_data);
|
||||
|
||||
struct hfp_gw;
|
||||
|
||||
struct hfp_gw *hfp_gw_new(int fd);
|
||||
|
||||
struct hfp_gw *hfp_gw_ref(struct hfp_gw *hfp);
|
||||
void hfp_gw_unref(struct hfp_gw *hfp);
|
||||
|
||||
bool hfp_gw_set_debug(struct hfp_gw *hfp, hfp_debug_func_t callback,
|
||||
void *user_data, hfp_destroy_func_t destroy);
|
||||
|
||||
bool hfp_gw_set_close_on_unref(struct hfp_gw *hfp, bool do_close);
|
||||
bool hfp_gw_set_permissive_syntax(struct hfp_gw *hfp, bool permissive);
|
||||
|
||||
bool hfp_gw_send_result(struct hfp_gw *hfp, enum hfp_result result);
|
||||
bool hfp_gw_send_error(struct hfp_gw *hfp, enum hfp_error error);
|
||||
bool hfp_gw_send_info(struct hfp_gw *hfp, const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
bool hfp_gw_set_command_handler(struct hfp_gw *hfp,
|
||||
hfp_command_func_t callback,
|
||||
void *user_data, hfp_destroy_func_t destroy);
|
||||
|
||||
bool hfp_gw_set_disconnect_handler(struct hfp_gw *hfp,
|
||||
hfp_disconnect_func_t callback,
|
||||
void *user_data,
|
||||
hfp_destroy_func_t destroy);
|
||||
|
||||
bool hfp_gw_disconnect(struct hfp_gw *hfp);
|
||||
|
||||
bool hfp_gw_register(struct hfp_gw *hfp, hfp_result_func_t callback,
|
||||
const char *prefix,
|
||||
void *user_data,
|
||||
hfp_destroy_func_t destroy);
|
||||
bool hfp_gw_unregister(struct hfp_gw *hfp, const char *prefix);
|
||||
|
||||
bool hfp_context_get_number(struct hfp_context *context,
|
||||
unsigned int *val);
|
||||
bool hfp_context_get_number_default(struct hfp_context *context,
|
||||
unsigned int *val,
|
||||
unsigned int default_val);
|
||||
bool hfp_context_open_container(struct hfp_context *context);
|
||||
bool hfp_context_close_container(struct hfp_context *context);
|
||||
bool hfp_context_get_string(struct hfp_context *context, char *buf,
|
||||
uint8_t len);
|
||||
bool hfp_context_get_unquoted_string(struct hfp_context *context,
|
||||
char *buf, uint8_t len);
|
||||
bool hfp_context_get_range(struct hfp_context *context, unsigned int *min,
|
||||
unsigned int *max);
|
||||
bool hfp_context_has_next(struct hfp_context *context);
|
||||
void hfp_context_skip_field(struct hfp_context *context);
|
||||
|
||||
typedef void (*hfp_hf_result_func_t)(struct hfp_context *context,
|
||||
void *user_data);
|
||||
|
||||
typedef void (*hfp_response_func_t)(enum hfp_result result,
|
||||
enum hfp_error cme_err,
|
||||
void *user_data);
|
||||
|
||||
struct hfp_hf;
|
||||
|
||||
struct hfp_hf *hfp_hf_new(int fd);
|
||||
|
||||
struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
|
||||
void hfp_hf_unref(struct hfp_hf *hfp);
|
||||
bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
|
||||
void *user_data, hfp_destroy_func_t destroy);
|
||||
bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close);
|
||||
bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
|
||||
hfp_disconnect_func_t callback,
|
||||
void *user_data,
|
||||
hfp_destroy_func_t destroy);
|
||||
bool hfp_hf_disconnect(struct hfp_hf *hfp);
|
||||
bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
|
||||
const char *prefix, void *user_data,
|
||||
hfp_destroy_func_t destroy);
|
||||
bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix);
|
||||
bool hfp_hf_send_command(struct hfp_hf *hfp, hfp_response_func_t resp_cb,
|
||||
void *user_data, const char *format, ...);
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "src/shared/io.h"
|
||||
#include "gattlib_internal.h"
|
||||
|
||||
struct io_watch {
|
||||
struct io *io;
|
||||
GSource* id;
|
||||
io_callback_func_t callback;
|
||||
io_destroy_func_t destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct io {
|
||||
int ref_count;
|
||||
GIOChannel *channel;
|
||||
struct io_watch *read_watch;
|
||||
struct io_watch *write_watch;
|
||||
struct io_watch *disconnect_watch;
|
||||
};
|
||||
|
||||
static struct io *io_ref(struct io *io)
|
||||
{
|
||||
if (!io)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&io->ref_count, 1);
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
static void io_unref(struct io *io)
|
||||
{
|
||||
if (!io)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&io->ref_count, 1))
|
||||
return;
|
||||
|
||||
g_free(io);
|
||||
}
|
||||
|
||||
struct io *io_new(int fd)
|
||||
{
|
||||
struct io *io;
|
||||
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
io = g_try_new0(struct io, 1);
|
||||
if (!io)
|
||||
return NULL;
|
||||
|
||||
io->channel = g_io_channel_unix_new(fd);
|
||||
|
||||
g_io_channel_set_encoding(io->channel, NULL, NULL);
|
||||
g_io_channel_set_buffered(io->channel, FALSE);
|
||||
|
||||
g_io_channel_set_close_on_unref(io->channel, FALSE);
|
||||
|
||||
return io_ref(io);
|
||||
}
|
||||
|
||||
static void watch_destroy(void *user_data)
|
||||
{
|
||||
struct io_watch *watch = user_data;
|
||||
struct io *io = watch->io;
|
||||
|
||||
if (watch == io->read_watch)
|
||||
io->read_watch = NULL;
|
||||
else if (watch == io->write_watch)
|
||||
io->write_watch = NULL;
|
||||
else if (watch == io->disconnect_watch)
|
||||
io->disconnect_watch = NULL;
|
||||
|
||||
if (watch->destroy)
|
||||
watch->destroy(watch->user_data);
|
||||
|
||||
io_unref(watch->io);
|
||||
g_free(watch);
|
||||
}
|
||||
|
||||
void io_destroy(struct io *io)
|
||||
{
|
||||
if (!io)
|
||||
return;
|
||||
|
||||
if (io->read_watch) {
|
||||
g_source_destroy(io->read_watch->id);
|
||||
io->read_watch = NULL;
|
||||
}
|
||||
|
||||
if (io->write_watch) {
|
||||
g_source_destroy(io->write_watch->id);
|
||||
io->write_watch = NULL;
|
||||
}
|
||||
|
||||
if (io->disconnect_watch) {
|
||||
g_source_destroy(io->disconnect_watch->id);
|
||||
io->disconnect_watch = NULL;
|
||||
}
|
||||
|
||||
g_io_channel_unref(io->channel);
|
||||
io->channel = NULL;
|
||||
|
||||
io_unref(io);
|
||||
}
|
||||
|
||||
int io_get_fd(struct io *io)
|
||||
{
|
||||
if (!io)
|
||||
return -ENOTCONN;
|
||||
|
||||
return g_io_channel_unix_get_fd(io->channel);
|
||||
}
|
||||
|
||||
bool io_set_close_on_destroy(struct io *io, bool do_close)
|
||||
{
|
||||
if (!io)
|
||||
return false;
|
||||
|
||||
if (do_close)
|
||||
g_io_channel_set_close_on_unref(io->channel, TRUE);
|
||||
else
|
||||
g_io_channel_set_close_on_unref(io->channel, FALSE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean watch_callback(GIOChannel *channel, GIOCondition cond,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct io_watch *watch = user_data;
|
||||
bool result, destroy;
|
||||
|
||||
destroy = watch == watch->io->disconnect_watch;
|
||||
|
||||
if (!destroy && (cond & (G_IO_ERR | G_IO_NVAL)))
|
||||
return FALSE;
|
||||
|
||||
if (watch->callback)
|
||||
result = watch->callback(watch->io, watch->user_data);
|
||||
else
|
||||
result = false;
|
||||
|
||||
return result ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static struct io_watch *watch_new(struct io *io, GIOCondition cond,
|
||||
io_callback_func_t callback, void *user_data,
|
||||
io_destroy_func_t destroy)
|
||||
{
|
||||
struct io_watch *watch;
|
||||
|
||||
watch = g_try_new0(struct io_watch, 1);
|
||||
if (!watch)
|
||||
return NULL;
|
||||
|
||||
watch->io = io_ref(io);
|
||||
watch->callback = callback;
|
||||
watch->destroy = destroy;
|
||||
watch->user_data = user_data;
|
||||
|
||||
watch->id = gattlib_watch_connection_full(io->channel,
|
||||
cond | G_IO_ERR | G_IO_NVAL,
|
||||
watch_callback, watch,
|
||||
watch_destroy);
|
||||
if (watch->id == NULL) {
|
||||
watch_destroy(watch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return watch;
|
||||
}
|
||||
|
||||
static bool io_set_handler(struct io *io, GIOCondition cond,
|
||||
io_callback_func_t callback, void *user_data,
|
||||
io_destroy_func_t destroy)
|
||||
{
|
||||
struct io_watch **watch;
|
||||
|
||||
if (!io)
|
||||
return false;
|
||||
|
||||
switch (cond) {
|
||||
case G_IO_IN:
|
||||
watch = &io->read_watch;
|
||||
break;
|
||||
case G_IO_OUT:
|
||||
watch = &io->write_watch;
|
||||
break;
|
||||
case G_IO_HUP:
|
||||
watch = &io->disconnect_watch;
|
||||
break;
|
||||
case G_IO_PRI:
|
||||
case G_IO_ERR:
|
||||
case G_IO_NVAL:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*watch) {
|
||||
g_source_destroy((*watch)->id);
|
||||
*watch = NULL;
|
||||
}
|
||||
|
||||
if (!callback)
|
||||
return true;
|
||||
|
||||
*watch = watch_new(io, cond, callback, user_data, destroy);
|
||||
if (!*watch)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool io_set_read_handler(struct io *io, io_callback_func_t callback,
|
||||
void *user_data, io_destroy_func_t destroy)
|
||||
{
|
||||
return io_set_handler(io, G_IO_IN, callback, user_data, destroy);
|
||||
}
|
||||
|
||||
bool io_set_write_handler(struct io *io, io_callback_func_t callback,
|
||||
void *user_data, io_destroy_func_t destroy)
|
||||
{
|
||||
return io_set_handler(io, G_IO_OUT, callback, user_data, destroy);
|
||||
}
|
||||
|
||||
bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
|
||||
void *user_data, io_destroy_func_t destroy)
|
||||
{
|
||||
return io_set_handler(io, G_IO_HUP, callback, user_data, destroy);
|
||||
}
|
||||
|
||||
ssize_t io_send(struct io *io, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
int fd;
|
||||
ssize_t ret;
|
||||
|
||||
if (!io || !io->channel)
|
||||
return -ENOTCONN;
|
||||
|
||||
fd = io_get_fd(io);
|
||||
|
||||
do {
|
||||
ret = writev(fd, iov, iovcnt);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool io_shutdown(struct io *io)
|
||||
{
|
||||
if (!io || !io->channel)
|
||||
return false;
|
||||
|
||||
return g_io_channel_shutdown(io->channel, TRUE, NULL)
|
||||
== G_IO_STATUS_NORMAL;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
typedef void (*io_destroy_func_t)(void *data);
|
||||
|
||||
struct io;
|
||||
|
||||
struct io *io_new(int fd);
|
||||
void io_destroy(struct io *io);
|
||||
|
||||
int io_get_fd(struct io *io);
|
||||
bool io_set_close_on_destroy(struct io *io, bool do_close);
|
||||
|
||||
ssize_t io_send(struct io *io, const struct iovec *iov, int iovcnt);
|
||||
bool io_shutdown(struct io *io);
|
||||
|
||||
typedef bool (*io_callback_func_t)(struct io *io, void *user_data);
|
||||
|
||||
bool io_set_read_handler(struct io *io, io_callback_func_t callback,
|
||||
void *user_data, io_destroy_func_t destroy);
|
||||
bool io_set_write_handler(struct io *io, io_callback_func_t callback,
|
||||
void *user_data, io_destroy_func_t destroy);
|
||||
bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
|
||||
void *user_data, io_destroy_func_t destroy);
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011-2014 Intel Corporation
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "mainloop.h"
|
||||
|
||||
#define MAX_EPOLL_EVENTS 10
|
||||
|
||||
static int epoll_fd;
|
||||
static int epoll_terminate;
|
||||
static int exit_status;
|
||||
|
||||
struct mainloop_data {
|
||||
int fd;
|
||||
uint32_t events;
|
||||
mainloop_event_func callback;
|
||||
mainloop_destroy_func destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
#define MAX_MAINLOOP_ENTRIES 128
|
||||
|
||||
static struct mainloop_data *mainloop_list[MAX_MAINLOOP_ENTRIES];
|
||||
|
||||
struct timeout_data {
|
||||
int fd;
|
||||
mainloop_timeout_func callback;
|
||||
mainloop_destroy_func destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct signal_data {
|
||||
int fd;
|
||||
sigset_t mask;
|
||||
mainloop_signal_func callback;
|
||||
mainloop_destroy_func destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static struct signal_data *signal_data;
|
||||
|
||||
void mainloop_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
|
||||
for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)
|
||||
mainloop_list[i] = NULL;
|
||||
|
||||
epoll_terminate = 0;
|
||||
}
|
||||
|
||||
void mainloop_quit(void)
|
||||
{
|
||||
epoll_terminate = 1;
|
||||
}
|
||||
|
||||
void mainloop_exit_success(void)
|
||||
{
|
||||
exit_status = EXIT_SUCCESS;
|
||||
epoll_terminate = 1;
|
||||
}
|
||||
|
||||
void mainloop_exit_failure(void)
|
||||
{
|
||||
exit_status = EXIT_FAILURE;
|
||||
epoll_terminate = 1;
|
||||
}
|
||||
|
||||
static void signal_callback(int fd, uint32_t events, void *user_data)
|
||||
{
|
||||
struct signal_data *data = user_data;
|
||||
struct signalfd_siginfo si;
|
||||
ssize_t result;
|
||||
|
||||
if (events & (EPOLLERR | EPOLLHUP)) {
|
||||
mainloop_quit();
|
||||
return;
|
||||
}
|
||||
|
||||
result = read(fd, &si, sizeof(si));
|
||||
if (result != sizeof(si))
|
||||
return;
|
||||
|
||||
if (data->callback)
|
||||
data->callback(si.ssi_signo, data->user_data);
|
||||
}
|
||||
|
||||
int mainloop_run(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (signal_data) {
|
||||
if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
signal_data->fd = signalfd(-1, &signal_data->mask,
|
||||
SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
if (signal_data->fd < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (mainloop_add_fd(signal_data->fd, EPOLLIN,
|
||||
signal_callback, signal_data, NULL) < 0) {
|
||||
close(signal_data->fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
exit_status = EXIT_SUCCESS;
|
||||
|
||||
while (!epoll_terminate) {
|
||||
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||
int n, nfds;
|
||||
|
||||
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
|
||||
if (nfds < 0)
|
||||
continue;
|
||||
|
||||
for (n = 0; n < nfds; n++) {
|
||||
struct mainloop_data *data = events[n].data.ptr;
|
||||
|
||||
data->callback(data->fd, events[n].events,
|
||||
data->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (signal_data) {
|
||||
mainloop_remove_fd(signal_data->fd);
|
||||
close(signal_data->fd);
|
||||
|
||||
if (signal_data->destroy)
|
||||
signal_data->destroy(signal_data->user_data);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {
|
||||
struct mainloop_data *data = mainloop_list[i];
|
||||
|
||||
mainloop_list[i] = NULL;
|
||||
|
||||
if (data) {
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
close(epoll_fd);
|
||||
epoll_fd = 0;
|
||||
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
|
||||
void *user_data, mainloop_destroy_func destroy)
|
||||
{
|
||||
struct mainloop_data *data;
|
||||
struct epoll_event ev;
|
||||
int err;
|
||||
|
||||
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)
|
||||
return -EINVAL;
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->fd = fd;
|
||||
data->events = events;
|
||||
data->callback = callback;
|
||||
data->destroy = destroy;
|
||||
data->user_data = user_data;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = events;
|
||||
ev.data.ptr = data;
|
||||
|
||||
err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);
|
||||
if (err < 0) {
|
||||
free(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
mainloop_list[fd] = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mainloop_modify_fd(int fd, uint32_t events)
|
||||
{
|
||||
struct mainloop_data *data;
|
||||
struct epoll_event ev;
|
||||
int err;
|
||||
|
||||
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
|
||||
return -EINVAL;
|
||||
|
||||
data = mainloop_list[fd];
|
||||
if (!data)
|
||||
return -ENXIO;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = events;
|
||||
ev.data.ptr = data;
|
||||
|
||||
err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data->events = events;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mainloop_remove_fd(int fd)
|
||||
{
|
||||
struct mainloop_data *data;
|
||||
int err;
|
||||
|
||||
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
|
||||
return -EINVAL;
|
||||
|
||||
data = mainloop_list[fd];
|
||||
if (!data)
|
||||
return -ENXIO;
|
||||
|
||||
mainloop_list[fd] = NULL;
|
||||
|
||||
err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
|
||||
free(data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void timeout_destroy(void *user_data)
|
||||
{
|
||||
struct timeout_data *data = user_data;
|
||||
|
||||
close(data->fd);
|
||||
data->fd = -1;
|
||||
|
||||
if (data->destroy)
|
||||
data->destroy(data->user_data);
|
||||
}
|
||||
|
||||
static void timeout_callback(int fd, uint32_t events, void *user_data)
|
||||
{
|
||||
struct timeout_data *data = user_data;
|
||||
uint64_t expired;
|
||||
ssize_t result;
|
||||
|
||||
if (events & (EPOLLERR | EPOLLHUP))
|
||||
return;
|
||||
|
||||
result = read(data->fd, &expired, sizeof(expired));
|
||||
if (result != sizeof(expired))
|
||||
return;
|
||||
|
||||
if (data->callback)
|
||||
data->callback(data->fd, data->user_data);
|
||||
}
|
||||
|
||||
static inline int timeout_set(int fd, unsigned int msec)
|
||||
{
|
||||
struct itimerspec itimer;
|
||||
unsigned int sec = msec / 1000;
|
||||
|
||||
memset(&itimer, 0, sizeof(itimer));
|
||||
itimer.it_interval.tv_sec = 0;
|
||||
itimer.it_interval.tv_nsec = 0;
|
||||
itimer.it_value.tv_sec = sec;
|
||||
itimer.it_value.tv_nsec = (msec - (sec * 1000)) * 1000;
|
||||
|
||||
return timerfd_settime(fd, 0, &itimer, NULL);
|
||||
}
|
||||
|
||||
int mainloop_add_timeout(unsigned int msec, mainloop_timeout_func callback,
|
||||
void *user_data, mainloop_destroy_func destroy)
|
||||
{
|
||||
struct timeout_data *data;
|
||||
|
||||
if (!callback)
|
||||
return -EINVAL;
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->callback = callback;
|
||||
data->destroy = destroy;
|
||||
data->user_data = user_data;
|
||||
|
||||
data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
if (data->fd < 0) {
|
||||
free(data);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (msec > 0) {
|
||||
if (timeout_set(data->fd, msec) < 0) {
|
||||
close(data->fd);
|
||||
free(data);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
|
||||
timeout_callback, data, timeout_destroy) < 0) {
|
||||
close(data->fd);
|
||||
free(data);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return data->fd;
|
||||
}
|
||||
|
||||
int mainloop_modify_timeout(int id, unsigned int msec)
|
||||
{
|
||||
if (msec > 0) {
|
||||
if (timeout_set(id, msec) < 0)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mainloop_remove_timeout(int id)
|
||||
{
|
||||
return mainloop_remove_fd(id);
|
||||
}
|
||||
|
||||
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
|
||||
void *user_data, mainloop_destroy_func destroy)
|
||||
{
|
||||
struct signal_data *data;
|
||||
|
||||
if (!mask || !callback)
|
||||
return -EINVAL;
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->callback = callback;
|
||||
data->destroy = destroy;
|
||||
data->user_data = user_data;
|
||||
|
||||
data->fd = -1;
|
||||
memcpy(&data->mask, mask, sizeof(sigset_t));
|
||||
|
||||
free(signal_data);
|
||||
signal_data = data;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011-2014 Intel Corporation
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
typedef void (*mainloop_destroy_func) (void *user_data);
|
||||
|
||||
typedef void (*mainloop_event_func) (int fd, uint32_t events, void *user_data);
|
||||
typedef void (*mainloop_timeout_func) (int id, void *user_data);
|
||||
typedef void (*mainloop_signal_func) (int signum, void *user_data);
|
||||
|
||||
void mainloop_init(void);
|
||||
void mainloop_quit(void);
|
||||
void mainloop_exit_success(void);
|
||||
void mainloop_exit_failure(void);
|
||||
int mainloop_run(void);
|
||||
|
||||
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
|
||||
void *user_data, mainloop_destroy_func destroy);
|
||||
int mainloop_modify_fd(int fd, uint32_t events);
|
||||
int mainloop_remove_fd(int fd);
|
||||
|
||||
int mainloop_add_timeout(unsigned int msec, mainloop_timeout_func callback,
|
||||
void *user_data, mainloop_destroy_func destroy);
|
||||
int mainloop_modify_timeout(int fd, unsigned int msec);
|
||||
int mainloop_remove_timeout(int id);
|
||||
|
||||
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
|
||||
void *user_data, mainloop_destroy_func destroy);
|
|
@ -0,0 +1,801 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib/bluetooth.h"
|
||||
#include "lib/mgmt.h"
|
||||
#include "lib/hci.h"
|
||||
|
||||
#include "src/shared/io.h"
|
||||
#include "src/shared/queue.h"
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/mgmt.h"
|
||||
|
||||
struct mgmt {
|
||||
int ref_count;
|
||||
int fd;
|
||||
bool close_on_unref;
|
||||
struct io *io;
|
||||
bool writer_active;
|
||||
struct queue *request_queue;
|
||||
struct queue *reply_queue;
|
||||
struct queue *pending_list;
|
||||
struct queue *notify_list;
|
||||
unsigned int next_request_id;
|
||||
unsigned int next_notify_id;
|
||||
bool need_notify_cleanup;
|
||||
bool in_notify;
|
||||
void *buf;
|
||||
uint16_t len;
|
||||
mgmt_debug_func_t debug_callback;
|
||||
mgmt_destroy_func_t debug_destroy;
|
||||
void *debug_data;
|
||||
};
|
||||
|
||||
struct mgmt_request {
|
||||
unsigned int id;
|
||||
uint16_t opcode;
|
||||
uint16_t index;
|
||||
void *buf;
|
||||
uint16_t len;
|
||||
mgmt_request_func_t callback;
|
||||
mgmt_destroy_func_t destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct mgmt_notify {
|
||||
unsigned int id;
|
||||
uint16_t event;
|
||||
uint16_t index;
|
||||
bool removed;
|
||||
mgmt_notify_func_t callback;
|
||||
mgmt_destroy_func_t destroy;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static void destroy_request(void *data)
|
||||
{
|
||||
struct mgmt_request *request = data;
|
||||
|
||||
if (request->destroy)
|
||||
request->destroy(request->user_data);
|
||||
|
||||
free(request->buf);
|
||||
free(request);
|
||||
}
|
||||
|
||||
static bool match_request_id(const void *a, const void *b)
|
||||
{
|
||||
const struct mgmt_request *request = a;
|
||||
unsigned int id = PTR_TO_UINT(b);
|
||||
|
||||
return request->id == id;
|
||||
}
|
||||
|
||||
static bool match_request_index(const void *a, const void *b)
|
||||
{
|
||||
const struct mgmt_request *request = a;
|
||||
uint16_t index = PTR_TO_UINT(b);
|
||||
|
||||
return request->index == index;
|
||||
}
|
||||
|
||||
static void destroy_notify(void *data)
|
||||
{
|
||||
struct mgmt_notify *notify = data;
|
||||
|
||||
if (notify->destroy)
|
||||
notify->destroy(notify->user_data);
|
||||
|
||||
free(notify);
|
||||
}
|
||||
|
||||
static bool match_notify_id(const void *a, const void *b)
|
||||
{
|
||||
const struct mgmt_notify *notify = a;
|
||||
unsigned int id = PTR_TO_UINT(b);
|
||||
|
||||
return notify->id == id;
|
||||
}
|
||||
|
||||
static bool match_notify_index(const void *a, const void *b)
|
||||
{
|
||||
const struct mgmt_notify *notify = a;
|
||||
uint16_t index = PTR_TO_UINT(b);
|
||||
|
||||
return notify->index == index;
|
||||
}
|
||||
|
||||
static bool match_notify_removed(const void *a, const void *b)
|
||||
{
|
||||
const struct mgmt_notify *notify = a;
|
||||
|
||||
return notify->removed;
|
||||
}
|
||||
|
||||
static void mark_notify_removed(void *data , void *user_data)
|
||||
{
|
||||
struct mgmt_notify *notify = data;
|
||||
uint16_t index = PTR_TO_UINT(user_data);
|
||||
|
||||
if (notify->index == index || index == MGMT_INDEX_NONE)
|
||||
notify->removed = true;
|
||||
}
|
||||
|
||||
static void write_watch_destroy(void *user_data)
|
||||
{
|
||||
struct mgmt *mgmt = user_data;
|
||||
|
||||
mgmt->writer_active = false;
|
||||
}
|
||||
|
||||
static bool send_request(struct mgmt *mgmt, struct mgmt_request *request)
|
||||
{
|
||||
struct iovec iov;
|
||||
ssize_t ret;
|
||||
|
||||
iov.iov_base = request->buf;
|
||||
iov.iov_len = request->len;
|
||||
|
||||
ret = io_send(mgmt->io, &iov, 1);
|
||||
if (ret < 0) {
|
||||
util_debug(mgmt->debug_callback, mgmt->debug_data,
|
||||
"write failed: %s", strerror(-ret));
|
||||
if (request->callback)
|
||||
request->callback(MGMT_STATUS_FAILED, 0, NULL,
|
||||
request->user_data);
|
||||
destroy_request(request);
|
||||
return false;
|
||||
}
|
||||
|
||||
util_debug(mgmt->debug_callback, mgmt->debug_data,
|
||||
"[0x%04x] command 0x%04x",
|
||||
request->index, request->opcode);
|
||||
|
||||
util_hexdump('<', request->buf, ret, mgmt->debug_callback,
|
||||
mgmt->debug_data);
|
||||
|
||||
queue_push_tail(mgmt->pending_list, request);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool can_write_data(struct io *io, void *user_data)
|
||||
{
|
||||
struct mgmt *mgmt = user_data;
|
||||
struct mgmt_request *request;
|
||||
bool can_write;
|
||||
|
||||
request = queue_pop_head(mgmt->reply_queue);
|
||||
if (!request) {
|
||||
/* only reply commands can jump the queue */
|
||||
if (!queue_isempty(mgmt->pending_list))
|
||||
return false;
|
||||
|
||||
request = queue_pop_head(mgmt->request_queue);
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
can_write = false;
|
||||
} else {
|
||||
/* allow multiple replies to jump the queue */
|
||||
can_write = !queue_isempty(mgmt->reply_queue);
|
||||
}
|
||||
|
||||
if (!send_request(mgmt, request))
|
||||
return true;
|
||||
|
||||
return can_write;
|
||||
}
|
||||
|
||||
static void wakeup_writer(struct mgmt *mgmt)
|
||||
{
|
||||
if (!queue_isempty(mgmt->pending_list)) {
|
||||
/* only queued reply commands trigger wakeup */
|
||||
if (queue_isempty(mgmt->reply_queue))
|
||||
return;
|
||||
}
|
||||
|
||||
if (mgmt->writer_active)
|
||||
return;
|
||||
|
||||
mgmt->writer_active = true;
|
||||
|
||||
io_set_write_handler(mgmt->io, can_write_data, mgmt,
|
||||
write_watch_destroy);
|
||||
}
|
||||
|
||||
struct opcode_index {
|
||||
uint16_t opcode;
|
||||
uint16_t index;
|
||||
};
|
||||
|
||||
static bool match_request_opcode_index(const void *a, const void *b)
|
||||
{
|
||||
const struct mgmt_request *request = a;
|
||||
const struct opcode_index *match = b;
|
||||
|
||||
return request->opcode == match->opcode &&
|
||||
request->index == match->index;
|
||||
}
|
||||
|
||||
static void request_complete(struct mgmt *mgmt, uint8_t status,
|
||||
uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param)
|
||||
{
|
||||
struct opcode_index match = { .opcode = opcode, .index = index };
|
||||
struct mgmt_request *request;
|
||||
|
||||
request = queue_remove_if(mgmt->pending_list,
|
||||
match_request_opcode_index, &match);
|
||||
if (request) {
|
||||
if (request->callback)
|
||||
request->callback(status, length, param,
|
||||
request->user_data);
|
||||
|
||||
destroy_request(request);
|
||||
}
|
||||
|
||||
wakeup_writer(mgmt);
|
||||
}
|
||||
|
||||
struct event_index {
|
||||
uint16_t event;
|
||||
uint16_t index;
|
||||
uint16_t length;
|
||||
const void *param;
|
||||
};
|
||||
|
||||
static void notify_handler(void *data, void *user_data)
|
||||
{
|
||||
struct mgmt_notify *notify = data;
|
||||
struct event_index *match = user_data;
|
||||
|
||||
if (notify->removed)
|
||||
return;
|
||||
|
||||
if (notify->event != match->event)
|
||||
return;
|
||||
|
||||
if (notify->index != match->index && notify->index != MGMT_INDEX_NONE)
|
||||
return;
|
||||
|
||||
if (notify->callback)
|
||||
notify->callback(match->index, match->length, match->param,
|
||||
notify->user_data);
|
||||
}
|
||||
|
||||
static void process_notify(struct mgmt *mgmt, uint16_t event, uint16_t index,
|
||||
uint16_t length, const void *param)
|
||||
{
|
||||
struct event_index match = { .event = event, .index = index,
|
||||
.length = length, .param = param };
|
||||
|
||||
mgmt->in_notify = true;
|
||||
|
||||
queue_foreach(mgmt->notify_list, notify_handler, &match);
|
||||
|
||||
mgmt->in_notify = false;
|
||||
|
||||
if (mgmt->need_notify_cleanup) {
|
||||
queue_remove_all(mgmt->notify_list, match_notify_removed,
|
||||
NULL, destroy_notify);
|
||||
mgmt->need_notify_cleanup = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool can_read_data(struct io *io, void *user_data)
|
||||
{
|
||||
struct mgmt *mgmt = user_data;
|
||||
struct mgmt_hdr *hdr;
|
||||
struct mgmt_ev_cmd_complete *cc;
|
||||
struct mgmt_ev_cmd_status *cs;
|
||||
ssize_t bytes_read;
|
||||
uint16_t opcode, event, index, length;
|
||||
|
||||
bytes_read = read(mgmt->fd, mgmt->buf, mgmt->len);
|
||||
if (bytes_read < 0)
|
||||
return false;
|
||||
|
||||
util_hexdump('>', mgmt->buf, bytes_read,
|
||||
mgmt->debug_callback, mgmt->debug_data);
|
||||
|
||||
if (bytes_read < MGMT_HDR_SIZE)
|
||||
return true;
|
||||
|
||||
hdr = mgmt->buf;
|
||||
event = btohs(hdr->opcode);
|
||||
index = btohs(hdr->index);
|
||||
length = btohs(hdr->len);
|
||||
|
||||
if (bytes_read < length + MGMT_HDR_SIZE)
|
||||
return true;
|
||||
|
||||
mgmt_ref(mgmt);
|
||||
|
||||
switch (event) {
|
||||
case MGMT_EV_CMD_COMPLETE:
|
||||
cc = mgmt->buf + MGMT_HDR_SIZE;
|
||||
opcode = btohs(cc->opcode);
|
||||
|
||||
util_debug(mgmt->debug_callback, mgmt->debug_data,
|
||||
"[0x%04x] command 0x%04x complete: 0x%02x",
|
||||
index, opcode, cc->status);
|
||||
|
||||
request_complete(mgmt, cc->status, opcode, index, length - 3,
|
||||
mgmt->buf + MGMT_HDR_SIZE + 3);
|
||||
break;
|
||||
case MGMT_EV_CMD_STATUS:
|
||||
cs = mgmt->buf + MGMT_HDR_SIZE;
|
||||
opcode = btohs(cs->opcode);
|
||||
|
||||
util_debug(mgmt->debug_callback, mgmt->debug_data,
|
||||
"[0x%04x] command 0x%02x status: 0x%02x",
|
||||
index, opcode, cs->status);
|
||||
|
||||
request_complete(mgmt, cs->status, opcode, index, 0, NULL);
|
||||
break;
|
||||
default:
|
||||
util_debug(mgmt->debug_callback, mgmt->debug_data,
|
||||
"[0x%04x] event 0x%04x", index, event);
|
||||
|
||||
process_notify(mgmt, event, index, length,
|
||||
mgmt->buf + MGMT_HDR_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
mgmt_unref(mgmt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct mgmt *mgmt_new(int fd)
|
||||
{
|
||||
struct mgmt *mgmt;
|
||||
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
mgmt = new0(struct mgmt, 1);
|
||||
mgmt->fd = fd;
|
||||
mgmt->close_on_unref = false;
|
||||
|
||||
mgmt->len = 512;
|
||||
mgmt->buf = malloc(mgmt->len);
|
||||
if (!mgmt->buf) {
|
||||
free(mgmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mgmt->io = io_new(fd);
|
||||
if (!mgmt->io) {
|
||||
free(mgmt->buf);
|
||||
free(mgmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mgmt->request_queue = queue_new();
|
||||
mgmt->reply_queue = queue_new();
|
||||
mgmt->pending_list = queue_new();
|
||||
mgmt->notify_list = queue_new();
|
||||
|
||||
if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {
|
||||
queue_destroy(mgmt->notify_list, NULL);
|
||||
queue_destroy(mgmt->pending_list, NULL);
|
||||
queue_destroy(mgmt->reply_queue, NULL);
|
||||
queue_destroy(mgmt->request_queue, NULL);
|
||||
io_destroy(mgmt->io);
|
||||
free(mgmt->buf);
|
||||
free(mgmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mgmt->writer_active = false;
|
||||
|
||||
return mgmt_ref(mgmt);
|
||||
}
|
||||
|
||||
struct mgmt *mgmt_new_default(void)
|
||||
{
|
||||
struct mgmt *mgmt;
|
||||
union {
|
||||
struct sockaddr common;
|
||||
struct sockaddr_hci hci;
|
||||
} addr;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
BTPROTO_HCI);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.hci.hci_family = AF_BLUETOOTH;
|
||||
addr.hci.hci_dev = HCI_DEV_NONE;
|
||||
addr.hci.hci_channel = HCI_CHANNEL_CONTROL;
|
||||
|
||||
if (bind(fd, &addr.common, sizeof(addr.hci)) < 0) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mgmt = mgmt_new(fd);
|
||||
if (!mgmt) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mgmt->close_on_unref = true;
|
||||
|
||||
return mgmt;
|
||||
}
|
||||
|
||||
struct mgmt *mgmt_ref(struct mgmt *mgmt)
|
||||
{
|
||||
if (!mgmt)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&mgmt->ref_count, 1);
|
||||
|
||||
return mgmt;
|
||||
}
|
||||
|
||||
void mgmt_unref(struct mgmt *mgmt)
|
||||
{
|
||||
if (!mgmt)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&mgmt->ref_count, 1))
|
||||
return;
|
||||
|
||||
mgmt_unregister_all(mgmt);
|
||||
mgmt_cancel_all(mgmt);
|
||||
|
||||
queue_destroy(mgmt->reply_queue, NULL);
|
||||
queue_destroy(mgmt->request_queue, NULL);
|
||||
|
||||
io_set_write_handler(mgmt->io, NULL, NULL, NULL);
|
||||
io_set_read_handler(mgmt->io, NULL, NULL, NULL);
|
||||
|
||||
io_destroy(mgmt->io);
|
||||
mgmt->io = NULL;
|
||||
|
||||
if (mgmt->close_on_unref)
|
||||
close(mgmt->fd);
|
||||
|
||||
if (mgmt->debug_destroy)
|
||||
mgmt->debug_destroy(mgmt->debug_data);
|
||||
|
||||
free(mgmt->buf);
|
||||
mgmt->buf = NULL;
|
||||
|
||||
if (!mgmt->in_notify) {
|
||||
queue_destroy(mgmt->notify_list, NULL);
|
||||
queue_destroy(mgmt->pending_list, NULL);
|
||||
free(mgmt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy)
|
||||
{
|
||||
if (!mgmt)
|
||||
return false;
|
||||
|
||||
if (mgmt->debug_destroy)
|
||||
mgmt->debug_destroy(mgmt->debug_data);
|
||||
|
||||
mgmt->debug_callback = callback;
|
||||
mgmt->debug_destroy = destroy;
|
||||
mgmt->debug_data = user_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgmt_set_close_on_unref(struct mgmt *mgmt, bool do_close)
|
||||
{
|
||||
if (!mgmt)
|
||||
return false;
|
||||
|
||||
mgmt->close_on_unref = do_close;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct mgmt_request *create_request(uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy)
|
||||
{
|
||||
struct mgmt_request *request;
|
||||
struct mgmt_hdr *hdr;
|
||||
|
||||
if (!opcode)
|
||||
return NULL;
|
||||
|
||||
if (length > 0 && !param)
|
||||
return NULL;
|
||||
|
||||
request = new0(struct mgmt_request, 1);
|
||||
request->len = length + MGMT_HDR_SIZE;
|
||||
request->buf = malloc(request->len);
|
||||
if (!request->buf) {
|
||||
free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
memcpy(request->buf + MGMT_HDR_SIZE, param, length);
|
||||
|
||||
hdr = request->buf;
|
||||
hdr->opcode = htobs(opcode);
|
||||
hdr->index = htobs(index);
|
||||
hdr->len = htobs(length);
|
||||
|
||||
request->opcode = opcode;
|
||||
request->index = index;
|
||||
|
||||
request->callback = callback;
|
||||
request->destroy = destroy;
|
||||
request->user_data = user_data;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy)
|
||||
{
|
||||
struct mgmt_request *request;
|
||||
|
||||
if (!mgmt)
|
||||
return 0;
|
||||
|
||||
request = create_request(opcode, index, length, param,
|
||||
callback, user_data, destroy);
|
||||
if (!request)
|
||||
return 0;
|
||||
|
||||
if (mgmt->next_request_id < 1)
|
||||
mgmt->next_request_id = 1;
|
||||
|
||||
request->id = mgmt->next_request_id++;
|
||||
|
||||
if (!queue_push_tail(mgmt->request_queue, request)) {
|
||||
free(request->buf);
|
||||
free(request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wakeup_writer(mgmt);
|
||||
|
||||
return request->id;
|
||||
}
|
||||
|
||||
unsigned int mgmt_send_nowait(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy)
|
||||
{
|
||||
struct mgmt_request *request;
|
||||
|
||||
if (!mgmt)
|
||||
return 0;
|
||||
|
||||
request = create_request(opcode, index, length, param,
|
||||
callback, user_data, destroy);
|
||||
if (!request)
|
||||
return 0;
|
||||
|
||||
if (mgmt->next_request_id < 1)
|
||||
mgmt->next_request_id = 1;
|
||||
|
||||
request->id = mgmt->next_request_id++;
|
||||
|
||||
if (!send_request(mgmt, request))
|
||||
return 0;
|
||||
|
||||
return request->id;
|
||||
}
|
||||
|
||||
unsigned int mgmt_reply(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy)
|
||||
{
|
||||
struct mgmt_request *request;
|
||||
|
||||
if (!mgmt)
|
||||
return 0;
|
||||
|
||||
request = create_request(opcode, index, length, param,
|
||||
callback, user_data, destroy);
|
||||
if (!request)
|
||||
return 0;
|
||||
|
||||
if (mgmt->next_request_id < 1)
|
||||
mgmt->next_request_id = 1;
|
||||
|
||||
request->id = mgmt->next_request_id++;
|
||||
|
||||
if (!queue_push_tail(mgmt->reply_queue, request)) {
|
||||
free(request->buf);
|
||||
free(request);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wakeup_writer(mgmt);
|
||||
|
||||
return request->id;
|
||||
}
|
||||
|
||||
bool mgmt_cancel(struct mgmt *mgmt, unsigned int id)
|
||||
{
|
||||
struct mgmt_request *request;
|
||||
|
||||
if (!mgmt || !id)
|
||||
return false;
|
||||
|
||||
request = queue_remove_if(mgmt->request_queue, match_request_id,
|
||||
UINT_TO_PTR(id));
|
||||
if (request)
|
||||
goto done;
|
||||
|
||||
request = queue_remove_if(mgmt->reply_queue, match_request_id,
|
||||
UINT_TO_PTR(id));
|
||||
if (request)
|
||||
goto done;
|
||||
|
||||
request = queue_remove_if(mgmt->pending_list, match_request_id,
|
||||
UINT_TO_PTR(id));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
done:
|
||||
destroy_request(request);
|
||||
|
||||
wakeup_writer(mgmt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgmt_cancel_index(struct mgmt *mgmt, uint16_t index)
|
||||
{
|
||||
if (!mgmt)
|
||||
return false;
|
||||
|
||||
queue_remove_all(mgmt->request_queue, match_request_index,
|
||||
UINT_TO_PTR(index), destroy_request);
|
||||
queue_remove_all(mgmt->reply_queue, match_request_index,
|
||||
UINT_TO_PTR(index), destroy_request);
|
||||
queue_remove_all(mgmt->pending_list, match_request_index,
|
||||
UINT_TO_PTR(index), destroy_request);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgmt_cancel_all(struct mgmt *mgmt)
|
||||
{
|
||||
if (!mgmt)
|
||||
return false;
|
||||
|
||||
queue_remove_all(mgmt->pending_list, NULL, NULL, destroy_request);
|
||||
queue_remove_all(mgmt->reply_queue, NULL, NULL, destroy_request);
|
||||
queue_remove_all(mgmt->request_queue, NULL, NULL, destroy_request);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
|
||||
mgmt_notify_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy)
|
||||
{
|
||||
struct mgmt_notify *notify;
|
||||
|
||||
if (!mgmt || !event)
|
||||
return 0;
|
||||
|
||||
notify = new0(struct mgmt_notify, 1);
|
||||
notify->event = event;
|
||||
notify->index = index;
|
||||
|
||||
notify->callback = callback;
|
||||
notify->destroy = destroy;
|
||||
notify->user_data = user_data;
|
||||
|
||||
if (mgmt->next_notify_id < 1)
|
||||
mgmt->next_notify_id = 1;
|
||||
|
||||
notify->id = mgmt->next_notify_id++;
|
||||
|
||||
if (!queue_push_tail(mgmt->notify_list, notify)) {
|
||||
free(notify);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return notify->id;
|
||||
}
|
||||
|
||||
bool mgmt_unregister(struct mgmt *mgmt, unsigned int id)
|
||||
{
|
||||
struct mgmt_notify *notify;
|
||||
|
||||
if (!mgmt || !id)
|
||||
return false;
|
||||
|
||||
notify = queue_remove_if(mgmt->notify_list, match_notify_id,
|
||||
UINT_TO_PTR(id));
|
||||
if (!notify)
|
||||
return false;
|
||||
|
||||
if (!mgmt->in_notify) {
|
||||
destroy_notify(notify);
|
||||
return true;
|
||||
}
|
||||
|
||||
notify->removed = true;
|
||||
mgmt->need_notify_cleanup = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgmt_unregister_index(struct mgmt *mgmt, uint16_t index)
|
||||
{
|
||||
if (!mgmt)
|
||||
return false;
|
||||
|
||||
if (mgmt->in_notify) {
|
||||
queue_foreach(mgmt->notify_list, mark_notify_removed,
|
||||
UINT_TO_PTR(index));
|
||||
mgmt->need_notify_cleanup = true;
|
||||
} else
|
||||
queue_remove_all(mgmt->notify_list, match_notify_index,
|
||||
UINT_TO_PTR(index), destroy_notify);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgmt_unregister_all(struct mgmt *mgmt)
|
||||
{
|
||||
if (!mgmt)
|
||||
return false;
|
||||
|
||||
if (mgmt->in_notify) {
|
||||
queue_foreach(mgmt->notify_list, mark_notify_removed,
|
||||
UINT_TO_PTR(MGMT_INDEX_NONE));
|
||||
mgmt->need_notify_cleanup = true;
|
||||
} else
|
||||
queue_remove_all(mgmt->notify_list, NULL, NULL, destroy_notify);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MGMT_VERSION(v, r) (((v) << 16) + (r))
|
||||
|
||||
typedef void (*mgmt_destroy_func_t)(void *user_data);
|
||||
|
||||
struct mgmt;
|
||||
|
||||
struct mgmt *mgmt_new(int fd);
|
||||
struct mgmt *mgmt_new_default(void);
|
||||
|
||||
struct mgmt *mgmt_ref(struct mgmt *mgmt);
|
||||
void mgmt_unref(struct mgmt *mgmt);
|
||||
|
||||
typedef void (*mgmt_debug_func_t)(const char *str, void *user_data);
|
||||
|
||||
bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy);
|
||||
|
||||
bool mgmt_set_close_on_unref(struct mgmt *mgmt, bool do_close);
|
||||
|
||||
typedef void (*mgmt_request_func_t)(uint8_t status, uint16_t length,
|
||||
const void *param, void *user_data);
|
||||
|
||||
unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy);
|
||||
unsigned int mgmt_send_nowait(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy);
|
||||
unsigned int mgmt_reply(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param,
|
||||
mgmt_request_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy);
|
||||
bool mgmt_cancel(struct mgmt *mgmt, unsigned int id);
|
||||
bool mgmt_cancel_index(struct mgmt *mgmt, uint16_t index);
|
||||
bool mgmt_cancel_all(struct mgmt *mgmt);
|
||||
|
||||
typedef void (*mgmt_notify_func_t)(uint16_t index, uint16_t length,
|
||||
const void *param, void *user_data);
|
||||
|
||||
unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
|
||||
mgmt_notify_func_t callback,
|
||||
void *user_data, mgmt_destroy_func_t destroy);
|
||||
bool mgmt_unregister(struct mgmt *mgmt, unsigned int id);
|
||||
bool mgmt_unregister_index(struct mgmt *mgmt, uint16_t index);
|
||||
bool mgmt_unregister_all(struct mgmt *mgmt);
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/shared/util.h"
|
||||
#include "src/shared/pcap.h"
|
||||
|
||||
struct pcap_hdr {
|
||||
uint32_t magic_number; /* magic number */
|
||||
uint16_t version_major; /* major version number */
|
||||
uint16_t version_minor; /* minor version number */
|
||||
int32_t thiszone; /* GMT to local correction */
|
||||
uint32_t sigfigs; /* accuracy of timestamps */
|
||||
uint32_t snaplen; /* max length of captured packets, in octets */
|
||||
uint32_t network; /* data link type */
|
||||
} __attribute__ ((packed));
|
||||
#define PCAP_HDR_SIZE (sizeof(struct pcap_hdr))
|
||||
|
||||
struct pcap_pkt {
|
||||
uint32_t ts_sec; /* timestamp seconds */
|
||||
uint32_t ts_usec; /* timestamp microseconds */
|
||||
uint32_t incl_len; /* number of octets of packet saved in file */
|
||||
uint32_t orig_len; /* actual length of packet */
|
||||
} __attribute__ ((packed));
|
||||
#define PCAP_PKT_SIZE (sizeof(struct pcap_pkt))
|
||||
|
||||
struct pcap_ppi {
|
||||
uint8_t version; /* version, currently 0 */
|
||||
uint8_t flags; /* flags */
|
||||
uint16_t len; /* length of entire message */
|
||||
uint32_t dlt; /* data link type */
|
||||
} __attribute__ ((packed));
|
||||
#define PCAP_PPI_SIZE (sizeof(struct pcap_ppi))
|
||||
|
||||
struct pcap {
|
||||
int ref_count;
|
||||
int fd;
|
||||
uint32_t type;
|
||||
uint32_t snaplen;
|
||||
};
|
||||
|
||||
struct pcap *pcap_open(const char *path)
|
||||
{
|
||||
struct pcap *pcap;
|
||||
struct pcap_hdr hdr;
|
||||
ssize_t len;
|
||||
|
||||
pcap = calloc(1, sizeof(*pcap));
|
||||
if (!pcap)
|
||||
return NULL;
|
||||
|
||||
pcap->fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (pcap->fd < 0) {
|
||||
free(pcap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = read(pcap->fd, &hdr, PCAP_HDR_SIZE);
|
||||
if (len < 0 || len != PCAP_HDR_SIZE)
|
||||
goto failed;
|
||||
|
||||
if (hdr.magic_number != 0xa1b2c3d4)
|
||||
goto failed;
|
||||
|
||||
if (hdr.version_major != 2 || hdr.version_minor != 4)
|
||||
goto failed;
|
||||
|
||||
pcap->snaplen = hdr.snaplen;
|
||||
pcap->type = hdr.network;
|
||||
|
||||
return pcap_ref(pcap);
|
||||
|
||||
failed:
|
||||
close(pcap->fd);
|
||||
free(pcap);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pcap *pcap_ref(struct pcap *pcap)
|
||||
{
|
||||
if (!pcap)
|
||||
return NULL;
|
||||
|
||||
__sync_fetch_and_add(&pcap->ref_count, 1);
|
||||
|
||||
return pcap;
|
||||
}
|
||||
|
||||
void pcap_unref(struct pcap *pcap)
|
||||
{
|
||||
if (!pcap)
|
||||
return;
|
||||
|
||||
if (__sync_sub_and_fetch(&pcap->ref_count, 1))
|
||||
return;
|
||||
|
||||
if (pcap->fd >= 0)
|
||||
close(pcap->fd);
|
||||
|
||||
free(pcap);
|
||||
}
|
||||
|
||||
uint32_t pcap_get_type(struct pcap *pcap)
|
||||
{
|
||||
if (!pcap)
|
||||
return PCAP_TYPE_INVALID;
|
||||
|
||||
return pcap->type;
|
||||
}
|
||||
|
||||
uint32_t pcap_get_snaplen(struct pcap *pcap)
|
||||
{
|
||||
if (!pcap)
|
||||
return 0;
|
||||
|
||||
return pcap->snaplen;
|
||||
}
|
||||
|
||||
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
||||
void *data, uint32_t size, uint32_t *len)
|
||||
{
|
||||
struct pcap_pkt pkt;
|
||||
uint32_t toread;
|
||||
ssize_t bytes_read;
|
||||
|
||||
if (!pcap)
|
||||
return false;
|
||||
|
||||
bytes_read = read(pcap->fd, &pkt, PCAP_PKT_SIZE);
|
||||
if (bytes_read != PCAP_PKT_SIZE)
|
||||
return false;
|
||||
|
||||
if (pkt.incl_len > size)
|
||||
toread = size;
|
||||
else
|
||||
toread = pkt.incl_len;
|
||||
|
||||
bytes_read = read(pcap->fd, data, toread);
|
||||
if (bytes_read < 0)
|
||||
return false;
|
||||
|
||||
if (tv) {
|
||||
tv->tv_sec = pkt.ts_sec;
|
||||
tv->tv_usec = pkt.ts_usec;
|
||||
}
|
||||
|
||||
if (len)
|
||||
*len = toread;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pcap_read_ppi(struct pcap *pcap, struct timeval *tv, uint32_t *type,
|
||||
void *data, uint32_t size,
|
||||
uint32_t *offset, uint32_t *len)
|
||||
{
|
||||
struct pcap_pkt pkt;
|
||||
struct pcap_ppi ppi;
|
||||
uint16_t pph_len;
|
||||
uint32_t toread;
|
||||
ssize_t bytes_read;
|
||||
|
||||
if (!pcap)
|
||||
return false;
|
||||
|
||||
bytes_read = read(pcap->fd, &pkt, PCAP_PKT_SIZE);
|
||||
if (bytes_read != PCAP_PKT_SIZE)
|
||||
return false;
|
||||
|
||||
if (pkt.incl_len > size)
|
||||
toread = size;
|
||||
else
|
||||
toread = pkt.incl_len;
|
||||
|
||||
bytes_read = read(pcap->fd, &ppi, PCAP_PPI_SIZE);
|
||||
if (bytes_read != PCAP_PPI_SIZE)
|
||||
return false;
|
||||
|
||||
if (ppi.flags)
|
||||
return false;
|
||||
|
||||
pph_len = le16_to_cpu(ppi.len);
|
||||
if (pph_len < PCAP_PPI_SIZE)
|
||||
return false;
|
||||
|
||||
bytes_read = read(pcap->fd, data, toread - PCAP_PPI_SIZE);
|
||||
if (bytes_read < 0)
|
||||
return false;
|
||||
|
||||
if (tv) {
|
||||
tv->tv_sec = pkt.ts_sec;
|
||||
tv->tv_usec = pkt.ts_usec;
|
||||
}
|
||||
|
||||
if (type)
|
||||
*type = le32_to_cpu(ppi.dlt);
|
||||
|
||||
if (offset)
|
||||
*offset = pph_len - PCAP_PPI_SIZE;
|
||||
|
||||
if (len)
|
||||
*len = toread - pph_len;
|
||||
|
||||
return true;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue