8

I don't often post on forums like this, but when I do, there's always someone in the comments telling me I violated some practice of forum posting and I never get a legitimate answer, so I figured I'd explain my situation carefully before I get started:

  1. I am no expert on Bluetooth PAN, so this might not even be possible. If so, just let me know.
  2. I've exhausted about seven hours browsing Stack Exchange and other forums for tutorials or explanations. Hardly any are quite what I'm looking for and the ones that were remotely similar were mostly from several years ago, making them extremely outdated.

With that out of the way, here's what I'm trying to do and some requirements:

  1. Establish a Bluetooth network with a raspberry pi as the client with various devices connected to it. From what I've read, that's called a PAN server.
  2. The raspberry pi will host a Node express server that has a website the connected devices can access.
  3. The raspberry pi can't host an access point network that broadcasts on 2.4 or 5ghz, hence the reason for Bluetooth. The setting where this is used has a strict rule against hosting WiFi networks. That would be my first choice, but Bluetooth seems to be the only option that doesn't break this rule.

I've followed about five or six solutions thoroughly, but it seems that most are just for bridging other devices to a WiFi network the pi is on. What I'm looking for is a solution to bridge the devices to the loopback of the pi where the server is hosted. I've tried bridge_ports lo in the /etc/network/interfaces file for the bridge, but apparently that doesn't work. I'm clearly no expert in this, so could someone help me out? Sorry if I'm sounding blunt, I don't post often on forums like this and want to make sure I'm clear about what I'm looking for and don't want to break some community code or whatever.

Edit: Sorry, should have mentioned: this is a pi 3B on Buster 2019-09-26

11
  • See raspberrypi.stackexchange.com/a/61153/8697
    – Milliways
    Commented Feb 7, 2020 at 6:36
  • 2
    Welcome to Raspberry Pi :-) If you get some hints here to manage your question please don't see it as criticism. It's only to help you to get better answers with a good question. But you already have made a good question as you can see by the upvotes :)
    – Ingo
    Commented Feb 7, 2020 at 10:56
  • Hello and welcome – Contrary to what you said "The raspberry pi can't host an access point network that broadcasts on 2.4 or 5ghz", it has if you bought a Raspberry Pi 3 or a newer model/version. Also, you can plug a wireless dongle. So, please add the model/version and OS. Commented Feb 7, 2020 at 11:40
  • From my understanding, not hosting a WiFi is not a restriction of the device but the scenario where the poster wants to use his Raspberry Pi. I.e. the Raspberry Pi could create a WiFi network but it may not do so due to external constraints.
    – Betaminos
    Commented Feb 7, 2020 at 16:38
  • @M.Rostami in the area where we have the pi set up, hotspots and access points are strictly forbidden. I would've just done that, but there are huge consequences for setting up routers and hotspots, even if they're hidden.
    – Amon Green
    Commented Feb 7, 2020 at 21:53

1 Answer 1

7

It seems that you have had no response to this so I thought I would have a try to see how far I got. These are my notes from the journey. This was not a successful journey for me but I'm hoping by sharing my failure it will help someone build on it.

From searching around it is clear that how to configure Bluetooth Personal Area Networks with BlueZ has changed dramatically over the last few years. Most of the tutorials I found used tools that have since been deprecated.

As I could not find a good tutorial I went and looked at more formal documentation.

The Bluetooth SIG has a document on the PAN profile at: https://www.bluetooth.com/specifications/profiles-overview/

and the PAN Profile overview on the Symbian Developer Library I found helpful: From: https://docs.huihoo.com/symbian/s60-5th-edition-cpp-developers-library-v2.1/GUID-35228542-8C95-4849-A73F-2B4F082F0C44/sdk/doc_source/guide/Short-Link-Services-subsystem-guide/ShortLinkServices/BluetoothProfiles/BluetoothPAN/BTPANProfileOverview.html

It appears there are three main variations on a PAN. This is backed up when looking in the BlueZ Network DBus API. However, the BlueZ API seems to have client/server of either GN, NAP or PANU whereas the above documents talk about the PANU always being the client. I did some drawnings of how I think it is in BlueZ:

Network Bridge - Client Raspberry Pi - Server Phone

enter image description here

