in hv_fcopy.c [226:307]
void hv_fcopy_onchannelcallback(void *context)
{
struct vmbus_channel *channel = context;
u32 recvlen;
u64 requestid;
struct hv_fcopy_hdr *fcopy_msg;
struct icmsg_hdr *icmsghdr;
int fcopy_srv_version;
if (fcopy_transaction.state > HVUTIL_READY)
return;
if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) {
pr_err_ratelimited("Fcopy 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("Fcopy request received. Packet length too small: %d\n",
recvlen);
return;
}
icmsghdr = (struct icmsg_hdr *)&recv_buffer[
sizeof(struct vmbuspipe_hdr)];
if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
if (vmbus_prep_negotiate_resp(icmsghdr,
recv_buffer, recvlen,
fw_versions, FW_VER_COUNT,
fcopy_versions, FCOPY_VER_COUNT,
NULL, &fcopy_srv_version)) {
pr_info("FCopy IC version %d.%d\n",
fcopy_srv_version >> 16,
fcopy_srv_version & 0xFFFF);
}
} else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) {
/* Ensure recvlen is big enough to contain hv_fcopy_hdr */
if (recvlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) {
pr_err_ratelimited("Invalid Fcopy hdr. Packet length too small: %u\n",
recvlen);
return;
}
fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ICMSG_HDR];
/*
* Stash away this global state for completing the
* transaction; note transactions are serialized.
*/
fcopy_transaction.recv_len = recvlen;
fcopy_transaction.recv_req_id = requestid;
fcopy_transaction.fcopy_msg = fcopy_msg;
if (fcopy_transaction.state < HVUTIL_READY) {
/* Userspace is not registered yet */
fcopy_respond_to_host(HV_E_FAIL);
return;
}
fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
/*
* Send the information to the user-level daemon.
*/
schedule_work(&fcopy_send_work);
schedule_delayed_work(&fcopy_timeout_work,
HV_UTIL_TIMEOUT * HZ);
return;
} else {
pr_err_ratelimited("Fcopy request received. Invalid msg type: %d\n",
icmsghdr->icmsgtype);
return;
}
icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
VM_PKT_DATA_INBAND, 0);
}