aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_sock.c
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2014-06-18 09:37:07 -0400
committerMarcel Holtmann <marcel@holtmann.org>2014-07-03 11:42:43 -0400
commit0498878b18993891f7b71c75b6adcb7c157501db (patch)
tree644ce8cb68ff8d441f5e0d8871a31fa9bb2348c0 /net/bluetooth/l2cap_sock.c
parent111902f7236ff8139c30c2b9709c999fcb931399 (diff)
Bluetooth: Provide L2CAP ops callback for memcpy_fromiovec
The highly optimized TX path for L2CAP channels and its fragmentation within the HCI ACL packets requires to copy data from user provided IO vectors and also kernel provided memory buffers. This patch allows channel clients to provide a memcpy_fromiovec callback to keep this optimized behavior, but adapt it to kernel vs user memory for the TX path. For all kernel internal L2CAP channels, a default implementation is provided that can be referenced. In case of A2MP, this fixes a long-standing issue with wrongly accessing kernel memory as user memory. This patch originally by Marcel Holtmann. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r--net/bluetooth/l2cap_sock.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 55215ebf6547..bf72886de6ef 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1313,6 +1313,13 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
1313 return skb; 1313 return skb;
1314} 1314}
1315 1315
1316static int l2cap_sock_memcpy_fromiovec_cb(struct l2cap_chan *chan,
1317 unsigned char *kdata,
1318 struct iovec *iov, int len)
1319{
1320 return memcpy_fromiovec(kdata, iov, len);
1321}
1322
1316static void l2cap_sock_ready_cb(struct l2cap_chan *chan) 1323static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
1317{ 1324{
1318 struct sock *sk = chan->data; 1325 struct sock *sk = chan->data;
@@ -1379,19 +1386,20 @@ static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
1379} 1386}
1380 1387
1381static const struct l2cap_ops l2cap_chan_ops = { 1388static const struct l2cap_ops l2cap_chan_ops = {
1382 .name = "L2CAP Socket Interface", 1389 .name = "L2CAP Socket Interface",
1383 .new_connection = l2cap_sock_new_connection_cb, 1390 .new_connection = l2cap_sock_new_connection_cb,
1384 .recv = l2cap_sock_recv_cb, 1391 .recv = l2cap_sock_recv_cb,
1385 .close = l2cap_sock_close_cb, 1392 .close = l2cap_sock_close_cb,
1386 .teardown = l2cap_sock_teardown_cb, 1393 .teardown = l2cap_sock_teardown_cb,
1387 .state_change = l2cap_sock_state_change_cb, 1394 .state_change = l2cap_sock_state_change_cb,
1388 .ready = l2cap_sock_ready_cb, 1395 .ready = l2cap_sock_ready_cb,
1389 .defer = l2cap_sock_defer_cb, 1396 .defer = l2cap_sock_defer_cb,
1390 .resume = l2cap_sock_resume_cb, 1397 .resume = l2cap_sock_resume_cb,
1391 .suspend = l2cap_sock_suspend_cb, 1398 .suspend = l2cap_sock_suspend_cb,
1392 .set_shutdown = l2cap_sock_set_shutdown_cb, 1399 .set_shutdown = l2cap_sock_set_shutdown_cb,
1393 .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, 1400 .get_sndtimeo = l2cap_sock_get_sndtimeo_cb,
1394 .alloc_skb = l2cap_sock_alloc_skb_cb, 1401 .alloc_skb = l2cap_sock_alloc_skb_cb,
1402 .memcpy_fromiovec = l2cap_sock_memcpy_fromiovec_cb,
1395}; 1403};
1396 1404
1397static void l2cap_sock_destruct(struct sock *sk) 1405static void l2cap_sock_destruct(struct sock *sk)