Network Bridge (Network Aggregation Point) [nap]

enter image description here

Group Ad-hoc Network [gn]

enter image description here

Peer to Peer [panu]

enter image description here

In the BlueZ readme it suggests the networking profiles are enabled by default. https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/README#n188

The networking API is documentated at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/network-api.txt

They have an example/test Python script for this client functionality at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test/test-network

And for a PAN Network server: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test/test-nap

There is a thread about using this on the developer mailing list. https://marc.info/?l=linux-bluetooth&m=145504188107174&w=2 There seems to be good information in the thread but (spoiler alert) they didn't get it working but that was a few years ago.

However, I did find a follow-up that is disconnected from the main thread: https://marc.info/?l=linux-bluetooth&m=149129232432090&w=2 Not a conclusive answer but there was a reply from one of the main developers suggesting it should work. This last thread talked about running a test-gn script which I could not find.

For the server, the NetworkServer1 Register method is called from the adapter device object path. Using bluetoothctl show before and after this Register command will show that a PAN UUID has been added.

For the client, the Network1 Connect method is called from the remote device object path. For this path to be there, the client and server device need to have been paired. I have been using bluetoothctl to do the pairing.

I edited /etc/dbus-1/system.d/bluetooth.conf to include permission for the Network1 and NetworkServer1 interfaces. I did this on both my test Raspberry Pi's

  <policy user="root">
    <allow own="org.bluez"/>
    <allow send_destination="org.bluez"/>
    <allow send_interface="org.bluez.Agent1"/>
    <allow send_interface="org.bluez.MediaEndpoint1"/>
    <allow send_interface="org.bluez.MediaPlayer1"/>
    <allow send_interface="org.bluez.Profile1"/>
    <allow send_interface="org.bluez.GattCharacteristic1"/>
    <allow send_interface="org.bluez.GattDescriptor1"/>
    <allow send_interface="org.bluez.LEAdvertisement1"/>
    <allow send_interface="org.bluez.Network1"/>
    <allow send_interface="org.bluez.NetworkServer1"/>
    <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
    <allow send_interface="org.freedesktop.DBus.Properties"/>
  </policy>

Tethering to phone

I tested tethering to my phone as this just required me to get the client working. This worked well. I enabled Bluetooth tethering on my Android phone. Then on the Raspberry Pi, using bluetoothctl, scanned, paired, and trusted before using the following commandline to connect:

busctl call org.bluez /org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx org.bluez.Network1 Connect s pan_type

[xx_xx_xx_xx_xx_xx being the BD_ADDR of my phone with : replaced with _]

[pan_type is one of gn, panu, or nap]

I have been using a python script to do the same [network_client.py]:

import argparse
from signal import pause
import pydbus

parser = argparse.ArgumentParser()
parser.add_argument('d', help='BD_ADDR of network server')
parser.add_argument('u', help='Server type to connect to [gn, panu, nap]')
args = parser.parse_args()

device = args.d
device_path = f"/org/bluez/hci0/dev_{device.replace(':', '_')}"
bus = pydbus.SystemBus()

network = bus.get('org.bluez', device_path)['org.bluez.Network1']
print(f'Connecting to {args.d} as a {args.u}')
network.Connect(args.u)
try:
    print('Press CTRL-C to disconnect')
    pause()
except KeyboardInterrupt:
    print('Disconnecting from network')
network.Disconnect()

Using the command line:

python3 network_client.py xx:xx:xx:xx:xx:xx nap

These instructions remain valid for the different client types you may want to connect to whether that is on a phone or a Raspberry Pi.

Setting up Bluetooth PAN Server.

I have found this to be the more difficult part because of my lack of knowledge on setting up network bridges and understanding what BlueZ is doing for me and what I need to do. I have found the following documents useful references for creating network bridge on the Bluetooth PAN server. :

Iproute2 tutorial https://www.howtogeek.com/657911/how-to-use-the-ip-command-on-linux/

Iproute2 examples https://baturin.org/docs/iproute2/

As I don't have this fully worked out I am using iproute2 on the command line so settings aren't saved. This means when I make errors, a reboot resets things to a working state

