2017-10-18 12:06:12

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 0/3] 6LoWPAN tun/tap device


Hi,

These patches aim at a bit different approach in handling IP over
Bluetooth Low Energy connections that what has been implemented in the
kernel so far. The goal is to lift the current L2CAP channel handling
into Bluez userspace with the following benefits:
* Authorization agent can be used directly
* Use common code to handle profiles/services
* Async IO
* No new sets of kernel APIs are needed

The essence of the change is to use a regular TUN/TAP interface
enhanced with 6LoWPAN header compression and decompression with Bluez
handling all other aspects of Bluetooth Low Energy connections. As the
kernel already contains a very capable 6LoWPAN implementation, it is
reused with the TUN/TAP driver providing appropriate IP interface
handling while sending the resulting 6LoWPAN compressed IP packets to
user space and Bluez that will send them further over BT LE L2CAP.
These changes are not bound to current BT LE IPSP implementation, other
upcoming BT LE profiles or other user space components can freely reuse
what is being presented here. Luiz will send the corresponding changes
for Bluez in a short while.

Patches 1/3 and 2/3 introduce no new functionality but only a trivial
transformation where the 6LoWPAN compression would take struct
lowpan_dev instead of the bigger struct net_device. The reason is to
decouple 6LoWPAN compression from the net_device itself, as the
intended TUN/TAP driver does not have any relation to 6LoWPAN link
types and the compression/decompression functionality is in essence a
library to produce the desired IP packet transformation.

Patch 3/3 introduces 6LoWPAN handling into the current tun.c driver by
adding a new IFF_6LO flag for turning the feature on and off.
Admittedly the features could be implemented better than it is right
now, the point is not to come up with the prettiest code but to
introduce the feature and then start discussing what the best option is
to implement such an interface variant - is it via such an IFF_6LO
flag, should a particular new type of BT LE 6LowPAN interface be
created, or can this be generalized to cover also 802.15.4 interfaces
although the 802.15.4 technology does not have anything corresponding
to the Bluez user space daemon.

Patches apply to bluetooth-next fac72b24 as of today.


Cheers,

Patrik


Patrik Flykt (3):
6lowpan: Use struct lowpan_dev instead of net_device
6lowpan: Factor out lowpan device context initialization
tun: Add 6LoWPAN compression/decompression to tun driver

drivers/net/tun.c | 61 +++++++++++++++++++++-
include/net/6lowpan.h | 10 ++--
include/uapi/linux/if_tun.h | 1 +
net/6lowpan/core.c | 22 +++++---
net/6lowpan/iphc.c | 121 +++++++++++++++++++-------------------------
net/6lowpan/nhc.c | 8 +--
net/6lowpan/nhc.h | 2 +-
net/bluetooth/6lowpan.c | 6 ++-
net/ieee802154/6lowpan/rx.c | 3 +-
net/ieee802154/6lowpan/tx.c | 2 +-
10 files changed, 147 insertions(+), 89 deletions(-)

--
2.11.0



2017-10-27 10:19:10

by Patrik Flykt

[permalink] [raw]
Subject: Re: [RFC 3/3] tun: Add 6LoWPAN compression/decompression to tun driver


Hi Alex,

On Thu, 2017-10-26 at 10:54 -0400, Alexander Aring wrote:
> LOWPAN_IPHC_MAX_HC_BUF_LEN more bytes are added to sk_buff headroom
> > to ensure there will be enough bytes to push headers to. This is
> > probably an overkill and probably done wrongly anyway.
> >
>
> This define should be removed because there exists no case where the
> compression will be larger than the ipv6 header and vice versa.

Ok, good to know. I could not convince myself otherwise, so I took a
shot at it with a really big cannon. I will remove this from any future
iterations.

> > An ethernet MAC header is added in front of the (compressed) IPv6
> > datagram in both directions; no such transport exists for 6LoWPAN,
> > but this is just an example implementation trying to explain the
> > idea behind the BTLE handling in user space and the 6LoWPAN
> > compression and decompression in kernel space. Thus the tun/tap
> > driver comes in handy as the victim of the demonstration.
>
> Sorry but this really scares me.

The header format should of course take 802.15.4 and Bluetooth into
account, but for the time being this was the easiest wrt time that I
could implement and simplest to understand. See
https://marc.info/?l=linux-wpan&m=150849496308755&w=2 how it is all
used together in Luiz' patch set.

Do we have a user space entity for 802.15.4 similar to Bluez that needs
to do the same thing? If yes, the different address lengths will then
mandate a new header format to be used that fits both technologies and
8, 6 and 2 byte MAC addresses.

> The kernel use 6LoWPAN IPHC for
> ethernet (as mac header information) and you doing BTLE/L2CAP stuff
> in user space which is not anymore for your original use-case which
> is "ethernet".

It's actually the other way round. BTLE/IPSP requires 6LoWPAN
copmression in RFC 7668. Those BTLE/IPSP encapsulated 6LoWPAN
compressed IPv6 packets need to end up somewhere, and as Bluetooth uses
otherwise "ethernet compatible" MAC addresses, it's really easy to
write an ethernet header in front and have the rest of the Linux kernel
to forward it, be it via a bridge or plain IP routing.

> This might work for now, because only address handling is used in
> IPHC as MAC header information and eth/btle use the same address
> length (besides that the address is not always the same and BTLE is
> not a EUI-48 address with multicast bit etc.)

Yes, the address generation is different from 802.15.4, see RFC 7668,
Section 3.2.2.

> You cannot simple use MAC X handling in kernelspace and use then MAC
> handling Y in userspace - this will not work for long time.

Sending ethernet frames stuffed with 6LoWPAN is not a generally good
idea, its just easy for demonstration purposes. As above, a new header
format of expressing MAC addresses is probably the way to go?

> I already
> fight with UDP based protocols in 802.15.4 6LoWPAN who depends on
> 802.15.4 MAC information which are not just addressing information.

Quickly looking into UDP header compression didn't reveal any further
dependencies on MAC addressing, which specification did you have in
mind wrt UDP or similar layer headers?

> If they need more bluetooth related information there you have no
> possibility to get them. The same for next header compression which
> might want more MAC information than just addressing for bluetooth.

There are no additional dependencies or even planned ones from 6LoWPAN
to Bluetooth that I'm aware of. So I'd go with the assumption that
6LoWPAN will know only of the MAC addresses and the (MAC layer) data
length, with the rest of the information being on IP(v6) level.

> > +                       if (lowpan_header_decompress(skb, &tun-
> > >ldev,
> > +                                                       tun->dev-
> > >dev_addr,
> > +                                                       &eth.h_sour
> > ce) < 0) {
>
> This will make a module dependency of 6lowpan_iphc for the tap
> driver. I am pretty sure that the tap driver people doesn't like
> that.

Ok, needs to be adressed.

> Which
> brings me to another issue with this patch:
> Why you don't create a virtual lowpan interface on top of the tap
> device. This handling is _incredibly_ against our design to have a
> 6LoWPAN interface device type for the user space.
> Now we have will have a tap device which makes internally 6LoWPAN
> handling but is not visible as 6LoWPAN interface in the user space,
> this will confuse 6LoWPAN user space applications.

The only user space application that will know of 6LoWPAN compression
being applied is Bluez. There are zero parameters that can be tuned, as
Bluetooth specifies no configurable knobs for the 6LoWPAN IPv6
datagrams that are transported over BTLE/IPSP. The Bluetooth
specification relies on RFC 7668 getting the IPv6 details in sync end
to end.

What, if any, user space application would be able to manipulate a
Bluetooth 6LoWPAN interface and why? Much like a VPN with compression,
Bluetooth is by its nature tunneling 6LoWPAN IPv6 over BTLE/IPSP so
there is no inherent need of a device driver specific for handling
6LoWPAN.

> What our design is (just to remember):
>  - Ethernet interface (MAC/6LoWPAN view, before adaption)
>  - 6LoWPAN interface (IPv6 view, after adaption)
>
> I am pretty sure you can run your above changes transparently
> separated of TAP driver by adding a 6LoWPAN interface on top. This
> will also make no dependency to the TAP driver.

Probably. But that also means there is some other user space
application that can somehow manipulate such an interface. But for
Bluetooth there already is Bluez that takes care of setting up and
tearing down connections, si there isn't much need of any other
application to control or configure BTLE/IPSP interfaces?

> I guess what you want is a TAP interface which is NOT ethernet. It
> need to get some special MAC information for your subsystem which is
> BTLE. Not using ethernet here. To have the assumption here "it will
> work because the address length is the same" is simple wrong, they
> will be more use-cases where upper-layers need to have special MAC
> information belongs to your link-layer subsystem.

So it does sound like we do want a decent header for 6LowPAN traffic
which can take both 802.15.4 and Bluetooth systems into account when
dealing with the TAP file descriptor pulling the packets to/from user
space, right? The end result in the kernel should be ethernet MAC
frames for Bluetooth for maximum compatibility with all other
networking subsystems, and with 802.15.4 frames for IEEE 802.15.4?


Cheers,

Patrik

2017-10-27 08:35:42

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC 3/3] tun: Add 6LoWPAN compression/decompression to tun driver

Hi Alex,

On Thu, Oct 26, 2017 at 5:54 PM, Alexander Aring <[email protected]> wrote:
> Hi,
>
> First: I always asked myself: 6LoTUN makes no sense because 6LoWPAN
> depends on MAC information and TUN interfaces works because IPv6
> doesn't depend on MAC information. Now everything is more clear, this
> has nothing todo with TUN it's TAP because you use ethernet MAC
> information to do 6LoWPAN stuff.
>
> On Wed, Oct 18, 2017 at 8:27 AM, Patrik Flykt
> <[email protected]> wrote:
>> Define a new IFF_6LO flag for the tun/tap driver that enables 6LoWPAN
>> compression/decompression for tap devices. This is achieved by calling
>> lowpan_header_compress once the sk_buff is destined for user space and
>> calling lowpan_header_decompress when the user space writes packets to
>> kernel. A copy of the ethernet MAC headers are needed both ways, as
>> the 6LoWPAN compression may end up expanding the header size by one
>> byte in the worst case.
>>
>> LOWPAN_IPHC_MAX_HC_BUF_LEN more bytes are added to sk_buff headroom
>> to ensure there will be enough bytes to push headers to. This is
>> probably an overkill and probably done wrongly anyway.
>>
> This define should be removed because there exists no case where the
> compression will be larger than the ipv6 header and vice versa.
>
>
>> An ethernet MAC header is added in front of the (compressed) IPv6
>> datagram in both directions; no such transport exists for 6LoWPAN,
>> but this is just an example implementation trying to explain the
>> idea behind the BTLE handling in user space and the 6LoWPAN
>> compression and decompression in kernel space. Thus the tun/tap
>> driver comes in handy as the victim of the demonstration.
>>
>
> Sorry but this really scares me. The kernel use 6LoWPAN IPHC for
> ethernet (as mac header information) and you doing BTLE/L2CAP stuff in
> user space which is not anymore for your original use-case which is
> "ethernet".

You should check what TUNSETLINK does, it does accept changing the
dev->type which are setting to ARPHRD_6LOWPAN:

https://marc.info/?l=linux-bluetooth&m=150901023927589&w=2

We could perhaps even replace the ether_header with something else if
we detect this change, perhaps even set ARPHRD_6LOWPAN by default if
IFF_6LO is set, anyway if you are claiming TAP = Ethernet I don't
think this is valid in the light of TUNSETLINK.

> This might work for now, because only address handling is used in IPHC
> as MAC header information and eth/btle use the same address length
> (besides that the address is not always the same and BTLE is not a
> EUI-48 address with multicast bit etc.)

When the dev->type is ARPHRD_6LOWPAN the IID will be generated
properly, but we might change the frame format to not reuse the
ethernet header if there is interest in using 6LoWPAN with other
tecnologies.

> You cannot simple use MAC X handling in kernelspace and use then MAC
> handling Y in userspace - this will not work for long time. I already
> fight with UDP based protocols in 802.15.4 6LoWPAN who depends on
> 802.15.4 MAC information which are not just addressing information. If
> they need more bluetooth related information there you have no
> possibility to get them. The same for next header compression which
> might want more MAC information than just addressing for bluetooth.

Not sure I follow this comment, what the MAC has to do with IP protocols?

>> Signed-off-by: Patrik Flykt <[email protected]>
>> ---
>>
>> Hi,
>>
>> This is the one applying on fac72b24.
>>
>>
>> Patrik
>>
>>
>> drivers/net/tun.c | 61 +++++++++++++++++++++++++++++++++++++++++++--
>> include/uapi/linux/if_tun.h | 1 +
>> 2 files changed, 60 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
>> index 57e4c31fa84a..11b6494bb7ca 100644
>> --- a/drivers/net/tun.c
>> +++ b/drivers/net/tun.c
>> @@ -66,6 +66,7 @@
>> #include <linux/nsproxy.h>
>> #include <linux/virtio_net.h>
>> #include <linux/rcupdate.h>
>> +#include <net/6lowpan.h>
>> #include <net/net_namespace.h>
>> #include <net/netns/generic.h>
>> #include <net/rtnetlink.h>
>> @@ -231,6 +232,8 @@ struct tun_struct {
>> u32 rx_batched;
>> struct tun_pcpu_stats __percpu *pcpu_stats;
>> struct bpf_prog __rcu *xdp_prog;
>> +
>> + struct lowpan_dev ldev;
>> };
>>
>> static int tun_napi_receive(struct napi_struct *napi, int budget)
>> @@ -1071,6 +1074,9 @@ static void tun_set_headroom(struct net_device *dev, int new_hr)
>> new_hr = NET_SKB_PAD;
>>
>> tun->align = new_hr;
>> +
>> + if ((tun->flags & (IFF_TAP|IFF_6LO)) == (IFF_TAP|IFF_6LO))
>> + tun->align += LOWPAN_IPHC_MAX_HC_BUF_LEN;
>> }
>>
>> static void
>> @@ -1697,6 +1703,27 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
>> skb->dev = tun->dev;
>> break;
>> case IFF_TAP:
>> + if (tun->flags & IFF_6LO) {
>> + struct ethhdr eth;
>> +
>> + skb_reset_mac_header(skb);
>> + memcpy(&eth, skb_mac_header(skb), sizeof(eth));
>> +
>> + skb_pull(skb, sizeof(struct ethhdr));
>> + skb_reset_network_header(skb);
>> +
>> + if (lowpan_header_decompress(skb, &tun->ldev,
>> + tun->dev->dev_addr,
>> + &eth.h_source) < 0) {
>
> This will make a module dependency of 6lowpan_iphc for the tap driver.
> I am pretty sure that the tap driver people doesn't like that.

This is a valid concern that we should address.

> Which
> brings me to another issue with this patch:
> Why you don't create a virtual lowpan interface on top of the tap
> device. This handling is _incredibly_ against our design to have a
> 6LoWPAN interface device type for the user space.
> Now we have will have a tap device which makes internally 6LoWPAN
> handling but is not visible as 6LoWPAN interface in the user space,
> this will confuse 6LoWPAN user space applications.
>
> What our design is (just to remember):
> - Ethernet interface (MAC/6LoWPAN view, before adaption)
> - 6LoWPAN interface (IPv6 view, after adaption)

Except that for Bluetooth we have a _tunnel_, not a netdev, so I don't
think we necessarily need this stacking of interfaces just to do
header compression. Also when it comes to IoT devices we don't want to
spend memory on things we don't necessarily need.

> I am pretty sure you can run your above changes transparently
> separated of TAP driver by adding a 6LoWPAN interface on top. This
> will also make no dependency to the TAP driver.

There might be other ways as well, like detecting if 6lowpan has been
enabled, etc, which is less expensive than the interface stacking.

> I guess what you want is a TAP interface which is NOT ethernet. It
> need to get some special MAC information for your subsystem which is
> BTLE. Not using ethernet here. To have the assumption here "it will
> work because the address length is the same" is simple wrong, they
> will be more use-cases where upper-layers need to have special MAC
> information belongs to your link-layer subsystem.
> So, my guess, the bluetooth subsystem need some TAP like
> interface(hci) maybe? 6LoWPAN has nothing to do with ethernet yet. You
> need to put more logic in your link-layer subsystem to adapt ideas
> from other link-layer subsystems which has no 6LoWPAN support at all.

TUN/TAP are meant for _tunnels_ which is exactly what IPSP is, it is a
Bluetooth L2CAP channel and I don't see anyone suggesting doing a
netdev based on TCP socket which is analogous to L2CAP in Bluetooth
world, or do we?

--
Luiz Augusto von Dentz

2017-10-26 14:54:01

by Alexander Aring

[permalink] [raw]
Subject: Re: [RFC 3/3] tun: Add 6LoWPAN compression/decompression to tun driver

Hi,

First: I always asked myself: 6LoTUN makes no sense because 6LoWPAN
depends on MAC information and TUN interfaces works because IPv6
doesn't depend on MAC information. Now everything is more clear, this
has nothing todo with TUN it's TAP because you use ethernet MAC
information to do 6LoWPAN stuff.

On Wed, Oct 18, 2017 at 8:27 AM, Patrik Flykt
<[email protected]> wrote:
> Define a new IFF_6LO flag for the tun/tap driver that enables 6LoWPAN
> compression/decompression for tap devices. This is achieved by calling
> lowpan_header_compress once the sk_buff is destined for user space and
> calling lowpan_header_decompress when the user space writes packets to
> kernel. A copy of the ethernet MAC headers are needed both ways, as
> the 6LoWPAN compression may end up expanding the header size by one
> byte in the worst case.
>
> LOWPAN_IPHC_MAX_HC_BUF_LEN more bytes are added to sk_buff headroom
> to ensure there will be enough bytes to push headers to. This is
> probably an overkill and probably done wrongly anyway.
>
This define should be removed because there exists no case where the
compression will be larger than the ipv6 header and vice versa.


> An ethernet MAC header is added in front of the (compressed) IPv6
> datagram in both directions; no such transport exists for 6LoWPAN,
> but this is just an example implementation trying to explain the
> idea behind the BTLE handling in user space and the 6LoWPAN
> compression and decompression in kernel space. Thus the tun/tap
> driver comes in handy as the victim of the demonstration.
>

Sorry but this really scares me. The kernel use 6LoWPAN IPHC for
ethernet (as mac header information) and you doing BTLE/L2CAP stuff in
user space which is not anymore for your original use-case which is
"ethernet".
This might work for now, because only address handling is used in IPHC
as MAC header information and eth/btle use the same address length
(besides that the address is not always the same and BTLE is not a
EUI-48 address with multicast bit etc.)
You cannot simple use MAC X handling in kernelspace and use then MAC
handling Y in userspace - this will not work for long time. I already
fight with UDP based protocols in 802.15.4 6LoWPAN who depends on
802.15.4 MAC information which are not just addressing information. If
they need more bluetooth related information there you have no
possibility to get them. The same for next header compression which
might want more MAC information than just addressing for bluetooth.

> Signed-off-by: Patrik Flykt <[email protected]>
> ---
>
> Hi,
>
> This is the one applying on fac72b24.
>
>
> Patrik
>
>
> drivers/net/tun.c | 61 +++++++++++++++++++++++++++++++++++++++++++--
> include/uapi/linux/if_tun.h | 1 +
> 2 files changed, 60 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index 57e4c31fa84a..11b6494bb7ca 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -66,6 +66,7 @@
> #include <linux/nsproxy.h>
> #include <linux/virtio_net.h>
> #include <linux/rcupdate.h>
> +#include <net/6lowpan.h>
> #include <net/net_namespace.h>
> #include <net/netns/generic.h>
> #include <net/rtnetlink.h>
> @@ -231,6 +232,8 @@ struct tun_struct {
> u32 rx_batched;
> struct tun_pcpu_stats __percpu *pcpu_stats;
> struct bpf_prog __rcu *xdp_prog;
> +
> + struct lowpan_dev ldev;
> };
>
> static int tun_napi_receive(struct napi_struct *napi, int budget)
> @@ -1071,6 +1074,9 @@ static void tun_set_headroom(struct net_device *dev, int new_hr)
> new_hr = NET_SKB_PAD;
>
> tun->align = new_hr;
> +
> + if ((tun->flags & (IFF_TAP|IFF_6LO)) == (IFF_TAP|IFF_6LO))
> + tun->align += LOWPAN_IPHC_MAX_HC_BUF_LEN;
> }
>
> static void
> @@ -1697,6 +1703,27 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> skb->dev = tun->dev;
> break;
> case IFF_TAP:
> + if (tun->flags & IFF_6LO) {
> + struct ethhdr eth;
> +
> + skb_reset_mac_header(skb);
> + memcpy(&eth, skb_mac_header(skb), sizeof(eth));
> +
> + skb_pull(skb, sizeof(struct ethhdr));
> + skb_reset_network_header(skb);
> +
> + if (lowpan_header_decompress(skb, &tun->ldev,
> + tun->dev->dev_addr,
> + &eth.h_source) < 0) {

This will make a module dependency of 6lowpan_iphc for the tap driver.
I am pretty sure that the tap driver people doesn't like that. Which
brings me to another issue with this patch:
Why you don't create a virtual lowpan interface on top of the tap
device. This handling is _incredibly_ against our design to have a
6LoWPAN interface device type for the user space.
Now we have will have a tap device which makes internally 6LoWPAN
handling but is not visible as 6LoWPAN interface in the user space,
this will confuse 6LoWPAN user space applications.

What our design is (just to remember):
- Ethernet interface (MAC/6LoWPAN view, before adaption)
- 6LoWPAN interface (IPv6 view, after adaption)

I am pretty sure you can run your above changes transparently
separated of TAP driver by adding a 6LoWPAN interface on top. This
will also make no dependency to the TAP driver.

I guess what you want is a TAP interface which is NOT ethernet. It
need to get some special MAC information for your subsystem which is
BTLE. Not using ethernet here. To have the assumption here "it will
work because the address length is the same" is simple wrong, they
will be more use-cases where upper-layers need to have special MAC
information belongs to your link-layer subsystem.
So, my guess, the bluetooth subsystem need some TAP like
interface(hci) maybe? 6LoWPAN has nothing to do with ethernet yet. You
need to put more logic in your link-layer subsystem to adapt ideas
from other link-layer subsystems which has no 6LoWPAN support at all.

- Alex

2017-10-18 12:27:05

by Patrik Flykt

[permalink] [raw]
Subject: Re: [RFC 3/3] tun: Add 6LoWPAN compression/decompression to tun driver

Define a new IFF_6LO flag for the tun/tap driver that enables 6LoWPAN
compression/decompression for tap devices. This is achieved by calling
lowpan_header_compress once the sk_buff is destined for user space and
calling lowpan_header_decompress when the user space writes packets to
kernel. A copy of the ethernet MAC headers are needed both ways, as
the 6LoWPAN compression may end up expanding the header size by one
byte in the worst case.

LOWPAN_IPHC_MAX_HC_BUF_LEN more bytes are added to sk_buff headroom
to ensure there will be enough bytes to push headers to. This is
probably an overkill and probably done wrongly anyway.

An ethernet MAC header is added in front of the (compressed) IPv6
datagram in both directions; no such transport exists for 6LoWPAN,
but this is just an example implementation trying to explain the
idea behind the BTLE handling in user space and the 6LoWPAN
compression and decompression in kernel space. Thus the tun/tap
driver comes in handy as the victim of the demonstration.

Signed-off-by: Patrik Flykt <[email protected]>
---

Hi,

This is the one applying on fac72b24.


Patrik


drivers/net/tun.c | 61 +++++++++++++++++++++++++++++++++++++++++++--
include/uapi/linux/if_tun.h | 1 +
2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 57e4c31fa84a..11b6494bb7ca 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -66,6 +66,7 @@
#include <linux/nsproxy.h>
#include <linux/virtio_net.h>
#include <linux/rcupdate.h>
+#include <net/6lowpan.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
@@ -231,6 +232,8 @@ struct tun_struct {
u32 rx_batched;
struct tun_pcpu_stats __percpu *pcpu_stats;
struct bpf_prog __rcu *xdp_prog;
+
+ struct lowpan_dev ldev;
};

static int tun_napi_receive(struct napi_struct *napi, int budget)
@@ -1071,6 +1074,9 @@ static void tun_set_headroom(struct net_device *dev, int new_hr)
new_hr = NET_SKB_PAD;

tun->align = new_hr;
+
+ if ((tun->flags & (IFF_TAP|IFF_6LO)) == (IFF_TAP|IFF_6LO))
+ tun->align += LOWPAN_IPHC_MAX_HC_BUF_LEN;
}

static void
@@ -1697,6 +1703,27 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb->dev = tun->dev;
break;
case IFF_TAP:
+ if (tun->flags & IFF_6LO) {
+ struct ethhdr eth;
+
+ skb_reset_mac_header(skb);
+ memcpy(&eth, skb_mac_header(skb), sizeof(eth));
+
+ skb_pull(skb, sizeof(struct ethhdr));
+ skb_reset_network_header(skb);
+
+ if (lowpan_header_decompress(skb, &tun->ldev,
+ tun->dev->dev_addr,
+ &eth.h_source) < 0) {
+ this_cpu_inc(tun->pcpu_stats->rx_dropped);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ memcpy(skb_push(skb, sizeof(eth)), &eth, sizeof(eth));
+ skb_reset_mac_header(skb);
+ }
+
if (!frags)
skb->protocol = eth_type_trans(skb, tun->dev);
break;
@@ -1809,6 +1836,25 @@ static ssize_t tun_put_user(struct tun_struct *tun,
int vlan_hlen = 0;
int vnet_hdr_sz = 0;

+ if ((tun->flags & (IFF_6LO | IFF_TAP)) == (IFF_6LO | IFF_TAP) &&
+ skb->protocol == htons(ETH_P_IPV6)) {
+ struct ethhdr eth;
+ int err;
+
+ memcpy(&eth, skb_mac_header(skb), sizeof(eth));
+
+ skb_pull(skb, sizeof(struct ethhdr));
+ skb_reset_network_header(skb);
+
+ err = lowpan_header_compress(skb, &tun->ldev, &eth.h_dest,
+ tun->dev->dev_addr);
+ if (err < 0)
+ return -EINVAL;
+
+ memcpy(skb_push(skb, sizeof(eth)), &eth, sizeof(eth));
+ skb_reset_mac_header(skb);
+ }
+
if (skb_vlan_tag_present(skb))
vlan_hlen = VLAN_HLEN;

@@ -2117,7 +2163,8 @@ static struct proto tun_proto = {

static int tun_flags(struct tun_struct *tun)
{
- return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP);
+ return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP |
+ IFF_6LO);
}

static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr,
@@ -2196,6 +2243,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
!!(tun->flags & IFF_MULTI_QUEUE))
return -EINVAL;

+ if (ifr->ifr_flags & IFF_6LO && !(ifr->ifr_flags & IFF_TAP))
+ return -EINVAL;
+
if (tun_not_capable(tun))
return -EPERM;
err = security_tun_dev_open(tun->security);
@@ -2236,9 +2286,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
/* TAP device */
flags |= IFF_TAP;
name = "tap%d";
+ if (ifr->ifr_flags & IFF_6LO)
+ flags |= IFF_6LO;
} else
return -EINVAL;

+ if (ifr->ifr_flags & IFF_6LO && !(ifr->ifr_flags & IFF_TAP))
+ return -EINVAL;
+
if (*ifr->ifr_name)
name = ifr->ifr_name;

@@ -2277,6 +2332,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
if (err < 0)
goto err_free_stat;

+ lowpan_initialize_ctx(&tun->ldev, LOWPAN_LLTYPE_BTLE);
+
tun_net_init(dev);
tun_flow_init(tun);

@@ -2480,7 +2537,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
* This is needed because we never checked for invalid flags on
* TUNSETIFF.
*/
- return put_user(IFF_TUN | IFF_TAP | TUN_FEATURES,
+ return put_user(IFF_TUN | IFF_TAP | IFF_6LO | TUN_FEATURES,
(unsigned int __user*)argp);
} else if (cmd == TUNSETQUEUE)
return tun_set_queue(file, &ifr);
diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h
index 365ade5685c9..52815e4f1366 100644
--- a/include/uapi/linux/if_tun.h
+++ b/include/uapi/linux/if_tun.h
@@ -62,6 +62,7 @@
#define IFF_TAP 0x0002
#define IFF_NAPI 0x0010
#define IFF_NAPI_FRAGS 0x0020
+#define IFF_6LO 0X0040
#define IFF_NO_PI 0x1000
/* This flag has no real effect */
#define IFF_ONE_QUEUE 0x2000
--
2.11.0


2017-10-18 12:17:24

by Patrik Flykt

[permalink] [raw]
Subject: Re: [RFC 0/3] 6LoWPAN tun/tap device

On Wed, 2017-10-18 at 15:06 +0300, Patrik Flykt wrote:
> Patches apply to bluetooth-next fac72b24 as of today.

Hrm, patches 1/3 and 2/3 apply on fac72b24, patch 3/3 was apparently
left behind and applies only on 493668b4.


Patrik

2017-10-18 12:06:13

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 1/3] 6lowpan: Use struct lowpan_dev instead of net_device

Use struct lowpan_dev instead of struct net_device when accessing
6lo header compression funcitons. With this change the caller needs
to cast its private data pointer with the help of the lowpan_dev()
function and not the 6lo header compression code.

All users of 6lo header compression are also updated.

Signed-off-by: Patrik Flykt <[email protected]>
---
include/net/6lowpan.h | 8 +--
net/6lowpan/iphc.c | 121 +++++++++++++++++++-------------------------
net/6lowpan/nhc.c | 8 +--
net/6lowpan/nhc.h | 2 +-
net/bluetooth/6lowpan.c | 6 ++-
net/ieee802154/6lowpan/rx.c | 3 +-
net/ieee802154/6lowpan/tx.c | 2 +-
7 files changed, 69 insertions(+), 81 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index a71378007e61..7f21e156c9d6 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -299,13 +299,13 @@ void lowpan_unregister_netdev(struct net_device *dev);
* reallocate headroom.
*
* @skb: the buffer which should be manipulate.
- * @dev: the lowpan net device pointer.
+ * @ldev: the lowpan device pointer.
* @daddr: destination lladdr of mac header which is used for compression
* methods.
* @saddr: source lladdr of mac header which is used for compression
* methods.
*/
-int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
+int lowpan_header_decompress(struct sk_buff *skb, struct lowpan_dev *ldev,
const void *daddr, const void *saddr);

/**
@@ -318,13 +318,13 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
* which is the IPHC "more bytes than IPv6 header" at worst case.
*
* @skb: the buffer which should be manipulate.
- * @dev: the lowpan net device pointer.
+ * @ldev: the lowpan device pointer.
* @daddr: destination lladdr of mac header which is used for compression
* methods.
* @saddr: source lladdr of mac header which is used for compression
* methods.
*/
-int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
+int lowpan_header_compress(struct sk_buff *skb, struct lowpan_dev *ldev,
const void *daddr, const void *saddr);

#endif /* __6LOWPAN_H__ */
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 6b1042e21656..0485f1744016 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -48,7 +48,6 @@

#include <linux/bitops.h>
#include <linux/if_arp.h>
-#include <linux/netdevice.h>

#include <net/6lowpan.h>
#include <net/ipv6.h>
@@ -187,9 +186,9 @@ lowpan_iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
}

static struct lowpan_iphc_ctx *
-lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id)
+lowpan_iphc_ctx_get_by_id(struct lowpan_dev *ldev, u8 id)
{
- struct lowpan_iphc_ctx *ret = &lowpan_dev(dev)->ctx.table[id];
+ struct lowpan_iphc_ctx *ret = &ldev->ctx.table[id];

if (!lowpan_iphc_ctx_is_active(ret))
return NULL;
@@ -198,10 +197,10 @@ lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id)
}

