void hv_vss_onchannelcallback()

in hv_snapshot.c [288:359]


void hv_vss_onchannelcallback(void *context)
{
	struct vmbus_channel *channel = context;
	u32 recvlen;
	u64 requestid;
	struct hv_vss_msg *vss_msg;
	int vss_srv_version;

	struct icmsg_hdr *icmsghdrp;

	if (vss_transaction.state > HVUTIL_READY)
		return;

	if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) {
		pr_err_ratelimited("VSS request received. Could not read into recv buf\n");
		return;
	}

	if (!recvlen)
		return;

	/* Ensure recvlen is big enough to read header data */
	if (recvlen < ICMSG_HDR) {
		pr_err_ratelimited("VSS request received. Packet length too small: %d\n",
				   recvlen);
		return;
	}

	icmsghdrp = (struct icmsg_hdr *)&recv_buffer[sizeof(struct vmbuspipe_hdr)];

	if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
		if (vmbus_prep_negotiate_resp(icmsghdrp,
				recv_buffer, recvlen,
				fw_versions, FW_VER_COUNT,
				vss_versions, VSS_VER_COUNT,
				NULL, &vss_srv_version)) {

			pr_info("VSS IC version %d.%d\n",
				vss_srv_version >> 16,
				vss_srv_version & 0xFFFF);
		}
	} else if (icmsghdrp->icmsgtype == ICMSGTYPE_VSS) {
		/* Ensure recvlen is big enough to contain hv_vss_msg */
		if (recvlen < ICMSG_HDR + sizeof(struct hv_vss_msg)) {
			pr_err_ratelimited("Invalid VSS msg. Packet length too small: %u\n",
					   recvlen);
			return;
		}
		vss_msg = (struct hv_vss_msg *)&recv_buffer[ICMSG_HDR];

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

		vss_transaction.recv_len = recvlen;
		vss_transaction.recv_req_id = requestid;
		vss_transaction.msg = (struct hv_vss_msg *)vss_msg;

		schedule_work(&vss_handle_request_work);
		return;
	} else {
		pr_err_ratelimited("VSS request received. Invalid msg type: %d\n",
				   icmsghdrp->icmsgtype);
		return;
	}

	icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
		ICMSGHDRFLAG_RESPONSE;
	vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
			 VM_PKT_DATA_INBAND, 0);
}