aboutsummaryrefslogtreecommitdiffstats
path: root/meta-ivi-bsp
diff options
context:
space:
mode:
Diffstat (limited to 'meta-ivi-bsp')
-rw-r--r--meta-ivi-bsp/classes/sdcard_image.bbclass87
-rw-r--r--meta-ivi-bsp/recipes-bsp/u-boot/files/no_delay.patch13
-rw-r--r--meta-ivi-bsp/recipes-bsp/u-boot/u-boot_2011.06.bbappend5
-rw-r--r--meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config/vexpressa9/xorg.conf26
-rw-r--r--meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend4
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch6387
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/beagle_qemu.cfg5
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg13
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg13
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg843
-rw-r--r--meta-ivi-bsp/recipes-kernel/linux/linux-yocto_3.8.bbappend25
11 files changed, 7421 insertions, 0 deletions
diff --git a/meta-ivi-bsp/classes/sdcard_image.bbclass b/meta-ivi-bsp/classes/sdcard_image.bbclass
new file mode 100644
index 0000000..de3682f
--- /dev/null
+++ b/meta-ivi-bsp/classes/sdcard_image.bbclass
@@ -0,0 +1,87 @@
+inherit image_types
+
+#
+# Create an image that can by written onto a SD card using dd.
+#
+# The disk layout used is:
+#
+# 0 -> IMAGE_ROOTFS_ALIGNMENT - reserved for other data
+# IMAGE_ROOTFS_ALIGNMENT -> BOOT_SPACE - bootloader and/or kernel
+# BOOT_SPACE -> SDIMG_SIZE - rootfs
+#
+
+# Default Free space = 1.3x
+# Use IMAGE_OVERHEAD_FACTOR to add more space
+# <--------->
+# 4KiB 20MiB SDIMG_ROOTFS
+# <-----------------------> <----------> <---------------------->
+# ------------------------ ------------ ------------------------ -------------------------------
+# | IMAGE_ROOTFS_ALIGNMENT | BOOT_SPACE | ROOTFS_SIZE | IMAGE_ROOTFS_ALIGNMENT |
+# ------------------------ ------------ ------------------------ -------------------------------
+# ^ ^ ^ ^ ^
+# | | | | |
+# 0 4096 4KiB + 20MiB 4KiB + 20Mib + SDIMG_ROOTFS 4KiB + 20MiB + SDIMG_ROOTFS + 4KiB
+
+
+# Boot partition volume id
+BOOTDD_VOLUME_ID ?= "${MACHINE}"
+
+# Boot partition size [in KiB]
+BOOT_SPACE ?= "20480"
+
+# Set alignment to 4MB [in KiB]
+IMAGE_ROOTFS_ALIGNMENT = "4096"
+
+# Use an uncompressed ext3 by default as rootfs
+SDIMG_ROOTFS_TYPE ?= "ext3"
+SDIMG_ROOTFS = "${IMAGE_NAME}.rootfs.${SDIMG_ROOTFS_TYPE}"
+
+IMAGE_DEPENDS_vexpressa9-sdimg = " \
+ parted-native \
+ mtools-native \
+ dosfstools-native \
+ virtual/kernel \
+ "
+
+# SD card image name
+SDIMG = "${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.vexpressa9-sdimg"
+
+IMAGEDATESTAMP = "${@time.strftime('%Y.%m.%d',time.gmtime())}"
+
+IMAGE_CMD_vexpressa9-sdimg () {
+ # Align partitions
+ BOOT_SPACE_ALIGNED=$(expr ${BOOT_SPACE} + ${IMAGE_ROOTFS_ALIGNMENT} - 1)
+ BOOT_SPACE_ALIGNED=$(expr ${BOOT_SPACE_ALIGNED} - ${BOOT_SPACE_ALIGNED} % ${IMAGE_ROOTFS_ALIGNMENT})
+ SDIMG_SIZE=$(expr ${IMAGE_ROOTFS_ALIGNMENT} + ${BOOT_SPACE_ALIGNED} + $ROOTFS_SIZE + ${IMAGE_ROOTFS_ALIGNMENT})
+
+ # Initialize sdcard image file
+ dd if=/dev/zero of=${SDIMG} bs=1 count=0 seek=$(expr 1024 \* ${SDIMG_SIZE})
+
+ # Create partition table
+ parted -s ${SDIMG} mklabel msdos
+ # Create boot partition and mark it as bootable
+ parted -s ${SDIMG} unit KiB mkpart primary fat32 ${IMAGE_ROOTFS_ALIGNMENT} $(expr ${BOOT_SPACE_ALIGNED} \+ ${IMAGE_ROOTFS_ALIGNMENT})
+ parted -s ${SDIMG} set 1 boot on
+ # Create rootfs partition
+ parted -s ${SDIMG} unit KiB mkpart primary ext2 $(expr ${BOOT_SPACE_ALIGNED} \+ ${IMAGE_ROOTFS_ALIGNMENT}) $(expr ${BOOT_SPACE_ALIGNED} \+ ${IMAGE_ROOTFS_ALIGNMENT} \+ ${ROOTFS_SIZE})
+ parted ${SDIMG} print
+
+ # Create a vfat image with boot files
+ BOOT_BLOCKS=$(LC_ALL=C parted -s ${SDIMG} unit b print | awk '/ 1 / { print substr($4, 1, length($4 -1)) / 512 /2 }')
+ mkfs.vfat -n "${BOOTDD_VOLUME_ID}" -S 512 -C ${WORKDIR}/boot.img $BOOT_BLOCKS
+ mcopy -i ${WORKDIR}/boot.img -s ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}-${MACHINE}.bin ::kernel.img
+
+ # Add stamp file
+ echo "${IMAGE_NAME}-${IMAGEDATESTAMP}" > ${WORKDIR}/image-version-info
+ mcopy -i ${WORKDIR}/boot.img -v ${WORKDIR}//image-version-info ::
+
+ # Burn Partitions
+ dd if=${WORKDIR}/boot.img of=${SDIMG} conv=notrunc seek=1 bs=$(expr ${IMAGE_ROOTFS_ALIGNMENT} \* 1024) && sync && sync
+ # If SDIMG_ROOTFS_TYPE is a .xz file use xzcat
+ if [[ "$SDIMG_ROOTFS_TYPE" == *.xz ]]
+ then
+ xzcat ${SDIMG_ROOTFS} | dd of=${SDIMG} conv=notrunc seek=1 bs=$(expr 1024 \* ${BOOT_SPACE_ALIGNED} + ${IMAGE_ROOTFS_ALIGNMENT} \* 1024) && sync && sync
+ else
+ dd if=${SDIMG_ROOTFS} of=${SDIMG} conv=notrunc seek=1 bs=$(expr 1024 \* ${BOOT_SPACE_ALIGNED} + ${IMAGE_ROOTFS_ALIGNMENT} \* 1024) && sync && sync
+ fi
+}
diff --git a/meta-ivi-bsp/recipes-bsp/u-boot/files/no_delay.patch b/meta-ivi-bsp/recipes-bsp/u-boot/files/no_delay.patch
new file mode 100644
index 0000000..f280b7e
--- /dev/null
+++ b/meta-ivi-bsp/recipes-bsp/u-boot/files/no_delay.patch
@@ -0,0 +1,13 @@
+Index: git/include/configs/omap3_beagle.h
+===================================================================
+--- git.orig/include/configs/omap3_beagle.h 2012-01-20 02:19:54.582012450 +0200
++++ git/include/configs/omap3_beagle.h 2012-01-20 02:20:33.534011227 +0200
+@@ -195,7 +195,7 @@
+ /* partition */
+
+ /* Environment information */
+-#define CONFIG_BOOTDELAY 10
++#define CONFIG_BOOTDELAY 0
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+ "loadaddr=0x82000000\0" \
diff --git a/meta-ivi-bsp/recipes-bsp/u-boot/u-boot_2011.06.bbappend b/meta-ivi-bsp/recipes-bsp/u-boot/u-boot_2011.06.bbappend
new file mode 100644
index 0000000..672a019
--- /dev/null
+++ b/meta-ivi-bsp/recipes-bsp/u-boot/u-boot_2011.06.bbappend
@@ -0,0 +1,5 @@
+# Find "files" directory
+FILESEXTRAPATHS := "${THISDIR}/files"
+
+# Patch for removing autostart countdown
+SRC_URI_append_imx53qsb += "file://no_delay.patch"
diff --git a/meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config/vexpressa9/xorg.conf b/meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config/vexpressa9/xorg.conf
new file mode 100644
index 0000000..182fe46
--- /dev/null
+++ b/meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config/vexpressa9/xorg.conf
@@ -0,0 +1,26 @@
+
+Section "Device"
+ Identifier "Graphics Controller"
+ Driver "fbdev"
+EndSection
+
+Section "Monitor"
+ Identifier "Generic Monitor"
+ Option "DPMS"
+EndSection
+
+Section "Screen"
+ Identifier "Default Screen"
+ Device "Intel Graphics Driver"
+ Monitor "Generic Monitor"
+ DefaultDepth 16
+EndSection
+
+Section "ServerLayout"
+ Identifier "Default Layout"
+ Screen "Default Screen"
+EndSection
+
+Section "ServerFlags"
+ Option "DontZap" "0"
+EndSection
diff --git a/meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend b/meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend
new file mode 100644
index 0000000..dedce1f
--- /dev/null
+++ b/meta-ivi-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend
@@ -0,0 +1,4 @@
+# Append path for meta-ivi layer to include bsp xorg.conf
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+PRINC := "${@int(PRINC) + 1}"
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
new file mode 100644
index 0000000..1e05dd2
--- /dev/null
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
@@ -0,0 +1,6387 @@
+From 8c071e4a4be17b7bb01ab2a911c1697902dc2c35 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+Date: Wed, 20 Jun 2012 12:07:49 +0200
+Subject: [PATCH 1/1] net: bus: add the AF_BUS socket address family
+
+AF_BUS is a new socket address family that allows both unicast and
+multicast I on a local machine with total ordering for messages
+(every process on the same bus sees each message in the same order).
+
+A process can create buses to which other processes can connect and
+communicate with each other by sending messages. Processes' addresses are
+automatically assigned by the bus on connect and are unique. Messages can
+be sent either to process' unique address or to a bus multicast address.
+
+Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
+---
+ Documentation/networking/af_bus.txt | 558 ++++++++
+ drivers/connector/connector.c | 32 +
+ include/linux/bus.h | 34 +
+ include/linux/connector.h | 5 +-
+ include/linux/netfilter.h | 1 +
+ include/linux/security.h | 11 +
+ include/linux/socket.h | 5 +-
+ include/net/af_bus.h | 273 ++++
+ net/Kconfig | 1 +
+ net/Makefile | 1 +
+ net/bus/Kconfig | 15 +
+ net/bus/Makefile | 7 +
+ net/bus/af_bus.c | 2688 +++++++++++++++++++++++++++++++++++
+ net/bus/garbage.c | 322 +++++
+ net/core/scm.c | 3 +-
+ net/core/sock.c | 6 +-
+ net/netfilter/Kconfig | 2 +
+ net/netfilter/Makefile | 3 +
+ net/netfilter/nfdbus/Kconfig | 12 +
+ net/netfilter/nfdbus/Makefile | 6 +
+ net/netfilter/nfdbus/matchrule.c | 1132 +++++++++++++++
+ net/netfilter/nfdbus/matchrule.h | 82 ++
+ net/netfilter/nfdbus/message.c | 194 +++
+ net/netfilter/nfdbus/message.h | 71 +
+ net/netfilter/nfdbus/nfdbus.c | 456 ++++++
+ net/netfilter/nfdbus/nfdbus.h | 44 +
+ security/capability.c | 7 +
+ security/security.c | 7 +
+ security/selinux/hooks.c | 35 +
+ 29 files changed, 6007 insertions(+), 6 deletions(-)
+ create mode 100644 Documentation/networking/af_bus.txt
+ create mode 100644 include/linux/bus.h
+ create mode 100644 include/net/af_bus.h
+ create mode 100644 net/bus/Kconfig
+ create mode 100644 net/bus/Makefile
+ create mode 100644 net/bus/af_bus.c
+ create mode 100644 net/bus/garbage.c
+ create mode 100644 net/netfilter/nfdbus/Kconfig
+ create mode 100644 net/netfilter/nfdbus/Makefile
+ create mode 100644 net/netfilter/nfdbus/matchrule.c
+ create mode 100644 net/netfilter/nfdbus/matchrule.h
+ create mode 100644 net/netfilter/nfdbus/message.c
+ create mode 100644 net/netfilter/nfdbus/message.h
+ create mode 100644 net/netfilter/nfdbus/nfdbus.c
+ create mode 100644 net/netfilter/nfdbus/nfdbus.h
+
+diff --git a/Documentation/networking/af_bus.txt b/Documentation/networking/af_bus.txt
+new file mode 100644
+index 0000000..a0b078f
+--- /dev/null
++++ b/Documentation/networking/af_bus.txt
+@@ -0,0 +1,558 @@
++ The AF_BUS socket address family
++ ================================
++
++Introduction
++------------
++
++AF_BUS is a message oriented inter process communication system.
++
++The principle features are:
++
++ - Reliable datagram based communication (all sockets are of type
++ SOCK_SEQPACKET)
++
++ - Multicast message delivery (one to many, unicast as a subset)
++
++ - Strict ordering (messages are delivered to every client in the same order)
++
++ - Ability to pass file descriptors
++
++ - Ability to pass credentials
++
++The basic concept is to provide a virtual bus on which multiple
++processes can communicate and policy is imposed by a "bus master".
++
++A process can create buses to which other processes can connect and
++communicate with each other by sending messages. Processes' addresses
++are automatically assigned by the bus on connect and are
++unique. Messages can be sent either to a process' unique address or to
++a bus multicast addresses.
++
++Netfilter rules or Berkeley Packet Filter can be used to restrict the
++messages that each peer is allowed to receive. This is especially
++important when sending to multicast addresses.
++
++Besides messages, process can send and receive ancillary data (i.e.,
++SCM_RIGHTS for passing file descriptors or SCM_CREDENTIALS for passing
++Unix credentials). In the case of a multicast message all recipients
++of a message may obtain a copy a file descriptor or credentials.
++
++A bus is created by processes connecting on an AF_BUS socket. The
++"bus master" binds itself instead of connecting to the NULL address.
++
++The socket address is made up of a path component and a numeric
++component. The path component is either a pathname or an abstract
++socket similar to a unix socket. The numeric component is used to
++uniquely identify each connection to the bus. Thus the path identifies
++a specific bus and the numeric component the attachment to that bus.
++
++The process that calls bind(2) on the socket is the owner of the bus
++and is called the bus master. The master is a special client of the
++bus and has some responsibility for the bus' operation. The master is
++assigned a fixed address with all the bits zero (0x0000000000000000).
++
++Each process connected to an AF_BUS socket has one or more addresses
++within that bus. These addresses are 64-bit unsigned integers,
++interpreted by splitting the address into two parts: the most
++significant 16 bits are a prefix identifying the type of address, and
++the remaining 48 bits are the actual client address within that
++prefix, as shown in this figure:
++
++Bit: 0 15 16 63
++ +----------------+------------------------------------------------+
++ | Type prefix | Client address |
++ +----------------+------------------------------------------------+
++
++The prefix with all bits zero is reserved for use by the kernel, which
++automatically assigns one address from this prefix to each client on
++connection. The address in this prefix with all bits zero is always
++assigned to the bus master. Addresses on the prefix 0x0000 are unique
++and will never repeat for the lifetime of the bus master.
++
++A client may have multiple addresses. When data is sent to other
++clients, those clients will always see the sender address that is in
++the prefix 0x0000 address space when calling recvmsg(2) or
++recvfrom(2). Similarly, the prefix 0x0000 address is returned by calls
++to getsockname(2) and getpeername(2).
++
++For each prefix, the address where the least significant 48 bits are
++all 1 (i.e., 0xffffffffffff) is also reserved, and can be used to send
++multicast messages to all the peers on a prefix.
++
++The non-reserved addresses in each of the remaining prefixes are
++managed by the bus master, which may assign additional addresses to
++any other connected socket.
++
++Having different name-spaces has two advantages:
++
++ - Clients can have addresses on different mutually-exclusive
++ scopes. This permits sending multicast packets to only clients
++ that have addresses on a given prefix.
++
++ - The addressing scheme can be more flexible. The kernel will only
++ assign unique addresses on the all-bits-zero prefix (0x0000) and
++ allows the bus master process to assign additional addresses to
++ clients on other prefixes. By having different prefixes, the
++ kernel and bus master assignments will not collide.
++
++AF_BUS transport can support two network topologies. When a process
++first connects to the bus master, it can only communicate with the bus
++master. The process can't send and receive packets from other peers on
++the bus. So, from the client process point of view the network
++topology is point-to-point.
++
++The bus master can allow the connected peer to be part of the bus and
++start to communicate with other peers by setting a socket option with
++the setsockopt(2) system call using the accepted socket descriptor. At
++this point, the topology becomes a bus to the client process.
++
++Packets whose destination address is not assigned to any client are
++routed by default to the bus master (the client accepted socket
++descriptor).
++
++
++Semantics
++---------
++
++Bus features:
++
++ - Unicast and multicast addressing scheme.
++ - Ability to assign addresses from user-space with different prefixes.
++ - Automatic address assignment.
++ - Ordered packets delivery (FIFO, total ordering).
++ - File descriptor and credentials passing.
++ - Support for both point-to-point and bus network topologies.
++ - Bus control access managed from user-space.
++ - Netfilter hooks for packet sending, routing and receiving.
++
++A process (the "bus master") can create an AF_BUS bus with socket(2)
++and use bind(2) to assign an address to the bus. Then it can listen(2)
++on the created socket to start accepting incoming connections with
++accept(2).
++
++Processes can connect to the bus by creating a socket with socket(2)
++and using connect(2). The kernel will assign a unique address to each
++connection and messages can be sent and received by using BSD socket
++primitives.
++
++This uses the connect(2) semantic in a non-traditional way, with
++AF_BUS sockets, it's not possible to connect "my" socket to a specific
++peer socket whereas the traditional BSD sockets API usage, connect(2)
++either connects to stream sockets, or assigns a peer address to a
++datagram socket (so that send(2) can be used instead of sendto()).
++
++An AF_BUS socket address is represented as a combination of a bus
++address and a bus path name. Address are unique within a path. The
++unique bus address is further subdivided into a prefix and a client
++address. Thus the path identifies a specific bus and the numeric
++component the attachment to that bus.
++
++#define BUS_PATH_MAX 108
++
++/* Bus address */
++struct bus_addr {
++ uint64_t s_addr; /* 16-bit prefix + 48-bit client address */
++};
++
++/* Structure describing an AF_BUS socket address. */
++struct sockaddr_bus {
++ sa_family_t sbus_family; /* AF_BUS */
++ struct bus_addr sbus_addr; /* bus address */
++ char sbus_path[BUS_PATH_MAX]; /* pathname */
++};
++
++A process becomes a bus master for a given struct sockaddr_bus by
++calling bind(2) on an AF_BUS addresses. The argument must be { AF_BUS,
++0, path }.
++
++AF_BUS supports both abstract and non-abstract path names. Abstract
++names are distinguished by the fact that sbus_path[0] == '\0' and they
++don't represent file system paths while non-abstract paths are bound
++to a file system path name. (See the unix(7) man page for a discussion
++of abstract socket addresses in the AF_UNIX address family.)
++
++Then the process calls listen(2) to accept incoming connections. If
++that process calls getsockname(2), the returned address will be {
++AF_BUS, 0, path }.
++
++The conventional string form of the full address is path + ":" +
++prefix + "/" + client address. Prefix and client address are
++represented in hex.
++
++For example the address:
++
++struct sockaddr_bus addr;
++addr.sbus_family = AF_BUS;
++strcpy(addr.sbus_path, "/tmp/test");
++addr.sbus_addr.s_addr = 0x0002f00ddeadbeef;
++
++would be represented using the string /tmp/test:0002/f00ddeadbeef.
++
++If the bus_addr is 0, then both the prefix and client address may be
++omitted from the string form. To connect to a bus as a client it is
++sufficient to specify the path, since the listening address always has
++bus_addr == 0. it is not meanigful to specify 'bus_addr' as other than
++0 on connect()
++
++The AF_BUS implementation will automatically assign a unique address
++to each client but the bus master can assign additional addresses on a
++different prefix by means of the setsockopt(2) system call. For
++example:
++
++struct bus_addr addr;
++addr.s_addr = 0x0001deadfee1dead;
++ret = setsockopt(afd, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr));
++
++where afd is the accepted socket descriptor in the daemon. To show graphically:
++
++ L The AF_BUS listening socket }
++ / | \ }-- listener process
++ A1 A2 A3 The AF_BUS accepted sockets }
++ | | |
++ C1 C2 C3 The AF_BUS connected sockets }-- client processes
++
++So if setsockopt(A1, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr)) is
++called, C1 will get the new address.
++
++The inverse operation is BUS_DEL_ADDR, which the bus master can use to
++remove a client socket AF_BUS address:
++
++ret = setsockopt(afd, SOL_BUS, BUS_DEL_ADDR, &addr, sizeof(addr));
++
++Besides assigning additional addresses, the bus master has to allow a
++client process to communicate with other peers on the bus using a
++setsockopt(2):
++
++ret = setsockopt(afd, SOL_BUS, BUS_JOIN_BUS, NULL, 0);
++
++Clients are not meant to send messages to each other until the master
++tells them (in a protocol-specific way) that the BUS_JOIN_BUS
++setsockopt(2) call was made.
++
++If a client sends a message to a destination other than the bus
++master's all-zero address before joining the bus, a EHOSTUNREACH (No
++route to host) error is returned since the only host that exists in
++the point-to-point network before the client joins the bus are the
++client and the bus master.
++
++A EHOSTUNREACH is returned if a client that joined a bus tries to send
++a packet to a client from another bus. Cross-bus communication is not
++permited.
++
++When a process wants to send a unicast message to a peer, it fills a
++sockaddr structure and performs a socket operation (i.e., sendto(2))
++
++struct sockaddr_bus addr;
++char *msg = "Hello world";
++
++addr.sbus_family = AF_BUS;
++strcpy(addr.sbus_path, "/tmp/test");
++addr.sbus_addr.s_addr = 0x0001f00ddeadbeef;
++
++ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0,
++ (struct sockaddr*)&addr, sizeof(addr));
++
++The current implementation requires that the addr.sbus_path component
++match the one used to conenct() to the bus but in future this
++requirement will be removed.
++
++The kernel will first check that the socket is connected and that the
++bus path of the socket correspond with the destination, then it will
++extract the prefix and client address from the bus address using a
++fixed 16 -bit bitmask.
++
++prefix = bus address >> 48 & 0xffff
++client address = bus address & 0xffff
++
++If the client address is not all bits one, then the message is unicast
++and is delivered to the socket with that assigned address
++(0x0001f00ddeadbeef). Otherwise the message is multicast and is
++delivered to all the peers with this address prefix (0x0001 in this
++case).
++
++So, when a process wants to send a multicast message, it just has to
++fill the address structure with the address prefix + 0xffffffffffff:
++
++struct sockaddr_bus addr;
++char *msg = "Hello world";
++
++addr.bus_family = AF_BUS;
++strcpy(addr.sbus_path, "/tmp/test");
++addr.bus_addr = 0x0001ffffffffffff;
++
++ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0,
++ (struct sockaddr*)&addr, sizeof(addr));
++
++The kernel, will apply the binary and operation, learn that the
++address is 0xffffffffffff and send the message to all the peers on
++this prefix (0x0001).
++
++Socket transmit queued bytes are limited by a maximum send buffer size
++(sysctl_wmem_max) defined in the kernel and can be modified at runtime
++using the sysctl interface on /proc/sys/net/core/wmem_default. This
++parameter is global for all the sockets families in a Linux system.
++
++AF_BUS permits the definition of a per-bus maximum send buffer size
++using the BUS_SET_SENDBUF socket option. The bus master can call the
++setsockopt(2) system call using as a parameter the listening socket.
++The command sets a maximum write buffer that will be imposed on each
++new socket that connects to the bus:
++
++ret = setsockopt(serverfd, SOL_BUS, BUS_SET_SENDBUF, &sndbuf,
++sizeof(int));
++
++In the transmission path both Berkeley Packet Filters and Netfilter
++hooks are available, so they can be used to filter sending packets.
++
++
++Using this addressing scheme with D-Bus
++---------------------------------------
++
++As an example of a use case for AF_BUS, let's analyze how the D-Bus
++IPC system can be implemented on top of it.
++
++We define a new D-Bus address type "afbus".
++
++A D-Bus client may connect to an address of the form "afbus:path=X"
++where X is a string. This means that it connect()s to { AF_BUS, 0, X }.
++
++For example: afbus:path=/tmp/test connects to { AF_BUS, 0, /tmp/test }.
++
++A D-Bus daemon may listen on the address "afbus:", which means that it
++binds to { AF_BUS, 0, /tmp/test }. It will advertise an address of the
++form "afbus:path=/tmp/test" to clients, for instance via the
++--print-address option, or via dbus-launch setting the
++DBUS_SESSION_BUS_ADDRESS environment variable. For instance, "afbus:"
++is an appropriate default listening address for the session bus,
++resulting in dbus-launch setting the DBUS_SESSION_BUS_ADDRESS
++environment variable to something like
++"afbus:path=/tmp/test,guid=...".
++
++A D-Bus daemon may listen on the address "afbus:file=/some/file",
++which means that it will do as above, then write its path into the
++given well-known file. For instance,
++"afbus:file=/run/dbus/system_bus.afbus" is an appropriate listening
++address for the system bus. Only processes with suitable privileges to
++write to that file can impersonate the system bus.
++
++D-Bus clients wishing to connect to the well-known system bus should
++attempt to connect to afbus:file=/run/dbus/system_bus.afbus, falling
++back to unix:path=/var/run/dbus/system_bus_socket if that fails. On
++Linux systems, the well-known system bus daemon should attempt to
++listen on both of those addresses.
++
++The D-Bus daemon will serve as bus master as well since it will be the
++process that creates and listens on the AF_BUS socket.
++
++D-Bus clients will use the fixed bus master address (all zero bits) to
++send messages to the D-Bus daemon and the client's unique address to
++send messages to other D-Bus clients using the bus.
++
++When initially connected, D-Bus clients will only be able to
++communicate with the D-Bus daemon and will send authentication
++information (AUTH message and SCM_CREDENTIALS ancillary
++messages). Since the D-Bus daemon is also the bus master, it can allow
++D-Bus clients to join the bus and be able to send and receive D-Bus
++messages from other peers.
++
++On connection, the kernel will assign to each client an address in the
++prefix 0x0000. If a client attempts to send messages to clients other
++than the bus master, this is considered to be an error, and is
++prevented by the kernel.
++
++When the D-Bus daemon has authenticated a client and determined that
++it is authorized to be on this bus, it uses a setsockopt(2) call to
++tell the kernel that this client has permission to send messages. The
++D-Bus daemon then tells the client by sending the Hello() reply that
++it has made the setsockopt(2) call and that now is able to send
++messages to other peers on the bus.
++
++Well-known names are represented by addresses in the 0x0001, ... prefixes.
++
++Addresses in prefix 0x0000 must be mapped to D-Bus unique names in a
++way that can't collide with unique names allocated by the dbus-daemon
++for legacy clients.
++
++In order to be consistent with current D-Bus unique naming, the AF_BUS
++addresses can be mapped directly to D-Bus unique names, for example
++(0000/0000deadbeef to ":0.deadbeef"). Leading zeroes can be suppressed
++since the common case should be relatively small numbers (the kernel
++allocates client addresses sequentially, and machines could be
++rebooted occasionally).
++
++By having both AF_BUS and legacy D-Bus clients use the same address
++space, the D-Bus daemon can act as a proxy between clients and can be
++sure that D-Bus unique names will be unique for both AF_BUS and legacy
++clients.
++
++To act as a proxy between AF_BUS and legacy clients, each time the
++D-Bus daemon accepts a legacy connection (i.e., AF_UNIX), it will
++create an AF_BUS socket and establish a connection with itself. It
++will then associate this newly created connection with the legacy one.
++
++To explain it graphically:
++
++ L The AF_BUS listening socket }
++ / | \ }-- listener process
++ A1 A2 A3 The AF_BUS accepted sockets }
++ | | |
++ C1 C2 C3 The AF_BUS connected sockets, where:
++ | * C1 belongs to the listener process
++ | * C2 and C3 belongs to the client processes
++ |
++ L2--A4 The AF_UNIX listening and accepted sockets \
++ | in the listener process
++ C4 The AF_UNIX connected socket in the legacy client process
++
++
++where C2 and C3 are normal AF_BUS clients and C4 is a legacy
++client. The D-Bus daemon after accepting the connection using the
++legacy transport (A4), will create an AF_BUS socket pair (C1, A1)
++associated with the legacy client.
++
++Legacy clients will send messages to the D-Bus daemon using their
++legacy socket and the D-Bus daemon will extract the destination
++address, resolve to the corresponding AF_BUS address and use this to
++send the message to the right peer.
++
++Conversely, when an AF_BUS client sends a D-Bus message to a legacy
++client, it will use the AF_BUS address of the connection associated
++with that client. The D-Bus daemon will receive the message, modify
++the message's content to set SENDER headers based on the AF_BUS source
++address and use the legacy transport to send the D-Bus message to the
++legacy client.
++
++As a special case, the bus daemon's all-zeroes address maps to
++"org.freedesktop.DBus" and vice versa.
++
++When a D-Bus client receives an AF_BUS message from the bus master
++(0/0), it must use the SENDER header field in the D-Bus message, as
++for any other D-Bus transport, to determine whether the message is
++actually from the D-Bus daemon (the SENDER is "org.freedesktop.DBus"
++or missing), or from another client (the SENDER starts with ":"). It
++is valid for messages from another AF_BUS client to be received via
++the D-Bus daemon; if they are, the SENDER header field will always be
++set.
++
++Besides its unique name, D-Bus services can have well-known names such
++as org.gnome.Keyring or org.freedesktop.Telepathy. These well-known
++names can also be used as a D-Bus message destination
++address. Well-known names are not numeric and AF_BUS is not able to
++parse D-Bus messages.
++
++To solve this, the D-Bus daemon will assign an additional AF_BUS
++address to each D-Bus client that owns a well-known name. The mapping
++between well-known names and AF_BUS address is maintained by the D-Bus
++daemon on a persistent data structure.
++
++D-Bus client libraries will maintain a cache of these mappings so they
++can send messages to services with well-known names using their mapped
++AF_BUS address.
++
++If a client intending to send a D-Bus message to a given well-known
++name does not have that well-known name in its cache, it must send the
++AF_BUS message to the listener (0000/000000000000) instead.
++
++The listener must forward the D-Bus message to the owner of that
++well-known name, setting the SENDER header field if necessary. It may
++also send this AF_BUS-specific D-Bus signal to the sender, so that the
++sender can update its cache:
++
++ org.freedesktop.DBus.AF_BUS.Forwarded (STRING well_known_name,
++ UINT64 af_bus_client)
++
++ Emitted by the D-Bus daemon with sender "org.freedesktop.DBus"
++ and object path "/org/freedesktop/DBus" to indicate that
++ the well-known name well_known_name is represented by the
++ AF_BUS address { AF_BUS, af_bus_client, path } where
++ path is the path name used by this bus.
++
++ For instance, if the well-known name "org.gnome.Keyring"
++ is represented by AF_BUS address 0001/0000deadbeef,
++ the signal would have arguments ("org.gnome.Keyring",
++ 0x00010000deadbeef), corresponding to the AF_BUS
++ address { AF_BUS, 0x00010000deadbeef, /tmp/test }.
++
++If the D-Bus service for that well-known name is not active, then the
++D-Bus daemon will first do the service activation, assign an
++additional address to the recently activated service, store the
++well-known service to numeric address mapping on its persistent cache,
++and then send the AF_BUS.Forwarded signal back to the client.
++
++Once the mapping has been made, the AF_BUS address associated with a
++well-known name cannot be reused for the lifetime of the D-Bus daemon
++(which is the same as the lifetime of the socket).
++
++Nevertheless the AF_BUS address associated with a well-known name can
++change, for example if a service goes away and a new instance gets
++activated. This new instance can have a different AF_BUS address. The
++D-Bus daemon will maintain a list of the mappings that are currently
++valid so it can send the AF_BUS.
++
++Forwarded signal with the mapping information to the clients. Client
++libraries will maintain a fixed-size Last Recently Used (LRU) cache
++with previous mappings sent by the D-Bus daemon.
++
++If the clients overwrite a mapping due to the LRU replace policy and
++later want to send a D-Bus message to the overwritten well-known name,
++they will send the D-Bus message back to the D-Bus daemon and this
++will send the signal with the mapping information.
++
++If a service goes away or if the service AF_BUS address changed and
++the client still has the old AF_BUS address in its cache, it will send
++the D-Bus message to the old destination.
++
++Since packets whose destination AF_BUS addresses are not assigned to
++any process are routed by default to the bus master, the D-Bus daemon
++will receive these D-bus messages and send an AF_BUS.
++
++Forwarded signal back to the client with the new AF_BUS address so it
++can update its cache with the new mapping.
++
++For well-known names, the D-Bus daemon will use a different address
++prefix (0x0001) so it doesn't conflict with the D-Bus unique names
++address prefix (0x0000).
++
++Besides D-Bus method call messages which are unicast, D-Bus allows
++clients to send multicast messages (D-Bus signals). Clients can send
++signals messages using the bus unique name prefix multicast address
++(0x0001ffffffffffff).
++
++A netfilter hook is used to filter these multicast messages and only
++deliver to the correct peers based on match rules.
++
++
++D-Bus aware netfilter module
++----------------------------
++
++AF_BUS is designed to be a generic bus transport supporting both
++unicast and multicast communications.
++
++In order for D-Bus to operate efficiently, the transport method has to
++know the D-Bus message wire-protocol and D-Bus message structure. But
++adding this D-Bus specific knowledge to AF_BUS will break one of the
++fundamental design principles of any network protocol stack, namely
++layer-independence: layer n must not make any assumptions about the
++payload in layer n + 1.
++
++So, in order to have a clean protocol design but be able to allow the
++transport to analyze the D-Bus messages, netfilter hooks are used to
++do the filtering based on match rules.
++
++The kernel module has to maintain the match rules and the D-Bus daemon
++is responsible for managing this information. Every time an add match
++rule message is processed by the D-Bus daemon, this will update the
++netfilter module match rules set so the netfilter hook function can
++use that information to do the match rules based filtering.
++
++The D-Bus daemon and the netfilter module will use the generic netlink
++subsystem to do the kernel-to-user-space communication. Netlink is
++already used by most of the networking subsystem in Linux
++(iptables/netfilter, ip/routing, etc).
++
++We enforce a security scheme so only the bus master's user ID can
++update the netfilter module match rules set.
++
++The advantage of using the netfilter subsystem is that we decouple the
++mechanism from the policy. AF_BUS will only add a set of hook points
++and external modules will be used to enforce a given policy.
+diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
+index dde6a0f..a1f9364 100644
+--- a/drivers/connector/connector.c
++++ b/drivers/connector/connector.c
+@@ -118,6 +118,38 @@ nlmsg_failure:
+ EXPORT_SYMBOL_GPL(cn_netlink_send);
+
+ /*
++ * Send an unicast reply from a connector callback
++ *
++ */
++int cn_netlink_reply(struct cn_msg *msg, u32 pid, gfp_t gfp_mask)
++{
++ unsigned int size;
++ struct sk_buff *skb;
++ struct nlmsghdr *nlh;
++ struct cn_msg *data;
++ struct cn_dev *dev = &cdev;
++
++ size = NLMSG_SPACE(sizeof(*msg) + msg->len);
++
++ skb = alloc_skb(size, gfp_mask);
++ if (!skb)
++ return -ENOMEM;
++
++ nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh), 0);
++ if (nlh == NULL) {
++ kfree_skb(skb);
++ return -EMSGSIZE;
++ }
++
++ data = nlmsg_data(nlh);
++
++ memcpy(data, msg, sizeof(*data) + msg->len);
++
++ return netlink_unicast(dev->nls, skb, pid, 1);
++}
++EXPORT_SYMBOL_GPL(cn_netlink_reply);
++
++/*
+ * Callback helper - queues work and setup destructor for given data.
+ */
+ static int cn_call_callback(struct sk_buff *skb)
+diff --git a/include/linux/bus.h b/include/linux/bus.h
+new file mode 100644
+index 0000000..19cac36
+--- /dev/null
++++ b/include/linux/bus.h
+@@ -0,0 +1,34 @@
++#ifndef _LINUX_BUS_H
++#define _LINUX_BUS_H
++
++#include <linux/socket.h>
++
++/* 'protocol' to use in socket(AF_BUS, SOCK_SEQPACKET, protocol) */
++#define BUS_PROTO_NONE 0
++#define BUS_PROTO_DBUS 1
++#define BUS_PROTO_MAX 1
++
++#define BUS_PATH_MAX 108
++
++/**
++ * struct bus_addr - af_bus address
++ * @s_addr: an af_bus address (16-bit prefix + 48-bit client address)
++ */
++struct bus_addr {
++ u64 s_addr;
++};
++
++
++/**
++ * struct sockaddr_bus - af_bus socket address
++ * @sbus_family: the socket address family
++ * @sbus_addr: an af_bus address
++ * @sbus_path: a path name
++ */
++struct sockaddr_bus {
++ __kernel_sa_family_t sbus_family;
++ struct bus_addr sbus_addr;
++ char sbus_path[BUS_PATH_MAX];
++};
++
++#endif /* _LINUX_BUS_H */
+diff --git a/include/linux/connector.h b/include/linux/connector.h
+index 7638407..519d010 100644
+--- a/include/linux/connector.h
++++ b/include/linux/connector.h
+@@ -44,8 +44,10 @@
+ #define CN_VAL_DRBD 0x1
+ #define CN_KVP_IDX 0x9 /* HyperV KVP */
+ #define CN_KVP_VAL 0x1 /* queries from the kernel */
++#define CN_IDX_NFDBUS 0xA /* netfilter D-Bus */
++#define CN_VAL_NFDBUS 0x1
+
+-#define CN_NETLINK_USERS 10 /* Highest index + 1 */
++#define CN_NETLINK_USERS 11 /* Highest index + 1 */
+
+ /*
+ * Maximum connector's message size.
+@@ -125,6 +127,7 @@ int cn_add_callback(struct cb_id *id, const char *name,
+ void (*callback)(struct cn_msg *, struct netlink_skb_parms *));
+ void cn_del_callback(struct cb_id *);
+ int cn_netlink_send(struct cn_msg *, u32, gfp_t);
++int cn_netlink_reply(struct cn_msg *, u32, gfp_t);
+
+ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name,
+ struct cb_id *id,
+diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
+index 29734be..7cff0bd 100644
+--- a/include/linux/netfilter.h
++++ b/include/linux/netfilter.h
+@@ -67,6 +67,7 @@ enum {
+ NFPROTO_BRIDGE = 7,
+ NFPROTO_IPV6 = 10,
+ NFPROTO_DECNET = 12,
++ NFPROTO_BUS,
+ NFPROTO_NUMPROTO,
+ };
+
+diff --git a/include/linux/security.h b/include/linux/security.h
+index 673afbb..fa26c6d 100644
+--- a/include/linux/security.h
++++ b/include/linux/security.h
+@@ -1578,6 +1578,8 @@ struct security_operations {
+
+ #ifdef CONFIG_SECURITY_NETWORK
+ int (*unix_stream_connect) (struct sock *sock, struct sock *other, struct sock *newsk);
++ int (*bus_connect) (struct sock *sock, struct sock *other,
++ struct sock *newsk);
+ int (*unix_may_send) (struct socket *sock, struct socket *other);
+
+ int (*socket_create) (int family, int type, int protocol, int kern);
+@@ -2517,6 +2519,8 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32
+ #ifdef CONFIG_SECURITY_NETWORK
+
+ int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk);
++int security_bus_connect(struct sock *sock, struct sock *other,
++ struct sock *newsk);
+ int security_unix_may_send(struct socket *sock, struct socket *other);
+ int security_socket_create(int family, int type, int protocol, int kern);
+ int security_socket_post_create(struct socket *sock, int family,
+@@ -2564,6 +2568,13 @@ static inline int security_unix_stream_connect(struct sock *sock,
+ return 0;
+ }
+
++static inline int security_bus_connect(struct socket *sock,
++ struct sock *other,
++ struct sock *newsk)
++{
++ return 0;
++}
++
+ static inline int security_unix_may_send(struct socket *sock,
+ struct socket *other)
+ {
+diff --git a/include/linux/socket.h b/include/linux/socket.h
+index b84bbd4..59596d2 100644
+--- a/include/linux/socket.h
++++ b/include/linux/socket.h
+@@ -195,7 +195,8 @@ struct ucred {
+ #define AF_CAIF 37 /* CAIF sockets */
+ #define AF_ALG 38 /* Algorithm sockets */
+ #define AF_NFC 39 /* NFC sockets */
+-#define AF_MAX 40 /* For now.. */
++#define AF_BUS 40 /* BUS sockets */
++#define AF_MAX 41 /* For now.. */
+
+ /* Protocol families, same as address families. */
+ #define PF_UNSPEC AF_UNSPEC
+@@ -238,6 +239,7 @@ struct ucred {
+ #define PF_CAIF AF_CAIF
+ #define PF_ALG AF_ALG
+ #define PF_NFC AF_NFC
++#define PF_BUS AF_BUS
+ #define PF_MAX AF_MAX
+
+ /* Maximum queue length specifiable by listen. */
+@@ -312,6 +314,7 @@ struct ucred {
+ #define SOL_IUCV 277
+ #define SOL_CAIF 278
+ #define SOL_ALG 279
++#define SOL_BUS 280
+
+ /* IPX options */
+ #define IPX_TYPE 1
+diff --git a/include/net/af_bus.h b/include/net/af_bus.h
+new file mode 100644
+index 0000000..e63eb49
+--- /dev/null
++++ b/include/net/af_bus.h
+@@ -0,0 +1,273 @@
++/*
++ * Copyright (c) 2012, GENIVI Alliance
++ *
++ * Authors: Javier Martinez Canillas, <javier.martinez@collabora.co.uk>
++ * Alban Crequy, <alban.crequy@collabora.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Based on BSD Unix domain sockets (net/unix).
++ */
++
++#ifndef __LINUX_NET_AFBUS_H
++#define __LINUX_NET_AFBUS_H
++
++#include <linux/socket.h>
++#include <linux/bus.h>
++#include <linux/mutex.h>
++#include <net/sock.h>
++#include <net/tcp_states.h>
++
++extern void bus_inflight(struct file *fp);
++extern void bus_notinflight(struct file *fp);
++extern void bus_gc(void);
++extern void wait_for_bus_gc(void);
++extern struct sock *bus_get_socket(struct file *filp);
++extern struct sock *bus_peer_get(struct sock *);
++
++#define BUS_HASH_SIZE 256
++
++extern spinlock_t bus_address_lock;
++extern struct hlist_head bus_address_table[BUS_HASH_SIZE];
++
++#define BUS_MAX_QLEN 10
++#define BUS_MASTER_ADDR 0x0
++#define BUS_PREFIX_BITS 16
++#define BUS_CLIENT_BITS 48
++#define BUS_PREFIX_MASK 0xffff000000000000
++#define BUS_CLIENT_MASK 0x0000ffffffffffff
++
++/* AF_BUS socket options */
++#define BUS_ADD_ADDR 1
++#define BUS_JOIN_BUS 2
++#define BUS_DEL_ADDR 3
++#define BUS_SET_EAVESDROP 4
++#define BUS_UNSET_EAVESDROP 5
++#define BUS_SET_SENDBUF 6
++#define BUS_SET_MAXQLEN 7
++#define BUS_GET_QLENFULL 8
++
++/* Connection and socket states */
++enum {
++ BUS_ESTABLISHED = TCP_ESTABLISHED,
++ BUS_CLOSE = TCP_CLOSE,
++ BUS_LISTEN = TCP_LISTEN,
++ BUS_MAX_STATES
++};
++
++#define NF_BUS_SENDING 1
++
++extern unsigned int bus_tot_inflight;
++extern spinlock_t bus_table_lock;
++extern struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1];
++
++/**
++ * struct bus_address - an af_bus address associated with an af_bus sock
++ * @refcnt: address reference counter
++ * @len: address length
++ * @hash: address hash value
++ * @addr_node: member of struct bus_sock.addr_list
++ * @table_node: member of struct hlist_head bus_address_table[hash]
++ * @sock: the af_bus sock that owns this address
++ * @name: the socket address for this address
++ */
++struct bus_address {
++ atomic_t refcnt;
++ int len;
++ unsigned hash;
++ struct hlist_node addr_node;
++ struct hlist_node table_node;
++ struct sock *sock;
++ struct sockaddr_bus name[0];
++};
++
++/**
++ * struct bus_send_context - sending context for an socket buffer
++ * @sender_socket: the sender socket associated with this sk_buff
++ * @siocb: used to send ancillary data
++ * @timeo: sending timeout
++ * @max_level: file descriptor passing maximum recursion level
++ * @namelen: length of socket address name
++ * @hash: socket name hash value
++ * @other: destination sock
++ * @sender: sender socket address name
++ * @recipient: recipient socket address name
++ * @authenticated: flag whether the sock already joined the bus
++ * @bus_master_side: flag whether the sock is an accepted socket
++ * @to_master: flag whether the destination is the bus master
++ * @multicast: flag whether the destination is a multicast address
++ * @deliver: flag whether the skb has to be delivered
++ * @eavesdropper: flag whether the sock is allowed to eavesdrop
++ * @main_recipient: flag whether the sock is the main recipient
++ */
++struct bus_send_context {
++ struct socket *sender_socket;
++ struct sock_iocb *siocb;
++ long timeo;
++ int max_level;
++ int namelen;
++ unsigned hash;
++ struct sock *other;
++ struct sockaddr_bus *sender;
++ struct sockaddr_bus *recipient;
++ unsigned int authenticated:1;
++ unsigned int bus_master_side:1;
++ unsigned int to_master:1;
++ unsigned int multicast:1;
++ unsigned int deliver:1;
++ unsigned int eavesdropper:1;
++ unsigned int main_recipient:1;
++};
++
++/**
++ * struct bus_skb_parms - socket buffer parameters
++ * @pid: process id
++ * @cred: skb credentials
++ * @fp: passed file descriptors
++ * @secid: security id
++ * @sendctx: skb sending context
++ */
++struct bus_skb_parms {
++ struct pid *pid;
++ const struct cred *cred;
++ struct scm_fp_list *fp;
++#ifdef CONFIG_SECURITY_NETWORK
++ u32 secid;
++#endif
++ struct bus_send_context *sendctx;
++};
++
++#define BUSCB(skb) (*(struct bus_skb_parms *)&((skb)->cb))
++#define BUSSID(skb) (&BUSCB((skb)).secid)
++
++#define bus_state_lock(s) spin_lock(&bus_sk(s)->lock)
++#define bus_state_unlock(s) spin_unlock(&bus_sk(s)->lock)
++#define bus_state_lock_nested(s) \
++ spin_lock_nested(&bus_sk(s)->lock, \
++ SINGLE_DEPTH_NESTING)
++
++/**
++ * struct bus - a communication bus
++ * @master: the bus master sock
++ * @peers: list of struct bus_sock.bus_node allowed to join the bus
++ * @lock: protect peers concurrent access
++ * @send_lock: enforce atomic multicast delivery
++ * @kref: bus reference counter
++ * @addr_cnt: address number counter to assign prefix 0x0000 addresses
++ * @eavesdropper_cnt: eavesdroppers counter
++ */
++struct bus {
++ struct sock *master;
++ struct hlist_head peers;
++ spinlock_t lock;
++ spinlock_t send_lock;
++ struct kref kref;
++ atomic64_t addr_cnt;
++ atomic64_t eavesdropper_cnt;
++};
++
++/**
++ * struct bus_sock - an af_bus socket
++ * @sk: associated sock
++ * @addr: sock principal address
++ * @addr_list: list of struct bus_address.addr_node
++ * @path: sock path name
++ * @readlock: protect from concurrent reading
++ * @peer: peer sock
++ * @other: the listening sock
++ * @link: list of candidates for garbage collection
++ * @inflight: number of times the file descriptor is in flight
++ * @lock: protect the sock from concurrent access
++ * @gc_candidate: flag whether the is a candidate for gc
++ * @gc_maybe_cycle: flag whether could be a cyclic reference
++ * @recursion_level: file passing current recursion level
++ * @peer_wq: peer sock wait queue
++ * @bus: bus that this sock belongs to
++ * @bus_master: flag whether the sock is the bus master
++ * @bus_master_side: flag whether is an accepted socket
++ * @authenticated: flag whether the sock joined the bus
++ * @eavesdropper: flag whether the sock is allowed to eavesdrop
++ * @bus_node: member of struct bus.peers list of joined socks
++ */
++struct bus_sock {
++ /* WARNING: sk has to be the first member */
++ struct sock sk;
++ struct bus_address *addr;
++ struct hlist_head addr_list;
++ struct path path;
++ struct mutex readlock;
++ struct sock *peer;
++ struct sock *other;
++ struct list_head link;
++ atomic_long_t inflight;
++ spinlock_t lock;
++ unsigned int gc_candidate:1;
++ unsigned int gc_maybe_cycle:1;
++ unsigned char recursion_level;
++ struct socket_wq peer_wq;
++ struct bus *bus;
++ bool bus_master;
++ bool bus_master_side;
++ bool authenticated;
++ bool eavesdropper;
++ struct hlist_node bus_node;
++};
++#define bus_sk(__sk) ((struct bus_sock *)__sk)
++
++#define peer_wait peer_wq.wait
++
++/**
++ * bus_same_bus - Test if two socket address belongs to the same bus
++ * @sbusaddr1: socket address name
++ * @sbusaddr2: socket address name
++ */
++static inline bool bus_same_bus(struct sockaddr_bus *sbusaddr1,
++ struct sockaddr_bus *sbusaddr2)
++{
++ int offset;
++
++ if (sbusaddr1->sbus_path[0] != sbusaddr2->sbus_path[0])
++ return false;
++
++ /*
++ * abstract path names start with a null byte character,
++ * so they have to be compared starting at the second char.
++ */
++ offset = (sbusaddr1->sbus_path[0] == '\0');
++
++ return !strncmp(sbusaddr1->sbus_path + offset,
++ sbusaddr2->sbus_path + offset,
++ BUS_PATH_MAX);
++}
++
++static inline unsigned int bus_hash_fold(__wsum n)
++{
++ unsigned int hash = (__force unsigned int)n;
++ hash ^= hash>>16;
++ hash ^= hash>>8;
++ return hash&(BUS_HASH_SIZE-1);
++}
++
++static inline unsigned int bus_compute_hash(struct bus_addr addr)
++{
++ return bus_hash_fold(csum_partial((void *)&addr, sizeof(addr), 0));
++}
++
++long bus_inq_len(struct sock *sk);
++long bus_outq_len(struct sock *sk);
++
++#ifdef CONFIG_SYSCTL
++extern int bus_sysctl_register(struct net *net);
++extern void bus_sysctl_unregister(struct net *net);
++#else
++static inline int bus_sysctl_register(struct net *net) { return 0; }
++static inline void bus_sysctl_unregister(struct net *net) {}
++#endif
++
++bool bus_can_write(struct net *net, struct sockaddr_bus *addr, int len,
++ int protocol);
++
++#endif /* __LINUX_NET_AFBUS_H */
+diff --git a/net/Kconfig b/net/Kconfig
+index e07272d..c9774a1 100644
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -47,6 +47,7 @@ menu "Networking options"
+
+ source "net/packet/Kconfig"
+ source "net/unix/Kconfig"
++source "net/bus/Kconfig"
+ source "net/xfrm/Kconfig"
+ source "net/iucv/Kconfig"
+
+diff --git a/net/Makefile b/net/Makefile
+index ad432fa..3033018 100644
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/
+ obj-$(CONFIG_INET) += ipv4/
+ obj-$(CONFIG_XFRM) += xfrm/
+ obj-$(CONFIG_UNIX) += unix/
++obj-$(CONFIG_AF_BUS) += bus/
+ obj-$(CONFIG_NET) += ipv6/
+ obj-$(CONFIG_PACKET) += packet/
+ obj-$(CONFIG_NET_KEY) += key/
+diff --git a/net/bus/Kconfig b/net/bus/Kconfig
+new file mode 100644
+index 0000000..5f01410
+--- /dev/null
++++ b/net/bus/Kconfig
+@@ -0,0 +1,15 @@
++#
++# Bus Domain Sockets
++#
++
++config AF_BUS
++ tristate "Bus domain sockets (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ ---help---
++ If you say Y here, you will include support for Bus domain sockets.
++ These sockets are used to create communication buses for IPC.
++
++ To compile this driver as a module, choose M here: the module will be
++ called bus.
++
++ Say N unless you know what you are doing.
+diff --git a/net/bus/Makefile b/net/bus/Makefile
+new file mode 100644
+index 0000000..8c1fea2
+--- /dev/null
++++ b/net/bus/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the Linux bus domain socket layer.
++#
++
++obj-$(CONFIG_AF_BUS) += af-bus.o
++
++af-bus-y := af_bus.o garbage.o
+diff --git a/net/bus/af_bus.c b/net/bus/af_bus.c
+new file mode 100644
+index 0000000..5a00225
+--- /dev/null
++++ b/net/bus/af_bus.c
+@@ -0,0 +1,2688 @@
++/*
++ * Implementation of Bus domain sockets.
++ *
++ * Copyright (c) 2012, GENIVI Alliance
++ *
++ * Authors: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
++ * Alban Crequy <alban.crequy@collabora.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Based on BSD Unix domain sockets (net/unix).
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/stat.h>
++#include <linux/dcache.h>
++#include <linux/namei.h>
++#include <linux/socket.h>
++#include <linux/bus.h>
++#include <linux/fcntl.h>
++#include <linux/termios.h>
++#include <linux/sockios.h>
++#include <linux/net.h>
++#include <linux/in.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/net_namespace.h>
++#include <net/sock.h>
++#include <net/af_bus.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <net/scm.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/rtnetlink.h>
++#include <linux/mount.h>
++#include <net/checksum.h>
++#include <linux/security.h>
++
++struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1];
++EXPORT_SYMBOL_GPL(bus_socket_table);
++struct hlist_head bus_address_table[BUS_HASH_SIZE];
++EXPORT_SYMBOL_GPL(bus_address_table);
++DEFINE_SPINLOCK(bus_table_lock);
++DEFINE_SPINLOCK(bus_address_lock);
++EXPORT_SYMBOL_GPL(bus_address_lock);
++static atomic_long_t bus_nr_socks;
++
++#define bus_sockets_unbound (&bus_socket_table[BUS_HASH_SIZE])
++
++#define BUS_ABSTRACT(sk) (bus_sk(sk)->addr->hash != BUS_HASH_SIZE)
++
++#ifdef CONFIG_SECURITY_NETWORK
++static void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{
++ memcpy(BUSSID(skb), &scm->secid, sizeof(u32));
++}
++
++static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{
++ scm->secid = *BUSSID(skb);
++}
++#else
++static inline void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{ }
++
++static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
++{ }
++#endif /* CONFIG_SECURITY_NETWORK */
++
++/*
++ * SMP locking strategy:
++ * bus_socket_table hash table is protected with spinlock bus_table_lock
++ * bus_address_table hash table is protected with spinlock bus_address_lock
++ * each bus is protected by a separate spin lock.
++ * multicast atomic sending is protected by a separate spin lock.
++ * each socket state is protected by a separate spin lock.
++ * each socket address is protected by a separate spin lock.
++ *
++ * When holding more than one lock, use the following hierarchy:
++ * - bus_table_lock.
++ * - bus_address_lock.
++ * - socket lock.
++ * - bus lock.
++ * - bus send_lock.
++ * - sock address lock.
++ */
++
++#define bus_peer(sk) (bus_sk(sk)->peer)
++
++static inline int bus_our_peer(struct sock *sk, struct sock *osk)
++{
++ return bus_peer(osk) == sk;
++}
++
++static inline int bus_recvq_full(struct sock const *sk)
++{
++ return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog;
++}
++
++static inline u16 bus_addr_prefix(struct sockaddr_bus *busaddr)
++{
++ return (busaddr->sbus_addr.s_addr & BUS_PREFIX_MASK) >> BUS_CLIENT_BITS;
++}
++
++static inline u64 bus_addr_client(struct sockaddr_bus *sbusaddr)
++{
++ return sbusaddr->sbus_addr.s_addr & BUS_CLIENT_MASK;
++}
++
++static inline bool bus_mc_addr(struct sockaddr_bus *sbusaddr)
++{
++ return bus_addr_client(sbusaddr) == BUS_CLIENT_MASK;
++}
++
++struct sock *bus_peer_get(struct sock *s)
++{
++ struct sock *peer;
++
++ bus_state_lock(s);
++ peer = bus_peer(s);
++ if (peer)
++ sock_hold(peer);
++ bus_state_unlock(s);
++ return peer;
++}
++EXPORT_SYMBOL_GPL(bus_peer_get);
++
++static inline void bus_release_addr(struct bus_address *addr)
++{
++ if (atomic_dec_and_test(&addr->refcnt))
++ kfree(addr);
++}
++
++/*
++ * Check bus socket name:
++ * - should be not zero length.
++ * - if started by not zero, should be NULL terminated (FS object)
++ * - if started by zero, it is abstract name.
++ */
++
++static int bus_mkname(struct sockaddr_bus *sbusaddr, int len,
++ unsigned int *hashp)
++{
++ int offset = (sbusaddr->sbus_path[0] == '\0');
++
++ if (len <= sizeof(short) || len > sizeof(*sbusaddr))
++ return -EINVAL;
++ if (!sbusaddr || sbusaddr->sbus_family != AF_BUS)
++ return -EINVAL;
++
++ len = strnlen(sbusaddr->sbus_path + offset, BUS_PATH_MAX) + 1 +
++ sizeof(__kernel_sa_family_t) +
++ sizeof(struct bus_addr);
++
++ *hashp = bus_compute_hash(sbusaddr->sbus_addr);
++ return len;
++}
++
++static void __bus_remove_address(struct bus_address *addr)
++{
++ hlist_del(&addr->table_node);
++}
++
++static void __bus_insert_address(struct hlist_head *list,
++ struct bus_address *addr)
++{
++ hlist_add_head(&addr->table_node, list);
++}
++
++static inline void bus_remove_address(struct bus_address *addr)
++{
++ spin_lock(&bus_address_lock);
++ __bus_remove_address(addr);
++ spin_unlock(&bus_address_lock);
++}
++
++static inline void bus_insert_address(struct hlist_head *list,
++ struct bus_address *addr)
++{
++ spin_lock(&bus_address_lock);
++ __bus_insert_address(list, addr);
++ spin_unlock(&bus_address_lock);
++}
++
++static void __bus_remove_socket(struct sock *sk)
++{
++ sk_del_node_init(sk);
++}
++
++static void __bus_insert_socket(struct hlist_head *list, struct sock *sk)
++{
++ WARN_ON(!sk_unhashed(sk));
++ sk_add_node(sk, list);
++}
++
++static inline void bus_remove_socket(struct sock *sk)
++{
++ spin_lock(&bus_table_lock);
++ __bus_remove_socket(sk);
++ spin_unlock(&bus_table_lock);
++}
++
++static inline void bus_insert_socket(struct hlist_head *list, struct sock *sk)
++{
++ spin_lock(&bus_table_lock);
++ __bus_insert_socket(list, sk);
++ spin_unlock(&bus_table_lock);
++}
++
++static inline bool __bus_has_prefix(struct sock *sk, u16 prefix)
++{
++ struct bus_sock *u = bus_sk(sk);
++ struct bus_address *addr;
++ struct hlist_node *node;
++ bool ret = false;
++
++ hlist_for_each_entry(addr, node, &u->addr_list, addr_node) {
++ if (bus_addr_prefix(addr->name) == prefix)
++ ret = true;
++ }
++
++ return ret;
++}
++
++static inline bool bus_has_prefix(struct sock *sk, u16 prefix)
++{
++ bool ret;
++
++ bus_state_lock(sk);
++ ret = __bus_has_prefix(sk, prefix);
++ bus_state_unlock(sk);
++
++ return ret;
++}
++
++static inline bool __bus_eavesdropper(struct sock *sk, u16 condition)
++{
++ struct bus_sock *u = bus_sk(sk);
++
++ return u->eavesdropper;
++}
++
++static inline bool bus_eavesdropper(struct sock *sk, u16 condition)
++{
++ bool ret;
++
++ bus_state_lock(sk);
++ ret = __bus_eavesdropper(sk, condition);
++ bus_state_unlock(sk);
++
++ return ret;
++}
++
++static inline bool bus_has_prefix_eavesdropper(struct sock *sk, u16 prefix)
++{
++ bool ret;
++
++ bus_state_lock(sk);
++ ret = __bus_has_prefix(sk, prefix) || __bus_eavesdropper(sk, 0);
++ bus_state_unlock(sk);
++
++ return ret;
++}
++
++static inline struct bus_address *__bus_get_address(struct sock *sk,
++ struct bus_addr *sbus_addr)
++{
++ struct bus_sock *u = bus_sk(sk);
++ struct bus_address *addr = NULL;
++ struct hlist_node *node;
++
++ hlist_for_each_entry(addr, node, &u->addr_list, addr_node) {
++ if (addr->name->sbus_addr.s_addr == sbus_addr->s_addr)
++ return addr;
++ }
++
++ return NULL;
++}
++
++static inline struct bus_address *bus_get_address(struct sock *sk,
++ struct bus_addr *sbus_addr)
++{
++ struct bus_address *addr;
++
++ bus_state_lock(sk);
++ addr = __bus_get_address(sk, sbus_addr);
++ bus_state_unlock(sk);
++
++ return addr;
++}
++
++static struct sock *__bus_find_socket_byname(struct net *net,
++ struct sockaddr_bus *sbusname,
++ int len, unsigned int hash)
++{
++ struct sock *s;
++ struct hlist_node *node;
++
++ sk_for_each(s, node, &bus_socket_table[hash]) {
++ struct bus_sock *u = bus_sk(s);
++
++ if (!net_eq(sock_net(s), net))
++ continue;
++
++ if (u->addr->len == len &&
++ !memcmp(u->addr->name, sbusname, len))
++ return s;
++ }
++
++ return NULL;
++}
++
++static inline struct sock *bus_find_socket_byname(struct net *net,
++ struct sockaddr_bus *sbusname,
++ int len, unsigned int hash)
++{
++ struct sock *s;
++
++ spin_lock(&bus_table_lock);
++ s = __bus_find_socket_byname(net, sbusname, len, hash);
++ if (s)
++ sock_hold(s);
++ spin_unlock(&bus_table_lock);
++ return s;
++}
++
++static struct sock *__bus_find_socket_byaddress(struct net *net,
++ struct sockaddr_bus *sbusname,
++ int len, int protocol,
++ unsigned int hash)
++{
++ struct sock *s;
++ struct bus_address *addr;
++ struct hlist_node *node;
++ struct bus_sock *u;
++ int offset = (sbusname->sbus_path[0] == '\0');
++ int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX);
++
++ len = path_len + 1 + sizeof(__kernel_sa_family_t) +
++ sizeof(struct bus_addr);
++
++ hlist_for_each_entry(addr, node, &bus_address_table[hash],
++ table_node) {
++ s = addr->sock;
++ u = bus_sk(s);
++
++ if (s->sk_protocol != protocol)
++ continue;
++
++ if (!net_eq(sock_net(s), net))
++ continue;
++
++ if (addr->len == len &&
++ addr->name->sbus_family == sbusname->sbus_family &&
++ addr->name->sbus_addr.s_addr == sbusname->sbus_addr.s_addr
++ && bus_same_bus(addr->name, sbusname))
++ goto found;
++ }
++ s = NULL;
++found:
++ return s;
++}
++
++static inline struct sock *bus_find_socket_byaddress(struct net *net,
++ struct sockaddr_bus *name,
++ int len, int protocol,
++ unsigned int hash)
++{
++ struct sock *s;
++
++ spin_lock(&bus_address_lock);
++ s = __bus_find_socket_byaddress(net, name, len, protocol, hash);
++ if (s)
++ sock_hold(s);
++ spin_unlock(&bus_address_lock);
++ return s;
++}
++
++static inline int bus_writable(struct sock *sk)
++{
++ return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
++}
++
++static void bus_write_space(struct sock *sk)
++{
++ struct bus_sock *u = bus_sk(sk);
++ struct bus_sock *p;
++ struct hlist_node *node;
++ struct socket_wq *wq;
++
++ if (bus_writable(sk)) {
++ rcu_read_lock();
++ wq = rcu_dereference(sk->sk_wq);
++ if (wq_has_sleeper(wq))
++ wake_up_interruptible_sync_poll(&wq->wait,
++ POLLOUT | POLLWRNORM | POLLWRBAND);
++ sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
++ rcu_read_unlock();
++
++ if (u && u->bus) {
++ spin_lock(&u->bus->lock);
++ hlist_for_each_entry(p, node, &u->bus->peers,
++ bus_node) {
++ wake_up_interruptible_sync_poll(sk_sleep(&p->sk),
++ POLLOUT |
++ POLLWRNORM |
++ POLLWRBAND);
++ sk_wake_async(&p->sk, SOCK_WAKE_SPACE,
++ POLL_OUT);
++ }
++ spin_unlock(&u->bus->lock);
++ }
++ }
++}
++
++static void bus_bus_release(struct kref *kref)
++{
++ struct bus *bus;
++
++ bus = container_of(kref, struct bus, kref);
++
++ kfree(bus);
++}
++
++static void bus_sock_destructor(struct sock *sk)
++{
++ struct bus_sock *u = bus_sk(sk);
++
++ skb_queue_purge(&sk->sk_receive_queue);
++
++ WARN_ON(atomic_read(&sk->sk_wmem_alloc));
++ WARN_ON(!sk_unhashed(sk));
++ WARN_ON(sk->sk_socket);
++ if (!sock_flag(sk, SOCK_DEAD)) {
++ pr_info("Attempt to release alive bus socket: %p\n", sk);
++ return;
++ }
++
++ if (u->bus) {
++ kref_put(&u->bus->kref, bus_bus_release);
++ u->bus = NULL;
++ }
++
++ atomic_long_dec(&bus_nr_socks);
++ local_bh_disable();
++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
++ local_bh_enable();
++#ifdef BUS_REFCNT_DEBUG
++ pr_debug("BUS %p is destroyed, %ld are still alive.\n", sk,
++ atomic_long_read(&bus_nr_socks));
++#endif
++}
++
++static int bus_release_sock(struct sock *sk, int embrion)
++{
++ struct bus_sock *u = bus_sk(sk);
++ struct path path;
++ struct sock *skpair;
++ struct sk_buff *skb;
++ int state;
++ struct bus_address *addr;
++ struct hlist_node *node, *tmp;
++
++ bus_remove_socket(sk);
++
++ if (u->bus && u->authenticated &&
++ !u->bus_master && !u->bus_master_side) {
++ spin_lock(&u->bus->lock);
++ hlist_del(&u->bus_node);
++ if (u->eavesdropper)
++ atomic64_dec(&u->bus->eavesdropper_cnt);
++ spin_unlock(&u->bus->lock);
++ }
++
++ /* Clear state */
++ bus_state_lock(sk);
++ sock_orphan(sk);
++ sk->sk_shutdown = SHUTDOWN_MASK;
++ path = u->path;
++ u->path.dentry = NULL;
++ u->path.mnt = NULL;
++ state = sk->sk_state;
++ sk->sk_state = BUS_CLOSE;
++
++ if (u->bus_master)
++ u->bus->master = NULL;
++
++ if (u->bus_master_side) {
++ bus_release_addr(u->addr);
++ u->addr = NULL;
++ } else {
++ u->addr = NULL;
++
++ spin_lock(&bus_address_lock);
++ hlist_for_each_entry_safe(addr, node, tmp, &u->addr_list,
++ addr_node) {
++ hlist_del(&addr->addr_node);
++ __bus_remove_address(addr);
++ bus_release_addr(addr);
++ }
++ spin_unlock(&bus_address_lock);
++ }
++
++ bus_state_unlock(sk);
++
++ wake_up_interruptible_all(&u->peer_wait);
++
++ skpair = bus_peer(sk);
++
++ if (skpair != NULL) {
++ bus_state_lock(skpair);
++ /* No more writes */
++ skpair->sk_shutdown = SHUTDOWN_MASK;
++ if (!skb_queue_empty(&sk->sk_receive_queue) || embrion)
++ skpair->sk_err = ECONNRESET;
++ bus_state_unlock(skpair);
++ skpair->sk_state_change(skpair);
++ sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
++ sock_put(skpair); /* It may now die */
++ bus_peer(sk) = NULL;
++ }
++
++ /* Try to flush out this socket. Throw out buffers at least */
++
++ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
++ if (state == BUS_LISTEN)
++ bus_release_sock(skb->sk, 1);
++ /* passed fds are erased in the kfree_skb hook */
++ kfree_skb(skb);
++ }
++
++ if (path.dentry)
++ path_put(&path);
++
++ sock_put(sk);
++
++ /* ---- Socket is dead now and most probably destroyed ---- */
++
++ if (bus_tot_inflight)
++ bus_gc(); /* Garbage collect fds */
++
++ return 0;
++}
++
++static void init_peercred(struct sock *sk)
++{
++ put_pid(sk->sk_peer_pid);
++ if (sk->sk_peer_cred)
++ put_cred(sk->sk_peer_cred);
++ sk->sk_peer_pid = get_pid(task_tgid(current));
++ sk->sk_peer_cred = get_current_cred();
++}
++
++static void copy_peercred(struct sock *sk, struct sock *peersk)
++{
++ put_pid(sk->sk_peer_pid);
++ if (sk->sk_peer_cred)
++ put_cred(sk->sk_peer_cred);
++ sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
++ sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
++}
++
++static int bus_listen(struct socket *sock, int backlog)
++{
++ int err;
++ struct sock *sk = sock->sk;
++ struct bus_sock *u = bus_sk(sk);
++ struct pid *old_pid = NULL;
++ const struct cred *old_cred = NULL;
++
++ err = -EINVAL;
++ if (!u->addr || !u->bus_master)
++ goto out; /* Only listens on an bound an master socket */
++ bus_state_lock(sk);
++ if (sk->sk_state != BUS_CLOSE && sk->sk_state != BUS_LISTEN)
++ goto out_unlock;
++ if (backlog > sk->sk_max_ack_backlog)
++ wake_up_interruptible_all(&u->peer_wait);
++ sk->sk_max_ack_backlog = backlog;
++ sk->sk_state = BUS_LISTEN;
++ /* set credentials so connect can copy them */
++ init_peercred(sk);
++ err = 0;
++
++out_unlock:
++ bus_state_unlock(sk);
++ put_pid(old_pid);
++ if (old_cred)
++ put_cred(old_cred);
++out:
++ return err;
++}
++
++static int bus_release(struct socket *);
++static int bus_bind(struct socket *, struct sockaddr *, int);
++static int bus_connect(struct socket *, struct sockaddr *,
++ int addr_len, int flags);
++static int bus_accept(struct socket *, struct socket *, int);
++static int bus_getname(struct socket *, struct sockaddr *, int *, int);
++static unsigned int bus_poll(struct file *, struct socket *,
++ poll_table *);
++static int bus_ioctl(struct socket *, unsigned int, unsigned long);
++static int bus_shutdown(struct socket *, int);
++static int bus_setsockopt(struct socket *, int, int, char __user *,
++ unsigned int);
++static int bus_sendmsg(struct kiocb *, struct socket *,
++ struct msghdr *, size_t);
++static int bus_recvmsg(struct kiocb *, struct socket *,
++ struct msghdr *, size_t, int);
++
++static void bus_set_peek_off(struct sock *sk, int val)
++{
++ struct bus_sock *u = bus_sk(sk);
++
++ mutex_lock(&u->readlock);
++ sk->sk_peek_off = val;
++ mutex_unlock(&u->readlock);
++}
++
++static const struct proto_ops bus_seqpacket_ops = {
++ .family = PF_BUS,
++ .owner = THIS_MODULE,
++ .release = bus_release,
++ .bind = bus_bind,
++ .connect = bus_connect,
++ .socketpair = sock_no_socketpair,
++ .accept = bus_accept,
++ .getname = bus_getname,
++ .poll = bus_poll,
++ .ioctl = bus_ioctl,
++ .listen = bus_listen,
++ .shutdown = bus_shutdown,
++ .setsockopt = bus_setsockopt,
++ .getsockopt = sock_no_getsockopt,
++ .sendmsg = bus_sendmsg,
++ .recvmsg = bus_recvmsg,
++ .mmap = sock_no_mmap,
++ .sendpage = sock_no_sendpage,
++ .set_peek_off = bus_set_peek_off,
++};
++
++static struct proto bus_proto = {
++ .name = "BUS",
++ .owner = THIS_MODULE,
++ .obj_size = sizeof(struct bus_sock),
++};
++
++/*
++ * AF_BUS sockets do not interact with hardware, hence they
++ * dont trigger interrupts - so it's safe for them to have
++ * bh-unsafe locking for their sk_receive_queue.lock. Split off
++ * this special lock-class by reinitializing the spinlock key:
++ */
++static struct lock_class_key af_bus_sk_receive_queue_lock_key;
++
++static struct sock *bus_create1(struct net *net, struct socket *sock)
++{
++ struct sock *sk = NULL;
++ struct bus_sock *u;
++
++ atomic_long_inc(&bus_nr_socks);
++ if (atomic_long_read(&bus_nr_socks) > 2 * get_max_files())
++ goto out;
++
++ sk = sk_alloc(net, PF_BUS, GFP_KERNEL, &bus_proto);
++ if (!sk)
++ goto out;
++
++ sock_init_data(sock, sk);
++ lockdep_set_class(&sk->sk_receive_queue.lock,
++ &af_bus_sk_receive_queue_lock_key);
++
++ sk->sk_write_space = bus_write_space;
++ sk->sk_max_ack_backlog = BUS_MAX_QLEN;
++ sk->sk_destruct = bus_sock_destructor;
++ u = bus_sk(sk);
++ u->path.dentry = NULL;
++ u->path.mnt = NULL;
++ u->bus = NULL;
++ u->bus_master = false;
++ u->authenticated = false;
++ u->eavesdropper = false;
++ spin_lock_init(&u->lock);
++ atomic_long_set(&u->inflight, 0);
++ INIT_LIST_HEAD(&u->link);
++ INIT_HLIST_HEAD(&u->addr_list);
++ INIT_HLIST_NODE(&u->bus_node);
++ mutex_init(&u->readlock); /* single task reading lock */
++ init_waitqueue_head(&u->peer_wait);
++ bus_insert_socket(bus_sockets_unbound, sk);
++out:
++ if (sk == NULL)
++ atomic_long_dec(&bus_nr_socks);
++ else {
++ local_bh_disable();
++ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
++ local_bh_enable();
++ }
++ return sk;
++}
++
++static int bus_create(struct net *net, struct socket *sock, int protocol,
++ int kern)
++{
++ struct sock *sk;
++
++ if (protocol < BUS_PROTO_NONE || protocol > BUS_PROTO_DBUS)
++ return -EPROTONOSUPPORT;
++
++ if (protocol != BUS_PROTO_NONE)
++ request_module("net-pf-%d-proto-%d", PF_BUS, protocol);
++
++ sock->state = SS_UNCONNECTED;
++
++ if (sock->type == SOCK_SEQPACKET)
++ sock->ops = &bus_seqpacket_ops;
++ else
++ return -ESOCKTNOSUPPORT;
++
++ sk = bus_create1(net, sock);
++ if (!sk)
++ return -ENOMEM;
++
++ sk->sk_protocol = protocol;
++
++ return 0;
++}
++
++static int bus_release(struct socket *sock)
++{
++ struct sock *sk = sock->sk;
++
++ if (!sk)
++ return 0;
++
++ sock->sk = NULL;
++
++ return bus_release_sock(sk, 0);
++}
++
++static struct sock *bus_find_other(struct net *net,
++ struct sockaddr_bus *sbusname, int len,
++ int protocol, unsigned int hash, int *error)
++{
++ struct sock *u;
++ struct path path;
++ int err = 0;
++
++ if (sbusname->sbus_path[0]) {
++ struct inode *inode;
++ err = kern_path(sbusname->sbus_path, LOOKUP_FOLLOW, &path);
++ if (err)
++ goto fail;
++ inode = path.dentry->d_inode;
++ err = inode_permission(inode, MAY_WRITE);
++ if (err)
++ goto put_fail;
++
++ err = -ECONNREFUSED;
++ if (!S_ISSOCK(inode->i_mode))
++ goto put_fail;
++ u = bus_find_socket_byaddress(net, sbusname, len, protocol,
++ hash);
++ if (!u)
++ goto put_fail;
++
++ touch_atime(&path);
++ path_put(&path);
++
++ } else {
++ err = -ECONNREFUSED;
++ u = bus_find_socket_byaddress(net, sbusname, len, protocol, hash);
++ if (u) {
++ struct dentry *dentry;
++ dentry = bus_sk(u)->path.dentry;
++ if (dentry)
++ touch_atime(&bus_sk(u)->path);
++ } else
++ goto fail;
++ }
++
++ return u;
++
++put_fail:
++ path_put(&path);
++fail:
++ *error = err;
++ return NULL;
++}
++
++
++static int bus_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
++{
++ struct sock *sk = sock->sk;
++ struct net *net = sock_net(sk);
++ struct bus_sock *u = bus_sk(sk);
++ struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr;
++ char *sbus_path = sbusaddr->sbus_path;
++ struct dentry *dentry = NULL;
++ struct path path;
++ int err;
++ unsigned int hash;
++ struct bus_address *addr;
++ struct hlist_head *list;
++ struct bus *bus;
++
++ err = -EINVAL;
++ if (sbusaddr->sbus_family != AF_BUS)
++ goto out;
++
++ /* If the address is available, the socket is the bus master */
++ sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR;
++
++ err = bus_mkname(sbusaddr, addr_len, &hash);
++ if (err < 0)
++ goto out;
++ addr_len = err;
++
++ mutex_lock(&u->readlock);
++
++ err = -EINVAL;
++ if (u->addr)
++ goto out_up;
++
++ err = -ENOMEM;
++ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL);
++ if (!addr)
++ goto out_up;
++
++ memcpy(addr->name, sbusaddr, sizeof(struct sockaddr_bus));
++ addr->len = addr_len;
++ addr->hash = hash;
++ atomic_set(&addr->refcnt, 1);
++ addr->sock = sk;
++ INIT_HLIST_NODE(&addr->addr_node);
++ INIT_HLIST_NODE(&addr->table_node);
++
++ if (sbus_path[0]) {
++ umode_t mode;
++ err = 0;
++ /*
++ * Get the parent directory, calculate the hash for last
++ * component.
++ */
++ dentry = kern_path_create(AT_FDCWD, sbus_path, &path, 0);
++ err = PTR_ERR(dentry);
++ if (IS_ERR(dentry))
++ goto out_mknod_parent;
++
++ /*
++ * All right, let's create it.
++ */
++ mode = S_IFSOCK |
++ (SOCK_INODE(sock)->i_mode & ~current_umask());
++ err = mnt_want_write(path.mnt);
++ if (err)
++ goto out_mknod_dput;
++ err = security_path_mknod(&path, dentry, mode, 0);
++ if (err)
++ goto out_mknod_drop_write;
++ err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
++out_mknod_drop_write:
++ mnt_drop_write(path.mnt);
++ if (err)
++ goto out_mknod_dput;
++ mutex_unlock(&path.dentry->d_inode->i_mutex);
++ dput(path.dentry);
++ path.dentry = dentry;
++ }
++
++ err = -ENOMEM;
++ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
++ if (!bus)
++ goto out_unlock;
++
++ spin_lock(&bus_table_lock);
++
++ if (!sbus_path[0]) {
++ err = -EADDRINUSE;
++ if (__bus_find_socket_byname(net, sbusaddr, addr_len, hash)) {
++ bus_release_addr(addr);
++ kfree(bus);
++ goto out_unlock;
++ }
++
++ list = &bus_socket_table[addr->hash];
++ } else {
++ list = &bus_socket_table[dentry->d_inode->i_ino &
++ (BUS_HASH_SIZE-1)];
++ u->path = path;
++ }
++
++ kref_init(&bus->kref);
++ bus->master = sk;
++ INIT_HLIST_HEAD(&bus->peers);
++ spin_lock_init(&bus->lock);
++ spin_lock_init(&bus->send_lock);
++ atomic64_set(&bus->addr_cnt, 0);
++ atomic64_set(&bus->eavesdropper_cnt, 0);
++
++ hlist_add_head(&addr->addr_node, &u->addr_list);
++
++ err = 0;
++ __bus_remove_socket(sk);
++ u->addr = addr;
++ u->bus_master = true;
++ u->bus = bus;
++ __bus_insert_socket(list, sk);
++ bus_insert_address(&bus_address_table[addr->hash], addr);
++
++out_unlock:
++ spin_unlock(&bus_table_lock);
++out_up:
++ mutex_unlock(&u->readlock);
++out:
++ return err;
++
++out_mknod_dput:
++ dput(dentry);
++ mutex_unlock(&path.dentry->d_inode->i_mutex);
++ path_put(&path);
++out_mknod_parent:
++ if (err == -EEXIST)
++ err = -EADDRINUSE;
++ bus_release_addr(addr);
++ goto out_up;
++}
++
++static long bus_wait_for_peer(struct sock *other, long timeo)
++{
++ struct bus_sock *u = bus_sk(other);
++ int sched;
++ DEFINE_WAIT(wait);
++
++ prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE);
++
++ sched = !sock_flag(other, SOCK_DEAD) &&
++ !(other->sk_shutdown & RCV_SHUTDOWN) &&
++ bus_recvq_full(other);
++
++ bus_state_unlock(other);
++
++ if (sched)
++ timeo = schedule_timeout(timeo);
++
++ finish_wait(&u->peer_wait, &wait);
++ return timeo;
++}
++
++static int bus_connect(struct socket *sock, struct sockaddr *uaddr,
++ int addr_len, int flags)
++{
++ struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr;
++ struct sock *sk = sock->sk;
++ struct net *net = sock_net(sk);
++ struct bus_sock *u = bus_sk(sk), *newu, *otheru;
++ struct sock *newsk = NULL;
++ struct sock *other = NULL;
++ struct sk_buff *skb = NULL;
++ struct bus_address *addr = NULL;
++ unsigned int hash;
++ int st;
++ int err;
++ long timeo;
++
++ /* Only connections to the bus master is allowed */
++ sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR;
++
++ err = bus_mkname(sbusaddr, addr_len, &hash);
++ if (err < 0)
++ goto out;
++ addr_len = err;
++
++ err = -ENOMEM;
++ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL);
++ if (!addr)
++ goto out;
++
++ atomic_set(&addr->refcnt, 1);
++ INIT_HLIST_NODE(&addr->addr_node);
++ INIT_HLIST_NODE(&addr->table_node);
++
++ timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
++
++ /* First of all allocate resources.
++ If we will make it after state is locked,
++ we will have to recheck all again in any case.
++ */
++
++ err = -ENOMEM;
++
++ /* create new sock for complete connection */
++ newsk = bus_create1(sock_net(sk), NULL);
++ if (newsk == NULL)
++ goto out;
++
++ /* Allocate skb for sending to listening sock */
++ skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL);
++ if (skb == NULL)
++ goto out;
++
++restart:
++ /* Find listening sock. */
++ other = bus_find_other(net, sbusaddr, addr_len, sk->sk_protocol, hash,
++ &err);
++ if (!other)
++ goto out;
++
++ /* Latch state of peer */
++ bus_state_lock(other);
++
++ /* Apparently VFS overslept socket death. Retry. */
++ if (sock_flag(other, SOCK_DEAD)) {
++ bus_state_unlock(other);
++ sock_put(other);
++ goto restart;
++ }
++
++ err = -ECONNREFUSED;
++ if (other->sk_state != BUS_LISTEN)
++ goto out_unlock;
++ if (other->sk_shutdown & RCV_SHUTDOWN)
++ goto out_unlock;
++
++ if (bus_recvq_full(other)) {
++ err = -EAGAIN;
++ if (!timeo)
++ goto out_unlock;
++
++ timeo = bus_wait_for_peer(other, timeo);
++
++ err = sock_intr_errno(timeo);
++ if (signal_pending(current))
++ goto out;
++ sock_put(other);
++ goto restart;
++ }
++
++ /* Latch our state.
++
++ It is tricky place. We need to grab our state lock and cannot
++ drop lock on peer. It is dangerous because deadlock is
++ possible. Connect to self case and simultaneous
++ attempt to connect are eliminated by checking socket
++ state. other is BUS_LISTEN, if sk is BUS_LISTEN we
++ check this before attempt to grab lock.
++
++ Well, and we have to recheck the state after socket locked.
++ */
++ st = sk->sk_state;
++
++ switch (st) {
++ case BUS_CLOSE:
++ /* This is ok... continue with connect */
++ break;
++ case BUS_ESTABLISHED:
++ /* Socket is already connected */
++ err = -EISCONN;
++ goto out_unlock;
++ default:
++ err = -EINVAL;
++ goto out_unlock;
++ }
++
++ bus_state_lock_nested(sk);
++
++ if (sk->sk_state != st) {
++ bus_state_unlock(sk);
++ bus_state_unlock(other);
++ sock_put(other);
++ goto restart;
++ }
++
++ err = security_bus_connect(sk, other, newsk);
++ if (err) {
++ bus_state_unlock(sk);
++ goto out_unlock;
++ }
++
++ /* The way is open! Fastly set all the necessary fields... */
++
++ sock_hold(sk);
++ bus_peer(newsk) = sk;
++ newsk->sk_state = BUS_ESTABLISHED;
++ newsk->sk_type = sk->sk_type;
++ newsk->sk_protocol = sk->sk_protocol;
++ init_peercred(newsk);
++ newu = bus_sk(newsk);
++ RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
++ otheru = bus_sk(other);
++
++ /* copy address information from listening to new sock*/
++ if (otheru->addr && otheru->bus_master) {
++ atomic_inc(&otheru->addr->refcnt);
++ newu->addr = otheru->addr;
++ memcpy(addr->name, otheru->addr->name,
++ sizeof(struct sockaddr_bus));
++ addr->len = otheru->addr->len;
++ addr->name->sbus_addr.s_addr =
++ (atomic64_inc_return(&otheru->bus->addr_cnt) &
++ BUS_CLIENT_MASK);
++ addr->hash = bus_compute_hash(addr->name->sbus_addr);
++ addr->sock = sk;
++ u->addr = addr;
++ kref_get(&otheru->bus->kref);
++ u->bus = otheru->bus;
++ u->bus_master_side = false;
++ kref_get(&otheru->bus->kref);
++ newu->bus = otheru->bus;
++ newu->bus_master_side = true;
++ hlist_add_head(&addr->addr_node, &u->addr_list);
++
++ bus_insert_address(&bus_address_table[addr->hash], addr);
++ }
++ if (otheru->path.dentry) {
++ path_get(&otheru->path);
++ newu->path = otheru->path;
++ }
++
++ /* Set credentials */
++ copy_peercred(sk, other);
++ sk->sk_sndbuf = other->sk_sndbuf;
++ sk->sk_max_ack_backlog = other->sk_max_ack_backlog;
++ newsk->sk_sndbuf = other->sk_sndbuf;
++
++ sock->state = SS_CONNECTED;
++ sk->sk_state = BUS_ESTABLISHED;
++ sock_hold(newsk);
++
++ smp_mb__after_atomic_inc(); /* sock_hold() does an atomic_inc() */
++ bus_peer(sk) = newsk;
++
++ bus_state_unlock(sk);
++
++ /* take ten and and send info to listening sock */
++ spin_lock(&other->sk_receive_queue.lock);
++ __skb_queue_tail(&other->sk_receive_queue, skb);
++ spin_unlock(&other->sk_receive_queue.lock);
++ bus_state_unlock(other);
++ other->sk_data_ready(other, 0);
++ sock_put(other);
++ return 0;
++
++out_unlock:
++ if (other)
++ bus_state_unlock(other);
++
++out:
++ kfree_skb(skb);
++ if (addr)
++ bus_release_addr(addr);
++ if (newsk)
++ bus_release_sock(newsk, 0);
++ if (other)
++ sock_put(other);
++ return err;
++}
++
++static int bus_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++ struct sock *sk = sock->sk;
++ struct sock *tsk;
++ struct sk_buff *skb;
++ int err;
++
++ err = -EINVAL;
++ if (sk->sk_state != BUS_LISTEN)
++ goto out;
++
++ /* If socket state is BUS_LISTEN it cannot change (for now...),
++ * so that no locks are necessary.
++ */
++
++ skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
++ if (!skb) {
++ /* This means receive shutdown. */
++ if (err == 0)
++ err = -EINVAL;
++ goto out;
++ }
++
++ tsk = skb->sk;
++ skb_free_datagram(sk, skb);
++ wake_up_interruptible(&bus_sk(sk)->peer_wait);
++
++ /* attach accepted sock to socket */
++ bus_state_lock(tsk);
++ newsock->state = SS_CONNECTED;
++ sock_graft(tsk, newsock);
++ bus_state_unlock(tsk);
++ return 0;
++
++out:
++ return err;
++}
++
++
++static int bus_getname(struct socket *sock, struct sockaddr *uaddr,
++ int *uaddr_len, int peer)
++{
++ struct sock *sk = sock->sk;
++ struct bus_sock *u;
++ DECLARE_SOCKADDR(struct sockaddr_bus *, sbusaddr, uaddr);
++ int err = 0;
++
++ if (peer) {
++ sk = bus_peer_get(sk);
++
++ err = -ENOTCONN;
++ if (!sk)
++ goto out;
++ err = 0;
++ } else {
++ sock_hold(sk);
++ }
++
++ u = bus_sk(sk);
++
++ bus_state_lock(sk);
++ if (!u->addr) {
++ sbusaddr->sbus_family = AF_BUS;
++ sbusaddr->sbus_path[0] = 0;
++ *uaddr_len = sizeof(short);
++ } else {
++ struct bus_address *addr = u->addr;
++
++ *uaddr_len = sizeof(struct sockaddr_bus);
++ memcpy(sbusaddr, addr->name, *uaddr_len);
++ }
++ bus_state_unlock(sk);
++ sock_put(sk);
++out:
++ return err;
++}
++
++static void bus_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
++{
++ int i;
++
++ scm->fp = BUSCB(skb).fp;
++ BUSCB(skb).fp = NULL;
++
++ for (i = scm->fp->count-1; i >= 0; i--)
++ bus_notinflight(scm->fp->fp[i]);
++}
++
++static void bus_destruct_scm(struct sk_buff *skb)
++{
++ struct scm_cookie scm;
++ memset(&scm, 0, sizeof(scm));
++ scm.pid = BUSCB(skb).pid;
++ scm.cred = BUSCB(skb).cred;
++ if (BUSCB(skb).fp)
++ bus_detach_fds(&scm, skb);
++
++ scm_destroy(&scm);
++ if (skb->sk)
++ sock_wfree(skb);
++}
++
++#define MAX_RECURSION_LEVEL 4
++
++static int bus_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
++{
++ int i;
++ unsigned char max_level = 0;
++ int bus_sock_count = 0;
++
++ for (i = scm->fp->count - 1; i >= 0; i--) {
++ struct sock *sk = bus_get_socket(scm->fp->fp[i]);
++
++ if (sk) {
++ bus_sock_count++;
++ max_level = max(max_level,
++ bus_sk(sk)->recursion_level);
++ }
++ }
++ if (unlikely(max_level > MAX_RECURSION_LEVEL))
++ return -ETOOMANYREFS;
++
++ /*
++ * Need to duplicate file references for the sake of garbage
++ * collection. Otherwise a socket in the fps might become a
++ * candidate for GC while the skb is not yet queued.
++ */
++ BUSCB(skb).fp = scm_fp_dup(scm->fp);
++ if (!BUSCB(skb).fp)
++ return -ENOMEM;
++
++ if (bus_sock_count) {
++ for (i = scm->fp->count - 1; i >= 0; i--)
++ bus_inflight(scm->fp->fp[i]);
++ }
++ return max_level;
++}
++
++static int bus_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb,
++ bool send_fds)
++{
++ int err = 0;
++
++ BUSCB(skb).pid = get_pid(scm->pid);
++ if (scm->cred)
++ BUSCB(skb).cred = get_cred(scm->cred);
++ BUSCB(skb).fp = NULL;
++ if (scm->fp && send_fds)
++ err = bus_attach_fds(scm, skb);
++
++ skb->destructor = bus_destruct_scm;
++ return err;
++}
++
++/*
++ * Some apps rely on write() giving SCM_CREDENTIALS
++ * We include credentials if source or destination socket
++ * asserted SOCK_PASSCRED.
++ */
++static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
++ const struct sock *other)
++{
++ if (BUSCB(skb).cred)
++ return;
++ if (test_bit(SOCK_PASSCRED, &sock->flags) ||
++ !other->sk_socket ||
++ test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
++ BUSCB(skb).pid = get_pid(task_tgid(current));
++ BUSCB(skb).cred = get_current_cred();
++ }
++}
++
++/*
++ * Send AF_BUS data.
++ */
++
++static void bus_deliver_skb(struct sk_buff *skb)
++{
++ struct bus_send_context *sendctx = BUSCB(skb).sendctx;
++ struct socket *sock = sendctx->sender_socket;
++
++ if (sock_flag(sendctx->other, SOCK_RCVTSTAMP))
++ __net_timestamp(skb);
++ maybe_add_creds(skb, sock, sendctx->other);
++ skb_queue_tail(&sendctx->other->sk_receive_queue, skb);
++ if (sendctx->max_level > bus_sk(sendctx->other)->recursion_level)
++ bus_sk(sendctx->other)->recursion_level = sendctx->max_level;
++}
++
++/**
++ * bus_sendmsg_finish - delivery an skb to a destination
++ * @skb: sk_buff to deliver
++ *
++ * Delivers a packet to a destination. The skb control buffer has
++ * all the information about the destination contained on sending
++ * context. If the sending is unicast, then the skb is delivered
++ * and the receiver notified but if the sending is multicast, the
++ * skb is just marked as delivered and the actual delivery is made
++ * outside the function with the bus->send_lock held to ensure that
++ * the multicast sending is atomic.
++ */
++static int bus_sendmsg_finish(struct sk_buff *skb)
++{
++ int err;
++ struct bus_send_context *sendctx;
++ struct socket *sock;
++ struct sock *sk;
++ struct net *net;
++ size_t len = skb->len;
++
++ sendctx = BUSCB(skb).sendctx;
++ sock = sendctx->sender_socket;
++ sk = sock->sk;
++ net = sock_net(sk);
++
++restart:
++ if (!sendctx->other) {
++ err = -ECONNRESET;
++ if (sendctx->recipient == NULL)
++ goto out_free;
++
++ sendctx->other = bus_find_other(net, sendctx->recipient,
++ sendctx->namelen,
++ sk->sk_protocol,
++ sendctx->hash, &err);
++
++ if (sendctx->other == NULL ||
++ !bus_sk(sendctx->other)->authenticated) {
++
++ if (sendctx->other)
++ sock_put(sendctx->other);
++
++ if (!bus_sk(sk)->bus_master_side) {
++ err = -ENOTCONN;
++ sendctx->other = bus_peer_get(sk);
++ if (!sendctx->other)
++ goto out_free;
++ } else {
++ sendctx->other = sk;
++ sock_hold(sendctx->other);
++ }
++ }
++ }
++
++ if (sk_filter(sendctx->other, skb) < 0) {
++ /* Toss the packet but do not return any error to the sender */
++ err = len;
++ goto out_free;
++ }
++
++ bus_state_lock(sendctx->other);
++
++ if (sock_flag(sendctx->other, SOCK_DEAD)) {
++ /*
++ * Check with 1003.1g - what should
++ * datagram error
++ */
++ bus_state_unlock(sendctx->other);
++ sock_put(sendctx->other);
++
++ err = 0;
++ bus_state_lock(sk);
++ if (bus_peer(sk) == sendctx->other) {
++ bus_peer(sk) = NULL;
++ bus_state_unlock(sk);
++ sock_put(sendctx->other);
++ err = -ECONNREFUSED;
++ } else {
++ bus_state_unlock(sk);
++ }
++
++ sendctx->other = NULL;
++ if (err)
++ goto out_free;
++ goto restart;
++ }
++
++ err = -EPIPE;
++ if (sendctx->other->sk_shutdown & RCV_SHUTDOWN)
++ goto out_unlock;
++
++ if (bus_recvq_full(sendctx->other)) {
++ if (!sendctx->timeo) {
++ err = -EAGAIN;
++ goto out_unlock;
++ }
++
++ sendctx->timeo = bus_wait_for_peer(sendctx->other,
++ sendctx->timeo);
++
++ err = sock_intr_errno(sendctx->timeo);
++ if (signal_pending(current))
++ goto out_free;
++
++ goto restart;
++ }
++
++ if (!sendctx->multicast && !sendctx->eavesdropper) {
++ bus_deliver_skb(skb);
++ bus_state_unlock(sendctx->other);
++ sendctx->other->sk_data_ready(sendctx->other, 0);
++ sock_put(sendctx->other);
++ } else {
++ sendctx->deliver = 1;
++ bus_state_unlock(sendctx->other);
++ }
++
++ return len;
++
++out_unlock:
++ bus_state_unlock(sendctx->other);
++out_free:
++ kfree_skb(skb);
++ if (sendctx->other)
++ sock_put(sendctx->other);
++
++ return err;
++}
++
++/**
++ * bus_sendmsg_mcast - do a multicast sending
++ * @skb: sk_buff to deliver
++ *
++ * Send a packet to a multicast destination.
++ * The function is also called for unicast sending when eavesdropping
++ * is enabled. Since the unicast destination and the eavesdroppers
++ * have to receive the packet atomically.
++ */
++static int bus_sendmsg_mcast(struct sk_buff *skb)
++{
++ struct bus_send_context *sendctx;
++ struct bus_send_context *tmpctx;
++ struct socket *sock;
++ struct sock *sk;
++ struct net *net;
++ struct bus_sock *u, *s;
++ struct hlist_node *node;
++ u16 prefix = 0;
++ struct sk_buff **skb_set = NULL;
++ struct bus_send_context **sendctx_set = NULL;
++ int rcp_cnt, send_cnt;
++ int i;
++ int err;
++ int len = skb->len;
++ bool (*is_receiver) (struct sock *, u16);
++ bool main_rcp_found = false;
++
++ sendctx = BUSCB(skb).sendctx;
++ sendctx->deliver = 0;
++ sock = sendctx->sender_socket;
++ sk = sock->sk;
++ u = bus_sk(sk);
++ net = sock_net(sk);
++
++ if (sendctx->multicast) {
++ prefix = bus_addr_prefix(sendctx->recipient);
++ if (sendctx->eavesdropper)
++ is_receiver = &bus_has_prefix_eavesdropper;
++ else
++ is_receiver = &bus_has_prefix;
++ } else {
++ is_receiver = &bus_eavesdropper;
++
++ /*
++ * If the destination is not the peer accepted socket
++ * we have to get the correct destination.
++ */
++ if (!sendctx->to_master && sendctx->recipient) {
++ sendctx->other = bus_find_other(net, sendctx->recipient,
++ sendctx->namelen,
++ sk->sk_protocol,
++ sendctx->hash, &err);
++
++
++ if (sendctx->other == NULL ||
++ !bus_sk(sendctx->other)->authenticated) {
++
++ if (sendctx->other)
++ sock_put(sendctx->other);
++
++ if (sendctx->other == NULL) {
++ if (!bus_sk(sk)->bus_master_side) {
++ err = -ENOTCONN;
++ sendctx->other = bus_peer_get(sk);
++ if (!sendctx->other)
++ goto out;
++ } else {
++ sendctx->other = sk;
++ sock_hold(sendctx->other);
++ }
++ }
++ sendctx->to_master = 1;
++ }
++ }
++ }
++
++
++try_again:
++ rcp_cnt = 0;
++ main_rcp_found = false;
++
++ spin_lock(&u->bus->lock);
++
++ hlist_for_each_entry(s, node, &u->bus->peers, bus_node) {
++
++ if (!net_eq(sock_net(&s->sk), net))
++ continue;
++
++ if (is_receiver(&s->sk, prefix) ||
++ (!sendctx->multicast &&
++ !sendctx->to_master &&
++ &s->sk == sendctx->other))
++ rcp_cnt++;
++ }
++
++ spin_unlock(&u->bus->lock);
++
++ /*
++ * Memory can't be allocated while holding a spinlock so
++ * we have to release the lock, do the allocation for the
++ * array to store each destination peer sk_buff and grab
++ * the bus peer lock again. Peers could have joined the
++ * bus while we relesed the lock so we allocate 5 more
++ * recipients hoping that this will be enough to not having
++ * to try again in case only a few peers joined the bus.
++ */
++ rcp_cnt += 5;
++ skb_set = kzalloc(sizeof(struct sk_buff *) * rcp_cnt, GFP_KERNEL);
++
++ if (!skb_set) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ sendctx_set = kzalloc(sizeof(struct bus_send_context *) * rcp_cnt,
++ GFP_KERNEL);
++ if (!sendctx_set) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ for (i = 0; i < rcp_cnt; i++) {
++ skb_set[i] = skb_clone(skb, GFP_KERNEL);
++ if (!skb_set[i]) {
++ err = -ENOMEM;
++ goto out_free;
++ }
++ sendctx_set[i] = BUSCB(skb_set[i]).sendctx
++ = kmalloc(sizeof(*sendctx) * rcp_cnt, GFP_KERNEL);
++ if (!sendctx_set[i]) {
++ err = -ENOMEM;
++ goto out_free;
++ }
++ memcpy(sendctx_set[i], sendctx, sizeof(*sendctx));
++ err = bus_scm_to_skb(sendctx_set[i]->siocb->scm,
++ skb_set[i], true);
++ if (err < 0)
++ goto out_free;
++ bus_get_secdata(sendctx_set[i]->siocb->scm,
++ skb_set[i]);
++
++ sendctx_set[i]->other = NULL;
++ }
++
++ send_cnt = 0;
++
++ spin_lock(&u->bus->lock);
++
++ hlist_for_each_entry(s, node, &u->bus->peers, bus_node) {
++
++ if (!net_eq(sock_net(&s->sk), net))
++ continue;
++
++ if (send_cnt >= rcp_cnt) {
++ spin_unlock(&u->bus->lock);
++
++ for (i = 0; i < rcp_cnt; i++) {
++ sock_put(sendctx_set[i]->other);
++ kfree_skb(skb_set[i]);
++ kfree(sendctx_set[i]);
++ }
++ kfree(skb_set);
++ kfree(sendctx_set);
++ sendctx_set = NULL;
++ skb_set = NULL;
++ goto try_again;
++ }
++
++ if (is_receiver(&s->sk, prefix) ||
++ (!sendctx->multicast &&
++ !sendctx->to_master &&
++ &s->sk == sendctx->other)) {
++ skb_set_owner_w(skb_set[send_cnt], &s->sk);
++ tmpctx = BUSCB(skb_set[send_cnt]).sendctx;
++ sock_hold(&s->sk);
++ if (&s->sk == sendctx->other) {
++ tmpctx->main_recipient = 1;
++ main_rcp_found = true;
++ }
++ tmpctx->other = &s->sk;
++ tmpctx->recipient = s->addr->name;
++ tmpctx->eavesdropper = bus_eavesdropper(&s->sk, 0);
++
++ send_cnt++;
++ }
++ }
++
++ spin_unlock(&u->bus->lock);
++
++ /*
++ * Peers have left the bus so we have to free
++ * their pre-allocated bus_send_context and
++ * socket buffers.
++ */
++ if (send_cnt < rcp_cnt) {
++ for (i = send_cnt; i < rcp_cnt; i++) {
++ kfree_skb(skb_set[i]);
++ kfree(sendctx_set[i]);
++ }
++ rcp_cnt = send_cnt;
++ }
++
++ for (i = 0; i < send_cnt; i++) {
++ tmpctx = BUSCB(skb_set[i]).sendctx;
++ tmpctx->deliver = 0;
++ err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb_set[i],
++ NULL, NULL, bus_sendmsg_finish);
++ if (err == -EPERM)
++ sock_put(tmpctx->other);
++ }
++
++ /*
++ * If the send context is not multicast, the destination
++ * coud be either the peer accepted socket descriptor or
++ * a peer that is not an eavesdropper. If the peer is not
++ * the accepted socket descriptor and has been authenticated,
++ * it is a member of the bus peer list so it has already been
++ * marked for delivery.
++ * But if the destination is the accepted socket descriptor
++ * or is a non-authenticated peer it is not a member of the
++ * bus peer list so the packet has to be explicitly deliver
++ * to it.
++ */
++
++ if (!sendctx->multicast &&
++ (sendctx->to_master ||
++ (sendctx->bus_master_side && !main_rcp_found))) {
++ sendctx->main_recipient = 1;
++ err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL,
++ bus_sendmsg_finish);
++ if (err == -EPERM)
++ sock_put(sendctx->other);
++ }
++
++ spin_lock(&u->bus->send_lock);
++
++ for (i = 0; i < send_cnt; i++) {
++ tmpctx = sendctx_set[i];
++ if (tmpctx->deliver != 1)
++ continue;
++
++ bus_state_lock(tmpctx->other);
++ bus_deliver_skb(skb_set[i]);
++ bus_state_unlock(tmpctx->other);
++ }
++
++ if (!sendctx->multicast &&
++ sendctx->deliver == 1 &&
++ !bus_sk(sendctx->other)->eavesdropper) {
++ bus_state_lock(sendctx->other);
++ bus_deliver_skb(skb);
++ bus_state_unlock(sendctx->other);
++ }
++
++ spin_unlock(&u->bus->send_lock);
++
++ for (i = 0; i < send_cnt; i++) {
++ tmpctx = sendctx_set[i];
++ if (tmpctx->deliver != 1)
++ continue;
++
++ tmpctx->other->sk_data_ready(tmpctx->other, 0);
++ sock_put(tmpctx->other);
++ }
++
++ if (!sendctx->multicast &&
++ sendctx->deliver == 1 &&
++ !bus_sk(sendctx->other)->eavesdropper) {
++ sendctx->other->sk_data_ready(sendctx->other, 0);
++ sock_put(sendctx->other);
++ }
++
++ err = len;
++ goto out;
++
++out_free:
++ for (i = 0; i < rcp_cnt; i++) {
++ if (skb_set[i])
++ kfree_skb(skb_set[i]);
++ }
++
++out:
++ kfree(skb_set);
++ if (sendctx_set) {
++ for (i = 0; i < rcp_cnt; i++)
++ kfree(sendctx_set[i]);
++ kfree(sendctx_set);
++ }
++
++ if (sendctx->deliver == 0) {
++ if (!sendctx->to_master &&
++ !(sendctx->bus_master_side && !main_rcp_found))
++ kfree_skb(skb);
++ if (!sendctx->to_master &&
++ !(sendctx->bus_master_side && !main_rcp_found))
++ if (sendctx->other)
++ sock_put(sendctx->other);
++ }
++ scm_destroy(sendctx->siocb->scm);
++
++ return err;
++}
++
++static inline void bus_copy_path(struct sockaddr_bus *dest,
++ struct sockaddr_bus *src)
++{
++ int offset;
++
++ /*
++ * abstract path names start with a null byte character,
++ * so they have to be compared starting at the second char.
++ */
++ offset = (src->sbus_path[0] == '\0');
++
++ strncpy(dest->sbus_path + offset,
++ src->sbus_path + offset,
++ BUS_PATH_MAX);
++}
++
++/**
++ * bus_sendmsg - send an skb to a destination
++ * @kiocb: I/O control block info
++ * @sock: sender socket
++ * @msg: message header
++ * @len: message length
++ *
++ * Send an socket buffer to a destination. The destination could be
++ * either an unicast or a multicast address. In any case, a copy of
++ * the packet has to be send to all the sockets that are allowed to
++ * eavesdrop the communication bus.
++ *
++ * If the destination address is not associated with any socket, the
++ * packet is default routed to the bus master (the sender accepted
++ * socket).
++ *
++ * The af_bus sending path is hooked to the netfilter subsystem so
++ * netfilter hooks can filter or modify the packet before delivery.
++ */
++static int bus_sendmsg(struct kiocb *kiocb, struct socket *sock,
++ struct msghdr *msg, size_t len)
++{
++ struct sock *sk = sock->sk;
++ struct bus_sock *u = bus_sk(sk);
++ struct sockaddr_bus *sbusaddr = msg->msg_name;
++ int err;
++ struct sk_buff *skb;
++ struct scm_cookie tmp_scm;
++ bool to_master = false;
++ bool multicast = false;
++ struct bus_send_context sendctx;
++
++ err = sock_error(sk);
++ if (err)
++ return err;
++
++ if (sk->sk_state != BUS_ESTABLISHED)
++ return -ENOTCONN;
++
++ if (!msg->msg_namelen)
++ sbusaddr = NULL;
++
++ if (sbusaddr)
++ bus_copy_path(sbusaddr, u->addr->name);
++
++ if ((!sbusaddr && !u->bus_master_side) ||
++ (sbusaddr && sbusaddr->sbus_addr.s_addr == BUS_MASTER_ADDR))
++ to_master = true;
++ else if (sbusaddr && !u->bus_master_side && !u->authenticated)
++ return -EHOSTUNREACH;
++
++ sendctx.namelen = 0; /* fake GCC */
++ sendctx.siocb = kiocb_to_siocb(kiocb);
++ sendctx.other = NULL;
++
++ if (NULL == sendctx.siocb->scm)
++ sendctx.siocb->scm = &tmp_scm;
++ wait_for_bus_gc();
++ err = scm_send(sock, msg, sendctx.siocb->scm, false);
++ if (err < 0)
++ return err;
++
++ err = -EOPNOTSUPP;
++ if (msg->msg_flags&MSG_OOB)
++ goto out;
++
++ if (sbusaddr && !to_master) {
++ err = bus_mkname(sbusaddr, msg->msg_namelen, &sendctx.hash);
++ if (err < 0)
++ goto out;
++ sendctx.namelen = err;
++ multicast = bus_mc_addr(sbusaddr);
++ } else {
++ err = -ENOTCONN;
++ sendctx.other = bus_peer_get(sk);
++ if (!sendctx.other)
++ goto out;
++ }
++
++ err = -EMSGSIZE;
++ if (len > sk->sk_sndbuf - 32)
++ goto out;
++
++ sendctx.timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
++
++restart:
++ bus_state_lock(sk);
++ if (bus_recvq_full(sk)) {
++ err = -EAGAIN;
++ if (!sendctx.timeo) {
++ bus_state_unlock(sk);
++ goto out;
++ }
++
++ sendctx.timeo = bus_wait_for_peer(sk, sendctx.timeo);
++
++ err = sock_intr_errno(sendctx.timeo);
++ if (signal_pending(current))
++ goto out;
++
++ goto restart;
++ } else {
++ bus_state_unlock(sk);
++ }
++
++ skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err);
++ if (skb == NULL)
++ goto out;
++
++ err = bus_scm_to_skb(sendctx.siocb->scm, skb, true);
++ if (err < 0)
++ goto out_free;
++ sendctx.max_level = err + 1;
++ bus_get_secdata(sendctx.siocb->scm, skb);
++
++ skb_reset_transport_header(skb);
++ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
++ if (err)
++ goto out_free;
++
++ sendctx.sender_socket = sock;
++ if (u->bus_master_side && sendctx.other) {
++ /* if the bus master sent an unicast message to a peer, we
++ * need the address of that peer
++ */
++ sendctx.sender = bus_sk(sendctx.other)->addr->name;
++ } else {
++ sendctx.sender = u->addr->name;
++ }
++ sendctx.recipient = sbusaddr;
++ sendctx.authenticated = u->authenticated;
++ sendctx.bus_master_side = u->bus_master_side;
++ sendctx.to_master = to_master;
++ sendctx.multicast = multicast;
++ sendctx.eavesdropper = atomic64_read(&u->bus->eavesdropper_cnt) ? 1 : 0;
++ BUSCB(skb).sendctx = &sendctx;
++
++ if (sendctx.multicast || sendctx.eavesdropper) {
++ sendctx.main_recipient = 0;
++ err = bus_sendmsg_mcast(skb);
++ return sendctx.multicast ? len : err;
++ } else {
++ sendctx.main_recipient = 1;
++ len = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL,
++ bus_sendmsg_finish);
++
++ if (len == -EPERM) {
++ err = len;
++ goto out;
++ } else {
++ scm_destroy(sendctx.siocb->scm);
++ return len;
++ }
++ }
++
++out_free:
++ kfree_skb(skb);
++out:
++ if (sendctx.other)
++ sock_put(sendctx.other);
++ scm_destroy(sendctx.siocb->scm);
++ return err;
++}
++
++static void bus_copy_addr(struct msghdr *msg, struct sock *sk)
++{
++ struct bus_sock *u = bus_sk(sk);
++
++ msg->msg_namelen = 0;
++ if (u->addr) {
++ msg->msg_namelen = u->addr->len;
++ memcpy(msg->msg_name, u->addr->name,
++ sizeof(struct sockaddr_bus));
++ }
++}
++
++static int bus_recvmsg(struct kiocb *iocb, struct socket *sock,
++ struct msghdr *msg, size_t size, int flags)
++{
++ struct sock_iocb *siocb = kiocb_to_siocb(iocb);
++ struct scm_cookie tmp_scm;
++ struct sock *sk = sock->sk;
++ struct bus_sock *u = bus_sk(sk);
++ int noblock = flags & MSG_DONTWAIT;
++ struct sk_buff *skb;
++ int err;
++ int peeked, skip;
++
++ if (sk->sk_state != BUS_ESTABLISHED)
++ return -ENOTCONN;
++
++ err = -EOPNOTSUPP;
++ if (flags&MSG_OOB)
++ goto out;
++
++ msg->msg_namelen = 0;
++
++ err = mutex_lock_interruptible(&u->readlock);
++ if (err) {
++ err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
++ goto out;
++ }
++
++ skip = sk_peek_offset(sk, flags);
++
++ skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
++ if (!skb) {
++ bus_state_lock(sk);
++ /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
++ if (err == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN))
++ err = 0;
++ bus_state_unlock(sk);
++ goto out_unlock;
++ }
++
++ wake_up_interruptible_sync_poll(&u->peer_wait,
++ POLLOUT | POLLWRNORM | POLLWRBAND);
++
++ if (msg->msg_name)
++ bus_copy_addr(msg, skb->sk);
++
++ if (size > skb->len - skip)
++ size = skb->len - skip;
++ else if (size < skb->len - skip)
++ msg->msg_flags |= MSG_TRUNC;
++
++ err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size);
++ if (err)
++ goto out_free;
++
++ if (sock_flag(sk, SOCK_RCVTSTAMP))
++ __sock_recv_timestamp(msg, sk, skb);
++
++ if (!siocb->scm) {
++ siocb->scm = &tmp_scm;
++ memset(&tmp_scm, 0, sizeof(tmp_scm));
++ }
++ scm_set_cred(siocb->scm, BUSCB(skb).pid, BUSCB(skb).cred);
++ bus_set_secdata(siocb->scm, skb);
++
++ if (!(flags & MSG_PEEK)) {
++ if (BUSCB(skb).fp)
++ bus_detach_fds(siocb->scm, skb);
++
++ sk_peek_offset_bwd(sk, skb->len);
++ } else {
++ /* It is questionable: on PEEK we could:
++ - do not return fds - good, but too simple 8)
++ - return fds, and do not return them on read (old strategy,
++ apparently wrong)
++ - clone fds (I chose it for now, it is the most universal
++ solution)
++
++ POSIX 1003.1g does not actually define this clearly
++ at all. POSIX 1003.1g doesn't define a lot of things
++ clearly however!
++
++ */
++
++ sk_peek_offset_fwd(sk, size);
++
++ if (BUSCB(skb).fp)
++ siocb->scm->fp = scm_fp_dup(BUSCB(skb).fp);
++ }
++ err = (flags & MSG_TRUNC) ? skb->len - skip : size;
++
++ scm_recv(sock, msg, siocb->scm, flags);
++
++out_free:
++ skb_free_datagram(sk, skb);
++out_unlock:
++ mutex_unlock(&u->readlock);
++out:
++ return err;
++}
++
++static int bus_shutdown(struct socket *sock, int mode)
++{
++ struct sock *sk = sock->sk;
++ struct sock *other;
++
++ mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);
++
++ if (!mode)
++ return 0;
++
++ bus_state_lock(sk);
++ sk->sk_shutdown |= mode;
++ other = bus_peer(sk);
++ if (other)
++ sock_hold(other);
++ bus_state_unlock(sk);
++ sk->sk_state_change(sk);
++
++ if (other) {
++
++ int peer_mode = 0;
++
++ if (mode&RCV_SHUTDOWN)
++ peer_mode |= SEND_SHUTDOWN;
++ if (mode&SEND_SHUTDOWN)
++ peer_mode |= RCV_SHUTDOWN;
++ bus_state_lock(other);
++ other->sk_shutdown |= peer_mode;
++ bus_state_unlock(other);
++ other->sk_state_change(other);
++ if (peer_mode == SHUTDOWN_MASK)
++ sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP);
++ else if (peer_mode & RCV_SHUTDOWN)
++ sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN);
++ sock_put(other);
++ }
++
++ return 0;
++}
++
++static int bus_add_addr(struct sock *sk, struct bus_addr *sbus_addr)
++{
++ struct bus_address *addr;
++ struct sock *other;
++ struct bus_sock *u = bus_sk(sk);
++ struct net *net = sock_net(sk);
++ int ret = 0;
++
++ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL);
++ if (!addr) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ memcpy(addr->name, u->addr->name, sizeof(struct sockaddr_bus));
++ addr->len = u->addr->len;
++
++ addr->name->sbus_addr.s_addr = sbus_addr->s_addr;
++ addr->hash = bus_compute_hash(addr->name->sbus_addr);
++ other = bus_find_socket_byaddress(net, addr->name, addr->len,
++ sk->sk_protocol, addr->hash);
++
++ if (other) {
++ sock_put(other);
++ kfree(addr);
++ ret = -EADDRINUSE;
++ goto out;
++ }
++
++ atomic_set(&addr->refcnt, 1);
++ INIT_HLIST_NODE(&addr->addr_node);
++ INIT_HLIST_NODE(&addr->table_node);
++
++ addr->sock = sk;
++
++ hlist_add_head(&addr->addr_node, &u->addr_list);
++ bus_insert_address(&bus_address_table[addr->hash], addr);
++
++out:
++ sock_put(sk);
++
++ return ret;
++}
++
++static int bus_del_addr(struct sock *sk, struct bus_addr *sbus_addr)
++{
++ struct bus_address *addr;
++ int ret = 0;
++
++ bus_state_lock(sk);
++ addr = __bus_get_address(sk, sbus_addr);
++ if (!addr) {
++ ret = -EINVAL;
++ bus_state_unlock(sk);
++ goto out;
++ }
++ hlist_del(&addr->addr_node);
++ bus_state_unlock(sk);
++
++ bus_remove_address(addr);
++ bus_release_addr(addr);
++out:
++ sock_put(sk);
++
++ return ret;
++}
++
++static int bus_join_bus(struct sock *sk)
++{
++ struct sock *peer;
++ struct bus_sock *u = bus_sk(sk), *peeru;
++ int err = 0;
++
++ peer = bus_peer_get(sk);
++ if (!peer)
++ return -ENOTCONN;
++ peeru = bus_sk(peer);
++
++ if (!u->bus_master_side || peeru->authenticated) {
++ err = -EINVAL;
++ goto sock_put_out;
++ }
++
++ if (sk->sk_state != BUS_ESTABLISHED) {
++ err = -ENOTCONN;
++ goto sock_put_out;
++ }
++
++ if (peer->sk_shutdown != 0) {
++ err = -ENOTCONN;
++ goto sock_put_out;
++ }
++
++ bus_state_lock(peer);
++ peeru->authenticated = true;
++ bus_state_unlock(peer);
++
++ spin_lock(&u->bus->lock);
++ hlist_add_head(&peeru->bus_node, &u->bus->peers);
++ spin_unlock(&u->bus->lock);
++
++sock_put_out:
++ sock_put(peer);
++ return err;
++}
++
++static int __bus_set_eavesdrop(struct sock *sk, bool eavesdrop)
++{
++ struct sock *peer = bus_peer_get(sk);
++ struct bus_sock *u = bus_sk(sk), *peeru;
++ int err = 0;
++
++ if (!peer)
++ return -ENOTCONN;
++
++ if (sk->sk_state != BUS_ESTABLISHED) {
++ err = -ENOTCONN;
++ goto sock_put_out;
++ }
++
++ peeru = bus_sk(peer);
++
++ if (!u->bus_master_side || !peeru->authenticated) {
++ err = -EINVAL;
++ goto sock_put_out;
++ }
++
++ if (peer->sk_shutdown != 0) {
++ err = -ENOTCONN;
++ goto sock_put_out;
++ }
++
++ bus_state_lock(peeru);
++ if (peeru->eavesdropper != eavesdrop) {
++ peeru->eavesdropper = eavesdrop;
++ if (eavesdrop)
++ atomic64_inc(&u->bus->eavesdropper_cnt);
++ else
++ atomic64_dec(&u->bus->eavesdropper_cnt);
++ }
++ bus_state_unlock(peeru);
++
++sock_put_out:
++ sock_put(peer);
++ return err;
++}
++
++static int bus_set_eavesdrop(struct sock *sk)
++{
++ return __bus_set_eavesdrop(sk, true);
++}
++
++static int bus_unset_eavesdrop(struct sock *sk)
++{
++ return __bus_set_eavesdrop(sk, false);
++}
++
++static inline void sk_sendbuf_set(struct sock *sk, int sndbuf)
++{
++ bus_state_lock(sk);
++ sk->sk_sndbuf = sndbuf;
++ bus_state_unlock(sk);
++}
++
++static inline void sk_maxqlen_set(struct sock *sk, int qlen)
++{
++ bus_state_lock(sk);
++ sk->sk_max_ack_backlog = qlen;
++ bus_state_unlock(sk);
++}
++
++static int bus_get_qlenfull(struct sock *sk)
++{
++ struct sock *peer;
++ struct bus_sock *u = bus_sk(sk), *peeru;
++ int ret = 0;
++
++ peer = bus_peer_get(sk);
++ if (!peer)
++ return -ENOTCONN;
++
++ peeru = bus_sk(peer);
++
++ if (!u->bus_master_side || peeru->authenticated) {
++ ret = -EINVAL;
++ goto sock_put_out;
++ }
++
++ if (sk->sk_state != BUS_ESTABLISHED) {
++ ret = -ENOTCONN;
++ goto sock_put_out;
++ }
++
++ if (peer->sk_shutdown != 0) {
++ ret = -ENOTCONN;
++ goto sock_put_out;
++ }
++
++ ret = bus_recvq_full(peer);
++
++sock_put_out:
++ sock_put(peer);
++ return ret;
++}
++
++static int bus_setsockopt(struct socket *sock, int level, int optname,
++ char __user *optval, unsigned int optlen)
++{
++ struct bus_addr addr;
++ int res;
++ int val;
++
++ if (level != SOL_BUS)
++ return -ENOPROTOOPT;
++
++ switch (optname) {
++ case BUS_ADD_ADDR:
++ case BUS_DEL_ADDR:
++ if (optlen < sizeof(struct bus_addr))
++ return -EINVAL;
++
++ if (!bus_sk(sock->sk)->bus_master_side)
++ return -EINVAL;
++
++ if (copy_from_user(&addr, optval, sizeof(struct bus_addr)))
++ return -EFAULT;
++
++ if (optname == BUS_ADD_ADDR)
++ res = bus_add_addr(bus_peer_get(sock->sk), &addr);
++ else
++ res = bus_del_addr(bus_peer_get(sock->sk), &addr);
++ break;
++ case BUS_JOIN_BUS:
++ res = bus_join_bus(sock->sk);
++ break;
++ case BUS_SET_EAVESDROP:
++ res = bus_set_eavesdrop(sock->sk);
++ break;
++ case BUS_UNSET_EAVESDROP:
++ res = bus_unset_eavesdrop(sock->sk);
++ break;
++ case BUS_SET_SENDBUF:
++ case BUS_SET_MAXQLEN:
++ if (sock->sk->sk_state != BUS_LISTEN) {
++ res = -EINVAL;
++ } else {
++ res = -EFAULT;
++
++ if (copy_from_user(&val, optval, optlen))
++ break;
++
++ res = 0;
++
++ if (optname == BUS_SET_SENDBUF)
++ sk_sendbuf_set(sock->sk, val);
++ else
++ sk_maxqlen_set(sock->sk, val);
++ }
++ break;
++ case BUS_GET_QLENFULL:
++ res = bus_get_qlenfull(sock->sk);
++
++ if (copy_to_user(&res, optval, optlen)) {
++ res = -EFAULT;
++ break;
++ }
++ res = 0;
++ break;
++ default:
++ res = -EINVAL;
++ break;
++ }
++
++ return res;
++}
++
++long bus_inq_len(struct sock *sk)
++{
++ struct sk_buff *skb;
++ long amount = 0;
++
++ if (sk->sk_state == BUS_LISTEN)
++ return -EINVAL;
++
++ spin_lock(&sk->sk_receive_queue.lock);
++ skb_queue_walk(&sk->sk_receive_queue, skb)
++ amount += skb->len;
++ spin_unlock(&sk->sk_receive_queue.lock);
++
++ return amount;
++}
++EXPORT_SYMBOL_GPL(bus_inq_len);
++
++long bus_outq_len(struct sock *sk)
++{
++ return sk_wmem_alloc_get(sk);
++}
++EXPORT_SYMBOL_GPL(bus_outq_len);
++
++static int bus_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++ struct sock *sk = sock->sk;
++ long amount = 0;
++ int err;
++
++ switch (cmd) {
++ case SIOCOUTQ:
++ amount = bus_outq_len(sk);
++ err = put_user(amount, (int __user *)arg);
++ break;
++ case SIOCINQ:
++ amount = bus_inq_len(sk);
++ if (amount < 0)
++ err = amount;
++ else
++ err = put_user(amount, (int __user *)arg);
++ break;
++ default:
++ err = -ENOIOCTLCMD;
++ break;
++ }
++ return err;
++}
++
++static unsigned int bus_poll(struct file *file, struct socket *sock,
++ poll_table *wait)
++{
++ struct sock *sk = sock->sk, *other;
++ unsigned int mask, writable;
++ struct bus_sock *u = bus_sk(sk), *p;
++ struct hlist_node *node;
++
++ sock_poll_wait(file, sk_sleep(sk), wait);
++ mask = 0;
++
++ /* exceptional events? */
++ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
++ mask |= POLLERR;
++ if (sk->sk_shutdown & RCV_SHUTDOWN)
++ mask |= POLLRDHUP | POLLIN | POLLRDNORM;
++ if (sk->sk_shutdown == SHUTDOWN_MASK)
++ mask |= POLLHUP;
++
++ /* readable? */
++ if (!skb_queue_empty(&sk->sk_receive_queue))
++ mask |= POLLIN | POLLRDNORM;
++
++ /* Connection-based need to check for termination and startup */
++ if (sk->sk_state == BUS_CLOSE)
++ mask |= POLLHUP;
++
++ /* No write status requested, avoid expensive OUT tests. */
++ if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT)))
++ return mask;
++
++ writable = bus_writable(sk);
++ other = bus_peer_get(sk);
++ if (other) {
++ if (bus_recvq_full(other))
++ writable = 0;
++ sock_put(other);
++ }
++
++ /*
++ * If the socket has already joined the bus we have to check
++ * that each peer receiver queue on the bus is not full.
++ */
++ if (!u->bus_master_side && u->authenticated) {
++ spin_lock(&u->bus->lock);
++ hlist_for_each_entry(p, node, &u->bus->peers, bus_node) {
++ if (bus_recvq_full(&p->sk)) {
++ writable = 0;
++ break;
++ }
++ }
++ spin_unlock(&u->bus->lock);
++ }
++
++ if (writable)
++ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
++ else
++ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
++
++ return mask;
++}
++
++#ifdef CONFIG_PROC_FS
++static struct sock *first_bus_socket(int *i)
++{
++ for (*i = 0; *i <= BUS_HASH_SIZE; (*i)++) {
++ if (!hlist_empty(&bus_socket_table[*i]))
++ return __sk_head(&bus_socket_table[*i]);
++ }
++ return NULL;
++}
++
++static struct sock *next_bus_socket(int *i, struct sock *s)
++{
++ struct sock *next = sk_next(s);
++ /* More in this chain? */
++ if (next)
++ return next;
++ /* Look for next non-empty chain. */
++ for ((*i)++; *i <= BUS_HASH_SIZE; (*i)++) {
++ if (!hlist_empty(&bus_socket_table[*i]))
++ return __sk_head(&bus_socket_table[*i]);
++ }
++ return NULL;
++}
++
++struct bus_iter_state {
++ struct seq_net_private p;
++ int i;
++};
++
++static struct sock *bus_seq_idx(struct seq_file *seq, loff_t pos)
++{
++ struct bus_iter_state *iter = seq->private;
++ loff_t off = 0;
++ struct sock *s;
++
++ for (s = first_bus_socket(&iter->i); s;
++ s = next_bus_socket(&iter->i, s)) {
++ if (sock_net(s) != seq_file_net(seq))
++ continue;
++ if (off == pos)
++ return s;
++ ++off;
++ }
++ return NULL;
++}
++
++static void *bus_seq_start(struct seq_file *seq, loff_t *pos)
++ __acquires(bus_table_lock)
++{
++ spin_lock(&bus_table_lock);
++ return *pos ? bus_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN;
++}
++
++static void *bus_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++{
++ struct bus_iter_state *iter = seq->private;
++ struct sock *sk = v;
++ ++*pos;
++
++ if (v == SEQ_START_TOKEN)
++ sk = first_bus_socket(&iter->i);
++ else
++ sk = next_bus_socket(&iter->i, sk);
++ while (sk && (sock_net(sk) != seq_file_net(seq)))
++ sk = next_bus_socket(&iter->i, sk);
++ return sk;
++}
++
++static void bus_seq_stop(struct seq_file *seq, void *v)
++ __releases(bus_table_lock)
++{
++ spin_unlock(&bus_table_lock);
++}
++
++static int bus_seq_show(struct seq_file *seq, void *v)
++{
++
++ if (v == SEQ_START_TOKEN)
++ seq_puts(seq, "Num RefCount Protocol Flags Type St " \
++ "Inode Path\n");
++ else {
++ struct sock *s = v;
++ struct bus_sock *u = bus_sk(s);
++ bus_state_lock(s);
++
++ seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu",
++ s,
++ atomic_read(&s->sk_refcnt),
++ 0,
++ s->sk_state == BUS_LISTEN ? __SO_ACCEPTCON : 0,
++ s->sk_type,
++ s->sk_socket ?
++ (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) :
++ (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),
++ sock_i_ino(s));
++
++ if (u->addr) {
++ int i, len;
++ seq_putc(seq, ' ');
++
++ i = 0;
++ len = u->addr->len - sizeof(short);
++ if (!BUS_ABSTRACT(s))
++ len--;
++ else {
++ seq_putc(seq, '@');
++ i++;
++ }
++ for ( ; i < len; i++)
++ seq_putc(seq, u->addr->name->sbus_path[i]);
++ }
++ bus_state_unlock(s);
++ seq_putc(seq, '\n');
++ }
++
++ return 0;
++}
++
++static const struct seq_operations bus_seq_ops = {
++ .start = bus_seq_start,
++ .next = bus_seq_next,
++ .stop = bus_seq_stop,
++ .show = bus_seq_show,
++};
++
++static int bus_seq_open(struct inode *inode, struct file *file)
++{
++ return seq_open_net(inode, file, &bus_seq_ops,
++ sizeof(struct bus_iter_state));
++}
++
++static const struct file_operations bus_seq_fops = {
++ .owner = THIS_MODULE,
++ .open = bus_seq_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release_net,
++};
++
++#endif
++
++static const struct net_proto_family bus_family_ops = {
++ .family = PF_BUS,
++ .create = bus_create,
++ .owner = THIS_MODULE,
++};
++
++static int __init af_bus_init(void)
++{
++ int rc = -1;
++ struct sk_buff *dummy_skb;
++
++ BUILD_BUG_ON(sizeof(struct bus_skb_parms) > sizeof(dummy_skb->cb));
++
++ rc = proto_register(&bus_proto, 1);
++ if (rc != 0) {
++ pr_crit("%s: Cannot create bus_sock SLAB cache!\n", __func__);
++ return rc;
++ }
++
++ sock_register(&bus_family_ops);
++ return rc;
++}
++
++static void __exit af_bus_exit(void)
++{
++ sock_unregister(PF_BUS);
++ proto_unregister(&bus_proto);
++}
++
++module_init(af_bus_init);
++module_exit(af_bus_exit);
++
++MODULE_AUTHOR("Alban Crequy, Javier Martinez Canillas");
++MODULE_DESCRIPTION("Linux Bus domain sockets");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_NETPROTO(PF_BUS);
+diff --git a/net/bus/garbage.c b/net/bus/garbage.c
+new file mode 100644
+index 0000000..2435f38
+--- /dev/null
++++ b/net/bus/garbage.c
+@@ -0,0 +1,322 @@
++/*
++ * Garbage Collector For AF_BUS sockets
++ *
++ * Based on Garbage Collector For AF_UNIX sockets (net/unix/garbage.c).
++ */
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/socket.h>
++#include <linux/un.h>
++#include <linux/net.h>
++#include <linux/fs.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/file.h>
++#include <linux/proc_fs.h>
++#include <linux/mutex.h>
++#include <linux/wait.h>
++
++#include <net/sock.h>
++#include <net/af_bus.h>
++#include <net/scm.h>
++#include <net/tcp_states.h>
++
++/* Internal data structures and random procedures: */
++
++static LIST_HEAD(gc_inflight_list);
++static LIST_HEAD(gc_candidates);
++static DEFINE_SPINLOCK(bus_gc_lock);
++static DECLARE_WAIT_QUEUE_HEAD(bus_gc_wait);
++
++unsigned int bus_tot_inflight;
++
++
++struct sock *bus_get_socket(struct file *filp)
++{
++ struct sock *u_sock = NULL;
++ struct inode *inode = filp->f_path.dentry->d_inode;
++
++ /*
++ * Socket ?
++ */
++ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
++ struct socket *sock = SOCKET_I(inode);
++ struct sock *s = sock->sk;
++
++ /*
++ * PF_BUS ?
++ */
++ if (s && sock->ops && sock->ops->family == PF_BUS)
++ u_sock = s;
++ }
++ return u_sock;
++}
++
++/*
++ * Keep the number of times in flight count for the file
++ * descriptor if it is for an AF_BUS socket.
++ */
++
++void bus_inflight(struct file *fp)
++{
++ struct sock *s = bus_get_socket(fp);
++ if (s) {
++ struct bus_sock *u = bus_sk(s);
++ spin_lock(&bus_gc_lock);
++ if (atomic_long_inc_return(&u->inflight) == 1) {
++ BUG_ON(!list_empty(&u->link));
++ list_add_tail(&u->link, &gc_inflight_list);
++ } else {
++ BUG_ON(list_empty(&u->link));
++ }
++ bus_tot_inflight++;
++ spin_unlock(&bus_gc_lock);
++ }
++}
++
++void bus_notinflight(struct file *fp)
++{
++ struct sock *s = bus_get_socket(fp);
++ if (s) {
++ struct bus_sock *u = bus_sk(s);
++ spin_lock(&bus_gc_lock);
++ BUG_ON(list_empty(&u->link));
++ if (atomic_long_dec_and_test(&u->inflight))
++ list_del_init(&u->link);
++ bus_tot_inflight--;
++ spin_unlock(&bus_gc_lock);
++ }
++}
++
++static void scan_inflight(struct sock *x, void (*func)(struct bus_sock *),
++ struct sk_buff_head *hitlist)
++{
++ struct sk_buff *skb;
++ struct sk_buff *next;
++
++ spin_lock(&x->sk_receive_queue.lock);
++ skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
++ /*
++ * Do we have file descriptors ?
++ */
++ if (BUSCB(skb).fp) {
++ bool hit = false;
++ /*
++ * Process the descriptors of this socket
++ */
++ int nfd = BUSCB(skb).fp->count;
++ struct file **fp = BUSCB(skb).fp->fp;
++ while (nfd--) {
++ /*
++ * Get the socket the fd matches
++ * if it indeed does so
++ */
++ struct sock *sk = bus_get_socket(*fp++);
++ if (sk) {
++ struct bus_sock *u = bus_sk(sk);
++
++ /*
++ * Ignore non-candidates, they could
++ * have been added to the queues after
++ * starting the garbage collection
++ */
++ if (u->gc_candidate) {
++ hit = true;
++ func(u);
++ }
++ }
++ }
++ if (hit && hitlist != NULL) {
++ __skb_unlink(skb, &x->sk_receive_queue);
++ __skb_queue_tail(hitlist, skb);
++ }
++ }
++ }
++ spin_unlock(&x->sk_receive_queue.lock);
++}
++
++static void scan_children(struct sock *x, void (*func)(struct bus_sock *),
++ struct sk_buff_head *hitlist)
++{
++ if (x->sk_state != TCP_LISTEN)
++ scan_inflight(x, func, hitlist);
++ else {
++ struct sk_buff *skb;
++ struct sk_buff *next;
++ struct bus_sock *u;
++ LIST_HEAD(embryos);
++
++ /*
++ * For a listening socket collect the queued embryos
++ * and perform a scan on them as well.
++ */
++ spin_lock(&x->sk_receive_queue.lock);
++ skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
++ u = bus_sk(skb->sk);
++
++ /*
++ * An embryo cannot be in-flight, so it's safe
++ * to use the list link.
++ */
++ BUG_ON(!list_empty(&u->link));
++ list_add_tail(&u->link, &embryos);
++ }
++ spin_unlock(&x->sk_receive_queue.lock);
++
++ while (!list_empty(&embryos)) {
++ u = list_entry(embryos.next, struct bus_sock, link);
++ scan_inflight(&u->sk, func, hitlist);
++ list_del_init(&u->link);
++ }
++ }
++}
++
++static void dec_inflight(struct bus_sock *usk)
++{
++ atomic_long_dec(&usk->inflight);
++}
++
++static void inc_inflight(struct bus_sock *usk)
++{
++ atomic_long_inc(&usk->inflight);
++}
++
++static void inc_inflight_move_tail(struct bus_sock *u)
++{
++ atomic_long_inc(&u->inflight);
++ /*
++ * If this still might be part of a cycle, move it to the end
++ * of the list, so that it's checked even if it was already
++ * passed over
++ */
++ if (u->gc_maybe_cycle)
++ list_move_tail(&u->link, &gc_candidates);
++}
++
++static bool gc_in_progress = false;
++#define BUS_INFLIGHT_TRIGGER_GC 16000
++
++void wait_for_bus_gc(void)
++{
++ /*
++ * If number of inflight sockets is insane,
++ * force a garbage collect right now.
++ */
++ if (bus_tot_inflight > BUS_INFLIGHT_TRIGGER_GC && !gc_in_progress)
++ bus_gc();
++ wait_event(bus_gc_wait, gc_in_progress == false);
++}
++
++/* The external entry point: bus_gc() */
++void bus_gc(void)
++{
++ struct bus_sock *u;
++ struct bus_sock *next;
++ struct sk_buff_head hitlist;
++ struct list_head cursor;
++ LIST_HEAD(not_cycle_list);
++
++ spin_lock(&bus_gc_lock);
++
++ /* Avoid a recursive GC. */
++ if (gc_in_progress)
++ goto out;
++
++ gc_in_progress = true;
++ /*
++ * First, select candidates for garbage collection. Only
++ * in-flight sockets are considered, and from those only ones
++ * which don't have any external reference.
++ *
++ * Holding bus_gc_lock will protect these candidates from
++ * being detached, and hence from gaining an external
++ * reference. Since there are no possible receivers, all
++ * buffers currently on the candidates' queues stay there
++ * during the garbage collection.
++ *
++ * We also know that no new candidate can be added onto the
++ * receive queues. Other, non candidate sockets _can_ be
++ * added to queue, so we must make sure only to touch
++ * candidates.
++ */
++ list_for_each_entry_safe(u, next, &gc_inflight_list, link) {
++ long total_refs;
++ long inflight_refs;
++
++ total_refs = file_count(u->sk.sk_socket->file);
++ inflight_refs = atomic_long_read(&u->inflight);
++
++ BUG_ON(inflight_refs < 1);
++ BUG_ON(total_refs < inflight_refs);
++ if (total_refs == inflight_refs) {
++ list_move_tail(&u->link, &gc_candidates);
++ u->gc_candidate = 1;
++ u->gc_maybe_cycle = 1;
++ }
++ }
++
++ /*
++ * Now remove all internal in-flight reference to children of
++ * the candidates.
++ */
++ list_for_each_entry(u, &gc_candidates, link)
++ scan_children(&u->sk, dec_inflight, NULL);
++
++ /*
++ * Restore the references for children of all candidates,
++ * which have remaining references. Do this recursively, so
++ * only those remain, which form cyclic references.
++ *
++ * Use a "cursor" link, to make the list traversal safe, even
++ * though elements might be moved about.
++ */
++ list_add(&cursor, &gc_candidates);
++ while (cursor.next != &gc_candidates) {
++ u = list_entry(cursor.next, struct bus_sock, link);
++
++ /* Move cursor to after the current position. */
++ list_move(&cursor, &u->link);
++
++ if (atomic_long_read(&u->inflight) > 0) {
++ list_move_tail(&u->link, &not_cycle_list);
++ u->gc_maybe_cycle = 0;
++ scan_children(&u->sk, inc_inflight_move_tail, NULL);
++ }
++ }
++ list_del(&cursor);
++
++ /*
++ * not_cycle_list contains those sockets which do not make up a
++ * cycle. Restore these to the inflight list.
++ */
++ while (!list_empty(&not_cycle_list)) {
++ u = list_entry(not_cycle_list.next, struct bus_sock, link);
++ u->gc_candidate = 0;
++ list_move_tail(&u->link, &gc_inflight_list);
++ }
++
++ /*
++ * Now gc_candidates contains only garbage. Restore original
++ * inflight counters for these as well, and remove the skbuffs
++ * which are creating the cycle(s).
++ */
++ skb_queue_head_init(&hitlist);
++ list_for_each_entry(u, &gc_candidates, link)
++ scan_children(&u->sk, inc_inflight, &hitlist);
++
++ spin_unlock(&bus_gc_lock);
++
++ /* Here we are. Hitlist is filled. Die. */
++ __skb_queue_purge(&hitlist);
++
++ spin_lock(&bus_gc_lock);
++
++ /* All candidates should have been detached by now. */
++ BUG_ON(!list_empty(&gc_candidates));
++ gc_in_progress = false;
++ wake_up(&bus_gc_wait);
++
++ out:
++ spin_unlock(&bus_gc_lock);
++}
+diff --git a/net/core/scm.c b/net/core/scm.c
+index 611c5ef..87e3152 100644
+--- a/net/core/scm.c
++++ b/net/core/scm.c
+@@ -158,7 +158,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
+ switch (cmsg->cmsg_type)
+ {
+ case SCM_RIGHTS:
+- if (!sock->ops || sock->ops->family != PF_UNIX)
++ if (!sock->ops || (sock->ops->family != PF_UNIX &&
++ sock->ops->family != PF_BUS))
+ goto error;
+ err=scm_fp_copy(cmsg, &p->fp);
+ if (err<0)
+diff --git a/net/core/sock.c b/net/core/sock.c
+index b2e14c0..17abe99 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -205,7 +205,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
+ "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
+ "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
+ "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" ,
+- "sk_lock-AF_NFC" , "sk_lock-AF_MAX"
++ "sk_lock-AF_NFC" , "sk_lock-AF_BUS" , "sk_lock-AF_MAX"
+ };
+ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
+ "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
+@@ -221,7 +221,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
+ "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
+ "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
+ "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" ,
+- "slock-AF_NFC" , "slock-AF_MAX"
++ "slock-AF_NFC" , "slock-AF_BUS" , "slock-AF_MAX"
+ };
+ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
+ "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
+@@ -237,7 +237,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
+ "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
+ "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
+ "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" ,
+- "clock-AF_NFC" , "clock-AF_MAX"
++ "clock-AF_NFC" , "clock-AF_BUS" , "clock-AF_MAX"
+ };
+
+ /*
+diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
+index 0c6f67e..58ed81d 100644
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -1151,3 +1151,5 @@ endmenu
+ source "net/netfilter/ipset/Kconfig"
+
+ source "net/netfilter/ipvs/Kconfig"
++
++source "net/netfilter/nfdbus/Kconfig"
+diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
+index ca36765..89752a0 100644
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -119,3 +119,6 @@ obj-$(CONFIG_IP_SET) += ipset/
+
+ # IPVS
+ obj-$(CONFIG_IP_VS) += ipvs/
++
++# Dbus
++obj-$(CONFIG_NETFILTER_DBUS) += nfdbus/
+diff --git a/net/netfilter/nfdbus/Kconfig b/net/netfilter/nfdbus/Kconfig
+new file mode 100644
+index 0000000..25699a1
+--- /dev/null
++++ b/net/netfilter/nfdbus/Kconfig
+@@ -0,0 +1,12 @@
++#
++# Netfilter D-Bus module configuration
++#
++config NETFILTER_DBUS
++ tristate "Netfilter D-bus (EXPERIMENTAL)"
++ depends on AF_BUS && CONNECTOR && EXPERIMENTAL
++ ---help---
++ If you say Y here, you will include support for a netfilter hook to
++ parse D-Bus messages sent using the AF_BUS socket address family.
++
++ To compile this as a module, choose M here: the module will be
++ called netfilter_dbus.
+diff --git a/net/netfilter/nfdbus/Makefile b/net/netfilter/nfdbus/Makefile
+new file mode 100644
+index 0000000..1a825f8
+--- /dev/null
++++ b/net/netfilter/nfdbus/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for the netfilter D-Bus module
++#
++obj-$(CONFIG_NETFILTER_DBUS) += netfilter_dbus.o
++
++netfilter_dbus-y := nfdbus.o message.o matchrule.o
+diff --git a/net/netfilter/nfdbus/matchrule.c b/net/netfilter/nfdbus/matchrule.c
+new file mode 100644
+index 0000000..4106bd5
+--- /dev/null
++++ b/net/netfilter/nfdbus/matchrule.c
+@@ -0,0 +1,1132 @@
++/*
++ * matchrule.c D-Bus match rule implementation
++ *
++ * Based on signals.c from dbus
++ *
++ * Copyright (C) 2010 Collabora, Ltd.
++ * Copyright (C) 2003, 2005 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include "matchrule.h"
++
++#include <linux/rbtree.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++
++#include "message.h"
++
++enum bus_match_flags {
++ BUS_MATCH_MESSAGE_TYPE = 1 << 0,
++ BUS_MATCH_INTERFACE = 1 << 1,
++ BUS_MATCH_MEMBER = 1 << 2,
++ BUS_MATCH_SENDER = 1 << 3,
++ BUS_MATCH_DESTINATION = 1 << 4,
++ BUS_MATCH_PATH = 1 << 5,
++ BUS_MATCH_ARGS = 1 << 6,
++ BUS_MATCH_PATH_NAMESPACE = 1 << 7,
++ BUS_MATCH_CLIENT_IS_EAVESDROPPING = 1 << 8
++};
++
++struct bus_match_rule {
++ /* For debugging only*/
++ char *rule_text;
++
++ unsigned int flags; /**< BusMatchFlags */
++
++ int message_type;
++ char *interface;
++ char *member;
++ char *sender;
++ char *destination;
++ char *path;
++
++ unsigned int *arg_lens;
++ char **args;
++ int args_len;
++
++ /* bus_match_rule is attached to rule_pool, either in a simple
++ * double-linked list if the rule does not have any interface, or in a
++ * red-black tree sorted by interface. If several rules can have the
++ * same interface, the first one is attached with struct rb_node and the
++ * next ones are in the list
++ */
++
++ struct rb_node node;
++ /* Doubly-linked non-circular list. If the rule has an interface, it is
++ * in the rb tree and the single head is right here. Otherwise, the
++ * single head is in rule_pool->rules_without_iface. With this data
++ * structure, we don't need any allocation to insert or remove the rule.
++ */
++ struct hlist_head first;
++ struct hlist_node list;
++
++ /* used to delete all names from the tree */
++ struct list_head del_list;
++};
++
++struct dbus_name {
++ struct rb_node node;
++ char *name;
++
++ /* used to delete all names from the tree */
++ struct list_head del_list;
++};
++
++#define BUS_MATCH_ARG_IS_PATH 0x8000000u
++
++#define DBUS_STRING_MAX_LENGTH 1024
++
++/** Max length of a match rule string; to keep people from hosing the
++ * daemon with some huge rule
++ */
++#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024
++
++struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags)
++{
++ struct bus_match_rule *rule;
++
++ rule = kzalloc(sizeof(struct bus_match_rule), gfp_flags);
++ if (rule == NULL)
++ return NULL;
++
++ return rule;
++}
++
++void bus_match_rule_free(struct bus_match_rule *rule)
++{
++ kfree(rule->rule_text);
++ kfree(rule->interface);
++ kfree(rule->member);
++ kfree(rule->sender);
++ kfree(rule->destination);
++ kfree(rule->path);
++ kfree(rule->arg_lens);
++
++ /* can't use dbus_free_string_array() since there
++ * are embedded NULL
++ */
++ if (rule->args) {
++ int i;
++
++ i = 0;
++ while (i < rule->args_len) {
++ kfree(rule->args[i]);
++ ++i;
++ }
++
++ kfree(rule->args);
++ }
++
++ kfree(rule);
++}
++
++static int
++bus_match_rule_set_message_type(struct bus_match_rule *rule,
++ int type,
++ gfp_t gfp_flags)
++{
++ rule->flags |= BUS_MATCH_MESSAGE_TYPE;
++
++ rule->message_type = type;
++
++ return 1;
++}
++
++static int
++bus_match_rule_set_interface(struct bus_match_rule *rule,
++ const char *interface,
++ gfp_t gfp_flags)
++{
++ char *new;
++
++ WARN_ON(!interface);
++
++ new = kstrdup(interface, gfp_flags);
++ if (new == NULL)
++ return 0;
++
++ rule->flags |= BUS_MATCH_INTERFACE;
++ kfree(rule->interface);
++ rule->interface = new;
++
++ return 1;
++}
++
++static int
++bus_match_rule_set_member(struct bus_match_rule *rule,
++ const char *member,
++ gfp_t gfp_flags)
++{
++ char *new;
++
++ WARN_ON(!member);
++
++ new = kstrdup(member, gfp_flags);
++ if (new == NULL)
++ return 0;
++
++ rule->flags |= BUS_MATCH_MEMBER;
++ kfree(rule->member);
++ rule->member = new;
++
++ return 1;
++}
++
++static int
++bus_match_rule_set_sender(struct bus_match_rule *rule,
++ const char *sender,
++ gfp_t gfp_flags)
++{
++ char *new;
++
++ WARN_ON(!sender);
++
++ new = kstrdup(sender, gfp_flags);
++ if (new == NULL)
++ return 0;
++
++ rule->flags |= BUS_MATCH_SENDER;
++ kfree(rule->sender);
++ rule->sender = new;
++
++ return 1;
++}
++
++static int
++bus_match_rule_set_destination(struct bus_match_rule *rule,
++ const char *destination,
++ gfp_t gfp_flags)
++{
++ char *new;
++
++ WARN_ON(!destination);
++
++ new = kstrdup(destination, gfp_flags);
++ if (new == NULL)
++ return 0;
++
++ rule->flags |= BUS_MATCH_DESTINATION;
++ kfree(rule->destination);
++ rule->destination = new;
++
++ return 1;
++}
++
++#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || \
++ ((c) == '\r'))
++
++static int find_key(const char *str, int start, char *key, int *value_pos)
++{
++ const char *p;
++ const char *s;
++ const char *key_start;
++ const char *key_end;
++
++ s = str;
++
++ p = s + start;
++
++ while (*p && ISWHITE(*p))
++ ++p;
++
++ key_start = p;
++
++ while (*p && *p != '=' && !ISWHITE(*p))
++ ++p;
++
++ key_end = p;
++
++ while (*p && ISWHITE(*p))
++ ++p;
++
++ if (key_start == key_end) {
++ /* Empty match rules or trailing whitespace are OK */
++ *value_pos = p - s;
++ return 1;
++ }
++
++ if (*p != '=') {
++ pr_warn("Match rule has a key with no subsequent '=' character");
++ return 0;
++ }
++ ++p;
++
++ strncat(key, key_start, key_end - key_start);
++
++ *value_pos = p - s;
++
++ return 1;
++}
++
++static int find_value(const char *str, int start, const char *key, char *value,
++ int *value_end)
++{
++ const char *p;
++ const char *s;
++ char quote_char;
++ int orig_len;
++
++ orig_len = strlen(value);
++
++ s = str;
++
++ p = s + start;
++
++ quote_char = '\0';
++
++ while (*p) {
++ if (quote_char == '\0') {
++ switch (*p) {
++ case '\0':
++ goto done;
++
++ case '\'':
++ quote_char = '\'';
++ goto next;
++
++ case ',':
++ ++p;
++ goto done;
++
++ case '\\':
++ quote_char = '\\';
++ goto next;
++
++ default:
++ strncat(value, p, 1);
++ }
++ } else if (quote_char == '\\') {
++ /*\ only counts as an escape if escaping a quote mark */
++ if (*p != '\'')
++ strncat(value, "\\", 1);
++
++ strncat(value, p, 1);
++
++ quote_char = '\0';
++ } else {
++ if (*p == '\'')
++ quote_char = '\0';
++ else
++ strncat(value, p, 1);
++ }
++
++next:
++ ++p;
++ }
++
++done:
++
++ if (quote_char == '\\')
++ strncat(value, "\\", 1);
++ else if (quote_char == '\'') {
++ pr_warn("Unbalanced quotation marks in match rule");
++ return 0;
++ }
++
++ /* Zero-length values are allowed */
++
++ *value_end = p - s;
++
++ return 1;
++}
++
++/* duplicates aren't allowed so the real legitimate max is only 6 or
++ * so. Leaving extra so we don't have to bother to update it.
++ * FIXME this is sort of busted now with arg matching, but we let
++ * you match on up to 10 args for now
++ */
++#define MAX_RULE_TOKENS 16
++
++/* this is slightly too high level to be termed a "token"
++ * but let's not be pedantic.
++ */
++struct rule_token {
++ char *key;
++ char *value;
++};
++
++static int tokenize_rule(const char *rule_text,
++ struct rule_token tokens[MAX_RULE_TOKENS],
++ gfp_t gfp_flags)
++{
++ int i;
++ int pos;
++ int retval;
++
++ retval = 0;
++
++ i = 0;
++ pos = 0;
++ while (i < MAX_RULE_TOKENS &&
++ pos < strlen(rule_text)) {
++ char *key;
++ char *value;
++
++ key = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags);
++ if (!key) {
++ pr_err("Out of memory");
++ return 0;
++ }
++
++ value = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags);
++ if (!value) {
++ kfree(key);
++ pr_err("Out of memory");
++ return 0;
++ }
++
++ if (!find_key(rule_text, pos, key, &pos))
++ goto out;
++
++ if (strlen(key) == 0)
++ goto next;
++
++ tokens[i].key = key;
++
++ if (!find_value(rule_text, pos, tokens[i].key, value, &pos))
++ goto out;
++
++ tokens[i].value = value;
++
++next:
++ ++i;
++ }
++
++ retval = 1;
++
++out:
++ if (!retval) {
++ i = 0;
++ while (tokens[i].key || tokens[i].value) {
++ kfree(tokens[i].key);
++ kfree(tokens[i].value);
++ tokens[i].key = NULL;
++ tokens[i].value = NULL;
++ ++i;
++ }
++ }
++
++ return retval;
++}
++
++/*
++ * The format is comma-separated with strings quoted with single quotes
++ * as for the shell (to escape a literal single quote, use '\'').
++ *
++ * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',
++ * member='Foo', path='/bar/foo',destination=':452345.34'
++ *
++ */
++struct bus_match_rule *bus_match_rule_parse(const char *rule_text,
++ gfp_t gfp_flags)
++{
++ struct bus_match_rule *rule;
++ struct rule_token tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */
++ int i;
++
++ if (strlen(rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) {
++ pr_warn("Match rule text is %ld bytes, maximum is %d",
++ strlen(rule_text),
++ DBUS_MAXIMUM_MATCH_RULE_LENGTH);
++ return NULL;
++ }
++
++ memset(tokens, '\0', sizeof(tokens));
++
++ rule = bus_match_rule_new(gfp_flags);
++ if (rule == NULL) {
++ pr_err("Out of memory");
++ goto failed;
++ }
++
++ rule->rule_text = kstrdup(rule_text, gfp_flags);
++ if (rule->rule_text == NULL) {
++ pr_err("Out of memory");
++ goto failed;
++ }
++
++ if (!tokenize_rule(rule_text, tokens, gfp_flags))
++ goto failed;
++
++ i = 0;
++ while (tokens[i].key != NULL) {
++ const char *key = tokens[i].key;
++ const char *value = tokens[i].value;
++
++ if (strcmp(key, "type") == 0) {
++ int t;
++
++ if (rule->flags & BUS_MATCH_MESSAGE_TYPE) {
++ pr_warn("Key %s specified twice in match rule\n",
++ key);
++ goto failed;
++ }
++
++ t = dbus_message_type_from_string(value);
++
++ if (t == DBUS_MESSAGE_TYPE_INVALID) {
++ pr_warn("Invalid message type (%s) in match rule\n",
++ value);
++ goto failed;
++ }
++
++ if (!bus_match_rule_set_message_type(rule, t,
++ gfp_flags)) {
++ pr_err("Out of memeory");
++ goto failed;
++ }
++ } else if (strcmp(key, "sender") == 0) {
++ if (rule->flags & BUS_MATCH_SENDER) {
++ pr_warn("Key %s specified twice in match rule\n",
++ key);
++ goto failed;
++ }
++
++ if (!bus_match_rule_set_sender(rule, value,
++ gfp_flags)) {
++ pr_err("Out of memeory");
++ goto failed;
++ }
++ } else if (strcmp(key, "interface") == 0) {
++ if (rule->flags & BUS_MATCH_INTERFACE) {
++ pr_warn("Key %s specified twice in match rule\n",
++ key);
++ goto failed;
++ }
++
++ if (!bus_match_rule_set_interface(rule, value,
++ gfp_flags)) {
++ pr_err("Out of memeory");
++ goto failed;
++ }
++ } else if (strcmp(key, "member") == 0) {
++ if (rule->flags & BUS_MATCH_MEMBER) {
++ pr_warn("Key %s specified twice in match rule\n",
++ key);
++ goto failed;
++ }
++
++ if (!bus_match_rule_set_member(rule, value,
++ gfp_flags)) {
++ pr_err("Out of memeory");
++ goto failed;
++ }
++ } else if (strcmp(key, "destination") == 0) {
++ if (rule->flags & BUS_MATCH_DESTINATION) {
++ pr_warn("Key %s specified twice in match rule\n",
++ key);
++ goto failed;
++ }
++
++ if (!bus_match_rule_set_destination(rule, value,
++ gfp_flags)) {
++ pr_err("Out of memeory");
++ goto failed;
++ }
++ } else if (strcmp(key, "eavesdrop") == 0) {
++ if (strcmp(value, "true") == 0) {
++ rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
++ } else if (strcmp(value, "false") == 0) {
++ rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
++ } else {
++ pr_warn("eavesdrop='%s' is invalid, " \
++ "it should be 'true' or 'false'\n",
++ value);
++ goto failed;
++ }
++ } else if (strncmp(key, "arg", 3) != 0) {
++ pr_warn("Unknown key \"%s\" in match rule\n",
++ key);
++ goto failed;
++ }
++
++ ++i;
++ }
++
++ goto out;
++
++failed:
++ if (rule) {
++ bus_match_rule_free(rule);
++ rule = NULL;
++ }
++
++out:
++
++ i = 0;
++ while (tokens[i].key || tokens[i].value) {
++ WARN_ON(i >= MAX_RULE_TOKENS);
++ kfree(tokens[i].key);
++ kfree(tokens[i].value);
++ ++i;
++ }
++
++ return rule;
++}
++
++/* return the match rule containing the hlist_head. It may not be the first
++ * match rule in the list. */
++struct bus_match_rule *match_rule_search(struct rb_root *root,
++ const char *interface)
++{
++ struct rb_node *node = root->rb_node;
++
++ while (node) {
++ struct bus_match_rule *data =
++ container_of(node, struct bus_match_rule, node);
++ int result;
++
++ result = strcmp(interface, data->interface);
++
++ if (result < 0)
++ node = node->rb_left;
++ else if (result > 0)
++ node = node->rb_right;
++ else
++ return data;
++ }
++ return NULL;
++}
++
++void match_rule_insert(struct rb_root *root, struct bus_match_rule *data)
++{
++ struct rb_node **new = &(root->rb_node), *parent = NULL;
++
++ /* Figure out where to put new node */
++ while (*new) {
++ struct bus_match_rule *this =
++ container_of(*new, struct bus_match_rule, node);
++ int result = strcmp(data->interface, this->interface);
++
++ parent = *new;
++ if (result < 0)
++ new = &((*new)->rb_left);
++ else if (result > 0)
++ new = &((*new)->rb_right);
++ else {
++ /* the head is not used */
++ INIT_HLIST_HEAD(&data->first);
++ /* Add it at the beginning of the list */
++ hlist_add_head(&data->list, &this->first);
++ return;
++ }
++ }
++
++ /* this rule is single in its list */
++ INIT_HLIST_HEAD(&data->first);
++ hlist_add_head(&data->list, &data->first);
++
++ /* Add new node and rebalance tree. */
++ rb_link_node(&data->node, parent, new);
++ rb_insert_color(&data->node, root);
++}
++
++struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags)
++{
++ struct bus_match_maker *matchmaker;
++ int i;
++
++ matchmaker = kzalloc(sizeof(struct bus_match_maker), gfp_flags);
++ if (matchmaker == NULL)
++ return NULL;
++
++ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) {
++ struct rule_pool *p = matchmaker->rules_by_type + i;
++
++ p->rules_by_iface = RB_ROOT;
++ }
++
++ kref_init(&matchmaker->kref);
++
++ return matchmaker;
++}
++
++void bus_matchmaker_free(struct kref *kref)
++{
++ struct bus_match_maker *matchmaker;
++ struct list_head del_list;
++ struct rb_node *n;
++ int i;
++
++ matchmaker = container_of(kref, struct bus_match_maker, kref);
++
++ /* free names */
++ INIT_LIST_HEAD(&del_list);
++ n = matchmaker->names.rb_node;
++ if (n) {
++ struct dbus_name *dbus_name, *cur, *tmp;
++
++ dbus_name = rb_entry(n, struct dbus_name, node);
++ list_add_tail(&dbus_name->del_list, &del_list);
++
++ list_for_each_entry(cur, &del_list, del_list) {
++ struct dbus_name *right, *left;
++ if (cur->node.rb_right) {
++ right = rb_entry(cur->node.rb_right,
++ struct dbus_name, node);
++ list_add_tail(&right->del_list, &del_list);
++ }
++ if (cur->node.rb_left) {
++ left = rb_entry(cur->node.rb_left,
++ struct dbus_name, node);
++ list_add_tail(&left->del_list, &del_list);
++ }
++ }
++ list_for_each_entry_safe(dbus_name, tmp, &del_list, del_list) {
++ kfree(dbus_name->name);
++ list_del(&dbus_name->del_list);
++ kfree(dbus_name);
++ }
++ }
++ WARN_ON(!list_empty_careful(&del_list));
++
++ /* free match rules */
++ for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++) {
++ struct rule_pool *pool = matchmaker->rules_by_type + i;
++ struct bus_match_rule *match_rule, *cur, *tmp;
++ struct hlist_node *list_tmp, *list_tmp2;
++
++ /* free match rules from the list */
++ hlist_for_each_entry_safe(cur, list_tmp, list_tmp2,
++ &pool->rules_without_iface, list) {
++ bus_match_rule_free(cur);
++ }
++
++ /* free match rules from the tree */
++ if (!pool->rules_by_iface.rb_node)
++ continue;
++ match_rule = rb_entry(pool->rules_by_iface.rb_node,
++ struct bus_match_rule, node);
++ list_add_tail(&match_rule->del_list, &del_list);
++
++ list_for_each_entry(cur, &del_list, del_list) {
++ struct bus_match_rule *right, *left;
++ if (cur->node.rb_right) {
++ right = rb_entry(cur->node.rb_right,
++ struct bus_match_rule, node);
++ list_add_tail(&right->del_list, &del_list);
++ }
++ if (cur->node.rb_left) {
++ left = rb_entry(cur->node.rb_left,
++ struct bus_match_rule, node);
++ list_add_tail(&left->del_list, &del_list);
++ }
++ }
++ list_for_each_entry_safe(match_rule, tmp, &del_list, del_list) {
++ /* keep a ref during the loop to ensure the first
++ * iteration of the loop does not delete it */
++ hlist_for_each_entry_safe(cur, list_tmp, list_tmp2,
++ &match_rule->first, list) {
++ if (cur != match_rule)
++ bus_match_rule_free(cur);
++ }
++ list_del(&match_rule->del_list);
++ bus_match_rule_free(match_rule);
++ }
++ WARN_ON(!list_empty_careful(&del_list));
++ }
++
++ kfree(matchmaker);
++}
++
++/* The rule can't be modified after it's added. */
++int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker,
++ struct bus_match_rule *rule)
++{
++ struct rule_pool *pool;
++
++ WARN_ON(rule->message_type < 0);
++ WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES);
++
++ pool = matchmaker->rules_by_type + rule->message_type;
++
++ if (rule->interface)
++ match_rule_insert(&pool->rules_by_iface, rule);
++ else
++ hlist_add_head(&rule->list, &pool->rules_without_iface);
++
++ return 1;
++}
++
++static int match_rule_equal(struct bus_match_rule *a,
++ struct bus_match_rule *b)
++{
++ if (a->flags != b->flags)
++ return 0;
++
++ if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
++ a->message_type != b->message_type)
++ return 0;
++
++ if ((a->flags & BUS_MATCH_MEMBER) &&
++ strcmp(a->member, b->member) != 0)
++ return 0;
++
++ if ((a->flags & BUS_MATCH_PATH) &&
++ strcmp(a->path, b->path) != 0)
++ return 0;
++
++ if ((a->flags & BUS_MATCH_INTERFACE) &&
++ strcmp(a->interface, b->interface) != 0)
++ return 0;
++
++ if ((a->flags & BUS_MATCH_SENDER) &&
++ strcmp(a->sender, b->sender) != 0)
++ return 0;
++
++ if ((a->flags & BUS_MATCH_DESTINATION) &&
++ strcmp(a->destination, b->destination) != 0)
++ return 0;
++
++ if (a->flags & BUS_MATCH_ARGS) {
++ int i;
++
++ if (a->args_len != b->args_len)
++ return 0;
++
++ i = 0;
++ while (i < a->args_len) {
++ int length;
++
++ if ((a->args[i] != NULL) != (b->args[i] != NULL))
++ return 0;
++
++ if (a->arg_lens[i] != b->arg_lens[i])
++ return 0;
++
++ length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
++
++ if (a->args[i] != NULL) {
++ WARN_ON(!b->args[i]);
++ if (memcmp(a->args[i], b->args[i], length) != 0)
++ return 0;
++ }
++
++ ++i;
++ }
++ }
++
++ return 1;
++}
++
++/* Remove a single rule which is equal to the given rule by value */
++void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker,
++ struct bus_match_rule *rule)
++{
++ struct rule_pool *pool;
++
++ WARN_ON(rule->message_type < 0);
++ WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES);
++
++ pool = matchmaker->rules_by_type + rule->message_type;
++
++ if (rule->interface) {
++ struct bus_match_rule *head =
++ match_rule_search(&pool->rules_by_iface,
++ rule->interface);
++
++ struct hlist_node *cur;
++ struct bus_match_rule *cur_rule;
++ hlist_for_each_entry(cur_rule, cur, &head->first, list) {
++ if (match_rule_equal(cur_rule, rule)) {
++ hlist_del(cur);
++ if (hlist_empty(&head->first))
++ rb_erase(&head->node,
++ &pool->rules_by_iface);
++ bus_match_rule_free(cur_rule);
++ break;
++ }
++ }
++ } else {
++ struct hlist_head *head = &pool->rules_without_iface;
++
++ struct hlist_node *cur;
++ struct bus_match_rule *cur_rule;
++ hlist_for_each_entry(cur_rule, cur, head, list) {
++ if (match_rule_equal(cur_rule, rule)) {
++ hlist_del(cur);
++ bus_match_rule_free(cur_rule);
++ break;
++ }
++ }
++ }
++
++}
++
++static int connection_is_primary_owner(struct bus_match_maker *connection,
++ const char *service_name)
++{
++ struct rb_node *node = connection->names.rb_node;
++
++ if (!service_name)
++ return 0;
++
++ while (node) {
++ struct dbus_name *data = container_of(node, struct dbus_name,
++ node);
++ int result;
++
++ result = strcmp(service_name, data->name);
++
++ if (result < 0)
++ node = node->rb_left;
++ else if (result > 0)
++ node = node->rb_right;
++ else
++ return 1;
++ }
++ return 0;
++}
++
++static int match_rule_matches(struct bus_match_maker *matchmaker,
++ struct bus_match_maker *sender,
++ int eavesdrop,
++ struct bus_match_rule *rule,
++ const struct dbus_message *message)
++{
++ /* Don't consider the rule if this is a eavesdropping match rule
++ * and eavesdropping is not allowed on that peer */
++ if ((rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) && !eavesdrop)
++ return 0;
++
++ /* Since D-Bus 1.5.6, match rules do not match messages which have a
++ * DESTINATION field unless the match rule specifically requests this
++ * by specifying eavesdrop='true' in the match rule. */
++ if (message->destination &&
++ !(rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING))
++ return 0;
++
++ if (rule->flags & BUS_MATCH_MEMBER) {
++ const char *member;
++
++ WARN_ON(!rule->member);
++
++ member = message->member;
++ if (member == NULL)
++ return 0;
++
++ if (strcmp(member, rule->member) != 0)
++ return 0;
++ }
++
++ if (rule->flags & BUS_MATCH_SENDER) {
++ WARN_ON(!rule->sender);
++
++ if (sender == NULL) {
++ if (strcmp(rule->sender,
++ "org.freedesktop.DBus") != 0)
++ return 0;
++ } else
++ if (!connection_is_primary_owner(sender, rule->sender))
++ return 0;
++ }
++
++ if (rule->flags & BUS_MATCH_DESTINATION) {
++ const char *destination;
++
++ WARN_ON(!rule->destination);
++
++ destination = message->destination;
++ if (destination == NULL)
++ return 0;
++
++ /* This will not just work out of the box because it this is
++ * an eavesdropping match rule. */
++ if (matchmaker == NULL) {
++ if (strcmp(rule->destination,
++ "org.freedesktop.DBus") != 0)
++ return 0;
++ } else
++ if (!connection_is_primary_owner(matchmaker,
++ rule->destination))
++ return 0;
++ }
++
++ if (rule->flags & BUS_MATCH_PATH) {
++ const char *path;
++
++ WARN_ON(!rule->path);
++
++ path = message->path;
++ if (path == NULL)
++ return 0;
++
++ if (strcmp(path, rule->path) != 0)
++ return 0;
++ }
++
++ return 1;
++}
++
++static bool get_recipients_from_list(struct bus_match_maker *matchmaker,
++ struct bus_match_maker *sender,
++ int eavesdrop,
++ struct hlist_head *rules,
++ const struct dbus_message *message)
++{
++ struct hlist_node *cur;
++ struct bus_match_rule *rule;
++
++ if (rules == NULL) {
++ pr_debug("no rules of this type\n");
++ return 0;
++ }
++
++ hlist_for_each_entry(rule, cur, rules, list) {
++ if (match_rule_matches(matchmaker, sender, eavesdrop, rule,
++ message)) {
++ pr_debug("[YES] deliver with match rule \"%s\"\n",
++ rule->rule_text);
++ return 1;
++ } else {
++ pr_debug("[NO] deliver with match rule \"%s\"\n",
++ rule->rule_text);
++ }
++ }
++ pr_debug("[NO] no match rules\n");
++ return 0;
++}
++
++static struct hlist_head
++*bus_matchmaker_get_rules(struct bus_match_maker *matchmaker,
++ int message_type, const char *interface)
++{
++ static struct hlist_head empty = {0,};
++ struct rule_pool *p;
++
++ WARN_ON(message_type < 0);
++ WARN_ON(message_type >= DBUS_NUM_MESSAGE_TYPES);
++
++ p = matchmaker->rules_by_type + message_type;
++
++ if (interface == NULL)
++ return &p->rules_without_iface;
++ else {
++ struct bus_match_rule *rule =
++ match_rule_search(&p->rules_by_iface, interface);
++ if (rule)
++ return &rule->first;
++ else
++ return &empty;
++ }
++}
++
++bool bus_matchmaker_filter(struct bus_match_maker *matchmaker,
++ struct bus_match_maker *sender,
++ int eavesdrop,
++ const struct dbus_message *message)
++{
++ int type;
++ const char *interface;
++ struct hlist_head *neither, *just_type, *just_iface, *both;
++
++ type = message->type;
++ interface = message->interface;
++
++ neither = bus_matchmaker_get_rules(matchmaker,
++ DBUS_MESSAGE_TYPE_INVALID, NULL);
++ just_type = just_iface = both = NULL;
++
++ if (interface != NULL)
++ just_iface = bus_matchmaker_get_rules(matchmaker,
++ DBUS_MESSAGE_TYPE_INVALID,
++ interface);
++
++ if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES) {
++ just_type = bus_matchmaker_get_rules(matchmaker, type, NULL);
++
++ if (interface != NULL)
++ both = bus_matchmaker_get_rules(matchmaker, type,
++ interface);
++ }
++
++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, neither,
++ message))
++ return 1;
++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_iface,
++ message))
++ return 1;
++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_type,
++ message))
++ return 1;
++ if (get_recipients_from_list(matchmaker, sender, eavesdrop, both,
++ message))
++ return 1;
++
++ return connection_is_primary_owner(matchmaker, message->destination);
++}
++
++void bus_matchmaker_add_name(struct bus_match_maker *matchmaker,
++ const char *name,
++ gfp_t gfp_flags)
++{
++ struct dbus_name *dbus_name;
++ struct rb_node **new = &(matchmaker->names.rb_node), *parent = NULL;
++
++ dbus_name = kmalloc(sizeof(struct dbus_name), gfp_flags);
++ if (!dbus_name)
++ return;
++ dbus_name->name = kstrdup(name, gfp_flags);
++ if (!dbus_name->name)
++ return;
++
++ /* Figure out where to put new node */
++ while (*new) {
++ struct dbus_name *this = container_of(*new, struct dbus_name,
++ node);
++ int result = strcmp(dbus_name->name, this->name);
++
++ parent = *new;
++ if (result < 0)
++ new = &((*new)->rb_left);
++ else if (result > 0)
++ new = &((*new)->rb_right);
++ else
++ return;
++ }
++
++ /* Add new node and rebalance tree. */
++ rb_link_node(&dbus_name->node, parent, new);
++ rb_insert_color(&dbus_name->node, &matchmaker->names);
++}
++
++void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker,
++ const char *name)
++{
++ struct rb_node *node = matchmaker->names.rb_node;
++
++ while (node) {
++ struct dbus_name *data = container_of(node, struct dbus_name,
++ node);
++ int result;
++
++ result = strcmp(name, data->name);
++
++ if (result < 0)
++ node = node->rb_left;
++ else if (result > 0)
++ node = node->rb_right;
++ else {
++ rb_erase(&data->node, &matchmaker->names);
++ kfree(data->name);
++ kfree(data);
++ }
++ }
++
++}
++
+diff --git a/net/netfilter/nfdbus/matchrule.h b/net/netfilter/nfdbus/matchrule.h
+new file mode 100644
+index 0000000..e16580c
+--- /dev/null
++++ b/net/netfilter/nfdbus/matchrule.h
+@@ -0,0 +1,82 @@
++/*
++ * signals.h Bus signal connection implementation
++ *
++ * Copyright (C) 2003 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef BUS_SIGNALS_H
++#define BUS_SIGNALS_H
++
++#include <linux/gfp.h>
++#include <linux/list.h>
++#include <linux/rbtree.h>
++#include <linux/slab.h>
++#include <net/af_bus.h>
++
++#include "message.h"
++
++struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags);
++void bus_match_rule_free(struct bus_match_rule *rule);
++
++struct bus_match_rule *bus_match_rule_parse(const char *rule_text,
++ gfp_t gfp_flags);
++
++struct rule_pool {
++ /* Maps non-NULL interface names to a list of bus_match_rule */
++ struct rb_root rules_by_iface;
++
++ /* List of bus_match_rule which don't specify an interface */
++ struct hlist_head rules_without_iface;
++};
++
++struct bus_match_maker {
++ struct sockaddr_bus addr;
++
++ struct hlist_node table_node;
++
++ /* Pools of rules, grouped by the type of message they match. 0
++ * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a
++ * message type.
++ */
++ struct rule_pool rules_by_type[DBUS_NUM_MESSAGE_TYPES];
++
++ struct rb_root names;
++
++ struct kref kref;
++};
++
++
++struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags);
++void bus_matchmaker_free(struct kref *kref);
++
++int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker,
++ struct bus_match_rule *rule);
++void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker,
++ struct bus_match_rule *value);
++
++bool bus_matchmaker_filter(struct bus_match_maker *matchmaker,
++ struct bus_match_maker *sender,
++ int eavesdrop,
++ const struct dbus_message *message);
++
++void bus_matchmaker_add_name(struct bus_match_maker *matchmaker,
++ const char *name, gfp_t gfp_flags);
++void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker,
++ const char *name);
++
++#endif /* BUS_SIGNALS_H */
+diff --git a/net/netfilter/nfdbus/message.c b/net/netfilter/nfdbus/message.c
+new file mode 100644
+index 0000000..93c409c
+--- /dev/null
++++ b/net/netfilter/nfdbus/message.c
+@@ -0,0 +1,194 @@
++/*
++ * message.c Basic D-Bus message parsing
++ *
++ * Copyright (C) 2010-2012 Collabora Ltd
++ * Authors: Alban Crequy <alban.crequy@collabora.co.uk>
++ * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc.
++ * Copyright (C) 2002, 2003 CodeFactory AB
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#include <linux/slab.h>
++
++#include "message.h"
++
++int dbus_message_type_from_string(const char *type_str)
++{
++ if (strcmp(type_str, "method_call") == 0)
++ return DBUS_MESSAGE_TYPE_METHOD_CALL;
++ if (strcmp(type_str, "method_return") == 0)
++ return DBUS_MESSAGE_TYPE_METHOD_RETURN;
++ else if (strcmp(type_str, "signal") == 0)
++ return DBUS_MESSAGE_TYPE_SIGNAL;
++ else if (strcmp(type_str, "error") == 0)
++ return DBUS_MESSAGE_TYPE_ERROR;
++ else
++ return DBUS_MESSAGE_TYPE_INVALID;
++}
++
++int dbus_message_parse(unsigned char *message, size_t len,
++ struct dbus_message *dbus_message)
++{
++ unsigned char *cur;
++ int array_header_len;
++
++ dbus_message->message = message;
++
++ if (len < 4 + 4 + 4 + 4 || message[1] == 0 || message[1] > 4)
++ return -EINVAL;
++
++ dbus_message->type = message[1];
++ dbus_message->body_length = *((u32 *)(message + 4));
++ cur = message + 12;
++ array_header_len = *(u32 *)cur;
++ dbus_message->len_offset = 12;
++ cur += 4;
++ while (cur < message + len
++ && cur < message + 12 + 4 + array_header_len) {
++ int header_code;
++ int signature_len;
++ unsigned char *signature;
++ int str_len;
++ unsigned char *str;
++
++ /* D-Bus alignment craziness */
++ if ((cur - message) % 8 != 0)
++ cur += 8 - (cur - message) % 8;
++
++ header_code = *(char *)cur;
++ cur++;
++ signature_len = *(char *)cur;
++ /* All header fields of the current D-Bus spec have a simple
++ * type, either o, s, g, or u */
++ if (signature_len != 1)
++ return -EINVAL;
++ cur++;
++ signature = cur;
++ cur += signature_len + 1;
++ if (signature[0] != 'o' &&
++ signature[0] != 's' &&
++ signature[0] != 'g' &&
++ signature[0] != 'u')
++ return -EINVAL;
++
++ if (signature[0] == 'u') {
++ cur += 4;
++ continue;
++ }
++
++ if (signature[0] != 'g') {
++ str_len = *(u32 *)cur;
++ cur += 4;
++ } else {
++ str_len = *(char *)cur;
++ cur += 1;
++ }
++
++ str = cur;
++ switch (header_code) {
++ case 1:
++ dbus_message->path = str;
++ break;
++ case 2:
++ dbus_message->interface = str;
++ break;
++ case 3:
++ dbus_message->member = str;
++ break;
++ case 6:
++ dbus_message->destination = str;
++ break;
++ case 7:
++ dbus_message->sender = str;
++ break;
++ case 8:
++ dbus_message->body_signature = str;
++ break;
++ }
++ cur += str_len + 1;
++ }
++
++ dbus_message->padding_end = (8 - (cur - message) % 8) % 8;
++
++ /* Jump to body D-Bus alignment craziness */
++ if ((cur - message) % 8 != 0)
++ cur += 8 - (cur - message) % 8;
++ dbus_message->new_header_offset = cur - message;
++
++ if (dbus_message->new_header_offset
++ + dbus_message->body_length != len) {
++ pr_warn("Message truncated? " \
++ "Header %d + Body %d != Length %zd\n",
++ dbus_message->new_header_offset,
++ dbus_message->body_length, len);
++ return -EINVAL;
++ }
++
++ if (dbus_message->body_signature &&
++ dbus_message->body_signature[0] == 's') {
++ int str_len;
++ str_len = *(u32 *)cur;
++ cur += 4;
++ dbus_message->arg0 = cur;
++ cur += str_len + 1;
++ }
++
++ if ((cur - message) % 4 != 0)
++ cur += 4 - (cur - message) % 4;
++
++ if (dbus_message->body_signature &&
++ dbus_message->body_signature[0] == 's' &&
++ dbus_message->body_signature[1] == 's') {
++ int str_len;
++ str_len = *(u32 *)cur;
++ cur += 4;
++ dbus_message->arg1 = cur;
++ cur += str_len + 1;
++ }
++
++ if ((cur - message) % 4 != 0)
++ cur += 4 - (cur - message) % 4;
++
++ if (dbus_message->body_signature &&
++ dbus_message->body_signature[0] == 's' &&
++ dbus_message->body_signature[1] == 's' &&
++ dbus_message->body_signature[2] == 's') {
++ int str_len;
++ str_len = *(u32 *)cur;
++ cur += 4;
++ dbus_message->arg2 = cur;
++ cur += str_len + 1;
++ }
++
++ if ((cur - message) % 4 != 0)
++ cur += 4 - (cur - message) % 4;
++
++ if (dbus_message->type == DBUS_MESSAGE_TYPE_SIGNAL &&
++ dbus_message->sender && dbus_message->path &&
++ dbus_message->interface && dbus_message->member &&
++ dbus_message->arg0 &&
++ strcmp(dbus_message->sender, "org.freedesktop.DBus") == 0 &&
++ strcmp(dbus_message->interface, "org.freedesktop.DBus") == 0 &&
++ strcmp(dbus_message->path, "/org/freedesktop/DBus") == 0) {
++ if (strcmp(dbus_message->member, "NameAcquired") == 0)
++ dbus_message->name_acquired = dbus_message->arg0;
++ else if (strcmp(dbus_message->member, "NameLost") == 0)
++ dbus_message->name_lost = dbus_message->arg0;
++ }
++
++ return 0;
++}
+diff --git a/net/netfilter/nfdbus/message.h b/net/netfilter/nfdbus/message.h
+new file mode 100644
+index 0000000..e3ea4d3
+--- /dev/null
++++ b/net/netfilter/nfdbus/message.h
+@@ -0,0 +1,71 @@
++/*
++ * message.h Basic D-Bus message parsing
++ *
++ * Copyright (C) 2010 Collabora Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef DBUS_MESSAGE_H
++#define DBUS_MESSAGE_H
++
++#include <linux/list.h>
++
++#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024
++
++/* Types of message */
++
++#define DBUS_MESSAGE_TYPE_INVALID 0
++#define DBUS_MESSAGE_TYPE_METHOD_CALL 1
++#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
++#define DBUS_MESSAGE_TYPE_ERROR 3
++#define DBUS_MESSAGE_TYPE_SIGNAL 4
++#define DBUS_NUM_MESSAGE_TYPES 5
++
++/* No need to implement a feature-complete parser. It only implement what is
++ * needed by the bus. */
++struct dbus_message {
++ char *message;
++ size_t len;
++ size_t new_len;
++
++ /* direct pointers to the fields */
++ int type;
++ char *path;
++ char *interface;
++ char *member;
++ char *destination;
++ char *sender;
++ char *body_signature;
++ int body_length;
++ char *arg0;
++ char *arg1;
++ char *arg2;
++ char *name_acquired;
++ char *name_lost;
++
++ /* How to add the 'sender' field in the headers */
++ int new_header_offset;
++ int len_offset;
++ int padding_end;
++};
++
++int dbus_message_type_from_string(const char *type_str);
++
++int dbus_message_parse(unsigned char *message, size_t len,
++ struct dbus_message *dbus_message);
++
++#endif /* DBUS_MESSAGE_H */
+diff --git a/net/netfilter/nfdbus/nfdbus.c b/net/netfilter/nfdbus/nfdbus.c
+new file mode 100644
+index 0000000..f6642e2
+--- /dev/null
++++ b/net/netfilter/nfdbus/nfdbus.c
+@@ -0,0 +1,456 @@
++/*
++ * nfdbus.c - Netfilter module for AF_BUS/BUS_PROTO_DBUS.
++ */
++
++#define DRIVER_AUTHOR "Alban Crequy"
++#define DRIVER_DESC "Netfilter module for AF_BUS/BUS_PROTO_DBUS."
++
++#include "nfdbus.h"
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter.h>
++#include <linux/connector.h>
++#include <net/af_bus.h>
++
++#include "message.h"
++#include "matchrule.h"
++
++static struct nf_hook_ops nfho_dbus;
++
++static struct cb_id cn_cmd_id = { CN_IDX_NFDBUS, CN_VAL_NFDBUS };
++
++static unsigned int hash;
++
++/* Scoped by AF_BUS address */
++struct hlist_head matchrules_table[BUS_HASH_SIZE];
++DEFINE_SPINLOCK(matchrules_lock);
++
++static struct bus_match_maker *find_match_maker(struct sockaddr_bus *addr,
++ bool create, bool delete)
++{
++ u64 hash;
++ struct hlist_node *node;
++ struct bus_match_maker *matchmaker;
++ int path_len = strlen(addr->sbus_path);
++
++ hash = csum_partial(addr->sbus_path,
++ strlen(addr->sbus_path), 0);
++ hash ^= addr->sbus_addr.s_addr;
++ hash ^= hash >> 32;
++ hash ^= hash >> 16;
++ hash ^= hash >> 8;
++ hash &= 0xff;
++
++ spin_lock(&matchrules_lock);
++ hlist_for_each_entry(matchmaker, node, &matchrules_table[hash],
++ table_node) {
++ if (addr->sbus_family == matchmaker->addr.sbus_family &&
++ addr->sbus_addr.s_addr == matchmaker->addr.sbus_addr.s_addr &&
++ !memcmp(addr->sbus_path, matchmaker->addr.sbus_path,
++ path_len)) {
++ kref_get(&matchmaker->kref);
++ if (delete)
++ hlist_del(&matchmaker->table_node);
++ spin_unlock(&matchrules_lock);
++ pr_debug("Found matchmaker for hash %llu", hash);
++ return matchmaker;
++ }
++ }
++ spin_unlock(&matchrules_lock);
++
++ if (!create) {
++ pr_debug("Matchmaker for hash %llu not found", hash);
++ return NULL;
++ }
++
++ matchmaker = bus_matchmaker_new(GFP_ATOMIC);
++ matchmaker->addr.sbus_family = addr->sbus_family;
++ matchmaker->addr.sbus_addr.s_addr = addr->sbus_addr.s_addr;
++ memcpy(matchmaker->addr.sbus_path, addr->sbus_path, BUS_PATH_MAX);
++
++ pr_debug("Create new matchmaker for hash %llu\n", hash);
++ spin_lock(&matchrules_lock);
++ hlist_add_head(&matchmaker->table_node, &matchrules_table[hash]);
++ kref_get(&matchmaker->kref);
++ spin_unlock(&matchrules_lock);
++ return matchmaker;
++}
++
++static unsigned int dbus_filter(unsigned int hooknum,
++ struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ struct bus_send_context *sendctx;
++ struct bus_match_maker *matchmaker = NULL;
++ struct bus_match_maker *sender = NULL;
++ struct dbus_message msg = {0,};
++ unsigned char *data;
++ size_t len;
++ int err;
++ int ret;
++
++ if (!skb->sk || skb->sk->sk_family != PF_BUS) {
++ WARN(1, "netfilter_dbus received an invalid skb");
++ return NF_DROP;
++ }
++
++ data = skb->data;
++ sendctx = BUSCB(skb).sendctx;
++ if (!sendctx || !sendctx->sender || !sendctx->sender_socket) {
++ WARN(1, "netfilter_dbus received an AF_BUS packet" \
++ " without context. This is a bug. Dropping the"
++ " packet.");
++ return NF_DROP;
++ }
++
++ if (sendctx->sender_socket->sk->sk_protocol != BUS_PROTO_DBUS) {
++ /* This kernel module is for D-Bus. It must not
++ * interfere with other users of AF_BUS. */
++ return NF_ACCEPT;
++ }
++ if (sendctx->recipient)
++ matchmaker = find_match_maker(sendctx->recipient, false, false);
++
++ len = skb_tail_pointer(skb) - data;
++
++ if (sendctx->to_master && sendctx->main_recipient) {
++ pr_debug("AF_BUS packet to the bus master. ACCEPT.\n");
++ ret = NF_ACCEPT;
++ goto out;
++ }
++
++ if (sendctx->main_recipient && !sendctx->bus_master_side) {
++ pr_debug("AF_BUS packet from a peer to a peer (unicast). ACCEPT.\n");
++ ret = NF_ACCEPT;
++ goto out;
++ }
++
++ err = dbus_message_parse(data, len, &msg);
++ if (err) {
++ if (!sendctx->main_recipient) {
++ pr_debug("AF_BUS packet for an eavesdropper or " \
++ "multicast is not parsable. DROP.\n");
++ ret = NF_DROP;
++ goto out;
++ } else if (sendctx->bus_master_side) {
++ pr_debug("AF_BUS packet from bus master is not parsable. ACCEPT.\n");
++ ret = NF_ACCEPT;
++ goto out;
++ } else {
++ pr_debug("AF_BUS packet from peer is not parsable. DROP.\n");
++ ret = NF_DROP;
++ goto out;
++ }
++ }
++
++ if (sendctx->bus_master_side && !sendctx->main_recipient) {
++ pr_debug("AF_BUS packet '%s' from the bus master is for an " \
++ "eavesdropper. DROP.\n",
++ msg.member ? msg.member : "");
++ ret = NF_DROP;
++ goto out;
++ }
++ if (sendctx->bus_master_side) {
++ if (msg.name_acquired) {
++ pr_debug("New name: %s [%p %p].\n",
++ msg.name_acquired, sendctx->sender,
++ sendctx->recipient);
++
++ sender = find_match_maker(sendctx->sender, true, false);
++ bus_matchmaker_add_name(sender, msg.name_acquired,
++ GFP_ATOMIC);
++ }
++ if (msg.name_lost) {
++ pr_debug("Lost name: %s [%p %p].\n",
++ msg.name_lost, sendctx->sender,
++ sendctx->recipient);
++
++ sender = find_match_maker(sendctx->sender, true, false);
++ bus_matchmaker_remove_name(sender, msg.name_acquired);
++ }
++
++ pr_debug("AF_BUS packet '%s' from the bus master. ACCEPT.\n",
++ msg.member ? msg.member : "");
++ ret = NF_ACCEPT;
++ goto out;
++ }
++
++ pr_debug("Multicast AF_BUS packet, %ld bytes, " \
++ "considering recipient %lld...\n", len,
++ sendctx->recipient ? sendctx->recipient->sbus_addr.s_addr : 0);
++
++ pr_debug("Message type %d %s->%s [iface: %s][member: %s][matchmaker=%p]...\n",
++ msg.type,
++ msg.sender ? msg.sender : "",
++ msg.destination ? msg.destination : "",
++ msg.interface ? msg.interface : "",
++ msg.member ? msg.member : "",
++ matchmaker);
++
++ if (!matchmaker) {
++ pr_debug("No match rules for this recipient. DROP.\n");
++ ret = NF_DROP;
++ goto out;
++ }
++
++ sender = find_match_maker(sendctx->sender, true, false);
++ err = bus_matchmaker_filter(matchmaker, sender, sendctx->eavesdropper,
++ &msg);
++ if (err) {
++ pr_debug("Matchmaker: ACCEPT.\n");
++ ret = NF_ACCEPT;
++ goto out;
++ } else {
++ pr_debug("Matchmaker: DROP.\n");
++ ret = NF_DROP;
++ goto out;
++ }
++
++out:
++ if (matchmaker)
++ kref_put(&matchmaker->kref, bus_matchmaker_free);
++ if (sender)
++ kref_put(&sender->kref, bus_matchmaker_free);
++ return ret;
++}
++
++/* Taken from drbd_nl_send_reply() */
++static void nfdbus_nl_send_reply(struct cn_msg *msg, int ret_code)
++{
++ char buffer[sizeof(struct cn_msg)+sizeof(struct nfdbus_nl_cfg_reply)];
++ struct cn_msg *cn_reply = (struct cn_msg *) buffer;
++ struct nfdbus_nl_cfg_reply *reply =
++ (struct nfdbus_nl_cfg_reply *)cn_reply->data;
++ int rr;
++
++ memset(buffer, 0, sizeof(buffer));
++ cn_reply->id = msg->id;
++
++ cn_reply->seq = msg->seq;
++ cn_reply->ack = msg->ack + 1;
++ cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply);
++ cn_reply->flags = 0;
++
++ reply->ret_code = ret_code;
++
++ rr = cn_netlink_send(cn_reply, 0, GFP_NOIO);
++ if (rr && rr != -ESRCH)
++ pr_debug("nfdbus: cn_netlink_send()=%d\n", rr);
++}
++
++/**
++ * nfdbus_check_perm - check if a pid is allowed to update match rules
++ * @sockaddr_bus: the socket address of the bus
++ * @pid: the process id that wants to update the match rules set
++ *
++ * Test if a given process id is allowed to update the match rules set
++ * for this bus. Only the process that owns the bus master listen socket
++ * is allowed to update the match rules set for the bus.
++ */
++static bool nfdbus_check_perm(struct sockaddr_bus *sbusname, pid_t pid)
++{
++ struct net *net = get_net_ns_by_pid(pid);
++ struct sock *s;
++ struct bus_address *addr;
++ struct hlist_node *node;
++ int offset = (sbusname->sbus_path[0] == '\0');
++ int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX);
++ int len;
++ if (!net)
++ return false;
++
++ len = path_len + 1 + sizeof(__kernel_sa_family_t) +
++ sizeof(struct bus_addr);
++
++ spin_lock(&bus_address_lock);
++
++ hlist_for_each_entry(addr, node, &bus_address_table[hash],
++ table_node) {
++ s = addr->sock;
++
++ if (s->sk_protocol != BUS_PROTO_DBUS)
++ continue;
++
++ if (!net_eq(sock_net(s), net))
++ continue;
++
++ if (addr->len == len &&
++ addr->name->sbus_family == sbusname->sbus_family &&
++ addr->name->sbus_addr.s_addr == BUS_MASTER_ADDR &&
++ bus_same_bus(addr->name, sbusname) &&
++ pid_nr(s->sk_peer_pid) == pid) {
++ spin_unlock(&bus_address_lock);
++ return true;
++ }
++ }
++
++ spin_unlock(&bus_address_lock);
++
++ return false;
++}
++
++static void cn_cmd_cb(struct cn_msg *msg, struct netlink_skb_parms *nsp)
++{
++ struct nfdbus_nl_cfg_req *nlp = (struct nfdbus_nl_cfg_req *)msg->data;
++ struct cn_msg *cn_reply;
++ struct nfdbus_nl_cfg_reply *reply;
++ int retcode, rr;
++ pid_t pid = task_tgid_vnr(current);
++ int reply_size = sizeof(struct cn_msg)
++ + sizeof(struct nfdbus_nl_cfg_reply);
++
++ pr_debug("nfdbus: %s nsp->pid=%d pid=%d\n", __func__, nsp->pid, pid);
++
++ if (!nfdbus_check_perm(&nlp->addr, pid)) {
++ pr_debug(KERN_ERR "nfdbus: pid=%d is not allowed!\n", pid);
++ retcode = EPERM;
++ goto fail;
++ }
++
++ cn_reply = kzalloc(reply_size, GFP_KERNEL);
++ if (!cn_reply) {
++ retcode = ENOMEM;
++ goto fail;
++ }
++ reply = (struct nfdbus_nl_cfg_reply *) cn_reply->data;
++
++ if (msg->len < sizeof(struct nfdbus_nl_cfg_req)) {
++ reply->ret_code = EINVAL;
++ } else if (nlp->cmd == NFDBUS_CMD_ADDMATCH) {
++ struct bus_match_rule *rule;
++ struct bus_match_maker *matchmaker;
++ reply->ret_code = 0;
++
++ if (msg->len == 0)
++ reply->ret_code = EINVAL;
++
++ rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC);
++ if (rule) {
++ matchmaker = find_match_maker(&nlp->addr, true, false);
++ pr_debug("Add match rule for matchmaker %p\n",
++ matchmaker);
++ bus_matchmaker_add_rule(matchmaker, rule);
++ kref_put(&matchmaker->kref, bus_matchmaker_free);
++ } else {
++ reply->ret_code = EINVAL;
++ }
++ } else if (nlp->cmd == NFDBUS_CMD_REMOVEMATCH) {
++ struct bus_match_rule *rule;
++ struct bus_match_maker *matchmaker;
++
++ rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC);
++ matchmaker = find_match_maker(&nlp->addr, false, false);
++ if (!matchmaker) {
++ reply->ret_code = EINVAL;
++ } else {
++ pr_debug("Remove match rule for matchmaker %p\n",
++ matchmaker);
++ bus_matchmaker_remove_rule_by_value(matchmaker, rule);
++ kref_put(&matchmaker->kref, bus_matchmaker_free);
++ reply->ret_code = 0;
++ }
++ bus_match_rule_free(rule);
++
++ } else if (nlp->cmd == NFDBUS_CMD_REMOVEALLMATCH) {
++ struct bus_match_maker *matchmaker;
++
++ matchmaker = find_match_maker(&nlp->addr, false, true);
++ if (!matchmaker) {
++ reply->ret_code = EINVAL;
++ } else {
++ pr_debug("Remove matchmaker %p\n", matchmaker);
++ kref_put(&matchmaker->kref, bus_matchmaker_free);
++ kref_put(&matchmaker->kref, bus_matchmaker_free);
++ reply->ret_code = 0;
++ }
++
++ } else {
++ reply->ret_code = EINVAL;
++ }
++
++ cn_reply->id = msg->id;
++ cn_reply->seq = msg->seq;
++ cn_reply->ack = msg->ack + 1;
++ cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply);
++ cn_reply->flags = 0;
++
++ rr = cn_netlink_reply(cn_reply, nsp->pid, GFP_KERNEL);
++ if (rr && rr != -ESRCH)
++ pr_debug("nfdbus: cn_netlink_send()=%d\n", rr);
++ pr_debug("nfdbus: cn_netlink_reply(pid=%d)=%d\n", nsp->pid, rr);
++
++ kfree(cn_reply);
++ return;
++fail:
++ nfdbus_nl_send_reply(msg, retcode);
++}
++
++static int __init nfdbus_init(void)
++{
++ int err;
++ struct bus_addr master_addr;
++
++ master_addr.s_addr = BUS_MASTER_ADDR;
++ hash = bus_compute_hash(master_addr);
++
++ pr_debug("Loading netfilter_dbus\n");
++
++ /* Install D-Bus netfilter hook */
++ nfho_dbus.hook = dbus_filter;
++ nfho_dbus.hooknum = NF_BUS_SENDING;
++ nfho_dbus.pf = NFPROTO_BUS; /* Do not use PF_BUS, you fool! */
++ nfho_dbus.priority = 0;
++ nfho_dbus.owner = THIS_MODULE;
++ err = nf_register_hook(&nfho_dbus);
++ if (err)
++ return err;
++ pr_debug("Netfilter hook for D-Bus: installed.\n");
++
++ /* Install connector hook */
++ err = cn_add_callback(&cn_cmd_id, "nfdbus", cn_cmd_cb);
++ if (err)
++ goto err_cn_cmd_out;
++ pr_debug("Connector hook: installed.\n");
++
++ return 0;
++
++err_cn_cmd_out:
++ nf_unregister_hook(&nfho_dbus);
++
++ return err;
++}
++
++static void __exit nfdbus_cleanup(void)
++{
++ int i;
++ struct hlist_node *node, *tmp;
++ struct bus_match_maker *matchmaker;
++ nf_unregister_hook(&nfho_dbus);
++
++ cn_del_callback(&cn_cmd_id);
++
++ spin_lock(&matchrules_lock);
++ for (i = 0; i < BUS_HASH_SIZE; i++) {
++ hlist_for_each_entry_safe(matchmaker, node, tmp,
++ &matchrules_table[i], table_node) {
++ hlist_del(&matchmaker->table_node);
++ kref_put(&matchmaker->kref, bus_matchmaker_free);
++ }
++ }
++ spin_unlock(&matchrules_lock);
++
++ pr_debug("Unloading netfilter_dbus\n");
++}
++
++module_init(nfdbus_init);
++module_exit(nfdbus_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_ALIAS_NET_PF_PROTO(PF_BUS, BUS_PROTO_DBUS);
+diff --git a/net/netfilter/nfdbus/nfdbus.h b/net/netfilter/nfdbus/nfdbus.h
+new file mode 100644
+index 0000000..477bde3
+--- /dev/null
++++ b/net/netfilter/nfdbus/nfdbus.h
+@@ -0,0 +1,44 @@
++/*
++ * nfdbus.h Netfilter module for AF_BUS/BUS_PROTO_DBUS.
++ *
++ * Copyright (C) 2012 Collabora Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef NETFILTER_DBUS_H
++#define NETFILTER_DBUS_H
++
++#include <linux/types.h>
++#include <linux/bus.h>
++
++#define NFDBUS_CMD_ADDMATCH 0x01
++#define NFDBUS_CMD_REMOVEMATCH 0x02
++#define NFDBUS_CMD_REMOVEALLMATCH 0x03
++
++struct nfdbus_nl_cfg_req {
++ __u32 cmd;
++ __u32 len;
++ struct sockaddr_bus addr;
++ __u64 pad;
++ unsigned char data[0];
++};
++
++struct nfdbus_nl_cfg_reply {
++ __u32 ret_code;
++};
++
++#endif /* NETFILTER_DBUS_H */
+diff --git a/security/capability.c b/security/capability.c
+index 5bb21b1..5b966a6 100644
+--- a/security/capability.c
++++ b/security/capability.c
+@@ -563,6 +563,12 @@ static int cap_unix_may_send(struct socket *sock, struct socket *other)
+ return 0;
+ }
+
++static int cap_bus_connect(struct sock *sock, struct sock *other,
++ struct sock *newsk)
++{
++ return 0;
++}
++
+ static int cap_socket_create(int family, int type, int protocol, int kern)
+ {
+ return 0;
+@@ -1015,6 +1021,7 @@ void __init security_fixup_ops(struct security_operations *ops)
+ #ifdef CONFIG_SECURITY_NETWORK
+ set_to_cap_if_null(ops, unix_stream_connect);
+ set_to_cap_if_null(ops, unix_may_send);
++ set_to_cap_if_null(ops, bus_connect);
+ set_to_cap_if_null(ops, socket_create);
+ set_to_cap_if_null(ops, socket_post_create);
+ set_to_cap_if_null(ops, socket_bind);
+diff --git a/security/security.c b/security/security.c
+index bf619ff..54582ea 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -1018,6 +1018,13 @@ int security_unix_may_send(struct socket *sock, struct socket *other)
+ }
+ EXPORT_SYMBOL(security_unix_may_send);
+
++int security_bus_connect(struct sock *sock, struct sock *other,
++ struct sock *newsk)
++{
++ return security_ops->bus_connect(sock, other, newsk);
++}
++EXPORT_SYMBOL(security_bus_connect);
++
+ int security_socket_create(int family, int type, int protocol, int kern)
+ {
+ return security_ops->socket_create(family, type, protocol, kern);
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index d85b793..37573f2 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -67,6 +67,7 @@
+ #include <linux/quota.h>
+ #include <linux/un.h> /* for Unix socket types */
+ #include <net/af_unix.h> /* for Unix socket types */
++#include <net/af_bus.h> /* for Bus socket types */
+ #include <linux/parser.h>
+ #include <linux/nfs_mount.h>
+ #include <net/ipv6.h>
+@@ -4102,6 +4103,39 @@ static int selinux_socket_unix_may_send(struct socket *sock,
+ &ad);
+ }
+
++static int selinux_socket_bus_connect(struct sock *sock, struct sock *other,
++ struct sock *newsk)
++{
++ struct sk_security_struct *sksec_sock = sock->sk_security;
++ struct sk_security_struct *sksec_other = other->sk_security;
++ struct sk_security_struct *sksec_new = newsk->sk_security;
++ struct common_audit_data ad;
++ struct lsm_network_audit net = {0,};
++ int err;
++
++ ad.type = LSM_AUDIT_DATA_NET;
++ ad.u.net = &net;
++ ad.u.net->sk = other;
++
++ err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
++ sksec_other->sclass,
++ UNIX_STREAM_SOCKET__CONNECTTO, &ad);
++ if (err)
++ return err;
++
++ /* server child socket */
++ sksec_new->peer_sid = sksec_sock->sid;
++ err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
++ &sksec_new->sid);
++ if (err)
++ return err;
++
++ /* connecting socket */
++ sksec_sock->peer_sid = sksec_new->sid;
++
++ return 0;
++}
++
+ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
+ u32 peer_sid,
+ struct common_audit_data *ad)
+@@ -5656,6 +5690,7 @@ static struct security_operations selinux_ops = {
+
+ .unix_stream_connect = selinux_socket_unix_stream_connect,
+ .unix_may_send = selinux_socket_unix_may_send,
++ .bus_connect = selinux_socket_bus_connect,
+
+ .socket_create = selinux_socket_create,
+ .socket_post_create = selinux_socket_post_create,
+--
+1.7.7.6
+
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/beagle_qemu.cfg b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/beagle_qemu.cfg
new file mode 100644
index 0000000..0ace211
--- /dev/null
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/beagle_qemu.cfg
@@ -0,0 +1,5 @@
+CONFIG_PANEL_GENERIC_DPI=y
+
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_OMAP3=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg
new file mode 100644
index 0000000..eb78e01
--- /dev/null
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86.cfg
@@ -0,0 +1,13 @@
+#additional configs requested by SysInfra EG
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+
+# config for adding support for AF_BUS sockets
+CONFIG_AF_BUS=y
+CONFIG_NETFILTER_DBUS=y
+
+# Activate ecryptfs
+CONFIG_EXPERIMENTAL=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO=y
+CONFIG_ECRYPT_FS=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
new file mode 100644
index 0000000..eb78e01
--- /dev/null
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/qemux86_64.cfg
@@ -0,0 +1,13 @@
+#additional configs requested by SysInfra EG
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+
+# config for adding support for AF_BUS sockets
+CONFIG_AF_BUS=y
+CONFIG_NETFILTER_DBUS=y
+
+# Activate ecryptfs
+CONFIG_EXPERIMENTAL=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO=y
+CONFIG_ECRYPT_FS=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
new file mode 100644
index 0000000..bbe9ba3
--- /dev/null
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto/vexpress_a9.cfg
@@ -0,0 +1,843 @@
+# Kernel fragment taken from linaro.org
+# http://releases.linaro.org/platform/linaro-n/hwpacks/11.09/
+
+CONFIG_AC97_BUS=y
+CONFIG_AEABI=y
+CONFIG_AIO=y
+CONFIG_ALIGNMENT_TRAP=y
+CONFIG_ANON_INODES=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_VEXPRESS_CA9X4=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_CPU_TOPOLOGY=y
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_TIMER_SP804=y
+CONFIG_ARM_UNWIND=y
+CONFIG_AT76C50X_USB=m
+CONFIG_ATA=y
+CONFIG_ATAGS_PROC=y
+CONFIG_ATA_BMDMA=y
+CONFIG_ATA_SFF=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATH_COMMON=m
+CONFIG_AUDIT=y
+CONFIG_AUDIT_GENERIC=y
+CONFIG_AUTOFS4_FS=m
+CONFIG_AVERAGE=y
+CONFIG_B43=m
+CONFIG_B43LEGACY=m
+CONFIG_B43LEGACY_DEBUG=y
+CONFIG_B43LEGACY_DMA=y
+CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
+CONFIG_B43LEGACY_HWRNG=y
+CONFIG_B43LEGACY_LEDS=y
+CONFIG_B43LEGACY_PIO=y
+CONFIG_B43_HWRNG=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_PIO=y
+CONFIG_B43_SSB=y
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+CONFIG_BCMA_POSSIBLE=y
+CONFIG_BINARY_PRINTF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BITREVERSE=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLOCK=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_BOUNCE=y
+CONFIG_BRANCH_PROFILE_NONE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BT=m
+CONFIG_BTRFS_FS=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BUG=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CACHE_PL310=y
+CONFIG_CAN_PM_TRACE=y
+CONFIG_CARL9170=m
+CONFIG_CARL9170_LEDS=y
+CONFIG_CARL9170_WPC=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CFG80211=m
+CONFIG_CFG80211_DEFAULT_PS=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_CGROUPS=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_CONNECTOR=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_CPUSETS=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_HAS_PMU=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRAMFS=y
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CROSS_COMPILE=""
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_PREEMPT=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_USER=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DEFAULT_CFQ=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+CONFIG_DEFAULT_SECURITY="apparmor"
+CONFIG_DEFAULT_SECURITY_APPARMOR=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DNOTIFY=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DYNAMIC_FTRACE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_ELF_CORE=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_EPOLL=y
+CONFIG_EVENTFD=y
+CONFIG_EVENT_POWER_TRACING_DEPRECATED=y
+CONFIG_EVENT_TRACING=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_EXPERT=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_FAT_FS=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FLATMEM=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAME_WARN=1024
+CONFIG_FREEZER=y
+CONFIG_FSNOTIFY=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FTRACE=y
+CONFIG_FTRACE_MCOUNT_RECORD=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FUTEX=y
+CONFIG_FW_LOADER=y
+CONFIG_GENERIC_ACL=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAVE_AOUT=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_MACH_CLKDEV=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PATA_PLATFORM=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_KYE=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_HOTPLUG=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HWMON=m
+CONFIG_HW_CONSOLE=y
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_HW_RANDOM=m
+CONFIG_HZ=100
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_ICST=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INET=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_INOTIFY_USER=y
+CONFIG_INPUT=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_MOUSE=y
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_IOMMU_SUPPORT=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IPV6=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_SIT=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_WORK=y
+CONFIG_ISO9660_FS=m
+CONFIG_JBD=y
+CONFIG_JBD2=y
+CONFIG_JFFS2_CMODE_PRIORITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JOLIET=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KERNEL_GZIP=y
+CONFIG_KEXEC=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_TWL4030=y
+CONFIG_KEYS=y
+CONFIG_KPROBES=y
+CONFIG_KPROBES_SANITY_TEST=y
+CONFIG_KPROBE_EVENT=y
+CONFIG_KRETPROBES=y
+CONFIG_KS8851=y
+CONFIG_KS8851_MLL=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_LBDAF=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LIB80211=m
+CONFIG_LIBCRC32C=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_SPI=m
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LOCAL_TIMERS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKDEP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKD_V4=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_HWSIM=m
+CONFIG_MAC80211_LEDS=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MD=y
+CONFIG_MII=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_MMC=y
+CONFIG_MMC_ARMMMCI=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMU=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+CONFIG_MSDOS_FS=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_MTD=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_OOPS=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_NAMESPACES=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEON=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETLABEL=y
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_NET_SCHED=y
+CONFIG_NEW_LEDS=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_USE_KERNEL_DNS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NLATTR=y
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NOP_TRACER=y
+CONFIG_NO_HZ=y
+CONFIG_NR_CPUS=4
+CONFIG_OC_ETM=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_DEVICE=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_I2C=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OF_SPI=y
+CONFIG_OPROFILE=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_P54_COMMON=m
+CONFIG_P54_LEDS=y
+CONFIG_P54_SPI=m
+CONFIG_P54_USB=m
+CONFIG_PACKET=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PHYLIB=y
+CONFIG_PLAT_VERSATILE=y
+CONFIG_PLAT_VERSATILE_CLCD=y
+CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y
+CONFIG_PM=y
+CONFIG_PM_ADVANCED_DEBUG=y
+CONFIG_PM_CLK=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+CONFIG_PREEMPT_RCU=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTK=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_EVENTS=y
+CONFIG_PROC_FS=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROFILING=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+CONFIG_RCU_FANOUT=32
+CONFIG_RD_BZIP2=y
+CONFIG_RD_GZIP=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_RD_XZ=y
+CONFIG_REGMAP=y
+CONFIG_RELAY=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RING_BUFFER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_ROOT_NFS=y
+CONFIG_RPS=y
+CONFIG_RT2500USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT35XX=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_RT2800_LIB=m
+CONFIG_RT2X00=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_LEDS=y
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT73USB=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PL031=y
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+CONFIG_RTL8192CU=m
+CONFIG_RTL8192C_COMMON=m
+CONFIG_RTLWIFI=m
+CONFIG_RT_MUTEXES=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_SCSI_MOD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_PROC_FS=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+CONFIG_SDIO_UART=y
+CONFIG_SECCOMP=y
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PATH=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIO=y
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SHMEM=y
+CONFIG_SIGNALFD=y
+CONFIG_SLAB=y
+CONFIG_SLABINFO=y
+CONFIG_SMC91X=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+CONFIG_SND=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_ARM=y
+CONFIG_SND_ARMAACI=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_HWDEP=m
+CONFIG_SND_JACK=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_PCM=y
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+CONFIG_SND_SPI=y
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VMASTER=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_PL022=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+CONFIG_SSB=m
+CONFIG_SSB_BLOCKIO=y
+CONFIG_SSB_POSSIBLE=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+CONFIG_STACKTRACE=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_STANDALONE=y
+CONFIG_STOP_MACHINE=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWAP=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYN_COOKIES=y
+CONFIG_SYSCTL=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSFS=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_TIMERFD=y
+CONFIG_TIMER_STATS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TRACEPOINTS=y
+CONFIG_TRACE_IRQFLAGS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_TUN=y
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_TWL4030_WATCHDOG=y
+CONFIG_TWL6030_USB=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_UID16=y
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_USB=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_DEVICE_CLASS=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_FUSB300=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_HID=y
+CONFIG_USB_ISP1760_HCD=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_MON=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_NET_CDC_NCM=y
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_NET_NET1080=y
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_OTG=y
+CONFIG_USB_OTG_UTILS=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_TEST=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_WDM=y
+CONFIG_USB_ZD1201=m
+CONFIG_USB_ZERO=m
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFAT_FS=y
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_WL1251=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL12XX=m
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX_PLATFORM_DATA=y
+CONFIG_WL12XX_SDIO=m
+CONFIG_WL12XX_SPI=m
+CONFIG_WLAN=y
+CONFIG_XFRM=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_USER=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZD1211RW=m
+CONFIG_ZISOFS=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
+
+#additional configs requested by SysInfra EG
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+
+# config for adding support for AF_BUS sockets
+CONFIG_AF_BUS=y
+CONFIG_NETFILTER_DBUS=y
+
+CONFIG_REGULATOR=n
+
+# Activate ecryptfs
+CONFIG_EXPERIMENTAL=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO=y
+CONFIG_ECRYPT_FS=y
diff --git a/meta-ivi-bsp/recipes-kernel/linux/linux-yocto_3.8.bbappend b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto_3.8.bbappend
new file mode 100644
index 0000000..c09d607
--- /dev/null
+++ b/meta-ivi-bsp/recipes-kernel/linux/linux-yocto_3.8.bbappend
@@ -0,0 +1,25 @@
+PRINC := "${@int(PRINC) + 2}"
+
+# find defconfig path
+FILESEXTRAPATHS := "${THISDIR}/${PN}"
+
+# Kernel configs
+SRC_URI_append_beagleboard = " \
+ file://beagle_qemu.cfg \
+ "
+
+SRC_URI_append_vexpressa9 = " \
+ file://vexpress_a9.cfg \
+ "
+
+SRC_URI_append_qemux86 = " \
+ file://qemux86.cfg \
+ "
+
+SRC_URI_append_qemux86-64 = " \
+ file://qemux86_64.cfg \
+ "
+
+KMACHINE_vexpressa9 = "beagleboard"
+SRCREV_machine_vexpressa9 ?= "${AUTOREV}"
+COMPATIBLE_MACHINE_vexpressa9 = "vexpressa9"