예제 #1
0
static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_disconn_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	if (ev->status)
		return;

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn) {
		conn->state = BT_CLOSED;

		hci_proto_disconn_cfm(conn, ev->reason);
		hci_conn_del(conn);
	}

	hci_dev_unlock(hdev);
}
예제 #2
0
static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
{
	struct hci_cp_create_conn *cp;
	struct hci_conn *conn;

	BT_DBG("%s status 0x%x", hdev->name, status);

	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
	if (!cp)
		return;

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);

	BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);

	if (status) {
		if (conn && conn->state == BT_CONNECT) {
			if (status != 0x0c || conn->attempt > 2) {
				conn->state = BT_CLOSED;
				hci_proto_connect_cfm(conn, status);
				hci_conn_del(conn);
			} else
				conn->state = BT_CONNECT2;
		}
	} else {
		if (!conn) {
			conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
			if (conn) {
				conn->out = 1;
				conn->link_mode |= HCI_LM_MASTER;
			} else
				BT_ERR("No memmory for new connection");
		}
	}

	hci_dev_unlock(hdev);
}
예제 #3
0
static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_role_discovery *rp = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	if (rp->status)
		return;

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
	if (conn) {
		if (rp->role)
			conn->link_mode &= ~HCI_LM_MASTER;
		else
			conn->link_mode |= HCI_LM_MASTER;
	}

	hci_dev_unlock(hdev);
}
예제 #4
0
/* Disconnect Complete */
static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
	struct hci_conn *conn = NULL;
	__u16 handle = __le16_to_cpu(dc->handle);

	BT_DBG("%s status %d", hdev->name, dc->status);

	if (dc->status)
		return;

	hci_dev_lock(hdev);
	
	conn = conn_hash_lookup_handle(hdev, handle);
	if (conn) {
		conn->state = BT_CLOSED;
		hci_proto_disconn_ind(conn, dc->reason);
		hci_conn_del(conn);
	}

	hci_dev_unlock(hdev);
}
예제 #5
0
static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
{
	struct hci_cp_exit_sniff_mode *cp;
	struct hci_conn *conn;

	BT_DBG("%s status 0x%x", hdev->name, status);

	if (!status)
		return;

	cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
	if (!cp)
		return;

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
	if (conn)
		clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);

	hci_dev_unlock(hdev);
}
예제 #6
0
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_clock_offset *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn && !ev->status) {
		struct inquiry_entry *ie;

		ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
		if (ie) {
			ie->data.clock_offset = ev->clock_offset;
			ie->timestamp = jiffies;
		}
	}

	hci_dev_unlock(hdev);
}
예제 #7
0
/* Role Change */
static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	evt_role_change *rc = (evt_role_change *) skb->data;
	struct hci_conn *conn = NULL;

	BT_DBG("%s status %d", hdev->name, rc->status);

	if (rc->status)
		return;

	hci_dev_lock(hdev);
	
	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
	if (conn) {
		if (rc->role)
			conn->link_mode &= ~HCI_LM_MASTER;
		else 
			conn->link_mode |= HCI_LM_MASTER;
	}

	hci_dev_unlock(hdev);
}
예제 #8
0
//BT_TIK 2011.09.23 SH Start : QoS patch from IL
static inline void hci_flowspec_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_flowspec_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	if (!ev->status) {
		hci_dev_lock(hdev);

		conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
		if (conn) {
/*
			conn->qos_info.delay_variation =
					le32_to_cpu(ev->qos.delay_variation);
			conn->qos_info.latency = le32_to_cpu(ev->qos.latency);
			conn->qos_info.peak_bandwidth =
					le32_to_cpu(ev->qos.peak_bandwidth);
			conn->qos_info.service_type = ev->qos.service_type;
			conn->qos_info.token_rate = le32_to_cpu(ev->qos.token_rate);
*/
			conn->flowspec.bucket_size =
					le32_to_cpu(ev->flowspec.bucket_size);
			conn->flowspec.flowdir = ev->flowspec.flowdir;
			conn->flowspec.latency =
					le32_to_cpu(ev->flowspec.latency);
			conn->flowspec.peak_bandwidth = le32_to_cpu(ev->flowspec.peak_bandwidth);
			conn->flowspec.service_type = ev->flowspec.service_type;
			conn->flowspec.token_rate = le32_to_cpu(ev->flowspec.token_rate);
		}

		hci_dev_unlock(hdev);
	}
    //BT_TIK 2011.09.23 SH : Removed HCI_OP_SET_FLOW_SPEC because kernel version of
	//                      GT-P1010 is different from one of patch from IL
	//hci_req_complete(hdev, HCI_OP_SET_FLOW_SPEC, ev->status);
	hci_req_complete(hdev, ev->status);
}
예제 #9
0
static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_remote_ext_features *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s", hdev->name);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn) {
		if (!ev->status && ev->page == 0x01) {
			struct inquiry_entry *ie;

			if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)))
				ie->data.ssp_mode = (ev->features[0] & 0x01);

			conn->ssp_mode = (ev->features[0] & 0x01);
		}

		if (conn->state == BT_CONFIG) {
			if (!ev->status && hdev->ssp_mode > 0 &&
					conn->ssp_mode > 0 && conn->out &&
					conn->sec_level != BT_SECURITY_SDP) {
				struct hci_cp_auth_requested cp;
				cp.handle = ev->handle;
				hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
							sizeof(cp), &cp);
			} else {
				conn->state = BT_CONNECTED;
				hci_proto_connect_cfm(conn, ev->status);
				hci_conn_put(conn);
			}
		}
	}

	hci_dev_unlock(hdev);
}
예제 #10
0
static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_write_link_policy *rp = (void *) skb->data;
	struct hci_conn *conn;
	void *sent;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	if (rp->status)
		return;

	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
	if (!sent)
		return;

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
	if (conn)
		conn->link_policy = get_unaligned_le16(sent + 2);

	hci_dev_unlock(hdev);
}
예제 #11
0
static void confirm_work(struct work_struct *work)
{
	struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
	struct l2cap_conn *conn = smp->conn;
	struct hci_dev *hdev = conn->hcon->hdev;
	struct crypto_blkcipher *tfm = hdev->tfm_aes;
	struct smp_cmd_pairing_confirm cp;
	int ret;
	u8 reason;

	BT_DBG("conn %p", conn);

	/* Prevent mutual access to hdev->tfm_aes */
	hci_dev_lock(hdev);

	ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
		     conn->hcon->init_addr_type, &conn->hcon->init_addr,
		     conn->hcon->resp_addr_type, &conn->hcon->resp_addr,
		     cp.confirm_val);

	hci_dev_unlock(hdev);

	if (ret) {
		reason = SMP_UNSPECIFIED;
		goto error;
	}

	clear_bit(SMP_FLAG_CFM_PENDING, &smp->smp_flags);

	smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);

	return;

