]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/bluetooth/l2cap_sock.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/blueto...
[karo-tx-linux.git] / net / bluetooth / l2cap_sock.c
index 9ed6501d90f64d457d9ce000c6842dcb7eb64bc0..f73704321a77d0eaf74b3570da554855405a0358 100644 (file)
@@ -26,6 +26,9 @@
 
 /* Bluetooth L2CAP sockets. */
 
+#include <linux/security.h>
+#include <linux/export.h>
+
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
@@ -467,6 +470,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
                break;
 
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (put_user(chan->chan_policy, (u32 __user *) optval))
+                       err = -EFAULT;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -613,8 +626,13 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
                chan->sec_level = sec.level;
 
+               if (!chan->conn)
+                       break;
+
                conn = chan->conn;
-               if (conn && chan->scid == L2CAP_CID_LE_DATA) {
+
+               /*change security for LE channels */
+               if (chan->scid == L2CAP_CID_LE_DATA) {
                        if (!conn->hcon->out) {
                                err = -EINVAL;
                                break;
@@ -622,9 +640,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
                        if (smp_conn_security(conn, sec.level))
                                break;
-
-                       err = 0;
                        sk->sk_state = BT_CONFIG;
+
+               /* or for ACL link, under defer_setup time */
+               } else if (sk->sk_state == BT_CONNECT2 &&
+                                       bt_sk(sk)->defer_setup) {
+                       err = l2cap_chan_check_security(chan);
+               } else {
+                       err = -EINVAL;
                }
                break;
 
@@ -690,6 +713,31 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
                break;
 
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (chan->mode != L2CAP_MODE_ERTM &&
+                               chan->mode != L2CAP_MODE_STREAMING) {
+                       err = -EOPNOTSUPP;
+                       break;
+               }
+
+               chan->chan_policy = (u8) opt;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -946,6 +994,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->tx_win_max = pchan->tx_win_max;
                chan->sec_level = pchan->sec_level;
                chan->flags = pchan->flags;
+
+               security_sk_clone(parent, sk);
        } else {
 
                switch (sk->sk_type) {