From: Greg Kroah-Hartman Date: Wed, 11 Sep 2013 20:03:45 +0000 (-0700) Subject: start the 3.10 series X-Git-Tag: v3.10.28-ltsi-rc1~28 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ef93f49acef249cc4d5c6593313a7439d00e0228;p=platform%2Fkernel%2Flinux-stable.git start the 3.10 series Remove everything, as it all fails to build, except for lttng. That too fails to build, but hopefully someone will send me patches to fix that soon... Signed-off-by: Greg Kroah-Hartman --- diff --git a/patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch b/patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch deleted file mode 100644 index fa2f7f903425..000000000000 --- a/patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 6a6b05153678be7f443dc66be6fac842135aac00 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 12:07:49 +0200 -Subject: [PATCH 01/15] net: bus: add the AF_BUS socket address family - -AF_BUS is a new socket address family that allows both unicast and -multicast I on a local machine with total ordering for messages -(every process on the same bus sees each message in the same order). - -A process can create buses to which other processes can connect and -communicate with each other by sending messages. Processes' addresses are -automatically assigned by the bus on connect and are unique. Messages can -be sent either to process' unique address or to a bus multicast address. - -Signed-off-by: Javier Martinez Canillas ---- - include/linux/socket.h | 5 ++++- - net/core/sock.c | 6 +++--- - 2 files changed, 7 insertions(+), 4 deletions(-) - -diff --git a/include/linux/socket.h b/include/linux/socket.h -index b84bbd4..59596d2 100644 ---- a/include/linux/socket.h -+++ b/include/linux/socket.h -@@ -195,7 +195,8 @@ struct ucred { - #define AF_CAIF 37 /* CAIF sockets */ - #define AF_ALG 38 /* Algorithm sockets */ - #define AF_NFC 39 /* NFC sockets */ --#define AF_MAX 40 /* For now.. */ -+#define AF_BUS 40 /* BUS sockets */ -+#define AF_MAX 41 /* For now.. */ - - /* Protocol families, same as address families. */ - #define PF_UNSPEC AF_UNSPEC -@@ -238,6 +239,7 @@ struct ucred { - #define PF_CAIF AF_CAIF - #define PF_ALG AF_ALG - #define PF_NFC AF_NFC -+#define PF_BUS AF_BUS - #define PF_MAX AF_MAX - - /* Maximum queue length specifiable by listen. */ -@@ -312,6 +314,7 @@ struct ucred { - #define SOL_IUCV 277 - #define SOL_CAIF 278 - #define SOL_ALG 279 -+#define SOL_BUS 280 - - /* IPX options */ - #define IPX_TYPE 1 -diff --git a/net/core/sock.c b/net/core/sock.c -index 4b469e3..7d6d3f6 100644 ---- a/net/core/sock.c -+++ b/net/core/sock.c -@@ -205,7 +205,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = { - "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , - "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , - "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" , -- "sk_lock-AF_NFC" , "sk_lock-AF_MAX" -+ "sk_lock-AF_NFC" , "sk_lock-AF_BUS" , "sk_lock-AF_MAX" - }; - static const char *const af_family_slock_key_strings[AF_MAX+1] = { - "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , -@@ -221,7 +221,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = { - "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , - "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , - "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" , -- "slock-AF_NFC" , "slock-AF_MAX" -+ "slock-AF_NFC" , "slock-AF_BUS" , "slock-AF_MAX" - }; - static const char *const af_family_clock_key_strings[AF_MAX+1] = { - "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , -@@ -237,7 +237,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = { - "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , - "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , - "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" , -- "clock-AF_NFC" , "clock-AF_MAX" -+ "clock-AF_NFC" , "clock-AF_BUS" , "clock-AF_MAX" - }; - - /* --- -1.7.7.6 - diff --git a/patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch b/patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch deleted file mode 100644 index 37c85e7dcaa5..000000000000 --- a/patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch +++ /dev/null @@ -1,581 +0,0 @@ -From 9943977a50f55ee53cde6f9c4fa4f1bb25761d71 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Tue, 26 Jun 2012 14:32:43 +0200 -Subject: [PATCH 02/15] net: bus: Add AF_BUS documentation - -AF_BUS is different to other POSIX BSD sockets address families so a -is good to have a documentation about its design, ABI and semantics. - -Signed-off-by: Javier Martinez Canillas ---- - Documentation/networking/af_bus.txt | 558 +++++++++++++++++++++++++++++++++++ - 1 files changed, 558 insertions(+), 0 deletions(-) - create mode 100644 Documentation/networking/af_bus.txt - -diff --git a/Documentation/networking/af_bus.txt b/Documentation/networking/af_bus.txt -new file mode 100644 -index 0000000..cfef22f ---- /dev/null -+++ b/Documentation/networking/af_bus.txt -@@ -0,0 +1,558 @@ -+ The AF_BUS socket address family -+ ================================ -+ -+Introduction -+------------ -+ -+AF_BUS is a message oriented inter process communication system. -+ -+The principle features are: -+ -+ - Reliable datagram based communication (all sockets are of type -+ SOCK_SEQPACKET) -+ -+ - Multicast message delivery (one to many, unicast as a subset) -+ -+ - Strict ordering (messages are delivered to every client in the same order) -+ -+ - Ability to pass file descriptors -+ -+ - Ability to pass credentials -+ -+The basic concept is to provide a virtual bus on which multiple -+processes can communicate and policy is imposed by a "bus master". -+ -+A process can create buses to which other processes can connect and -+communicate with each other by sending messages. Processes' addresses -+are automatically assigned by the bus on connect and are -+unique. Messages can be sent either to a process' unique address or to -+a bus multicast addresses. -+ -+Netfilter rules or Berkeley Packet Filter can be used to restrict the -+messages that each peer is allowed to receive. This is especially -+important when sending to multicast addresses. -+ -+Besides messages, process can send and receive ancillary data (i.e., -+SCM_RIGHTS for passing file descriptors or SCM_CREDENTIALS for passing -+Unix credentials). In the case of a multicast message all recipients -+of a message may obtain a copy a file descriptor or credentials. -+ -+A bus is created by processes connecting on an AF_BUS socket. The -+"bus master" binds itself instead of connecting to the NULL address. -+ -+The socket address is made up of a path component and a numeric -+component. The path component is either a pathname or an abstract -+socket similar to a unix socket. The numeric component is used to -+uniquely identify each connection to the bus. Thus the path identifies -+a specific bus and the numeric component the attachment to that bus. -+ -+The process that calls bind(2) on the socket is the owner of the bus -+and is called the bus master. The master is a special client of the -+bus and has some responsibility for the bus' operation. The master is -+assigned a fixed address with all the bits zero (0x0000000000000000). -+ -+Each process connected to an AF_BUS socket has one or more addresses -+within that bus. These addresses are 64-bit unsigned integers, -+interpreted by splitting the address into two parts: the most -+significant 16 bits are a prefix identifying the type of address, and -+the remaining 48 bits are the actual client address within that -+prefix, as shown in this figure: -+ -+Bit: 0 15 16 63 -+ +----------------+------------------------------------------------+ -+ | Type prefix | Client address | -+ +----------------+------------------------------------------------+ -+ -+The prefix with all bits zero is reserved for use by the kernel, which -+automatically assigns one address from this prefix to each client on -+connection. The address in this prefix with all bits zero is always -+assigned to the bus master. Addresses on the prefix 0x0000 are unique -+and will never repeat for the lifetime of the bus master. -+ -+A client may have multiple addresses. When data is sent to other -+clients, those clients will always see the sender address that is in -+the prefix 0x0000 address space when calling recvmsg(2) or -+recvfrom(2). Similarly, the prefix 0x0000 address is returned by calls -+to getsockname(2) and getpeername(2). -+ -+For each prefix, the address where the least significant 48 bits are -+all 1 (i.e., 0xffffffffffff) is also reserved, and can be used to send -+multicast messages to all the peers on a prefix. -+ -+The non-reserved addresses in each of the remaining prefixes are -+managed by the bus master, which may assign additional addresses to -+any other connected socket. -+ -+Having different name-spaces has two advantages: -+ -+ - Clients can have addresses on different mutually-exclusive -+ scopes. This permits sending multicast packets to only clients -+ that have addresses on a given prefix. -+ -+ - The addressing scheme can be more flexible. The kernel will only -+ assign unique addresses on the all-bits-zero prefix (0x0000) and -+ allows the bus master process to assign additional addresses to -+ clients on other prefixes. By having different prefixes, the -+ kernel and bus master assignments will not collide. -+ -+AF_BUS transport can support two network topologies. When a process -+first connects to the bus master, it can only communicate with the bus -+master. The process can't send and receive packets from other peers on -+the bus. So, from the client process point of view the network -+topology is point-to-point. -+ -+The bus master can allow the connected peer to be part of the bus and -+start to communicate with other peers by setting a socket option with -+the setsockopt(2) system call using the accepted socket descriptor. At -+this point, the topology becomes a bus to the client process. -+ -+Packets whose destination address is not assigned to any client are -+routed by default to the bus master (the client accepted socket -+descriptor). -+ -+ -+Semantics -+--------- -+ -+Bus features: -+ -+ - Unicast and multicast addressing scheme. -+ - Ability to assign addresses from user-space with different prefixes. -+ - Automatic address assignment. -+ - Ordered packets delivery (FIFO, total ordering). -+ - File descriptor and credentials passing. -+ - Support for both point-to-point and bus network topologies. -+ - Bus control access managed from user-space. -+ - Netfilter hooks for packet sending, routing and receiving. -+ -+A process (the "bus master") can create an AF_BUS bus with socket(2) -+and use bind(2) to assign an address to the bus. Then it can listen(2) -+on the created socket to start accepting incoming connections with -+accept(2). -+ -+Processes can connect to the bus by creating a socket with socket(2) -+and using connect(2). The kernel will assign a unique address to each -+connection and messages can be sent and received by using BSD socket -+primitives. -+ -+This uses the connect(2) semantic in a non-traditional way, with -+AF_BUS sockets, it's not possible to connect "my" socket to a specific -+peer socket whereas the traditional BSD sockets API usage, connect(2) -+either connects to stream sockets, or assigns a peer address to a -+datagram socket (so that send(2) can be used instead of sendto()). -+ -+An AF_BUS socket address is represented as a combination of a bus -+address and a bus path name. Address are unique within a path. The -+unique bus address is further subdivided into a prefix and a client -+address. Thus the path identifies a specific bus and the numeric -+component the attachment to that bus. -+ -+#define BUS_PATH_MAX 108 -+ -+/* Bus address */ -+struct bus_addr { -+ uint64_t s_addr; /* 16-bit prefix + 48-bit client address */ -+}; -+ -+/* Structure describing an AF_BUS socket address. */ -+struct sockaddr_bus { -+ sa_family_t sbus_family; /* AF_BUS */ -+ struct bus_addr sbus_addr; /* bus address */ -+ char sbus_path[BUS_PATH_MAX]; /* pathname */ -+}; -+ -+A process becomes a bus master for a given struct sockaddr_bus by -+calling bind(2) on an AF_BUS addresses. The argument must be { AF_BUS, -+0, path }. -+ -+AF_BUS supports both abstract and non-abstract path names. Abstract -+names are distinguished by the fact that sbus_path[0] == '\0' and they -+don't represent file system paths while non-abstract paths are bound -+to a file system path name. (See the unix(7) man page for a discussion -+of abstract socket addresses in the AF_UNIX address family.) -+ -+Then the process calls listen(2) to accept incoming connections. If -+that process calls getsockname(2), the returned address will be { -+AF_BUS, 0, path }. -+ -+The conventional string form of the full address is path + ":" + -+prefix + "/" + client address. Prefix and client address are -+represented in hex. -+ -+For example the address: -+ -+struct sockaddr_bus addr; -+addr.sbus_family = AF_BUS; -+strcpy(addr.sbus_path, "/tmp/test"); -+addr.sbus_addr.s_addr = 0x0002f00ddeadbeef; -+ -+would be represented using the string /tmp/test:0002/f00ddeadbeef. -+ -+If the bus_addr is 0, then both the prefix and client address may be -+omitted from the string form. To connect to a bus as a client it is -+sufficient to specify the path, since the listening address always has -+bus_addr == 0. it is not meanigful to specify 'bus_addr' as other than -+0 on connect() -+ -+The AF_BUS implementation will automatically assign a unique address -+to each client but the bus master can assign additional addresses on a -+different prefix by means of the setsockopt(2) system call. For -+example: -+ -+struct bus_addr addr; -+addr.s_addr = 0x0001deadfee1dead; -+ret = setsockopt(afd, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr)); -+ -+where afd is the accepted socket descriptor in the daemon. To show graphically: -+ -+ L The AF_BUS listening socket } -+ / | \ }-- listener process -+ A1 A2 A3 The AF_BUS accepted sockets } -+ | | | -+ C1 C2 C3 The AF_BUS connected sockets }-- client processes -+ -+So if setsockopt(A1, SOL_BUS, BUS_ADD_ADDR, &addr, sizeof(addr)) is -+called, C1 will get the new address. -+ -+The inverse operation is BUS_DEL_ADDR, which the bus master can use to -+remove a client socket AF_BUS address: -+ -+ret = setsockopt(afd, SOL_BUS, BUS_DEL_ADDR, &addr, sizeof(addr)); -+ -+Besides assigning additional addresses, the bus master has to allow a -+client process to communicate with other peers on the bus using a -+setsockopt(2): -+ -+ret = setsockopt(afd, SOL_BUS, BUS_JOIN_BUS, NULL, 0); -+ -+Clients are not meant to send messages to each other until the master -+tells them (in a protocol-specific way) that the BUS_JOIN_BUS -+setsockopt(2) call was made. -+ -+If a client sends a message to a destination other than the bus -+master's all-zero address before joining the bus, a EHOSTUNREACH (No -+route to host) error is returned since the only host that exists in -+the point-to-point network before the client joins the bus are the -+client and the bus master. -+ -+A EHOSTUNREACH is returned if a client that joined a bus tries to send -+a packet to a client from another bus. Cross-bus communication is not -+permited. -+ -+When a process wants to send a unicast message to a peer, it fills a -+sockaddr structure and performs a socket operation (i.e., sendto(2)) -+ -+struct sockaddr_bus addr; -+char *msg = "Hello world"; -+ -+addr.sbus_family = AF_BUS; -+strcpy(addr.sbus_path, "/tmp/test"); -+addr.sbus_addr.s_addr = 0x0001f00ddeadbeef; -+ -+ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0, -+ (struct sockaddr*)&addr, sizeof(addr)); -+ -+The current implementation requires that the addr.sbus_path component -+match the one used to conenct() to the bus but in future this -+requirement will be removed. -+ -+The kernel will first check that the socket is connected and that the -+bus path of the socket correspond with the destination, then it will -+extract the prefix and client address from the bus address using a -+fixed 16 -bit bitmask. -+ -+prefix = bus address >> 48 & 0xffff -+client address = bus address & 0xffff -+ -+If the client address is not all bits one, then the message is unicast -+and is delivered to the socket with that assigned address -+(0x0001f00ddeadbeef). Otherwise the message is multicast and is -+delivered to all the peers with this address prefix (0x0001 in this -+case). -+ -+So, when a process wants to send a multicast message, it just has to -+fill the address structure with the address prefix + 0xffffffffffff: -+ -+struct sockaddr_bus addr; -+char *msg = "Hello world"; -+ -+addr.bus_family = AF_BUS; -+strcpy(addr.sbus_path, "/tmp/test"); -+addr.bus_addr = 0x0001ffffffffffff; -+ -+ret = sendto(sockfd, "Hello world", strlen("Hello world"), 0, -+ (struct sockaddr*)&addr, sizeof(addr)); -+ -+The kernel, will apply the binary and operation, learn that the -+address is 0xffffffffffff and send the message to all the peers on -+this prefix (0x0001). -+ -+Socket transmit queued bytes are limited by a maximum send buffer size -+(sysctl_wmem_max) defined in the kernel and can be modified at runtime -+using the sysctl interface on /proc/sys/net/core/wmem_default. This -+parameter is global for all the sockets families in a Linux system. -+ -+AF_BUS permits the definition of a per-bus maximum send buffer size -+using the BUS_SET_SENDBUF socket option. The bus master can call the -+setsockopt(2) system call using as a parameter the listening socket. -+The command sets a maximum write buffer that will be imposed on each -+new socket that connects to the bus: -+ -+ret = setsockopt(serverfd, SOL_BUS, BUS_SET_SENDBUF, &sndbuf, -+sizeof(int)); -+ -+In the transmission path both Berkeley Packet Filters and Netfilter -+hooks are available, so they can be used to filter sending packets. -+ -+ -+Using this addressing scheme with D-Bus -+--------------------------------------- -+ -+As an example of a use case for AF_BUS, let's analyze how the D-Bus -+IPC system can be implemented on top of it. -+ -+We define a new D-Bus address type "afbus". -+ -+A D-Bus client may connect to an address of the form "afbus:path=X" -+where X is a string. This means that it connect()s to { AF_BUS, 0, X }. -+ -+For example: afbus:path=/tmp/test connects to { AF_BUS, 0, /tmp/test }. -+ -+A D-Bus daemon may listen on the address "afbus:", which means that it -+binds to { AF_BUS, 0, /tmp/test }. It will advertise an address of the -+form "afbus:path=/tmp/test" to clients, for instance via the -+--print-address option, or via dbus-launch setting the -+DBUS_SESSION_BUS_ADDRESS environment variable. For instance, "afbus:" -+is an appropriate default listening address for the session bus, -+resulting in dbus-launch setting the DBUS_SESSION_BUS_ADDRESS -+environment variable to something like -+"afbus:path=/tmp/test,guid=...". -+ -+A D-Bus daemon may listen on the address "afbus:file=/some/file", -+which means that it will do as above, then write its path into the -+given well-known file. For instance, -+"afbus:file=/run/dbus/system_bus.afbus" is an appropriate listening -+address for the system bus. Only processes with suitable privileges to -+write to that file can impersonate the system bus. -+ -+D-Bus clients wishing to connect to the well-known system bus should -+attempt to connect to afbus:file=/run/dbus/system_bus.afbus, falling -+back to unix:path=/var/run/dbus/system_bus_socket if that fails. On -+Linux systems, the well-known system bus daemon should attempt to -+listen on both of those addresses. -+ -+The D-Bus daemon will serve as bus master as well since it will be the -+process that creates and listens on the AF_BUS socket. -+ -+D-Bus clients will use the fixed bus master address (all zero bits) to -+send messages to the D-Bus daemon and the client's unique address to -+send messages to other D-Bus clients using the bus. -+ -+When initially connected, D-Bus clients will only be able to -+communicate with the D-Bus daemon and will send authentication -+information (AUTH message and SCM_CREDENTIALS ancillary -+messages). Since the D-Bus daemon is also the bus master, it can allow -+D-Bus clients to join the bus and be able to send and receive D-Bus -+messages from other peers. -+ -+On connection, the kernel will assign to each client an address in the -+prefix 0x0000. If a client attempts to send messages to clients other -+than the bus master, this is considered to be an error, and is -+prevented by the kernel. -+ -+When the D-Bus daemon has authenticated a client and determined that -+it is authorized to be on this bus, it uses a setsockopt(2) call to -+tell the kernel that this client has permission to send messages. The -+D-Bus daemon then tells the client by sending the Hello() reply that -+it has made the setsockopt(2) call and that now is able to send -+messages to other peers on the bus. -+ -+Well-known names are represented by addresses in the 0x0001, ... prefixes. -+ -+Addresses in prefix 0x0000 must be mapped to D-Bus unique names in a -+way that can't collide with unique names allocated by the dbus-daemon -+for legacy clients. -+ -+In order to be consistent with current D-Bus unique naming, the AF_BUS -+addresses can be mapped directly to D-Bus unique names, for example -+(0000/0000deadbeef to ":0.deadbeef"). Leading zeroes can be suppressed -+since the common case should be relatively small numbers (the kernel -+allocates client addresses sequentially, and machines could be -+rebooted occasionally). -+ -+By having both AF_BUS and legacy D-Bus clients use the same address -+space, the D-Bus daemon can act as a proxy between clients and can be -+sure that D-Bus unique names will be unique for both AF_BUS and legacy -+clients. -+ -+To act as a proxy between AF_BUS and legacy clients, each time the -+D-Bus daemon accepts a legacy connection (i.e., AF_UNIX), it will -+create an AF_BUS socket and establish a connection with itself. It -+will then associate this newly created connection with the legacy one. -+ -+To explain it graphically: -+ -+ L The AF_BUS listening socket } -+ / | \ }-- listener process -+ A1 A2 A3 The AF_BUS accepted sockets } -+ | | | -+ C1 C2 C3 The AF_BUS connected sockets, where: -+ | * C1 belongs to the listener process -+ | * C2 and C3 belongs to the client processes -+ | -+ L2--A4 The AF_UNIX listening and accepted sockets \ -+ | in the listener process -+ C4 The AF_UNIX connected socket in the legacy client process -+ -+ -+where C2 and C3 are normal AF_BUS clients and C4 is a legacy -+client. The D-Bus daemon after accepting the connection using the -+legacy transport (A4), will create an AF_BUS socket pair (C1, A1) -+associated with the legacy client. -+ -+Legacy clients will send messages to the D-Bus daemon using their -+legacy socket and the D-Bus daemon will extract the destination -+address, resolve to the corresponding AF_BUS address and use this to -+send the message to the right peer. -+ -+Conversely, when an AF_BUS client sends a D-Bus message to a legacy -+client, it will use the AF_BUS address of the connection associated -+with that client. The D-Bus daemon will receive the message, modify -+the message's content to set SENDER headers based on the AF_BUS source -+address and use the legacy transport to send the D-Bus message to the -+legacy client. -+ -+As a special case, the bus daemon's all-zeroes address maps to -+"org.freedesktop.DBus" and vice versa. -+ -+When a D-Bus client receives an AF_BUS message from the bus master -+(0/0), it must use the SENDER header field in the D-Bus message, as -+for any other D-Bus transport, to determine whether the message is -+actually from the D-Bus daemon (the SENDER is "org.freedesktop.DBus" -+or missing), or from another client (the SENDER starts with ":"). It -+is valid for messages from another AF_BUS client to be received via -+the D-Bus daemon; if they are, the SENDER header field will always be -+set. -+ -+Besides its unique name, D-Bus services can have well-known names such -+as org.gnome.Keyring or org.freedesktop.Telepathy. These well-known -+names can also be used as a D-Bus message destination -+address. Well-known names are not numeric and AF_BUS is not able to -+parse D-Bus messages. -+ -+To solve this, the D-Bus daemon will assign an additional AF_BUS -+address to each D-Bus client that owns a well-known name. The mapping -+between well-known names and AF_BUS address is maintained by the D-Bus -+daemon on a persistent data structure. -+ -+D-Bus client libraries will maintain a cache of these mappings so they -+can send messages to services with well-known names using their mapped -+AF_BUS address. -+ -+If a client intending to send a D-Bus message to a given well-known -+name does not have that well-known name in its cache, it must send the -+AF_BUS message to the listener (0000/000000000000) instead. -+ -+The listener must forward the D-Bus message to the owner of that -+well-known name, setting the SENDER header field if necessary. It may -+also send this AF_BUS-specific D-Bus signal to the sender, so that the -+sender can update its cache: -+ -+ org.freedesktop.DBus.AF_BUS.Forwarded (STRING well_known_name, -+ UINT64 af_bus_client) -+ -+ Emitted by the D-Bus daemon with sender "org.freedesktop.DBus" -+ and object path "/org/freedesktop/DBus" to indicate that -+ the well-known name well_known_name is represented by the -+ AF_BUS address { AF_BUS, af_bus_client, path } where -+ path is the path name used by this bus. -+ -+ For instance, if the well-known name "org.gnome.Keyring" -+ is represented by AF_BUS address 0001/0000deadbeef, -+ the signal would have arguments ("org.gnome.Keyring", -+ 0x00010000deadbeef), corresponding to the AF_BUS -+ address { AF_BUS, 0x00010000deadbeef, /tmp/test }. -+ -+If the D-Bus service for that well-known name is not active, then the -+D-Bus daemon will first do the service activation, assign an -+additional address to the recently activated service, store the -+well-known service to numeric address mapping on its persistent cache, -+and then send the AF_BUS.Forwarded signal back to the client. -+ -+Once the mapping has been made, the AF_BUS address associated with a -+well-known name cannot be reused for the lifetime of the D-Bus daemon -+(which is the same as the lifetime of the socket). -+ -+Nevertheless the AF_BUS address associated with a well-known name can -+change, for example if a service goes away and a new instance gets -+activated. This new instance can have a different AF_BUS address. The -+D-Bus daemon will maintain a list of the mappings that are currently -+valid so it can send the AF_BUS. -+ -+Forwarded signal with the mapping information to the clients. Client -+libraries will maintain a fixed-size Last Recently Used (LRU) cache -+with previous mappings sent by the D-Bus daemon. -+ -+If the clients overwrite a mapping due to the LRU replace policy and -+later want to send a D-Bus message to the overwritten well-known name, -+they will send the D-Bus message back to the D-Bus daemon and this -+will send the signal with the mapping information. -+ -+If a service goes away or if the service AF_BUS address changed and -+the client still has the old AF_BUS address in its cache, it will send -+the D-Bus message to the old destination. -+ -+Since packets whose destination AF_BUS addresses are not assigned to -+any process are routed by default to the bus master, the D-Bus daemon -+will receive these D-bus messages and send an AF_BUS. -+ -+Forwarded signal back to the client with the new AF_BUS address so it -+can update its cache with the new mapping. -+ -+For well-known names, the D-Bus daemon will use a different address -+prefix (0x0001) so it doesn't conflict with the D-Bus unique names -+address prefix (0x0000). -+ -+Besides D-Bus method call messages which are unicast, D-Bus allows -+clients to send multicast messages (D-Bus signals). Clients can send -+signals messages using the bus unique name prefix multicast address -+(0x0001ffffffffffff). -+ -+A netfilter hook is used to filter these multicast messages and only -+deliver to the correct peers based on match rules. -+ -+ -+D-Bus aware netfilter module -+---------------------------- -+ -+AF_BUS is designed to be a generic bus transport supporting both -+unicast and multicast communications. -+ -+In order for D-Bus to operate efficiently, the transport method has to -+know the D-Bus message wire-protocol and D-Bus message structure. But -+adding this D-Bus specific knowledge to AF_BUS will break one of the -+fundamental design principles of any network protocol stack, namely -+layer-independence: layer n must not make any assumptions about the -+payload in layer n + 1. -+ -+So, in order to have a clean protocol design but be able to allow the -+transport to analyze the D-Bus messages, netfilter hooks are used to -+do the filtering based on match rules. -+ -+The kernel module has to maintain the match rules and the D-Bus daemon -+is responsible for managing this information. Every time an add match -+rule message is processed by the D-Bus daemon, this will update the -+netfilter module match rules set so the netfilter hook function can -+use that information to do the match rules based filtering. -+ -+The D-Bus daemon and the netfilter module will use the generic netlink -+subsystem to do the kernel-to-user-space communication. Netlink is -+already used by most of the networking subsystem in Linux -+(iptables/netfilter, ip/routing, etc). -+ -+We enforce a security scheme so only the bus master's user ID can -+update the netfilter module match rules set. -+ -+The advantage of using the netfilter subsystem is that we decouple the -+mechanism from the policy. AF_BUS will only add a set of hook points -+and external modules will be used to enforce a given policy. --- -1.7.7.6 - diff --git a/patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch b/patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch deleted file mode 100644 index 3c2388a1a85f..000000000000 --- a/patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch +++ /dev/null @@ -1,348 +0,0 @@ -From 7fcfceea3fefae54e168726703c5030725106e6b Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 12:18:56 +0200 -Subject: [PATCH 03/15] net: bus: add af_bus address and af_bus socket address - definitions - -An AF_BUS socket can have many addresses associated. This allows to send -multicast packets on different domains. An af_bus address is an unsigned -64-bit value that contains two fields: a 16-bit prefix and a 48-bit client -address. - -Each bus has an associated path name that uniquely identifies the bus. -So, a socket address is composed of the bus path and the peer address. - -Clients can send unicast packets to each other and multicast to different -prefixes but they can only connect(2) to a special socket that owns the -bus an is known as the bus master. - -Signed-off-by: Javier Martinez Canillas ---- - include/linux/bus.h | 34 ++++++ - include/net/af_bus.h | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 307 insertions(+), 0 deletions(-) - create mode 100644 include/linux/bus.h - create mode 100644 include/net/af_bus.h - -diff --git a/include/linux/bus.h b/include/linux/bus.h -new file mode 100644 -index 0000000..19cac36 ---- /dev/null -+++ b/include/linux/bus.h -@@ -0,0 +1,34 @@ -+#ifndef _LINUX_BUS_H -+#define _LINUX_BUS_H -+ -+#include -+ -+/* 'protocol' to use in socket(AF_BUS, SOCK_SEQPACKET, protocol) */ -+#define BUS_PROTO_NONE 0 -+#define BUS_PROTO_DBUS 1 -+#define BUS_PROTO_MAX 1 -+ -+#define BUS_PATH_MAX 108 -+ -+/** -+ * struct bus_addr - af_bus address -+ * @s_addr: an af_bus address (16-bit prefix + 48-bit client address) -+ */ -+struct bus_addr { -+ u64 s_addr; -+}; -+ -+ -+/** -+ * struct sockaddr_bus - af_bus socket address -+ * @sbus_family: the socket address family -+ * @sbus_addr: an af_bus address -+ * @sbus_path: a path name -+ */ -+struct sockaddr_bus { -+ __kernel_sa_family_t sbus_family; -+ struct bus_addr sbus_addr; -+ char sbus_path[BUS_PATH_MAX]; -+}; -+ -+#endif /* _LINUX_BUS_H */ -diff --git a/include/net/af_bus.h b/include/net/af_bus.h -new file mode 100644 -index 0000000..e63eb49 ---- /dev/null -+++ b/include/net/af_bus.h -@@ -0,0 +1,273 @@ -+/* -+ * Copyright (c) 2012, GENIVI Alliance -+ * -+ * Authors: Javier Martinez Canillas, -+ * Alban Crequy, -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+extern void bus_inflight(struct file *fp); -+extern void bus_notinflight(struct file *fp); -+extern void bus_gc(void); -+extern void wait_for_bus_gc(void); -+extern struct sock *bus_get_socket(struct file *filp); -+extern struct sock *bus_peer_get(struct sock *); -+ -+#define BUS_HASH_SIZE 256 -+ -+extern spinlock_t bus_address_lock; -+extern struct hlist_head bus_address_table[BUS_HASH_SIZE]; -+ -+#define BUS_MAX_QLEN 10 -+#define BUS_MASTER_ADDR 0x0 -+#define BUS_PREFIX_BITS 16 -+#define BUS_CLIENT_BITS 48 -+#define BUS_PREFIX_MASK 0xffff000000000000 -+#define BUS_CLIENT_MASK 0x0000ffffffffffff -+ -+/* AF_BUS socket options */ -+#define BUS_ADD_ADDR 1 -+#define BUS_JOIN_BUS 2 -+#define BUS_DEL_ADDR 3 -+#define BUS_SET_EAVESDROP 4 -+#define BUS_UNSET_EAVESDROP 5 -+#define BUS_SET_SENDBUF 6 -+#define BUS_SET_MAXQLEN 7 -+#define BUS_GET_QLENFULL 8 -+ -+/* Connection and socket states */ -+enum { -+ BUS_ESTABLISHED = TCP_ESTABLISHED, -+ BUS_CLOSE = TCP_CLOSE, -+ BUS_LISTEN = TCP_LISTEN, -+ BUS_MAX_STATES -+}; -+ -+#define NF_BUS_SENDING 1 -+ -+extern unsigned int bus_tot_inflight; -+extern spinlock_t bus_table_lock; -+extern struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1]; -+ -+/** -+ * struct bus_address - an af_bus address associated with an af_bus sock -+ * @refcnt: address reference counter -+ * @len: address length -+ * @hash: address hash value -+ * @addr_node: member of struct bus_sock.addr_list -+ * @table_node: member of struct hlist_head bus_address_table[hash] -+ * @sock: the af_bus sock that owns this address -+ * @name: the socket address for this address -+ */ -+struct bus_address { -+ atomic_t refcnt; -+ int len; -+ unsigned hash; -+ struct hlist_node addr_node; -+ struct hlist_node table_node; -+ struct sock *sock; -+ struct sockaddr_bus name[0]; -+}; -+ -+/** -+ * struct bus_send_context - sending context for an socket buffer -+ * @sender_socket: the sender socket associated with this sk_buff -+ * @siocb: used to send ancillary data -+ * @timeo: sending timeout -+ * @max_level: file descriptor passing maximum recursion level -+ * @namelen: length of socket address name -+ * @hash: socket name hash value -+ * @other: destination sock -+ * @sender: sender socket address name -+ * @recipient: recipient socket address name -+ * @authenticated: flag whether the sock already joined the bus -+ * @bus_master_side: flag whether the sock is an accepted socket -+ * @to_master: flag whether the destination is the bus master -+ * @multicast: flag whether the destination is a multicast address -+ * @deliver: flag whether the skb has to be delivered -+ * @eavesdropper: flag whether the sock is allowed to eavesdrop -+ * @main_recipient: flag whether the sock is the main recipient -+ */ -+struct bus_send_context { -+ struct socket *sender_socket; -+ struct sock_iocb *siocb; -+ long timeo; -+ int max_level; -+ int namelen; -+ unsigned hash; -+ struct sock *other; -+ struct sockaddr_bus *sender; -+ struct sockaddr_bus *recipient; -+ unsigned int authenticated:1; -+ unsigned int bus_master_side:1; -+ unsigned int to_master:1; -+ unsigned int multicast:1; -+ unsigned int deliver:1; -+ unsigned int eavesdropper:1; -+ unsigned int main_recipient:1; -+}; -+ -+/** -+ * struct bus_skb_parms - socket buffer parameters -+ * @pid: process id -+ * @cred: skb credentials -+ * @fp: passed file descriptors -+ * @secid: security id -+ * @sendctx: skb sending context -+ */ -+struct bus_skb_parms { -+ struct pid *pid; -+ const struct cred *cred; -+ struct scm_fp_list *fp; -+#ifdef CONFIG_SECURITY_NETWORK -+ u32 secid; -+#endif -+ struct bus_send_context *sendctx; -+}; -+ -+#define BUSCB(skb) (*(struct bus_skb_parms *)&((skb)->cb)) -+#define BUSSID(skb) (&BUSCB((skb)).secid) -+ -+#define bus_state_lock(s) spin_lock(&bus_sk(s)->lock) -+#define bus_state_unlock(s) spin_unlock(&bus_sk(s)->lock) -+#define bus_state_lock_nested(s) \ -+ spin_lock_nested(&bus_sk(s)->lock, \ -+ SINGLE_DEPTH_NESTING) -+ -+/** -+ * struct bus - a communication bus -+ * @master: the bus master sock -+ * @peers: list of struct bus_sock.bus_node allowed to join the bus -+ * @lock: protect peers concurrent access -+ * @send_lock: enforce atomic multicast delivery -+ * @kref: bus reference counter -+ * @addr_cnt: address number counter to assign prefix 0x0000 addresses -+ * @eavesdropper_cnt: eavesdroppers counter -+ */ -+struct bus { -+ struct sock *master; -+ struct hlist_head peers; -+ spinlock_t lock; -+ spinlock_t send_lock; -+ struct kref kref; -+ atomic64_t addr_cnt; -+ atomic64_t eavesdropper_cnt; -+}; -+ -+/** -+ * struct bus_sock - an af_bus socket -+ * @sk: associated sock -+ * @addr: sock principal address -+ * @addr_list: list of struct bus_address.addr_node -+ * @path: sock path name -+ * @readlock: protect from concurrent reading -+ * @peer: peer sock -+ * @other: the listening sock -+ * @link: list of candidates for garbage collection -+ * @inflight: number of times the file descriptor is in flight -+ * @lock: protect the sock from concurrent access -+ * @gc_candidate: flag whether the is a candidate for gc -+ * @gc_maybe_cycle: flag whether could be a cyclic reference -+ * @recursion_level: file passing current recursion level -+ * @peer_wq: peer sock wait queue -+ * @bus: bus that this sock belongs to -+ * @bus_master: flag whether the sock is the bus master -+ * @bus_master_side: flag whether is an accepted socket -+ * @authenticated: flag whether the sock joined the bus -+ * @eavesdropper: flag whether the sock is allowed to eavesdrop -+ * @bus_node: member of struct bus.peers list of joined socks -+ */ -+struct bus_sock { -+ /* WARNING: sk has to be the first member */ -+ struct sock sk; -+ struct bus_address *addr; -+ struct hlist_head addr_list; -+ struct path path; -+ struct mutex readlock; -+ struct sock *peer; -+ struct sock *other; -+ struct list_head link; -+ atomic_long_t inflight; -+ spinlock_t lock; -+ unsigned int gc_candidate:1; -+ unsigned int gc_maybe_cycle:1; -+ unsigned char recursion_level; -+ struct socket_wq peer_wq; -+ struct bus *bus; -+ bool bus_master; -+ bool bus_master_side; -+ bool authenticated; -+ bool eavesdropper; -+ struct hlist_node bus_node; -+}; -+#define bus_sk(__sk) ((struct bus_sock *)__sk) -+ -+#define peer_wait peer_wq.wait -+ -+/** -+ * bus_same_bus - Test if two socket address belongs to the same bus -+ * @sbusaddr1: socket address name -+ * @sbusaddr2: socket address name -+ */ -+static inline bool bus_same_bus(struct sockaddr_bus *sbusaddr1, -+ struct sockaddr_bus *sbusaddr2) -+{ -+ int offset; -+ -+ if (sbusaddr1->sbus_path[0] != sbusaddr2->sbus_path[0]) -+ return false; -+ -+ /* -+ * abstract path names start with a null byte character, -+ * so they have to be compared starting at the second char. -+ */ -+ offset = (sbusaddr1->sbus_path[0] == '\0'); -+ -+ return !strncmp(sbusaddr1->sbus_path + offset, -+ sbusaddr2->sbus_path + offset, -+ BUS_PATH_MAX); -+} -+ -+static inline unsigned int bus_hash_fold(__wsum n) -+{ -+ unsigned int hash = (__force unsigned int)n; -+ hash ^= hash>>16; -+ hash ^= hash>>8; -+ return hash&(BUS_HASH_SIZE-1); -+} -+ -+static inline unsigned int bus_compute_hash(struct bus_addr addr) -+{ -+ return bus_hash_fold(csum_partial((void *)&addr, sizeof(addr), 0)); -+} -+ -+long bus_inq_len(struct sock *sk); -+long bus_outq_len(struct sock *sk); -+ -+#ifdef CONFIG_SYSCTL -+extern int bus_sysctl_register(struct net *net); -+extern void bus_sysctl_unregister(struct net *net); -+#else -+static inline int bus_sysctl_register(struct net *net) { return 0; } -+static inline void bus_sysctl_unregister(struct net *net) {} -+#endif -+ -+bool bus_can_write(struct net *net, struct sockaddr_bus *addr, int len, -+ int protocol); -+ -+#endif /* __LINUX_NET_AFBUS_H */ --- -1.7.7.6 - diff --git a/patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch b/patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch deleted file mode 100644 index 79dc0610443b..000000000000 --- a/patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 67699fea892540b8bdce95ae22ae43c94b684d29 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 14:29:14 +0200 -Subject: [PATCH 04/15] security: Add Linux Security Modules hook for AF_BUS - sockets - -AF_BUS implements a security hook bus_connect() to be used by LSM -to enforce connectivity security policies. - -Signed-off-by: Javier Martinez Canillas ---- - include/linux/security.h | 11 +++++++++++ - security/capability.c | 7 +++++++ - security/security.c | 7 +++++++ - 3 files changed, 25 insertions(+), 0 deletions(-) - -diff --git a/include/linux/security.h b/include/linux/security.h -index 673afbb..fa26c6d 100644 ---- a/include/linux/security.h -+++ b/include/linux/security.h -@@ -1578,6 +1578,8 @@ struct security_operations { - - #ifdef CONFIG_SECURITY_NETWORK - int (*unix_stream_connect) (struct sock *sock, struct sock *other, struct sock *newsk); -+ int (*bus_connect) (struct sock *sock, struct sock *other, -+ struct sock *newsk); - int (*unix_may_send) (struct socket *sock, struct socket *other); - - int (*socket_create) (int family, int type, int protocol, int kern); -@@ -2517,6 +2519,8 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 - #ifdef CONFIG_SECURITY_NETWORK - - int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk); -+int security_bus_connect(struct sock *sock, struct sock *other, -+ struct sock *newsk); - int security_unix_may_send(struct socket *sock, struct socket *other); - int security_socket_create(int family, int type, int protocol, int kern); - int security_socket_post_create(struct socket *sock, int family, -@@ -2564,6 +2568,13 @@ static inline int security_unix_stream_connect(struct sock *sock, - return 0; - } - -+static inline int security_bus_connect(struct socket *sock, -+ struct sock *other, -+ struct sock *newsk) -+{ -+ return 0; -+} -+ - static inline int security_unix_may_send(struct socket *sock, - struct socket *other) - { -diff --git a/security/capability.c b/security/capability.c -index 5bb21b1..5b966a6 100644 ---- a/security/capability.c -+++ b/security/capability.c -@@ -563,6 +563,12 @@ static int cap_unix_may_send(struct socket *sock, struct socket *other) - return 0; - } - -+static int cap_bus_connect(struct sock *sock, struct sock *other, -+ struct sock *newsk) -+{ -+ return 0; -+} -+ - static int cap_socket_create(int family, int type, int protocol, int kern) - { - return 0; -@@ -1015,6 +1021,7 @@ void __init security_fixup_ops(struct security_operations *ops) - #ifdef CONFIG_SECURITY_NETWORK - set_to_cap_if_null(ops, unix_stream_connect); - set_to_cap_if_null(ops, unix_may_send); -+ set_to_cap_if_null(ops, bus_connect); - set_to_cap_if_null(ops, socket_create); - set_to_cap_if_null(ops, socket_post_create); - set_to_cap_if_null(ops, socket_bind); -diff --git a/security/security.c b/security/security.c -index bf619ff..54582ea 100644 ---- a/security/security.c -+++ b/security/security.c -@@ -1018,6 +1018,13 @@ int security_unix_may_send(struct socket *sock, struct socket *other) - } - EXPORT_SYMBOL(security_unix_may_send); - -+int security_bus_connect(struct sock *sock, struct sock *other, -+ struct sock *newsk) -+{ -+ return security_ops->bus_connect(sock, other, newsk); -+} -+EXPORT_SYMBOL(security_bus_connect); -+ - int security_socket_create(int family, int type, int protocol, int kern) - { - return security_ops->socket_create(family, type, protocol, kern); --- -1.7.7.6 - diff --git a/patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch b/patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch deleted file mode 100644 index 3eccc0ea6f96..000000000000 --- a/patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 714516658e81f2342fe5fd2b8f5493d19f3731b4 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 14:32:26 +0200 -Subject: [PATCH 05/15] security: selinux: Add AF_BUS socket SELinux hooks - -Add Security-Enhanced Linux (SELinux) hook for AF_BUS socket address family. - -Signed-off-by: Javier Martinez Canillas ---- - security/selinux/hooks.c | 35 +++++++++++++++++++++++++++++++++++ - 1 files changed, 35 insertions(+), 0 deletions(-) - -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index 5626222..91edbdd 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -67,6 +67,7 @@ - #include - #include /* for Unix socket types */ - #include /* for Unix socket types */ -+#include /* for Bus socket types */ - #include - #include - #include -@@ -4102,6 +4103,39 @@ static int selinux_socket_unix_may_send(struct socket *sock, - &ad); - } - -+static int selinux_socket_bus_connect(struct sock *sock, struct sock *other, -+ struct sock *newsk) -+{ -+ struct sk_security_struct *sksec_sock = sock->sk_security; -+ struct sk_security_struct *sksec_other = other->sk_security; -+ struct sk_security_struct *sksec_new = newsk->sk_security; -+ struct common_audit_data ad; -+ struct lsm_network_audit net = {0,}; -+ int err; -+ -+ ad.type = LSM_AUDIT_DATA_NET; -+ ad.u.net = &net; -+ ad.u.net->sk = other; -+ -+ err = avc_has_perm(sksec_sock->sid, sksec_other->sid, -+ sksec_other->sclass, -+ UNIX_STREAM_SOCKET__CONNECTTO, &ad); -+ if (err) -+ return err; -+ -+ /* server child socket */ -+ sksec_new->peer_sid = sksec_sock->sid; -+ err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid, -+ &sksec_new->sid); -+ if (err) -+ return err; -+ -+ /* connecting socket */ -+ sksec_sock->peer_sid = sksec_new->sid; -+ -+ return 0; -+} -+ - static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, - u32 peer_sid, - struct common_audit_data *ad) -@@ -5656,6 +5690,7 @@ static struct security_operations selinux_ops = { - - .unix_stream_connect = selinux_socket_unix_stream_connect, - .unix_may_send = selinux_socket_unix_may_send, -+ .bus_connect = selinux_socket_bus_connect, - - .socket_create = selinux_socket_create, - .socket_post_create = selinux_socket_post_create, --- -1.7.7.6 - diff --git a/patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch b/patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch deleted file mode 100644 index 130f88f66699..000000000000 --- a/patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b7943d96bba05258c0eeabed0aa6e006a3ec06ec Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 14:59:16 +0200 -Subject: [PATCH 06/15] netfilter: add NFPROTO_BUS hook constant for AF_BUS - socket family - -AF_BUS sockets add a netfilter NF_HOOK() on the packet sending path. -This allows packet to be mangled by registered netfilter hooks. - -Signed-off-by: Javier Martinez Canillas ---- - include/linux/netfilter.h | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h -index 29734be..7cff0bd 100644 ---- a/include/linux/netfilter.h -+++ b/include/linux/netfilter.h -@@ -67,6 +67,7 @@ enum { - NFPROTO_BRIDGE = 7, - NFPROTO_IPV6 = 10, - NFPROTO_DECNET = 12, -+ NFPROTO_BUS, - NFPROTO_NUMPROTO, - }; - --- -1.7.7.6 - diff --git a/patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch b/patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch deleted file mode 100644 index 935cb39ad78c..000000000000 --- a/patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch +++ /dev/null @@ -1,36 +0,0 @@ -From efe7f1ea3bc352b350671bb8c2b5e573672faf6a Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 15:22:08 +0200 -Subject: [PATCH 07/15] scm: allow AF_BUS sockets to send ancillary data - -UNIX domain sockets support passing file descriptors or process -credentials in the form of ancillary data. - -Since AF_BUS sockets are used to communicate processes on a local -machine, they should also support passing control messages. -The core socket level control messages processing only allows sockets -whose family is PF_UNIX to send SCM_RIGHTS type messages. So, let's -also allow to PF_BUS sockets. - -Signed-off-by: Javier Martinez Canillas ---- - net/core/scm.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/net/core/scm.c b/net/core/scm.c -index 611c5ef..87e3152 100644 ---- a/net/core/scm.c -+++ b/net/core/scm.c -@@ -158,7 +158,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) - switch (cmsg->cmsg_type) - { - case SCM_RIGHTS: -- if (!sock->ops || sock->ops->family != PF_UNIX) -+ if (!sock->ops || (sock->ops->family != PF_UNIX && -+ sock->ops->family != PF_BUS)) - goto error; - err=scm_fp_copy(cmsg, &p->fp); - if (err<0) --- -1.7.7.6 - diff --git a/patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch b/patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch deleted file mode 100644 index e748e56dee35..000000000000 --- a/patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch +++ /dev/null @@ -1,2739 +0,0 @@ -From d1bbdbce93bba76325b0d22da84cb8833da49df0 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 15:29:34 +0200 -Subject: [PATCH 08/15] net: bus: Add implementation of Bus domain sockets - -Each process connected to an AF_BUS socket, has one or more addresses -within that bus. These addresses are 64-bit unsigned integers, -interpreted by splitting the address into two parts: the most significant -16 bits are a prefix identifying the type of address, and the remaining -48 bits are the actual client address within that prefix. - -The process that calls bind(2) on the socket is the owner of the bus and -is called the bus master. The master is a special client of the bus and has -some responsibility for the bus' operation. The master is assigned a fixed -address with all the bits zero. - -The prefix with all bits zero is reserved for use by the kernel, which -automatically assigns one address from this prefix to each client on -connection. The address in this prefix with all bits zero is always -assigned to the bus master. Addresses on the prefix 0000 are unique -and will never repeat for the lifetime of the bus master. - -AF_BUS transport can support two network topologies. When a process -first connect to the bus master, it can only communicate with the -bus master. The process can't send and receive packets from other -peers on the bus. So, from the client process point of view the -network topology is point-to-point. - -The bus master can allow the connected peer to be part of the bus -and start to communicate with other peers by setting an socket option -with the setsockopt(2) system call using the accepted socket descriptor. -At this point, the topology becomes a bus to the client process. - -Packets whose destination address is not assigned to any client are routed -by default to the bus master (the client accepted socket descriptor). - -Signed-off-by: Javier Martinez Canillas ---- - net/bus/af_bus.c | 2688 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 2688 insertions(+), 0 deletions(-) - create mode 100644 net/bus/af_bus.c - -diff --git a/net/bus/af_bus.c b/net/bus/af_bus.c -new file mode 100644 -index 0000000..d25af65 ---- /dev/null -+++ b/net/bus/af_bus.c -@@ -0,0 +1,2688 @@ -+/* -+ * Implementation of Bus domain sockets. -+ * -+ * Copyright (c) 2012, GENIVI Alliance -+ * -+ * Authors: Javier Martinez Canillas -+ * Alban Crequy -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1]; -+EXPORT_SYMBOL_GPL(bus_socket_table); -+struct hlist_head bus_address_table[BUS_HASH_SIZE]; -+EXPORT_SYMBOL_GPL(bus_address_table); -+DEFINE_SPINLOCK(bus_table_lock); -+DEFINE_SPINLOCK(bus_address_lock); -+EXPORT_SYMBOL_GPL(bus_address_lock); -+static atomic_long_t bus_nr_socks; -+ -+#define bus_sockets_unbound (&bus_socket_table[BUS_HASH_SIZE]) -+ -+#define BUS_ABSTRACT(sk) (bus_sk(sk)->addr->hash != BUS_HASH_SIZE) -+ -+#ifdef CONFIG_SECURITY_NETWORK -+static void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) -+{ -+ memcpy(BUSSID(skb), &scm->secid, sizeof(u32)); -+} -+ -+static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) -+{ -+ scm->secid = *BUSSID(skb); -+} -+#else -+static inline void bus_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) -+{ } -+ -+static inline void bus_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) -+{ } -+#endif /* CONFIG_SECURITY_NETWORK */ -+ -+/* -+ * SMP locking strategy: -+ * bus_socket_table hash table is protected with spinlock bus_table_lock -+ * bus_address_table hash table is protected with spinlock bus_address_lock -+ * each bus is protected by a separate spin lock. -+ * multicast atomic sending is protected by a separate spin lock. -+ * each socket state is protected by a separate spin lock. -+ * each socket address is protected by a separate spin lock. -+ * -+ * When holding more than one lock, use the following hierarchy: -+ * - bus_table_lock. -+ * - bus_address_lock. -+ * - socket lock. -+ * - bus lock. -+ * - bus send_lock. -+ * - sock address lock. -+ */ -+ -+#define bus_peer(sk) (bus_sk(sk)->peer) -+ -+static inline int bus_our_peer(struct sock *sk, struct sock *osk) -+{ -+ return bus_peer(osk) == sk; -+} -+ -+static inline int bus_recvq_full(struct sock const *sk) -+{ -+ return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; -+} -+ -+static inline u16 bus_addr_prefix(struct sockaddr_bus *busaddr) -+{ -+ return (busaddr->sbus_addr.s_addr & BUS_PREFIX_MASK) >> BUS_CLIENT_BITS; -+} -+ -+static inline u64 bus_addr_client(struct sockaddr_bus *sbusaddr) -+{ -+ return sbusaddr->sbus_addr.s_addr & BUS_CLIENT_MASK; -+} -+ -+static inline bool bus_mc_addr(struct sockaddr_bus *sbusaddr) -+{ -+ return bus_addr_client(sbusaddr) == BUS_CLIENT_MASK; -+} -+ -+struct sock *bus_peer_get(struct sock *s) -+{ -+ struct sock *peer; -+ -+ bus_state_lock(s); -+ peer = bus_peer(s); -+ if (peer) -+ sock_hold(peer); -+ bus_state_unlock(s); -+ return peer; -+} -+EXPORT_SYMBOL_GPL(bus_peer_get); -+ -+static inline void bus_release_addr(struct bus_address *addr) -+{ -+ if (atomic_dec_and_test(&addr->refcnt)) -+ kfree(addr); -+} -+ -+/* -+ * Check bus socket name: -+ * - should be not zero length. -+ * - if started by not zero, should be NULL terminated (FS object) -+ * - if started by zero, it is abstract name. -+ */ -+ -+static int bus_mkname(struct sockaddr_bus *sbusaddr, int len, -+ unsigned int *hashp) -+{ -+ int offset = (sbusaddr->sbus_path[0] == '\0'); -+ -+ if (len <= sizeof(short) || len > sizeof(*sbusaddr)) -+ return -EINVAL; -+ if (!sbusaddr || sbusaddr->sbus_family != AF_BUS) -+ return -EINVAL; -+ -+ len = strnlen(sbusaddr->sbus_path + offset, BUS_PATH_MAX) + 1 + -+ sizeof(__kernel_sa_family_t) + -+ sizeof(struct bus_addr); -+ -+ *hashp = bus_compute_hash(sbusaddr->sbus_addr); -+ return len; -+} -+ -+static void __bus_remove_address(struct bus_address *addr) -+{ -+ hlist_del(&addr->table_node); -+} -+ -+static void __bus_insert_address(struct hlist_head *list, -+ struct bus_address *addr) -+{ -+ hlist_add_head(&addr->table_node, list); -+} -+ -+static inline void bus_remove_address(struct bus_address *addr) -+{ -+ spin_lock(&bus_address_lock); -+ __bus_remove_address(addr); -+ spin_unlock(&bus_address_lock); -+} -+ -+static inline void bus_insert_address(struct hlist_head *list, -+ struct bus_address *addr) -+{ -+ spin_lock(&bus_address_lock); -+ __bus_insert_address(list, addr); -+ spin_unlock(&bus_address_lock); -+} -+ -+static void __bus_remove_socket(struct sock *sk) -+{ -+ sk_del_node_init(sk); -+} -+ -+static void __bus_insert_socket(struct hlist_head *list, struct sock *sk) -+{ -+ WARN_ON(!sk_unhashed(sk)); -+ sk_add_node(sk, list); -+} -+ -+static inline void bus_remove_socket(struct sock *sk) -+{ -+ spin_lock(&bus_table_lock); -+ __bus_remove_socket(sk); -+ spin_unlock(&bus_table_lock); -+} -+ -+static inline void bus_insert_socket(struct hlist_head *list, struct sock *sk) -+{ -+ spin_lock(&bus_table_lock); -+ __bus_insert_socket(list, sk); -+ spin_unlock(&bus_table_lock); -+} -+ -+static inline bool __bus_has_prefix(struct sock *sk, u16 prefix) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ struct bus_address *addr; -+ struct hlist_node *node; -+ bool ret = false; -+ -+ hlist_for_each_entry(addr, node, &u->addr_list, addr_node) { -+ if (bus_addr_prefix(addr->name) == prefix) -+ ret = true; -+ } -+ -+ return ret; -+} -+ -+static inline bool bus_has_prefix(struct sock *sk, u16 prefix) -+{ -+ bool ret; -+ -+ bus_state_lock(sk); -+ ret = __bus_has_prefix(sk, prefix); -+ bus_state_unlock(sk); -+ -+ return ret; -+} -+ -+static inline bool __bus_eavesdropper(struct sock *sk, u16 condition) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ -+ return u->eavesdropper; -+} -+ -+static inline bool bus_eavesdropper(struct sock *sk, u16 condition) -+{ -+ bool ret; -+ -+ bus_state_lock(sk); -+ ret = __bus_eavesdropper(sk, condition); -+ bus_state_unlock(sk); -+ -+ return ret; -+} -+ -+static inline bool bus_has_prefix_eavesdropper(struct sock *sk, u16 prefix) -+{ -+ bool ret; -+ -+ bus_state_lock(sk); -+ ret = __bus_has_prefix(sk, prefix) || __bus_eavesdropper(sk, 0); -+ bus_state_unlock(sk); -+ -+ return ret; -+} -+ -+static inline struct bus_address *__bus_get_address(struct sock *sk, -+ struct bus_addr *sbus_addr) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ struct bus_address *addr = NULL; -+ struct hlist_node *node; -+ -+ hlist_for_each_entry(addr, node, &u->addr_list, addr_node) { -+ if (addr->name->sbus_addr.s_addr == sbus_addr->s_addr) -+ return addr; -+ } -+ -+ return NULL; -+} -+ -+static inline struct bus_address *bus_get_address(struct sock *sk, -+ struct bus_addr *sbus_addr) -+{ -+ struct bus_address *addr; -+ -+ bus_state_lock(sk); -+ addr = __bus_get_address(sk, sbus_addr); -+ bus_state_unlock(sk); -+ -+ return addr; -+} -+ -+static struct sock *__bus_find_socket_byname(struct net *net, -+ struct sockaddr_bus *sbusname, -+ int len, unsigned int hash) -+{ -+ struct sock *s; -+ struct hlist_node *node; -+ -+ sk_for_each(s, node, &bus_socket_table[hash]) { -+ struct bus_sock *u = bus_sk(s); -+ -+ if (!net_eq(sock_net(s), net)) -+ continue; -+ -+ if (u->addr->len == len && -+ !memcmp(u->addr->name, sbusname, len)) -+ return s; -+ } -+ -+ return NULL; -+} -+ -+static inline struct sock *bus_find_socket_byname(struct net *net, -+ struct sockaddr_bus *sbusname, -+ int len, unsigned int hash) -+{ -+ struct sock *s; -+ -+ spin_lock(&bus_table_lock); -+ s = __bus_find_socket_byname(net, sbusname, len, hash); -+ if (s) -+ sock_hold(s); -+ spin_unlock(&bus_table_lock); -+ return s; -+} -+ -+static struct sock *__bus_find_socket_byaddress(struct net *net, -+ struct sockaddr_bus *sbusname, -+ int len, int protocol, -+ unsigned int hash) -+{ -+ struct sock *s; -+ struct bus_address *addr; -+ struct hlist_node *node; -+ struct bus_sock *u; -+ int offset = (sbusname->sbus_path[0] == '\0'); -+ int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX); -+ -+ len = path_len + 1 + sizeof(__kernel_sa_family_t) + -+ sizeof(struct bus_addr); -+ -+ hlist_for_each_entry(addr, node, &bus_address_table[hash], -+ table_node) { -+ s = addr->sock; -+ u = bus_sk(s); -+ -+ if (s->sk_protocol != protocol) -+ continue; -+ -+ if (!net_eq(sock_net(s), net)) -+ continue; -+ -+ if (addr->len == len && -+ addr->name->sbus_family == sbusname->sbus_family && -+ addr->name->sbus_addr.s_addr == sbusname->sbus_addr.s_addr -+ && bus_same_bus(addr->name, sbusname)) -+ goto found; -+ } -+ s = NULL; -+found: -+ return s; -+} -+ -+static inline struct sock *bus_find_socket_byaddress(struct net *net, -+ struct sockaddr_bus *name, -+ int len, int protocol, -+ unsigned int hash) -+{ -+ struct sock *s; -+ -+ spin_lock(&bus_address_lock); -+ s = __bus_find_socket_byaddress(net, name, len, protocol, hash); -+ if (s) -+ sock_hold(s); -+ spin_unlock(&bus_address_lock); -+ return s; -+} -+ -+static inline int bus_writable(struct sock *sk) -+{ -+ return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; -+} -+ -+static void bus_write_space(struct sock *sk) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ struct bus_sock *p; -+ struct hlist_node *node; -+ struct socket_wq *wq; -+ -+ if (bus_writable(sk)) { -+ rcu_read_lock(); -+ wq = rcu_dereference(sk->sk_wq); -+ if (wq_has_sleeper(wq)) -+ wake_up_interruptible_sync_poll(&wq->wait, -+ POLLOUT | POLLWRNORM | POLLWRBAND); -+ sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); -+ rcu_read_unlock(); -+ -+ if (u && u->bus) { -+ spin_lock(&u->bus->lock); -+ hlist_for_each_entry(p, node, &u->bus->peers, -+ bus_node) { -+ wake_up_interruptible_sync_poll(sk_sleep(&p->sk), -+ POLLOUT | -+ POLLWRNORM | -+ POLLWRBAND); -+ sk_wake_async(&p->sk, SOCK_WAKE_SPACE, -+ POLL_OUT); -+ } -+ spin_unlock(&u->bus->lock); -+ } -+ } -+} -+ -+static void bus_bus_release(struct kref *kref) -+{ -+ struct bus *bus; -+ -+ bus = container_of(kref, struct bus, kref); -+ -+ kfree(bus); -+} -+ -+static void bus_sock_destructor(struct sock *sk) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ -+ skb_queue_purge(&sk->sk_receive_queue); -+ -+ WARN_ON(atomic_read(&sk->sk_wmem_alloc)); -+ WARN_ON(!sk_unhashed(sk)); -+ WARN_ON(sk->sk_socket); -+ if (!sock_flag(sk, SOCK_DEAD)) { -+ pr_info("Attempt to release alive bus socket: %p\n", sk); -+ return; -+ } -+ -+ if (u->bus) { -+ kref_put(&u->bus->kref, bus_bus_release); -+ u->bus = NULL; -+ } -+ -+ atomic_long_dec(&bus_nr_socks); -+ local_bh_disable(); -+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); -+ local_bh_enable(); -+#ifdef BUS_REFCNT_DEBUG -+ pr_debug("BUS %p is destroyed, %ld are still alive.\n", sk, -+ atomic_long_read(&bus_nr_socks)); -+#endif -+} -+ -+static int bus_release_sock(struct sock *sk, int embrion) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ struct path path; -+ struct sock *skpair; -+ struct sk_buff *skb; -+ int state; -+ struct bus_address *addr; -+ struct hlist_node *node, *tmp; -+ -+ bus_remove_socket(sk); -+ -+ if (u->bus && u->authenticated && -+ !u->bus_master && !u->bus_master_side) { -+ spin_lock(&u->bus->lock); -+ hlist_del(&u->bus_node); -+ if (u->eavesdropper) -+ atomic64_dec(&u->bus->eavesdropper_cnt); -+ spin_unlock(&u->bus->lock); -+ } -+ -+ /* Clear state */ -+ bus_state_lock(sk); -+ sock_orphan(sk); -+ sk->sk_shutdown = SHUTDOWN_MASK; -+ path = u->path; -+ u->path.dentry = NULL; -+ u->path.mnt = NULL; -+ state = sk->sk_state; -+ sk->sk_state = BUS_CLOSE; -+ -+ if (u->bus_master) -+ u->bus->master = NULL; -+ -+ if (u->bus_master_side) { -+ bus_release_addr(u->addr); -+ u->addr = NULL; -+ } else { -+ u->addr = NULL; -+ -+ spin_lock(&bus_address_lock); -+ hlist_for_each_entry_safe(addr, node, tmp, &u->addr_list, -+ addr_node) { -+ hlist_del(&addr->addr_node); -+ __bus_remove_address(addr); -+ bus_release_addr(addr); -+ } -+ spin_unlock(&bus_address_lock); -+ } -+ -+ bus_state_unlock(sk); -+ -+ wake_up_interruptible_all(&u->peer_wait); -+ -+ skpair = bus_peer(sk); -+ -+ if (skpair != NULL) { -+ bus_state_lock(skpair); -+ /* No more writes */ -+ skpair->sk_shutdown = SHUTDOWN_MASK; -+ if (!skb_queue_empty(&sk->sk_receive_queue) || embrion) -+ skpair->sk_err = ECONNRESET; -+ bus_state_unlock(skpair); -+ skpair->sk_state_change(skpair); -+ sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); -+ sock_put(skpair); /* It may now die */ -+ bus_peer(sk) = NULL; -+ } -+ -+ /* Try to flush out this socket. Throw out buffers at least */ -+ -+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { -+ if (state == BUS_LISTEN) -+ bus_release_sock(skb->sk, 1); -+ /* passed fds are erased in the kfree_skb hook */ -+ kfree_skb(skb); -+ } -+ -+ if (path.dentry) -+ path_put(&path); -+ -+ sock_put(sk); -+ -+ /* ---- Socket is dead now and most probably destroyed ---- */ -+ -+ if (bus_tot_inflight) -+ bus_gc(); /* Garbage collect fds */ -+ -+ return 0; -+} -+ -+static void init_peercred(struct sock *sk) -+{ -+ put_pid(sk->sk_peer_pid); -+ if (sk->sk_peer_cred) -+ put_cred(sk->sk_peer_cred); -+ sk->sk_peer_pid = get_pid(task_tgid(current)); -+ sk->sk_peer_cred = get_current_cred(); -+} -+ -+static void copy_peercred(struct sock *sk, struct sock *peersk) -+{ -+ put_pid(sk->sk_peer_pid); -+ if (sk->sk_peer_cred) -+ put_cred(sk->sk_peer_cred); -+ sk->sk_peer_pid = get_pid(peersk->sk_peer_pid); -+ sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); -+} -+ -+static int bus_listen(struct socket *sock, int backlog) -+{ -+ int err; -+ struct sock *sk = sock->sk; -+ struct bus_sock *u = bus_sk(sk); -+ struct pid *old_pid = NULL; -+ const struct cred *old_cred = NULL; -+ -+ err = -EINVAL; -+ if (!u->addr || !u->bus_master) -+ goto out; /* Only listens on an bound an master socket */ -+ bus_state_lock(sk); -+ if (sk->sk_state != BUS_CLOSE && sk->sk_state != BUS_LISTEN) -+ goto out_unlock; -+ if (backlog > sk->sk_max_ack_backlog) -+ wake_up_interruptible_all(&u->peer_wait); -+ sk->sk_max_ack_backlog = backlog; -+ sk->sk_state = BUS_LISTEN; -+ /* set credentials so connect can copy them */ -+ init_peercred(sk); -+ err = 0; -+ -+out_unlock: -+ bus_state_unlock(sk); -+ put_pid(old_pid); -+ if (old_cred) -+ put_cred(old_cred); -+out: -+ return err; -+} -+ -+static int bus_release(struct socket *); -+static int bus_bind(struct socket *, struct sockaddr *, int); -+static int bus_connect(struct socket *, struct sockaddr *, -+ int addr_len, int flags); -+static int bus_accept(struct socket *, struct socket *, int); -+static int bus_getname(struct socket *, struct sockaddr *, int *, int); -+static unsigned int bus_poll(struct file *, struct socket *, -+ poll_table *); -+static int bus_ioctl(struct socket *, unsigned int, unsigned long); -+static int bus_shutdown(struct socket *, int); -+static int bus_setsockopt(struct socket *, int, int, char __user *, -+ unsigned int); -+static int bus_sendmsg(struct kiocb *, struct socket *, -+ struct msghdr *, size_t); -+static int bus_recvmsg(struct kiocb *, struct socket *, -+ struct msghdr *, size_t, int); -+ -+static void bus_set_peek_off(struct sock *sk, int val) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ -+ mutex_lock(&u->readlock); -+ sk->sk_peek_off = val; -+ mutex_unlock(&u->readlock); -+} -+ -+static const struct proto_ops bus_seqpacket_ops = { -+ .family = PF_BUS, -+ .owner = THIS_MODULE, -+ .release = bus_release, -+ .bind = bus_bind, -+ .connect = bus_connect, -+ .socketpair = sock_no_socketpair, -+ .accept = bus_accept, -+ .getname = bus_getname, -+ .poll = bus_poll, -+ .ioctl = bus_ioctl, -+ .listen = bus_listen, -+ .shutdown = bus_shutdown, -+ .setsockopt = bus_setsockopt, -+ .getsockopt = sock_no_getsockopt, -+ .sendmsg = bus_sendmsg, -+ .recvmsg = bus_recvmsg, -+ .mmap = sock_no_mmap, -+ .sendpage = sock_no_sendpage, -+ .set_peek_off = bus_set_peek_off, -+}; -+ -+static struct proto bus_proto = { -+ .name = "BUS", -+ .owner = THIS_MODULE, -+ .obj_size = sizeof(struct bus_sock), -+}; -+ -+/* -+ * AF_BUS sockets do not interact with hardware, hence they -+ * dont trigger interrupts - so it's safe for them to have -+ * bh-unsafe locking for their sk_receive_queue.lock. Split off -+ * this special lock-class by reinitializing the spinlock key: -+ */ -+static struct lock_class_key af_bus_sk_receive_queue_lock_key; -+ -+static struct sock *bus_create1(struct net *net, struct socket *sock) -+{ -+ struct sock *sk = NULL; -+ struct bus_sock *u; -+ -+ atomic_long_inc(&bus_nr_socks); -+ if (atomic_long_read(&bus_nr_socks) > 2 * get_max_files()) -+ goto out; -+ -+ sk = sk_alloc(net, PF_BUS, GFP_KERNEL, &bus_proto); -+ if (!sk) -+ goto out; -+ -+ sock_init_data(sock, sk); -+ lockdep_set_class(&sk->sk_receive_queue.lock, -+ &af_bus_sk_receive_queue_lock_key); -+ -+ sk->sk_write_space = bus_write_space; -+ sk->sk_max_ack_backlog = BUS_MAX_QLEN; -+ sk->sk_destruct = bus_sock_destructor; -+ u = bus_sk(sk); -+ u->path.dentry = NULL; -+ u->path.mnt = NULL; -+ u->bus = NULL; -+ u->bus_master = false; -+ u->authenticated = false; -+ u->eavesdropper = false; -+ spin_lock_init(&u->lock); -+ atomic_long_set(&u->inflight, 0); -+ INIT_LIST_HEAD(&u->link); -+ INIT_HLIST_HEAD(&u->addr_list); -+ INIT_HLIST_NODE(&u->bus_node); -+ mutex_init(&u->readlock); /* single task reading lock */ -+ init_waitqueue_head(&u->peer_wait); -+ bus_insert_socket(bus_sockets_unbound, sk); -+out: -+ if (sk == NULL) -+ atomic_long_dec(&bus_nr_socks); -+ else { -+ local_bh_disable(); -+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); -+ local_bh_enable(); -+ } -+ return sk; -+} -+ -+static int bus_create(struct net *net, struct socket *sock, int protocol, -+ int kern) -+{ -+ struct sock *sk; -+ -+ if (protocol < BUS_PROTO_NONE || protocol > BUS_PROTO_DBUS) -+ return -EPROTONOSUPPORT; -+ -+ if (protocol != BUS_PROTO_NONE) -+ request_module("net-pf-%d-proto-%d", PF_BUS, protocol); -+ -+ sock->state = SS_UNCONNECTED; -+ -+ if (sock->type == SOCK_SEQPACKET) -+ sock->ops = &bus_seqpacket_ops; -+ else -+ return -ESOCKTNOSUPPORT; -+ -+ sk = bus_create1(net, sock); -+ if (!sk) -+ return -ENOMEM; -+ -+ sk->sk_protocol = protocol; -+ -+ return 0; -+} -+ -+static int bus_release(struct socket *sock) -+{ -+ struct sock *sk = sock->sk; -+ -+ if (!sk) -+ return 0; -+ -+ sock->sk = NULL; -+ -+ return bus_release_sock(sk, 0); -+} -+ -+static struct sock *bus_find_other(struct net *net, -+ struct sockaddr_bus *sbusname, int len, -+ int protocol, unsigned int hash, int *error) -+{ -+ struct sock *u; -+ struct path path; -+ int err = 0; -+ -+ if (sbusname->sbus_path[0]) { -+ struct inode *inode; -+ err = kern_path(sbusname->sbus_path, LOOKUP_FOLLOW, &path); -+ if (err) -+ goto fail; -+ inode = path.dentry->d_inode; -+ err = inode_permission(inode, MAY_WRITE); -+ if (err) -+ goto put_fail; -+ -+ err = -ECONNREFUSED; -+ if (!S_ISSOCK(inode->i_mode)) -+ goto put_fail; -+ u = bus_find_socket_byaddress(net, sbusname, len, protocol, -+ hash); -+ if (!u) -+ goto put_fail; -+ -+ touch_atime(&path); -+ path_put(&path); -+ -+ } else { -+ err = -ECONNREFUSED; -+ u = bus_find_socket_byaddress(net, sbusname, len, protocol, hash); -+ if (u) { -+ struct dentry *dentry; -+ dentry = bus_sk(u)->path.dentry; -+ if (dentry) -+ touch_atime(&bus_sk(u)->path); -+ } else -+ goto fail; -+ } -+ -+ return u; -+ -+put_fail: -+ path_put(&path); -+fail: -+ *error = err; -+ return NULL; -+} -+ -+ -+static int bus_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) -+{ -+ struct sock *sk = sock->sk; -+ struct net *net = sock_net(sk); -+ struct bus_sock *u = bus_sk(sk); -+ struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr; -+ char *sbus_path = sbusaddr->sbus_path; -+ struct dentry *dentry = NULL; -+ struct path path; -+ int err; -+ unsigned int hash; -+ struct bus_address *addr; -+ struct hlist_head *list; -+ struct bus *bus; -+ -+ err = -EINVAL; -+ if (sbusaddr->sbus_family != AF_BUS) -+ goto out; -+ -+ /* If the address is available, the socket is the bus master */ -+ sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR; -+ -+ err = bus_mkname(sbusaddr, addr_len, &hash); -+ if (err < 0) -+ goto out; -+ addr_len = err; -+ -+ mutex_lock(&u->readlock); -+ -+ err = -EINVAL; -+ if (u->addr) -+ goto out_up; -+ -+ err = -ENOMEM; -+ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL); -+ if (!addr) -+ goto out_up; -+ -+ memcpy(addr->name, sbusaddr, sizeof(struct sockaddr_bus)); -+ addr->len = addr_len; -+ addr->hash = hash; -+ atomic_set(&addr->refcnt, 1); -+ addr->sock = sk; -+ INIT_HLIST_NODE(&addr->addr_node); -+ INIT_HLIST_NODE(&addr->table_node); -+ -+ if (sbus_path[0]) { -+ umode_t mode; -+ err = 0; -+ /* -+ * Get the parent directory, calculate the hash for last -+ * component. -+ */ -+ dentry = kern_path_create(AT_FDCWD, sbus_path, &path, 0); -+ err = PTR_ERR(dentry); -+ if (IS_ERR(dentry)) -+ goto out_mknod_parent; -+ -+ /* -+ * All right, let's create it. -+ */ -+ mode = S_IFSOCK | -+ (SOCK_INODE(sock)->i_mode & ~current_umask()); -+ err = mnt_want_write(path.mnt); -+ if (err) -+ goto out_mknod_dput; -+ err = security_path_mknod(&path, dentry, mode, 0); -+ if (err) -+ goto out_mknod_drop_write; -+ err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); -+out_mknod_drop_write: -+ mnt_drop_write(path.mnt); -+ if (err) -+ goto out_mknod_dput; -+ mutex_unlock(&path.dentry->d_inode->i_mutex); -+ dput(path.dentry); -+ path.dentry = dentry; -+ } -+ -+ err = -ENOMEM; -+ bus = kzalloc(sizeof(*bus), GFP_KERNEL); -+ if (!bus) -+ goto out_unlock; -+ -+ spin_lock(&bus_table_lock); -+ -+ if (!sbus_path[0]) { -+ err = -EADDRINUSE; -+ if (__bus_find_socket_byname(net, sbusaddr, addr_len, hash)) { -+ bus_release_addr(addr); -+ kfree(bus); -+ goto out_unlock; -+ } -+ -+ list = &bus_socket_table[addr->hash]; -+ } else { -+ list = &bus_socket_table[dentry->d_inode->i_ino & -+ (BUS_HASH_SIZE-1)]; -+ u->path = path; -+ } -+ -+ kref_init(&bus->kref); -+ bus->master = sk; -+ INIT_HLIST_HEAD(&bus->peers); -+ spin_lock_init(&bus->lock); -+ spin_lock_init(&bus->send_lock); -+ atomic64_set(&bus->addr_cnt, 0); -+ atomic64_set(&bus->eavesdropper_cnt, 0); -+ -+ hlist_add_head(&addr->addr_node, &u->addr_list); -+ -+ err = 0; -+ __bus_remove_socket(sk); -+ u->addr = addr; -+ u->bus_master = true; -+ u->bus = bus; -+ __bus_insert_socket(list, sk); -+ bus_insert_address(&bus_address_table[addr->hash], addr); -+ -+out_unlock: -+ spin_unlock(&bus_table_lock); -+out_up: -+ mutex_unlock(&u->readlock); -+out: -+ return err; -+ -+out_mknod_dput: -+ dput(dentry); -+ mutex_unlock(&path.dentry->d_inode->i_mutex); -+ path_put(&path); -+out_mknod_parent: -+ if (err == -EEXIST) -+ err = -EADDRINUSE; -+ bus_release_addr(addr); -+ goto out_up; -+} -+ -+static long bus_wait_for_peer(struct sock *other, long timeo) -+{ -+ struct bus_sock *u = bus_sk(other); -+ int sched; -+ DEFINE_WAIT(wait); -+ -+ prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE); -+ -+ sched = !sock_flag(other, SOCK_DEAD) && -+ !(other->sk_shutdown & RCV_SHUTDOWN) && -+ bus_recvq_full(other); -+ -+ bus_state_unlock(other); -+ -+ if (sched) -+ timeo = schedule_timeout(timeo); -+ -+ finish_wait(&u->peer_wait, &wait); -+ return timeo; -+} -+ -+static int bus_connect(struct socket *sock, struct sockaddr *uaddr, -+ int addr_len, int flags) -+{ -+ struct sockaddr_bus *sbusaddr = (struct sockaddr_bus *)uaddr; -+ struct sock *sk = sock->sk; -+ struct net *net = sock_net(sk); -+ struct bus_sock *u = bus_sk(sk), *newu, *otheru; -+ struct sock *newsk = NULL; -+ struct sock *other = NULL; -+ struct sk_buff *skb = NULL; -+ struct bus_address *addr = NULL; -+ unsigned int hash; -+ int st; -+ int err; -+ long timeo; -+ -+ /* Only connections to the bus master is allowed */ -+ sbusaddr->sbus_addr.s_addr = BUS_MASTER_ADDR; -+ -+ err = bus_mkname(sbusaddr, addr_len, &hash); -+ if (err < 0) -+ goto out; -+ addr_len = err; -+ -+ err = -ENOMEM; -+ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL); -+ if (!addr) -+ goto out; -+ -+ atomic_set(&addr->refcnt, 1); -+ INIT_HLIST_NODE(&addr->addr_node); -+ INIT_HLIST_NODE(&addr->table_node); -+ -+ timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); -+ -+ /* First of all allocate resources. -+ If we will make it after state is locked, -+ we will have to recheck all again in any case. -+ */ -+ -+ err = -ENOMEM; -+ -+ /* create new sock for complete connection */ -+ newsk = bus_create1(sock_net(sk), NULL); -+ if (newsk == NULL) -+ goto out; -+ -+ /* Allocate skb for sending to listening sock */ -+ skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); -+ if (skb == NULL) -+ goto out; -+ -+restart: -+ /* Find listening sock. */ -+ other = bus_find_other(net, sbusaddr, addr_len, sk->sk_protocol, hash, -+ &err); -+ if (!other) -+ goto out; -+ -+ /* Latch state of peer */ -+ bus_state_lock(other); -+ -+ /* Apparently VFS overslept socket death. Retry. */ -+ if (sock_flag(other, SOCK_DEAD)) { -+ bus_state_unlock(other); -+ sock_put(other); -+ goto restart; -+ } -+ -+ err = -ECONNREFUSED; -+ if (other->sk_state != BUS_LISTEN) -+ goto out_unlock; -+ if (other->sk_shutdown & RCV_SHUTDOWN) -+ goto out_unlock; -+ -+ if (bus_recvq_full(other)) { -+ err = -EAGAIN; -+ if (!timeo) -+ goto out_unlock; -+ -+ timeo = bus_wait_for_peer(other, timeo); -+ -+ err = sock_intr_errno(timeo); -+ if (signal_pending(current)) -+ goto out; -+ sock_put(other); -+ goto restart; -+ } -+ -+ /* Latch our state. -+ -+ It is tricky place. We need to grab our state lock and cannot -+ drop lock on peer. It is dangerous because deadlock is -+ possible. Connect to self case and simultaneous -+ attempt to connect are eliminated by checking socket -+ state. other is BUS_LISTEN, if sk is BUS_LISTEN we -+ check this before attempt to grab lock. -+ -+ Well, and we have to recheck the state after socket locked. -+ */ -+ st = sk->sk_state; -+ -+ switch (st) { -+ case BUS_CLOSE: -+ /* This is ok... continue with connect */ -+ break; -+ case BUS_ESTABLISHED: -+ /* Socket is already connected */ -+ err = -EISCONN; -+ goto out_unlock; -+ default: -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ bus_state_lock_nested(sk); -+ -+ if (sk->sk_state != st) { -+ bus_state_unlock(sk); -+ bus_state_unlock(other); -+ sock_put(other); -+ goto restart; -+ } -+ -+ err = security_bus_connect(sk, other, newsk); -+ if (err) { -+ bus_state_unlock(sk); -+ goto out_unlock; -+ } -+ -+ /* The way is open! Fastly set all the necessary fields... */ -+ -+ sock_hold(sk); -+ bus_peer(newsk) = sk; -+ newsk->sk_state = BUS_ESTABLISHED; -+ newsk->sk_type = sk->sk_type; -+ newsk->sk_protocol = sk->sk_protocol; -+ init_peercred(newsk); -+ newu = bus_sk(newsk); -+ RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); -+ otheru = bus_sk(other); -+ -+ /* copy address information from listening to new sock*/ -+ if (otheru->addr && otheru->bus_master) { -+ atomic_inc(&otheru->addr->refcnt); -+ newu->addr = otheru->addr; -+ memcpy(addr->name, otheru->addr->name, -+ sizeof(struct sockaddr_bus)); -+ addr->len = otheru->addr->len; -+ addr->name->sbus_addr.s_addr = -+ (atomic64_inc_return(&otheru->bus->addr_cnt) & -+ BUS_CLIENT_MASK); -+ addr->hash = bus_compute_hash(addr->name->sbus_addr); -+ addr->sock = sk; -+ u->addr = addr; -+ kref_get(&otheru->bus->kref); -+ u->bus = otheru->bus; -+ u->bus_master_side = false; -+ kref_get(&otheru->bus->kref); -+ newu->bus = otheru->bus; -+ newu->bus_master_side = true; -+ hlist_add_head(&addr->addr_node, &u->addr_list); -+ -+ bus_insert_address(&bus_address_table[addr->hash], addr); -+ } -+ if (otheru->path.dentry) { -+ path_get(&otheru->path); -+ newu->path = otheru->path; -+ } -+ -+ /* Set credentials */ -+ copy_peercred(sk, other); -+ sk->sk_sndbuf = other->sk_sndbuf; -+ sk->sk_max_ack_backlog = other->sk_max_ack_backlog; -+ newsk->sk_sndbuf = other->sk_sndbuf; -+ -+ sock->state = SS_CONNECTED; -+ sk->sk_state = BUS_ESTABLISHED; -+ sock_hold(newsk); -+ -+ smp_mb__after_atomic_inc(); /* sock_hold() does an atomic_inc() */ -+ bus_peer(sk) = newsk; -+ -+ bus_state_unlock(sk); -+ -+ /* take ten and and send info to listening sock */ -+ spin_lock(&other->sk_receive_queue.lock); -+ __skb_queue_tail(&other->sk_receive_queue, skb); -+ spin_unlock(&other->sk_receive_queue.lock); -+ bus_state_unlock(other); -+ other->sk_data_ready(other, 0); -+ sock_put(other); -+ return 0; -+ -+out_unlock: -+ if (other) -+ bus_state_unlock(other); -+ -+out: -+ kfree_skb(skb); -+ if (addr) -+ bus_release_addr(addr); -+ if (newsk) -+ bus_release_sock(newsk, 0); -+ if (other) -+ sock_put(other); -+ return err; -+} -+ -+static int bus_accept(struct socket *sock, struct socket *newsock, int flags) -+{ -+ struct sock *sk = sock->sk; -+ struct sock *tsk; -+ struct sk_buff *skb; -+ int err; -+ -+ err = -EINVAL; -+ if (sk->sk_state != BUS_LISTEN) -+ goto out; -+ -+ /* If socket state is BUS_LISTEN it cannot change (for now...), -+ * so that no locks are necessary. -+ */ -+ -+ skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); -+ if (!skb) { -+ /* This means receive shutdown. */ -+ if (err == 0) -+ err = -EINVAL; -+ goto out; -+ } -+ -+ tsk = skb->sk; -+ skb_free_datagram(sk, skb); -+ wake_up_interruptible(&bus_sk(sk)->peer_wait); -+ -+ /* attach accepted sock to socket */ -+ bus_state_lock(tsk); -+ newsock->state = SS_CONNECTED; -+ sock_graft(tsk, newsock); -+ bus_state_unlock(tsk); -+ return 0; -+ -+out: -+ return err; -+} -+ -+ -+static int bus_getname(struct socket *sock, struct sockaddr *uaddr, -+ int *uaddr_len, int peer) -+{ -+ struct sock *sk = sock->sk; -+ struct bus_sock *u; -+ DECLARE_SOCKADDR(struct sockaddr_bus *, sbusaddr, uaddr); -+ int err = 0; -+ -+ if (peer) { -+ sk = bus_peer_get(sk); -+ -+ err = -ENOTCONN; -+ if (!sk) -+ goto out; -+ err = 0; -+ } else { -+ sock_hold(sk); -+ } -+ -+ u = bus_sk(sk); -+ -+ bus_state_lock(sk); -+ if (!u->addr) { -+ sbusaddr->sbus_family = AF_BUS; -+ sbusaddr->sbus_path[0] = 0; -+ *uaddr_len = sizeof(short); -+ } else { -+ struct bus_address *addr = u->addr; -+ -+ *uaddr_len = sizeof(struct sockaddr_bus); -+ memcpy(sbusaddr, addr->name, *uaddr_len); -+ } -+ bus_state_unlock(sk); -+ sock_put(sk); -+out: -+ return err; -+} -+ -+static void bus_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) -+{ -+ int i; -+ -+ scm->fp = BUSCB(skb).fp; -+ BUSCB(skb).fp = NULL; -+ -+ for (i = scm->fp->count-1; i >= 0; i--) -+ bus_notinflight(scm->fp->fp[i]); -+} -+ -+static void bus_destruct_scm(struct sk_buff *skb) -+{ -+ struct scm_cookie scm; -+ memset(&scm, 0, sizeof(scm)); -+ scm.pid = BUSCB(skb).pid; -+ scm.cred = BUSCB(skb).cred; -+ if (BUSCB(skb).fp) -+ bus_detach_fds(&scm, skb); -+ -+ scm_destroy(&scm); -+ if (skb->sk) -+ sock_wfree(skb); -+} -+ -+#define MAX_RECURSION_LEVEL 4 -+ -+static int bus_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) -+{ -+ int i; -+ unsigned char max_level = 0; -+ int bus_sock_count = 0; -+ -+ for (i = scm->fp->count - 1; i >= 0; i--) { -+ struct sock *sk = bus_get_socket(scm->fp->fp[i]); -+ -+ if (sk) { -+ bus_sock_count++; -+ max_level = max(max_level, -+ bus_sk(sk)->recursion_level); -+ } -+ } -+ if (unlikely(max_level > MAX_RECURSION_LEVEL)) -+ return -ETOOMANYREFS; -+ -+ /* -+ * Need to duplicate file references for the sake of garbage -+ * collection. Otherwise a socket in the fps might become a -+ * candidate for GC while the skb is not yet queued. -+ */ -+ BUSCB(skb).fp = scm_fp_dup(scm->fp); -+ if (!BUSCB(skb).fp) -+ return -ENOMEM; -+ -+ if (bus_sock_count) { -+ for (i = scm->fp->count - 1; i >= 0; i--) -+ bus_inflight(scm->fp->fp[i]); -+ } -+ return max_level; -+} -+ -+static int bus_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, -+ bool send_fds) -+{ -+ int err = 0; -+ -+ BUSCB(skb).pid = get_pid(scm->pid); -+ if (scm->cred) -+ BUSCB(skb).cred = get_cred(scm->cred); -+ BUSCB(skb).fp = NULL; -+ if (scm->fp && send_fds) -+ err = bus_attach_fds(scm, skb); -+ -+ skb->destructor = bus_destruct_scm; -+ return err; -+} -+ -+/* -+ * Some apps rely on write() giving SCM_CREDENTIALS -+ * We include credentials if source or destination socket -+ * asserted SOCK_PASSCRED. -+ */ -+static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, -+ const struct sock *other) -+{ -+ if (BUSCB(skb).cred) -+ return; -+ if (test_bit(SOCK_PASSCRED, &sock->flags) || -+ !other->sk_socket || -+ test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) { -+ BUSCB(skb).pid = get_pid(task_tgid(current)); -+ BUSCB(skb).cred = get_current_cred(); -+ } -+} -+ -+/* -+ * Send AF_BUS data. -+ */ -+ -+static void bus_deliver_skb(struct sk_buff *skb) -+{ -+ struct bus_send_context *sendctx = BUSCB(skb).sendctx; -+ struct socket *sock = sendctx->sender_socket; -+ -+ if (sock_flag(sendctx->other, SOCK_RCVTSTAMP)) -+ __net_timestamp(skb); -+ maybe_add_creds(skb, sock, sendctx->other); -+ skb_queue_tail(&sendctx->other->sk_receive_queue, skb); -+ if (sendctx->max_level > bus_sk(sendctx->other)->recursion_level) -+ bus_sk(sendctx->other)->recursion_level = sendctx->max_level; -+} -+ -+/** -+ * bus_sendmsg_finish - delivery an skb to a destination -+ * @skb: sk_buff to deliver -+ * -+ * Delivers a packet to a destination. The skb control buffer has -+ * all the information about the destination contained on sending -+ * context. If the sending is unicast, then the skb is delivered -+ * and the receiver notified but if the sending is multicast, the -+ * skb is just marked as delivered and the actual delivery is made -+ * outside the function with the bus->send_lock held to ensure that -+ * the multicast sending is atomic. -+ */ -+static int bus_sendmsg_finish(struct sk_buff *skb) -+{ -+ int err; -+ struct bus_send_context *sendctx; -+ struct socket *sock; -+ struct sock *sk; -+ struct net *net; -+ size_t len = skb->len; -+ -+ sendctx = BUSCB(skb).sendctx; -+ sock = sendctx->sender_socket; -+ sk = sock->sk; -+ net = sock_net(sk); -+ -+restart: -+ if (!sendctx->other) { -+ err = -ECONNRESET; -+ if (sendctx->recipient == NULL) -+ goto out_free; -+ -+ sendctx->other = bus_find_other(net, sendctx->recipient, -+ sendctx->namelen, -+ sk->sk_protocol, -+ sendctx->hash, &err); -+ -+ if (sendctx->other == NULL || -+ !bus_sk(sendctx->other)->authenticated) { -+ -+ if (sendctx->other) -+ sock_put(sendctx->other); -+ -+ if (!bus_sk(sk)->bus_master_side) { -+ err = -ENOTCONN; -+ sendctx->other = bus_peer_get(sk); -+ if (!sendctx->other) -+ goto out_free; -+ } else { -+ sendctx->other = sk; -+ sock_hold(sendctx->other); -+ } -+ } -+ } -+ -+ if (sk_filter(sendctx->other, skb) < 0) { -+ /* Toss the packet but do not return any error to the sender */ -+ err = len; -+ goto out_free; -+ } -+ -+ bus_state_lock(sendctx->other); -+ -+ if (sock_flag(sendctx->other, SOCK_DEAD)) { -+ /* -+ * Check with 1003.1g - what should -+ * datagram error -+ */ -+ bus_state_unlock(sendctx->other); -+ sock_put(sendctx->other); -+ -+ err = 0; -+ bus_state_lock(sk); -+ if (bus_peer(sk) == sendctx->other) { -+ bus_peer(sk) = NULL; -+ bus_state_unlock(sk); -+ sock_put(sendctx->other); -+ err = -ECONNREFUSED; -+ } else { -+ bus_state_unlock(sk); -+ } -+ -+ sendctx->other = NULL; -+ if (err) -+ goto out_free; -+ goto restart; -+ } -+ -+ err = -EPIPE; -+ if (sendctx->other->sk_shutdown & RCV_SHUTDOWN) -+ goto out_unlock; -+ -+ if (bus_recvq_full(sendctx->other)) { -+ if (!sendctx->timeo) { -+ err = -EAGAIN; -+ goto out_unlock; -+ } -+ -+ sendctx->timeo = bus_wait_for_peer(sendctx->other, -+ sendctx->timeo); -+ -+ err = sock_intr_errno(sendctx->timeo); -+ if (signal_pending(current)) -+ goto out_free; -+ -+ goto restart; -+ } -+ -+ if (!sendctx->multicast && !sendctx->eavesdropper) { -+ bus_deliver_skb(skb); -+ bus_state_unlock(sendctx->other); -+ sendctx->other->sk_data_ready(sendctx->other, 0); -+ sock_put(sendctx->other); -+ } else { -+ sendctx->deliver = 1; -+ bus_state_unlock(sendctx->other); -+ } -+ -+ return len; -+ -+out_unlock: -+ bus_state_unlock(sendctx->other); -+out_free: -+ kfree_skb(skb); -+ if (sendctx->other) -+ sock_put(sendctx->other); -+ -+ return err; -+} -+ -+/** -+ * bus_sendmsg_mcast - do a multicast sending -+ * @skb: sk_buff to deliver -+ * -+ * Send a packet to a multicast destination. -+ * The function is also called for unicast sending when eavesdropping -+ * is enabled. Since the unicast destination and the eavesdroppers -+ * have to receive the packet atomically. -+ */ -+static int bus_sendmsg_mcast(struct sk_buff *skb) -+{ -+ struct bus_send_context *sendctx; -+ struct bus_send_context *tmpctx; -+ struct socket *sock; -+ struct sock *sk; -+ struct net *net; -+ struct bus_sock *u, *s; -+ struct hlist_node *node; -+ u16 prefix = 0; -+ struct sk_buff **skb_set = NULL; -+ struct bus_send_context **sendctx_set = NULL; -+ int rcp_cnt, send_cnt; -+ int i; -+ int err; -+ int len = skb->len; -+ bool (*is_receiver) (struct sock *, u16); -+ bool main_rcp_found = false; -+ -+ sendctx = BUSCB(skb).sendctx; -+ sendctx->deliver = 0; -+ sock = sendctx->sender_socket; -+ sk = sock->sk; -+ u = bus_sk(sk); -+ net = sock_net(sk); -+ -+ if (sendctx->multicast) { -+ prefix = bus_addr_prefix(sendctx->recipient); -+ if (sendctx->eavesdropper) -+ is_receiver = &bus_has_prefix_eavesdropper; -+ else -+ is_receiver = &bus_has_prefix; -+ } else { -+ is_receiver = &bus_eavesdropper; -+ -+ /* -+ * If the destination is not the peer accepted socket -+ * we have to get the correct destination. -+ */ -+ if (!sendctx->to_master && sendctx->recipient) { -+ sendctx->other = bus_find_other(net, sendctx->recipient, -+ sendctx->namelen, -+ sk->sk_protocol, -+ sendctx->hash, &err); -+ -+ -+ if (sendctx->other == NULL || -+ !bus_sk(sendctx->other)->authenticated) { -+ -+ if (sendctx->other) -+ sock_put(sendctx->other); -+ -+ if (sendctx->other == NULL) { -+ if (!bus_sk(sk)->bus_master_side) { -+ err = -ENOTCONN; -+ sendctx->other = bus_peer_get(sk); -+ if (!sendctx->other) -+ goto out; -+ } else { -+ sendctx->other = sk; -+ sock_hold(sendctx->other); -+ } -+ } -+ sendctx->to_master = 1; -+ } -+ } -+ } -+ -+ -+try_again: -+ rcp_cnt = 0; -+ main_rcp_found = false; -+ -+ spin_lock(&u->bus->lock); -+ -+ hlist_for_each_entry(s, node, &u->bus->peers, bus_node) { -+ -+ if (!net_eq(sock_net(&s->sk), net)) -+ continue; -+ -+ if (is_receiver(&s->sk, prefix) || -+ (!sendctx->multicast && -+ !sendctx->to_master && -+ &s->sk == sendctx->other)) -+ rcp_cnt++; -+ } -+ -+ spin_unlock(&u->bus->lock); -+ -+ /* -+ * Memory can't be allocated while holding a spinlock so -+ * we have to release the lock, do the allocation for the -+ * array to store each destination peer sk_buff and grab -+ * the bus peer lock again. Peers could have joined the -+ * bus while we relesed the lock so we allocate 5 more -+ * recipients hoping that this will be enough to not having -+ * to try again in case only a few peers joined the bus. -+ */ -+ rcp_cnt += 5; -+ skb_set = kzalloc(sizeof(struct sk_buff *) * rcp_cnt, GFP_KERNEL); -+ -+ if (!skb_set) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ sendctx_set = kzalloc(sizeof(struct bus_send_context *) * rcp_cnt, -+ GFP_KERNEL); -+ if (!sendctx_set) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ for (i = 0; i < rcp_cnt; i++) { -+ skb_set[i] = skb_clone(skb, GFP_KERNEL); -+ if (!skb_set[i]) { -+ err = -ENOMEM; -+ goto out_free; -+ } -+ sendctx_set[i] = BUSCB(skb_set[i]).sendctx -+ = kmalloc(sizeof(*sendctx) * rcp_cnt, GFP_KERNEL); -+ if (!sendctx_set[i]) { -+ err = -ENOMEM; -+ goto out_free; -+ } -+ memcpy(sendctx_set[i], sendctx, sizeof(*sendctx)); -+ err = bus_scm_to_skb(sendctx_set[i]->siocb->scm, -+ skb_set[i], true); -+ if (err < 0) -+ goto out_free; -+ bus_get_secdata(sendctx_set[i]->siocb->scm, -+ skb_set[i]); -+ -+ sendctx_set[i]->other = NULL; -+ } -+ -+ send_cnt = 0; -+ -+ spin_lock(&u->bus->lock); -+ -+ hlist_for_each_entry(s, node, &u->bus->peers, bus_node) { -+ -+ if (!net_eq(sock_net(&s->sk), net)) -+ continue; -+ -+ if (send_cnt >= rcp_cnt) { -+ spin_unlock(&u->bus->lock); -+ -+ for (i = 0; i < rcp_cnt; i++) { -+ sock_put(sendctx_set[i]->other); -+ kfree_skb(skb_set[i]); -+ kfree(sendctx_set[i]); -+ } -+ kfree(skb_set); -+ kfree(sendctx_set); -+ sendctx_set = NULL; -+ skb_set = NULL; -+ goto try_again; -+ } -+ -+ if (is_receiver(&s->sk, prefix) || -+ (!sendctx->multicast && -+ !sendctx->to_master && -+ &s->sk == sendctx->other)) { -+ skb_set_owner_w(skb_set[send_cnt], &s->sk); -+ tmpctx = BUSCB(skb_set[send_cnt]).sendctx; -+ sock_hold(&s->sk); -+ if (&s->sk == sendctx->other) { -+ tmpctx->main_recipient = 1; -+ main_rcp_found = true; -+ } -+ tmpctx->other = &s->sk; -+ tmpctx->recipient = s->addr->name; -+ tmpctx->eavesdropper = bus_eavesdropper(&s->sk, 0); -+ -+ send_cnt++; -+ } -+ } -+ -+ spin_unlock(&u->bus->lock); -+ -+ /* -+ * Peers have left the bus so we have to free -+ * their pre-allocated bus_send_context and -+ * socket buffers. -+ */ -+ if (send_cnt < rcp_cnt) { -+ for (i = send_cnt; i < rcp_cnt; i++) { -+ kfree_skb(skb_set[i]); -+ kfree(sendctx_set[i]); -+ } -+ rcp_cnt = send_cnt; -+ } -+ -+ for (i = 0; i < send_cnt; i++) { -+ tmpctx = BUSCB(skb_set[i]).sendctx; -+ tmpctx->deliver = 0; -+ err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb_set[i], -+ NULL, NULL, bus_sendmsg_finish); -+ if (err == -EPERM) -+ sock_put(tmpctx->other); -+ } -+ -+ /* -+ * If the send context is not multicast, the destination -+ * coud be either the peer accepted socket descriptor or -+ * a peer that is not an eavesdropper. If the peer is not -+ * the accepted socket descriptor and has been authenticated, -+ * it is a member of the bus peer list so it has already been -+ * marked for delivery. -+ * But if the destination is the accepted socket descriptor -+ * or is a non-authenticated peer it is not a member of the -+ * bus peer list so the packet has to be explicitly deliver -+ * to it. -+ */ -+ -+ if (!sendctx->multicast && -+ (sendctx->to_master || -+ (sendctx->bus_master_side && !main_rcp_found))) { -+ sendctx->main_recipient = 1; -+ err = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL, -+ bus_sendmsg_finish); -+ if (err == -EPERM) -+ sock_put(sendctx->other); -+ } -+ -+ spin_lock(&u->bus->send_lock); -+ -+ for (i = 0; i < send_cnt; i++) { -+ tmpctx = sendctx_set[i]; -+ if (tmpctx->deliver != 1) -+ continue; -+ -+ bus_state_lock(tmpctx->other); -+ bus_deliver_skb(skb_set[i]); -+ bus_state_unlock(tmpctx->other); -+ } -+ -+ if (!sendctx->multicast && -+ sendctx->deliver == 1 && -+ !bus_sk(sendctx->other)->eavesdropper) { -+ bus_state_lock(sendctx->other); -+ bus_deliver_skb(skb); -+ bus_state_unlock(sendctx->other); -+ } -+ -+ spin_unlock(&u->bus->send_lock); -+ -+ for (i = 0; i < send_cnt; i++) { -+ tmpctx = sendctx_set[i]; -+ if (tmpctx->deliver != 1) -+ continue; -+ -+ tmpctx->other->sk_data_ready(tmpctx->other, 0); -+ sock_put(tmpctx->other); -+ } -+ -+ if (!sendctx->multicast && -+ sendctx->deliver == 1 && -+ !bus_sk(sendctx->other)->eavesdropper) { -+ sendctx->other->sk_data_ready(sendctx->other, 0); -+ sock_put(sendctx->other); -+ } -+ -+ err = len; -+ goto out; -+ -+out_free: -+ for (i = 0; i < rcp_cnt; i++) { -+ if (skb_set[i]) -+ kfree_skb(skb_set[i]); -+ } -+ -+out: -+ kfree(skb_set); -+ if (sendctx_set) { -+ for (i = 0; i < rcp_cnt; i++) -+ kfree(sendctx_set[i]); -+ kfree(sendctx_set); -+ } -+ -+ if (sendctx->deliver == 0) { -+ if (!sendctx->to_master && -+ !(sendctx->bus_master_side && !main_rcp_found)) -+ kfree_skb(skb); -+ if (!sendctx->to_master && -+ !(sendctx->bus_master_side && !main_rcp_found)) -+ if (sendctx->other) -+ sock_put(sendctx->other); -+ } -+ scm_destroy(sendctx->siocb->scm); -+ -+ return err; -+} -+ -+static inline void bus_copy_path(struct sockaddr_bus *dest, -+ struct sockaddr_bus *src) -+{ -+ int offset; -+ -+ /* -+ * abstract path names start with a null byte character, -+ * so they have to be compared starting at the second char. -+ */ -+ offset = (src->sbus_path[0] == '\0'); -+ -+ strncpy(dest->sbus_path + offset, -+ src->sbus_path + offset, -+ BUS_PATH_MAX); -+} -+ -+/** -+ * bus_sendmsg - send an skb to a destination -+ * @kiocb: I/O control block info -+ * @sock: sender socket -+ * @msg: message header -+ * @len: message length -+ * -+ * Send an socket buffer to a destination. The destination could be -+ * either an unicast or a multicast address. In any case, a copy of -+ * the packet has to be send to all the sockets that are allowed to -+ * eavesdrop the communication bus. -+ * -+ * If the destination address is not associated with any socket, the -+ * packet is default routed to the bus master (the sender accepted -+ * socket). -+ * -+ * The af_bus sending path is hooked to the netfilter subsystem so -+ * netfilter hooks can filter or modify the packet before delivery. -+ */ -+static int bus_sendmsg(struct kiocb *kiocb, struct socket *sock, -+ struct msghdr *msg, size_t len) -+{ -+ struct sock *sk = sock->sk; -+ struct bus_sock *u = bus_sk(sk); -+ struct sockaddr_bus *sbusaddr = msg->msg_name; -+ int err; -+ struct sk_buff *skb; -+ struct scm_cookie tmp_scm; -+ bool to_master = false; -+ bool multicast = false; -+ struct bus_send_context sendctx; -+ -+ err = sock_error(sk); -+ if (err) -+ return err; -+ -+ if (sk->sk_state != BUS_ESTABLISHED) -+ return -ENOTCONN; -+ -+ if (!msg->msg_namelen) -+ sbusaddr = NULL; -+ -+ if (sbusaddr) -+ bus_copy_path(sbusaddr, u->addr->name); -+ -+ if ((!sbusaddr && !u->bus_master_side) || -+ (sbusaddr && sbusaddr->sbus_addr.s_addr == BUS_MASTER_ADDR)) -+ to_master = true; -+ else if (sbusaddr && !u->bus_master_side && !u->authenticated) -+ return -EHOSTUNREACH; -+ -+ sendctx.namelen = 0; /* fake GCC */ -+ sendctx.siocb = kiocb_to_siocb(kiocb); -+ sendctx.other = NULL; -+ -+ if (NULL == sendctx.siocb->scm) -+ sendctx.siocb->scm = &tmp_scm; -+ wait_for_bus_gc(); -+ err = scm_send(sock, msg, sendctx.siocb->scm, false); -+ if (err < 0) -+ return err; -+ -+ err = -EOPNOTSUPP; -+ if (msg->msg_flags&MSG_OOB) -+ goto out; -+ -+ if (sbusaddr && !to_master) { -+ err = bus_mkname(sbusaddr, msg->msg_namelen, &sendctx.hash); -+ if (err < 0) -+ goto out; -+ sendctx.namelen = err; -+ multicast = bus_mc_addr(sbusaddr); -+ } else { -+ err = -ENOTCONN; -+ sendctx.other = bus_peer_get(sk); -+ if (!sendctx.other) -+ goto out; -+ } -+ -+ err = -EMSGSIZE; -+ if (len > sk->sk_sndbuf - 32) -+ goto out; -+ -+ sendctx.timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); -+ -+restart: -+ bus_state_lock(sk); -+ if (bus_recvq_full(sk)) { -+ err = -EAGAIN; -+ if (!sendctx.timeo) { -+ bus_state_unlock(sk); -+ goto out; -+ } -+ -+ sendctx.timeo = bus_wait_for_peer(sk, sendctx.timeo); -+ -+ err = sock_intr_errno(sendctx.timeo); -+ if (signal_pending(current)) -+ goto out; -+ -+ goto restart; -+ } else { -+ bus_state_unlock(sk); -+ } -+ -+ skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err); -+ if (skb == NULL) -+ goto out; -+ -+ err = bus_scm_to_skb(sendctx.siocb->scm, skb, true); -+ if (err < 0) -+ goto out_free; -+ sendctx.max_level = err + 1; -+ bus_get_secdata(sendctx.siocb->scm, skb); -+ -+ skb_reset_transport_header(skb); -+ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); -+ if (err) -+ goto out_free; -+ -+ sendctx.sender_socket = sock; -+ if (u->bus_master_side && sendctx.other) { -+ /* if the bus master sent an unicast message to a peer, we -+ * need the address of that peer -+ */ -+ sendctx.sender = bus_sk(sendctx.other)->addr->name; -+ } else { -+ sendctx.sender = u->addr->name; -+ } -+ sendctx.recipient = sbusaddr; -+ sendctx.authenticated = u->authenticated; -+ sendctx.bus_master_side = u->bus_master_side; -+ sendctx.to_master = to_master; -+ sendctx.multicast = multicast; -+ sendctx.eavesdropper = atomic64_read(&u->bus->eavesdropper_cnt) ? 1 : 0; -+ BUSCB(skb).sendctx = &sendctx; -+ -+ if (sendctx.multicast || sendctx.eavesdropper) { -+ sendctx.main_recipient = 0; -+ err = bus_sendmsg_mcast(skb); -+ return sendctx.multicast ? len : err; -+ } else { -+ sendctx.main_recipient = 1; -+ len = NF_HOOK(NFPROTO_BUS, NF_BUS_SENDING, skb, NULL, NULL, -+ bus_sendmsg_finish); -+ -+ if (len == -EPERM) { -+ err = len; -+ goto out; -+ } else { -+ scm_destroy(sendctx.siocb->scm); -+ return len; -+ } -+ } -+ -+out_free: -+ kfree_skb(skb); -+out: -+ if (sendctx.other) -+ sock_put(sendctx.other); -+ scm_destroy(sendctx.siocb->scm); -+ return err; -+} -+ -+static void bus_copy_addr(struct msghdr *msg, struct sock *sk) -+{ -+ struct bus_sock *u = bus_sk(sk); -+ -+ msg->msg_namelen = 0; -+ if (u->addr) { -+ msg->msg_namelen = u->addr->len; -+ memcpy(msg->msg_name, u->addr->name, -+ sizeof(struct sockaddr_bus)); -+ } -+} -+ -+static int bus_recvmsg(struct kiocb *iocb, struct socket *sock, -+ struct msghdr *msg, size_t size, int flags) -+{ -+ struct sock_iocb *siocb = kiocb_to_siocb(iocb); -+ struct scm_cookie tmp_scm; -+ struct sock *sk = sock->sk; -+ struct bus_sock *u = bus_sk(sk); -+ int noblock = flags & MSG_DONTWAIT; -+ struct sk_buff *skb; -+ int err; -+ int peeked, skip; -+ -+ if (sk->sk_state != BUS_ESTABLISHED) -+ return -ENOTCONN; -+ -+ err = -EOPNOTSUPP; -+ if (flags&MSG_OOB) -+ goto out; -+ -+ msg->msg_namelen = 0; -+ -+ err = mutex_lock_interruptible(&u->readlock); -+ if (err) { -+ err = sock_intr_errno(sock_rcvtimeo(sk, noblock)); -+ goto out; -+ } -+ -+ skip = sk_peek_offset(sk, flags); -+ -+ skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err); -+ if (!skb) { -+ bus_state_lock(sk); -+ /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ -+ if (err == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN)) -+ err = 0; -+ bus_state_unlock(sk); -+ goto out_unlock; -+ } -+ -+ wake_up_interruptible_sync_poll(&u->peer_wait, -+ POLLOUT | POLLWRNORM | POLLWRBAND); -+ -+ if (msg->msg_name) -+ bus_copy_addr(msg, skb->sk); -+ -+ if (size > skb->len - skip) -+ size = skb->len - skip; -+ else if (size < skb->len - skip) -+ msg->msg_flags |= MSG_TRUNC; -+ -+ err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size); -+ if (err) -+ goto out_free; -+ -+ if (sock_flag(sk, SOCK_RCVTSTAMP)) -+ __sock_recv_timestamp(msg, sk, skb); -+ -+ if (!siocb->scm) { -+ siocb->scm = &tmp_scm; -+ memset(&tmp_scm, 0, sizeof(tmp_scm)); -+ } -+ scm_set_cred(siocb->scm, BUSCB(skb).pid, BUSCB(skb).cred); -+ bus_set_secdata(siocb->scm, skb); -+ -+ if (!(flags & MSG_PEEK)) { -+ if (BUSCB(skb).fp) -+ bus_detach_fds(siocb->scm, skb); -+ -+ sk_peek_offset_bwd(sk, skb->len); -+ } else { -+ /* It is questionable: on PEEK we could: -+ - do not return fds - good, but too simple 8) -+ - return fds, and do not return them on read (old strategy, -+ apparently wrong) -+ - clone fds (I chose it for now, it is the most universal -+ solution) -+ -+ POSIX 1003.1g does not actually define this clearly -+ at all. POSIX 1003.1g doesn't define a lot of things -+ clearly however! -+ -+ */ -+ -+ sk_peek_offset_fwd(sk, size); -+ -+ if (BUSCB(skb).fp) -+ siocb->scm->fp = scm_fp_dup(BUSCB(skb).fp); -+ } -+ err = (flags & MSG_TRUNC) ? skb->len - skip : size; -+ -+ scm_recv(sock, msg, siocb->scm, flags); -+ -+out_free: -+ skb_free_datagram(sk, skb); -+out_unlock: -+ mutex_unlock(&u->readlock); -+out: -+ return err; -+} -+ -+static int bus_shutdown(struct socket *sock, int mode) -+{ -+ struct sock *sk = sock->sk; -+ struct sock *other; -+ -+ mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN); -+ -+ if (!mode) -+ return 0; -+ -+ bus_state_lock(sk); -+ sk->sk_shutdown |= mode; -+ other = bus_peer(sk); -+ if (other) -+ sock_hold(other); -+ bus_state_unlock(sk); -+ sk->sk_state_change(sk); -+ -+ if (other) { -+ -+ int peer_mode = 0; -+ -+ if (mode&RCV_SHUTDOWN) -+ peer_mode |= SEND_SHUTDOWN; -+ if (mode&SEND_SHUTDOWN) -+ peer_mode |= RCV_SHUTDOWN; -+ bus_state_lock(other); -+ other->sk_shutdown |= peer_mode; -+ bus_state_unlock(other); -+ other->sk_state_change(other); -+ if (peer_mode == SHUTDOWN_MASK) -+ sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); -+ else if (peer_mode & RCV_SHUTDOWN) -+ sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); -+ sock_put(other); -+ } -+ -+ return 0; -+} -+ -+static int bus_add_addr(struct sock *sk, struct bus_addr *sbus_addr) -+{ -+ struct bus_address *addr; -+ struct sock *other; -+ struct bus_sock *u = bus_sk(sk); -+ struct net *net = sock_net(sk); -+ int ret = 0; -+ -+ addr = kzalloc(sizeof(*addr) + sizeof(struct sockaddr_bus), GFP_KERNEL); -+ if (!addr) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ memcpy(addr->name, u->addr->name, sizeof(struct sockaddr_bus)); -+ addr->len = u->addr->len; -+ -+ addr->name->sbus_addr.s_addr = sbus_addr->s_addr; -+ addr->hash = bus_compute_hash(addr->name->sbus_addr); -+ other = bus_find_socket_byaddress(net, addr->name, addr->len, -+ sk->sk_protocol, addr->hash); -+ -+ if (other) { -+ sock_put(other); -+ kfree(addr); -+ ret = -EADDRINUSE; -+ goto out; -+ } -+ -+ atomic_set(&addr->refcnt, 1); -+ INIT_HLIST_NODE(&addr->addr_node); -+ INIT_HLIST_NODE(&addr->table_node); -+ -+ addr->sock = sk; -+ -+ hlist_add_head(&addr->addr_node, &u->addr_list); -+ bus_insert_address(&bus_address_table[addr->hash], addr); -+ -+out: -+ sock_put(sk); -+ -+ return ret; -+} -+ -+static int bus_del_addr(struct sock *sk, struct bus_addr *sbus_addr) -+{ -+ struct bus_address *addr; -+ int ret = 0; -+ -+ bus_state_lock(sk); -+ addr = __bus_get_address(sk, sbus_addr); -+ if (!addr) { -+ ret = -EINVAL; -+ bus_state_unlock(sk); -+ goto out; -+ } -+ hlist_del(&addr->addr_node); -+ bus_state_unlock(sk); -+ -+ bus_remove_address(addr); -+ bus_release_addr(addr); -+out: -+ sock_put(sk); -+ -+ return ret; -+} -+ -+static int bus_join_bus(struct sock *sk) -+{ -+ struct sock *peer; -+ struct bus_sock *u = bus_sk(sk), *peeru; -+ int err = 0; -+ -+ peer = bus_peer_get(sk); -+ if (!peer) -+ return -ENOTCONN; -+ peeru = bus_sk(peer); -+ -+ if (!u->bus_master_side || peeru->authenticated) { -+ err = -EINVAL; -+ goto sock_put_out; -+ } -+ -+ if (sk->sk_state != BUS_ESTABLISHED) { -+ err = -ENOTCONN; -+ goto sock_put_out; -+ } -+ -+ if (peer->sk_shutdown != 0) { -+ err = -ENOTCONN; -+ goto sock_put_out; -+ } -+ -+ bus_state_lock(peer); -+ peeru->authenticated = true; -+ bus_state_unlock(peer); -+ -+ spin_lock(&u->bus->lock); -+ hlist_add_head(&peeru->bus_node, &u->bus->peers); -+ spin_unlock(&u->bus->lock); -+ -+sock_put_out: -+ sock_put(peer); -+ return err; -+} -+ -+static int __bus_set_eavesdrop(struct sock *sk, bool eavesdrop) -+{ -+ struct sock *peer = bus_peer_get(sk); -+ struct bus_sock *u = bus_sk(sk), *peeru; -+ int err = 0; -+ -+ if (!peer) -+ return -ENOTCONN; -+ -+ if (sk->sk_state != BUS_ESTABLISHED) { -+ err = -ENOTCONN; -+ goto sock_put_out; -+ } -+ -+ peeru = bus_sk(peer); -+ -+ if (!u->bus_master_side || !peeru->authenticated) { -+ err = -EINVAL; -+ goto sock_put_out; -+ } -+ -+ if (peer->sk_shutdown != 0) { -+ err = -ENOTCONN; -+ goto sock_put_out; -+ } -+ -+ bus_state_lock(peeru); -+ if (peeru->eavesdropper != eavesdrop) { -+ peeru->eavesdropper = eavesdrop; -+ if (eavesdrop) -+ atomic64_inc(&u->bus->eavesdropper_cnt); -+ else -+ atomic64_dec(&u->bus->eavesdropper_cnt); -+ } -+ bus_state_unlock(peeru); -+ -+sock_put_out: -+ sock_put(peer); -+ return err; -+} -+ -+static int bus_set_eavesdrop(struct sock *sk) -+{ -+ return __bus_set_eavesdrop(sk, true); -+} -+ -+static int bus_unset_eavesdrop(struct sock *sk) -+{ -+ return __bus_set_eavesdrop(sk, false); -+} -+ -+static inline void sk_sendbuf_set(struct sock *sk, int sndbuf) -+{ -+ bus_state_lock(sk); -+ sk->sk_sndbuf = sndbuf; -+ bus_state_unlock(sk); -+} -+ -+static inline void sk_maxqlen_set(struct sock *sk, int qlen) -+{ -+ bus_state_lock(sk); -+ sk->sk_max_ack_backlog = qlen; -+ bus_state_unlock(sk); -+} -+ -+static int bus_get_qlenfull(struct sock *sk) -+{ -+ struct sock *peer; -+ struct bus_sock *u = bus_sk(sk), *peeru; -+ int ret = 0; -+ -+ peer = bus_peer_get(sk); -+ if (!peer) -+ return -ENOTCONN; -+ -+ peeru = bus_sk(peer); -+ -+ if (!u->bus_master_side || peeru->authenticated) { -+ ret = -EINVAL; -+ goto sock_put_out; -+ } -+ -+ if (sk->sk_state != BUS_ESTABLISHED) { -+ ret = -ENOTCONN; -+ goto sock_put_out; -+ } -+ -+ if (peer->sk_shutdown != 0) { -+ ret = -ENOTCONN; -+ goto sock_put_out; -+ } -+ -+ ret = bus_recvq_full(peer); -+ -+sock_put_out: -+ sock_put(peer); -+ return ret; -+} -+ -+static int bus_setsockopt(struct socket *sock, int level, int optname, -+ char __user *optval, unsigned int optlen) -+{ -+ struct bus_addr addr; -+ int res; -+ int val; -+ -+ if (level != SOL_BUS) -+ return -ENOPROTOOPT; -+ -+ switch (optname) { -+ case BUS_ADD_ADDR: -+ case BUS_DEL_ADDR: -+ if (optlen < sizeof(struct bus_addr)) -+ return -EINVAL; -+ -+ if (!bus_sk(sock->sk)->bus_master_side) -+ return -EINVAL; -+ -+ if (copy_from_user(&addr, optval, sizeof(struct bus_addr))) -+ return -EFAULT; -+ -+ if (optname == BUS_ADD_ADDR) -+ res = bus_add_addr(bus_peer_get(sock->sk), &addr); -+ else -+ res = bus_del_addr(bus_peer_get(sock->sk), &addr); -+ break; -+ case BUS_JOIN_BUS: -+ res = bus_join_bus(sock->sk); -+ break; -+ case BUS_SET_EAVESDROP: -+ res = bus_set_eavesdrop(sock->sk); -+ break; -+ case BUS_UNSET_EAVESDROP: -+ res = bus_unset_eavesdrop(sock->sk); -+ break; -+ case BUS_SET_SENDBUF: -+ case BUS_SET_MAXQLEN: -+ if (sock->sk->sk_state != BUS_LISTEN) { -+ res = -EINVAL; -+ } else { -+ res = -EFAULT; -+ -+ if (copy_from_user(&val, optval, optlen)) -+ break; -+ -+ res = 0; -+ -+ if (optname == BUS_SET_SENDBUF) -+ sk_sendbuf_set(sock->sk, val); -+ else -+ sk_maxqlen_set(sock->sk, val); -+ } -+ break; -+ case BUS_GET_QLENFULL: -+ res = bus_get_qlenfull(sock->sk); -+ -+ if (copy_to_user(&res, optval, optlen)) { -+ res = -EFAULT; -+ break; -+ } -+ res = 0; -+ break; -+ default: -+ res = -EINVAL; -+ break; -+ } -+ -+ return res; -+} -+ -+long bus_inq_len(struct sock *sk) -+{ -+ struct sk_buff *skb; -+ long amount = 0; -+ -+ if (sk->sk_state == BUS_LISTEN) -+ return -EINVAL; -+ -+ spin_lock(&sk->sk_receive_queue.lock); -+ skb_queue_walk(&sk->sk_receive_queue, skb) -+ amount += skb->len; -+ spin_unlock(&sk->sk_receive_queue.lock); -+ -+ return amount; -+} -+EXPORT_SYMBOL_GPL(bus_inq_len); -+ -+long bus_outq_len(struct sock *sk) -+{ -+ return sk_wmem_alloc_get(sk); -+} -+EXPORT_SYMBOL_GPL(bus_outq_len); -+ -+static int bus_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -+{ -+ struct sock *sk = sock->sk; -+ long amount = 0; -+ int err; -+ -+ switch (cmd) { -+ case SIOCOUTQ: -+ amount = bus_outq_len(sk); -+ err = put_user(amount, (int __user *)arg); -+ break; -+ case SIOCINQ: -+ amount = bus_inq_len(sk); -+ if (amount < 0) -+ err = amount; -+ else -+ err = put_user(amount, (int __user *)arg); -+ break; -+ default: -+ err = -ENOIOCTLCMD; -+ break; -+ } -+ return err; -+} -+ -+static unsigned int bus_poll(struct file *file, struct socket *sock, -+ poll_table *wait) -+{ -+ struct sock *sk = sock->sk, *other; -+ unsigned int mask, writable; -+ struct bus_sock *u = bus_sk(sk), *p; -+ struct hlist_node *node; -+ -+ sock_poll_wait(file, sk_sleep(sk), wait); -+ mask = 0; -+ -+ /* exceptional events? */ -+ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) -+ mask |= POLLERR; -+ if (sk->sk_shutdown & RCV_SHUTDOWN) -+ mask |= POLLRDHUP | POLLIN | POLLRDNORM; -+ if (sk->sk_shutdown == SHUTDOWN_MASK) -+ mask |= POLLHUP; -+ -+ /* readable? */ -+ if (!skb_queue_empty(&sk->sk_receive_queue)) -+ mask |= POLLIN | POLLRDNORM; -+ -+ /* Connection-based need to check for termination and startup */ -+ if (sk->sk_state == BUS_CLOSE) -+ mask |= POLLHUP; -+ -+ /* No write status requested, avoid expensive OUT tests. */ -+ if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT))) -+ return mask; -+ -+ writable = bus_writable(sk); -+ other = bus_peer_get(sk); -+ if (other) { -+ if (bus_recvq_full(other)) -+ writable = 0; -+ sock_put(other); -+ } -+ -+ /* -+ * If the socket has already joined the bus we have to check -+ * that each peer receiver queue on the bus is not full. -+ */ -+ if (!u->bus_master_side && u->authenticated) { -+ spin_lock(&u->bus->lock); -+ hlist_for_each_entry(p, node, &u->bus->peers, bus_node) { -+ if (bus_recvq_full(&p->sk)) { -+ writable = 0; -+ break; -+ } -+ } -+ spin_unlock(&u->bus->lock); -+ } -+ -+ if (writable) -+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND; -+ else -+ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); -+ -+ return mask; -+} -+ -+#ifdef CONFIG_PROC_FS -+static struct sock *first_bus_socket(int *i) -+{ -+ for (*i = 0; *i <= BUS_HASH_SIZE; (*i)++) { -+ if (!hlist_empty(&bus_socket_table[*i])) -+ return __sk_head(&bus_socket_table[*i]); -+ } -+ return NULL; -+} -+ -+static struct sock *next_bus_socket(int *i, struct sock *s) -+{ -+ struct sock *next = sk_next(s); -+ /* More in this chain? */ -+ if (next) -+ return next; -+ /* Look for next non-empty chain. */ -+ for ((*i)++; *i <= BUS_HASH_SIZE; (*i)++) { -+ if (!hlist_empty(&bus_socket_table[*i])) -+ return __sk_head(&bus_socket_table[*i]); -+ } -+ return NULL; -+} -+ -+struct bus_iter_state { -+ struct seq_net_private p; -+ int i; -+}; -+ -+static struct sock *bus_seq_idx(struct seq_file *seq, loff_t pos) -+{ -+ struct bus_iter_state *iter = seq->private; -+ loff_t off = 0; -+ struct sock *s; -+ -+ for (s = first_bus_socket(&iter->i); s; -+ s = next_bus_socket(&iter->i, s)) { -+ if (sock_net(s) != seq_file_net(seq)) -+ continue; -+ if (off == pos) -+ return s; -+ ++off; -+ } -+ return NULL; -+} -+ -+static void *bus_seq_start(struct seq_file *seq, loff_t *pos) -+ __acquires(bus_table_lock) -+{ -+ spin_lock(&bus_table_lock); -+ return *pos ? bus_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN; -+} -+ -+static void *bus_seq_next(struct seq_file *seq, void *v, loff_t *pos) -+{ -+ struct bus_iter_state *iter = seq->private; -+ struct sock *sk = v; -+ ++*pos; -+ -+ if (v == SEQ_START_TOKEN) -+ sk = first_bus_socket(&iter->i); -+ else -+ sk = next_bus_socket(&iter->i, sk); -+ while (sk && (sock_net(sk) != seq_file_net(seq))) -+ sk = next_bus_socket(&iter->i, sk); -+ return sk; -+} -+ -+static void bus_seq_stop(struct seq_file *seq, void *v) -+ __releases(bus_table_lock) -+{ -+ spin_unlock(&bus_table_lock); -+} -+ -+static int bus_seq_show(struct seq_file *seq, void *v) -+{ -+ -+ if (v == SEQ_START_TOKEN) -+ seq_puts(seq, "Num RefCount Protocol Flags Type St " \ -+ "Inode Path\n"); -+ else { -+ struct sock *s = v; -+ struct bus_sock *u = bus_sk(s); -+ bus_state_lock(s); -+ -+ seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu", -+ s, -+ atomic_read(&s->sk_refcnt), -+ 0, -+ s->sk_state == BUS_LISTEN ? __SO_ACCEPTCON : 0, -+ s->sk_type, -+ s->sk_socket ? -+ (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : -+ (s->sk_state == BUS_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), -+ sock_i_ino(s)); -+ -+ if (u->addr) { -+ int i, len; -+ seq_putc(seq, ' '); -+ -+ i = 0; -+ len = u->addr->len - sizeof(short); -+ if (!BUS_ABSTRACT(s)) -+ len--; -+ else { -+ seq_putc(seq, '@'); -+ i++; -+ } -+ for ( ; i < len; i++) -+ seq_putc(seq, u->addr->name->sbus_path[i]); -+ } -+ bus_state_unlock(s); -+ seq_putc(seq, '\n'); -+ } -+ -+ return 0; -+} -+ -+static const struct seq_operations bus_seq_ops = { -+ .start = bus_seq_start, -+ .next = bus_seq_next, -+ .stop = bus_seq_stop, -+ .show = bus_seq_show, -+}; -+ -+static int bus_seq_open(struct inode *inode, struct file *file) -+{ -+ return seq_open_net(inode, file, &bus_seq_ops, -+ sizeof(struct bus_iter_state)); -+} -+ -+static const struct file_operations bus_seq_fops = { -+ .owner = THIS_MODULE, -+ .open = bus_seq_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release_net, -+}; -+ -+#endif -+ -+static const struct net_proto_family bus_family_ops = { -+ .family = PF_BUS, -+ .create = bus_create, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init af_bus_init(void) -+{ -+ int rc = -1; -+ struct sk_buff *dummy_skb; -+ -+ BUILD_BUG_ON(sizeof(struct bus_skb_parms) > sizeof(dummy_skb->cb)); -+ -+ rc = proto_register(&bus_proto, 1); -+ if (rc != 0) { -+ pr_crit("%s: Cannot create bus_sock SLAB cache!\n", __func__); -+ return rc; -+ } -+ -+ sock_register(&bus_family_ops); -+ return rc; -+} -+ -+static void __exit af_bus_exit(void) -+{ -+ sock_unregister(PF_BUS); -+ proto_unregister(&bus_proto); -+} -+ -+module_init(af_bus_init); -+module_exit(af_bus_exit); -+ -+MODULE_AUTHOR("Alban Crequy, Javier Martinez Canillas"); -+MODULE_DESCRIPTION("Linux Bus domain sockets"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_NETPROTO(PF_BUS); --- -1.7.7.6 - diff --git a/patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch b/patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch deleted file mode 100644 index aaf0cc586f7d..000000000000 --- a/patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch +++ /dev/null @@ -1,344 +0,0 @@ -From 2a2abe6e793a5b7f027d8af33f1ebb3e106016eb Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 15:56:38 +0200 -Subject: [PATCH 09/15] net: bus: Add garbage collector for AF_BUS sockets. - -This patch adds a garbage collector for AF_BUS sockets. - -Signed-off-by: Javier Martinez Canillas ---- - net/bus/garbage.c | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 322 insertions(+), 0 deletions(-) - create mode 100644 net/bus/garbage.c - -diff --git a/net/bus/garbage.c b/net/bus/garbage.c -new file mode 100644 -index 0000000..2435f38 ---- /dev/null -+++ b/net/bus/garbage.c -@@ -0,0 +1,322 @@ -+/* -+ * Garbage Collector For AF_BUS sockets -+ * -+ * Based on Garbage Collector For AF_UNIX sockets (net/unix/garbage.c). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+/* Internal data structures and random procedures: */ -+ -+static LIST_HEAD(gc_inflight_list); -+static LIST_HEAD(gc_candidates); -+static DEFINE_SPINLOCK(bus_gc_lock); -+static DECLARE_WAIT_QUEUE_HEAD(bus_gc_wait); -+ -+unsigned int bus_tot_inflight; -+ -+ -+struct sock *bus_get_socket(struct file *filp) -+{ -+ struct sock *u_sock = NULL; -+ struct inode *inode = filp->f_path.dentry->d_inode; -+ -+ /* -+ * Socket ? -+ */ -+ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { -+ struct socket *sock = SOCKET_I(inode); -+ struct sock *s = sock->sk; -+ -+ /* -+ * PF_BUS ? -+ */ -+ if (s && sock->ops && sock->ops->family == PF_BUS) -+ u_sock = s; -+ } -+ return u_sock; -+} -+ -+/* -+ * Keep the number of times in flight count for the file -+ * descriptor if it is for an AF_BUS socket. -+ */ -+ -+void bus_inflight(struct file *fp) -+{ -+ struct sock *s = bus_get_socket(fp); -+ if (s) { -+ struct bus_sock *u = bus_sk(s); -+ spin_lock(&bus_gc_lock); -+ if (atomic_long_inc_return(&u->inflight) == 1) { -+ BUG_ON(!list_empty(&u->link)); -+ list_add_tail(&u->link, &gc_inflight_list); -+ } else { -+ BUG_ON(list_empty(&u->link)); -+ } -+ bus_tot_inflight++; -+ spin_unlock(&bus_gc_lock); -+ } -+} -+ -+void bus_notinflight(struct file *fp) -+{ -+ struct sock *s = bus_get_socket(fp); -+ if (s) { -+ struct bus_sock *u = bus_sk(s); -+ spin_lock(&bus_gc_lock); -+ BUG_ON(list_empty(&u->link)); -+ if (atomic_long_dec_and_test(&u->inflight)) -+ list_del_init(&u->link); -+ bus_tot_inflight--; -+ spin_unlock(&bus_gc_lock); -+ } -+} -+ -+static void scan_inflight(struct sock *x, void (*func)(struct bus_sock *), -+ struct sk_buff_head *hitlist) -+{ -+ struct sk_buff *skb; -+ struct sk_buff *next; -+ -+ spin_lock(&x->sk_receive_queue.lock); -+ skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { -+ /* -+ * Do we have file descriptors ? -+ */ -+ if (BUSCB(skb).fp) { -+ bool hit = false; -+ /* -+ * Process the descriptors of this socket -+ */ -+ int nfd = BUSCB(skb).fp->count; -+ struct file **fp = BUSCB(skb).fp->fp; -+ while (nfd--) { -+ /* -+ * Get the socket the fd matches -+ * if it indeed does so -+ */ -+ struct sock *sk = bus_get_socket(*fp++); -+ if (sk) { -+ struct bus_sock *u = bus_sk(sk); -+ -+ /* -+ * Ignore non-candidates, they could -+ * have been added to the queues after -+ * starting the garbage collection -+ */ -+ if (u->gc_candidate) { -+ hit = true; -+ func(u); -+ } -+ } -+ } -+ if (hit && hitlist != NULL) { -+ __skb_unlink(skb, &x->sk_receive_queue); -+ __skb_queue_tail(hitlist, skb); -+ } -+ } -+ } -+ spin_unlock(&x->sk_receive_queue.lock); -+} -+ -+static void scan_children(struct sock *x, void (*func)(struct bus_sock *), -+ struct sk_buff_head *hitlist) -+{ -+ if (x->sk_state != TCP_LISTEN) -+ scan_inflight(x, func, hitlist); -+ else { -+ struct sk_buff *skb; -+ struct sk_buff *next; -+ struct bus_sock *u; -+ LIST_HEAD(embryos); -+ -+ /* -+ * For a listening socket collect the queued embryos -+ * and perform a scan on them as well. -+ */ -+ spin_lock(&x->sk_receive_queue.lock); -+ skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { -+ u = bus_sk(skb->sk); -+ -+ /* -+ * An embryo cannot be in-flight, so it's safe -+ * to use the list link. -+ */ -+ BUG_ON(!list_empty(&u->link)); -+ list_add_tail(&u->link, &embryos); -+ } -+ spin_unlock(&x->sk_receive_queue.lock); -+ -+ while (!list_empty(&embryos)) { -+ u = list_entry(embryos.next, struct bus_sock, link); -+ scan_inflight(&u->sk, func, hitlist); -+ list_del_init(&u->link); -+ } -+ } -+} -+ -+static void dec_inflight(struct bus_sock *usk) -+{ -+ atomic_long_dec(&usk->inflight); -+} -+ -+static void inc_inflight(struct bus_sock *usk) -+{ -+ atomic_long_inc(&usk->inflight); -+} -+ -+static void inc_inflight_move_tail(struct bus_sock *u) -+{ -+ atomic_long_inc(&u->inflight); -+ /* -+ * If this still might be part of a cycle, move it to the end -+ * of the list, so that it's checked even if it was already -+ * passed over -+ */ -+ if (u->gc_maybe_cycle) -+ list_move_tail(&u->link, &gc_candidates); -+} -+ -+static bool gc_in_progress = false; -+#define BUS_INFLIGHT_TRIGGER_GC 16000 -+ -+void wait_for_bus_gc(void) -+{ -+ /* -+ * If number of inflight sockets is insane, -+ * force a garbage collect right now. -+ */ -+ if (bus_tot_inflight > BUS_INFLIGHT_TRIGGER_GC && !gc_in_progress) -+ bus_gc(); -+ wait_event(bus_gc_wait, gc_in_progress == false); -+} -+ -+/* The external entry point: bus_gc() */ -+void bus_gc(void) -+{ -+ struct bus_sock *u; -+ struct bus_sock *next; -+ struct sk_buff_head hitlist; -+ struct list_head cursor; -+ LIST_HEAD(not_cycle_list); -+ -+ spin_lock(&bus_gc_lock); -+ -+ /* Avoid a recursive GC. */ -+ if (gc_in_progress) -+ goto out; -+ -+ gc_in_progress = true; -+ /* -+ * First, select candidates for garbage collection. Only -+ * in-flight sockets are considered, and from those only ones -+ * which don't have any external reference. -+ * -+ * Holding bus_gc_lock will protect these candidates from -+ * being detached, and hence from gaining an external -+ * reference. Since there are no possible receivers, all -+ * buffers currently on the candidates' queues stay there -+ * during the garbage collection. -+ * -+ * We also know that no new candidate can be added onto the -+ * receive queues. Other, non candidate sockets _can_ be -+ * added to queue, so we must make sure only to touch -+ * candidates. -+ */ -+ list_for_each_entry_safe(u, next, &gc_inflight_list, link) { -+ long total_refs; -+ long inflight_refs; -+ -+ total_refs = file_count(u->sk.sk_socket->file); -+ inflight_refs = atomic_long_read(&u->inflight); -+ -+ BUG_ON(inflight_refs < 1); -+ BUG_ON(total_refs < inflight_refs); -+ if (total_refs == inflight_refs) { -+ list_move_tail(&u->link, &gc_candidates); -+ u->gc_candidate = 1; -+ u->gc_maybe_cycle = 1; -+ } -+ } -+ -+ /* -+ * Now remove all internal in-flight reference to children of -+ * the candidates. -+ */ -+ list_for_each_entry(u, &gc_candidates, link) -+ scan_children(&u->sk, dec_inflight, NULL); -+ -+ /* -+ * Restore the references for children of all candidates, -+ * which have remaining references. Do this recursively, so -+ * only those remain, which form cyclic references. -+ * -+ * Use a "cursor" link, to make the list traversal safe, even -+ * though elements might be moved about. -+ */ -+ list_add(&cursor, &gc_candidates); -+ while (cursor.next != &gc_candidates) { -+ u = list_entry(cursor.next, struct bus_sock, link); -+ -+ /* Move cursor to after the current position. */ -+ list_move(&cursor, &u->link); -+ -+ if (atomic_long_read(&u->inflight) > 0) { -+ list_move_tail(&u->link, ¬_cycle_list); -+ u->gc_maybe_cycle = 0; -+ scan_children(&u->sk, inc_inflight_move_tail, NULL); -+ } -+ } -+ list_del(&cursor); -+ -+ /* -+ * not_cycle_list contains those sockets which do not make up a -+ * cycle. Restore these to the inflight list. -+ */ -+ while (!list_empty(¬_cycle_list)) { -+ u = list_entry(not_cycle_list.next, struct bus_sock, link); -+ u->gc_candidate = 0; -+ list_move_tail(&u->link, &gc_inflight_list); -+ } -+ -+ /* -+ * Now gc_candidates contains only garbage. Restore original -+ * inflight counters for these as well, and remove the skbuffs -+ * which are creating the cycle(s). -+ */ -+ skb_queue_head_init(&hitlist); -+ list_for_each_entry(u, &gc_candidates, link) -+ scan_children(&u->sk, inc_inflight, &hitlist); -+ -+ spin_unlock(&bus_gc_lock); -+ -+ /* Here we are. Hitlist is filled. Die. */ -+ __skb_queue_purge(&hitlist); -+ -+ spin_lock(&bus_gc_lock); -+ -+ /* All candidates should have been detached by now. */ -+ BUG_ON(!list_empty(&gc_candidates)); -+ gc_in_progress = false; -+ wake_up(&bus_gc_wait); -+ -+ out: -+ spin_unlock(&bus_gc_lock); -+} --- -1.7.7.6 - diff --git a/patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch b/patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch deleted file mode 100644 index 19e3f4bf7c75..000000000000 --- a/patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 89d9d1c0afd8d782a9726dfb79646022086a21bb Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 16:16:40 +0200 -Subject: [PATCH 10/15] net: bus: Add the AF_BUS socket address family to - KBuild - -This patch adds the AF_BUS code to the Linux Kernel build system. - -Signed-off-by: Javier Martinez Canillas ---- - net/Kconfig | 1 + - net/Makefile | 1 + - net/bus/Kconfig | 15 +++++++++++++++ - net/bus/Makefile | 7 +++++++ - 4 files changed, 24 insertions(+), 0 deletions(-) - create mode 100644 net/bus/Kconfig - create mode 100644 net/bus/Makefile - -diff --git a/net/Kconfig b/net/Kconfig -index e07272d..c9774a1 100644 ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -47,6 +47,7 @@ menu "Networking options" - - source "net/packet/Kconfig" - source "net/unix/Kconfig" -+source "net/bus/Kconfig" - source "net/xfrm/Kconfig" - source "net/iucv/Kconfig" - -diff --git a/net/Makefile b/net/Makefile -index ad432fa..3033018 100644 ---- a/net/Makefile -+++ b/net/Makefile -@@ -19,6 +19,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/ - obj-$(CONFIG_INET) += ipv4/ - obj-$(CONFIG_XFRM) += xfrm/ - obj-$(CONFIG_UNIX) += unix/ -+obj-$(CONFIG_AF_BUS) += bus/ - obj-$(CONFIG_NET) += ipv6/ - obj-$(CONFIG_PACKET) += packet/ - obj-$(CONFIG_NET_KEY) += key/ -diff --git a/net/bus/Kconfig b/net/bus/Kconfig -new file mode 100644 -index 0000000..5f01410 ---- /dev/null -+++ b/net/bus/Kconfig -@@ -0,0 +1,15 @@ -+# -+# Bus Domain Sockets -+# -+ -+config AF_BUS -+ tristate "Bus domain sockets (EXPERIMENTAL)" -+ depends on EXPERIMENTAL -+ ---help--- -+ If you say Y here, you will include support for Bus domain sockets. -+ These sockets are used to create communication buses for IPC. -+ -+ To compile this driver as a module, choose M here: the module will be -+ called bus. -+ -+ Say N unless you know what you are doing. -diff --git a/net/bus/Makefile b/net/bus/Makefile -new file mode 100644 -index 0000000..8c1fea2 ---- /dev/null -+++ b/net/bus/Makefile -@@ -0,0 +1,7 @@ -+# -+# Makefile for the Linux bus domain socket layer. -+# -+ -+obj-$(CONFIG_AF_BUS) += af-bus.o -+ -+af-bus-y := af_bus.o garbage.o --- -1.7.7.6 - diff --git a/patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch b/patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch deleted file mode 100644 index dd8cf5ad816a..000000000000 --- a/patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch +++ /dev/null @@ -1,87 +0,0 @@ -From b0049444e09caf7cb41f63a8648cc1a98a5940cf Mon Sep 17 00:00:00 2001 -From: Alban Crequy -Date: Wed, 20 Jun 2012 18:04:37 +0200 -Subject: [PATCH 11/15] netlink: connector: implement cn_netlink_reply - -In a connector callback, it was not possible to reply to a message only to a -sender. This patch implements cn_netlink_reply(). It uses the connector socket -to send an unicast netlink message back to the sender. - -The following pseudo-code can be used from a connector callback: - - struct cn_msg *cn_reply; - cn_reply = kzalloc(sizeof(struct cn_msg) - + sizeof(struct ..._nl_cfg_reply), GFP_KERNEL); - - cn_reply->id = msg->id; - cn_reply->seq = msg->seq; - cn_reply->ack = msg->ack + 1; - cn_reply->len = sizeof(struct ..._nl_cfg_reply); - cn_reply->flags = 0; - - rr = cn_netlink_reply(cn_reply, nsp->pid, GFP_KERNEL); - -Signed-off-by: Alban Crequy ---- - drivers/connector/connector.c | 32 ++++++++++++++++++++++++++++++++ - include/linux/connector.h | 1 + - 2 files changed, 33 insertions(+), 0 deletions(-) - -diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c -index dde6a0f..a1f9364 100644 ---- a/drivers/connector/connector.c -+++ b/drivers/connector/connector.c -@@ -118,6 +118,38 @@ nlmsg_failure: - EXPORT_SYMBOL_GPL(cn_netlink_send); - - /* -+ * Send an unicast reply from a connector callback -+ * -+ */ -+int cn_netlink_reply(struct cn_msg *msg, u32 pid, gfp_t gfp_mask) -+{ -+ unsigned int size; -+ struct sk_buff *skb; -+ struct nlmsghdr *nlh; -+ struct cn_msg *data; -+ struct cn_dev *dev = &cdev; -+ -+ size = NLMSG_SPACE(sizeof(*msg) + msg->len); -+ -+ skb = alloc_skb(size, gfp_mask); -+ if (!skb) -+ return -ENOMEM; -+ -+ nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh), 0); -+ if (nlh == NULL) { -+ kfree_skb(skb); -+ return -EMSGSIZE; -+ } -+ -+ data = nlmsg_data(nlh); -+ -+ memcpy(data, msg, sizeof(*data) + msg->len); -+ -+ return netlink_unicast(dev->nls, skb, pid, 1); -+} -+EXPORT_SYMBOL_GPL(cn_netlink_reply); -+ -+/* - * Callback helper - queues work and setup destructor for given data. - */ - static int cn_call_callback(struct sk_buff *skb) -diff --git a/include/linux/connector.h b/include/linux/connector.h -index 7638407..c27be60 100644 ---- a/include/linux/connector.h -+++ b/include/linux/connector.h -@@ -125,6 +125,7 @@ int cn_add_callback(struct cb_id *id, const char *name, - void (*callback)(struct cn_msg *, struct netlink_skb_parms *)); - void cn_del_callback(struct cb_id *); - int cn_netlink_send(struct cn_msg *, u32, gfp_t); -+int cn_netlink_reply(struct cn_msg *, u32, gfp_t); - - int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name, - struct cb_id *id, --- -1.7.7.6 - diff --git a/patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch b/patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch deleted file mode 100644 index 7bd7553fd610..000000000000 --- a/patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch +++ /dev/null @@ -1,42 +0,0 @@ -From b34502ec47d9b6cdc526c762837fd242cb674c44 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 18:15:09 +0200 -Subject: [PATCH 12/15] netlink: connector: Add idx and val identifiers for - netfilter D-Bus - -The D-bus IPC system implements a transport that uses AF_BUS sockets to -send D-Bus messages to the peers. This allows decouple the routing logic -from the daemon and move it to the kernel which has the advantage of -reducing the number of context switches and the messages copied to -user-space. - -A D-Bus protocol aware netfilter module decide which peer can recive a -given message based on a set of D-Bus match rules. These match rules -are set from user-space using the netlink connector API. - -Based on a previous patch by Alban Crequy. - -Signed-off-by: Javier Martinez Canillas ---- - include/linux/connector.h | 4 +++- - 1 files changed, 3 insertions(+), 1 deletions(-) - -diff --git a/include/linux/connector.h b/include/linux/connector.h -index c27be60..519d010 100644 ---- a/include/linux/connector.h -+++ b/include/linux/connector.h -@@ -44,8 +44,10 @@ - #define CN_VAL_DRBD 0x1 - #define CN_KVP_IDX 0x9 /* HyperV KVP */ - #define CN_KVP_VAL 0x1 /* queries from the kernel */ -+#define CN_IDX_NFDBUS 0xA /* netfilter D-Bus */ -+#define CN_VAL_NFDBUS 0x1 - --#define CN_NETLINK_USERS 10 /* Highest index + 1 */ -+#define CN_NETLINK_USERS 11 /* Highest index + 1 */ - - /* - * Maximum connector's message size. --- -1.7.7.6 - diff --git a/patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch b/patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch deleted file mode 100644 index c00eae3c6cf8..000000000000 --- a/patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch +++ /dev/null @@ -1,299 +0,0 @@ -From ef39ec62107dfb7fa0ecd43026804e214569cad5 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 19:01:52 +0200 -Subject: [PATCH 13/15] netfilter: nfdbus: Add D-bus message parsing - -The netfilter D-Bus module needs to parse D-bus messages sent by -applications to decide whether a peer can receive or not a D-Bus -message. Add D-bus message parsing logic to be able to analyze. - -Based on a previous patch by Alban Crequy. - -Signed-off-by: Javier Martinez Canillas ---- - net/bus/nfdbus/message.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++ - net/bus/nfdbus/message.h | 71 +++++++++++++++++ - 2 files changed, 265 insertions(+), 0 deletions(-) - create mode 100644 net/bus/nfdbus/message.c - create mode 100644 net/bus/nfdbus/message.h - -diff --git a/net/bus/nfdbus/message.c b/net/bus/nfdbus/message.c -new file mode 100644 -index 0000000..93c409c ---- /dev/null -+++ b/net/bus/nfdbus/message.c -@@ -0,0 +1,194 @@ -+/* -+ * message.c Basic D-Bus message parsing -+ * -+ * Copyright (C) 2010-2012 Collabora Ltd -+ * Authors: Alban Crequy -+ * 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 -+ -+#include "message.h" -+ -+int dbus_message_type_from_string(const char *type_str) -+{ -+ if (strcmp(type_str, "method_call") == 0) -+ return DBUS_MESSAGE_TYPE_METHOD_CALL; -+ if (strcmp(type_str, "method_return") == 0) -+ return DBUS_MESSAGE_TYPE_METHOD_RETURN; -+ else if (strcmp(type_str, "signal") == 0) -+ return DBUS_MESSAGE_TYPE_SIGNAL; -+ else if (strcmp(type_str, "error") == 0) -+ return DBUS_MESSAGE_TYPE_ERROR; -+ else -+ return DBUS_MESSAGE_TYPE_INVALID; -+} -+ -+int dbus_message_parse(unsigned char *message, size_t len, -+ struct dbus_message *dbus_message) -+{ -+ unsigned char *cur; -+ int array_header_len; -+ -+ dbus_message->message = message; -+ -+ if (len < 4 + 4 + 4 + 4 || message[1] == 0 || message[1] > 4) -+ return -EINVAL; -+ -+ dbus_message->type = message[1]; -+ dbus_message->body_length = *((u32 *)(message + 4)); -+ cur = message + 12; -+ array_header_len = *(u32 *)cur; -+ dbus_message->len_offset = 12; -+ cur += 4; -+ while (cur < message + len -+ && cur < message + 12 + 4 + array_header_len) { -+ int header_code; -+ int signature_len; -+ unsigned char *signature; -+ int str_len; -+ unsigned char *str; -+ -+ /* D-Bus alignment craziness */ -+ if ((cur - message) % 8 != 0) -+ cur += 8 - (cur - message) % 8; -+ -+ header_code = *(char *)cur; -+ cur++; -+ signature_len = *(char *)cur; -+ /* All header fields of the current D-Bus spec have a simple -+ * type, either o, s, g, or u */ -+ if (signature_len != 1) -+ return -EINVAL; -+ cur++; -+ signature = cur; -+ cur += signature_len + 1; -+ if (signature[0] != 'o' && -+ signature[0] != 's' && -+ signature[0] != 'g' && -+ signature[0] != 'u') -+ return -EINVAL; -+ -+ if (signature[0] == 'u') { -+ cur += 4; -+ continue; -+ } -+ -+ if (signature[0] != 'g') { -+ str_len = *(u32 *)cur; -+ cur += 4; -+ } else { -+ str_len = *(char *)cur; -+ cur += 1; -+ } -+ -+ str = cur; -+ switch (header_code) { -+ case 1: -+ dbus_message->path = str; -+ break; -+ case 2: -+ dbus_message->interface = str; -+ break; -+ case 3: -+ dbus_message->member = str; -+ break; -+ case 6: -+ dbus_message->destination = str; -+ break; -+ case 7: -+ dbus_message->sender = str; -+ break; -+ case 8: -+ dbus_message->body_signature = str; -+ break; -+ } -+ cur += str_len + 1; -+ } -+ -+ dbus_message->padding_end = (8 - (cur - message) % 8) % 8; -+ -+ /* Jump to body D-Bus alignment craziness */ -+ if ((cur - message) % 8 != 0) -+ cur += 8 - (cur - message) % 8; -+ dbus_message->new_header_offset = cur - message; -+ -+ if (dbus_message->new_header_offset -+ + dbus_message->body_length != len) { -+ pr_warn("Message truncated? " \ -+ "Header %d + Body %d != Length %zd\n", -+ dbus_message->new_header_offset, -+ dbus_message->body_length, len); -+ return -EINVAL; -+ } -+ -+ if (dbus_message->body_signature && -+ dbus_message->body_signature[0] == 's') { -+ int str_len; -+ str_len = *(u32 *)cur; -+ cur += 4; -+ dbus_message->arg0 = cur; -+ cur += str_len + 1; -+ } -+ -+ if ((cur - message) % 4 != 0) -+ cur += 4 - (cur - message) % 4; -+ -+ if (dbus_message->body_signature && -+ dbus_message->body_signature[0] == 's' && -+ dbus_message->body_signature[1] == 's') { -+ int str_len; -+ str_len = *(u32 *)cur; -+ cur += 4; -+ dbus_message->arg1 = cur; -+ cur += str_len + 1; -+ } -+ -+ if ((cur - message) % 4 != 0) -+ cur += 4 - (cur - message) % 4; -+ -+ if (dbus_message->body_signature && -+ dbus_message->body_signature[0] == 's' && -+ dbus_message->body_signature[1] == 's' && -+ dbus_message->body_signature[2] == 's') { -+ int str_len; -+ str_len = *(u32 *)cur; -+ cur += 4; -+ dbus_message->arg2 = cur; -+ cur += str_len + 1; -+ } -+ -+ if ((cur - message) % 4 != 0) -+ cur += 4 - (cur - message) % 4; -+ -+ if (dbus_message->type == DBUS_MESSAGE_TYPE_SIGNAL && -+ dbus_message->sender && dbus_message->path && -+ dbus_message->interface && dbus_message->member && -+ dbus_message->arg0 && -+ strcmp(dbus_message->sender, "org.freedesktop.DBus") == 0 && -+ strcmp(dbus_message->interface, "org.freedesktop.DBus") == 0 && -+ strcmp(dbus_message->path, "/org/freedesktop/DBus") == 0) { -+ if (strcmp(dbus_message->member, "NameAcquired") == 0) -+ dbus_message->name_acquired = dbus_message->arg0; -+ else if (strcmp(dbus_message->member, "NameLost") == 0) -+ dbus_message->name_lost = dbus_message->arg0; -+ } -+ -+ return 0; -+} -diff --git a/net/bus/nfdbus/message.h b/net/bus/nfdbus/message.h -new file mode 100644 -index 0000000..e3ea4d3 ---- /dev/null -+++ b/net/bus/nfdbus/message.h -@@ -0,0 +1,71 @@ -+/* -+ * message.h Basic D-Bus message parsing -+ * -+ * Copyright (C) 2010 Collabora Ltd -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#ifndef DBUS_MESSAGE_H -+#define DBUS_MESSAGE_H -+ -+#include -+ -+#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 -+ -+/* Types of message */ -+ -+#define DBUS_MESSAGE_TYPE_INVALID 0 -+#define DBUS_MESSAGE_TYPE_METHOD_CALL 1 -+#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 -+#define DBUS_MESSAGE_TYPE_ERROR 3 -+#define DBUS_MESSAGE_TYPE_SIGNAL 4 -+#define DBUS_NUM_MESSAGE_TYPES 5 -+ -+/* No need to implement a feature-complete parser. It only implement what is -+ * needed by the bus. */ -+struct dbus_message { -+ char *message; -+ size_t len; -+ size_t new_len; -+ -+ /* direct pointers to the fields */ -+ int type; -+ char *path; -+ char *interface; -+ char *member; -+ char *destination; -+ char *sender; -+ char *body_signature; -+ int body_length; -+ char *arg0; -+ char *arg1; -+ char *arg2; -+ char *name_acquired; -+ char *name_lost; -+ -+ /* How to add the 'sender' field in the headers */ -+ int new_header_offset; -+ int len_offset; -+ int padding_end; -+}; -+ -+int dbus_message_type_from_string(const char *type_str); -+ -+int dbus_message_parse(unsigned char *message, size_t len, -+ struct dbus_message *dbus_message); -+ -+#endif /* DBUS_MESSAGE_H */ --- -1.7.7.6 - diff --git a/patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch b/patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch deleted file mode 100644 index 2404f38ce72e..000000000000 --- a/patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch +++ /dev/null @@ -1,1247 +0,0 @@ -From 7532e3f92cd858c9cbe441895f3e33d007c59f57 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Wed, 20 Jun 2012 19:05:54 +0200 -Subject: [PATCH 14/15] netfilter: nfdbus: Add D-bus match rule implementation - -The D-Bus netfilter module needs to decode D-Bus match rules to decide -if a given peer can receive or not a D-Bus message. Add a match rule -implementation to be used by the netfilter D-Bus module. - -Based on a previous patch by Alban Crequy. - -Signed-off-by: Javier Martinez Canillas ---- - net/bus/nfdbus/matchrule.c | 1131 ++++++++++++++++++++++++++++++++++++++++++++ - net/bus/nfdbus/matchrule.h | 82 ++++ - 2 files changed, 1213 insertions(+), 0 deletions(-) - create mode 100644 net/bus/nfdbus/matchrule.c - create mode 100644 net/bus/nfdbus/matchrule.h - -diff --git a/net/bus/nfdbus/matchrule.c b/net/bus/nfdbus/matchrule.c -new file mode 100644 -index 0000000..1946345 ---- /dev/null -+++ b/net/bus/nfdbus/matchrule.c -@@ -0,0 +1,1131 @@ -+/* -+ * matchrule.c D-Bus match rule implementation -+ * -+ * Based on signals.c from dbus -+ * -+ * Copyright (C) 2010 Collabora, Ltd. -+ * Copyright (C) 2003, 2005 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#include "matchrule.h" -+ -+#include -+#include -+#include -+ -+#include "message.h" -+ -+enum bus_match_flags { -+ BUS_MATCH_MESSAGE_TYPE = 1 << 0, -+ BUS_MATCH_INTERFACE = 1 << 1, -+ BUS_MATCH_MEMBER = 1 << 2, -+ BUS_MATCH_SENDER = 1 << 3, -+ BUS_MATCH_DESTINATION = 1 << 4, -+ BUS_MATCH_PATH = 1 << 5, -+ BUS_MATCH_ARGS = 1 << 6, -+ BUS_MATCH_PATH_NAMESPACE = 1 << 7, -+ BUS_MATCH_CLIENT_IS_EAVESDROPPING = 1 << 8 -+}; -+ -+struct bus_match_rule { -+ /* For debugging only*/ -+ char *rule_text; -+ -+ unsigned int flags; /**< BusMatchFlags */ -+ -+ int message_type; -+ char *interface; -+ char *member; -+ char *sender; -+ char *destination; -+ char *path; -+ -+ unsigned int *arg_lens; -+ char **args; -+ int args_len; -+ -+ /* bus_match_rule is attached to rule_pool, either in a simple -+ * double-linked list if the rule does not have any interface, or in a -+ * red-black tree sorted by interface. If several rules can have the -+ * same interface, the first one is attached with struct rb_node and the -+ * next ones are in the list -+ */ -+ -+ struct rb_node node; -+ /* Doubly-linked non-circular list. If the rule has an interface, it is -+ * in the rb tree and the single head is right here. Otherwise, the -+ * single head is in rule_pool->rules_without_iface. With this data -+ * structure, we don't need any allocation to insert or remove the rule. -+ */ -+ struct hlist_head first; -+ struct hlist_node list; -+ -+ /* used to delete all names from the tree */ -+ struct list_head del_list; -+}; -+ -+struct dbus_name { -+ struct rb_node node; -+ char *name; -+ -+ /* used to delete all names from the tree */ -+ struct list_head del_list; -+}; -+ -+#define BUS_MATCH_ARG_IS_PATH 0x8000000u -+ -+#define DBUS_STRING_MAX_LENGTH 1024 -+ -+/** Max length of a match rule string; to keep people from hosing the -+ * daemon with some huge rule -+ */ -+#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 -+ -+struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags) -+{ -+ struct bus_match_rule *rule; -+ -+ rule = kzalloc(sizeof(struct bus_match_rule), gfp_flags); -+ if (rule == NULL) -+ return NULL; -+ -+ return rule; -+} -+ -+void bus_match_rule_free(struct bus_match_rule *rule) -+{ -+ kfree(rule->rule_text); -+ kfree(rule->interface); -+ kfree(rule->member); -+ kfree(rule->sender); -+ kfree(rule->destination); -+ kfree(rule->path); -+ kfree(rule->arg_lens); -+ -+ /* can't use dbus_free_string_array() since there -+ * are embedded NULL -+ */ -+ if (rule->args) { -+ int i; -+ -+ i = 0; -+ while (i < rule->args_len) { -+ kfree(rule->args[i]); -+ ++i; -+ } -+ -+ kfree(rule->args); -+ } -+ -+ kfree(rule); -+} -+ -+static int -+bus_match_rule_set_message_type(struct bus_match_rule *rule, -+ int type, -+ gfp_t gfp_flags) -+{ -+ rule->flags |= BUS_MATCH_MESSAGE_TYPE; -+ -+ rule->message_type = type; -+ -+ return 1; -+} -+ -+static int -+bus_match_rule_set_interface(struct bus_match_rule *rule, -+ const char *interface, -+ gfp_t gfp_flags) -+{ -+ char *new; -+ -+ WARN_ON(!interface); -+ -+ new = kstrdup(interface, gfp_flags); -+ if (new == NULL) -+ return 0; -+ -+ rule->flags |= BUS_MATCH_INTERFACE; -+ kfree(rule->interface); -+ rule->interface = new; -+ -+ return 1; -+} -+ -+static int -+bus_match_rule_set_member(struct bus_match_rule *rule, -+ const char *member, -+ gfp_t gfp_flags) -+{ -+ char *new; -+ -+ WARN_ON(!member); -+ -+ new = kstrdup(member, gfp_flags); -+ if (new == NULL) -+ return 0; -+ -+ rule->flags |= BUS_MATCH_MEMBER; -+ kfree(rule->member); -+ rule->member = new; -+ -+ return 1; -+} -+ -+static int -+bus_match_rule_set_sender(struct bus_match_rule *rule, -+ const char *sender, -+ gfp_t gfp_flags) -+{ -+ char *new; -+ -+ WARN_ON(!sender); -+ -+ new = kstrdup(sender, gfp_flags); -+ if (new == NULL) -+ return 0; -+ -+ rule->flags |= BUS_MATCH_SENDER; -+ kfree(rule->sender); -+ rule->sender = new; -+ -+ return 1; -+} -+ -+static int -+bus_match_rule_set_destination(struct bus_match_rule *rule, -+ const char *destination, -+ gfp_t gfp_flags) -+{ -+ char *new; -+ -+ WARN_ON(!destination); -+ -+ new = kstrdup(destination, gfp_flags); -+ if (new == NULL) -+ return 0; -+ -+ rule->flags |= BUS_MATCH_DESTINATION; -+ kfree(rule->destination); -+ rule->destination = new; -+ -+ return 1; -+} -+ -+#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || \ -+ ((c) == '\r')) -+ -+static int find_key(const char *str, int start, char *key, int *value_pos) -+{ -+ const char *p; -+ const char *s; -+ const char *key_start; -+ const char *key_end; -+ -+ s = str; -+ -+ p = s + start; -+ -+ while (*p && ISWHITE(*p)) -+ ++p; -+ -+ key_start = p; -+ -+ while (*p && *p != '=' && !ISWHITE(*p)) -+ ++p; -+ -+ key_end = p; -+ -+ while (*p && ISWHITE(*p)) -+ ++p; -+ -+ if (key_start == key_end) { -+ /* Empty match rules or trailing whitespace are OK */ -+ *value_pos = p - s; -+ return 1; -+ } -+ -+ if (*p != '=') { -+ pr_warn("Match rule has a key with no subsequent '=' character"); -+ return 0; -+ } -+ ++p; -+ -+ strncat(key, key_start, key_end - key_start); -+ -+ *value_pos = p - s; -+ -+ return 1; -+} -+ -+static int find_value(const char *str, int start, const char *key, char *value, -+ int *value_end) -+{ -+ const char *p; -+ const char *s; -+ char quote_char; -+ int orig_len; -+ -+ orig_len = strlen(value); -+ -+ s = str; -+ -+ p = s + start; -+ -+ quote_char = '\0'; -+ -+ while (*p) { -+ if (quote_char == '\0') { -+ switch (*p) { -+ case '\0': -+ goto done; -+ -+ case '\'': -+ quote_char = '\''; -+ goto next; -+ -+ case ',': -+ ++p; -+ goto done; -+ -+ case '\\': -+ quote_char = '\\'; -+ goto next; -+ -+ default: -+ strncat(value, p, 1); -+ } -+ } else if (quote_char == '\\') { -+ /*\ only counts as an escape if escaping a quote mark */ -+ if (*p != '\'') -+ strncat(value, "\\", 1); -+ -+ strncat(value, p, 1); -+ -+ quote_char = '\0'; -+ } else { -+ if (*p == '\'') -+ quote_char = '\0'; -+ else -+ strncat(value, p, 1); -+ } -+ -+next: -+ ++p; -+ } -+ -+done: -+ -+ if (quote_char == '\\') -+ strncat(value, "\\", 1); -+ else if (quote_char == '\'') { -+ pr_warn("Unbalanced quotation marks in match rule"); -+ return 0; -+ } -+ -+ /* Zero-length values are allowed */ -+ -+ *value_end = p - s; -+ -+ return 1; -+} -+ -+/* duplicates aren't allowed so the real legitimate max is only 6 or -+ * so. Leaving extra so we don't have to bother to update it. -+ * FIXME this is sort of busted now with arg matching, but we let -+ * you match on up to 10 args for now -+ */ -+#define MAX_RULE_TOKENS 16 -+ -+/* this is slightly too high level to be termed a "token" -+ * but let's not be pedantic. -+ */ -+struct rule_token { -+ char *key; -+ char *value; -+}; -+ -+static int tokenize_rule(const char *rule_text, -+ struct rule_token tokens[MAX_RULE_TOKENS], -+ gfp_t gfp_flags) -+{ -+ int i; -+ int pos; -+ int retval; -+ -+ retval = 0; -+ -+ i = 0; -+ pos = 0; -+ while (i < MAX_RULE_TOKENS && -+ pos < strlen(rule_text)) { -+ char *key; -+ char *value; -+ -+ key = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags); -+ if (!key) { -+ pr_err("Out of memory"); -+ return 0; -+ } -+ -+ value = kzalloc(DBUS_STRING_MAX_LENGTH, gfp_flags); -+ if (!value) { -+ kfree(key); -+ pr_err("Out of memory"); -+ return 0; -+ } -+ -+ if (!find_key(rule_text, pos, key, &pos)) -+ goto out; -+ -+ if (strlen(key) == 0) -+ goto next; -+ -+ tokens[i].key = key; -+ -+ if (!find_value(rule_text, pos, tokens[i].key, value, &pos)) -+ goto out; -+ -+ tokens[i].value = value; -+ -+next: -+ ++i; -+ } -+ -+ retval = 1; -+ -+out: -+ if (!retval) { -+ i = 0; -+ while (tokens[i].key || tokens[i].value) { -+ kfree(tokens[i].key); -+ kfree(tokens[i].value); -+ tokens[i].key = NULL; -+ tokens[i].value = NULL; -+ ++i; -+ } -+ } -+ -+ return retval; -+} -+ -+/* -+ * The format is comma-separated with strings quoted with single quotes -+ * as for the shell (to escape a literal single quote, use '\''). -+ * -+ * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus', -+ * member='Foo', path='/bar/foo',destination=':452345.34' -+ * -+ */ -+struct bus_match_rule *bus_match_rule_parse(const char *rule_text, -+ gfp_t gfp_flags) -+{ -+ struct bus_match_rule *rule; -+ struct rule_token tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */ -+ int i; -+ -+ if (strlen(rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) { -+ pr_warn("Match rule text is %ld bytes, maximum is %d", -+ strlen(rule_text), -+ DBUS_MAXIMUM_MATCH_RULE_LENGTH); -+ return NULL; -+ } -+ -+ memset(tokens, '\0', sizeof(tokens)); -+ -+ rule = bus_match_rule_new(gfp_flags); -+ if (rule == NULL) { -+ pr_err("Out of memory"); -+ goto failed; -+ } -+ -+ rule->rule_text = kstrdup(rule_text, gfp_flags); -+ if (rule->rule_text == NULL) { -+ pr_err("Out of memory"); -+ goto failed; -+ } -+ -+ if (!tokenize_rule(rule_text, tokens, gfp_flags)) -+ goto failed; -+ -+ i = 0; -+ while (tokens[i].key != NULL) { -+ const char *key = tokens[i].key; -+ const char *value = tokens[i].value; -+ -+ if (strcmp(key, "type") == 0) { -+ int t; -+ -+ if (rule->flags & BUS_MATCH_MESSAGE_TYPE) { -+ pr_warn("Key %s specified twice in match rule\n", -+ key); -+ goto failed; -+ } -+ -+ t = dbus_message_type_from_string(value); -+ -+ if (t == DBUS_MESSAGE_TYPE_INVALID) { -+ pr_warn("Invalid message type (%s) in match rule\n", -+ value); -+ goto failed; -+ } -+ -+ if (!bus_match_rule_set_message_type(rule, t, -+ gfp_flags)) { -+ pr_err("Out of memeory"); -+ goto failed; -+ } -+ } else if (strcmp(key, "sender") == 0) { -+ if (rule->flags & BUS_MATCH_SENDER) { -+ pr_warn("Key %s specified twice in match rule\n", -+ key); -+ goto failed; -+ } -+ -+ if (!bus_match_rule_set_sender(rule, value, -+ gfp_flags)) { -+ pr_err("Out of memeory"); -+ goto failed; -+ } -+ } else if (strcmp(key, "interface") == 0) { -+ if (rule->flags & BUS_MATCH_INTERFACE) { -+ pr_warn("Key %s specified twice in match rule\n", -+ key); -+ goto failed; -+ } -+ -+ if (!bus_match_rule_set_interface(rule, value, -+ gfp_flags)) { -+ pr_err("Out of memeory"); -+ goto failed; -+ } -+ } else if (strcmp(key, "member") == 0) { -+ if (rule->flags & BUS_MATCH_MEMBER) { -+ pr_warn("Key %s specified twice in match rule\n", -+ key); -+ goto failed; -+ } -+ -+ if (!bus_match_rule_set_member(rule, value, -+ gfp_flags)) { -+ pr_err("Out of memeory"); -+ goto failed; -+ } -+ } else if (strcmp(key, "destination") == 0) { -+ if (rule->flags & BUS_MATCH_DESTINATION) { -+ pr_warn("Key %s specified twice in match rule\n", -+ key); -+ goto failed; -+ } -+ -+ if (!bus_match_rule_set_destination(rule, value, -+ gfp_flags)) { -+ pr_err("Out of memeory"); -+ goto failed; -+ } -+ } else if (strcmp(key, "eavesdrop") == 0) { -+ if (strcmp(value, "true") == 0) { -+ rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING; -+ } else if (strcmp(value, "false") == 0) { -+ rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING); -+ } else { -+ pr_warn("eavesdrop='%s' is invalid, " \ -+ "it should be 'true' or 'false'\n", -+ value); -+ goto failed; -+ } -+ } else if (strncmp(key, "arg", 3) != 0) { -+ pr_warn("Unknown key \"%s\" in match rule\n", -+ key); -+ goto failed; -+ } -+ -+ ++i; -+ } -+ -+ goto out; -+ -+failed: -+ if (rule) { -+ bus_match_rule_free(rule); -+ rule = NULL; -+ } -+ -+out: -+ -+ i = 0; -+ while (tokens[i].key || tokens[i].value) { -+ WARN_ON(i >= MAX_RULE_TOKENS); -+ kfree(tokens[i].key); -+ kfree(tokens[i].value); -+ ++i; -+ } -+ -+ return rule; -+} -+ -+/* return the match rule containing the hlist_head. It may not be the first -+ * match rule in the list. */ -+struct bus_match_rule *match_rule_search(struct rb_root *root, -+ const char *interface) -+{ -+ struct rb_node *node = root->rb_node; -+ -+ while (node) { -+ struct bus_match_rule *data = -+ container_of(node, struct bus_match_rule, node); -+ int result; -+ -+ result = strcmp(interface, data->interface); -+ -+ if (result < 0) -+ node = node->rb_left; -+ else if (result > 0) -+ node = node->rb_right; -+ else -+ return data; -+ } -+ return NULL; -+} -+ -+void match_rule_insert(struct rb_root *root, struct bus_match_rule *data) -+{ -+ struct rb_node **new = &(root->rb_node), *parent = NULL; -+ -+ /* Figure out where to put new node */ -+ while (*new) { -+ struct bus_match_rule *this = -+ container_of(*new, struct bus_match_rule, node); -+ int result = strcmp(data->interface, this->interface); -+ -+ parent = *new; -+ if (result < 0) -+ new = &((*new)->rb_left); -+ else if (result > 0) -+ new = &((*new)->rb_right); -+ else { -+ /* the head is not used */ -+ INIT_HLIST_HEAD(&data->first); -+ /* Add it at the beginning of the list */ -+ hlist_add_head(&data->list, &this->first); -+ return; -+ } -+ } -+ -+ /* this rule is single in its list */ -+ INIT_HLIST_HEAD(&data->first); -+ hlist_add_head(&data->list, &data->first); -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&data->node, parent, new); -+ rb_insert_color(&data->node, root); -+} -+ -+struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags) -+{ -+ struct bus_match_maker *matchmaker; -+ int i; -+ -+ matchmaker = kzalloc(sizeof(struct bus_match_maker), gfp_flags); -+ if (matchmaker == NULL) -+ return NULL; -+ -+ for (i = DBUS_MESSAGE_TYPE_INVALID; i < DBUS_NUM_MESSAGE_TYPES; i++) { -+ struct rule_pool *p = matchmaker->rules_by_type + i; -+ -+ p->rules_by_iface = RB_ROOT; -+ } -+ -+ kref_init(&matchmaker->kref); -+ -+ return matchmaker; -+} -+ -+void bus_matchmaker_free(struct kref *kref) -+{ -+ struct bus_match_maker *matchmaker; -+ struct list_head del_list; -+ struct rb_node *n; -+ int i; -+ -+ matchmaker = container_of(kref, struct bus_match_maker, kref); -+ -+ /* free names */ -+ INIT_LIST_HEAD(&del_list); -+ n = matchmaker->names.rb_node; -+ if (n) { -+ struct dbus_name *dbus_name, *cur, *tmp; -+ -+ dbus_name = rb_entry(n, struct dbus_name, node); -+ list_add_tail(&dbus_name->del_list, &del_list); -+ -+ list_for_each_entry(cur, &del_list, del_list) { -+ struct dbus_name *right, *left; -+ if (cur->node.rb_right) { -+ right = rb_entry(cur->node.rb_right, -+ struct dbus_name, node); -+ list_add_tail(&right->del_list, &del_list); -+ } -+ if (cur->node.rb_left) { -+ left = rb_entry(cur->node.rb_left, -+ struct dbus_name, node); -+ list_add_tail(&left->del_list, &del_list); -+ } -+ } -+ list_for_each_entry_safe(dbus_name, tmp, &del_list, del_list) { -+ kfree(dbus_name->name); -+ list_del(&dbus_name->del_list); -+ kfree(dbus_name); -+ } -+ } -+ WARN_ON(!list_empty_careful(&del_list)); -+ -+ /* free match rules */ -+ for (i = 0 ; i < DBUS_NUM_MESSAGE_TYPES ; i++) { -+ struct rule_pool *pool = matchmaker->rules_by_type + i; -+ struct bus_match_rule *match_rule, *cur, *tmp; -+ struct hlist_node *list_tmp, *list_tmp2; -+ -+ /* free match rules from the list */ -+ hlist_for_each_entry_safe(cur, list_tmp, list_tmp2, -+ &pool->rules_without_iface, list) { -+ bus_match_rule_free(cur); -+ } -+ -+ /* free match rules from the tree */ -+ if (!pool->rules_by_iface.rb_node) -+ continue; -+ match_rule = rb_entry(pool->rules_by_iface.rb_node, -+ struct bus_match_rule, node); -+ list_add_tail(&match_rule->del_list, &del_list); -+ -+ list_for_each_entry(cur, &del_list, del_list) { -+ struct bus_match_rule *right, *left; -+ if (cur->node.rb_right) { -+ right = rb_entry(cur->node.rb_right, -+ struct bus_match_rule, node); -+ list_add_tail(&right->del_list, &del_list); -+ } -+ if (cur->node.rb_left) { -+ left = rb_entry(cur->node.rb_left, -+ struct bus_match_rule, node); -+ list_add_tail(&left->del_list, &del_list); -+ } -+ } -+ list_for_each_entry_safe(match_rule, tmp, &del_list, del_list) { -+ /* keep a ref during the loop to ensure the first -+ * iteration of the loop does not delete it */ -+ hlist_for_each_entry_safe(cur, list_tmp, list_tmp2, -+ &match_rule->first, list) { -+ if (cur != match_rule) -+ bus_match_rule_free(cur); -+ } -+ list_del(&match_rule->del_list); -+ bus_match_rule_free(match_rule); -+ } -+ WARN_ON(!list_empty_careful(&del_list)); -+ } -+ -+ kfree(matchmaker); -+} -+ -+/* The rule can't be modified after it's added. */ -+int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker, -+ struct bus_match_rule *rule) -+{ -+ struct rule_pool *pool; -+ -+ WARN_ON(rule->message_type < 0); -+ WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES); -+ -+ pool = matchmaker->rules_by_type + rule->message_type; -+ -+ if (rule->interface) -+ match_rule_insert(&pool->rules_by_iface, rule); -+ else -+ hlist_add_head(&rule->list, &pool->rules_without_iface); -+ -+ return 1; -+} -+ -+static int match_rule_equal(struct bus_match_rule *a, -+ struct bus_match_rule *b) -+{ -+ if (a->flags != b->flags) -+ return 0; -+ -+ if ((a->flags & BUS_MATCH_MESSAGE_TYPE) && -+ a->message_type != b->message_type) -+ return 0; -+ -+ if ((a->flags & BUS_MATCH_MEMBER) && -+ strcmp(a->member, b->member) != 0) -+ return 0; -+ -+ if ((a->flags & BUS_MATCH_PATH) && -+ strcmp(a->path, b->path) != 0) -+ return 0; -+ -+ if ((a->flags & BUS_MATCH_INTERFACE) && -+ strcmp(a->interface, b->interface) != 0) -+ return 0; -+ -+ if ((a->flags & BUS_MATCH_SENDER) && -+ strcmp(a->sender, b->sender) != 0) -+ return 0; -+ -+ if ((a->flags & BUS_MATCH_DESTINATION) && -+ strcmp(a->destination, b->destination) != 0) -+ return 0; -+ -+ if (a->flags & BUS_MATCH_ARGS) { -+ int i; -+ -+ if (a->args_len != b->args_len) -+ return 0; -+ -+ i = 0; -+ while (i < a->args_len) { -+ int length; -+ -+ if ((a->args[i] != NULL) != (b->args[i] != NULL)) -+ return 0; -+ -+ if (a->arg_lens[i] != b->arg_lens[i]) -+ return 0; -+ -+ length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; -+ -+ if (a->args[i] != NULL) { -+ WARN_ON(!b->args[i]); -+ if (memcmp(a->args[i], b->args[i], length) != 0) -+ return 0; -+ } -+ -+ ++i; -+ } -+ } -+ -+ return 1; -+} -+ -+/* Remove a single rule which is equal to the given rule by value */ -+void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker, -+ struct bus_match_rule *rule) -+{ -+ struct rule_pool *pool; -+ -+ WARN_ON(rule->message_type < 0); -+ WARN_ON(rule->message_type >= DBUS_NUM_MESSAGE_TYPES); -+ -+ pool = matchmaker->rules_by_type + rule->message_type; -+ -+ if (rule->interface) { -+ struct bus_match_rule *head = -+ match_rule_search(&pool->rules_by_iface, -+ rule->interface); -+ -+ struct hlist_node *cur; -+ struct bus_match_rule *cur_rule; -+ hlist_for_each_entry(cur_rule, cur, &head->first, list) { -+ if (match_rule_equal(cur_rule, rule)) { -+ hlist_del(cur); -+ if (hlist_empty(&head->first)) -+ rb_erase(&head->node, -+ &pool->rules_by_iface); -+ bus_match_rule_free(cur_rule); -+ break; -+ } -+ } -+ } else { -+ struct hlist_head *head = &pool->rules_without_iface; -+ -+ struct hlist_node *cur; -+ struct bus_match_rule *cur_rule; -+ hlist_for_each_entry(cur_rule, cur, head, list) { -+ if (match_rule_equal(cur_rule, rule)) { -+ hlist_del(cur); -+ bus_match_rule_free(cur_rule); -+ break; -+ } -+ } -+ } -+ -+} -+ -+static int connection_is_primary_owner(struct bus_match_maker *connection, -+ const char *service_name) -+{ -+ struct rb_node *node = connection->names.rb_node; -+ -+ if (!service_name) -+ return 0; -+ -+ while (node) { -+ struct dbus_name *data = container_of(node, struct dbus_name, -+ node); -+ int result; -+ -+ result = strcmp(service_name, data->name); -+ -+ if (result < 0) -+ node = node->rb_left; -+ else if (result > 0) -+ node = node->rb_right; -+ else -+ return 1; -+ } -+ return 0; -+} -+ -+static int match_rule_matches(struct bus_match_maker *matchmaker, -+ struct bus_match_maker *sender, -+ int eavesdrop, -+ struct bus_match_rule *rule, -+ const struct dbus_message *message) -+{ -+ /* Don't consider the rule if this is a eavesdropping match rule -+ * and eavesdropping is not allowed on that peer */ -+ if ((rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) && !eavesdrop) -+ return 0; -+ -+ /* Since D-Bus 1.5.6, match rules do not match messages which have a -+ * DESTINATION field unless the match rule specifically requests this -+ * by specifying eavesdrop='true' in the match rule. */ -+ if (message->destination && -+ !(rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)) -+ return 0; -+ -+ if (rule->flags & BUS_MATCH_MEMBER) { -+ const char *member; -+ -+ WARN_ON(!rule->member); -+ -+ member = message->member; -+ if (member == NULL) -+ return 0; -+ -+ if (strcmp(member, rule->member) != 0) -+ return 0; -+ } -+ -+ if (rule->flags & BUS_MATCH_SENDER) { -+ WARN_ON(!rule->sender); -+ -+ if (sender == NULL) { -+ if (strcmp(rule->sender, -+ "org.freedesktop.DBus") != 0) -+ return 0; -+ } else -+ if (!connection_is_primary_owner(sender, rule->sender)) -+ return 0; -+ } -+ -+ if (rule->flags & BUS_MATCH_DESTINATION) { -+ const char *destination; -+ -+ WARN_ON(!rule->destination); -+ -+ destination = message->destination; -+ if (destination == NULL) -+ return 0; -+ -+ /* This will not just work out of the box because it this is -+ * an eavesdropping match rule. */ -+ if (matchmaker == NULL) { -+ if (strcmp(rule->destination, -+ "org.freedesktop.DBus") != 0) -+ return 0; -+ } else -+ if (!connection_is_primary_owner(matchmaker, -+ rule->destination)) -+ return 0; -+ } -+ -+ if (rule->flags & BUS_MATCH_PATH) { -+ const char *path; -+ -+ WARN_ON(!rule->path); -+ -+ path = message->path; -+ if (path == NULL) -+ return 0; -+ -+ if (strcmp(path, rule->path) != 0) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static bool get_recipients_from_list(struct bus_match_maker *matchmaker, -+ struct bus_match_maker *sender, -+ int eavesdrop, -+ struct hlist_head *rules, -+ const struct dbus_message *message) -+{ -+ struct hlist_node *cur; -+ struct bus_match_rule *rule; -+ -+ if (rules == NULL) { -+ pr_debug("no rules of this type\n"); -+ return 0; -+ } -+ -+ hlist_for_each_entry(rule, cur, rules, list) { -+ if (match_rule_matches(matchmaker, sender, eavesdrop, rule, -+ message)) { -+ pr_debug("[YES] deliver with match rule \"%s\"\n", -+ rule->rule_text); -+ return 1; -+ } else { -+ pr_debug("[NO] deliver with match rule \"%s\"\n", -+ rule->rule_text); -+ } -+ } -+ pr_debug("[NO] no match rules\n"); -+ return 0; -+} -+ -+static struct hlist_head -+*bus_matchmaker_get_rules(struct bus_match_maker *matchmaker, -+ int message_type, const char *interface) -+{ -+ static struct hlist_head empty = {0,}; -+ struct rule_pool *p; -+ -+ WARN_ON(message_type < 0); -+ WARN_ON(message_type >= DBUS_NUM_MESSAGE_TYPES); -+ -+ p = matchmaker->rules_by_type + message_type; -+ -+ if (interface == NULL) -+ return &p->rules_without_iface; -+ else { -+ struct bus_match_rule *rule = -+ match_rule_search(&p->rules_by_iface, interface); -+ if (rule) -+ return &rule->first; -+ else -+ return ∅ -+ } -+} -+ -+bool bus_matchmaker_filter(struct bus_match_maker *matchmaker, -+ struct bus_match_maker *sender, -+ int eavesdrop, -+ const struct dbus_message *message) -+{ -+ int type; -+ const char *interface; -+ struct hlist_head *neither, *just_type, *just_iface, *both; -+ -+ type = message->type; -+ interface = message->interface; -+ -+ neither = bus_matchmaker_get_rules(matchmaker, -+ DBUS_MESSAGE_TYPE_INVALID, NULL); -+ just_type = just_iface = both = NULL; -+ -+ if (interface != NULL) -+ just_iface = bus_matchmaker_get_rules(matchmaker, -+ DBUS_MESSAGE_TYPE_INVALID, -+ interface); -+ -+ if (type > DBUS_MESSAGE_TYPE_INVALID && type < DBUS_NUM_MESSAGE_TYPES) { -+ just_type = bus_matchmaker_get_rules(matchmaker, type, NULL); -+ -+ if (interface != NULL) -+ both = bus_matchmaker_get_rules(matchmaker, type, -+ interface); -+ } -+ -+ if (get_recipients_from_list(matchmaker, sender, eavesdrop, neither, -+ message)) -+ return 1; -+ if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_iface, -+ message)) -+ return 1; -+ if (get_recipients_from_list(matchmaker, sender, eavesdrop, just_type, -+ message)) -+ return 1; -+ if (get_recipients_from_list(matchmaker, sender, eavesdrop, both, -+ message)) -+ return 1; -+ -+ return connection_is_primary_owner(matchmaker, message->destination); -+} -+ -+void bus_matchmaker_add_name(struct bus_match_maker *matchmaker, -+ const char *name, -+ gfp_t gfp_flags) -+{ -+ struct dbus_name *dbus_name; -+ struct rb_node **new = &(matchmaker->names.rb_node), *parent = NULL; -+ -+ dbus_name = kmalloc(sizeof(struct dbus_name), gfp_flags); -+ if (!dbus_name) -+ return; -+ dbus_name->name = kstrdup(name, gfp_flags); -+ if (!dbus_name->name) -+ return; -+ -+ /* Figure out where to put new node */ -+ while (*new) { -+ struct dbus_name *this = container_of(*new, struct dbus_name, -+ node); -+ int result = strcmp(dbus_name->name, this->name); -+ -+ parent = *new; -+ if (result < 0) -+ new = &((*new)->rb_left); -+ else if (result > 0) -+ new = &((*new)->rb_right); -+ else -+ return; -+ } -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&dbus_name->node, parent, new); -+ rb_insert_color(&dbus_name->node, &matchmaker->names); -+} -+ -+void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker, -+ const char *name) -+{ -+ struct rb_node *node = matchmaker->names.rb_node; -+ -+ while (node) { -+ struct dbus_name *data = container_of(node, struct dbus_name, -+ node); -+ int result; -+ -+ result = strcmp(name, data->name); -+ -+ if (result < 0) -+ node = node->rb_left; -+ else if (result > 0) -+ node = node->rb_right; -+ else { -+ rb_erase(&data->node, &matchmaker->names); -+ kfree(data->name); -+ kfree(data); -+ } -+ } -+ -+} -diff --git a/net/bus/nfdbus/matchrule.h b/net/bus/nfdbus/matchrule.h -new file mode 100644 -index 0000000..e16580c ---- /dev/null -+++ b/net/bus/nfdbus/matchrule.h -@@ -0,0 +1,82 @@ -+/* -+ * signals.h Bus signal connection implementation -+ * -+ * Copyright (C) 2003 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#ifndef BUS_SIGNALS_H -+#define BUS_SIGNALS_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "message.h" -+ -+struct bus_match_rule *bus_match_rule_new(gfp_t gfp_flags); -+void bus_match_rule_free(struct bus_match_rule *rule); -+ -+struct bus_match_rule *bus_match_rule_parse(const char *rule_text, -+ gfp_t gfp_flags); -+ -+struct rule_pool { -+ /* Maps non-NULL interface names to a list of bus_match_rule */ -+ struct rb_root rules_by_iface; -+ -+ /* List of bus_match_rule which don't specify an interface */ -+ struct hlist_head rules_without_iface; -+}; -+ -+struct bus_match_maker { -+ struct sockaddr_bus addr; -+ -+ struct hlist_node table_node; -+ -+ /* Pools of rules, grouped by the type of message they match. 0 -+ * (DBUS_MESSAGE_TYPE_INVALID) represents rules that do not specify a -+ * message type. -+ */ -+ struct rule_pool rules_by_type[DBUS_NUM_MESSAGE_TYPES]; -+ -+ struct rb_root names; -+ -+ struct kref kref; -+}; -+ -+ -+struct bus_match_maker *bus_matchmaker_new(gfp_t gfp_flags); -+void bus_matchmaker_free(struct kref *kref); -+ -+int bus_matchmaker_add_rule(struct bus_match_maker *matchmaker, -+ struct bus_match_rule *rule); -+void bus_matchmaker_remove_rule_by_value(struct bus_match_maker *matchmaker, -+ struct bus_match_rule *value); -+ -+bool bus_matchmaker_filter(struct bus_match_maker *matchmaker, -+ struct bus_match_maker *sender, -+ int eavesdrop, -+ const struct dbus_message *message); -+ -+void bus_matchmaker_add_name(struct bus_match_maker *matchmaker, -+ const char *name, gfp_t gfp_flags); -+void bus_matchmaker_remove_name(struct bus_match_maker *matchmaker, -+ const char *name); -+ -+#endif /* BUS_SIGNALS_H */ --- -1.7.7.6 - diff --git a/patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch b/patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch deleted file mode 100644 index 3df3c5e7022b..000000000000 --- a/patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch +++ /dev/null @@ -1,593 +0,0 @@ -From e4839f64c6608a2199d46819e77ed03233563301 Mon Sep 17 00:00:00 2001 -From: Alban Crequy -Date: Fri, 22 Jun 2012 14:20:50 +0200 -Subject: [PATCH 15/15] netfilter: add netfilter D-Bus module - -AF_BUS has netfilter hooks on the packet sending path. This allows the -netfilter subsystem to register netfilter hook handlers. - -The netfilter_dbus module allows to inspect D-Bus messages and take -actions based on the information contained on these messages. - -Signed-off-by: Alban Crequy ---- - net/bus/Kconfig | 2 + - net/bus/Makefile | 3 + - net/bus/nfdbus/Kconfig | 12 ++ - net/bus/nfdbus/Makefile | 6 + - net/bus/nfdbus/nfdbus.c | 458 +++++++++++++++++++++++++++++++++++++++++++++++ - net/bus/nfdbus/nfdbus.h | 44 +++++ - 6 files changed, 525 insertions(+), 0 deletions(-) - create mode 100644 net/bus/nfdbus/Kconfig - create mode 100644 net/bus/nfdbus/Makefile - create mode 100644 net/bus/nfdbus/nfdbus.c - create mode 100644 net/bus/nfdbus/nfdbus.h - -diff --git a/net/bus/Kconfig b/net/bus/Kconfig -index 5f01410..4ec0beec 100644 ---- a/net/bus/Kconfig -+++ b/net/bus/Kconfig -@@ -13,3 +13,5 @@ config AF_BUS - called bus. - - Say N unless you know what you are doing. -+ -+source "net/bus/nfdbus/Kconfig" -diff --git a/net/bus/Makefile b/net/bus/Makefile -index 8c1fea2..a6ba263 100644 ---- a/net/bus/Makefile -+++ b/net/bus/Makefile -@@ -5,3 +5,6 @@ - obj-$(CONFIG_AF_BUS) += af-bus.o - - af-bus-y := af_bus.o garbage.o -+ -+# Dbus -+obj-$(CONFIG_NETFILTER_DBUS) += nfdbus/ -diff --git a/net/bus/nfdbus/Kconfig b/net/bus/nfdbus/Kconfig -new file mode 100644 -index 0000000..25699a1 ---- /dev/null -+++ b/net/bus/nfdbus/Kconfig -@@ -0,0 +1,12 @@ -+# -+# Netfilter D-Bus module configuration -+# -+config NETFILTER_DBUS -+ tristate "Netfilter D-bus (EXPERIMENTAL)" -+ depends on AF_BUS && CONNECTOR && EXPERIMENTAL -+ ---help--- -+ If you say Y here, you will include support for a netfilter hook to -+ parse D-Bus messages sent using the AF_BUS socket address family. -+ -+ To compile this as a module, choose M here: the module will be -+ called netfilter_dbus. -diff --git a/net/bus/nfdbus/Makefile b/net/bus/nfdbus/Makefile -new file mode 100644 -index 0000000..1a825f8 ---- /dev/null -+++ b/net/bus/nfdbus/Makefile -@@ -0,0 +1,6 @@ -+# -+# Makefile for the netfilter D-Bus module -+# -+obj-$(CONFIG_NETFILTER_DBUS) += netfilter_dbus.o -+ -+netfilter_dbus-y := nfdbus.o message.o matchrule.o -diff --git a/net/bus/nfdbus/nfdbus.c b/net/bus/nfdbus/nfdbus.c -new file mode 100644 -index 0000000..be8387a ---- /dev/null -+++ b/net/bus/nfdbus/nfdbus.c -@@ -0,0 +1,458 @@ -+/* -+ * nfdbus.c - Netfilter module for AF_BUS/BUS_PROTO_DBUS. -+ */ -+ -+#define DRIVER_AUTHOR "Alban Crequy" -+#define DRIVER_DESC "Netfilter module for AF_BUS/BUS_PROTO_DBUS." -+ -+#include "nfdbus.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "message.h" -+#include "matchrule.h" -+ -+static struct nf_hook_ops nfho_dbus; -+ -+static struct cb_id cn_cmd_id = { CN_IDX_NFDBUS, CN_VAL_NFDBUS }; -+ -+static unsigned int hash; -+ -+/* Scoped by AF_BUS address */ -+struct hlist_head matchrules_table[BUS_HASH_SIZE]; -+DEFINE_SPINLOCK(matchrules_lock); -+ -+static struct bus_match_maker *find_match_maker(struct sockaddr_bus *addr, -+ bool create, bool delete) -+{ -+ u64 hash; -+ struct hlist_node *node; -+ struct bus_match_maker *matchmaker; -+ int path_len = strlen(addr->sbus_path); -+ -+ hash = csum_partial(addr->sbus_path, -+ strlen(addr->sbus_path), 0); -+ hash ^= addr->sbus_addr.s_addr; -+ hash ^= hash >> 32; -+ hash ^= hash >> 16; -+ hash ^= hash >> 8; -+ hash &= 0xff; -+ -+ spin_lock(&matchrules_lock); -+ hlist_for_each_entry(matchmaker, node, &matchrules_table[hash], -+ table_node) { -+ if (addr->sbus_family == matchmaker->addr.sbus_family && -+ addr->sbus_addr.s_addr == matchmaker->addr.sbus_addr.s_addr && -+ !memcmp(addr->sbus_path, matchmaker->addr.sbus_path, -+ path_len)) { -+ kref_get(&matchmaker->kref); -+ if (delete) -+ hlist_del(&matchmaker->table_node); -+ spin_unlock(&matchrules_lock); -+ pr_debug("Found matchmaker for hash %llu", hash); -+ return matchmaker; -+ } -+ } -+ spin_unlock(&matchrules_lock); -+ -+ if (!create) { -+ pr_debug("Matchmaker for hash %llu not found", hash); -+ return NULL; -+ } -+ -+ matchmaker = bus_matchmaker_new(GFP_ATOMIC); -+ matchmaker->addr.sbus_family = addr->sbus_family; -+ matchmaker->addr.sbus_addr.s_addr = addr->sbus_addr.s_addr; -+ memcpy(matchmaker->addr.sbus_path, addr->sbus_path, BUS_PATH_MAX); -+ -+ pr_debug("Create new matchmaker for hash %llu\n", hash); -+ spin_lock(&matchrules_lock); -+ hlist_add_head(&matchmaker->table_node, &matchrules_table[hash]); -+ kref_get(&matchmaker->kref); -+ spin_unlock(&matchrules_lock); -+ return matchmaker; -+} -+ -+static unsigned int dbus_filter(unsigned int hooknum, -+ struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ int (*okfn)(struct sk_buff *)) -+{ -+ struct bus_send_context *sendctx; -+ struct bus_match_maker *matchmaker = NULL; -+ struct bus_match_maker *sender = NULL; -+ struct dbus_message msg = {0,}; -+ unsigned char *data; -+ size_t len; -+ int err; -+ int ret; -+ -+ if (!skb->sk || skb->sk->sk_family != PF_BUS) { -+ WARN(1, "netfilter_dbus received an invalid skb"); -+ return NF_DROP; -+ } -+ -+ data = skb->data; -+ sendctx = BUSCB(skb).sendctx; -+ if (!sendctx || !sendctx->sender || !sendctx->sender_socket) { -+ WARN(1, "netfilter_dbus received an AF_BUS packet" \ -+ " without context. This is a bug. Dropping the" -+ " packet."); -+ return NF_DROP; -+ } -+ -+ if (sendctx->sender_socket->sk->sk_protocol != BUS_PROTO_DBUS) { -+ /* This kernel module is for D-Bus. It must not -+ * interfere with other users of AF_BUS. */ -+ return NF_ACCEPT; -+ } -+ if (sendctx->recipient) -+ matchmaker = find_match_maker(sendctx->recipient, false, false); -+ -+ len = skb_tail_pointer(skb) - data; -+ -+ if (sendctx->to_master && sendctx->main_recipient) { -+ pr_debug("AF_BUS packet to the bus master. ACCEPT.\n"); -+ ret = NF_ACCEPT; -+ goto out; -+ } -+ -+ if (sendctx->main_recipient && !sendctx->bus_master_side) { -+ pr_debug("AF_BUS packet from a peer to a peer (unicast). ACCEPT.\n"); -+ ret = NF_ACCEPT; -+ goto out; -+ } -+ -+ err = dbus_message_parse(data, len, &msg); -+ if (err) { -+ if (!sendctx->main_recipient) { -+ pr_debug("AF_BUS packet for an eavesdropper or " \ -+ "multicast is not parsable. DROP.\n"); -+ ret = NF_DROP; -+ goto out; -+ } else if (sendctx->bus_master_side) { -+ pr_debug("AF_BUS packet from bus master is not parsable. ACCEPT.\n"); -+ ret = NF_ACCEPT; -+ goto out; -+ } else { -+ pr_debug("AF_BUS packet from peer is not parsable. DROP.\n"); -+ ret = NF_DROP; -+ goto out; -+ } -+ } -+ -+ if (sendctx->bus_master_side && !sendctx->main_recipient) { -+ pr_debug("AF_BUS packet '%s' from the bus master is for an " \ -+ "eavesdropper. DROP.\n", -+ msg.member ? msg.member : ""); -+ ret = NF_DROP; -+ goto out; -+ } -+ if (sendctx->bus_master_side) { -+ if (msg.name_acquired) { -+ pr_debug("New name: %s [%p %p].\n", -+ msg.name_acquired, sendctx->sender, -+ sendctx->recipient); -+ -+ sender = find_match_maker(sendctx->sender, true, false); -+ bus_matchmaker_add_name(sender, msg.name_acquired, -+ GFP_ATOMIC); -+ } -+ if (msg.name_lost) { -+ pr_debug("Lost name: %s [%p %p].\n", -+ msg.name_lost, sendctx->sender, -+ sendctx->recipient); -+ -+ sender = find_match_maker(sendctx->sender, true, false); -+ bus_matchmaker_remove_name(sender, msg.name_acquired); -+ } -+ -+ pr_debug("AF_BUS packet '%s' from the bus master. ACCEPT.\n", -+ msg.member ? msg.member : ""); -+ ret = NF_ACCEPT; -+ goto out; -+ } -+ -+ pr_debug("Multicast AF_BUS packet, %ld bytes, " \ -+ "considering recipient %lld...\n", len, -+ sendctx->recipient ? sendctx->recipient->sbus_addr.s_addr : 0); -+ -+ pr_debug("Message type %d %s->%s [iface: %s][member: %s][matchmaker=%p]...\n", -+ msg.type, -+ msg.sender ? msg.sender : "", -+ msg.destination ? msg.destination : "", -+ msg.interface ? msg.interface : "", -+ msg.member ? msg.member : "", -+ matchmaker); -+ -+ if (!matchmaker) { -+ pr_debug("No match rules for this recipient. DROP.\n"); -+ ret = NF_DROP; -+ goto out; -+ } -+ -+ sender = find_match_maker(sendctx->sender, true, false); -+ err = bus_matchmaker_filter(matchmaker, sender, sendctx->eavesdropper, -+ &msg); -+ if (err) { -+ pr_debug("Matchmaker: ACCEPT.\n"); -+ ret = NF_ACCEPT; -+ goto out; -+ } else { -+ pr_debug("Matchmaker: DROP.\n"); -+ ret = NF_DROP; -+ goto out; -+ } -+ -+out: -+ if (matchmaker) -+ kref_put(&matchmaker->kref, bus_matchmaker_free); -+ if (sender) -+ kref_put(&sender->kref, bus_matchmaker_free); -+ return ret; -+} -+ -+/* Taken from drbd_nl_send_reply() */ -+static void nfdbus_nl_send_reply(struct cn_msg *msg, int ret_code) -+{ -+ char buffer[sizeof(struct cn_msg)+sizeof(struct nfdbus_nl_cfg_reply)]; -+ struct cn_msg *cn_reply = (struct cn_msg *) buffer; -+ struct nfdbus_nl_cfg_reply *reply = -+ (struct nfdbus_nl_cfg_reply *)cn_reply->data; -+ int rr; -+ -+ memset(buffer, 0, sizeof(buffer)); -+ cn_reply->id = msg->id; -+ -+ cn_reply->seq = msg->seq; -+ cn_reply->ack = msg->ack + 1; -+ cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply); -+ cn_reply->flags = 0; -+ -+ reply->ret_code = ret_code; -+ -+ rr = cn_netlink_send(cn_reply, 0, GFP_NOIO); -+ if (rr && rr != -ESRCH) -+ pr_debug("nfdbus: cn_netlink_send()=%d\n", rr); -+} -+ -+/** -+ * nfdbus_check_perm - check if a pid is allowed to update match rules -+ * @sockaddr_bus: the socket address of the bus -+ * @pid: the process id that wants to update the match rules set -+ * -+ * Test if a given process id is allowed to update the match rules set -+ * for this bus. Only the process that owns the bus master listen socket -+ * is allowed to update the match rules set for the bus. -+ */ -+static bool nfdbus_check_perm(struct sockaddr_bus *sbusname, pid_t pid) -+{ -+ struct net *net = get_net_ns_by_pid(pid); -+ struct sock *s; -+ struct bus_address *addr; -+ struct hlist_node *node; -+ int offset = (sbusname->sbus_path[0] == '\0'); -+ int path_len = strnlen(sbusname->sbus_path + offset, BUS_PATH_MAX); -+ int len; -+ if (!net) -+ return false; -+ -+ len = path_len + 1 + sizeof(__kernel_sa_family_t) + -+ sizeof(struct bus_addr); -+ -+ spin_lock(&bus_address_lock); -+ -+ hlist_for_each_entry(addr, node, &bus_address_table[hash], -+ table_node) { -+ s = addr->sock; -+ -+ if (s->sk_protocol != BUS_PROTO_DBUS) -+ continue; -+ -+ if (!net_eq(sock_net(s), net)) -+ continue; -+ -+ if (addr->len == len && -+ addr->name->sbus_family == sbusname->sbus_family && -+ addr->name->sbus_addr.s_addr == BUS_MASTER_ADDR && -+ bus_same_bus(addr->name, sbusname) && -+ pid_nr(s->sk_peer_pid) == pid) { -+ spin_unlock(&bus_address_lock); -+ return true; -+ } -+ } -+ -+ spin_unlock(&bus_address_lock); -+ -+ return false; -+} -+ -+static void cn_cmd_cb(struct cn_msg *msg, struct netlink_skb_parms *nsp) -+{ -+ struct nfdbus_nl_cfg_req *nlp = (struct nfdbus_nl_cfg_req *)msg->data; -+ struct cn_msg *cn_reply; -+ struct nfdbus_nl_cfg_reply *reply; -+ int retcode, rr; -+ pid_t pid = task_tgid_vnr(current); -+ int reply_size = sizeof(struct cn_msg) -+ + sizeof(struct nfdbus_nl_cfg_reply); -+ -+ pr_debug("nfdbus: %s nsp->pid=%d pid=%d\n", __func__, nsp->pid, pid); -+ -+ if (!nfdbus_check_perm(&nlp->addr, pid)) { -+ pr_debug(KERN_ERR "nfdbus: pid=%d is not allowed!\n", pid); -+ retcode = EPERM; -+ goto fail; -+ } -+ -+ cn_reply = kzalloc(reply_size, GFP_KERNEL); -+ if (!cn_reply) { -+ retcode = ENOMEM; -+ goto fail; -+ } -+ reply = (struct nfdbus_nl_cfg_reply *) cn_reply->data; -+ -+ if (msg->len < sizeof(struct nfdbus_nl_cfg_req)) { -+ reply->ret_code = EINVAL; -+ } else if (nlp->cmd == NFDBUS_CMD_ADDMATCH) { -+ struct bus_match_rule *rule; -+ struct bus_match_maker *matchmaker; -+ reply->ret_code = 0; -+ -+ if (msg->len == 0) -+ reply->ret_code = EINVAL; -+ -+ rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC); -+ if (rule) { -+ matchmaker = find_match_maker(&nlp->addr, true, false); -+ pr_debug("Add match rule for matchmaker %p\n", -+ matchmaker); -+ bus_matchmaker_add_rule(matchmaker, rule); -+ kref_put(&matchmaker->kref, bus_matchmaker_free); -+ } else { -+ reply->ret_code = EINVAL; -+ } -+ } else if (nlp->cmd == NFDBUS_CMD_REMOVEMATCH) { -+ struct bus_match_rule *rule; -+ struct bus_match_maker *matchmaker; -+ -+ rule = bus_match_rule_parse(nlp->data, GFP_ATOMIC); -+ if (rule) { -+ matchmaker = find_match_maker(&nlp->addr, false, false); -+ if (!matchmaker) { -+ reply->ret_code = EINVAL; -+ } else { -+ pr_debug("Remove match rule for matchmaker %p\n", -+ matchmaker); -+ bus_matchmaker_remove_rule_by_value(matchmaker, rule); -+ kref_put(&matchmaker->kref, bus_matchmaker_free); -+ reply->ret_code = 0; -+ } -+ bus_match_rule_free(rule); -+ } -+ -+ } else if (nlp->cmd == NFDBUS_CMD_REMOVEALLMATCH) { -+ struct bus_match_maker *matchmaker; -+ -+ matchmaker = find_match_maker(&nlp->addr, false, true); -+ if (!matchmaker) { -+ reply->ret_code = EINVAL; -+ } else { -+ pr_debug("Remove matchmaker %p\n", matchmaker); -+ kref_put(&matchmaker->kref, bus_matchmaker_free); -+ kref_put(&matchmaker->kref, bus_matchmaker_free); -+ reply->ret_code = 0; -+ } -+ -+ } else { -+ reply->ret_code = EINVAL; -+ } -+ -+ cn_reply->id = msg->id; -+ cn_reply->seq = msg->seq; -+ cn_reply->ack = msg->ack + 1; -+ cn_reply->len = sizeof(struct nfdbus_nl_cfg_reply); -+ cn_reply->flags = 0; -+ -+ rr = cn_netlink_reply(cn_reply, nsp->pid, GFP_KERNEL); -+ if (rr && rr != -ESRCH) -+ pr_debug("nfdbus: cn_netlink_send()=%d\n", rr); -+ pr_debug("nfdbus: cn_netlink_reply(pid=%d)=%d\n", nsp->pid, rr); -+ -+ kfree(cn_reply); -+ return; -+fail: -+ nfdbus_nl_send_reply(msg, retcode); -+} -+ -+static int __init nfdbus_init(void) -+{ -+ int err; -+ struct bus_addr master_addr; -+ -+ master_addr.s_addr = BUS_MASTER_ADDR; -+ hash = bus_compute_hash(master_addr); -+ -+ pr_debug("Loading netfilter_dbus\n"); -+ -+ /* Install D-Bus netfilter hook */ -+ nfho_dbus.hook = dbus_filter; -+ nfho_dbus.hooknum = NF_BUS_SENDING; -+ nfho_dbus.pf = NFPROTO_BUS; /* Do not use PF_BUS, you fool! */ -+ nfho_dbus.priority = 0; -+ nfho_dbus.owner = THIS_MODULE; -+ err = nf_register_hook(&nfho_dbus); -+ if (err) -+ return err; -+ pr_debug("Netfilter hook for D-Bus: installed.\n"); -+ -+ /* Install connector hook */ -+ err = cn_add_callback(&cn_cmd_id, "nfdbus", cn_cmd_cb); -+ if (err) -+ goto err_cn_cmd_out; -+ pr_debug("Connector hook: installed.\n"); -+ -+ return 0; -+ -+err_cn_cmd_out: -+ nf_unregister_hook(&nfho_dbus); -+ -+ return err; -+} -+ -+static void __exit nfdbus_cleanup(void) -+{ -+ int i; -+ struct hlist_node *node, *tmp; -+ struct bus_match_maker *matchmaker; -+ nf_unregister_hook(&nfho_dbus); -+ -+ cn_del_callback(&cn_cmd_id); -+ -+ spin_lock(&matchrules_lock); -+ for (i = 0; i < BUS_HASH_SIZE; i++) { -+ hlist_for_each_entry_safe(matchmaker, node, tmp, -+ &matchrules_table[i], table_node) { -+ hlist_del(&matchmaker->table_node); -+ kref_put(&matchmaker->kref, bus_matchmaker_free); -+ } -+ } -+ spin_unlock(&matchrules_lock); -+ -+ pr_debug("Unloading netfilter_dbus\n"); -+} -+ -+module_init(nfdbus_init); -+module_exit(nfdbus_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_ALIAS_NET_PF_PROTO(PF_BUS, BUS_PROTO_DBUS); -diff --git a/net/bus/nfdbus/nfdbus.h b/net/bus/nfdbus/nfdbus.h -new file mode 100644 -index 0000000..477bde3 ---- /dev/null -+++ b/net/bus/nfdbus/nfdbus.h -@@ -0,0 +1,44 @@ -+/* -+ * nfdbus.h Netfilter module for AF_BUS/BUS_PROTO_DBUS. -+ * -+ * Copyright (C) 2012 Collabora Ltd -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#ifndef NETFILTER_DBUS_H -+#define NETFILTER_DBUS_H -+ -+#include -+#include -+ -+#define NFDBUS_CMD_ADDMATCH 0x01 -+#define NFDBUS_CMD_REMOVEMATCH 0x02 -+#define NFDBUS_CMD_REMOVEALLMATCH 0x03 -+ -+struct nfdbus_nl_cfg_req { -+ __u32 cmd; -+ __u32 len; -+ struct sockaddr_bus addr; -+ __u64 pad; -+ unsigned char data[0]; -+}; -+ -+struct nfdbus_nl_cfg_reply { -+ __u32 ret_code; -+}; -+ -+#endif /* NETFILTER_DBUS_H */ --- -1.7.7.6 - diff --git a/patches.af_bus/af_bus-make-netfilter_dbus-depend-on-netfilter.patch b/patches.af_bus/af_bus-make-netfilter_dbus-depend-on-netfilter.patch deleted file mode 100644 index c10f3db4f6d5..000000000000 --- a/patches.af_bus/af_bus-make-netfilter_dbus-depend-on-netfilter.patch +++ /dev/null @@ -1,67 +0,0 @@ -From javier.martinez@collabora.co.uk Thu Jan 24 00:08:10 2013 -From: Javier Martinez Canillas -Date: Thu, 24 Jan 2013 09:07:53 +0100 -Subject: af_bus: make NETFILTER_DBUS depend on NETFILTER -To: Greg KH -Cc: ltsi-dev@lists.linuxfoundation.org, Stephen Lawrence , Jeremiah Foster , Javier Martinez Canillas -Message-ID: <1359014873-29358-1-git-send-email-javier.martinez@collabora.co.uk> - - -some users report to had a build error when NETFILTER config -option is not set: - -net/bus/af_bus.c: In function 'bus_sendmsg': -net/bus/af_bus.c:1511:7: warning: 'rcp_cnt' may be used uninitialized in -this function - CC net/bus/garbage.o - LD net/bus/af-bus.o - CC net/bus/nfdbus/nfdbus.o -net/bus/nfdbus/nfdbus.c: In function 'nfdbus_init': -net/bus/nfdbus/nfdbus.c:406:2: error: invalid use of undefined type -'struct nf_hook_ops' -net/bus/nfdbus/nfdbus.c:407:2: error: invalid use of undefined type -'struct nf_hook_ops' -net/bus/nfdbus/nfdbus.c:408:2: error: invalid use of undefined type -'struct nf_hook_ops' -net/bus/nfdbus/nfdbus.c:409:2: error: invalid use of undefined type -'struct nf_hook_ops' -net/bus/nfdbus/nfdbus.c:410:2: error: invalid use of undefined type -'struct nf_hook_ops' -net/bus/nfdbus/nfdbus.c:411:2: error: implicit declaration of function -'nf_register_hook' -net/bus/nfdbus/nfdbus.c:425:2: error: implicit declaration of function -'nf_unregister_hook' -make[3]: *** [net/bus/nfdbus/nfdbus.o] Error 1 -make[2]: *** [net/bus/nfdbus] Error 2 -make[1]: *** [net/bus] Error 2 -make: *** [net] Error 2 - -this is because NETFILTER_DBUS uses symbols only defined when NETFITER=y - -Signed-off-by: Javier Martinez Canillas ---- - -Hello Greg, - -I've seen that people send you incremental patches and you store them -on "patches.fixes" directory. That's why I'm sending a delta patch. - -Please let me know if you prefer to have the original corresponding -patch with this fix squashed. - -Thanks a lot. - - net/bus/nfdbus/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/net/bus/nfdbus/Kconfig -+++ b/net/bus/nfdbus/Kconfig -@@ -3,7 +3,7 @@ - # - config NETFILTER_DBUS - tristate "Netfilter D-bus (EXPERIMENTAL)" -- depends on AF_BUS && CONNECTOR && EXPERIMENTAL -+ depends on AF_BUS && NETFILTER && 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. diff --git a/patches.armadillo800/0001-ARM-shmobile-add-common-DMAEngine-definitions.patch b/patches.armadillo800/0001-ARM-shmobile-add-common-DMAEngine-definitions.patch deleted file mode 100644 index 5316285a382f..000000000000 --- a/patches.armadillo800/0001-ARM-shmobile-add-common-DMAEngine-definitions.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 4d3626f914a2b4023a3edf428640e578527ac0c8 Mon Sep 17 00:00:00 2001 -From: Kuninori Morimoto -Date: Mon, 25 Jun 2012 03:43:00 -0700 -Subject: ARM: shmobile: add common DMAEngine definitions - -Current shmobile have DMAEngine specific settings on each CPU code, -but SH-ARM DMAC use same value. - -This patch adds new dma-register.h header to share definitions -and reduce a waste of code on SH-ARM architecture. - -Signed-off-by: Kuninori Morimoto -Acked-by: Magnus Damm -Signed-off-by: Rafael J. Wysocki -(cherry picked from commit 5ca1d44f6a99b29ab164a06f4ec71950d6939fb5) - -Signed-off-by: Simon Horman ---- - arch/arm/mach-shmobile/include/mach/dma-register.h | 84 ++++++++++++++++++++++ - 1 file changed, 84 insertions(+) - create mode 100644 arch/arm/mach-shmobile/include/mach/dma-register.h - -diff --git a/arch/arm/mach-shmobile/include/mach/dma-register.h b/arch/arm/mach-shmobile/include/mach/dma-register.h -new file mode 100644 -index 0000000..97c40bd ---- /dev/null -+++ b/arch/arm/mach-shmobile/include/mach/dma-register.h -@@ -0,0 +1,84 @@ -+/* -+ * SH-ARM CPU-specific DMA definitions, used by both DMA drivers -+ * -+ * Copyright (C) 2012 Renesas Solutions Corp -+ * -+ * Kuninori Morimoto -+ * -+ * Based on arch/sh/include/cpu-sh4/cpu/dma-register.h -+ * Copyright (C) 2010 Guennadi Liakhovetski -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef DMA_REGISTER_H -+#define DMA_REGISTER_H -+ -+/* -+ * Direct Memory Access Controller -+ */ -+ -+/* Transmit sizes and respective CHCR register values */ -+enum { -+ XMIT_SZ_8BIT = 0, -+ XMIT_SZ_16BIT = 1, -+ XMIT_SZ_32BIT = 2, -+ XMIT_SZ_64BIT = 7, -+ XMIT_SZ_128BIT = 3, -+ XMIT_SZ_256BIT = 4, -+ XMIT_SZ_512BIT = 5, -+}; -+ -+/* log2(size / 8) - used to calculate number of transfers */ -+static const unsigned int dma_ts_shift[] = { -+ [XMIT_SZ_8BIT] = 0, -+ [XMIT_SZ_16BIT] = 1, -+ [XMIT_SZ_32BIT] = 2, -+ [XMIT_SZ_64BIT] = 3, -+ [XMIT_SZ_128BIT] = 4, -+ [XMIT_SZ_256BIT] = 5, -+ [XMIT_SZ_512BIT] = 6, -+}; -+ -+#define TS_LOW_BIT 0x3 /* --xx */ -+#define TS_HI_BIT 0xc /* xx-- */ -+ -+#define TS_LOW_SHIFT (3) -+#define TS_HI_SHIFT (20 - 2) /* 2 bits for shifted low TS */ -+ -+#define TS_INDEX2VAL(i) \ -+ ((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\ -+ (((i) & TS_HI_BIT) << TS_HI_SHIFT)) -+ -+#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz))) -+#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz))) -+ -+ -+/* -+ * USB High-Speed DMAC -+ */ -+/* Transmit sizes and respective CHCR register values */ -+enum { -+ USBTS_XMIT_SZ_8BYTE = 0, -+ USBTS_XMIT_SZ_16BYTE = 1, -+ USBTS_XMIT_SZ_32BYTE = 2, -+}; -+ -+/* log2(size / 8) - used to calculate number of transfers */ -+static const unsigned int dma_usbts_shift[] = { -+ [USBTS_XMIT_SZ_8BYTE] = 3, -+ [USBTS_XMIT_SZ_16BYTE] = 4, -+ [USBTS_XMIT_SZ_32BYTE] = 5, -+}; -+ -+#define USBTS_LOW_BIT 0x3 /* --xx */ -+#define USBTS_HI_BIT 0x0 /* ---- */ -+ -+#define USBTS_LOW_SHIFT 6 -+#define USBTS_HI_SHIFT 0 -+ -+#define USBTS_INDEX2VAL(i) (((i) & 3) << 6) -+ -+#endif /* DMA_REGISTER_H */ --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0002-ARM-shmobile-soc-core-add-R-mobile-PM-domain-common-.patch b/patches.armadillo800/0002-ARM-shmobile-soc-core-add-R-mobile-PM-domain-common-.patch deleted file mode 100644 index 2acaf3de704c..000000000000 --- a/patches.armadillo800/0002-ARM-shmobile-soc-core-add-R-mobile-PM-domain-common-.patch +++ /dev/null @@ -1,260 +0,0 @@ -From c13b4e8e39cad46f37b794ba12b8a97569767e25 Mon Sep 17 00:00:00 2001 -From: Kuninori Morimoto -Date: Thu, 5 Jul 2012 01:24:46 -0700 -Subject: ARM: shmobile: soc-core: add R-mobile PM domain common APIs - -This patch adds Renesas R-mobile series common PM domain APIs. -R-mobile CPU can use/switch this API - -Signed-off-by: Kuninori Morimoto -Acked-by: Magnus Damm -Signed-off-by: Rafael J. Wysocki -(cherry picked from commit 8f45b112fc66ef6869ccca4c3966976982f496a9) - -Signed-off-by: Simon Horman ---- - arch/arm/mach-shmobile/Makefile | 1 + - arch/arm/mach-shmobile/include/mach/pm-rmobile.h | 44 ++++++ - arch/arm/mach-shmobile/pm-rmobile.c | 167 +++++++++++++++++++++++ - 3 files changed, 212 insertions(+) - create mode 100644 arch/arm/mach-shmobile/include/mach/pm-rmobile.h - create mode 100644 arch/arm/mach-shmobile/pm-rmobile.c - -diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile -index e7c2590..53846a1e 100644 ---- a/arch/arm/mach-shmobile/Makefile -+++ b/arch/arm/mach-shmobile/Makefile -@@ -37,6 +37,7 @@ obj-$(CONFIG_ARCH_R8A7740) += entry-intc.o - # PM objects - obj-$(CONFIG_SUSPEND) += suspend.o - obj-$(CONFIG_CPU_IDLE) += cpuidle.o -+obj-$(CONFIG_ARCH_SHMOBILE) += pm-rmobile.o - obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o - obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o - -diff --git a/arch/arm/mach-shmobile/include/mach/pm-rmobile.h b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h -new file mode 100644 -index 0000000..5a40284 ---- /dev/null -+++ b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h -@@ -0,0 +1,44 @@ -+/* -+ * Copyright (C) 2012 Renesas Solutions Corp. -+ * -+ * Kuninori Morimoto -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+#ifndef PM_RMOBILE_H -+#define PM_RMOBILE_H -+ -+#include -+ -+struct platform_device; -+ -+struct rmobile_pm_domain { -+ struct generic_pm_domain genpd; -+ struct dev_power_governor *gov; -+ int (*suspend)(void); -+ void (*resume)(void); -+ unsigned int bit_shift; -+ bool no_debug; -+}; -+ -+static inline -+struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d) -+{ -+ return container_of(d, struct rmobile_pm_domain, genpd); -+} -+ -+#ifdef CONFIG_PM -+extern void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd); -+extern void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd, -+ struct platform_device *pdev); -+extern void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd, -+ struct rmobile_pm_domain *rmobile_sd); -+#else -+#define rmobile_init_pm_domain(pd) do { } while (0) -+#define rmobile_add_device_to_domain(pd, pdev) do { } while (0) -+#define rmobile_pm_add_subdomain(pd, sd) do { } while (0) -+#endif /* CONFIG_PM */ -+ -+#endif /* PM_RMOBILE_H */ -diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c -new file mode 100644 -index 0000000..a856254 ---- /dev/null -+++ b/arch/arm/mach-shmobile/pm-rmobile.c -@@ -0,0 +1,167 @@ -+/* -+ * rmobile power management support -+ * -+ * Copyright (C) 2012 Renesas Solutions Corp. -+ * Copyright (C) 2012 Kuninori Morimoto -+ * -+ * based on pm-sh7372.c -+ * Copyright (C) 2011 Magnus Damm -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* SYSC */ -+#define SPDCR 0xe6180008 -+#define SWUCR 0xe6180014 -+#define PSTR 0xe6180080 -+ -+#define PSTR_RETRIES 100 -+#define PSTR_DELAY_US 10 -+ -+#ifdef CONFIG_PM -+static int rmobile_pd_power_down(struct generic_pm_domain *genpd) -+{ -+ struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd); -+ unsigned int mask = 1 << rmobile_pd->bit_shift; -+ -+ if (rmobile_pd->suspend) { -+ int ret = rmobile_pd->suspend(); -+ -+ if (ret) -+ return ret; -+ } -+ -+ if (__raw_readl(PSTR) & mask) { -+ unsigned int retry_count; -+ __raw_writel(mask, SPDCR); -+ -+ for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { -+ if (!(__raw_readl(SPDCR) & mask)) -+ break; -+ cpu_relax(); -+ } -+ } -+ -+ if (!rmobile_pd->no_debug) -+ pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", -+ genpd->name, mask, __raw_readl(PSTR)); -+ -+ return 0; -+} -+ -+static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd, -+ bool do_resume) -+{ -+ unsigned int mask = 1 << rmobile_pd->bit_shift; -+ unsigned int retry_count; -+ int ret = 0; -+ -+ if (__raw_readl(PSTR) & mask) -+ goto out; -+ -+ __raw_writel(mask, SWUCR); -+ -+ for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { -+ if (!(__raw_readl(SWUCR) & mask)) -+ break; -+ if (retry_count > PSTR_RETRIES) -+ udelay(PSTR_DELAY_US); -+ else -+ cpu_relax(); -+ } -+ if (!retry_count) -+ ret = -EIO; -+ -+ if (!rmobile_pd->no_debug) -+ pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", -+ rmobile_pd->genpd.name, mask, __raw_readl(PSTR)); -+ -+out: -+ if (ret == 0 && rmobile_pd->resume && do_resume) -+ rmobile_pd->resume(); -+ -+ return ret; -+} -+ -+static int rmobile_pd_power_up(struct generic_pm_domain *genpd) -+{ -+ return __rmobile_pd_power_up(to_rmobile_pd(genpd), true); -+} -+ -+static bool rmobile_pd_active_wakeup(struct device *dev) -+{ -+ bool (*active_wakeup)(struct device *dev); -+ -+ active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; -+ return active_wakeup ? active_wakeup(dev) : true; -+} -+ -+static int rmobile_pd_stop_dev(struct device *dev) -+{ -+ int (*stop)(struct device *dev); -+ -+ stop = dev_gpd_data(dev)->ops.stop; -+ if (stop) { -+ int ret = stop(dev); -+ if (ret) -+ return ret; -+ } -+ return pm_clk_suspend(dev); -+} -+ -+static int rmobile_pd_start_dev(struct device *dev) -+{ -+ int (*start)(struct device *dev); -+ int ret; -+ -+ ret = pm_clk_resume(dev); -+ if (ret) -+ return ret; -+ -+ start = dev_gpd_data(dev)->ops.start; -+ if (start) -+ ret = start(dev); -+ -+ return ret; -+} -+ -+void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) -+{ -+ struct generic_pm_domain *genpd = &rmobile_pd->genpd; -+ struct dev_power_governor *gov = rmobile_pd->gov; -+ -+ pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); -+ genpd->dev_ops.stop = rmobile_pd_stop_dev; -+ genpd->dev_ops.start = rmobile_pd_start_dev; -+ genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup; -+ genpd->dev_irq_safe = true; -+ genpd->power_off = rmobile_pd_power_down; -+ genpd->power_on = rmobile_pd_power_up; -+ __rmobile_pd_power_up(rmobile_pd, false); -+} -+ -+void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd, -+ struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ -+ pm_genpd_add_device(&rmobile_pd->genpd, dev); -+ if (pm_clk_no_clocks(dev)) -+ pm_clk_add(dev, NULL); -+} -+ -+void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd, -+ struct rmobile_pm_domain *rmobile_sd) -+{ -+ pm_genpd_add_subdomain(&rmobile_pd->genpd, &rmobile_sd->genpd); -+} -+#endif /* CONFIG_PM */ --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0003-media-V4L2-sh_mobile_ceu-manage-lower-8bit-bus.patch b/patches.armadillo800/0003-media-V4L2-sh_mobile_ceu-manage-lower-8bit-bus.patch deleted file mode 100644 index e133ecf33aa8..000000000000 --- a/patches.armadillo800/0003-media-V4L2-sh_mobile_ceu-manage-lower-8bit-bus.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 657ed37c21c4b58b2ce736343d1c653a842f7299 Mon Sep 17 00:00:00 2001 -From: Kuninori Morimoto -Date: Tue, 8 May 2012 00:00:07 -0300 -Subject: [media] V4L2: sh_mobile_ceu: manage lower 8bit bus - -CAMCR::DTIF feild controls camera bus as upper8bit/16bit/lower8bit. -This patch manages unmanaged lower 8bit bus - -Signed-off-by: Kuninori Morimoto -Signed-off-by: Guennadi Liakhovetski -Signed-off-by: Mauro Carvalho Chehab -(cherry picked from commit 2564f67bc8d56e5c7fc2970f80f41f2d38db3e21) - -Signed-off-by: Simon Horman ---- - drivers/media/video/sh_mobile_ceu_camera.c | 8 +++++--- - include/media/sh_mobile_ceu.h | 1 + - 2 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c -index 424dfac..4e0b654 100644 ---- a/drivers/media/video/sh_mobile_ceu_camera.c -+++ b/drivers/media/video/sh_mobile_ceu_camera.c -@@ -881,11 +881,13 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) - - value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; - value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; -- value |= pcdev->is_16bit ? 1 << 12 : 0; - -- /* CSI2 mode */ -- if (pcdev->pdata->csi2) -+ if (pcdev->pdata->csi2) /* CSI2 mode */ - value |= 3 << 12; -+ else if (pcdev->is_16bit) -+ value |= 1 << 12; -+ else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT) -+ value |= 2 << 12; - - ceu_write(pcdev, CAMCR, value); - -diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h -index a90a765..6fdb6ad 100644 ---- a/include/media/sh_mobile_ceu.h -+++ b/include/media/sh_mobile_ceu.h -@@ -5,6 +5,7 @@ - #define SH_CEU_FLAG_USE_16BIT_BUS (1 << 1) /* use 16bit bus width */ - #define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */ - #define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */ -+#define SH_CEU_FLAG_LOWER_8BIT (1 << 4) /* default upper 8bit */ - - struct device; - struct resource; --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0004-regulator-support-multiple-dummy-fixed-regulators.patch b/patches.armadillo800/0004-regulator-support-multiple-dummy-fixed-regulators.patch deleted file mode 100644 index fb5e5111c483..000000000000 --- a/patches.armadillo800/0004-regulator-support-multiple-dummy-fixed-regulators.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 5d792a5a2daa8e2d397c0b5f45ac76c9e0d175ff Mon Sep 17 00:00:00 2001 -From: Guennadi Liakhovetski -Date: Tue, 19 Jun 2012 17:43:56 +0200 -Subject: regulator: support multiple dummy fixed regulators - -Currently regulator_register_fixed() uses a constant name to register a -fixed dummy regulator. This is sufficient in principle, since there is no -reason to register multiple such regulators. The user can simply supply all -consumers in one array and use it to initialise such a regulator. However, -in some cases it can be convenient to register multiple such regulators. -This is also a prerequisite for the upcoming patch, that will add a voltage -parameter to this function. The original function is provided as a wrapper -macro. - -Signed-off-by: Guennadi Liakhovetski -Signed-off-by: Mark Brown -(cherry picked from commit dfad84aeab5f71b33a12e6803a809f698bdef5a2) - -Signed-off-by: Simon Horman ---- - drivers/regulator/fixed-helper.c | 14 +++++++++++--- - include/linux/regulator/fixed.h | 7 +++++-- - 2 files changed, 16 insertions(+), 5 deletions(-) - -diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c -index cacd33c..3aa268d 100644 ---- a/drivers/regulator/fixed-helper.c -+++ b/drivers/regulator/fixed-helper.c -@@ -1,4 +1,5 @@ - #include -+#include - #include - #include - #include -@@ -13,16 +14,18 @@ static void regulator_fixed_release(struct device *dev) - { - struct fixed_regulator_data *data = container_of(dev, - struct fixed_regulator_data, pdev.dev); -+ kfree(data->cfg.supply_name); - kfree(data); - } - - /** -- * regulator_register_fixed - register a no-op fixed regulator -+ * regulator_register_fixed_name - register a no-op fixed regulator - * @id: platform device id -+ * @name: name to be used for the regulator - * @supplies: consumers for this regulator - * @num_supplies: number of consumers - */ --struct platform_device *regulator_register_fixed(int id, -+struct platform_device *regulator_register_always_on(int id, const char *name, - struct regulator_consumer_supply *supplies, int num_supplies) - { - struct fixed_regulator_data *data; -@@ -31,7 +34,12 @@ struct platform_device *regulator_register_fixed(int id, - if (!data) - return NULL; - -- data->cfg.supply_name = "fixed-dummy"; -+ data->cfg.supply_name = kstrdup(name, GFP_KERNEL); -+ if (!data->cfg.supply_name) { -+ kfree(data); -+ return NULL; -+ } -+ - data->cfg.microvolts = 0; - data->cfg.gpio = -EINVAL; - data->cfg.enabled_at_boot = 1; -diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h -index 936a7d8..7bb456c 100644 ---- a/include/linux/regulator/fixed.h -+++ b/include/linux/regulator/fixed.h -@@ -51,14 +51,17 @@ struct fixed_voltage_config { - struct regulator_consumer_supply; - - #if IS_ENABLED(CONFIG_REGULATOR) --struct platform_device *regulator_register_fixed(int id, -+struct platform_device *regulator_register_always_on(int id, const char *name, - struct regulator_consumer_supply *supplies, int num_supplies); - #else --static inline struct platform_device *regulator_register_fixed(int id, -+static inline struct platform_device *regulator_register_always_on(int id, const char *name, - struct regulator_consumer_supply *supplies, int num_supplies) - { - return NULL; - } - #endif - -+#define regulator_register_fixed(id, s, ns) regulator_register_always_on(id, \ -+ "fixed-dummy", s, ns) -+ - #endif --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0005-regulator-extend-the-fixed-dummy-voltage-regulator-t.patch b/patches.armadillo800/0005-regulator-extend-the-fixed-dummy-voltage-regulator-t.patch deleted file mode 100644 index dccde558658f..000000000000 --- a/patches.armadillo800/0005-regulator-extend-the-fixed-dummy-voltage-regulator-t.patch +++ /dev/null @@ -1,70 +0,0 @@ -From c5249f06fd57ea88ef47b750dc11a6f683bd5e5d Mon Sep 17 00:00:00 2001 -From: Guennadi Liakhovetski -Date: Tue, 19 Jun 2012 17:44:39 +0200 -Subject: regulator: extend the fixed dummy voltage regulator to accept voltage - -Trivially extend the regulator_register_always_on() helper function to be -even more useful by adding a voltage parameter to it. - -Signed-off-by: Guennadi Liakhovetski -Signed-off-by: Mark Brown -(cherry picked from commit 15719ccc274981b19ad8fe9ac20c94249de8a257) - -Signed-off-by: Simon Horman ---- - drivers/regulator/fixed-helper.c | 5 +++-- - include/linux/regulator/fixed.h | 6 +++--- - 2 files changed, 6 insertions(+), 5 deletions(-) - -diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c -index 3aa268d..f9d0279 100644 ---- a/drivers/regulator/fixed-helper.c -+++ b/drivers/regulator/fixed-helper.c -@@ -24,9 +24,10 @@ static void regulator_fixed_release(struct device *dev) - * @name: name to be used for the regulator - * @supplies: consumers for this regulator - * @num_supplies: number of consumers -+ * @uv: voltage in microvolts - */ - struct platform_device *regulator_register_always_on(int id, const char *name, -- struct regulator_consumer_supply *supplies, int num_supplies) -+ struct regulator_consumer_supply *supplies, int num_supplies, int uv) - { - struct fixed_regulator_data *data; - -@@ -40,7 +41,7 @@ struct platform_device *regulator_register_always_on(int id, const char *name, - return NULL; - } - -- data->cfg.microvolts = 0; -+ data->cfg.microvolts = uv; - data->cfg.gpio = -EINVAL; - data->cfg.enabled_at_boot = 1; - data->cfg.init_data = &data->init_data; -diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h -index 7bb456c..f6372ee 100644 ---- a/include/linux/regulator/fixed.h -+++ b/include/linux/regulator/fixed.h -@@ -52,16 +52,16 @@ struct regulator_consumer_supply; - - #if IS_ENABLED(CONFIG_REGULATOR) - struct platform_device *regulator_register_always_on(int id, const char *name, -- struct regulator_consumer_supply *supplies, int num_supplies); -+ struct regulator_consumer_supply *supplies, int num_supplies, int uv); - #else - static inline struct platform_device *regulator_register_always_on(int id, const char *name, -- struct regulator_consumer_supply *supplies, int num_supplies) -+ struct regulator_consumer_supply *supplies, int num_supplies, int uv) - { - return NULL; - } - #endif - - #define regulator_register_fixed(id, s, ns) regulator_register_always_on(id, \ -- "fixed-dummy", s, ns) -+ "fixed-dummy", s, ns, 0) - - #endif --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0006-Input-gpio_keys-remove-useless-reinitialization-of-p.patch b/patches.armadillo800/0006-Input-gpio_keys-remove-useless-reinitialization-of-p.patch deleted file mode 100644 index 0f2761ddaffb..000000000000 --- a/patches.armadillo800/0006-Input-gpio_keys-remove-useless-reinitialization-of-p.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5f0a6815e3a7c5e73486b7b0a7ffffcf78b81cee Mon Sep 17 00:00:00 2001 -From: Tobias Klauser -Date: Mon, 11 Jun 2012 23:55:32 -0700 -Subject: Input: gpio_keys - remove useless reinitialization of pdata->nbuttons - -pdata is zeroed using memset just a few lines before, so there is no -need to set the nbuttons member to 0 again. - -Signed-off-by: Tobias Klauser -Signed-off-by: Dmitry Torokhov -(cherry picked from commit 4eceb14f669cb9e9d189019e8fcbf73577fe77a7) - -Signed-off-by: Simon Horman ---- - drivers/input/keyboard/gpio_keys.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c -index 62bfce4..cbb1add 100644 ---- a/drivers/input/keyboard/gpio_keys.c -+++ b/drivers/input/keyboard/gpio_keys.c -@@ -559,7 +559,6 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, - pdata->rep = !!of_get_property(node, "autorepeat", NULL); - - /* First count the subnodes */ -- pdata->nbuttons = 0; - pp = NULL; - while ((pp = of_get_next_child(node, pp))) - pdata->nbuttons++; --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0007-Input-st1232-add-device-tree-support.patch b/patches.armadillo800/0007-Input-st1232-add-device-tree-support.patch deleted file mode 100644 index d0a9ee2bf961..000000000000 --- a/patches.armadillo800/0007-Input-st1232-add-device-tree-support.patch +++ /dev/null @@ -1,49 +0,0 @@ -From ccbea8cbb6f976a4ed42dfba5648bfb543f520d1 Mon Sep 17 00:00:00 2001 -From: Magnus Damm -Date: Tue, 3 Apr 2012 11:30:28 -0700 -Subject: Input: st1232 - add device tree support - -This patch enables DT support for the st1232 driver -which is primarily used on the sh7372 Mackerel board. - -[dtor@mail.ru: chnaged to use CONFIG_OF and of_match_ptr] -Signed-off-by: Magnus Damm -Acked-by: Arnd Bergmann -Signed-off-by: Dmitry Torokhov -(cherry picked from commit e6293d2f8a6cd427a1ef4ddecb16b1d5ae1929cd) - -Signed-off-by: Simon Horman ---- - drivers/input/touchscreen/st1232.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c -index cbbf71b..216fabb 100644 ---- a/drivers/input/touchscreen/st1232.c -+++ b/drivers/input/touchscreen/st1232.c -@@ -255,6 +255,14 @@ static const struct i2c_device_id st1232_ts_id[] = { - }; - MODULE_DEVICE_TABLE(i2c, st1232_ts_id); - -+#ifdef CONFIG_OF -+static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = { -+ { .compatible = "sitronix,st1232", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); -+#endif -+ - static struct i2c_driver st1232_ts_driver = { - .probe = st1232_ts_probe, - .remove = __devexit_p(st1232_ts_remove), -@@ -262,6 +270,7 @@ static struct i2c_driver st1232_ts_driver = { - .driver = { - .name = ST1232_TS_NAME, - .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(st1232_ts_dt_ids), - #ifdef CONFIG_PM - .pm = &st1232_ts_pm_ops, - #endif --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0008-Input-st1232-switch-to-using-SIMPLE_DEV_PM_OPS.patch b/patches.armadillo800/0008-Input-st1232-switch-to-using-SIMPLE_DEV_PM_OPS.patch deleted file mode 100644 index 95252d1ed1bb..000000000000 --- a/patches.armadillo800/0008-Input-st1232-switch-to-using-SIMPLE_DEV_PM_OPS.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 456b9180124a8edec6c90cbd4d2b3f7c8a09a6f7 Mon Sep 17 00:00:00 2001 -From: Dmitry Torokhov -Date: Tue, 3 Apr 2012 11:30:28 -0700 -Subject: Input: st1232 - switch to using SIMPLE_DEV_PM_OPS - -Acked-by: Rafael J. Wysocki -Reviewed-by: Simon Horman -Signed-off-by: Dmitry Torokhov -(cherry picked from commit b3571400395e318306165eabbfbe05a4c3e4366c) - -Signed-off-by: Simon Horman ---- - drivers/input/touchscreen/st1232.c | 11 ++++------- - 1 file changed, 4 insertions(+), 7 deletions(-) - -diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c -index 216fabb..6cb68a1 100644 ---- a/drivers/input/touchscreen/st1232.c -+++ b/drivers/input/touchscreen/st1232.c -@@ -218,7 +218,7 @@ static int __devexit st1232_ts_remove(struct i2c_client *client) - return 0; - } - --#ifdef CONFIG_PM -+#ifdef CONFIG_PM_SLEEP - static int st1232_ts_suspend(struct device *dev) - { - struct i2c_client *client = to_i2c_client(dev); -@@ -243,12 +243,11 @@ static int st1232_ts_resume(struct device *dev) - return 0; - } - --static const struct dev_pm_ops st1232_ts_pm_ops = { -- .suspend = st1232_ts_suspend, -- .resume = st1232_ts_resume, --}; - #endif - -+static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, -+ st1232_ts_suspend, st1232_ts_resume); -+ - static const struct i2c_device_id st1232_ts_id[] = { - { ST1232_TS_NAME, 0 }, - { } -@@ -271,9 +270,7 @@ static struct i2c_driver st1232_ts_driver = { - .name = ST1232_TS_NAME, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(st1232_ts_dt_ids), --#ifdef CONFIG_PM - .pm = &st1232_ts_pm_ops, --#endif - }, - }; - --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0009-net-sh_eth-add-support-R8A7740.patch b/patches.armadillo800/0009-net-sh_eth-add-support-R8A7740.patch deleted file mode 100644 index 24501ce745b1..000000000000 --- a/patches.armadillo800/0009-net-sh_eth-add-support-R8A7740.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 38480ba305384441ebefad2684028756f7eab8b2 Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Wed, 4 Apr 2012 18:37:10 +0000 -Subject: net: sh_eth: add support R8A7740 - -The R8A7740 has a Gigabit Ethernet MAC. This patch supports it. - -Signed-off-by: Yoshihiro Shimoda -Tested-by: Kuninori Morimoto -Signed-off-by: David S. Miller -(cherry picked from commit 73a0d907301ece200d32b4e8ba2da2ca296b507f) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/Kconfig | 7 ++- - drivers/net/ethernet/renesas/sh_eth.c | 114 +++++++++++++++++++++++++++++++++- - drivers/net/ethernet/renesas/sh_eth.h | 5 +- - 3 files changed, 120 insertions(+), 6 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig -index 3fb2355..46df3a0 100644 ---- a/drivers/net/ethernet/renesas/Kconfig -+++ b/drivers/net/ethernet/renesas/Kconfig -@@ -4,11 +4,11 @@ - - config SH_ETH - tristate "Renesas SuperH Ethernet support" -- depends on SUPERH && \ -+ depends on (SUPERH || ARCH_SHMOBILE) && \ - (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \ - CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \ - CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \ -- CPU_SUBTYPE_SH7757) -+ CPU_SUBTYPE_SH7757 || ARCH_R8A7740) - select CRC32 - select NET_CORE - select MII -@@ -17,4 +17,5 @@ config SH_ETH - ---help--- - Renesas SuperH Ethernet device driver. - This driver supporting CPUs are: -- - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763 and SH7757. -+ - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757, -+ and R8A7740. -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index d63e09b..be3c221 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -386,6 +386,114 @@ static void sh_eth_reset_hw_crc(struct net_device *ndev) - sh_eth_write(ndev, 0x0, CSMR); - } - -+#elif defined(CONFIG_ARCH_R8A7740) -+#define SH_ETH_HAS_TSU 1 -+static void sh_eth_chip_reset(struct net_device *ndev) -+{ -+ struct sh_eth_private *mdp = netdev_priv(ndev); -+ unsigned long mii; -+ -+ /* reset device */ -+ sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR); -+ mdelay(1); -+ -+ switch (mdp->phy_interface) { -+ case PHY_INTERFACE_MODE_GMII: -+ mii = 2; -+ break; -+ case PHY_INTERFACE_MODE_MII: -+ mii = 1; -+ break; -+ case PHY_INTERFACE_MODE_RMII: -+ default: -+ mii = 0; -+ break; -+ } -+ sh_eth_write(ndev, mii, RMII_MII); -+} -+ -+static void sh_eth_reset(struct net_device *ndev) -+{ -+ int cnt = 100; -+ -+ sh_eth_write(ndev, EDSR_ENALL, EDSR); -+ sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR); -+ while (cnt > 0) { -+ if (!(sh_eth_read(ndev, EDMR) & 0x3)) -+ break; -+ mdelay(1); -+ cnt--; -+ } -+ if (cnt == 0) -+ printk(KERN_ERR "Device reset fail\n"); -+ -+ /* Table Init */ -+ sh_eth_write(ndev, 0x0, TDLAR); -+ sh_eth_write(ndev, 0x0, TDFAR); -+ sh_eth_write(ndev, 0x0, TDFXR); -+ sh_eth_write(ndev, 0x0, TDFFR); -+ sh_eth_write(ndev, 0x0, RDLAR); -+ sh_eth_write(ndev, 0x0, RDFAR); -+ sh_eth_write(ndev, 0x0, RDFXR); -+ sh_eth_write(ndev, 0x0, RDFFR); -+} -+ -+static void sh_eth_set_duplex(struct net_device *ndev) -+{ -+ struct sh_eth_private *mdp = netdev_priv(ndev); -+ -+ if (mdp->duplex) /* Full */ -+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR); -+ else /* Half */ -+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR); -+} -+ -+static void sh_eth_set_rate(struct net_device *ndev) -+{ -+ struct sh_eth_private *mdp = netdev_priv(ndev); -+ -+ switch (mdp->speed) { -+ case 10: /* 10BASE */ -+ sh_eth_write(ndev, GECMR_10, GECMR); -+ break; -+ case 100:/* 100BASE */ -+ sh_eth_write(ndev, GECMR_100, GECMR); -+ break; -+ case 1000: /* 1000BASE */ -+ sh_eth_write(ndev, GECMR_1000, GECMR); -+ break; -+ default: -+ break; -+ } -+} -+ -+/* R8A7740 */ -+static struct sh_eth_cpu_data sh_eth_my_cpu_data = { -+ .chip_reset = sh_eth_chip_reset, -+ .set_duplex = sh_eth_set_duplex, -+ .set_rate = sh_eth_set_rate, -+ -+ .ecsr_value = ECSR_ICD | ECSR_MPD, -+ .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, -+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, -+ -+ .tx_check = EESR_TC1 | EESR_FTC, -+ .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \ -+ EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \ -+ EESR_ECI, -+ .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \ -+ EESR_TFE, -+ -+ .apr = 1, -+ .mpr = 1, -+ .tpauser = 1, -+ .bculr = 1, -+ .hw_swap = 1, -+ .no_trimd = 1, -+ .no_ade = 1, -+ .tsu = 1, -+}; -+ - #elif defined(CONFIG_CPU_SUBTYPE_SH7619) - #define SH_ETH_RESET_DEFAULT 1 - static struct sh_eth_cpu_data sh_eth_my_cpu_data = { -@@ -443,7 +551,7 @@ static void sh_eth_reset(struct net_device *ndev) - } - #endif - --#if defined(CONFIG_CPU_SH4) -+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) - static void sh_eth_set_receive_align(struct sk_buff *skb) - { - int reserve; -@@ -919,6 +1027,10 @@ static int sh_eth_rx(struct net_device *ndev) - desc_status = edmac_to_cpu(mdp, rxdesc->status); - pkt_len = rxdesc->frame_length; - -+#if defined(CONFIG_ARCH_R8A7740) -+ desc_status >>= 16; -+#endif -+ - if (--boguscnt < 0) - break; - -diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h -index 0fa14afc..57b8e1f 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.h -+++ b/drivers/net/ethernet/renesas/sh_eth.h -@@ -372,7 +372,7 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { - }; - - /* Driver's parameters */ --#if defined(CONFIG_CPU_SH4) -+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) - #define SH4_SKB_RX_ALIGN 32 - #else - #define SH2_SH3_SKB_RX_ALIGN 2 -@@ -381,7 +381,8 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { - /* - * Register's bits - */ --#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) -+#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) ||\ -+ defined(CONFIG_ARCH_R8A7740) - /* EDSR */ - enum EDSR_BIT { - EDSR_ENT = 0x01, EDSR_ENR = 0x02, --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0010-net-sh_eth-fix-the-rxdesc-pointer-when-rx-descriptor.patch b/patches.armadillo800/0010-net-sh_eth-fix-the-rxdesc-pointer-when-rx-descriptor.patch deleted file mode 100644 index f06a9706150d..000000000000 --- a/patches.armadillo800/0010-net-sh_eth-fix-the-rxdesc-pointer-when-rx-descriptor.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 02098572c84a88121b0baeb2b96cea47f17f2e3e Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Mon, 28 May 2012 23:07:55 +0000 -Subject: net: sh_eth: fix the rxdesc pointer when rx descriptor empty happens - -When Receive Descriptor Empty happens, rxdesc pointer of the driver -and actual next descriptor of the controller may be mismatch. -This patch fixes it. - -Signed-off-by: Yoshihiro Shimoda -Signed-off-by: David S. Miller -(cherry picked from commit 79fba9f51755c704c0a7d7b7f0df10874dc0a744) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index be3c221..667169b 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -1101,8 +1101,12 @@ static int sh_eth_rx(struct net_device *ndev) - - /* Restart Rx engine if stopped. */ - /* If we don't need to check status, don't. -KDU */ -- if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) -+ if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) { -+ /* fix the values for the next receiving */ -+ mdp->cur_rx = mdp->dirty_rx = (sh_eth_read(ndev, RDFAR) - -+ sh_eth_read(ndev, RDLAR)) >> 4; - sh_eth_write(ndev, EDRRR_R, EDRRR); -+ } - - return 0; - } -@@ -1199,8 +1203,6 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) - /* Receive Descriptor Empty int */ - ndev->stats.rx_over_errors++; - -- if (sh_eth_read(ndev, EDRRR) ^ EDRRR_R) -- sh_eth_write(ndev, EDRRR_R, EDRRR); - if (netif_msg_rx_err(mdp)) - dev_err(&ndev->dev, "Receive Descriptor Empty\n"); - } --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0011-net-sh_eth-fix-the-condition-to-fix-the-cur_tx-dirty.patch b/patches.armadillo800/0011-net-sh_eth-fix-the-condition-to-fix-the-cur_tx-dirty.patch deleted file mode 100644 index 9d3e463e2e06..000000000000 --- a/patches.armadillo800/0011-net-sh_eth-fix-the-condition-to-fix-the-cur_tx-dirty.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 1c70638e065f5a6bba99f0e27a3b4a4931c77681 Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Wed, 20 Jun 2012 15:26:34 +0000 -Subject: net: sh_eth: fix the condition to fix the cur_tx/dirty_rx - -The following commit couldn't work if the RMCR is not set to 1. - -"net: sh_eth: fix the rxdesc pointer when rx descriptor empty happens" -commit id 79fba9f51755c704c0a7d7b7f0df10874dc0a744 - -If RMCR is not set, the controller will clear the EDRRR after it received -a frame. In this case, the driver doesn't need to fix the value of -cur_rx/dirty_rx. The driver only needs it when the controll detects -receive descriptors are empty. - -Signed-off-by: Yoshihiro Shimoda -Tested-by: Guennadi Liakhovetski -Signed-off-by: David S. Miller -(cherry picked from commit a18e08bdcf845efb7344cea146e683df746bbfb4) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index 667169b..79bf09b 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -1011,7 +1011,7 @@ static int sh_eth_txfree(struct net_device *ndev) - } - - /* Packet receive function */ --static int sh_eth_rx(struct net_device *ndev) -+static int sh_eth_rx(struct net_device *ndev, u32 intr_status) - { - struct sh_eth_private *mdp = netdev_priv(ndev); - struct sh_eth_rxdesc *rxdesc; -@@ -1102,9 +1102,11 @@ static int sh_eth_rx(struct net_device *ndev) - /* Restart Rx engine if stopped. */ - /* If we don't need to check status, don't. -KDU */ - if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) { -- /* fix the values for the next receiving */ -- mdp->cur_rx = mdp->dirty_rx = (sh_eth_read(ndev, RDFAR) - -- sh_eth_read(ndev, RDLAR)) >> 4; -+ /* fix the values for the next receiving if RDE is set */ -+ if (intr_status & EESR_RDE) -+ mdp->cur_rx = mdp->dirty_rx = -+ (sh_eth_read(ndev, RDFAR) - -+ sh_eth_read(ndev, RDLAR)) >> 4; - sh_eth_write(ndev, EDRRR_R, EDRRR); - } - -@@ -1273,7 +1275,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) - EESR_RTSF | /* short frame recv */ - EESR_PRE | /* PHY-LSI recv error */ - EESR_CERF)){ /* recv frame CRC error */ -- sh_eth_rx(ndev); -+ sh_eth_rx(ndev, intr_status); - } - - /* Tx Check */ --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0012-net-sh-eth-Add-support-selecting-MII-function-for-SH.patch b/patches.armadillo800/0012-net-sh-eth-Add-support-selecting-MII-function-for-SH.patch deleted file mode 100644 index 66b1134781ac..000000000000 --- a/patches.armadillo800/0012-net-sh-eth-Add-support-selecting-MII-function-for-SH.patch +++ /dev/null @@ -1,196 +0,0 @@ -From a9d45f3559e2b48428446114ae6817f8a4883de8 Mon Sep 17 00:00:00 2001 -From: Nobuhiro Iwamatsu -Date: Mon, 25 Jun 2012 17:34:14 +0000 -Subject: net/sh-eth: Add support selecting MII function for SH7734 and R8A7740 - -Ethernet IP of SH7734 and R8A7740 has selecting MII register. -The user needs to change a value according to MII to be used. -This adds the function to change the value of this register. - -Signed-off-by: Nobuhiro Iwamatsu -Signed-off-by: David S. Miller -(cherry picked from commit 5e7a76be0e48217aff6b6f34bdcce4725db999e2) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 108 ++++++++++++++++++++-------------- - drivers/net/ethernet/renesas/sh_eth.h | 1 + - 2 files changed, 66 insertions(+), 43 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index 79bf09b..8d696e0 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -49,6 +49,34 @@ - NETIF_MSG_RX_ERR| \ - NETIF_MSG_TX_ERR) - -+#if defined(CONFIG_CPU_SUBTYPE_SH7734) || \ -+ defined(CONFIG_CPU_SUBTYPE_SH7763) || \ -+ defined(CONFIG_ARCH_R8A7740) -+static void sh_eth_select_mii(struct net_device *ndev) -+{ -+ u32 value = 0x0; -+ struct sh_eth_private *mdp = netdev_priv(ndev); -+ -+ switch (mdp->phy_interface) { -+ case PHY_INTERFACE_MODE_GMII: -+ value = 0x2; -+ break; -+ case PHY_INTERFACE_MODE_MII: -+ value = 0x1; -+ break; -+ case PHY_INTERFACE_MODE_RMII: -+ value = 0x0; -+ break; -+ default: -+ pr_warn("PHY interface mode was not setup. Set to MII.\n"); -+ value = 0x1; -+ break; -+ } -+ -+ sh_eth_write(ndev, value, RMII_MII); -+} -+#endif -+ - /* There is CPU dependent code */ - #if defined(CONFIG_CPU_SUBTYPE_SH7724) - #define SH_ETH_RESET_DEFAULT 1 -@@ -283,6 +311,7 @@ static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp) - #elif defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) - #define SH_ETH_HAS_TSU 1 - static void sh_eth_reset_hw_crc(struct net_device *ndev); -+ - static void sh_eth_chip_reset(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -@@ -292,35 +321,6 @@ static void sh_eth_chip_reset(struct net_device *ndev) - mdelay(1); - } - --static void sh_eth_reset(struct net_device *ndev) --{ -- int cnt = 100; -- -- sh_eth_write(ndev, EDSR_ENALL, EDSR); -- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR); -- while (cnt > 0) { -- if (!(sh_eth_read(ndev, EDMR) & 0x3)) -- break; -- mdelay(1); -- cnt--; -- } -- if (cnt == 0) -- printk(KERN_ERR "Device reset fail\n"); -- -- /* Table Init */ -- sh_eth_write(ndev, 0x0, TDLAR); -- sh_eth_write(ndev, 0x0, TDFAR); -- sh_eth_write(ndev, 0x0, TDFXR); -- sh_eth_write(ndev, 0x0, TDFFR); -- sh_eth_write(ndev, 0x0, RDLAR); -- sh_eth_write(ndev, 0x0, RDFAR); -- sh_eth_write(ndev, 0x0, RDFXR); -- sh_eth_write(ndev, 0x0, RDFFR); -- -- /* Reset HW CRC register */ -- sh_eth_reset_hw_crc(ndev); --} -- - static void sh_eth_set_duplex(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -@@ -377,9 +377,43 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { - .tsu = 1, - #if defined(CONFIG_CPU_SUBTYPE_SH7734) - .hw_crc = 1, -+ .select_mii = 1, - #endif - }; - -+static void sh_eth_reset(struct net_device *ndev) -+{ -+ int cnt = 100; -+ -+ sh_eth_write(ndev, EDSR_ENALL, EDSR); -+ sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR); -+ while (cnt > 0) { -+ if (!(sh_eth_read(ndev, EDMR) & 0x3)) -+ break; -+ mdelay(1); -+ cnt--; -+ } -+ if (cnt == 0) -+ printk(KERN_ERR "Device reset fail\n"); -+ -+ /* Table Init */ -+ sh_eth_write(ndev, 0x0, TDLAR); -+ sh_eth_write(ndev, 0x0, TDFAR); -+ sh_eth_write(ndev, 0x0, TDFXR); -+ sh_eth_write(ndev, 0x0, TDFFR); -+ sh_eth_write(ndev, 0x0, RDLAR); -+ sh_eth_write(ndev, 0x0, RDFAR); -+ sh_eth_write(ndev, 0x0, RDFXR); -+ sh_eth_write(ndev, 0x0, RDFFR); -+ -+ /* Reset HW CRC register */ -+ sh_eth_reset_hw_crc(ndev); -+ -+ /* Select MII mode */ -+ if (sh_eth_my_cpu_data.select_mii) -+ sh_eth_select_mii(ndev); -+} -+ - static void sh_eth_reset_hw_crc(struct net_device *ndev) - { - if (sh_eth_my_cpu_data.hw_crc) -@@ -391,25 +425,12 @@ static void sh_eth_reset_hw_crc(struct net_device *ndev) - static void sh_eth_chip_reset(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -- unsigned long mii; - - /* reset device */ - sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR); - mdelay(1); - -- switch (mdp->phy_interface) { -- case PHY_INTERFACE_MODE_GMII: -- mii = 2; -- break; -- case PHY_INTERFACE_MODE_MII: -- mii = 1; -- break; -- case PHY_INTERFACE_MODE_RMII: -- default: -- mii = 0; -- break; -- } -- sh_eth_write(ndev, mii, RMII_MII); -+ sh_eth_select_mii(ndev); - } - - static void sh_eth_reset(struct net_device *ndev) -@@ -492,6 +513,7 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { - .no_trimd = 1, - .no_ade = 1, - .tsu = 1, -+ .select_mii = 1, - }; - - #elif defined(CONFIG_CPU_SUBTYPE_SH7619) -diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h -index 57b8e1f..d6763b1392 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.h -+++ b/drivers/net/ethernet/renesas/sh_eth.h -@@ -757,6 +757,7 @@ struct sh_eth_cpu_data { - unsigned no_trimd:1; /* E-DMAC DO NOT have TRIMD */ - unsigned no_ade:1; /* E-DMAC DO NOT have ADE bit in EESR */ - unsigned hw_crc:1; /* E-DMAC have CSMR */ -+ unsigned select_mii:1; /* EtherC have RMII_MII (MII select register) */ - }; - - struct sh_eth_private { --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0013-net-sh-eth-Check-return-value-of-sh_eth_reset-when-c.patch b/patches.armadillo800/0013-net-sh-eth-Check-return-value-of-sh_eth_reset-when-c.patch deleted file mode 100644 index 1cca1a6b8fa9..000000000000 --- a/patches.armadillo800/0013-net-sh-eth-Check-return-value-of-sh_eth_reset-when-c.patch +++ /dev/null @@ -1,215 +0,0 @@ -From d9b780ce68b329aa745868803ec0419a3fd6975f Mon Sep 17 00:00:00 2001 -From: Nobuhiro Iwamatsu -Date: Mon, 25 Jun 2012 17:35:12 +0000 -Subject: net/sh-eth: Check return value of sh_eth_reset when chip reset fail - -The sh_eth_reset function resets chip, but this performs nothing when failed. -This changes sh_eth_reset return an error, when this failed in reset. - -Signed-off-by: Nobuhiro Iwamatsu -Signed-off-by: David S. Miller -(cherry picked from commit 5cee1d37c9f565f1aa515408863dbb13db67dab9) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 88 ++++++++++++++++++++++------------- - 1 file changed, 56 insertions(+), 32 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index 8d696e0..326cb91 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -130,6 +130,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { - #elif defined(CONFIG_CPU_SUBTYPE_SH7757) - #define SH_ETH_HAS_BOTH_MODULES 1 - #define SH_ETH_HAS_TSU 1 -+static int sh_eth_check_reset(struct net_device *ndev); -+ - static void sh_eth_set_duplex(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -@@ -204,23 +206,19 @@ static void sh_eth_chip_reset_giga(struct net_device *ndev) - } - - static int sh_eth_is_gether(struct sh_eth_private *mdp); --static void sh_eth_reset(struct net_device *ndev) -+static int sh_eth_reset(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -- int cnt = 100; -+ int ret = 0; - - if (sh_eth_is_gether(mdp)) { - sh_eth_write(ndev, 0x03, EDSR); - sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, - EDMR); -- while (cnt > 0) { -- if (!(sh_eth_read(ndev, EDMR) & 0x3)) -- break; -- mdelay(1); -- cnt--; -- } -- if (cnt < 0) -- printk(KERN_ERR "Device reset fail\n"); -+ -+ ret = sh_eth_check_reset(ndev); -+ if (ret) -+ goto out; - - /* Table Init */ - sh_eth_write(ndev, 0x0, TDLAR); -@@ -238,6 +236,9 @@ static void sh_eth_reset(struct net_device *ndev) - sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER, - EDMR); - } -+ -+out: -+ return ret; - } - - static void sh_eth_set_duplex_giga(struct net_device *ndev) -@@ -310,6 +311,7 @@ static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp) - - #elif defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) - #define SH_ETH_HAS_TSU 1 -+static int sh_eth_check_reset(struct net_device *ndev); - static void sh_eth_reset_hw_crc(struct net_device *ndev); - - static void sh_eth_chip_reset(struct net_device *ndev) -@@ -381,20 +383,16 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { - #endif - }; - --static void sh_eth_reset(struct net_device *ndev) -+static int sh_eth_reset(struct net_device *ndev) - { -- int cnt = 100; -+ int ret = 0; - - sh_eth_write(ndev, EDSR_ENALL, EDSR); - sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR); -- while (cnt > 0) { -- if (!(sh_eth_read(ndev, EDMR) & 0x3)) -- break; -- mdelay(1); -- cnt--; -- } -- if (cnt == 0) -- printk(KERN_ERR "Device reset fail\n"); -+ -+ ret = sh_eth_check_reset(ndev); -+ if (ret) -+ goto out; - - /* Table Init */ - sh_eth_write(ndev, 0x0, TDLAR); -@@ -412,6 +410,8 @@ static void sh_eth_reset(struct net_device *ndev) - /* Select MII mode */ - if (sh_eth_my_cpu_data.select_mii) - sh_eth_select_mii(ndev); -+out: -+ return ret; - } - - static void sh_eth_reset_hw_crc(struct net_device *ndev) -@@ -422,6 +422,8 @@ static void sh_eth_reset_hw_crc(struct net_device *ndev) - - #elif defined(CONFIG_ARCH_R8A7740) - #define SH_ETH_HAS_TSU 1 -+static int sh_eth_check_reset(struct net_device *ndev); -+ - static void sh_eth_chip_reset(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -@@ -433,20 +435,16 @@ static void sh_eth_chip_reset(struct net_device *ndev) - sh_eth_select_mii(ndev); - } - --static void sh_eth_reset(struct net_device *ndev) -+static int sh_eth_reset(struct net_device *ndev) - { -- int cnt = 100; -+ int ret = 0; - - sh_eth_write(ndev, EDSR_ENALL, EDSR); - sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR); -- while (cnt > 0) { -- if (!(sh_eth_read(ndev, EDMR) & 0x3)) -- break; -- mdelay(1); -- cnt--; -- } -- if (cnt == 0) -- printk(KERN_ERR "Device reset fail\n"); -+ -+ ret = sh_eth_check_reset(ndev); -+ if (ret) -+ goto out; - - /* Table Init */ - sh_eth_write(ndev, 0x0, TDLAR); -@@ -457,6 +455,9 @@ static void sh_eth_reset(struct net_device *ndev) - sh_eth_write(ndev, 0x0, RDFAR); - sh_eth_write(ndev, 0x0, RDFXR); - sh_eth_write(ndev, 0x0, RDFFR); -+ -+out: -+ return ret; - } - - static void sh_eth_set_duplex(struct net_device *ndev) -@@ -565,11 +566,31 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd) - - #if defined(SH_ETH_RESET_DEFAULT) - /* Chip Reset */ --static void sh_eth_reset(struct net_device *ndev) -+static int sh_eth_reset(struct net_device *ndev) - { - sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER, EDMR); - mdelay(3); - sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER, EDMR); -+ -+ return 0; -+} -+#else -+static int sh_eth_check_reset(struct net_device *ndev) -+{ -+ int ret = 0; -+ int cnt = 100; -+ -+ while (cnt > 0) { -+ if (!(sh_eth_read(ndev, EDMR) & 0x3)) -+ break; -+ mdelay(1); -+ cnt--; -+ } -+ if (cnt < 0) { -+ printk(KERN_ERR "Device reset fail\n"); -+ ret = -ETIMEDOUT; -+ } -+ return ret; - } - #endif - -@@ -924,7 +945,9 @@ static int sh_eth_dev_init(struct net_device *ndev) - u32 val; - - /* Soft Reset */ -- sh_eth_reset(ndev); -+ ret = sh_eth_reset(ndev); -+ if (ret) -+ goto out; - - /* Descriptor format */ - sh_eth_ring_format(ndev); -@@ -998,6 +1021,7 @@ static int sh_eth_dev_init(struct net_device *ndev) - - netif_start_queue(ndev); - -+out: - return ret; - } - --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0014-net-sh_eth-remove-unnecessary-function.patch b/patches.armadillo800/0014-net-sh_eth-remove-unnecessary-function.patch deleted file mode 100644 index 029365f01b9b..000000000000 --- a/patches.armadillo800/0014-net-sh_eth-remove-unnecessary-function.patch +++ /dev/null @@ -1,94 +0,0 @@ -From da239ac021220b753bc1f21495ed187275f935aa Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Tue, 26 Jun 2012 19:59:51 +0000 -Subject: net: sh_eth: remove unnecessary function - -The sh_eth_timer() called mod_timer() for itself. So, this patch -removes the function. - -Signed-off-by: Yoshihiro Shimoda -Signed-off-by: David S. Miller -(cherry picked from commit c26502680e59af556211fc3fd3ae0f2aa5d98440) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 22 ---------------------- - drivers/net/ethernet/renesas/sh_eth.h | 1 - - 2 files changed, 23 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index 326cb91..cf0bc31 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -1339,14 +1339,6 @@ other_irq: - return ret; - } - --static void sh_eth_timer(unsigned long data) --{ -- struct net_device *ndev = (struct net_device *)data; -- struct sh_eth_private *mdp = netdev_priv(ndev); -- -- mod_timer(&mdp->timer, jiffies + (10 * HZ)); --} -- - /* PHY state control function */ - static void sh_eth_adjust_link(struct net_device *ndev) - { -@@ -1594,11 +1586,6 @@ static int sh_eth_open(struct net_device *ndev) - if (ret) - goto out_free_irq; - -- /* Set the timer to check for link beat. */ -- init_timer(&mdp->timer); -- mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ -- setup_timer(&mdp->timer, sh_eth_timer, (unsigned long)ndev); -- - return ret; - - out_free_irq: -@@ -1623,9 +1610,6 @@ static void sh_eth_tx_timeout(struct net_device *ndev) - /* tx_errors count up */ - ndev->stats.tx_errors++; - -- /* timer off */ -- del_timer_sync(&mdp->timer); -- - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - rxdesc = &mdp->rx_ring[i]; -@@ -1643,10 +1627,6 @@ static void sh_eth_tx_timeout(struct net_device *ndev) - - /* device init */ - sh_eth_dev_init(ndev); -- -- /* timer on */ -- mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */ -- add_timer(&mdp->timer); - } - - /* Packet transmit function */ -@@ -1719,8 +1699,6 @@ static int sh_eth_close(struct net_device *ndev) - - free_irq(ndev->irq, ndev); - -- del_timer_sync(&mdp->timer); -- - /* Free all the skbuffs in the Rx queue. */ - sh_eth_ring_free(ndev); - -diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h -index d6763b1392..5af3f2a 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.h -+++ b/drivers/net/ethernet/renesas/sh_eth.h -@@ -772,7 +772,6 @@ struct sh_eth_private { - struct sh_eth_txdesc *tx_ring; - struct sk_buff **rx_skbuff; - struct sk_buff **tx_skbuff; -- struct timer_list timer; - spinlock_t lock; - u32 cur_rx, dirty_rx; /* Producer/consumer ring indices */ - u32 cur_tx, dirty_tx; --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0015-net-sh_eth-remove-unnecessary-members-definitions.patch b/patches.armadillo800/0015-net-sh_eth-remove-unnecessary-members-definitions.patch deleted file mode 100644 index 95923c02d692..000000000000 --- a/patches.armadillo800/0015-net-sh_eth-remove-unnecessary-members-definitions.patch +++ /dev/null @@ -1,140 +0,0 @@ -From c0de8fd97587b151f04aeb92c1946d30e04b3f8a Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Tue, 26 Jun 2012 19:59:58 +0000 -Subject: net: sh_eth: remove unnecessary members/definitions - -This patch removes unnecessary members in sh_th_private. -This patch also removes unnecessary definitions in sh_eth.h - -Signed-off-by: Yoshihiro Shimoda -Signed-off-by: David S. Miller -(cherry picked from commit 2ecbb783c3bf5a63f555c39deef308dcc1902b7f) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 7 +--- - drivers/net/ethernet/renesas/sh_eth.h | 69 ----------------------------------- - 2 files changed, 1 insertion(+), 75 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index cf0bc31..43e76d2 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -941,7 +941,6 @@ static int sh_eth_dev_init(struct net_device *ndev) - { - int ret = 0; - struct sh_eth_private *mdp = netdev_priv(ndev); -- u_int32_t rx_int_var, tx_int_var; - u32 val; - - /* Soft Reset */ -@@ -971,9 +970,7 @@ static int sh_eth_dev_init(struct net_device *ndev) - /* Frame recv control */ - sh_eth_write(ndev, mdp->cd->rmcr_value, RMCR); - -- rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5; -- tx_int_var = mdp->tx_int_var = DESC_I_TINT2; -- sh_eth_write(ndev, rx_int_var | tx_int_var, TRSCER); -+ sh_eth_write(ndev, DESC_I_RINT8 | DESC_I_RINT5 | DESC_I_TINT2, TRSCER); - - if (mdp->cd->bculr) - sh_eth_write(ndev, 0x800, BCULR); /* Burst sycle set */ -@@ -2336,8 +2333,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev) - - /* debug message level */ - mdp->msg_enable = SH_ETH_DEF_MSG_ENABLE; -- mdp->post_rx = POST_RX >> (devno << 1); -- mdp->post_fw = POST_FW >> (devno << 1); - - /* read and set MAC address */ - read_mac_address(ndev, pd->mac_addr); -diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h -index 5af3f2a..37a0702 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.h -+++ b/drivers/net/ethernet/renesas/sh_eth.h -@@ -585,71 +585,6 @@ enum RPADIR_BIT { - /* FDR */ - #define DEFAULT_FDR_INIT 0x00000707 - --enum phy_offsets { -- PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3, -- PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6, -- PHY_16 = 16, --}; -- --/* PHY_CTRL */ --enum PHY_CTRL_BIT { -- PHY_C_RESET = 0x8000, PHY_C_LOOPBK = 0x4000, PHY_C_SPEEDSL = 0x2000, -- PHY_C_ANEGEN = 0x1000, PHY_C_PWRDN = 0x0800, PHY_C_ISO = 0x0400, -- PHY_C_RANEG = 0x0200, PHY_C_DUPLEX = 0x0100, PHY_C_COLT = 0x0080, --}; --#define DM9161_PHY_C_ANEGEN 0 /* auto nego special */ -- --/* PHY_STAT */ --enum PHY_STAT_BIT { -- PHY_S_100T4 = 0x8000, PHY_S_100X_F = 0x4000, PHY_S_100X_H = 0x2000, -- PHY_S_10T_F = 0x1000, PHY_S_10T_H = 0x0800, PHY_S_ANEGC = 0x0020, -- PHY_S_RFAULT = 0x0010, PHY_S_ANEGA = 0x0008, PHY_S_LINK = 0x0004, -- PHY_S_JAB = 0x0002, PHY_S_EXTD = 0x0001, --}; -- --/* PHY_ANA */ --enum PHY_ANA_BIT { -- PHY_A_NP = 0x8000, PHY_A_ACK = 0x4000, PHY_A_RF = 0x2000, -- PHY_A_FCS = 0x0400, PHY_A_T4 = 0x0200, PHY_A_FDX = 0x0100, -- PHY_A_HDX = 0x0080, PHY_A_10FDX = 0x0040, PHY_A_10HDX = 0x0020, -- PHY_A_SEL = 0x001e, --}; --/* PHY_ANL */ --enum PHY_ANL_BIT { -- PHY_L_NP = 0x8000, PHY_L_ACK = 0x4000, PHY_L_RF = 0x2000, -- PHY_L_FCS = 0x0400, PHY_L_T4 = 0x0200, PHY_L_FDX = 0x0100, -- PHY_L_HDX = 0x0080, PHY_L_10FDX = 0x0040, PHY_L_10HDX = 0x0020, -- PHY_L_SEL = 0x001f, --}; -- --/* PHY_ANE */ --enum PHY_ANE_BIT { -- PHY_E_PDF = 0x0010, PHY_E_LPNPA = 0x0008, PHY_E_NPA = 0x0004, -- PHY_E_PRX = 0x0002, PHY_E_LPANEGA = 0x0001, --}; -- --/* DM9161 */ --enum PHY_16_BIT { -- PHY_16_BP4B45 = 0x8000, PHY_16_BPSCR = 0x4000, PHY_16_BPALIGN = 0x2000, -- PHY_16_BP_ADPOK = 0x1000, PHY_16_Repeatmode = 0x0800, -- PHY_16_TXselect = 0x0400, -- PHY_16_Rsvd = 0x0200, PHY_16_RMIIEnable = 0x0100, -- PHY_16_Force100LNK = 0x0080, -- PHY_16_APDLED_CTL = 0x0040, PHY_16_COLLED_CTL = 0x0020, -- PHY_16_RPDCTR_EN = 0x0010, -- PHY_16_ResetStMch = 0x0008, PHY_16_PreamSupr = 0x0004, -- PHY_16_Sleepmode = 0x0002, -- PHY_16_RemoteLoopOut = 0x0001, --}; -- --#define POST_RX 0x08 --#define POST_FW 0x04 --#define POST0_RX (POST_RX) --#define POST0_FW (POST_FW) --#define POST1_RX (POST_RX >> 2) --#define POST1_FW (POST_FW >> 2) --#define POST_ALL (POST0_RX | POST0_FW | POST1_RX | POST1_FW) -- - /* ARSTR */ - enum ARSTR_BIT { ARSTR_ARSTR = 0x00000001, }; - -@@ -786,10 +721,6 @@ struct sh_eth_private { - int msg_enable; - int speed; - int duplex; -- u32 rx_int_var, tx_int_var; /* interrupt control variables */ -- char post_rx; /* POST receive */ -- char post_fw; /* POST forward */ -- struct net_device_stats tsu_stats; /* TSU forward status */ - int port; /* for TSU */ - int vlan_num_ids; /* for VLAN tag filter */ - --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0016-net-sh_eth-fix-up-the-buffer-pointers.patch b/patches.armadillo800/0016-net-sh_eth-fix-up-the-buffer-pointers.patch deleted file mode 100644 index 5e09276e0726..000000000000 --- a/patches.armadillo800/0016-net-sh_eth-fix-up-the-buffer-pointers.patch +++ /dev/null @@ -1,94 +0,0 @@ -From ec575069aff289fc8d05d09b897bb05e55e90adf Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Tue, 26 Jun 2012 20:00:01 +0000 -Subject: net: sh_eth: fix up the buffer pointers - -After freeing the buffer, the driver should change the value of -the pointer to NULL. - -Signed-off-by: Yoshihiro Shimoda -Signed-off-by: David S. Miller -(cherry picked from commit 91c77550000a7d888aaf9f9ac13e3e3485d18560) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 31 ++++++++++++++++++++++++------- - 1 file changed, 24 insertions(+), 7 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index 43e76d2..2dd2ff5 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -788,6 +788,7 @@ static void sh_eth_ring_free(struct net_device *ndev) - } - } - kfree(mdp->rx_skbuff); -+ mdp->rx_skbuff = NULL; - - /* Free Tx skb ringbuffer */ - if (mdp->tx_skbuff) { -@@ -797,6 +798,7 @@ static void sh_eth_ring_free(struct net_device *ndev) - } - } - kfree(mdp->tx_skbuff); -+ mdp->tx_skbuff = NULL; - } - - /* format skb and descriptor buffer */ -@@ -933,10 +935,31 @@ desc_ring_free: - skb_ring_free: - /* Free Rx and Tx skb ring buffer */ - sh_eth_ring_free(ndev); -+ mdp->tx_ring = NULL; -+ mdp->rx_ring = NULL; - - return ret; - } - -+static void sh_eth_free_dma_buffer(struct sh_eth_private *mdp) -+{ -+ int ringsize; -+ -+ if (mdp->rx_ring) { -+ ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; -+ dma_free_coherent(NULL, ringsize, mdp->rx_ring, -+ mdp->rx_desc_dma); -+ mdp->rx_ring = NULL; -+ } -+ -+ if (mdp->tx_ring) { -+ ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; -+ dma_free_coherent(NULL, ringsize, mdp->tx_ring, -+ mdp->tx_desc_dma); -+ mdp->tx_ring = NULL; -+ } -+} -+ - static int sh_eth_dev_init(struct net_device *ndev) - { - int ret = 0; -@@ -1677,7 +1700,6 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) - static int sh_eth_close(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -- int ringsize; - - netif_stop_queue(ndev); - -@@ -1700,12 +1722,7 @@ static int sh_eth_close(struct net_device *ndev) - sh_eth_ring_free(ndev); - - /* free DMA buffer */ -- ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; -- dma_free_coherent(NULL, ringsize, mdp->rx_ring, mdp->rx_desc_dma); -- -- /* free DMA buffer */ -- ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; -- dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma); -+ sh_eth_free_dma_buffer(mdp); - - pm_runtime_put_sync(&mdp->pdev->dev); - --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0017-net-sh_eth-add-support-for-set_ringparam-get_ringpar.patch b/patches.armadillo800/0017-net-sh_eth-add-support-for-set_ringparam-get_ringpar.patch deleted file mode 100644 index d1a976c408bd..000000000000 --- a/patches.armadillo800/0017-net-sh_eth-add-support-for-set_ringparam-get_ringpar.patch +++ /dev/null @@ -1,407 +0,0 @@ -From 53432c5cc072269a7e3ac40d2731da16434a24b2 Mon Sep 17 00:00:00 2001 -From: Yoshihiro Shimoda -Date: Tue, 26 Jun 2012 20:00:03 +0000 -Subject: net: sh_eth: add support for set_ringparam/get_ringparam - -This patch supports the ethtool's set_ringparam() and get_ringparam(). - -Signed-off-by: Yoshihiro Shimoda -Signed-off-by: David S. Miller -(cherry picked from commit 525b8075edda9c2ab4b81e210505bd7487ea6e56) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/sh_eth.c | 139 ++++++++++++++++++++++++++-------- - drivers/net/ethernet/renesas/sh_eth.h | 6 ++ - 2 files changed, 112 insertions(+), 33 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index 2dd2ff5..af0b867 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -782,7 +782,7 @@ static void sh_eth_ring_free(struct net_device *ndev) - - /* Free Rx skb ringbuffer */ - if (mdp->rx_skbuff) { -- for (i = 0; i < RX_RING_SIZE; i++) { -+ for (i = 0; i < mdp->num_rx_ring; i++) { - if (mdp->rx_skbuff[i]) - dev_kfree_skb(mdp->rx_skbuff[i]); - } -@@ -792,7 +792,7 @@ static void sh_eth_ring_free(struct net_device *ndev) - - /* Free Tx skb ringbuffer */ - if (mdp->tx_skbuff) { -- for (i = 0; i < TX_RING_SIZE; i++) { -+ for (i = 0; i < mdp->num_tx_ring; i++) { - if (mdp->tx_skbuff[i]) - dev_kfree_skb(mdp->tx_skbuff[i]); - } -@@ -809,8 +809,8 @@ static void sh_eth_ring_format(struct net_device *ndev) - struct sk_buff *skb; - struct sh_eth_rxdesc *rxdesc = NULL; - struct sh_eth_txdesc *txdesc = NULL; -- int rx_ringsize = sizeof(*rxdesc) * RX_RING_SIZE; -- int tx_ringsize = sizeof(*txdesc) * TX_RING_SIZE; -+ int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring; -+ int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring; - - mdp->cur_rx = mdp->cur_tx = 0; - mdp->dirty_rx = mdp->dirty_tx = 0; -@@ -818,7 +818,7 @@ static void sh_eth_ring_format(struct net_device *ndev) - memset(mdp->rx_ring, 0, rx_ringsize); - - /* build Rx ring buffer */ -- for (i = 0; i < RX_RING_SIZE; i++) { -+ for (i = 0; i < mdp->num_rx_ring; i++) { - /* skb */ - mdp->rx_skbuff[i] = NULL; - skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz); -@@ -844,7 +844,7 @@ static void sh_eth_ring_format(struct net_device *ndev) - } - } - -- mdp->dirty_rx = (u32) (i - RX_RING_SIZE); -+ mdp->dirty_rx = (u32) (i - mdp->num_rx_ring); - - /* Mark the last entry as wrapping the ring. */ - rxdesc->status |= cpu_to_edmac(mdp, RD_RDEL); -@@ -852,7 +852,7 @@ static void sh_eth_ring_format(struct net_device *ndev) - memset(mdp->tx_ring, 0, tx_ringsize); - - /* build Tx ring buffer */ -- for (i = 0; i < TX_RING_SIZE; i++) { -+ for (i = 0; i < mdp->num_tx_ring; i++) { - mdp->tx_skbuff[i] = NULL; - txdesc = &mdp->tx_ring[i]; - txdesc->status = cpu_to_edmac(mdp, TD_TFP); -@@ -886,7 +886,7 @@ static int sh_eth_ring_init(struct net_device *ndev) - mdp->rx_buf_sz += NET_IP_ALIGN; - - /* Allocate RX and TX skb rings */ -- mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE, -+ mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * mdp->num_rx_ring, - GFP_KERNEL); - if (!mdp->rx_skbuff) { - dev_err(&ndev->dev, "Cannot allocate Rx skb\n"); -@@ -894,7 +894,7 @@ static int sh_eth_ring_init(struct net_device *ndev) - return ret; - } - -- mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * TX_RING_SIZE, -+ mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * mdp->num_tx_ring, - GFP_KERNEL); - if (!mdp->tx_skbuff) { - dev_err(&ndev->dev, "Cannot allocate Tx skb\n"); -@@ -903,7 +903,7 @@ static int sh_eth_ring_init(struct net_device *ndev) - } - - /* Allocate all Rx descriptors. */ -- rx_ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; -+ rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; - mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma, - GFP_KERNEL); - -@@ -917,7 +917,7 @@ static int sh_eth_ring_init(struct net_device *ndev) - mdp->dirty_rx = 0; - - /* Allocate all Tx descriptors. */ -- tx_ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; -+ tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; - mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma, - GFP_KERNEL); - if (!mdp->tx_ring) { -@@ -946,21 +946,21 @@ static void sh_eth_free_dma_buffer(struct sh_eth_private *mdp) - int ringsize; - - if (mdp->rx_ring) { -- ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; -+ ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring; - dma_free_coherent(NULL, ringsize, mdp->rx_ring, - mdp->rx_desc_dma); - mdp->rx_ring = NULL; - } - - if (mdp->tx_ring) { -- ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; -+ ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring; - dma_free_coherent(NULL, ringsize, mdp->tx_ring, - mdp->tx_desc_dma); - mdp->tx_ring = NULL; - } - } - --static int sh_eth_dev_init(struct net_device *ndev) -+static int sh_eth_dev_init(struct net_device *ndev, bool start) - { - int ret = 0; - struct sh_eth_private *mdp = netdev_priv(ndev); -@@ -1008,7 +1008,8 @@ static int sh_eth_dev_init(struct net_device *ndev) - RFLR); - - sh_eth_write(ndev, sh_eth_read(ndev, EESR), EESR); -- sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); -+ if (start) -+ sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); - - /* PAUSE Prohibition */ - val = (sh_eth_read(ndev, ECMR) & ECMR_DM) | -@@ -1023,7 +1024,8 @@ static int sh_eth_dev_init(struct net_device *ndev) - sh_eth_write(ndev, mdp->cd->ecsr_value, ECSR); - - /* E-MAC Interrupt Enable register */ -- sh_eth_write(ndev, mdp->cd->ecsipr_value, ECSIPR); -+ if (start) -+ sh_eth_write(ndev, mdp->cd->ecsipr_value, ECSIPR); - - /* Set MAC address */ - update_mac_address(ndev); -@@ -1036,10 +1038,12 @@ static int sh_eth_dev_init(struct net_device *ndev) - if (mdp->cd->tpauser) - sh_eth_write(ndev, TPAUSER_UNLIMITED, TPAUSER); - -- /* Setting the Rx mode will start the Rx process. */ -- sh_eth_write(ndev, EDRRR_R, EDRRR); -+ if (start) { -+ /* Setting the Rx mode will start the Rx process. */ -+ sh_eth_write(ndev, EDRRR_R, EDRRR); - -- netif_start_queue(ndev); -+ netif_start_queue(ndev); -+ } - - out: - return ret; -@@ -1054,7 +1058,7 @@ static int sh_eth_txfree(struct net_device *ndev) - int entry = 0; - - for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) { -- entry = mdp->dirty_tx % TX_RING_SIZE; -+ entry = mdp->dirty_tx % mdp->num_tx_ring; - txdesc = &mdp->tx_ring[entry]; - if (txdesc->status & cpu_to_edmac(mdp, TD_TACT)) - break; -@@ -1067,7 +1071,7 @@ static int sh_eth_txfree(struct net_device *ndev) - freeNum++; - } - txdesc->status = cpu_to_edmac(mdp, TD_TFP); -- if (entry >= TX_RING_SIZE - 1) -+ if (entry >= mdp->num_tx_ring - 1) - txdesc->status |= cpu_to_edmac(mdp, TD_TDLE); - - ndev->stats.tx_packets++; -@@ -1082,8 +1086,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) - struct sh_eth_private *mdp = netdev_priv(ndev); - struct sh_eth_rxdesc *rxdesc; - -- int entry = mdp->cur_rx % RX_RING_SIZE; -- int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx; -+ int entry = mdp->cur_rx % mdp->num_rx_ring; -+ int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx; - struct sk_buff *skb; - u16 pkt_len = 0; - u32 desc_status; -@@ -1134,13 +1138,13 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) - ndev->stats.rx_bytes += pkt_len; - } - rxdesc->status |= cpu_to_edmac(mdp, RD_RACT); -- entry = (++mdp->cur_rx) % RX_RING_SIZE; -+ entry = (++mdp->cur_rx) % mdp->num_rx_ring; - rxdesc = &mdp->rx_ring[entry]; - } - - /* Refill the Rx ring buffers. */ - for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) { -- entry = mdp->dirty_rx % RX_RING_SIZE; -+ entry = mdp->dirty_rx % mdp->num_rx_ring; - rxdesc = &mdp->rx_ring[entry]; - /* The size of the buffer is 16 byte boundary. */ - rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); -@@ -1157,7 +1161,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) - skb_checksum_none_assert(skb); - rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); - } -- if (entry >= RX_RING_SIZE - 1) -+ if (entry >= mdp->num_rx_ring - 1) - rxdesc->status |= - cpu_to_edmac(mdp, RD_RACT | RD_RFP | RD_RDEL); - else -@@ -1557,6 +1561,71 @@ static void sh_eth_get_strings(struct net_device *ndev, u32 stringset, u8 *data) - } - } - -+static void sh_eth_get_ringparam(struct net_device *ndev, -+ struct ethtool_ringparam *ring) -+{ -+ struct sh_eth_private *mdp = netdev_priv(ndev); -+ -+ ring->rx_max_pending = RX_RING_MAX; -+ ring->tx_max_pending = TX_RING_MAX; -+ ring->rx_pending = mdp->num_rx_ring; -+ ring->tx_pending = mdp->num_tx_ring; -+} -+ -+static int sh_eth_set_ringparam(struct net_device *ndev, -+ struct ethtool_ringparam *ring) -+{ -+ struct sh_eth_private *mdp = netdev_priv(ndev); -+ int ret; -+ -+ if (ring->tx_pending > TX_RING_MAX || -+ ring->rx_pending > RX_RING_MAX || -+ ring->tx_pending < TX_RING_MIN || -+ ring->rx_pending < RX_RING_MIN) -+ return -EINVAL; -+ if (ring->rx_mini_pending || ring->rx_jumbo_pending) -+ return -EINVAL; -+ -+ if (netif_running(ndev)) { -+ netif_tx_disable(ndev); -+ /* Disable interrupts by clearing the interrupt mask. */ -+ sh_eth_write(ndev, 0x0000, EESIPR); -+ /* Stop the chip's Tx and Rx processes. */ -+ sh_eth_write(ndev, 0, EDTRR); -+ sh_eth_write(ndev, 0, EDRRR); -+ synchronize_irq(ndev->irq); -+ } -+ -+ /* Free all the skbuffs in the Rx queue. */ -+ sh_eth_ring_free(ndev); -+ /* Free DMA buffer */ -+ sh_eth_free_dma_buffer(mdp); -+ -+ /* Set new parameters */ -+ mdp->num_rx_ring = ring->rx_pending; -+ mdp->num_tx_ring = ring->tx_pending; -+ -+ ret = sh_eth_ring_init(ndev); -+ if (ret < 0) { -+ dev_err(&ndev->dev, "%s: sh_eth_ring_init failed.\n", __func__); -+ return ret; -+ } -+ ret = sh_eth_dev_init(ndev, false); -+ if (ret < 0) { -+ dev_err(&ndev->dev, "%s: sh_eth_dev_init failed.\n", __func__); -+ return ret; -+ } -+ -+ if (netif_running(ndev)) { -+ sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); -+ /* Setting the Rx mode will start the Rx process. */ -+ sh_eth_write(ndev, EDRRR_R, EDRRR); -+ netif_wake_queue(ndev); -+ } -+ -+ return 0; -+} -+ - static const struct ethtool_ops sh_eth_ethtool_ops = { - .get_settings = sh_eth_get_settings, - .set_settings = sh_eth_set_settings, -@@ -1567,6 +1636,8 @@ static const struct ethtool_ops sh_eth_ethtool_ops = { - .get_strings = sh_eth_get_strings, - .get_ethtool_stats = sh_eth_get_ethtool_stats, - .get_sset_count = sh_eth_get_sset_count, -+ .get_ringparam = sh_eth_get_ringparam, -+ .set_ringparam = sh_eth_set_ringparam, - }; - - /* network device open function */ -@@ -1597,7 +1668,7 @@ static int sh_eth_open(struct net_device *ndev) - goto out_free_irq; - - /* device init */ -- ret = sh_eth_dev_init(ndev); -+ ret = sh_eth_dev_init(ndev, true); - if (ret) - goto out_free_irq; - -@@ -1631,7 +1702,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev) - ndev->stats.tx_errors++; - - /* Free all the skbuffs in the Rx queue. */ -- for (i = 0; i < RX_RING_SIZE; i++) { -+ for (i = 0; i < mdp->num_rx_ring; i++) { - rxdesc = &mdp->rx_ring[i]; - rxdesc->status = 0; - rxdesc->addr = 0xBADF00D0; -@@ -1639,14 +1710,14 @@ static void sh_eth_tx_timeout(struct net_device *ndev) - dev_kfree_skb(mdp->rx_skbuff[i]); - mdp->rx_skbuff[i] = NULL; - } -- for (i = 0; i < TX_RING_SIZE; i++) { -+ for (i = 0; i < mdp->num_tx_ring; i++) { - if (mdp->tx_skbuff[i]) - dev_kfree_skb(mdp->tx_skbuff[i]); - mdp->tx_skbuff[i] = NULL; - } - - /* device init */ -- sh_eth_dev_init(ndev); -+ sh_eth_dev_init(ndev, true); - } - - /* Packet transmit function */ -@@ -1658,7 +1729,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) - unsigned long flags; - - spin_lock_irqsave(&mdp->lock, flags); -- if ((mdp->cur_tx - mdp->dirty_tx) >= (TX_RING_SIZE - 4)) { -+ if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) { - if (!sh_eth_txfree(ndev)) { - if (netif_msg_tx_queued(mdp)) - dev_warn(&ndev->dev, "TxFD exhausted.\n"); -@@ -1669,7 +1740,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) - } - spin_unlock_irqrestore(&mdp->lock, flags); - -- entry = mdp->cur_tx % TX_RING_SIZE; -+ entry = mdp->cur_tx % mdp->num_tx_ring; - mdp->tx_skbuff[entry] = skb; - txdesc = &mdp->tx_ring[entry]; - /* soft swap. */ -@@ -1683,7 +1754,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) - else - txdesc->buffer_length = skb->len; - -- if (entry >= TX_RING_SIZE - 1) -+ if (entry >= mdp->num_tx_ring - 1) - txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE); - else - txdesc->status |= cpu_to_edmac(mdp, TD_TACT); -@@ -2313,6 +2384,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) - ether_setup(ndev); - - mdp = netdev_priv(ndev); -+ mdp->num_tx_ring = TX_RING_SIZE; -+ mdp->num_rx_ring = RX_RING_SIZE; - mdp->addr = ioremap(res->start, resource_size(res)); - if (mdp->addr == NULL) { - ret = -ENOMEM; -diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h -index 37a0702..bae84fd 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.h -+++ b/drivers/net/ethernet/renesas/sh_eth.h -@@ -27,6 +27,10 @@ - #define TX_TIMEOUT (5*HZ) - #define TX_RING_SIZE 64 /* Tx ring size */ - #define RX_RING_SIZE 64 /* Rx ring size */ -+#define TX_RING_MIN 64 -+#define RX_RING_MIN 64 -+#define TX_RING_MAX 1024 -+#define RX_RING_MAX 1024 - #define ETHERSMALL 60 - #define PKT_BUF_SZ 1538 - #define SH_ETH_TSU_TIMEOUT_MS 500 -@@ -701,6 +705,8 @@ struct sh_eth_private { - const u16 *reg_offset; - void __iomem *addr; - void __iomem *tsu_addr; -+ u32 num_rx_ring; -+ u32 num_tx_ring; - dma_addr_t rx_desc_dma; - dma_addr_t tx_desc_dma; - struct sh_eth_rxdesc *rx_ring; --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0018-net-sh_eth-Add-eth-support-for-R8A7779-device.patch b/patches.armadillo800/0018-net-sh_eth-Add-eth-support-for-R8A7779-device.patch deleted file mode 100644 index 91821e19678b..000000000000 --- a/patches.armadillo800/0018-net-sh_eth-Add-eth-support-for-R8A7779-device.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 404932d6f9282b0b5acf10d854fd65611f884521 Mon Sep 17 00:00:00 2001 -From: Phil Edworthy -Date: Tue, 14 Aug 2012 20:33:29 +0000 -Subject: net: sh_eth: Add eth support for R8A7779 device - -Signed-off-by: Phil Edworthy -Signed-off-by: David S. Miller -(cherry picked from commit d0418bb7123f44b23d69ac349eec7daf9103472f) - -Signed-off-by: Simon Horman ---- - drivers/net/ethernet/renesas/Kconfig | 4 ++-- - drivers/net/ethernet/renesas/sh_eth.c | 11 ++++++++--- - 2 files changed, 10 insertions(+), 5 deletions(-) - -diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig -index 46df3a0..24c2305 100644 ---- a/drivers/net/ethernet/renesas/Kconfig -+++ b/drivers/net/ethernet/renesas/Kconfig -@@ -8,7 +8,7 @@ config SH_ETH - (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \ - CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \ - CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \ -- CPU_SUBTYPE_SH7757 || ARCH_R8A7740) -+ CPU_SUBTYPE_SH7757 || ARCH_R8A7740 || ARCH_R8A7779) - select CRC32 - select NET_CORE - select MII -@@ -18,4 +18,4 @@ config SH_ETH - Renesas SuperH Ethernet device driver. - This driver supporting CPUs are: - - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757, -- and R8A7740. -+ R8A7740 and R8A7779. -diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c -index af0b867..bad8f2e 100644 ---- a/drivers/net/ethernet/renesas/sh_eth.c -+++ b/drivers/net/ethernet/renesas/sh_eth.c -@@ -78,7 +78,7 @@ static void sh_eth_select_mii(struct net_device *ndev) - #endif - - /* There is CPU dependent code */ --#if defined(CONFIG_CPU_SUBTYPE_SH7724) -+#if defined(CONFIG_CPU_SUBTYPE_SH7724) || defined(CONFIG_ARCH_R8A7779) - #define SH_ETH_RESET_DEFAULT 1 - static void sh_eth_set_duplex(struct net_device *ndev) - { -@@ -93,13 +93,18 @@ static void sh_eth_set_duplex(struct net_device *ndev) - static void sh_eth_set_rate(struct net_device *ndev) - { - struct sh_eth_private *mdp = netdev_priv(ndev); -+ unsigned int bits = ECMR_RTM; -+ -+#if defined(CONFIG_ARCH_R8A7779) -+ bits |= ECMR_ELB; -+#endif - - switch (mdp->speed) { - case 10: /* 10BASE */ -- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_RTM, ECMR); -+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~bits, ECMR); - break; - case 100:/* 100BASE */ -- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_RTM, ECMR); -+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | bits, ECMR); - break; - default: - break; --- -1.8.0.197.g5a90748 - diff --git a/patches.armadillo800/0019-ASoC-add-generic-simple-card-support.patch b/patches.armadillo800/0019-ASoC-add-generic-simple-card-support.patch deleted file mode 100644 index 731314e79a6d..000000000000 --- a/patches.armadillo800/0019-ASoC-add-generic-simple-card-support.patch +++ /dev/null @@ -1,220 +0,0 @@ -From e824e077a91eecb30f3a4124516811ffc382b5a8 Mon Sep 17 00:00:00 2001 -From: Kuninori Morimoto -Date: Sun, 8 Apr 2012 21:17:50 -0700 -Subject: ASoC: add generic simple-card support - -Current ASoC requires card.c file to each platforms in order to -specifies its CPU and Codecs pair. -But the differences between these were only value/strings of setting. -In order to reduce duplicate driver, this patch adds generic/simple-card. - -Signed-off-by: Kuninori Morimoto -Signed-off-by: Mark Brown -(cherry picked from commit f2390880ec0264a0ed26b32c23bc23435b4297da) - -Signed-off-by: Simon Horman ---- - include/sound/simple_card.h | 38 +++++++++++++ - sound/soc/Kconfig | 3 + - sound/soc/Makefile | 1 - sound/soc/generic/Kconfig | 4 + - sound/soc/generic/Makefile | 3 + - sound/soc/generic/simple-card.c | 114 ++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 163 insertions(+) - create mode 100644 include/sound/simple_card.h - create mode 100644 sound/soc/generic/Kconfig - create mode 100644 sound/soc/generic/Makefile - create mode 100644 sound/soc/generic/simple-card.c - ---- /dev/null -+++ b/include/sound/simple_card.h -@@ -0,0 +1,38 @@ -+/* -+ * ASoC simple sound card support -+ * -+ * Copyright (C) 2012 Renesas Solutions Corp. -+ * Kuninori Morimoto -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __SIMPLE_CARD_H -+#define __SIMPLE_CARD_H -+ -+#include -+ -+struct asoc_simple_dai_init_info { -+ unsigned int fmt; -+ unsigned int cpu_daifmt; -+ unsigned int codec_daifmt; -+ unsigned int sysclk; -+}; -+ -+struct asoc_simple_card_info { -+ const char *name; -+ const char *card; -+ const char *cpu_dai; -+ const char *codec; -+ const char *platform; -+ const char *codec_dai; -+ struct asoc_simple_dai_init_info *init; /* for snd_link.init */ -+ -+ /* used in simple-card.c */ -+ struct snd_soc_dai_link snd_link; -+ struct snd_soc_card snd_card; -+}; -+ -+#endif /* __SIMPLE_CARD_H */ ---- a/sound/soc/Kconfig -+++ b/sound/soc/Kconfig -@@ -52,5 +52,8 @@ source "sound/soc/txx9/Kconfig" - # Supported codecs - source "sound/soc/codecs/Kconfig" - -+# generic frame-work -+source "sound/soc/generic/Kconfig" -+ - endif # SND_SOC - ---- a/sound/soc/Makefile -+++ b/sound/soc/Makefile -@@ -7,6 +7,7 @@ endif - - obj-$(CONFIG_SND_SOC) += snd-soc-core.o - obj-$(CONFIG_SND_SOC) += codecs/ -+obj-$(CONFIG_SND_SOC) += generic/ - obj-$(CONFIG_SND_SOC) += atmel/ - obj-$(CONFIG_SND_SOC) += au1x/ - obj-$(CONFIG_SND_SOC) += blackfin/ ---- /dev/null -+++ b/sound/soc/generic/Kconfig -@@ -0,0 +1,4 @@ -+config SND_SIMPLE_CARD -+ tristate "ASoC Simple sound card support" -+ help -+ This option enables generic simple sound card support ---- /dev/null -+++ b/sound/soc/generic/Makefile -@@ -0,0 +1,3 @@ -+snd-soc-simple-card-objs := simple-card.o -+ -+obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o ---- /dev/null -+++ b/sound/soc/generic/simple-card.c -@@ -0,0 +1,114 @@ -+/* -+ * ASoC simple sound card support -+ * -+ * Copyright (C) 2012 Renesas Solutions Corp. -+ * Kuninori Morimoto -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#define asoc_simple_get_card_info(p) \ -+ container_of(p->dai_link, struct asoc_simple_card_info, snd_link) -+ -+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd); -+ struct asoc_simple_dai_init_info *iinfo = cinfo->init; -+ struct snd_soc_dai *codec = rtd->codec_dai; -+ struct snd_soc_dai *cpu = rtd->cpu_dai; -+ unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt; -+ unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt; -+ int ret; -+ -+ if (codec_daifmt) { -+ ret = snd_soc_dai_set_fmt(codec, codec_daifmt); -+ if (ret < 0) -+ return ret; -+ } -+ -+ if (iinfo->sysclk) { -+ ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0); -+ if (ret < 0) -+ return ret; -+ } -+ -+ if (cpu_daifmt) { -+ ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int asoc_simple_card_probe(struct platform_device *pdev) -+{ -+ struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; -+ -+ if (!cinfo) { -+ dev_err(&pdev->dev, "no info for asoc-simple-card\n"); -+ return -EINVAL; -+ } -+ -+ if (!cinfo->name || -+ !cinfo->card || -+ !cinfo->cpu_dai || -+ !cinfo->codec || -+ !cinfo->platform || -+ !cinfo->codec_dai) { -+ dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n"); -+ return -EINVAL; -+ } -+ -+ /* -+ * init snd_soc_dai_link -+ */ -+ cinfo->snd_link.name = cinfo->name; -+ cinfo->snd_link.stream_name = cinfo->name; -+ cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai; -+ cinfo->snd_link.platform_name = cinfo->platform; -+ cinfo->snd_link.codec_name = cinfo->codec; -+ cinfo->snd_link.codec_dai_name = cinfo->codec_dai; -+ -+ /* enable snd_link.init if cinfo has settings */ -+ if (cinfo->init) -+ cinfo->snd_link.init = asoc_simple_card_dai_init; -+ -+ /* -+ * init snd_soc_card -+ */ -+ cinfo->snd_card.name = cinfo->card; -+ cinfo->snd_card.owner = THIS_MODULE; -+ cinfo->snd_card.dai_link = &cinfo->snd_link; -+ cinfo->snd_card.num_links = 1; -+ cinfo->snd_card.dev = &pdev->dev; -+ -+ return snd_soc_register_card(&cinfo->snd_card); -+} -+ -+static int asoc_simple_card_remove(struct platform_device *pdev) -+{ -+ struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; -+ -+ return snd_soc_unregister_card(&cinfo->snd_card); -+} -+ -+static struct platform_driver asoc_simple_card = { -+ .driver = { -+ .name = "asoc-simple-card", -+ }, -+ .probe = asoc_simple_card_probe, -+ .remove = asoc_simple_card_remove, -+}; -+ -+module_platform_driver(asoc_simple_card); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("ASoC Simple Sound Card"); -+MODULE_AUTHOR("Kuninori Morimoto "); diff --git a/patches.armadillo800/0020-ASoC-sh-fsi-use-simple-card-instead-of-fsi-ak4642.patch b/patches.armadillo800/0020-ASoC-sh-fsi-use-simple-card-instead-of-fsi-ak4642.patch deleted file mode 100644 index a6129227a8f3..000000000000 --- a/patches.armadillo800/0020-ASoC-sh-fsi-use-simple-card-instead-of-fsi-ak4642.patch +++ /dev/null @@ -1,358 +0,0 @@ -From 69dbe4e265126dd9dcd679d7f707c73fa86b88ef Mon Sep 17 00:00:00 2001 -From: Kuninori Morimoto -Date: Sun, 8 Apr 2012 21:18:28 -0700 -Subject: ASoC: sh: fsi: use simple-card instead of fsi-ak4642 - -This patch uses simple-card driver instead of fsi-ak4642 on each board. -To select AK4642 driver, each boards select it on Kconfig. - -This patch removes fsi-ak4642 driver which is no longer needed - -Signed-off-by: Kuninori Morimoto -Signed-off-by: Mark Brown -(cherry picked from commit af8a2fe12fae1b59178dc96e396e5665bcbea7da) - -Signed-off-by: Simon Horman ---- - arch/arm/mach-shmobile/Kconfig | 2 + - arch/arm/mach-shmobile/board-ap4evb.c | 15 ++++- - arch/arm/mach-shmobile/board-mackerel.c | 15 ++++- - arch/sh/boards/Kconfig | 1 + - arch/sh/boards/mach-se/7724/setup.c | 15 ++++- - include/sound/sh_fsi.h | 12 ---- - sound/soc/sh/Kconfig | 8 --- - sound/soc/sh/Makefile | 2 - - sound/soc/sh/fsi-ak4642.c | 108 -------------------------------- - 9 files changed, 39 insertions(+), 139 deletions(-) - delete mode 100644 sound/soc/sh/fsi-ak4642.c - -diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig -index 34560ca..2cda0c2 100644 ---- a/arch/arm/mach-shmobile/Kconfig -+++ b/arch/arm/mach-shmobile/Kconfig -@@ -58,6 +58,7 @@ config MACH_AP4EVB - depends on ARCH_SH7372 - select ARCH_REQUIRE_GPIOLIB - select SH_LCD_MIPI_DSI -+ select SND_SOC_AK4642 if SND_SIMPLE_CARD - - choice - prompt "AP4EVB LCD panel selection" -@@ -82,6 +83,7 @@ config MACH_MACKEREL - bool "mackerel board" - depends on ARCH_SH7372 - select ARCH_REQUIRE_GPIOLIB -+ select SND_SOC_AK4642 if SND_SIMPLE_CARD - - config MACH_KOTA2 - bool "KOTA2 board" -diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c -index b56dde2..b397512 100644 ---- a/arch/arm/mach-shmobile/board-ap4evb.c -+++ b/arch/arm/mach-shmobile/board-ap4evb.c -@@ -50,6 +50,7 @@ - #include - - #include -+#include - - #include