error:
	smp_failure(conn, reason);
}
예제 #12
0
/* Mode Change */
static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn) {
		conn->mode = ev->mode;
		conn->interval = __le16_to_cpu(ev->interval);

		if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
			if (conn->mode == HCI_CM_ACTIVE)
				conn->power_save = 1;
			else
				conn->power_save = 0;
		}
	}

	hci_dev_unlock(hdev);
}
예제 #13
0
파일: hci_event.c 프로젝트: kzlin129/tt-gpl
/* Authentication Complete */
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data;
	struct hci_conn *conn = NULL;
	__u16 handle = __le16_to_cpu(ev->handle);

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, handle);
	if (conn) {
		if (!ev->status)
			conn->link_mode |= HCI_LM_AUTH;

		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);

		hci_auth_cfm(conn, ev->status);

		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
			if (!ev->status) {
				struct hci_cp_set_conn_encrypt cp;
				cp.handle  = __cpu_to_le16(conn->handle);
				cp.encrypt = 1;
				hci_send_cmd(conn->hdev, OGF_LINK_CTL,
						OCF_SET_CONN_ENCRYPT,
						sizeof(cp), &cp);
			} else {
				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
				hci_encrypt_cfm(conn, ev->status, 0x00);
			}
		}
	}

	hci_dev_unlock(hdev);
}
예제 #14
0
static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
	if (!conn) {
		if (ev->link_type == ESCO_LINK)
			goto unlock;

		conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
		if (!conn)
			goto unlock;

		conn->type = SCO_LINK;
	}

	if (!ev->status) {
		conn->handle = __le16_to_cpu(ev->handle);
		conn->state  = BT_CONNECTED;

		hci_conn_add_sysfs(conn);
	} else
		conn->state = BT_CLOSED;

	hci_proto_connect_cfm(conn, ev->status);
	if (ev->status)
		hci_conn_del(conn);