static struct lowpan_iphc_ctx *
-lowpan_iphc_ctx_get_by_addr(const struct net_device *dev,
+lowpan_iphc_ctx_get_by_addr(struct lowpan_dev *ldev,
const struct in6_addr *addr)
{
- struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table;
+ struct lowpan_iphc_ctx *table = ldev->ctx.table;
struct lowpan_iphc_ctx *ret = NULL;
struct in6_addr addr_pfx;
u8 addr_plen;
@@ -242,10 +241,10 @@ lowpan_iphc_ctx_get_by_addr(const struct net_device *dev,
}

static struct lowpan_iphc_ctx *
-lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
+lowpan_iphc_ctx_get_by_mcast_addr(struct lowpan_dev *ldev,
const struct in6_addr *addr)
{
- struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table;
+ struct lowpan_iphc_ctx *table = ldev->ctx.table;
struct lowpan_iphc_ctx *ret = NULL;
struct in6_addr addr_mcast, network_pfx = {};
int i;
@@ -278,15 +277,15 @@ lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
return ret;
}

-static void lowpan_iphc_uncompress_lladdr(const struct net_device *dev,
+static void lowpan_iphc_uncompress_lladdr(const struct lowpan_dev *ldev,
struct in6_addr *ipaddr,
const void *lladdr)
{
- switch (dev->addr_len) {
- case ETH_ALEN:
+ switch (ldev->lltype) {
+ case LOWPAN_LLTYPE_BTLE:
lowpan_iphc_uncompress_eui48_lladdr(ipaddr, lladdr);
break;
- case EUI64_ADDR_LEN:
+ case LOWPAN_LLTYPE_IEEE802154:
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
break;
default:
@@ -301,7 +300,7 @@ static void lowpan_iphc_uncompress_lladdr(const struct net_device *dev,
* address_mode is the masked value for sam or dam value
*/
static int lowpan_iphc_uncompress_addr(struct sk_buff *skb,
- const struct net_device *dev,
+ const struct lowpan_dev *ldev,
struct in6_addr *ipaddr,
u8 address_mode, const void *lladdr)
{
@@ -332,14 +331,7 @@ static int lowpan_iphc_uncompress_addr(struct sk_buff *skb,
case LOWPAN_IPHC_SAM_11:
case LOWPAN_IPHC_DAM_11:
fail = false;
- switch (lowpan_dev(dev)->lltype) {
- case LOWPAN_LLTYPE_IEEE802154:
- lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
- break;
- default:
- lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr);
- break;
- }
+ lowpan_iphc_uncompress_lladdr(ldev, ipaddr, lladdr);
break;
default:
pr_debug("Invalid address mode value: 0x%x\n", address_mode);
@@ -361,7 +353,7 @@ static int lowpan_iphc_uncompress_addr(struct sk_buff *skb,
* based address(non-multicast).
*/
static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb,
- const struct net_device *dev,
+ const struct lowpan_dev *ldev,
const struct lowpan_iphc_ctx *ctx,
struct in6_addr *ipaddr,
u8 address_mode, const void *lladdr)
@@ -393,14 +385,7 @@ static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb,
case LOWPAN_IPHC_SAM_11:
case LOWPAN_IPHC_DAM_11:
fail = false;
- switch (lowpan_dev(dev)->lltype) {
- case LOWPAN_LLTYPE_IEEE802154:
- lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
- break;
- default:
- lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr);
- break;
- }
+ lowpan_iphc_uncompress_lladdr(ldev, ipaddr, lladdr);
ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
break;
default:
@@ -609,7 +594,7 @@ static const u8 lowpan_ttl_values[] = {
[LOWPAN_IPHC_HLIM_11] = 255,
};

-int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
+int lowpan_header_decompress(struct sk_buff *skb, struct lowpan_dev *ldev,
const void *daddr, const void *saddr)
{
struct ipv6hdr hdr = {};
@@ -657,22 +642,22 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
}

if (iphc1 & LOWPAN_IPHC_SAC) {
- spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
- ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_SCI(cid));
+ spin_lock_bh(&ldev->ctx.lock);
+ ci = lowpan_iphc_ctx_get_by_id(ldev, LOWPAN_IPHC_CID_SCI(cid));
if (!ci) {
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);
return -EINVAL;
}

pr_debug("SAC bit is set. Handle context based source address.\n");
- err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.saddr,
+ err = lowpan_iphc_uncompress_ctx_addr(skb, ldev, ci, &hdr.saddr,
iphc1 & LOWPAN_IPHC_SAM_MASK,
saddr);
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);
} else {
/* Source address uncompression */
pr_debug("source address stateless compression\n");
- err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.saddr,
+ err = lowpan_iphc_uncompress_addr(skb, ldev, &hdr.saddr,
iphc1 & LOWPAN_IPHC_SAM_MASK,
saddr);
}
@@ -685,10 +670,10 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC:
skb->pkt_type = PACKET_BROADCAST;

- spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
- ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
+ spin_lock_bh(&ldev->ctx.lock);
+ ci = lowpan_iphc_ctx_get_by_id(ldev, LOWPAN_IPHC_CID_DCI(cid));
if (!ci) {
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);
return -EINVAL;
}

@@ -697,7 +682,7 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
err = lowpan_uncompress_multicast_ctx_daddr(skb, ci,
&hdr.daddr,
iphc1 & LOWPAN_IPHC_DAM_MASK);
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);
break;
case LOWPAN_IPHC_M:
skb->pkt_type = PACKET_BROADCAST;
@@ -709,24 +694,24 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
case LOWPAN_IPHC_DAC:
skb->pkt_type = PACKET_HOST;

- spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
- ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
+ spin_lock_bh(&ldev->ctx.lock);
+ ci = lowpan_iphc_ctx_get_by_id(ldev, LOWPAN_IPHC_CID_DCI(cid));
if (!ci) {
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);
return -EINVAL;
}

/* Destination address context based uncompression */
pr_debug("DAC bit is set. Handle context based destination address.\n");
- err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.daddr,
+ err = lowpan_iphc_uncompress_ctx_addr(skb, ldev, ci, &hdr.daddr,
iphc1 & LOWPAN_IPHC_DAM_MASK,
daddr);
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);
break;
default:
skb->pkt_type = PACKET_HOST;

