Skip to content

Commit 81be03e

Browse files
Vudentzholtmann
authored andcommitted
Bluetooth: RFCOMM: Replace use of memcpy_from_msg with bt_skb_sendmmsg
This makes use of bt_skb_sendmmsg instead using memcpy_from_msg which is not considered safe to be used when lock_sock is held. Also make rfcomm_dlc_send handle skb with fragments and queue them all atomically. Signed-off-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 0771cbb commit 81be03e

File tree

2 files changed

+53
-43
lines changed

2 files changed

+53
-43
lines changed

net/bluetooth/rfcomm/core.c

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -549,22 +549,58 @@ struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel)
549549
return dlc;
550550
}
551551

552+
static int rfcomm_dlc_send_frag(struct rfcomm_dlc *d, struct sk_buff *frag)
553+
{
554+
int len = frag->len;
555+
556+
BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
557+
558+
if (len > d->mtu)
559+
return -EINVAL;
560+
561+
rfcomm_make_uih(frag, d->addr);
562+
__skb_queue_tail(&d->tx_queue, frag);
563+
564+
return len;
565+
}
566+
552567
int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
553568
{
554-
int len = skb->len;
569+
unsigned long flags;
570+
struct sk_buff *frag, *next;
571+
int len;
555572

556573
if (d->state != BT_CONNECTED)
557574
return -ENOTCONN;
558575

559-
BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
576+
frag = skb_shinfo(skb)->frag_list;
577+
skb_shinfo(skb)->frag_list = NULL;
560578

561-
if (len > d->mtu)
562-
return -EINVAL;
579+
/* Queue all fragments atomically. */
580+
spin_lock_irqsave(&d->tx_queue.lock, flags);
563581

564-
rfcomm_make_uih(skb, d->addr);
565-
skb_queue_tail(&d->tx_queue, skb);
582+
len = rfcomm_dlc_send_frag(d, skb);
583+
if (len < 0 || !frag)
584+
goto unlock;
585+
586+
for (; frag; frag = next) {
587+
int ret;
588+
589+
next = frag->next;
590+
591+
ret = rfcomm_dlc_send_frag(d, frag);
592+
if (ret < 0) {
593+
kfree_skb(frag);
594+
goto unlock;
595+
}
596+
597+
len += ret;
598+
}
599+
600+
unlock:
601+
spin_unlock_irqrestore(&d->tx_queue.lock, flags);
566602

567-
if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
603+
if (len > 0 && !test_bit(RFCOMM_TX_THROTTLED, &d->flags))
568604
rfcomm_schedule();
569605
return len;
570606
}

net/bluetooth/rfcomm/sock.c

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -575,46 +575,20 @@ static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg,
575575
lock_sock(sk);
576576

577577
sent = bt_sock_wait_ready(sk, msg->msg_flags);
578-
if (sent)
579-
goto done;
580-
581-
while (len) {
582-
size_t size = min_t(size_t, len, d->mtu);
583-
int err;
584-
585-
skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
586-
msg->msg_flags & MSG_DONTWAIT, &err);
587-
if (!skb) {
588-
if (sent == 0)
589-
sent = err;
590-
break;
591-
}
592-
skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
593-
594-
err = memcpy_from_msg(skb_put(skb, size), msg, size);
595-
if (err) {
596-
kfree_skb(skb);
597-
if (sent == 0)
598-
sent = err;
599-
break;
600-
}
601578

602-
skb->priority = sk->sk_priority;
579+
release_sock(sk);
603580

604-
err = rfcomm_dlc_send(d, skb);
605-
if (err < 0) {
606-
kfree_skb(skb);
607-
if (sent == 0)
608-
sent = err;
609-
break;
610-
}
581+
if (sent)
582+
return sent;
611583

612-
sent += size;
613-
len -= size;
614-
}
584+
skb = bt_skb_sendmmsg(sk, msg, len, d->mtu, RFCOMM_SKB_HEAD_RESERVE,
585+
RFCOMM_SKB_TAIL_RESERVE);
586+
if (IS_ERR_OR_NULL(skb))
587+
return PTR_ERR(skb);
615588

616-
done:
617-
release_sock(sk);
589+
sent = rfcomm_dlc_send(d, skb);
590+
if (sent < 0)
591+
kfree_skb(skb);
618592

619593
return sent;
620594
}

0 commit comments

Comments
 (0)