unlock:
	hci_dev_unlock(hdev);
}
예제 #15
0
/* Connect Complete */
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
	struct hci_conn *conn, *pend;

	BT_DBG("%s", hdev->name);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
	if (!conn) {
		hci_dev_unlock(hdev);
		return;
	}

	if (!ev->status) {
		conn->handle = __le16_to_cpu(ev->handle);
		conn->state  = BT_CONNECTED;

		if (test_bit(HCI_AUTH, &hdev->flags))
			conn->link_mode |= HCI_LM_AUTH;

		if (test_bit(HCI_ENCRYPT, &hdev->flags))
			conn->link_mode |= HCI_LM_ENCRYPT;

		/* Get remote features */
		if (conn->type == ACL_LINK) {
			struct hci_cp_read_remote_features cp;
			cp.handle = ev->handle;
			hci_send_cmd(hdev, OGF_LINK_CTL,
				OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp);
		}

		/* Set link policy */
		if (conn->type == ACL_LINK && hdev->link_policy) {
			struct hci_cp_write_link_policy cp;
			cp.handle = ev->handle;
			cp.policy = __cpu_to_le16(hdev->link_policy);
			hci_send_cmd(hdev, OGF_LINK_POLICY,
				OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
		}

		/* Set packet type for incoming connection */
		if (!conn->out) {
			struct hci_cp_change_conn_ptype cp;
			cp.handle = ev->handle;
			cp.pkt_type = (conn->type == ACL_LINK) ?
				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);

			hci_send_cmd(hdev, OGF_LINK_CTL,
				OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
		} else {
			/* Update disconnect timer */
			hci_conn_hold(conn);
			hci_conn_put(conn);
		}
	} else
		conn->state = BT_CLOSED;

	if (conn->type == ACL_LINK) {
		struct hci_conn *sco = conn->link;
		if (sco) {
			if (!ev->status)
				hci_add_sco(sco, conn->handle);
			else {
				hci_proto_connect_cfm(sco, ev->status);
				hci_conn_del(sco);
			}
		}
	}

	hci_proto_connect_cfm(conn, ev->status);
	if (ev->status)
		hci_conn_del(conn);

	pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
	if (pend)
		hci_acl_connect(pend);

	hci_dev_unlock(hdev);
}
예제 #16
0
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
						u8 local_io, u8 remote_io)
{
	struct hci_conn *hcon = conn->hcon;
	u8 method;
	u32 passkey = 0;
	int ret = 0;

	/* Initialize key to JUST WORKS */
	memset(hcon->tk, 0, sizeof(hcon->tk));
	hcon->tk_valid = FALSE;
	hcon->auth = auth;

	/* By definition, OOB data will be used if both sides have it available
	 */
	if (remote_oob && hcon->oob) {
		method = SMP_REQ_OOB;
		goto agent_request;
	}

	BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);

	/* If neither side wants MITM, use JUST WORKS */
	/* If either side has unknown io_caps, use JUST_WORKS */
	if (!(auth & SMP_AUTH_MITM) ||
			local_io > SMP_IO_KEYBOARD_DISPLAY ||
			remote_io > SMP_IO_KEYBOARD_DISPLAY) {
		hcon->auth &= ~SMP_AUTH_MITM;
		hcon->tk_valid = TRUE;
		return 0;
	}

	/* MITM is now officially requested, but not required */
	/* Determine what we need (if anything) from the agent */
	method = gen_method[local_io][remote_io];

	BT_DBG("tk_method: %d", method);

	if (method == SMP_JUST_WORKS || method == SMP_JUST_CFM)
		hcon->auth &= ~SMP_AUTH_MITM;

	/* Don't bother confirming unbonded JUST_WORKS */
	if (!(auth & SMP_AUTH_BONDING) && method == SMP_JUST_CFM) {
		hcon->tk_valid = TRUE;
		return 0;
	} else if (method == SMP_JUST_WORKS) {
		hcon->tk_valid = TRUE;
		return 0;
	} else if (method == SMP_OVERLAP) {
		if (hcon->link_mode & HCI_LM_MASTER)
			method = SMP_CFM_PASSKEY;
		else
			method = SMP_REQ_PASSKEY;
	}

	BT_DBG("tk_method-2: %d", method);

	if (method == SMP_CFM_PASSKEY) {
		u8 key[16];
		/* Generate a passkey for display. It is not valid until
		 * confirmed.
		 */
		memset(key, 0, sizeof(key));
		get_random_bytes(&passkey, sizeof(passkey));
		passkey %= 1000000;
		put_unaligned_le32(passkey, key);
		swap128(key, hcon->tk);
		BT_DBG("PassKey: %d", passkey);
	}

