Index: contrib/hyperv/tools/hv_kvp_daemon.c =================================================================== --- contrib/hyperv/tools/hv_kvp_daemon.c +++ contrib/hyperv/tools/hv_kvp_daemon.c @@ -54,6 +54,7 @@ #include #include "hv_kvp.h" +#include "hv_common.h" typedef uint8_t __u8; typedef uint16_t __u16; @@ -782,11 +783,11 @@ } if ((length - *offset) < addr_length + 1) { - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); } if (str == NULL) { strlcpy(buffer, "inet_ntop failed\n", length); - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); } if (*offset == 0) { strlcpy(buffer, tmp, length); @@ -832,7 +833,7 @@ if (getifaddrs(&ifap)) { strlcpy(buffer, "getifaddrs failed\n", buffer_length); - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); } curp = ifap; @@ -954,7 +955,7 @@ ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); if (ret < 0) { - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); } return (0); @@ -979,7 +980,7 @@ if (file == NULL) { KVP_LOG(LOG_ERR, "FreeBSD Failed to open config file\n"); - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); } /* @@ -988,7 +989,7 @@ mac_addr = kvp_if_name_to_mac(if_name); if (mac_addr == NULL) { - error = HV_KVP_E_FAIL; + error = HV_E_FAIL; goto kvp_set_ip_info_error; } /* MAC Address */ @@ -1096,13 +1097,13 @@ KVP_LOG(LOG_DEBUG, "In kvp_op_getipinfo.\n"); ip_val = &op_msg->body.kvp_ip_val; - op_msg->hdr.error = HV_KVP_S_OK; + op_msg->hdr.error = HV_S_OK; if_name = kvp_mac_to_if_name((char *)ip_val->adapter_id); if (if_name == NULL) { /* No interface found with the mac address. */ - op_msg->hdr.error = HV_KVP_E_FAIL; + op_msg->hdr.error = HV_E_FAIL; goto kvp_op_getipinfo_done; } @@ -1126,13 +1127,13 @@ KVP_LOG(LOG_DEBUG, "In kvp_op_setipinfo.\n"); ip_val = &op_msg->body.kvp_ip_val; - op_msg->hdr.error = HV_KVP_S_OK; + op_msg->hdr.error = HV_S_OK; if_name = (char *)ip_val->adapter_id; if (if_name == NULL) { /* No adapter provided. */ - op_msg->hdr.error = HV_KVP_GUID_NOTFOUND; + op_msg->hdr.error = HV_GUID_NOTFOUND; goto kvp_op_setipinfo_done; } @@ -1154,7 +1155,7 @@ assert(op_hdlr != NULL); op_pool = op_msg->hdr.kvp_hdr.pool; - op_msg->hdr.error = HV_KVP_S_OK; + op_msg->hdr.error = HV_S_OK; switch(op_hdlr->kvp_op_key) { case HV_KVP_OP_SET: @@ -1198,7 +1199,7 @@ } if (error != 0) - op_msg->hdr.error = HV_KVP_S_CONT; + op_msg->hdr.error = HV_S_CONT; return(error); } @@ -1216,7 +1217,7 @@ op = op_msg->hdr.kvp_hdr.operation; op_pool = op_msg->hdr.kvp_hdr.pool; - op_msg->hdr.error = HV_KVP_S_OK; + op_msg->hdr.error = HV_S_OK; /* * If the pool is not HV_KVP_POOL_AUTO, read from the appropriate @@ -1229,7 +1230,7 @@ HV_KVP_EXCHANGE_MAX_KEY_SIZE, op_msg->body.kvp_enum_data.data.msg_value.value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) { - op_msg->hdr.error = HV_KVP_S_CONT; + op_msg->hdr.error = HV_S_CONT; error = -1; } goto kvp_op_enumerate_done; @@ -1298,7 +1299,7 @@ KVP_LOG(LOG_ERR, "Auto pool Index %d not found.\n", op_msg->body.kvp_enum_data.index); #endif - op_msg->hdr.error = HV_KVP_S_CONT; + op_msg->hdr.error = HV_S_CONT; error = -1; break; } @@ -1496,7 +1497,7 @@ */ error = kvp_op_hdlrs[op].kvp_op_exec(hv_msg, (void *)&kvp_op_hdlrs[op]); - if (error != 0 && hv_msg->hdr.error != HV_KVP_S_CONT) + if (error != 0 && hv_msg->hdr.error != HV_S_CONT) KVP_LOG(LOG_WARNING, "Operation failed OP = %d, error = 0x%x\n", op, error); Index: sys/dev/hyperv/utilities/hv_heartbeat.c =================================================================== --- sys/dev/hyperv/utilities/hv_heartbeat.c +++ sys/dev/hyperv/utilities/hv_heartbeat.c @@ -80,9 +80,7 @@ */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: - error = vmbus_ic_negomsg(sc, data, &dlen); - if (error) - return; + hv_util_negotiate_version(sc->ic_dev, data, util_fw_ver, hb_srv_ver); break; case VMBUS_ICMSG_TYPE_HEARTBEAT: Index: sys/dev/hyperv/utilities/hv_kvp.h =================================================================== --- sys/dev/hyperv/utilities/hv_kvp.h +++ sys/dev/hyperv/utilities/hv_kvp.h @@ -149,15 +149,6 @@ /* * Some Hyper-V status codes. */ -#define HV_KVP_S_OK 0x00000000 -#define HV_KVP_E_FAIL 0x80004005 -#define HV_KVP_S_CONT 0x80070103 -#define HV_ERROR_NOT_SUPPORTED 0x80070032 -#define HV_ERROR_MACHINE_LOCKED 0x800704F7 -#define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F -#define HV_INVALIDARG 0x80070057 -#define HV_KVP_GUID_NOTFOUND 0x80041002 - #define ADDR_FAMILY_NONE 0x00 #define ADDR_FAMILY_IPV4 0x01 #define ADDR_FAMILY_IPV6 0x02 Index: sys/dev/hyperv/utilities/hv_kvp.c =================================================================== --- sys/dev/hyperv/utilities/hv_kvp.c +++ sys/dev/hyperv/utilities/hv_kvp.c @@ -62,6 +62,7 @@ #include #include +#include #include "hv_util.h" #include "unicode.h" @@ -212,48 +213,6 @@ sizeof(struct hv_vmbus_icmsg_hdr)]; } - -/* - * hv_kvp - version neogtiation function - */ -static void -hv_kvp_negotiate_version(struct hv_vmbus_icmsg_hdr *icmsghdrp, uint8_t *buf) -{ - struct hv_vmbus_icmsg_negotiate *negop; - int icframe_vercnt; - int icmsg_vercnt; - - icmsghdrp->icmsgsize = 0x10; - - negop = (struct hv_vmbus_icmsg_negotiate *)&buf[ - sizeof(struct hv_vmbus_pipe_hdr) + - sizeof(struct hv_vmbus_icmsg_hdr)]; - icframe_vercnt = negop->icframe_vercnt; - icmsg_vercnt = negop->icmsg_vercnt; - - /* - * Select the framework version number we will support - */ - if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) { - icframe_vercnt = 3; - if (icmsg_vercnt > 2) - icmsg_vercnt = 4; - else - icmsg_vercnt = 3; - } else { - icframe_vercnt = 1; - icmsg_vercnt = 1; - } - - negop->icframe_vercnt = 1; - negop->icmsg_vercnt = 1; - negop->icversion_data[0].major = icframe_vercnt; - negop->icversion_data[0].minor = 0; - negop->icversion_data[1].major = icmsg_vercnt; - negop->icversion_data[1].minor = 0; -} - - /* * Convert ip related info in umsg from utf8 to utf16 and store in hmsg */ @@ -535,7 +494,7 @@ host_exchg_data->value_type = HV_REG_SZ; if ((hkey_len < 0) || (hvalue_len < 0)) - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); return (KVP_SUCCESS); @@ -553,12 +512,12 @@ host_exchg_data->value_type = HV_REG_SZ; if ((hkey_len < 0) || (hvalue_len < 0)) - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); return (KVP_SUCCESS); default: - return (HV_KVP_E_FAIL); + return (HV_E_FAIL); } } @@ -575,7 +534,7 @@ &sc->rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)]; if (error) - error = HV_KVP_E_FAIL; + error = HV_E_FAIL; hv_icmsg_hdrp->status = error; hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE; @@ -623,7 +582,7 @@ uint64_t requestid; struct hv_vmbus_icmsg_hdr *icmsghdrp; int ret = 0; - hv_kvp_sc *sc; + hv_kvp_sc *sc; hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__); @@ -643,7 +602,8 @@ hv_kvp_transaction_init(sc, recvlen, requestid, kvp_buf); if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) { - hv_kvp_negotiate_version(icmsghdrp, kvp_buf); + hv_util_negotiate_version(sc->dev, kvp_buf, + util_fw_ver, kvp_srv_ver); hv_kvp_respond_host(sc, ret); /* @@ -689,7 +649,7 @@ */ if (hv_kvp_req_in_progress(sc)) { hv_kvp_log_info("%s: request was still active after wait so failing\n", __func__); - hv_kvp_respond_host(sc, HV_KVP_E_FAIL); + hv_kvp_respond_host(sc, HV_E_FAIL); sc->req_in_progress = false; } Index: sys/dev/hyperv/utilities/hv_shutdown.c =================================================================== --- sys/dev/hyperv/utilities/hv_shutdown.c +++ sys/dev/hyperv/utilities/hv_shutdown.c @@ -82,9 +82,7 @@ */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: - error = vmbus_ic_negomsg(sc, data, &dlen); - if (error) - return; + hv_util_negotiate_version(sc->ic_dev, data, util_fw_ver, sd_srv_ver); break; case VMBUS_ICMSG_TYPE_SHUTDOWN: Index: sys/dev/hyperv/utilities/hv_timesync.c =================================================================== --- sys/dev/hyperv/utilities/hv_timesync.c +++ sys/dev/hyperv/utilities/hv_timesync.c @@ -162,9 +162,7 @@ */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: - error = vmbus_ic_negomsg(sc, data, &dlen); - if (error) - return; + hv_util_negotiate_version(sc->ic_dev, data, util_fw_ver, ts_srv_ver); break; case VMBUS_ICMSG_TYPE_TIMESYNC: Index: sys/dev/hyperv/utilities/hv_util.h =================================================================== --- sys/dev/hyperv/utilities/hv_util.h +++ sys/dev/hyperv/utilities/hv_util.h @@ -54,6 +54,11 @@ int hv_util_attach(device_t dev, vmbus_chan_callback_t cb); int hv_util_detach(device_t dev); int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]); -int vmbus_ic_negomsg(struct hv_util_sc *, void *data, int *dlen); +boolean_t hv_util_negotiate_version(device_t, uint8_t*, int, int); +extern int util_fw_ver; +extern int sd_srv_ver; +extern int ts_srv_ver; +extern int hb_srv_ver; +extern int kvp_srv_ver; #endif Index: sys/dev/hyperv/utilities/hv_util.c =================================================================== --- sys/dev/hyperv/utilities/hv_util.c +++ sys/dev/hyperv/utilities/hv_util.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include "vmbus_if.h" @@ -53,53 +55,11 @@ __offsetof(struct vmbus_icmsg_negotiate, ic_ver[VMBUS_IC_VERCNT]) CTASSERT(VMBUS_IC_NEGOSZ < VMBUS_IC_BRSIZE); -int -vmbus_ic_negomsg(struct hv_util_sc *sc, void *data, int *dlen0) -{ - struct vmbus_icmsg_negotiate *nego; - int cnt, major, dlen = *dlen0; - - /* - * Preliminary message size verification - */ - if (dlen < sizeof(*nego)) { - device_printf(sc->ic_dev, "truncated ic negotiate, len %d\n", - dlen); - return EINVAL; - } - nego = data; - - cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt; - if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) { - device_printf(sc->ic_dev, "ic negotiate does not contain " - "versions %d\n", dlen); - return EINVAL; - } - - /* Select major version; XXX looks wrong. */ - if (nego->ic_fwver_cnt >= 2 && VMBUS_ICVER_MAJOR(nego->ic_ver[1]) == 3) - major = 3; - else - major = 1; - - /* One framework version */ - nego->ic_fwver_cnt = 1; - nego->ic_ver[0] = VMBUS_IC_VERSION(major, 0); - - /* One message version */ - nego->ic_msgver_cnt = 1; - nego->ic_ver[1] = VMBUS_IC_VERSION(major, 0); - - /* Update data size */ - nego->ic_hdr.ic_dsize = VMBUS_IC_NEGOSZ - - sizeof(struct vmbus_icmsg_hdr); - - /* Update total size, if necessary */ - if (dlen < VMBUS_IC_NEGOSZ) - *dlen0 = VMBUS_IC_NEGOSZ; - - return 0; -} +int util_fw_ver = UTIL_FW_VERSION; +int sd_srv_ver = SD_VERSION; +int ts_srv_ver = TS_VERSION; +int hb_srv_ver = HB_VERSION; +int kvp_srv_ver = KVP_WIN8_SRV_VERSION; int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]) @@ -124,13 +84,37 @@ { struct hv_util_sc *sc = device_get_softc(dev); struct vmbus_channel *chan = vmbus_get_channel(dev); + uint32_t vmbus_version; int error; + vmbus_version = VMBUS_GET_VERSION(device_get_parent(dev), dev); sc->ic_dev = dev; sc->ic_buflen = VMBUS_IC_BRSIZE; sc->receive_buffer = malloc(VMBUS_IC_BRSIZE, M_DEVBUF, M_WAITOK | M_ZERO); + switch(vmbus_version) { + case VMBUS_VERSION_WS2008: + util_fw_ver = UTIL_WS2K8_FW_VERSION; + kvp_srv_ver = KVP_WS2008_SRV_VERSION; + sd_srv_ver = SD_WS2008_VERSION; + ts_srv_ver = TS_WS2008_VERSION; + hb_srv_ver = HB_WS2008_VERSION; + break; + case VMBUS_VERSION_WIN7: + util_fw_ver = UTIL_FW_VERSION; + kvp_srv_ver = KVP_WIN7_SRV_VERSION; + sd_srv_ver = SD_VERSION; + ts_srv_ver = TS_VERSION; + hb_srv_ver = HB_VERSION; + break; + default: + util_fw_ver = UTIL_FW_VERSION; + kvp_srv_ver = KVP_WIN8_SRV_VERSION; + sd_srv_ver = SD_VERSION; + ts_srv_ver = TS_VERSION; + hb_srv_ver = HB_VERSION; + } /* * These services are not performance critical and do not need * batched reading. Furthermore, some services such as KVP can @@ -159,3 +143,103 @@ return (0); } + +/* + * version neogtiation function + * Create default response for Hyper-V Negotiate message + * @buf: Raw buffer channel data + * @framewrk_ver specifies the framework version that we can support + * @service_ver specifies the service version we can support. + */ + +boolean_t +hv_util_negotiate_version(device_t dev, uint8_t *buf, + int framewrk_ver, int service_ver) +{ + struct hv_vmbus_icmsg_negotiate *negop; + int icmsg_major, icmsg_minor; + int fw_major, fw_minor; + int srv_major, srv_minor; + int i; + int icframe_major, icframe_minor; + struct hv_vmbus_icmsg_hdr *icmsghdrp; + boolean_t found = FALSE; + + icmsghdrp = (struct hv_vmbus_icmsg_hdr *) + &buf[sizeof(struct hv_vmbus_pipe_hdr)]; + icmsghdrp->icmsgsize = 0x10; + + fw_major = (framewrk_ver >> 16); + fw_minor = (framewrk_ver & 0xFFFF); + + srv_major = (service_ver >> 16); + srv_minor = (service_ver & 0xFFFF); + + negop = (struct hv_vmbus_icmsg_negotiate *)&buf[ + sizeof(struct hv_vmbus_pipe_hdr) + + sizeof(struct hv_vmbus_icmsg_hdr)]; + + icframe_major = negop->icframe_vercnt; + icframe_minor = 0; + icmsg_major = negop->icmsg_vercnt; + icmsg_minor = 0; + /* + * Select the framework version number we will support + */ + for (i = 0; i < negop->icframe_vercnt; i++) { + if ((negop->icversion_data[i].major == fw_major) && + (negop->icversion_data[i].minor == fw_minor)) { + icframe_major = negop->icversion_data[i].major; + icframe_minor = negop->icversion_data[i].minor; + found = true; + } + } + + if (!found) + goto handle_error; + found = false; + + for (i = negop->icframe_vercnt; + i < negop->icframe_vercnt + negop->icmsg_vercnt; i++) { + if ((negop->icversion_data[i].major == srv_major) && + (negop->icversion_data[i].minor == srv_minor)) { + icmsg_major = negop->icversion_data[i].major; + icmsg_minor = negop->icversion_data[i].minor; + found = true; + } + } + +handle_error: + if (bootverbose) { + device_printf(dev, "selected frame version: [%d:%d]\n", + icframe_major, icframe_minor); + for (i = 0; i < negop->icframe_vercnt; i++) { + device_printf(dev, "frame versions: [%d:%d]\n", + negop->icversion_data[i].major, + negop->icversion_data[i].minor); + } + device_printf(dev, "selected service version: [%d:%d]\n", + icmsg_major, icmsg_minor); + + for (i = negop->icframe_vercnt; + i < negop->icframe_vercnt + negop->icmsg_vercnt; i++) { + device_printf(dev, "service version [%d:%d]\n", + negop->icversion_data[i].major, + negop->icversion_data[i].minor); + } + } + + if (!found) { + negop->icframe_vercnt = 0; + negop->icmsg_vercnt = 0; + } else { + negop->icframe_vercnt = 1; + negop->icmsg_vercnt = 1; + } + + negop->icversion_data[0].major = icframe_major; + negop->icversion_data[0].minor = icframe_minor; + negop->icversion_data[1].major = icmsg_major; + negop->icversion_data[1].minor = icmsg_minor; + return found; +} Index: sys/dev/hyperv/utilities/hv_utilreg.h =================================================================== --- sys/dev/hyperv/utilities/hv_utilreg.h +++ sys/dev/hyperv/utilities/hv_utilreg.h @@ -29,11 +29,6 @@ #ifndef _HV_UTILREG_H_ #define _HV_UTILREG_H_ -#define HV_S_OK 0x00000000 -#define HV_E_FAIL 0x80004005 -#define HV_ERROR_NOT_SUPPORTED 0x80070032 -#define HV_ERROR_MACHINE_LOCKED 0x800704F7 - /* * Common defines for Hyper-V ICs */ Index: sys/dev/hyperv/utilities/vmbus_icreg.h =================================================================== --- sys/dev/hyperv/utilities/vmbus_icreg.h +++ sys/dev/hyperv/utilities/vmbus_icreg.h @@ -39,10 +39,6 @@ #define VMBUS_ICMSG_STATUS_OK 0x00000000 #define VMBUS_ICMSG_STATUS_FAIL 0x80004005 -#define VMBUS_IC_VERSION(major, minor) ((major) | (((uint32_t)(minor)) << 16)) -#define VMBUS_ICVER_MAJOR(ver) ((ver) & 0xffff) -#define VMBUS_ICVER_MINOR(ver) (((ver) & 0xffff0000) >> 16) - struct vmbus_pipe_hdr { uint32_t ph_flags; uint32_t ph_msgsz;