aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-05-17 23:53:44 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-06-04 23:34:04 -0400
commitbed68bde7ebdb591cc67921261307626c8f37936 (patch)
tree67a920542cc82703bf00fffcca6ab03e69f0dba6 /net/bluetooth/l2cap_core.c
parente1fbd4c19a5c4d4f490d70e73745cf2cf0dc1955 (diff)
Bluetooth: Send SREJ frames when packets go missing
The ERTM specification lays out three scenarios for sending SREJ frames to request retransmission of specific frames. l2cap_send_srej requests all frames up to a given txseq that are not already queued for reassembly. l2cap_send_srej_tail only requests the most recent missing frame. l2cap_send_srej_list resends SREJ frames for data that was requested for resend but never received. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c56
1 files changed, 53 insertions, 3 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 26963a5e3f5..5823697cf9d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2239,17 +2239,67 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
2239 2239
2240static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) 2240static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
2241{ 2241{
2242 /* Placeholder */ 2242 struct l2cap_ctrl control;
2243 u16 seq;
2244
2245 BT_DBG("chan %p, txseq %d", chan, txseq);
2246
2247 memset(&control, 0, sizeof(control));
2248 control.sframe = 1;
2249 control.super = L2CAP_SUPER_SREJ;
2250
2251 for (seq = chan->expected_tx_seq; seq != txseq;
2252 seq = __next_seq(chan, seq)) {
2253 if (!l2cap_ertm_seq_in_queue(&chan->srej_q, seq)) {
2254 control.reqseq = seq;
2255 l2cap_send_sframe(chan, &control);
2256 l2cap_seq_list_append(&chan->srej_list, seq);
2257 }
2258 }
2259
2260 chan->expected_tx_seq = __next_seq(chan, txseq);
2243} 2261}
2244 2262
2245static void l2cap_send_srej_tail(struct l2cap_chan *chan) 2263static void l2cap_send_srej_tail(struct l2cap_chan *chan)
2246{ 2264{
2247 /* Placeholder */ 2265 struct l2cap_ctrl control;
2266
2267 BT_DBG("chan %p", chan);
2268
2269 if (chan->srej_list.tail == L2CAP_SEQ_LIST_CLEAR)
2270 return;
2271
2272 memset(&control, 0, sizeof(control));
2273 control.sframe = 1;
2274 control.super = L2CAP_SUPER_SREJ;
2275 control.reqseq = chan->srej_list.tail;
2276 l2cap_send_sframe(chan, &control);
2248} 2277}
2249 2278
2250static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq) 2279static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq)
2251{ 2280{
2252 /* Placeholder */ 2281 struct l2cap_ctrl control;
2282 u16 initial_head;
2283 u16 seq;
2284
2285 BT_DBG("chan %p, txseq %d", chan, txseq);
2286
2287 memset(&control, 0, sizeof(control));
2288 control.sframe = 1;
2289 control.super = L2CAP_SUPER_SREJ;
2290
2291 /* Capture initial list head to allow only one pass through the list. */
2292 initial_head = chan->srej_list.head;
2293
2294 do {
2295 seq = l2cap_seq_list_pop(&chan->srej_list);
2296 if (seq == txseq || seq == L2CAP_SEQ_LIST_CLEAR)
2297 break;
2298
2299 control.reqseq = seq;
2300 l2cap_send_sframe(chan, &control);
2301 l2cap_seq_list_append(&chan->srej_list, seq);
2302 } while (chan->srej_list.head != initial_head);
2253} 2303}
2254 2304
2255static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) 2305static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq)