diff mbox

[RFC] net: arinc429: Add ARINC-429 stack

Message ID 1446419775-5215-1-git-send-email-marex@denx.de
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Marek Vasut Nov. 1, 2015, 11:16 p.m. UTC
The ARINC-429 is a technical standard, which describes, among others,
a data bus used by airplanes. The standard contains much more, since
it is based off the ISO/OSI model, but this patch implements just the
data bus protocol.

This stack is derived from the SocketCAN implementation, already present
in the kernel and thus behaves in a very similar fashion. Thus far, we
support sending RAW ARINC-429 datagrams, configuration of the RX and TX
clock speed and filtering.

The ARINC-429 datagram is four-byte long. The first byte is always the
LABEL, the function of remaining three bytes can vary, so we handle it
as an opaque PAYLOAD. The userspace tools can send these datagrams via
a standard socket.

A LABEL-based filtering can be configured on each socket separately in
a way comparable to CAN -- user uses setsockopt() to push a list of
label,mask tuples into the kernel and the kernel will deliver a datagram
to the socket if (<received_label> & mask) == (label & mask), otherwise
the datagram is not delivered.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: David S. Miller" <davem@davemloft.net>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Wolfgang Grandegger <wg@grandegger.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>
To: netdev@vger.kernel.org
---
 MAINTAINERS                           |  19 +
 drivers/net/Makefile                  |   1 +
 drivers/net/arinc429/Kconfig          |  32 ++
 drivers/net/arinc429/Makefile         |  11 +
 drivers/net/arinc429/dev.c            | 448 +++++++++++++++++++
 drivers/net/arinc429/varinc429.c      | 163 +++++++
 include/linux/arinc429/core.h         |  61 +++
 include/linux/arinc429/dev.h          |  81 ++++
 include/linux/arinc429/skb.h          |  79 ++++
 include/linux/socket.h                |   4 +-
 include/uapi/linux/arinc429.h         |  88 ++++
 include/uapi/linux/arinc429/Kbuild    |   6 +
 include/uapi/linux/arinc429/netlink.h |  55 +++
 include/uapi/linux/arinc429/raw.h     |  36 ++
 include/uapi/linux/if_arp.h           |   1 +
 include/uapi/linux/if_ether.h         |   1 +
 net/Kconfig                           |   1 +
 net/Makefile                          |   1 +
 net/arinc429/Kconfig                  |  31 ++
 net/arinc429/Makefile                 |   9 +
 net/arinc429/af_arinc429.c            | 812 ++++++++++++++++++++++++++++++++++
 net/arinc429/af_arinc429.h            | 100 +++++
 net/arinc429/proc.c                   | 432 ++++++++++++++++++
 net/arinc429/raw.c                    | 758 +++++++++++++++++++++++++++++++
 24 files changed, 3229 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/arinc429/Kconfig
 create mode 100644 drivers/net/arinc429/Makefile
 create mode 100644 drivers/net/arinc429/dev.c
 create mode 100644 drivers/net/arinc429/varinc429.c
 create mode 100644 include/linux/arinc429/core.h
 create mode 100644 include/linux/arinc429/dev.h
 create mode 100644 include/linux/arinc429/skb.h
 create mode 100644 include/uapi/linux/arinc429.h
 create mode 100644 include/uapi/linux/arinc429/Kbuild
 create mode 100644 include/uapi/linux/arinc429/netlink.h
 create mode 100644 include/uapi/linux/arinc429/raw.h
 create mode 100644 net/arinc429/Kconfig
 create mode 100644 net/arinc429/Makefile
 create mode 100644 net/arinc429/af_arinc429.c
 create mode 100644 net/arinc429/af_arinc429.h
 create mode 100644 net/arinc429/proc.c
 create mode 100644 net/arinc429/raw.c

Comments

Marc Kleine-Budde Nov. 2, 2015, 9:47 a.m. UTC | #1
On 11/02/2015 12:16 AM, Marek Vasut wrote:
> The ARINC-429 is a technical standard, which describes, among others,
> a data bus used by airplanes. The standard contains much more, since
> it is based off the ISO/OSI model, but this patch implements just the
> data bus protocol.
> 
> This stack is derived from the SocketCAN implementation, already present
> in the kernel and thus behaves in a very similar fashion. Thus far, we
> support sending RAW ARINC-429 datagrams, configuration of the RX and TX
> clock speed and filtering.
> 
> The ARINC-429 datagram is four-byte long. The first byte is always the
> LABEL, the function of remaining three bytes can vary, so we handle it
> as an opaque PAYLOAD. The userspace tools can send these datagrams via
> a standard socket.
> 
> A LABEL-based filtering can be configured on each socket separately in
> a way comparable to CAN -- user uses setsockopt() to push a list of
> label,mask tuples into the kernel and the kernel will deliver a datagram
> to the socket if (<received_label> & mask) == (label & mask), otherwise
> the datagram is not delivered.

What's difference compared to CAN besides a different MTU? The CAN stack
is already capable to handle CAN and CAN-FD frames. Would it make sense
to integrate the ARINC-429 into the existing CAN stack?

Marc
Oliver Hartkopp Nov. 2, 2015, 11:14 a.m. UTC | #2
On 02.11.2015 10:47, Marc Kleine-Budde wrote:
> On 11/02/2015 12:16 AM, Marek Vasut wrote:
>> The ARINC-429 is a technical standard, which describes, among others,
>> a data bus used by airplanes. The standard contains much more, since
>> it is based off the ISO/OSI model, but this patch implements just the
>> data bus protocol.
>>
>> This stack is derived from the SocketCAN implementation, already present
>> in the kernel and thus behaves in a very similar fashion. Thus far, we
>> support sending RAW ARINC-429 datagrams, configuration of the RX and TX
>> clock speed and filtering.
>>
>> The ARINC-429 datagram is four-byte long. The first byte is always the
>> LABEL, the function of remaining three bytes can vary, so we handle it
>> as an opaque PAYLOAD. The userspace tools can send these datagrams via
>> a standard socket.
>>
>> A LABEL-based filtering can be configured on each socket separately in
>> a way comparable to CAN -- user uses setsockopt() to push a list of
>> label,mask tuples into the kernel and the kernel will deliver a datagram
>> to the socket if (<received_label> & mask) == (label & mask), otherwise
>> the datagram is not delivered.
>
> What's difference compared to CAN besides a different MTU? The CAN stack
> is already capable to handle CAN and CAN-FD frames. Would it make sense
> to integrate the ARINC-429 into the existing CAN stack?

That was my first impression too.

What about defining some overlay data structure to map ARINC-429 frames into 
CAN frames?

E.g. we could write the ARINC 32 bit data completely into data[0..3] and 
additionally copy the 8 bit label information (or should it better be 10 bit 
including the Source/Destination Identifiers?) additionally into the can_id.

 From what I can see the filtering by label is similar to filtering by can_id.
And you would be able to use the can-gw functionality too.

The only real difference is the bitrate configuration of the ARINC interface.

I wonder if a similar approach would fit here as we discussed with the 
University of Prague for a LIN implementation using the PF_CAN infrastructure:

http://rtime.felk.cvut.cz/can/lin-bus/

It could probably boil down to a 'CAN interface' that is named arinc0 which 
implements the serial driver like in slcan.c or sllin.c ...

Regards,
Oliver

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 2, 2015, 6:16 p.m. UTC | #3
On Monday, November 02, 2015 at 12:14:27 PM, Oliver Hartkopp wrote:
> On 02.11.2015 10:47, Marc Kleine-Budde wrote:
> > On 11/02/2015 12:16 AM, Marek Vasut wrote:
> >> The ARINC-429 is a technical standard, which describes, among others,
> >> a data bus used by airplanes. The standard contains much more, since
> >> it is based off the ISO/OSI model, but this patch implements just the
> >> data bus protocol.
> >> 
> >> This stack is derived from the SocketCAN implementation, already present
> >> in the kernel and thus behaves in a very similar fashion. Thus far, we
> >> support sending RAW ARINC-429 datagrams, configuration of the RX and TX
> >> clock speed and filtering.
> >> 
> >> The ARINC-429 datagram is four-byte long. The first byte is always the
> >> LABEL, the function of remaining three bytes can vary, so we handle it
> >> as an opaque PAYLOAD. The userspace tools can send these datagrams via
> >> a standard socket.
> >> 
> >> A LABEL-based filtering can be configured on each socket separately in
> >> a way comparable to CAN -- user uses setsockopt() to push a list of
> >> label,mask tuples into the kernel and the kernel will deliver a datagram
> >> to the socket if (<received_label> & mask) == (label & mask), otherwise
> >> the datagram is not delivered.
> > 
> > What's difference compared to CAN besides a different MTU? The CAN stack
> > is already capable to handle CAN and CAN-FD frames. Would it make sense
> > to integrate the ARINC-429 into the existing CAN stack?
> 
> That was my first impression too.

Hi!

> What about defining some overlay data structure to map ARINC-429 frames
> into CAN frames?

I agree about the code reuse, it was stupid to do such a blatant copy of the
code all right. I don't think it's such a great idea to outright place ARINC 
support into the CAN stack though. They're two different busses after all. 
Please see below.

> E.g. we could write the ARINC 32 bit data completely into data[0..3] and
> additionally copy the 8 bit label information (or should it better be 10
> bit including the Source/Destination Identifiers?) additionally into the
> can_id.
> 
>  From what I can see the filtering by label is similar to filtering by
> can_id. And you would be able to use the can-gw functionality too.

This is correct.

> The only real difference is the bitrate configuration of the ARINC
> interface.

There might be additional ARINC-specific configuration bits involved,
but thus far, that's correct.

> I wonder if a similar approach would fit here as we discussed with the
> University of Prague for a LIN implementation using the PF_CAN
> infrastructure:

OT: Hey, there is no "University of Prague", there are two universities in 
Prague to boot -- Charles University and Czech Technical University -- you
mean the later ;-)

> http://rtime.felk.cvut.cz/can/lin-bus/
> 
> It could probably boil down to a 'CAN interface' that is named arinc0 which
> implements the serial driver like in slcan.c or sllin.c ...

I was thinking about this and I mostly agree with you. Obviously, copying the
code this way was dumb. On the other hand, ARINC and CAN are two different sort 
of busses, so I'd propose something slightly different here to avoid confusion 
and prevent the future extensions (or protocols) from adding unrelated cruft 
into the CAN stack.

I would propose we (read: me) create some sort of "common" core, which would
contain the following:
 - drivers/net/: big part of the device interface here is common
                 big part of the virtual interface here is common
                 -> CAN or ARINC can just add their own specific callbacks and
                    be done with it
                   
 - net/: there's a lot of common parts as well, like the filtering can be
         unified such that it can be used by both. A big part of the socket
         handling is also similar.

This would also let the slcan or sllin or whatever stuff they made at CVUT just
plug into this "common" core part.

Now I wonder if we should introduce AF_ARINC or stick to AF_CAN for both. I'd
be much happier to keep those two separate, again, to avoid confusion.

What do you think please ?

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Aleksander Morgado Nov. 2, 2015, 7:41 p.m. UTC | #4
On Mon, Nov 2, 2015 at 12:14 PM, Oliver Hartkopp <socketcan@hartkopp.net> wrote:
>
> What about defining some overlay data structure to map ARINC-429 frames into
> CAN frames?
>
> E.g. we could write the ARINC 32 bit data completely into data[0..3] and
> additionally copy the 8 bit label information (or should it better be 10 bit
> including the Source/Destination Identifiers?) additionally into the can_id.

Note that the only bits which are always treated as non-data are the 8
label bits (well, and the parity bit #31). The 2 SDI bits (#8, #9) may
be used as data bits when a high resolution is needed, like Lat/Long
encoded in binary words 310 and 311. I wouldn't make any assumption on
what's on those 2 bits; i.e. they're not always "source/destination".
Oliver Hartkopp Nov. 2, 2015, 7:55 p.m. UTC | #5
On 11/02/2015 08:41 PM, Aleksander Morgado wrote:
> On Mon, Nov 2, 2015 at 12:14 PM, Oliver Hartkopp <socketcan@hartkopp.net> wrote:
>>
>> What about defining some overlay data structure to map ARINC-429 frames into
>> CAN frames?
>>
>> E.g. we could write the ARINC 32 bit data completely into data[0..3] and
>> additionally copy the 8 bit label information (or should it better be 10 bit
>> including the Source/Destination Identifiers?) additionally into the can_id.
> 
> Note that the only bits which are always treated as non-data are the 8
> label bits (well, and the parity bit #31). The 2 SDI bits (#8, #9) may
> be used as data bits when a high resolution is needed, like Lat/Long
> encoded in binary words 310 and 311. I wouldn't make any assumption on
> what's on those 2 bits; i.e. they're not always "source/destination".
> 

You definitely know these details better than me. That's why I'm asking.

Would hosting the 32 bit in the struct can_frame.data and just the 8 bit label
in struct can_frame.can_id offer the functionality you need?

Besides the arinc429_frame struct

struct arinc429_frame {
	__u8	label;		/* 8 bit label */
	__u8	data[3];	/* Up-to 23 bits are valid. */
};

everything else roughly looks like copy&paste from PF_CAN with renaming.

So when we can fit the arinc frames into CAN frames and re-use the existing
CAN infrastructure - we are almost done.

Regards,
Oliver

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vostrikov Andrey Nov. 2, 2015, 8:15 p.m. UTC | #6
Hi,

> I was thinking about this and I mostly agree with you. Obviously, copying the
> code this way was dumb. On the other hand, ARINC and CAN are two different sort
> of busses, so I'd propose something slightly different here to avoid confusion
> and prevent the future extensions (or protocols) from adding unrelated cruft
> into the CAN stack.

Another  major  difference  between  CAN and ARINC429 is that ARINC is
simplex.  It  does  not  need  loopback  and echo. For example HOLT IC
chip  HI-3593  has  two receivers and single transmitter, which
should  be  instantiated as separate devices, as each channel could be
connected to different network.

It  would  be nice if new ARINC framework will provide means to create
RX  or  TX  only  network device and have -rx- or -tx- as part of device
name.

Label  space in ARINC is much smaller than in CAN, is it really needed
to  have  hash  and  masks? May be simple bitmap for 256 bits will fit
better.  At least it could be directly provided to mentioned HOLT chip
to do filtering in hardware.
Marek Vasut Nov. 2, 2015, 8:25 p.m. UTC | #7
On Monday, November 02, 2015 at 09:15:21 PM, Vostrikov Andrey wrote:
> Hi,

Hi,

> > I was thinking about this and I mostly agree with you. Obviously, copying
> > the code this way was dumb. On the other hand, ARINC and CAN are two
> > different sort of busses, so I'd propose something slightly different
> > here to avoid confusion and prevent the future extensions (or protocols)
> > from adding unrelated cruft into the CAN stack.
> 
> Another  major  difference  between  CAN and ARINC429 is that ARINC is
> simplex.  It  does  not  need  loopback  and echo. For example HOLT IC
> chip  HI-3593  has  two receivers and single transmitter, which
> should  be  instantiated as separate devices, as each channel could be
> connected to different network.

So this would effectively be three devices, correct ?  I think you can just
register a regular ARINC device for each channel and be done with it. Loopback
and echo can be configurable.

> It  would  be nice if new ARINC framework will provide means to create
> RX  or  TX  only  network device and have -rx- or -tx- as part of device
> name.

I'd say you can fail the TX if you're trying to send via an RX-only channel.
The naming can probably be also tweaked, but I don't see much value in that,
especially since you can rename those interfaces by using udev rules. Checking
if the interface supports RX/TX should be done by other means, not the name.

> Label  space in ARINC is much smaller than in CAN, is it really needed
> to  have  hash  and  masks? May be simple bitmap for 256 bits will fit
> better.  At least it could be directly provided to mentioned HOLT chip
> to do filtering in hardware.

CAN does the can_id filtering this way and I find it familiar and convenient,
so I don't see a reason not to re-use it. If the hardware has some special
support for the frame filtering, it's the driver that should convert the
filter specification into form which the hardware understands -- this sort
of configuration is done only once at the beginning of operation, so some
small overhead of the conversion of the filter setting should be acceptable,
we're talking about generating 256 entries for the hardware from ID/mask tuple,
no big deal here.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Aleksander Morgado Nov. 3, 2015, 10:36 a.m. UTC | #8
Hey!

On Mon, Nov 2, 2015 at 9:25 PM, Marek Vasut <marex@denx.de> wrote:
>> > I was thinking about this and I mostly agree with you. Obviously, copying
>> > the code this way was dumb. On the other hand, ARINC and CAN are two
>> > different sort of busses, so I'd propose something slightly different
>> > here to avoid confusion and prevent the future extensions (or protocols)
>> > from adding unrelated cruft into the CAN stack.
>>

I'd keep them separate not because ARINC may add unrelated cruft into
the CAN stack, but because ARINC is much simpler than CAN already...

>> Another  major  difference  between  CAN and ARINC429 is that ARINC is
>> simplex.  It  does  not  need  loopback  and echo. For example HOLT IC
>> chip  HI-3593  has  two receivers and single transmitter, which
>> should  be  instantiated as separate devices, as each channel could be
>> connected to different network.
>
> So this would effectively be three devices, correct ?  I think you can just
> register a regular ARINC device for each channel and be done with it. Loopback
> and echo can be configurable.
>

I tend to agree with Andrey here; I'm not sure I see any use case for
the echo feature (a TX channel is a TX channel, you don't expect
anything back), and just testing purposes for the loopback.

>> It  would  be nice if new ARINC framework will provide means to create
>> RX  or  TX  only  network device and have -rx- or -tx- as part of device
>> name.
>
> I'd say you can fail the TX if you're trying to send via an RX-only channel.
> The naming can probably be also tweaked, but I don't see much value in that,
> especially since you can rename those interfaces by using udev rules. Checking
> if the interface supports RX/TX should be done by other means, not the name.
>

I don't like the naming change specifying whether -rx or -tx, but it's
true that there are no real channels doing RX and TX at the same time.
You may have a device with multiple channels, and in that case you may
have RX channels and TX channels in the same device, but then the RX
and TX channels may be connected to different buses. Systems will
usually do either TX or RX; and for the case where both things could
make sense (I have a simulator setup that I use that way), the direct
way is to interconnect a TX port with a RX port physically.

>> Label  space in ARINC is much smaller than in CAN, is it really needed
>> to  have  hash  and  masks? May be simple bitmap for 256 bits will fit
>> better.  At least it could be directly provided to mentioned HOLT chip
>> to do filtering in hardware.
>
> CAN does the can_id filtering this way and I find it familiar and convenient,
> so I don't see a reason not to re-use it. If the hardware has some special
> support for the frame filtering, it's the driver that should convert the
> filter specification into form which the hardware understands -- this sort
> of configuration is done only once at the beginning of operation, so some
> small overhead of the conversion of the filter setting should be acceptable,
> we're talking about generating 256 entries for the hardware from ID/mask tuple,
> no big deal here.

I also tend to see this filtering setup a bit of over-engineered for
ARINC429. A fixed-sized 256 bitmask per socket to specify which labels
are wanted is more than enough. And that will then actually have a
direct relationship with the hardware label filtering setup. It's true
that the filter list is built at the beginning, but the filters then
need to get applied per ARINC word received.

Also, this setup is forcing users to look for the minimum set of
filters to match the labels they want to receive. In practice, users
will just want to receive a given set of labels and would likely end
up with one filter per label wanted with a 0xFF mask to match the full
label they want. I'd prefer if the users could just give a 256 bit
mask, one bit per ARINC label wanted, it would make much more sense.
All this complex filtering setup, including the inverse filter (no
clear usecase for that), looks a bit out of context in ARINC429. The
filtering interface and implementation could be much simpler and I
believe it would actually fit better what users expect from it.


Unrelated to all this, another key point in ARINC is the timing for
each label when transmitting. The common case you get is different
labels being sent continuously with a given rate for each. E.g. labels
310 and 311 every 80ms, label 312 every 120ms and so on. I'm not sure
the HOLT chips have any specific way of configuring this, but I've
seen some USB devices which actually have APIs to say e.g. "send label
310 every 80ms" and then you can just update the value being sent
without needing to take care of the TX rate. I'd have loved to see
that instead of the complex filtering :) I know this is way too much
for the generic kernel driver, though, so just a heads up of how this
usually works.
Marc Kleine-Budde Nov. 3, 2015, 11:36 a.m. UTC | #9
On 11/03/2015 11:36 AM, Aleksander Morgado wrote:
> On Mon, Nov 2, 2015 at 9:25 PM, Marek Vasut <marex@denx.de> wrote:
>>>> I was thinking about this and I mostly agree with you. Obviously, copying
>>>> the code this way was dumb. On the other hand, ARINC and CAN are two
>>>> different sort of busses, so I'd propose something slightly different
>>>> here to avoid confusion and prevent the future extensions (or protocols)
>>>> from adding unrelated cruft into the CAN stack.

> I'd keep them separate not because ARINC may add unrelated cruft into
> the CAN stack, but because ARINC is much simpler than CAN already...

What about maintainability? Why take care of two almost identical
subsystems? With making one stack "simpler" you increase, from my point
of view, the costs of maintaining even more. If you fix problems in one
stack you have to adopt the other, too.

Marc
Aleksander Morgado Nov. 3, 2015, 3:06 p.m. UTC | #10
On Tue, Nov 3, 2015 at 12:36 PM, Marc Kleine-Budde <mkl@pengutronix.de> wrote:
> On 11/03/2015 11:36 AM, Aleksander Morgado wrote:
>> On Mon, Nov 2, 2015 at 9:25 PM, Marek Vasut <marex@denx.de> wrote:
>>>>> I was thinking about this and I mostly agree with you. Obviously, copying
>>>>> the code this way was dumb. On the other hand, ARINC and CAN are two
>>>>> different sort of busses, so I'd propose something slightly different
>>>>> here to avoid confusion and prevent the future extensions (or protocols)
>>>>> from adding unrelated cruft into the CAN stack.
>
>> I'd keep them separate not because ARINC may add unrelated cruft into
>> the CAN stack, but because ARINC is much simpler than CAN already...
>
> What about maintainability? Why take care of two almost identical
> subsystems? With making one stack "simpler" you increase, from my point
> of view, the costs of maintaining even more. If you fix problems in one
> stack you have to adopt the other, too.

If they can share common code, that's fine, that probably can be
worked around if needed. My main issues are actually with all the
behavior that CAN supports and doesn't make much sense in ARINC, like
the complex ID filtering scheme for example (ARINC just requires 256
bits for a minimum filter), or the duplex TX/RX setup for channels
(channels are either RX or TX, not both), or the local
echoing/loopback (which wouldn't make much sense for TX-only
channels). The minimum subset of features required by an ARINC driver
is actually very small. Trying to "fit" ARINC as a subset of CAN may
actually be harder than keeping it separate maintainability wise.
Maybe the issue here is that the original patch is too CAN-like while
it shouldn't be, don't know.
Marc Kleine-Budde Nov. 3, 2015, 3:15 p.m. UTC | #11
On 11/03/2015 04:06 PM, Aleksander Morgado wrote:
>> What about maintainability? Why take care of two almost identical
>> subsystems? With making one stack "simpler" you increase, from my point
>> of view, the costs of maintaining even more. If you fix problems in one
>> stack you have to adopt the other, too.
> 
> If they can share common code, that's fine, that probably can be
> worked around if needed. My main issues are actually with all the
> behavior that CAN supports and doesn't make much sense in ARINC, like
> the complex ID filtering scheme for example (ARINC just requires 256
> bits for a minimum filter),

I think it should be possible to use a simple/different filter mechanism
for ARINC packages.

> or the duplex TX/RX setup for channels
> (channels are either RX or TX, not both), or the local
> echoing/loopback (which wouldn't make much sense for TX-only
> channels).

Local echo/loopback comes in two flavours:
- Other socket receive local generate frames, too.
  This is interesting if you want to merge two ARINC node on single
  device.
- Sending socket receives send frame, too. This is useful if you need
  the feedback that the frame has _really_ been send, not just pushed
  into the networking stack.

> The minimum subset of features required by an ARINC driver
> is actually very small. Trying to "fit" ARINC as a subset of CAN may
> actually be harder than keeping it separate maintainability wise.
> Maybe the issue here is that the original patch is too CAN-like while
> it shouldn't be, don't know.

regards,
Marc
Marek Vasut Nov. 3, 2015, 3:19 p.m. UTC | #12
On Tuesday, November 03, 2015 at 04:06:05 PM, Aleksander Morgado wrote:
> On Tue, Nov 3, 2015 at 12:36 PM, Marc Kleine-Budde <mkl@pengutronix.de> wrote:
> > On 11/03/2015 11:36 AM, Aleksander Morgado wrote:
> >> On Mon, Nov 2, 2015 at 9:25 PM, Marek Vasut <marex@denx.de> wrote:
> >>>>> I was thinking about this and I mostly agree with you. Obviously,
> >>>>> copying the code this way was dumb. On the other hand, ARINC and CAN
> >>>>> are two different sort of busses, so I'd propose something slightly
> >>>>> different here to avoid confusion and prevent the future extensions
> >>>>> (or protocols) from adding unrelated cruft into the CAN stack.
> >> 
> >> I'd keep them separate not because ARINC may add unrelated cruft into
> >> the CAN stack, but because ARINC is much simpler than CAN already...
> > 
> > What about maintainability? Why take care of two almost identical
> > subsystems? With making one stack "simpler" you increase, from my point
> > of view, the costs of maintaining even more. If you fix problems in one
> > stack you have to adopt the other, too.
> 
> If they can share common code, that's fine, that probably can be
> worked around if needed. My main issues are actually with all the
> behavior that CAN supports and doesn't make much sense in ARINC, like
> the complex ID filtering scheme for example (ARINC just requires 256
> bits for a minimum filter)

So does CAN, I don't see a problem re-using the filtering infrastructure here.

> , or the duplex TX/RX setup for channels
> (channels are either RX or TX, not both), or the local
> echoing/loopback (which wouldn't make much sense for TX-only
> channels).

Aren't the RX-only/TX-only channels rather a special case ? In that case, you
can register a device per each such channel and be done with it, no ?

> The minimum subset of features required by an ARINC driver
> is actually very small. Trying to "fit" ARINC as a subset of CAN may
> actually be harder than keeping it separate maintainability wise.
> Maybe the issue here is that the original patch is too CAN-like while
> it shouldn't be, don't know.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Aleksander Morgado Nov. 3, 2015, 4:10 p.m. UTC | #13
>> or the duplex TX/RX setup for channels
>> (channels are either RX or TX, not both), or the local
>> echoing/loopback (which wouldn't make much sense for TX-only
>> channels).
>
> Local echo/loopback comes in two flavours:
> - Other socket receive local generate frames, too.
>   This is interesting if you want to merge two ARINC node on single
>   device.

I'd actually love having this for a simulator setup I use where I
currently physically connect cables from a TX channel in one adapter
to a RX channel in another adapter. But I'm not sure there's a
specific real usecase for that apart from testing purposes.

> - Sending socket receives send frame, too. This is useful if you need
>   the feedback that the frame has _really_ been send, not just pushed
>   into the networking stack.

I'd say that a TX error count could be enough here. I'm not sure if
having the echo would justify making the TX channels also
read-capable.

Remember that the actual hardware will have read-only or write-only
channels itself. Each of the real hardware channels exposed in
userspace as interfaces will therefore be read-only or write-only, and
the user will need to know that before using them. An application
wanting to read from channels will need to open and read from the RX
channels only, an application wanting to write to the channels will
need to open and write the TX channels only. The kernel should somehow
specify the type for each of the channels, not to confuse the users.
The virtual interface with both R/W caps doesn't really match what you
would expect in a real interface.
Aleksander Morgado Nov. 3, 2015, 4:18 p.m. UTC | #14
On Tue, Nov 3, 2015 at 4:19 PM, Marek Vasut <marex@denx.de> wrote:
>> , or the duplex TX/RX setup for channels
>> (channels are either RX or TX, not both), or the local
>> echoing/loopback (which wouldn't make much sense for TX-only
>> channels).
>
> Aren't the RX-only/TX-only channels rather a special case ?

They're actually the only case AFAIK. You've got systems generating
streams of ARINC429 words (e.g. the IRS, the FMC...) and systems that
may consume the streams from multiple independent channels (e.g. the
IFE). I try to think of each logical bus as a single transmitter
broadcasting to multiple receivers.
Aleksander Morgado Nov. 3, 2015, 4:47 p.m. UTC | #15
On Tue, Nov 3, 2015 at 4:19 PM, Marek Vasut <marex@denx.de> wrote:
>> >>>>> I was thinking about this and I mostly agree with you. Obviously,
>> >>>>> copying the code this way was dumb. On the other hand, ARINC and CAN
>> >>>>> are two different sort of busses, so I'd propose something slightly
>> >>>>> different here to avoid confusion and prevent the future extensions
>> >>>>> (or protocols) from adding unrelated cruft into the CAN stack.
>> >>
>> >> I'd keep them separate not because ARINC may add unrelated cruft into
>> >> the CAN stack, but because ARINC is much simpler than CAN already...
>> >
>> > What about maintainability? Why take care of two almost identical
>> > subsystems? With making one stack "simpler" you increase, from my point
>> > of view, the costs of maintaining even more. If you fix problems in one
>> > stack you have to adopt the other, too.
>>
>> If they can share common code, that's fine, that probably can be
>> worked around if needed. My main issues are actually with all the
>> behavior that CAN supports and doesn't make much sense in ARINC, like
>> the complex ID filtering scheme for example (ARINC just requires 256
>> bits for a minimum filter)
>
> So does CAN, I don't see a problem re-using the filtering infrastructure here.

Aren't CAN IDs more than 8-bit long?

Also, ARINC429 labels are logically identifying the data type of the
value being sent, not a given "node" as CAN IDs are (If I'm not
mistaken, correct me if wrong). A single system (e.g. IRS) will send
multiple different labels (e.g. 310 for Latitude, 311 for
Longitude...) to different consumers (e.g. IFE will read all those).
The way a receiver identifies what system generated a given word (as
the same label may have different meaning if sent by different
systems) is usually by mapping in which RX port the word was received
(or also through the special 377 label which may be used as equipment
ID).
Aleksander Morgado Nov. 3, 2015, 4:56 p.m. UTC | #16
On Tue, Nov 3, 2015 at 5:18 PM, Aleksander Morgado
<aleksander@aleksander.es> wrote:
> On Tue, Nov 3, 2015 at 4:19 PM, Marek Vasut <marex@denx.de> wrote:
>>> , or the duplex TX/RX setup for channels
>>> (channels are either RX or TX, not both), or the local
>>> echoing/loopback (which wouldn't make much sense for TX-only
>>> channels).
>>
>> Aren't the RX-only/TX-only channels rather a special case ?
>
> They're actually the only case AFAIK. You've got systems generating
> streams of ARINC429 words (e.g. the IRS, the FMC...) and systems that
> may consume the streams from multiple independent channels (e.g. the
> IFE). I try to think of each logical bus as a single transmitter
> broadcasting to multiple receivers.

I've re-checked the spec and it does say that there may be systems
that act as source (TX) and sink (RX), e.g. DME, VOR or ILS. But in
those cases, they will actually have separate TX and RX physical
ports.
Oliver Hartkopp Nov. 3, 2015, 5:01 p.m. UTC | #17
On 11/03/2015 11:36 AM, Aleksander Morgado wrote:

> Unrelated to all this, another key point in ARINC is the timing for
> each label when transmitting. The common case you get is different
> labels being sent continuously with a given rate for each. E.g. labels
> 310 and 311 every 80ms, label 312 every 120ms and so on. I'm not sure
> the HOLT chips have any specific way of configuring this, but I've
> seen some USB devices which actually have APIs to say e.g. "send label
> 310 every 80ms" and then you can just update the value being sent
> without needing to take care of the TX rate. I'd have loved to see
> that instead of the complex filtering :) I know this is way too much
> for the generic kernel driver, though, so just a heads up of how this
> usually works.
> 

