Skip to content

Commit

Permalink
[Bluetooth] Track connection packet type changes
Browse files Browse the repository at this point in the history
The connection packet type can be changed after the connection has been
established and thus needs to be properly tracked to ensure that the
host stack has always correct and valid information about it.

On incoming connections the Bluetooth core switches the supported packet
types to the configured list for this controller. However the usefulness
of this feature has been questioned a lot. The general consent is that
every Bluetooth host stack should enable as many packet types as the
hardware actually supports and leave the decision to the link manager
software running on the Bluetooth chip.

When running on Bluetooth 2.0 or later hardware, don't change the packet
type for incoming connections anymore. This hardware likely supports
Enhanced Data Rate and thus leave it completely up to the link manager
to pick the best packet type.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
Marcel Holtmann committed Jul 14, 2008
1 parent 9dc0a3a commit a874641
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 15 deletions.
9 changes: 9 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ enum {
#define ESCO_EV4 0x0010
#define ESCO_EV5 0x0020

#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)

/* ACL flags */
#define ACL_CONT 0x01
#define ACL_START 0x02
Expand Down Expand Up @@ -696,6 +698,13 @@ struct hci_ev_clock_offset {
__le16 clock_offset;
} __attribute__ ((packed));

#define HCI_EV_PKT_TYPE_CHANGE 0x1d
struct hci_ev_pkt_type_change {
__u8 status;
__le16 handle;
__le16 pkt_type;
} __attribute__ ((packed));

#define HCI_EV_PSCAN_REP_MODE 0x20
struct hci_ev_pscan_rep_mode {
bdaddr_t bdaddr;
Expand Down
1 change: 1 addition & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ struct hci_conn {
__u8 dev_class[3];
__u8 features[8];
__u16 interval;
__u16 pkt_type;
__u16 link_policy;
__u32 link_mode;
__u8 power_save;
Expand Down
32 changes: 24 additions & 8 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ void hci_acl_connect(struct hci_conn *conn)
BT_DBG("%p", conn);

conn->state = BT_CONNECT;
conn->out = 1;
conn->out = 1;

conn->link_mode = HCI_LM_MASTER;

conn->attempt++;
Expand All @@ -76,7 +77,7 @@ void hci_acl_connect(struct hci_conn *conn)
memcpy(conn->dev_class, ie->data.dev_class, 3);
}

cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
cp.pkt_type = cpu_to_le16(conn->pkt_type);
if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
cp.role_switch = 0x01;
else
Expand Down Expand Up @@ -122,7 +123,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn->out = 1;

cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
cp.pkt_type = cpu_to_le16(conn->pkt_type);

hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
}
Expand All @@ -138,7 +139,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
conn->out = 1;

cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(hdev->esco_type);
cp.pkt_type = cpu_to_le16(conn->pkt_type);

cp.tx_bandwidth = cpu_to_le32(0x00001f40);
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
Expand Down Expand Up @@ -199,13 +200,28 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
return NULL;

bacpy(&conn->dst, dst);
conn->hdev = hdev;
conn->type = type;
conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;
conn->hdev = hdev;
conn->type = type;
conn->mode = HCI_CM_ACTIVE;
conn->state = BT_OPEN;

conn->power_save = 1;

switch (type) {
case ACL_LINK:
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
break;
case SCO_LINK:
if (lmp_esco_capable(hdev))
conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
else
conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
break;
case ESCO_LINK:
conn->pkt_type = hdev->esco_type;
break;
}

skb_queue_head_init(&conn->data_q);

setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
Expand Down
32 changes: 25 additions & 7 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,14 +699,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
}

/* Set packet type for incoming connection */
if (!conn->out) {
if (!conn->out && hdev->hci_ver < 3) {
struct hci_cp_change_conn_ptype cp;
cp.handle = ev->handle;
cp.pkt_type = (conn->type == ACL_LINK) ?
cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);

hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
cp.pkt_type = cpu_to_le16(conn->pkt_type);
hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
sizeof(cp), &cp);
} else {
/* Update disconnect timer */
hci_conn_hold(conn);
Expand Down Expand Up @@ -786,7 +784,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
struct hci_cp_accept_sync_conn_req cp;

bacpy(&cp.bdaddr, &ev->bdaddr);
cp.pkt_type = cpu_to_le16(hdev->esco_type);
cp.pkt_type = cpu_to_le16(conn->pkt_type);

cp.tx_bandwidth = cpu_to_le32(0x00001f40);
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
Expand Down Expand Up @@ -1237,6 +1235,22 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_dev_unlock(hdev);
}

static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_pkt_type_change *ev = (void *) skb->data;
struct hci_conn *conn;

BT_DBG("%s status %d", hdev->name, ev->status);

hci_dev_lock(hdev);

conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn && !ev->status)
conn->pkt_type = __le16_to_cpu(ev->pkt_type);

hci_dev_unlock(hdev);
}

static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
Expand Down Expand Up @@ -1480,6 +1494,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_clock_offset_evt(hdev, skb);
break;

case HCI_EV_PKT_TYPE_CHANGE:
hci_pkt_type_change_evt(hdev, skb);
break;

case HCI_EV_PSCAN_REP_MODE:
hci_pscan_rep_mode_evt(hdev, skb);
break;
Expand Down

0 comments on commit a874641

Please sign in to comment.