Sunday, April 10, 2016

IPv6 over Bluetooth on the BeagleBone Black

When we remotely connect to a BeagleBone Black we generally SSH into them over a WiFi or wired network.  There are several drawbacks to using a WiFi or wired network connection with a BeagleBone Black especially with robotic projects.  In this post I will demonstrate how we can use 6LoWPAN over Bluetooth Smart to connect two BeagleBone Blacks together.  This will allow us to use standard Internet technologies like SSH or HTTP over a Bluetooth connection. 

6LoWPAN (IPv6 over Low Power Wireless Networks) for Bluetooth was introduced with the Bluetooth Smart 4.2 specifications.  It is defined by RFC7668. 6LoWPAN is a software specification that will work with most Bluetooth 4.0 adapters therefore we do not need a special Bluetooth 4.2 adapter to use it.  We also do not need any additional network infrastructure, beside the Bluetooth adapters, like we do with wired and WiFi networks.  Bluetooth smart technologies also use significantly less power as compared to USB WiFi adapters.

One thing to note is I am using two BeagleBone Blacks for this post however these instructions will also work with Ubuntu 15 computers (or most other Linux based computers) if you are using a 4.4.X or newer kernel.  You can check your kernel version by issuing the following command:

uname -r

In this post I will walk though installing a new kernel on the BeagleBone Black.  If you are using Ubuntu 15 and have an older kernel, you will need to upgrade it.  This Google search should return a number of sites that will walk you though the upgrade process.

For this post I am starting with the standard Debian 8.3 image on a 16 gig SD card.  When I attempted the steps described in this post with a 4 gig SD card I ran out of room so you will need to use at least an 8 gig SD card.  The first step will be installing a new kernel.


Installing a new kernel on your BeagleBone Black (pre-built 4.4.6-bone6 kernel)

If you attempt to use 6LoWPAN with the standard kernel that comes with Debian 8.3 the two devices appear to connect however the connection will drop after a few seconds.  The problem is fixed in the 4.4.X or newer kernels.  The kernel that I am using is the pre-built 4.4.6-bone6 kernel.  Any of the 4.4.X or newer kernels should work but I can confirm that the 4.4.6-bone6 kernel does work. 

When I first followed the steps define in this post I already had Swift installed on both of my BeagleBone Blacks as described in this post and the kernel installed correctly with the Bluetooth drivers.  After working with this a little bit, I had to reset one of my BeagleBone Blacks and I ended up installing the new kernel without installing Swift first.  When the installation of the new kernel was complete and my BeagleBone Black came back up, after the reboot, my Bluetooth adapters no longer worked.  In the logs I saw that there was an issue loading the Broadcom drivers for the adapter.  It took me two days of experimenting but I finally figured out that if I installed Swift first then after the new kernel was installed my Bluetooth adapters worked properly.  I believe it has to do with installing libicu-dev and clang-3.6 with Swift. 

If you have a problem with your adapter after upgrading the kernel you may want to start over and use the following steps to install libicu-dev and clang-3.6 prior to upgrading your kernel.

sudo apt-get install libicu-dev
sudo apt-get install clang-3.6
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100

When we install the 4.4.6-bone6 kernel we also need to install the headers.  The following command will install both the kernel and the headers.

apt-get install linux-headers-4.4.6-bone6 linux-image-4.4.6-bone6

Once the new kernel is installed we will need to restart the BeagleBone Black.  Once it has restarted we can begin configuring the 6LoWPAN connection on both the master and slave devices.

Configure the 6LoWPAN Master

The 6LoWPAN Master is the device that listens for incoming connections.  Create a new file named bluetoothMaster.sh on the device you wish to use as the master and put the following code in it.

modprobe bluetooth_6lowpan
echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable
hciconfig hci0 leadv

In this script we begin by loading the bluetooth_6lowpan module.  We then echo a 1 into the 6lowpan_enable file.  This will enable 6LoWPAN on the device.  Finally we use the hciconfig hci0 leadv command to begin advertising. 

We will also need another script that will setup the network once the client connects.  Let's call this script setNet.sh but we will want to wait to add the code to this script until the first client connects.  This will make it easer to get the IP Address that we will define for our interface.

Configure the 6LoWPAN Slave

The 6LoWPAN Slave is the device that connects to the master.  Create a new file named bluetoothSlave.sh and put the following code in it.

modprobe bluetooth_6lowpan
echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable
hcitool lecc 98:58:8a:06:db:9b
echo "connect 98:58:8a:06:db:9b 1" > /sys/kernel/debug/bluetooth/6lowpan_control

Note:  Change the 98:58:8a:06:db:9b in this script to the Bluetooth MAC address of the Bluetooth adapter on the master device.  To get the MAC address for a Bluetooth adapter you can use the hcitool dev command on the device that the Bluetooth adapter is connected to. 

In this script we begin by loading the bluetooth_6lowpan module and enabling 6lowpan as we did in the bluetoothMaster.sh script.  We then use the hcitool command with the lecc option to connect to the master.  The address in the hcitool command is the MAC address for the Bluetooth adapter on the master.   Finally we echo “connect {MAC address} 1” to the 6lowpan_control file which will enable the 6LoWPAN connection between the master and slave devices.

