diff options
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, ¬_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(¬_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 ∅ -+ } -+} -+ -+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 = " \ |