Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06f62094 authored by Rupesh Tatiya's avatar Rupesh Tatiya
Browse files

bluetooth: return on incorrect version or firmware download failure



if execution continues even after an error in get version or firmware
download, there can be page fault or memory corruption.

Change-Id: I3678fbc390376b81c1e10f426772428ad0c5d7ac
Signed-off-by: default avatarRupesh Tatiya <rtatiya@codeaurora.org>
parent f5d3db32
Loading
Loading
Loading
Loading
+63 −61
Original line number Diff line number Diff line
/*
 * Copyright (c) 2008-2009 Atheros Communications Inc.
 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
@@ -31,6 +31,8 @@
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>

#include "ath3k.h"

#define VERSION "1.0"
#define ATH3K_FIRMWARE	"ath3k-1.fw"

@@ -75,14 +77,6 @@
#define ATH3K_XTAL_FREQ_19P2			0x02
#define ATH3K_NAME_LEN				0xFF

struct ath3k_version {
	unsigned int	rom_version;
	unsigned int	build_version;
	unsigned int	ram_version;
	unsigned char	ref_clock;
	unsigned char	reserved[0x07];
};

struct __packed rome1_1_version {
	u8	type;
	u8	length[3];
@@ -337,10 +331,15 @@ static int ath3k_get_version(struct usb_device *udev,
	return ret;
}

int get_rome_version(struct usb_device *udev)
int get_rome_version(struct usb_device *udev, struct ath3k_version *version)
{
	struct ath3k_version fw_version;
	int ret = 0;
	int ret;

	if (!version) {
		BT_ERR("NULL output parameters");
		return -EINVAL;
	}

	ret = ath3k_get_version(udev, &fw_version);
	if (ret < 0) {
@@ -352,12 +351,15 @@ int get_rome_version(struct usb_device *udev)
	case ROME1_1_USB_CHIP_VERSION:
	case ROME2_1_USB_CHIP_VERSION:
	case ROME3_0_USB_CHIP_VERSION:
		ret = fw_version.rom_version;
		memcpy(version, &fw_version, sizeof(struct ath3k_version));
		ret = 0;
		break;
	default:
		ret = 0;
		BT_ERR("Unsupported ROME USB version");
		ret = -EINVAL;
		break;
	}

	return ret;
}
EXPORT_SYMBOL(get_rome_version);
@@ -450,12 +452,13 @@ static int ath3k_set_normal_mode(struct usb_device *udev)
			NULL, 0, USB_CTRL_SET_TIMEOUT);
}

static int ath3k_load_patch(struct usb_device *udev)
static int ath3k_load_patch(struct usb_device *udev,
						struct ath3k_version *version)
{
	unsigned char fw_state;
	char filename[ATH3K_NAME_LEN] = {0};
	const struct firmware *firmware;
	struct ath3k_version fw_version, pt_version;
	struct ath3k_version pt_version;
	struct rome2_1_version *rome2_1_version;
	struct rome1_1_version *rome1_1_version;
	int ret;
@@ -474,66 +477,67 @@ static int ath3k_load_patch(struct usb_device *udev)
	}
	BT_DBG("Downloading RamPatch(fw_state: %d)", fw_state);

	ret = ath3k_get_version(udev, &fw_version);
	if (ret < 0) {
		BT_ERR("Can't get version to change to load ram patch err");
		return ret;
	}
	if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION) {
	switch (version->rom_version) {
	case ROME1_1_USB_CHIP_VERSION:
		BT_DBG("Chip Detected as ROME1.1");
		snprintf(filename, ATH3K_NAME_LEN, ROME1_1_USB_RAMPATCH_FILE);
	} else if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) {
		break;
	case ROME2_1_USB_CHIP_VERSION:
		BT_DBG("Chip Detected as ROME2.1");
		snprintf(filename, ATH3K_NAME_LEN, ROME2_1_USB_RAMPATCH_FILE);
	} else if (fw_version.rom_version == ROME3_0_USB_CHIP_VERSION) {
		break;
	case ROME3_0_USB_CHIP_VERSION:
		BT_DBG("Chip Detected as ROME3.0");
		snprintf(filename, ATH3K_NAME_LEN, ROME3_0_USB_RAMPATCH_FILE);
	} else {
		break;
	default:
		BT_DBG("Chip Detected as Ath3k");
		snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
		fw_version.rom_version);
		version->rom_version);
		break;
	}

	ret = request_firmware(&firmware, filename, &udev->dev);
	if (ret < 0) {
		BT_ERR("Patch file not found %s", filename);
		return ret;
	}

	if ((fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(fw_version.rom_version == ROME3_0_USB_CHIP_VERSION)) {
	if ((version->rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(version->rom_version == ROME3_0_USB_CHIP_VERSION)) {
		rome2_1_version = (struct rome2_1_version *) firmware->data;
		pt_version.rom_version = rome2_1_version->build_ver;
		pt_version.build_version = rome2_1_version->patch_ver;
		BT_DBG("pt_ver.rome_ver : 0x%x", pt_version.rom_version);
		BT_DBG("pt_ver.build_ver: 0x%x", pt_version.build_version);
		BT_DBG("fw_ver.rom_ver: 0x%x", fw_version.rom_version);
		BT_DBG("fw_ver.build_ver: 0x%x", fw_version.build_version);
	} else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION) {
		BT_DBG("fw_ver.rom_ver: 0x%x", version->rom_version);
		BT_DBG("fw_ver.build_ver: 0x%x", version->build_version);
	} else if (version->rom_version == ROME1_1_USB_CHIP_VERSION) {
		rome1_1_version = (struct rome1_1_version *) firmware->data;
		pt_version.build_version = rome1_1_version->build_ver;
		pt_version.rom_version = rome1_1_version->patch_ver;
		BT_DBG("pt_ver.rom1.1_ver : 0x%x", pt_version.rom_version);
		BT_DBG("pt_ver.build1.1_ver: 0x%x", pt_version.build_version);
		BT_DBG("fw_ver.rom1.1_ver: 0x%x", fw_version.rom_version);
		BT_DBG("fw_ver.build1.1_ver: 0x%x", fw_version.build_version);
		BT_DBG("fw_ver.rom1.1_ver: 0x%x", version->rom_version);
		BT_DBG("fw_ver.build1.1_ver: 0x%x", version->build_version);
	} else {
		pt_version.rom_version = *(int *)(firmware->data +
						firmware->size - 8);
		pt_version.build_version = *(int *)
		(firmware->data + firmware->size - 4);
	}
	if ((pt_version.rom_version != fw_version.rom_version) ||
		(pt_version.build_version <= fw_version.build_version)) {
	if ((pt_version.rom_version != version->rom_version) ||
		(pt_version.build_version <= version->build_version)) {
		BT_ERR("Patch file version did not match with firmware");
		release_firmware(firmware);
		return -EINVAL;
	}

	if ((fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(fw_version.rom_version == ROME3_0_USB_CHIP_VERSION))
	if ((version->rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(version->rom_version == ROME3_0_USB_CHIP_VERSION))
		ret = ath3k_load_fwfile(udev, firmware,
						ROME2_1_USB_RAMPATCH_HEADER);
	else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION)
	else if (version->rom_version == ROME1_1_USB_CHIP_VERSION)
		ret = ath3k_load_fwfile(udev, firmware,
						 ROME1_1_USB_RAMPATCH_HEADER);
	else
@@ -544,12 +548,12 @@ static int ath3k_load_patch(struct usb_device *udev)
	return ret;
}

static int ath3k_load_syscfg(struct usb_device *udev)
static int ath3k_load_syscfg(struct usb_device *udev,
						struct ath3k_version *version)
{
	unsigned char fw_state;
	char filename[ATH3K_NAME_LEN] = {0};
	const struct firmware *firmware;
	struct ath3k_version fw_version;
	int clk_value, ret;

	ret = ath3k_get_state(udev, &fw_state);
@@ -566,14 +570,7 @@ static int ath3k_load_syscfg(struct usb_device *udev)
	}
	BT_DBG("Downloading NVM(fw_state: %d)", fw_state);

	ret = ath3k_get_version(udev, &fw_version);
	if (ret < 0) {
		BT_ERR("Can't get version to change to load ram patch err");
		return ret;
	}

	switch (fw_version.ref_clock) {

	switch (version->ref_clock) {
	case ATH3K_XTAL_FREQ_26M:
		clk_value = 26;
		break;
@@ -588,15 +585,15 @@ static int ath3k_load_syscfg(struct usb_device *udev)
		break;
	}

	if (fw_version.rom_version == ROME2_1_USB_CHIP_VERSION)
	if (version->rom_version == ROME2_1_USB_CHIP_VERSION)
		snprintf(filename, ATH3K_NAME_LEN, ROME2_1_USB_NVM_FILE);
	else if (fw_version.rom_version == ROME3_0_USB_CHIP_VERSION)
	else if (version->rom_version == ROME3_0_USB_CHIP_VERSION)
		snprintf(filename, ATH3K_NAME_LEN, ROME3_0_USB_NVM_FILE);
	else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION)
	else if (version->rom_version == ROME1_1_USB_CHIP_VERSION)
		snprintf(filename, ATH3K_NAME_LEN, ROME1_1_USB_NVM_FILE);
	else
		snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
			fw_version.rom_version, clk_value, ".dfu");
			version->rom_version, clk_value, ".dfu");

	ret = request_firmware(&firmware, filename, &udev->dev);
	if (ret < 0) {
@@ -604,29 +601,29 @@ static int ath3k_load_syscfg(struct usb_device *udev)
		return ret;
	}

	if ((fw_version.rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(fw_version.rom_version == ROME3_0_USB_CHIP_VERSION))
	if ((version->rom_version == ROME2_1_USB_CHIP_VERSION) ||
		(version->rom_version == ROME3_0_USB_CHIP_VERSION))
		ret = ath3k_load_fwfile(udev, firmware, ROME2_1_USB_NVM_HEADER);
	else if (fw_version.rom_version == ROME1_1_USB_CHIP_VERSION)
	else if (version->rom_version == ROME1_1_USB_CHIP_VERSION)
		ret = ath3k_load_fwfile(udev, firmware, ROME1_1_USB_NVM_HEADER);
	else
		ret = ath3k_load_fwfile(udev, firmware, FW_HDR_SIZE);

	release_firmware(firmware);

	return ret;
}


int rome_download(struct usb_device *udev)
int rome_download(struct usb_device *udev, struct ath3k_version *version)
{
	int ret;

	ret = ath3k_load_patch(udev);
	ret = ath3k_load_patch(udev, version);
	if (ret < 0) {
		BT_ERR("Loading patch file failed");
		return ret;
	}
	ret = ath3k_load_syscfg(udev);
	ret = ath3k_load_syscfg(udev, version);
	if (ret < 0) {
		BT_ERR("Loading sysconfig file failed");
		return ret;
@@ -635,21 +632,26 @@ int rome_download(struct usb_device *udev)
	return ret;
}
EXPORT_SYMBOL(rome_download);

static int ath3k_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
{
	const struct firmware *firmware;
	struct usb_device *udev = interface_to_usbdev(intf);
	int ret;
	struct ath3k_version version;

	BT_DBG("intf %p id %p", intf, id);

	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
		return -ENODEV;
	if (get_rome_version(udev)) {

	ret = get_rome_version(udev, &version);
	if (!ret) {
		BT_INFO("Rome detected, fw dnld will be triggered from btusb");
		return -ENODEV;
	}

	/* match device ID in ath3k blacklist table */
	if (!id->driver_info) {
		const struct usb_device_id *match;
@@ -665,12 +667,12 @@ static int ath3k_probe(struct usb_interface *intf,
		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001)
			return -ENODEV;

		ret = ath3k_load_patch(udev);
		ret = ath3k_load_patch(udev, &version);
		if (ret < 0) {
			BT_ERR("Loading patch file failed");
			return ret;
		}
		ret = ath3k_load_syscfg(udev);
		ret = ath3k_load_syscfg(udev, &version);
		if (ret < 0) {
			BT_ERR("Loading sysconfig file failed");
			return ret;
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2008-2009 Atheros Communications Inc.
 * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
*/

#include <linux/usb.h>

struct ath3k_version {
	unsigned int	rom_version;
	unsigned int	build_version;
	unsigned int	ram_version;
	unsigned char	ref_clock;
	unsigned char	reserved[0x07];
};

int get_rome_version(struct usb_device *udev, struct ath3k_version *version);
int rome_download(struct usb_device *udev, struct ath3k_version *version);
+17 −8
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

#include "ath3k.h"

#define VERSION "0.6"

static bool disable_scofix;
@@ -1964,7 +1966,8 @@ static int btusb_probe(struct usb_interface *intf,
	struct usb_endpoint_descriptor *ep_desc;
	struct btusb_data *data;
	struct hci_dev *hdev;
	int i, version, err;
	int i, err;
	struct ath3k_version version;

	BT_DBG("intf %p id %p", intf, id);

@@ -1985,18 +1988,24 @@ static int btusb_probe(struct usb_interface *intf,

	if (id->driver_info & BTUSB_ATH3012) {
		struct usb_device *udev = interface_to_usbdev(intf);

		version = get_rome_version(udev);
		BT_INFO("Rome Version: 0x%x",  version);
		/* Old firmware would otherwise let ath3k driver load
		 * patch and sysconfig files */
		if (version)
			rome_download(udev);
		else if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001) {
		err = get_rome_version(udev, &version);
		if (err < 0) {
			if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
				BT_INFO("FW for ar3k is yet to be downloaded");
			else
				BT_ERR("Failed to get ROME USB version");
			return -ENODEV;
		}
		BT_INFO("Rome Version: 0x%x", version.rom_version);
		err = rome_download(udev, &version);
		if (err < 0) {
			BT_ERR("Failed to download ROME firmware");
			return -ENODEV;
		}
	}

	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;
+1 −4
Original line number Diff line number Diff line
/*
   BlueZ - Bluetooth protocol stack for Linux
   Copyright (C) 2000-2001 Qualcomm Incorporated
   Copyright (C) 2014 The Linux Foundation. All rights reserved.
   Copyright (C) 2014-2015 The Linux Foundation. All rights reserved.

   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>

@@ -362,7 +362,4 @@ void sco_exit(void);

void bt_sock_reclassify_lock(struct sock *sk, int proto);

int get_rome_version(struct usb_device *udev);
int rome_download(struct usb_device *udev);

#endif /* __BLUETOOTH_H */