Bluetooth: hidp: handle kernel_sendmsg() errors correctly
authorDavid Herrmann <dh.herrmann@gmail.com>
Sat, 6 Apr 2013 18:28:48 +0000 (20:28 +0200)
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>
Wed, 17 Apr 2013 06:03:59 +0000 (03:03 -0300)
We shouldn't push back the skbs if kernel_sendmsg() fails. Instead, we
terminate the connection and drop the skb. Only on EAGAIN we push it back
and return.
l2cap doesn't return EAGAIN, yet, but this guarantees we're safe if it
will at some time in the future.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
net/bluetooth/hidp/core.c

index 481bbb8c7220a21b495c3684d6edabd4c39a1ee2..3f6ef0630a8e64e5a25b51bdb27f1b97394d6a65 100644 (file)
@@ -639,13 +639,19 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
 static void hidp_process_intr_transmit(struct hidp_session *session)
 {
        struct sk_buff *skb;
+       int ret;
 
        BT_DBG("session %p", session);
 
        while ((skb = skb_dequeue(&session->intr_transmit))) {
-               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
+               ret = hidp_send_frame(session->intr_sock, skb->data, skb->len);
+               if (ret == -EAGAIN) {
                        skb_queue_head(&session->intr_transmit, skb);
                        break;
+               } else if (ret < 0) {
+                       hidp_session_terminate(session);
+                       kfree_skb(skb);
+                       break;
                }
 
                hidp_set_timer(session);
@@ -656,13 +662,19 @@ static void hidp_process_intr_transmit(struct hidp_session *session)
 static void hidp_process_ctrl_transmit(struct hidp_session *session)
 {
        struct sk_buff *skb;
+       int ret;
 
        BT_DBG("session %p", session);
 
        while ((skb = skb_dequeue(&session->ctrl_transmit))) {
-               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
+               ret = hidp_send_frame(session->ctrl_sock, skb->data, skb->len);
+               if (ret == -EAGAIN) {
                        skb_queue_head(&session->ctrl_transmit, skb);
                        break;
+               } else if (ret < 0) {
+                       hidp_session_terminate(session);
+                       kfree_skb(skb);
+                       break;
                }
 
                hidp_set_timer(session);