diff options
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 130 |
1 files changed, 119 insertions, 11 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3bb1611b9d4..a4bb27e8427 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | /* Bluetooth L2CAP sockets. */ | 28 | /* Bluetooth L2CAP sockets. */ |
29 | 29 | ||
30 | #include <linux/security.h> | ||
31 | #include <linux/export.h> | 30 | #include <linux/export.h> |
32 | 31 | ||
33 | #include <net/bluetooth/bluetooth.h> | 32 | #include <net/bluetooth/bluetooth.h> |
@@ -89,8 +88,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
89 | if (err < 0) | 88 | if (err < 0) |
90 | goto done; | 89 | goto done; |
91 | 90 | ||
92 | if (__le16_to_cpu(la.l2_psm) == 0x0001 || | 91 | if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP || |
93 | __le16_to_cpu(la.l2_psm) == 0x0003) | 92 | __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM) |
94 | chan->sec_level = BT_SECURITY_SDP; | 93 | chan->sec_level = BT_SECURITY_SDP; |
95 | 94 | ||
96 | bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); | 95 | bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); |
@@ -446,6 +445,22 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch | |||
446 | return err; | 445 | return err; |
447 | } | 446 | } |
448 | 447 | ||
448 | static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu) | ||
449 | { | ||
450 | switch (chan->scid) { | ||
451 | case L2CAP_CID_LE_DATA: | ||
452 | if (mtu < L2CAP_LE_MIN_MTU) | ||
453 | return false; | ||
454 | break; | ||
455 | |||
456 | default: | ||
457 | if (mtu < L2CAP_DEFAULT_MIN_MTU) | ||
458 | return false; | ||
459 | } | ||
460 | |||
461 | return true; | ||
462 | } | ||
463 | |||
449 | static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) | 464 | static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) |
450 | { | 465 | { |
451 | struct sock *sk = sock->sk; | 466 | struct sock *sk = sock->sk; |
@@ -484,6 +499,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us | |||
484 | break; | 499 | break; |
485 | } | 500 | } |
486 | 501 | ||
502 | if (!l2cap_valid_mtu(chan, opts.imtu)) { | ||
503 | err = -EINVAL; | ||
504 | break; | ||
505 | } | ||
506 | |||
487 | chan->mode = opts.mode; | 507 | chan->mode = opts.mode; |
488 | switch (chan->mode) { | 508 | switch (chan->mode) { |
489 | case L2CAP_MODE_BASIC: | 509 | case L2CAP_MODE_BASIC: |
@@ -873,9 +893,34 @@ static int l2cap_sock_release(struct socket *sock) | |||
873 | return err; | 893 | return err; |
874 | } | 894 | } |
875 | 895 | ||
876 | static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) | 896 | static void l2cap_sock_cleanup_listen(struct sock *parent) |
877 | { | 897 | { |
878 | struct sock *sk, *parent = data; | 898 | struct sock *sk; |
899 | |||
900 | BT_DBG("parent %p", parent); | ||
901 | |||
902 | /* Close not yet accepted channels */ | ||
903 | while ((sk = bt_accept_dequeue(parent, NULL))) { | ||
904 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | ||
905 | |||
906 | l2cap_chan_lock(chan); | ||
907 | __clear_chan_timer(chan); | ||
908 | l2cap_chan_close(chan, ECONNRESET); | ||
909 | l2cap_chan_unlock(chan); | ||
910 | |||
911 | l2cap_sock_kill(sk); | ||
912 | } | ||
913 | } | ||
914 | |||
915 | static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) | ||
916 | { | ||
917 | struct sock *sk, *parent = chan->data; | ||
918 | |||
919 | /* Check for backlog size */ | ||
920 | if (sk_acceptq_is_full(parent)) { | ||
921 | BT_DBG("backlog full %d", parent->sk_ack_backlog); | ||
922 | return NULL; | ||
923 | } | ||
879 | 924 | ||
880 | sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, | 925 | sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, |
881 | GFP_ATOMIC); | 926 | GFP_ATOMIC); |
@@ -889,10 +934,10 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) | |||
889 | return l2cap_pi(sk)->chan; | 934 | return l2cap_pi(sk)->chan; |
890 | } | 935 | } |
891 | 936 | ||
892 | static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) | 937 | static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) |
893 | { | 938 | { |
894 | int err; | 939 | int err; |
895 | struct sock *sk = data; | 940 | struct sock *sk = chan->data; |
896 | struct l2cap_pinfo *pi = l2cap_pi(sk); | 941 | struct l2cap_pinfo *pi = l2cap_pi(sk); |
897 | 942 | ||
898 | lock_sock(sk); | 943 | lock_sock(sk); |
@@ -925,16 +970,57 @@ done: | |||
925 | return err; | 970 | return err; |
926 | } | 971 | } |
927 | 972 | ||
928 | static void l2cap_sock_close_cb(void *data) | 973 | static void l2cap_sock_close_cb(struct l2cap_chan *chan) |
929 | { | 974 | { |
930 | struct sock *sk = data; | 975 | struct sock *sk = chan->data; |
931 | 976 | ||
932 | l2cap_sock_kill(sk); | 977 | l2cap_sock_kill(sk); |
933 | } | 978 | } |
934 | 979 | ||
935 | static void l2cap_sock_state_change_cb(void *data, int state) | 980 | static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err) |
936 | { | 981 | { |
937 | struct sock *sk = data; | 982 | struct sock *sk = chan->data; |
983 | struct sock *parent; | ||
984 | |||
985 | lock_sock(sk); | ||
986 | |||
987 | parent = bt_sk(sk)->parent; | ||
988 | |||
989 | sock_set_flag(sk, SOCK_ZAPPED); | ||
990 | |||
991 | switch (chan->state) { | ||
992 | case BT_OPEN: | ||
993 | case BT_BOUND: | ||
994 | case BT_CLOSED: | ||
995 | break; | ||
996 | case BT_LISTEN: | ||
997 | l2cap_sock_cleanup_listen(sk); | ||
998 | sk->sk_state = BT_CLOSED; | ||
999 | chan->state = BT_CLOSED; | ||
1000 | |||
1001 | break; | ||
1002 | default: | ||
1003 | sk->sk_state = BT_CLOSED; | ||
1004 | chan->state = BT_CLOSED; | ||
1005 | |||
1006 | sk->sk_err = err; | ||
1007 | |||
1008 | if (parent) { | ||
1009 | bt_accept_unlink(sk); | ||
1010 | parent->sk_data_ready(parent, 0); | ||
1011 | } else { | ||
1012 | sk->sk_state_change(sk); | ||
1013 | } | ||
1014 | |||
1015 | break; | ||
1016 | } | ||
1017 | |||
1018 | release_sock(sk); | ||
1019 | } | ||
1020 | |||
1021 | static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state) | ||
1022 | { | ||
1023 | struct sock *sk = chan->data; | ||
938 | 1024 | ||
939 | sk->sk_state = state; | 1025 | sk->sk_state = state; |
940 | } | 1026 | } |
@@ -955,12 +1041,34 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, | |||
955 | return skb; | 1041 | return skb; |
956 | } | 1042 | } |
957 | 1043 | ||
1044 | static void l2cap_sock_ready_cb(struct l2cap_chan *chan) | ||
1045 | { | ||
1046 | struct sock *sk = chan->data; | ||
1047 | struct sock *parent; | ||
1048 | |||
1049 | lock_sock(sk); | ||
1050 | |||
1051 | parent = bt_sk(sk)->parent; | ||
1052 | |||
1053 | BT_DBG("sk %p, parent %p", sk, parent); | ||
1054 | |||
1055 | sk->sk_state = BT_CONNECTED; | ||
1056 | sk->sk_state_change(sk); | ||
1057 | |||
1058 | if (parent) | ||
1059 | parent->sk_data_ready(parent, 0); | ||
1060 | |||
1061 | release_sock(sk); | ||
1062 | } | ||
1063 | |||
958 | static struct l2cap_ops l2cap_chan_ops = { | 1064 | static struct l2cap_ops l2cap_chan_ops = { |
959 | .name = "L2CAP Socket Interface", | 1065 | .name = "L2CAP Socket Interface", |
960 | .new_connection = l2cap_sock_new_connection_cb, | 1066 | .new_connection = l2cap_sock_new_connection_cb, |
961 | .recv = l2cap_sock_recv_cb, | 1067 | .recv = l2cap_sock_recv_cb, |
962 | .close = l2cap_sock_close_cb, | 1068 | .close = l2cap_sock_close_cb, |
1069 | .teardown = l2cap_sock_teardown_cb, | ||
963 | .state_change = l2cap_sock_state_change_cb, | 1070 | .state_change = l2cap_sock_state_change_cb, |
1071 | .ready = l2cap_sock_ready_cb, | ||
964 | .alloc_skb = l2cap_sock_alloc_skb_cb, | 1072 | .alloc_skb = l2cap_sock_alloc_skb_cb, |
965 | }; | 1073 | }; |
966 | 1074 | ||