Common server setup for all PAN types

  1. Modify /etc/dbus-1/system.d/bluetooth.conf to include Network1 and NetworkServer1 interfaces (same as client setup)
  2. Create the network bridge before launching the Bluetooth PAN server
  3. Ensure the PAN is registered before the client pairs with the server
  4. use trust in bluetoothctl to ensure the server and client trust each other
  5. If things don't appear to be working, look for error messages on the server with service bluetooth status

Common error messages in service bluetooth status [server]

Bridge specified in Register command does not exist

BNEP server cannot be added
bnep: Can't add bnep0 to the bridge

Connection from client without server registered (0x1116 = NAP, 0x1117 = GN etc) or permissions in /etc/dbus-1/system.d/bluetooth.conf

Server error, bridge not initialized: (0x1116)
Jul 26 10:43:11 raspberrypi bluetoothd[581]: BNEP server cannot be added

Common script exit error messages [client]

PAN type not registered on Server

gi.repository.GLib.Error: g-io-error-quark: GDBus.Error:org.bluez.Error.Failed: Input/output error (36)

Starting a client for a PAN type that hasn't been paired with on specified server or permissions in /etc/dbus-1/system.d/bluetooth.conf hasn't been set.

gi.repository.GLib.Error: g-io-error-quark: GDBus.Error:org.bluez.Error.NotSupported: Operation is not supported (36)

Basic form for BlueZ register of PAN on server

This can be done on the commandline with one of the DBus tools. e.g.:

busctl call org.bluez/ org/bluez/hci0 org.bluez.NetworkServer1 Register ss pan_type bridge_name 

Or I have been using a Python script [network_server.py]:

import argparse
import pydbus
from gi.repository import GLib

bus = pydbus.SystemBus()

server = bus.get('org.bluez', '/org/bluez/hci0')['org.bluez.NetworkServer1']

parser = argparse.ArgumentParser()
parser.add_argument('u', help='Server role [gn, panu, nap]')
args = parser.parse_args()

if args.u == 'gn':
    bridge = 'bluez_gn'
elif args.u == 'panu':
    bridge = 'bluez_panu'
else:
    bridge = 'bluez_nap'

server.Register(args.u, bridge)

print(f'Service {args.u} is registered with bridge {bridge}')

mainloop = GLib.MainLoop()
print('Press CTRL-C to disconnect')
try:
    mainloop.run()
except KeyboardInterrupt:
    mainloop.quit()

Pairing process

The server needs to be started before the client

Care needs to be taken when pairing two Raspberry Pi's together for PAN to ensure things are done in the correct order

On server:

server: Define bridge for PAN type
server: start server script so PAN UUID is in list of services
server[bluetoothctl]: `default-agent`
server[bluetoothctl]: `discoverable on` <leave bluetoothctl running>

On client

client[bluetoothctl]: `default-agent`
client[bluetoothctl]: `scan on`
client[bluetoothctl]: `scan off`
client[bluetoothctl]: `pair xx:xx:xx:xx:xx:xx` <need to type yes on both machines>
client[bluetoothctl]: `trust xx:xx:xx:xx:xx:xx`

On Server

server[bluetoothctl]: `trust yy:yy:yy:yy:yy:yy`

On Client

client: start client script

Peer to Peer [panu]

Work In Progress

Group Network [gn]

sudo ip link add name bluez_gn type bridge
sudo ip link set bluez_gn up
python3 network_server.py gn

I then use the pairing process outlined above before starting the client. After ~30 seconds I can use ip addr show to see that client bnep0 has an ip address and I can ping it. However, I can't ping the server from the client. I suspect this is because I have created the bridge incorrectly.

Network Bridge (Network Aggregation Point) [nap]

On the server RPi, I have wired internet on eth0 so this is how I setup the bridge and start the server

sudo ip link add name bluez_nap type bridge
sudo ip link set bluez_nap up
sudo ip link set dev eth0 master bluez_nap
python3 network_server.py nap

I then use the pairing process outlined above before starting the client. This give my PAN client access to the internet over bluetooth. However, I do loose network access to the PAN server. I suspect this means my bridge setup is not not complete.

Command to get status information

Commands I've been using to check on status etc are:

service bluetooth status
sudo btmon -t
ip address show
ip route show
ip link show
dmesg -w

If anyone understands why BNEP server is not being created then please let me know.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.