Testing the 6LoWPAN connection

Now that we have a 6LoWPAN connection between our two devices we can test the connection by attempting to ping one device from the other.  The first thing we need to do is to get the IPv6 addresses assigned to each device. We can do this by running the following command on each device.
ifconfig bt0

You should see something like this:

bt0       Link encap:UNSPEC  HWaddr 98-58-8A-FF-FE-06-DB-9B-00-00-00-00-00-00-00-00 
          inet6 addr: fe80::9a58:8aff:fe06:db9b/64 Scope:Link
          UP POINTOPOINT RUNNING MULTICAST  MTU:1280  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:527 (527.0 B)  TX bytes:321 (321.0 B)

If this were the bt0 address on my master device then on the slave device I would run the following command:

ping6 –I bt0 fe80::9a58:8aff:fe06:db9b

If the ping works then our connection is correctly setup however addresses with the fe80 prefix are link-local address that really isn’t that useful except for testing the connection.  Lets see how we could generate a non link-local address and assign it to the bt0 interface.

Generating and setting an IPv6 address

Before we generate our own IPv6 address, lets look at how the OS generated the link-local address.  In the example above the address generate when the interface came up is: fe80::9a58:8aff:fe06:db9b .  The Bluetooth MAC address for the adapter is: 98:58:8a:06:db:9b.  Do you notice anything similar between the IPv6 address assigned to the bt0 adapter and the MAC address of the Bluetooth adapter?

As you probably saw, the OS uses the Bluetooth MAC address to generate the IPv6 address.  Lets look at how the IPv6 address was generated.  We start off with the MAC address and add an 0xFF and 0xFE between the third and forth octet to give us 98:58:8a:ff:fe:06:db:9b.  We then OR 0x02 to the first octet to give us 9a:58:8a:ff:fe:06:db:9b.  We can now covert this to standard IPv6 notation where we group four hexadecimal digits together and separate the groups by a colon.  This will give us  9a58:8aff:fe06:db9b.   Finally we need to add a prefix.  The OS used the fe80 prefix that is reserved for link-local connections which gave us the fe80::9a58:8aff:fe06:db9b .   

For the IPv6 address that we will assign to the bt0 interface we will use the 2001:db8 prefix that is reserved for documentation.  This will give us the following address: 2001:db8::9a58:8aff:fe06:db9b.  Since the OS generates the link-local address, rather than going through these calculation steps we could simply take the link-local address and remove the fe80 prefix and add the prefix we wish to use.

Now that we have an address we will want to assign it to the bt0 interface.  To do this we will add the following line to the setNet.sh script on the master:

ifconfig bt0 inet6 add 2001:db8::9a58:8aff:fe06:db9b/64

Remember to replace 2001:db8::9a58:8aff:fe06:db9b with the address for your device. 

We will also want to add the following two lines to the end of the bluetoothSlave.sh file on the slave device:

sleep 2 //pause to make sure the bt0 interface is up
ifconfig bt0 inet6 add 2001:db8::5ef3:70ff:fe75:b1d6/64

Remember to replace the 2001:db8::5ef3:70ff:fe75:b1d6 address with the one for your slave.

The final scripts

Before we test everything lets look at the final versions of our scripts.  On the master we have two scripts.  These are named bluetoothMaster.sh and setNet.sh.  The bluetoothMaster.sh should contain the following code:
 
modprobe bluetooth_6lowpan
echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable
hciconfig hci0 leadv

The setNet.sh should contain the following code:

ifconfig bt0 inet6 add 2001:db8::9a58:8aff:fe06:db9b/64

Remember to replace the IPv6 address in this script with the correct address for your device.

The slave should contain one script named bluetoothSlave.sh which should contain the following code.

modprobe bluetooth_6lowpan
echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable
hcitool lecc 98:58:8a:06:db:9b
echo "connect 98:58:8a:06:db:9b 1" > /sys/kernel/debug/bluetooth/6lowpan_control

sleep 2 //pause to make sure the bt0 interface is up
ifconfig bt0 inet6 add 2001:db8::5ef3:70ff:fe75:b1d6/64

In this script your will want to replace the  98:58:8a:06:db:9b with the Bluetooth MAC address of your Master device and replace the 2001:db8::5ef3:70ff:fe75:b1d6  with the IPv6 address for your slave device.

Putting it all together

Now that we have our scripts lets test everything and see how it works.  Go ahead and reboot both devices to clear everything.  When the master device comes up run the bluetoothMaster.sh script.  After the bluetoothMaster.sh finishes, run the bluetoothSlave.sh script on the slave device.  After the bluetoothSlave.sh finishes run the setNet.sh script on the master.  

After all three scripts complete the 6LoWPAN connection should be up.  We can test this with the ifconfig bt0 command.  If all is well we should see that the bt0 interface is up on both devices with both the link-local IPv6 address and the IPv6 address that you assigned it.  We can now test the connection by using ssh to remotely connect to one device from the other.



No comments:

Post a Comment