The CAN stack already has a solution for this.

The CAN_BCM socket is a programmable (content) filter for cyclic messages
which are common in automotive setups to detect timeouts in cyclic messages
(sender fails).

An the best thing: You can use the Linux internal high-res timers to send
messages - just by creating a TX_SETUP configuration for the BCM.

Read this:
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/networking/can.txt?h=linux-4.2.y#n634

Just one more reason to use PF_CAN :-)


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Oliver Hartkopp Nov. 3, 2015, 5:32 p.m. UTC | #18
On 11/03/2015 05:10 PM, Aleksander Morgado wrote:
>>> or the duplex TX/RX setup for channels
>>> (channels are either RX or TX, not both), or the local
>>> echoing/loopback (which wouldn't make much sense for TX-only
>>> channels).
>>
>> Local echo/loopback comes in two flavours:
>> - Other socket receive local generate frames, too.
>>   This is interesting if you want to merge two ARINC node on single
>>   device.
> 
> I'd actually love having this for a simulator setup I use where I
> currently physically connect cables from a TX channel in one adapter
> to a RX channel in another adapter. But I'm not sure there's a
> specific real usecase for that apart from testing purposes.

Once you have ever used this functionalities you will start to think beyond.

It's a matter of (stress-)testing your applications after build on virtual
CAN/ARINC interfaces. You will start to use the can-gw to route and/or modify
frames between interfaces. You have all the tools to display/log/visualize and
replay data. There's a wireshark plugin for PF_CAN you can easily adapt to
present ARINC data, etc.

So when thinking about using PF_CAN as ARINC429 base ...

This is the CAN frame structure:

https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/networking/can.txt?h=linux-4.2.y#n264

    struct can_frame {
            canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
            __u8    can_dlc; /* frame payload length in byte (0 .. 8) */
            __u8    __pad;   /* padding */
            __u8    __res0;  /* reserved / padding */
            __u8    __res1;  /* reserved / padding */
            __u8    data[8] __attribute__((aligned(8)));
    };


So what about defining an arinc429_frame like this:

    struct a429_frame {
            __u32   label;   /* ARINC 429 label */
            __u8    length;  /* always set to 3 */
            __u8    __pad;   /* padding */
            __u8    __res0;  /* reserved / padding */
            __u8    __res1;  /* reserved / padding */
            __u8    data[8] __attribute__((aligned(8)));
    };

Don't know if your suggestion

+ * ARINC packet:
+ *
+ * .-.---.------.---.-----.
+ * |P|SSM| Data |SDI|Label|
+ * '-'---'------'---'-----'
+ *  3 3 2 2....1 1 9 8...0
+ *  1 0 9 8    1 0
+ */
+
+/**
+ * struct arinc429_frame - basic ARINC429 frame structure
+ * @label:	ARINC429 label
+ * @data:	ARINC429 P, SSM, DATA and SDI
+ */
+struct arinc429_frame {
+	__u8	label;		/* 8 bit label */
+	__u8	data[3];	/* Up-to 23 bits are valid. */
+};

is really handy to use for arinc application programmers.

It looks like you need to shift the stuff in user space every time.

So you might better think of something like this:

    struct a429_frame {
            __u32   label;   /* ARINC 429 label */
            __u8    length;  /* always set to 8 */
            __u8    __pad;   /* padding */
            __u8    __res0;  /* reserved / padding */
            __u8    __res1;  /* reserved / padding */
            __u32   data __attribute__((aligned(8)));
            __u8    p;       /* p */
            __u8    ssm;     /* ssm */
            __u8    sdi;     /* sdi */
            __u8    __end;   /* padding */
    };

Good thing would be that you can directly see the content in logfiles and you
can easily modify the content on the fly by can-gw.

Of course the arinc netdevice driver would have to take care to do the correct
rx/tx whatever. But routing and processing arinc content through the CAN stack
does not seem to be a bad idea IMO.

Regards,
Oliver
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 5:33 p.m. UTC | #19
On Tuesday, November 03, 2015 at 05:56:53 PM, Aleksander Morgado wrote:
> On Tue, Nov 3, 2015 at 5:18 PM, Aleksander Morgado
> 
> <aleksander@aleksander.es> wrote:
> > On Tue, Nov 3, 2015 at 4:19 PM, Marek Vasut <marex@denx.de> wrote:
> >>> , or the duplex TX/RX setup for channels
> >>> (channels are either RX or TX, not both), or the local
> >>> echoing/loopback (which wouldn't make much sense for TX-only
> >>> channels).
> >> 
> >> Aren't the RX-only/TX-only channels rather a special case ?
> > 
> > They're actually the only case AFAIK. You've got systems generating
> > streams of ARINC429 words (e.g. the IRS, the FMC...) and systems that
> > may consume the streams from multiple independent channels (e.g. the
> > IFE). I try to think of each logical bus as a single transmitter
> > broadcasting to multiple receivers.
> 
> I've re-checked the spec and it does say that there may be systems
> that act as source (TX) and sink (RX), e.g. DME, VOR or ILS. But in
> those cases, they will actually have separate TX and RX physical
> ports.

So, considering that hi3593 which as 2x RX and 1x TX port, what about
registering one device per port and be done with it ?

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 5:37 p.m. UTC | #20
On Tuesday, November 03, 2015 at 05:47:54 PM, Aleksander Morgado wrote:
> On Tue, Nov 3, 2015 at 4:19 PM, Marek Vasut <marex@denx.de> wrote:
> >> >>>>> I was thinking about this and I mostly agree with you. Obviously,
> >> >>>>> copying the code this way was dumb. On the other hand, ARINC and
> >> >>>>> CAN are two different sort of busses, so I'd propose something
> >> >>>>> slightly different here to avoid confusion and prevent the future
> >> >>>>> extensions (or protocols) from adding unrelated cruft into the
> >> >>>>> CAN stack.
> >> >> 
> >> >> I'd keep them separate not because ARINC may add unrelated cruft into
> >> >> the CAN stack, but because ARINC is much simpler than CAN already...
> >> > 
> >> > What about maintainability? Why take care of two almost identical
> >> > subsystems? With making one stack "simpler" you increase, from my
> >> > point of view, the costs of maintaining even more. If you fix
> >> > problems in one stack you have to adopt the other, too.
> >> 
> >> If they can share common code, that's fine, that probably can be
> >> worked around if needed. My main issues are actually with all the
> >> behavior that CAN supports and doesn't make much sense in ARINC, like
> >> the complex ID filtering scheme for example (ARINC just requires 256
> >> bits for a minimum filter)
> > 
> > So does CAN, I don't see a problem re-using the filtering infrastructure
> > here.
> 
> Aren't CAN IDs more than 8-bit long?

11bit for CAN, but that's a minor detail.

> Also, ARINC429 labels are logically identifying the data type of the
> value being sent, not a given "node" as CAN IDs are (If I'm not
> mistaken, correct me if wrong). A single system (e.g. IRS) will send
> multiple different labels (e.g. 310 for Latitude, 311 for
> Longitude...) to different consumers (e.g. IFE will read all those).

In that case, filter those LABELs which you want to receive and decide
on their datatype in your application based on the LABEL. This works
just fine in my opinion.

On the other hand, you cansend those LABELs which you want to transmit
as well, again the logic for determining which LABEL to send is in your
application.

> The way a receiver identifies what system generated a given word (as
> the same label may have different meaning if sent by different
> systems) is usually by mapping in which RX port the word was received
> (or also through the special 377 label which may be used as equipment
> ID).

Well that's fine, isn't it ?

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 5:41 p.m. UTC | #21
On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:

[...]

> It looks like you need to shift the stuff in user space every time.
> 
> So you might better think of something like this:
> 
>     struct a429_frame {
>             __u32   label;   /* ARINC 429 label */
>             __u8    length;  /* always set to 8 */
>             __u8    __pad;   /* padding */
>             __u8    __res0;  /* reserved / padding */
>             __u8    __res1;  /* reserved / padding */
>             __u32   data __attribute__((aligned(8)));
>             __u8    p;       /* p */
>             __u8    ssm;     /* ssm */
>             __u8    sdi;     /* sdi */
>             __u8    __end;   /* padding */
>     };

You don't want to interpret those P(arity)/SSM/SDI bits, since they differ
depending on whatever the remote party sends. That's why I decided to just
make those into 3-bytes of data and let the userland application deal with
it as seen fit. Besides, the ARINC "FTP" really uses those 3 bytes as plain
data.

> Good thing would be that you can directly see the content in logfiles and
> you can easily modify the content on the fly by can-gw.
> 
> Of course the arinc netdevice driver would have to take care to do the
> correct rx/tx whatever. But routing and processing arinc content through
> the CAN stack does not seem to be a bad idea IMO.

Pretty much, yeah.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Oliver Hartkopp Nov. 3, 2015, 6:03 p.m. UTC | #22
On 11/03/2015 06:41 PM, Marek Vasut wrote:
> On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:
> 
> [...]
> 
>> It looks like you need to shift the stuff in user space every time.
>>
>> So you might better think of something like this:
>>
>>     struct a429_frame {
>>             __u32   label;   /* ARINC 429 label */
>>             __u8    length;  /* always set to 8 */
>>             __u8    __pad;   /* padding */
>>             __u8    __res0;  /* reserved / padding */
>>             __u8    __res1;  /* reserved / padding */
>>             __u32   data __attribute__((aligned(8)));
>>             __u8    p;       /* p */
>>             __u8    ssm;     /* ssm */
>>             __u8    sdi;     /* sdi */
>>             __u8    __end;   /* padding */
>>     };
> 
> You don't want to interpret those P(arity)/SSM/SDI bits, since they differ
> depending on whatever the remote party sends. That's why I decided to just
> make those into 3-bytes of data and let the userland application deal with
> it as seen fit. Besides, the ARINC "FTP" really uses those 3 bytes as plain
> data.

Ok. I did not know what P was for :-)

Btw. it can make sense to introduce an union struct where different options to
access the content are possible.

E.g. you might have a 32 bit word, some bit-wise specification and a four byte
tuple to access the three bytes for ARINC FTP ...

Regards,
Oliver

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 7:19 p.m. UTC | #23
On Tuesday, November 03, 2015 at 07:03:26 PM, Oliver Hartkopp wrote:
> On 11/03/2015 06:41 PM, Marek Vasut wrote:
> > On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:
> > 
> > [...]
> > 
> >> It looks like you need to shift the stuff in user space every time.
> >> 
> >> So you might better think of something like this:
> >>     struct a429_frame {
> >>     
> >>             __u32   label;   /* ARINC 429 label */
> >>             __u8    length;  /* always set to 8 */
> >>             __u8    __pad;   /* padding */
> >>             __u8    __res0;  /* reserved / padding */
> >>             __u8    __res1;  /* reserved / padding */
> >>             __u32   data __attribute__((aligned(8)));
> >>             __u8    p;       /* p */
> >>             __u8    ssm;     /* ssm */
> >>             __u8    sdi;     /* sdi */
> >>             __u8    __end;   /* padding */
> >>     
> >>     };
> > 
> > You don't want to interpret those P(arity)/SSM/SDI bits, since they
> > differ depending on whatever the remote party sends. That's why I
> > decided to just make those into 3-bytes of data and let the userland
> > application deal with it as seen fit. Besides, the ARINC "FTP" really
> > uses those 3 bytes as plain data.
> 
> Ok. I did not know what P was for :-)

Oh yeah. P is parity and it's optional as well and can be odd/even depending
on the remote endpoint (sigh).

> Btw. it can make sense to introduce an union struct where different options
> to access the content are possible.

This would be pretty nasty I think. By reading the ARINC specification, the
SSM can be either 2 or 3 bits, the SDI is who-knows-what depending on the
remote endpoint and the P is also not always present. I'm not convinced that
the kernel should interpret the 3 byte ARINC payload in any way. (but I wonder
if my argument presented above is convincing at all either ...).

So while we can do it for the common case, I wonder if this isn't 
overengineering things a bit right from the beginning. Wouldn't it
make more sense to add this only once the need for it is there?
Such change won't create an incompatible change to the ABI, so from
my perspective, postponing it won't hurt.

> E.g. you might have a 32 bit word, some bit-wise specification and a four
> byte tuple to access the three bytes for ARINC FTP ...

I understand the idea, yes.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Oliver Hartkopp Nov. 3, 2015, 7:28 p.m. UTC | #24
On 11/03/2015 08:19 PM, Marek Vasut wrote:
> On Tuesday, November 03, 2015 at 07:03:26 PM, Oliver Hartkopp wrote:
>> On 11/03/2015 06:41 PM, Marek Vasut wrote:
>>> On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:
>>>
>>> [...]
>>>
>>>> It looks like you need to shift the stuff in user space every time.
>>>>
>>>> So you might better think of something like this:
>>>>     struct a429_frame {
>>>>     
>>>>             __u32   label;   /* ARINC 429 label */
>>>>             __u8    length;  /* always set to 8 */
>>>>             __u8    __pad;   /* padding */
>>>>             __u8    __res0;  /* reserved / padding */
>>>>             __u8    __res1;  /* reserved / padding */
>>>>             __u32   data __attribute__((aligned(8)));
>>>>             __u8    p;       /* p */
>>>>             __u8    ssm;     /* ssm */
>>>>             __u8    sdi;     /* sdi */
>>>>             __u8    __end;   /* padding */
>>>>     
>>>>     };
>>>
>>> You don't want to interpret those P(arity)/SSM/SDI bits, since they
>>> differ depending on whatever the remote party sends. That's why I
>>> decided to just make those into 3-bytes of data and let the userland
>>> application deal with it as seen fit. Besides, the ARINC "FTP" really
>>> uses those 3 bytes as plain data.
>>
>> Ok. I did not know what P was for :-)
> 
> Oh yeah. P is parity and it's optional as well and can be odd/even depending
> on the remote endpoint (sigh).
> 
>> Btw. it can make sense to introduce an union struct where different options
>> to access the content are possible.
> 
> This would be pretty nasty I think. By reading the ARINC specification, the
> SSM can be either 2 or 3 bits, the SDI is who-knows-what depending on the
> remote endpoint and the P is also not always present. I'm not convinced that
> the kernel should interpret the 3 byte ARINC payload in any way. (but I wonder
> if my argument presented above is convincing at all either ...).

Right.

When we define a user visible data structure, this is written into stone.

When ARINC isn't even sure about the detailed interpretation we should
definitely keep our fingers away from doing it ourselves.

Best regards,
Oliver

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vostrikov Andrey Nov. 3, 2015, 8:15 p.m. UTC | #25
Hi, Marek.

> So, considering that hi3593 which as 2x RX and 1x TX port, what about
> registering one device per port and be done with it ?
Yes, that is fine. It could be easily done.
Just drop tx requests on rx channel and vice versa.
Vostrikov Andrey Nov. 3, 2015, 8:26 p.m. UTC | #26
Hi, Oliver.

> So when thinking about using PF_CAN as ARINC429 base ...

