Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Drivers: hv: util: Properly handle version negotiations.

The current version negotiation code is not "future proof". Fix this
by allowing each service the flexibility to either specify the highest
version it can support or it can support the highest version number
the host is offering.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

K. Y. Srinivasan and committed by
Greg Kroah-Hartman
c836d0ab a3605300

+49 -21
+38 -16
drivers/hv/channel_mgmt.c
··· 46 46 * 47 47 * @icmsghdrp is of type &struct icmsg_hdr. 48 48 * @negop is of type &struct icmsg_negotiate. 49 - * Set up and fill in default negotiate response message. This response can 50 - * come from both the vmbus driver and the hv_utils driver. The current api 51 - * will respond properly to both Windows 2008 and Windows 2008-R2 operating 52 - * systems. 49 + * Set up and fill in default negotiate response message. 50 + * 51 + * The max_fw_version specifies the maximum framework version that 52 + * we can support and max _srv_version specifies the maximum service 53 + * version we can support. A special value MAX_SRV_VER can be 54 + * specified to indicate that we can handle the maximum version 55 + * exposed by the host. 53 56 * 54 57 * Mainly used by Hyper-V drivers. 55 58 */ 56 59 void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, 57 - struct icmsg_negotiate *negop, u8 *buf) 60 + struct icmsg_negotiate *negop, u8 *buf, 61 + int max_fw_version, int max_srv_version) 58 62 { 63 + int icframe_vercnt; 64 + int icmsg_vercnt; 65 + int i; 66 + 59 67 icmsghdrp->icmsgsize = 0x10; 60 68 61 69 negop = (struct icmsg_negotiate *)&buf[ 62 70 sizeof(struct vmbuspipe_hdr) + 63 71 sizeof(struct icmsg_hdr)]; 64 72 65 - if (negop->icframe_vercnt == 2 && 66 - negop->icversion_data[1].major == 3) { 67 - negop->icversion_data[0].major = 3; 68 - negop->icversion_data[0].minor = 0; 69 - negop->icversion_data[1].major = 3; 70 - negop->icversion_data[1].minor = 0; 71 - } else { 72 - negop->icversion_data[0].major = 1; 73 - negop->icversion_data[0].minor = 0; 74 - negop->icversion_data[1].major = 1; 75 - negop->icversion_data[1].minor = 0; 73 + icframe_vercnt = negop->icframe_vercnt; 74 + icmsg_vercnt = negop->icmsg_vercnt; 75 + 76 + /* 77 + * Select the framework version number we will 78 + * support. 79 + */ 80 + 81 + for (i = 0; i < negop->icframe_vercnt; i++) { 82 + if (negop->icversion_data[i].major <= max_fw_version) 83 + icframe_vercnt = negop->icversion_data[i].major; 76 84 } 77 85 86 + for (i = negop->icframe_vercnt; 87 + (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) { 88 + if (negop->icversion_data[i].major <= max_srv_version) 89 + icmsg_vercnt = negop->icversion_data[i].major; 90 + } 91 + 92 + /* 93 + * Respond with the maximum framework and service 94 + * version numbers we can support. 95 + */ 78 96 negop->icframe_vercnt = 1; 79 97 negop->icmsg_vercnt = 1; 98 + negop->icversion_data[0].major = icframe_vercnt; 99 + negop->icversion_data[0].minor = 0; 100 + negop->icversion_data[1].major = icmsg_vercnt; 101 + negop->icversion_data[1].minor = 0; 80 102 } 81 103 82 104 EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
+2 -1
drivers/hv/hv_kvp.c
··· 394 394 sizeof(struct vmbuspipe_hdr)]; 395 395 396 396 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 397 - vmbus_prep_negotiate_resp(icmsghdrp, negop, recv_buffer); 397 + vmbus_prep_negotiate_resp(icmsghdrp, negop, 398 + recv_buffer, MAX_SRV_VER, MAX_SRV_VER); 398 399 } else { 399 400 kvp_msg = (struct hv_kvp_msg *)&recv_buffer[ 400 401 sizeof(struct vmbuspipe_hdr) +
+6 -3
drivers/hv/hv_util.c
··· 70 70 sizeof(struct vmbuspipe_hdr)]; 71 71 72 72 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 73 - vmbus_prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf); 73 + vmbus_prep_negotiate_resp(icmsghdrp, negop, 74 + shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER); 74 75 } else { 75 76 shutdown_msg = 76 77 (struct shutdown_msg_data *)&shut_txf_buf[ ··· 196 195 sizeof(struct vmbuspipe_hdr)]; 197 196 198 197 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 199 - vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf); 198 + vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf, 199 + MAX_SRV_VER, MAX_SRV_VER); 200 200 } else { 201 201 timedatap = (struct ictimesync_data *)&time_txf_buf[ 202 202 sizeof(struct vmbuspipe_hdr) + ··· 236 234 sizeof(struct vmbuspipe_hdr)]; 237 235 238 236 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 239 - vmbus_prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf); 237 + vmbus_prep_negotiate_resp(icmsghdrp, NULL, 238 + hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER); 240 239 } else { 241 240 heartbeat_msg = 242 241 (struct heartbeat_msg_data *)&hbeat_txf_buf[
+3 -1
include/linux/hyperv.h
··· 1035 1035 void (*callback) (void *context); 1036 1036 }; 1037 1037 1038 + #define MAX_SRV_VER 0x7ffffff 1038 1039 extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *, 1039 - struct icmsg_negotiate *, u8 *); 1040 + struct icmsg_negotiate *, u8 *, int, 1041 + int); 1040 1042 1041 1043 int hv_kvp_init(struct hv_util_service *); 1042 1044 void hv_kvp_deinit(void);