static int l2cap_sock_release(struct socket *sock) { struct sock *sk = sock->sk; struct sock *srv_sk = NULL; int err; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA && !l2cap_pi(sk)->incoming) srv_sk = l2cap_find_sock_by_fixed_cid_and_dir(L2CAP_CID_LE_DATA, &bt_sk(sk)->src, &bt_sk(sk)->dst, 1); BT_DBG("client:%p server:%p", sk, srv_sk); if (srv_sk) l2cap_sock_set_timer(srv_sk, 1); err = l2cap_sock_shutdown(sock, 2); sock_orphan(sk); l2cap_sock_kill(sk); return err; }
/* ---- L2CAP timers ---- */ static void l2cap_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; int reason; BT_DBG("sock %p state %d", sk, sk->sk_state); bh_lock_sock(sk); if (sock_owned_by_user(sk)) { /* sk is owned by user. Try again later */ l2cap_sock_set_timer(sk, HZ / 5); bh_unlock_sock(sk); sock_put(sk); return; } if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) reason = ECONNREFUSED; else if (sk->sk_state == BT_CONNECT && l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) reason = ECONNREFUSED; else reason = ETIMEDOUT; __l2cap_sock_close(sk, reason); bh_unlock_sock(sk); l2cap_sock_kill(sk); sock_put(sk); }
static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) { l2cap_disconn_req *req = (l2cap_disconn_req *) data; l2cap_disconn_rsp rsp; __u16 dcid, scid; struct sock *sk; scid = __le16_to_cpu(req->scid); dcid = __le16_to_cpu(req->dcid); BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) return 0; rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); sk->shutdown = SHUTDOWN_MASK; l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); l2cap_sock_kill(sk); return 0; }
static int l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn; struct sock *sk; if (!(conn = hcon->l2cap_data)) return 0; BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); if (conn->rx_skb) kfree_skb(conn->rx_skb); /* Kill channels */ while ((sk = conn->chan_list.head)) { bh_lock_sock(sk); l2cap_chan_del(sk, err); bh_unlock_sock(sk); l2cap_sock_kill(sk); } hcon->l2cap_data = NULL; kfree(conn); MOD_DEC_USE_COUNT; return 0; }
static int l2cap_sock_release(struct socket *sock) { struct sock *sk = sock->sk; struct sock *sk2 = NULL; int err; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; /* If this is an ATT socket, find it's matching server/client */ if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) sk2 = l2cap_find_sock_by_fixed_cid_and_dir(L2CAP_CID_LE_DATA, &bt_sk(sk)->src, &bt_sk(sk)->dst, l2cap_pi(sk)->incoming ? 0 : 1); /* If matching socket found, request tear down */ BT_DBG("sock:%p companion:%p", sk, sk2); if (sk2) l2cap_sock_set_timer(sk2, 1); err = l2cap_sock_shutdown(sock, 2); sock_orphan(sk); l2cap_sock_kill(sk); return err; }
/* Must be called on unlocked socket. */ static void l2cap_sock_close(struct sock *sk) { l2cap_sock_clear_timer(sk); lock_sock(sk); __l2cap_sock_close(sk, ECONNRESET); release_sock(sk); l2cap_sock_kill(sk); }
/* ----- L2CAP timers ------ */ static void l2cap_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; BT_DBG("sock %p state %d", sk, sk->state); bh_lock_sock(sk); __l2cap_sock_close(sk, ETIMEDOUT); bh_unlock_sock(sk); l2cap_sock_kill(sk); sock_put(sk); }
static int l2cap_sock_release(struct socket *sock) { struct sock *sk = sock->sk; int err; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; err = l2cap_sock_shutdown(sock, 2); sock_orphan(sk); l2cap_sock_kill(sk); return err; }
static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) { l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; __u16 dcid, scid; struct sock *sk; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) return 0; l2cap_chan_del(sk, 0); bh_unlock_sock(sk); l2cap_sock_kill(sk); return 0; }
static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) { struct l2cap_chan_list *list = &conn->chan_list; l2cap_conn_req *req = (l2cap_conn_req *) data; l2cap_conn_rsp rsp; struct sock *sk, *parent; int result = 0, status = 0; __u16 dcid = 0, scid = __le16_to_cpu(req->scid); __u16 psm = req->psm; BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); /* Check if we have socket listening on psm */ parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); if (!parent) { result = L2CAP_CR_BAD_PSM; goto sendresp; } result = L2CAP_CR_NO_MEM; /* Check for backlog size */ if (parent->ack_backlog > parent->max_ack_backlog) { BT_DBG("backlog full %d", parent->ack_backlog); goto response; } sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC); if (!sk) goto response; write_lock(&list->lock); /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(list, scid)) { write_unlock(&list->lock); sk->zapped = 1; l2cap_sock_kill(sk); goto response; } hci_conn_hold(conn->hcon); l2cap_sock_init(sk, parent); bacpy(&bluez_pi(sk)->src, conn->src); bacpy(&bluez_pi(sk)->dst, conn->dst); l2cap_pi(sk)->psm = psm; l2cap_pi(sk)->dcid = scid; __l2cap_chan_add(conn, sk, parent); dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sndtimeo); /* Service level security */ result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHEN_PEND; sk->state = BT_CONNECT2; l2cap_pi(sk)->ident = cmd->ident; if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) { if (!hci_conn_encrypt(conn->hcon)) goto done; } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { if (!hci_conn_auth(conn->hcon)) goto done; } sk->state = BT_CONFIG; result = status = 0; done: write_unlock(&list->lock); response: bh_unlock_sock(parent); sendresp: rsp.scid = __cpu_to_le16(scid); rsp.dcid = __cpu_to_le16(dcid); rsp.result = __cpu_to_le16(result); rsp.status = __cpu_to_le16(status); l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); return 0; }