af_bus patches added
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Dec 2012 17:42:24 +0000 (09:42 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Dec 2012 17:42:24 +0000 (09:42 -0800)
16 files changed:
patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch [new file with mode: 0644]
patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch [new file with mode: 0644]
patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch [new file with mode: 0644]
patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch [new file with mode: 0644]
patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch [new file with mode: 0644]
patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch [new file with mode: 0644]
patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch [new file with mode: 0644]
patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch [new file with mode: 0644]
patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch [new file with mode: 0644]
patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch [new file with mode: 0644]
patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch [new file with mode: 0644]
patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch [new file with mode: 0644]
patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch [new file with mode: 0644]
patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch [new file with mode: 0644]
patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch [new file with mode: 0644]
series

diff --git a/patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch b/patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
new file mode 100644 (file)
index 0000000..fa2f7f9
--- /dev/null
@@ -0,0 +1,84 @@
+From 6a6b05153678be7f443dc66be6fac842135aac00 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 12:07:49 +0200
+Subject: [PATCH 01/15] net: bus: add the AF_BUS socket address family
+
+AF_BUS is a new socket address family that allows both unicast and
+multicast I on a local machine with total ordering for messages
+(every process on the same bus sees each message in the same order).
+
+A process can create buses to which other processes can connect and
+communicate with each other by sending messages. Processes' addresses are
+automatically assigned by the bus on connect and are unique. Messages can
+be sent either to process' unique address or to a bus multicast address.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ include/linux/socket.h |    5 ++++-
+ net/core/sock.c        |    6 +++---
+ 2 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/socket.h b/include/linux/socket.h
+index b84bbd4..59596d2 100644
+--- a/include/linux/socket.h
++++ b/include/linux/socket.h
+@@ -195,7 +195,8 @@ struct ucred {
+ #define AF_CAIF               37      /* CAIF sockets                 */
+ #define AF_ALG                38      /* Algorithm sockets            */
+ #define AF_NFC                39      /* NFC sockets                  */
+-#define AF_MAX                40      /* For now.. */
++#define AF_BUS                40      /* BUS sockets                  */
++#define AF_MAX                41      /* For now.. */
+ /* Protocol families, same as address families. */
+ #define PF_UNSPEC     AF_UNSPEC
+@@ -238,6 +239,7 @@ struct ucred {
+ #define PF_CAIF               AF_CAIF
+ #define PF_ALG                AF_ALG
+ #define PF_NFC                AF_NFC
++#define PF_BUS                AF_BUS
+ #define PF_MAX                AF_MAX
+ /* Maximum queue length specifiable by listen.  */
+@@ -312,6 +314,7 @@ struct ucred {
+ #define SOL_IUCV      277
+ #define SOL_CAIF      278
+ #define SOL_ALG               279
++#define SOL_BUS               280
+ /* IPX options */
+ #define IPX_TYPE      1
+diff --git a/net/core/sock.c b/net/core/sock.c
+index 4b469e3..7d6d3f6 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -205,7 +205,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
+   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
+   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
+   "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG"      ,
+-  "sk_lock-AF_NFC"   , "sk_lock-AF_MAX"
++  "sk_lock-AF_NFC"   , "sk_lock-AF_BUS"     , "sk_lock-AF_MAX"
+ };
+ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
+   "slock-AF_UNSPEC", "slock-AF_UNIX"     , "slock-AF_INET"     ,
+@@ -221,7 +221,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
+   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
+   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
+   "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG"      ,
+-  "slock-AF_NFC"   , "slock-AF_MAX"
++  "slock-AF_NFC"   , "slock-AF_BUS"     , "slock-AF_MAX"
+ };
+ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
+   "clock-AF_UNSPEC", "clock-AF_UNIX"     , "clock-AF_INET"     ,
+@@ -237,7 +237,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
+   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
+   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
+   "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG"      ,
+-  "clock-AF_NFC"   , "clock-AF_MAX"
++  "clock-AF_NFC"   , "clock-AF_BUS"     , "clock-AF_MAX"
+ };
+ /*
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch b/patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch
new file mode 100644 (file)
index 0000000..37c85e7
--- /dev/null
@@ -0,0 +1,581 @@
+From 9943977a50f55ee53cde6f9c4fa4f1bb25761d71 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Tue, 26 Jun 2012 14:32:43 +0200
+Subject: [PATCH 02/15] net: bus: Add AF_BUS documentation
+
+AF_BUS is different to other POSIX BSD sockets address families so a
+is good to have a documentation about its design, ABI and semantics.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ Documentation/networking/af_bus.txt |  558 +++++++++++++++++++++++++++++++++++
+ 1 files changed, 558 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/networking/af_bus.txt
+
+diff --git a/Documentation/networking/af_bus.txt b/Documentation/networking/af_bus.txt
+new file mode 100644
+index 0000000..cfef22f
+--- /dev/null
++++ b/Documentation/networking/af_bus.txt
+@@ -0,0 +1,558 @@
++                      The AF_BUS socket address family
++                      ================================
++
++Introduction
++------------
++
++AF_BUS is a message oriented inter process communication system.
++
++The principle features are:
++
++ - Reliable datagram based communication (all sockets are of type
++   SOCK_SEQPACKET)
++
++ - Multicast message delivery (one to many, unicast as a subset)
++
++ - Strict ordering (messages are delivered to every client in the same order)
++
++ - Ability to pass file descriptors
++
++ - Ability to pass credentials
++
++The basic concept is to provide a virtual bus on which multiple
++processes can communicate and policy is imposed by a "bus master".
++
++A process can create buses to which other processes can connect and
++communicate with each other by sending messages. Processes' addresses
++are automatically assigned by the bus on connect and are
++unique. Messages can be sent either to a process' unique address or to
++a bus multicast addresses.
++
++Netfilter rules or Berkeley Packet Filter can be used to restrict the
++messages that each peer is allowed to receive. This is especially
++important when sending to multicast addresses.
++
++Besides messages, process can send and receive ancillary data (i.e.,
++SCM_RIGHTS for passing file descriptors or SCM_CREDENTIALS for passing
++Unix credentials). In the case of a multicast message all recipients
++of a message may obtain a copy a file descriptor or credentials.
++
++A bus is created by processes connecting on an AF_BUS socket. The
++"bus master" binds itself instead of connecting to the NULL address.
++
++The socket address is made up of a path component and a numeric
++component. The path component is either a pathname or an abstract
++socket similar to a unix socket. The numeric component is used to
++uniquely identify each connection to the bus. Thus the path identifies
++a specific bus and the numeric component the attachment to that bus.
++
++The process that calls bind(2) on the socket is the owner of the bus
++and is called the bus master. The master is a special client of the
++bus and has some responsibility for the bus' operation. The master is
++assigned a fixed address with all the bits zero (0x0000000000000000).
++
++Each process connected to an AF_BUS socket has one or more addresses
++within that bus. These addresses are 64-bit unsigned integers,
++interpreted by splitting the address into two parts: the most
++significant 16 bits are a prefix identifying the type of address, and
++the remaining 48 bits are the actual client address within that
++prefix, as shown in this figure:
++
++Bit:  0             15 16                                            63
++     +----------------+------------------------------------------------+
++     |  Type prefix   |                Client address                  |
++     +----------------+------------------------------------------------+
++
++The prefix with all bits zero is reserved for use by the kernel, which
++automatically assigns one address from this prefix to each client on
++connection.  The address in this prefix with all bits zero is always
++assigned to the bus master. Addresses on the prefix 0x0000 are unique
++and will never repeat for the lifetime of the bus master.
++
++A client may have multiple addresses. When data is sent to other
++clients, those clients will always see the sender address that is in
++the prefix 0x0000 address space when calling recvmsg(2) or
++recvfrom(2). Similarly, the prefix 0x0000 address is returned by calls
++to getsockname(2) and getpeername(2).
++
++For each prefix, the address where the least significant 48 bits are
++all 1 (i.e., 0xffffffffffff) is also reserved, and can be used to send
++multicast messages to all the peers on a prefix.
++
++The non-reserved addresses in each of the remaining prefixes are
++managed by the bus master, which may assign additional addresses to
++any other connected socket.
++
++Having different name-spaces has two advantages:
++
++  - Clients can have addresses on different mutually-exclusive
++    scopes. This permits sending multicast packets to only clients
++    that have addresses on a given prefix.
++
++  - The addressing scheme can be more flexible. The kernel will only
++    assign unique addresses on the all-bits-zero prefix (0x0000) and
++    allows the bus master process to assign additional addresses to
++    clients on other prefixes.  By having different prefixes, the
++    kernel and bus master assignments will not collide.
++
++AF_BUS transport can support two network topologies. When a process
++first connects to the bus master, it can only communicate with the bus
++master. The process can't send and receive packets from other peers on
++the bus. So, from the client process point of view the network
++topology is point-to-point.
++
++The bus master can allow the connected peer to be part of the bus and
++start to communicate with other peers by setting a socket option with
++the setsockopt(2) system call using the accepted socket descriptor. At
++this point, the topology becomes a bus to the client process.
++
++Packets whose destination address is not assigned to any client are
++routed by default to the bus master (the client accepted socket
++descriptor).
++
++
++Semantics
++---------
++
++Bus features:
++
++ - Unicast and multicast addressing scheme.
++ - Ability to assign addresses from user-space with different prefixes.
++ - Automatic address assignment.
++ - Ordered packets delivery (FIFO, total ordering).
++ - File descriptor and credentials passing.
++ - Support for both point-to-point and bus network topologies.
++ - Bus control access managed from user-space.
++ - Netfilter hooks for packet sending, routing and receiving.
++
++A process (the "bus master") can create an AF_BUS bus with socket(2)
++and use bind(2) to assign an address to the bus. Then it can listen(2)
++on the created socket to start accepting incoming connections with
++accept(2).
++
++Processes can connect to the bus by creating a socket with socket(2)
++and using connect(2). The kernel will assign a unique address to each
++connection and messages can be sent and received by using BSD socket
++primitives.
++
++This uses the connect(2) semantic in a non-traditional way, with
++AF_BUS sockets, it's not possible to connect "my" socket to a specific
++peer socket whereas the traditional BSD sockets API usage, connect(2)
++either connects to stream sockets, or assigns a peer address to a
++datagram socket (so that send(2) can be used instead of sendto()).
++
++An AF_BUS socket address is represented as a combination of a bus
++address and a bus path name. Address are unique within a path. The
++unique bus address is further subdivided into a prefix and a client
++address. Thus the path identifies a specific bus and the numeric
++component the attachment to that bus.
++
++#define BUS_PATH_MAX    108
++
++/* Bus address */
++struct bus_addr {
++      uint64_t    s_addr;     /* 16-bit prefix + 48-bit client address */
++};
++
++/* Structure describing an AF_BUS socket address. */
++struct sockaddr_bus {
++      sa_family_t     sbus_family;              /* AF_BUS */
++      struct bus_addr sbus_addr;                /* bus address */
++      char            sbus_path[BUS_PATH_MAX];  /* pathname */
++};
++
++A process becomes a bus master for a given struct sockaddr_bus by
++calling bind(2) on an AF_BUS addresses. The argument must be { AF_BUS,
++0, path }.
++
++AF_BUS supports both abstract and non-abstract path names. Abstract
++names are distinguished by the fact that sbus_path[0] == '\0' and they
++don't represent file system paths while non-abstract paths are bound
++to a file system path name. (See the unix(7) man page for a discussion
++of abstract socket addresses in the AF_UNIX address family.)
++
++Then the process calls listen(2) to accept incoming connections. If
++that process calls getsockname(2), the returned address will be {
++AF_BUS, 0, path }.
++
++The conventional string form of the full address is path + ":" +
++prefix + "/" + client address. Prefix and client address are
++represented in hex.
++
++For example the address:
++
++struct sockaddr_bus addr;
++addr.sbus_family = AF_BUS;
++strcpy(addr.sbus_path, "/tmp/test");
++addr.sbus_addr.s_addr   = 0x0002f00ddeadbeef;
++
++would be represented using the string /tmp/test:0002/f00ddeadbeef.
++
++If the bus_addr is 0, then both the prefix and client address may be
++omitted from the string form.  To connect to a bus as a client it is
++sufficient to specify the path, since the listening address always has
++bus_addr == 0. it is not meanigful to specify 'bus_addr' as other than
++0 on connect()
++
++The AF_BUS implementation will automatically assign a unique address
++to each client but the bus master can assign additional addresses on a
++different prefix by means of the setsockopt(2) system call. For
++example:
++
++struct bus_addr addr;
++addr.s_addr = 0x0001deadfee1dead;
++ret = setsockopt(afd, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr));
++
++where afd is the accepted socket descriptor in the daemon. To show graphically:
++
++        L          The AF_BUS listening socket  }
++       /  |  \                                    }-- listener process
++     A1  A2  A3      The AF_BUS accepted sockets  }
++      |   |   |
++     C1  C2  C3      The AF_BUS connected sockets }-- client processes
++
++So if setsockopt(A1, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr)) is
++called, C1 will get the new address.
++
++The inverse operation is BUS_DEL_ADDR, which the bus master can use to
++remove a client socket AF_BUS address:
++
++ret = setsockopt(afd, SOL_BUS, BUS_DEL_ADDR, &addr, sizeof(addr));
++
++Besides assigning additional addresses, the bus master has to allow a
++client process to communicate with other peers on the bus using a
++setsockopt(2):
++
++ret = setsockopt(afd, SOL_BUS, BUS_JOIN_BUS, NULL, 0);
++
++Clients are not meant to send messages to each other until the master
++tells them (in a protocol-specific way) that the BUS_JOIN_BUS
++setsockopt(2) call was made.
++
++If a client sends a message to a destination other than the bus
++master's all-zero address before joining the bus, a EHOSTUNREACH (No
++route to host) error is returned since the only host that exists in
++the point-to-point network before the client joins the bus are the
++client and the bus master.
++
++A EHOSTUNREACH is returned if a client that joined a bus tries to send
++a packet to a client from another bus. Cross-bus communication is not
++permited.
++
++When a process wants to send a unicast message to a peer, it fills a
++sockaddr structure and performs a socket operation (i.e., sendto(2))
++
++struct sockaddr_bus addr;
++char *msg = "Hello world";
++
++addr.sbus_family         = AF_BUS;
++strcpy(addr.sbus_path, "/tmp/test");
++addr.sbus_addr.s_addr   = 0x0001f00ddeadbeef;
++
++ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0,
++          (struct sockaddr*)&addr, sizeof(addr));
++
++The current implementation requires that the addr.sbus_path component
++match the one used to conenct() to the bus but in future this
++requirement will be removed.
++
++The kernel will first check that the socket is connected and that the
++bus path of the socket correspond with the destination, then it will
++extract the prefix and client address from the bus address using a
++fixed 16 -bit bitmask.
++
++prefix                = bus address >> 48 & 0xffff
++client address        = bus address & 0xffff
++
++If the client address is not all bits one, then the message is unicast
++and is delivered to the socket with that assigned address
++(0x0001f00ddeadbeef).  Otherwise the message is multicast and is
++delivered to all the peers with this address prefix (0x0001 in this
++case).
++
++So, when a process wants to send a multicast message, it just has to
++fill the address structure with the address prefix + 0xffffffffffff:
++
++struct sockaddr_bus addr;
++char *msg = "Hello world";
++
++addr.bus_family = AF_BUS;
++strcpy(addr.sbus_path, "/tmp/test");
++addr.bus_addr   = 0x0001ffffffffffff;
++
++ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0,
++          (struct sockaddr*)&addr, sizeof(addr));
++
++The kernel, will apply the binary and operation, learn that the
++address is 0xffffffffffff and send the message to all the peers on
++this prefix (0x0001).
++
++Socket transmit queued bytes are limited by a maximum send buffer size
++(sysctl_wmem_max) defined in the kernel and can be modified at runtime
++using the sysctl interface on /proc/sys/net/core/wmem_default. This
++parameter is global for all the sockets families in a Linux system.
++
++AF_BUS permits the definition of a per-bus maximum send buffer size
++using the BUS_SET_SENDBUF socket option. The bus master can call the
++setsockopt(2) system call using as a parameter the listening socket.
++The command sets a maximum write buffer that will be imposed on each
++new socket that connects to the bus:
++
++ret = setsockopt(serverfd, SOL_BUS, BUS_SET_SENDBUF, &sndbuf,
++sizeof(int));
++
++In the transmission path both Berkeley Packet Filters and Netfilter
++hooks are available, so they can be used to filter sending packets.
++
++
++Using this addressing scheme with D-Bus
++---------------------------------------
++
++As an example of a use case for AF_BUS, let's analyze how the D-Bus
++IPC system can be implemented on top of it.
++
++We define a new D-Bus address type "afbus".
++
++A D-Bus client may connect to an address of the form "afbus:path=X"
++where X is a string. This means that it connect()s to { AF_BUS, 0, X }.
++
++For example: afbus:path=/tmp/test connects to { AF_BUS, 0, /tmp/test }.
++
++A D-Bus daemon may listen on the address "afbus:", which means that it
++binds to { AF_BUS, 0, /tmp/test }. It will advertise an address of the
++form "afbus:path=/tmp/test" to clients, for instance via the
++--print-address option, or via dbus-launch setting the
++DBUS_SESSION_BUS_ADDRESS environment variable.  For instance, "afbus:"
++is an appropriate default listening address for the session bus,
++resulting in dbus-launch setting the DBUS_SESSION_BUS_ADDRESS
++environment variable to something like
++"afbus:path=/tmp/test,guid=...".
++
++A D-Bus daemon may listen on the address "afbus:file=/some/file",
++which means that it will do as above, then write its path into the
++given well-known file.  For instance,
++"afbus:file=/run/dbus/system_bus.afbus" is an appropriate listening
++address for the system bus. Only processes with suitable privileges to
++write to that file can impersonate the system bus.
++
++D-Bus clients wishing to connect to the well-known system bus should
++attempt to connect to afbus:file=/run/dbus/system_bus.afbus, falling
++back to unix:path=/var/run/dbus/system_bus_socket if that fails. On
++Linux systems, the well-known system bus daemon should attempt to
++listen on both of those addresses.
++
++The D-Bus daemon will serve as bus master as well since it will be the
++process that creates and listens on the AF_BUS socket.
++
++D-Bus clients will use the fixed bus master address (all zero bits) to
++send messages to the D-Bus daemon and the client's unique address to
++send messages to other D-Bus clients using the bus.
++
++When initially connected, D-Bus clients will only be able to
++communicate with the D-Bus daemon and will send authentication
++information (AUTH message and SCM_CREDENTIALS ancillary
++messages). Since the D-Bus daemon is also the bus master, it can allow
++D-Bus clients to join the bus and be able to send and receive D-Bus
++messages from other peers.
++
++On connection, the kernel will assign to each client an address in the
++prefix 0x0000. If a client attempts to send messages to clients other
++than the bus master, this is considered to be an error, and is
++prevented by the kernel.
++
++When the D-Bus daemon has authenticated a client and determined that
++it is authorized to be on this bus, it uses a setsockopt(2) call to
++tell the kernel that this client has permission to send messages. The
++D-Bus daemon then tells the client by sending the Hello() reply that
++it has made the setsockopt(2) call and that now is able to send
++messages to other peers on the bus.
++
++Well-known names are represented by addresses in the 0x0001, ... prefixes.
++
++Addresses in prefix 0x0000 must be mapped to D-Bus unique names in a
++way that can't collide with unique names allocated by the dbus-daemon
++for legacy clients.
++
++In order to be consistent with current D-Bus unique naming, the AF_BUS
++addresses can be mapped directly to D-Bus unique names, for example
++(0000/0000deadbeef to ":0.deadbeef"). Leading zeroes can be suppressed
++since the common case should be relatively small numbers (the kernel
++allocates client addresses sequentially, and machines could be
++rebooted occasionally).
++
++By having both AF_BUS and legacy D-Bus clients use the same address
++space, the D-Bus daemon can act as a proxy between clients and can be
++sure that D-Bus unique names will be unique for both AF_BUS and legacy
++clients.
++
++To act as a proxy between AF_BUS and legacy clients, each time the
++D-Bus daemon accepts a legacy connection (i.e., AF_UNIX), it will
++create an AF_BUS socket and establish a connection with itself. It
++will then associate this newly created connection with the legacy one.
++
++To explain it graphically:
++
++        L          The AF_BUS listening socket  }
++       /  |  \                                    }-- listener process
++     A1  A2  A3      The AF_BUS accepted sockets  }
++      |   |   |
++     C1  C2  C3      The AF_BUS connected sockets, where:
++      |                    * C1 belongs to the listener process
++      |                    * C2 and C3 belongs to the client processes
++      |
++ L2--A4       The AF_UNIX listening and accepted sockets \
++      |                            in the listener process
++     C4       The AF_UNIX connected socket in the legacy client process
++
++
++where C2 and C3 are normal AF_BUS clients and C4 is a legacy
++client. The D-Bus daemon after accepting the connection using the
++legacy transport (A4), will create an AF_BUS socket pair (C1, A1)
++associated with the legacy client.
++
++Legacy clients will send messages to the D-Bus daemon using their
++legacy socket and the D-Bus daemon will extract the destination
++address, resolve to the corresponding AF_BUS address and use this to
++send the message to the right peer.
++
++Conversely, when an AF_BUS client sends a D-Bus message to a legacy
++client, it will use the AF_BUS address of the connection associated
++with that client. The D-Bus daemon will receive the message, modify
++the message's content to set SENDER headers based on the AF_BUS source
++address and use the legacy transport to send the D-Bus message to the
++legacy client.
++
++As a special case, the bus daemon's all-zeroes address maps to
++"org.freedesktop.DBus" and vice versa.
++
++When a D-Bus client receives an AF_BUS message from the bus master
++(0/0), it must use the SENDER header field in the D-Bus message, as
++for any other D-Bus transport, to determine whether the message is
++actually from the D-Bus daemon (the SENDER is "org.freedesktop.DBus"
++or missing), or from another client (the SENDER starts with ":"). It
++is valid for messages from another AF_BUS client to be received via
++the D-Bus daemon; if they are, the SENDER header field will always be
++set.
++
++Besides its unique name, D-Bus services can have well-known names such
++as org.gnome.Keyring or org.freedesktop.Telepathy. These well-known
++names can also be used as a D-Bus message destination
++address. Well-known names are not numeric and AF_BUS is not able to
++parse D-Bus messages.
++
++To solve this, the D-Bus daemon will assign an additional AF_BUS
++address to each D-Bus client that owns a well-known name. The mapping
++between well-known names and AF_BUS address is maintained by the D-Bus
++daemon on a persistent data structure.
++
++D-Bus client libraries will maintain a cache of these mappings so they
++can send messages to services with well-known names using their mapped
++AF_BUS address.
++
++If a client intending to send a D-Bus message to a given well-known
++name does not have that well-known name in its cache, it must send the
++AF_BUS message to the listener (0000/000000000000) instead.
++
++The listener must forward the D-Bus message to the owner of that
++well-known name, setting the SENDER header field if necessary. It may
++also send this AF_BUS-specific D-Bus signal to the sender, so that the
++sender can update its cache:
++
++     org.freedesktop.DBus.AF_BUS.Forwarded (STRING well_known_name,
++       UINT64 af_bus_client)
++
++       Emitted by the D-Bus daemon with sender "org.freedesktop.DBus"
++       and object path "/org/freedesktop/DBus" to indicate that
++       the well-known name well_known_name is represented by the
++       AF_BUS address { AF_BUS, af_bus_client, path } where
++       path is the path name used by this bus.
++
++       For instance, if the well-known name "org.gnome.Keyring"
++       is represented by AF_BUS address 0001/0000deadbeef,
++       the signal would have arguments ("org.gnome.Keyring",
++       0x00010000deadbeef), corresponding to the AF_BUS
++       address { AF_BUS, 0x00010000deadbeef, /tmp/test }.
++
++If the D-Bus service for that well-known name is not active, then the
++D-Bus daemon will first do the service activation, assign an
++additional address to the recently activated service, store the
++well-known service to numeric address mapping on its persistent cache,
++and then send the AF_BUS.Forwarded signal back to the client.
++
++Once the mapping has been made, the AF_BUS address associated with a
++well-known name cannot be reused for the lifetime of the D-Bus daemon
++(which is the same as the lifetime of the socket).
++
++Nevertheless the AF_BUS address associated with a well-known name can
++change, for example if a service goes away and a new instance gets
++activated. This new instance can have a different AF_BUS address.  The
++D-Bus daemon will maintain a list of the mappings that are currently
++valid so it can send the AF_BUS.
++
++Forwarded signal with the mapping information to the clients. Client
++libraries will maintain a fixed-size Last Recently Used (LRU) cache
++with previous mappings sent by the D-Bus daemon.
++
++If the clients overwrite a mapping due to the LRU replace policy and
++later want to send a D-Bus message to the overwritten well-known name,
++they will send the D-Bus message back to the D-Bus daemon and this
++will send the signal with the mapping information.
++
++If a service goes away or if the service AF_BUS address changed and
++the client still has the old AF_BUS address in its cache, it will send
++the D-Bus message to the old destination.
++
++Since packets whose destination AF_BUS addresses are not assigned to
++any process are routed by default to the bus master, the D-Bus daemon
++will receive these D-bus messages and send an AF_BUS.
++
++Forwarded signal back to the client with the new AF_BUS address so it
++can update its cache with the new mapping.
++
++For well-known names, the D-Bus daemon will use a different address
++prefix (0x0001) so it doesn't conflict with the D-Bus unique names
++address prefix (0x0000).
++
++Besides D-Bus method call messages which are unicast, D-Bus allows
++clients to send multicast messages (D-Bus signals). Clients can send
++signals messages using the bus unique name prefix multicast address
++(0x0001ffffffffffff).
++
++A netfilter hook is used to filter these multicast messages and only
++deliver to the correct peers based on match rules.
++
++
++D-Bus aware netfilter module
++----------------------------
++
++AF_BUS is designed to be a generic bus transport supporting both
++unicast and multicast communications.
++
++In order for D-Bus to operate efficiently, the transport method has to
++know the D-Bus message wire-protocol and D-Bus message structure. But
++adding this D-Bus specific knowledge to AF_BUS will break one of the
++fundamental design principles of any network protocol stack, namely
++layer-independence: layer n must not make any assumptions about the
++payload in layer n + 1.
++
++So, in order to have a clean protocol design but be able to allow the
++transport to analyze the D-Bus messages, netfilter hooks are used to
++do the filtering based on match rules.
++
++The kernel module has to maintain the match rules and the D-Bus daemon
++is responsible for managing this information. Every time an add match
++rule message is processed by the D-Bus daemon, this will update the
++netfilter module match rules set so the netfilter hook function can
++use that information to do the match rules based filtering.
++
++The D-Bus daemon and the netfilter module will use the generic netlink
++subsystem to do the kernel-to-user-space communication. Netlink is
++already used by most of the networking subsystem in Linux
++(iptables/netfilter, ip/routing, etc).
++
++We enforce a security scheme so only the bus master's user ID can
++update the netfilter module match rules set.
++
++The advantage of using the netfilter subsystem is that we decouple the
++mechanism from the policy. AF_BUS will only add a set of hook points
++and external modules will be used to enforce a given policy.
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch b/patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch
new file mode 100644 (file)
index 0000000..3c2388a
--- /dev/null
@@ -0,0 +1,348 @@
+From 7fcfceea3fefae54e168726703c5030725106e6b Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 12:18:56 +0200
+Subject: [PATCH 03/15] net: bus: add af_bus address and af_bus socket address
+ definitions
+
+An AF_BUS socket can have many addresses associated. This allows to send
+multicast packets on different domains. An af_bus address is an unsigned
+64-bit value that contains two fields: a 16-bit prefix and a 48-bit client
+address.
+
+Each bus has an associated path name that uniquely identifies the bus.
+So, a socket address is composed of the bus path and the peer address.
+
+Clients can send unicast packets to each other and multicast to different
+prefixes but they can only connect(2) to a special socket that owns the
+bus an is known as the bus master.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ include/linux/bus.h  |   34 ++++++
+ include/net/af_bus.h |  273 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 307 insertions(+), 0 deletions(-)
+ create mode 100644 include/linux/bus.h
+ create mode 100644 include/net/af_bus.h
+
+diff --git a/include/linux/bus.h b/include/linux/bus.h
+new file mode 100644
+index 0000000..19cac36
+--- /dev/null
++++ b/include/linux/bus.h
+@@ -0,0 +1,34 @@
++#ifndef _LINUX_BUS_H
++#define _LINUX_BUS_H
++
++#include <linux/socket.h>
++
++/* 'protocol' to use in socket(AF_BUS, SOCK_SEQPACKET, protocol) */
++#define BUS_PROTO_NONE        0
++#define BUS_PROTO_DBUS        1
++#define BUS_PROTO_MAX 1
++
++#define BUS_PATH_MAX  108
++
++/**
++ * struct bus_addr - af_bus address
++ * @s_addr: an af_bus address (16-bit prefix + 48-bit client address)
++ */
++struct bus_addr {
++      u64 s_addr;
++};
++
++
++/**
++ * struct sockaddr_bus - af_bus socket address
++ * @sbus_family: the socket address family
++ * @sbus_addr: an af_bus address
++ * @sbus_path: a path name
++ */
++struct sockaddr_bus {
++      __kernel_sa_family_t sbus_family;
++      struct bus_addr      sbus_addr;
++      char sbus_path[BUS_PATH_MAX];
++};
++
++#endif /* _LINUX_BUS_H */
+diff --git a/include/net/af_bus.h b/include/net/af_bus.h
+new file mode 100644
+index 0000000..e63eb49
+--- /dev/null
++++ b/include/net/af_bus.h
+@@ -0,0 +1,273 @@
++/*
++ * Copyright (c) 2012, GENIVI Alliance
++ *
++ * Authors:   Javier Martinez Canillas, <javier.martinez@collabora.co.uk>
++ *              Alban Crequy, <alban.crequy@collabora.co.uk>
++ *
++ *            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.
++ *
++ * Based on BSD Unix domain sockets (net/unix).
++ */
++
++#ifndef __LINUX_NET_AFBUS_H
++#define __LINUX_NET_AFBUS_H
++
++#include <linux/socket.h>
++#include <linux/bus.h>
++#include <linux/mutex.h>
++#include <net/sock.h>
++#include <net/tcp_states.h>
++
++extern void bus_inflight(struct file *fp);
++extern void bus_notinflight(struct file *fp);
++extern void bus_gc(void);
++extern void wait_for_bus_gc(void);
++extern struct sock *bus_get_socket(struct file *filp);
++extern struct sock *bus_peer_get(struct sock *);
++
++#define BUS_HASH_SIZE 256
++
++extern spinlock_t bus_address_lock;
++extern struct hlist_head bus_address_table[BUS_HASH_SIZE];
++
++#define BUS_MAX_QLEN    10
++#define BUS_MASTER_ADDR 0x0
++#define BUS_PREFIX_BITS 16
++#define BUS_CLIENT_BITS 48
++#define BUS_PREFIX_MASK 0xffff000000000000
++#define BUS_CLIENT_MASK 0x0000ffffffffffff
++
++/* AF_BUS socket options */
++#define BUS_ADD_ADDR 1
++#define BUS_JOIN_BUS 2
++#define BUS_DEL_ADDR 3
++#define BUS_SET_EAVESDROP 4
++#define BUS_UNSET_EAVESDROP 5
++#define BUS_SET_SENDBUF 6
++#define BUS_SET_MAXQLEN 7
++#define BUS_GET_QLENFULL 8
++
++/* Connection and socket states */
++enum {
++      BUS_ESTABLISHED = TCP_ESTABLISHED,
++      BUS_CLOSE = TCP_CLOSE,
++      BUS_LISTEN = TCP_LISTEN,
++      BUS_MAX_STATES
++};
++
++#define NF_BUS_SENDING 1
++
++extern unsigned int bus_tot_inflight;
++extern spinlock_t bus_table_lock;
++extern struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1];
++
++/**
++ * struct bus_address - an af_bus address associated with an af_bus sock
++ * @refcnt: address reference counter
++ * @len: address length
++ * @hash: address hash value
++ * @addr_node: member of struct bus_sock.addr_list
++ * @table_node: member of struct hlist_head bus_address_table[hash]
++ * @sock: the af_bus sock that owns this address
++ * @name: the socket address for this address
++ */
++struct bus_address {
++      atomic_t        refcnt;
++      int             len;
++      unsigned        hash;
++      struct hlist_node addr_node;
++      struct hlist_node table_node;
++      struct sock  *sock;
++      struct sockaddr_bus name[0];
++};
++
++/**
++ * struct bus_send_context - sending context for an socket buffer
++ * @sender_socket: the sender socket associated with this sk_buff
++ * @siocb: used to send ancillary data
++ * @timeo: sending timeout
++ * @max_level: file descriptor passing maximum recursion level
++ * @namelen: length of socket address name
++ * @hash: socket name hash value
++ * @other: destination sock
++ * @sender: sender socket address name
++ * @recipient: recipient socket address name
++ * @authenticated: flag whether the sock already joined the bus
++ * @bus_master_side: flag whether the sock is an accepted socket
++ * @to_master: flag whether the destination is the bus master
++ * @multicast: flag whether the destination is a multicast address
++ * @deliver: flag whether the skb has to be delivered
++ * @eavesdropper: flag whether the sock is allowed to eavesdrop
++ * @main_recipient: flag whether the sock is the main recipient
++ */
++struct bus_send_context {
++      struct socket *sender_socket;
++      struct sock_iocb *siocb;
++      long timeo;
++      int max_level;
++      int namelen;
++      unsigned hash;
++      struct sock *other;
++      struct sockaddr_bus     *sender;
++      struct sockaddr_bus     *recipient;
++      unsigned int            authenticated:1;
++      unsigned int            bus_master_side:1;
++      unsigned int            to_master:1;
++      unsigned int            multicast:1;
++      unsigned int            deliver:1;
++      unsigned int            eavesdropper:1;
++      unsigned int            main_recipient:1;
++};
++
++/**
++ * struct bus_skb_parms - socket buffer parameters
++ * @pid: process id
++ * @cred: skb credentials
++ * @fp: passed file descriptors
++ * @secid: security id
++ * @sendctx: skb sending context
++ */
++struct bus_skb_parms {
++      struct pid              *pid;
++      const struct cred       *cred;
++      struct scm_fp_list      *fp;
++#ifdef CONFIG_SECURITY_NETWORK
++      u32                     secid;
++#endif
++      struct bus_send_context *sendctx;
++};
++
++#define BUSCB(skb)      (*(struct bus_skb_parms *)&((skb)->cb))
++#define BUSSID(skb)     (&BUSCB((skb)).secid)
++
++#define bus_state_lock(s)     spin_lock(&bus_sk(s)->lock)
++#define bus_state_unlock(s)   spin_unlock(&bus_sk(s)->lock)
++#define bus_state_lock_nested(s) \
++                              spin_lock_nested(&bus_sk(s)->lock, \
++                              SINGLE_DEPTH_NESTING)
++
++/**
++ * struct bus - a communication bus
++ * @master: the bus master sock
++ * @peers: list of struct bus_sock.bus_node allowed to join the bus
++ * @lock: protect peers concurrent access
++ * @send_lock: enforce atomic multicast delivery
++ * @kref: bus reference counter
++ * @addr_cnt: address number counter to assign prefix 0x0000 addresses
++ * @eavesdropper_cnt: eavesdroppers counter
++ */
++struct bus {
++      struct sock             *master;
++      struct hlist_head       peers;
++      spinlock_t              lock;
++      spinlock_t              send_lock;
++      struct kref             kref;
++      atomic64_t              addr_cnt;
++      atomic64_t              eavesdropper_cnt;
++};
++
++/**
++ * struct bus_sock - an af_bus socket
++ * @sk: associated sock
++ * @addr: sock principal address
++ * @addr_list: list of struct bus_address.addr_node
++ * @path: sock path name
++ * @readlock: protect from concurrent reading
++ * @peer: peer sock
++ * @other: the listening sock
++ * @link: list of candidates for garbage collection
++ * @inflight: number of times the file descriptor is in flight
++ * @lock: protect the sock from concurrent access
++ * @gc_candidate: flag whether the is a candidate for gc
++ * @gc_maybe_cycle: flag whether could be a cyclic reference
++ * @recursion_level: file passing current recursion level
++ * @peer_wq: peer sock wait queue
++ * @bus: bus that this sock belongs to
++ * @bus_master: flag whether the sock is the bus master
++ * @bus_master_side: flag whether is an accepted socket
++ * @authenticated: flag whether the sock joined the bus
++ * @eavesdropper: flag whether the sock is allowed to eavesdrop
++ * @bus_node: member of struct bus.peers list of joined socks
++ */
++struct bus_sock {
++      /* WARNING: sk has to be the first member */
++      struct sock             sk;
++      struct bus_address     *addr;
++      struct hlist_head       addr_list;
++      struct path             path;
++      struct mutex            readlock;
++      struct sock             *peer;
++      struct sock             *other;
++      struct list_head        link;
++      atomic_long_t           inflight;
++      spinlock_t              lock;
++      unsigned int            gc_candidate:1;
++      unsigned int            gc_maybe_cycle:1;
++      unsigned char           recursion_level;
++      struct socket_wq        peer_wq;
++      struct bus              *bus;
++      bool                    bus_master;
++      bool                    bus_master_side;
++      bool                    authenticated;
++      bool                    eavesdropper;
++      struct hlist_node       bus_node;
++};
++#define bus_sk(__sk) ((struct bus_sock *)__sk)
++
++#define peer_wait peer_wq.wait
++
++/**
++ * bus_same_bus - Test if two socket address belongs to the same bus
++ * @sbusaddr1: socket address name
++ * @sbusaddr2: socket address name
++ */
++static inline bool bus_same_bus(struct sockaddr_bus *sbusaddr1,
++                              struct sockaddr_bus *sbusaddr2)
++{
++      int offset;
++
++      if (sbusaddr1->sbus_path[0] != sbusaddr2->sbus_path[0])
++              return false;
++
++      /*
++       * abstract path names start with a null byte character,
++       * so they have to be compared starting at the second char.
++       */
++      offset = (sbusaddr1->sbus_path[0] == '\0');
++
++      return !strncmp(sbusaddr1->sbus_path + offset,
++                     sbusaddr2->sbus_path + offset,
++                     BUS_PATH_MAX);
++}
++
++static inline unsigned int bus_hash_fold(__wsum n)
++{
++      unsigned int hash = (__force unsigned int)n;
++      hash ^= hash>>16;
++      hash ^= hash>>8;
++      return hash&(BUS_HASH_SIZE-1);
++}
++
++static inline unsigned int bus_compute_hash(struct bus_addr addr)
++{
++      return bus_hash_fold(csum_partial((void *)&addr, sizeof(addr), 0));
++}
++
++long bus_inq_len(struct sock *sk);
++long bus_outq_len(struct sock *sk);
++
++#ifdef CONFIG_SYSCTL
++extern int bus_sysctl_register(struct net *net);
++extern void bus_sysctl_unregister(struct net *net);
++#else
++static inline int bus_sysctl_register(struct net *net) { return 0; }
++static inline void bus_sysctl_unregister(struct net *net) {}
++#endif
++
++bool bus_can_write(struct net *net, struct sockaddr_bus *addr, int len,
++                 int protocol);
++
++#endif /* __LINUX_NET_AFBUS_H */
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch b/patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch
new file mode 100644 (file)
index 0000000..79dc061
--- /dev/null
@@ -0,0 +1,98 @@
+From 67699fea892540b8bdce95ae22ae43c94b684d29 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 14:29:14 +0200
+Subject: [PATCH 04/15] security: Add Linux Security Modules hook for AF_BUS
+ sockets
+
+AF_BUS implements a security hook bus_connect() to be used by LSM
+to enforce connectivity security policies.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ include/linux/security.h |   11 +++++++++++
+ security/capability.c    |    7 +++++++
+ security/security.c      |    7 +++++++
+ 3 files changed, 25 insertions(+), 0 deletions(-)
+
+diff --git a/include/linux/security.h b/include/linux/security.h
+index 673afbb..fa26c6d 100644
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -1578,6 +1578,8 @@ struct security_operations {
+ #ifdef CONFIG_SECURITY_NETWORK
+       int (*unix_stream_connect) (struct sock *sock, struct sock *other, struct sock *newsk);
++      int (*bus_connect) (struct sock *sock, struct sock *other,
++                          struct sock *newsk);
+       int (*unix_may_send) (struct socket *sock, struct socket *other);
+       int (*socket_create) (int family, int type, int protocol, int kern);
+@@ -2517,6 +2519,8 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32
+ #ifdef CONFIG_SECURITY_NETWORK
+ int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk);
++int security_bus_connect(struct sock *sock, struct sock *other,
++                       struct sock *newsk);
+ int security_unix_may_send(struct socket *sock,  struct socket *other);
+ int security_socket_create(int family, int type, int protocol, int kern);
+ int security_socket_post_create(struct socket *sock, int family,
+@@ -2564,6 +2568,13 @@ static inline int security_unix_stream_connect(struct sock *sock,
+       return 0;
+ }
++static inline int security_bus_connect(struct socket *sock,
++                                     struct sock *other,
++                                     struct sock *newsk)
++{
++      return 0;
++}
++
+ static inline int security_unix_may_send(struct socket *sock,
+                                        struct socket *other)
+ {
+diff --git a/security/capability.c b/security/capability.c
+index 5bb21b1..5b966a6 100644
+--- a/security/capability.c
++++ b/security/capability.c
+@@ -563,6 +563,12 @@ static int cap_unix_may_send(struct socket *sock, struct socket *other)
+       return 0;
+ }
++static int cap_bus_connect(struct sock *sock, struct sock *other,
++                         struct sock *newsk)
++{
++      return 0;
++}
++
+ static int cap_socket_create(int family, int type, int protocol, int kern)
+ {
+       return 0;
+@@ -1015,6 +1021,7 @@ void __init security_fixup_ops(struct security_operations *ops)
+ #ifdef CONFIG_SECURITY_NETWORK
+       set_to_cap_if_null(ops, unix_stream_connect);
+       set_to_cap_if_null(ops, unix_may_send);
++      set_to_cap_if_null(ops, bus_connect);
+       set_to_cap_if_null(ops, socket_create);
+       set_to_cap_if_null(ops, socket_post_create);
+       set_to_cap_if_null(ops, socket_bind);
+diff --git a/security/security.c b/security/security.c
+index bf619ff..54582ea 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -1018,6 +1018,13 @@ int security_unix_may_send(struct socket *sock,  struct socket *other)
+ }
+ EXPORT_SYMBOL(security_unix_may_send);
++int security_bus_connect(struct sock *sock, struct sock *other,
++                              struct sock *newsk)
++{
++      return security_ops->bus_connect(sock, other, newsk);
++}
++EXPORT_SYMBOL(security_bus_connect);
++
+ int security_socket_create(int family, int type, int protocol, int kern)
+ {
+       return security_ops->socket_create(family, type, protocol, kern);
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch b/patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch
new file mode 100644 (file)
index 0000000..3eccc0e
--- /dev/null
@@ -0,0 +1,75 @@
+From 714516658e81f2342fe5fd2b8f5493d19f3731b4 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 14:32:26 +0200
+Subject: [PATCH 05/15] security: selinux: Add AF_BUS socket SELinux hooks
+
+Add Security-Enhanced Linux (SELinux) hook for AF_BUS socket address family.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ security/selinux/hooks.c |   35 +++++++++++++++++++++++++++++++++++
+ 1 files changed, 35 insertions(+), 0 deletions(-)
+
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index 5626222..91edbdd 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -67,6 +67,7 @@
+ #include <linux/quota.h>
+ #include <linux/un.h>         /* for Unix socket types */
+ #include <net/af_unix.h>      /* for Unix socket types */
++#include <net/af_bus.h>       /* for Bus socket types */
+ #include <linux/parser.h>
+ #include <linux/nfs_mount.h>
+ #include <net/ipv6.h>
+@@ -4102,6 +4103,39 @@ static int selinux_socket_unix_may_send(struct socket *sock,
+                           &ad);
+ }
++static int selinux_socket_bus_connect(struct sock *sock, struct sock *other,
++                                    struct sock *newsk)
++{
++      struct sk_security_struct *sksec_sock = sock->sk_security;
++      struct sk_security_struct *sksec_other = other->sk_security;
++      struct sk_security_struct *sksec_new = newsk->sk_security;
++      struct common_audit_data ad;
++      struct lsm_network_audit net = {0,};
++      int err;
++
++      ad.type = LSM_AUDIT_DATA_NET;
++      ad.u.net = &net;
++      ad.u.net->sk = other;
++
++      err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
++                         sksec_other->sclass,
++                         UNIX_STREAM_SOCKET__CONNECTTO, &ad);
++      if (err)
++              return err;
++
++      /* server child socket */
++      sksec_new->peer_sid = sksec_sock->sid;
++      err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
++                                  &sksec_new->sid);
++      if (err)
++              return err;
++
++      /* connecting socket */
++      sksec_sock->peer_sid = sksec_new->sid;
++
++      return 0;
++}
++
+ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
+                                   u32 peer_sid,
+                                   struct common_audit_data *ad)
+@@ -5656,6 +5690,7 @@ static struct security_operations selinux_ops = {
+       .unix_stream_connect =          selinux_socket_unix_stream_connect,
+       .unix_may_send =                selinux_socket_unix_may_send,
++      .bus_connect =                  selinux_socket_bus_connect,
+       .socket_create =                selinux_socket_create,
+       .socket_post_create =           selinux_socket_post_create,
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch b/patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch
new file mode 100644 (file)
index 0000000..130f88f
--- /dev/null
@@ -0,0 +1,29 @@
+From b7943d96bba05258c0eeabed0aa6e006a3ec06ec Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 14:59:16 +0200
+Subject: [PATCH 06/15] netfilter: add NFPROTO_BUS hook constant for AF_BUS
+ socket family
+
+AF_BUS sockets add a netfilter NF_HOOK() on the packet sending path.
+This allows packet to be mangled by registered netfilter hooks.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ include/linux/netfilter.h |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
+index 29734be..7cff0bd 100644
+--- a/include/linux/netfilter.h
++++ b/include/linux/netfilter.h
+@@ -67,6 +67,7 @@ enum {
+       NFPROTO_BRIDGE =  7,
+       NFPROTO_IPV6   = 10,
+       NFPROTO_DECNET = 12,
++      NFPROTO_BUS,
+       NFPROTO_NUMPROTO,
+ };
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch b/patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch
new file mode 100644 (file)
index 0000000..935cb39
--- /dev/null
@@ -0,0 +1,36 @@
+From efe7f1ea3bc352b350671bb8c2b5e573672faf6a Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 15:22:08 +0200
+Subject: [PATCH 07/15] scm: allow AF_BUS sockets to send ancillary data
+
+UNIX domain sockets support passing file descriptors or process
+credentials in the form of ancillary data.
+
+Since AF_BUS sockets are used to communicate processes on a local
+machine, they should also support passing control messages.
+The core socket level control messages processing only allows sockets
+whose family is PF_UNIX to send SCM_RIGHTS type messages. So, let's
+also allow to PF_BUS sockets.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ net/core/scm.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/net/core/scm.c b/net/core/scm.c
+index 611c5ef..87e3152 100644
+--- a/net/core/scm.c
++++ b/net/core/scm.c
+@@ -158,7 +158,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
+               switch (cmsg->cmsg_type)
+               {
+               case SCM_RIGHTS:
+-                      if (!sock->ops || sock->ops->family != PF_UNIX)
++                      if (!sock->ops || (sock->ops->family != PF_UNIX &&
++                                         sock->ops->family != PF_BUS))
+                               goto error;
+                       err=scm_fp_copy(cmsg, &p->fp);
+                       if (err<0)
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch b/patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch
new file mode 100644 (file)
index 0000000..e748e56
--- /dev/null
@@ -0,0 +1,2739 @@
+From d1bbdbce93bba76325b0d22da84cb8833da49df0 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 15:29:34 +0200
+Subject: [PATCH 08/15] net: bus: Add implementation of Bus domain sockets
+
+Each process connected to an AF_BUS socket, has one or more addresses
+within that bus. These addresses are 64-bit unsigned integers,
+interpreted by splitting the address into two parts: the most significant
+16 bits are a prefix identifying the type of address, and the remaining
+48 bits are the actual client address within that prefix.
+
+The process that calls bind(2) on the socket is the owner of the bus and
+is called the bus master. The master is a special client of the bus and has
+some responsibility for the bus' operation. The master is assigned a fixed
+address with all the bits zero.
+
+The prefix with all bits zero is reserved for use by the kernel, which
+automatically assigns one address from this prefix to each client on
+connection. The address in this prefix with all bits zero is always
+assigned to the bus master. Addresses on the prefix 0000 are unique
+and will never repeat for the lifetime of the bus master.
+
+AF_BUS transport can support two network topologies. When a process
+first connect to the bus master, it can only communicate with the
+bus master. The process can't send and receive packets from other
+peers on the bus. So, from the client process point of view the
+network topology is point-to-point.
+
+The bus master can allow the connected peer to be part of the bus
+and start to communicate with other peers by setting an socket option
+with the setsockopt(2) system call using the accepted socket descriptor.
+At this point, the topology becomes a bus to the client process.
+
+Packets whose destination address is not assigned to any client are routed
+by default to the bus master (the client accepted socket descriptor).
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ net/bus/af_bus.c | 2688 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 2688 insertions(+), 0 deletions(-)
+ create mode 100644 net/bus/af_bus.c
+
+diff --git a/net/bus/af_bus.c b/net/bus/af_bus.c
+new file mode 100644
+index 0000000..d25af65
+--- /dev/null
++++ b/net/bus/af_bus.c
+@@ -0,0 +1,2688 @@
++/*
++ * Implementation of Bus domain sockets.
++ *
++ * Copyright (c) 2012, GENIVI Alliance
++ *
++ * Authors:   Javier Martinez Canillas <javier.martinez@collabora.co.uk>
++ *              Alban Crequy <alban.crequy@collabora.co.uk>
++ *
++ *            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.
++ *
++ * Based on BSD Unix domain sockets (net/unix).
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/stat.h>
++#include <linux/dcache.h>
++#include <linux/namei.h>
++#include <linux/socket.h>
++#include <linux/bus.h>
++#include <linux/fcntl.h>
++#include <linux/termios.h>
++#include <linux/sockios.h>
++#include <linux/net.h>
++#include <linux/in.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/net_namespace.h>
++#include <net/sock.h>
++#include <net/af_bus.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <net/scm.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/rtnetlink.h>
++#include <linux/mount.h>
++#include <net/checksum.h>
++#include <linux/security.h>
++
++struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1];
++EXPORT_SYMBOL_GPL(bus_socket_table);
++struct hlist_head bus_address_table[BUS_HASH_SIZE];
++EXPORT_SYMBOL_GPL(bus_address_table);
++DEFINE_SPINLOCK(bus_table_lock);
++DEFINE_SPINLOCK(bus_address_lock);
++EXPORT_SYMBOL_GPL(bus_address_lock);
++static atomic_long_t bus_nr_socks;
++
++#define bus_sockets_unbound   (&bus_socket_table[BUS_HASH_SIZE])
++
++#define BUS_ABSTRACT(sk)      (bus_sk(sk)->addr->hash != BUS_HASH_SIZE)
++
++#ifdef CONFIG_SECURITY_NETWORK
++static void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{
++      memcpy(BUSSID(skb), &scm->secid, sizeof(u32));
++}
++
++static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{
++      scm->secid = *BUSSID(skb);
++}
++#else
++static inline void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{ }
++
++static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{ }
++#endif /* CONFIG_SECURITY_NETWORK */
++
++/*
++ *  SMP locking strategy:
++ *    bus_socket_table hash table is protected with spinlock bus_table_lock
++ *    bus_address_table hash table is protected with spinlock bus_address_lock
++ *    each bus is protected by a separate spin lock.
++ *    multicast atomic sending is protected by a separate spin lock.
++ *    each socket state is protected by a separate spin lock.
++ *    each socket address is protected by a separate spin lock.
++ *
++ *  When holding more than one lock, use the following hierarchy:
++ *  - bus_table_lock.
++ *  - bus_address_lock.
++ *  - socket lock.
++ *  - bus lock.
++ *  - bus send_lock.
++ *  - sock address lock.
++ */
++
++#define bus_peer(sk) (bus_sk(sk)->peer)
++
++static inline int bus_our_peer(struct sock *sk, struct sock *osk)
++{
++      return bus_peer(osk) == sk;
++}
++
++static inline int bus_recvq_full(struct sock const *sk)
++{
++      return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog;
++}
++
++static inline u16 bus_addr_prefix(struct sockaddr_bus *busaddr)
++{
++      return (busaddr->sbus_addr.s_addr & BUS_PREFIX_MASK) >> BUS_CLIENT_BITS;
++}
++
++static inline u64 bus_addr_client(struct sockaddr_bus *sbusaddr)
++{
++      return sbusaddr->sbus_addr.s_addr & BUS_CLIENT_MASK;
++}
++
++static inline bool bus_mc_addr(struct sockaddr_bus *sbusaddr)
++{
++      return bus_addr_client(sbusaddr) == BUS_CLIENT_MASK;
++}
++
++struct sock *bus_peer_get(struct sock *s)
++{
++      struct sock *peer;
++
++      bus_state_lock(s);
++      peer = bus_peer(s);
++      if (peer)
++              sock_hold(peer);
++      bus_state_unlock(s);
++      return peer;
++}
++EXPORT_SYMBOL_GPL(bus_peer_get);
++
++static inline void bus_release_addr(struct bus_address *addr)
++{
++      if (atomic_dec_and_test(&addr->refcnt))
++              kfree(addr);
++}
++
++/*
++ *    Check bus socket name:
++ *            - should be not zero length.
++ *            - if started by not zero, should be NULL terminated (FS object)
++ *            - if started by zero, it is abstract name.
++ */
++
++static int bus_mkname(struct sockaddr_bus *sbusaddr, int len,
++                    unsigned int *hashp)
++{
++      int offset = (sbusaddr->sbus_path[0] == '\0');
++
++      if (len <= sizeof(short) || len > sizeof(*sbusaddr))
++              return -EINVAL;
++      if (!sbusaddr || sbusaddr->sbus_family != AF_BUS)
++              return -EINVAL;
++
++      len = strnlen(sbusaddr->sbus_path + offset, BUS_PATH_MAX) + 1 +
++              sizeof(__kernel_sa_family_t) +
++              sizeof(struct bus_addr);
++
++      *hashp = bus_compute_hash(sbusaddr->sbus_addr);
++      return len;
++}
++
++static void __bus_remove_address(struct bus_address *addr)
++{
++      hlist_del(&addr->table_node);
++}
++
++static void __bus_insert_address(struct hlist_head *list,
++                               struct bus_address *addr)
++{
++      hlist_add_head(&addr->table_node, list);
++}
++
++static inline void bus_remove_address(struct bus_address *addr)
++{
++      spin_lock(&bus_address_lock);
++      __bus_remove_address(addr);
++      spin_unlock(&bus_address_lock);
++}
++
++static inline void bus_insert_address(struct hlist_head *list,
++                                    struct bus_address *addr)
++{
++      spin_lock(&bus_address_lock);
++      __bus_insert_address(list, addr);
++      spin_unlock(&bus_address_lock);
++}
++
++static void __bus_remove_socket(struct sock *sk)
++{
++      sk_del_node_init(sk);
++}
++
++static void __bus_insert_socket(struct hlist_head *list, struct sock *sk)
++{
++      WARN_ON(!sk_unhashed(sk));
++      sk_add_node(sk, list);
++}
++
++static inline void bus_remove_socket(struct sock *sk)
++{
++      spin_lock(&bus_table_lock);
++      __bus_remove_socket(sk);
++      spin_unlock(&bus_table_lock);
++}
++
++static inline void bus_insert_socket(struct hlist_head *list, struct sock *sk)
++{
++      spin_lock(&bus_table_lock);
++      __bus_insert_socket(list, sk);
++      spin_unlock(&bus_table_lock);
++}
++
++static inline bool __bus_has_prefix(struct sock *sk, u16 prefix)
++{
++      struct bus_sock *u = bus_sk(sk);
++      struct bus_address *addr;
++      struct hlist_node *node;
++      bool ret = false;
++
++      hlist_for_each_entry(addr, node, &u->addr_list, addr_node) {
++              if (bus_addr_prefix(addr->name) == prefix)
++                      ret = true;
++      }
++
++      return ret;
++}
++
++static inline bool bus_has_prefix(struct sock *sk, u16 prefix)
++{
++      bool ret;
++
++      bus_state_lock(sk);
++      ret = __bus_has_prefix(sk, prefix);
++      bus_state_unlock(sk);
++
++      return ret;
++}
++
++static inline bool __bus_eavesdropper(struct sock *sk, u16 condition)
++{
++      struct bus_sock *u = bus_sk(sk);
++
++      return u->eavesdropper;
++}
++
++static inline bool bus_eavesdropper(struct sock *sk, u16 condition)
++{
++      bool ret;
++
++      bus_state_lock(sk);
++      ret = __bus_eavesdropper(sk, condition);
++      bus_state_unlock(sk);
++
++      return ret;
++}
++
++static inline bool bus_has_prefix_eavesdropper(struct sock *sk, u16 prefix)
++{
++      bool ret;
++
++      bus_state_lock(sk);
++      ret = __bus_has_prefix(sk, prefix) || __bus_eavesdropper(sk, 0);
++      bus_state_unlock(sk);
++
++      return ret;
++}
++
++static inline struct bus_address *__bus_get_address(struct sock *sk,
++                                                  struct bus_addr *sbus_addr)
++{
++      struct bus_sock *u = bus_sk(sk);
++      struct bus_address *addr = NULL;
++      struct hlist_node *node;
++
++      hlist_for_each_entry(addr, node, &u->addr_list, addr_node) {
++              if (addr->name->sbus_addr.s_addr == sbus_addr->s_addr)
++                      return addr;
++      }
++
++      return NULL;
++}
++
++static inline struct bus_address *bus_get_address(struct sock *sk,
++                                                struct bus_addr *sbus_addr)
++{
++      struct bus_address *addr;
++
++      bus_state_lock(sk);
++      addr = __bus_get_address(sk, sbus_addr);
++      bus_state_unlock(sk);
++
++      return addr;
++}
++
++static struct sock *__bus_find_socket_byname(struct net *net,
++                                           struct sockaddr_bus *sbusname,
++                                           int len, unsigned int hash)
++{
++      struct sock *s;
++      struct hlist_node *node;
++
++      sk_for_each(s, node, &bus_socket_table[hash]) {
++              struct bus_sock *u = bus_sk(s);
++
++              if (!net_eq(sock_net(s), net))
++                      continue;
++
++              if (u->addr->len == len &&
++                  !memcmp(u->addr->name, sbusname, len))
++                      return s;
++      }
++
++      return NULL;
++}
++
++static inline struct sock *bus_find_socket_byname(struct net *net,
++                                                struct sockaddr_bus *sbusname,
++                                                int len, unsigned int hash)
++{
++      struct sock *s;
++
++      spin_lock(&bus_table_lock);
++      s = __bus_find_socket_byname(net, sbusname, len, hash);
++      if (s)
++              sock_hold(s);
++      spin_unlock(&bus_table_lock);
++      return s;
++}
++
++static struct sock *__bus_find_socket_byaddress(struct net *net,
++                                              struct sockaddr_bus *sbusname,
++                                              int len, int protocol,
++                                              unsigned int hash)
++{
++      struct sock *s;
++      struct bus_address *addr;
++      struct hlist_node *node;
++      struct bus_sock *u;
++      int offset = (sbusname->sbus_path[0] == '\0');
++      int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX);
++
++      len = path_len + 1 + sizeof(__kernel_sa_family_t) +
++            sizeof(struct bus_addr);
++
++      hlist_for_each_entry(addr, node, &bus_address_table[hash],
++                           table_node) {
++              s = addr->sock;
++              u = bus_sk(s);
++
++              if (s->sk_protocol != protocol)
++                      continue;
++
++              if (!net_eq(sock_net(s), net))
++                      continue;
++
++              if (addr->len == len &&
++                  addr->name->sbus_family == sbusname->sbus_family &&
++                  addr->name->sbus_addr.s_addr == sbusname->sbus_addr.s_addr
++                  && bus_same_bus(addr->name, sbusname))
++                      goto found;
++      }
++      s = NULL;
++found:
++      return s;
++}
++
++static inline struct sock *bus_find_socket_byaddress(struct net *net,
++                                                   struct sockaddr_bus *name,
++                                                   int len, int protocol,
++                                                   unsigned int hash)
++{
++      struct sock *s;
++
++      spin_lock(&bus_address_lock);
++      s = __bus_find_socket_byaddress(net, name, len, protocol, hash);
++      if (s)
++              sock_hold(s);
++      spin_unlock(&bus_address_lock);
++      return s;
++}
++
++static inline int bus_writable(struct sock *sk)
++{
++      return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
++}
++
++static void bus_write_space(struct sock *sk)
++{
++      struct bus_sock *u = bus_sk(sk);
++      struct bus_sock *p;
++      struct hlist_node *node;
++      struct socket_wq *wq;
++
++      if (bus_writable(sk)) {
++              rcu_read_lock();
++              wq = rcu_dereference(sk->sk_wq);
++              if (wq_has_sleeper(wq))
++                      wake_up_interruptible_sync_poll(&wq->wait,
++                              POLLOUT | POLLWRNORM | POLLWRBAND);
++              sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
++              rcu_read_unlock();
++
++              if (u && u->bus) {
++                      spin_lock(&u->bus->lock);
++                      hlist_for_each_entry(p, node, &u->bus->peers,
++                                           bus_node) {
++                              wake_up_interruptible_sync_poll(sk_sleep(&p->sk),
++                                                              POLLOUT |
++                                                              POLLWRNORM |
++                                                              POLLWRBAND);
++                              sk_wake_async(&p->sk, SOCK_WAKE_SPACE,
++                                            POLL_OUT);
++                      }
++                      spin_unlock(&u->bus->lock);
++              }
++      }
++}
++
++static void bus_bus_release(struct kref *kref)
++{
++      struct bus *bus;
++
++      bus = container_of(kref, struct bus, kref);
++
++      kfree(bus);
++}
++
++static void bus_sock_destructor(struct sock *sk)
++{
++      struct bus_sock *u = bus_sk(sk);
++
++      skb_queue_purge(&sk->sk_receive_queue);
++
++      WARN_ON(atomic_read(&sk->sk_wmem_alloc));
++      WARN_ON(!sk_unhashed(sk));
++      WARN_ON(sk->sk_socket);
++      if (!sock_flag(sk, SOCK_DEAD)) {
++              pr_info("Attempt to release alive bus socket: %p\n", sk);
++              return;
++      }
++
++      if (u->bus) {
++              kref_put(&u->bus->kref, bus_bus_release);
++              u->bus = NULL;
++      }
++
++      atomic_long_dec(&bus_nr_socks);
++      local_bh_disable();
++      sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
++      local_bh_enable();
++#ifdef BUS_REFCNT_DEBUG
++      pr_debug("BUS %p is destroyed, %ld are still alive.\n", sk,
++               atomic_long_read(&bus_nr_socks));
++#endif
++}
++
++static int bus_release_sock(struct sock *sk, int embrion)
++{
++      struct bus_sock *u = bus_sk(sk);
++      struct path path;
++      struct sock *skpair;
++      struct sk_buff *skb;
++      int state;
++      struct bus_address *addr;
++      struct hlist_node *node, *tmp;
++
++      bus_remove_socket(sk);
++
++      if (u->bus && u->authenticated &&
++          !u->bus_master && !u->bus_master_side) {
++              spin_lock(&u->bus->lock);
++              hlist_del(&u->bus_node);
++              if (u->eavesdropper)
++                      atomic64_dec(&u->bus->eavesdropper_cnt);
++              spin_unlock(&u->bus->lock);
++      }
++
++      /* Clear state */
++      bus_state_lock(sk);
++      sock_orphan(sk);
++      sk->sk_shutdown = SHUTDOWN_MASK;
++      path         = u->path;
++      u->path.dentry = NULL;
++      u->path.mnt = NULL;
++      state = sk->sk_state;
++      sk->sk_state = BUS_CLOSE;
++
++      if (u->bus_master)
++                      u->bus->master = NULL;
++
++      if (u->bus_master_side) {
++              bus_release_addr(u->addr);
++              u->addr = NULL;
++      } else {
++              u->addr = NULL;
++
++              spin_lock(&bus_address_lock);
++              hlist_for_each_entry_safe(addr, node, tmp, &u->addr_list,
++                                        addr_node) {
++                      hlist_del(&addr->addr_node);
++                      __bus_remove_address(addr);
++                      bus_release_addr(addr);
++              }
++              spin_unlock(&bus_address_lock);
++      }
++
++      bus_state_unlock(sk);
++
++      wake_up_interruptible_all(&u->peer_wait);
++
++      skpair = bus_peer(sk);
++
++      if (skpair != NULL) {
++              bus_state_lock(skpair);
++              /* No more writes */
++              skpair->sk_shutdown = SHUTDOWN_MASK;
++              if (!skb_queue_empty(&sk->sk_receive_queue) || embrion)
++                      skpair->sk_err = ECONNRESET;
++              bus_state_unlock(skpair);
++              skpair->sk_state_change(skpair);
++              sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
++              sock_put(skpair); /* It may now die */
++              bus_peer(sk) = NULL;
++      }
++
++      /* Try to flush out this socket. Throw out buffers at least */
++
++      while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
++              if (state == BUS_LISTEN)
++                      bus_release_sock(skb->sk, 1);
++              /* passed fds are erased in the kfree_skb hook        */
++              kfree_skb(skb);
++      }
++
++      if (path.dentry)
++              path_put(&path);
++
++      sock_put(sk);
++
++      /* ---- Socket is dead now and most probably destroyed ---- */
++
++      if (bus_tot_inflight)
++              bus_gc();               /* Garbage collect fds */
++
++      return 0;
++}
++
++static void init_peercred(struct sock *sk)
++{
++      put_pid(sk->sk_peer_pid);
++      if (sk->sk_peer_cred)
++              put_cred(sk->sk_peer_cred);
++      sk->sk_peer_pid  = get_pid(task_tgid(current));
++      sk->sk_peer_cred = get_current_cred();
++}
++
++static void copy_peercred(struct sock *sk, struct sock *peersk)
++{
++      put_pid(sk->sk_peer_pid);
++      if (sk->sk_peer_cred)
++              put_cred(sk->sk_peer_cred);
++      sk->sk_peer_pid  = get_pid(peersk->sk_peer_pid);
++      sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
++}
++
++static int bus_listen(struct socket *sock, int backlog)
++{
++      int err;
++      struct sock *sk = sock->sk;
++      struct bus_sock *u = bus_sk(sk);
++      struct pid *old_pid = NULL;
++      const struct cred *old_cred = NULL;
++
++      err = -EINVAL;
++      if (!u->addr || !u->bus_master)
++              goto out;       /* Only listens on an bound an master socket */
++      bus_state_lock(sk);
++      if (sk->sk_state != BUS_CLOSE && sk->sk_state != BUS_LISTEN)
++              goto out_unlock;
++      if (backlog > sk->sk_max_ack_backlog)
++              wake_up_interruptible_all(&u->peer_wait);
++      sk->sk_max_ack_backlog  = backlog;
++      sk->sk_state            = BUS_LISTEN;
++      /* set credentials so connect can copy them */
++      init_peercred(sk);
++      err = 0;
++
++out_unlock:
++      bus_state_unlock(sk);
++      put_pid(old_pid);
++      if (old_cred)
++              put_cred(old_cred);
++out:
++      return err;
++}
++
++static int bus_release(struct socket *);
++static int bus_bind(struct socket *, struct sockaddr *, int);
++static int bus_connect(struct socket *, struct sockaddr *,
++                             int addr_len, int flags);
++static int bus_accept(struct socket *, struct socket *, int);
++static int bus_getname(struct socket *, struct sockaddr *, int *, int);
++static unsigned int bus_poll(struct file *, struct socket *,
++                                  poll_table *);
++static int bus_ioctl(struct socket *, unsigned int, unsigned long);
++static int bus_shutdown(struct socket *, int);
++static int bus_setsockopt(struct socket *, int, int, char __user *,
++                         unsigned int);
++static int bus_sendmsg(struct kiocb *, struct socket *,
++                     struct msghdr *, size_t);
++static int bus_recvmsg(struct kiocb *, struct socket *,
++                     struct msghdr *, size_t, int);
++
++static void bus_set_peek_off(struct sock *sk, int val)
++{
++      struct bus_sock *u = bus_sk(sk);
++
++      mutex_lock(&u->readlock);
++      sk->sk_peek_off = val;
++      mutex_unlock(&u->readlock);
++}
++
++static const struct proto_ops bus_seqpacket_ops = {
++      .family =       PF_BUS,
++      .owner =        THIS_MODULE,
++      .release =      bus_release,
++      .bind =         bus_bind,
++      .connect =      bus_connect,
++      .socketpair =   sock_no_socketpair,
++      .accept =       bus_accept,
++      .getname =      bus_getname,
++      .poll =         bus_poll,
++      .ioctl =        bus_ioctl,
++      .listen =       bus_listen,
++      .shutdown =     bus_shutdown,
++      .setsockopt =   bus_setsockopt,
++      .getsockopt =   sock_no_getsockopt,
++      .sendmsg =      bus_sendmsg,
++      .recvmsg =      bus_recvmsg,
++      .mmap =         sock_no_mmap,
++      .sendpage =     sock_no_sendpage,
++      .set_peek_off = bus_set_peek_off,
++};
++
++static struct proto bus_proto = {
++      .name                   = "BUS",
++      .owner                  = THIS_MODULE,
++      .obj_size               = sizeof(struct bus_sock),
++};
++
++/*
++ * AF_BUS sockets do not interact with hardware, hence they
++ * dont trigger interrupts - so it's safe for them to have
++ * bh-unsafe locking for their sk_receive_queue.lock. Split off
++ * this special lock-class by reinitializing the spinlock key:
++ */
++static struct lock_class_key af_bus_sk_receive_queue_lock_key;
++
++static struct sock *bus_create1(struct net *net, struct socket *sock)
++{
++      struct sock *sk = NULL;
++      struct bus_sock *u;
++
++      atomic_long_inc(&bus_nr_socks);
++      if (atomic_long_read(&bus_nr_socks) > 2 * get_max_files())
++              goto out;
++
++      sk = sk_alloc(net, PF_BUS, GFP_KERNEL, &bus_proto);
++      if (!sk)
++              goto out;
++
++      sock_init_data(sock, sk);
++      lockdep_set_class(&sk->sk_receive_queue.lock,
++                              &af_bus_sk_receive_queue_lock_key);
++
++      sk->sk_write_space      = bus_write_space;
++      sk->sk_max_ack_backlog  = BUS_MAX_QLEN;
++      sk->sk_destruct         = bus_sock_destructor;
++      u         = bus_sk(sk);
++      u->path.dentry = NULL;
++      u->path.mnt = NULL;
++      u->bus = NULL;
++      u->bus_master = false;
++      u->authenticated = false;
++      u->eavesdropper = false;
++      spin_lock_init(&u->lock);
++      atomic_long_set(&u->inflight, 0);
++      INIT_LIST_HEAD(&u->link);
++      INIT_HLIST_HEAD(&u->addr_list);
++      INIT_HLIST_NODE(&u->bus_node);
++      mutex_init(&u->readlock); /* single task reading lock */
++      init_waitqueue_head(&u->peer_wait);
++      bus_insert_socket(bus_sockets_unbound, sk);
++out:
++      if (sk == NULL)
++              atomic_long_dec(&bus_nr_socks);
++      else {
++              local_bh_disable();
++              sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
++              local_bh_enable();
++      }
++      return sk;
++}
++
++static int bus_create(struct net *net, struct socket *sock, int protocol,
++                     int kern)
++{
++      struct sock *sk;
++
++      if (protocol < BUS_PROTO_NONE || protocol > BUS_PROTO_DBUS)
++              return -EPROTONOSUPPORT;
++
++      if (protocol != BUS_PROTO_NONE)
++              request_module("net-pf-%d-proto-%d", PF_BUS, protocol);
++
++      sock->state = SS_UNCONNECTED;
++
++      if (sock->type == SOCK_SEQPACKET)
++              sock->ops = &bus_seqpacket_ops;
++      else
++              return -ESOCKTNOSUPPORT;
++
++      sk = bus_create1(net, sock);
++      if (!sk)
++              return -ENOMEM;
++
++      sk->sk_protocol = protocol;
++
++      return 0;
++}
++
++static int bus_release(struct socket *sock)
++{
++      struct sock *sk = sock->sk;
++
++      if (!sk)
++              return 0;
++
++      sock->sk = NULL;
++
++      return bus_release_sock(sk, 0);
++}
++
++static struct sock *bus_find_other(struct net *net,
++                                 struct sockaddr_bus *sbusname, int len,
++                                 int protocol, unsigned int hash, int *error)
++{
++      struct sock *u;
++      struct path path;
++      int err = 0;
++
++      if (sbusname->sbus_path[0]) {
++              struct inode *inode;
++              err = kern_path(sbusname->sbus_path, LOOKUP_FOLLOW, &path);
++              if (err)
++                      goto fail;
++              inode = path.dentry->d_inode;
++              err = inode_permission(inode, MAY_WRITE);
++              if (err)
++                      goto put_fail;
++
++              err = -ECONNREFUSED;
++              if (!S_ISSOCK(inode->i_mode))
++                      goto put_fail;
++              u = bus_find_socket_byaddress(net, sbusname, len, protocol,
++                                            hash);
++              if (!u)
++                      goto put_fail;
++
++              touch_atime(&path);
++              path_put(&path);
++
++      } else {
++              err = -ECONNREFUSED;
++              u = bus_find_socket_byaddress(net, sbusname, len, protocol, hash);
++              if (u) {
++                      struct dentry *dentry;
++                      dentry = bus_sk(u)->path.dentry;
++                      if (dentry)
++                              touch_atime(&bus_sk(u)->path);
++              } else
++                      goto fail;
++      }
++
++      return u;
++
++put_fail:
++      path_put(&path);
++fail:
++      *error = err;
++      return NULL;
++}
++
++
++static int bus_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
++{
++      struct sock *sk = sock->sk;
++      struct net *net = sock_net(sk);
++      struct bus_sock *u = bus_sk(sk);
++      struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr;
++      char *sbus_path = sbusaddr->sbus_path;
++      struct dentry *dentry = NULL;
++      struct path path;
++      int err;
++      unsigned int hash;
++      struct bus_address *addr;
++      struct hlist_head *list;
++      struct bus *bus;
++
++      err = -EINVAL;
++      if (sbusaddr->sbus_family != AF_BUS)
++              goto out;
++
++      /* If the address is available, the socket is the bus master */
++      sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR;
++
++      err = bus_mkname(sbusaddr, addr_len, &hash);
++      if (err < 0)
++              goto out;
++      addr_len = err;
++
++      mutex_lock(&u->readlock);
++
++      err = -EINVAL;
++      if (u->addr)
++              goto out_up;
++
++      err = -ENOMEM;
++      addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL);
++      if (!addr)
++              goto out_up;
++
++      memcpy(addr->name, sbusaddr, sizeof(struct sockaddr_bus));
++      addr->len = addr_len;
++      addr->hash = hash;
++      atomic_set(&addr->refcnt, 1);
++      addr->sock = sk;
++      INIT_HLIST_NODE(&addr->addr_node);
++      INIT_HLIST_NODE(&addr->table_node);
++
++      if (sbus_path[0]) {
++              umode_t mode;
++              err = 0;
++              /*
++               * Get the parent directory, calculate the hash for last
++               * component.
++               */
++              dentry = kern_path_create(AT_FDCWD, sbus_path, &path, 0);
++              err = PTR_ERR(dentry);
++              if (IS_ERR(dentry))
++                      goto out_mknod_parent;
++
++              /*
++               * All right, let's create it.
++               */
++              mode = S_IFSOCK |
++                     (SOCK_INODE(sock)->i_mode & ~current_umask());
++              err = mnt_want_write(path.mnt);
++              if (err)
++                      goto out_mknod_dput;
++              err = security_path_mknod(&path, dentry, mode, 0);
++              if (err)
++                      goto out_mknod_drop_write;
++              err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
++out_mknod_drop_write:
++              mnt_drop_write(path.mnt);
++              if (err)
++                      goto out_mknod_dput;
++              mutex_unlock(&path.dentry->d_inode->i_mutex);
++              dput(path.dentry);
++              path.dentry = dentry;
++      }
++
++      err = -ENOMEM;
++      bus = kzalloc(sizeof(*bus), GFP_KERNEL);
++      if (!bus)
++              goto out_unlock;
++
++      spin_lock(&bus_table_lock);
++
++      if (!sbus_path[0]) {
++              err = -EADDRINUSE;
++              if (__bus_find_socket_byname(net, sbusaddr, addr_len, hash)) {
++                      bus_release_addr(addr);
++                      kfree(bus);
++                      goto out_unlock;
++              }
++
++              list = &bus_socket_table[addr->hash];
++      } else {
++              list = &bus_socket_table[dentry->d_inode->i_ino &
++                                       (BUS_HASH_SIZE-1)];
++              u->path = path;
++      }
++
++      kref_init(&bus->kref);
++      bus->master = sk;
++      INIT_HLIST_HEAD(&bus->peers);
++      spin_lock_init(&bus->lock);
++      spin_lock_init(&bus->send_lock);
++      atomic64_set(&bus->addr_cnt, 0);
++      atomic64_set(&bus->eavesdropper_cnt, 0);
++
++      hlist_add_head(&addr->addr_node, &u->addr_list);
++
++      err = 0;
++      __bus_remove_socket(sk);
++      u->addr = addr;
++      u->bus_master = true;
++      u->bus = bus;
++      __bus_insert_socket(list, sk);
++      bus_insert_address(&bus_address_table[addr->hash], addr);
++
++out_unlock:
++      spin_unlock(&bus_table_lock);
++out_up:
++      mutex_unlock(&u->readlock);
++out:
++      return err;
++
++out_mknod_dput:
++      dput(dentry);
++      mutex_unlock(&path.dentry->d_inode->i_mutex);
++      path_put(&path);
++out_mknod_parent:
++      if (err == -EEXIST)
++              err = -EADDRINUSE;
++      bus_release_addr(addr);
++      goto out_up;
++}
++
++static long bus_wait_for_peer(struct sock *other, long timeo)
++{
++      struct bus_sock *u = bus_sk(other);
++      int sched;
++      DEFINE_WAIT(wait);
++
++      prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE);
++
++      sched = !sock_flag(other, SOCK_DEAD) &&
++              !(other->sk_shutdown & RCV_SHUTDOWN) &&
++              bus_recvq_full(other);
++
++      bus_state_unlock(other);
++
++      if (sched)
++              timeo = schedule_timeout(timeo);
++
++      finish_wait(&u->peer_wait, &wait);
++      return timeo;
++}
++
++static int bus_connect(struct socket *sock, struct sockaddr *uaddr,
++                             int addr_len, int flags)
++{
++      struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr;
++      struct sock *sk = sock->sk;
++      struct net *net = sock_net(sk);
++      struct bus_sock *u = bus_sk(sk), *newu, *otheru;
++      struct sock *newsk = NULL;
++      struct sock *other = NULL;
++      struct sk_buff *skb = NULL;
++      struct bus_address *addr = NULL;
++      unsigned int hash;
++      int st;
++      int err;
++      long timeo;
++
++      /* Only connections to the bus master is allowed */
++      sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR;
++
++      err = bus_mkname(sbusaddr, addr_len, &hash);
++      if (err < 0)
++              goto out;
++      addr_len = err;
++
++      err = -ENOMEM;
++      addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL);
++      if (!addr)
++              goto out;
++
++      atomic_set(&addr->refcnt, 1);
++      INIT_HLIST_NODE(&addr->addr_node);
++      INIT_HLIST_NODE(&addr->table_node);
++
++      timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
++
++      /* First of all allocate resources.
++         If we will make it after state is locked,
++         we will have to recheck all again in any case.
++       */
++
++      err = -ENOMEM;
++
++      /* create new sock for complete connection */
++      newsk = bus_create1(sock_net(sk), NULL);
++      if (newsk == NULL)
++              goto out;
++
++      /* Allocate skb for sending to listening sock */
++      skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL);
++      if (skb == NULL)
++              goto out;
++
++restart:
++      /*  Find listening sock. */
++      other = bus_find_other(net, sbusaddr, addr_len, sk->sk_protocol, hash,
++                             &err);
++      if (!other)
++              goto out;
++
++      /* Latch state of peer */
++      bus_state_lock(other);
++
++      /* Apparently VFS overslept socket death. Retry. */
++      if (sock_flag(other, SOCK_DEAD)) {
++              bus_state_unlock(other);
++              sock_put(other);
++              goto restart;
++      }
++
++      err = -ECONNREFUSED;
++      if (other->sk_state != BUS_LISTEN)
++              goto out_unlock;
++      if (other->sk_shutdown & RCV_SHUTDOWN)
++              goto out_unlock;
++
++      if (bus_recvq_full(other)) {
++              err = -EAGAIN;
++              if (!timeo)
++                      goto out_unlock;
++
++              timeo = bus_wait_for_peer(other, timeo);
++
++              err = sock_intr_errno(timeo);
++              if (signal_pending(current))
++                      goto out;
++              sock_put(other);
++              goto restart;
++      }
++
++      /* Latch our state.
++
++         It is tricky place. We need to grab our state lock and cannot
++         drop lock on peer. It is dangerous because deadlock is
++         possible. Connect to self case and simultaneous
++         attempt to connect are eliminated by checking socket
++         state. other is BUS_LISTEN, if sk is BUS_LISTEN we
++         check this before attempt to grab lock.
++
++         Well, and we have to recheck the state after socket locked.
++       */
++      st = sk->sk_state;
++
++      switch (st) {
++      case BUS_CLOSE:
++              /* This is ok... continue with connect */
++              break;
++      case BUS_ESTABLISHED:
++              /* Socket is already connected */
++              err = -EISCONN;
++              goto out_unlock;
++      default:
++              err = -EINVAL;
++              goto out_unlock;
++      }
++
++      bus_state_lock_nested(sk);
++
++      if (sk->sk_state != st) {
++              bus_state_unlock(sk);
++              bus_state_unlock(other);
++              sock_put(other);
++              goto restart;
++      }
++
++      err = security_bus_connect(sk, other, newsk);
++      if (err) {
++              bus_state_unlock(sk);
++              goto out_unlock;
++      }
++
++      /* The way is open! Fastly set all the necessary fields... */
++
++      sock_hold(sk);
++      bus_peer(newsk) = sk;
++      newsk->sk_state         = BUS_ESTABLISHED;
++      newsk->sk_type          = sk->sk_type;
++      newsk->sk_protocol      = sk->sk_protocol;
++      init_peercred(newsk);
++      newu = bus_sk(newsk);
++      RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
++      otheru = bus_sk(other);
++
++      /* copy address information from listening to new sock*/
++      if (otheru->addr && otheru->bus_master) {
++              atomic_inc(&otheru->addr->refcnt);
++              newu->addr = otheru->addr;
++              memcpy(addr->name, otheru->addr->name,
++                     sizeof(struct sockaddr_bus));
++              addr->len = otheru->addr->len;
++              addr->name->sbus_addr.s_addr =
++                      (atomic64_inc_return(&otheru->bus->addr_cnt) &
++                       BUS_CLIENT_MASK);
++              addr->hash = bus_compute_hash(addr->name->sbus_addr);
++              addr->sock = sk;
++              u->addr = addr;
++              kref_get(&otheru->bus->kref);
++              u->bus = otheru->bus;
++              u->bus_master_side = false;
++              kref_get(&otheru->bus->kref);
++              newu->bus = otheru->bus;
++              newu->bus_master_side = true;
++              hlist_add_head(&addr->addr_node, &u->addr_list);
++
++              bus_insert_address(&bus_address_table[addr->hash], addr);
++      }
++      if (otheru->path.dentry) {
++              path_get(&otheru->path);
++              newu->path = otheru->path;
++      }
++
++      /* Set credentials */
++      copy_peercred(sk, other);
++      sk->sk_sndbuf = other->sk_sndbuf;
++      sk->sk_max_ack_backlog  = other->sk_max_ack_backlog;
++      newsk->sk_sndbuf = other->sk_sndbuf;
++
++      sock->state     = SS_CONNECTED;
++      sk->sk_state    = BUS_ESTABLISHED;
++      sock_hold(newsk);
++
++      smp_mb__after_atomic_inc();     /* sock_hold() does an atomic_inc() */
++      bus_peer(sk)    = newsk;
++
++      bus_state_unlock(sk);
++
++      /* take ten and and send info to listening sock */
++      spin_lock(&other->sk_receive_queue.lock);
++      __skb_queue_tail(&other->sk_receive_queue, skb);
++      spin_unlock(&other->sk_receive_queue.lock);
++      bus_state_unlock(other);
++      other->sk_data_ready(other, 0);
++      sock_put(other);
++      return 0;
++
++out_unlock:
++      if (other)
++              bus_state_unlock(other);
++
++out:
++      kfree_skb(skb);
++      if (addr)
++              bus_release_addr(addr);
++      if (newsk)
++              bus_release_sock(newsk, 0);
++      if (other)
++              sock_put(other);
++      return err;
++}
++
++static int bus_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++      struct sock *sk = sock->sk;
++      struct sock *tsk;
++      struct sk_buff *skb;
++      int err;
++
++      err = -EINVAL;
++      if (sk->sk_state != BUS_LISTEN)
++              goto out;
++
++      /* If socket state is BUS_LISTEN it cannot change (for now...),
++       * so that no locks are necessary.
++       */
++
++      skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
++      if (!skb) {
++              /* This means receive shutdown. */
++              if (err == 0)
++                      err = -EINVAL;
++              goto out;
++      }
++
++      tsk = skb->sk;
++      skb_free_datagram(sk, skb);
++      wake_up_interruptible(&bus_sk(sk)->peer_wait);
++
++      /* attach accepted sock to socket */
++      bus_state_lock(tsk);
++      newsock->state = SS_CONNECTED;
++      sock_graft(tsk, newsock);
++      bus_state_unlock(tsk);
++      return 0;
++
++out:
++      return err;
++}
++
++
++static int bus_getname(struct socket *sock, struct sockaddr *uaddr,
++                     int *uaddr_len, int peer)
++{
++      struct sock *sk = sock->sk;
++      struct bus_sock *u;
++      DECLARE_SOCKADDR(struct sockaddr_bus *, sbusaddr, uaddr);
++      int err = 0;
++
++      if (peer) {
++              sk = bus_peer_get(sk);
++
++              err = -ENOTCONN;
++              if (!sk)
++                      goto out;
++              err = 0;
++      } else {
++              sock_hold(sk);
++      }
++
++      u = bus_sk(sk);
++
++      bus_state_lock(sk);
++      if (!u->addr) {
++              sbusaddr->sbus_family = AF_BUS;
++              sbusaddr->sbus_path[0] = 0;
++              *uaddr_len = sizeof(short);
++      } else {
++              struct bus_address *addr = u->addr;
++
++              *uaddr_len = sizeof(struct sockaddr_bus);
++              memcpy(sbusaddr, addr->name, *uaddr_len);
++      }
++      bus_state_unlock(sk);
++      sock_put(sk);
++out:
++      return err;
++}
++
++static void bus_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
++{
++      int i;
++
++      scm->fp = BUSCB(skb).fp;
++      BUSCB(skb).fp = NULL;
++
++      for (i = scm->fp->count-1; i >= 0; i--)
++              bus_notinflight(scm->fp->fp[i]);
++}
++
++static void bus_destruct_scm(struct sk_buff *skb)
++{
++      struct scm_cookie scm;
++      memset(&scm, 0, sizeof(scm));
++      scm.pid  = BUSCB(skb).pid;
++      scm.cred = BUSCB(skb).cred;
++      if (BUSCB(skb).fp)
++              bus_detach_fds(&scm, skb);
++
++      scm_destroy(&scm);
++      if (skb->sk)
++              sock_wfree(skb);
++}
++
++#define MAX_RECURSION_LEVEL 4
++
++static int bus_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
++{
++      int i;
++      unsigned char max_level = 0;
++      int bus_sock_count = 0;
++
++      for (i = scm->fp->count - 1; i >= 0; i--) {
++              struct sock *sk = bus_get_socket(scm->fp->fp[i]);
++
++              if (sk) {
++                      bus_sock_count++;
++                      max_level = max(max_level,
++                                      bus_sk(sk)->recursion_level);
++              }
++      }
++      if (unlikely(max_level > MAX_RECURSION_LEVEL))
++              return -ETOOMANYREFS;
++
++      /*
++       * Need to duplicate file references for the sake of garbage
++       * collection.  Otherwise a socket in the fps might become a
++       * candidate for GC while the skb is not yet queued.
++       */
++      BUSCB(skb).fp = scm_fp_dup(scm->fp);
++      if (!BUSCB(skb).fp)
++              return -ENOMEM;
++
++      if (bus_sock_count) {
++              for (i = scm->fp->count - 1; i >= 0; i--)
++                      bus_inflight(scm->fp->fp[i]);
++      }
++      return max_level;
++}
++
++static int bus_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb,
++                        bool send_fds)
++{
++      int err = 0;
++
++      BUSCB(skb).pid  = get_pid(scm->pid);
++      if (scm->cred)
++              BUSCB(skb).cred = get_cred(scm->cred);
++      BUSCB(skb).fp = NULL;
++      if (scm->fp && send_fds)
++              err = bus_attach_fds(scm, skb);
++
++      skb->destructor = bus_destruct_scm;
++      return err;
++}
++
++/*
++ * Some apps rely on write() giving SCM_CREDENTIALS
++ * We include credentials if source or destination socket
++ * asserted SOCK_PASSCRED.
++ */
++static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
++                          const struct sock *other)
++{
++      if (BUSCB(skb).cred)
++              return;
++      if (test_bit(SOCK_PASSCRED, &sock->flags) ||
++          !other->sk_socket ||
++          test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
++              BUSCB(skb).pid  = get_pid(task_tgid(current));
++              BUSCB(skb).cred = get_current_cred();
++      }
++}
++
++/*
++ *    Send AF_BUS data.
++ */
++
++static void bus_deliver_skb(struct sk_buff *skb)
++{
++      struct bus_send_context *sendctx = BUSCB(skb).sendctx;
++      struct socket *sock = sendctx->sender_socket;
++
++      if (sock_flag(sendctx->other, SOCK_RCVTSTAMP))
++              __net_timestamp(skb);
++      maybe_add_creds(skb, sock, sendctx->other);
++      skb_queue_tail(&sendctx->other->sk_receive_queue, skb);
++      if (sendctx->max_level > bus_sk(sendctx->other)->recursion_level)
++              bus_sk(sendctx->other)->recursion_level = sendctx->max_level;
++}
++
++/**
++ * bus_sendmsg_finish - delivery an skb to a destination
++ * @skb: sk_buff to deliver
++ *
++ * Delivers a packet to a destination. The skb control buffer has
++ * all the information about the destination contained on sending
++ * context. If the sending is unicast, then the skb is delivered
++ * and the receiver notified but if the sending is multicast, the
++ * skb is just marked as delivered and the actual delivery is made
++ * outside the function with the bus->send_lock held to ensure that
++ * the multicast sending is atomic.
++ */
++static int bus_sendmsg_finish(struct sk_buff *skb)
++{
++      int err;
++      struct bus_send_context *sendctx;
++      struct socket *sock;
++      struct sock *sk;
++      struct net *net;
++      size_t len = skb->len;
++
++      sendctx = BUSCB(skb).sendctx;
++      sock = sendctx->sender_socket;
++      sk = sock->sk;
++      net = sock_net(sk);
++
++restart:
++      if (!sendctx->other) {
++              err = -ECONNRESET;
++              if (sendctx->recipient == NULL)
++                      goto out_free;
++
++              sendctx->other = bus_find_other(net, sendctx->recipient,
++                                              sendctx->namelen,
++                                              sk->sk_protocol,
++                                              sendctx->hash, &err);
++
++              if (sendctx->other == NULL ||
++                  !bus_sk(sendctx->other)->authenticated) {
++
++                      if (sendctx->other)
++                              sock_put(sendctx->other);
++
++                      if (!bus_sk(sk)->bus_master_side) {
++                              err = -ENOTCONN;
++                              sendctx->other = bus_peer_get(sk);
++                              if (!sendctx->other)
++                                      goto out_free;
++                      } else {
++                              sendctx->other = sk;
++                              sock_hold(sendctx->other);
++                      }
++              }
++      }
++
++      if (sk_filter(sendctx->other, skb) < 0) {
++              /* Toss the packet but do not return any error to the sender */
++              err = len;
++              goto out_free;
++      }
++
++      bus_state_lock(sendctx->other);
++
++      if (sock_flag(sendctx->other, SOCK_DEAD)) {
++              /*
++               *      Check with 1003.1g - what should
++               *      datagram error
++               */
++              bus_state_unlock(sendctx->other);
++              sock_put(sendctx->other);
++
++              err = 0;
++              bus_state_lock(sk);
++              if (bus_peer(sk) == sendctx->other) {
++                      bus_peer(sk) = NULL;
++                      bus_state_unlock(sk);
++                      sock_put(sendctx->other);
++                      err = -ECONNREFUSED;
++              } else {
++                      bus_state_unlock(sk);
++              }
++
++              sendctx->other = NULL;
++              if (err)
++                      goto out_free;
++              goto restart;
++      }
++
++      err = -EPIPE;
++      if (sendctx->other->sk_shutdown & RCV_SHUTDOWN)
++              goto out_unlock;
++
++      if (bus_recvq_full(sendctx->other)) {
++              if (!sendctx->timeo) {
++                      err = -EAGAIN;
++                      goto out_unlock;
++              }
++
++              sendctx->timeo = bus_wait_for_peer(sendctx->other,
++                                                 sendctx->timeo);
++
++              err = sock_intr_errno(sendctx->timeo);
++              if (signal_pending(current))
++                      goto out_free;
++
++              goto restart;
++      }
++
++      if (!sendctx->multicast && !sendctx->eavesdropper) {
++              bus_deliver_skb(skb);
++              bus_state_unlock(sendctx->other);
++              sendctx->other->sk_data_ready(sendctx->other, 0);
++              sock_put(sendctx->other);
++      } else {
++              sendctx->deliver = 1;
++              bus_state_unlock(sendctx->other);
++      }
++
++      return len;
++
++out_unlock:
++      bus_state_unlock(sendctx->other);
++out_free:
++      kfree_skb(skb);
++      if (sendctx->other)
++              sock_put(sendctx->other);
++
++      return err;
++}
++
++/**
++ * bus_sendmsg_mcast - do a multicast sending
++ * @skb: sk_buff to deliver
++ *
++ * Send a packet to a multicast destination.
++ * The function is also called for unicast sending when eavesdropping
++ * is enabled. Since the unicast destination and the eavesdroppers
++ * have to receive the packet atomically.
++ */
++static int bus_sendmsg_mcast(struct sk_buff *skb)
++{
++      struct bus_send_context *sendctx;
++      struct bus_send_context *tmpctx;
++      struct socket *sock;
++      struct sock *sk;
++      struct net *net;
++      struct bus_sock *u, *s;
++      struct hlist_node *node;
++      u16 prefix = 0;
++      struct sk_buff **skb_set = NULL;
++      struct bus_send_context **sendctx_set = NULL;
++      int  rcp_cnt, send_cnt;
++      int i;
++      int err;
++      int len = skb->len;
++      bool (*is_receiver) (struct sock *, u16);
++      bool main_rcp_found = false;
++
++      sendctx = BUSCB(skb).sendctx;
++      sendctx->deliver = 0;
++      sock = sendctx->sender_socket;
++      sk = sock->sk;
++      u = bus_sk(sk);
++      net = sock_net(sk);
++
++      if (sendctx->multicast) {
++              prefix = bus_addr_prefix(sendctx->recipient);
++              if (sendctx->eavesdropper)
++                      is_receiver = &bus_has_prefix_eavesdropper;
++              else
++                      is_receiver = &bus_has_prefix;
++      } else {
++              is_receiver = &bus_eavesdropper;
++
++              /*
++               * If the destination is not the peer accepted socket
++               * we have to get the correct destination.
++               */
++              if (!sendctx->to_master && sendctx->recipient) {
++                      sendctx->other = bus_find_other(net, sendctx->recipient,
++                                                      sendctx->namelen,
++                                                      sk->sk_protocol,
++                                                      sendctx->hash, &err);
++
++
++                      if (sendctx->other == NULL ||
++                          !bus_sk(sendctx->other)->authenticated) {
++
++                              if (sendctx->other)
++                                      sock_put(sendctx->other);
++
++                              if (sendctx->other == NULL) {
++                                      if (!bus_sk(sk)->bus_master_side) {
++                                              err = -ENOTCONN;
++                                              sendctx->other = bus_peer_get(sk);
++                                              if (!sendctx->other)
++                                                      goto out;
++                                      } else {
++                                              sendctx->other = sk;
++                                              sock_hold(sendctx->other);
++                                      }
++                              }
++                              sendctx->to_master = 1;
++                      }
++              }
++      }
++
++
++try_again:
++      rcp_cnt = 0;
++      main_rcp_found = false;
++
++      spin_lock(&u->bus->lock);
++
++      hlist_for_each_entry(s, node, &u->bus->peers, bus_node) {
++
++              if (!net_eq(sock_net(&s->sk), net))
++                      continue;
++
++              if (is_receiver(&s->sk, prefix) ||
++                  (!sendctx->multicast &&
++                   !sendctx->to_master &&
++                   &s->sk == sendctx->other))
++                      rcp_cnt++;
++      }
++
++      spin_unlock(&u->bus->lock);
++
++      /*
++       * Memory can't be allocated while holding a spinlock so
++       * we have to release the lock, do the allocation for the
++       * array to store each destination peer sk_buff and grab
++       * the bus peer lock again. Peers could have joined the
++       * bus while we relesed the lock so we allocate 5 more
++       * recipients hoping that this will be enough to not having
++       * to try again in case only a few peers joined the bus.
++       */
++      rcp_cnt += 5;
++      skb_set = kzalloc(sizeof(struct sk_buff *) * rcp_cnt, GFP_KERNEL);
++
++      if (!skb_set) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      sendctx_set = kzalloc(sizeof(struct bus_send_context *) * rcp_cnt,
++                            GFP_KERNEL);
++      if (!sendctx_set) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      for (i = 0; i < rcp_cnt; i++) {
++              skb_set[i] = skb_clone(skb, GFP_KERNEL);
++              if (!skb_set[i]) {
++                      err = -ENOMEM;
++                      goto out_free;
++              }
++              sendctx_set[i] = BUSCB(skb_set[i]).sendctx
++                      = kmalloc(sizeof(*sendctx) * rcp_cnt, GFP_KERNEL);
++              if (!sendctx_set[i]) {
++                      err = -ENOMEM;
++                      goto out_free;
++              }
++              memcpy(sendctx_set[i], sendctx, sizeof(*sendctx));
++              err = bus_scm_to_skb(sendctx_set[i]->siocb->scm,
++                                   skb_set[i], true);
++              if (err < 0)
++                      goto out_free;
++              bus_get_secdata(sendctx_set[i]->siocb->scm,
++                              skb_set[i]);
++
++              sendctx_set[i]->other = NULL;
++      }
++
++      send_cnt = 0;
++
++      spin_lock(&u->bus->lock);
++
++      hlist_for_each_entry(s, node, &u->bus->peers, bus_node) {
++
++              if (!net_eq(sock_net(&s->sk), net))
++                      continue;
++
++              if (send_cnt >= rcp_cnt) {
++                      spin_unlock(&u->bus->lock);
++
++                      for (i = 0; i < rcp_cnt; i++) {
++                              sock_put(sendctx_set[i]->other);
++                              kfree_skb(skb_set[i]);
++                              kfree(sendctx_set[i]);
++                      }
++                      kfree(skb_set);
++                      kfree(sendctx_set);
++                      sendctx_set = NULL;
++                      skb_set = NULL;
++                      goto try_again;
++              }
++
++              if (is_receiver(&s->sk, prefix) ||
++                  (!sendctx->multicast &&
++                   !sendctx->to_master &&
++                   &s->sk == sendctx->other)) {
++                      skb_set_owner_w(skb_set[send_cnt], &s->sk);
++                      tmpctx = BUSCB(skb_set[send_cnt]).sendctx;
++                      sock_hold(&s->sk);
++                      if (&s->sk == sendctx->other) {
++                              tmpctx->main_recipient = 1;
++                              main_rcp_found = true;
++                      }
++                      tmpctx->other = &s->sk;
++                      tmpctx->recipient = s->addr->name;
++                      tmpctx->eavesdropper = bus_eavesdropper(&s->sk, 0);
++
++                      send_cnt++;
++              }
++      }
++
++      spin_unlock(&u->bus->lock);
++
++      /*
++       * Peers have left the bus so we have to free
++       * their pre-allocated bus_send_context and
++       * socket buffers.
++       */
++      if (send_cnt < rcp_cnt) {
++              for (i = send_cnt; i < rcp_cnt; i++) {
++                      kfree_skb(skb_set[i]);
++                      kfree(sendctx_set[i]);
++              }
++              rcp_cnt = send_cnt;
++      }
++
++      for (i = 0; i < send_cnt; i++) {
++              tmpctx = BUSCB(skb_set[i]).sendctx;
++              tmpctx->deliver = 0;
++              err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb_set[i],
++                            NULL, NULL, bus_sendmsg_finish);
++              if (err == -EPERM)
++                      sock_put(tmpctx->other);
++      }
++
++      /*
++       * If the send context is not multicast, the destination
++       * coud be either the peer accepted socket descriptor or
++       * a peer that is not an eavesdropper. If the peer is not
++       * the accepted socket descriptor and has been authenticated,
++       * it is a member of the bus peer list so it has already been
++       * marked for delivery.
++       * But if the destination is the accepted socket descriptor
++       * or is a non-authenticated peer it is not a member of the
++       * bus peer list so the packet has to be explicitly deliver
++       * to it.
++       */
++
++      if (!sendctx->multicast &&
++          (sendctx->to_master ||
++           (sendctx->bus_master_side && !main_rcp_found))) {
++              sendctx->main_recipient = 1;
++              err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL,
++                      bus_sendmsg_finish);
++              if (err == -EPERM)
++                      sock_put(sendctx->other);
++      }
++
++      spin_lock(&u->bus->send_lock);
++
++      for (i = 0; i < send_cnt; i++) {
++              tmpctx = sendctx_set[i];
++              if (tmpctx->deliver != 1)
++                      continue;
++
++              bus_state_lock(tmpctx->other);
++              bus_deliver_skb(skb_set[i]);
++              bus_state_unlock(tmpctx->other);
++      }
++
++      if (!sendctx->multicast &&
++          sendctx->deliver == 1 &&
++          !bus_sk(sendctx->other)->eavesdropper) {
++              bus_state_lock(sendctx->other);
++              bus_deliver_skb(skb);
++              bus_state_unlock(sendctx->other);
++      }
++
++      spin_unlock(&u->bus->send_lock);
++
++      for (i = 0; i < send_cnt; i++) {
++              tmpctx = sendctx_set[i];
++              if (tmpctx->deliver != 1)
++                      continue;
++
++              tmpctx->other->sk_data_ready(tmpctx->other, 0);
++              sock_put(tmpctx->other);
++      }
++
++      if (!sendctx->multicast &&
++          sendctx->deliver == 1 &&
++          !bus_sk(sendctx->other)->eavesdropper) {
++              sendctx->other->sk_data_ready(sendctx->other, 0);
++              sock_put(sendctx->other);
++      }
++
++      err = len;
++      goto out;
++
++out_free:
++      for (i = 0; i < rcp_cnt; i++) {
++              if (skb_set[i])
++                      kfree_skb(skb_set[i]);
++      }
++
++out:
++      kfree(skb_set);
++      if (sendctx_set) {
++              for (i = 0; i < rcp_cnt; i++)
++                      kfree(sendctx_set[i]);
++              kfree(sendctx_set);
++      }
++
++      if (sendctx->deliver == 0) {
++              if (!sendctx->to_master &&
++                  !(sendctx->bus_master_side && !main_rcp_found))
++                      kfree_skb(skb);
++              if (!sendctx->to_master &&
++                  !(sendctx->bus_master_side && !main_rcp_found))
++                      if (sendctx->other)
++                              sock_put(sendctx->other);
++      }
++      scm_destroy(sendctx->siocb->scm);
++
++      return err;
++}
++
++static inline void bus_copy_path(struct sockaddr_bus *dest,
++                               struct sockaddr_bus *src)
++{
++      int offset;
++
++      /*
++       * abstract path names start with a null byte character,
++       * so they have to be compared starting at the second char.
++       */
++      offset = (src->sbus_path[0] == '\0');
++
++      strncpy(dest->sbus_path + offset,
++              src->sbus_path + offset,
++              BUS_PATH_MAX);
++}
++
++/**
++ * bus_sendmsg - send an skb to a destination
++ * @kiocb: I/O control block info
++ * @sock: sender socket
++ * @msg: message header
++ * @len: message length
++ *
++ * Send an socket buffer to a destination. The destination could be
++ * either an unicast or a multicast address. In any case, a copy of
++ * the packet has to be send to all the sockets that are allowed to
++ * eavesdrop the communication bus.
++ *
++ * If the destination address is not associated with any socket, the
++ * packet is default routed to the bus master (the sender accepted
++ * socket).
++ *
++ * The af_bus sending path is hooked to the netfilter subsystem so
++ * netfilter hooks can filter or modify the packet before delivery.
++ */
++static int bus_sendmsg(struct kiocb *kiocb, struct socket *sock,
++                              struct msghdr *msg, size_t len)
++{
++      struct sock *sk = sock->sk;
++      struct bus_sock *u = bus_sk(sk);
++      struct sockaddr_bus *sbusaddr = msg->msg_name;
++      int err;
++      struct sk_buff *skb;
++      struct scm_cookie tmp_scm;
++      bool to_master = false;
++      bool multicast = false;
++      struct bus_send_context sendctx;
++
++      err = sock_error(sk);
++      if (err)
++              return err;
++
++      if (sk->sk_state != BUS_ESTABLISHED)
++              return -ENOTCONN;
++
++      if (!msg->msg_namelen)
++              sbusaddr = NULL;
++
++      if (sbusaddr)
++              bus_copy_path(sbusaddr, u->addr->name);
++
++      if ((!sbusaddr && !u->bus_master_side) ||
++          (sbusaddr && sbusaddr->sbus_addr.s_addr == BUS_MASTER_ADDR))
++              to_master = true;
++      else if (sbusaddr && !u->bus_master_side && !u->authenticated)
++              return -EHOSTUNREACH;
++
++      sendctx.namelen = 0; /* fake GCC */
++      sendctx.siocb = kiocb_to_siocb(kiocb);
++      sendctx.other = NULL;
++
++      if (NULL == sendctx.siocb->scm)
++              sendctx.siocb->scm = &tmp_scm;
++      wait_for_bus_gc();
++      err = scm_send(sock, msg, sendctx.siocb->scm, false);
++      if (err < 0)
++              return err;
++
++      err = -EOPNOTSUPP;
++      if (msg->msg_flags&MSG_OOB)
++              goto out;
++
++      if (sbusaddr && !to_master) {
++              err = bus_mkname(sbusaddr, msg->msg_namelen, &sendctx.hash);
++              if (err < 0)
++                      goto out;
++              sendctx.namelen = err;
++              multicast = bus_mc_addr(sbusaddr);
++      } else {
++              err = -ENOTCONN;
++              sendctx.other = bus_peer_get(sk);
++              if (!sendctx.other)
++                      goto out;
++      }
++
++      err = -EMSGSIZE;
++      if (len > sk->sk_sndbuf - 32)
++              goto out;
++
++      sendctx.timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
++
++restart:
++      bus_state_lock(sk);
++      if (bus_recvq_full(sk)) {
++              err = -EAGAIN;
++              if (!sendctx.timeo) {
++                      bus_state_unlock(sk);
++                      goto out;
++              }
++
++              sendctx.timeo = bus_wait_for_peer(sk, sendctx.timeo);
++
++              err = sock_intr_errno(sendctx.timeo);
++              if (signal_pending(current))
++                      goto out;
++
++              goto restart;
++      } else {
++              bus_state_unlock(sk);
++      }
++
++      skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);
++      if (skb == NULL)
++              goto out;
++
++      err = bus_scm_to_skb(sendctx.siocb->scm, skb, true);
++      if (err < 0)
++              goto out_free;
++      sendctx.max_level = err + 1;
++      bus_get_secdata(sendctx.siocb->scm, skb);
++
++      skb_reset_transport_header(skb);
++      err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
++      if (err)
++              goto out_free;
++
++      sendctx.sender_socket = sock;
++      if (u->bus_master_side && sendctx.other) {
++              /* if the bus master sent an unicast message to a peer, we
++               * need the address of that peer
++               */
++              sendctx.sender = bus_sk(sendctx.other)->addr->name;
++      } else {
++              sendctx.sender = u->addr->name;
++      }
++      sendctx.recipient = sbusaddr;
++      sendctx.authenticated = u->authenticated;
++      sendctx.bus_master_side = u->bus_master_side;
++      sendctx.to_master = to_master;
++      sendctx.multicast = multicast;
++      sendctx.eavesdropper = atomic64_read(&u->bus->eavesdropper_cnt) ? 1 : 0;
++      BUSCB(skb).sendctx = &sendctx;
++
++      if (sendctx.multicast || sendctx.eavesdropper) {
++              sendctx.main_recipient = 0;
++              err = bus_sendmsg_mcast(skb);
++              return sendctx.multicast ? len : err;
++      } else {
++              sendctx.main_recipient = 1;
++              len = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL,
++                            bus_sendmsg_finish);
++
++              if (len == -EPERM) {
++                      err = len;
++                      goto out;
++              } else {
++                      scm_destroy(sendctx.siocb->scm);
++                      return len;
++              }
++      }
++
++out_free:
++      kfree_skb(skb);
++out:
++      if (sendctx.other)
++              sock_put(sendctx.other);
++      scm_destroy(sendctx.siocb->scm);
++      return err;
++}
++
++static void bus_copy_addr(struct msghdr *msg, struct sock *sk)
++{
++      struct bus_sock *u = bus_sk(sk);
++
++      msg->msg_namelen = 0;
++      if (u->addr) {
++              msg->msg_namelen = u->addr->len;
++              memcpy(msg->msg_name, u->addr->name,
++                     sizeof(struct sockaddr_bus));
++      }
++}
++
++static int bus_recvmsg(struct kiocb *iocb, struct socket *sock,
++                        struct msghdr *msg, size_t size, int flags)
++{
++      struct sock_iocb *siocb = kiocb_to_siocb(iocb);
++      struct scm_cookie tmp_scm;
++      struct sock *sk = sock->sk;
++      struct bus_sock *u = bus_sk(sk);
++      int noblock = flags & MSG_DONTWAIT;
++      struct sk_buff *skb;
++      int err;
++      int peeked, skip;
++
++      if (sk->sk_state != BUS_ESTABLISHED)
++              return -ENOTCONN;
++
++      err = -EOPNOTSUPP;
++      if (flags&MSG_OOB)
++              goto out;
++
++      msg->msg_namelen = 0;
++
++      err = mutex_lock_interruptible(&u->readlock);
++      if (err) {
++              err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
++              goto out;
++      }
++
++      skip = sk_peek_offset(sk, flags);
++
++      skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
++      if (!skb) {
++              bus_state_lock(sk);
++              /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
++              if (err == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN))
++                      err = 0;
++              bus_state_unlock(sk);
++              goto out_unlock;
++      }
++
++      wake_up_interruptible_sync_poll(&u->peer_wait,
++                                      POLLOUT | POLLWRNORM | POLLWRBAND);
++
++      if (msg->msg_name)
++              bus_copy_addr(msg, skb->sk);
++
++      if (size > skb->len - skip)
++              size = skb->len - skip;
++      else if (size < skb->len - skip)
++              msg->msg_flags |= MSG_TRUNC;
++
++      err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size);
++      if (err)
++              goto out_free;
++
++      if (sock_flag(sk, SOCK_RCVTSTAMP))
++              __sock_recv_timestamp(msg, sk, skb);
++
++      if (!siocb->scm) {
++              siocb->scm = &tmp_scm;
++              memset(&tmp_scm, 0, sizeof(tmp_scm));
++      }
++      scm_set_cred(siocb->scm, BUSCB(skb).pid, BUSCB(skb).cred);
++      bus_set_secdata(siocb->scm, skb);
++
++      if (!(flags & MSG_PEEK)) {
++              if (BUSCB(skb).fp)
++                      bus_detach_fds(siocb->scm, skb);
++
++              sk_peek_offset_bwd(sk, skb->len);
++      } else {
++              /* It is questionable: on PEEK we could:
++                 - do not return fds - good, but too simple 8)
++                 - return fds, and do not return them on read (old strategy,
++                   apparently wrong)
++                 - clone fds (I chose it for now, it is the most universal
++                   solution)
++
++                 POSIX 1003.1g does not actually define this clearly
++                 at all. POSIX 1003.1g doesn't define a lot of things
++                 clearly however!
++
++              */
++
++              sk_peek_offset_fwd(sk, size);
++
++              if (BUSCB(skb).fp)
++                      siocb->scm->fp = scm_fp_dup(BUSCB(skb).fp);
++      }
++      err = (flags & MSG_TRUNC) ? skb->len - skip : size;
++
++      scm_recv(sock, msg, siocb->scm, flags);
++
++out_free:
++      skb_free_datagram(sk, skb);
++out_unlock:
++      mutex_unlock(&u->readlock);
++out:
++      return err;
++}
++
++static int bus_shutdown(struct socket *sock, int mode)
++{
++      struct sock *sk = sock->sk;
++      struct sock *other;
++
++      mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);
++
++      if (!mode)
++              return 0;
++
++      bus_state_lock(sk);
++      sk->sk_shutdown |= mode;
++      other = bus_peer(sk);
++      if (other)
++              sock_hold(other);
++      bus_state_unlock(sk);
++      sk->sk_state_change(sk);
++
++      if (other) {
++
++              int peer_mode = 0;
++
++              if (mode&RCV_SHUTDOWN)
++                      peer_mode |= SEND_SHUTDOWN;
++              if (mode&SEND_SHUTDOWN)
++                      peer_mode |= RCV_SHUTDOWN;
++              bus_state_lock(other);
++              other->sk_shutdown |= peer_mode;
++              bus_state_unlock(other);
++              other->sk_state_change(other);
++              if (peer_mode == SHUTDOWN_MASK)
++                      sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP);
++              else if (peer_mode & RCV_SHUTDOWN)
++                      sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN);
++              sock_put(other);
++      }
++
++      return 0;
++}
++
++static int bus_add_addr(struct sock *sk, struct bus_addr *sbus_addr)
++{
++      struct bus_address *addr;
++      struct sock *other;
++      struct bus_sock *u = bus_sk(sk);
++      struct net *net = sock_net(sk);
++      int ret = 0;
++
++      addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL);
++      if (!addr) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      memcpy(addr->name, u->addr->name, sizeof(struct sockaddr_bus));
++      addr->len = u->addr->len;
++
++      addr->name->sbus_addr.s_addr = sbus_addr->s_addr;
++      addr->hash = bus_compute_hash(addr->name->sbus_addr);
++      other = bus_find_socket_byaddress(net, addr->name, addr->len,
++                                        sk->sk_protocol, addr->hash);
++
++      if (other) {
++              sock_put(other);
++              kfree(addr);
++              ret = -EADDRINUSE;
++              goto out;
++      }
++
++      atomic_set(&addr->refcnt, 1);
++      INIT_HLIST_NODE(&addr->addr_node);
++      INIT_HLIST_NODE(&addr->table_node);
++
++      addr->sock = sk;
++
++      hlist_add_head(&addr->addr_node, &u->addr_list);
++      bus_insert_address(&bus_address_table[addr->hash], addr);
++
++out:
++      sock_put(sk);
++
++      return ret;
++}
++
++static int bus_del_addr(struct sock *sk, struct bus_addr *sbus_addr)
++{
++      struct bus_address *addr;
++      int ret = 0;
++
++      bus_state_lock(sk);
++      addr = __bus_get_address(sk, sbus_addr);
++      if (!addr) {
++              ret = -EINVAL;
++              bus_state_unlock(sk);
++              goto out;
++      }
++      hlist_del(&addr->addr_node);
++      bus_state_unlock(sk);
++
++      bus_remove_address(addr);
++      bus_release_addr(addr);
++out:
++      sock_put(sk);
++
++      return ret;
++}
++
++static int bus_join_bus(struct sock *sk)
++{
++      struct sock *peer;
++      struct bus_sock *u = bus_sk(sk), *peeru;
++      int err = 0;
++
++      peer = bus_peer_get(sk);
++      if (!peer)
++              return -ENOTCONN;
++      peeru = bus_sk(peer);
++
++      if (!u->bus_master_side || peeru->authenticated) {
++              err = -EINVAL;
++              goto sock_put_out;
++      }
++
++      if (sk->sk_state != BUS_ESTABLISHED) {
++              err = -ENOTCONN;
++              goto sock_put_out;
++      }
++
++      if (peer->sk_shutdown != 0) {
++              err = -ENOTCONN;
++              goto sock_put_out;
++      }
++
++      bus_state_lock(peer);
++      peeru->authenticated = true;
++      bus_state_unlock(peer);
++
++      spin_lock(&u->bus->lock);
++      hlist_add_head(&peeru->bus_node, &u->bus->peers);
++      spin_unlock(&u->bus->lock);
++
++sock_put_out:
++      sock_put(peer);
++      return err;
++}
++
++static int __bus_set_eavesdrop(struct sock *sk, bool eavesdrop)
++{
++      struct sock *peer = bus_peer_get(sk);
++      struct bus_sock *u = bus_sk(sk), *peeru;
++      int err = 0;
++
++      if (!peer)
++              return -ENOTCONN;
++
++      if (sk->sk_state != BUS_ESTABLISHED) {
++              err = -ENOTCONN;
++              goto sock_put_out;
++      }
++
++      peeru = bus_sk(peer);
++
++      if (!u->bus_master_side || !peeru->authenticated) {
++              err = -EINVAL;
++              goto sock_put_out;
++      }
++
++      if (peer->sk_shutdown != 0) {
++              err = -ENOTCONN;
++              goto sock_put_out;
++      }
++
++      bus_state_lock(peeru);
++      if (peeru->eavesdropper != eavesdrop) {
++              peeru->eavesdropper = eavesdrop;
++              if (eavesdrop)
++                      atomic64_inc(&u->bus->eavesdropper_cnt);
++              else
++                      atomic64_dec(&u->bus->eavesdropper_cnt);
++      }
++      bus_state_unlock(peeru);
++
++sock_put_out:
++      sock_put(peer);
++      return err;
++}
++
++static int bus_set_eavesdrop(struct sock *sk)
++{
++      return __bus_set_eavesdrop(sk, true);
++}
++
++static int bus_unset_eavesdrop(struct sock *sk)
++{
++      return __bus_set_eavesdrop(sk, false);
++}
++
++static inline void sk_sendbuf_set(struct sock *sk, int sndbuf)
++{
++      bus_state_lock(sk);
++      sk->sk_sndbuf = sndbuf;
++      bus_state_unlock(sk);
++}
++
++static inline void sk_maxqlen_set(struct sock *sk, int qlen)
++{
++      bus_state_lock(sk);
++      sk->sk_max_ack_backlog = qlen;
++      bus_state_unlock(sk);
++}
++
++static int bus_get_qlenfull(struct sock *sk)
++{
++      struct sock *peer;
++      struct bus_sock *u = bus_sk(sk), *peeru;
++      int ret = 0;
++
++      peer = bus_peer_get(sk);
++      if (!peer)
++              return -ENOTCONN;
++
++      peeru = bus_sk(peer);
++
++      if (!u->bus_master_side || peeru->authenticated) {
++              ret = -EINVAL;
++              goto sock_put_out;
++      }
++
++      if (sk->sk_state != BUS_ESTABLISHED) {
++              ret = -ENOTCONN;
++              goto sock_put_out;
++      }
++
++      if (peer->sk_shutdown != 0) {
++              ret = -ENOTCONN;
++              goto sock_put_out;
++      }
++
++      ret = bus_recvq_full(peer);
++
++sock_put_out:
++      sock_put(peer);
++      return ret;
++}
++
++static int bus_setsockopt(struct socket *sock, int level, int optname,
++                         char __user *optval, unsigned int optlen)
++{
++      struct bus_addr addr;
++      int res;
++      int val;
++
++      if (level != SOL_BUS)
++              return -ENOPROTOOPT;
++
++      switch (optname) {
++      case BUS_ADD_ADDR:
++      case BUS_DEL_ADDR:
++              if (optlen < sizeof(struct bus_addr))
++                      return -EINVAL;
++
++              if (!bus_sk(sock->sk)->bus_master_side)
++                      return -EINVAL;
++
++              if (copy_from_user(&addr, optval, sizeof(struct bus_addr)))
++                      return -EFAULT;
++
++              if (optname == BUS_ADD_ADDR)
++                      res = bus_add_addr(bus_peer_get(sock->sk), &addr);
++              else
++                      res = bus_del_addr(bus_peer_get(sock->sk), &addr);
++              break;
++      case BUS_JOIN_BUS:
++              res = bus_join_bus(sock->sk);
++              break;
++      case BUS_SET_EAVESDROP:
++              res = bus_set_eavesdrop(sock->sk);
++              break;
++      case BUS_UNSET_EAVESDROP:
++              res = bus_unset_eavesdrop(sock->sk);
++              break;
++      case BUS_SET_SENDBUF:
++      case BUS_SET_MAXQLEN:
++              if (sock->sk->sk_state != BUS_LISTEN) {
++                      res = -EINVAL;
++              } else {
++                      res = -EFAULT;
++
++                      if (copy_from_user(&val, optval, optlen))
++                              break;
++
++                      res = 0;
++
++                      if (optname == BUS_SET_SENDBUF)
++                              sk_sendbuf_set(sock->sk, val);
++                      else
++                              sk_maxqlen_set(sock->sk, val);
++              }
++              break;
++      case BUS_GET_QLENFULL:
++              res = bus_get_qlenfull(sock->sk);
++
++              if (copy_to_user(&res, optval, optlen)) {
++                      res = -EFAULT;
++                      break;
++              }
++              res = 0;
++              break;
++      default:
++              res = -EINVAL;
++              break;
++      }
++
++      return res;
++}
++
++long bus_inq_len(struct sock *sk)
++{
++      struct sk_buff *skb;
++      long amount = 0;
++
++      if (sk->sk_state == BUS_LISTEN)
++              return -EINVAL;
++
++      spin_lock(&sk->sk_receive_queue.lock);
++      skb_queue_walk(&sk->sk_receive_queue, skb)
++              amount += skb->len;
++      spin_unlock(&sk->sk_receive_queue.lock);
++
++      return amount;
++}
++EXPORT_SYMBOL_GPL(bus_inq_len);
++
++long bus_outq_len(struct sock *sk)
++{
++      return sk_wmem_alloc_get(sk);
++}
++EXPORT_SYMBOL_GPL(bus_outq_len);
++
++static int bus_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++      struct sock *sk = sock->sk;
++      long amount = 0;
++      int err;
++
++      switch (cmd) {
++      case SIOCOUTQ:
++              amount = bus_outq_len(sk);
++              err = put_user(amount, (int __user *)arg);
++              break;
++      case SIOCINQ:
++              amount = bus_inq_len(sk);
++              if (amount < 0)
++                      err = amount;
++              else
++                      err = put_user(amount, (int __user *)arg);
++              break;
++      default:
++              err = -ENOIOCTLCMD;
++              break;
++      }
++      return err;
++}
++
++static unsigned int bus_poll(struct file *file, struct socket *sock,
++                                  poll_table *wait)
++{
++      struct sock *sk = sock->sk, *other;
++      unsigned int mask, writable;
++      struct bus_sock *u = bus_sk(sk), *p;
++      struct hlist_node *node;
++
++      sock_poll_wait(file, sk_sleep(sk), wait);
++      mask = 0;
++
++      /* exceptional events? */
++      if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
++              mask |= POLLERR;
++      if (sk->sk_shutdown & RCV_SHUTDOWN)
++              mask |= POLLRDHUP | POLLIN | POLLRDNORM;
++      if (sk->sk_shutdown == SHUTDOWN_MASK)
++              mask |= POLLHUP;
++
++      /* readable? */
++      if (!skb_queue_empty(&sk->sk_receive_queue))
++              mask |= POLLIN | POLLRDNORM;
++
++      /* Connection-based need to check for termination and startup */
++      if (sk->sk_state == BUS_CLOSE)
++              mask |= POLLHUP;
++
++      /* No write status requested, avoid expensive OUT tests. */
++      if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT)))
++              return mask;
++
++      writable = bus_writable(sk);
++      other = bus_peer_get(sk);
++      if (other) {
++              if (bus_recvq_full(other))
++                      writable = 0;
++              sock_put(other);
++      }
++
++      /*
++       * If the socket has already joined the bus we have to check
++       * that each peer receiver queue on the bus is not full.
++       */
++      if (!u->bus_master_side && u->authenticated) {
++              spin_lock(&u->bus->lock);
++              hlist_for_each_entry(p, node, &u->bus->peers, bus_node) {
++                      if (bus_recvq_full(&p->sk)) {
++                              writable = 0;
++                              break;
++                      }
++              }
++              spin_unlock(&u->bus->lock);
++      }
++
++      if (writable)
++              mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
++      else
++              set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
++
++      return mask;
++}
++
++#ifdef CONFIG_PROC_FS
++static struct sock *first_bus_socket(int *i)
++{
++      for (*i = 0; *i <= BUS_HASH_SIZE; (*i)++) {
++              if (!hlist_empty(&bus_socket_table[*i]))
++                      return __sk_head(&bus_socket_table[*i]);
++      }
++      return NULL;
++}
++
++static struct sock *next_bus_socket(int *i, struct sock *s)
++{
++      struct sock *next = sk_next(s);
++      /* More in this chain? */
++      if (next)
++              return next;
++      /* Look for next non-empty chain. */
++      for ((*i)++; *i <= BUS_HASH_SIZE; (*i)++) {
++              if (!hlist_empty(&bus_socket_table[*i]))
++                      return __sk_head(&bus_socket_table[*i]);
++      }
++      return NULL;
++}
++
++struct bus_iter_state {
++      struct seq_net_private p;
++      int i;
++};
++
++static struct sock *bus_seq_idx(struct seq_file *seq, loff_t pos)
++{
++      struct bus_iter_state *iter = seq->private;
++      loff_t off = 0;
++      struct sock *s;
++
++      for (s = first_bus_socket(&iter->i); s;
++           s = next_bus_socket(&iter->i, s)) {
++              if (sock_net(s) != seq_file_net(seq))
++                      continue;
++              if (off == pos)
++                      return s;
++              ++off;
++      }
++      return NULL;
++}
++
++static void *bus_seq_start(struct seq_file *seq, loff_t *pos)
++      __acquires(bus_table_lock)
++{
++      spin_lock(&bus_table_lock);
++      return *pos ? bus_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN;
++}
++
++static void *bus_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++{
++      struct bus_iter_state *iter = seq->private;
++      struct sock *sk = v;
++      ++*pos;
++
++      if (v == SEQ_START_TOKEN)
++              sk = first_bus_socket(&iter->i);
++      else
++              sk = next_bus_socket(&iter->i, sk);
++      while (sk && (sock_net(sk) != seq_file_net(seq)))
++              sk = next_bus_socket(&iter->i, sk);
++      return sk;
++}
++
++static void bus_seq_stop(struct seq_file *seq, void *v)
++      __releases(bus_table_lock)
++{
++      spin_unlock(&bus_table_lock);
++}
++
++static int bus_seq_show(struct seq_file *seq, void *v)
++{
++
++      if (v == SEQ_START_TOKEN)
++              seq_puts(seq, "Num       RefCount Protocol Flags    Type St " \
++                       "Inode Path\n");
++      else {
++              struct sock *s = v;
++              struct bus_sock *u = bus_sk(s);
++              bus_state_lock(s);
++
++              seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu",
++                      s,
++                      atomic_read(&s->sk_refcnt),
++                      0,
++                      s->sk_state == BUS_LISTEN ? __SO_ACCEPTCON : 0,
++                      s->sk_type,
++                      s->sk_socket ?
++                      (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) :
++                      (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),
++                      sock_i_ino(s));
++
++              if (u->addr) {
++                      int i, len;
++                      seq_putc(seq, ' ');
++
++                      i = 0;
++                      len = u->addr->len - sizeof(short);
++                      if (!BUS_ABSTRACT(s))
++                              len--;
++                      else {
++                              seq_putc(seq, '@');
++                              i++;
++                      }
++                      for ( ; i < len; i++)
++                              seq_putc(seq, u->addr->name->sbus_path[i]);
++              }
++              bus_state_unlock(s);
++              seq_putc(seq, '\n');
++      }
++
++      return 0;
++}
++
++static const struct seq_operations bus_seq_ops = {
++      .start  = bus_seq_start,
++      .next   = bus_seq_next,
++      .stop   = bus_seq_stop,
++      .show   = bus_seq_show,
++};
++
++static int bus_seq_open(struct inode *inode, struct file *file)
++{
++      return seq_open_net(inode, file, &bus_seq_ops,
++                          sizeof(struct bus_iter_state));
++}
++
++static const struct file_operations bus_seq_fops = {
++      .owner          = THIS_MODULE,
++      .open           = bus_seq_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = seq_release_net,
++};
++
++#endif
++
++static const struct net_proto_family bus_family_ops = {
++      .family = PF_BUS,
++      .create = bus_create,
++      .owner  = THIS_MODULE,
++};
++
++static int __init af_bus_init(void)
++{
++      int rc = -1;
++      struct sk_buff *dummy_skb;
++
++      BUILD_BUG_ON(sizeof(struct bus_skb_parms) > sizeof(dummy_skb->cb));
++
++      rc = proto_register(&bus_proto, 1);
++      if (rc != 0) {
++              pr_crit("%s: Cannot create bus_sock SLAB cache!\n", __func__);
++              return rc;
++      }
++
++      sock_register(&bus_family_ops);
++      return rc;
++}
++
++static void __exit af_bus_exit(void)
++{
++      sock_unregister(PF_BUS);
++      proto_unregister(&bus_proto);
++}
++
++module_init(af_bus_init);
++module_exit(af_bus_exit);
++
++MODULE_AUTHOR("Alban Crequy, Javier Martinez Canillas");
++MODULE_DESCRIPTION("Linux Bus domain sockets");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_NETPROTO(PF_BUS);
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch b/patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch
new file mode 100644 (file)
index 0000000..aaf0cc5
--- /dev/null
@@ -0,0 +1,344 @@
+From 2a2abe6e793a5b7f027d8af33f1ebb3e106016eb Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 15:56:38 +0200
+Subject: [PATCH 09/15] net: bus: Add garbage collector for AF_BUS sockets.
+
+This patch adds a garbage collector for AF_BUS sockets.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ net/bus/garbage.c |  322 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 322 insertions(+), 0 deletions(-)
+ create mode 100644 net/bus/garbage.c
+
+diff --git a/net/bus/garbage.c b/net/bus/garbage.c
+new file mode 100644
+index 0000000..2435f38
+--- /dev/null
++++ b/net/bus/garbage.c
+@@ -0,0 +1,322 @@
++/*
++ * Garbage Collector For AF_BUS sockets
++ *
++ * Based on Garbage Collector For AF_UNIX sockets (net/unix/garbage.c).
++ */
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/socket.h>
++#include <linux/un.h>
++#include <linux/net.h>
++#include <linux/fs.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/file.h>
++#include <linux/proc_fs.h>
++#include <linux/mutex.h>
++#include <linux/wait.h>
++
++#include <net/sock.h>
++#include <net/af_bus.h>
++#include <net/scm.h>
++#include <net/tcp_states.h>
++
++/* Internal data structures and random procedures: */
++
++static LIST_HEAD(gc_inflight_list);
++static LIST_HEAD(gc_candidates);
++static DEFINE_SPINLOCK(bus_gc_lock);
++static DECLARE_WAIT_QUEUE_HEAD(bus_gc_wait);
++
++unsigned int bus_tot_inflight;
++
++
++struct sock *bus_get_socket(struct file *filp)
++{
++      struct sock *u_sock = NULL;
++      struct inode *inode = filp->f_path.dentry->d_inode;
++
++      /*
++       *      Socket ?
++       */
++      if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
++              struct socket *sock = SOCKET_I(inode);
++              struct sock *s = sock->sk;
++
++              /*
++               *      PF_BUS ?
++               */
++              if (s && sock->ops && sock->ops->family == PF_BUS)
++                      u_sock = s;
++      }
++      return u_sock;
++}
++
++/*
++ *    Keep the number of times in flight count for the file
++ *    descriptor if it is for an AF_BUS socket.
++ */
++
++void bus_inflight(struct file *fp)
++{
++      struct sock *s = bus_get_socket(fp);
++      if (s) {
++              struct bus_sock *u = bus_sk(s);
++              spin_lock(&bus_gc_lock);
++              if (atomic_long_inc_return(&u->inflight) == 1) {
++                      BUG_ON(!list_empty(&u->link));
++                      list_add_tail(&u->link, &gc_inflight_list);
++              } else {
++                      BUG_ON(list_empty(&u->link));
++              }
++              bus_tot_inflight++;
++              spin_unlock(&bus_gc_lock);
++      }
++}
++
++void bus_notinflight(struct file *fp)
++{
++      struct sock *s = bus_get_socket(fp);
++      if (s) {
++              struct bus_sock *u = bus_sk(s);
++              spin_lock(&bus_gc_lock);
++              BUG_ON(list_empty(&u->link));
++              if (atomic_long_dec_and_test(&u->inflight))
++                      list_del_init(&u->link);
++              bus_tot_inflight--;
++              spin_unlock(&bus_gc_lock);
++      }
++}
++
++static void scan_inflight(struct sock *x, void (*func)(struct bus_sock *),
++                        struct sk_buff_head *hitlist)
++{
++      struct sk_buff *skb;
++      struct sk_buff *next;
++
++      spin_lock(&x->sk_receive_queue.lock);
++      skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
++              /*
++               *      Do we have file descriptors ?
++               */
++              if (BUSCB(skb).fp) {
++                      bool hit = false;
++                      /*
++                       *      Process the descriptors of this socket
++                       */
++                      int nfd = BUSCB(skb).fp->count;
++                      struct file **fp = BUSCB(skb).fp->fp;
++                      while (nfd--) {
++                              /*
++                               *      Get the socket the fd matches
++                               *      if it indeed does so
++                               */
++                              struct sock *sk = bus_get_socket(*fp++);
++                              if (sk) {
++                                      struct bus_sock *u = bus_sk(sk);
++
++                                      /*
++                                       * Ignore non-candidates, they could
++                                       * have been added to the queues after
++                                       * starting the garbage collection
++                                       */
++                                      if (u->gc_candidate) {
++                                              hit = true;
++                                              func(u);
++                                      }
++                              }
++                      }
++                      if (hit && hitlist != NULL) {
++                              __skb_unlink(skb, &x->sk_receive_queue);
++                              __skb_queue_tail(hitlist, skb);
++                      }
++              }
++      }
++      spin_unlock(&x->sk_receive_queue.lock);
++}
++
++static void scan_children(struct sock *x, void (*func)(struct bus_sock *),
++                        struct sk_buff_head *hitlist)
++{
++      if (x->sk_state != TCP_LISTEN)
++              scan_inflight(x, func, hitlist);
++      else {
++              struct sk_buff *skb;
++              struct sk_buff *next;
++              struct bus_sock *u;
++              LIST_HEAD(embryos);
++
++              /*
++               * For a listening socket collect the queued embryos
++               * and perform a scan on them as well.
++               */
++              spin_lock(&x->sk_receive_queue.lock);
++              skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
++                      u = bus_sk(skb->sk);
++
++                      /*
++                       * An embryo cannot be in-flight, so it's safe
++                       * to use the list link.
++                       */
++                      BUG_ON(!list_empty(&u->link));
++                      list_add_tail(&u->link, &embryos);
++              }
++              spin_unlock(&x->sk_receive_queue.lock);
++
++              while (!list_empty(&embryos)) {
++                      u = list_entry(embryos.next, struct bus_sock, link);
++                      scan_inflight(&u->sk, func, hitlist);
++                      list_del_init(&u->link);
++              }
++      }
++}
++
++static void dec_inflight(struct bus_sock *usk)
++{
++      atomic_long_dec(&usk->inflight);
++}
++
++static void inc_inflight(struct bus_sock *usk)
++{
++      atomic_long_inc(&usk->inflight);
++}
++
++static void inc_inflight_move_tail(struct bus_sock *u)
++{
++      atomic_long_inc(&u->inflight);
++      /*
++       * If this still might be part of a cycle, move it to the end
++       * of the list, so that it's checked even if it was already
++       * passed over
++       */
++      if (u->gc_maybe_cycle)
++              list_move_tail(&u->link, &gc_candidates);
++}
++
++static bool gc_in_progress = false;
++#define BUS_INFLIGHT_TRIGGER_GC 16000
++
++void wait_for_bus_gc(void)
++{
++      /*
++       * If number of inflight sockets is insane,
++       * force a garbage collect right now.
++       */
++      if (bus_tot_inflight > BUS_INFLIGHT_TRIGGER_GC && !gc_in_progress)
++              bus_gc();
++      wait_event(bus_gc_wait, gc_in_progress == false);
++}
++
++/* The external entry point: bus_gc() */
++void bus_gc(void)
++{
++      struct bus_sock *u;
++      struct bus_sock *next;
++      struct sk_buff_head hitlist;
++      struct list_head cursor;
++      LIST_HEAD(not_cycle_list);
++
++      spin_lock(&bus_gc_lock);
++
++      /* Avoid a recursive GC. */
++      if (gc_in_progress)
++              goto out;
++
++      gc_in_progress = true;
++      /*
++       * First, select candidates for garbage collection.  Only
++       * in-flight sockets are considered, and from those only ones
++       * which don't have any external reference.
++       *
++       * Holding bus_gc_lock will protect these candidates from
++       * being detached, and hence from gaining an external
++       * reference.  Since there are no possible receivers, all
++       * buffers currently on the candidates' queues stay there
++       * during the garbage collection.
++       *
++       * We also know that no new candidate can be added onto the
++       * receive queues.  Other, non candidate sockets _can_ be
++       * added to queue, so we must make sure only to touch
++       * candidates.
++       */
++      list_for_each_entry_safe(u, next, &gc_inflight_list, link) {
++              long total_refs;
++              long inflight_refs;
++
++              total_refs = file_count(u->sk.sk_socket->file);
++              inflight_refs = atomic_long_read(&u->inflight);
++
++              BUG_ON(inflight_refs < 1);
++              BUG_ON(total_refs < inflight_refs);
++              if (total_refs == inflight_refs) {
++                      list_move_tail(&u->link, &gc_candidates);
++                      u->gc_candidate = 1;
++                      u->gc_maybe_cycle = 1;
++              }
++      }
++
++      /*
++       * Now remove all internal in-flight reference to children of
++       * the candidates.
++       */
++      list_for_each_entry(u, &gc_candidates, link)
++              scan_children(&u->sk, dec_inflight, NULL);
++
++      /*
++       * Restore the references for children of all candidates,
++       * which have remaining references.  Do this recursively, so
++       * only those remain, which form cyclic references.
++       *
++       * Use a "cursor" link, to make the list traversal safe, even
++       * though elements might be moved about.
++       */
++      list_add(&cursor, &gc_candidates);
++      while (cursor.next != &gc_candidates) {
++              u = list_entry(cursor.next, struct bus_sock, link);
++
++              /* Move cursor to after the current position. */
++              list_move(&cursor, &u->link);
++
++              if (atomic_long_read(&u->inflight) > 0) {
++                      list_move_tail(&u->link, &not_cycle_list);
++                      u->gc_maybe_cycle = 0;
++                      scan_children(&u->sk, inc_inflight_move_tail, NULL);
++              }
++      }
++      list_del(&cursor);
++
++      /*
++       * not_cycle_list contains those sockets which do not make up a
++       * cycle.  Restore these to the inflight list.
++       */
++      while (!list_empty(&not_cycle_list)) {
++              u = list_entry(not_cycle_list.next, struct bus_sock, link);
++              u->gc_candidate = 0;
++              list_move_tail(&u->link, &gc_inflight_list);
++      }
++
++      /*
++       * Now gc_candidates contains only garbage.  Restore original
++       * inflight counters for these as well, and remove the skbuffs
++       * which are creating the cycle(s).
++       */
++      skb_queue_head_init(&hitlist);
++      list_for_each_entry(u, &gc_candidates, link)
++      scan_children(&u->sk, inc_inflight, &hitlist);
++
++      spin_unlock(&bus_gc_lock);
++
++      /* Here we are. Hitlist is filled. Die. */
++      __skb_queue_purge(&hitlist);
++
++      spin_lock(&bus_gc_lock);
++
++      /* All candidates should have been detached by now. */
++      BUG_ON(!list_empty(&gc_candidates));
++      gc_in_progress = false;
++      wake_up(&bus_gc_wait);
++
++ out:
++      spin_unlock(&bus_gc_lock);
++}
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch b/patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch
new file mode 100644 (file)
index 0000000..19e3f4b
--- /dev/null
@@ -0,0 +1,79 @@
+From 89d9d1c0afd8d782a9726dfb79646022086a21bb Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 16:16:40 +0200
+Subject: [PATCH 10/15] net: bus: Add the AF_BUS socket address family to
+ KBuild
+
+This patch adds the AF_BUS code to the Linux Kernel build system.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ net/Kconfig      |    1 +
+ net/Makefile     |    1 +
+ net/bus/Kconfig  |   15 +++++++++++++++
+ net/bus/Makefile |    7 +++++++
+ 4 files changed, 24 insertions(+), 0 deletions(-)
+ create mode 100644 net/bus/Kconfig
+ create mode 100644 net/bus/Makefile
+
+diff --git a/net/Kconfig b/net/Kconfig
+index e07272d..c9774a1 100644
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -47,6 +47,7 @@ menu "Networking options"
+ source "net/packet/Kconfig"
+ source "net/unix/Kconfig"
++source "net/bus/Kconfig"
+ source "net/xfrm/Kconfig"
+ source "net/iucv/Kconfig"
+diff --git a/net/Makefile b/net/Makefile
+index ad432fa..3033018 100644
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_NETFILTER)              += netfilter/
+ obj-$(CONFIG_INET)            += ipv4/
+ obj-$(CONFIG_XFRM)            += xfrm/
+ obj-$(CONFIG_UNIX)            += unix/
++obj-$(CONFIG_AF_BUS)          += bus/
+ obj-$(CONFIG_NET)             += ipv6/
+ obj-$(CONFIG_PACKET)          += packet/
+ obj-$(CONFIG_NET_KEY)         += key/
+diff --git a/net/bus/Kconfig b/net/bus/Kconfig
+new file mode 100644
+index 0000000..5f01410
+--- /dev/null
++++ b/net/bus/Kconfig
+@@ -0,0 +1,15 @@
++#
++# Bus Domain Sockets
++#
++
++config AF_BUS
++      tristate "Bus domain sockets (EXPERIMENTAL)"
++      depends on EXPERIMENTAL
++      ---help---
++        If you say Y here, you will include support for Bus domain sockets.
++        These sockets are used to create communication buses for IPC.
++
++        To compile this driver as a module, choose M here: the module will be
++        called bus.
++
++        Say N unless you know what you are doing.
+diff --git a/net/bus/Makefile b/net/bus/Makefile
+new file mode 100644
+index 0000000..8c1fea2
+--- /dev/null
++++ b/net/bus/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the Linux bus domain socket layer.
++#
++
++obj-$(CONFIG_AF_BUS)  += af-bus.o
++
++af-bus-y              := af_bus.o garbage.o
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch b/patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch
new file mode 100644 (file)
index 0000000..dd8cf5a
--- /dev/null
@@ -0,0 +1,87 @@
+From b0049444e09caf7cb41f63a8648cc1a98a5940cf Mon Sep 17 00:00:00 2001
+From: Alban Crequy <alban.crequy@collabora.co.uk>
+Date: Wed, 20 Jun 2012 18:04:37 +0200
+Subject: [PATCH 11/15] netlink: connector: implement cn_netlink_reply
+
+In a connector callback, it was not possible to reply to a message only to a
+sender. This patch implements cn_netlink_reply(). It uses the connector socket
+to send an unicast netlink message back to the sender.
+
+The following pseudo-code can be used from a connector callback:
+
+        struct cn_msg *cn_reply;
+        cn_reply = kzalloc(sizeof(struct cn_msg)
+                + sizeof(struct ..._nl_cfg_reply), GFP_KERNEL);
+
+        cn_reply->id = msg->id;
+        cn_reply->seq = msg->seq;
+        cn_reply->ack = msg->ack  + 1;
+        cn_reply->len = sizeof(struct ..._nl_cfg_reply);
+        cn_reply->flags = 0;
+
+        rr = cn_netlink_reply(cn_reply, nsp->pid, GFP_KERNEL);
+
+Signed-off-by: Alban Crequy <alban.crequy@collabora.co.uk>
+---
+ drivers/connector/connector.c |   32 ++++++++++++++++++++++++++++++++
+ include/linux/connector.h     |    1 +
+ 2 files changed, 33 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
+index dde6a0f..a1f9364 100644
+--- a/drivers/connector/connector.c
++++ b/drivers/connector/connector.c
+@@ -118,6 +118,38 @@ nlmsg_failure:
+ EXPORT_SYMBOL_GPL(cn_netlink_send);
+ /*
++ * Send an unicast reply from a connector callback
++ *
++ */
++int cn_netlink_reply(struct cn_msg *msg, u32 pid, gfp_t gfp_mask)
++{
++      unsigned int size;
++      struct sk_buff *skb;
++      struct nlmsghdr *nlh;
++      struct cn_msg *data;
++      struct cn_dev *dev = &cdev;
++
++      size = NLMSG_SPACE(sizeof(*msg) + msg->len);
++
++      skb = alloc_skb(size, gfp_mask);
++      if (!skb)
++              return -ENOMEM;
++
++      nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh), 0);
++      if (nlh == NULL) {
++              kfree_skb(skb);
++              return -EMSGSIZE;
++      }
++
++      data = nlmsg_data(nlh);
++
++      memcpy(data, msg, sizeof(*data) + msg->len);
++
++      return netlink_unicast(dev->nls, skb, pid, 1);
++}
++EXPORT_SYMBOL_GPL(cn_netlink_reply);
++
++/*
+  * Callback helper - queues work and setup destructor for given data.
+  */
+ static int cn_call_callback(struct sk_buff *skb)
+diff --git a/include/linux/connector.h b/include/linux/connector.h
+index 7638407..c27be60 100644
+--- a/include/linux/connector.h
++++ b/include/linux/connector.h
+@@ -125,6 +125,7 @@ int cn_add_callback(struct cb_id *id, const char *name,
+                   void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
+ void cn_del_callback(struct cb_id *);
+ int cn_netlink_send(struct cn_msg *, u32, gfp_t);
++int cn_netlink_reply(struct cn_msg *, u32, gfp_t);
+ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
+                         struct cb_id *id,
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch b/patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch
new file mode 100644 (file)
index 0000000..7bd7553
--- /dev/null
@@ -0,0 +1,42 @@
+From b34502ec47d9b6cdc526c762837fd242cb674c44 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 18:15:09 +0200
+Subject: [PATCH 12/15] netlink: connector: Add idx and val identifiers for
+ netfilter D-Bus
+
+The D-bus IPC system implements a transport that uses AF_BUS sockets to
+send D-Bus messages to the peers. This allows decouple the routing logic
+from the daemon and move it to the kernel which has the advantage of
+reducing the number of context switches and the messages copied to
+user-space.
+
+A D-Bus protocol aware netfilter module decide which peer can recive a
+given message based on a set of D-Bus match rules. These match rules
+are set from user-space using the netlink connector API.
+
+Based on a previous patch by Alban Crequy.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ include/linux/connector.h |    4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/include/linux/connector.h b/include/linux/connector.h
+index c27be60..519d010 100644
+--- a/include/linux/connector.h
++++ b/include/linux/connector.h
+@@ -44,8 +44,10 @@
+ #define CN_VAL_DRBD                   0x1
+ #define CN_KVP_IDX                    0x9     /* HyperV KVP */
+ #define CN_KVP_VAL                    0x1     /* queries from the kernel */
++#define CN_IDX_NFDBUS                   0xA     /* netfilter D-Bus */
++#define CN_VAL_NFDBUS                   0x1
+-#define CN_NETLINK_USERS              10      /* Highest index + 1 */
++#define CN_NETLINK_USERS              11      /* Highest index + 1 */
+ /*
+  * Maximum connector's message size.
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch b/patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch
new file mode 100644 (file)
index 0000000..c00eae3
--- /dev/null
@@ -0,0 +1,299 @@
+From ef39ec62107dfb7fa0ecd43026804e214569cad5 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 19:01:52 +0200
+Subject: [PATCH 13/15] netfilter: nfdbus: Add D-bus message parsing
+
+The netfilter D-Bus module needs to parse D-bus messages sent by
+applications to decide whether a peer can receive or not a D-Bus
+message. Add D-bus message parsing logic to be able to analyze.
+
+Based on a previous patch by Alban Crequy.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ net/bus/nfdbus/message.c |  194 ++++++++++++++++++++++++++++++++++++++++++++++
+ net/bus/nfdbus/message.h |   71 +++++++++++++++++
+ 2 files changed, 265 insertions(+), 0 deletions(-)
+ create mode 100644 net/bus/nfdbus/message.c
+ create mode 100644 net/bus/nfdbus/message.h
+
+diff --git a/net/bus/nfdbus/message.c b/net/bus/nfdbus/message.c
+new file mode 100644
+index 0000000..93c409c
+--- /dev/null
++++ b/net/bus/nfdbus/message.c
+@@ -0,0 +1,194 @@
++/*
++ * message.c  Basic D-Bus message parsing
++ *
++ * Copyright (C) 2010-2012  Collabora Ltd
++ * Authors:   Alban Crequy <alban.crequy@collabora.co.uk>
++ * Copyright (C) 2002, 2003, 2004, 2005  Red Hat Inc.
++ * Copyright (C) 2002, 2003  CodeFactory AB
++ *
++ * 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/slab.h>
++
++#include "message.h"
++
++int dbus_message_type_from_string(const char *type_str)
++{
++      if (strcmp(type_str, "method_call") == 0)
++              return DBUS_MESSAGE_TYPE_METHOD_CALL;
++      if (strcmp(type_str, "method_return") == 0)
++              return DBUS_MESSAGE_TYPE_METHOD_RETURN;
++      else if (strcmp(type_str, "signal") == 0)
++              return DBUS_MESSAGE_TYPE_SIGNAL;
++      else if (strcmp(type_str, "error") == 0)
++              return DBUS_MESSAGE_TYPE_ERROR;
++      else
++              return DBUS_MESSAGE_TYPE_INVALID;
++}
++
++int dbus_message_parse(unsigned char *message, size_t len,
++                     struct dbus_message *dbus_message)
++{
++      unsigned char *cur;
++      int array_header_len;
++
++      dbus_message->message = message;
++
++      if (len < 4 + 4 + 4 + 4 || message[1] == 0 || message[1] > 4)
++              return -EINVAL;
++
++      dbus_message->type = message[1];
++      dbus_message->body_length = *((u32 *)(message + 4));
++      cur = message + 12;
++      array_header_len = *(u32 *)cur;
++      dbus_message->len_offset = 12;
++      cur += 4;
++      while (cur < message + len
++             && cur < message + 12 + 4 + array_header_len) {
++              int header_code;
++              int signature_len;
++              unsigned char *signature;
++              int str_len;
++              unsigned char *str;
++
++              /* D-Bus alignment craziness */
++              if ((cur - message) % 8 != 0)
++                      cur += 8 - (cur - message) % 8;
++
++              header_code = *(char *)cur;
++              cur++;
++              signature_len = *(char *)cur;
++              /* All header fields of the current D-Bus spec have a simple
++               * type, either o, s, g, or u */
++              if (signature_len != 1)
++                      return -EINVAL;
++              cur++;
++              signature = cur;
++              cur += signature_len + 1;
++              if (signature[0] != 'o' &&
++                  signature[0] != 's' &&
++                  signature[0] != 'g' &&
++                  signature[0] != 'u')
++                      return -EINVAL;
++
++              if (signature[0] == 'u') {
++                      cur += 4;
++                      continue;
++              }
++
++              if (signature[0] != 'g') {
++                      str_len = *(u32 *)cur;
++                      cur += 4;
++              } else {
++                      str_len = *(char *)cur;
++                      cur += 1;
++              }
++
++              str = cur;
++              switch (header_code) {
++              case 1:
++                      dbus_message->path = str;
++                      break;
++              case 2:
++                      dbus_message->interface = str;
++                      break;
++              case 3:
++                      dbus_message->member = str;
++                      break;
++              case 6:
++                      dbus_message->destination = str;
++                      break;
++              case 7:
++                      dbus_message->sender = str;
++                      break;
++              case 8:
++                      dbus_message->body_signature = str;
++                      break;
++              }
++              cur += str_len + 1;
++      }
++
++      dbus_message->padding_end = (8 - (cur - message) % 8) % 8;
++
++      /* Jump to body D-Bus alignment craziness */
++      if ((cur - message) % 8 != 0)
++              cur += 8 - (cur - message) % 8;
++      dbus_message->new_header_offset = cur - message;
++
++      if (dbus_message->new_header_offset
++          + dbus_message->body_length != len) {
++              pr_warn("Message truncated? " \
++                      "Header %d + Body %d != Length %zd\n",
++                      dbus_message->new_header_offset,
++                      dbus_message->body_length, len);
++              return -EINVAL;
++      }
++
++      if (dbus_message->body_signature &&
++          dbus_message->body_signature[0] == 's') {
++              int str_len;
++              str_len = *(u32 *)cur;
++              cur += 4;
++              dbus_message->arg0 = cur;
++              cur += str_len + 1;
++      }
++
++      if ((cur - message) % 4 != 0)
++              cur += 4 - (cur - message) % 4;
++
++      if (dbus_message->body_signature &&
++          dbus_message->body_signature[0] == 's' &&
++          dbus_message->body_signature[1] == 's') {
++              int str_len;
++              str_len = *(u32 *)cur;
++              cur += 4;
++              dbus_message->arg1 = cur;
++              cur += str_len + 1;
++      }
++
++      if ((cur - message) % 4 != 0)
++              cur += 4 - (cur - message) % 4;
++
++      if (dbus_message->body_signature &&
++          dbus_message->body_signature[0] == 's' &&
++          dbus_message->body_signature[1] == 's' &&
++          dbus_message->body_signature[2] == 's') {
++              int str_len;
++              str_len = *(u32 *)cur;
++              cur += 4;
++              dbus_message->arg2 = cur;
++              cur += str_len + 1;
++      }
++
++      if ((cur - message) % 4 != 0)
++              cur += 4 - (cur - message) % 4;
++
++      if (dbus_message->type == DBUS_MESSAGE_TYPE_SIGNAL &&
++          dbus_message->sender && dbus_message->path &&
++          dbus_message->interface && dbus_message->member &&
++          dbus_message->arg0 &&
++          strcmp(dbus_message->sender, "org.freedesktop.DBus") == 0 &&
++          strcmp(dbus_message->interface, "org.freedesktop.DBus") == 0 &&
++          strcmp(dbus_message->path, "/org/freedesktop/DBus") == 0) {
++              if (strcmp(dbus_message->member, "NameAcquired") == 0)
++                      dbus_message->name_acquired = dbus_message->arg0;
++              else if (strcmp(dbus_message->member, "NameLost") == 0)
++                      dbus_message->name_lost = dbus_message->arg0;
++      }
++
++      return 0;
++}
+diff --git a/net/bus/nfdbus/message.h b/net/bus/nfdbus/message.h
+new file mode 100644
+index 0000000..e3ea4d3
+--- /dev/null
++++ b/net/bus/nfdbus/message.h
+@@ -0,0 +1,71 @@
++/*
++ * message.h  Basic D-Bus message parsing
++ *
++ * Copyright (C) 2010  Collabora Ltd
++ *
++ * 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef DBUS_MESSAGE_H
++#define DBUS_MESSAGE_H
++
++#include <linux/list.h>
++
++#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024
++
++/* Types of message */
++
++#define DBUS_MESSAGE_TYPE_INVALID       0
++#define DBUS_MESSAGE_TYPE_METHOD_CALL   1
++#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
++#define DBUS_MESSAGE_TYPE_ERROR         3
++#define DBUS_MESSAGE_TYPE_SIGNAL        4
++#define DBUS_NUM_MESSAGE_TYPES          5
++
++/* No need to implement a feature-complete parser. It only implement what is
++ * needed by the bus. */
++struct dbus_message {
++      char *message;
++      size_t len;
++      size_t new_len;
++
++      /* direct pointers to the fields */
++      int type;
++      char *path;
++      char *interface;
++      char *member;
++      char *destination;
++      char *sender;
++      char *body_signature;
++      int body_length;
++      char *arg0;
++      char *arg1;
++      char *arg2;
++      char *name_acquired;
++      char *name_lost;
++
++      /* How to add the 'sender' field in the headers */
++      int new_header_offset;
++      int len_offset;
++      int padding_end;
++};
++
++int dbus_message_type_from_string(const char *type_str);
++
++int dbus_message_parse(unsigned char *message, size_t len,
++                     struct dbus_message *dbus_message);
++
++#endif /* DBUS_MESSAGE_H */
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch b/patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch
new file mode 100644 (file)
index 0000000..2404f38
--- /dev/null
@@ -0,0 +1,1247 @@
+From 7532e3f92cd858c9cbe441895f3e33d007c59f57 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 19:05:54 +0200
+Subject: [PATCH 14/15] netfilter: nfdbus: Add D-bus match rule implementation
+
+The D-Bus netfilter module needs to decode D-Bus match rules to decide
+if a given peer can receive or not a D-Bus message. Add a match rule
+implementation to be used by the netfilter D-Bus module.
+
+Based on a previous patch by Alban Crequy.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ net/bus/nfdbus/matchrule.c | 1131 ++++++++++++++++++++++++++++++++++++++++++++
+ net/bus/nfdbus/matchrule.h |   82 ++++
+ 2 files changed, 1213 insertions(+), 0 deletions(-)
+ create mode 100644 net/bus/nfdbus/matchrule.c
+ create mode 100644 net/bus/nfdbus/matchrule.h
+
+diff --git a/net/bus/nfdbus/matchrule.c b/net/bus/nfdbus/matchrule.c
+new file mode 100644
+index 0000000..1946345
+--- /dev/null
++++ b/net/bus/nfdbus/matchrule.c
+@@ -0,0 +1,1131 @@
++/*
++ * matchrule.c  D-Bus match rule implementation
++ *
++ * Based on signals.c from dbus
++ *
++ * Copyright (C) 2010  Collabora, Ltd.
++ * Copyright (C) 2003, 2005  Red Hat, Inc.
++ *
++ * 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include "matchrule.h"
++
++#include <linux/rbtree.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++
++#include "message.h"
++
++enum bus_match_flags {
++      BUS_MATCH_MESSAGE_TYPE            = 1 << 0,
++      BUS_MATCH_INTERFACE               = 1 << 1,
++      BUS_MATCH_MEMBER                  = 1 << 2,
++      BUS_MATCH_SENDER                  = 1 << 3,
++      BUS_MATCH_DESTINATION             = 1 << 4,
++      BUS_MATCH_PATH                    = 1 << 5,
++      BUS_MATCH_ARGS                    = 1 << 6,
++      BUS_MATCH_PATH_NAMESPACE          = 1 << 7,
++      BUS_MATCH_CLIENT_IS_EAVESDROPPING = 1 << 8
++};
++
++struct bus_match_rule {
++      /* For debugging only*/
++      char *rule_text;
++
++      unsigned int flags; /**< BusMatchFlags */
++
++      int   message_type;
++      char *interface;
++      char *member;
++      char *sender;
++      char *destination;
++      char *path;
++
++      unsigned int *arg_lens;
++      char **args;
++      int args_len;
++
++      /* bus_match_rule is attached to rule_pool, either in a simple
++       * double-linked list if the rule does not have any interface, or in a
++       * red-black tree sorted by interface. If several rules can have the
++       * same interface, the first one is attached with struct rb_node and the
++       * next ones are in the list
++       */
++
++      struct rb_node node;
++      /* Doubly-linked non-circular list. If the rule has an interface, it is
++       * in the rb tree and the single head is right here. Otherwise, the
++       * single head is in rule_pool->rules_without_iface. With this data
++       * structure, we don't need any allocation to insert or remove the rule.
++       */
++      struct hlist_head first;
++      struct hlist_node list;
++
++      /* used to delete all names from the tree */
++      struct list_head del_list;
++};
++
++struct dbus_name {
++      struct rb_node node;
++      char *name;
++
++      /* used to delete all names from the tree */
++      struct list_head del_list;
++};
++
++#define BUS_MATCH_ARG_IS_PATH  0x8000000u
++
++#define DBUS_STRING_MAX_LENGTH 1024
++
++/** Max length of a match rule string; to keep people from hosing the
++ * daemon with some huge rule
++ */
++#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024
++
++struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags)
++{
++      struct bus_match_rule *rule;
++
++      rule = kzalloc(sizeof(struct bus_match_rule), gfp_flags);
++      if (rule == NULL)
++              return NULL;
++
++      return rule;
++}
++
++void bus_match_rule_free(struct bus_match_rule *rule)
++{
++      kfree(rule->rule_text);
++      kfree(rule->interface);
++      kfree(rule->member);
++      kfree(rule->sender);
++      kfree(rule->destination);
++      kfree(rule->path);
++      kfree(rule->arg_lens);
++
++      /* can't use dbus_free_string_array() since there
++       * are embedded NULL
++       */
++      if (rule->args) {
++              int i;
++
++              i = 0;
++              while (i < rule->args_len) {
++                      kfree(rule->args[i]);
++                      ++i;
++              }
++
++              kfree(rule->args);
++      }
++
++      kfree(rule);
++}
++
++static int
++bus_match_rule_set_message_type(struct bus_match_rule *rule,
++                              int type,
++                              gfp_t gfp_flags)
++{
++      rule->flags |= BUS_MATCH_MESSAGE_TYPE;
++
++      rule->message_type = type;
++
++      return 1;
++}
++
++static int
++bus_match_rule_set_interface(struct bus_match_rule *rule,
++                           const char *interface,
++                           gfp_t gfp_flags)
++{
++      char *new;
++
++      WARN_ON(!interface);
++
++      new = kstrdup(interface, gfp_flags);
++      if (new == NULL)
++              return 0;
++
++      rule->flags |= BUS_MATCH_INTERFACE;
++      kfree(rule->interface);
++      rule->interface = new;
++
++      return 1;
++}
++
++static int
++bus_match_rule_set_member(struct bus_match_rule *rule,
++                        const char *member,
++                        gfp_t gfp_flags)
++{
++      char *new;
++
++      WARN_ON(!member);
++
++      new = kstrdup(member, gfp_flags);
++      if (new == NULL)
++              return 0;
++
++      rule->flags |= BUS_MATCH_MEMBER;
++      kfree(rule->member);
++      rule->member = new;
++
++      return 1;
++}
++
++static int
++bus_match_rule_set_sender(struct bus_match_rule *rule,
++                        const char *sender,
++                        gfp_t gfp_flags)
++{
++      char *new;
++
++      WARN_ON(!sender);
++
++      new = kstrdup(sender, gfp_flags);
++      if (new == NULL)
++              return 0;
++
++      rule->flags |= BUS_MATCH_SENDER;
++      kfree(rule->sender);
++      rule->sender = new;
++
++      return 1;
++}
++
++static int
++bus_match_rule_set_destination(struct bus_match_rule *rule,
++                             const char   *destination,
++                             gfp_t gfp_flags)
++{
++      char *new;
++
++      WARN_ON(!destination);
++
++      new = kstrdup(destination, gfp_flags);
++      if (new == NULL)
++              return 0;
++
++      rule->flags |= BUS_MATCH_DESTINATION;
++      kfree(rule->destination);
++      rule->destination = new;
++
++      return 1;
++}
++
++#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || \
++                  ((c) == '\r'))
++
++static int find_key(const char *str, int start, char *key, int *value_pos)
++{
++      const char *p;
++      const char *s;
++      const char *key_start;
++      const char *key_end;
++
++      s = str;
++
++      p = s + start;
++
++      while (*p && ISWHITE(*p))
++              ++p;
++
++      key_start = p;
++
++      while (*p && *p != '=' && !ISWHITE(*p))
++              ++p;
++
++      key_end = p;
++
++      while (*p && ISWHITE(*p))
++              ++p;
++
++      if (key_start == key_end) {
++              /* Empty match rules or trailing whitespace are OK */
++              *value_pos = p - s;
++              return 1;
++      }
++
++      if (*p != '=') {
++              pr_warn("Match rule has a key with no subsequent '=' character");
++              return 0;
++      }
++      ++p;
++
++      strncat(key, key_start, key_end - key_start);
++
++      *value_pos = p - s;
++
++      return 1;
++}
++
++static int find_value(const char *str, int start, const char *key, char *value,
++                    int *value_end)
++{
++      const char *p;
++      const char *s;
++      char quote_char;
++      int orig_len;
++
++      orig_len = strlen(value);
++
++      s = str;
++
++      p = s + start;
++
++      quote_char = '\0';
++
++      while (*p) {
++              if (quote_char == '\0') {
++                      switch (*p) {
++                      case '\0':
++                              goto done;
++
++                      case '\'':
++                              quote_char = '\'';
++                              goto next;
++
++                      case ',':
++                              ++p;
++                              goto done;
++
++                      case '\\':
++                              quote_char = '\\';
++                              goto next;
++
++                      default:
++                              strncat(value, p, 1);
++                      }
++              } else if (quote_char == '\\') {
++                      /*\ only counts as an escape if escaping a quote mark */
++                      if (*p != '\'')
++                              strncat(value, "\\", 1);
++
++                      strncat(value, p, 1);
++
++                      quote_char = '\0';
++              } else {
++                      if (*p == '\'')
++                              quote_char = '\0';
++                      else
++                              strncat(value, p, 1);
++              }
++
++next:
++              ++p;
++      }
++
++done:
++
++      if (quote_char == '\\')
++              strncat(value, "\\", 1);
++      else if (quote_char == '\'') {
++              pr_warn("Unbalanced quotation marks in match rule");
++              return 0;
++      }
++
++      /* Zero-length values are allowed */
++
++      *value_end = p - s;
++
++      return 1;
++}
++
++/* duplicates aren't allowed so the real legitimate max is only 6 or
++ * so. Leaving extra so we don't have to bother to update it.
++ * FIXME this is sort of busted now with arg matching, but we let
++ * you match on up to 10 args for now
++ */
++#define MAX_RULE_TOKENS 16
++
++/* this is slightly too high level to be termed a "token"
++ * but let's not be pedantic.
++ */
++struct rule_token {
++      char *key;
++      char *value;
++};
++
++static int tokenize_rule(const char *rule_text,
++                       struct rule_token tokens[MAX_RULE_TOKENS],
++                       gfp_t gfp_flags)
++{
++      int i;
++      int pos;
++      int retval;
++
++      retval = 0;
++
++      i = 0;
++      pos = 0;
++      while (i < MAX_RULE_TOKENS &&
++             pos < strlen(rule_text)) {
++              char *key;
++              char *value;
++
++              key = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags);
++              if (!key) {
++                      pr_err("Out of memory");
++                      return 0;
++              }
++
++              value = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags);
++              if (!value) {
++                      kfree(key);
++                      pr_err("Out of memory");
++                      return 0;
++              }
++
++              if (!find_key(rule_text, pos, key, &pos))
++                      goto out;
++
++              if (strlen(key) == 0)
++                      goto next;
++
++              tokens[i].key = key;
++
++              if (!find_value(rule_text, pos, tokens[i].key, value, &pos))
++                      goto out;
++
++              tokens[i].value = value;
++
++next:
++              ++i;
++      }
++
++      retval = 1;
++
++out:
++      if (!retval) {
++              i = 0;
++              while (tokens[i].key || tokens[i].value) {
++                      kfree(tokens[i].key);
++                      kfree(tokens[i].value);
++                      tokens[i].key = NULL;
++                      tokens[i].value = NULL;
++                      ++i;
++              }
++      }
++
++      return retval;
++}
++
++/*
++ * The format is comma-separated with strings quoted with single quotes
++ * as for the shell (to escape a literal single quote, use '\'').
++ *
++ * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',
++ * member='Foo', path='/bar/foo',destination=':452345.34'
++ *
++ */
++struct bus_match_rule *bus_match_rule_parse(const char *rule_text,
++                                          gfp_t gfp_flags)
++{
++      struct bus_match_rule *rule;
++      struct rule_token tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
++      int i;
++
++      if (strlen(rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) {
++              pr_warn("Match rule text is %ld bytes, maximum is %d",
++                          strlen(rule_text),
++                          DBUS_MAXIMUM_MATCH_RULE_LENGTH);
++              return NULL;
++      }
++
++      memset(tokens, '\0', sizeof(tokens));
++
++      rule = bus_match_rule_new(gfp_flags);
++      if (rule == NULL) {
++              pr_err("Out of memory");
++              goto failed;
++      }
++
++      rule->rule_text = kstrdup(rule_text, gfp_flags);
++      if (rule->rule_text == NULL) {
++              pr_err("Out of memory");
++              goto failed;
++      }
++
++      if (!tokenize_rule(rule_text, tokens, gfp_flags))
++              goto failed;
++
++      i = 0;
++      while (tokens[i].key != NULL) {
++              const char *key = tokens[i].key;
++              const char *value = tokens[i].value;
++
++              if (strcmp(key, "type") == 0) {
++                      int t;
++
++                      if (rule->flags & BUS_MATCH_MESSAGE_TYPE) {
++                              pr_warn("Key %s specified twice in match rule\n",
++                                      key);
++                              goto failed;
++                      }
++
++                      t = dbus_message_type_from_string(value);
++
++                      if (t == DBUS_MESSAGE_TYPE_INVALID) {
++                              pr_warn("Invalid message type (%s) in match rule\n",
++                                      value);
++                              goto failed;
++                      }
++
++                      if (!bus_match_rule_set_message_type(rule, t,
++                                                           gfp_flags)) {
++                              pr_err("Out of memeory");
++                              goto failed;
++                      }
++              } else if (strcmp(key, "sender") == 0) {
++                      if (rule->flags & BUS_MATCH_SENDER) {
++                              pr_warn("Key %s specified twice in match rule\n",
++                                      key);
++                              goto failed;
++                      }
++
++                      if (!bus_match_rule_set_sender(rule, value,
++                                                     gfp_flags)) {
++                              pr_err("Out of memeory");
++                              goto failed;
++                      }
++              } else if (strcmp(key, "interface") == 0) {
++                      if (rule->flags & BUS_MATCH_INTERFACE) {
++                              pr_warn("Key %s specified twice in match rule\n",
++                                      key);
++                              goto failed;
++                      }
++
++                      if (!bus_match_rule_set_interface(rule, value,
++                                                        gfp_flags)) {
++                              pr_err("Out of memeory");
++                              goto failed;
++                      }
++              } else if (strcmp(key, "member") == 0) {
++                      if (rule->flags & BUS_MATCH_MEMBER) {
++                              pr_warn("Key %s specified twice in match rule\n",
++                                      key);
++                              goto failed;
++                      }
++
++                      if (!bus_match_rule_set_member(rule, value,
++                                                     gfp_flags)) {
++                              pr_err("Out of memeory");
++                              goto failed;
++                      }
++              } else if (strcmp(key, "destination") == 0) {
++                      if (rule->flags & BUS_MATCH_DESTINATION) {
++                              pr_warn("Key %s specified twice in match rule\n",
++                                      key);
++                              goto failed;
++                      }
++
++                      if (!bus_match_rule_set_destination(rule, value,
++                                                          gfp_flags)) {
++                              pr_err("Out of memeory");
++                              goto failed;
++                      }
++              } else if (strcmp(key, "eavesdrop") == 0) {
++                      if (strcmp(value, "true") == 0) {
++                              rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
++                      } else if (strcmp(value, "false") == 0) {
++                              rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
++                      } else {
++                              pr_warn("eavesdrop='%s' is invalid, " \
++                                      "it should be 'true' or 'false'\n",
++                                      value);
++                              goto failed;
++                      }
++              } else if (strncmp(key, "arg", 3) != 0) {
++                      pr_warn("Unknown key \"%s\" in match rule\n",
++                                 key);
++                      goto failed;
++              }
++
++              ++i;
++      }
++
++      goto out;
++
++failed:
++      if (rule) {
++              bus_match_rule_free(rule);
++              rule = NULL;
++      }
++
++out:
++
++      i = 0;
++      while (tokens[i].key || tokens[i].value) {
++              WARN_ON(i >= MAX_RULE_TOKENS);
++              kfree(tokens[i].key);
++              kfree(tokens[i].value);
++              ++i;
++      }
++
++      return rule;
++}
++
++/* return the match rule containing the hlist_head. It may not be the first
++ * match rule in the list. */
++struct bus_match_rule *match_rule_search(struct rb_root *root,
++                                       const char *interface)
++{
++      struct rb_node *node = root->rb_node;
++
++      while (node) {
++              struct bus_match_rule *data =
++                      container_of(node, struct bus_match_rule, node);
++              int result;
++
++              result = strcmp(interface, data->interface);
++
++              if (result < 0)
++                      node = node->rb_left;
++              else if (result > 0)
++                      node = node->rb_right;
++              else
++                      return data;
++      }
++      return NULL;
++}
++
++void match_rule_insert(struct rb_root *root, struct bus_match_rule *data)
++{
++      struct rb_node **new = &(root->rb_node), *parent = NULL;
++
++      /* Figure out where to put new node */
++      while (*new) {
++              struct bus_match_rule *this =
++                      container_of(*new, struct bus_match_rule, node);
++              int result = strcmp(data->interface, this->interface);
++
++              parent = *new;
++              if (result < 0)
++                      new = &((*new)->rb_left);
++              else if (result > 0)
++                      new = &((*new)->rb_right);
++              else {
++                      /* the head is not used */
++                      INIT_HLIST_HEAD(&data->first);
++                      /* Add it at the beginning of the list */
++                      hlist_add_head(&data->list, &this->first);
++                      return;
++              }
++      }
++
++      /* this rule is single in its list */
++      INIT_HLIST_HEAD(&data->first);
++      hlist_add_head(&data->list, &data->first);
++
++      /* Add new node and rebalance tree. */
++      rb_link_node(&data->node, parent, new);
++      rb_insert_color(&data->node, root);
++}
++
++struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags)
++{
++      struct bus_match_maker *matchmaker;
++      int i;
++
++      matchmaker = kzalloc(sizeof(struct bus_match_maker), gfp_flags);
++      if (matchmaker == NULL)
++              return NULL;
++
++      for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) {
++              struct rule_pool *p = matchmaker->rules_by_type + i;
++
++              p->rules_by_iface = RB_ROOT;
++      }
++
++      kref_init(&matchmaker->kref);
++
++      return matchmaker;
++}
++
++void bus_matchmaker_free(struct kref *kref)
++{
++      struct bus_match_maker *matchmaker;
++      struct list_head del_list;
++      struct rb_node *n;
++      int i;
++
++      matchmaker = container_of(kref, struct bus_match_maker, kref);
++
++      /* free names */
++      INIT_LIST_HEAD(&del_list);
++      n = matchmaker->names.rb_node;
++      if (n) {
++              struct dbus_name *dbus_name, *cur, *tmp;
++
++              dbus_name = rb_entry(n, struct dbus_name, node);
++              list_add_tail(&dbus_name->del_list, &del_list);
++
++              list_for_each_entry(cur, &del_list, del_list) {
++                      struct dbus_name *right, *left;
++                      if (cur->node.rb_right) {
++                              right = rb_entry(cur->node.rb_right,
++                                               struct dbus_name, node);
++                              list_add_tail(&right->del_list, &del_list);
++                      }
++                      if (cur->node.rb_left) {
++                              left = rb_entry(cur->node.rb_left,
++                                              struct dbus_name, node);
++                              list_add_tail(&left->del_list, &del_list);
++                      }
++              }
++              list_for_each_entry_safe(dbus_name, tmp, &del_list, del_list) {
++                      kfree(dbus_name->name);
++                      list_del(&dbus_name->del_list);
++                      kfree(dbus_name);
++              }
++      }
++      WARN_ON(!list_empty_careful(&del_list));
++
++      /* free match rules */
++      for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++) {
++              struct rule_pool *pool = matchmaker->rules_by_type + i;
++              struct bus_match_rule *match_rule, *cur, *tmp;
++              struct hlist_node *list_tmp, *list_tmp2;
++
++              /* free match rules from the list */
++              hlist_for_each_entry_safe(cur, list_tmp, list_tmp2,
++                                        &pool->rules_without_iface, list) {
++                      bus_match_rule_free(cur);
++              }
++
++              /* free match rules from the tree */
++              if (!pool->rules_by_iface.rb_node)
++                      continue;
++              match_rule = rb_entry(pool->rules_by_iface.rb_node,
++                                    struct bus_match_rule, node);
++              list_add_tail(&match_rule->del_list, &del_list);
++
++              list_for_each_entry(cur, &del_list, del_list) {
++                      struct bus_match_rule *right, *left;
++                      if (cur->node.rb_right) {
++                              right = rb_entry(cur->node.rb_right,
++                                               struct bus_match_rule, node);
++                              list_add_tail(&right->del_list, &del_list);
++                      }
++                      if (cur->node.rb_left) {
++                              left = rb_entry(cur->node.rb_left,
++                                              struct bus_match_rule, node);
++                              list_add_tail(&left->del_list, &del_list);
++                      }
++              }
++              list_for_each_entry_safe(match_rule, tmp, &del_list, del_list) {
++                      /* keep a ref during the loop to ensure the first
++                       * iteration of the loop does not delete it */
++                      hlist_for_each_entry_safe(cur, list_tmp, list_tmp2,
++                                                &match_rule->first, list) {
++                              if (cur != match_rule)
++                                      bus_match_rule_free(cur);
++                      }
++                      list_del(&match_rule->del_list);
++                      bus_match_rule_free(match_rule);
++              }
++              WARN_ON(!list_empty_careful(&del_list));
++      }
++
++      kfree(matchmaker);
++}
++
++/* The rule can't be modified after it's added. */
++int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker,
++                          struct bus_match_rule *rule)
++{
++      struct rule_pool *pool;
++
++      WARN_ON(rule->message_type < 0);
++      WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES);
++
++      pool = matchmaker->rules_by_type + rule->message_type;
++
++      if (rule->interface)
++              match_rule_insert(&pool->rules_by_iface, rule);
++      else
++              hlist_add_head(&rule->list, &pool->rules_without_iface);
++
++      return 1;
++}
++
++static int match_rule_equal(struct bus_match_rule *a,
++                          struct bus_match_rule *b)
++{
++      if (a->flags != b->flags)
++              return 0;
++
++      if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
++          a->message_type != b->message_type)
++              return 0;
++
++      if ((a->flags & BUS_MATCH_MEMBER) &&
++          strcmp(a->member, b->member) != 0)
++              return 0;
++
++      if ((a->flags & BUS_MATCH_PATH) &&
++          strcmp(a->path, b->path) != 0)
++              return 0;
++
++      if ((a->flags & BUS_MATCH_INTERFACE) &&
++          strcmp(a->interface, b->interface) != 0)
++              return 0;
++
++      if ((a->flags & BUS_MATCH_SENDER) &&
++          strcmp(a->sender, b->sender) != 0)
++              return 0;
++
++      if ((a->flags & BUS_MATCH_DESTINATION) &&
++          strcmp(a->destination, b->destination) != 0)
++              return 0;
++
++      if (a->flags & BUS_MATCH_ARGS) {
++              int i;
++
++              if (a->args_len != b->args_len)
++                      return 0;
++
++              i = 0;
++              while (i < a->args_len) {
++                      int length;
++
++                      if ((a->args[i] != NULL) != (b->args[i] != NULL))
++                              return 0;
++
++                      if (a->arg_lens[i] != b->arg_lens[i])
++                              return 0;
++
++                      length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
++
++                      if (a->args[i] != NULL) {
++                              WARN_ON(!b->args[i]);
++                              if (memcmp(a->args[i], b->args[i], length) != 0)
++                                      return 0;
++                      }
++
++                      ++i;
++              }
++      }
++
++      return 1;
++}
++
++/* Remove a single rule which is equal to the given rule by value */
++void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker,
++                                       struct bus_match_rule *rule)
++{
++      struct rule_pool *pool;
++
++      WARN_ON(rule->message_type < 0);
++      WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES);
++
++      pool = matchmaker->rules_by_type + rule->message_type;
++
++      if (rule->interface) {
++              struct bus_match_rule *head =
++                      match_rule_search(&pool->rules_by_iface,
++                                        rule->interface);
++
++              struct hlist_node *cur;
++              struct bus_match_rule *cur_rule;
++              hlist_for_each_entry(cur_rule, cur, &head->first, list) {
++                      if (match_rule_equal(cur_rule, rule)) {
++                              hlist_del(cur);
++                              if (hlist_empty(&head->first))
++                                      rb_erase(&head->node,
++                                               &pool->rules_by_iface);
++                              bus_match_rule_free(cur_rule);
++                              break;
++                      }
++              }
++      } else {
++              struct hlist_head *head = &pool->rules_without_iface;
++
++              struct hlist_node *cur;
++              struct bus_match_rule *cur_rule;
++              hlist_for_each_entry(cur_rule, cur, head, list) {
++                      if (match_rule_equal(cur_rule, rule)) {
++                              hlist_del(cur);
++                              bus_match_rule_free(cur_rule);
++                              break;
++                      }
++              }
++      }
++
++}
++
++static int connection_is_primary_owner(struct bus_match_maker *connection,
++                                     const char *service_name)
++{
++      struct rb_node *node = connection->names.rb_node;
++
++      if (!service_name)
++              return 0;
++
++      while (node) {
++              struct dbus_name *data = container_of(node, struct dbus_name,
++                                                    node);
++              int result;
++
++              result = strcmp(service_name, data->name);
++
++              if (result < 0)
++                      node = node->rb_left;
++              else if (result > 0)
++                      node = node->rb_right;
++              else
++                      return 1;
++      }
++      return 0;
++}
++
++static int match_rule_matches(struct bus_match_maker *matchmaker,
++                            struct bus_match_maker *sender,
++                            int eavesdrop,
++                            struct bus_match_rule *rule,
++                            const struct dbus_message *message)
++{
++      /* Don't consider the rule if this is a eavesdropping match rule
++       * and eavesdropping is not allowed on that peer */
++      if ((rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) && !eavesdrop)
++              return 0;
++
++      /* Since D-Bus 1.5.6, match rules do not match messages which have a
++       * DESTINATION field unless the match rule specifically requests this
++       * by specifying eavesdrop='true' in the match rule. */
++      if (message->destination &&
++          !(rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING))
++              return 0;
++
++      if (rule->flags & BUS_MATCH_MEMBER) {
++              const char *member;
++
++              WARN_ON(!rule->member);
++
++              member = message->member;
++              if (member == NULL)
++                      return 0;
++
++              if (strcmp(member, rule->member) != 0)
++                      return 0;
++      }
++
++      if (rule->flags & BUS_MATCH_SENDER) {
++              WARN_ON(!rule->sender);
++
++              if (sender == NULL) {
++                      if (strcmp(rule->sender,
++                                 "org.freedesktop.DBus") != 0)
++                              return 0;
++              } else
++                      if (!connection_is_primary_owner(sender, rule->sender))
++                              return 0;
++      }
++
++      if (rule->flags & BUS_MATCH_DESTINATION) {
++              const char *destination;
++
++              WARN_ON(!rule->destination);
++
++              destination = message->destination;
++              if (destination == NULL)
++                      return 0;
++
++              /* This will not just work out of the box because it this is
++               * an eavesdropping match rule. */
++              if (matchmaker == NULL) {
++                      if (strcmp(rule->destination,
++                                 "org.freedesktop.DBus") != 0)
++                              return 0;
++              } else
++                      if (!connection_is_primary_owner(matchmaker,
++                                                       rule->destination))
++                              return 0;
++      }
++
++      if (rule->flags & BUS_MATCH_PATH) {
++              const char *path;
++
++              WARN_ON(!rule->path);
++
++              path = message->path;
++              if (path == NULL)
++                      return 0;
++
++              if (strcmp(path, rule->path) != 0)
++                      return 0;
++      }
++
++      return 1;
++}
++
++static bool get_recipients_from_list(struct bus_match_maker *matchmaker,
++                                   struct bus_match_maker *sender,
++                                   int eavesdrop,
++                                   struct hlist_head *rules,
++                                   const struct dbus_message *message)
++{
++      struct hlist_node *cur;
++      struct bus_match_rule *rule;
++
++      if (rules == NULL) {
++              pr_debug("no rules of this type\n");
++              return 0;
++      }
++
++      hlist_for_each_entry(rule, cur, rules, list) {
++              if (match_rule_matches(matchmaker, sender, eavesdrop, rule,
++                                      message)) {
++                      pr_debug("[YES] deliver with match rule \"%s\"\n",
++                               rule->rule_text);
++                      return 1;
++              } else {
++                      pr_debug("[NO]  deliver with match rule \"%s\"\n",
++                               rule->rule_text);
++              }
++      }
++      pr_debug("[NO]  no match rules\n");
++      return 0;
++}
++
++static struct hlist_head
++*bus_matchmaker_get_rules(struct bus_match_maker *matchmaker,
++                        int message_type, const char *interface)
++{
++      static struct hlist_head empty = {0,};
++      struct rule_pool *p;
++
++      WARN_ON(message_type < 0);
++      WARN_ON(message_type >= DBUS_NUM_MESSAGE_TYPES);
++
++      p = matchmaker->rules_by_type + message_type;
++
++      if (interface == NULL)
++              return &p->rules_without_iface;
++      else {
++              struct bus_match_rule *rule =
++                      match_rule_search(&p->rules_by_iface, interface);
++              if (rule)
++                      return &rule->first;
++              else
++                      return &empty;
++      }
++}
++
++bool bus_matchmaker_filter(struct bus_match_maker *matchmaker,
++                         struct bus_match_maker *sender,
++                         int eavesdrop,
++                         const struct dbus_message *message)
++{
++      int type;
++      const char *interface;
++      struct hlist_head *neither, *just_type, *just_iface, *both;
++
++      type = message->type;
++      interface = message->interface;
++
++      neither = bus_matchmaker_get_rules(matchmaker,
++                                         DBUS_MESSAGE_TYPE_INVALID, NULL);
++      just_type = just_iface = both = NULL;
++
++      if (interface != NULL)
++              just_iface = bus_matchmaker_get_rules(matchmaker,
++                                                    DBUS_MESSAGE_TYPE_INVALID,
++                                                    interface);
++
++      if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES) {
++              just_type = bus_matchmaker_get_rules(matchmaker, type, NULL);
++
++              if (interface != NULL)
++                      both = bus_matchmaker_get_rules(matchmaker, type,
++                                                      interface);
++      }
++
++      if (get_recipients_from_list(matchmaker, sender, eavesdrop, neither,
++                                   message))
++              return 1;
++      if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_iface,
++                                   message))
++              return 1;
++      if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_type,
++                                   message))
++              return 1;
++      if (get_recipients_from_list(matchmaker, sender, eavesdrop, both,
++                                   message))
++              return 1;
++
++      return connection_is_primary_owner(matchmaker, message->destination);
++}
++
++void bus_matchmaker_add_name(struct bus_match_maker *matchmaker,
++                           const char *name,
++                           gfp_t gfp_flags)
++{
++      struct dbus_name *dbus_name;
++      struct rb_node **new = &(matchmaker->names.rb_node), *parent = NULL;
++
++      dbus_name = kmalloc(sizeof(struct dbus_name), gfp_flags);
++      if (!dbus_name)
++              return;
++      dbus_name->name = kstrdup(name, gfp_flags);
++      if (!dbus_name->name)
++              return;
++
++      /* Figure out where to put new node */
++      while (*new) {
++              struct dbus_name *this = container_of(*new, struct dbus_name,
++                                                    node);
++              int result = strcmp(dbus_name->name, this->name);
++
++              parent = *new;
++              if (result < 0)
++                      new = &((*new)->rb_left);
++              else if (result > 0)
++                      new = &((*new)->rb_right);
++              else
++                      return;
++      }
++
++      /* Add new node and rebalance tree. */
++      rb_link_node(&dbus_name->node, parent, new);
++      rb_insert_color(&dbus_name->node, &matchmaker->names);
++}
++
++void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker,
++                              const char *name)
++{
++      struct rb_node *node = matchmaker->names.rb_node;
++
++      while (node) {
++              struct dbus_name *data = container_of(node, struct dbus_name,
++                                                    node);
++              int result;
++
++              result = strcmp(name, data->name);
++
++              if (result < 0)
++                      node = node->rb_left;
++              else if (result > 0)
++                      node = node->rb_right;
++              else {
++                      rb_erase(&data->node, &matchmaker->names);
++                      kfree(data->name);
++                      kfree(data);
++              }
++      }
++
++}
+diff --git a/net/bus/nfdbus/matchrule.h b/net/bus/nfdbus/matchrule.h
+new file mode 100644
+index 0000000..e16580c
+--- /dev/null
++++ b/net/bus/nfdbus/matchrule.h
+@@ -0,0 +1,82 @@
++/*
++ * signals.h  Bus signal connection implementation
++ *
++ * Copyright (C) 2003  Red Hat, Inc.
++ *
++ * 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef BUS_SIGNALS_H
++#define BUS_SIGNALS_H
++
++#include <linux/gfp.h>
++#include <linux/list.h>
++#include <linux/rbtree.h>
++#include <linux/slab.h>
++#include <net/af_bus.h>
++
++#include "message.h"
++
++struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags);
++void bus_match_rule_free(struct bus_match_rule *rule);
++
++struct bus_match_rule *bus_match_rule_parse(const char *rule_text,
++                                          gfp_t gfp_flags);
++
++struct rule_pool {
++      /* Maps non-NULL interface names to a list of bus_match_rule */
++      struct rb_root rules_by_iface;
++
++      /* List of bus_match_rule which don't specify an interface */
++      struct hlist_head rules_without_iface;
++};
++
++struct bus_match_maker {
++      struct sockaddr_bus addr;
++
++      struct hlist_node table_node;
++
++      /* Pools of rules, grouped by the type of message they match. 0
++       * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a
++       * message type.
++       */
++      struct rule_pool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
++
++      struct rb_root names;
++
++      struct kref kref;
++};
++
++
++struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags);
++void bus_matchmaker_free(struct kref *kref);
++
++int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker,
++                          struct bus_match_rule *rule);
++void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker,
++                                       struct bus_match_rule *value);
++
++bool bus_matchmaker_filter(struct bus_match_maker *matchmaker,
++                         struct bus_match_maker *sender,
++                         int eavesdrop,
++                         const struct dbus_message *message);
++
++void bus_matchmaker_add_name(struct bus_match_maker *matchmaker,
++                           const char *name, gfp_t gfp_flags);
++void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker,
++                              const char *name);
++
++#endif /* BUS_SIGNALS_H */
+-- 
+1.7.7.6
+
diff --git a/patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch b/patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch
new file mode 100644 (file)
index 0000000..3df3c5e
--- /dev/null
@@ -0,0 +1,593 @@
+From e4839f64c6608a2199d46819e77ed03233563301 Mon Sep 17 00:00:00 2001
+From: Alban Crequy <alban.crequy@collabora.co.uk>
+Date: Fri, 22 Jun 2012 14:20:50 +0200
+Subject: [PATCH 15/15] netfilter: add netfilter D-Bus module
+
+AF_BUS has netfilter hooks on the packet sending path. This allows the
+netfilter subsystem to register netfilter hook handlers.
+
+The netfilter_dbus module allows to inspect D-Bus messages and take
+actions based on the information contained on these messages.
+
+Signed-off-by: Alban Crequy <alban.crequy@collabora.co.uk>
+---
+ net/bus/Kconfig         |    2 +
+ net/bus/Makefile        |    3 +
+ net/bus/nfdbus/Kconfig  |   12 ++
+ net/bus/nfdbus/Makefile |    6 +
+ net/bus/nfdbus/nfdbus.c |  458 +++++++++++++++++++++++++++++++++++++++++++++++
+ net/bus/nfdbus/nfdbus.h |   44 +++++
+ 6 files changed, 525 insertions(+), 0 deletions(-)
+ create mode 100644 net/bus/nfdbus/Kconfig
+ create mode 100644 net/bus/nfdbus/Makefile
+ create mode 100644 net/bus/nfdbus/nfdbus.c
+ create mode 100644 net/bus/nfdbus/nfdbus.h
+
+diff --git a/net/bus/Kconfig b/net/bus/Kconfig
+index 5f01410..4ec0beec 100644
+--- a/net/bus/Kconfig
++++ b/net/bus/Kconfig
+@@ -13,3 +13,5 @@ config AF_BUS
+         called bus.
+         Say N unless you know what you are doing.
++
++source "net/bus/nfdbus/Kconfig"
+diff --git a/net/bus/Makefile b/net/bus/Makefile
+index 8c1fea2..a6ba263 100644
+--- a/net/bus/Makefile
++++ b/net/bus/Makefile
+@@ -5,3 +5,6 @@
+ obj-$(CONFIG_AF_BUS)  += af-bus.o
+ af-bus-y              := af_bus.o garbage.o
++
++# Dbus
++obj-$(CONFIG_NETFILTER_DBUS) += nfdbus/
+diff --git a/net/bus/nfdbus/Kconfig b/net/bus/nfdbus/Kconfig
+new file mode 100644
+index 0000000..25699a1
+--- /dev/null
++++ b/net/bus/nfdbus/Kconfig
+@@ -0,0 +1,12 @@
++#
++# Netfilter D-Bus module configuration
++#
++config NETFILTER_DBUS
++      tristate "Netfilter D-bus (EXPERIMENTAL)"
++      depends on AF_BUS && CONNECTOR && EXPERIMENTAL
++      ---help---
++        If you say Y here, you will include support for a netfilter hook to
++        parse D-Bus messages sent using the AF_BUS socket address family.
++
++        To compile this as a module, choose M here: the module will be
++        called netfilter_dbus.
+diff --git a/net/bus/nfdbus/Makefile b/net/bus/nfdbus/Makefile
+new file mode 100644
+index 0000000..1a825f8
+--- /dev/null
++++ b/net/bus/nfdbus/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for the netfilter D-Bus module
++#
++obj-$(CONFIG_NETFILTER_DBUS) += netfilter_dbus.o
++
++netfilter_dbus-y := nfdbus.o message.o matchrule.o
+diff --git a/net/bus/nfdbus/nfdbus.c b/net/bus/nfdbus/nfdbus.c
+new file mode 100644
+index 0000000..be8387a
+--- /dev/null
++++ b/net/bus/nfdbus/nfdbus.c
+@@ -0,0 +1,458 @@
++/*
++ *  nfdbus.c - Netfilter module for AF_BUS/BUS_PROTO_DBUS.
++ */
++
++#define DRIVER_AUTHOR "Alban Crequy"
++#define DRIVER_DESC   "Netfilter module for AF_BUS/BUS_PROTO_DBUS."
++
++#include "nfdbus.h"
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter.h>
++#include <linux/connector.h>
++#include <net/af_bus.h>
++
++#include "message.h"
++#include "matchrule.h"
++
++static struct nf_hook_ops nfho_dbus;
++
++static struct cb_id cn_cmd_id = { CN_IDX_NFDBUS, CN_VAL_NFDBUS };
++
++static unsigned int hash;
++
++/* Scoped by AF_BUS address */
++struct hlist_head matchrules_table[BUS_HASH_SIZE];
++DEFINE_SPINLOCK(matchrules_lock);
++
++static struct bus_match_maker *find_match_maker(struct sockaddr_bus *addr,
++              bool create, bool delete)
++{
++      u64 hash;
++      struct hlist_node *node;
++      struct bus_match_maker *matchmaker;
++      int path_len = strlen(addr->sbus_path);
++
++      hash = csum_partial(addr->sbus_path,
++                          strlen(addr->sbus_path), 0);
++      hash ^= addr->sbus_addr.s_addr;
++      hash ^= hash >> 32;
++      hash ^= hash >> 16;
++      hash ^= hash >> 8;
++      hash &= 0xff;
++
++      spin_lock(&matchrules_lock);
++      hlist_for_each_entry(matchmaker, node, &matchrules_table[hash],
++                           table_node) {
++              if (addr->sbus_family == matchmaker->addr.sbus_family &&
++                  addr->sbus_addr.s_addr == matchmaker->addr.sbus_addr.s_addr &&
++                  !memcmp(addr->sbus_path, matchmaker->addr.sbus_path,
++                         path_len)) {
++                      kref_get(&matchmaker->kref);
++                      if (delete)
++                              hlist_del(&matchmaker->table_node);
++                      spin_unlock(&matchrules_lock);
++                      pr_debug("Found matchmaker for hash %llu", hash);
++                      return matchmaker;
++              }
++      }
++      spin_unlock(&matchrules_lock);
++
++      if (!create) {
++              pr_debug("Matchmaker for hash %llu not found", hash);
++              return NULL;
++      }
++
++      matchmaker = bus_matchmaker_new(GFP_ATOMIC);
++      matchmaker->addr.sbus_family = addr->sbus_family;
++      matchmaker->addr.sbus_addr.s_addr = addr->sbus_addr.s_addr;
++      memcpy(matchmaker->addr.sbus_path, addr->sbus_path, BUS_PATH_MAX);
++
++      pr_debug("Create new matchmaker for hash %llu\n", hash);
++      spin_lock(&matchrules_lock);
++      hlist_add_head(&matchmaker->table_node, &matchrules_table[hash]);
++      kref_get(&matchmaker->kref);
++      spin_unlock(&matchrules_lock);
++      return matchmaker;
++}
++
++static unsigned int dbus_filter(unsigned int hooknum,
++                              struct sk_buff *skb,
++                              const struct net_device *in,
++                              const struct net_device *out,
++                              int (*okfn)(struct sk_buff *))
++{
++      struct bus_send_context *sendctx;
++      struct bus_match_maker *matchmaker = NULL;
++      struct bus_match_maker *sender = NULL;
++      struct dbus_message msg = {0,};
++      unsigned char *data;
++      size_t len;
++      int err;
++      int ret;
++
++      if (!skb->sk || skb->sk->sk_family != PF_BUS) {
++              WARN(1, "netfilter_dbus received an invalid skb");
++              return NF_DROP;
++      }
++
++      data = skb->data;
++      sendctx = BUSCB(skb).sendctx;
++      if (!sendctx || !sendctx->sender || !sendctx->sender_socket) {
++              WARN(1, "netfilter_dbus received an AF_BUS packet" \
++                   " without context. This is a bug. Dropping the"
++                      " packet.");
++              return NF_DROP;
++      }
++
++      if (sendctx->sender_socket->sk->sk_protocol != BUS_PROTO_DBUS) {
++              /* This kernel module is for D-Bus. It must not
++               * interfere with other users of AF_BUS. */
++              return NF_ACCEPT;
++      }
++      if (sendctx->recipient)
++              matchmaker = find_match_maker(sendctx->recipient, false, false);
++
++      len =  skb_tail_pointer(skb) - data;
++
++      if (sendctx->to_master && sendctx->main_recipient) {
++              pr_debug("AF_BUS packet to the bus master. ACCEPT.\n");
++              ret = NF_ACCEPT;
++              goto out;
++      }
++
++      if (sendctx->main_recipient && !sendctx->bus_master_side) {
++              pr_debug("AF_BUS packet from a peer to a peer (unicast). ACCEPT.\n");
++              ret = NF_ACCEPT;
++              goto out;
++      }
++
++      err = dbus_message_parse(data, len, &msg);
++      if (err) {
++              if (!sendctx->main_recipient) {
++                      pr_debug("AF_BUS packet for an eavesdropper or " \
++                               "multicast is not parsable. DROP.\n");
++                      ret = NF_DROP;
++                      goto out;
++              } else if (sendctx->bus_master_side) {
++                      pr_debug("AF_BUS packet from bus master is not parsable. ACCEPT.\n");
++                      ret = NF_ACCEPT;
++                      goto out;
++              } else {
++                      pr_debug("AF_BUS packet from peer is not parsable. DROP.\n");
++                      ret = NF_DROP;
++                      goto out;
++              }
++      }
++
++      if (sendctx->bus_master_side && !sendctx->main_recipient) {
++              pr_debug("AF_BUS packet '%s' from the bus master is for an " \
++                       "eavesdropper. DROP.\n",
++                     msg.member ? msg.member : "");
++              ret = NF_DROP;
++              goto out;
++      }
++      if (sendctx->bus_master_side) {
++              if (msg.name_acquired) {
++                      pr_debug("New name: %s [%p %p].\n",
++                               msg.name_acquired, sendctx->sender,
++                               sendctx->recipient);
++
++                      sender = find_match_maker(sendctx->sender, true, false);
++                      bus_matchmaker_add_name(sender, msg.name_acquired,
++                                              GFP_ATOMIC);
++              }
++              if (msg.name_lost) {
++                      pr_debug("Lost name: %s [%p %p].\n",
++                               msg.name_lost, sendctx->sender,
++                               sendctx->recipient);
++
++                      sender = find_match_maker(sendctx->sender, true, false);
++                      bus_matchmaker_remove_name(sender, msg.name_acquired);
++              }
++
++              pr_debug("AF_BUS packet '%s' from the bus master. ACCEPT.\n",
++                       msg.member ? msg.member : "");
++              ret = NF_ACCEPT;
++              goto out;
++      }
++
++      pr_debug("Multicast AF_BUS packet, %ld bytes, " \
++               "considering recipient %lld...\n", len,
++               sendctx->recipient ? sendctx->recipient->sbus_addr.s_addr : 0);
++
++      pr_debug("Message type %d %s->%s [iface: %s][member: %s][matchmaker=%p]...\n",
++               msg.type,
++               msg.sender ? msg.sender : "",
++               msg.destination ? msg.destination : "",
++               msg.interface ? msg.interface : "",
++               msg.member ? msg.member : "",
++               matchmaker);
++
++      if (!matchmaker) {
++              pr_debug("No match rules for this recipient. DROP.\n");
++              ret = NF_DROP;
++              goto out;
++      }
++
++      sender = find_match_maker(sendctx->sender, true, false);
++      err = bus_matchmaker_filter(matchmaker, sender, sendctx->eavesdropper,
++                                  &msg);
++      if (err) {
++              pr_debug("Matchmaker: ACCEPT.\n");
++              ret = NF_ACCEPT;
++              goto out;
++      } else {
++              pr_debug("Matchmaker: DROP.\n");
++              ret = NF_DROP;
++              goto out;
++      }
++
++out:
++      if (matchmaker)
++              kref_put(&matchmaker->kref, bus_matchmaker_free);
++      if (sender)
++              kref_put(&sender->kref, bus_matchmaker_free);
++      return ret;
++}
++
++/* Taken from drbd_nl_send_reply() */
++static void nfdbus_nl_send_reply(struct cn_msg *msg, int ret_code)
++{
++      char buffer[sizeof(struct cn_msg)+sizeof(struct nfdbus_nl_cfg_reply)];
++      struct cn_msg *cn_reply = (struct cn_msg *) buffer;
++      struct nfdbus_nl_cfg_reply *reply =
++              (struct nfdbus_nl_cfg_reply *)cn_reply->data;
++      int rr;
++
++      memset(buffer, 0, sizeof(buffer));
++      cn_reply->id = msg->id;
++
++      cn_reply->seq = msg->seq;
++      cn_reply->ack = msg->ack  + 1;
++      cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply);
++      cn_reply->flags = 0;
++
++      reply->ret_code = ret_code;
++
++      rr = cn_netlink_send(cn_reply, 0, GFP_NOIO);
++      if (rr && rr != -ESRCH)
++              pr_debug("nfdbus: cn_netlink_send()=%d\n", rr);
++}
++
++/**
++ * nfdbus_check_perm - check if a pid is allowed to update match rules
++ * @sockaddr_bus: the socket address of the bus
++ * @pid: the process id that wants to update the match rules set
++ *
++ * Test if a given process id is allowed to update the match rules set
++ * for this bus. Only the process that owns the bus master listen socket
++ * is allowed to update the match rules set for the bus.
++ */
++static bool nfdbus_check_perm(struct sockaddr_bus *sbusname, pid_t pid)
++{
++      struct net *net = get_net_ns_by_pid(pid);
++      struct sock *s;
++      struct bus_address *addr;
++      struct hlist_node *node;
++      int offset = (sbusname->sbus_path[0] == '\0');
++      int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX);
++      int len;
++      if (!net)
++              return false;
++
++      len = path_len + 1 + sizeof(__kernel_sa_family_t) +
++            sizeof(struct bus_addr);
++
++      spin_lock(&bus_address_lock);
++
++      hlist_for_each_entry(addr, node, &bus_address_table[hash],
++                           table_node) {
++              s = addr->sock;
++
++              if (s->sk_protocol != BUS_PROTO_DBUS)
++                      continue;
++
++              if (!net_eq(sock_net(s), net))
++                      continue;
++
++              if (addr->len == len &&
++                  addr->name->sbus_family == sbusname->sbus_family &&
++                  addr->name->sbus_addr.s_addr == BUS_MASTER_ADDR &&
++                  bus_same_bus(addr->name, sbusname) &&
++                  pid_nr(s->sk_peer_pid) == pid) {
++                      spin_unlock(&bus_address_lock);
++                      return true;
++              }
++      }
++
++      spin_unlock(&bus_address_lock);
++
++      return false;
++}
++
++static void cn_cmd_cb(struct cn_msg *msg, struct netlink_skb_parms *nsp)
++{
++      struct nfdbus_nl_cfg_req *nlp = (struct nfdbus_nl_cfg_req *)msg->data;
++      struct cn_msg *cn_reply;
++      struct nfdbus_nl_cfg_reply *reply;
++      int retcode, rr;
++      pid_t pid = task_tgid_vnr(current);
++      int reply_size = sizeof(struct cn_msg)
++              + sizeof(struct nfdbus_nl_cfg_reply);
++
++      pr_debug("nfdbus: %s nsp->pid=%d pid=%d\n", __func__, nsp->pid, pid);
++
++      if (!nfdbus_check_perm(&nlp->addr, pid)) {
++              pr_debug(KERN_ERR "nfdbus: pid=%d is not allowed!\n", pid);
++              retcode = EPERM;
++              goto fail;
++      }
++
++      cn_reply = kzalloc(reply_size, GFP_KERNEL);
++      if (!cn_reply) {
++              retcode = ENOMEM;
++              goto fail;
++      }
++      reply = (struct nfdbus_nl_cfg_reply *) cn_reply->data;
++
++      if (msg->len < sizeof(struct nfdbus_nl_cfg_req)) {
++              reply->ret_code = EINVAL;
++      } else if (nlp->cmd == NFDBUS_CMD_ADDMATCH) {
++              struct bus_match_rule *rule;
++              struct bus_match_maker *matchmaker;
++              reply->ret_code = 0;
++
++              if (msg->len == 0)
++                      reply->ret_code = EINVAL;
++
++              rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC);
++              if (rule) {
++                      matchmaker = find_match_maker(&nlp->addr, true, false);
++                      pr_debug("Add match rule for matchmaker %p\n",
++                               matchmaker);
++                      bus_matchmaker_add_rule(matchmaker, rule);
++                      kref_put(&matchmaker->kref, bus_matchmaker_free);
++              } else {
++                      reply->ret_code = EINVAL;
++              }
++      } else if (nlp->cmd == NFDBUS_CMD_REMOVEMATCH) {
++              struct bus_match_rule *rule;
++              struct bus_match_maker *matchmaker;
++
++              rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC);
++              if (rule) {
++                      matchmaker = find_match_maker(&nlp->addr, false, false);
++                      if (!matchmaker) {
++                              reply->ret_code = EINVAL;
++                      } else {
++                              pr_debug("Remove match rule for matchmaker %p\n",
++                                       matchmaker);
++                              bus_matchmaker_remove_rule_by_value(matchmaker, rule);
++                              kref_put(&matchmaker->kref, bus_matchmaker_free);
++                              reply->ret_code = 0;
++                      }
++                      bus_match_rule_free(rule);
++              }
++
++      } else if (nlp->cmd == NFDBUS_CMD_REMOVEALLMATCH) {
++              struct bus_match_maker *matchmaker;
++
++              matchmaker = find_match_maker(&nlp->addr, false, true);
++              if (!matchmaker) {
++                      reply->ret_code = EINVAL;
++              } else {
++                      pr_debug("Remove matchmaker %p\n", matchmaker);
++                      kref_put(&matchmaker->kref, bus_matchmaker_free);
++                      kref_put(&matchmaker->kref, bus_matchmaker_free);
++                      reply->ret_code = 0;
++              }
++
++      } else {
++              reply->ret_code = EINVAL;
++      }
++
++      cn_reply->id = msg->id;
++      cn_reply->seq = msg->seq;
++      cn_reply->ack = msg->ack + 1;
++      cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply);
++      cn_reply->flags = 0;
++
++      rr = cn_netlink_reply(cn_reply, nsp->pid, GFP_KERNEL);
++      if (rr && rr != -ESRCH)
++              pr_debug("nfdbus: cn_netlink_send()=%d\n", rr);
++      pr_debug("nfdbus: cn_netlink_reply(pid=%d)=%d\n", nsp->pid, rr);
++
++      kfree(cn_reply);
++      return;
++fail:
++      nfdbus_nl_send_reply(msg, retcode);
++}
++
++static int __init nfdbus_init(void)
++{
++      int err;
++      struct bus_addr master_addr;
++
++      master_addr.s_addr = BUS_MASTER_ADDR;
++      hash = bus_compute_hash(master_addr);
++
++      pr_debug("Loading netfilter_dbus\n");
++
++      /* Install D-Bus netfilter hook */
++      nfho_dbus.hook     = dbus_filter;
++      nfho_dbus.hooknum  = NF_BUS_SENDING;
++      nfho_dbus.pf       = NFPROTO_BUS; /* Do not use PF_BUS, you fool! */
++      nfho_dbus.priority = 0;
++      nfho_dbus.owner = THIS_MODULE;
++      err = nf_register_hook(&nfho_dbus);
++      if (err)
++              return err;
++      pr_debug("Netfilter hook for D-Bus: installed.\n");
++
++      /* Install connector hook */
++      err = cn_add_callback(&cn_cmd_id, "nfdbus", cn_cmd_cb);
++      if (err)
++              goto err_cn_cmd_out;
++      pr_debug("Connector hook: installed.\n");
++
++      return 0;
++
++err_cn_cmd_out:
++      nf_unregister_hook(&nfho_dbus);
++
++      return err;
++}
++
++static void __exit nfdbus_cleanup(void)
++{
++      int i;
++      struct hlist_node *node, *tmp;
++      struct bus_match_maker *matchmaker;
++      nf_unregister_hook(&nfho_dbus);
++
++      cn_del_callback(&cn_cmd_id);
++
++      spin_lock(&matchrules_lock);
++      for (i = 0; i < BUS_HASH_SIZE; i++) {
++              hlist_for_each_entry_safe(matchmaker, node, tmp,
++                                        &matchrules_table[i], table_node) {
++                      hlist_del(&matchmaker->table_node);
++                      kref_put(&matchmaker->kref, bus_matchmaker_free);
++              }
++      }
++      spin_unlock(&matchrules_lock);
++
++      pr_debug("Unloading netfilter_dbus\n");
++}
++
++module_init(nfdbus_init);
++module_exit(nfdbus_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_ALIAS_NET_PF_PROTO(PF_BUS, BUS_PROTO_DBUS);
+diff --git a/net/bus/nfdbus/nfdbus.h b/net/bus/nfdbus/nfdbus.h
+new file mode 100644
+index 0000000..477bde3
+--- /dev/null
++++ b/net/bus/nfdbus/nfdbus.h
+@@ -0,0 +1,44 @@
++/*
++ * nfdbus.h  Netfilter module for AF_BUS/BUS_PROTO_DBUS.
++ *
++ * Copyright (C) 2012  Collabora Ltd
++ *
++ * 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef NETFILTER_DBUS_H
++#define NETFILTER_DBUS_H
++
++#include <linux/types.h>
++#include <linux/bus.h>
++
++#define NFDBUS_CMD_ADDMATCH        0x01
++#define NFDBUS_CMD_REMOVEMATCH     0x02
++#define NFDBUS_CMD_REMOVEALLMATCH  0x03
++
++struct nfdbus_nl_cfg_req {
++      __u32 cmd;
++      __u32 len;
++      struct sockaddr_bus addr;
++      __u64 pad;
++      unsigned char data[0];
++};
++
++struct nfdbus_nl_cfg_reply {
++      __u32 ret_code;
++};
++
++#endif /* NETFILTER_DBUS_H */
+-- 
+1.7.7.6
+
diff --git a/series b/series
index 14756f7fcd2373480df76a78146e8dbedeffbdc7..ec59e9343f4c39fe4eba29f971adf55b41483e12 100644 (file)
--- a/series
+++ b/series
@@ -539,3 +539,18 @@ patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch
 patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch
 
 
+patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
+patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch
+patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch
+patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch
+patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch
+patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch
+patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch
+patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch
+patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch
+patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch
+patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch
+patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch
+patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch
+patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch
+patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch