aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-04-11 13:48:42 -0400
committerGustavo Padovan <gustavo@padovan.org>2012-05-09 00:40:30 -0400
commit3c588192b5e5328cdfc8e299c55477004d397208 (patch)
tree1bedbf322a6b1ded901dc00724e5f8c290098997 /net/bluetooth/l2cap_core.c
parent9033894722ec595053c92bfa4359b37e7bc91b78 (diff)
Bluetooth: Add the l2cap_seq_list structure for tracking frames
A sequence list is a data structure used to track frames that need to be retransmitted, and frames that have been requested for retransmission by the remote device. It can compactly represent a list of sequence numbers within the ERTM transmit window. Memory for the list is allocated once at connection time, and common operations in ERTM are O(1). Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c150
1 files changed, 142 insertions, 8 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 03746f565fc..041ebed9e64 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -232,6 +232,121 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
232 release_sock(sk); 232 release_sock(sk);
233} 233}
234 234
235/* ---- L2CAP sequence number lists ---- */
236
237/* For ERTM, ordered lists of sequence numbers must be tracked for
238 * SREJ requests that are received and for frames that are to be
239 * retransmitted. These seq_list functions implement a singly-linked
240 * list in an array, where membership in the list can also be checked
241 * in constant time. Items can also be added to the tail of the list
242 * and removed from the head in constant time, without further memory
243 * allocs or frees.
244 */
245
246static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size)
247{
248 size_t alloc_size, i;
249
250 /* Allocated size is a power of 2 to map sequence numbers
251 * (which may be up to 14 bits) in to a smaller array that is
252 * sized for the negotiated ERTM transmit windows.
253 */
254 alloc_size = roundup_pow_of_two(size);
255
256 seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL);
257 if (!seq_list->list)
258 return -ENOMEM;
259
260 seq_list->mask = alloc_size - 1;
261 seq_list->head = L2CAP_SEQ_LIST_CLEAR;
262 seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
263 for (i = 0; i < alloc_size; i++)
264 seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR;
265
266 return 0;
267}
268
269static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list)
270{
271 kfree(seq_list->list);
272}
273
274static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list,
275 u16 seq)
276{
277 /* Constant-time check for list membership */
278 return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR;
279}
280
281static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq)
282{
283 u16 mask = seq_list->mask;
284
285 if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) {
286 /* In case someone tries to pop the head of an empty list */
287 return L2CAP_SEQ_LIST_CLEAR;
288 } else if (seq_list->head == seq) {
289 /* Head can be removed in constant time */
290 seq_list->head = seq_list->list[seq & mask];
291 seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
292
293 if (seq_list->head == L2CAP_SEQ_LIST_TAIL) {
294 seq_list->head = L2CAP_SEQ_LIST_CLEAR;
295 seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
296 }
297 } else {
298 /* Walk the list to find the sequence number */
299 u16 prev = seq_list->head;
300 while (seq_list->list[prev & mask] != seq) {
301 prev = seq_list->list[prev & mask];
302 if (prev == L2CAP_SEQ_LIST_TAIL)
303 return L2CAP_SEQ_LIST_CLEAR;
304 }
305
306 /* Unlink the number from the list and clear it */
307 seq_list->list[prev & mask] = seq_list->list[seq & mask];
308 seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
309 if (seq_list->tail == seq)
310 seq_list->tail = prev;
311 }
312 return seq;
313}
314
315static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list)
316{
317 /* Remove the head in constant time */
318 return l2cap_seq_list_remove(seq_list, seq_list->head);
319}
320
321static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list)
322{
323 if (seq_list->head != L2CAP_SEQ_LIST_CLEAR) {
324 u16 i;
325 for (i = 0; i <= seq_list->mask; i++)
326 seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR;
327
328 seq_list->head = L2CAP_SEQ_LIST_CLEAR;
329 seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
330 }
331}
332
333static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq)
334{
335 u16 mask = seq_list->mask;
336
337 /* All appends happen in constant time */
338
339 if (seq_list->list[seq & mask] == L2CAP_SEQ_LIST_CLEAR) {
340 if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR)
341 seq_list->head = seq;
342 else
343 seq_list->list[seq_list->tail & mask] = seq;
344
345 seq_list->tail = seq;
346 seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL;
347 }
348}
349
235static void l2cap_chan_timeout(struct work_struct *work) 350static void l2cap_chan_timeout(struct work_struct *work)
236{ 351{
237 struct l2cap_chan *chan = container_of(work, struct l2cap_chan, 352 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
@@ -414,6 +529,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
414 529
415 skb_queue_purge(&chan->srej_q); 530 skb_queue_purge(&chan->srej_q);
416 531
532 l2cap_seq_list_free(&chan->srej_list);
533 l2cap_seq_list_free(&chan->retrans_list);
417 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { 534 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
418 list_del(&l->list); 535 list_del(&l->list);
419 kfree(l); 536 kfree(l);
@@ -2045,8 +2162,10 @@ static void l2cap_ack_timeout(struct work_struct *work)
2045 l2cap_chan_put(chan); 2162 l2cap_chan_put(chan);
2046} 2163}
2047 2164
2048static inline void l2cap_ertm_init(struct l2cap_chan *chan) 2165static inline int l2cap_ertm_init(struct l2cap_chan *chan)
2049{ 2166{
2167 int err;
2168
2050 chan->expected_ack_seq = 0; 2169 chan->expected_ack_seq = 0;
2051 chan->unacked_frames = 0; 2170 chan->unacked_frames = 0;
2052 chan->buffer_seq = 0; 2171 chan->buffer_seq = 0;
@@ -2060,6 +2179,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
2060 skb_queue_head_init(&chan->srej_q); 2179 skb_queue_head_init(&chan->srej_q);
2061 2180
2062 INIT_LIST_HEAD(&chan->srej_l); 2181 INIT_LIST_HEAD(&chan->srej_l);
2182 err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
2183 if (err < 0)
2184 return err;
2185
2186 return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
2063} 2187}
2064 2188
2065static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) 2189static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2853,7 +2977,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
2853 u16 dcid, flags; 2977 u16 dcid, flags;
2854 u8 rsp[64]; 2978 u8 rsp[64];
2855 struct l2cap_chan *chan; 2979 struct l2cap_chan *chan;
2856 int len; 2980 int len, err = 0;
2857 2981
2858 dcid = __le16_to_cpu(req->dcid); 2982 dcid = __le16_to_cpu(req->dcid);
2859 flags = __le16_to_cpu(req->flags); 2983 flags = __le16_to_cpu(req->flags);
@@ -2924,9 +3048,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
2924 chan->expected_tx_seq = 0; 3048 chan->expected_tx_seq = 0;
2925 skb_queue_head_init(&chan->tx_q); 3049 skb_queue_head_init(&chan->tx_q);
2926 if (chan->mode == L2CAP_MODE_ERTM) 3050 if (chan->mode == L2CAP_MODE_ERTM)
2927 l2cap_ertm_init(chan); 3051 err = l2cap_ertm_init(chan);
3052
3053 if (err < 0)
3054 l2cap_send_disconn_req(chan->conn, chan, -err);
3055 else
3056 l2cap_chan_ready(chan);
2928 3057
2929 l2cap_chan_ready(chan);
2930 goto unlock; 3058 goto unlock;
2931 } 3059 }
2932 3060
@@ -2954,7 +3082,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
2954 3082
2955unlock: 3083unlock:
2956 l2cap_chan_unlock(chan); 3084 l2cap_chan_unlock(chan);
2957 return 0; 3085 return err;
2958} 3086}
2959 3087
2960static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 3088static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
@@ -2963,6 +3091,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
2963 u16 scid, flags, result; 3091 u16 scid, flags, result;
2964 struct l2cap_chan *chan; 3092 struct l2cap_chan *chan;
2965 int len = le16_to_cpu(cmd->len) - sizeof(*rsp); 3093 int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
3094 int err = 0;
2966 3095
2967 scid = __le16_to_cpu(rsp->scid); 3096 scid = __le16_to_cpu(rsp->scid);
2968 flags = __le16_to_cpu(rsp->flags); 3097 flags = __le16_to_cpu(rsp->flags);
@@ -3054,14 +3183,17 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
3054 chan->expected_tx_seq = 0; 3183 chan->expected_tx_seq = 0;
3055 skb_queue_head_init(&chan->tx_q); 3184 skb_queue_head_init(&chan->tx_q);
3056 if (chan->mode == L2CAP_MODE_ERTM) 3185 if (chan->mode == L2CAP_MODE_ERTM)
3057 l2cap_ertm_init(chan); 3186 err = l2cap_ertm_init(chan);
3058 3187
3059 l2cap_chan_ready(chan); 3188 if (err < 0)
3189 l2cap_send_disconn_req(chan->conn, chan, -err);
3190 else
3191 l2cap_chan_ready(chan);
3060 } 3192 }
3061 3193
3062done: 3194done:
3063 l2cap_chan_unlock(chan); 3195 l2cap_chan_unlock(chan);
3064 return 0; 3196 return err;
3065} 3197}
3066 3198
3067static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 3199static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
@@ -3805,6 +3937,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
3805 BT_DBG("chan %p, Enter local busy", chan); 3937 BT_DBG("chan %p, Enter local busy", chan);
3806 3938
3807 set_bit(CONN_LOCAL_BUSY, &chan->conn_state); 3939 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3940 l2cap_seq_list_clear(&chan->srej_list);
3808 3941
3809 __set_ack_timer(chan); 3942 __set_ack_timer(chan);
3810} 3943}
@@ -3897,6 +4030,7 @@ static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
3897 while (tx_seq != chan->expected_tx_seq) { 4030 while (tx_seq != chan->expected_tx_seq) {
3898 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); 4031 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
3899 control |= __set_reqseq(chan, chan->expected_tx_seq); 4032 control |= __set_reqseq(chan, chan->expected_tx_seq);
4033 l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq);
3900 l2cap_send_sframe(chan, control); 4034 l2cap_send_sframe(chan, control);
3901 4035
3902 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); 4036 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);