- err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.daddr,
+ err = lowpan_iphc_uncompress_addr(skb, ldev, &hdr.daddr,
iphc1 & LOWPAN_IPHC_DAM_MASK,
daddr);
pr_debug("dest: stateless compression mode %d dest %pI6c\n",
@@ -739,7 +724,7 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,

/* Next header data uncompression */
if (iphc0 & LOWPAN_IPHC_NH) {
- err = lowpan_nhc_do_uncompression(skb, dev, &hdr);
+ err = lowpan_nhc_do_uncompression(skb, ldev, &hdr);
if (err < 0)
return err;
} else {
@@ -748,7 +733,7 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
return err;
}

- switch (lowpan_dev(dev)->lltype) {
+ switch (ldev->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_802154_cb(skb)->d_size)
hdr.payload_len = htons(lowpan_802154_cb(skb)->d_size -
@@ -827,14 +812,14 @@ lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
return lladdr_compress;
}

-static bool lowpan_iphc_addr_equal(const struct net_device *dev,
+static bool lowpan_iphc_addr_equal(const struct lowpan_dev *ldev,
const struct lowpan_iphc_ctx *ctx,
const struct in6_addr *ipaddr,
const void *lladdr)
{
struct in6_addr tmp = {};

- lowpan_iphc_uncompress_lladdr(dev, &tmp, lladdr);
+ lowpan_iphc_uncompress_lladdr(ldev, &tmp, lladdr);

if (ctx)
ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
@@ -842,7 +827,7 @@ static bool lowpan_iphc_addr_equal(const struct net_device *dev,
return ipv6_addr_equal(&tmp, ipaddr);
}

-static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
+static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct lowpan_dev *ldev,
const struct in6_addr *ipaddr,
const struct lowpan_iphc_ctx *ctx,
const unsigned char *lladdr, bool sam)
@@ -850,7 +835,7 @@ static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
struct in6_addr tmp = {};
u8 dam;

- switch (lowpan_dev(dev)->lltype) {
+ switch (ldev->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx,
lladdr)) {
@@ -859,7 +844,7 @@ static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
}
break;
default:
- if (lowpan_iphc_addr_equal(dev, ctx, ipaddr, lladdr)) {
+ if (lowpan_iphc_addr_equal(ldev, ctx, ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11;
goto out;
}
@@ -940,13 +925,13 @@ lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
return lladdr_compress;
}

-static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
+static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct lowpan_dev *ldev,
const struct in6_addr *ipaddr,
const unsigned char *lladdr, bool sam)
{
u8 dam = LOWPAN_IPHC_DAM_01;

- switch (lowpan_dev(dev)->lltype) {
+ switch (ldev->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
@@ -955,7 +940,7 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
}
break;
default:
- if (lowpan_iphc_addr_equal(dev, NULL, ipaddr, lladdr)) {
+ if (lowpan_iphc_addr_equal(ldev, NULL, ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11;
pr_debug("address compression 0 bits\n");
goto out;
@@ -1127,7 +1112,7 @@ static u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr,
return val;
}

-int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
+int lowpan_header_compress(struct sk_buff *skb, struct lowpan_dev *ldev,
const void *daddr, const void *saddr)
{
u8 iphc0, iphc1, *hc_ptr, cid = 0;
@@ -1162,24 +1147,24 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
skb->data, skb->len);

ipv6_daddr_type = ipv6_addr_type(&hdr->daddr);
- spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_lock_bh(&ldev->ctx.lock);
if (ipv6_daddr_type & IPV6_ADDR_MULTICAST)
- dci = lowpan_iphc_ctx_get_by_mcast_addr(dev, &hdr->daddr);
+ dci = lowpan_iphc_ctx_get_by_mcast_addr(ldev, &hdr->daddr);
else
- dci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->daddr);
+ dci = lowpan_iphc_ctx_get_by_addr(ldev, &hdr->daddr);
if (dci) {
memcpy(&dci_entry, dci, sizeof(*dci));
cid |= dci->id;
}
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);

- spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
- sci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->saddr);
+ spin_lock_bh(&ldev->ctx.lock);
+ sci = lowpan_iphc_ctx_get_by_addr(ldev, &hdr->saddr);
if (sci) {
memcpy(&sci_entry, sci, sizeof(*sci));
cid |= (sci->id << 4);
}
- spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
+ spin_unlock_bh(&ldev->ctx.lock);

/* if cid is zero it will be compressed */
if (cid) {
@@ -1230,7 +1215,7 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
iphc1 |= LOWPAN_IPHC_SAC;
} else {
if (sci) {
- iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
+ iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, ldev,
&hdr->saddr,
&sci_entry, saddr,
true);
@@ -1238,7 +1223,7 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
} else {
if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL &&
lowpan_is_linklocal_zero_padded(hdr->saddr)) {
- iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
+ iphc1 |= lowpan_compress_addr_64(&hc_ptr, ldev,
&hdr->saddr,
saddr, true);
pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
@@ -1266,7 +1251,7 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
}
} else {
if (dci) {
- iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
+ iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, ldev,
&hdr->daddr,
&dci_entry, daddr,
false);
@@ -1274,7 +1259,7 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
} else {
if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL &&
lowpan_is_linklocal_zero_padded(hdr->daddr)) {
- iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
+ iphc1 |= lowpan_compress_addr_64(&hc_ptr, ldev,
&hdr->daddr,
daddr, false);
pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n",
diff --git a/net/6lowpan/nhc.c b/net/6lowpan/nhc.c
index 4fa2fdda174d..7d695bbd4bb5 100644
--- a/net/6lowpan/nhc.c
+++ b/net/6lowpan/nhc.c
@@ -155,7 +155,7 @@ int lowpan_nhc_do_compression(struct sk_buff *skb, const struct ipv6hdr *hdr,
}

int lowpan_nhc_do_uncompression(struct sk_buff *skb,
- const struct net_device *dev,
+ const struct lowpan_dev *ldev,
struct ipv6hdr *hdr)
{
struct lowpan_nhc *nhc;
@@ -174,13 +174,13 @@ int lowpan_nhc_do_uncompression(struct sk_buff *skb,
}
} else {
spin_unlock_bh(&lowpan_nhc_lock);
- netdev_warn(dev, "received nhc id for %s which is not implemented.\n",
- nhc->name);
+ /* netdev_warn(dev, "received nhc id for %s which is not implemented.\n", */
+ /* nhc->name); */
return -ENOTSUPP;
}
} else {
spin_unlock_bh(&lowpan_nhc_lock);
- netdev_warn(dev, "received unknown nhc id which was not found.\n");
+ /* netdev_warn(dev, "received unknown nhc id which was not found.\n"); */
return -ENOENT;
}

diff --git a/net/6lowpan/nhc.h b/net/6lowpan/nhc.h
index 803041400136..d2e594ea89f1 100644
--- a/net/6lowpan/nhc.h
+++ b/net/6lowpan/nhc.h
@@ -117,7 +117,7 @@ int lowpan_nhc_do_compression(struct sk_buff *skb, const struct ipv6hdr *hdr,
* @hdr: ipv6hdr for setting nexthdr value.
*/
int lowpan_nhc_do_uncompression(struct sk_buff *skb,
- const struct net_device *dev,
+ const struct lowpan_dev *ldev,
struct ipv6hdr *hdr);

/**
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 4e2576fc0c59..6b45c890aa47 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -276,7 +276,8 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,

saddr = peer->lladdr;

- return lowpan_header_decompress(skb, netdev, netdev->dev_addr, saddr);
+ return lowpan_header_decompress(skb, lowpan_dev(netdev),
+ netdev->dev_addr, saddr);
}

static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
@@ -431,7 +432,8 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
status = 1;
}

- lowpan_header_compress(skb, netdev, daddr, dev->netdev->dev_addr);
+ lowpan_header_compress(skb, lowpan_dev(netdev), daddr,
+ dev->netdev->dev_addr);

err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
if (err < 0)
diff --git a/net/ieee802154/6lowpan/rx.c b/net/ieee802154/6lowpan/rx.c
index 649e7d45e88f..c29249be3114 100644
--- a/net/ieee802154/6lowpan/rx.c
+++ b/net/ieee802154/6lowpan/rx.c
@@ -95,7 +95,8 @@ int lowpan_iphc_decompress(struct sk_buff *skb)
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
return -EINVAL;

- return lowpan_header_decompress(skb, skb->dev, &hdr.dest, &hdr.source);
+ return lowpan_header_decompress(skb, lowpan_dev(skb->dev), &hdr.dest,
+ &hdr.source);
}

static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index e6ff5128e61a..b748efba4fba 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -236,7 +236,7 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
memcpy(&info, lowpan_skb_priv(skb), sizeof(info));

*dgram_size = skb->len;
- lowpan_header_compress(skb, ldev, &info.daddr, &info.saddr);
+ lowpan_header_compress(skb, lowpan_dev(ldev), &info.daddr, &info.saddr);
/* dgram_offset = (saved bytes after compression) + lowpan header len */
*dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);

--
2.11.0


2017-10-18 12:06:15

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 3/3] tun: Add 6LoWPAN compression/decompression to tun driver

Define a new IFF_6LO flag for the tun/tap driver that enables 6LoWPAN
compression/decompression for tap devices. This is achieved by calling
lowpan_header_compress once the sk_buff is destined for user space and
calling lowpan_header_decompress when the user space writes packets to
kernel. A copy of the ethernet MAC headers are needed both ways, as
the 6LoWPAN compression may end up expanding the header size by one
byte in the worst case.

LOWPAN_IPHC_MAX_HC_BUF_LEN more bytes are added to sk_buff headroom
to ensure there will be enough bytes to push headers to. This is
probably an overkill and probably done wrongly anyway.

An ethernet MAC header is added in front of the (compressed) IPv6
datagram in both directions; no such transport exists for 6LoWPAN,
but this is just an example implementation trying to explain the
idea behind the BTLE handling in user space and the 6LoWPAN
compression and decompression in kernel space. Thus the tun/tap
driver comes in handy as the victim of the demonstration.

Signed-off-by: Patrik Flykt <[email protected]>
---
drivers/net/tun.c | 61 +++++++++++++++++++++++++++++++++++++++++++--
include/uapi/linux/if_tun.h | 1 +
2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 3c9985f29950..8770ad46d3ef 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -66,6 +66,7 @@
#include <linux/nsproxy.h>
#include <linux/virtio_net.h>
#include <linux/rcupdate.h>
+#include <net/6lowpan.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
@@ -227,6 +228,8 @@ struct tun_struct {
u32 rx_batched;
struct tun_pcpu_stats __percpu *pcpu_stats;
struct bpf_prog __rcu *xdp_prog;
+
+ struct lowpan_dev ldev;
};

#ifdef CONFIG_TUN_VNET_CROSS_LE
@@ -975,6 +978,9 @@ static void tun_set_headroom(struct net_device *dev, int new_hr)
new_hr = NET_SKB_PAD;

tun->align = new_hr;
+
+ if ((tun->flags & (IFF_TAP|IFF_6LO)) == (IFF_TAP|IFF_6LO))
+ tun->align += LOWPAN_IPHC_MAX_HC_BUF_LEN;
}

static void
@@ -1515,6 +1521,27 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb->dev = tun->dev;
break;
case IFF_TAP:
+ if (tun->flags & IFF_6LO) {
+ struct ethhdr eth;
+
+ skb_reset_mac_header(skb);
+ memcpy(&eth, skb_mac_header(skb), sizeof(eth));
+
+ skb_pull(skb, sizeof(struct ethhdr));
+ skb_reset_network_header(skb);
+
+ if (lowpan_header_decompress(skb, &tun->ldev,
+ tun->dev->dev_addr,
+ &eth.h_source) < 0) {
+ this_cpu_inc(tun->pcpu_stats->rx_dropped);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ memcpy(skb_push(skb, sizeof(eth)), &eth, sizeof(eth));
+ skb_reset_mac_header(skb);
+ }
+
skb->protocol = eth_type_trans(skb, tun->dev);
break;
}
@@ -1596,6 +1623,25 @@ static ssize_t tun_put_user(struct tun_struct *tun,
int vlan_hlen = 0;
int vnet_hdr_sz = 0;

+ if ((tun->flags & (IFF_6LO | IFF_TAP)) == (IFF_6LO | IFF_TAP) &&
+ skb->protocol == htons(ETH_P_IPV6)) {
+ struct ethhdr eth;
+ int err;
+
+ memcpy(&eth, skb_mac_header(skb), sizeof(eth));
+
+ skb_pull(skb, sizeof(struct ethhdr));
+ skb_reset_network_header(skb);
+
+ err = lowpan_header_compress(skb, &tun->ldev, &eth.h_dest,
+ tun->dev->dev_addr);
+ if (err < 0)
+ return -EINVAL;
+
+ memcpy(skb_push(skb, sizeof(eth)), &eth, sizeof(eth));
+ skb_reset_mac_header(skb);
+ }
+
if (skb_vlan_tag_present(skb))
vlan_hlen = VLAN_HLEN;

@@ -1904,7 +1950,8 @@ static struct proto tun_proto = {

static int tun_flags(struct tun_struct *tun)
{
- return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP);
+ return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP |
+ IFF_6LO);
}

static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr,
@@ -1974,6 +2021,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
!!(tun->flags & IFF_MULTI_QUEUE))
return -EINVAL;

