aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Andersson <gand@acm.org>2016-11-10 10:22:10 +0100
committerGunnar Andersson <gand@acm.org>2016-11-10 10:38:28 +0100
commita2f421e98de524e3342b4637835491fde3b0a250 (patch)
treedd5d53e352fbe139940609bf05d2eb9dc59327b9
parent88357c7a3855b3e32e2173a51f6afe2a6881be5a (diff)
downloadmeta-ivi-a2f421e98de524e3342b4637835491fde3b0a250.tar.gz
meta-ivi-a2f421e98de524e3342b4637835491fde3b0a250.tar.bz2
meta-ivi-a2f421e98de524e3342b4637835491fde3b0a250.zip
Delete 0001-net-bus-add-the-AF_BUS-socket-address-family.patch
AF_BUS is no longer part of the platform. No reason to keep the patch in the file tree. Signed-off-by: Gunnar Andersson <gand@acm.org>
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch6387
1 files changed, 0 insertions, 6387 deletions
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
deleted file mode 100644
index 1e05dd2..0000000
--- a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
+++ /dev/null
@@ -1,6387 +0,0 @@
-From 8c071e4a4be17b7bb01ab2a911c1697902dc2c35 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 1/1] 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>
----
- Documentation/networking/af_bus.txt | 558 ++++++++
- drivers/connector/connector.c | 32 +
- include/linux/bus.h | 34 +
- include/linux/connector.h | 5 +-
- include/linux/netfilter.h | 1 +
- include/linux/security.h | 11 +
- include/linux/socket.h | 5 +-
- include/net/af_bus.h | 273 ++++
- net/Kconfig | 1 +
- net/Makefile | 1 +
- net/bus/Kconfig | 15 +
- net/bus/Makefile | 7 +
- net/bus/af_bus.c | 2688 +++++++++++++++++++++++++++++++++++
- net/bus/garbage.c | 322 +++++
- net/core/scm.c | 3 +-
- net/core/sock.c | 6 +-
- net/netfilter/Kconfig | 2 +
- net/netfilter/Makefile | 3 +
- net/netfilter/nfdbus/Kconfig | 12 +
- net/netfilter/nfdbus/Makefile | 6 +
- net/netfilter/nfdbus/matchrule.c | 1132 +++++++++++++++
- net/netfilter/nfdbus/matchrule.h | 82 ++
- net/netfilter/nfdbus/message.c | 194 +++
- net/netfilter/nfdbus/message.h | 71 +
- net/netfilter/nfdbus/nfdbus.c | 456 ++++++
- net/netfilter/nfdbus/nfdbus.h | 44 +
- security/capability.c | 7 +
- security/security.c | 7 +
- security/selinux/hooks.c | 35 +
- 29 files changed, 6007 insertions(+), 6 deletions(-)
- create mode 100644 Documentation/networking/af_bus.txt
- create mode 100644 include/linux/bus.h
- create mode 100644 include/net/af_bus.h
- create mode 100644 net/bus/Kconfig
- create mode 100644 net/bus/Makefile
- create mode 100644 net/bus/af_bus.c
- create mode 100644 net/bus/garbage.c
- create mode 100644 net/netfilter/nfdbus/Kconfig
- create mode 100644 net/netfilter/nfdbus/Makefile
- create mode 100644 net/netfilter/nfdbus/matchrule.c
- create mode 100644 net/netfilter/nfdbus/matchrule.h
- create mode 100644 net/netfilter/nfdbus/message.c
- create mode 100644 net/netfilter/nfdbus/message.h
- create mode 100644 net/netfilter/nfdbus/nfdbus.c
- create mode 100644 net/netfilter/nfdbus/nfdbus.h
-
-diff --git a/Documentation/networking/af_bus.txt b/Documentation/networking/af_bus.txt
-new file mode 100644
-index 0000000..a0b078f
---- /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.
-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/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/linux/connector.h b/include/linux/connector.h
-index 7638407..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.
-@@ -125,6 +127,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,
-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,
- };
-
-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/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/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 */
-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
-diff --git a/net/bus/af_bus.c b/net/bus/af_bus.c
-new file mode 100644
-index 0000000..5a00225
---- /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);
-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);
-+}
-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)
-diff --git a/net/core/sock.c b/net/core/sock.c
-index b2e14c0..17abe99 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"
- };
-
- /*
-diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
-index 0c6f67e..58ed81d 100644
---- a/net/netfilter/Kconfig
-+++ b/net/netfilter/Kconfig
-@@ -1151,3 +1151,5 @@ endmenu
- source "net/netfilter/ipset/Kconfig"
-
- source "net/netfilter/ipvs/Kconfig"
-+
-+source "net/netfilter/nfdbus/Kconfig"
-diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
-index ca36765..89752a0 100644
---- a/net/netfilter/Makefile
-+++ b/net/netfilter/Makefile
-@@ -119,3 +119,6 @@ obj-$(CONFIG_IP_SET) += ipset/
-
- # IPVS
- obj-$(CONFIG_IP_VS) += ipvs/
-+
-+# Dbus
-+obj-$(CONFIG_NETFILTER_DBUS) += nfdbus/
-diff --git a/net/netfilter/nfdbus/Kconfig b/net/netfilter/nfdbus/Kconfig
-new file mode 100644
-index 0000000..25699a1
---- /dev/null
-+++ b/net/netfilter/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/netfilter/nfdbus/Makefile b/net/netfilter/nfdbus/Makefile
-new file mode 100644
-index 0000000..1a825f8
---- /dev/null
-+++ b/net/netfilter/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/netfilter/nfdbus/matchrule.c b/net/netfilter/nfdbus/matchrule.c
-new file mode 100644
-index 0000000..4106bd5
---- /dev/null
-+++ b/net/netfilter/nfdbus/matchrule.c
-@@ -0,0 +1,1132 @@
-+/*
-+ * 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/netfilter/nfdbus/matchrule.h b/net/netfilter/nfdbus/matchrule.h
-new file mode 100644
-index 0000000..e16580c
---- /dev/null
-+++ b/net/netfilter/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 */
-diff --git a/net/netfilter/nfdbus/message.c b/net/netfilter/nfdbus/message.c
-new file mode 100644
-index 0000000..93c409c
---- /dev/null
-+++ b/net/netfilter/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/netfilter/nfdbus/message.h b/net/netfilter/nfdbus/message.h
-new file mode 100644
-index 0000000..e3ea4d3
---- /dev/null
-+++ b/net/netfilter/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 */
-diff --git a/net/netfilter/nfdbus/nfdbus.c b/net/netfilter/nfdbus/nfdbus.c
-new file mode 100644
-index 0000000..f6642e2
---- /dev/null
-+++ b/net/netfilter/nfdbus/nfdbus.c
-@@ -0,0 +1,456 @@
-+/*
-+ * 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);
-+ 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/netfilter/nfdbus/nfdbus.h b/net/netfilter/nfdbus/nfdbus.h
-new file mode 100644
-index 0000000..477bde3
---- /dev/null
-+++ b/net/netfilter/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 */
-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);
-diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
-index d85b793..37573f2 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
-