static void heartbeat_onchannelcallback()

in hv_util.c [487:554]


static void heartbeat_onchannelcallback(void *context)
{
	struct vmbus_channel *channel = context;
	u32 recvlen;
	u64 requestid;
	struct icmsg_hdr *icmsghdrp;
	struct heartbeat_msg_data *heartbeat_msg;
	u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;

	while (1) {

		if (vmbus_recvpacket(channel, hbeat_txf_buf, HV_HYP_PAGE_SIZE,
				     &recvlen, &requestid)) {
			pr_err_ratelimited("Heartbeat request received. Could not read into hbeat txf buf\n");
			return;
		}

		if (!recvlen)
			break;

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

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

		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
			if (vmbus_prep_negotiate_resp(icmsghdrp,
					hbeat_txf_buf, recvlen,
					fw_versions, FW_VER_COUNT,
					hb_versions, HB_VER_COUNT,
					NULL, &hb_srv_version)) {

				pr_info("Heartbeat IC version %d.%d\n",
					hb_srv_version >> 16,
					hb_srv_version & 0xFFFF);
			}
		} else if (icmsghdrp->icmsgtype == ICMSGTYPE_HEARTBEAT) {
			/*
			 * Ensure recvlen is big enough to read seq_num. Reserved area is not
			 * included in the check as the host may not fill it up entirely
			 */
			if (recvlen < ICMSG_HDR + sizeof(u64)) {
				pr_err_ratelimited("Invalid heartbeat msg data. Length too small: %u\n",
						   recvlen);
				break;
			}
			heartbeat_msg = (struct heartbeat_msg_data *)&hbeat_txf_buf[ICMSG_HDR];

			heartbeat_msg->seq_num += 1;
		} else {
			icmsghdrp->status = HV_E_FAIL;
			pr_err_ratelimited("Heartbeat request received. Invalid msg type: %d\n",
					   icmsghdrp->icmsgtype);
		}

		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
			| ICMSGHDRFLAG_RESPONSE;

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