From 59790aa2873cb3c32db02c777f08eb19faccf5fa Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 29 Sep 2014 10:55:46 +0300 Subject: [PATCH 01/11] Bluetooth: 6lowpan: Make sure skb exists before accessing it We need to make sure that the saved skb exists when resuming or suspending a CoC channel. This can happen if initial credits is 0 when channel is connected. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 0920cb6ed572..5d3e6202da3d 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -950,6 +950,9 @@ static void chan_suspend_cb(struct l2cap_chan *chan) BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb); + if (!skb) + return; + lowpan_cb(skb)->status = -EAGAIN; } @@ -959,6 +962,9 @@ static void chan_resume_cb(struct l2cap_chan *chan) BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb); + if (!skb) + return; + lowpan_cb(skb)->status = 0; } From 36b3dd250dde5317fa6bb8c9010e1e7ab7f2265a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 29 Sep 2014 16:37:25 +0300 Subject: [PATCH 02/11] Bluetooth: 6lowpan: Ensure header compression does not corrupt IPv6 header If skb is going to multiple destinations, then make sure that we do not overwrite the common IPv6 headers. So before compressing the IPv6 headers, we copy the skb and that is then sent to 6LoWPAN Bluetooth devices. This is a similar patch as what was done for IEEE 802.154 6LoWPAN in commit f19f4f9525cf3 ("ieee802154: 6lowpan: ensure header compression does not corrupt ipv6 header") Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 137 ++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 53 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 5d3e6202da3d..2ec7c84c2000 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -426,38 +426,33 @@ static void convert_dest_bdaddr(struct in6_addr *ip6_daddr, *addr_type = get_addr_type_from_eui64(addr->b[5]); } -static int header_create(struct sk_buff *skb, struct net_device *netdev, - unsigned short type, const void *_daddr, - const void *_saddr, unsigned int len) +static int setup_header(struct sk_buff *skb, struct net_device *netdev, + bdaddr_t *peer_addr, u8 *peer_addr_type) { - struct ipv6hdr *hdr; + struct in6_addr ipv6_daddr; struct lowpan_dev *dev; struct lowpan_peer *peer; bdaddr_t addr, *any = BDADDR_ANY; - u8 *saddr, *daddr = any->b; - u8 addr_type; - - if (type != ETH_P_IPV6) - return -EINVAL; - - hdr = ipv6_hdr(skb); + u8 *daddr = any->b; + int err, status = 0; dev = lowpan_dev(netdev); - if (ipv6_addr_is_multicast(&hdr->daddr)) { - memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, - sizeof(struct in6_addr)); + memcpy(&ipv6_daddr, &lowpan_cb(skb)->addr, sizeof(ipv6_daddr)); + + if (ipv6_addr_is_multicast(&ipv6_daddr)) { lowpan_cb(skb)->chan = NULL; } else { unsigned long flags; + u8 addr_type; /* Get destination BT device from skb. * If there is no such peer then discard the packet. */ - convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); + convert_dest_bdaddr(&ipv6_daddr, &addr, &addr_type); BT_DBG("dest addr %pMR type %d IP %pI6c", &addr, - addr_type, &hdr->daddr); + addr_type, &ipv6_daddr); read_lock_irqsave(&devices_lock, flags); peer = peer_lookup_ba(dev, &addr, addr_type); @@ -470,7 +465,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, * the destination address. */ read_lock_irqsave(&devices_lock, flags); - peer = peer_lookup_dst(dev, &hdr->daddr, skb); + peer = peer_lookup_dst(dev, &ipv6_daddr, skb); read_unlock_irqrestore(&devices_lock, flags); if (!peer) { BT_DBG("no such peer %pMR found", &addr); @@ -479,29 +474,56 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, } daddr = peer->eui64_addr; - - memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, - sizeof(struct in6_addr)); + *peer_addr = addr; + *peer_addr_type = addr_type; lowpan_cb(skb)->chan = peer->chan; + + status = 1; } - saddr = dev->netdev->dev_addr; + lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr, + dev->netdev->dev_addr, skb->len); - return lowpan_header_compress(skb, netdev, type, daddr, saddr, len); + err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0); + if (err < 0) + return err; + + return status; +} + +static int header_create(struct sk_buff *skb, struct net_device *netdev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) +{ + struct ipv6hdr *hdr; + + if (type != ETH_P_IPV6) + return -EINVAL; + + hdr = ipv6_hdr(skb); + + memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr)); + + return 0; } /* Packet to BT LE device */ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, - struct net_device *netdev) + struct net_device *netdev, bool is_mcast) { struct msghdr msg; struct kvec iv; int err; /* Remember the skb so that we can send EAGAIN to the caller if - * we run out of credits. + * we run out of credits. This is not done for multicast packets + * because we generate mcast packet in this module and are not + * really able to remember the skb after this packet is sent. */ - chan->data = skb; + if (is_mcast) + chan->data = NULL; + else + chan->data = skb; memset(&msg, 0, sizeof(msg)); msg.msg_iov = (struct iovec *) &iv; @@ -549,7 +571,11 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { local_skb = skb_clone(skb, GFP_ATOMIC); - send_pkt(pentry->chan, local_skb, netdev); + BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p", + netdev->name, + &pentry->chan->dst, pentry->chan->dst_type, + &pentry->peer_addr, pentry->chan); + send_pkt(pentry->chan, local_skb, netdev, true); kfree_skb(local_skb); } @@ -561,43 +587,48 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) { int err = 0; - struct lowpan_dev *dev; - struct lowpan_peer *peer; bdaddr_t addr; u8 addr_type; - if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) { - /* We need to send the packet to every device - * behind this interface. + /* We must take a copy of the skb before we modify/replace the ipv6 + * header as the header could be used elsewhere + */ + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) + return NET_XMIT_DROP; + + /* Return values from setup_header() + * <0 - error, packet is dropped + * 0 - this is a multicast packet + * 1 - this is unicast packet + */ + err = setup_header(skb, netdev, &addr, &addr_type); + if (err < 0) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + + if (err) { + if (lowpan_cb(skb)->chan) { + BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p", + netdev->name, &addr, addr_type, + &lowpan_cb(skb)->addr, lowpan_cb(skb)->chan); + err = send_pkt(lowpan_cb(skb)->chan, skb, netdev, + false); + } else { + err = -ENOENT; + } + } else { + /* We need to send the packet to every device behind this + * interface. */ send_mcast_pkt(skb, netdev); - } else { - unsigned long flags; - - convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); - dev = lowpan_dev(netdev); - - read_lock_irqsave(&devices_lock, flags); - peer = peer_lookup_ba(dev, &addr, addr_type); - if (!peer) - peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb); - read_unlock_irqrestore(&devices_lock, flags); - - BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", - netdev->name, &addr, addr_type, - &lowpan_cb(skb)->addr, peer); - - if (peer && peer->chan) - err = send_pkt(peer->chan, skb, netdev); - else - err = -ENOENT; } - dev_kfree_skb(skb); if (err) BT_DBG("ERROR: xmit failed (%d)", err); - return (err < 0) ? NET_XMIT_DROP : err; + return err < 0 ? NET_XMIT_DROP : err; } static const struct net_device_ops netdev_ops = { From 156395c9989a76228e0da40e71267a3d4fb07419 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 29 Sep 2014 16:37:26 +0300 Subject: [PATCH 03/11] Bluetooth: 6lowpan: Enable multicast support Set multicast support for 6lowpan network interface. This is needed in every network interface that supports IPv6. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 2ec7c84c2000..f0432aea8dad 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -648,7 +648,8 @@ static void netdev_setup(struct net_device *dev) dev->needed_tailroom = 0; dev->mtu = IPV6_MIN_MTU; dev->tx_queue_len = 0; - dev->flags = IFF_RUNNING | IFF_POINTOPOINT; + dev->flags = IFF_RUNNING | IFF_POINTOPOINT | + IFF_MULTICAST; dev->watchdog_timeo = 0; dev->netdev_ops = &netdev_ops; From 1e3e492c3d7e78dad29ec0d6f36e18a785ea2720 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 30 Sep 2014 06:45:32 -0400 Subject: [PATCH 04/11] Bluetooth: btmrvl: rename definitions from 88xx to 8897 Register offsets are different for SD8897 and newer chip SD8887. We can not have common btmrvl_sdio_card_reg map for them. Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 3e683b153259..b549fb538684 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -84,7 +84,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .int_read_to_clear = false, }; -static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { +static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { .cfg = 0x00, .host_int_mask = 0x02, .host_intstatus = 0x03, @@ -131,7 +131,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", - .reg = &btmrvl_reg_88xx, + .reg = &btmrvl_reg_8897, .support_pscan_win_report = true, .sd_blksz_fw_dl = 256, }; From 3907d55801a631862ffca2b85c536ea5ceed2dc9 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Tue, 30 Sep 2014 06:45:33 -0400 Subject: [PATCH 05/11] Bluetooth: btmrvl: support Marvell Bluetooth device SD8887 This patch adds driver support for marvell SD8887 chip. Signed-off-by: Xinming Hu Signed-off-by: Kevin Gan Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 4 ++-- drivers/bluetooth/btmrvl_sdio.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index fa7fd62ddffa..4547dc238fc7 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -201,7 +201,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688/8787/8797/8897. + Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -214,7 +214,7 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897 + devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897 chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index b549fb538684..550bce089fa6 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -84,6 +84,26 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .int_read_to_clear = false, }; +static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = { + .cfg = 0x00, + .host_int_mask = 0x08, + .host_intstatus = 0x0C, + .card_status = 0x5C, + .sq_read_base_addr_a0 = 0x6C, + .sq_read_base_addr_a1 = 0x6D, + .card_revision = 0xC8, + .card_fw_status0 = 0x88, + .card_fw_status1 = 0x89, + .card_rx_len = 0x8A, + .card_rx_unit = 0x8B, + .io_port_0 = 0xE4, + .io_port_1 = 0xE5, + .io_port_2 = 0xE6, + .int_read_to_clear = true, + .host_int_rsr = 0x04, + .card_misc_cfg = 0xD8, +}; + static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = { .cfg = 0x00, .host_int_mask = 0x02, @@ -128,6 +148,14 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .sd_blksz_fw_dl = 256, }; +static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = { + .helper = NULL, + .firmware = "mrvl/sd8887_uapsta.bin", + .reg = &btmrvl_reg_8887, + .support_pscan_win_report = true, + .sd_blksz_fw_dl = 256, +}; + static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", @@ -149,6 +177,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8797 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, + /* Marvell SD8887 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136), + .driver_data = (unsigned long)&btmrvl_sdio_sd8887 }, /* Marvell SD8897 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), .driver_data = (unsigned long) &btmrvl_sdio_sd8897 }, @@ -1280,4 +1311,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); From 6a57dba9f0107b21cab06f7c898935d747d4738a Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 30 Sep 2014 07:39:05 -0400 Subject: [PATCH 06/11] Bluetooth: btusb: remove redundant lock variable This variable is nowhere used in the code. Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a423b84a0ed3..edfc17bfcd44 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -268,8 +268,6 @@ struct btusb_data { struct usb_interface *intf; struct usb_interface *isoc; - spinlock_t lock; - unsigned long flags; struct work_struct work; @@ -2002,8 +2000,6 @@ static int btusb_probe(struct usb_interface *intf, data->udev = interface_to_usbdev(intf); data->intf = intf; - spin_lock_init(&data->lock); - INIT_WORK(&data->work, btusb_work); INIT_WORK(&data->waker, btusb_waker); init_usb_anchor(&data->deferred); From 02e246aee868e982eecc25ee97d02acf2c2b8884 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Oct 2014 10:16:22 +0300 Subject: [PATCH 07/11] Bluetooth: Fix lockdep warning with l2cap_chan_connect The L2CAP connection's channel list lock (conn->chan_lock) must never be taken while already holding a channel lock (chan->lock) in order to avoid lock-inversion and lockdep warnings. So far the l2cap_chan_connect function has acquired the chan->lock early in the function and then later called l2cap_chan_add(conn, chan) which will try to take the conn->chan_lock. This violates the correct order of taking the locks and may lead to the following type of lockdep warnings: -> #1 (&conn->chan_lock){+.+...}: [] lock_acquire+0x9d/0x140 [] mutex_lock_nested+0x6c/0x420 [] l2cap_chan_add+0x1e/0x40 [bluetooth] [] l2cap_chan_connect+0x348/0x8f0 [bluetooth] [] lowpan_control_write+0x221/0x2d0 [bluetooth_6lowpan] -> #0 (&chan->lock){+.+.+.}: [] __lock_acquire+0x1a18/0x1d20 [] lock_acquire+0x9d/0x140 [] mutex_lock_nested+0x6c/0x420 [] l2cap_connect_cfm+0x1dd/0x3f0 [bluetooth] [] hci_le_meta_evt+0x11a4/0x1260 [bluetooth] [] hci_event_packet+0x3ab/0x3120 [bluetooth] [] hci_rx_work+0x208/0x4a0 [bluetooth] CPU0 CPU1 ---- ---- lock(&conn->chan_lock); lock(&chan->lock); lock(&conn->chan_lock); lock(&chan->lock); Before calling l2cap_chan_add() the channel is not part of the conn->chan_l list, and can therefore only be accessed by the L2CAP user (such as l2cap_sock.c). We can therefore assume that it is the responsibility of the user to handle mutual exclusion until this point (which we can see is already true in l2cap_sock.c by it in many places touching chan members without holding chan->lock). Since the hci_conn and by exctension l2cap_conn creation in the l2cap_chan_connect() function depend on chan details we cannot simply add a mutex_lock(&conn->chan_lock) in the beginning of the function (since the conn object doesn't yet exist there). What we can do however is move the chan->lock taking later into the function where we already have the conn object and can that way take conn->chan_lock first. This patch implements the above strategy and does some other necessary changes such as using __l2cap_chan_add() which assumes conn->chan_lock is held, as well as adding a second needed label so the unlocking happens as it should. Reported-by: Jukka Rissanen Signed-off-by: Johan Hedberg Tested-by: Jukka Rissanen Acked-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8d53fc57faba..b6f9777e057d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6980,8 +6980,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, hci_dev_lock(hdev); - l2cap_chan_lock(chan); - if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && chan->chan_type != L2CAP_CHAN_RAW) { err = -EINVAL; @@ -7078,17 +7076,20 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, goto done; } + mutex_lock(&conn->chan_lock); + l2cap_chan_lock(chan); + if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { hci_conn_drop(hcon); err = -EBUSY; - goto done; + goto chan_unlock; } /* Update source addr of the socket */ bacpy(&chan->src, &hcon->src); chan->src_type = bdaddr_type(hcon, hcon->src_type); - l2cap_chan_add(conn, chan); + __l2cap_chan_add(conn, chan); /* l2cap_chan_add takes its own ref so we can drop this one */ hci_conn_drop(hcon); @@ -7114,8 +7115,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, err = 0; -done: +chan_unlock: l2cap_chan_unlock(chan); + mutex_unlock(&conn->chan_lock); +done: hci_dev_unlock(hdev); hci_dev_put(hdev); return err; From fc12518a4bcbd4214652291df76f692343bca3d5 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 1 Oct 2014 11:30:26 +0300 Subject: [PATCH 08/11] Bluetooth: 6lowpan: Memory leak as the skb is not freed The earlier multicast commit 36b3dd250dde ("Bluetooth: 6lowpan: Ensure header compression does not corrupt IPv6 header") lost one skb free which then caused memory leak. Signed-off-by: Jukka Rissanen Signed-off-by: Johan Hedberg --- net/bluetooth/6lowpan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index f0432aea8dad..add2b58312d7 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -625,6 +625,8 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) send_mcast_pkt(skb, netdev); } + dev_kfree_skb(skb); + if (err) BT_DBG("ERROR: xmit failed (%d)", err); From a7807d73a0fa9b33dbdfd5f1cb97970ccc91d77e Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 1 Oct 2014 11:30:57 +0300 Subject: [PATCH 09/11] Bluetooth: 6lowpan: Avoid memory leak if memory allocation fails If skb_unshare() returns NULL, then we leak the original skb. Solution is to use temp variable to hold the new skb. Signed-off-by: Jukka Rissanen Signed-off-by: Johan Hedberg --- net/bluetooth/6lowpan.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index add2b58312d7..44eaad77e70c 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -589,13 +589,17 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) int err = 0; bdaddr_t addr; u8 addr_type; + struct sk_buff *tmpskb; /* We must take a copy of the skb before we modify/replace the ipv6 * header as the header could be used elsewhere */ - skb = skb_unshare(skb, GFP_ATOMIC); - if (!skb) + tmpskb = skb_unshare(skb, GFP_ATOMIC); + if (!tmpskb) { + kfree_skb(skb); return NET_XMIT_DROP; + } + skb = tmpskb; /* Return values from setup_header() * <0 - error, packet is dropped From d7b6b0a532da7de25e16deed610658cfa1969fe9 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 1 Oct 2014 15:59:14 +0300 Subject: [PATCH 10/11] Bluetooth: 6lowpan: Return EAGAIN error also for multicast packets Make sure that we are able to return EAGAIN from l2cap_chan_send() even for multicast packets. The error code was ignored unncessarily. Signed-off-by: Jukka Rissanen Signed-off-by: Johan Hedberg --- net/bluetooth/6lowpan.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 44eaad77e70c..fcfaa7006b28 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -509,21 +509,16 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, /* Packet to BT LE device */ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, - struct net_device *netdev, bool is_mcast) + struct net_device *netdev) { struct msghdr msg; struct kvec iv; int err; /* Remember the skb so that we can send EAGAIN to the caller if - * we run out of credits. This is not done for multicast packets - * because we generate mcast packet in this module and are not - * really able to remember the skb after this packet is sent. + * we run out of credits. */ - if (is_mcast) - chan->data = NULL; - else - chan->data = skb; + chan->data = skb; memset(&msg, 0, sizeof(msg)); msg.msg_iov = (struct iovec *) &iv; @@ -575,7 +570,7 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) netdev->name, &pentry->chan->dst, pentry->chan->dst_type, &pentry->peer_addr, pentry->chan); - send_pkt(pentry->chan, local_skb, netdev, true); + send_pkt(pentry->chan, local_skb, netdev); kfree_skb(local_skb); } @@ -617,8 +612,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p", netdev->name, &addr, addr_type, &lowpan_cb(skb)->addr, lowpan_cb(skb)->chan); - err = send_pkt(lowpan_cb(skb)->chan, skb, netdev, - false); + err = send_pkt(lowpan_cb(skb)->chan, skb, netdev); } else { err = -ENOENT; } From 9c238ca8ec79c38ab22762b44aeaf7a42fc97b18 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 1 Oct 2014 15:59:15 +0300 Subject: [PATCH 11/11] Bluetooth: 6lowpan: Check transmit errors for multicast packets We did not return error if multicast packet transmit failed. This might not be desired so return error also in this case. If there are multiple 6lowpan devices where the multicast packet is sent, then return error even if sending to only one of them fails. Signed-off-by: Jukka Rissanen Signed-off-by: Johan Hedberg --- net/bluetooth/6lowpan.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index fcfaa7006b28..c2e0d14433df 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -546,11 +546,12 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, return err; } -static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) +static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) { struct sk_buff *local_skb; struct lowpan_dev *entry, *tmp; unsigned long flags; + int err = 0; read_lock_irqsave(&devices_lock, flags); @@ -564,19 +565,25 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) dev = lowpan_dev(entry->netdev); list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { + int ret; + local_skb = skb_clone(skb, GFP_ATOMIC); BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p", netdev->name, &pentry->chan->dst, pentry->chan->dst_type, &pentry->peer_addr, pentry->chan); - send_pkt(pentry->chan, local_skb, netdev); + ret = send_pkt(pentry->chan, local_skb, netdev); + if (ret < 0) + err = ret; kfree_skb(local_skb); } } read_unlock_irqrestore(&devices_lock, flags); + + return err; } static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) @@ -620,7 +627,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) /* We need to send the packet to every device behind this * interface. */ - send_mcast_pkt(skb, netdev); + err = send_mcast_pkt(skb, netdev); } dev_kfree_skb(skb);