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);
}
}