agent_request:
	hci_dev_lock(hcon->hdev);

	switch (method) {
	case SMP_REQ_PASSKEY:
		ret = mgmt_user_confirm_request(hcon->hdev->id,
				HCI_EV_USER_PASSKEY_REQUEST, conn->dst, 0);
		break;
	case SMP_CFM_PASSKEY:
	default:
		ret = mgmt_user_confirm_request(hcon->hdev->id,
			HCI_EV_USER_CONFIRM_REQUEST, conn->dst, passkey);
		break;
	}

	hci_dev_unlock(hcon->hdev);

	return ret;
}
예제 #17
0
static void random_work(struct work_struct *work)
{
	struct smp_chan *smp = container_of(work, struct smp_chan, random);
	struct l2cap_conn *conn = smp->conn;
	struct hci_conn *hcon = conn->hcon;
	struct hci_dev *hdev = hcon->hdev;
	struct crypto_blkcipher *tfm = hdev->tfm_aes;
	u8 reason, confirm[16];
	int ret;

	if (IS_ERR_OR_NULL(tfm)) {
		reason = SMP_UNSPECIFIED;
		goto error;
	}

	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");

	/* Prevent mutual access to hdev->tfm_aes */
	hci_dev_lock(hdev);

	ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
		     hcon->init_addr_type, &hcon->init_addr,
		     hcon->resp_addr_type, &hcon->resp_addr, confirm);

	hci_dev_unlock(hdev);

	if (ret) {
		reason = SMP_UNSPECIFIED;
		goto error;
	}

	if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
		BT_ERR("Pairing failed (confirmation values mismatch)");
		reason = SMP_CONFIRM_FAILED;
		goto error;
	}

	if (hcon->out) {
		u8 stk[16];
		__le64 rand = 0;
		__le16 ediv = 0;

		smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk);

		memset(stk + smp->enc_key_size, 0,
		       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);

		if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) {
			reason = SMP_UNSPECIFIED;
			goto error;
		}

		hci_le_start_enc(hcon, ediv, rand, stk);
		hcon->enc_key_size = smp->enc_key_size;
	} else {
		u8 stk[16], auth;
		__le64 rand = 0;
		__le16 ediv = 0;

		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
			     smp->prnd);

		smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk);

		memset(stk + smp->enc_key_size, 0,
		       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);

		if (hcon->pending_sec_level == BT_SECURITY_HIGH)
			auth = 1;
		else
			auth = 0;

		hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
			    HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size,
			    ediv, rand);
	}

	return;

error:
	smp_failure(conn, reason);
}
예제 #18
0
static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_remote_features *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn) {
		if (!ev->status)
			memcpy(conn->features, ev->features, 8);

		if (conn->state == BT_CONFIG) {
			if (!ev->status && lmp_ssp_capable(hdev) &&
						lmp_ssp_capable(conn)) {
				struct hci_cp_read_remote_ext_features cp;
				cp.handle = ev->handle;
				cp.page = 0x01;
				hci_send_cmd(hdev,
					HCI_OP_READ_REMOTE_EXT_FEATURES,
							sizeof(cp), &cp);
			} else {
                if (!(conn->features[3]&(0x02|0x04)))   /* not support 2M/3M EDR. 0x02=2M  0x04=3M */
                {                    
                    if (!(conn->link_mode & HCI_LM_MASTER)) /* act as slave */
                    {                        
                        if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) 
                        {
                            struct hci_cp_switch_role cp;
                            cp.bdaddr.b[0]= 0;    /* init */
                            cp.bdaddr.b[1]= 0;
                            cp.bdaddr.b[2]= 0;
                            cp.bdaddr.b[3]= 0;
                            cp.bdaddr.b[4]= 0;
                            cp.bdaddr.b[5]= 0;
                            cp.role = 0;

                            bacpy(&cp.bdaddr, &conn->dst);
                            /* switch to master */
                            cp.role = 0x0; 
                            BT_DBG("switch to master");
                            hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
                        }
                    }
                    else 
                    {
                        struct hci_cp_write_link_policy cp;
                        cp.handle = 0; /* init */
                        cp.policy = 0;

                        /* disable role_switch if already act as master */
                        cp.handle = cpu_to_le16(conn->handle);
                        conn->link_policy |= HCI_LP_SNIFF;
                        conn->link_policy |= HCI_LP_HOLD;
                        conn->link_policy &= ~HCI_LP_RSWITCH;
                        cp.policy = cpu_to_le16(conn->link_policy);
                        hci_send_cmd(conn->hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
                    }
                }                        
				conn->state = BT_CONNECTED;
				hci_proto_connect_cfm(conn, ev->status);
				hci_conn_put(conn);
			}
		}
	}

	hci_dev_unlock(hdev);
}
예제 #19
0
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
						u8 local_io, u8 remote_io)
{
	struct hci_conn *hcon = conn->hcon;
	u8 method;
	u32 passkey = 0;
	int ret = 0;

	
	memset(hcon->tk, 0, sizeof(hcon->tk));
	hcon->tk_valid = FALSE;
	hcon->auth = auth;

	if (remote_oob && hcon->oob) {
		method = SMP_REQ_OOB;
		goto agent_request;
	}

	BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);

	
	
	if (!(auth & SMP_AUTH_MITM) ||
			local_io > SMP_IO_KEYBOARD_DISPLAY ||
			remote_io > SMP_IO_KEYBOARD_DISPLAY) {
		hcon->auth &= ~SMP_AUTH_MITM;
		hcon->tk_valid = TRUE;
		return 0;
	}

	
	
	method = gen_method[local_io][remote_io];

	BT_DBG("tk_method: %d", method);

	if (method == SMP_JUST_WORKS || method == SMP_JUST_CFM)
		hcon->auth &= ~SMP_AUTH_MITM;

	
	if (!(auth & SMP_AUTH_BONDING) && method == SMP_JUST_CFM) {
		hcon->tk_valid = TRUE;
		return 0;
	} else if (method == SMP_JUST_WORKS) {
		hcon->tk_valid = TRUE;
		return 0;
	} else if (method == SMP_OVERLAP) {
		if (hcon->link_mode & HCI_LM_MASTER)
			method = SMP_CFM_PASSKEY;
		else
			method = SMP_REQ_PASSKEY;
	}

	BT_DBG("tk_method-2: %d", method);

	if (method == SMP_CFM_PASSKEY) {
		u8 key[16];
		memset(key, 0, sizeof(key));
		get_random_bytes(&passkey, sizeof(passkey));
		passkey %= 1000000;
		put_unaligned_le32(passkey, key);
		swap128(key, hcon->tk);
		BT_DBG("PassKey: %d", passkey);
	}

