aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2011-02-03 23:40:28 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-02-07 22:43:30 -0500
commitaf6bcd8205ac06fa1de98b2b28303157fb9c3dfc (patch)
tree42407e728ed5b3f61dab1c1b338b93d8321930cb /net/bluetooth/l2cap_sock.c
parent554f05bb8a0707dcc0ba4ea1dba1fb9970846ab5 (diff)
Bluetooth: move l2cap_sock_bind()/listen() to l2cap_sock.c
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 20efd240a786..ef9a60fda495 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -62,6 +62,141 @@ static void l2cap_sock_timeout(unsigned long arg)
62 sock_put(sk); 62 sock_put(sk);
63} 63}
64 64
65static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
66{
67 struct sock *sk;
68 struct hlist_node *node;
69 sk_for_each(sk, node, &l2cap_sk_list.head)
70 if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
71 goto found;
72 sk = NULL;
73found:
74 return sk;
75}
76
77static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
78{
79 struct sock *sk = sock->sk;
80 struct sockaddr_l2 la;
81 int len, err = 0;
82
83 BT_DBG("sk %p", sk);
84
85 if (!addr || addr->sa_family != AF_BLUETOOTH)
86 return -EINVAL;
87
88 memset(&la, 0, sizeof(la));
89 len = min_t(unsigned int, sizeof(la), alen);
90 memcpy(&la, addr, len);
91
92 if (la.l2_cid)
93 return -EINVAL;
94
95 lock_sock(sk);
96
97 if (sk->sk_state != BT_OPEN) {
98 err = -EBADFD;
99 goto done;
100 }
101
102 if (la.l2_psm) {
103 __u16 psm = __le16_to_cpu(la.l2_psm);
104
105 /* PSM must be odd and lsb of upper byte must be 0 */
106 if ((psm & 0x0101) != 0x0001) {
107 err = -EINVAL;
108 goto done;
109 }
110
111 /* Restrict usage of well-known PSMs */
112 if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
113 err = -EACCES;
114 goto done;
115 }
116 }
117
118 write_lock_bh(&l2cap_sk_list.lock);
119
120 if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
121 err = -EADDRINUSE;
122 } else {
123 /* Save source address */
124 bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
125 l2cap_pi(sk)->psm = la.l2_psm;
126 l2cap_pi(sk)->sport = la.l2_psm;
127 sk->sk_state = BT_BOUND;
128
129 if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
130 __le16_to_cpu(la.l2_psm) == 0x0003)
131 l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
132 }
133
134 write_unlock_bh(&l2cap_sk_list.lock);
135
136done:
137 release_sock(sk);
138 return err;
139}
140
141static int l2cap_sock_listen(struct socket *sock, int backlog)
142{
143 struct sock *sk = sock->sk;
144 int err = 0;
145
146 BT_DBG("sk %p backlog %d", sk, backlog);
147
148 lock_sock(sk);
149
150 if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
151 || sk->sk_state != BT_BOUND) {
152 err = -EBADFD;
153 goto done;
154 }
155
156 switch (l2cap_pi(sk)->mode) {
157 case L2CAP_MODE_BASIC:
158 break;
159 case L2CAP_MODE_ERTM:
160 case L2CAP_MODE_STREAMING:
161 if (!disable_ertm)
162 break;
163 /* fall through */
164 default:
165 err = -ENOTSUPP;
166 goto done;
167 }
168
169 if (!l2cap_pi(sk)->psm) {
170 bdaddr_t *src = &bt_sk(sk)->src;
171 u16 psm;
172
173 err = -EINVAL;
174
175 write_lock_bh(&l2cap_sk_list.lock);
176
177 for (psm = 0x1001; psm < 0x1100; psm += 2)
178 if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
179 l2cap_pi(sk)->psm = cpu_to_le16(psm);
180 l2cap_pi(sk)->sport = cpu_to_le16(psm);
181 err = 0;
182 break;
183 }
184
185 write_unlock_bh(&l2cap_sk_list.lock);
186
187 if (err < 0)
188 goto done;
189 }
190
191 sk->sk_max_ack_backlog = backlog;
192 sk->sk_ack_backlog = 0;
193 sk->sk_state = BT_LISTEN;
194
195done:
196 release_sock(sk);
197 return err;
198}
199
65static int l2cap_sock_release(struct socket *sock) 200static int l2cap_sock_release(struct socket *sock)
66{ 201{
67 struct sock *sk = sock->sk; 202 struct sock *sk = sock->sk;