From: Jukka Rissanen <jukka.rissanen@linux.intel.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH v3 1/6] Bluetooth: Refactor l2cap_sock_sendmsg() to copy user buffer
Date: Wed, 28 May 2014 14:43:03 +0300 [thread overview]
Message-ID: <1401277388-4611-2-git-send-email-jukka.rissanen@linux.intel.com> (raw)
In-Reply-To: <1401277388-4611-1-git-send-email-jukka.rissanen@linux.intel.com>
The l2cap_chan_send() is changed to use kernel memory directly,
so this function must read the user buffer before sending the
message.
The change is done as the 6LoWPAN also uses l2cap_chan_send()
and in order to minimize the amount of code changes, we must
copy the user buffer in sock handling code.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
include/net/bluetooth/l2cap.h | 4 +--
net/bluetooth/a2mp.c | 12 +------
net/bluetooth/l2cap_core.c | 81 ++++++++++++++++++++++++-------------------
net/bluetooth/l2cap_sock.c | 14 +++++++-
4 files changed, 61 insertions(+), 50 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 4abdcb2..d9506e0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -872,8 +872,8 @@ struct l2cap_chan *l2cap_chan_create(void);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
bdaddr_t *dst, u8 dst_type);
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
- u32 priority);
+int l2cap_chan_send(struct l2cap_chan *chan, void *buf, size_t len,
+ u32 priority, unsigned int flags);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
int l2cap_chan_check_security(struct l2cap_chan *chan);
void l2cap_chan_set_defaults(struct l2cap_chan *chan);
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 9514cc9..6b99b1b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -48,22 +48,12 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
struct l2cap_chan *chan = mgr->a2mp_chan;
struct a2mp_cmd *cmd;
u16 total_len = len + sizeof(*cmd);
- struct kvec iv;
- struct msghdr msg;
cmd = __a2mp_build(code, ident, len, data);
if (!cmd)
return;
- iv.iov_base = cmd;
- iv.iov_len = total_len;
-
- memset(&msg, 0, sizeof(msg));
-
- msg.msg_iov = (struct iovec *) &iv;
- msg.msg_iovlen = 1;
-
- l2cap_chan_send(chan, &msg, total_len, 0);
+ l2cap_chan_send(chan, cmd, total_len, 0, 0);
kfree(cmd);
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a1e5bb7..bb41d9b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2098,19 +2098,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
}
}
-static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
- struct msghdr *msg, int len,
- int count, struct sk_buff *skb)
+static inline int l2cap_from_skbuff(struct l2cap_chan *chan,
+ void *buf, int len,
+ unsigned int flags, int count,
+ struct sk_buff *skb)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff **frag;
int sent = 0;
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
- return -EFAULT;
+ memcpy(skb_put(skb, count), buf, count);
sent += count;
len -= count;
+ buf += count;
/* Continuation fragments (no L2CAP header) */
frag = &skb_shinfo(skb)->frag_list;
@@ -2120,19 +2121,19 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
count = min_t(unsigned int, conn->mtu, len);
tmp = chan->ops->alloc_skb(chan, count,
- msg->msg_flags & MSG_DONTWAIT);
+ flags & MSG_DONTWAIT);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
*frag = tmp;
- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
- return -EFAULT;
+ memcpy(skb_put(*frag, count), buf, count);
(*frag)->priority = skb->priority;
sent += count;
len -= count;
+ buf += count;
skb->len += (*frag)->len;
skb->data_len += (*frag)->len;
@@ -2144,8 +2145,9 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
}
static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 priority)
+ void *buf, size_t len,
+ u32 priority,
+ unsigned int flags)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
@@ -2158,7 +2160,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT);
+ flags & MSG_DONTWAIT);
if (IS_ERR(skb))
return skb;
@@ -2170,7 +2172,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE);
put_unaligned(chan->psm, (__le16 *) skb_put(skb, L2CAP_PSMLEN_SIZE));
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
+ err = l2cap_from_skbuff(chan, buf, len, flags, count, skb);
if (unlikely(err < 0)) {
kfree_skb(skb);
return ERR_PTR(err);
@@ -2179,8 +2181,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
}
static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u32 priority)
+ void *buf, size_t len,
+ u32 priority, unsigned int flags)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
@@ -2192,7 +2194,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE,
- msg->msg_flags & MSG_DONTWAIT);
+ flags & MSG_DONTWAIT);
if (IS_ERR(skb))
return skb;
@@ -2203,7 +2205,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
lh->cid = cpu_to_le16(chan->dcid);
lh->len = cpu_to_le16(len);
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
+ err = l2cap_from_skbuff(chan, buf, len, flags, count, skb);
if (unlikely(err < 0)) {
kfree_skb(skb);
return ERR_PTR(err);
@@ -2212,8 +2214,8 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
}
static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
- struct msghdr *msg, size_t len,
- u16 sdulen)
+ void *buf, size_t len,
+ u16 sdulen, unsigned int flags)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
@@ -2236,7 +2238,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT);
+ flags & MSG_DONTWAIT);
if (IS_ERR(skb))
return skb;
@@ -2254,7 +2256,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
if (sdulen)
put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
+ err = l2cap_from_skbuff(chan, buf, len, flags, count, skb);
if (unlikely(err < 0)) {
kfree_skb(skb);
return ERR_PTR(err);
@@ -2267,14 +2269,15 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
static int l2cap_segment_sdu(struct l2cap_chan *chan,
struct sk_buff_head *seg_queue,
- struct msghdr *msg, size_t len)
+ void *buf, size_t len,
+ unsigned int flags)
{
struct sk_buff *skb;
u16 sdu_len;
size_t pdu_len;
u8 sar;
- BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
+ BT_DBG("chan %p, buf %p, len %zu", chan, buf, len);
/* It is critical that ERTM PDUs fit in a single HCI fragment,
* so fragmented skbs are not used. The HCI layer's handling
@@ -2308,7 +2311,8 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
}
while (len > 0) {
- skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len);
+ skb = l2cap_create_iframe_pdu(chan, buf, pdu_len, sdu_len,
+ flags);
if (IS_ERR(skb)) {
__skb_queue_purge(seg_queue);
@@ -2336,8 +2340,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
}
static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
- struct msghdr *msg,
- size_t len, u16 sdulen)
+ void *buf, size_t len,
+ u16 sdulen,
+ unsigned int flags)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
@@ -2357,7 +2362,7 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT);
+ flags & MSG_DONTWAIT);
if (IS_ERR(skb))
return skb;
@@ -2369,7 +2374,7 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
if (sdulen)
put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
- err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
+ err = l2cap_from_skbuff(chan, buf, len, flags, count, skb);
if (unlikely(err < 0)) {
kfree_skb(skb);
return ERR_PTR(err);
@@ -2380,13 +2385,14 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
struct sk_buff_head *seg_queue,
- struct msghdr *msg, size_t len)
+ void *buf, size_t len,
+ unsigned int flags)
{
struct sk_buff *skb;
size_t pdu_len;
u16 sdu_len;
- BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
+ BT_DBG("chan %p, buf %p, len %zu", chan, buf, len);
pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE;
@@ -2399,7 +2405,8 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
if (len <= pdu_len)
pdu_len = len;
- skb = l2cap_create_le_flowctl_pdu(chan, msg, pdu_len, sdu_len);
+ skb = l2cap_create_le_flowctl_pdu(chan, buf, pdu_len, sdu_len,
+ flags);
if (IS_ERR(skb)) {
__skb_queue_purge(seg_queue);
return PTR_ERR(skb);
@@ -2408,6 +2415,7 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
__skb_queue_tail(seg_queue, skb);
len -= pdu_len;
+ buf += pdu_len;
if (sdu_len) {
sdu_len = 0;
@@ -2418,8 +2426,8 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
return 0;
}
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
- u32 priority)
+int l2cap_chan_send(struct l2cap_chan *chan, void *buf, size_t len,
+ u32 priority, unsigned int flags)
{
struct sk_buff *skb;
int err;
@@ -2430,7 +2438,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
/* Connectionless channel */
if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
- skb = l2cap_create_connless_pdu(chan, msg, len, priority);
+ skb = l2cap_create_connless_pdu(chan, buf, len, priority,
+ flags);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -2457,7 +2466,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
__skb_queue_head_init(&seg_queue);
- err = l2cap_segment_le_sdu(chan, &seg_queue, msg, len);
+ err = l2cap_segment_le_sdu(chan, &seg_queue, buf, len, flags);
if (chan->state != BT_CONNECTED) {
__skb_queue_purge(&seg_queue);
@@ -2487,7 +2496,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
return -EMSGSIZE;
/* Create a basic PDU */
- skb = l2cap_create_basic_pdu(chan, msg, len, priority);
+ skb = l2cap_create_basic_pdu(chan, buf, len, priority, flags);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -2517,7 +2526,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
* since it's possible to block while waiting for memory
* allocation.
*/
- err = l2cap_segment_sdu(chan, &seg_queue, msg, len);
+ err = l2cap_segment_sdu(chan, &seg_queue, buf, len, flags);
/* The channel could have been closed while segmenting,
* check that it is still connected.
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index f59e00c..e66c14c 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -948,6 +948,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ void *buf;
int err;
BT_DBG("sock %p, sk %p", sock, sk);
@@ -968,10 +969,21 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
if (err)
return err;
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (memcpy_fromiovec(buf, msg->msg_iov, len)) {
+ err = -EFAULT;
+ goto done;
+ }
+
l2cap_chan_lock(chan);
- err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
+ err = l2cap_chan_send(chan, buf, len, sk->sk_priority, msg->msg_flags);
l2cap_chan_unlock(chan);
+done:
+ kfree(buf);
return err;
}
--
1.8.3.1
next prev parent reply other threads:[~2014-05-28 11:43 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-28 11:43 [PATCH v3 0/6] Bluetooth LE 6LoWPAN using CoC Jukka Rissanen
2014-05-28 11:43 ` Jukka Rissanen [this message]
2014-05-31 4:37 ` [PATCH v3 1/6] Bluetooth: Refactor l2cap_sock_sendmsg() to copy user buffer Marcel Holtmann
2014-05-28 11:43 ` [PATCH v3 2/6] Bluetooth: l2cap: Set more channel defaults Jukka Rissanen
2014-05-31 4:39 ` Marcel Holtmann
2014-05-28 11:43 ` [PATCH v3 3/6] Bluetooth: 6LoWPAN: Use connected oriented channel instead of fixed one Jukka Rissanen
2014-05-28 11:43 ` [PATCH v3 4/6] Bluetooth: 6LoWPAN: Create a kernel module Jukka Rissanen
2014-05-28 11:43 ` [PATCH v3 5/6] Bluetooth: 6LoWPAN: Count module usage Jukka Rissanen
2014-05-30 8:11 ` Jukka Rissanen
2014-05-28 11:43 ` [PATCH v3 6/6] Bluetooth: 6LoWPAN: Remove network devices when unloading Jukka Rissanen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1401277388-4611-2-git-send-email-jukka.rissanen@linux.intel.com \
--to=jukka.rissanen@linux.intel.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).