aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch6387
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg4
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg4
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg4
-rw-r--r--meta-ivi/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch3201
-rw-r--r--meta-ivi/recipes-core-ivi/dbus/dbus_%.bbappend4
6 files changed, 0 insertions, 9604 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
-
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg
index 99c0c4f..4c87eda 100644
--- a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg
@@ -4,10 +4,6 @@
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
-# config for adding support for AF_BUS sockets
-# CONFIG_AF_BUS is not set
-# CONFIG_NETFILTER_DBUS is not set
-
# Activate ecryptfs
CONFIG_EXPERIMENTAL=y
CONFIG_KEYS=y
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg
index 99c0c4f..4c87eda 100644
--- a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg
@@ -4,10 +4,6 @@
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
-# config for adding support for AF_BUS sockets
-# CONFIG_AF_BUS is not set
-# CONFIG_NETFILTER_DBUS is not set
-
# Activate ecryptfs
CONFIG_EXPERIMENTAL=y
CONFIG_KEYS=y
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg
index d2e76e1..cbcbc7d 100644
--- a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg
@@ -832,10 +832,6 @@ CONFIG_ZONE_DMA_FLAG=0
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
-# config for adding support for AF_BUS sockets
-# CONFIG_AF_BUS is not set
-# CONFIG_NETFILTER_DBUS is not set
-
CONFIG_REGULATOR=n
# Activate ecryptfs
diff --git a/meta-ivi/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch b/meta-ivi/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch
deleted file mode 100644
index 2e91507..0000000
--- a/meta-ivi/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch
+++ /dev/null
@@ -1,3201 +0,0 @@
-diff --git a/bus/Makefile.am b/bus/Makefile.am
-index 6cbc09a..cf3a962 100644
---- a/bus/Makefile.am
-+++ b/bus/Makefile.am
-@@ -63,6 +63,15 @@ endif
- endif
- endif
-
-+if HAVE_AFBUS
-+AFBUS_SOURCE = \
-+ driver-afbus.c \
-+ driver-afbus.h \
-+ $(NULL)
-+else
-+AFBUS_SOURCE =
-+endif
-+
- BUS_SOURCES= \
- activation.c \
- activation.h \
-@@ -83,6 +92,7 @@ BUS_SOURCES= \
- dispatch.h \
- driver.c \
- driver.h \
-+ $(AFBUS_SOURCE) \
- expirelist.c \
- expirelist.h \
- policy.c \
-diff --git a/bus/bus.c b/bus/bus.c
-index e80e708..5038958 100644
---- a/bus/bus.c
-+++ b/bus/bus.c
-@@ -52,11 +52,20 @@ struct BusContext
- char *type;
- char *servicehelper;
- char *address;
-+
-+ /* if we are in AF_BUS compat mode, contains the AF_BUS address */
-+ char *main_address;
-+
- char *pidfile;
- char *user;
- char *log_prefix;
- DBusLoop *loop;
- DBusList *servers;
-+
-+ /* One of the servers may be a AF_BUS server. We can have at most only one
-+ * AF_BUS server. */
-+ DBusServer *main_afbus_server;
-+
- BusConnections *connections;
- BusActivation *activation;
- BusRegistry *registry;
-@@ -207,6 +216,29 @@ free_server_data (void *data)
- dbus_free (bd);
- }
-
-+static void
-+shutdown_server (BusContext *context,
-+ DBusServer *server)
-+{
-+ if (server == NULL ||
-+ !dbus_server_get_is_connected (server))
-+ return;
-+
-+ if (!dbus_server_set_watch_functions (server,
-+ NULL, NULL, NULL,
-+ context,
-+ NULL))
-+ _dbus_assert_not_reached ("setting watch functions to NULL failed");
-+
-+ if (!dbus_server_set_timeout_functions (server,
-+ NULL, NULL, NULL,
-+ context,
-+ NULL))
-+ _dbus_assert_not_reached ("setting timeout functions to NULL failed");
-+
-+ dbus_server_disconnect (server);
-+}
-+
- static dbus_bool_t
- setup_server (BusContext *context,
- DBusServer *server,
-@@ -275,6 +307,7 @@ process_config_first_time_only (BusContext *context,
- DBusString log_prefix;
- DBusList *link;
- DBusList **addresses;
-+ DBusList **addresses_if_possible;
- const char *user, *pidfile;
- char **auth_mechanisms;
- DBusList **auth_mechanisms_list;
-@@ -448,6 +481,7 @@ process_config_first_time_only (BusContext *context,
- while (link != NULL)
- {
- DBusServer *server;
-+ dbus_bool_t is_afbus;
-
- server = dbus_server_listen (link->data, error);
- if (server == NULL)
-@@ -455,17 +489,78 @@ process_config_first_time_only (BusContext *context,
- _DBUS_ASSERT_ERROR_IS_SET (error);
- goto failed;
- }
-- else if (!setup_server (context, server, auth_mechanisms, error))
-+ is_afbus = dbus_server_is_afbus (server);
-+
-+ /* Only accept one AF_BUS server */
-+ if (is_afbus && context->main_afbus_server != NULL)
- {
-+ dbus_server_disconnect (server);
-+ dbus_server_unref (server);
-+ dbus_set_error (error,
-+ DBUS_ERROR_MULTIPLE_AFBUS,
-+ "Cannot listen on multiple AF_BUS address");
-+ goto failed;
-+ }
-+
-+ if (!setup_server (context, server, auth_mechanisms, error))
-+ {
-+ shutdown_server (context, server);
-+ dbus_server_unref (server);
- _DBUS_ASSERT_ERROR_IS_SET (error);
- goto failed;
- }
-+ if (is_afbus)
-+ context->main_afbus_server = server;
-
- if (!_dbus_list_append (&context->servers, server))
- goto oom;
-
- link = _dbus_list_get_next_link (addresses, link);
- }
-+
-+ addresses_if_possible =
-+ bus_config_parser_get_addresses_if_possible (parser);
-+
-+ link = _dbus_list_get_first_link (addresses_if_possible);
-+ while (link != NULL)
-+ {
-+ DBusServer *server;
-+ dbus_bool_t is_afbus;
-+
-+ server = dbus_server_listen (link->data, NULL);
-+ if (server == NULL)
-+ {
-+ link = _dbus_list_get_next_link (addresses_if_possible, link);
-+ continue;
-+ }
-+ is_afbus = dbus_server_is_afbus (server);
-+
-+ /* Only accept one AF_BUS server */
-+ if (is_afbus && context->main_afbus_server != NULL)
-+ {
-+ dbus_server_disconnect (server);
-+ dbus_server_unref (server);
-+
-+ link = _dbus_list_get_next_link (addresses_if_possible, link);
-+ continue;
-+ }
-+
-+ if (!setup_server (context, server, auth_mechanisms, NULL))
-+ {
-+ shutdown_server (context, server);
-+ dbus_server_unref (server);
-+
-+ link = _dbus_list_get_next_link (addresses_if_possible, link);
-+ continue;
-+ }
-+ if (is_afbus)
-+ context->main_afbus_server = server;
-+
-+ if (!_dbus_list_append (&context->servers, server))
-+ goto oom;
-+
-+ link = _dbus_list_get_next_link (addresses_if_possible, link);
-+ }
- }
-
- context->fork = bus_config_parser_get_fork (parser);
-@@ -499,6 +594,7 @@ process_config_every_time (BusContext *context,
- DBusError *error)
- {
- DBusString full_address;
-+ DBusString main_address;
- DBusList *link;
- DBusList **dirs;
- char *addr;
-@@ -518,6 +614,12 @@ process_config_every_time (BusContext *context,
- return FALSE;
- }
-
-+ if (!_dbus_string_init (&main_address))
-+ {
-+ BUS_SET_OOM (error);
-+ return FALSE;
-+ }
-+
- /* get our limits and timeout lengths */
- bus_config_parser_get_limits (parser, &context->limits);
-
-@@ -554,6 +656,18 @@ process_config_every_time (BusContext *context,
- goto failed;
- }
-
-+ if (dbus_server_is_afbus (link->data))
-+ {
-+ /* There must be at most one AF_BUS server */
-+ _dbus_assert (_dbus_string_get_length (&main_address) == 0);
-+
-+ if (!_dbus_string_append (&main_address, addr))
-+ {
-+ BUS_SET_OOM (error);
-+ goto failed;
-+ }
-+ }
-+
- dbus_free (addr);
- addr = NULL;
-
-@@ -561,7 +675,10 @@ process_config_every_time (BusContext *context,
- }
-
- if (is_reload)
-- dbus_free (context->address);
-+ {
-+ dbus_free (context->address);
-+ dbus_free (context->main_address);
-+ }
-
- if (!_dbus_string_copy_data (&full_address, &context->address))
- {
-@@ -569,6 +686,12 @@ process_config_every_time (BusContext *context,
- goto failed;
- }
-
-+ if (!_dbus_string_copy_data (&main_address, &context->main_address))
-+ {
-+ BUS_SET_OOM (error);
-+ goto failed;
-+ }
-+
- /* get the service directories */
- dirs = bus_config_parser_get_service_dirs (parser);
-
-@@ -609,6 +732,7 @@ process_config_every_time (BusContext *context,
-
- failed:
- _dbus_string_free (&full_address);
-+ _dbus_string_free (&main_address);
-
- if (addr)
- dbus_free (addr);
-@@ -990,29 +1114,6 @@ bus_context_reload_config (BusContext *context,
- return ret;
- }
-
--static void
--shutdown_server (BusContext *context,
-- DBusServer *server)
--{
-- if (server == NULL ||
-- !dbus_server_get_is_connected (server))
-- return;
--
-- if (!dbus_server_set_watch_functions (server,
-- NULL, NULL, NULL,
-- context,
-- NULL))
-- _dbus_assert_not_reached ("setting watch functions to NULL failed");
--
-- if (!dbus_server_set_timeout_functions (server,
-- NULL, NULL, NULL,
-- context,
-- NULL))
-- _dbus_assert_not_reached ("setting timeout functions to NULL failed");
--
-- dbus_server_disconnect (server);
--}
--
- void
- bus_context_shutdown (BusContext *context)
- {
-@@ -1099,6 +1200,7 @@ bus_context_unref (BusContext *context)
- dbus_free (context->log_prefix);
- dbus_free (context->type);
- dbus_free (context->address);
-+ dbus_free (context->main_address);
- dbus_free (context->user);
- dbus_free (context->servicehelper);
-
-@@ -1134,6 +1236,12 @@ bus_context_get_address (BusContext *context)
- }
-
- const char*
-+bus_context_get_main_address (BusContext *context)
-+{
-+ return context->main_address;
-+}
-+
-+const char*
- bus_context_get_servicehelper (BusContext *context)
- {
- return context->servicehelper;
-diff --git a/bus/bus.h b/bus/bus.h
-index 3597884..f2a55f2 100644
---- a/bus/bus.h
-+++ b/bus/bus.h
-@@ -88,6 +88,7 @@ dbus_bool_t bus_context_get_id (BusContext
- DBusString *uuid);
- const char* bus_context_get_type (BusContext *context);
- const char* bus_context_get_address (BusContext *context);
-+const char* bus_context_get_main_address (BusContext *context);
- const char* bus_context_get_servicehelper (BusContext *context);
- dbus_bool_t bus_context_get_systemd_activation (BusContext *context);
- BusRegistry* bus_context_get_registry (BusContext *context);
-diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
-index c522ff4..8747835 100644
---- a/bus/config-parser-common.c
-+++ b/bus/config-parser-common.c
-@@ -63,6 +63,10 @@ bus_config_parser_element_name_to_type (const char *name)
- {
- return ELEMENT_LISTEN;
- }
-+ else if (strcmp (name, "listen_if_possible") == 0)
-+ {
-+ return ELEMENT_LISTEN_IF_POSSIBLE;
-+ }
- else if (strcmp (name, "auth") == 0)
- {
- return ELEMENT_AUTH;
-@@ -145,6 +149,8 @@ bus_config_parser_element_type_to_name (ElementType type)
- return "user";
- case ELEMENT_LISTEN:
- return "listen";
-+ case ELEMENT_LISTEN_IF_POSSIBLE:
-+ return "listen_if_possible";
- case ELEMENT_AUTH:
- return "auth";
- case ELEMENT_POLICY:
-diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
-index 186bf4c..6ea509c 100644
---- a/bus/config-parser-common.h
-+++ b/bus/config-parser-common.h
-@@ -31,6 +31,7 @@ typedef enum
- ELEMENT_INCLUDE,
- ELEMENT_USER,
- ELEMENT_LISTEN,
-+ ELEMENT_LISTEN_IF_POSSIBLE,
- ELEMENT_AUTH,
- ELEMENT_POLICY,
- ELEMENT_LIMIT,
-diff --git a/bus/config-parser.c b/bus/config-parser.c
-index 07e8fbb..fffc0e1 100644
---- a/bus/config-parser.c
-+++ b/bus/config-parser.c
-@@ -96,6 +96,8 @@ struct BusConfigParser
-
- DBusList *listen_on; /**< List of addresses to listen to */
-
-+ DBusList *listen_on_if_possible; /**< List of addresses to listen to, but continue on failure */
-+
- DBusList *mechanisms; /**< Auth mechanisms */
-
- DBusList *service_dirs; /**< Directories to look for session services in */
-@@ -327,6 +329,9 @@ merge_included (BusConfigParser *parser,
- while ((link = _dbus_list_pop_first_link (&included->listen_on)))
- _dbus_list_append_link (&parser->listen_on, link);
-
-+ while ((link = _dbus_list_pop_first_link (&included->listen_on_if_possible)))
-+ _dbus_list_append_link (&parser->listen_on_if_possible, link);
-+
- while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
- _dbus_list_append_link (&parser->mechanisms, link);
-
-@@ -497,6 +502,12 @@ bus_config_parser_unref (BusConfigParser *parser)
-
- _dbus_list_clear (&parser->listen_on);
-
-+ _dbus_list_foreach (&parser->listen_on_if_possible,
-+ (DBusForeachFunction) dbus_free,
-+ NULL);
-+
-+ _dbus_list_clear (&parser->listen_on_if_possible);
-+
- _dbus_list_foreach (&parser->service_dirs,
- (DBusForeachFunction) dbus_free,
- NULL);
-@@ -774,6 +785,19 @@ start_busconfig_child (BusConfigParser *parser,
-
- return TRUE;
- }
-+ else if (element_type == ELEMENT_LISTEN_IF_POSSIBLE)
-+ {
-+ if (!check_no_attributes (parser, "listen_if_possible", attribute_names, attribute_values, error))
-+ return FALSE;
-+
-+ if (push_element (parser, ELEMENT_LISTEN_IF_POSSIBLE) == NULL)
-+ {
-+ BUS_SET_OOM (error);
-+ return FALSE;
-+ }
-+
-+ return TRUE;
-+ }
- else if (element_type == ELEMENT_AUTH)
- {
- if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
-@@ -2018,6 +2042,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
- case ELEMENT_USER:
- case ELEMENT_CONFIGTYPE:
- case ELEMENT_LISTEN:
-+ case ELEMENT_LISTEN_IF_POSSIBLE:
- case ELEMENT_PIDFILE:
- case ELEMENT_AUTH:
- case ELEMENT_SERVICEDIR:
-@@ -2518,6 +2543,24 @@ bus_config_parser_content (BusConfigParser *parser,
- }
- break;
-
-+ case ELEMENT_LISTEN_IF_POSSIBLE:
-+ {
-+ char *s;
-+
-+ e->had_content = TRUE;
-+
-+ if (!_dbus_string_copy_data (content, &s))
-+ goto nomem;
-+
-+ if (!_dbus_list_append (&parser->listen_on_if_possible,
-+ s))
-+ {
-+ dbus_free (s);
-+ goto nomem;
-+ }
-+ }
-+ break;
-+
- case ELEMENT_AUTH:
- {
- char *s;
-@@ -2646,6 +2689,12 @@ bus_config_parser_get_addresses (BusConfigParser *parser)
- }
-
- DBusList**
-+bus_config_parser_get_addresses_if_possible (BusConfigParser *parser)
-+{
-+ return &parser->listen_on_if_possible;
-+}
-+
-+DBusList**
- bus_config_parser_get_mechanisms (BusConfigParser *parser)
- {
- return &parser->mechanisms;
-@@ -3123,6 +3172,9 @@ config_parsers_equal (const BusConfigParser *a,
- if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
- return FALSE;
-
-+ if (!lists_of_c_strings_equal (a->listen_on_if_possible, b->listen_on_if_possible))
-+ return FALSE;
-+
- if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
- return FALSE;
-
-diff --git a/bus/config-parser.h b/bus/config-parser.h
-index ba5bf74..f8a3c07 100644
---- a/bus/config-parser.h
-+++ b/bus/config-parser.h
-@@ -61,6 +61,7 @@ dbus_bool_t bus_config_parser_finished (BusConfigParser *parser,
- const char* bus_config_parser_get_user (BusConfigParser *parser);
- const char* bus_config_parser_get_type (BusConfigParser *parser);
- DBusList** bus_config_parser_get_addresses (BusConfigParser *parser);
-+DBusList** bus_config_parser_get_addresses_if_possible (BusConfigParser *parser);
- DBusList** bus_config_parser_get_mechanisms (BusConfigParser *parser);
- dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser);
- dbus_bool_t bus_config_parser_get_allow_anonymous (BusConfigParser *parser);
-diff --git a/bus/connection.c b/bus/connection.c
-index d69758c..2d68c84 100644
---- a/bus/connection.c
-+++ b/bus/connection.c
-@@ -30,9 +30,16 @@
- #include "signals.h"
- #include "expirelist.h"
- #include "selinux.h"
-+#include "driver-afbus.h"
- #include <dbus/dbus-list.h>
- #include <dbus/dbus-hash.h>
- #include <dbus/dbus-timeout.h>
-+#ifdef HAVE_AFBUS
-+#include <dbus/dbus-transport-afbus.h>
-+#endif
-+
-+#include <sys/types.h> /* See NOTES */
-+#include <sys/socket.h>
-
- /* Trim executed commands to this length; we want to keep logs readable */
- #define MAX_LOG_COMMAND_LEN 50
-@@ -94,6 +101,13 @@ typedef struct
- char *cached_loginfo_string;
- BusSELinuxID *selinux_id;
-
-+ dbus_bool_t peer_address_set;
-+ struct sockaddr_storage peer_address;
-+ socklen_t peer_addrlen;
-+ DBusConnection *proxy_connection; /**< If this is a compat connection,
-+ proxy_connection is the proxy
-+ connection to AF_BUS */
-+
- long connection_tv_sec; /**< Time when we connected (seconds component) */
- long connection_tv_usec; /**< Time when we connected (microsec component) */
- int stamp; /**< connections->stamp last time we were traversed */
-@@ -184,12 +198,33 @@ adjust_connections_for_uid (BusConnections *connections,
- }
- }
-
-+static DBusHandlerResult
-+proxy_connection_message_filter (DBusConnection *connection,
-+ DBusMessage *message,
-+ void *user_data)
-+{
-+ DBusConnection *source_connection = user_data;
-+
-+ if (dbus_message_get_destination (message) == NULL &&
-+ dbus_message_is_signal (message,
-+ DBUS_INTERFACE_LOCAL,
-+ "Disconnected"))
-+ {
-+ dbus_connection_close (source_connection);
-+ return DBUS_HANDLER_RESULT_HANDLED;
-+ }
-+
-+ dbus_connection_send (source_connection, message, NULL);
-+ return DBUS_HANDLER_RESULT_HANDLED;
-+}
-+
- void
- bus_connection_disconnected (DBusConnection *connection)
- {
- BusConnectionData *d;
- BusService *service;
- BusMatchmaker *matchmaker;
-+ DBusError error;
-
- d = BUS_CONNECTION_DATA (connection);
- _dbus_assert (d != NULL);
-@@ -197,6 +232,20 @@ bus_connection_disconnected (DBusConnection *connection)
- _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
- d->name ? d->name : "(inactive)");
-
-+ if (d->proxy_connection)
-+ {
-+ dbus_connection_remove_filter (d->proxy_connection,
-+ proxy_connection_message_filter, connection);
-+ dbus_connection_close (d->proxy_connection);
-+ dbus_connection_unref (d->proxy_connection);
-+ d->proxy_connection = NULL;
-+ }
-+
-+ dbus_error_init (&error);
-+
-+ if (!bus_driver_afbus_disconnected(connection, &error))
-+ dbus_error_free (&error);
-+
- /* Delete our match rules */
- if (d->n_match_rules > 0)
- {
-@@ -309,6 +358,18 @@ bus_connection_disconnected (DBusConnection *connection)
- dbus_connection_unref (connection);
- }
-
-+DBusConnection *
-+bus_connection_get_proxy_connection (DBusConnection *connection)
-+{
-+ BusConnectionData *d;
-+
-+ d = BUS_CONNECTION_DATA (connection);
-+
-+ _dbus_assert (d != NULL);
-+
-+ return d->proxy_connection;
-+}
-+
- static dbus_bool_t
- add_connection_watch (DBusWatch *watch,
- void *data)
-@@ -588,6 +649,52 @@ oom:
- return FALSE;
- }
-
-+#ifdef HAVE_AFBUS
-+static dbus_bool_t
-+bus_connections_setup_proxy_connection (BusConnections *connections,
-+ DBusConnection *connection,
-+ const char *main_address)
-+{
-+ BusConnectionData *d = BUS_CONNECTION_DATA (connection);
-+ DBusError error;
-+ dbus_bool_t retval = FALSE;
-+
-+ dbus_error_init (&error);
-+
-+ d->proxy_connection
-+ = dbus_connection_open_private (main_address, &error);
-+ if (dbus_error_is_set (&error))
-+ {
-+ dbus_error_free (&error);
-+ goto out;
-+ }
-+
-+ dbus_connection_set_route_peer_messages (d->proxy_connection, TRUE);
-+
-+ dbus_connection_set_dispatch_status_function (d->proxy_connection,
-+ dispatch_status_function,
-+ bus_context_get_loop (connections->context), NULL);
-+
-+ if (!dbus_connection_add_filter(d->proxy_connection,
-+ proxy_connection_message_filter, connection, NULL))
-+ goto out;
-+
-+
-+ if (!dbus_connection_set_watch_functions (d->proxy_connection,
-+ add_connection_watch,
-+ remove_connection_watch,
-+ toggle_connection_watch,
-+ connection,
-+ NULL))
-+ goto out;
-+
-+ return TRUE;
-+
-+out:
-+ return retval;
-+}
-+#endif
-+
- dbus_bool_t
- bus_connections_setup_connection (BusConnections *connections,
- DBusConnection *connection)
-@@ -596,7 +703,6 @@ bus_connections_setup_connection (BusConnections *connections,
- BusConnectionData *d;
- dbus_bool_t retval;
- DBusError error;
--
-
- d = dbus_new0 (BusConnectionData, 1);
-
-@@ -622,8 +728,32 @@ bus_connections_setup_connection (BusConnections *connections,
- dbus_connection_set_route_peer_messages (connection, TRUE);
-
- retval = FALSE;
--
- dbus_error_init (&error);
-+
-+#ifdef HAVE_AFBUS
-+ d->peer_addrlen = sizeof(d->peer_address);
-+ d->peer_address_set = dbus_connection_get_peer_address (connection,
-+ &d->peer_address, (long int *)&d->peer_addrlen);
-+
-+ /* If this connection is not AF_BUS, and we have a AF_BUS
-+ * server, we are in compat mode and we need to setup a
-+ * new connection */
-+ if (d->peer_address_set &&
-+ ((struct sockaddr *)&d->peer_address)->sa_family != AF_BUS)
-+ {
-+ const char *main_address;
-+ main_address = bus_context_get_main_address (connections->context);
-+ if (main_address && main_address[0] != '\0')
-+ {
-+ if (!bus_connections_setup_proxy_connection (connections, connection,
-+ main_address))
-+ {
-+ goto out;
-+ }
-+ }
-+ }
-+#endif
-+
- d->selinux_id = bus_selinux_init_connection_id (connection,
- &error);
- if (dbus_error_is_set (&error))
-@@ -2383,3 +2513,21 @@ bus_connection_get_peak_bus_names (DBusConnection *connection)
- return d->peak_bus_names;
- }
- #endif /* DBUS_ENABLE_STATS */
-+
-+int
-+bus_connection_get_peer_address (DBusConnection *connection,
-+ struct sockaddr **peer_address,
-+ socklen_t *peer_addrlen)
-+{
-+ BusConnectionData *d;
-+
-+ d = BUS_CONNECTION_DATA (connection);
-+
-+ if (!d->peer_address_set)
-+ return FALSE;
-+
-+ *peer_address = (struct sockaddr *) &d->peer_address;
-+ *peer_addrlen = d->peer_addrlen;
-+
-+ return TRUE;
-+}
-diff --git a/bus/connection.h b/bus/connection.h
-index c936021..95856f3 100644
---- a/bus/connection.h
-+++ b/bus/connection.h
-@@ -24,6 +24,8 @@
- #ifndef BUS_CONNECTION_H
- #define BUS_CONNECTION_H
-
-+#include <sys/types.h>
-+#include <sys/socket.h>
- #include <dbus/dbus.h>
- #include <dbus/dbus-list.h>
- #include "bus.h"
-@@ -103,8 +105,9 @@ dbus_bool_t bus_connection_complete (DBusConnection *connection,
- const DBusString *name,
- DBusError *error);
-
--/* called by dispatch.c when the connection is dropped */
--void bus_connection_disconnected (DBusConnection *connection);
-+/* called by dispatch.c */
-+void bus_connection_disconnected (DBusConnection *connection);
-+DBusConnection *bus_connection_get_proxy_connection (DBusConnection *connection);
-
- dbus_bool_t bus_connection_is_in_unix_group (DBusConnection *connection,
- unsigned long gid);
-@@ -151,4 +154,9 @@ int bus_connections_get_peak_bus_names_per_conn (BusConnections *connections);
- int bus_connection_get_peak_match_rules (DBusConnection *connection);
- int bus_connection_get_peak_bus_names (DBusConnection *connection);
-
-+/* called by driver-afbus.c */
-+int bus_connection_get_peer_address (DBusConnection *connection,
-+ struct sockaddr **peer_address,
-+ socklen_t *peer_addrlen);
-+
- #endif /* BUS_CONNECTION_H */
-diff --git a/bus/dispatch.c b/bus/dispatch.c
-index 7a96f9d..4feae05 100644
---- a/bus/dispatch.c
-+++ b/bus/dispatch.c
-@@ -27,6 +27,7 @@
- #include "dispatch.h"
- #include "connection.h"
- #include "driver.h"
-+#include "driver-afbus.h"
- #include "services.h"
- #include "activation.h"
- #include "utils.h"
-@@ -129,6 +130,18 @@ bus_dispatch_matches (BusTransaction *transaction,
- BUS_SET_OOM (error);
- return FALSE;
- }
-+
-+ /* If using AF_BUS and the message came to the daemon, the client sending
-+ * the message doesn't yet know the address for this service, so notify
-+ * it of the address associated with the service. */
-+ if (!bus_driver_afbus_emit_forwarded (transaction,
-+ sender,
-+ addressed_recipient,
-+ dbus_message_get_destination (message)))
-+ {
-+ _dbus_verbose ("bus_driver_afbus_emit_forwarded() failed\n");
-+ return FALSE;
-+ }
- }
-
- /* Now dispatch to others who look interested in this message */
-@@ -180,6 +193,7 @@ bus_dispatch (DBusConnection *connection,
- BusContext *context;
- DBusHandlerResult result;
- DBusConnection *addressed_recipient;
-+ DBusConnection *proxy_connection;
-
- result = DBUS_HANDLER_RESULT_HANDLED;
-
-@@ -241,6 +255,15 @@ bus_dispatch (DBusConnection *connection,
- }
- }
-
-+ /* Directly send the message to the proxy without analysing it */
-+ proxy_connection = bus_connection_get_proxy_connection (connection);
-+ if (proxy_connection)
-+ {
-+ if (!dbus_connection_send (proxy_connection, message, NULL))
-+ BUS_SET_OOM (&error);
-+ goto out;
-+ }
-+
- /* Create our transaction */
- transaction = bus_transaction_new (context);
- if (transaction == NULL)
-diff --git a/bus/driver-afbus.c b/bus/driver-afbus.c
-new file mode 100644
-index 0000000..70edafb
---- /dev/null
-+++ b/bus/driver-afbus.c
-@@ -0,0 +1,345 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* driver.c Bus client, AF_BUS bits (driver)
-+ *
-+ * Copyright (C) 2012 Collabora Ltd
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * 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 <config.h>
-+
-+#include "driver-afbus.h"
-+
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <asm/types.h>
-+#include <errno.h>
-+#include <linux/netlink.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/connector.h>
-+#include <dbus/dbus-transport-afbus.h>
-+
-+#define CN_IDX_NFDBUS 0xA /* netfilter D-Bus */
-+#define CN_VAL_NFDBUS 0x1
-+
-+#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;
-+};
-+
-+static int
-+ensure_nl_sock(DBusError *error)
-+{
-+ static int nlsock = 0;
-+
-+ struct sockaddr_nl l_local;
-+ int fd;
-+ int ret;
-+
-+ if (nlsock > 0)
-+ return nlsock;
-+
-+ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-+ if (fd == -1) {
-+ dbus_set_error (error, DBUS_ERROR_NETLINK,
-+ "Couldn't use the netlink socket: %s",
-+ strerror(errno));
-+ return -1;
-+ }
-+
-+ if (!_dbus_set_fd_nonblocking (fd, error))
-+ {
-+ _dbus_close_socket (fd, NULL);
-+ return -1;
-+ }
-+
-+ l_local.nl_family = AF_NETLINK;
-+ l_local.nl_groups = 0;
-+ l_local.nl_pid = 0;
-+ ret = bind(fd, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl));
-+ if (ret == -1) {
-+ close(fd);
-+ dbus_set_error (error, DBUS_ERROR_NETLINK,
-+ "Couldn't bind the netlink socket: %s",
-+ strerror(errno));
-+ return -1;
-+ }
-+
-+ nlsock = fd;
-+ return nlsock;
-+}
-+
-+static int netlink_send(int nlsock, struct cn_msg *msg, int seq)
-+{
-+ struct nlmsghdr *nlh;
-+ unsigned int size;
-+ char buf[4096];
-+ struct cn_msg *m;
-+
-+ size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
-+
-+ nlh = (struct nlmsghdr *)buf;
-+ nlh->nlmsg_seq = seq;
-+ nlh->nlmsg_pid = getpid();
-+ nlh->nlmsg_type = NLMSG_DONE;
-+ nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
-+ nlh->nlmsg_flags = 0;
-+
-+ m = NLMSG_DATA(nlh);
-+ memcpy(m, msg, sizeof(*m) + msg->len);
-+
-+ return send(nlsock, nlh, size, 0);
-+}
-+
-+static dbus_bool_t
-+bus_driver_afbus_upload_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ int cmd,
-+ DBusError *error)
-+{
-+ static int seq;
-+
-+ int nlsock;
-+ int ret;
-+
-+ char buf[sizeof(struct cn_msg) + sizeof(struct nfdbus_nl_cfg_req) + 1024];
-+
-+ struct cn_msg *data;
-+ struct nlmsghdr *reply;
-+ struct nfdbus_nl_cfg_req *req;
-+ //struct nfdbus_nl_cfg_reply *req_reply;
-+
-+ struct sockaddr_storage *address;
-+ socklen_t addrlen = sizeof(address);
-+
-+ if (!bus_connection_get_peer_address(connection,
-+ (struct sockaddr **) &address, &addrlen))
-+ return TRUE;
-+
-+ if (((struct sockaddr*)address)->sa_family != AF_BUS)
-+ return TRUE;
-+
-+ nlsock = ensure_nl_sock (error);
-+ if (nlsock == -1)
-+ return FALSE;
-+
-+ memset(buf, 0, sizeof(buf));
-+
-+ data = (struct cn_msg *)buf;
-+
-+ data->id.idx = CN_IDX_NFDBUS;
-+ data->id.val = CN_VAL_NFDBUS;
-+ data->seq = seq++;
-+ data->ack = 0;
-+ data->len = sizeof(struct nfdbus_nl_cfg_req) + strlen(rule) + 1;
-+ req = (struct nfdbus_nl_cfg_req *) data->data;
-+
-+ req->cmd = cmd;
-+ req->len = strlen(rule) + 1;
-+ req->addr = *(struct sockaddr_bus *)address;
-+ strcpy((char *)req->data, rule);
-+
-+ ret = netlink_send(nlsock, data, seq++);
-+ if (ret <= 0)
-+ {
-+ }
-+
-+ memset(buf, 0, sizeof(buf));
-+ ret = recv(nlsock, buf, sizeof(buf), 0);
-+ if (ret <= 0)
-+ {
-+ }
-+
-+ reply = (struct nlmsghdr *)buf;
-+ if (reply->nlmsg_type != NLMSG_DONE)
-+ {
-+ }
-+
-+ return TRUE;
-+}
-+
-+dbus_bool_t
-+bus_driver_afbus_add_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ DBusError *error)
-+{
-+ if (bus_driver_afbus_upload_match_rule (connection, rule, NFDBUS_CMD_ADDMATCH, error))
-+ {
-+ /* Check if the match rule is for eavesdropping, and set the socket
-+ * to allow receiving all messages if so */
-+ if (strstr (rule, "eavesdrop=true"))
-+ {
-+ int fd;
-+
-+ if (dbus_connection_get_socket (connection, &fd))
-+ {
-+ if (setsockopt (fd, SOL_BUS, BUS_SET_EAVESDROP, NULL, 0) == 0)
-+ return TRUE;
-+ else
-+ {
-+ dbus_set_error (error,
-+ _dbus_error_from_errno (errno),
-+ "Failed to setsockopt on socket %d: %s",
-+ fd, _dbus_strerror (errno));
-+ }
-+ }
-+ else
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ }
-+ else
-+ return TRUE;
-+ }
-+
-+ return FALSE;
-+}
-+
-+dbus_bool_t
-+bus_driver_afbus_remove_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ DBusError *error)
-+{
-+ return bus_driver_afbus_upload_match_rule (connection, rule, NFDBUS_CMD_REMOVEMATCH, error);
-+}
-+
-+dbus_bool_t
-+bus_driver_afbus_append_unique_name (DBusConnection *connection,
-+ DBusString *str)
-+{
-+ struct sockaddr_bus address;
-+ long len = sizeof(address);
-+
-+ memset (&address, 0, sizeof (address));
-+ if (!dbus_connection_get_peer_address(connection, &address, &len) ||
-+ address.sbus_family != AF_BUS)
-+ return FALSE;
-+
-+ if (!_dbus_string_append (str, "AF-BUS."))
-+ return FALSE;
-+
-+ if (!_dbus_string_append_uint (str, address.sbus_addr.s_addr))
-+ return FALSE;
-+
-+ return TRUE;
-+}
-+
-+dbus_bool_t
-+bus_driver_afbus_emit_forwarded (BusTransaction *transaction,
-+ DBusConnection *connection,
-+ DBusConnection *addressed_recipient,
-+ const char *service_name)
-+{
-+ struct sockaddr_bus address;
-+ long len = sizeof (address);
-+ DBusMessage *message;
-+ dbus_bool_t result = FALSE;
-+
-+ memset (&address, 0, sizeof (address));
-+ if (!dbus_connection_get_peer_address (addressed_recipient, &address, &len) ||
-+ address.sbus_family != AF_BUS)
-+ {
-+ /* Don't return an error if it is not a AF_BUS socket */
-+ return TRUE;
-+ }
-+
-+ /* Prepare the message to be sent */
-+ message = dbus_message_new_signal (DBUS_PATH_AFBUS,
-+ DBUS_INTERFACE_AFBUS,
-+ "Forwarded");
-+ if (message == NULL)
-+ {
-+ _dbus_verbose ("Could not allocate AF_BUS.Forwarded signal message\n");
-+ return FALSE;
-+ }
-+
-+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
-+ {
-+ _dbus_verbose ("Could not set sender for AF_BUS.Forwarded signal message\n");
-+ goto out;
-+ }
-+
-+ if (!dbus_message_append_args (message,
-+ DBUS_TYPE_STRING, &service_name,
-+ DBUS_TYPE_UINT64, &address.sbus_addr.s_addr,
-+ DBUS_TYPE_INVALID))
-+ {
-+ _dbus_verbose ("Could not append arguments for AF_BUS.Forwarded signal message\n");
-+ goto out;
-+ }
-+
-+ if (bus_transaction_send (transaction, connection, message))
-+ result = TRUE;
-+ else
-+ _dbus_verbose ("Could not send AF_BUS.Forwarded signal message\n");
-+
-+ out:
-+ dbus_message_unref (message);
-+
-+ return result;
-+}
-+
-+dbus_bool_t
-+bus_driver_afbus_assign_address (DBusConnection *connection)
-+{
-+ struct sockaddr_bus address;
-+ long len = sizeof (address);
-+ int fd;
-+ static dbus_uint64_t next_address = 0x1111000000000001ULL;
-+
-+ memset (&address, 0, sizeof (address));
-+ if (!dbus_connection_get_peer_address (connection, &address, &len) ||
-+ ((struct sockaddr *) &address)->sa_family != AF_BUS)
-+ {
-+ /* Don't return an error if it is not a AF_BUS socket */
-+ return TRUE;
-+ }
-+
-+ if (!dbus_connection_get_unix_fd (connection, &fd))
-+ {
-+ return FALSE;
-+ }
-+
-+ address.sbus_addr.s_addr = next_address;
-+ if (setsockopt (fd, SOL_BUS, BUS_ADD_ADDR, &address, sizeof (address)) != 0)
-+ {
-+ return FALSE;
-+ }
-+
-+ next_address++;
-+
-+ return TRUE;
-+}
-+
-+dbus_bool_t
-+bus_driver_afbus_disconnected (DBusConnection *connection,
-+ DBusError *error)
-+{
-+ return bus_driver_afbus_upload_match_rule (connection, "",
-+ NFDBUS_CMD_REMOVEALLMATCH, error);
-+}
-diff --git a/bus/driver-afbus.h b/bus/driver-afbus.h
-new file mode 100644
-index 0000000..9c40111
---- /dev/null
-+++ b/bus/driver-afbus.h
-@@ -0,0 +1,96 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* driver-afbus.h Bus client, AF_BUS bits (driver)
-+ *
-+ * Copyright (C) 2012 Collabora Ltd
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * 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_DRIVER_AFBUS_H
-+#define BUS_DRIVER_AFBUS_H
-+
-+#include <config.h>
-+#include <sys/socket.h>
-+#include <dbus/dbus.h>
-+#include "connection.h"
-+
-+#if HAVE_AFBUS
-+dbus_bool_t bus_driver_afbus_add_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ DBusError *error);
-+dbus_bool_t bus_driver_afbus_remove_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ DBusError *error);
-+dbus_bool_t bus_driver_afbus_append_unique_name (DBusConnection *connection,
-+ DBusString *str);
-+dbus_bool_t bus_driver_afbus_emit_forwarded (BusTransaction *transaction,
-+ DBusConnection *connection,
-+ DBusConnection *addressed_recipient,
-+ const char *service_name);
-+dbus_bool_t bus_driver_afbus_assign_address (DBusConnection *connection);
-+dbus_bool_t bus_driver_afbus_disconnected (DBusConnection *connection,
-+ DBusError *error);
-+#else
-+static inline
-+dbus_bool_t bus_driver_afbus_add_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ DBusError *error)
-+{
-+ return TRUE;
-+}
-+
-+static inline
-+dbus_bool_t bus_driver_afbus_remove_match_rule (DBusConnection *connection,
-+ const char *rule,
-+ DBusError *error)
-+{
-+ return TRUE;
-+}
-+
-+static inline
-+dbus_bool_t bus_driver_afbus_append_unique_name (DBusConnection *connection,
-+ DBusString *str)
-+{
-+ return TRUE;
-+}
-+
-+static inline
-+dbus_bool_t bus_driver_afbus_emit_forwarded (BusTransaction *transaction,
-+ DBusConnection *connection,
-+ DBusConnection *addressed_recipient,
-+ const char *service_name)
-+{
-+ return TRUE;
-+}
-+
-+static inline
-+dbus_bool_t bus_driver_afbus_assign_address (DBusConnection *connection)
-+{
-+ return TRUE;
-+}
-+
-+static inline
-+dbus_bool_t bus_driver_afbus_disconnected (DBusConnection *connection,
-+ DBusError *error)
-+{
-+ return TRUE;
-+}
-+
-+#endif
-+
-+#endif /* BUS_DRIVER_AFBUS_H */
-diff --git a/bus/driver.c b/bus/driver.c
-index 574e0f3..11767c8 100644
---- a/bus/driver.c
-+++ b/bus/driver.c
-@@ -26,6 +26,7 @@
- #include "activation.h"
- #include "connection.h"
- #include "driver.h"
-+#include "driver-afbus.h"
- #include "dispatch.h"
- #include "services.h"
- #include "selinux.h"
-@@ -182,8 +183,9 @@ bus_driver_send_service_acquired (DBusConnection *connection,
- }
-
- static dbus_bool_t
--create_unique_client_name (BusRegistry *registry,
-- DBusString *str)
-+create_unique_client_name (DBusConnection *connection,
-+ BusRegistry *registry,
-+ DBusString *str)
- {
- /* We never want to use the same unique client name twice, because
- * we want to guarantee that if you send a message to a given unique
-@@ -214,19 +216,23 @@ create_unique_client_name (BusRegistry *registry,
- _dbus_assert (next_major_number > 0);
- _dbus_assert (next_minor_number >= 0);
-
-- /* appname:MAJOR-MINOR */
-+ /* unique name:
-+ * :[AF-BUS.BUS-ADDRESS.]MAJOR.MINOR */
-
- if (!_dbus_string_append (str, ":"))
- return FALSE;
-
-- if (!_dbus_string_append_int (str, next_major_number))
-- return FALSE;
-+ if (!bus_driver_afbus_append_unique_name (connection, str))
-+ {
-+ if (!_dbus_string_append_int (str, next_major_number))
-+ return FALSE;
-
-- if (!_dbus_string_append (str, "."))
-- return FALSE;
-+ if (!_dbus_string_append (str, "."))
-+ return FALSE;
-
-- if (!_dbus_string_append_int (str, next_minor_number))
-- return FALSE;
-+ if (!_dbus_string_append_int (str, next_minor_number))
-+ return FALSE;
-+ }
-
- next_minor_number += 1;
-
-@@ -287,7 +293,7 @@ bus_driver_handle_hello (DBusConnection *connection,
-
- registry = bus_connection_get_registry (connection);
-
-- if (!create_unique_client_name (registry, &unique_name))
-+ if (!create_unique_client_name (connection, registry, &unique_name))
- {
- BUS_SET_OOM (error);
- goto out_0;
-@@ -610,6 +616,13 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
- goto out;
- }
-
-+ /* If using AF_BUS, assign an address to this peer */
-+ if (!bus_driver_afbus_assign_address (connection))
-+ {
-+ BUS_SET_OOM (error);
-+ goto out;
-+ }
-+
- retval = TRUE;
-
- out:
-@@ -988,6 +1001,9 @@ bus_driver_handle_add_match (DBusConnection *connection,
- if (rule == NULL)
- goto failed;
-
-+ if (!bus_driver_afbus_add_match_rule (connection, text, error))
-+ goto failed;
-+
- matchmaker = bus_connection_get_matchmaker (connection);
-
- if (!bus_matchmaker_add_rule (matchmaker, rule))
-@@ -1051,6 +1067,9 @@ bus_driver_handle_remove_match (DBusConnection *connection,
- message, error))
- goto failed;
-
-+ if (!bus_driver_afbus_remove_match_rule (connection, text, error))
-+ goto failed;
-+
- matchmaker = bus_connection_get_matchmaker (connection);
-
- if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
-@@ -1779,6 +1798,13 @@ static InterfaceHandler interface_handlers[] = {
- { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
- #ifdef DBUS_ENABLE_STATS
- { BUS_INTERFACE_STATS, stats_message_handlers, NULL },
-+#ifdef HAVE_AFBUS
-+ { DBUS_INTERFACE_AFBUS, NULL,
-+ " <signal name=\"AF_BUS.Forwarded\">\n"
-+ " <arg type=\"s\"/>\n"
-+ " <arg type=\"t\"/>\n"
-+ " </signal>\n" },
-+#endif
- #endif
- { NULL, NULL, NULL }
- };
-diff --git a/bus/session.conf.in b/bus/session.conf.in
-index e121ff9..09a7ecf 100644
---- a/bus/session.conf.in
-+++ b/bus/session.conf.in
-@@ -12,7 +12,8 @@
- the behavior of child processes. -->
- <keep_umask/>
-
-- <listen>@DBUS_SESSION_BUS_DEFAULT_ADDRESS@</listen>
-+ <listen_if_possible>afbus:tmpdir=/tmp</listen_if_possible>
-+ <listen>unix:tmpdir=/tmp</listen>
-
- <standard_session_servicedirs />
-
-diff --git a/bus/system.conf.in b/bus/system.conf.in
-index 92f4cc4..515509f 100644
---- a/bus/system.conf.in
-+++ b/bus/system.conf.in
-@@ -39,6 +39,7 @@
- means use abstract namespace, don't really create filesystem
- file; only Linux supports this. Use path=/whatever on other
- systems.) -->
-+ <listen_if_possible>afbus:@DBUS_SYSTEM_SOCKET@.afbus</listen_if_possible>
- <listen>@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@</listen>
-
- <policy context="default">
-diff --git a/configure.ac b/configure.ac
-index 4f86e9d..51a48fd 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1509,6 +1509,20 @@ if test "x$with_systemdsystemunitdir" != xno; then
- fi
- AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
-
-+## Check for AF_DBUS
-+AC_MSG_CHECKING([for AF_BUS socket family])
-+AC_COMPILE_IFELSE(
-+ [AC_LANG_PROGRAM(
-+ [[#include <sys/socket.h>]],
-+ [[return socket (PF_BUS, SOCK_STREAM, 0);]])],
-+ [have_afbus=yes],
-+ [have_afbus=no])
-+AC_MSG_RESULT([$have_afbus])
-+if test "x$have_afbus" = "xyes"; then
-+ AC_DEFINE(HAVE_AFBUS, 1, [Define if AF_BUS is available])
-+fi
-+AM_CONDITIONAL(HAVE_AFBUS, test "x$have_afbus" = "xyes")
-+
- ##### Set up location for system bus socket
- if ! test -z "$with_system_socket"; then
- DBUS_SYSTEM_SOCKET=$with_system_socket
-@@ -1648,7 +1662,11 @@ AC_SUBST(TEST_SOCKET_DIR)
- AC_DEFINE_UNQUOTED(DBUS_TEST_SOCKET_DIR, "$TEST_SOCKET_DIR", [Where to put test sockets])
-
- if test "x$dbus_unix" = xyes; then
-- TEST_LISTEN="unix:tmpdir=$TEST_SOCKET_DIR"
-+ if test "x$have_afbus" = "xyes"; then
-+ TEST_LISTEN="afbus:tmpdir=$TEST_SOCKET_DIR"
-+ else
-+ TEST_LISTEN="unix:tmpdir=$TEST_SOCKET_DIR"
-+ fi
- else
- TEST_LISTEN="tcp:host=localhost"
- fi
-@@ -1668,6 +1686,8 @@ if test x$dbus_win = xyes; then
- DBUS_SESSION_BUS_DEFAULT_ADDRESS="$with_dbus_session_bus_default_address"
- elif test x$have_launchd = xyes; then
- DBUS_SESSION_BUS_DEFAULT_ADDRESS="launchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKET"
-+elif test x$have_afbus = xyes; then
-+ DBUS_SESSION_BUS_DEFAULT_ADDRESS="afbus:tmpdir=$DBUS_SESSION_SOCKET_DIR"
- else
- DBUS_SESSION_BUS_DEFAULT_ADDRESS="unix:tmpdir=$DBUS_SESSION_SOCKET_DIR"
- fi
-diff --git a/dbus/Makefile.am b/dbus/Makefile.am
-index bb5ccca..b925419 100644
---- a/dbus/Makefile.am
-+++ b/dbus/Makefile.am
-@@ -87,6 +87,16 @@ else
- launchd_source =
- endif
-
-+if HAVE_AFBUS
-+afbus_source = \
-+ dbus-server-afbus.c \
-+ dbus-server-afbus.h \
-+ dbus-transport-afbus.c \
-+ dbus-transport-afbus.h
-+else
-+afbus_source =
-+endif
-+
- DBUS_LIB_arch_sources = \
- dbus-uuidgen.c \
- dbus-uuidgen.h \
-@@ -95,6 +105,7 @@ DBUS_LIB_arch_sources = \
-
- DBUS_SHARED_arch_sources = \
- $(launchd_source) \
-+ $(afbus_source) \
- dbus-file-unix.c \
- dbus-pipe-unix.c \
- dbus-sysdeps-unix.c \
-diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
-index ee33b6c..5f3a459 100644
---- a/dbus/dbus-connection.c
-+++ b/dbus/dbus-connection.c
-@@ -45,6 +45,8 @@
- #include "dbus-bus.h"
- #include "dbus-marshal-basic.h"
-
-+#include <sys/socket.h>
-+
- #ifdef DBUS_DISABLE_CHECKS
- #define TOOK_LOCK_CHECK(connection)
- #define RELEASING_LOCK_CHECK(connection)
-@@ -2054,9 +2056,15 @@ _dbus_connection_send_preallocated_and_unlock (DBusConnection *connection,
- dbus_uint32_t *client_serial)
- {
- DBusDispatchStatus status;
-+ const char *sender;
-
- HAVE_LOCK_CHECK (connection);
--
-+
-+ /* Set the sender field */
-+ sender = dbus_bus_get_unique_name (connection);
-+ if (sender)
-+ dbus_message_set_sender (message, sender);
-+
- _dbus_connection_send_preallocated_unlocked_no_update (connection,
- preallocated,
- message, client_serial);
-@@ -3359,6 +3367,7 @@ dbus_connection_send_with_reply (DBusConnection *connection,
- DBusPendingCall *pending;
- dbus_int32_t serial = -1;
- DBusDispatchStatus status;
-+ const char *sender;
-
- _dbus_return_val_if_fail (connection != NULL, FALSE);
- _dbus_return_val_if_fail (message != NULL, FALSE);
-@@ -3401,6 +3410,11 @@ dbus_connection_send_with_reply (DBusConnection *connection,
- return FALSE;
- }
-
-+ /* Set the sender field */
-+ sender = dbus_bus_get_unique_name (connection);
-+ if (sender)
-+ dbus_message_set_sender (message, sender);
-+
- /* Assign a serial to the message */
- serial = dbus_message_get_serial (message);
- if (serial == 0)
-@@ -5439,6 +5453,27 @@ dbus_connection_set_route_peer_messages (DBusConnection *connection,
- CONNECTION_UNLOCK (connection);
- }
-
-+dbus_bool_t
-+dbus_connection_get_peer_address (DBusConnection *connection,
-+ void *addr,
-+ long *len)
-+{
-+ dbus_bool_t res;
-+ int fd;
-+ socklen_t _len = *len;
-+
-+ _dbus_return_val_if_fail (connection != NULL, FALSE);
-+
-+ res = _dbus_transport_get_socket_fd (connection->transport, &fd);
-+ if (!res)
-+ return res;
-+
-+ res = getpeername(fd, (struct sockaddr *) addr, &_len) == 0;
-+ if (res)
-+ *len = _len;
-+ return res;
-+}
-+
- /**
- * Adds a message filter. Filters are handlers that are run on all
- * incoming messages, prior to the objects registered with
-diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
-index fe4d04e..81fe9f1 100644
---- a/dbus/dbus-connection.h
-+++ b/dbus/dbus-connection.h
-@@ -287,6 +287,10 @@ void dbus_connection_set_allow_anonymous (DBusConnection
- DBUS_EXPORT
- void dbus_connection_set_route_peer_messages (DBusConnection *connection,
- dbus_bool_t value);
-+DBUS_EXPORT
-+dbus_bool_t dbus_connection_get_peer_address (DBusConnection *connection,
-+ void *addr,
-+ long *len);
-
-
- /* Filters */
-diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
-index 60605ab..71c2870 100644
---- a/dbus/dbus-protocol.h
-+++ b/dbus/dbus-protocol.h
-@@ -458,6 +458,12 @@ extern "C" {
- /** XML document type declaration of the introspection format version 1.0 */
- #define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "\">\n"
-
-+/* AF_BUS errors */
-+
-+/** Tried to use a netlink socket and it failed. */
-+#define DBUS_ERROR_NETLINK "org.freedesktop.DBus.Error.NetLink"
-+#define DBUS_ERROR_MULTIPLE_AFBUS "org.freedesktop.DBus.Error.MultipleAFBUS"
-+
- /** @} */
-
- #ifdef __cplusplus
-diff --git a/dbus/dbus-server-afbus.c b/dbus/dbus-server-afbus.c
-new file mode 100644
-index 0000000..1d8e9bd
---- /dev/null
-+++ b/dbus/dbus-server-afbus.c
-@@ -0,0 +1,397 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* dbus-server-unix.c Server implementation for Unix network protocols.
-+ *
-+ * Copyright (C) 2012 Collabora Ltd
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * 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 <config.h>
-+#include <errno.h>
-+#include <sys/socket.h>
-+#include "dbus-connection-internal.h"
-+#include "dbus-server-afbus.h"
-+#include "dbus-server-protected.h"
-+#include "dbus-string.h"
-+#include "dbus-sysdeps.h"
-+#include "dbus-transport.h"
-+#include "dbus-transport-afbus.h"
-+
-+/**
-+ * @defgroup DBusServerAfbus DBusServer implementation for AF_BUS sockets
-+ * @ingroup DBusInternals
-+ * @brief Implementation details of DBusServer for AF_BUS sockets
-+ *
-+ * @{
-+ */
-+/**
-+ * Opaque object representing a AF_BUS-based server implementation.
-+ */
-+typedef struct DBusServerAfbus DBusServerAfbus;
-+
-+/**
-+ * Implementation details of DBusServerAfbus. All members
-+ * are private.
-+ */
-+struct DBusServerAfbus
-+{
-+ DBusServer base; /**< Parent class members. */
-+ int fd; /**< File descriptor. */
-+ DBusWatch *watch; /**< File descriptor watch. */
-+ DBusString address; /**< The server address */
-+};
-+
-+static void
-+afbus_finalize (DBusServer *server)
-+{
-+ DBusServerAfbus *afbus_server = (DBusServerAfbus *) server;
-+
-+ _dbus_server_finalize_base (server);
-+
-+ if (afbus_server->watch != NULL)
-+ {
-+ _dbus_watch_unref (afbus_server->watch);
-+ afbus_server->watch = NULL;
-+ }
-+
-+ dbus_free (server);
-+}
-+
-+static void
-+afbus_disconnect (DBusServer *server)
-+{
-+ DBusServerAfbus *afbus_server = (DBusServerAfbus *) server;
-+
-+ HAVE_LOCK_CHECK (server);
-+
-+ if (afbus_server->watch)
-+ {
-+ _dbus_server_remove_watch (server, afbus_server->watch);
-+ _dbus_watch_invalidate (afbus_server->watch);
-+ _dbus_watch_unref (afbus_server->watch);
-+ afbus_server->watch = NULL;
-+ }
-+
-+ _dbus_close_socket (afbus_server->fd, NULL);
-+ afbus_server->fd = -1;
-+
-+ HAVE_LOCK_CHECK (server);
-+}
-+
-+static const DBusServerVTable afbus_vtable = {
-+ afbus_finalize,
-+ afbus_disconnect
-+};
-+
-+static dbus_bool_t
-+handle_new_client (DBusServer *server,
-+ int client_fd)
-+{
-+ DBusTransport *transport;
-+ DBusConnection *connection;
-+ DBusNewConnectionFunction new_connection_function;
-+ void *new_connection_data;
-+
-+ _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
-+
-+ if (!_dbus_set_fd_nonblocking (client_fd, NULL))
-+ {
-+ SERVER_UNLOCK (server);
-+ return TRUE;
-+ }
-+
-+ transport = _dbus_transport_new_for_afbus (client_fd, &server->guid_hex, NULL);
-+ if (transport == NULL)
-+ {
-+ _dbus_close_socket (client_fd, NULL);
-+ SERVER_UNLOCK (server);
-+ return FALSE;
-+ }
-+
-+ if (!_dbus_transport_set_auth_mechanisms (transport,
-+ (const char **) server->auth_mechanisms))
-+ {
-+ _dbus_transport_unref (transport);
-+ SERVER_UNLOCK (server);
-+ return FALSE;
-+ }
-+
-+ /* note that client_fd is now owned by the transport, and will be
-+ * closed on transport disconnection/finalization
-+ */
-+ connection = _dbus_connection_new_for_transport (transport);
-+ _dbus_transport_unref (transport);
-+ transport = NULL; /* now under the connection lock */
-+
-+ if (connection == NULL)
-+ {
-+ SERVER_UNLOCK (server);
-+ return FALSE;
-+ }
-+
-+ /* See if someone wants to handle this new connection, self-referencing
-+ * for paranoia.
-+ */
-+ new_connection_function = server->new_connection_function;
-+ new_connection_data = server->new_connection_data;
-+
-+ _dbus_server_ref_unlocked (server);
-+ SERVER_UNLOCK (server);
-+
-+ if (new_connection_function)
-+ {
-+ (* new_connection_function) (server, connection,
-+ new_connection_data);
-+ }
-+ dbus_server_unref (server);
-+
-+ /* If no one grabbed a reference, the connection will die. */
-+ _dbus_connection_close_if_only_one_ref (connection);
-+ dbus_connection_unref (connection);
-+
-+ return TRUE;
-+}
-+
-+static dbus_bool_t
-+afbus_handle_watch (DBusWatch *watch,
-+ unsigned int flags,
-+ void *data)
-+{
-+ DBusServerAfbus *afbus_server = (DBusServerAfbus *) data;
-+ DBusServer *server = (DBusServer *) data;
-+
-+ SERVER_LOCK (server);
-+
-+#ifndef DBUS_DISABLE_ASSERT
-+ _dbus_assert (afbus_server->watch == watch);
-+#endif
-+
-+ _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
-+
-+ if (flags & DBUS_WATCH_READABLE)
-+ {
-+ int client_fd;
-+
-+ client_fd = _dbus_accept (afbus_server->fd);
-+ if (client_fd < 0)
-+ {
-+ /* EINTR handled for us */
-+
-+ if (_dbus_get_is_errno_eagain_or_ewouldblock ())
-+ _dbus_verbose ("No client available to accept after all\n");
-+ else
-+ _dbus_verbose ("Failed to accept a client connection: %s\n",
-+ _dbus_strerror_from_errno ());
-+
-+ SERVER_UNLOCK (server);
-+ }
-+ else
-+ {
-+ if (!handle_new_client (server, client_fd))
-+ _dbus_verbose ("Rejected client connection due to lack of memory\n");
-+ }
-+ }
-+
-+ if (flags & DBUS_WATCH_ERROR)
-+ _dbus_verbose ("Error on server listening socket\n");
-+
-+ if (flags & DBUS_WATCH_HANGUP)
-+ _dbus_verbose ("Hangup on server listening socket\n");
-+
-+ return TRUE;
-+}
-+
-+static DBusServer *
-+_dbus_server_new_for_afbus (int fd, const char *path, DBusError *error)
-+{
-+ DBusServerAfbus *afbus_server;
-+ DBusServer *server;
-+ struct sockaddr_bus sock_address;
-+
-+ afbus_server = dbus_new0 (DBusServerAfbus, 1);
-+ if (afbus_server == NULL)
-+ return NULL;
-+
-+ if (!_dbus_string_init (&afbus_server->address) ||
-+ !_dbus_string_append (&afbus_server->address, "afbus:path=") ||
-+ !_dbus_string_append (&afbus_server->address, path))
-+ {
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ goto failed_1;
-+ }
-+
-+ afbus_server->fd = fd;
-+
-+ sock_address.sbus_family = AF_BUS;
-+ strcpy (sock_address.sbus_path, path);
-+ if (bind (afbus_server->fd, (struct sockaddr *) &sock_address, sizeof (sock_address)) < 0)
-+ {
-+ dbus_set_error (error, _dbus_error_from_errno (errno),
-+ "Failed to bind socket \"%s\": %s",
-+ path, _dbus_strerror (errno));
-+ goto failed_1;
-+ }
-+
-+ if (listen (afbus_server->fd, 30 /* backlog */) < 0)
-+ {
-+ dbus_set_error (error, _dbus_error_from_errno (errno),
-+ "Failed to listen on AF_BUS socket: %s",
-+ _dbus_strerror (errno));
-+ goto failed_1;
-+ }
-+
-+ afbus_server->watch = _dbus_watch_new (fd,
-+ DBUS_WATCH_READABLE,
-+ TRUE,
-+ afbus_handle_watch, afbus_server,
-+ NULL);
-+ if (afbus_server->watch == NULL)
-+ goto failed_1;
-+
-+ if (!_dbus_server_init_base (&afbus_server->base,
-+ &afbus_vtable, &afbus_server->address))
-+ goto failed_2;
-+
-+ server = (DBusServer *) afbus_server;
-+ server->is_afbus = TRUE;
-+
-+
-+ SERVER_LOCK (server);
-+
-+ if (!_dbus_server_add_watch (&afbus_server->base,
-+ afbus_server->watch))
-+ {
-+ SERVER_UNLOCK (server);
-+ _dbus_server_finalize_base (&afbus_server->base);
-+
-+ goto failed_2;
-+ }
-+
-+ SERVER_UNLOCK (server);
-+
-+ _dbus_server_trace_ref (&afbus_server->base, 0, 1, "new_for_afbus");
-+ return (DBusServer *) afbus_server;
-+
-+ failed_2:
-+ _dbus_watch_unref (afbus_server->watch);
-+
-+ failed_1:
-+ _dbus_close_socket (afbus_server->fd, NULL);
-+ dbus_free (afbus_server);
-+
-+ return NULL;
-+}
-+
-+/**
-+ * Starts a DBusServer listening on AF_BUS socket.
-+ * Sets error if the result is not OK.
-+ *
-+ * @param entry an address entry
-+ * @param server_p location to store a new DBusServer, or #NULL on failure.
-+ * @param error location to store rationale for failure on bad address
-+ * @returns the outcome
-+ *
-+ */
-+DBusServerListenResult
-+_dbus_server_listen_afbus (DBusAddressEntry *entry,
-+ DBusServer **server_p,
-+ DBusError *error)
-+{
-+ const char *method, *path, *tmpdir;
-+ int listen_fd;
-+
-+ *server_p = NULL;
-+
-+ method = dbus_address_entry_get_method (entry);
-+ if (strcmp (method, "afbus") != 0)
-+ {
-+ /* If we don't handle the method, we return NULL with the
-+ * error unset
-+ */
-+ _DBUS_ASSERT_ERROR_IS_CLEAR(error);
-+ return DBUS_SERVER_LISTEN_NOT_HANDLED;
-+ }
-+
-+ path = dbus_address_entry_get_value (entry, "path");
-+ tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
-+
-+ if (path == NULL && tmpdir == NULL)
-+ {
-+ _dbus_set_bad_address(error, "unix",
-+ "path or tmpdir",
-+ NULL);
-+ return DBUS_SERVER_LISTEN_BAD_ADDRESS;
-+ }
-+
-+ if (path && tmpdir)
-+ {
-+ _dbus_set_bad_address(error, NULL, NULL,
-+ "cannot specify both \"path\" and \"tmpdir\" at the same time");
-+ return DBUS_SERVER_LISTEN_BAD_ADDRESS;
-+ }
-+
-+ if (!_dbus_open_socket (&listen_fd, PF_BUS, SOCK_SEQPACKET, BUS_PROTO_DBUS, error))
-+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
-+
-+ if (!_dbus_set_fd_nonblocking (listen_fd, error))
-+ goto failed_1;
-+
-+ if (tmpdir != NULL)
-+ {
-+ DBusString full_path;
-+ DBusString filename;
-+
-+ if (!_dbus_string_init (&full_path))
-+ {
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
-+ }
-+
-+ if (!_dbus_string_init (&filename))
-+ {
-+ _dbus_string_free (&full_path);
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
-+ }
-+
-+ if (!_dbus_string_append (&filename,
-+ "dbus-") ||
-+ !_dbus_generate_random_ascii (&filename, 10) ||
-+ !_dbus_string_append (&full_path, tmpdir) ||
-+ !_dbus_concat_dir_and_file (&full_path, &filename))
-+ {
-+ _dbus_string_free (&full_path);
-+ _dbus_string_free (&filename);
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
-+ }
-+
-+ path = _dbus_string_get_const_data (&full_path);
-+ }
-+
-+ *server_p = _dbus_server_new_for_afbus (listen_fd, path, error);
-+ if (*server_p == NULL)
-+ goto failed_1;
-+
-+ return DBUS_SERVER_LISTEN_OK;
-+
-+ failed_1:
-+ _dbus_close_socket (listen_fd, NULL);
-+
-+ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
-+}
-diff --git a/dbus/dbus-server-afbus.h b/dbus/dbus-server-afbus.h
-new file mode 100644
-index 0000000..8e5ad31
---- /dev/null
-+++ b/dbus/dbus-server-afbus.h
-@@ -0,0 +1,36 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* dbus-server-unix.h Server implementation for Unix network protocols.
-+ *
-+ * Copyright (C) 2012 Collabora Ltd
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * 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_SERVER_AFBUS_H
-+#define DBUS_SERVER_AFBUS_H
-+
-+#include "dbus-server-protected.h"
-+
-+DBUS_BEGIN_DECLS
-+
-+DBusServerListenResult _dbus_server_listen_afbus (DBusAddressEntry *entry,
-+ DBusServer **server_p,
-+ DBusError *error);
-+
-+DBUS_END_DECLS
-+
-+#endif
-diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
-index dd5234b..b423cb9 100644
---- a/dbus/dbus-server-protected.h
-+++ b/dbus/dbus-server-protected.h
-@@ -89,6 +89,9 @@ struct DBusServer
- #ifndef DBUS_DISABLE_CHECKS
- unsigned int have_server_lock : 1; /**< Does someone have the server mutex locked */
- #endif
-+#ifdef HAVE_AFBUS
-+ unsigned int is_afbus : 1; /**< TRUE if this server listen on a AF_BUS socket */
-+#endif
- };
-
- dbus_bool_t _dbus_server_init_base (DBusServer *server,
-diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
-index b62c2b4..2a23252 100644
---- a/dbus/dbus-server.c
-+++ b/dbus/dbus-server.c
-@@ -25,6 +25,9 @@
- #include "dbus-server.h"
- #include "dbus-server-unix.h"
- #include "dbus-server-socket.h"
-+#ifdef HAVE_AFBUS
-+#include "dbus-server-afbus.h"
-+#endif
- #include "dbus-string.h"
- #ifdef DBUS_BUILD_TESTS
- #include "dbus-server-debug-pipe.h"
-@@ -529,6 +532,9 @@ static const struct {
- } listen_funcs[] = {
- { _dbus_server_listen_socket }
- , { _dbus_server_listen_platform_specific }
-+#ifdef HAVE_AFBUS
-+ , { _dbus_server_listen_afbus }
-+#endif
- #ifdef DBUS_BUILD_TESTS
- , { _dbus_server_listen_debug_pipe }
- #endif
-@@ -844,6 +850,30 @@ dbus_server_get_address (DBusServer *server)
- }
-
- /**
-+ * Returns TRUE if the server listens on an AF_BUS address
-+ *
-+ * @param server the server
-+ * @returns TRUE if the server listens on an AF_BUS address
-+ */
-+dbus_bool_t
-+dbus_server_is_afbus (DBusServer *server)
-+{
-+ dbus_bool_t retval;
-+
-+ _dbus_return_val_if_fail (server != NULL, FALSE);
-+
-+#ifdef HAVE_AFBUS
-+ SERVER_LOCK (server);
-+ retval = server->is_afbus;
-+ SERVER_UNLOCK (server);
-+#else
-+ retval = FALSE;
-+#endif
-+
-+ return retval;
-+}
-+
-+/**
- * Returns the unique ID of the server, as a newly-allocated
- * string which must be freed by the caller. This ID is
- * normally used by clients to tell when two #DBusConnection
-diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h
-index bdbefa0..49cb9cf 100644
---- a/dbus/dbus-server.h
-+++ b/dbus/dbus-server.h
-@@ -62,6 +62,8 @@ dbus_bool_t dbus_server_get_is_connected (DBusServer *server);
- DBUS_EXPORT
- char* dbus_server_get_address (DBusServer *server);
- DBUS_EXPORT
-+dbus_bool_t dbus_server_is_afbus (DBusServer *server);
-+DBUS_EXPORT
- char* dbus_server_get_id (DBusServer *server);
- DBUS_EXPORT
- void dbus_server_set_new_connection_function (DBusServer *server,
-diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
-index 6a57670..b6b29b3 100644
---- a/dbus/dbus-shared.h
-+++ b/dbus/dbus-shared.h
-@@ -80,6 +80,10 @@ typedef enum
- #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
- /** The object path used in local/in-process-generated messages. */
- #define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local"
-+#ifdef HAVE_AFBUS
-+/** The object path used for AF_BUS sockets. */
-+#define DBUS_PATH_AFBUS "/org/freedesktop/DBus/AF_BUS"
-+#endif
-
- /* Interfaces, these #define don't do much other than
- * catch typos at compile time
-@@ -92,6 +96,10 @@ typedef enum
- #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
- /** The interface supported by most dbus peers */
- #define DBUS_INTERFACE_PEER "org.freedesktop.DBus.Peer"
-+#ifdef HAVE_AFBUS
-+/** The interface supported by AF_BUS transport */
-+#define DBUS_INTERFACE_AFBUS "org.freedesktop.DBus.AF_BUS"
-+#endif
-
- /** This is a special interface whose methods can only be invoked
- * by the local implementation (messages from remote apps aren't
-diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
-index cef8bd3..26e3d00 100644
---- a/dbus/dbus-sysdeps-unix.c
-+++ b/dbus/dbus-sysdeps-unix.c
-@@ -122,7 +122,7 @@
-
- #endif /* Solaris */
-
--static dbus_bool_t
-+dbus_bool_t
- _dbus_open_socket (int *fd_p,
- int domain,
- int type,
-diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
-index 4052cda..a589486 100644
---- a/dbus/dbus-sysdeps.h
-+++ b/dbus/dbus-sysdeps.h
-@@ -125,6 +125,11 @@ typedef unsigned long dbus_gid_t;
- *
- */
-
-+dbus_bool_t _dbus_open_socket (int *fd_p,
-+ int domain,
-+ int type,
-+ int protocol,
-+ DBusError *error);
- dbus_bool_t _dbus_close_socket (int fd,
- DBusError *error);
- int _dbus_read_socket (int fd,
-diff --git a/dbus/dbus-transport-afbus.c b/dbus/dbus-transport-afbus.c
-new file mode 100644
-index 0000000..9574bca
---- /dev/null
-+++ b/dbus/dbus-transport-afbus.c
-@@ -0,0 +1,394 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* dbus-transport-socket.h Socket subclasses of DBusTransport
-+ *
-+ * Copyright (C) 212 Collabora Ltd
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * 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 <config.h>
-+#include <errno.h>
-+#include <sys/socket.h>
-+#include "dbus-connection-internal.h"
-+#include "dbus-hash.h"
-+#include "dbus-transport-afbus.h"
-+#include "dbus-transport-socket.h"
-+#include "dbus-watch.h"
-+
-+static DBusHashTable *wkn_addresses_cache = NULL;
-+
-+/**
-+ * @defgroup DBusTransportAfbus AF_BUS-based DBusTransport implementation
-+ * @ingroup DBusInternals
-+ * @brief Implementation details of DBusTransport on AF_BUS sockets
-+ *
-+ * @{
-+ */
-+
-+/**
-+ * Opaque object representing a AF_BUS-based transport.
-+ */
-+typedef struct DBusTransportAfbus DBusTransportAfbus;
-+
-+/**
-+ * Implementation details of DBusTransportAfbus. All members are private.
-+ */
-+struct DBusTransportAfbus
-+{
-+ DBusTransportSocket base; /**< Parent instance */
-+};
-+
-+static dbus_bool_t
-+get_write_destination (int fd,
-+ DBusMessage *message,
-+ struct sockaddr_bus *sock)
-+{
-+ socklen_t addrlen;
-+ const char *destination;
-+ const char *sender;
-+
-+ /* if the sender is the bus driver, don't set the sockaddr, just let the
-+ * message be delivered to the peer socket
-+ */
-+ sender = dbus_message_get_sender (message);
-+ if (sender && strcmp (sender, DBUS_SERVICE_DBUS) == 0)
-+ {
-+ return FALSE;
-+ }
-+
-+ addrlen = sizeof(struct sockaddr_bus);
-+ if (getsockname (fd, (struct sockaddr *) sock, &addrlen) != 0)
-+ return FALSE;
-+ if (addrlen != sizeof(struct sockaddr_bus))
-+ return FALSE;
-+ if (sock->sbus_family != AF_BUS)
-+ return FALSE;
-+
-+ destination = dbus_message_get_destination (message);
-+ if (destination && strcmp (destination, DBUS_SERVICE_DBUS) == 0)
-+ {
-+ /* a message for the bus driver */
-+ sock->sbus_addr.s_addr = 0;
-+ return TRUE;
-+ }
-+
-+ if (destination != NULL && strlen (destination) > 0)
-+ {
-+ dbus_uint64_t peer = 0x0000000000000000ULL;
-+
-+ /* If destination is a unique name, just retrieve the peer address from it */
-+ if (strncmp (destination, ":AF-BUS.", 8) == 0)
-+ {
-+ DBusString tmp;
-+
-+ _dbus_string_init_const (&tmp, &destination[8]);
-+ if (!_dbus_string_parse_uint (&tmp, 0, (unsigned long *) &peer, NULL))
-+ peer = 0x0000000000000000ULL;
-+ _dbus_string_free (&tmp);
-+ }
-+ else
-+ {
-+ /* a message for a well known name */
-+ if (wkn_addresses_cache != NULL)
-+ {
-+ dbus_uint64_t *peer_pointer;
-+
-+ peer_pointer = (dbus_uint64_t *) _dbus_hash_table_lookup_string (wkn_addresses_cache, destination);
-+ if (peer_pointer != NULL)
-+ peer = *peer_pointer;
-+ }
-+ }
-+
-+ sock->sbus_addr.s_addr = peer;
-+
-+ return TRUE;
-+ }
-+ else
-+ {
-+ /* a multicast message */
-+ sock->sbus_addr.s_addr = 0x0000ffffffffffffULL;
-+ return TRUE;
-+ }
-+
-+ return FALSE;
-+}
-+
-+static int
-+afbus_write_socket (DBusTransportSocket *socket_transport,
-+ DBusMessage *message,
-+ const DBusString *buffer,
-+ int start,
-+ int len)
-+{
-+ int fd, bytes_written;
-+ struct sockaddr_bus sock;
-+
-+ if (!_dbus_transport_get_socket_fd ((DBusTransport *) socket_transport, &fd))
-+ {
-+ _dbus_verbose ("Couldn't get socket's file descriptor\n");
-+ return -1;
-+ }
-+
-+ if (get_write_destination (fd, message, &sock))
-+ {
-+ const char *data;
-+
-+ /* Send the data to specific address */
-+ data = _dbus_string_get_const_data_len (buffer, start, len);
-+
-+ bytes_written = sendto (fd, data, len, MSG_NOSIGNAL,
-+ (struct sockaddr *) &sock, sizeof (struct sockaddr_bus));
-+ }
-+ else
-+ bytes_written = _dbus_write_socket (fd, buffer, start, len);
-+
-+ return bytes_written;
-+}
-+
-+static int
-+afbus_write_socket_two (DBusTransportSocket *socket_transport,
-+ DBusMessage *message,
-+ const DBusString *header,
-+ int header_start,
-+ int header_len,
-+ const DBusString *body,
-+ int body_start,
-+ int body_len)
-+{
-+ int fd, bytes_written;
-+ struct sockaddr_bus sock;
-+
-+ if (!_dbus_transport_get_socket_fd ((DBusTransport *) socket_transport, &fd))
-+ {
-+ _dbus_verbose ("Couldn't get socket's file descriptor\n");
-+ return -1;
-+ }
-+
-+ if (get_write_destination (fd, message, &sock))
-+ {
-+ struct iovec vectors[2];
-+ const char *data1, *data2;
-+ struct msghdr m;
-+
-+ data1 = _dbus_string_get_const_data_len (header, header_start, header_len);
-+ if (body != NULL)
-+ data2 = _dbus_string_get_const_data_len (body, body_start, body_len);
-+ else
-+ {
-+ data2 = NULL;
-+ body_start = body_len = 0;
-+ }
-+
-+ vectors[0].iov_base = (char *) data1;
-+ vectors[0].iov_len = header_len;
-+ vectors[1].iov_base = (char *) data2;
-+ vectors[1].iov_len = body_len;
-+
-+ _DBUS_ZERO(m);
-+ m.msg_iov = vectors;
-+ m.msg_iovlen = data2 ? 2 : 1;
-+ m.msg_name = &sock;
-+ m.msg_namelen = sizeof (sock);
-+
-+ again:
-+ bytes_written = sendmsg (fd, &m, MSG_NOSIGNAL);
-+ if (bytes_written < 0 && errno == EINTR)
-+ goto again;
-+ }
-+ else
-+ bytes_written = _dbus_write_socket_two (fd, header, header_start, header_len, body, body_start, body_len);
-+
-+ return bytes_written;
-+}
-+
-+static void
-+afbus_authenticated (DBusTransportSocket *socket_transport)
-+{
-+ if (socket_transport->base.is_server)
-+ {
-+ /* Make the client join the bus when authenticated, so that it can send
-+ * unicast messages to peers other than the daemon */
-+ if (setsockopt (socket_transport->fd, SOL_BUS, BUS_JOIN_BUS, NULL, 0) != 0)
-+ {
-+ _dbus_verbose ("Could not join client to the bus\n");
-+ }
-+ }
-+}
-+
-+static void
-+afbus_message_received (DBusTransportSocket *socket_transport,
-+ DBusMessage *message)
-+{
-+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL)
-+ {
-+ const char *path, *interface, *member;
-+
-+ path = dbus_message_get_path (message);
-+ interface = dbus_message_get_interface (message);
-+ member = dbus_message_get_member (message);
-+
-+ if (strcmp (path, DBUS_PATH_AFBUS) == 0
-+ && strcmp (interface, DBUS_INTERFACE_AFBUS) == 0
-+ && strcmp (member, "Forwarded") == 0)
-+ {
-+ char *wkn;
-+ dbus_uint64_t peer;
-+ dbus_uint64_t *peer_pointer;
-+
-+ /* Update the cache */
-+ if (wkn_addresses_cache == NULL)
-+ {
-+ wkn_addresses_cache = _dbus_hash_table_new (DBUS_HASH_STRING,
-+ dbus_free,
-+ dbus_free);
-+ if (wkn_addresses_cache == NULL)
-+ return;
-+ }
-+
-+ dbus_message_get_args (message, NULL,
-+ DBUS_TYPE_STRING, &wkn,
-+ DBUS_TYPE_UINT64, &peer,
-+ DBUS_TYPE_INVALID);
-+
-+ peer_pointer = dbus_new (dbus_uint64_t, 1);
-+ *peer_pointer = peer;
-+ _dbus_hash_table_insert_string (wkn_addresses_cache,
-+ _dbus_strdup (wkn),
-+ (void *) peer_pointer);
-+ }
-+ }
-+}
-+
-+static const DBusTransportSocketVTable afbus_vtable = {
-+ afbus_write_socket,
-+ afbus_write_socket_two,
-+ afbus_authenticated,
-+ afbus_message_received
-+};
-+
-+/**
-+ * Creates a new AF_BUS-based transport for the given socket descriptor.
-+ *
-+ * @param fd the file descriptor.
-+ * @param server_guid non-#NULL if this transport is on the server side of a connection
-+ * @param address the transport's address
-+ * @returns the new transport, or #NULL if no memory.
-+ */
-+DBusTransport*
-+_dbus_transport_new_for_afbus (int fd,
-+ const DBusString *server_guid,
-+ const DBusString *address)
-+{
-+ DBusTransportAfbus *afbus_transport;
-+
-+ afbus_transport = dbus_new0 (DBusTransportAfbus, 1);
-+ if (afbus_transport == NULL)
-+ return NULL;
-+
-+ if (!_dbus_transport_socket_init_base (&afbus_transport->base,
-+ fd,
-+ &afbus_vtable,
-+ server_guid, address))
-+ goto failed_1;
-+
-+ return (DBusTransport *) afbus_transport;
-+
-+ failed_1:
-+ dbus_free (afbus_transport);
-+
-+ return NULL;
-+}
-+
-+/**
-+ * Opens a AF_BUS-based transport.
-+ *
-+ * @param entry the address entry to try opening as a tcp transport.
-+ * @param transport_p return location for the opened transport
-+ * @param error error to be set
-+ * @returns result of the attempt
-+ */
-+DBusTransportOpenResult
-+_dbus_transport_open_afbus (DBusAddressEntry *entry,
-+ DBusTransport **transport_p,
-+ DBusError *error)
-+{
-+ const char *method, *path;
-+ DBusString address;
-+ int fd;
-+ struct sockaddr_bus sock_address;
-+
-+ method = dbus_address_entry_get_method (entry);
-+ if (strcmp (method, "afbus") != 0)
-+ {
-+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-+ return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
-+ }
-+
-+ path = dbus_address_entry_get_value (entry, "path");
-+ if (path == NULL)
-+ {
-+ _dbus_set_bad_address (error, "afbus",
-+ "path or tmpdir",
-+ NULL);
-+ return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
-+ }
-+
-+ if (!_dbus_string_init (&address) ||
-+ !_dbus_string_append (&address, "afbus:path=") ||
-+ !_dbus_string_append (&address, path))
-+ {
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
-+ }
-+
-+ if (!_dbus_open_socket (&fd, PF_BUS, SOCK_SEQPACKET, BUS_PROTO_DBUS, error))
-+ goto failed_1;
-+
-+ if (!_dbus_set_fd_nonblocking (fd, error))
-+ goto failed_2;
-+
-+ sock_address.sbus_family = AF_BUS;
-+ strcpy (sock_address.sbus_path, path);
-+ if (connect (fd, (struct sockaddr *) &sock_address, sizeof (sock_address)) < 0)
-+ {
-+ dbus_set_error (error,
-+ _dbus_error_from_errno (errno),
-+ "Failed to connect to socket %s: %s",
-+ path, _dbus_strerror (errno));
-+ goto failed_2;
-+ }
-+
-+ *transport_p = _dbus_transport_new_for_afbus (fd, NULL, &address);
-+ if (*transport_p == NULL)
-+ {
-+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-+ goto failed_2;
-+ }
-+
-+ _dbus_string_free (&address);
-+
-+ return DBUS_TRANSPORT_OPEN_OK;
-+
-+ failed_2:
-+ _dbus_close_socket (fd, NULL);
-+
-+ failed_1:
-+ _dbus_string_free (&address);
-+
-+ return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
-+}
-diff --git a/dbus/dbus-transport-afbus.h b/dbus/dbus-transport-afbus.h
-new file mode 100644
-index 0000000..c94e32d
---- /dev/null
-+++ b/dbus/dbus-transport-afbus.h
-@@ -0,0 +1,41 @@
-+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-+/* dbus-transport-socket.h Socket subclasses of DBusTransport
-+ *
-+ * Copyright (C) 212 Collabora Ltd
-+ *
-+ * Licensed under the Academic Free License version 2.1
-+ *
-+ * 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_TRANSPORT_AFBUS_H
-+#define DBUS_TRANSPORT_AFBUS_H
-+
-+#include <sys/socket.h>
-+#include <sys/bus.h>
-+#include <dbus/dbus-transport-protected.h>
-+
-+DBUS_BEGIN_DECLS
-+
-+DBusTransport *_dbus_transport_new_for_afbus (int fd,
-+ const DBusString *server_guid,
-+ const DBusString *address);
-+DBusTransportOpenResult _dbus_transport_open_afbus (DBusAddressEntry *entry,
-+ DBusTransport **transport_p,
-+ DBusError *error);
-+
-+DBUS_END_DECLS
-+
-+#endif
-diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h
-index 44b9d78..9becbdb 100644
---- a/dbus/dbus-transport-protected.h
-+++ b/dbus/dbus-transport-protected.h
-@@ -69,6 +69,10 @@ struct DBusTransportVTable
- dbus_bool_t (* get_socket_fd) (DBusTransport *transport,
- int *fd_p);
- /**< Get socket file descriptor */
-+
-+ void (* process_incoming_message) (DBusTransport *transport,
-+ DBusMessage *message);
-+ /**> Method to allow transport to filter messages */
- };
-
- /**
-diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
-index 544d00a..a3951ef 100644
---- a/dbus/dbus-transport-socket.c
-+++ b/dbus/dbus-transport-socket.c
-@@ -22,6 +22,7 @@
- */
-
- #include <config.h>
-+#include <sys/ioctl.h>
- #include "dbus-internals.h"
- #include "dbus-connection-internal.h"
- #include "dbus-nonce.h"
-@@ -38,43 +39,13 @@
- * @{
- */
-
--/**
-- * Opaque object representing a socket file descriptor transport.
-- */
--typedef struct DBusTransportSocket DBusTransportSocket;
--
--/**
-- * Implementation details of DBusTransportSocket. All members are private.
-- */
--struct DBusTransportSocket
--{
-- DBusTransport base; /**< Parent instance */
-- int fd; /**< File descriptor. */
-- DBusWatch *read_watch; /**< Watch for readability. */
-- DBusWatch *write_watch; /**< Watch for writability. */
--
-- int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
-- int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
--
-- int message_bytes_written; /**< Number of bytes of current
-- * outgoing message that have
-- * been written.
-- */
-- DBusString encoded_outgoing; /**< Encoded version of current
-- * outgoing message.
-- */
-- DBusString encoded_incoming; /**< Encoded version of current
-- * incoming data.
-- */
--};
--
- static void
- free_watches (DBusTransport *transport)
- {
- DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
-
- _dbus_verbose ("start\n");
--
-+
- if (socket_transport->read_watch)
- {
- if (transport->connection)
-@@ -104,7 +75,7 @@ socket_finalize (DBusTransport *transport)
- DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
-
- _dbus_verbose ("\n");
--
-+
- free_watches (transport);
-
- _dbus_string_free (&socket_transport->encoded_outgoing);
-@@ -136,7 +107,16 @@ check_write_watch (DBusTransport *transport)
- _dbus_transport_ref (transport);
-
- if (_dbus_transport_get_is_authenticated (transport))
-- needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
-+ {
-+ if (!socket_transport->auth_notified &&
-+ socket_transport->vtable->authenticated != NULL)
-+ {
-+ socket_transport->auth_notified = TRUE;
-+ socket_transport->vtable->authenticated (socket_transport);
-+ }
-+
-+ needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
-+ }
- else
- {
- if (transport->send_credentials_pending)
-@@ -146,7 +126,7 @@ check_write_watch (DBusTransport *transport)
- DBusAuthState auth_state;
-
- auth_state = _dbus_auth_do_work (transport->auth);
--
-+
- /* If we need memory we install the write watch just in case,
- * if there's no need for it, it will get de-installed
- * next time we try reading.
-@@ -191,9 +171,18 @@ check_read_watch (DBusTransport *transport)
- _dbus_transport_ref (transport);
-
- if (_dbus_transport_get_is_authenticated (transport))
-- need_read_watch =
-- (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
-- (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
-+ {
-+ if (!socket_transport->auth_notified &&
-+ socket_transport->vtable->authenticated != NULL)
-+ {
-+ socket_transport->auth_notified = TRUE;
-+ socket_transport->vtable->authenticated (socket_transport);
-+ }
-+
-+ need_read_watch =
-+ (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
-+ (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
-+ }
- else
- {
- if (transport->receive_credentials_pending)
-@@ -489,6 +478,59 @@ do_authentication (DBusTransport *transport,
- return TRUE;
- }
-
-+static int
-+_write_socket (DBusTransportSocket *socket_transport,
-+ DBusMessage *message,
-+ const DBusString *buffer,
-+ int start,
-+ int len)
-+{
-+ int bytes_written;
-+
-+ if (socket_transport->vtable->write_socket != NULL)
-+ {
-+ bytes_written = socket_transport->vtable->write_socket (socket_transport,
-+ message,
-+ buffer, start, len);
-+ }
-+ else
-+ {
-+ bytes_written = _dbus_write_socket (socket_transport->fd,
-+ buffer,
-+ start, len);
-+ }
-+
-+ return bytes_written;
-+}
-+
-+static int
-+_write_socket_two (DBusTransportSocket *socket_transport,
-+ DBusMessage *message,
-+ const DBusString *header,
-+ int header_start,
-+ int header_len,
-+ const DBusString *body,
-+ int body_start,
-+ int body_len)
-+{
-+ int bytes_written;
-+
-+ if (socket_transport->vtable->write_socket_two != NULL)
-+ {
-+ bytes_written = socket_transport->vtable->write_socket_two (socket_transport, message,
-+ header, header_start, header_len,
-+ body, body_start, body_len);
-+ }
-+ else
-+ {
-+ bytes_written = _dbus_write_socket_two (socket_transport->fd,
-+ header, header_start, header_len,
-+ body, body_start, body_len);
-+ }
-+
-+ return bytes_written;
-+}
-+
- /* returns false on oom */
- static dbus_bool_t
- do_writing (DBusTransport *transport)
-@@ -579,12 +621,13 @@ do_writing (DBusTransport *transport)
- _dbus_verbose ("encoded message is %d bytes\n",
- total_bytes_to_write);
- #endif
--
-+
- bytes_written =
-- _dbus_write_socket (socket_transport->fd,
-- &socket_transport->encoded_outgoing,
-- socket_transport->message_bytes_written,
-- total_bytes_to_write - socket_transport->message_bytes_written);
-+ _write_socket (socket_transport,
-+ message,
-+ &socket_transport->encoded_outgoing,
-+ socket_transport->message_bytes_written,
-+ total_bytes_to_write - socket_transport->message_bytes_written);
- }
- else
- {
-@@ -623,21 +666,23 @@ do_writing (DBusTransport *transport)
- if (socket_transport->message_bytes_written < header_len)
- {
- bytes_written =
-- _dbus_write_socket_two (socket_transport->fd,
-- header,
-- socket_transport->message_bytes_written,
-- header_len - socket_transport->message_bytes_written,
-- body,
-- 0, body_len);
-+ _write_socket_two (socket_transport,
-+ message,
-+ header,
-+ socket_transport->message_bytes_written,
-+ header_len - socket_transport->message_bytes_written,
-+ body,
-+ 0, body_len);
- }
- else
- {
- bytes_written =
-- _dbus_write_socket (socket_transport->fd,
-- body,
-- (socket_transport->message_bytes_written - header_len),
-- body_len -
-- (socket_transport->message_bytes_written - header_len));
-+ _write_socket (socket_transport,
-+ message,
-+ body,
-+ (socket_transport->message_bytes_written - header_len),
-+ body_len -
-+ (socket_transport->message_bytes_written - header_len));
- }
- }
- }
-@@ -696,7 +741,7 @@ do_reading (DBusTransport *transport)
- {
- DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
- DBusString *buffer;
-- int bytes_read;
-+ int bytes_read, bytes_available;
- int total;
- dbus_bool_t oom;
-
-@@ -730,7 +775,12 @@ do_reading (DBusTransport *transport)
-
- if (!dbus_watch_get_enabled (socket_transport->read_watch))
- return TRUE;
--
-+
-+ if (ioctl (socket_transport->fd, FIONREAD, &bytes_available) < 0)
-+ bytes_available = socket_transport->max_bytes_read_per_iteration;
-+ else if (bytes_available < socket_transport->max_bytes_read_per_iteration)
-+ bytes_available = socket_transport->max_bytes_read_per_iteration;
-+
- if (_dbus_auth_needs_decoding (transport->auth))
- {
- /* Does fd passing even make sense with encoded data? */
-@@ -741,7 +791,7 @@ do_reading (DBusTransport *transport)
- else
- bytes_read = _dbus_read_socket (socket_transport->fd,
- &socket_transport->encoded_incoming,
-- socket_transport->max_bytes_read_per_iteration);
-+ bytes_available);
-
- _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) ==
- bytes_read);
-@@ -796,7 +846,7 @@ do_reading (DBusTransport *transport)
-
- bytes_read = _dbus_read_socket_with_unix_fds(socket_transport->fd,
- buffer,
-- socket_transport->max_bytes_read_per_iteration,
-+ bytes_available,
- fds, &n_fds);
-
- if (bytes_read >= 0 && n_fds > 0)
-@@ -808,7 +858,7 @@ do_reading (DBusTransport *transport)
- #endif
- {
- bytes_read = _dbus_read_socket (socket_transport->fd,
-- buffer, socket_transport->max_bytes_read_per_iteration);
-+ buffer, bytes_available);
- }
-
- _dbus_message_loader_return_buffer (transport->loader,
-@@ -1207,6 +1257,19 @@ socket_get_socket_fd (DBusTransport *transport,
- return TRUE;
- }
-
-+static void
-+socket_process_incoming_message (DBusTransport *transport,
-+ DBusMessage *message)
-+{
-+ DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
-+
-+ if (socket_transport->vtable->message_received != NULL)
-+ {
-+ (* socket_transport->vtable->message_received) (socket_transport,
-+ message);
-+ }
-+}
-+
- static const DBusTransportVTable socket_vtable = {
- socket_finalize,
- socket_handle_watch,
-@@ -1214,37 +1277,40 @@ static const DBusTransportVTable socket_vtable = {
- socket_connection_set,
- socket_do_iteration,
- socket_live_messages_changed,
-- socket_get_socket_fd
-+ socket_get_socket_fd,
-+ socket_process_incoming_message
- };
-
- /**
-- * Creates a new transport for the given socket file descriptor. The file
-- * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
-- * make it so). This function is shared by various transports that
-- * boil down to a full duplex file descriptor.
-+ * Initializes the base class members of DBusTransportSocket. Chained up to
-+ * by subclasses in their constructor. The server GUID is the
-+ * globally unique ID for the server creating this connection
-+ * and will be #NULL for the client side of a connection. The GUID
-+ * is in hex format.
- *
-- * @param fd the file descriptor.
-+ * @param socket_transport the transport being created.
-+ * @param fd The socket for this transport
-+ * @param vtable the subclass vtable.
- * @param server_guid non-#NULL if this transport is on the server side of a connection
-- * @param address the transport's address
-- * @returns the new transport, or #NULL if no memory.
-+ * @param address the address of the transport
-+ * @returns #TRUE on success.
- */
--DBusTransport*
--_dbus_transport_new_for_socket (int fd,
-- const DBusString *server_guid,
-- const DBusString *address)
-+dbus_bool_t
-+_dbus_transport_socket_init_base (DBusTransportSocket *socket_transport,
-+ int fd,
-+ const DBusTransportSocketVTable *vtable,
-+ const DBusString *server_guid,
-+ const DBusString *address)
- {
-- DBusTransportSocket *socket_transport;
--
-- socket_transport = dbus_new0 (DBusTransportSocket, 1);
-- if (socket_transport == NULL)
-- return NULL;
--
- if (!_dbus_string_init (&socket_transport->encoded_outgoing))
- goto failed_0;
-
- if (!_dbus_string_init (&socket_transport->encoded_incoming))
- goto failed_1;
--
-+
-+ socket_transport->auth_notified = FALSE;
-+ socket_transport->vtable = vtable;
-+
- socket_transport->write_watch = _dbus_watch_new (fd,
- DBUS_WATCH_WRITABLE,
- FALSE,
-@@ -1275,7 +1341,7 @@ _dbus_transport_new_for_socket (int fd,
- socket_transport->max_bytes_read_per_iteration = 2048;
- socket_transport->max_bytes_written_per_iteration = 2048;
-
-- return (DBusTransport*) socket_transport;
-+ return TRUE;
-
- failed_4:
- _dbus_watch_invalidate (socket_transport->read_watch);
-@@ -1288,8 +1354,46 @@ _dbus_transport_new_for_socket (int fd,
- failed_1:
- _dbus_string_free (&socket_transport->encoded_outgoing);
- failed_0:
-- dbus_free (socket_transport);
-- return NULL;
-+
-+ return FALSE;
-+}
-+
-+/**
-+ * Creates a new transport for the given socket file descriptor. The file
-+ * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
-+ * make it so). This function is shared by various transports that
-+ * boil down to a full duplex file descriptor.
-+ *
-+ * @param fd the file descriptor.
-+ * @param server_guid non-#NULL if this transport is on the server side of a connection
-+ * @param address the transport's address
-+ * @returns the new transport, or #NULL if no memory.
-+ */
-+DBusTransport*
-+_dbus_transport_new_for_socket (int fd,
-+ const DBusString *server_guid,
-+ const DBusString *address)
-+{
-+ DBusTransportSocket *socket_transport;
-+ static const DBusTransportSocketVTable vtable = {
-+ NULL
-+ };
-+
-+ socket_transport = dbus_new0 (DBusTransportSocket, 1);
-+ if (socket_transport == NULL)
-+ return NULL;
-+
-+ if (!_dbus_transport_socket_init_base (socket_transport,
-+ fd,
-+ &vtable,
-+ server_guid,
-+ address))
-+ {
-+ dbus_free (socket_transport);
-+ return NULL;
-+ }
-+
-+ return (DBusTransport *) socket_transport;
- }
-
- /**
-diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h
-index 8aefae3..ed7fdcc 100644
---- a/dbus/dbus-transport-socket.h
-+++ b/dbus/dbus-transport-socket.h
-@@ -27,6 +27,80 @@
-
- DBUS_BEGIN_DECLS
-
-+/**
-+ * Opaque object representing a socket file descriptor transport.
-+ */
-+typedef struct DBusTransportSocket DBusTransportSocket;
-+
-+/**
-+ * The virtual table that must be implemented to
-+ * create a socket-based transport.
-+ */
-+typedef struct DBusTransportSocketVTable DBusTransportSocketVTable;
-+
-+struct DBusTransportSocketVTable
-+{
-+ int (* write_socket) (DBusTransportSocket *socket_transport,
-+ DBusMessage *message,
-+ const DBusString *buffer,
-+ int start,
-+ int len);
-+ /**< Write part of a message to the transport */
-+
-+ int (* write_socket_two) (DBusTransportSocket *socket_transport,
-+ DBusMessage *message,
-+ const DBusString *header,
-+ int header_start,
-+ int header_len,
-+ const DBusString *body,
-+ int body_start,
-+ int body_len);
-+ /**< Write header and body to the transport */
-+
-+ void (* authenticated) (DBusTransportSocket *socket_transport);
-+ /**< Notification of authentication successful */
-+
-+ void (* message_received) (DBusTransportSocket *socket_transport,
-+ DBusMessage *message);
-+ /**< Notification of a message received */
-+};
-+
-+/**
-+ * Implementation details of DBusTransportSocket. All members are private.
-+ */
-+struct DBusTransportSocket
-+{
-+ DBusTransport base; /**< Parent instance */
-+ int fd; /**< File descriptor. */
-+ DBusWatch *read_watch; /**< Watch for readability. */
-+ DBusWatch *write_watch; /**< Watch for writability. */
-+
-+ int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
-+ int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
-+
-+ int message_bytes_written; /**< Number of bytes of current
-+ * outgoing message that have
-+ * been written.
-+ */
-+ DBusString encoded_outgoing; /**< Encoded version of current
-+ * outgoing message.
-+ */
-+ DBusString encoded_incoming; /**< Encoded version of current
-+ * incoming data.
-+ */
-+ dbus_bool_t auth_notified; /**< Have we notified subclasses
-+ * we are authenticated?
-+ */
-+ const DBusTransportSocketVTable *vtable; /**< Virtual table of transport methods. */
-+};
-+
-+dbus_bool_t _dbus_transport_socket_init_base (DBusTransportSocket *socket_transport,
-+ int fd,
-+ const DBusTransportSocketVTable *vtable,
-+ const DBusString *server_guid,
-+ const DBusString *address);
-+void _dbus_transport_socket_finalize_base (DBusTransportSocket *socket_transport);
-+
- DBusTransport* _dbus_transport_new_for_socket (int fd,
- const DBusString *server_guid,
- const DBusString *address);
-diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
-index 6b58fda..44923da 100644
---- a/dbus/dbus-transport.c
-+++ b/dbus/dbus-transport.c
-@@ -25,6 +25,9 @@
- #include "dbus-transport-protected.h"
- #include "dbus-transport-unix.h"
- #include "dbus-transport-socket.h"
-+#ifdef HAVE_AFBUS
-+#include "dbus-transport-afbus.h"
-+#endif
- #include "dbus-connection-internal.h"
- #include "dbus-watch.h"
- #include "dbus-auth.h"
-@@ -348,6 +351,9 @@ static const struct {
- { _dbus_transport_open_socket },
- { _dbus_transport_open_platform_specific },
- { _dbus_transport_open_autolaunch }
-+#ifdef HAVE_AFBUS
-+ , { _dbus_transport_open_afbus }
-+#endif
- #ifdef DBUS_BUILD_TESTS
- , { _dbus_transport_open_debug_pipe }
- #endif
-@@ -980,6 +986,28 @@ _dbus_transport_do_iteration (DBusTransport *transport,
- _dbus_verbose ("end\n");
- }
-
-+/**
-+ * Allows transports to process incoming messages
-+ *
-+ * @param transport the transport.
-+ * @param message the message to be filtered
-+ */
-+void
-+_dbus_transport_process_incoming_message (DBusTransport *transport,
-+ DBusMessage *message)
-+{
-+ _dbus_verbose ("Transport message filtering\n");
-+
-+ if (transport->vtable->process_incoming_message != NULL)
-+ {
-+ _dbus_transport_ref (transport);
-+ (* transport->vtable->process_incoming_message) (transport, message);
-+ _dbus_transport_unref (transport);
-+ }
-+
-+ _dbus_verbose ("end\n");
-+}
-+
- static dbus_bool_t
- recover_unused_bytes (DBusTransport *transport)
- {
-@@ -1134,6 +1162,7 @@ _dbus_transport_queue_messages (DBusTransport *transport)
- _dbus_assert (link != NULL);
-
- message = link->data;
-+ _dbus_transport_process_incoming_message (transport, message);
-
- _dbus_verbose ("queueing received message %p\n", message);
-
-diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
-index 4b82151..194b2c6 100644
---- a/dbus/dbus-transport.h
-+++ b/dbus/dbus-transport.h
-@@ -52,6 +52,8 @@ dbus_bool_t _dbus_transport_set_connection (DBusTransport
- void _dbus_transport_do_iteration (DBusTransport *transport,
- unsigned int flags,
- int timeout_milliseconds);
-+void _dbus_transport_process_incoming_message (DBusTransport *transport,
-+ DBusMessage *message);
- DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport);
- dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport);
-
-diff --git a/test/data/valid-config-files/basic.conf b/test/data/valid-config-files/basic.conf
-index 5297097..af46d8b 100644
---- a/test/data/valid-config-files/basic.conf
-+++ b/test/data/valid-config-files/basic.conf
-@@ -4,6 +4,8 @@
- <user>mybususer</user>
- <listen>unix:path=/foo/bar</listen>
- <listen>tcp:port=1234</listen>
-+ <listen_if_possible>tcp:port=1235</listen_if_possible>
-+ <listen_if_possible>pigeon:port=carrier,speed=110mph</listen_if_possible>
- <includedir>basic.d</includedir>
- <servicedir>/usr/share/foo</servicedir>
- <include ignore_missing="yes">nonexistent.conf</include>
diff --git a/meta-ivi/recipes-core-ivi/dbus/dbus_%.bbappend b/meta-ivi/recipes-core-ivi/dbus/dbus_%.bbappend
index ac73e11..e468884 100644
--- a/meta-ivi/recipes-core-ivi/dbus/dbus_%.bbappend
+++ b/meta-ivi/recipes-core-ivi/dbus/dbus_%.bbappend
@@ -1,9 +1,5 @@
FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
-# add support for GENIVI AF_Bus D-Bus Optimization
-# - http://projects.genivi.org/afbus-dbus-optimization/
-#SRC_URI_AFBUS = "file://dbus_1.6-add-afbus-support.patch"
-
# add support for GENIVI CommonAPI D-Bus runtime
# - http://projects.genivi.org/commonapi/
SRC_URI_append = " \