[Bluetooth] Make use of the default link policy settings
The Bluetooth specification supports the default link policy settings on a per host controller basis. For every new connection the link manager would then use these settings. It is better to use this instead of bothering the controller on every connection setup to overwrite the default settings. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
a8746417e8
commit
e4e8e37c42
@ -404,6 +404,17 @@ struct hci_rp_write_link_policy {
|
|||||||
__le16 handle;
|
__le16 handle;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
|
||||||
|
struct hci_rp_read_def_link_policy {
|
||||||
|
__u8 status;
|
||||||
|
__le16 policy;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
|
||||||
|
struct hci_cp_write_def_link_policy {
|
||||||
|
__le16 policy;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
#define HCI_OP_SNIFF_SUBRATE 0x0811
|
#define HCI_OP_SNIFF_SUBRATE 0x0811
|
||||||
struct hci_cp_sniff_subrate {
|
struct hci_cp_sniff_subrate {
|
||||||
__le16 handle;
|
__le16 handle;
|
||||||
|
@ -65,6 +65,8 @@ void hci_acl_connect(struct hci_conn *conn)
|
|||||||
|
|
||||||
conn->attempt++;
|
conn->attempt++;
|
||||||
|
|
||||||
|
conn->link_policy = hdev->link_policy;
|
||||||
|
|
||||||
memset(&cp, 0, sizeof(cp));
|
memset(&cp, 0, sizeof(cp));
|
||||||
bacpy(&cp.bdaddr, &conn->dst);
|
bacpy(&cp.bdaddr, &conn->dst);
|
||||||
cp.pscan_rep_mode = 0x02;
|
cp.pscan_rep_mode = 0x02;
|
||||||
|
@ -279,10 +279,20 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
|
|||||||
|
|
||||||
BT_DBG("%s %x", hdev->name, encrypt);
|
BT_DBG("%s %x", hdev->name, encrypt);
|
||||||
|
|
||||||
/* Authentication */
|
/* Encryption */
|
||||||
hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
|
hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
|
||||||
|
{
|
||||||
|
__le16 policy = cpu_to_le16(opt);
|
||||||
|
|
||||||
|
BT_DBG("%s %x", hdev->name, opt);
|
||||||
|
|
||||||
|
/* Default link policy */
|
||||||
|
hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get HCI device by index.
|
/* Get HCI device by index.
|
||||||
* Device is held on return. */
|
* Device is held on return. */
|
||||||
struct hci_dev *hci_dev_get(int index)
|
struct hci_dev *hci_dev_get(int index)
|
||||||
@ -694,32 +704,35 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
|
|||||||
msecs_to_jiffies(HCI_INIT_TIMEOUT));
|
msecs_to_jiffies(HCI_INIT_TIMEOUT));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HCISETLINKPOL:
|
||||||
|
err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
|
||||||
|
msecs_to_jiffies(HCI_INIT_TIMEOUT));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCISETLINKMODE:
|
||||||
|
hdev->link_mode = ((__u16) dr.dev_opt) &
|
||||||
|
(HCI_LM_MASTER | HCI_LM_ACCEPT);
|
||||||
|
break;
|
||||||
|
|
||||||
case HCISETPTYPE:
|
case HCISETPTYPE:
|
||||||
hdev->pkt_type = (__u16) dr.dev_opt;
|
hdev->pkt_type = (__u16) dr.dev_opt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCISETLINKPOL:
|
|
||||||
hdev->link_policy = (__u16) dr.dev_opt;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCISETLINKMODE:
|
|
||||||
hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCISETACLMTU:
|
case HCISETACLMTU:
|
||||||
hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1);
|
hdev->acl_mtu = *((__u16 *) &dr.dev_opt + 1);
|
||||||
hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
|
hdev->acl_pkts = *((__u16 *) &dr.dev_opt + 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCISETSCOMTU:
|
case HCISETSCOMTU:
|
||||||
hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1);
|
hdev->sco_mtu = *((__u16 *) &dr.dev_opt + 1);
|
||||||
hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
|
hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
hci_dev_put(hdev);
|
hci_dev_put(hdev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,25 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
|
|||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_rp_read_link_policy *rp = (void *) skb->data;
|
||||||
|
struct hci_conn *conn;
|
||||||
|
|
||||||
|
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||||
|
|
||||||
|
if (rp->status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
|
||||||
|
if (conn)
|
||||||
|
conn->link_policy = __le16_to_cpu(rp->policy);
|
||||||
|
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
}
|
||||||
|
|
||||||
static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct hci_rp_write_link_policy *rp = (void *) skb->data;
|
struct hci_rp_write_link_policy *rp = (void *) skb->data;
|
||||||
@ -128,13 +147,41 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
|||||||
hci_dev_lock(hdev);
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
|
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
|
||||||
if (conn) {
|
if (conn)
|
||||||
conn->link_policy = get_unaligned_le16(sent + 2);
|
conn->link_policy = get_unaligned_le16(sent + 2);
|
||||||
}
|
|
||||||
|
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
|
||||||
|
|
||||||
|
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||||
|
|
||||||
|
if (rp->status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hdev->link_policy = __le16_to_cpu(rp->policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
__u8 status = *((__u8 *) skb->data);
|
||||||
|
void *sent;
|
||||||
|
|
||||||
|
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||||
|
|
||||||
|
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY);
|
||||||
|
if (!sent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
hdev->link_policy = get_unaligned_le16(sent);
|
||||||
|
|
||||||
|
hci_req_complete(hdev, status);
|
||||||
|
}
|
||||||
|
|
||||||
static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
__u8 status = *((__u8 *) skb->data);
|
__u8 status = *((__u8 *) skb->data);
|
||||||
@ -347,8 +394,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
hdev->hci_ver = rp->hci_ver;
|
hdev->hci_ver = rp->hci_ver;
|
||||||
hdev->hci_rev = btohs(rp->hci_rev);
|
hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
|
||||||
hdev->manufacturer = btohs(rp->manufacturer);
|
hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
|
||||||
|
|
||||||
BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
|
BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
|
||||||
hdev->manufacturer,
|
hdev->manufacturer,
|
||||||
@ -690,14 +737,6 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||||||
hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
|
hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set link policy */
|
|
||||||
if (conn->type == ACL_LINK && hdev->link_policy) {
|
|
||||||
struct hci_cp_write_link_policy cp;
|
|
||||||
cp.handle = ev->handle;
|
|
||||||
cp.policy = cpu_to_le16(hdev->link_policy);
|
|
||||||
hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set packet type for incoming connection */
|
/* Set packet type for incoming connection */
|
||||||
if (!conn->out && hdev->hci_ver < 3) {
|
if (!conn->out && hdev->hci_ver < 3) {
|
||||||
struct hci_cp_change_conn_ptype cp;
|
struct hci_cp_change_conn_ptype cp;
|
||||||
@ -974,10 +1013,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||||||
hci_cc_role_discovery(hdev, skb);
|
hci_cc_role_discovery(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HCI_OP_READ_LINK_POLICY:
|
||||||
|
hci_cc_read_link_policy(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
case HCI_OP_WRITE_LINK_POLICY:
|
case HCI_OP_WRITE_LINK_POLICY:
|
||||||
hci_cc_write_link_policy(hdev, skb);
|
hci_cc_write_link_policy(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HCI_OP_READ_DEF_LINK_POLICY:
|
||||||
|
hci_cc_read_def_link_policy(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCI_OP_WRITE_DEF_LINK_POLICY:
|
||||||
|
hci_cc_write_def_link_policy(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
case HCI_OP_RESET:
|
case HCI_OP_RESET:
|
||||||
hci_cc_reset(hdev, skb);
|
hci_cc_reset(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user