> This is the CAN frame structure:

> https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/networking/can.txt?h=linux-4.2.y#n264

>     struct can_frame {
>             canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
>             __u8    can_dlc; /* frame payload length in byte (0 .. 8) */
>             __u8    __pad;   /* padding */
>             __u8    __res0;  /* reserved / padding */
>             __u8    __res1;  /* reserved / padding */
>             __u8    data[8] __attribute__((aligned(8)));
>     };


> So what about defining an arinc429_frame like this:

>     struct a429_frame {
>             __u32   label;   /* ARINC 429 label */
>             __u8    length;  /* always set to 3 */
>             __u8    __pad;   /* padding */
>             __u8    __res0;  /* reserved / padding */
>             __u8    __res1;  /* reserved / padding */
>             __u8    data[8] __attribute__((aligned(8)));
>     };
What  would  be  the  benefit  besides  reusing  CAN tools to have
arinc429 frame structure four times larger that it needs to be?

It just adds complexity to implement translation in device driver from
can-like  structures  to  native  4-bytes message. Similar translation
will be needed in application as well.

There   is   no   real   processing  needed for ARINC429 frames inside
framework. Almost all features  are  done  by  HW  itself  (label  filters,
label  priority matching,   label   bit  flipping,  rate  selection,  parity
and  sdi decoding) or by application.

I'd  prefer to have ARINC framework simple as it could be and separate
from  CAN,  as  these  buses are not similar, besides desire to re-use
SocketCAN interface/API to expose ARINC429 bus.

--
Best regards,
Andrey Vostrikov

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Oliver Hartkopp Nov. 3, 2015, 9:24 p.m. UTC | #27
Hi Andrey,

On 11/03/2015 09:26 PM, Vostrikov Andrey wrote:
> Hi, Oliver.
> 
>> So when thinking about using PF_CAN as ARINC429 base ...
> 
>> This is the CAN frame structure:
> 
>> https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/networking/can.txt?h=linux-4.2.y#n264
> 
>>     struct can_frame {
>>             canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
>>             __u8    can_dlc; /* frame payload length in byte (0 .. 8) */
>>             __u8    __pad;   /* padding */
>>             __u8    __res0;  /* reserved / padding */
>>             __u8    __res1;  /* reserved / padding */
>>             __u8    data[8] __attribute__((aligned(8)));
>>     };
> 
> 
>> So what about defining an arinc429_frame like this:
> 
>>     struct a429_frame {
>>             __u32   label;   /* ARINC 429 label */
>>             __u8    length;  /* always set to 3 */
>>             __u8    __pad;   /* padding */
>>             __u8    __res0;  /* reserved / padding */
>>             __u8    __res1;  /* reserved / padding */
>>             __u8    data[8] __attribute__((aligned(8)));
>>     };
> What  would  be  the  benefit  besides  reusing  CAN tools to have
> arinc429 frame structure four times larger that it needs to be?

Comparing to typical ethernet frames with 1500 bytes the 16 bytes for CAN
frames or 72 bytes for CAN FD frames are already too small in relation to the
socket buffer overhead.

If you want to improve the memory efficiency for arinc290 you should probably
consider to implement a character device based driver instead of creating a
new network protocol family.

> It just adds complexity to implement translation in device driver from
> can-like  structures  to  native  4-bytes message. Similar translation
> will be needed in application as well.

That's BS. You put the data into a struct a429_frame at driver level and you
read the data from struct a429_frame on application level.

Where is the 'translation'?

You would need to do the same with every other data structure in the world too.

> There   is   no   real   processing  needed for ARINC429 frames inside
> framework. Almost all features  are  done  by  HW  itself  (label  filters,
> label  priority matching,   label   bit  flipping,  rate  selection,  parity
> and  sdi decoding) or by application.

From what I've read so far there's also the sending of cyclic messages and
label filtering outside the HW - or why did you copy/paste the can_id/label
filter mechanism from af_can.c ?

> I'd  prefer to have ARINC framework simple as it could be and separate
> from  CAN,  as  these  buses are not similar, besides desire to re-use
> SocketCAN interface/API to expose ARINC429 bus.

From what I've seen so far the ARINC429 requirements can be handled with the
PF_CAN infrastructure only by defining a matching data structure and by adding
some arinc device specific configuration interface.

The latter is probably completely independent from the current CAN netlink
interface for configuration.

But the suggested arinc429 stuff for the network layer looks just like a
needless code duplication.
Maybe you don't need that fancy stuff that comes with PF_CAN. Did you ever
thought about implementing a chardev driver for the ARINC429 hardware? There
are out-of-tree CAN drivers (e.g. can4linux or PEAK System Linux driver) that
handle the transfer of data structures (CAN frames) from/to kernel space via
character device. See an example at https://en.wikipedia.org/wiki/Can4linux

Best regards,
Oliver

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 9:41 p.m. UTC | #28
On Tuesday, November 03, 2015 at 10:24:23 PM, Oliver Hartkopp wrote:
> Hi Andrey,
> 
> On 11/03/2015 09:26 PM, Vostrikov Andrey wrote:
> > Hi, Oliver.
> > 
> >> So when thinking about using PF_CAN as ARINC429 base ...
> >> 
> >> This is the CAN frame structure:
> >> 
> >> https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tre
> >> e/Documentation/networking/can.txt?h=linux-4.2.y#n264
> >> 
> >>     struct can_frame {
> >>     
> >>             canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
> >>             __u8    can_dlc; /* frame payload length in byte (0 .. 8) */
> >>             __u8    __pad;   /* padding */
> >>             __u8    __res0;  /* reserved / padding */
> >>             __u8    __res1;  /* reserved / padding */
> >>             __u8    data[8] __attribute__((aligned(8)));
> >>     
> >>     };
> >> 
> >> So what about defining an arinc429_frame like this:
> >>     struct a429_frame {
> >>     
> >>             __u32   label;   /* ARINC 429 label */
> >>             __u8    length;  /* always set to 3 */
> >>             __u8    __pad;   /* padding */
> >>             __u8    __res0;  /* reserved / padding */
> >>             __u8    __res1;  /* reserved / padding */
> >>             __u8    data[8] __attribute__((aligned(8)));
> >>     
> >>     };
> > 
> > What  would  be  the  benefit  besides  reusing  CAN tools to have
> > arinc429 frame structure four times larger that it needs to be?
> 
> Comparing to typical ethernet frames with 1500 bytes the 16 bytes for CAN
> frames or 72 bytes for CAN FD frames are already too small in relation to
> the socket buffer overhead.
> 
> If you want to improve the memory efficiency for arinc290 you should
> probably consider to implement a character device based driver instead of
> creating a new network protocol family.

See discussion:

http://comments.gmane.org/gmane.linux.kernel/1512019

Which is why I picked the socket variant.

> > It just adds complexity to implement translation in device driver from
> > can-like  structures  to  native  4-bytes message. Similar translation
> > will be needed in application as well.
> 
> That's BS. You put the data into a struct a429_frame at driver level and
> you read the data from struct a429_frame on application level.
> 
> Where is the 'translation'?
> 
> You would need to do the same with every other data structure in the world
> too.
> 
> > There   is   no   real   processing  needed for ARINC429 frames inside
> > framework. Almost all features  are  done  by  HW  itself  (label 
> > filters, label  priority matching,   label   bit  flipping,  rate 
> > selection,  parity and  sdi decoding) or by application.
> 
> From what I've read so far there's also the sending of cyclic messages and
> label filtering outside the HW - or why did you copy/paste the can_id/label
> filter mechanism from af_can.c ?

I think you might be mixing two people together here, I sent the patch and
Andrey and Aleksander are working for some other interested company.

The label filtering makes sense if you want to separate what you receive on 
which socket in userland, which allows an application to receive only relevant 
traffic.

Hardware-accelerated filtering is another thing and at this point, we should
not mix these two things. Does CAN framework have any such support for hardware
assisted can_id filtering btw ?

> > I'd  prefer to have ARINC framework simple as it could be and separate
> > from  CAN,  as  these  buses are not similar, besides desire to re-use
> > SocketCAN interface/API to expose ARINC429 bus.
> 
> From what I've seen so far the ARINC429 requirements can be handled with
> the PF_CAN infrastructure only by defining a matching data structure and
> by adding some arinc device specific configuration interface.
> 
> The latter is probably completely independent from the current CAN netlink
> interface for configuration.

Right.

> But the suggested arinc429 stuff for the network layer looks just like a
> needless code duplication.

Yes.

> Maybe you don't need that fancy stuff that comes with PF_CAN. Did you ever
> thought about implementing a chardev driver for the ARINC429 hardware?
> There are out-of-tree CAN drivers (e.g. can4linux or PEAK System Linux
> driver) that handle the transfer of data structures (CAN frames) from/to
> kernel space via character device. See an example at
> https://en.wikipedia.org/wiki/Can4linux

I guess I can answer that -- yes, I did, see above.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 9:43 p.m. UTC | #29
On Tuesday, November 03, 2015 at 08:28:43 PM, Oliver Hartkopp wrote:
> On 11/03/2015 08:19 PM, Marek Vasut wrote:
> > On Tuesday, November 03, 2015 at 07:03:26 PM, Oliver Hartkopp wrote:
> >> On 11/03/2015 06:41 PM, Marek Vasut wrote:
> >>> On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:
> >>> 
> >>> [...]
> >>> 
> >>>> It looks like you need to shift the stuff in user space every time.
> >>>> 
> >>>> So you might better think of something like this:
> >>>>     struct a429_frame {
> >>>>     
> >>>>             __u32   label;   /* ARINC 429 label */
> >>>>             __u8    length;  /* always set to 8 */
> >>>>             __u8    __pad;   /* padding */
> >>>>             __u8    __res0;  /* reserved / padding */
> >>>>             __u8    __res1;  /* reserved / padding */
> >>>>             __u32   data __attribute__((aligned(8)));
> >>>>             __u8    p;       /* p */
> >>>>             __u8    ssm;     /* ssm */
> >>>>             __u8    sdi;     /* sdi */
> >>>>             __u8    __end;   /* padding */
> >>>>     
> >>>>     };
> >>> 
> >>> You don't want to interpret those P(arity)/SSM/SDI bits, since they
> >>> differ depending on whatever the remote party sends. That's why I
> >>> decided to just make those into 3-bytes of data and let the userland
> >>> application deal with it as seen fit. Besides, the ARINC "FTP" really
> >>> uses those 3 bytes as plain data.
> >> 
> >> Ok. I did not know what P was for :-)
> > 
> > Oh yeah. P is parity and it's optional as well and can be odd/even
> > depending on the remote endpoint (sigh).
> > 
> >> Btw. it can make sense to introduce an union struct where different
> >> options to access the content are possible.
> > 
> > This would be pretty nasty I think. By reading the ARINC specification,
> > the SSM can be either 2 or 3 bits, the SDI is who-knows-what depending
> > on the remote endpoint and the P is also not always present. I'm not
> > convinced that the kernel should interpret the 3 byte ARINC payload in
> > any way. (but I wonder if my argument presented above is convincing at
> > all either ...).
> 
> Right.
> 
> When we define a user visible data structure, this is written into stone.
> 
> When ARINC isn't even sure about the detailed interpretation we should
> definitely keep our fingers away from doing it ourselves.

Right. Besides, such extension to the ABI can be done later if the need
arises (which I seriously doubt), can't it ? Handling the payload as a CAN
payload makes sense.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 3, 2015, 9:44 p.m. UTC | #30
On Monday, November 02, 2015 at 07:16:18 PM, Marek Vasut wrote:
> On Monday, November 02, 2015 at 12:14:27 PM, Oliver Hartkopp wrote:
> > On 02.11.2015 10:47, Marc Kleine-Budde wrote:
> > > On 11/02/2015 12:16 AM, Marek Vasut wrote:
> > >> The ARINC-429 is a technical standard, which describes, among others,
> > >> a data bus used by airplanes. The standard contains much more, since
> > >> it is based off the ISO/OSI model, but this patch implements just the
> > >> data bus protocol.
> > >> 
> > >> This stack is derived from the SocketCAN implementation, already
> > >> present in the kernel and thus behaves in a very similar fashion.
> > >> Thus far, we support sending RAW ARINC-429 datagrams, configuration
> > >> of the RX and TX clock speed and filtering.
> > >> 
> > >> The ARINC-429 datagram is four-byte long. The first byte is always the
> > >> LABEL, the function of remaining three bytes can vary, so we handle it
> > >> as an opaque PAYLOAD. The userspace tools can send these datagrams via
> > >> a standard socket.
> > >> 
> > >> A LABEL-based filtering can be configured on each socket separately in
> > >> a way comparable to CAN -- user uses setsockopt() to push a list of
> > >> label,mask tuples into the kernel and the kernel will deliver a
> > >> datagram to the socket if (<received_label> & mask) == (label &
> > >> mask), otherwise the datagram is not delivered.
> > > 
> > > What's difference compared to CAN besides a different MTU? The CAN
> > > stack is already capable to handle CAN and CAN-FD frames. Would it
> > > make sense to integrate the ARINC-429 into the existing CAN stack?
> > 
> > That was my first impression too.
> 
> Hi!
> 
> > What about defining some overlay data structure to map ARINC-429 frames
> > into CAN frames?
> 
> I agree about the code reuse, it was stupid to do such a blatant copy of
> the code all right. I don't think it's such a great idea to outright place
> ARINC support into the CAN stack though. They're two different busses
> after all. Please see below.
> 
> > E.g. we could write the ARINC 32 bit data completely into data[0..3] and
> > additionally copy the 8 bit label information (or should it better be 10
> > bit including the Source/Destination Identifiers?) additionally into the
> > can_id.
> > 
> >  From what I can see the filtering by label is similar to filtering by
> > 
> > can_id. And you would be able to use the can-gw functionality too.
> 
> This is correct.
> 
> > The only real difference is the bitrate configuration of the ARINC
> > interface.
> 
> There might be additional ARINC-specific configuration bits involved,
> but thus far, that's correct.
> 
> > I wonder if a similar approach would fit here as we discussed with the
> > University of Prague for a LIN implementation using the PF_CAN
> 
> > infrastructure:
> OT: Hey, there is no "University of Prague", there are two universities in
> Prague to boot -- Charles University and Czech Technical University -- you
> mean the later ;-)
> 
> > http://rtime.felk.cvut.cz/can/lin-bus/
> > 
> > It could probably boil down to a 'CAN interface' that is named arinc0
> > which implements the serial driver like in slcan.c or sllin.c ...
> 
> I was thinking about this and I mostly agree with you. Obviously, copying
> the code this way was dumb. On the other hand, ARINC and CAN are two
> different sort of busses, so I'd propose something slightly different here
> to avoid confusion and prevent the future extensions (or protocols) from
> adding unrelated cruft into the CAN stack.
> 
> I would propose we (read: me) create some sort of "common" core, which
> would contain the following:
>  - drivers/net/: big part of the device interface here is common
>                  big part of the virtual interface here is common
>                  -> CAN or ARINC can just add their own specific callbacks
> and be done with it
> 
>  - net/: there's a lot of common parts as well, like the filtering can be
>          unified such that it can be used by both. A big part of the socket
>          handling is also similar.
> 
> This would also let the slcan or sllin or whatever stuff they made at CVUT
> just plug into this "common" core part.
> 
> Now I wonder if we should introduce AF_ARINC or stick to AF_CAN for both.
> I'd be much happier to keep those two separate, again, to avoid confusion.
> 
> What do you think please ?

So, what do you think about this approach -- pulling out common core code from
CAN (so it can be re-used for ARINC) and having both of those (CAN and ARINC)
implement just a thin layer of adaptation code for this core ? Would this make
sense to you?
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vostrikov Andrey Nov. 3, 2015, 9:52 p.m. UTC | #31
Hi, Oliver.

> Comparing to typical ethernet frames with 1500 bytes the 16 bytes for CAN
> frames or 72 bytes for CAN FD frames are already too small in relation to the
> socket buffer overhead.
Ok,  if there is no big difference using 4-bytes structure or 16-bytes
structures, I do not have any objections.

> If you want to improve the memory efficiency for arinc290 you should probably
> consider to implement a character device based driver instead of creating a
> new network protocol family.
I  suppose  such  drivers  have  been  implemented before, but by some
reasons  socket  API is preferred now. I do not have any details regarding
this.

>> It just adds complexity to implement translation in device driver from
>> can-like  structures  to  native  4-bytes message. Similar translation
>> will be needed in application as well.

> That's BS. You put the data into a struct a429_frame at driver level and you
> read the data from struct a429_frame on application level.

> Where is the 'translation'?
Ok,  I overreacted a bit. Even in current proposal it is needed to move
bytes in HI-3593 driver as  well, as this chip accepts label as last byte,
instead  of  first  one  in SPI transfers. It was just a wish to use
same data without any actions when moving it between framework and HW.

> From what I've read so far there's also the sending of cyclic messages and
> label filtering outside the HW - or why did you copy/paste the can_id/label
> filter mechanism from af_can.c ?
It  is  not  I  who  copied CAN code, and I do not think that CAN label filter
mechanism  fits ARINC, as it looks overcomplicated for small label space
in ARINC429
Aleksander Morgado Nov. 4, 2015, 9:31 a.m. UTC | #32
On Tue, Nov 3, 2015 at 6:33 PM, Marek Vasut <marex@denx.de> wrote:
> On Tuesday, November 03, 2015 at 05:56:53 PM, Aleksander Morgado wrote:
>> On Tue, Nov 3, 2015 at 5:18 PM, Aleksander Morgado
>>
>> <aleksander@aleksander.es> wrote:
>> > On Tue, Nov 3, 2015 at 4:19 PM, Marek Vasut <marex@denx.de> wrote:
>> >>> , or the duplex TX/RX setup for channels
>> >>> (channels are either RX or TX, not both), or the local
>> >>> echoing/loopback (which wouldn't make much sense for TX-only
>> >>> channels).
>> >>
>> >> Aren't the RX-only/TX-only channels rather a special case ?
>> >
>> > They're actually the only case AFAIK. You've got systems generating
>> > streams of ARINC429 words (e.g. the IRS, the FMC...) and systems that
>> > may consume the streams from multiple independent channels (e.g. the
>> > IFE). I try to think of each logical bus as a single transmitter
>> > broadcasting to multiple receivers.
>>
>> I've re-checked the spec and it does say that there may be systems
>> that act as source (TX) and sink (RX), e.g. DME, VOR or ILS. But in
>> those cases, they will actually have separate TX and RX physical
>> ports.
>
> So, considering that hi3593 which as 2x RX and 1x TX port, what about
> registering one device per port and be done with it ?

Yes, as long as the RX device doesn't accept writing, and the TX
device doesn't accept reading (except for echo I guess, if that ends
up getting included), that would make sense. The kernel will need to
specify somehow the port type clearly.
Aleksander Morgado Nov. 4, 2015, 9:34 a.m. UTC | #33
On Tue, Nov 3, 2015 at 10:43 PM, Marek Vasut <marex@denx.de> wrote:
> On Tuesday, November 03, 2015 at 08:28:43 PM, Oliver Hartkopp wrote:
>> On 11/03/2015 08:19 PM, Marek Vasut wrote:
>> > On Tuesday, November 03, 2015 at 07:03:26 PM, Oliver Hartkopp wrote:
>> >> On 11/03/2015 06:41 PM, Marek Vasut wrote:
>> >>> On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:
>> >>>
>> >>> [...]
>> >>>
>> >>>> It looks like you need to shift the stuff in user space every time.
>> >>>>
>> >>>> So you might better think of something like this:
>> >>>>     struct a429_frame {
>> >>>>
>> >>>>             __u32   label;   /* ARINC 429 label */
>> >>>>             __u8    length;  /* always set to 8 */
>> >>>>             __u8    __pad;   /* padding */
>> >>>>             __u8    __res0;  /* reserved / padding */
>> >>>>             __u8    __res1;  /* reserved / padding */
>> >>>>             __u32   data __attribute__((aligned(8)));
>> >>>>             __u8    p;       /* p */
>> >>>>             __u8    ssm;     /* ssm */
>> >>>>             __u8    sdi;     /* sdi */
>> >>>>             __u8    __end;   /* padding */
>> >>>>
>> >>>>     };
>> >>>
>> >>> You don't want to interpret those P(arity)/SSM/SDI bits, since they
>> >>> differ depending on whatever the remote party sends. That's why I
>> >>> decided to just make those into 3-bytes of data and let the userland
>> >>> application deal with it as seen fit. Besides, the ARINC "FTP" really
>> >>> uses those 3 bytes as plain data.
>> >>
>> >> Ok. I did not know what P was for :-)
>> >
>> > Oh yeah. P is parity and it's optional as well and can be odd/even
>> > depending on the remote endpoint (sigh).
>> >
>> >> Btw. it can make sense to introduce an union struct where different
>> >> options to access the content are possible.
>> >
>> > This would be pretty nasty I think. By reading the ARINC specification,
>> > the SSM can be either 2 or 3 bits, the SDI is who-knows-what depending
>> > on the remote endpoint and the P is also not always present. I'm not
>> > convinced that the kernel should interpret the 3 byte ARINC payload in
>> > any way. (but I wonder if my argument presented above is convincing at
>> > all either ...).
>>
>> Right.
>>
>> When we define a user visible data structure, this is written into stone.
>>
>> When ARINC isn't even sure about the detailed interpretation we should
>> definitely keep our fingers away from doing it ourselves.
>
> Right. Besides, such extension to the ABI can be done later if the need
> arises (which I seriously doubt), can't it ? Handling the payload as a CAN
> payload makes sense.

Agree on this, the three non-label bytes in an ARINC word should be
taken as opaque payload. The only exception would be the parity most
significant bit, but I don't think it'd be an issue to have that in
the opaque payload.
Aleksander Morgado Nov. 4, 2015, 9:51 a.m. UTC | #34
On Tue, Nov 3, 2015 at 6:01 PM, Oliver Hartkopp <socketcan@hartkopp.net> wrote:
>> Unrelated to all this, another key point in ARINC is the timing for
>> each label when transmitting. The common case you get is different
>> labels being sent continuously with a given rate for each. E.g. labels
>> 310 and 311 every 80ms, label 312 every 120ms and so on. I'm not sure
>> the HOLT chips have any specific way of configuring this, but I've
>> seen some USB devices which actually have APIs to say e.g. "send label
>> 310 every 80ms" and then you can just update the value being sent
>> without needing to take care of the TX rate. I'd have loved to see
>> that instead of the complex filtering :) I know this is way too much
>> for the generic kernel driver, though, so just a heads up of how this
>> usually works.
>>
>
> The CAN stack already has a solution for this.
>
> The CAN_BCM socket is a programmable (content) filter for cyclic messages
> which are common in automotive setups to detect timeouts in cyclic messages
> (sender fails).
>
> An the best thing: You can use the Linux internal high-res timers to send
> messages - just by creating a TX_SETUP configuration for the BCM.
>
> Read this:
> https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/networking/can.txt?h=linux-4.2.y#n634
>
> Just one more reason to use PF_CAN :-)

This setup is actually very interesting for ARINC transmitters, indeed.
Oliver Hartkopp Nov. 4, 2015, 10:44 a.m. UTC | #35
Hi Marek,

On 03.11.2015 22:41, Marek Vasut wrote:
> On Tuesday, November 03, 2015 at 10:24:23 PM, Oliver Hartkopp wrote:


>> Comparing to typical ethernet frames with 1500 bytes the 16 bytes for CAN
>> frames or 72 bytes for CAN FD frames are already too small in relation to
>> the socket buffer overhead.
>>
>> If you want to improve the memory efficiency for arinc290 you should
>> probably consider to implement a character device based driver instead of
>> creating a new network protocol family.
>
> See discussion:
>
> http://comments.gmane.org/gmane.linux.kernel/1512019
>
> Which is why I picked the socket variant.
>

Oh. This provides a completely new perspective.

So far we just discussed about the 32 bit messages to be handled and filtered 
by the kernel.

This could have been done by

1. A chardev interface driver

2. A netdev interface driver (drivers/net/arinc429/...) and using PF_PACKET 
together with Berkley packet filtering (BPF)

3. A netdev interface driver (drivers/net/arinc429/...) and using PF_CAN which 
would lead to a arinc data structure which needs to be struct can_frame 
compatible.

But if you plan to implement the transport protocols (FTP/MAC) inside the 
Linux kernel that have been discussed in the URL above this would be a real 
difference to CAN related protocols. Only from that perspective a new protocol 
family would make sense.

(..)
>>  From what I've read so far there's also the sending of cyclic messages and
>> label filtering outside the HW - or why did you copy/paste the can_id/label
>> filter mechanism from af_can.c ?
>
> I think you might be mixing two people together here, I sent the patch and
> Andrey and Aleksander are working for some other interested company.

Sorry. Will try to bash only *you* in the future :-))

> The label filtering makes sense if you want to separate what you receive on
> which socket in userland, which allows an application to receive only relevant
> traffic.

ok.

>
> Hardware-accelerated filtering is another thing and at this point, we should
> not mix these two things. Does CAN framework have any such support for hardware
> assisted can_id filtering btw ?
>

No. We discussed about it. But the HW filter capabilities of CAN controllers 
have a wide range of functionality. Most filters make only sense in ECUs that 
pick specific CAN IDs for their functionality. It made no real sense to have 
an administrative configuration interface that limits the view to the CAN bus 
for the entire system. An we never had performance issues with the filtering 
in the softirq context in af_can.c

>>> I'd  prefer to have ARINC framework simple as it could be and separate
>>> from  CAN,  as  these  buses are not similar, besides desire to re-use
>>> SocketCAN interface/API to expose ARINC429 bus.
>>

>> Maybe you don't need that fancy stuff that comes with PF_CAN. Did you ever
>> thought about implementing a chardev driver for the ARINC429 hardware?
>> There are out-of-tree CAN drivers (e.g. can4linux or PEAK System Linux
>> driver) that handle the transfer of data structures (CAN frames) from/to
>> kernel space via character device. See an example at
>> https://en.wikipedia.org/wiki/Can4linux
>
> I guess I can answer that -- yes, I did, see above.
>

Ok - it seems to stick on the future plan whether it makes sense to implement 
the FTP/MAC transport protocols inside the kernel or not.

What's your thought about that?

Regards,
Oliver
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Marek Vasut Nov. 4, 2015, 1:54 p.m. UTC | #36
On Wednesday, November 04, 2015 at 10:34:50 AM, Aleksander Morgado wrote:
> On Tue, Nov 3, 2015 at 10:43 PM, Marek Vasut <marex@denx.de> wrote:
> > On Tuesday, November 03, 2015 at 08:28:43 PM, Oliver Hartkopp wrote:
> >> On 11/03/2015 08:19 PM, Marek Vasut wrote:
> >> > On Tuesday, November 03, 2015 at 07:03:26 PM, Oliver Hartkopp wrote:
> >> >> On 11/03/2015 06:41 PM, Marek Vasut wrote:
> >> >>> On Tuesday, November 03, 2015 at 06:32:12 PM, Oliver Hartkopp wrote:
> >> >>> 
> >> >>> [...]
> >> >>> 
> >> >>>> It looks like you need to shift the stuff in user space every time.
> >> >>>> 
> >> >>>> So you might better think of something like this:
> >> >>>>     struct a429_frame {
> >> >>>>     
> >> >>>>             __u32   label;   /* ARINC 429 label */
> >> >>>>             __u8    length;  /* always set to 8 */
> >> >>>>             __u8    __pad;   /* padding */
> >> >>>>             __u8    __res0;  /* reserved / padding */
> >> >>>>             __u8    __res1;  /* reserved / padding */
> >> >>>>             __u32   data __attribute__((aligned(8)));
> >> >>>>             __u8    p;       /* p */
> >> >>>>             __u8    ssm;     /* ssm */
> >> >>>>             __u8    sdi;     /* sdi */
> >> >>>>             __u8    __end;   /* padding */
> >> >>>>     
> >> >>>>     };
> >> >>> 
> >> >>> You don't want to interpret those P(arity)/SSM/SDI bits, since they
> >> >>> differ depending on whatever the remote party sends. That's why I
> >> >>> decided to just make those into 3-bytes of data and let the userland
> >> >>> application deal with it as seen fit. Besides, the ARINC "FTP"
> >> >>> really uses those 3 bytes as plain data.
> >> >> 
> >> >> Ok. I did not know what P was for :-)
> >> > 
> >> > Oh yeah. P is parity and it's optional as well and can be odd/even
> >> > depending on the remote endpoint (sigh).
> >> > 
> >> >> Btw. it can make sense to introduce an union struct where different
> >> >> options to access the content are possible.
> >> > 
> >> > This would be pretty nasty I think. By reading the ARINC
> >> > specification, the SSM can be either 2 or 3 bits, the SDI is
> >> > who-knows-what depending on the remote endpoint and the P is also not
> >> > always present. I'm not convinced that the kernel should interpret
> >> > the 3 byte ARINC payload in any way. (but I wonder if my argument
> >> > presented above is convincing at all either ...).
> >> 
> >> Right.
> >> 
> >> When we define a user visible data structure, this is written into
> >> stone.
> >> 
> >> When ARINC isn't even sure about the detailed interpretation we should
> >> definitely keep our fingers away from doing it ourselves.
> > 
> > Right. Besides, such extension to the ABI can be done later if the need
> > arises (which I seriously doubt), can't it ? Handling the payload as a
> > CAN payload makes sense.
> 
> Agree on this, the three non-label bytes in an ARINC word should be
> taken as opaque payload. The only exception would be the parity most
> significant bit, but I don't think it'd be an issue to have that in
> the opaque payload.

About the parity -- can we add some flag into the datagram to indicate we
want hardware to calculate the parity for that particular datagram for us?
And we'd also need to indicate what type of parity. I dunno if this is worth
the hassle.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vostrikov Andrey Nov. 4, 2015, 3:03 p.m. UTC | #37
Hi, Marek.

> About the parity -- can we add some flag into the datagram to indicate we
> want hardware to calculate the parity for that particular datagram for us?
> And we'd also need to indicate what type of parity. I dunno if this is worth
> the hassle.
This  is HW configuration property, it does not belong to  datagram. Also for TX
channels,  parity could  be  two  kinds:  odd and even, for RX it is only
on/off.

Parity  is  not  the  only property that needs to be configured in HW,
following could be needed as well,
- label bit flipping (on or off)
- rate change (low / high)
-  label  filters  and  label  priority matching (this could be HoltIC
specific)

I  suppose  all  these  properties  are  configured  only  once, at interface
initialization.
Marek Vasut Nov. 4, 2015, 3:07 p.m. UTC | #38
On Wednesday, November 04, 2015 at 04:03:16 PM, Vostrikov Andrey wrote:
> Hi, Marek.

Hi,

> > About the parity -- can we add some flag into the datagram to indicate we
> > want hardware to calculate the parity for that particular datagram for
> > us? And we'd also need to indicate what type of parity. I dunno if this
> > is worth the hassle.
> 
> This  is HW configuration property, it does not belong to  datagram. Also
> for TX channels,  parity could  be  two  kinds:  odd and even, for RX it
> is only on/off.

There are datagrams which do contain parity and ones which do not contain it,
correct ? Thus, it's a property of that particular datagram.

> Parity  is  not  the  only property that needs to be configured in HW,
> following could be needed as well,
> - label bit flipping (on or off)

This is hardware property.

> - rate change (low / high)

This is again hardware configuration -- you have to configure the link speed
before you do RX/TX.

> -  label  filters  and  label  priority matching (this could be HoltIC
> specific)
> 
> I  suppose  all  these  properties  are  configured  only  once, at
> interface initialization.

These three above, yes. Parity, I don't think so.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Vostrikov Andrey Nov. 4, 2015, 3:18 p.m. UTC | #39
Hi, Marek.

>> > About the parity -- can we add some flag into the datagram to indicate we
>> > want hardware to calculate the parity for that particular datagram for
>> > us? And we'd also need to indicate what type of parity. I dunno if this
>> > is worth the hassle.
>> 
>> This  is HW configuration property, it does not belong to  datagram. Also
>> for TX channels,  parity could  be  two  kinds:  odd and even, for RX it
>> is only on/off.

> There are datagrams which do contain parity and ones which do not contain it,
> correct ? Thus, it's a property of that particular datagram.
For   RX  side  it  is  both: datagram and HW (is it checked by receiver or not)
But  for TX side it is HW property of transmitter, either OFF or ON (odd or even).
Aleksander Morgado Nov. 4, 2015, 3:19 p.m. UTC | #40
On Wed, Nov 4, 2015 at 4:18 PM, Vostrikov Andrey
<andrey.vostrikov@cogentembedded.com> wrote:
>>> > About the parity -- can we add some flag into the datagram to indicate we
>>> > want hardware to calculate the parity for that particular datagram for
>>> > us? And we'd also need to indicate what type of parity. I dunno if this
>>> > is worth the hassle.
>>>
>>> This  is HW configuration property, it does not belong to  datagram. Also
>>> for TX channels,  parity could  be  two  kinds:  odd and even, for RX it
>>> is only on/off.
>
>> There are datagrams which do contain parity and ones which do not contain it,
>> correct ? Thus, it's a property of that particular datagram.

All ARINC words have bit #31 as parity bit; whether it's used or not
depends on the setup as Andrey says below.

> For   RX  side  it  is  both: datagram and HW (is it checked by receiver or not)
> But  for TX side it is HW property of transmitter, either OFF or ON (odd or even).
Marek Vasut Nov. 4, 2015, 3:33 p.m. UTC | #41
On Wednesday, November 04, 2015 at 04:19:45 PM, Aleksander Morgado wrote:
> On Wed, Nov 4, 2015 at 4:18 PM, Vostrikov Andrey
> 
> <andrey.vostrikov@cogentembedded.com> wrote:
> >>> > About the parity -- can we add some flag into the datagram to
> >>> > indicate we want hardware to calculate the parity for that
> >>> > particular datagram for us? And we'd also need to indicate what type
> >>> > of parity. I dunno if this is worth the hassle.
> >>> 
> >>> This  is HW configuration property, it does not belong to  datagram.
> >>> Also for TX channels,  parity could  be  two  kinds:  odd and even,
> >>> for RX it is only on/off.
> >> 
> >> There are datagrams which do contain parity and ones which do not
> >> contain it, correct ? Thus, it's a property of that particular
> >> datagram.
> 
> All ARINC words have bit #31 as parity bit; whether it's used or not
> depends on the setup as Andrey says below.

Can bit 31 be ever used for DATA instead of parity ? Or is this just me
not understanding the parlance of the specification, where "DATA" actually
means "DATA with parity" ?

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Aleksander Morgado Nov. 4, 2015, 3:45 p.m. UTC | #42
On Wed, Nov 4, 2015 at 4:33 PM, Marek Vasut <marex@denx.de> wrote:
> On Wednesday, November 04, 2015 at 04:19:45 PM, Aleksander Morgado wrote:
>> On Wed, Nov 4, 2015 at 4:18 PM, Vostrikov Andrey
>>
>> <andrey.vostrikov@cogentembedded.com> wrote:
>> >>> > About the parity -- can we add some flag into the datagram to
>> >>> > indicate we want hardware to calculate the parity for that
>> >>> > particular datagram for us? And we'd also need to indicate what type
>> >>> > of parity. I dunno if this is worth the hassle.
>> >>>
>> >>> This  is HW configuration property, it does not belong to  datagram.
>> >>> Also for TX channels,  parity could  be  two  kinds:  odd and even,
>> >>> for RX it is only on/off.
>> >>
>> >> There are datagrams which do contain parity and ones which do not
>> >> contain it, correct ? Thus, it's a property of that particular
>> >> datagram.
>>
>> All ARINC words have bit #31 as parity bit; whether it's used or not
>> depends on the setup as Andrey says below.
>
> Can bit 31 be ever used for DATA instead of parity ? Or is this just me
> not understanding the parlance of the specification, where "DATA" actually
> means "DATA with parity" ?

Well, as far as I know bit 31 is always parity bit, never used for
actual data contents. Which is the spec section that got you confused?
Maybe I'm the one which didn't read it well?
Marek Vasut Nov. 10, 2015, 4:15 p.m. UTC | #43
On Wednesday, November 04, 2015 at 04:45:20 PM, Aleksander Morgado wrote:
> On Wed, Nov 4, 2015 at 4:33 PM, Marek Vasut <marex@denx.de> wrote:
> > On Wednesday, November 04, 2015 at 04:19:45 PM, Aleksander Morgado wrote:
> >> On Wed, Nov 4, 2015 at 4:18 PM, Vostrikov Andrey
> >> 
> >> <andrey.vostrikov@cogentembedded.com> wrote:
> >> >>> > About the parity -- can we add some flag into the datagram to
> >> >>> > indicate we want hardware to calculate the parity for that
> >> >>> > particular datagram for us? And we'd also need to indicate what
> >> >>> > type of parity. I dunno if this is worth the hassle.
> >> >>> 
> >> >>> This  is HW configuration property, it does not belong to  datagram.
> >> >>> Also for TX channels,  parity could  be  two  kinds:  odd and even,
> >> >>> for RX it is only on/off.
> >> >> 
> >> >> There are datagrams which do contain parity and ones which do not
> >> >> contain it, correct ? Thus, it's a property of that particular
> >> >> datagram.
> >> 
> >> All ARINC words have bit #31 as parity bit; whether it's used or not
> >> depends on the setup as Andrey says below.
> > 
> > Can bit 31 be ever used for DATA instead of parity ? Or is this just me
> > not understanding the parlance of the specification, where "DATA"
> > actually means "DATA with parity" ?
> 
> Well, as far as I know bit 31 is always parity bit, never used for
> actual data contents. Which is the spec section that got you confused?
> Maybe I'm the one which didn't read it well?

Sorry for being so late into the discussion.

I got confused by hi-3585_v-rev-l.pdf page 7 right, CR4 lets you treat bit
32 as either data or parity. But I guess this is not the general case.

So I wonder, does it make sense to treat the P bit as data always and do
parity in software or not ?

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Aleksander Morgado Nov. 18, 2015, 4:38 p.m. UTC | #44
On Tue, Nov 10, 2015 at 5:15 PM, Marek Vasut <marex@denx.de> wrote:
>> >> >>> > About the parity -- can we add some flag into the datagram to
>> >> >>> > indicate we want hardware to calculate the parity for that
>> >> >>> > particular datagram for us? And we'd also need to indicate what
>> >> >>> > type of parity. I dunno if this is worth the hassle.
>> >> >>>
>> >> >>> This  is HW configuration property, it does not belong to  datagram.
>> >> >>> Also for TX channels,  parity could  be  two  kinds:  odd and even,
>> >> >>> for RX it is only on/off.
>> >> >>
>> >> >> There are datagrams which do contain parity and ones which do not
>> >> >> contain it, correct ? Thus, it's a property of that particular
>> >> >> datagram.
>> >>
>> >> All ARINC words have bit #31 as parity bit; whether it's used or not
>> >> depends on the setup as Andrey says below.
>> >
>> > Can bit 31 be ever used for DATA instead of parity ? Or is this just me
>> > not understanding the parlance of the specification, where "DATA"
>> > actually means "DATA with parity" ?
>>
>> Well, as far as I know bit 31 is always parity bit, never used for
>> actual data contents. Which is the spec section that got you confused?
>> Maybe I'm the one which didn't read it well?
>
> Sorry for being so late into the discussion.
>
> I got confused by hi-3585_v-rev-l.pdf page 7 right, CR4 lets you treat bit
> 32 as either data or parity. But I guess this is not the general case.
>
> So I wonder, does it make sense to treat the P bit as data always and do
> parity in software or not ?

I don't have an strong opinion on this, truth be told. It really
depends on whether we can tell the HW "go compute the parity
yourself". If we can ask for that, maybe we should allow configuring
that in the API with some flag. But anyway, treating P as data (i.e.
software should set parity bit to whatever is needed) is the most
generic thing you could do for a start, that shouldn't be wrong.
Marek Vasut Nov. 18, 2015, 4:41 p.m. UTC | #45
On Wednesday, November 18, 2015 at 05:38:02 PM, Aleksander Morgado wrote:
> On Tue, Nov 10, 2015 at 5:15 PM, Marek Vasut <marex@denx.de> wrote:
> >> >> >>> > About the parity -- can we add some flag into the datagram to
> >> >> >>> > indicate we want hardware to calculate the parity for that
> >> >> >>> > particular datagram for us? And we'd also need to indicate what
> >> >> >>> > type of parity. I dunno if this is worth the hassle.
> >> >> >>> 
> >> >> >>> This  is HW configuration property, it does not belong to 
> >> >> >>> datagram. Also for TX channels,  parity could  be  two  kinds: 
> >> >> >>> odd and even, for RX it is only on/off.
> >> >> >> 
> >> >> >> There are datagrams which do contain parity and ones which do not
> >> >> >> contain it, correct ? Thus, it's a property of that particular
> >> >> >> datagram.
> >> >> 
> >> >> All ARINC words have bit #31 as parity bit; whether it's used or not
> >> >> depends on the setup as Andrey says below.
> >> > 
> >> > Can bit 31 be ever used for DATA instead of parity ? Or is this just
> >> > me not understanding the parlance of the specification, where "DATA"
> >> > actually means "DATA with parity" ?
> >> 
> >> Well, as far as I know bit 31 is always parity bit, never used for
> >> actual data contents. Which is the spec section that got you confused?
> >> Maybe I'm the one which didn't read it well?
> > 
> > Sorry for being so late into the discussion.
> > 
> > I got confused by hi-3585_v-rev-l.pdf page 7 right, CR4 lets you treat
> > bit 32 as either data or parity. But I guess this is not the general
> > case.
> > 
> > So I wonder, does it make sense to treat the P bit as data always and do
> > parity in software or not ?
> 
> I don't have an strong opinion on this, truth be told. It really
> depends on whether we can tell the HW "go compute the parity
> yourself". If we can ask for that, maybe we should allow configuring
> that in the API with some flag. But anyway, treating P as data (i.e.
> software should set parity bit to whatever is needed) is the most
> generic thing you could do for a start, that shouldn't be wrong.

OK, let's treat it as data.

Since RC1 is out, I should start reworking the framework into more sensible
shape and repost before I miss the opportunity.

Best regards,
Marek Vasut
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 9de185d..cfa3a92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -814,6 +814,25 @@  S:	Maintained
 F:	drivers/net/arcnet/
 F:	include/uapi/linux/if_arcnet.h
 
+ARINC429 NETWORK LAYER
+M:	Marek Vasut <marex@denx.de>
+S:	Maintained
+F:	net/arinc429/
+F:	include/linux/arinc429/core.h
+F:	include/uapi/linux/arinc429.h
+F:	include/uapi/linux/arinc429/bcm.h
+F:	include/uapi/linux/arinc429/raw.h
+F:	include/uapi/linux/arinc429/gw.h
+
+ARINC429 NETWORK DRIVERS
+M:	Marek Vasut <marex@denx.de>
+S:	Maintained
+F:	drivers/net/arinc429/
+F:	include/linux/arinc429/dev.h
+F:	include/linux/arinc429/platform/
+F:	include/uapi/linux/arinc429/error.h
+F:	include/uapi/linux/arinc429/netlink.h
+
 ARM MFM AND FLOPPY DRIVERS
 M:	Ian Molton <spyro@f2s.com>
 S:	Maintained
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 900b0c5..d6e0682 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -31,6 +31,7 @@  obj-$(CONFIG_NET_VRF) += vrf.o
 # Networking Drivers
 #
 obj-$(CONFIG_ARCNET) += arcnet/
+obj-$(CONFIG_ARINC429) += arinc429/
 obj-$(CONFIG_DEV_APPLETALK) += appletalk/
 obj-$(CONFIG_CAIF) += caif/
 obj-$(CONFIG_CAN) += can/
diff --git a/drivers/net/arinc429/Kconfig b/drivers/net/arinc429/Kconfig
new file mode 100644
index 0000000..428164c
--- /dev/null
+++ b/drivers/net/arinc429/Kconfig
@@ -0,0 +1,32 @@ 
+menu "ARINC429 Device Drivers"
+
+config ARINC429_VARINC429
+	tristate "Virtual Local ARINC429 Interface (varinc429)"
+	---help---
+	  Similar to the network loopback devices, varinc429 offers a
+	  virtual local ARINC429 interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called varinc429.
+
+config ARINC429_DEV
+	tristate "Platform ARINC429 drivers with Netlink support"
+	default y
+	---help---
+	  Enables the common framework for platform ARINC429 drivers with Netlink
+	  support. This is the standard library for ARINC429 drivers.
+	  If unsure, say Y.
+
+if ARINC429_DEV
+
+endif
+
+config ARINC429_DEBUG_DEVICES
+	bool "ARINC429 devices debugging messages"
+	---help---
+	  Say Y here if you want the ARINC429 device drivers to produce a bunch of
+	  debug messages to the system log.  Select this if you are having
+	  a problem with ARINC429 support and want to see more of what is going
+	  on.
+
+endmenu
diff --git a/drivers/net/arinc429/Makefile b/drivers/net/arinc429/Makefile
new file mode 100644
index 0000000..70aaaac
--- /dev/null
+++ b/drivers/net/arinc429/Makefile
@@ -0,0 +1,11 @@ 
+#
+#  Makefile for the Linux Controller Area Network drivers.
+#
+
+obj-$(CONFIG_ARINC429_VARINC429)	+= varinc429.o
+
+obj-$(CONFIG_ARINC429_DEV)		+= arinc429-dev.o
+arinc429-dev-y				:= dev.o
+
+subdir-ccflags-y += -D__CHECK_ENDIAN__
+subdir-ccflags-$(CONFIG_ARINC429_DEBUG_DEVICES) += -DDEBUG
diff --git a/drivers/net/arinc429/dev.c b/drivers/net/arinc429/dev.c
new file mode 100644
index 0000000..0debeec
--- /dev/null
+++ b/drivers/net/arinc429/dev.c
@@ -0,0 +1,448 @@ 
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/arinc429.h>
+#include <linux/arinc429/dev.h>
+#include <linux/arinc429/skb.h>
+#include <linux/arinc429/netlink.h>
+#include <net/rtnetlink.h>
+
+#define MOD_DESC "ARINC429 device driver interface"
+
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+
+/*
+ * Local echo of ARINC429 messages
+ *
+ * ARINC429 network devices *should* support a local echo functionality
+ * (see Documentation/networking/can.txt). To test the handling of ARINC429
+ * interfaces that do not support the local echo both driver types are
+ * implemented. In the case that the driver does not support the echo
+ * the IFF_ECHO remains clear in dev->flags. This causes the PF_ARINC429 core
+ * to perform the echo as a fallback solution.
+ */
+static void arinc429_flush_echo_skb(struct net_device *dev)
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	int i;
+
+	for (i = 0; i < priv->echo_skb_max; i++) {
+		if (priv->echo_skb[i]) {
+			kfree_skb(priv->echo_skb[i]);
+			priv->echo_skb[i] = NULL;
+			stats->tx_dropped++;
+			stats->tx_aborted_errors++;
+		}
+	}
+}
+
+/*
+ * Put the skb on the stack to be looped backed locally lateron
+ *
+ * The function is typically called in the start_xmit function
+ * of the device driver. The driver must protect access to
+ * priv->echo_skb, if necessary.
+ */
+void arinc429_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
+			   unsigned int idx)
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+
+	BUG_ON(idx >= priv->echo_skb_max);
+
+	/* check flag whether this packet has to be looped back */
+	if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
+	    skb->protocol != htons(ETH_P_ARINC429)) {
+		kfree_skb(skb);
+		return;
+	}
+
+	if (!priv->echo_skb[idx]) {
+		skb = arinc429_create_echo_skb(skb);
+		if (!skb)
+			return;
+
+		/* make settings for echo to reduce code in irq context */
+		skb->pkt_type = PACKET_BROADCAST;
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		skb->dev = dev;
+
+		/* save this skb for tx interrupt echo handling */
+		priv->echo_skb[idx] = skb;
+	} else {
+		/* locking problem with netif_stop_queue() ?? */
+		netdev_err(dev, "%s: BUG! echo_skb is occupied!\n", __func__);
+		kfree_skb(skb);
+	}
+}
+EXPORT_SYMBOL_GPL(arinc429_put_echo_skb);
+
+/*
+ * Get the skb from the stack and loop it back locally
+ *
+ * The function is typically called when the TX done interrupt
+ * is handled in the device driver. The driver must protect
+ * access to priv->echo_skb, if necessary.
+ */
+unsigned int arinc429_get_echo_skb(struct net_device *dev, unsigned int idx)
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+
+	BUG_ON(idx >= priv->echo_skb_max);
+
+	if (priv->echo_skb[idx]) {
+		struct sk_buff *skb = priv->echo_skb[idx];
+
+		if (!(skb->tstamp.tv64))
+			__net_timestamp(skb);
+
+		netif_rx(priv->echo_skb[idx]);
+		priv->echo_skb[idx] = NULL;
+
+		return ARINC429_MTU;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arinc429_get_echo_skb);
+
+/*
+  * Remove the skb from the stack and free it.
+  *
+  * The function is typically called when TX failed.
+  */
+void arinc429_free_echo_skb(struct net_device *dev, unsigned int idx)
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+
+	BUG_ON(idx >= priv->echo_skb_max);
+
+	if (priv->echo_skb[idx]) {
+		dev_kfree_skb_any(priv->echo_skb[idx]);
+		priv->echo_skb[idx] = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(arinc429_free_echo_skb);
+
+static void arinc429_setup(struct net_device *dev)
+{
+	dev->type = ARPHRD_ARINC429;
+	dev->mtu = ARINC429_MTU;
+	dev->hard_header_len = 0;
+	dev->addr_len = 0;
+	dev->tx_queue_len = 10;
+
+	/* New-style flags. */
+	dev->flags = IFF_NOARP;
+	dev->features = NETIF_F_HW_CSUM;
+}
+
+struct sk_buff *alloc_arinc429_skb(struct net_device *dev,
+				   struct arinc429_frame **cf)
+{
+	struct sk_buff *skb;
+
+	skb = netdev_alloc_skb(dev, sizeof(struct arinc429_skb_priv) +
+			       sizeof(struct arinc429_frame));
+	if (unlikely(!skb))
+		return NULL;
+
+	__net_timestamp(skb);
+	skb->protocol = htons(ETH_P_ARINC429);
+	skb->pkt_type = PACKET_BROADCAST;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+
+	arinc429_skb_reserve(skb);
+	arinc429_skb_prv(skb)->ifindex = dev->ifindex;
+
+	*cf = (struct arinc429_frame *)skb_put(skb,
+					       sizeof(struct arinc429_frame));
+	memset(*cf, 0, sizeof(struct arinc429_frame));
+
+	return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_arinc429_skb);
+
+/*
+ * Allocate and setup space for the ARINC429 network device
+ */
+struct net_device *alloc_arinc429dev(int sizeof_priv, unsigned int echo_skb_max)
+{
+	struct net_device *dev;
+	struct arinc429_priv *priv;
+	int size;
+
+	if (echo_skb_max)
+		size = ALIGN(sizeof_priv, sizeof(struct sk_buff *)) +
+			echo_skb_max * sizeof(struct sk_buff *);
+	else
+		size = sizeof_priv;
+
+	dev = alloc_netdev(size, "arinc429-%d", NET_NAME_UNKNOWN,
+			   arinc429_setup);
+	if (!dev)
+		return NULL;
+
+	priv = netdev_priv(dev);
+
+	if (echo_skb_max) {
+		priv->echo_skb_max = echo_skb_max;
+		priv->echo_skb = (void *)priv +
+			ALIGN(sizeof_priv, sizeof(struct sk_buff *));
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_arinc429dev);
+
+/*
+ * Free space of the ARINC429 network device
+ */
+void free_arinc429dev(struct net_device *dev)
+{
+	free_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(free_arinc429dev);
+
+/*
+ * changing MTU and control mode for ARINC429 devices
+ */
+int arinc429_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* Do not allow changing the MTU while running */
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	if (new_mtu != ARINC429_MTU)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arinc429_change_mtu);
+
+/*
+ * Common open function when the device gets opened.
+ *
+ * This function should be called in the open function of the device
+ * driver.
+ */
+int open_arinc429dev(struct net_device *dev)
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+
+	if (!priv->rate.rx_rate || !priv->rate.tx_rate) {
+		netdev_err(dev, "data rate not yet defined\n");
+		return -EINVAL;
+	}
+
+	/* Switch carrier on if device was stopped while in bus-off state */
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(open_arinc429dev);
+
+/*
+ * Common close function for cleanup before the device gets closed.
+ *
+ * This function should be called in the close function of the device
+ * driver.
+ */
+void close_arinc429dev(struct net_device *dev)
+{
+	arinc429_flush_echo_skb(dev);
+}
+EXPORT_SYMBOL_GPL(close_arinc429dev);
+
+/*
+ * ARINC429 netlink interface
+ */
+static const struct nla_policy arinc429_policy[IFLA_ARINC429_MAX + 1] = {
+	[IFLA_ARINC429_RATE]	= { .len = sizeof(struct arinc429_rate) },
+	[IFLA_ARINC429_CTRLMODE] = { .len = sizeof(struct arinc429_ctrlmode) },
+};
+
+static int arinc429_changelink(struct net_device *dev,
+			       struct nlattr *tb[], struct nlattr *data[])
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+	int err;
+
+	/* We need synchronization with dev->stop() */
+	ASSERT_RTNL();
+
+	if (data[IFLA_ARINC429_RATE]) {
+		struct arinc429_rate clk;
+
+		/* Do not allow changing clock while running */
+		if (dev->flags & IFF_UP)
+			return -EBUSY;
+
+		/*
+		 * Check if the clock frequency is valid, ARINC429
+		 * supports either 12.5kHz bus (Low speed bus mode)
+		 * or 100kHz (High speed bus mode). If the speed is
+		 * set to 0, do not modify that configuration.
+		 */
+		memcpy(&clk, nla_data(data[IFLA_ARINC429_RATE]), sizeof(clk));
+		if (clk.rx_rate && clk.rx_rate != 12500 &&
+		    clk.rx_rate != 100000)
+			return -EINVAL;
+		if (clk.tx_rate && clk.tx_rate != 12500 &&
+		    clk.tx_rate != 100000)
+			return -EINVAL;
+
+		memcpy(&priv->rate, &clk, sizeof(clk));
+
+		if (priv->do_set_rate) {
+			/* Finally, set the data rate register */
+			err = priv->do_set_rate(dev);
+			if (err)
+				return err;
+		}
+	}
+
+	if (data[IFLA_ARINC429_CTRLMODE]) {
+		struct arinc429_ctrlmode *cm;
+
+		/* Do not allow changing controller mode while running */
+		if (dev->flags & IFF_UP)
+			return -EBUSY;
+		cm = nla_data(data[IFLA_ARINC429_CTRLMODE]);
+
+		/* check whether changed bits are allowed to be modified */
+		if (cm->mask & ~priv->ctrlmode_supported)
+			return -EOPNOTSUPP;
+
+		/* clear bits to be modified and copy the flag values */
+		priv->ctrlmode &= ~cm->mask;
+		priv->ctrlmode |= (cm->flags & cm->mask);
+	}
+
+	return 0;
+}
+
+static size_t arinc429_get_size(const struct net_device *dev)
+{
+	size_t size = 0;
+
+	/* IFLA_ARINC429_RATE */
+	size += nla_total_size(sizeof(struct arinc429_rate));
+	/* IFLA_ARINC429_CTRLMODE */
+	size += nla_total_size(sizeof(struct arinc429_ctrlmode));
+
+	return size;
+}
+
+static int arinc429_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct arinc429_priv *priv = netdev_priv(dev);
+	struct arinc429_ctrlmode cm = {.flags = priv->ctrlmode};
+
+	if (
+		nla_put(skb, IFLA_ARINC429_RATE, sizeof(priv->rate), &priv->rate) ||
+		nla_put(skb, IFLA_ARINC429_CTRLMODE, sizeof(cm), &cm)
+	)
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int arinc429_newlink(struct net *src_net, struct net_device *dev,
+			    struct nlattr *tb[], struct nlattr *data[])
+{
+	return -EOPNOTSUPP;
+}
+
+static struct rtnl_link_ops arinc429_link_ops __read_mostly = {
+	.kind		= "arinc429",
+	.maxtype	= IFLA_ARINC429_MAX,
+	.policy		= arinc429_policy,
+	.setup		= arinc429_setup,
+	.newlink	= arinc429_newlink,
+	.changelink	= arinc429_changelink,
+	.get_size	= arinc429_get_size,
+	.fill_info	= arinc429_fill_info,
+};
+
+/*
+ * Register the ARINC429 network device
+ */
+int register_arinc429dev(struct net_device *dev)
+{
+	dev->rtnl_link_ops = &arinc429_link_ops;
+	return register_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(register_arinc429dev);
+
+/*
+ * Unregister the ARINC429 network device
+ */
+void unregister_arinc429dev(struct net_device *dev)
+{
+	unregister_netdev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_arinc429dev);
+
+/*
+ * Test if a network device is a arinc429dev based device
+ * and return the arinc429_priv* if so.
+ */
+struct arinc429_priv *safe_arinc429dev_priv(struct net_device *dev)
+{
+	if ((dev->type != ARPHRD_ARINC429) ||
+	    (dev->rtnl_link_ops != &arinc429_link_ops))
+		return NULL;
+
+	return netdev_priv(dev);
+}
+EXPORT_SYMBOL_GPL(safe_arinc429dev_priv);
+
+static __init int arinc429_dev_init(void)
+{
+	int err;
+
+	err = rtnl_link_register(&arinc429_link_ops);
+	if (!err)
+		pr_info(MOD_DESC "\n");
+
+	return err;
+}
+module_init(arinc429_dev_init);
+
+static __exit void arinc429_dev_exit(void)
+{
+	rtnl_link_unregister(&arinc429_link_ops);
+}
+module_exit(arinc429_dev_exit);
+
+MODULE_ALIAS_RTNL_LINK("arinc429");
diff --git a/drivers/net/arinc429/varinc429.c b/drivers/net/arinc429/varinc429.c
new file mode 100644
index 0000000..775ae48
--- /dev/null
+++ b/drivers/net/arinc429/varinc429.c
@@ -0,0 +1,163 @@ 
+/*
+ * varinc429.c - Virtual ARINC429 interface
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/arinc429.h>
+#include <linux/arinc429/dev.h>
+#include <linux/arinc429/skb.h>
+#include <linux/slab.h>
+#include <net/rtnetlink.h>
+
+MODULE_DESCRIPTION("Virtual ARINC429 interface");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+
+/*
+ * ARINC429 test feature:
+ * Enable the echo on driver level for testing the ARINC429 core echo modes.
+ */
+
+static bool echo; /* echo testing. Default: 0 (Off) */
+module_param(echo, bool, S_IRUGO);
+MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
+
+static void varinc429_rx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_device_stats *stats = &dev->stats;
+
+	stats->rx_packets++;
+	stats->rx_bytes += ARINC429_MTU;
+
+	skb->pkt_type  = PACKET_BROADCAST;
+	skb->dev       = dev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	if (!(skb->tstamp.tv64))
+		__net_timestamp(skb);
+
+	netif_rx_ni(skb);
+}
+
+static netdev_tx_t varinc429_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_device_stats *stats = &dev->stats;
+	int loop;
+
+	if (arinc429_dropped_invalid_skb(dev, skb))
+		return NETDEV_TX_OK;
+
+	stats->tx_packets++;
+	stats->tx_bytes += ARINC429_MTU;
+
+	/* set flag whether this packet has to be looped back */
+	loop = skb->pkt_type == PACKET_LOOPBACK;
+
+	if (!echo) {
+		/* no echo handling available inside this driver */
+
+		if (loop) {
+			/*
+			 * Only count the packets here, because the
+			 * ARINC429 core already did the echo for us
+			 */
+			stats->rx_packets++;
+			stats->rx_bytes += ARINC429_MTU;
+		}
+		consume_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* Perform standard echo handling for ARINC429 network interfaces */
+	if (loop) {
+		skb = arinc429_create_echo_skb(skb);
+		if (!skb)
+			return NETDEV_TX_OK;
+
+		/* Receive with packet counting */
+		varinc429_rx(skb, dev);
+	} else {
+		/* No looped packets => no counting */
+		consume_skb(skb);
+	}
+	return NETDEV_TX_OK;
+}
+
+static int varinc429_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* Do not allow changing the MTU while running */
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	if (new_mtu != ARINC429_MTU)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static const struct net_device_ops varinc429_netdev_ops = {
+	.ndo_start_xmit = varinc429_tx,
+	.ndo_change_mtu = varinc429_change_mtu,
+};
+
+static void varinc429_setup(struct net_device *dev)
+{
+	dev->type		= ARPHRD_ARINC429;
+	dev->mtu		= ARINC429_MTU;
+	dev->hard_header_len	= 0;
+	dev->addr_len		= 0;
+	dev->tx_queue_len	= 0;
+	dev->flags		= IFF_NOARP;
+
+	/* set flags according to driver capabilities */
+	if (echo)
+		dev->flags |= IFF_ECHO;
+
+	dev->netdev_ops		= &varinc429_netdev_ops;
+	dev->destructor		= free_netdev;
+}
+
+static struct rtnl_link_ops varinc429_link_ops __read_mostly = {
+	.kind	= "varinc429",
+	.setup	= varinc429_setup,
+};
+
+static __init int varinc429_init_module(void)
+{
+	pr_info("varinc429: Virtual ARINC429 interface driver\n");
+
+	if (echo)
+		pr_info("varinc429: enabled echo on driver level.\n");
+
+	return rtnl_link_register(&varinc429_link_ops);
+}
+
+static __exit void varinc429_cleanup_module(void)
+{
+	rtnl_link_unregister(&varinc429_link_ops);
+}
+
+module_init(varinc429_init_module);
+module_exit(varinc429_cleanup_module);
diff --git a/include/linux/arinc429/core.h b/include/linux/arinc429/core.h
new file mode 100644
index 0000000..2e32858
--- /dev/null
+++ b/include/linux/arinc429/core.h
@@ -0,0 +1,61 @@ 
+/*
+ * linux/arinc429/core.h
+ *
+ * Protoypes and definitions for ARINC429 protocol modules
+ * using the PF_ARINC429 core.
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ */
+
+#ifndef __ARINC429_CORE_H__
+#define __ARINC429_CORE_H__
+
+#include <linux/arinc429.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#define ARINC429_VERSION "20151101"
+
+/* Increment this number each time you change some user-space interface */
+#define ARINC429_ABI_VERSION "1"
+
+#define ARINC429_VERSION_STRING		\
+	"rev " ARINC429_VERSION " abi " ARINC429_ABI_VERSION
+
+#define DNAME(dev) ((dev) ? (dev)->name : "any")
+
+/**
+ * struct arinc429_proto - ARINC429 protocol structure
+ * @type:       type argument in socket() syscall, e.g. SOCK_DGRAM.
+ * @protocol:   protocol number in socket() syscall.
+ * @ops:        pointer to struct proto_ops for sock->ops.
+ * @prot:       pointer to struct proto structure.
+ */
+struct arinc429_proto {
+	int			type;
+	int			protocol;
+	const struct proto_ops	*ops;
+	struct proto		*prot;
+};
+
+/* Function prototypes for the ARINC429 network layer core (af_arinc429.c) */
+extern int  arinc429_proto_register(const struct arinc429_proto *cp);
+extern void arinc429_proto_unregister(const struct arinc429_proto *cp);
+
+extern int  arinc429_rx_register(struct net_device *dev,
+				 struct arinc429_filter *filter,
+				 void (*func)(struct sk_buff *, void *),
+				 void *data, char *ident);
+
+extern void arinc429_rx_unregister(struct net_device *dev,
+				   struct arinc429_filter *filter,
+				   void (*func)(struct sk_buff *, void *),
+				   void *data);
+
+extern int arinc429_send(struct sk_buff *skb, int loop);
+extern int arinc429_ioctl(struct socket *sock, unsigned int cmd,
+			  unsigned long arg);
+
+#endif /* __ARINC429_CORE_H__ */
diff --git a/include/linux/arinc429/dev.h b/include/linux/arinc429/dev.h
new file mode 100644
index 0000000..e496fbf
--- /dev/null
+++ b/include/linux/arinc429/dev.h
@@ -0,0 +1,81 @@ 
+/*
+ * linux/arinc429/dev.h
+ *
+ * Definitions for the ARINC429 network device driver interface
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ */
+
+#ifndef __ARINC429_DEV_H__
+#define __ARINC429_DEV_H__
+
+#include <linux/arinc429.h>
+#include <linux/arinc429/netlink.h>
+
+/*
+ * ARINC429 mode
+ */
+enum arinc429_mode {
+	ARINC429_MODE_STOP = 0,
+	ARINC429_MODE_START,
+	ARINC429_MODE_SLEEP
+};
+
+/*
+ * ARINC429 common private data
+ */
+struct arinc429_priv {
+	struct arinc429_rate rate;
+	u32 ctrlmode;
+	u32 ctrlmode_supported;
+
+	int (*do_set_rate)(struct net_device *dev);
+	int (*do_set_mode)(struct net_device *dev, enum arinc429_mode mode);
+
+	unsigned int echo_skb_max;
+	struct sk_buff **echo_skb;
+};
+
+/* Drop a given socketbuffer if it does not contain a valid ARINC429 frame. */
+static inline int arinc429_dropped_invalid_skb(struct net_device *dev,
+					       struct sk_buff *skb)
+{
+	if (skb->protocol == htons(ETH_P_ARINC429)) {
+		if (unlikely(skb->len != ARINC429_MTU))
+			goto inval_skb;
+	} else
+		goto inval_skb;
+
+	return 0;
+
+inval_skb:
+	kfree_skb(skb);
+	dev->stats.tx_dropped++;
+	return 1;
+}
+
+struct net_device *alloc_arinc429dev(int sizeof_priv,
+				     unsigned int echo_skb_max);
+void free_arinc429dev(struct net_device *dev);
+
+/* a arinc429dev safe wrapper around netdev_priv */
+struct arinc429_priv *safe_arinc429dev_priv(struct net_device *dev);
+
+int open_arinc429dev(struct net_device *dev);
+void close_arinc429dev(struct net_device *dev);
+int arinc429_change_mtu(struct net_device *dev, int new_mtu);
+
+int register_arinc429dev(struct net_device *dev);
+void unregister_arinc429dev(struct net_device *dev);
+
+void arinc429_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
+		      unsigned int idx);
+unsigned int arinc429_get_echo_skb(struct net_device *dev, unsigned int idx);
+void arinc429_free_echo_skb(struct net_device *dev, unsigned int idx);
+
+struct sk_buff *alloc_arinc429_skb(struct net_device *dev,
+				   struct arinc429_frame **cf);
+
+#endif /* __ARINC429_DEV_H__ */
diff --git a/include/linux/arinc429/skb.h b/include/linux/arinc429/skb.h
new file mode 100644
index 0000000..20b76b5
--- /dev/null
+++ b/include/linux/arinc429/skb.h
@@ -0,0 +1,79 @@ 
+/*
+ * linux/arinc429/skb.h
+ *
+ * Definitions for the ARINC429 network socket buffer
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ */
+
+#ifndef __ARINC429_SKB_H__
+#define __ARINC429_SKB_H__
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/arinc429.h>
+#include <net/sock.h>
+
+/*
+ * The struct arinc429_skb_priv is used to transport additional information
+ * along with the stored struct arinc429(fd)_frame that arinc429 not be
+ * contained in existing struct sk_buff elements.
+ * N.B. that this information must not be modified in cloned ARINC429 sk_buffs.
+ * To modify the ARINC429 frame content or the struct arinc429_skb_priv content
+ * skb_copy() needs to be used instead of skb_clone().
+ */
+
+/**
+ * struct arinc429_skb_priv - private additional data inside ARINC429 sk_buffs
+ * @ifindex:	ifindex of the first interface the ARINC429 frame appeared on
+ * @cf:		align to the following ARINC429 frame at skb->data
+ */
+struct arinc429_skb_priv {
+	int			ifindex;
+	struct arinc429_frame	af[0];
+};
+
+static inline struct arinc429_skb_priv *arinc429_skb_prv(struct sk_buff *skb)
+{
+	return (struct arinc429_skb_priv *)(skb->head);
+}
+
+static inline void arinc429_skb_reserve(struct sk_buff *skb)
+{
+	skb_reserve(skb, sizeof(struct arinc429_skb_priv));
+}
+
+static inline void arinc429_skb_set_owner(struct sk_buff *skb, struct sock *sk)
+{
+	if (sk) {
+		sock_hold(sk);
+		skb->destructor = sock_efree;
+		skb->sk = sk;
+	}
+}
+
+/*
+ * returns an unshared skb owned by the original sock to be echo'ed back
+ */
+static inline struct sk_buff *arinc429_create_echo_skb(struct sk_buff *skb)
+{
+	if (skb_shared(skb)) {
+		struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+		if (likely(nskb)) {
+			arinc429_skb_set_owner(nskb, skb->sk);
+			consume_skb(skb);
+			return nskb;
+		}
+
+		kfree_skb(skb);
+		return NULL;
+	}
+
+	/* we can assume to have an unshared skb with proper owner */
+	return skb;
+}
+
+#endif /* __ARINC429_SKB_H__ */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 5bf59c8..627d4af 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -200,7 +200,8 @@  struct ucred {
 #define AF_ALG		38	/* Algorithm sockets		*/
 #define AF_NFC		39	/* NFC sockets			*/
 #define AF_VSOCK	40	/* vSockets			*/
-#define AF_MAX		41	/* For now.. */
+#define AF_ARINC429	41	/* ARINC429			*/
+#define AF_MAX		42	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -246,6 +247,7 @@  struct ucred {
 #define PF_ALG		AF_ALG
 #define PF_NFC		AF_NFC
 #define PF_VSOCK	AF_VSOCK
+#define PF_ARINC429	AF_ARINC429
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff --git a/include/uapi/linux/arinc429.h b/include/uapi/linux/arinc429.h
new file mode 100644
index 0000000..0cd5151
--- /dev/null
+++ b/include/uapi/linux/arinc429.h
@@ -0,0 +1,88 @@ 
+/*
+ * linux/arinc429.h
+ *
+ * Definitions for ARINC429 network layer
+ * (socket addr / ARINC429 frame / ARINC429 filter)
+ *
+ * * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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 __UAPI_ARINC429_H__
+#define __UAPI_ARINC429_H__
+
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/* ARINC429 kernel definitions */
+
+/*
+ * ARINC packet:
+ *
+ * .-.---.------.---.-----.
+ * |P|SSM| Data |SDI|Label|
+ * '-'---'------'---'-----'
+ *  3 3 2 2....1 1 9 8...0
+ *  1 0 9 8    1 0
+ */
+
+/**
+ * struct arinc429_frame - basic ARINC429 frame structure
+ * @label:	ARINC429 label
+ * @data:	ARINC429 P, SSM, DATA and SDI
+ */
+struct arinc429_frame {
+	__u8	label;		/* 8 bit label */
+	__u8	data[3];	/* Up-to 23 bits are valid. */
+};
+
+#define ARINC429_MTU		(sizeof(struct arinc429_frame))
+
+/* particular protocols of the protocol family PF_ARINC429 */
+#define ARINC429_RAW		1 /* RAW sockets */
+#define ARINC429_NPROTO		2
+
+#define SOL_ARINC429_BASE	100
+
+/**
+ * struct sockaddr_arinc429 - the sockaddr structure for ARINC429 sockets
+ * @arinc429_family:	address family number AF_ARINC429.
+ * @arinc429_ifindex:	ARINC429 network interface index.
+ * @arinc429_addr:	protocol specific address information
+ */
+struct sockaddr_arinc429 {
+	__kernel_sa_family_t arinc429_family;
+	int         arinc429_ifindex;
+	union {
+		/* reserved for future ARINC429 protocols address information */
+	} arinc429_addr;
+};
+
+/**
+ * struct arinc429_filter - ARINC429 ID based filter in arinc429_register().
+ * @arinc429_label: relevant bits of ARINC429 ID which are not masked out.
+ * @arinc429_mask:  ARINC429 mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *          <received_arinc429_id> & mask == arinc429_id & mask
+ */
+struct arinc429_filter {
+	__u8	label;		/* 8 bit label */
+	__u8	mask;		/* 8 bit label mask */
+#define ARINC429_INV_FILTER	0x00000001
+	__u32	flags;		/* Flags */
+};
+
+#endif /* __UAPI_ARINC429_H__ */
diff --git a/include/uapi/linux/arinc429/Kbuild b/include/uapi/linux/arinc429/Kbuild
new file mode 100644
index 0000000..21c91bf
--- /dev/null
+++ b/include/uapi/linux/arinc429/Kbuild
@@ -0,0 +1,6 @@ 
+# UAPI Header export list
+header-y += bcm.h
+header-y += error.h
+header-y += gw.h
+header-y += netlink.h
+header-y += raw.h
diff --git a/include/uapi/linux/arinc429/netlink.h b/include/uapi/linux/arinc429/netlink.h
new file mode 100644
index 0000000..5d2f48b
--- /dev/null
+++ b/include/uapi/linux/arinc429/netlink.h
@@ -0,0 +1,55 @@ 
+/*
+ * linux/arinc429/netlink.h
+ *
+ * Definitions for the ARINC429 netlink interface
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketARINC429 stack.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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 _UAPI_ARINC429_NETLINK_H
+#define _UAPI_ARINC429_NETLINK_H
+
+#include <linux/types.h>
+
+/*
+ * ARINC429 data rate parameters
+ */
+struct arinc429_rate {
+	__u32 rx_rate;		/* ARINC429 bus RX rate [Hz] */
+	__u32 tx_rate;		/* ARINC429 bus TX rate [Hz] */
+};
+
+/*
+ * ARINC429 controller mode
+ */
+struct arinc429_ctrlmode {
+	__u32 mask;
+	__u32 flags;
+};
+
+#define ARINC429_CTRLMODE_LOOPBACK	0x01	/* Loopback mode */
+
+/*
+ * ARINC429 netlink interface
+ */
+enum {
+	IFLA_ARINC429_UNSPEC,
+	IFLA_ARINC429_RATE,
+	IFLA_ARINC429_CTRLMODE,
+	__IFLA_ARINC429_MAX
+};
+
+#define IFLA_ARINC429_MAX	(__IFLA_ARINC429_MAX - 1)
+
+#endif /* !_UAPI_ARINC429_NETLINK_H */
diff --git a/include/uapi/linux/arinc429/raw.h b/include/uapi/linux/arinc429/raw.h
new file mode 100644
index 0000000..e951148
--- /dev/null
+++ b/include/uapi/linux/arinc429/raw.h
@@ -0,0 +1,36 @@ 
+/*
+ * linux/arinc429/raw.h
+ *
+ * Definitions for raw ARINC429 sockets
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * 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 _UAPI_ARINC429_RAW_H
+#define _UAPI_ARINC429_RAW_H
+
+#include <linux/arinc429.h>
+
+#define SOL_ARINC429_RAW (SOL_ARINC429_BASE + ARINC429_RAW)
+
+/* for socket options affecting the socket (not the global system) */
+
+enum {
+	ARINC429_RAW_FILTER = 1,	/* set 0 .. n arinc429_filter(s)     */
+	ARINC429_RAW_LOOPBACK,		/* local loopback (default:on)       */
+	ARINC429_RAW_RECV_OWN_MSGS,	/* receive my own msgs (default:off) */
+	ARINC429_RAW_JOIN_FILTERS,	/* all filters must match to trigger */
+};
+
+#endif /* !_UAPI_ARINC429_RAW_H */
diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h
index 4d024d7..3457947 100644
--- a/include/uapi/linux/if_arp.h
+++ b/include/uapi/linux/if_arp.h
@@ -53,6 +53,7 @@ 
 #define ARPHRD_X25	271		/* CCITT X.25			*/
 #define ARPHRD_HWX25	272		/* Boards with X.25 in firmware	*/
 #define ARPHRD_CAN	280		/* Controller Area Network      */
+#define ARPHRD_ARINC429	281		/* ARINC429			*/
 #define ARPHRD_PPP	512
 #define ARPHRD_CISCO	513		/* Cisco HDLC	 		*/
 #define ARPHRD_HDLC	ARPHRD_CISCO
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index ea9221b..8bbe328 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -126,6 +126,7 @@ 
 #define ETH_P_ARCNET	0x001A		/* 1A for ArcNet :-)            */
 #define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
 #define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
+#define ETH_P_ARINC429	0x001D		/* ARINC429			*/
 #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
 #define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/
diff --git a/net/Kconfig b/net/Kconfig
index 7021c1b..ec5efaa 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -345,6 +345,7 @@  endmenu
 
 endmenu
 
+source "net/arinc429/Kconfig"
 source "net/ax25/Kconfig"
 source "net/can/Kconfig"
 source "net/irda/Kconfig"
diff --git a/net/Makefile b/net/Makefile
index 3995613..b3ee049 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -28,6 +28,7 @@  obj-$(CONFIG_X25)		+= x25/
 obj-$(CONFIG_LAPB)		+= lapb/
 obj-$(CONFIG_NETROM)		+= netrom/
 obj-$(CONFIG_ROSE)		+= rose/
+obj-$(CONFIG_ARINC429)		+= arinc429/
 obj-$(CONFIG_AX25)		+= ax25/
 obj-$(CONFIG_CAN)		+= can/
 obj-$(CONFIG_IRDA)		+= irda/