agent_request:
	hci_dev_lock(hcon->hdev);

	switch (method) {
	case SMP_REQ_PASSKEY:
		ret = mgmt_user_confirm_request(hcon->hdev->id,
				HCI_EV_USER_PASSKEY_REQUEST, conn->dst, 0);
		break;
	case SMP_CFM_PASSKEY:
	default:
		ret = mgmt_user_confirm_request(hcon->hdev->id,
			HCI_EV_USER_CONFIRM_REQUEST, conn->dst, passkey);
		break;
	}

	hci_dev_unlock(hcon->hdev);

	return ret;
}
예제 #20
0
static inline 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;

	BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
					batostr(&ev->bdaddr), ev->link_type);

	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);

	if (mask & HCI_LM_ACCEPT) {
		/* Connection accepted */
		struct inquiry_entry *ie;
		struct hci_conn *conn;

		hci_dev_lock(hdev);

		if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr)))
			memcpy(ie->data.dev_class, ev->dev_class, 3);

		conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
		if (!conn) {
			/* pkt_type not yet used for incoming connections */
			if (!(conn = hci_conn_add(hdev, ev->link_type, 0,
							&ev->bdaddr))) {
				BT_ERR("No memmory for new connection");
				hci_dev_unlock(hdev);
				return;
			}
		}

		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)) {
			struct hci_cp_accept_conn_req cp;

			bacpy(&cp.bdaddr, &ev->bdaddr);

			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);
		} else {
			struct hci_cp_accept_sync_conn_req cp;

			bacpy(&cp.bdaddr, &ev->bdaddr);
			cp.pkt_type = cpu_to_le16(conn->pkt_type);

			cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
			cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
			cp.max_latency    = 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);
		}
	} else {
		/* Connection rejected */
		struct hci_cp_reject_conn_req cp;

		bacpy(&cp.bdaddr, &ev->bdaddr);
		cp.reason = 0x0f;
		hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
	}
}
예제 #21
0
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_auth_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn) {
		if (!ev->status)
			conn->link_mode |= HCI_LM_AUTH;
		else
			conn->sec_level = BT_SECURITY_LOW;
			
		//modify the problem of PIN or KEY MISSIMG  ZTE_BT_QXX_20101118 begin		
		if (ev->status == 0x06 && hdev->ssp_mode > 0 &&
                                       conn->ssp_mode > 0 && conn->out) { // PIN or KEY MISSING
                       struct hci_cp_auth_requested cp;
                       cp.handle = ev->handle;
                       hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
                                               sizeof(cp), &cp);
                       goto done;
               }
    //modify the problem of PIN or KEY MISSIMG  ZTE_BT_QXX_20101118 end
		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);

		if (conn->state == BT_CONFIG) {
			if (!ev->status && hdev->ssp_mode > 0 &&
							conn->ssp_mode > 0) {
				struct hci_cp_set_conn_encrypt cp;
				cp.handle  = ev->handle;
				cp.encrypt = 0x01;
				hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
							sizeof(cp), &cp);
			} else {
				conn->state = BT_CONNECTED;
				hci_proto_connect_cfm(conn, ev->status);
				hci_conn_put(conn);
			}
		} else {
			hci_auth_cfm(conn, ev->status);

			hci_conn_hold(conn);
			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
			hci_conn_put(conn);
		}

		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
			if (!ev->status) {
				struct hci_cp_set_conn_encrypt cp;
				cp.handle  = ev->handle;
				cp.encrypt = 0x01;
				hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
							sizeof(cp), &cp);
			} else {
				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
				hci_encrypt_cfm(conn, ev->status, 0x00);
			}
		}
	}
	
