diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-03 23:40:28 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-07 22:43:30 -0500 |
commit | af6bcd8205ac06fa1de98b2b28303157fb9c3dfc (patch) | |
tree | 42407e728ed5b3f61dab1c1b338b93d8321930cb /net/bluetooth/l2cap_sock.c | |
parent | 554f05bb8a0707dcc0ba4ea1dba1fb9970846ab5 (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.c | 135 |
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 | ||
65 | static 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; | ||
73 | found: | ||
74 | return sk; | ||
75 | } | ||
76 | |||
77 | static 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 | |||
136 | done: | ||
137 | release_sock(sk); | ||
138 | return err; | ||
139 | } | ||
140 | |||
141 | static 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 | |||
195 | done: | ||
196 | release_sock(sk); | ||
197 | return err; | ||
198 | } | ||
199 | |||
65 | static int l2cap_sock_release(struct socket *sock) | 200 | static int l2cap_sock_release(struct socket *sock) |
66 | { | 201 | { |
67 | struct sock *sk = sock->sk; | 202 | struct sock *sk = sock->sk; |