summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier Martinez Canillas <javier.martinez@collabora.co.uk>2012-06-20 12:18:56 +0200
committerRob Kendrick (humdrum) <rob.kendrick@codethink.co.uk>2013-06-11 11:02:48 +0100
commit8c8b2044ce0c3928b271b8a3603f81aaafd6f8b4 (patch)
treec3c68e9460d02745e9f6686b0df20ada80c5d94b
parentfd2ba705351f22d26cc0b90f95c013eeb8d17e1e (diff)
downloadlinux-8c8b2044ce0c3928b271b8a3603f81aaafd6f8b4.tar.gz
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 <javier.martinez@collabora.co.uk>
-rw-r--r--include/linux/bus.h34
-rw-r--r--include/net/af_bus.h273
2 files changed, 307 insertions, 0 deletions
diff --git a/include/linux/bus.h b/include/linux/bus.h
new file mode 100644
index 000000000000..19cac36727e1
--- /dev/null
+++ b/include/linux/bus.h
@@ -0,0 +1,34 @@
+#ifndef _LINUX_BUS_H
+#define _LINUX_BUS_H
+
+#include <linux/socket.h>
+
+/* 'protocol' to use in socket(AF_BUS, SOCK_SEQPACKET, protocol) */
+#define BUS_PROTO_NONE 0
+#define BUS_PROTO_DBUS 1
+#define BUS_PROTO_MAX 1
+
+#define BUS_PATH_MAX 108
+
+/**
+ * struct bus_addr - af_bus address
+ * @s_addr: an af_bus address (16-bit prefix + 48-bit client address)
+ */
+struct bus_addr {
+ u64 s_addr;
+};
+
+
+/**
+ * struct sockaddr_bus - af_bus socket address
+ * @sbus_family: the socket address family
+ * @sbus_addr: an af_bus address
+ * @sbus_path: a path name
+ */
+struct sockaddr_bus {
+ __kernel_sa_family_t sbus_family;
+ struct bus_addr sbus_addr;
+ char sbus_path[BUS_PATH_MAX];
+};
+
+#endif /* _LINUX_BUS_H */
diff --git a/include/net/af_bus.h b/include/net/af_bus.h
new file mode 100644
index 000000000000..e63eb49b6afb
--- /dev/null
+++ b/include/net/af_bus.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2012, GENIVI Alliance
+ *
+ * Authors: Javier Martinez Canillas, <javier.martinez@collabora.co.uk>
+ * Alban Crequy, <alban.crequy@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on BSD Unix domain sockets (net/unix).
+ */
+
+#ifndef __LINUX_NET_AFBUS_H
+#define __LINUX_NET_AFBUS_H
+
+#include <linux/socket.h>
+#include <linux/bus.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+
+extern void bus_inflight(struct file *fp);
+extern void bus_notinflight(struct file *fp);
+extern void bus_gc(void);
+extern void wait_for_bus_gc(void);
+extern struct sock *bus_get_socket(struct file *filp);
+extern struct sock *bus_peer_get(struct sock *);
+
+#define BUS_HASH_SIZE 256
+
+extern spinlock_t bus_address_lock;
+extern struct hlist_head bus_address_table[BUS_HASH_SIZE];
+
+#define BUS_MAX_QLEN 10
+#define BUS_MASTER_ADDR 0x0
+#define BUS_PREFIX_BITS 16
+#define BUS_CLIENT_BITS 48
+#define BUS_PREFIX_MASK 0xffff000000000000
+#define BUS_CLIENT_MASK 0x0000ffffffffffff
+
+/* AF_BUS socket options */
+#define BUS_ADD_ADDR 1
+#define BUS_JOIN_BUS 2
+#define BUS_DEL_ADDR 3
+#define BUS_SET_EAVESDROP 4
+#define BUS_UNSET_EAVESDROP 5
+#define BUS_SET_SENDBUF 6
+#define BUS_SET_MAXQLEN 7
+#define BUS_GET_QLENFULL 8
+
+/* Connection and socket states */
+enum {
+ BUS_ESTABLISHED = TCP_ESTABLISHED,
+ BUS_CLOSE = TCP_CLOSE,
+ BUS_LISTEN = TCP_LISTEN,
+ BUS_MAX_STATES
+};
+
+#define NF_BUS_SENDING 1
+
+extern unsigned int bus_tot_inflight;
+extern spinlock_t bus_table_lock;
+extern struct hlist_head bus_socket_table[BUS_HASH_SIZE + 1];
+
+/**
+ * struct bus_address - an af_bus address associated with an af_bus sock
+ * @refcnt: address reference counter
+ * @len: address length
+ * @hash: address hash value
+ * @addr_node: member of struct bus_sock.addr_list
+ * @table_node: member of struct hlist_head bus_address_table[hash]
+ * @sock: the af_bus sock that owns this address
+ * @name: the socket address for this address
+ */
+struct bus_address {
+ atomic_t refcnt;
+ int len;
+ unsigned hash;
+ struct hlist_node addr_node;
+ struct hlist_node table_node;
+ struct sock *sock;
+ struct sockaddr_bus name[0];
+};
+
+/**
+ * struct bus_send_context - sending context for an socket buffer
+ * @sender_socket: the sender socket associated with this sk_buff
+ * @siocb: used to send ancillary data
+ * @timeo: sending timeout
+ * @max_level: file descriptor passing maximum recursion level
+ * @namelen: length of socket address name
+ * @hash: socket name hash value
+ * @other: destination sock
+ * @sender: sender socket address name
+ * @recipient: recipient socket address name
+ * @authenticated: flag whether the sock already joined the bus
+ * @bus_master_side: flag whether the sock is an accepted socket
+ * @to_master: flag whether the destination is the bus master
+ * @multicast: flag whether the destination is a multicast address
+ * @deliver: flag whether the skb has to be delivered
+ * @eavesdropper: flag whether the sock is allowed to eavesdrop
+ * @main_recipient: flag whether the sock is the main recipient
+ */
+struct bus_send_context {
+ struct socket *sender_socket;
+ struct sock_iocb *siocb;
+ long timeo;
+ int max_level;
+ int namelen;
+ unsigned hash;
+ struct sock *other;
+ struct sockaddr_bus *sender;
+ struct sockaddr_bus *recipient;
+ unsigned int authenticated:1;
+ unsigned int bus_master_side:1;
+ unsigned int to_master:1;
+ unsigned int multicast:1;
+ unsigned int deliver:1;
+ unsigned int eavesdropper:1;
+ unsigned int main_recipient:1;
+};
+
+/**
+ * struct bus_skb_parms - socket buffer parameters
+ * @pid: process id
+ * @cred: skb credentials
+ * @fp: passed file descriptors
+ * @secid: security id
+ * @sendctx: skb sending context
+ */
+struct bus_skb_parms {
+ struct pid *pid;
+ const struct cred *cred;
+ struct scm_fp_list *fp;
+#ifdef CONFIG_SECURITY_NETWORK
+ u32 secid;
+#endif
+ struct bus_send_context *sendctx;
+};
+
+#define BUSCB(skb) (*(struct bus_skb_parms *)&((skb)->cb))
+#define BUSSID(skb) (&BUSCB((skb)).secid)
+
+#define bus_state_lock(s) spin_lock(&bus_sk(s)->lock)
+#define bus_state_unlock(s) spin_unlock(&bus_sk(s)->lock)
+#define bus_state_lock_nested(s) \
+ spin_lock_nested(&bus_sk(s)->lock, \
+ SINGLE_DEPTH_NESTING)
+
+/**
+ * struct bus - a communication bus
+ * @master: the bus master sock
+ * @peers: list of struct bus_sock.bus_node allowed to join the bus
+ * @lock: protect peers concurrent access
+ * @send_lock: enforce atomic multicast delivery
+ * @kref: bus reference counter
+ * @addr_cnt: address number counter to assign prefix 0x0000 addresses
+ * @eavesdropper_cnt: eavesdroppers counter
+ */
+struct bus {
+ struct sock *master;
+ struct hlist_head peers;
+ spinlock_t lock;
+ spinlock_t send_lock;
+ struct kref kref;
+ atomic64_t addr_cnt;
+ atomic64_t eavesdropper_cnt;
+};
+
+/**
+ * struct bus_sock - an af_bus socket
+ * @sk: associated sock
+ * @addr: sock principal address
+ * @addr_list: list of struct bus_address.addr_node
+ * @path: sock path name
+ * @readlock: protect from concurrent reading
+ * @peer: peer sock
+ * @other: the listening sock
+ * @link: list of candidates for garbage collection
+ * @inflight: number of times the file descriptor is in flight
+ * @lock: protect the sock from concurrent access
+ * @gc_candidate: flag whether the is a candidate for gc
+ * @gc_maybe_cycle: flag whether could be a cyclic reference
+ * @recursion_level: file passing current recursion level
+ * @peer_wq: peer sock wait queue
+ * @bus: bus that this sock belongs to
+ * @bus_master: flag whether the sock is the bus master
+ * @bus_master_side: flag whether is an accepted socket
+ * @authenticated: flag whether the sock joined the bus
+ * @eavesdropper: flag whether the sock is allowed to eavesdrop
+ * @bus_node: member of struct bus.peers list of joined socks
+ */
+struct bus_sock {
+ /* WARNING: sk has to be the first member */
+ struct sock sk;
+ struct bus_address *addr;
+ struct hlist_head addr_list;
+ struct path path;
+ struct mutex readlock;
+ struct sock *peer;
+ struct sock *other;
+ struct list_head link;
+ atomic_long_t inflight;
+ spinlock_t lock;
+ unsigned int gc_candidate:1;
+ unsigned int gc_maybe_cycle:1;
+ unsigned char recursion_level;
+ struct socket_wq peer_wq;
+ struct bus *bus;
+ bool bus_master;
+ bool bus_master_side;
+ bool authenticated;
+ bool eavesdropper;
+ struct hlist_node bus_node;
+};
+#define bus_sk(__sk) ((struct bus_sock *)__sk)
+
+#define peer_wait peer_wq.wait
+
+/**
+ * bus_same_bus - Test if two socket address belongs to the same bus
+ * @sbusaddr1: socket address name
+ * @sbusaddr2: socket address name
+ */
+static inline bool bus_same_bus(struct sockaddr_bus *sbusaddr1,
+ struct sockaddr_bus *sbusaddr2)
+{
+ int offset;
+
+ if (sbusaddr1->sbus_path[0] != sbusaddr2->sbus_path[0])
+ return false;
+
+ /*
+ * abstract path names start with a null byte character,
+ * so they have to be compared starting at the second char.
+ */
+ offset = (sbusaddr1->sbus_path[0] == '\0');
+
+ return !strncmp(sbusaddr1->sbus_path + offset,
+ sbusaddr2->sbus_path + offset,
+ BUS_PATH_MAX);
+}
+
+static inline unsigned int bus_hash_fold(__wsum n)
+{
+ unsigned int hash = (__force unsigned int)n;
+ hash ^= hash>>16;
+ hash ^= hash>>8;
+ return hash&(BUS_HASH_SIZE-1);
+}
+
+static inline unsigned int bus_compute_hash(struct bus_addr addr)
+{
+ return bus_hash_fold(csum_partial((void *)&addr, sizeof(addr), 0));
+}
+
+long bus_inq_len(struct sock *sk);
+long bus_outq_len(struct sock *sk);
+
+#ifdef CONFIG_SYSCTL
+extern int bus_sysctl_register(struct net *net);
+extern void bus_sysctl_unregister(struct net *net);
+#else
+static inline int bus_sysctl_register(struct net *net) { return 0; }
+static inline void bus_sysctl_unregister(struct net *net) {}
+#endif
+
+bool bus_can_write(struct net *net, struct sockaddr_bus *addr, int len,
+ int protocol);
+
+#endif /* __LINUX_NET_AFBUS_H */