Commit 9363d05d authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Update socket option handling

This patch unifies the socket option handling across the L2CAP,
SCO and RFCOMM socket layers.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 133ffc83
...@@ -38,17 +38,19 @@ struct sockaddr_l2 { ...@@ -38,17 +38,19 @@ struct sockaddr_l2 {
bdaddr_t l2_bdaddr; bdaddr_t l2_bdaddr;
}; };
/* Socket options */ /* L2CAP socket options */
#define L2CAP_OPTIONS 0x01 #define L2CAP_OPTIONS 0x01
struct l2cap_options { struct l2cap_options {
__u16 omtu; __u16 omtu;
__u16 imtu; __u16 imtu;
__u16 flush_to; __u16 flush_to;
__u8 mode;
}; };
#define L2CAP_CONNINFO 0x02 #define L2CAP_CONNINFO 0x02
struct l2cap_conninfo { struct l2cap_conninfo {
__u16 hci_handle; __u16 hci_handle;
__u8 dev_class[3];
}; };
#define L2CAP_LM 0x03 #define L2CAP_LM 0x03
...@@ -59,20 +61,6 @@ struct l2cap_conninfo { ...@@ -59,20 +61,6 @@ struct l2cap_conninfo {
#define L2CAP_LM_RELIABLE 0x0010 #define L2CAP_LM_RELIABLE 0x0010
#define L2CAP_LM_SECURE 0x0020 #define L2CAP_LM_SECURE 0x0020
#define L2CAP_QOS 0x04
struct l2cap_qos {
__u16 service_type;
__u32 token_rate;
__u32 token_bucket_size;
__u32 peak_bandwidth;
__u32 latency;
__u32 delay_variation;
};
#define L2CAP_SERV_NO_TRAFFIC 0x00
#define L2CAP_SERV_BEST_EFFORT 0x01
#define L2CAP_SERV_GUARANTEED 0x02
/* L2CAP command codes */ /* L2CAP command codes */
#define L2CAP_COMMAND_REJ 0x01 #define L2CAP_COMMAND_REJ 0x01
#define L2CAP_CONN_REQ 0x02 #define L2CAP_CONN_REQ 0x02
...@@ -154,6 +142,7 @@ struct l2cap_conf_opt { ...@@ -154,6 +142,7 @@ struct l2cap_conf_opt {
#define L2CAP_CONF_MTU 0x01 #define L2CAP_CONF_MTU 0x01
#define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_FLUSH_TO 0x02
#define L2CAP_CONF_QOS 0x03 #define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_MAX_SIZE 22 #define L2CAP_CONF_MAX_SIZE 22
...@@ -198,11 +187,11 @@ struct l2cap_conn { ...@@ -198,11 +187,11 @@ struct l2cap_conn {
bdaddr_t *dst; bdaddr_t *dst;
bdaddr_t *src; bdaddr_t *src;
unsigned int mtu; unsigned int mtu;
spinlock_t lock; spinlock_t lock;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
__u32 rx_len; __u32 rx_len;
__u8 rx_ident; __u8 rx_ident;
...@@ -222,7 +211,7 @@ struct l2cap_pinfo { ...@@ -222,7 +211,7 @@ struct l2cap_pinfo {
__u16 imtu; __u16 imtu;
__u16 omtu; __u16 omtu;
__u16 flush_to; __u16 flush_to;
__u32 link_mode; __u32 link_mode;
__u8 conf_state; __u8 conf_state;
......
...@@ -181,6 +181,8 @@ struct rfcomm_dlc { ...@@ -181,6 +181,8 @@ struct rfcomm_dlc {
u8 v24_sig; u8 v24_sig;
u8 mscex; u8 mscex;
u32 link_mode;
uint mtu; uint mtu;
uint cfc; uint cfc;
uint rx_credits; uint rx_credits;
...@@ -267,16 +269,31 @@ extern u8 rfcomm_crc_table[]; ...@@ -267,16 +269,31 @@ extern u8 rfcomm_crc_table[];
/* ---- RFCOMM sockets ---- */ /* ---- RFCOMM sockets ---- */
struct sockaddr_rc { struct sockaddr_rc {
sa_family_t rc_family; sa_family_t rc_family;
bdaddr_t rc_bdaddr; bdaddr_t rc_bdaddr;
u8 rc_channel; u8 rc_channel;
};
#define RFCOMM_CONNINFO 0x02
struct rfcomm_conninfo {
__u16 hci_handle;
__u8 dev_class[3];
}; };
#define RFCOMM_LM 0x03
#define RFCOMM_LM_MASTER 0x0001
#define RFCOMM_LM_AUTH 0x0002
#define RFCOMM_LM_ENCRYPT 0x0004
#define RFCOMM_LM_TRUSTED 0x0008
#define RFCOMM_LM_RELIABLE 0x0010
#define RFCOMM_LM_SECURE 0x0020
#define rfcomm_pi(sk) ((struct rfcomm_pinfo *)sk->sk_protinfo) #define rfcomm_pi(sk) ((struct rfcomm_pinfo *)sk->sk_protinfo)
struct rfcomm_pinfo { struct rfcomm_pinfo {
struct rfcomm_dlc *dlc; struct rfcomm_dlc *dlc;
u8 channel; u8 channel;
u32 link_mode;
}; };
int rfcomm_init_sockets(void); int rfcomm_init_sockets(void);
......
...@@ -39,15 +39,16 @@ struct sockaddr_sco { ...@@ -39,15 +39,16 @@ struct sockaddr_sco {
bdaddr_t sco_bdaddr; bdaddr_t sco_bdaddr;
}; };
/* set/get sockopt defines */ /* SCO socket options */
#define SCO_OPTIONS 0x01 #define SCO_OPTIONS 0x01
struct sco_options { struct sco_options {
__u16 mtu; __u16 mtu;
}; };
#define SCO_CONNINFO 0x02 #define SCO_CONNINFO 0x02
struct sco_conninfo { struct sco_conninfo {
__u16 hci_handle; __u16 hci_handle;
__u8 dev_class[3];
}; };
/* ---- SCO connections ---- */ /* ---- SCO connections ---- */
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "2.6" #define VERSION "2.7"
static struct proto_ops l2cap_sock_ops; static struct proto_ops l2cap_sock_ops;
...@@ -798,7 +798,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch ...@@ -798,7 +798,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
switch (optname) { switch (optname) {
case L2CAP_OPTIONS: case L2CAP_OPTIONS:
len = min_t(unsigned int, sizeof(opts), optlen); len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *)&opts, optval, len)) { if (copy_from_user((char *) &opts, optval, len)) {
err = -EFAULT; err = -EFAULT;
break; break;
} }
...@@ -807,7 +807,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch ...@@ -807,7 +807,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
break; break;
case L2CAP_LM: case L2CAP_LM:
if (get_user(opt, (u32 __user *)optval)) { if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT; err = -EFAULT;
break; break;
} }
...@@ -829,7 +829,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -829,7 +829,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct l2cap_options opts; struct l2cap_options opts;
struct l2cap_conninfo cinfo; struct l2cap_conninfo cinfo;
int len, err = 0; int len, err = 0;
BT_DBG("sk %p", sk);
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; return -EFAULT;
...@@ -841,15 +843,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -841,15 +843,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
opts.imtu = l2cap_pi(sk)->imtu; opts.imtu = l2cap_pi(sk)->imtu;
opts.omtu = l2cap_pi(sk)->omtu; opts.omtu = l2cap_pi(sk)->omtu;
opts.flush_to = l2cap_pi(sk)->flush_to; opts.flush_to = l2cap_pi(sk)->flush_to;
opts.mode = 0x00;
len = min_t(unsigned int, len, sizeof(opts)); len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *)&opts, len)) if (copy_to_user(optval, (char *) &opts, len))
err = -EFAULT; err = -EFAULT;
break; break;
case L2CAP_LM: case L2CAP_LM:
if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *)optval)) if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *) optval))
err = -EFAULT; err = -EFAULT;
break; break;
...@@ -860,9 +863,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -860,9 +863,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
} }
cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo)); len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *)&cinfo, len)) if (copy_to_user(optval, (char *) &cinfo, len))
err = -EFAULT; err = -EFAULT;
break; break;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/rfcomm.h>
#define VERSION "1.3" #define VERSION "1.4"
#ifndef CONFIG_BT_RFCOMM_DEBUG #ifndef CONFIG_BT_RFCOMM_DEBUG
#undef BT_DBG #undef BT_DBG
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG #ifndef CONFIG_BT_RFCOMM_DEBUG
...@@ -261,10 +263,18 @@ static void rfcomm_sock_close(struct sock *sk) ...@@ -261,10 +263,18 @@ static void rfcomm_sock_close(struct sock *sk)
static void rfcomm_sock_init(struct sock *sk, struct sock *parent) static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
{ {
struct rfcomm_pinfo *pi = rfcomm_pi(sk);
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
if (parent) if (parent) {
sk->sk_type = parent->sk_type; sk->sk_type = parent->sk_type;
pi->link_mode = rfcomm_pi(parent)->link_mode;
} else {
pi->link_mode = 0;
}
pi->dlc->link_mode = pi->link_mode;
} }
static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio) static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
...@@ -671,12 +681,22 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c ...@@ -671,12 +681,22 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
u32 opt;
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
lock_sock(sk); lock_sock(sk);
switch (optname) { switch (optname) {
case RFCOMM_LM:
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
rfcomm_pi(sk)->link_mode = opt;
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
...@@ -689,7 +709,9 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c ...@@ -689,7 +709,9 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int len, err = 0; struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
int len, err = 0;
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
...@@ -699,10 +721,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c ...@@ -699,10 +721,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
lock_sock(sk); lock_sock(sk);
switch (optname) { switch (optname) {
case RFCOMM_LM:
if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
err = -EFAULT;
break;
case RFCOMM_CONNINFO:
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
break;
}
l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len))
err = -EFAULT;
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
}; }
release_sock(sk); release_sock(sk);
return err; return err;
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "0.3" #define VERSION "0.4"
static struct proto_ops sco_sock_ops; static struct proto_ops sco_sock_ops;
...@@ -705,6 +705,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char ...@@ -705,6 +705,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
} }
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo)); len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *)&cinfo, len)) if (copy_to_user(optval, (char *)&cinfo, len))
...@@ -1045,7 +1046,7 @@ static void __exit sco_exit(void) ...@@ -1045,7 +1046,7 @@ static void __exit sco_exit(void)
module_init(sco_init); module_init(sco_init);
module_exit(sco_exit); module_exit(sco_exit);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment