in hv_util.c [394:480]
static void timesync_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
u32 recvlen;
u64 requestid;
struct icmsg_hdr *icmsghdrp;
struct ictimesync_data *timedatap;
struct ictimesync_ref_data *refdata;
u8 *time_txf_buf = util_timesynch.recv_buffer;
/*
* Drain the ring buffer and use the last packet to update
* host_ts
*/
while (1) {
int ret = vmbus_recvpacket(channel, time_txf_buf,
HV_HYP_PAGE_SIZE, &recvlen,
&requestid);
if (ret) {
pr_err_ratelimited("TimeSync IC pkt recv failed (Err: %d)\n",
ret);
break;
}
if (!recvlen)
break;
/* Ensure recvlen is big enough to read header data */
if (recvlen < ICMSG_HDR) {
pr_err_ratelimited("Timesync request received. Packet length too small: %d\n",
recvlen);
break;
}
icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
if (vmbus_prep_negotiate_resp(icmsghdrp,
time_txf_buf, recvlen,
fw_versions, FW_VER_COUNT,
ts_versions, TS_VER_COUNT,
NULL, &ts_srv_version)) {
pr_info("TimeSync IC version %d.%d\n",
ts_srv_version >> 16,
ts_srv_version & 0xFFFF);
}
} else if (icmsghdrp->icmsgtype == ICMSGTYPE_TIMESYNC) {
if (ts_srv_version > TS_VERSION_3) {
/* Ensure recvlen is big enough to read ictimesync_ref_data */
if (recvlen < ICMSG_HDR + sizeof(struct ictimesync_ref_data)) {
pr_err_ratelimited("Invalid ictimesync ref data. Length too small: %u\n",
recvlen);
break;
}
refdata = (struct ictimesync_ref_data *)&time_txf_buf[ICMSG_HDR];
adj_guesttime(refdata->parenttime,
refdata->vmreferencetime,
refdata->flags);
} else {
/* Ensure recvlen is big enough to read ictimesync_data */
if (recvlen < ICMSG_HDR + sizeof(struct ictimesync_data)) {
pr_err_ratelimited("Invalid ictimesync data. Length too small: %u\n",
recvlen);
break;
}
timedatap = (struct ictimesync_data *)&time_txf_buf[ICMSG_HDR];
adj_guesttime(timedatap->parenttime,
hv_read_reference_counter(),
timedatap->flags);
}
} else {
icmsghdrp->status = HV_E_FAIL;
pr_err_ratelimited("Timesync request received. Invalid msg type: %d\n",
icmsghdrp->icmsgtype);
}
icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
| ICMSGHDRFLAG_RESPONSE;
vmbus_sendpacket(channel, time_txf_buf,
recvlen, requestid,
VM_PKT_DATA_INBAND, 0);
}
}