Hi Frédéric, * Frédéric Dalleau <frederic.dalleau@xxxxxxxxxxxxxxx> [2012-11-19 17:35:57 +0100]: > In order to authenticate and configure an incoming SCO connection, the > BT_DEFER_SETUP option was added. This option is intended to defer reply > to Connect Request on SCO sockets. > When a connection is requested, the listening socket is unblocked but > the effective connection setup happens only on first recv. Any send > between accept and recv fails with -ENOTCONN. > --- > include/net/bluetooth/hci_core.h | 9 ++++--- > net/bluetooth/hci_event.c | 53 +++++++++++++++++++++++++++++++++++--- > net/bluetooth/sco.c | 35 ++++++++++++++++++++++--- > 3 files changed, 87 insertions(+), 10 deletions(-) > > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h > index ef5b85d..8fceb35 100644 > --- a/include/net/bluetooth/hci_core.h > +++ b/include/net/bluetooth/hci_core.h > @@ -376,7 +376,7 @@ extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt); > extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, > u16 flags); > > -extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); > +extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); > extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status); > extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); > extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); > @@ -577,6 +577,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); > int hci_conn_del(struct hci_conn *conn); > void hci_conn_hash_flush(struct hci_dev *hdev); > void hci_conn_check_pending(struct hci_dev *hdev); > +void hci_conn_accept(struct hci_conn *conn, int mask); > > struct hci_chan *hci_chan_create(struct hci_conn *conn); > void hci_chan_del(struct hci_chan *chan); > @@ -779,8 +780,10 @@ void hci_conn_del_sysfs(struct hci_conn *conn); > #define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR) > > /* ----- HCI protocols ----- */ > +#define HCI_PROTO_DEFER 0x01 > + > static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, > - __u8 type) > + __u8 type, __u8 *flags) Please fix the coding style here. > { > switch (type) { > case ACL_LINK: > @@ -788,7 +791,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, > > case SCO_LINK: > case ESCO_LINK: > - return sco_connect_ind(hdev, bdaddr); > + return sco_connect_ind(hdev, bdaddr, flags); > > default: > BT_ERR("unknown link type %d", type); > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c > index 9f5c5f2..f883ef5 100644 > --- a/net/bluetooth/hci_event.c > +++ b/net/bluetooth/hci_event.c > @@ -2047,15 +2047,54 @@ unlock: > hci_conn_check_pending(hdev); > } > > +void hci_conn_accept(struct hci_conn *conn, int mask) > +{ > + struct hci_dev *hdev = conn->hdev; > + > + BT_DBG("conn %p", conn); > + > + if (!lmp_esco_capable(hdev)) { > + struct hci_cp_accept_conn_req cp; > + > + conn->state = BT_CONFIG; > + bacpy(&cp.bdaddr, &conn->dst); > + > + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) > + cp.role = 0x00; /* Become master */ > + else > + cp.role = 0x01; /* Remain slave */ > + > + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), > + &cp); I don't think you need to break a line for this hci_send_cmd(), it won't cross the column 80. > + } else /* lmp_esco_capable(hdev)) */ { > + struct hci_cp_accept_sync_conn_req cp; > + > + conn->state = BT_CONFIG; > + bacpy(&cp.bdaddr, &conn->dst); > + cp.pkt_type = cpu_to_le16(conn->pkt_type); > + > + cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); > + cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); > + cp.max_latency = __constant_cpu_to_le16(0xffff); > + cp.content_format = cpu_to_le16(hdev->voice_setting); > + cp.retrans_effort = 0xff; > + > + hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, > + sizeof(cp), &cp); > + } > +} > + > static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) > { > struct hci_ev_conn_request *ev = (void *) skb->data; > int mask = hdev->link_mode; > + __u8 flags = 0; > > BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, > ev->link_type); > > - mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); > + mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, > + &flags); > > if ((mask & HCI_LM_ACCEPT) && > !hci_blacklist_lookup(hdev, &ev->bdaddr)) { > @@ -2081,12 +2120,13 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) > } > > memcpy(conn->dev_class, ev->dev_class, 3); > - conn->state = BT_CONNECT; > > hci_dev_unlock(hdev); > > - if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) { > + if (ev->link_type == ACL_LINK || > + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { > struct hci_cp_accept_conn_req cp; > + conn->state = BT_CONNECT; > > bacpy(&cp.bdaddr, &ev->bdaddr); > > @@ -2097,8 +2137,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) > > hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), > &cp); > - } else { > + } else if (!(flags & HCI_PROTO_DEFER)) { > struct hci_cp_accept_sync_conn_req cp; > + conn->state = BT_CONNECT; > > bacpy(&cp.bdaddr, &ev->bdaddr); > cp.pkt_type = cpu_to_le16(conn->pkt_type); > @@ -2111,6 +2152,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) > > hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, > sizeof(cp), &cp); > + } else { > + conn->state = BT_CONNECT2; > + hci_proto_connect_cfm(conn, 0); > + hci_conn_put(conn); > } > } else { > /* Connection rejected */ > diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c > index c6678f2..77210bf 100644 > --- a/net/bluetooth/sco.c > +++ b/net/bluetooth/sco.c > @@ -397,6 +397,7 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) > > if (parent) { > sk->sk_type = parent->sk_type; > + bt_sk(sk)->flags = bt_sk(parent)->flags; > security_sk_clone(parent, sk); > } > } > @@ -662,6 +663,28 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, > return err; > } > > +static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, > + struct msghdr *msg, size_t len, int flags) > +{ > + struct sock *sk = sock->sk; > + struct sco_pinfo *pi = sco_pi(sk); > + > + lock_sock(sk); > + > + if (sk->sk_state == BT_CONNECT2 && > + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { Wrong coding style here. > + hci_conn_accept(pi->conn->hcon, 0); > + sk->sk_state = BT_CONFIG; Where do you set sk_state to BT_CONNECTED. Doesn't it need to be here? Gustavo -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html