Bluetooth Network Aggregation Point

From Gentoo Wiki
Jump to: navigation, search

This article will deal with getting Gentoo to act as a Bluetooth Network Aggregation Point (NAP).

What is a NAP

The Bluetooth specification incorporates the ability to create a Personal Area Network (PAN). It is an Ethernet transparent protocol, thus all standard protocols (especially IP) can be used in such a PAN. A NAP can be thought of being the Master in such a network. It will provide the connectivity to other networks (Internet for instance), for up to eight via Bluetooth connected PAN devices (cell phones, PDAs, laptops maybe).

Scope of this article

We will deal with the creation of a Gentoo NAP, in order to connect a Bluetooth enabled cell phone with the Internet. Then for instance, one could synchronize the cell phone's contacts/calendar with a SyncML capable groupware server, located anywhere on the Internet (or the local network). We will henceforth call the NAP server "Gentoo-Box" and the PAN client "cell phone".


A Bluetooth installation must be done first. If you use simple-agent or bluetoothctl, no GUI programs or applets are needed. Set the "test-programs" USE flag on the net-wireless/bluez-4 package, to get the latest bluez-test-nap script. Newer net-wireless/bluez-5 doesn't have this USE flag yet, but the script named test-nap can be copied from the sources later. We also need Network Bridging, but with our own host configuration.

Setting up a network bridge

As the BlueZ NAP server relies on Gentoo to handle the Ethernet link created by BlueZ, we will create an Ethernet bridge, so we will be able to use the full power of the Gentoo startup scripts. Make sure to backup all files before editing them.

We will deal with the following scenario, as this is probably the easiest and most common case:

                             Global IP address  ┌─────>╎ Internet ╎
                                                │      +−−−−−−−−−−+
                          │                   Router                   │
                          │ (with DHCP and routing (NAT) capabilities) │
                                         ^              ^
                                         │              │
┌────────────┐       ┌────────────┐      │              │      +−−−−−−−−−−−−−−−+
│ Cell phone │<─────>│ Gentoo-Box │<─────┘              └─────>╎ Local network ╎
└────────────┘       └────────────┘                            +−−−−−−−−−−−−−−−+
                                         Local IP address

Execute ifconfig to locate the network card which connects to the router:

root #ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet  netmask  broadcast
        inet6 fe80::213:8fff:fea2:8e76  prefixlen 64  scopeid 0x20<link>
        ether 00:13:8f:a2:8e:76  txqueuelen 1000  (Ethernet)
        RX packets 101  bytes 12439 (12.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 82  bytes 9666 (9.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

The line "inet netmask broadcast" is the one you should be looking for.

Remember the device name (eth0) and edit /etc/conf.d/net:

FILE /etc/conf.d/net
# Comment out this line, and add the following lines:

This tells Gentoo to not ask for a DHCP lease on eth0 (actually it tells Gentoo to do nothing for eth0), and create a new bridge br1, which contains eth0. As eth0 used to get its IP address via DHCP, we set br1 to do exactly that. The options "bridge_stp_state_br1=1" and "bridge_forward_delay_br1=100" make sure, the Spanning Tree Protocol is used, and the forwarding state of the bridge will be reached within one second of a topology change. The last options speed up the cell phone connection considerably, as Gentoo tends to default to around 10 seconds, thus every cell phone connect would take at least that long.

Create a new symbolic link, and restart the network:

root #ln -s net.lo /etc/init.d/net.br1
root #rc-service net.eth0 stop && rc-service net.br1 start
 * Bringing up interface br1
 *   Creating bridge br1 ...
 *   Adding ports to br1
 *     eth0 ...                                                                                         [ ok ]
 * ...                                                                                    [ ok ]

Check, if you are connected to the web. If everything works well, add br1 to the "default" runlevel:

root #ping -c1
root #rc-update add net.br1 default

Connecting a cell phone to the Internet

BlueZ 4 method

Start the NAP service and notice interface br1. Enter in a terminal:

root #bluez-test-nap br1

Watch Syslog when you tell your cell phone to connect to the Internet using the Gentoo-Box as NAP:

root #tail -F /var/log/messages
Mar 20 14:59:35 gentoo bluetoothd[1427]: Added new connection: bnep0
Mar 20 14:59:35 gentoo bluetoothd[1427]: bridge br1: interface bnep0 added
Mar 20 14:59:35 gentoo kernel: device bnep0 entered promiscuous mode
Mar 20 14:59:35 gentoo kernel: br1: port 3(bnep0) entered listening state
Mar 20 14:59:37 gentoo kernel: br1: port 3(bnep0) entered learning state
Mar 20 14:59:39 gentoo kernel: br1: topology change detected, propagating
Mar 20 14:59:39 gentoo kernel: br1: port 3(bnep0) entered forwarding state

You should now be able to connect and load webpages.

Modifying the bluez-test-nap script

If you want to get rid of the sleep timer in the standard bluez-test-nap script, or you want to run the NAP service in the background, you could make these small changes:

FILE signal-pause.patch
--- /usr/bin/bluez-test-nap	2015-03-18 19:55:43.592015279 +0100
+++ /usr/local/bin/bluez-test-nap	2015-03-18 21:29:56.547071403 +0100
@@ -3,7 +3,7 @@
 from __future__ import absolute_import, print_function, unicode_literals
 import sys
-import time
+import signal
 import dbus
 from optparse import OptionParser, make_option
@@ -42,8 +42,12 @@
 print("Press CTRL-C to disconnect")
-	time.sleep(1000)
-	print("Terminating connection")
+	# CTRL-C = KeyboardInterrupt = SIGINT
+	# SIGINT is ignored in a non-interactive shell
+	# Use SIGUSR1 with a startup script
+	signal.signal(signal.SIGUSR1, signal.default_int_handler)
+	signal.pause()

Copy the script to an alternate location, and apply the patch:

root #cp /usr/bin/bluez-test-nap /usr/local/bin/bluez-test-nap
root #patch -p0 </PATH/TO/signal-pause.patch

Now the NAP service can be started in five ways:

  • If /usr/local/bin comes first in your $PATH, you can still type:
    root #bluez-test-nap br1
    root #which bluez-test-nap
  • To run the script in the background, and stop it:
    root #/usr/local/bin/bluez-test-nap br1 >/dev/null &
    root #killall -SIGINT bluez-test-nap
  • To run at startup, let /etc/init.d/local read next scripts. These files must be made executable:
    FILE /etc/local.d/bluez-test-nap.start
    hciconfig hci0 up || exit 1
    exec /usr/local/bin/bluez-test-nap br1 >/dev/null 2>&1 &
    FILE /etc/local.d/bluez-test-nap.stop
    killall -SIGUSR1 bluez-test-nap
    root #chmod +x /etc/local.d/bluez-test-nap.start /etc/local.d/bluez-test-nap.stop
  • Instead of the local.d files approach, it's better to use a real init script. This file must be made executable:
    FILE /etc/init.d/nap
    # Copyright 1999-2015 Gentoo Foundation
    # Distributed under the terms of the GNU General Public License v2
    # $Header: $
    depend() {
    	use net.br1
    	need bluetooth
    start() {
    	ebegin "Starting Bluetooth NAP"
    	hciconfig hci0 up || return 1
    	start-stop-daemon \
    		--start \
    		--make-pidfile \
    		--pidfile /var/run/ \
    		--background \
    		--exec /usr/local/bin/bluez-test-nap br1
    	eend $?
    stop() {
    	ebegin "Stopping Bluetooth NAP"
    	start-stop-daemon --stop --retry -INT/4/-TERM/1/-KILL/1 \
    		--pidfile /var/run/
    	eend $?
    root #chmod +x /etc/init.d/nap
  • In case of plugging and unplugging an USB dongle, just an udev rule can do the job:
    FILE /etc/udev/rules.d/90-bluetooth.rules
    ACTION=="add", KERNEL=="hci0", \
      RUN+="/bin/sh -c 'hciconfig hci0 up || exit 1; exec /usr/local/bin/bluez-test-nap br1 >/dev/null 2>&1 &'"
    ACTION=="remove", KERNEL=="hci0", \
      RUN+="/usr/bin/killall -SIGUSR1 bluez-test-nap"
    # In case of trouble (ugly):
    #ACTION=="remove", KERNEL=="hci0", \
    #  RUN+="/bin/sh -c 'killall -USR1 bluez-test-nap; killall -KILL bluetoothd; rc-service bluetooth restart'"

BlueZ 5 method

The BlueZ 4 way will work, but bluez-test-nap must be renamed to test-nap. Copy the new script test-nap and it's dependency, from the test directory in the source package to /usr/local/bin. The script test-nap must be made executable.

Also the default behaviour of BlueZ 5 changed. Before using test-nap, the device must be initialized. Desktop applications like BlueDevil do that automatically. Otherwise, this command can be used:

root #hciconfig hci0 up


No webpages can be loaded

If the phone does not show any sign of being connected, try Wireshark to figure out what packets are being sent and received. Maybe a simple

root #echo 1 > /proc/sys/net/ipv4/ip_forward

can do the trick. Make sure no firewall settings on the Gentoo-Box interfere.

Restore your old Internet connection

If you lose your Internet connectivity, if things break, restore your backup of /etc/conf.d/net and restart networking:

FILE /etc/conf.d/net
(old file)
root #rc-service net.eth0 restart

Tools for testing

There is a bluez-test-network utility, that you can use for testing PAN connection initiated from server side, and a monitor-bluetooth utility to watch what is going behind the D-Bus scene, because watching /var/log/messages can be not enough.