//modify the problem of PIN or KEY MISSIMG  ZTE_BT_QXX_20101118
done:   
	hci_dev_unlock(hdev);
}
예제 #22
0
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_conn_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s", hdev->name);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
	if (!conn) {
		if (ev->link_type != SCO_LINK)
			goto unlock;

		conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
		if (!conn)
			goto unlock;

		conn->type = SCO_LINK;
	}

	if (!ev->status) {
		conn->handle = __le16_to_cpu(ev->handle);

		if (conn->type == ACL_LINK) {
			conn->state = BT_CONFIG;
			hci_conn_hold(conn);
			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
		} else
			conn->state = BT_CONNECTED;

		hci_conn_hold_device(conn);
		hci_conn_add_sysfs(conn);

		if (test_bit(HCI_AUTH, &hdev->flags))
			conn->link_mode |= HCI_LM_AUTH;

		if (test_bit(HCI_ENCRYPT, &hdev->flags))
			conn->link_mode |= HCI_LM_ENCRYPT;

		/* Get remote features */
		if (conn->type == ACL_LINK) {
			struct hci_cp_read_remote_features cp;
			cp.handle = ev->handle;
			hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
							sizeof(cp), &cp);
		}

		/* Set packet type for incoming connection */
		if (!conn->out && hdev->hci_ver < 3) {
			struct hci_cp_change_conn_ptype cp;
			cp.handle = ev->handle;
			cp.pkt_type = cpu_to_le16(conn->pkt_type);
			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
							sizeof(cp), &cp);
		}
	} else
		conn->state = BT_CLOSED;

	if (conn->type == ACL_LINK) {
		struct hci_conn *sco = conn->link;
		if (sco) {
			if (!ev->status) {
				if (lmp_esco_capable(hdev))
					hci_setup_sync(sco, conn->handle);
				else
					hci_add_sco(sco, conn->handle);
			} else {
				hci_proto_connect_cfm(sco, ev->status);
				hci_conn_del(sco);
			}
		}
	}

	if (ev->status) {
		hci_proto_connect_cfm(conn, ev->status);
		hci_conn_del(conn);
	} else if (ev->link_type != ACL_LINK)
		hci_proto_connect_cfm(conn, ev->status);

