static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct link_key *key; BT_DBG("conn %p", conn); if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return 0; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (key && ((key->auth & SMP_AUTH_MITM) || !(rp->auth_req & SMP_AUTH_MITM))) { if (smp_encrypt_link(hcon, key) < 0) goto invalid_key; hcon->sec_level = authreq_to_seclevel(key->auth); if (!(hcon->link_mode & HCI_LM_ENCRYPT)) hci_conn_hold(hcon); return 0; } invalid_key: hcon->sec_req = FALSE; /* Switch to Pairing Connection Parameters */ hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT); skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); build_pairing_cmd(conn, &cp, NULL, rp->auth_req); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); hci_conn_hold(hcon); return 0; }
int smp_link_encrypt_cmplt(struct l2cap_conn *conn, u8 status, u8 encrypt) { struct hci_conn *hcon = conn->hcon; BT_DBG("smp: %d %d %d", status, encrypt, hcon->sec_req); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); #ifdef BLUETOOTH_CUSTOMIZE if (test_bit(HCI_CONN_LE_CONN_UPDATE_PEND, &hcon->pend)) { struct sock *sk; BT_DBG("HCI_CONN_LE_CONN_UPDATE_PEND"); sk = l2cap_find_sock_by_fixed_cid_and_dir(4, conn->src, conn->dst, 0); if (sk) { BT_DBG("call hci_le_conn_update"); hci_le_conn_update(hcon, bt_sk(sk)->le_params.interval_min, bt_sk(sk)->le_params.interval_max, bt_sk(sk)->le_params.latency, bt_sk(sk)->le_params.supervision_timeout); } } #endif /* BLUETOOTH_CUSTOMIZE */ if (!status && encrypt && hcon->sec_level < hcon->pending_sec_level) hcon->sec_level = hcon->pending_sec_level; if (!status && encrypt && !hcon->sec_req) return smp_distribute_keys(conn, 0); /* Fall back to Pairing request if failed a Link Security request */ else if (hcon->sec_req && (status || !encrypt)) smp_conn_security(conn, hcon->pending_sec_level); hci_conn_put(hcon); return 0; }
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; struct bt_power pwr; struct bt_le_params le_params; struct l2cap_conn *conn; int len, err = 0; u32 opt; BT_DBG("sk %p", sk); if (level == SOL_L2CAP) return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); if (level != SOL_BLUETOOTH) return -ENOPROTOOPT; lock_sock(sk); switch (optname) { case BT_SECURITY: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } sec.level = BT_SECURITY_LOW; len = min_t(unsigned int, sizeof(sec), optlen); if (copy_from_user((char *) &sec, optval, len)) { err = -EFAULT; break; } if (sec.level < BT_SECURITY_LOW || sec.level > BT_SECURITY_HIGH) { err = -EINVAL; break; } l2cap_pi(sk)->sec_level = sec.level; conn = l2cap_pi(sk)->conn; if (conn && l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) { if (!conn->hcon->out) { err = -EINVAL; break; } if (smp_conn_security(conn, sec.level)) break; err = 0; sk->sk_state = BT_CONFIG; } break; case BT_DEFER_SETUP: if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { err = -EINVAL; break; } if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } bt_sk(sk)->defer_setup = opt; break; case BT_POWER: if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } pwr.force_active = 1; len = min_t(unsigned int, sizeof(pwr), optlen); if (copy_from_user((char *) &pwr, optval, len)) { err = -EFAULT; break; } l2cap_pi(sk)->force_active = pwr.force_active; break; case BT_AMP_POLICY: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } if ((opt > BT_AMP_POLICY_PREFER_AMP) || ((l2cap_pi(sk)->mode != L2CAP_MODE_ERTM) && (l2cap_pi(sk)->mode != L2CAP_MODE_STREAMING))) { err = -EINVAL; break; } l2cap_pi(sk)->amp_pref = (u8) opt; BT_DBG("BT_AMP_POLICY now %d", opt); if ((sk->sk_state == BT_CONNECTED) && (l2cap_pi(sk)->amp_move_role == L2CAP_AMP_MOVE_NONE)) l2cap_amp_move_init(sk); break; case BT_FLUSHABLE: if (get_user(opt, (u32 __user *) optval)) { err = -EFAULT; break; } l2cap_pi(sk)->flushable = opt; break; case BT_LE_PARAMS: if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { err = -EINVAL; break; } if (copy_from_user((char *) &le_params, optval, sizeof(struct bt_le_params))) { err = -EFAULT; break; } conn = l2cap_pi(sk)->conn; if (!conn || !conn->hcon || l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) { memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); break; } if (!conn->hcon->out || !l2cap_sock_le_params_valid(&le_params)) { err = -EINVAL; break; } memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params)); hci_le_conn_update(conn->hcon, le_params.interval_min, le_params.interval_max, le_params.latency, le_params.supervision_timeout); break; default: err = -ENOPROTOOPT; break; } release_sock(sk); return err; }
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) { struct hci_conn *hcon = conn->hcon; __u8 authreq; BT_DBG("conn %p hcon %p %d req: %d", conn, hcon, hcon->sec_level, sec_level); if (IS_ERR(hcon->hdev->tfm)) return 1; if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) return -EINPROGRESS; if (sec_level == BT_SECURITY_LOW) return 1; if (hcon->sec_level >= sec_level) return 1; authreq = seclevel_to_authreq(sec_level); hcon->smp_conn = conn; hcon->pending_sec_level = sec_level; if ((hcon->link_mode & HCI_LM_MASTER) && !hcon->sec_req) { struct link_key *key; key = hci_find_link_key_type(hcon->hdev, conn->dst, KEY_TYPE_LTK); if (smp_encrypt_link(hcon, key) == 0) goto done; } hcon->sec_req = FALSE; if (hcon->link_mode & HCI_LM_MASTER) { struct smp_cmd_pairing cp; hci_le_conn_update(hcon, SMP_MIN_CONN_INTERVAL, SMP_MAX_CONN_INTERVAL, SMP_MAX_CONN_LATENCY, SMP_SUPERVISION_TIMEOUT); build_pairing_cmd(conn, &cp, NULL, authreq); hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); hci_conn_hold(hcon); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); } done: set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); return 0; }
static void hci_event_received(u8* data, u16 len) { u8 event_code; u8 param_len; u8 subcode; u8 *param; /* event format 0: event code 1: parameter total length *: parameters */ event_code = data[0]; param_len = data[1]; param = data + 2; hci_dumphex("EVT", data, len); switch (event_code) { #if !DISABLE_BT_CLASSICAL case HCI_CONN_CMPLT_EVT: hci_conn_cmplt(param, param_len); break; case HCI_CONN_REQ_EVT: hci_conn_req(param, param_len); break; #endif case HCI_DISCONN_CMPLT_EVT: hci_disconn_cmplt(param, param_len); break; case HCI_CMD_CMPLT_EVT: hci_cmd_cmplt(param, param_len); break; case HCI_CMD_STATUS_EVT: hci_cmd_status(param, param_len); break; case HCI_NUM_OF_CMPLT_PKTS_EVT: hci_num_of_cmplt_pkts(param, param_len); break; case HCI_HW_ERR_EVT: break; #if !DISABLE_BT_CLASSICAL case HCI_IO_CAP_REQ: hci_io_cap_req(param, param_len); break; case HCI_IO_CAP_RSP: hci_io_cap_rsp(param, param_len); break; case HCI_USER_CFM_REQ: hci_user_cfm_req(param, param_len); break; case HCI_SIMPLE_PAIR_CMPLT: hci_simple_pair_cmplt(param, param_len); break; #endif case HCI_LE_META_EVT: subcode = data[2]; switch(subcode) { case HCI_LE_CONN_CMPLT_EVT: hci_le_conn_cmplt(param, param_len); break; case HCI_LE_ADV_REPORT_EVT: hci_le_adv_report(param, param_len); break; case HCI_LE_CONN_UPDATE_EVT: hci_le_conn_update(param, param_len); break; case HCI_LE_LONG_TERM_KEY_REQ_EVT: hci_le_long_term_key_req(param, param_len); break; } case 0xFF: #if EM9301 { void em_event_input( u8* data, u8 len ); em_event_input( param, param_len ); } #endif break; } }