예제 #1
0
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;
}
예제 #2
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;
}
예제 #3
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;
}
예제 #4
0
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;
}
예제 #5
0
파일: hcid.c 프로젝트: github188/SimpleCode
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;
    }
}