+ if (ifr->ifr_flags & IFF_6LO && !(ifr->ifr_flags & IFF_TAP))
+ return -EINVAL;
+
if (tun_not_capable(tun))
return -EPERM;
err = security_tun_dev_open(tun->security);
@@ -2013,9 +2063,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
/* TAP device */
flags |= IFF_TAP;
name = "tap%d";
+ if (ifr->ifr_flags & IFF_6LO)
+ flags |= IFF_6LO;
} else
return -EINVAL;

+ if (ifr->ifr_flags & IFF_6LO && !(ifr->ifr_flags & IFF_TAP))
+ return -EINVAL;
+
if (*ifr->ifr_name)
name = ifr->ifr_name;

@@ -2054,6 +2109,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
if (err < 0)
goto err_free_stat;

+ lowpan_initialize_ctx(&tun->ldev, LOWPAN_LLTYPE_BTLE);
+
tun_net_init(dev);
tun_flow_init(tun);

@@ -2257,7 +2314,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
* This is needed because we never checked for invalid flags on
* TUNSETIFF.
*/
- return put_user(IFF_TUN | IFF_TAP | TUN_FEATURES,
+ return put_user(IFF_TUN | IFF_TAP | IFF_6LO | TUN_FEATURES,
(unsigned int __user*)argp);
} else if (cmd == TUNSETQUEUE)
return tun_set_queue(file, &ifr);
diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h
index 3cb5e1d85ddd..6e515c606754 100644
--- a/include/uapi/linux/if_tun.h
+++ b/include/uapi/linux/if_tun.h
@@ -60,6 +60,7 @@
/* TUNSETIFF ifr flags */
#define IFF_TUN 0x0001
#define IFF_TAP 0x0002
+#define IFF_6LO 0x0010
#define IFF_NO_PI 0x1000
/* This flag has no real effect */
#define IFF_ONE_QUEUE 0x2000
--
2.11.0


2017-10-18 12:06:14

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 2/3] 6lowpan: Factor out lowpan device context initialization

6lowpan context initialization will be used in other places,
factor it out without any changes in functionality.

Signed-off-by: Patrik Flykt <[email protected]>
---
include/net/6lowpan.h | 2 ++
net/6lowpan/core.c | 22 ++++++++++++++++------
2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 7f21e156c9d6..1df9ecf22a57 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -289,6 +289,8 @@ int lowpan_register_netdev(struct net_device *dev,
void lowpan_unregister_netdevice(struct net_device *dev);
void lowpan_unregister_netdev(struct net_device *dev);

+int lowpan_initialize_ctx(struct lowpan_dev *ldev, enum lowpan_lltypes lltype);
+
/**
* lowpan_header_decompress - replace 6LoWPAN header with IPv6 header
*
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 40d3d72beb53..29150a2c5e04 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -18,10 +18,24 @@

#include "6lowpan_i.h"

+int lowpan_initialize_ctx(struct lowpan_dev *ldev, enum lowpan_lltypes lltype)
+{
+ int i;
+
+ ldev->lltype = lltype;
+
+ spin_lock_init(&ldev->ctx.lock);
+ for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
+ ldev->ctx.table[i].id = i;
+
+ return 0;
+}
+EXPORT_SYMBOL(lowpan_initialize_ctx);
+
int lowpan_register_netdevice(struct net_device *dev,
enum lowpan_lltypes lltype)
{
- int i, ret;
+ int ret;

switch (lltype) {
case LOWPAN_LLTYPE_IEEE802154:
@@ -36,11 +50,7 @@ int lowpan_register_netdevice(struct net_device *dev,
dev->type = ARPHRD_6LOWPAN;
dev->mtu = IPV6_MIN_MTU;

- lowpan_dev(dev)->lltype = lltype;
-
- spin_lock_init(&lowpan_dev(dev)->ctx.lock);
- for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
- lowpan_dev(dev)->ctx.table[i].id = i;
+ lowpan_initialize_ctx(lowpan_dev(dev), lltype);

dev->ndisc_ops = &lowpan_ndisc_ops;

--
2.11.0