コード例 #1
0
ファイル: hv_kvp.c プロジェクト: 020gzh/linux
static int kvp_on_msg(void *msg, int len)
{
	struct hv_kvp_msg *message = (struct hv_kvp_msg *)msg;
	struct hv_kvp_msg_enumerate *data;
	int	error = 0;

	if (len < sizeof(*message))
		return -EINVAL;

	/*
	 * If we are negotiating the version information
	 * with the daemon; handle that first.
	 */

	if (kvp_transaction.state < HVUTIL_READY) {
		return kvp_handle_handshake(message);
	}

	/* We didn't send anything to userspace so the reply is spurious */
	if (kvp_transaction.state < HVUTIL_USERSPACE_REQ)
		return -EINVAL;

	kvp_transaction.state = HVUTIL_USERSPACE_RECV;

	/*
	 * Based on the version of the daemon, we propagate errors from the
	 * daemon differently.
	 */

	data = &message->body.kvp_enum_data;

	switch (dm_reg_value) {
	case KVP_OP_REGISTER:
		/*
		 * Null string is used to pass back error condition.
		 */
		if (data->data.key[0] == 0)
			error = HV_S_CONT;
		break;

	case KVP_OP_REGISTER1:
		/*
		 * We use the message header information from
		 * the user level daemon to transmit errors.
		 */
		error = message->error;
		break;
	}

	/*
	 * Complete the transaction by forwarding the key value
	 * to the host. But first, cancel the timeout.
	 */
	if (cancel_delayed_work_sync(&kvp_timeout_work)) {
		kvp_respond_to_host(message, error);
		hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
	}

	return 0;
}
コード例 #2
0
ファイル: hv_kvp.c プロジェクト: Niisp/MT6795.kernel
static void
kvp_work_func(struct work_struct *dummy)
{
    /*
     * If the timer fires, the user-mode component has not responded;
     * process the pending transaction.
     */
    kvp_respond_to_host(NULL, HV_E_FAIL);
}
コード例 #3
0
ファイル: hv_kvp.c プロジェクト: 125radheyshyam/linux
static void
kvp_work_func(struct work_struct *dummy)
{
	/*
	 * If the timer fires, the user-mode component has not responded;
	 * process the pending transaction.
	 */
	kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
}
コード例 #4
0
ファイル: hv_kvp.c プロジェクト: 020gzh/linux
static void kvp_timeout_func(struct work_struct *dummy)
{
	/*
	 * If the timer fires, the user-mode component has not responded;
	 * process the pending transaction.
	 */
	kvp_respond_to_host(NULL, HV_E_FAIL);

	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
}
コード例 #5
0
ファイル: hv_kvp.c プロジェクト: Niisp/MT6795.kernel
static void
kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
    struct hv_kvp_msg *message;
    struct hv_kvp_msg_enumerate *data;
    int	error = 0;

    message = (struct hv_kvp_msg *)msg->data;

    /*
     * If we are negotiating the version information
     * with the daemon; handle that first.
     */

    if (in_hand_shake) {
        if (kvp_handle_handshake(message))
            in_hand_shake = false;
        return;
    }

    /*
     * Based on the version of the daemon, we propagate errors from the
     * daemon differently.
     */

    data = &message->body.kvp_enum_data;

    switch (dm_reg_value) {
    case KVP_OP_REGISTER:
        /*
         * Null string is used to pass back error condition.
         */
        if (data->data.key[0] == 0)
            error = HV_S_CONT;
        break;

    case KVP_OP_REGISTER1:
        /*
         * We use the message header information from
         * the user level daemon to transmit errors.
         */
        error = message->error;
        break;
    }

    /*
     * Complete the transaction by forwarding the key value
     * to the host. But first, cancel the timeout.
     */
    if (cancel_delayed_work_sync(&kvp_work))
        kvp_respond_to_host(message, error);
}
コード例 #6
0
ファイル: hv_kvp.c プロジェクト: 125radheyshyam/linux
static void
kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
{
	struct hv_ku_msg *message;

	message = (struct hv_ku_msg *)msg->data;
	if (msg->seq == KVP_REGISTER) {
		pr_info("KVP: user-mode registering done.\n");
		kvp_register();
	}

	if (msg->seq == KVP_USER_SET) {
		/*
		 * Complete the transaction by forwarding the key value
		 * to the host. But first, cancel the timeout.
		 */
		if (cancel_delayed_work_sync(&kvp_work))
			kvp_respond_to_host(message->kvp_key,
						message->kvp_value,
						!strlen(message->kvp_key));
	}
}
コード例 #7
0
ファイル: hv_kvp.c プロジェクト: 168519/linux
static void
kvp_send_key(struct work_struct *dummy)
{
	struct cn_msg *msg;
	struct hv_kvp_msg *message;
	struct hv_kvp_msg *in_msg;
	__u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
	__u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
	__u32 val32;
	__u64 val64;
	int rc;

	msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
	if (!msg)
		return;

	msg->id.idx =  CN_KVP_IDX;
	msg->id.val = CN_KVP_VAL;

	message = (struct hv_kvp_msg *)msg->data;
	message->kvp_hdr.operation = operation;
	message->kvp_hdr.pool = pool;
	in_msg = kvp_transaction.kvp_msg;

	/*
	 * The key/value strings sent from the host are encoded in
	 * in utf16; convert it to utf8 strings.
	 * The host assures us that the utf16 strings will not exceed
	 * the max lengths specified. We will however, reserve room
	 * for the string terminating character - in the utf16s_utf8s()
	 * function we limit the size of the buffer where the converted
	 * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee
	 * that the strings can be properly terminated!
	 */

	switch (message->kvp_hdr.operation) {
	case KVP_OP_SET_IP_INFO:
		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
		break;
	case KVP_OP_GET_IP_INFO:
		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
		break;
	case KVP_OP_SET:
		switch (in_msg->body.kvp_set.data.value_type) {
		case REG_SZ:
			/*
			 * The value is a string - utf16 encoding.
			 */
			message->body.kvp_set.data.value_size =
				utf16s_to_utf8s(
				(wchar_t *)in_msg->body.kvp_set.data.value,
				in_msg->body.kvp_set.data.value_size,
				UTF16_LITTLE_ENDIAN,
				message->body.kvp_set.data.value,
				HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
				break;

		case REG_U32:
			/*
			 * The value is a 32 bit scalar.
			 * We save this as a utf8 string.
			 */
			val32 = in_msg->body.kvp_set.data.value_u32;
			message->body.kvp_set.data.value_size =
				sprintf(message->body.kvp_set.data.value,
					"%d", val32) + 1;
			break;

		case REG_U64:
			/*
			 * The value is a 64 bit scalar.
			 * We save this as a utf8 string.
			 */
			val64 = in_msg->body.kvp_set.data.value_u64;
			message->body.kvp_set.data.value_size =
				sprintf(message->body.kvp_set.data.value,
					"%llu", val64) + 1;
			break;

		}
	case KVP_OP_GET:
		message->body.kvp_set.data.key_size =
			utf16s_to_utf8s(
			(wchar_t *)in_msg->body.kvp_set.data.key,
			in_msg->body.kvp_set.data.key_size,
			UTF16_LITTLE_ENDIAN,
			message->body.kvp_set.data.key,
			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
			break;

	case KVP_OP_DELETE:
		message->body.kvp_delete.key_size =
			utf16s_to_utf8s(
			(wchar_t *)in_msg->body.kvp_delete.key,
			in_msg->body.kvp_delete.key_size,
			UTF16_LITTLE_ENDIAN,
			message->body.kvp_delete.key,
			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
			break;

	case KVP_OP_ENUMERATE:
		message->body.kvp_enum_data.index =
			in_msg->body.kvp_enum_data.index;
			break;
	}

	msg->len = sizeof(struct hv_kvp_msg);
	rc = cn_netlink_send(msg, 0, 0, GFP_ATOMIC);
	if (rc) {
		pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
		if (cancel_delayed_work_sync(&kvp_work))
			kvp_respond_to_host(message, HV_E_FAIL);
	}

	kfree(msg);

	return;
}
コード例 #8
0
ファイル: hv_kvp.c プロジェクト: 020gzh/linux
static void kvp_on_reset(void)
{
	if (cancel_delayed_work_sync(&kvp_timeout_work))
		kvp_respond_to_host(NULL, HV_E_FAIL);
	kvp_transaction.state = HVUTIL_DEVICE_INIT;
}
コード例 #9
0
ファイル: hv_kvp.c プロジェクト: 020gzh/linux
void hv_kvp_onchannelcallback(void *context)
{
	struct vmbus_channel *channel = context;
	u32 recvlen;
	u64 requestid;

	struct hv_kvp_msg *kvp_msg;

	struct icmsg_hdr *icmsghdrp;
	struct icmsg_negotiate *negop = NULL;
	int util_fw_version;
	int kvp_srv_version;

	if (kvp_transaction.state > HVUTIL_READY)
		return;

	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
			 &requestid);

	if (recvlen > 0) {
		icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
			sizeof(struct vmbuspipe_hdr)];

		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
			/*
			 * Based on the host, select appropriate
			 * framework and service versions we will
			 * negotiate.
			 */
			switch (vmbus_proto_version) {
			case (VERSION_WS2008):
				util_fw_version = UTIL_WS2K8_FW_VERSION;
				kvp_srv_version = WS2008_SRV_VERSION;
				break;
			case (VERSION_WIN7):
				util_fw_version = UTIL_FW_VERSION;
				kvp_srv_version = WIN7_SRV_VERSION;
				break;
			default:
				util_fw_version = UTIL_FW_VERSION;
				kvp_srv_version = WIN8_SRV_VERSION;
			}
			vmbus_prep_negotiate_resp(icmsghdrp, negop,
				 recv_buffer, util_fw_version,
				 kvp_srv_version);

		} else {
			kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
				sizeof(struct vmbuspipe_hdr) +
				sizeof(struct icmsg_hdr)];

			/*
			 * Stash away this global state for completing the
			 * transaction; note transactions are serialized.
			 */

			kvp_transaction.recv_len = recvlen;
			kvp_transaction.recv_req_id = requestid;
			kvp_transaction.kvp_msg = kvp_msg;

			if (kvp_transaction.state < HVUTIL_READY) {
				/* Userspace is not registered yet */
				kvp_respond_to_host(NULL, HV_E_FAIL);
				return;
			}
			kvp_transaction.state = HVUTIL_HOSTMSG_RECEIVED;

			/*
			 * Get the information from the
			 * user-mode component.
			 * component. This transaction will be
			 * completed when we get the value from
			 * the user-mode component.
			 * Set a timeout to deal with
			 * user-mode not responding.
			 */
			schedule_work(&kvp_sendkey_work);
			schedule_delayed_work(&kvp_timeout_work,
					      HV_UTIL_TIMEOUT * HZ);

			return;

		}

		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
			| ICMSGHDRFLAG_RESPONSE;

		vmbus_sendpacket(channel, recv_buffer,
				       recvlen, requestid,
				       VM_PKT_DATA_INBAND, 0);
	}

}
コード例 #10
0
ファイル: hv_kvp.c プロジェクト: LIS/lis-next
static void
kvp_send_key(struct work_struct *dummy)
{
	struct hv_kvp_msg *message;
	struct hv_kvp_msg *in_msg;
	__u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
	__u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
	__u32 val32;
	__u64 val64;
	int rc;

	/* The transaction state is wrong. */
	if (kvp_transaction.state != HVUTIL_HOSTMSG_RECEIVED)
		return;

	message = kzalloc(sizeof(*message), GFP_KERNEL);
	if (!message)
		return;

	message->kvp_hdr.operation = operation;
	message->kvp_hdr.pool = pool;
	in_msg = kvp_transaction.kvp_msg;

	/*
	 * The key/value strings sent from the host are encoded in
	 * in utf16; convert it to utf8 strings.
	 * The host assures us that the utf16 strings will not exceed
	 * the max lengths specified. We will however, reserve room
	 * for the string terminating character - in the utf16s_utf8s()
	 * function we limit the size of the buffer where the converted
	 * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to guarantee
	 * that the strings can be properly terminated!
	 */

	switch (message->kvp_hdr.operation) {
	case KVP_OP_SET_IP_INFO:
		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
		break;
	case KVP_OP_GET_IP_INFO:
		/*
		 * We only need to pass on the info of operation, adapter_id
		 * and addr_family to the userland kvp daemon.
		 */
		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
		break;
	case KVP_OP_SET:
		switch (in_msg->body.kvp_set.data.value_type) {
		case REG_SZ:
			/*
			 * The value is a string - utf16 encoding.
			 */
			message->body.kvp_set.data.value_size =
				utf16s_to_utf8s(
				(wchar_t *)in_msg->body.kvp_set.data.value,
				in_msg->body.kvp_set.data.value_size,
				UTF16_LITTLE_ENDIAN,
				message->body.kvp_set.data.value,
				HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
			break;

		case REG_U32:
			/*
			 * The value is a 32 bit scalar.
			 * We save this as a utf8 string.
			 */
			val32 = in_msg->body.kvp_set.data.value_u32;
			message->body.kvp_set.data.value_size =
				sprintf(message->body.kvp_set.data.value,
					"%u", val32) + 1;
			break;

		case REG_U64:
			/*
			 * The value is a 64 bit scalar.
			 * We save this as a utf8 string.
			 */
			val64 = in_msg->body.kvp_set.data.value_u64;
			message->body.kvp_set.data.value_size =
				sprintf(message->body.kvp_set.data.value,
					"%llu", val64) + 1;
			break;

		}

		/*
		 * The key is always a string - utf16 encoding.
		 */
		message->body.kvp_set.data.key_size =
			utf16s_to_utf8s(
			(wchar_t *)in_msg->body.kvp_set.data.key,
			in_msg->body.kvp_set.data.key_size,
			UTF16_LITTLE_ENDIAN,
			message->body.kvp_set.data.key,
			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;

		break;

	case KVP_OP_GET:
		message->body.kvp_get.data.key_size =
			utf16s_to_utf8s(
			(wchar_t *)in_msg->body.kvp_get.data.key,
			in_msg->body.kvp_get.data.key_size,
			UTF16_LITTLE_ENDIAN,
			message->body.kvp_get.data.key,
			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
		break;

	case KVP_OP_DELETE:
		message->body.kvp_delete.key_size =
			utf16s_to_utf8s(
			(wchar_t *)in_msg->body.kvp_delete.key,
			in_msg->body.kvp_delete.key_size,
			UTF16_LITTLE_ENDIAN,
			message->body.kvp_delete.key,
			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
		break;

	case KVP_OP_ENUMERATE:
		message->body.kvp_enum_data.index =
			in_msg->body.kvp_enum_data.index;
		break;
	}

	kvp_transaction.state = HVUTIL_USERSPACE_REQ;
	rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL);
	if (rc) {
		pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
		if (cancel_delayed_work_sync(&kvp_timeout_work)) {
			kvp_respond_to_host(message, HV_E_FAIL);
			kvp_transaction.state = HVUTIL_READY;
		}
	}

	kfree(message);
}