Skip to content

Commit

Permalink
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/bluetooth/bluetooth-next
  • Loading branch information
John W. Linville committed Nov 21, 2012
2 parents b311749 + 2b2fec4 commit d2ff5ee
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 29 deletions.
1 change: 1 addition & 0 deletions drivers/bluetooth/btusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },

/* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0b05, 0x17b5) },
{ USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x413c, 0x8197) },
Expand Down
22 changes: 21 additions & 1 deletion include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ enum {
#define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
#define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */
#define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */
#define HCI_CMD_TIMEOUT msecs_to_jiffies(1000) /* 1 second */
#define HCI_CMD_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
#define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */
#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */

Expand Down Expand Up @@ -319,6 +319,9 @@ enum {
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01

/* The core spec defines 127 as the "not available" value */
#define HCI_TX_POWER_INVALID 127

/* Extended Inquiry Response field types */
#define EIR_FLAGS 0x01 /* flags */
#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
Expand All @@ -335,6 +338,13 @@ enum {
#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
#define EIR_DEVICE_ID 0x10 /* device ID */

/* Low Energy Advertising Flags */
#define LE_AD_LIMITED 0x01 /* Limited Discoverable */
#define LE_AD_GENERAL 0x02 /* General Discoverable */
#define LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */
#define LE_AD_SIM_LE_BREDR_CTRL 0x08 /* Simultaneous LE & BR/EDR Controller */
#define LE_AD_SIM_LE_BREDR_HOST 0x10 /* Simultaneous LE & BR/EDR Host */

/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000

Expand Down Expand Up @@ -939,6 +949,16 @@ struct hci_rp_le_read_adv_tx_power {
__s8 tx_power;
} __packed;

#define HCI_MAX_AD_LENGTH 31

#define HCI_OP_LE_SET_ADV_DATA 0x2008
struct hci_cp_le_set_adv_data {
__u8 length;
__u8 data[HCI_MAX_AD_LENGTH];
} __packed;

#define HCI_OP_LE_SET_ADV_ENABLE 0x200a

#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
struct hci_cp_le_set_scan_param {
__u8 type;
Expand Down
4 changes: 4 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ struct hci_dev {
struct le_scan_params le_scan_params;

__s8 adv_tx_power;
__u8 adv_data[HCI_MAX_AD_LENGTH];
__u8 adv_data_len;

int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
Expand Down Expand Up @@ -734,6 +736,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);

int hci_update_ad(struct hci_dev *hdev);

void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);

int hci_recv_frame(struct sk_buff *skb);
Expand Down
2 changes: 1 addition & 1 deletion include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan);
void l2cap_move_start(struct l2cap_chan *chan);
void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
u8 status);
void l2cap_physical_cfm(struct l2cap_chan *chan, int result);
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);

#endif /* __L2CAP_H */
8 changes: 6 additions & 2 deletions net/bluetooth/amp.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,13 +386,17 @@ void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)

bredr_chan = mgr->bredr_chan;

l2cap_chan_lock(bredr_chan);

set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
bredr_chan->remote_amp_id = hs_hcon->remote_id;
bredr_chan->local_amp_id = hs_hcon->hdev->id;
bredr_chan->hs_hcon = hs_hcon;
bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu;
bredr_chan->fcs = L2CAP_FCS_NONE;

l2cap_physical_cfm(bredr_chan, 0);
__l2cap_physical_cfm(bredr_chan, 0);

l2cap_chan_unlock(bredr_chan);

hci_dev_put(bredr_hdev);
}
Expand Down
98 changes: 98 additions & 0 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,

BT_DBG("cache %p, %pMR", cache, &data->bdaddr);

hci_remove_remote_oob_data(hdev, &data->bdaddr);

if (ssp)
*ssp = data->ssp_mode;

Expand Down Expand Up @@ -594,6 +596,99 @@ int hci_inquiry(void __user *arg)
return err;
}

static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
{
u8 ad_len = 0, flags = 0;
size_t name_len;

if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
flags |= LE_AD_GENERAL;

if (!lmp_bredr_capable(hdev))
flags |= LE_AD_NO_BREDR;

if (lmp_le_br_capable(hdev))
flags |= LE_AD_SIM_LE_BREDR_CTRL;

if (lmp_host_le_br_capable(hdev))
flags |= LE_AD_SIM_LE_BREDR_HOST;

if (flags) {
BT_DBG("adv flags 0x%02x", flags);

ptr[0] = 2;
ptr[1] = EIR_FLAGS;
ptr[2] = flags;

ad_len += 3;
ptr += 3;
}

if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
ptr[0] = 2;
ptr[1] = EIR_TX_POWER;
ptr[2] = (u8) hdev->adv_tx_power;

ad_len += 3;
ptr += 3;
}

name_len = strlen(hdev->dev_name);
if (name_len > 0) {
size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;

if (name_len > max_len) {
name_len = max_len;
ptr[1] = EIR_NAME_SHORT;
} else
ptr[1] = EIR_NAME_COMPLETE;

ptr[0] = name_len + 1;

memcpy(ptr + 2, hdev->dev_name, name_len);

ad_len += (name_len + 2);
ptr += (name_len + 2);
}

return ad_len;
}

int hci_update_ad(struct hci_dev *hdev)
{
struct hci_cp_le_set_adv_data cp;
u8 len;
int err;

hci_dev_lock(hdev);

if (!lmp_le_capable(hdev)) {
err = -EINVAL;
goto unlock;
}

memset(&cp, 0, sizeof(cp));

len = create_ad(hdev, cp.data);

if (hdev->adv_data_len == len &&
memcmp(cp.data, hdev->adv_data, len) == 0) {
err = 0;
goto unlock;
}

memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
hdev->adv_data_len = len;

cp.length = len;
err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);

unlock:
hci_dev_unlock(hdev);

return err;
}

/* ---- HCI ioctl helpers ---- */

int hci_dev_open(__u16 dev)
Expand Down Expand Up @@ -651,6 +746,7 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
hci_update_ad(hdev);
if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
Expand Down Expand Up @@ -1606,6 +1702,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->esco_type = (ESCO_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
hdev->io_capability = 0x03; /* No Input No Output */
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;

hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
Expand Down
44 changes: 43 additions & 1 deletion net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
BIT(HCI_PERIODIC_INQ));

hdev->discovery.state = DISCOVERY_STOPPED;
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_tx_power = HCI_TX_POWER_INVALID;

memset(hdev->adv_data, 0, sizeof(hdev->adv_data));
hdev->adv_data_len = 0;
}

static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
Expand All @@ -224,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)

hci_dev_unlock(hdev);

if (!status && !test_bit(HCI_INIT, &hdev->flags))
hci_update_ad(hdev);

hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
}

Expand Down Expand Up @@ -1089,8 +1097,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,

BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);

if (!rp->status)
if (!rp->status) {
hdev->adv_tx_power = rp->tx_power;
if (!test_bit(HCI_INIT, &hdev->flags))
hci_update_ad(hdev);
}

hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
}
Expand Down Expand Up @@ -1179,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}

static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 *sent, status = *((__u8 *) skb->data);

BT_DBG("%s status 0x%2.2x", hdev->name, status);

sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE);
if (!sent)
return;

hci_dev_lock(hdev);

if (!status) {
if (*sent)
set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
else
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
}

hci_dev_unlock(hdev);

if (!test_bit(HCI_INIT, &hdev->flags))
hci_update_ad(hdev);

hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status);
}

static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
Expand Down Expand Up @@ -2574,6 +2612,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_set_scan_param(hdev, skb);
break;

case HCI_OP_LE_SET_ADV_ENABLE:
hci_cc_le_set_adv_enable(hdev, skb);
break;

case HCI_OP_LE_SET_SCAN_ENABLE:
hci_cc_le_set_scan_enable(hdev, skb);
break;
Expand Down
Loading

0 comments on commit d2ff5ee

Please sign in to comment.