diff --git a/net/arinc429/Kconfig b/net/arinc429/Kconfig
new file mode 100644
index 0000000..2952123
--- /dev/null
+++ b/net/arinc429/Kconfig
@@ -0,0 +1,31 @@ 
+#
+# ARINC429 network layer core configuration
+#
+
+menuconfig ARINC429
+	depends on NET
+	tristate "ARINC429 bus subsystem support"
+	---help---
+	  ARINC429 is a slow communication protocol used in avionics.
+	  More information on the ARINC429 protocol family PF_ARINC429
+	  is contained in <Documentation/networking/arinc429.txt>.
+
+	  If you want ARINC429 support you should say Y here and also to
+	  the specific driver for your controller(s) below.
+
+if ARINC429
+
+config ARINC429_RAW
+	tristate "Raw ARINC429 Protocol"
+	default y
+	---help---
+	  The raw ARINC429 protocol option offers access to the ARINC429
+	  bus via the BSD socket API. You probably want to use the raw
+	  socket in most cases where no higher level protocol is being
+	  used. The raw socket has several filter options e.g. ID masking
+	  / error frames. To receive/send raw ARINC429 messages, use AF_ARINC429
+	  with protocol ARINC429_RAW.
+
+source "drivers/net/arinc429/Kconfig"
+
+endif
diff --git a/net/arinc429/Makefile b/net/arinc429/Makefile
new file mode 100644
index 0000000..f444729
--- /dev/null
+++ b/net/arinc429/Makefile
@@ -0,0 +1,9 @@ 
+#
+#  Makefile for the Linux Controller Area Network core.
+#
+
+obj-$(CONFIG_ARINC429)		+= arinc429.o
+arinc429-y			:= af_arinc429.o proc.o
+
+obj-$(CONFIG_ARINC429_RAW)	+= arinc429-raw.o
+arinc429-raw-y			:= raw.o
diff --git a/net/arinc429/af_arinc429.c b/net/arinc429/af_arinc429.c
new file mode 100644
index 0000000..39c8d0a
--- /dev/null
+++ b/net/arinc429/af_arinc429.c
@@ -0,0 +1,812 @@ 
+/*
+ * af_arinc429.c - Protocol family ARINC429 core module
+ *                 (used by different ARINC429 protocol modules)
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/uaccess.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/socket.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/arinc429.h>
+#include <linux/arinc429/core.h>
+#include <linux/arinc429/skb.h>
+#include <linux/ratelimit.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+
+#include "af_arinc429.h"
+
+MODULE_DESCRIPTION("ARINC429 PF_ARINC429 core");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+
+MODULE_ALIAS_NETPROTO(PF_ARINC429);
+
+/* receive filters subscribed for 'all' ARINC429 devices */
+struct dev_rcv_lists arinc429_rx_alldev_list;
+static DEFINE_SPINLOCK(arinc429_rcvlists_lock);
+
+static struct kmem_cache *rcv_cache __read_mostly;
+
+/* table of registered ARINC429 protocols */
+static const struct arinc429_proto *proto_tab[ARINC429_NPROTO] __read_mostly;
+static DEFINE_MUTEX(proto_tab_lock);
+
+struct timer_list arinc429_stattimer;   /* timer for statistics update */
+struct s_stats    arinc429_stats;       /* packet statistics */
+struct s_pstats   arinc429_pstats;      /* receive list statistics */
+
+/*
+ * af_arinc429 socket functions
+ */
+
+int arinc429_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+
+	switch (cmd) {
+	case SIOCGSTAMP:
+		return sock_get_timestamp(sk, (struct timeval __user *)arg);
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+EXPORT_SYMBOL(arinc429_ioctl);
+
+static void arinc429_sock_destruct(struct sock *sk)
+{
+	skb_queue_purge(&sk->sk_receive_queue);
+}
+
+static const struct arinc429_proto *arinc429_get_proto(int protocol)
+{
+	const struct arinc429_proto *cp;
+
+	rcu_read_lock();
+	cp = rcu_dereference(proto_tab[protocol]);
+	if (cp && !try_module_get(cp->prot->owner))
+		cp = NULL;
+	rcu_read_unlock();
+
+	return cp;
+}
+
+static inline void arinc429_put_proto(const struct arinc429_proto *cp)
+{
+	module_put(cp->prot->owner);
+}
+
+static int arinc429_create(struct net *net, struct socket *sock, int protocol,
+			   int kern)
+{
+	struct sock *sk;
+	const struct arinc429_proto *cp;
+	int err = 0;
+
+	sock->state = SS_UNCONNECTED;
+
+	if (protocol < 0 || protocol >= ARINC429_NPROTO)
+		return -EINVAL;
+
+	if (!net_eq(net, &init_net))
+		return -EAFNOSUPPORT;
+
+	cp = arinc429_get_proto(protocol);
+
+#ifdef CONFIG_MODULES
+	if (!cp) {
+		/* Try to load protocol module if kernel is modular */
+		err = request_module("arinc429-proto-%d", protocol);
+
+		/*
+		 * In case of error we only print a message but don't
+		 * return the error code immediately.  Below we will
+		 * return -EPROTONOSUPPORT
+		 */
+		if (err) {
+			pr_err_ratelimited(
+				"arinc429: request_module (arinc429-proto-%d) failed.\n",
+				protocol);
+		}
+
+		cp = arinc429_get_proto(protocol);
+	}
+#endif
+
+	/* Check for available protocol and correct usage */
+	if (!cp)
+		return -EPROTONOSUPPORT;
+
+	if (cp->type != sock->type) {
+		err = -EPROTOTYPE;
+		goto errout;
+	}
+
+	sock->ops = cp->ops;
+
+	sk = sk_alloc(net, PF_ARINC429, GFP_KERNEL, cp->prot, kern);
+	if (!sk) {
+		err = -ENOMEM;
+		goto errout;
+	}
+
+	sock_init_data(sock, sk);
+	sk->sk_destruct = arinc429_sock_destruct;
+
+	if (sk->sk_prot->init)
+		err = sk->sk_prot->init(sk);
+
+	if (err) {
+		/* release sk on errors */
+		sock_orphan(sk);
+		sock_put(sk);
+	}
+
+ errout:
+	arinc429_put_proto(cp);
+	return err;
+}
+
+/*
+ * af_arinc429 tx path
+ */
+
+/**
+ * arinc429_send - transmit a ARINC429 frame (optional with local loopback)
+ * @skb: pointer to socket buffer with ARINC429 frame in data section
+ * @loop: loopback for listeners on local ARINC429 sockets
+ *        (recommended default!)
+ *
+ * Due to the loopback this routine must not be called from hardirq context.
+ *
+ * Return:
+ *  0 on success
+ *  -ENETDOWN when the selected interface is down
+ *  -ENOBUFS on full driver queue (see net_xmit_errno())
+ *  -ENOMEM when local loopback failed at calling skb_clone()
+ *  -EPERM when trying to send on a non-ARINC429 interface
+ *  -EMSGSIZE ARINC429 frame size is bigger than ARINC429 interface MTU
+ *  -EINVAL when the skb->data does not contain a valid ARINC429 frame
+ */
+int arinc429_send(struct sk_buff *skb, int loop)
+{
+	struct sk_buff *newskb = NULL;
+	int err = -EINVAL;
+
+	if (skb->len == ARINC429_MTU)
+		skb->protocol = htons(ETH_P_ARINC429);
+	else
+		goto inval_skb;
+
+	/*
+	 * Make sure the ARINC429 frame can pass the selected
+	 * ARINC429 netdevice.
+	 */
+	if (unlikely(skb->len > skb->dev->mtu)) {
+		err = -EMSGSIZE;
+		goto inval_skb;
+	}
+
+	if (unlikely(skb->dev->type != ARPHRD_ARINC429)) {
+		err = -EPERM;
+		goto inval_skb;
+	}
+
+	if (unlikely(!(skb->dev->flags & IFF_UP))) {
+		err = -ENETDOWN;
+		goto inval_skb;
+	}
+
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+
+	if (loop) {
+		/* local loopback of sent ARINC429 frames */
+
+		/* indication for the ARINC429 driver: do loopback */
+		skb->pkt_type = PACKET_LOOPBACK;
+
+		/*
+		 * The reference to the originating sock may be required
+		 * by the receiving socket to check whether the frame is
+		 * its own.
+		 * Example: arinc429_raw sockopt ARINC429_RAW_RECV_OWN_MSGS
+		 * Therefore we have to ensure that skb->sk remains the
+		 * reference to the originating sock by restoring skb->sk
+		 * after each skb_clone() or skb_orphan() usage.
+		 */
+
+		if (!(skb->dev->flags & IFF_ECHO)) {
+			/*
+			 * If the interface is not capable to do loopback
+			 * itself, we do it here.
+			 */
+			newskb = skb_clone(skb, GFP_ATOMIC);
+			if (!newskb) {
+				kfree_skb(skb);
+				return -ENOMEM;
+			}
+
+			arinc429_skb_set_owner(newskb, skb->sk);
+			newskb->ip_summed = CHECKSUM_UNNECESSARY;
+			newskb->pkt_type = PACKET_BROADCAST;
+		}
+	} else {
+		/* indication for the ARINC429 driver: no loopback required */
+		skb->pkt_type = PACKET_HOST;
+	}
+
+	/* send to netdevice */
+	err = dev_queue_xmit(skb);
+	if (err > 0)
+		err = net_xmit_errno(err);
+
+	if (err) {
+		kfree_skb(newskb);
+		return err;
+	}
+
+	if (newskb) {
+		if (!(newskb->tstamp.tv64))
+			__net_timestamp(newskb);
+
+		netif_rx_ni(newskb);
+	}
+
+	/* update statistics */
+	arinc429_stats.tx_frames++;
+	arinc429_stats.tx_frames_delta++;
+
+	return 0;
+
+inval_skb:
+	kfree_skb(skb);
+	return err;
+}
+EXPORT_SYMBOL(arinc429_send);
+
+/*
+ * af_arinc429 rx path
+ */
+
+static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
+{
+	if (!dev)
+		return &arinc429_rx_alldev_list;
+	else
+		return (struct dev_rcv_lists *)dev->ml_priv;
+}
+
+/**
+ * find_rcv_list - determine optimal filterlist inside device filter struct
+ * @label: pointer to ARINC429 identifier of a given arinc429_filter
+ * @mask: pointer to ARINC429 mask of a given arinc429_filter
+ * @inv: filter is inverted
+ * @d: pointer to the device filter struct
+ *
+ * Description:
+ *  Returns the optimal filterlist to reduce the filter handling in the
+ *  receive path. This function is called by service functions that need
+ *  to register or unregister a arinc429_filter in the filter lists.
+ *
+ *  A filter matches in general, when
+ *
+ *          <received_label> & mask == label & mask
+ *
+ *  The filter can be inverted (ARINC429_INV_FILTER bit set in label).
+ *
+ * Return:
+ *  Pointer to optimal filterlist for the given label/mask pair.
+ *  Constistency checked mask.
+ *  Reduced label to have a preprocessed filter compare value.
+ */
+static struct hlist_head *find_rcv_list(u8 *label, u8 *mask, const bool inv,
+					struct dev_rcv_lists *d)
+{
+	/* reduce condition testing at receive time */
+	*label &= *mask;
+
+	/* inverse label/can_mask filter */
+	if (inv)
+		return &d->rx[RX_INV];
+
+	/* mask == 0 => no condition testing at receive time */
+	if (!(*mask))
+		return &d->rx[RX_ALL];
+
+	/* default: filter via label/can_mask */
+	return &d->rx[RX_FIL];
+}
+
+/**
+ * arinc429_rx_register - subscribe ARINC429 frames from a specific interface
+ * @dev: pointer to netdevice (NULL => subscribe from 'all' devices list)
+ * @filter: ARINC429 filter (see description)
+ * @func: callback function on filter match
+ * @data: returned parameter for callback function
+ * @ident: string for calling module identification
+ *
+ * Description:
+ *  Invokes the callback function with the received sk_buff and the given
+ *  parameter 'data' on a matching receive filter. A filter matches, when
+ *
+ *          <received_arinc429_id> & mask == arinc429_id & mask
+ *
+ *  The filter can be inverted (ARINC429_INV_FILTER bit set in arinc429_id)
+ *  or it can filter for error message frames (ARINC429_ERR_FLAG bit set in
+ *  mask).
+ *
+ *  The provided pointer to the sk_buff is guaranteed to be valid as long as
+ *  the callback function is running. The callback function must *not* free
+ *  the given sk_buff while processing it's task. When the given sk_buff is
+ *  needed after the end of the callback function it must be cloned inside
+ *  the callback function with skb_clone().
+ *
+ * Return:
+ *  0 on success
+ *  -ENOMEM on missing cache mem to create subscription entry
+ *  -ENODEV unknown device
+ */
+int arinc429_rx_register(struct net_device *dev,
+			 struct arinc429_filter *filter,
+			 void (*func)(struct sk_buff *, void *), void *data,
+			 char *ident)
+{
+	struct receiver *r;
+	struct hlist_head *rl;
+	struct dev_rcv_lists *d;
+	int err = 0;
+	u8 label = filter->label;
+	u8 mask = filter->mask;
+	const bool inv = filter->flags & ARINC429_INV_FILTER;
+
+	/* insert new receiver  (dev,label,mask) -> (func,data) */
+
+	if (dev && dev->type != ARPHRD_ARINC429)
+		return -ENODEV;
+
+	r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
+	if (!r)
+		return -ENOMEM;
+
+	spin_lock(&arinc429_rcvlists_lock);
+
+	d = find_dev_rcv_lists(dev);
+	if (d) {
+		rl = find_rcv_list(&label, &mask, inv, d);
+
+		r->label   = label;
+		r->mask    = mask;
+		r->matches = 0;
+		r->func    = func;
+		r->data    = data;
+		r->ident   = ident;
+
+		hlist_add_head_rcu(&r->list, rl);
+		d->entries++;
+
+		arinc429_pstats.rcv_entries++;
+		if (arinc429_pstats.rcv_entries_max < arinc429_pstats.rcv_entries)
+			arinc429_pstats.rcv_entries_max = arinc429_pstats.rcv_entries;
+	} else {
+		kmem_cache_free(rcv_cache, r);
+		err = -ENODEV;
+	}
+
+	spin_unlock(&arinc429_rcvlists_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(arinc429_rx_register);
+
+/*
+ * arinc429_rx_delete_receiver - rcu callback for single receiver entry removal
+ */
+static void arinc429_rx_delete_receiver(struct rcu_head *rp)
+{
+	struct receiver *r = container_of(rp, struct receiver, rcu);
+
+	kmem_cache_free(rcv_cache, r);
+}
+
+/**
+ * arinc429_rx_unregister - unsubscribe ARINC429 frames from specific interface
+ * @dev: pointer to netdevice (NULL => unsubscribe from 'all' devices list)
+ * @filter: ARINC429 filter
+ * @func: callback function on filter match
+ * @data: returned parameter for callback function
+ *
+ * Description:
+ *  Removes subscription entry depending on given (subscription) values.
+ */
+void arinc429_rx_unregister(struct net_device *dev,
+			    struct arinc429_filter *filter,
+			    void (*func)(struct sk_buff *, void *),
+			    void *data)
+{
+	struct receiver *r = NULL;
+	struct hlist_head *rl;
+	struct dev_rcv_lists *d;
+	u8 label = filter->label;
+	u8 mask = filter->mask;
+	const bool inv = filter->flags & ARINC429_INV_FILTER;
+
+	if (dev && dev->type != ARPHRD_ARINC429)
+		return;
+
+	spin_lock(&arinc429_rcvlists_lock);
+
+	d = find_dev_rcv_lists(dev);
+	if (!d) {
+		pr_err("BUG: receive list not found for dev %s, label %02X, mask %02X\n",
+		       DNAME(dev), label, mask);
+		goto out;
+	}
+
+	rl = find_rcv_list(&label, &mask, inv, d);
+
+	/*
+	 * Search the receiver list for the item to delete.  This should
+	 * exist, since no receiver may be unregistered that hasn't
+	 * been registered before.
+	 */
+
+	hlist_for_each_entry_rcu(r, rl, list) {
+		if (r->label == label && r->mask == mask &&
+		    r->func == func && r->data == data)
+			break;
+	}
+
+	/*
+	 * Check for bugs in ARINC429 protocol implementations using af_arinc429.c:
+	 * 'r' will be NULL if no matching list item was found for removal.
+	 */
+
+	if (!r) {
+		WARN(1, "BUG: receive list entry not found for dev %s, id %02X, mask %02X\n",
+		     DNAME(dev), label, mask);
+		goto out;
+	}
+
+	hlist_del_rcu(&r->list);
+	d->entries--;
+
+	if (arinc429_pstats.rcv_entries > 0)
+		arinc429_pstats.rcv_entries--;
+
+	/* remove device structure requested by NETDEV_UNREGISTER */
+	if (d->remove_on_zero_entries && !d->entries) {
+		kfree(d);
+		dev->ml_priv = NULL;
+	}
+
+ out:
+	spin_unlock(&arinc429_rcvlists_lock);
+
+	/* schedule the receiver item for deletion */
+	if (r)
+		call_rcu(&r->rcu, arinc429_rx_delete_receiver);
+}
+EXPORT_SYMBOL(arinc429_rx_unregister);
+
+static inline void deliver(struct sk_buff *skb, struct receiver *r)
+{
+	r->func(skb, r->data);
+	r->matches++;
+}
+
+static unsigned int arinc429_rcv_filter(struct dev_rcv_lists *d,
+					struct sk_buff *skb)
+{
+	struct receiver *r;
+	unsigned int matches = 0;
+	struct arinc429_frame *af = (struct arinc429_frame *)skb->data;
+	__u8 label = af->label;
+
+	if (d->entries == 0)
+		return 0;
+
+	/* check for unfiltered entries */
+	hlist_for_each_entry_rcu(r, &d->rx[RX_ALL], list) {
+		deliver(skb, r);
+		matches++;
+	}
+
+	/* check for label/mask entries */
+	hlist_for_each_entry_rcu(r, &d->rx[RX_FIL], list) {
+		if ((label & r->mask) == r->label) {
+			deliver(skb, r);
+			matches++;
+		}
+	}
+
+	/* check for inverted label/mask entries */
+	hlist_for_each_entry_rcu(r, &d->rx[RX_INV], list) {
+		if ((label & r->mask) != r->label) {
+			deliver(skb, r);
+			matches++;
+		}
+	}
+
+	return matches;
+}
+
+static void arinc429_receive(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dev_rcv_lists *d;
+	unsigned int matches;
+
+	/* update statistics */
+	arinc429_stats.rx_frames++;
+	arinc429_stats.rx_frames_delta++;
+
+	rcu_read_lock();
+
+	/* deliver the packet to sockets listening on all devices */
+	matches = arinc429_rcv_filter(&arinc429_rx_alldev_list, skb);
+
+	/* find receive list for this device */
+	d = find_dev_rcv_lists(dev);
+	if (d)
+		matches += arinc429_rcv_filter(d, skb);
+
+	rcu_read_unlock();
+
+	/* consume the skbuff allocated by the netdevice driver */
+	consume_skb(skb);
+
+	if (matches > 0) {
+		arinc429_stats.matches++;
+		arinc429_stats.matches_delta++;
+	}
+}
+
+static int arinc429_rcv(struct sk_buff *skb, struct net_device *dev,
+			struct packet_type *pt, struct net_device *orig_dev)
+{
+	int ret;
+
+	if (unlikely(!net_eq(dev_net(dev), &init_net)))
+		goto drop;
+
+	ret = WARN_ONCE(dev->type != ARPHRD_ARINC429 ||
+			skb->len != ARINC429_MTU,
+			"PF_ARINC429: dropped non conform ARINC429 skbuf: dev type %d, len %d\n",
+			dev->type, skb->len);
+	if (ret)
+		goto drop;
+
+	arinc429_receive(skb, dev);
+	return NET_RX_SUCCESS;
+
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+/*
+ * af_arinc429 protocol functions
+ */
+
+/**
+ * arinc429_proto_register - register ARINC429 transport protocol
+ * @cp: pointer to ARINC429 protocol structure
+ *
+ * Return:
+ *  0 on success
+ *  -EINVAL invalid (out of range) protocol number
+ *  -EBUSY  protocol already in use
+ *  -ENOBUF if proto_register() fails
+ */
+int arinc429_proto_register(const struct arinc429_proto *cp)
+{
+	int proto = cp->protocol;
+	int err = 0;
+
+	if (proto < 0 || proto >= ARINC429_NPROTO) {
+		pr_err("arinc429: protocol number %d out of range\n", proto);
+		return -EINVAL;
+	}
+
+	err = proto_register(cp->prot, 0);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&proto_tab_lock);
+
+	if (proto_tab[proto]) {
+		pr_err("arinc429: protocol %d already registered\n", proto);
+		err = -EBUSY;
+	} else {
+		RCU_INIT_POINTER(proto_tab[proto], cp);
+	}
+
+	mutex_unlock(&proto_tab_lock);
+
+	if (err < 0)
+		proto_unregister(cp->prot);
+
+	return err;
+}
+EXPORT_SYMBOL(arinc429_proto_register);
+
+/**
+ * arinc429_proto_unregister - unregister ARINC429 transport protocol
+ * @cp: pointer to ARINC429 protocol structure
+ */
+void arinc429_proto_unregister(const struct arinc429_proto *cp)
+{
+	int proto = cp->protocol;
+
+	mutex_lock(&proto_tab_lock);
+	BUG_ON(proto_tab[proto] != cp);
+	RCU_INIT_POINTER(proto_tab[proto], NULL);
+	mutex_unlock(&proto_tab_lock);
+
+	synchronize_rcu();
+
+	proto_unregister(cp->prot);
+}
+EXPORT_SYMBOL(arinc429_proto_unregister);
+
+/*
+ * af_arinc429 notifier to create/remove ARINC429 netdevice specific structs
+ */
+static int arinc429_notifier(struct notifier_block *nb, unsigned long msg,
+			     void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct dev_rcv_lists *d;
+
+	if (!net_eq(dev_net(dev), &init_net))
+		return NOTIFY_DONE;
+
+	if (dev->type != ARPHRD_ARINC429)
+		return NOTIFY_DONE;
+
+	switch (msg) {
+	case NETDEV_REGISTER:
+
+		/* create new dev_rcv_lists for this device */
+		d = kzalloc(sizeof(*d), GFP_KERNEL);
+		if (!d)
+			return NOTIFY_DONE;
+		BUG_ON(dev->ml_priv);
+		dev->ml_priv = d;
+
+		break;
+
+	case NETDEV_UNREGISTER:
+		spin_lock(&arinc429_rcvlists_lock);
+
+		d = dev->ml_priv;
+		if (d) {
+			if (d->entries)
+				d->remove_on_zero_entries = 1;
+			else {
+				kfree(d);
+				dev->ml_priv = NULL;
+			}
+		} else {
+			pr_err("arinc429: notifier: receive list not found for dev %s\n",
+			       dev->name);
+		}
+
+		spin_unlock(&arinc429_rcvlists_lock);
+
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ * af_arinc429 module init/exit functions
+ */
+static struct packet_type arinc429_packet __read_mostly = {
+	.type	= cpu_to_be16(ETH_P_ARINC429),
+	.func	= arinc429_rcv,
+};
+
+static const struct net_proto_family arinc429_family_ops = {
+	.family	= PF_ARINC429,
+	.create	= arinc429_create,
+	.owner	= THIS_MODULE,
+};
+
+/* notifier block for netdevice event */
+static struct notifier_block arinc429_netdev_notifier __read_mostly = {
+	.notifier_call = arinc429_notifier,
+};
+
+static __init int arinc429_init(void)
+{
+	pr_info("arinc429: ARINC429 core (" ARINC429_VERSION_STRING ")\n");
+
+	memset(&arinc429_rx_alldev_list, 0, sizeof(arinc429_rx_alldev_list));
+
+	rcv_cache = kmem_cache_create("arinc429_receiver",
+				      sizeof(struct receiver),
+				      0, 0, NULL);
+	if (!rcv_cache)
+		return -ENOMEM;
+
+	/* the statistics are updated every second (timer triggered) */
+	setup_timer(&arinc429_stattimer, arinc429_stat_update, 0);
+	mod_timer(&arinc429_stattimer, round_jiffies(jiffies + HZ));
+
+	arinc429_init_proc();
+
+	/* protocol register */
+	sock_register(&arinc429_family_ops);
+	register_netdevice_notifier(&arinc429_netdev_notifier);
+	dev_add_pack(&arinc429_packet);
+
+	return 0;
+}
+
+static __exit void arinc429_exit(void)
+{
+	struct net_device *dev;
+
+	del_timer_sync(&arinc429_stattimer);
+
+	arinc429_remove_proc();
+
+	/* protocol unregister */
+	dev_remove_pack(&arinc429_packet);
+	unregister_netdevice_notifier(&arinc429_netdev_notifier);
+	sock_unregister(PF_ARINC429);
+
+	/* remove created dev_rcv_lists from still registered devices */
+	rcu_read_lock();
+	for_each_netdev_rcu(&init_net, dev) {
+		if (dev->type == ARPHRD_ARINC429 && dev->ml_priv) {
+			struct dev_rcv_lists *d = dev->ml_priv;
+
+			BUG_ON(d->entries);
+			kfree(d);
+			dev->ml_priv = NULL;
+		}
+	}
+	rcu_read_unlock();
+
+	rcu_barrier(); /* Wait for completion of call_rcu()'s */
+
+	kmem_cache_destroy(rcv_cache);
+}
+
+module_init(arinc429_init);
+module_exit(arinc429_exit);
diff --git a/net/arinc429/af_arinc429.h b/net/arinc429/af_arinc429.h
new file mode 100644
index 0000000..7e4b00e
--- /dev/null
+++ b/net/arinc429/af_arinc429.h
@@ -0,0 +1,100 @@ 
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AF_ARINC429_H
+#define AF_ARINC429_H
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+#include <linux/arinc429.h>
+
+/* af_arinc429 rx dispatcher structures */
+
+struct receiver {
+	struct hlist_node	list;
+	struct rcu_head		rcu;
+	__u8			label;
+	__u8			mask;
+	unsigned long		matches;
+	void			(*func)(struct sk_buff *, void *);
+	void			*data;
+	char			*ident;
+};
+
+enum { RX_ALL, RX_FIL, RX_INV, RX_MAX };
+
+/* per device receive filters linked at dev->ml_priv */
+struct dev_rcv_lists {
+	struct hlist_head	rx[RX_MAX];
+	int			remove_on_zero_entries;
+	int			entries;
+};
+
+/* statistic structures */
+
+/* can be reset e.g. by arinc429_init_stats() */
+struct s_stats {
+	unsigned long jiffies_init;
+
+	unsigned long rx_frames;
+	unsigned long tx_frames;
+	unsigned long matches;
+
+	unsigned long total_rx_rate;
+	unsigned long total_tx_rate;
+	unsigned long total_rx_match_ratio;
+
+	unsigned long current_rx_rate;
+	unsigned long current_tx_rate;
+	unsigned long current_rx_match_ratio;
+
+	unsigned long max_rx_rate;
+	unsigned long max_tx_rate;
+	unsigned long max_rx_match_ratio;
+
+	unsigned long rx_frames_delta;
+	unsigned long tx_frames_delta;
+	unsigned long matches_delta;
+};
+
+/* persistent statistics */
+struct s_pstats {
+	unsigned long stats_reset;
+	unsigned long user_reset;
+	unsigned long rcv_entries;
+	unsigned long rcv_entries_max;
+};
+
+/* receive filters subscribed for 'all' ARINC429 devices */
+extern struct dev_rcv_lists arinc429_rx_alldev_list;
+
+/* function prototypes for the ARINC429 networklayer procfs (proc.c) */
+void arinc429_init_proc(void);
+void arinc429_remove_proc(void);
+void arinc429_stat_update(unsigned long data);
+
+/* structures and variables from af_arinc429.c needed in proc.c for reading */
+extern struct timer_list arinc429_stattimer;    /* timer for stats update */
+extern struct s_stats    arinc429_stats;        /* packet statistics */
+extern struct s_pstats   arinc429_pstats;       /* receive list statistics */
+extern struct hlist_head arinc429_rx_dev_list;  /* rx dispatcher structures */
+
+#endif /* AF_ARINC429_H */
diff --git a/net/arinc429/proc.c b/net/arinc429/proc.c
new file mode 100644
index 0000000..28856a3
--- /dev/null
+++ b/net/arinc429/proc.c
@@ -0,0 +1,432 @@ 
+/*
+ * proc.c - procfs support for Protocol family ARINC429 core module
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+#include <linux/if_arp.h>
+#include <linux/arinc429/core.h>
+
+#include "af_arinc429.h"
+
+/*
+ * proc filenames for the PF_ARINC429 core
+ */
+
+#define ARINC429_PROC_VERSION     "version"
+#define ARINC429_PROC_STATS       "stats"
+#define ARINC429_PROC_RESET_STATS "reset_stats"
+#define ARINC429_PROC_RCVLIST_ALL "rcvlist_all"
+#define ARINC429_PROC_RCVLIST_FIL "rcvlist_fil"
+#define ARINC429_PROC_RCVLIST_INV "rcvlist_inv"
+
+static struct proc_dir_entry *arinc429_dir;
+static struct proc_dir_entry *pde_version;
+static struct proc_dir_entry *pde_stats;
+static struct proc_dir_entry *pde_reset_stats;
+static struct proc_dir_entry *pde_rcvlist_all;
+static struct proc_dir_entry *pde_rcvlist_fil;
+static struct proc_dir_entry *pde_rcvlist_inv;
+
+static int user_reset;
+
+static const char rx_list_name[][8] = {
+	[RX_ALL] = "rx_all",
+	[RX_FIL] = "rx_fil",
+	[RX_INV] = "rx_inv",
+};
+
+/*
+ * af_arinc429 statistics stuff
+ */
+
+static void arinc429_init_stats(void)
+{
+	/*
+	 * This memset function is called from a timer context (when
+	 * arinc429_stattimer is active which is the default) OR in a process
+	 * context (reading the proc_fs when arinc429_stattimer is disabled).
+	 */
+	memset(&arinc429_stats, 0, sizeof(arinc429_stats));
+	arinc429_stats.jiffies_init = jiffies;
+
+	arinc429_pstats.stats_reset++;
+
+	if (user_reset) {
+		user_reset = 0;
+		arinc429_pstats.user_reset++;
+	}
+}
+
+static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
+			       unsigned long count)
+{
+	unsigned long rate;
+
+	if (oldjif == newjif)
+		return 0;
+
+	/* see arinc429_stat_update() - this should NEVER happen! */
+	if (count > (ULONG_MAX / HZ)) {
+		pr_err("arinc429: calc_rate: count exceeded! %ld\n", count);
+		return 99999999;
+	}
+
+	rate = (count * HZ) / (newjif - oldjif);
+
+	return rate;
+}
+
+void arinc429_stat_update(unsigned long data)
+{
+	unsigned long j = jiffies; /* snapshot */
+
+	/* restart counting in timer context on user request */
+	if (user_reset)
+		arinc429_init_stats();
+
+	/* restart counting on jiffies overflow */
+	if (j < arinc429_stats.jiffies_init)
+		arinc429_init_stats();
+
+	/* prevent overflow in calc_rate() */
+	if (arinc429_stats.rx_frames > (ULONG_MAX / HZ))
+		arinc429_init_stats();
+
+	/* prevent overflow in calc_rate() */
+	if (arinc429_stats.tx_frames > (ULONG_MAX / HZ))
+		arinc429_init_stats();
+
+	/* matches overflow - very improbable */
+	if (arinc429_stats.matches > (ULONG_MAX / 100))
+		arinc429_init_stats();
+
+	/* calc total values */
+	if (arinc429_stats.rx_frames)
+		arinc429_stats.total_rx_match_ratio =
+			(arinc429_stats.matches * 100) /
+			arinc429_stats.rx_frames;
+
+	arinc429_stats.total_tx_rate = calc_rate(arinc429_stats.jiffies_init,
+						 j, arinc429_stats.tx_frames);
+	arinc429_stats.total_rx_rate = calc_rate(arinc429_stats.jiffies_init,
+						 j, arinc429_stats.rx_frames);
+
+	/* calc current values */
+	if (arinc429_stats.rx_frames_delta)
+		arinc429_stats.current_rx_match_ratio =
+			(arinc429_stats.matches_delta * 100) /
+			arinc429_stats.rx_frames_delta;
+
+	arinc429_stats.current_tx_rate =
+		calc_rate(0, HZ, arinc429_stats.tx_frames_delta);
+	arinc429_stats.current_rx_rate =
+		calc_rate(0, HZ, arinc429_stats.rx_frames_delta);
+
+	/* check / update maximum values */
+	if (arinc429_stats.max_tx_rate < arinc429_stats.current_tx_rate)
+		arinc429_stats.max_tx_rate = arinc429_stats.current_tx_rate;
+
+	if (arinc429_stats.max_rx_rate < arinc429_stats.current_rx_rate)
+		arinc429_stats.max_rx_rate = arinc429_stats.current_rx_rate;
+
+	if (arinc429_stats.max_rx_match_ratio < arinc429_stats.current_rx_match_ratio)
+		arinc429_stats.max_rx_match_ratio = arinc429_stats.current_rx_match_ratio;
+
+	/* clear values for 'current rate' calculation */
+	arinc429_stats.tx_frames_delta = 0;
+	arinc429_stats.rx_frames_delta = 0;
+	arinc429_stats.matches_delta   = 0;
+
+	/* restart timer (one second) */
+	mod_timer(&arinc429_stattimer, round_jiffies(jiffies + HZ));
+}
+
+/*
+ * proc read functions
+ */
+
+static void arinc429_print_rcvlist(struct seq_file *m,
+				   struct hlist_head *rx_list,
+				   struct net_device *dev)
+{
+	struct receiver *r;
+
+	seq_puts(m, "  device      label  mask  function  userdata   matches  ident\n");
+
+	hlist_for_each_entry_rcu(r, rx_list, list) {
+		char *fmt = "   %-5s     %02x     %02x   %pK  %pK  %8ld  %s\n";
+
+		seq_printf(m, fmt, DNAME(dev), r->label, r->mask,
+			   r->func, r->data, r->matches, r->ident);
+	}
+}
+
+static int arinc429_stats_proc_show(struct seq_file *m, void *v)
+{
+	seq_putc(m, '\n');
+	seq_printf(m, " %8ld transmitted frames (TXF)\n",
+		   arinc429_stats.tx_frames);
+	seq_printf(m, " %8ld received frames (RXF)\n",
+		   arinc429_stats.rx_frames);
+	seq_printf(m, " %8ld matched frames (RXMF)\n",
+		   arinc429_stats.matches);
+
+	seq_putc(m, '\n');
+
+	if (arinc429_stattimer.function == arinc429_stat_update) {
+		seq_printf(m, " %8ld %% total match ratio (RXMR)\n",
+			   arinc429_stats.total_rx_match_ratio);
+
+		seq_printf(m, " %8ld frames/s total tx rate (TXR)\n",
+			   arinc429_stats.total_tx_rate);
+		seq_printf(m, " %8ld frames/s total rx rate (RXR)\n",
+			   arinc429_stats.total_rx_rate);
+
+		seq_putc(m, '\n');
+
+		seq_printf(m, " %8ld %% current match ratio (CRXMR)\n",
+			   arinc429_stats.current_rx_match_ratio);
+
+		seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n",
+			   arinc429_stats.current_tx_rate);
+		seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n",
+			   arinc429_stats.current_rx_rate);
+
+		seq_putc(m, '\n');
+
+		seq_printf(m, " %8ld %% max match ratio (MRXMR)\n",
+			   arinc429_stats.max_rx_match_ratio);
+
+		seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n",
+			   arinc429_stats.max_tx_rate);
+		seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n",
+			   arinc429_stats.max_rx_rate);
+
+		seq_putc(m, '\n');
+	}
+
+	seq_printf(m, " %8ld current receive list entries (CRCV)\n",
+		   arinc429_pstats.rcv_entries);
+	seq_printf(m, " %8ld maximum receive list entries (MRCV)\n",
+		   arinc429_pstats.rcv_entries_max);
+
+	if (arinc429_pstats.stats_reset)
+		seq_printf(m, "\n %8ld statistic resets (STR)\n",
+			   arinc429_pstats.stats_reset);
+
+	if (arinc429_pstats.user_reset)
+		seq_printf(m, " %8ld user statistic resets (USTR)\n",
+			   arinc429_pstats.user_reset);
+
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static int arinc429_stats_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, arinc429_stats_proc_show, NULL);
+}
+
+static const struct file_operations arinc429_stats_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= arinc429_stats_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int arinc429_reset_stats_proc_show(struct seq_file *m, void *v)
+{
+	user_reset = 1;
+
+	if (arinc429_stattimer.function == arinc429_stat_update) {
+		seq_printf(m, "Scheduled statistic reset #%ld.\n",
+			   arinc429_pstats.stats_reset + 1);
+
+	} else {
+		if (arinc429_stats.jiffies_init != jiffies)
+			arinc429_init_stats();
+
+		seq_printf(m, "Performed statistic reset #%ld.\n",
+			   arinc429_pstats.stats_reset);
+	}
+	return 0;
+}
+
+static int arinc429_reset_stats_proc_open(struct inode *inode,
+					  struct file *file)
+{
+	return single_open(file, arinc429_reset_stats_proc_show, NULL);
+}
+
+static const struct file_operations arinc429_reset_stats_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= arinc429_reset_stats_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int arinc429_version_proc_show(struct seq_file *m, void *v)
+{
+	seq_printf(m, "%s\n", ARINC429_VERSION_STRING);
+	return 0;
+}
+
+static int arinc429_version_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, arinc429_version_proc_show, NULL);
+}
+
+static const struct file_operations arinc429_version_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= arinc429_version_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static inline void arinc429_rcvlist_proc_show_one(struct seq_file *m, int idx,
+						  struct net_device *dev,
+						  struct dev_rcv_lists *d)
+{
+	if (!hlist_empty(&d->rx[idx]))
+		arinc429_print_rcvlist(m, &d->rx[idx], dev);
+	else
+		seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
+}
+
+static int arinc429_rcvlist_proc_show(struct seq_file *m, void *v)
+{
+	/* double cast to prevent GCC warning */
+	int idx = (int)(long)m->private;
+	struct net_device *dev;
+	struct dev_rcv_lists *d;
+
+	seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
+
+	rcu_read_lock();
+
+	/* receive list for 'all' ARINC429 devices (dev == NULL) */
+	d = &arinc429_rx_alldev_list;
+	arinc429_rcvlist_proc_show_one(m, idx, NULL, d);
+
+	/* receive list for registered ARINC429 devices */
+	for_each_netdev_rcu(&init_net, dev) {
+		if (dev->type == ARPHRD_ARINC429 && dev->ml_priv)
+			arinc429_rcvlist_proc_show_one(m, idx, dev,
+						       dev->ml_priv);
+	}
+
+	rcu_read_unlock();
+
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static int arinc429_rcvlist_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, arinc429_rcvlist_proc_show, PDE_DATA(inode));
+}
+
+static const struct file_operations arinc429_rcvlist_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= arinc429_rcvlist_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/*
+ * proc utility functions
+ */
+
+static void arinc429_remove_proc_readentry(const char *name)
+{
+	if (arinc429_dir)
+		remove_proc_entry(name, arinc429_dir);
+}
+
+/*
+ * arinc429_init_proc - create main ARINC429 proc directory and procfs entries
+ */
+void arinc429_init_proc(void)
+{
+	/* create /proc/net/arinc429 directory */
+	arinc429_dir = proc_mkdir("arinc429", init_net.proc_net);
+
+	if (!arinc429_dir) {
+		pr_info("arinc429: failed to create /proc/net/arinc429 . CONFIG_PROC_FS missing?\n");
+		return;
+	}
+
+	/* own procfs entries from the AF_ARINC429 core */
+	pde_version     = proc_create(ARINC429_PROC_VERSION, 0644,
+				      arinc429_dir,
+				      &arinc429_version_proc_fops);
+	pde_stats       = proc_create(ARINC429_PROC_STATS, 0644,
+				      arinc429_dir,
+				      &arinc429_stats_proc_fops);
+	pde_reset_stats = proc_create(ARINC429_PROC_RESET_STATS, 0644,
+				      arinc429_dir,
+				      &arinc429_reset_stats_proc_fops);
+	pde_rcvlist_all = proc_create_data(ARINC429_PROC_RCVLIST_ALL, 0644,
+					   arinc429_dir,
+					   &arinc429_rcvlist_proc_fops,
+					   (void *)RX_ALL);
+	pde_rcvlist_fil = proc_create_data(ARINC429_PROC_RCVLIST_FIL, 0644,
+					   arinc429_dir,
+					   &arinc429_rcvlist_proc_fops,
+					   (void *)RX_FIL);
+	pde_rcvlist_inv = proc_create_data(ARINC429_PROC_RCVLIST_INV, 0644,
+					   arinc429_dir,
+					   &arinc429_rcvlist_proc_fops,
+					   (void *)RX_INV);
+}
+
+/*
+ * arinc429_remove_proc - remove procfs entries and main ARINC429 proc directory
+ */
+void arinc429_remove_proc(void)
+{
+	if (pde_version)
+		arinc429_remove_proc_readentry(ARINC429_PROC_VERSION);
+
+	if (pde_stats)
+		arinc429_remove_proc_readentry(ARINC429_PROC_STATS);
+
+	if (pde_reset_stats)
+		arinc429_remove_proc_readentry(ARINC429_PROC_RESET_STATS);
+
+	if (pde_rcvlist_all)
+		arinc429_remove_proc_readentry(ARINC429_PROC_RCVLIST_ALL);
+
+	if (pde_rcvlist_fil)
+		arinc429_remove_proc_readentry(ARINC429_PROC_RCVLIST_FIL);
+
+	if (pde_rcvlist_inv)
+		arinc429_remove_proc_readentry(ARINC429_PROC_RCVLIST_INV);
+
+	if (arinc429_dir)
+		remove_proc_entry("arinc429", init_net.proc_net);
+}
diff --git a/net/arinc429/raw.c b/net/arinc429/raw.c
new file mode 100644
index 0000000..82e057b
--- /dev/null
+++ b/net/arinc429/raw.c
@@ -0,0 +1,758 @@ 
+/*
+ * raw.c - Raw sockets for protocol family ARINC429
+ *
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * Based on the SocketCAN stack.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/uio.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/socket.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/arinc429.h>
+#include <linux/arinc429/core.h>
+#include <linux/arinc429/skb.h>
+#include <linux/arinc429/raw.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+
+#define ARINC429_RAW_VERSION ARINC429_VERSION
+
+MODULE_DESCRIPTION("PF_ARINC429 raw protocol");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_ALIAS("arinc429-proto-1");
+
+/*
+ * A raw socket has a list of arinc429_filters attached to it, each receiving
+ * the ARINC429 frames matching that filter.  If the filter list is empty,
+ * no ARINC429 frames will be received by the socket.  The default after
+ * opening the socket, is to have one filter which receives all frames.
+ * The filter list is allocated dynamically with the exception of the
+ * list containing only one item.  This common case is optimized by
+ * storing the single filter in dfilter, to avoid using dynamic memory.
+ */
+
+struct uniqframe {
+	ktime_t tstamp;
+	const struct sk_buff *skb;
+	unsigned int join_rx_count;
+};
+
+struct raw_sock {
+	struct sock sk;
+	int bound;
+	int ifindex;
+	struct notifier_block notifier;
+	int loopback;
+	int recv_own_msgs;
+	int join_filters;
+	int count;                 /* number of active filters */
+	struct arinc429_filter dfilter; /* default/single filter */
+	struct arinc429_filter *filter; /* pointer to filter(s) */
+	struct uniqframe __percpu *uniq;
+};
+
+/*
+ * Return pointer to store the extra msg flags for raw_recvmsg().
+ * We use the space of one unsigned int beyond the 'struct sockaddr_arinc429'
+ * in skb->cb.
+ */
+static inline unsigned int *raw_flags(struct sk_buff *skb)
+{
+	sock_skb_cb_check_size(sizeof(struct sockaddr_arinc429) +
+			       sizeof(unsigned int));
+
+	/* return pointer after struct sockaddr_arinc429 */
+	return (unsigned int *)(&((struct sockaddr_arinc429 *)skb->cb)[1]);
+}
+
+static inline struct raw_sock *raw_sk(const struct sock *sk)
+{
+	return (struct raw_sock *)sk;
+}
+
+static void raw_rcv(struct sk_buff *oskb, void *data)
+{
+	struct sock *sk = (struct sock *)data;
+	struct raw_sock *ro = raw_sk(sk);
+	struct sockaddr_arinc429 *addr;
+	struct sk_buff *skb;
+	unsigned int *pflags;
+
+	/* check the received tx sock reference */
+	if (!ro->recv_own_msgs && oskb->sk == sk)
+		return;
+
+	/* do not pass non-ARINC429 frames to a socket */
+	if (oskb->len != ARINC429_MTU)
+		return;
+
+	/* eliminate multiple filter matches for the same skb */
+	if (this_cpu_ptr(ro->uniq)->skb == oskb &&
+	    ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) {
+		if (ro->join_filters) {
+			this_cpu_inc(ro->uniq->join_rx_count);
+			/* drop frame until all enabled filters matched */
+			if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count)
+				return;
+		} else {
+			return;
+		}
+	} else {
+		this_cpu_ptr(ro->uniq)->skb = oskb;
+		this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp;
+		this_cpu_ptr(ro->uniq)->join_rx_count = 1;
+		/* drop first frame to check all enabled filters? */
+		if (ro->join_filters && ro->count > 1)
+			return;
+	}
+
+	/* clone the given skb to be able to enqueue it into the rcv queue */
+	skb = skb_clone(oskb, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	/*
+	 *  Put the datagram to the queue so that raw_recvmsg() can
+	 *  get it from there.  We need to pass the interface index to
+	 *  raw_recvmsg().  We pass a whole struct sockaddr_arinc429 in skb->cb
+	 *  containing the interface index.
+	 */
+
+	sock_skb_cb_check_size(sizeof(struct sockaddr_arinc429));
+	addr = (struct sockaddr_arinc429 *)skb->cb;
+	memset(addr, 0, sizeof(*addr));
+	addr->arinc429_family  = AF_ARINC429;
+	addr->arinc429_ifindex = skb->dev->ifindex;
+
+	/* add ARINC429 specific message flags for raw_recvmsg() */
+	pflags = raw_flags(skb);
+	*pflags = 0;
+	if (oskb->sk)
+		*pflags |= MSG_DONTROUTE;
+	if (oskb->sk == sk)
+		*pflags |= MSG_CONFIRM;
+
+	if (sock_queue_rcv_skb(sk, skb) < 0)
+		kfree_skb(skb);
+}
+
+static int raw_enable_filters(struct net_device *dev, struct sock *sk,
+			      struct arinc429_filter *filter, int count)
+{
+	int err = 0;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		err = arinc429_rx_register(dev, &filter[i], raw_rcv, sk, "raw");
+		if (err) {
+			/* clean up successfully registered filters */
+			while (--i >= 0)
+				arinc429_rx_unregister(dev, &filter[i],
+						       raw_rcv, sk);
+			break;
+		}
+	}
+
+	return err;
+}
+
+static void raw_disable_filters(struct net_device *dev, struct sock *sk,
+				struct arinc429_filter *filter, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		arinc429_rx_unregister(dev, &filter[i], raw_rcv, sk);
+}
+
+static inline void raw_disable_allfilters(struct net_device *dev,
+					  struct sock *sk)
+{
+	struct raw_sock *ro = raw_sk(sk);
+
+	raw_disable_filters(dev, sk, ro->filter, ro->count);
+}
+
+static int raw_enable_allfilters(struct net_device *dev, struct sock *sk)
+{
+	struct raw_sock *ro = raw_sk(sk);
+	int err;
+
+	err = raw_enable_filters(dev, sk, ro->filter, ro->count);
+
+	return err;
+}
+
+static int raw_notifier(struct notifier_block *nb,
+			unsigned long msg, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
+	struct sock *sk = &ro->sk;
+
+	if (!net_eq(dev_net(dev), &init_net))
+		return NOTIFY_DONE;
+
+	if (dev->type != ARPHRD_ARINC429)
+		return NOTIFY_DONE;
+
+	if (ro->ifindex != dev->ifindex)
+		return NOTIFY_DONE;
+
+	switch (msg) {
+	case NETDEV_UNREGISTER:
+		lock_sock(sk);
+		/* remove current filters & unregister */
+		if (ro->bound)
+			raw_disable_allfilters(dev, sk);
+
+		if (ro->count > 1)
+			kfree(ro->filter);
+
+		ro->ifindex = 0;
+		ro->bound   = 0;
+		ro->count   = 0;
+		release_sock(sk);
+
+		sk->sk_err = ENODEV;
+		if (!sock_flag(sk, SOCK_DEAD))
+			sk->sk_error_report(sk);
+		break;
+
+	case NETDEV_DOWN:
+		sk->sk_err = ENETDOWN;
+		if (!sock_flag(sk, SOCK_DEAD))
+			sk->sk_error_report(sk);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int raw_init(struct sock *sk)
+{
+	struct raw_sock *ro = raw_sk(sk);
+
+	ro->bound            = 0;
+	ro->ifindex          = 0;
+
+	/* set default filter to single entry dfilter */
+	ro->dfilter.label    = 0;
+	ro->dfilter.mask     = 0;
+	ro->filter           = &ro->dfilter;
+	ro->count            = 1;
+
+	/* set default loopback behaviour */
+	ro->loopback         = 1;
+	ro->recv_own_msgs    = 0;
+	ro->join_filters     = 0;
+
+	/* alloc_percpu provides zero'ed memory */
+	ro->uniq = alloc_percpu(struct uniqframe);
+	if (unlikely(!ro->uniq))
+		return -ENOMEM;
+
+	/* set notifier */
+	ro->notifier.notifier_call = raw_notifier;
+
+	register_netdevice_notifier(&ro->notifier);
+
+	return 0;
+}
+
+static int raw_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct raw_sock *ro;
+
+	if (!sk)
+		return 0;
+
+	ro = raw_sk(sk);
+
+	unregister_netdevice_notifier(&ro->notifier);
+
+	lock_sock(sk);
+
+	/* remove current filters & unregister */
+	if (ro->bound) {
+		if (ro->ifindex) {
+			struct net_device *dev;
+
+			dev = dev_get_by_index(&init_net, ro->ifindex);
+			if (dev) {
+				raw_disable_allfilters(dev, sk);
+				dev_put(dev);
+			}
+		} else {
+			raw_disable_allfilters(NULL, sk);
+		}
+	}
+
+	if (ro->count > 1)
+		kfree(ro->filter);
+
+	ro->ifindex = 0;
+	ro->bound   = 0;
+	ro->count   = 0;
+	free_percpu(ro->uniq);
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+
+	release_sock(sk);
+	sock_put(sk);
+
+	return 0;
+}
+
+static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+{
+	struct sockaddr_arinc429 *addr = (struct sockaddr_arinc429 *)uaddr;
+	struct sock *sk = sock->sk;
+	struct raw_sock *ro = raw_sk(sk);
+	int ifindex;
+	int err = 0;
+	int notify_enetdown = 0;
+
+	if (len < sizeof(*addr))
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (ro->bound && addr->arinc429_ifindex == ro->ifindex)
+		goto out;
+
+	if (addr->arinc429_ifindex) {
+		struct net_device *dev;
+
+		dev = dev_get_by_index(&init_net, addr->arinc429_ifindex);
+		if (!dev) {
+			err = -ENODEV;
+			goto out;
+		}
+		if (dev->type != ARPHRD_ARINC429) {
+			dev_put(dev);
+			err = -ENODEV;
+			goto out;
+		}
+		if (!(dev->flags & IFF_UP))
+			notify_enetdown = 1;
+
+		ifindex = dev->ifindex;
+
+		/* filters set by default/setsockopt */
+		err = raw_enable_allfilters(dev, sk);
+		dev_put(dev);
+	} else {
+		ifindex = 0;
+
+		/* filters set by default/setsockopt */
+		err = raw_enable_allfilters(NULL, sk);
+	}
+
+	if (!err) {
+		if (ro->bound) {
+			/* unregister old filters */
+			if (ro->ifindex) {
+				struct net_device *dev;
+
+				dev = dev_get_by_index(&init_net, ro->ifindex);
+				if (dev) {
+					raw_disable_allfilters(dev, sk);
+					dev_put(dev);
+				}
+			} else {
+				raw_disable_allfilters(NULL, sk);
+			}
+		}
+		ro->ifindex = ifindex;
+		ro->bound = 1;
+	}
+
+ out:
+	release_sock(sk);
+
+	if (notify_enetdown) {
+		sk->sk_err = ENETDOWN;
+		if (!sock_flag(sk, SOCK_DEAD))
+			sk->sk_error_report(sk);
+	}
+
+	return err;
+}
+
+static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
+		       int *len, int peer)
+{
+	struct sockaddr_arinc429 *addr = (struct sockaddr_arinc429 *)uaddr;
+	struct sock *sk = sock->sk;
+	struct raw_sock *ro = raw_sk(sk);
+
+	if (peer)
+		return -EOPNOTSUPP;
+
+	memset(addr, 0, sizeof(*addr));
+	addr->arinc429_family  = AF_ARINC429;
+	addr->arinc429_ifindex = ro->ifindex;
+
+	*len = sizeof(*addr);
+
+	return 0;
+}
+
+static int raw_setsockopt(struct socket *sock, int level, int optname,
+			  char __user *optval, unsigned int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct raw_sock *ro = raw_sk(sk);
+	struct arinc429_filter *filter = NULL;  /* dyn. alloc'ed filters */
+	struct arinc429_filter sfilter;         /* single filter */
+	struct net_device *dev = NULL;
+	int count = 0;
+	int err = 0;
+
+	if (level != SOL_ARINC429_RAW)
+		return -EINVAL;
+
+	switch (optname) {
+	case ARINC429_RAW_FILTER:
+		if (optlen % sizeof(struct arinc429_filter) != 0)
+			return -EINVAL;
+
+		count = optlen / sizeof(struct arinc429_filter);
+
+		if (count > 1) {
+			/* filter does not fit into dfilter => alloc space */
+			filter = memdup_user(optval, optlen);
+			if (IS_ERR(filter))
+				return PTR_ERR(filter);
+		} else if (count == 1) {
+			if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
+				return -EFAULT;
+		}
+
+		lock_sock(sk);
+
+		if (ro->bound && ro->ifindex)
+			dev = dev_get_by_index(&init_net, ro->ifindex);
+
+		if (ro->bound) {
+			/* (try to) register the new filters */
+			if (count == 1)
+				err = raw_enable_filters(dev, sk, &sfilter, 1);
+			else
+				err = raw_enable_filters(dev, sk, filter,
+							 count);
+			if (err) {
+				if (count > 1)
+					kfree(filter);
+				goto out_fil;
+			}
+
+			/* remove old filter registrations */
+			raw_disable_filters(dev, sk, ro->filter, ro->count);
+		}
+
+		/* remove old filter space */
+		if (ro->count > 1)
+			kfree(ro->filter);
+
+		/* link new filters to the socket */
+		if (count == 1) {
+			/* copy filter data for single filter */
+			ro->dfilter = sfilter;
+			filter = &ro->dfilter;
+		}
+		ro->filter = filter;
+		ro->count  = count;
+
+ out_fil:
+		if (dev)
+			dev_put(dev);
+
+		release_sock(sk);
+
+		break;
+
+	case ARINC429_RAW_LOOPBACK:
+		if (optlen != sizeof(ro->loopback))
+			return -EINVAL;
+
+		if (copy_from_user(&ro->loopback, optval, optlen))
+			return -EFAULT;
+
+		break;
+
+	case ARINC429_RAW_RECV_OWN_MSGS:
+		if (optlen != sizeof(ro->recv_own_msgs))
+			return -EINVAL;
+
+		if (copy_from_user(&ro->recv_own_msgs, optval, optlen))
+			return -EFAULT;
+
+		break;
+
+	case ARINC429_RAW_JOIN_FILTERS:
+		if (optlen != sizeof(ro->join_filters))
+			return -EINVAL;
+
+		if (copy_from_user(&ro->join_filters, optval, optlen))
+			return -EFAULT;
+
+		break;
+
+	default:
+		return -ENOPROTOOPT;
+	}
+	return err;
+}
+
+static int raw_getsockopt(struct socket *sock, int level, int optname,
+			  char __user *optval, int __user *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct raw_sock *ro = raw_sk(sk);
+	int len;
+	void *val;
+	int err = 0;
+
+	if (level != SOL_ARINC429_RAW)
+		return -EINVAL;
+	if (get_user(len, optlen))
+		return -EFAULT;
+	if (len < 0)
+		return -EINVAL;
+
+	switch (optname) {
+	case ARINC429_RAW_FILTER:
+		lock_sock(sk);
+		if (ro->count > 0) {
+			int fsize = ro->count * sizeof(struct arinc429_filter);
+
+			if (len > fsize)
+				len = fsize;
+			if (copy_to_user(optval, ro->filter, len))
+				err = -EFAULT;
+		} else {
+			len = 0;
+		}
+		release_sock(sk);
+
+		if (!err)
+			err = put_user(len, optlen);
+		return err;
+
+	case ARINC429_RAW_LOOPBACK:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = &ro->loopback;
+		break;
+
+	case ARINC429_RAW_RECV_OWN_MSGS:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = &ro->recv_own_msgs;
+		break;
+
+	case ARINC429_RAW_JOIN_FILTERS:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = &ro->join_filters;
+		break;
+
+	default:
+		return -ENOPROTOOPT;
+	}
+
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, val, len))
+		return -EFAULT;
+	return 0;
+}
+
+static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+{
+	struct sock *sk = sock->sk;
+	struct raw_sock *ro = raw_sk(sk);
+	struct sk_buff *skb;
+	struct net_device *dev;
+	int ifindex;
+	int err;
+
+	if (msg->msg_name) {
+		DECLARE_SOCKADDR(struct sockaddr_arinc429 *, addr,
+				 msg->msg_name);
+
+		if (msg->msg_namelen < sizeof(*addr))
+			return -EINVAL;
+
+		if (addr->arinc429_family != AF_ARINC429)
+			return -EINVAL;
+
+		ifindex = addr->arinc429_ifindex;
+	} else {
+		ifindex = ro->ifindex;
+	}
+
+	if (unlikely(size != ARINC429_MTU))
+		return -EINVAL;
+
+	dev = dev_get_by_index(&init_net, ifindex);
+	if (!dev)
+		return -ENXIO;
+
+	skb = sock_alloc_send_skb(sk, size + sizeof(struct arinc429_skb_priv),
+				  msg->msg_flags & MSG_DONTWAIT, &err);
+	if (!skb)
+		goto put_dev;
+
+	arinc429_skb_reserve(skb);
+	arinc429_skb_prv(skb)->ifindex = dev->ifindex;
+
+	err = memcpy_from_msg(skb_put(skb, size), msg, size);
+	if (err < 0)
+		goto free_skb;
+
+	sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
+
+	skb->dev = dev;
+	skb->sk  = sk;
+	skb->priority = sk->sk_priority;
+
+	err = arinc429_send(skb, ro->loopback);
+
+	dev_put(dev);
+
+	if (err)
+		goto send_failed;
+
+	return size;
+
+free_skb:
+	kfree_skb(skb);
+put_dev:
+	dev_put(dev);
+send_failed:
+	return err;
+}
+
+static int raw_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
+		       int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int err = 0;
+	int noblock;
+
+	noblock =  flags & MSG_DONTWAIT;
+	flags   &= ~MSG_DONTWAIT;
+
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
+	if (!skb)
+		return err;
+
+	if (size < skb->len)
+		msg->msg_flags |= MSG_TRUNC;
+	else
+		size = skb->len;
+
+	err = memcpy_to_msg(msg, skb->data, size);
+	if (err < 0) {
+		skb_free_datagram(sk, skb);
+		return err;
+	}
+
+	sock_recv_ts_and_drops(msg, sk, skb);
+
+	if (msg->msg_name) {
+		__sockaddr_check_size(sizeof(struct sockaddr_arinc429));
+		msg->msg_namelen = sizeof(struct sockaddr_arinc429);
+		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
+	}
+
+	/* assign the flags that have been recorded in raw_rcv() */
+	msg->msg_flags |= *(raw_flags(skb));
+
+	skb_free_datagram(sk, skb);
+
+	return size;
+}
+
+static const struct proto_ops raw_ops = {
+	.family        = PF_ARINC429,
+	.release       = raw_release,
+	.bind          = raw_bind,
+	.connect       = sock_no_connect,
+	.socketpair    = sock_no_socketpair,
+	.accept        = sock_no_accept,
+	.getname       = raw_getname,
+	.poll          = datagram_poll,
+	/* use arinc429_ioctl() from af_arinc429.c */
+	.ioctl         = arinc429_ioctl,
+	.listen        = sock_no_listen,
+	.shutdown      = sock_no_shutdown,
+	.setsockopt    = raw_setsockopt,
+	.getsockopt    = raw_getsockopt,
+	.sendmsg       = raw_sendmsg,
+	.recvmsg       = raw_recvmsg,
+	.mmap          = sock_no_mmap,
+	.sendpage      = sock_no_sendpage,
+};
+
+static struct proto raw_proto __read_mostly = {
+	.name       = "ARINC429_RAW",
+	.owner      = THIS_MODULE,
+	.obj_size   = sizeof(struct raw_sock),
+	.init       = raw_init,
+};
+
+static const struct arinc429_proto raw_arinc429_proto = {
+	.type       = SOCK_RAW,
+	.protocol   = ARINC429_RAW,
+	.ops        = &raw_ops,
+	.prot       = &raw_proto,
+};
+
+static __init int raw_module_init(void)
+{
+	int err;
+
+	pr_info("arinc429: raw protocol (rev " ARINC429_RAW_VERSION ")\n");
+
+	err = arinc429_proto_register(&raw_arinc429_proto);
+	if (err < 0)
+		pr_err("arinc429: registration of raw protocol failed\n");
+
+	return err;
+}
+
+static __exit void raw_module_exit(void)
+{
+	arinc429_proto_unregister(&raw_arinc429_proto);
+}
+
+module_init(raw_module_init);
+module_exit(raw_module_exit);