diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-05-01 15:15:37 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-05-10 03:28:47 -0400 |
commit | 9e917af13d59182f95bbb5483dc0c4254dfb7944 (patch) | |
tree | 03f3fffbce196c30e7ae456b838f5cefcb2a681f /net/bluetooth/l2cap.c | |
parent | 36f2fd585f43199f006a3b5ff84e95815102cd31 (diff) |
Bluetooth: Implement SendAck() Action on ERTM.
Shall be used to ack received frames, It must decide type of
acknowledgment between a RR frame, a RNR frame or transmission of
pending I-frames.
It also modifies l2cap_ertm_send() to report the number of frames sent.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2e354d29f102..0a739ef167c2 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -352,6 +352,11 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) | |||
352 | count = min_t(unsigned int, conn->mtu, hlen); | 352 | count = min_t(unsigned int, conn->mtu, hlen); |
353 | control |= L2CAP_CTRL_FRAME_TYPE; | 353 | control |= L2CAP_CTRL_FRAME_TYPE; |
354 | 354 | ||
355 | if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { | ||
356 | control |= L2CAP_CTRL_FINAL; | ||
357 | pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; | ||
358 | } | ||
359 | |||
355 | skb = bt_skb_alloc(count, GFP_ATOMIC); | 360 | skb = bt_skb_alloc(count, GFP_ATOMIC); |
356 | if (!skb) | 361 | if (!skb) |
357 | return -ENOMEM; | 362 | return -ENOMEM; |
@@ -1364,7 +1369,7 @@ static int l2cap_ertm_send(struct sock *sk) | |||
1364 | struct sk_buff *skb, *tx_skb; | 1369 | struct sk_buff *skb, *tx_skb; |
1365 | struct l2cap_pinfo *pi = l2cap_pi(sk); | 1370 | struct l2cap_pinfo *pi = l2cap_pi(sk); |
1366 | u16 control, fcs; | 1371 | u16 control, fcs; |
1367 | int err; | 1372 | int err, nsent = 0; |
1368 | 1373 | ||
1369 | if (pi->conn_state & L2CAP_CONN_WAIT_F) | 1374 | if (pi->conn_state & L2CAP_CONN_WAIT_F) |
1370 | return 0; | 1375 | return 0; |
@@ -1414,8 +1419,27 @@ static int l2cap_ertm_send(struct sock *sk) | |||
1414 | sk->sk_send_head = NULL; | 1419 | sk->sk_send_head = NULL; |
1415 | else | 1420 | else |
1416 | sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); | 1421 | sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); |
1422 | |||
1423 | nsent++; | ||
1417 | } | 1424 | } |
1418 | 1425 | ||
1426 | return nsent; | ||
1427 | } | ||
1428 | |||
1429 | static int l2cap_send_ack(struct l2cap_pinfo *pi) | ||
1430 | { | ||
1431 | struct sock *sk = (struct sock *)pi; | ||
1432 | u16 control = 0; | ||
1433 | |||
1434 | control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
1435 | |||
1436 | if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { | ||
1437 | control |= L2CAP_SUPER_RCV_NOT_READY; | ||
1438 | return l2cap_send_sframe(pi, control); | ||
1439 | } else if (l2cap_ertm_send(sk) == 0) { | ||
1440 | control |= L2CAP_SUPER_RCV_READY; | ||
1441 | return l2cap_send_sframe(pi, control); | ||
1442 | } | ||
1419 | return 0; | 1443 | return 0; |
1420 | } | 1444 | } |
1421 | 1445 | ||
@@ -1678,7 +1702,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms | |||
1678 | else | 1702 | else |
1679 | err = l2cap_ertm_send(sk); | 1703 | err = l2cap_ertm_send(sk); |
1680 | 1704 | ||
1681 | if (!err) | 1705 | if (err >= 0) |
1682 | err = len; | 1706 | err = len; |
1683 | break; | 1707 | break; |
1684 | 1708 | ||
@@ -3178,10 +3202,6 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) | |||
3178 | if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && | 3202 | if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && |
3179 | pi->frames_sent == 0) { | 3203 | pi->frames_sent == 0) { |
3180 | control |= L2CAP_SUPER_RCV_READY; | 3204 | control |= L2CAP_SUPER_RCV_READY; |
3181 | if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { | ||
3182 | control |= L2CAP_CTRL_FINAL; | ||
3183 | pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; | ||
3184 | } | ||
3185 | l2cap_send_sframe(pi, control); | 3205 | l2cap_send_sframe(pi, control); |
3186 | } | 3206 | } |
3187 | } | 3207 | } |
@@ -3362,7 +3382,6 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str | |||
3362 | struct l2cap_pinfo *pi = l2cap_pi(sk); | 3382 | struct l2cap_pinfo *pi = l2cap_pi(sk); |
3363 | u8 tx_seq = __get_txseq(rx_control); | 3383 | u8 tx_seq = __get_txseq(rx_control); |
3364 | u8 req_seq = __get_reqseq(rx_control); | 3384 | u8 req_seq = __get_reqseq(rx_control); |
3365 | u16 tx_control = 0; | ||
3366 | u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; | 3385 | u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; |
3367 | int err = 0; | 3386 | int err = 0; |
3368 | 3387 | ||
@@ -3449,11 +3468,9 @@ expected: | |||
3449 | return err; | 3468 | return err; |
3450 | 3469 | ||
3451 | pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; | 3470 | pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; |
3452 | if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { | 3471 | if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) |
3453 | tx_control |= L2CAP_SUPER_RCV_READY; | 3472 | l2cap_send_ack(pi); |
3454 | tx_control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; | 3473 | |
3455 | l2cap_send_sframe(pi, tx_control); | ||
3456 | } | ||
3457 | return 0; | 3474 | return 0; |
3458 | } | 3475 | } |
3459 | 3476 | ||