Loading drivers/bluetooth/hci_usb.c +8 −8 Original line number Original line Diff line number Diff line Loading @@ -115,11 +115,11 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, /* Broadcom BCM2045 */ /* Broadcom BCM2045 */ { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* IBM/Lenovo ThinkPad with Broadcom chip */ /* IBM/Lenovo ThinkPad with Broadcom chip */ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Targus ACB10US */ /* Targus ACB10US */ { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, Loading @@ -128,17 +128,17 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, /* HP laptop with Broadcom chip */ /* HP laptop with Broadcom chip */ { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Dell laptop with Broadcom chip */ /* Dell laptop with Broadcom chip */ { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, /* Kensington Bluetooth USB adapter */ /* Kensington Bluetooth USB adapter */ { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* ISSC Bluetooth Adapter v3.1 */ /* ISSC Bluetooth Adapter v3.1 */ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, Loading @@ -148,8 +148,8 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, /* Belkin F8T012 and F8T013 devices */ /* Belkin F8T012 and F8T013 devices */ { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Digianswer devices */ /* Digianswer devices */ { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, Loading include/net/bluetooth/l2cap.h +6 −2 Original line number Original line Diff line number Diff line Loading @@ -129,8 +129,10 @@ struct l2cap_conf_rsp { __u8 data[0]; __u8 data[0]; } __attribute__ ((packed)); } __attribute__ ((packed)); #define L2CAP_CONF_SUCCESS 0x00 #define L2CAP_CONF_SUCCESS 0x0000 #define L2CAP_CONF_UNACCEPT 0x01 #define L2CAP_CONF_UNACCEPT 0x0001 #define L2CAP_CONF_REJECT 0x0002 #define L2CAP_CONF_UNKNOWN 0x0003 struct l2cap_conf_opt { struct l2cap_conf_opt { __u8 type; __u8 type; Loading Loading @@ -215,6 +217,8 @@ struct l2cap_pinfo { __u32 link_mode; __u32 link_mode; __u8 conf_req[64]; __u8 conf_len; __u8 conf_state; __u8 conf_state; __u8 conf_retry; __u8 conf_retry; __u16 conf_mtu; __u16 conf_mtu; Loading net/bluetooth/l2cap.c +80 −64 Original line number Original line Diff line number Diff line Loading @@ -507,6 +507,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } } /* Default config options */ /* Default config options */ pi->conf_len = 0; pi->conf_mtu = L2CAP_DEFAULT_MTU; pi->conf_mtu = L2CAP_DEFAULT_MTU; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; } } Loading Loading @@ -1271,42 +1272,6 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned return len; return len; } } static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len) { int type, hint, olen; unsigned long val; void *ptr = data; BT_DBG("sk %p len %d", sk, len); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val); hint = type & 0x80; type &= 0x7f; switch (type) { case L2CAP_CONF_MTU: l2cap_pi(sk)->conf_mtu = val; break; case L2CAP_CONF_FLUSH_TO: l2cap_pi(sk)->flush_to = val; break; case L2CAP_CONF_QOS: break; default: if (hint) break; /* FIXME: Reject unknown option */ break; } } } static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) { { struct l2cap_conf_opt *opt = *ptr; struct l2cap_conf_opt *opt = *ptr; Loading Loading @@ -1358,39 +1323,75 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) return ptr - data; return ptr - data; } } static inline int l2cap_conf_output(struct sock *sk, void **ptr) static int l2cap_parse_conf_req(struct sock *sk, void *data) { { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_pinfo *pi = l2cap_pi(sk); int result = 0; struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *req = pi->conf_req; int len = pi->conf_len; int type, hint, olen; unsigned long val; u16 result = L2CAP_CONF_SUCCESS; BT_DBG("sk %p", sk); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); hint = type & 0x80; type &= 0x7f; switch (type) { case L2CAP_CONF_MTU: pi->conf_mtu = val; break; case L2CAP_CONF_FLUSH_TO: pi->flush_to = val; break; case L2CAP_CONF_QOS: break; default: if (hint) break; result = L2CAP_CONF_UNKNOWN; *((u8 *) ptr++) = type; break; } } if (result == L2CAP_CONF_SUCCESS) { /* Configure output options and let the other side know /* Configure output options and let the other side know * which ones we don't like. */ * which ones we don't like. */ if (pi->conf_mtu < pi->omtu) if (pi->conf_mtu < pi->omtu) result = L2CAP_CONF_UNACCEPT; result = L2CAP_CONF_UNACCEPT; else else pi->omtu = pi->conf_mtu; pi->omtu = pi->conf_mtu; l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu); l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); } rsp->scid = cpu_to_le16(pi->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(0x0000); BT_DBG("sk %p result %d", sk, result); return ptr - data; return result; } } static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result) static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) { { struct l2cap_conf_rsp *rsp = data; struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *ptr = rsp->data; u16 flags = 0; BT_DBG("sk %p complete %d", sk, result ? 1 : 0); if (result) BT_DBG("sk %p", sk); *result = l2cap_conf_output(sk, &ptr); else flags = 0x0001; rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp->result = cpu_to_le16(result ? *result : 0); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(flags); rsp->flags = cpu_to_le16(flags); return ptr - data; return ptr - data; Loading Loading @@ -1535,7 +1536,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u16 dcid, flags; u8 rsp[64]; u8 rsp[64]; struct sock *sk; struct sock *sk; int result; int len; dcid = __le16_to_cpu(req->dcid); dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); flags = __le16_to_cpu(req->flags); Loading @@ -1548,25 +1549,40 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (sk->sk_state == BT_DISCONN) if (sk->sk_state == BT_DISCONN) goto unlock; goto unlock; l2cap_parse_conf_req(sk, req->data, cmd->len - sizeof(*req)); /* Reject if config buffer is too small. */ len = cmd->len - sizeof(*req); if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, L2CAP_CONF_REJECT, flags), rsp); goto unlock; } /* Store config. */ memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len); l2cap_pi(sk)->conf_len += len; if (flags & 0x0001) { if (flags & 0x0001) { /* Incomplete config. Send empty response. */ /* Incomplete config. Send empty response. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); l2cap_build_conf_rsp(sk, rsp, L2CAP_CONF_SUCCESS, 0x0001), rsp); goto unlock; goto unlock; } } /* Complete config. */ /* Complete config. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len = l2cap_parse_conf_req(sk, rsp); l2cap_build_conf_rsp(sk, rsp, &result), rsp); if (len < 0) if (result) goto unlock; goto unlock; /* Output config done */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); /* Output config done. */ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; /* Reset config buffer. */ l2cap_pi(sk)->conf_len = 0; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { sk->sk_state = BT_CONNECTED; sk->sk_state = BT_CONNECTED; l2cap_chan_ready(sk); l2cap_chan_ready(sk); Loading Loading
drivers/bluetooth/hci_usb.c +8 −8 Original line number Original line Diff line number Diff line Loading @@ -115,11 +115,11 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, /* Broadcom BCM2045 */ /* Broadcom BCM2045 */ { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* IBM/Lenovo ThinkPad with Broadcom chip */ /* IBM/Lenovo ThinkPad with Broadcom chip */ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Targus ACB10US */ /* Targus ACB10US */ { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, Loading @@ -128,17 +128,17 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, /* HP laptop with Broadcom chip */ /* HP laptop with Broadcom chip */ { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Dell laptop with Broadcom chip */ /* Dell laptop with Broadcom chip */ { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, /* Kensington Bluetooth USB adapter */ /* Kensington Bluetooth USB adapter */ { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* ISSC Bluetooth Adapter v3.1 */ /* ISSC Bluetooth Adapter v3.1 */ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, Loading @@ -148,8 +148,8 @@ static struct usb_device_id blacklist_ids[] = { { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, /* Belkin F8T012 and F8T013 devices */ /* Belkin F8T012 and F8T013 devices */ { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_WRONG_SCO_MTU }, { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, /* Digianswer devices */ /* Digianswer devices */ { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, Loading
include/net/bluetooth/l2cap.h +6 −2 Original line number Original line Diff line number Diff line Loading @@ -129,8 +129,10 @@ struct l2cap_conf_rsp { __u8 data[0]; __u8 data[0]; } __attribute__ ((packed)); } __attribute__ ((packed)); #define L2CAP_CONF_SUCCESS 0x00 #define L2CAP_CONF_SUCCESS 0x0000 #define L2CAP_CONF_UNACCEPT 0x01 #define L2CAP_CONF_UNACCEPT 0x0001 #define L2CAP_CONF_REJECT 0x0002 #define L2CAP_CONF_UNKNOWN 0x0003 struct l2cap_conf_opt { struct l2cap_conf_opt { __u8 type; __u8 type; Loading Loading @@ -215,6 +217,8 @@ struct l2cap_pinfo { __u32 link_mode; __u32 link_mode; __u8 conf_req[64]; __u8 conf_len; __u8 conf_state; __u8 conf_state; __u8 conf_retry; __u8 conf_retry; __u16 conf_mtu; __u16 conf_mtu; Loading
net/bluetooth/l2cap.c +80 −64 Original line number Original line Diff line number Diff line Loading @@ -507,6 +507,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } } /* Default config options */ /* Default config options */ pi->conf_len = 0; pi->conf_mtu = L2CAP_DEFAULT_MTU; pi->conf_mtu = L2CAP_DEFAULT_MTU; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; } } Loading Loading @@ -1271,42 +1272,6 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned return len; return len; } } static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len) { int type, hint, olen; unsigned long val; void *ptr = data; BT_DBG("sk %p len %d", sk, len); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val); hint = type & 0x80; type &= 0x7f; switch (type) { case L2CAP_CONF_MTU: l2cap_pi(sk)->conf_mtu = val; break; case L2CAP_CONF_FLUSH_TO: l2cap_pi(sk)->flush_to = val; break; case L2CAP_CONF_QOS: break; default: if (hint) break; /* FIXME: Reject unknown option */ break; } } } static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) { { struct l2cap_conf_opt *opt = *ptr; struct l2cap_conf_opt *opt = *ptr; Loading Loading @@ -1358,39 +1323,75 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) return ptr - data; return ptr - data; } } static inline int l2cap_conf_output(struct sock *sk, void **ptr) static int l2cap_parse_conf_req(struct sock *sk, void *data) { { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_pinfo *pi = l2cap_pi(sk); int result = 0; struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *req = pi->conf_req; int len = pi->conf_len; int type, hint, olen; unsigned long val; u16 result = L2CAP_CONF_SUCCESS; BT_DBG("sk %p", sk); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); hint = type & 0x80; type &= 0x7f; switch (type) { case L2CAP_CONF_MTU: pi->conf_mtu = val; break; case L2CAP_CONF_FLUSH_TO: pi->flush_to = val; break; case L2CAP_CONF_QOS: break; default: if (hint) break; result = L2CAP_CONF_UNKNOWN; *((u8 *) ptr++) = type; break; } } if (result == L2CAP_CONF_SUCCESS) { /* Configure output options and let the other side know /* Configure output options and let the other side know * which ones we don't like. */ * which ones we don't like. */ if (pi->conf_mtu < pi->omtu) if (pi->conf_mtu < pi->omtu) result = L2CAP_CONF_UNACCEPT; result = L2CAP_CONF_UNACCEPT; else else pi->omtu = pi->conf_mtu; pi->omtu = pi->conf_mtu; l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu); l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); } rsp->scid = cpu_to_le16(pi->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(0x0000); BT_DBG("sk %p result %d", sk, result); return ptr - data; return result; } } static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result) static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) { { struct l2cap_conf_rsp *rsp = data; struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *ptr = rsp->data; u16 flags = 0; BT_DBG("sk %p complete %d", sk, result ? 1 : 0); if (result) BT_DBG("sk %p", sk); *result = l2cap_conf_output(sk, &ptr); else flags = 0x0001; rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp->result = cpu_to_le16(result ? *result : 0); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(flags); rsp->flags = cpu_to_le16(flags); return ptr - data; return ptr - data; Loading Loading @@ -1535,7 +1536,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u16 dcid, flags; u8 rsp[64]; u8 rsp[64]; struct sock *sk; struct sock *sk; int result; int len; dcid = __le16_to_cpu(req->dcid); dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); flags = __le16_to_cpu(req->flags); Loading @@ -1548,25 +1549,40 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (sk->sk_state == BT_DISCONN) if (sk->sk_state == BT_DISCONN) goto unlock; goto unlock; l2cap_parse_conf_req(sk, req->data, cmd->len - sizeof(*req)); /* Reject if config buffer is too small. */ len = cmd->len - sizeof(*req); if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, L2CAP_CONF_REJECT, flags), rsp); goto unlock; } /* Store config. */ memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len); l2cap_pi(sk)->conf_len += len; if (flags & 0x0001) { if (flags & 0x0001) { /* Incomplete config. Send empty response. */ /* Incomplete config. Send empty response. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); l2cap_build_conf_rsp(sk, rsp, L2CAP_CONF_SUCCESS, 0x0001), rsp); goto unlock; goto unlock; } } /* Complete config. */ /* Complete config. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len = l2cap_parse_conf_req(sk, rsp); l2cap_build_conf_rsp(sk, rsp, &result), rsp); if (len < 0) if (result) goto unlock; goto unlock; /* Output config done */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); /* Output config done. */ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; /* Reset config buffer. */ l2cap_pi(sk)->conf_len = 0; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { sk->sk_state = BT_CONNECTED; sk->sk_state = BT_CONNECTED; l2cap_chan_ready(sk); l2cap_chan_ready(sk); Loading