unlock:
	hci_dev_unlock(hdev);

	hci_conn_check_pending(hdev);
}
예제 #23
0
/* Connect Complete */
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
	struct hci_conn *conn = NULL;

	BT_DBG("%s", hdev->name);

	hci_dev_lock(hdev);
	
	conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
	if (!conn) {
		hci_dev_unlock(hdev);
		return;
	}

	if (!cc->status) {
		conn->handle = __le16_to_cpu(cc->handle);
		conn->state  = BT_CONNECTED;

		if (test_bit(HCI_AUTH, &hdev->flags))
			conn->link_mode |= HCI_LM_AUTH;
		
		if (test_bit(HCI_ENCRYPT, &hdev->flags))
			conn->link_mode |= HCI_LM_ENCRYPT;


		/* Set link policy */
		if (conn->type == ACL_LINK && hdev->link_policy) {
			write_link_policy_cp lp;
			lp.handle = cc->handle;
			lp.policy = __cpu_to_le16(hdev->link_policy);
			hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
				WRITE_LINK_POLICY_CP_SIZE, &lp);
		}

		/* Set packet type for incomming connection */
		if (!conn->out) {
			change_conn_ptype_cp cp;
			cp.handle = cc->handle;
			cp.pkt_type = (conn->type == ACL_LINK) ? 
				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);

			hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE,
				CHANGE_CONN_PTYPE_CP_SIZE, &cp);
		}
	} else
		conn->state = BT_CLOSED;

	if (conn->type == ACL_LINK) {
		struct hci_conn *sco = conn->link;
		if (sco) {
			if (!cc->status)
				hci_add_sco(sco, conn->handle);
			else {
				hci_proto_connect_cfm(sco, cc->status);
				hci_conn_del(sco);
			}
		}
	}

	hci_proto_connect_cfm(conn, cc->status);
	if (cc->status)
		hci_conn_del(conn);

	hci_dev_unlock(hdev);
}
예제 #24
0
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
						u8 local_io, u8 remote_io)
{
	struct hci_conn *hcon = conn->hcon;
	struct smp_chan *smp = conn->smp_chan;
	u8 method;
	u32 passkey = 0;
	int ret = 0;

	/* Initialize key for JUST WORKS */
	memset(smp->tk, 0, sizeof(smp->tk));
	clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);

	BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);

	/* If neither side wants MITM, use JUST WORKS */
	/* If either side has unknown io_caps, use JUST WORKS */
	/* Otherwise, look up method from the table */
	if (!(auth & SMP_AUTH_MITM) ||
			local_io > SMP_IO_KEYBOARD_DISPLAY ||
			remote_io > SMP_IO_KEYBOARD_DISPLAY)
		method = JUST_WORKS;
	else
		method = gen_method[remote_io][local_io];

	/* If not bonding, don't ask user to confirm a Zero TK */
	if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
		method = JUST_WORKS;

	/* If Just Works, Continue with Zero TK */
	if (method == JUST_WORKS) {
		set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags);
		return 0;
	}

	/* Not Just Works/Confirm results in MITM Authentication */
	if (method != JUST_CFM)
		set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags);

	/* If both devices have Keyoard-Display I/O, the master
	 * Confirms and the slave Enters the passkey.
	 */
	if (method == OVERLAP) {
		if (hcon->link_mode & HCI_LM_MASTER)
			method = CFM_PASSKEY;
		else
			method = REQ_PASSKEY;
	}

	/* Generate random passkey. Not valid until confirmed. */
	if (method == CFM_PASSKEY) {
		u8 key[16];

		memset(key, 0, sizeof(key));
		get_random_bytes(&passkey, sizeof(passkey));
		passkey %= 1000000;
		put_unaligned_le32(passkey, key);
		swap128(key, smp->tk);
		BT_DBG("PassKey: %d", passkey);
	}

	hci_dev_lock(hcon->hdev);

	if (method == REQ_PASSKEY)
		ret = mgmt_user_passkey_request(hcon->hdev, conn->dst,
						hcon->type, hcon->dst_type);
	else
		ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
						hcon->type, hcon->dst_type,
						cpu_to_le32(passkey), 0);

	hci_dev_unlock(hcon->hdev);

	return ret;
}
예제 #25
0
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_auth_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s status %d", hdev->name, ev->status);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
	if (conn) {
		if (!ev->status)
			conn->link_mode |= HCI_LM_AUTH;
		else
			conn->sec_level = BT_SECURITY_LOW;
// BEGIN SS_BLUEZ_BT +kjh 2011.03.17 : 
// workaround for nobonding. 
// cond 1. local has link key. remote doesn't have link key.
// cond 2. local & remote are ssp mode
// cond 3. send opp file from local to remote
// result -> pin or key missing err returned.
// so send "HCI_OP_AUTH_REQUESTED" one more time. 
		if (ev->status == 0x06 && hdev->ssp_mode > 0 &&  // 0x06 Error code (PIN or key missing)
				conn->ssp_mode > 0 && conn->out) { // hdev: remote device, conn: connection 
			struct hci_cp_auth_requested cp;
			cp.handle = ev->handle;
			hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
				sizeof(cp), &cp);
			printk(KERN_ERR "error code = 0x06, sspmode => HCI_OP_AUTH_REQUESTED");
			goto done;
		}
// END SS_BLUEZ_BT	
		
		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);

		if (conn->state == BT_CONFIG) {
			if (!ev->status && hdev->ssp_mode > 0 &&
							conn->ssp_mode > 0) {
				struct hci_cp_set_conn_encrypt cp;
				cp.handle  = ev->handle;
				cp.encrypt = 0x01;
				hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
							sizeof(cp), &cp);
			} else {
				conn->state = BT_CONNECTED;
				hci_proto_connect_cfm(conn, ev->status);
				hci_conn_put(conn);
			}
		} else {
			hci_auth_cfm(conn, ev->status);

			hci_conn_hold(conn);
			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
			hci_conn_put(conn);
		}

		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
			if (!ev->status) {
				struct hci_cp_set_conn_encrypt cp;
				cp.handle  = ev->handle;
				cp.encrypt = 0x01;
				hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
							sizeof(cp), &cp);
			} else {
				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
				hci_encrypt_cfm(conn, ev->status, 0x00);
			}
		}
	}

// BEGIN SS_BLUEZ_BT +kjh 2011.03.17 : 
done:
// END SS_BLUEZ_BT	

	hci_dev_unlock(hdev);
}