From owner-svn-src-all@FreeBSD.ORG Thu Sep 25 20:34:17 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 8E6A6694; Thu, 25 Sep 2014 20:34:17 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 746BEC45; Thu, 25 Sep 2014 20:34:17 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s8PKYH9v082522; Thu, 25 Sep 2014 20:34:17 GMT (envelope-from delphij@FreeBSD.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s8PKYE3m082507; Thu, 25 Sep 2014 20:34:14 GMT (envelope-from delphij@FreeBSD.org) Message-Id: <201409252034.s8PKYE3m082507@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: delphij set sender to delphij@FreeBSD.org using -f From: Xin LI Date: Thu, 25 Sep 2014 20:34:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r272128 - in stable/10: . contrib/hyperv etc/devd etc/mtree libexec libexec/hyperv share/mk sys/conf sys/dev/hyperv/include sys/dev/hyperv/utilities sys/modules/hyperv/utilities tools/b... X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Sep 2014 20:34:17 -0000 Author: delphij Date: Thu Sep 25 20:34:13 2014 New Revision: 272128 URL: http://svnweb.freebsd.org/changeset/base/272128 Log: MFC r271493,271688,271689,271696,271854: Import HyperV Key-Value Pair (KVP) driver and daemon code by Microsoft, many thanks for their continued support of FreeBSD. While I'm there, also implement a new build knob, WITHOUT_HYPERV to disable building and installing of the HyperV utilities when necessary. The HyperV utilities are only built for i386 and amd64 targets. Approved by: re (gjb) Added: stable/10/contrib/hyperv/ - copied from r271493, head/contrib/hyperv/ stable/10/etc/devd/hyperv.conf - copied, changed from r271696, head/etc/devd/hyperv.conf stable/10/libexec/hyperv/ - copied from r271493, head/libexec/hyperv/ stable/10/sys/dev/hyperv/utilities/hv_kvp.c - copied unchanged from r271493, head/sys/dev/hyperv/utilities/hv_kvp.c stable/10/sys/dev/hyperv/utilities/unicode.h - copied unchanged from r271493, head/sys/dev/hyperv/utilities/unicode.h stable/10/tools/build/options/WITHOUT_HYPERV - copied unchanged from r271493, head/tools/build/options/WITHOUT_HYPERV stable/10/tools/build/options/WITH_HYPERV - copied unchanged from r271493, head/tools/build/options/WITH_HYPERV stable/10/usr.sbin/hyperv/ - copied from r271493, head/usr.sbin/hyperv/ Modified: stable/10/ObsoleteFiles.inc stable/10/etc/devd/Makefile stable/10/etc/mtree/BSD.usr.dist stable/10/etc/mtree/BSD.var.dist stable/10/libexec/Makefile stable/10/share/mk/bsd.own.mk stable/10/sys/conf/files.amd64 stable/10/sys/conf/files.i386 stable/10/sys/dev/hyperv/include/hyperv.h stable/10/sys/dev/hyperv/utilities/hv_kvp.h stable/10/sys/dev/hyperv/utilities/hv_util.c stable/10/sys/modules/hyperv/utilities/Makefile stable/10/tools/build/mk/OptionalObsoleteFiles.inc stable/10/usr.sbin/Makefile.amd64 stable/10/usr.sbin/Makefile.i386 Directory Properties: stable/10/ (props changed) Modified: stable/10/ObsoleteFiles.inc ============================================================================== --- stable/10/ObsoleteFiles.inc Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/ObsoleteFiles.inc Thu Sep 25 20:34:13 2014 (r272128) @@ -38,6 +38,8 @@ # xargs -n1 | sort | uniq -d; # done +# 20140925: hv_kvpd rc.d script removed in favor of devd configuration +OLD_FILES+=etc/rc.d/hv_kvpd # 20140814: libopie version bump OLD_LIBS+=usr/lib/libopie.so.7 OLD_LIBS+=usr/lib32/libopie.so.7 Modified: stable/10/etc/devd/Makefile ============================================================================== --- stable/10/etc/devd/Makefile Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/etc/devd/Makefile Thu Sep 25 20:34:13 2014 (r272128) @@ -10,6 +10,10 @@ FILES+= apple.conf FILES+= asus.conf .endif +.if ${MK_HYPERV} != "no" +FILES+= hyperv.conf +.endif + NO_OBJ= FILESDIR= /etc/devd FILESMODE= 644 Copied and modified: stable/10/etc/devd/hyperv.conf (from r271696, head/etc/devd/hyperv.conf) ============================================================================== --- head/etc/devd/hyperv.conf Wed Sep 17 02:32:22 2014 (r271696, copy source) +++ stable/10/etc/devd/hyperv.conf Thu Sep 25 20:34:13 2014 (r272128) @@ -6,7 +6,7 @@ notify 10 { match "system" "DEVFS"; match "subsystem" "CDEV"; match "type" "CREATE"; - match "cdev" "/dev/hv_kvp_dev"; + match "cdev" "hv_kvp_dev"; action "/usr/sbin/hv_kvp_daemon"; }; @@ -14,6 +14,6 @@ notify 10 { match "system" "DEVFS"; match "subsystem" "CDEV"; match "type" "DESTROY"; - match "cdev" "/dev/hv_kvp_dev"; + match "cdev" "hv_kvp_dev"; action "pkill -x hv_kvp_daemon"; }; Modified: stable/10/etc/mtree/BSD.usr.dist ============================================================================== --- stable/10/etc/mtree/BSD.usr.dist Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/etc/mtree/BSD.usr.dist Thu Sep 25 20:34:13 2014 (r272128) @@ -108,6 +108,8 @@ .. bsdinstall .. + hyperv + .. lpr ru .. Modified: stable/10/etc/mtree/BSD.var.dist ============================================================================== --- stable/10/etc/mtree/BSD.var.dist Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/etc/mtree/BSD.var.dist Thu Sep 25 20:34:13 2014 (r272128) @@ -42,6 +42,8 @@ .. freebsd-update mode=0700 .. + hyperv mode=0700 + .. ipf mode=0700 .. pkg Modified: stable/10/libexec/Makefile ============================================================================== --- stable/10/libexec/Makefile Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/libexec/Makefile Thu Sep 25 20:34:13 2014 (r272128) @@ -10,6 +10,7 @@ SUBDIR= ${_atf} \ fingerd \ ftpd \ getty \ + ${_hyperv} \ ${_mail.local} \ ${_mknetid} \ ${_pppoed} \ @@ -42,6 +43,10 @@ _atrun= atrun _comsat= comsat .endif +.if ${MK_HYPERV} != "no" +_hyperv= hyperv +.endif + .if ${MK_NIS} != "no" _mknetid= mknetid _ypxfr= ypxfr Modified: stable/10/share/mk/bsd.own.mk ============================================================================== --- stable/10/share/mk/bsd.own.mk Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/share/mk/bsd.own.mk Thu Sep 25 20:34:13 2014 (r272128) @@ -438,6 +438,12 @@ __DEFAULT_YES_OPTIONS+=FDT .else __DEFAULT_NO_OPTIONS+=FDT .endif +# HyperV is only available for x86 and amd64. +.if ${__T} == "amd64" || ${__T} == "i386" +__DEFAULT_YES_OPTIONS+=HYPERV +.else +__DEFAULT_NO_OPTIONS+=HYPERV +.endif .undef __T # Modified: stable/10/sys/conf/files.amd64 ============================================================================== --- stable/10/sys/conf/files.amd64 Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/sys/conf/files.amd64 Thu Sep 25 20:34:13 2014 (r272128) @@ -234,6 +234,7 @@ dev/hyperv/netvsc/hv_netvsc_drv_freebsd. dev/hyperv/netvsc/hv_rndis_filter.c optional hyperv dev/hyperv/stordisengage/hv_ata_pci_disengage.c optional hyperv dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv +dev/hyperv/utilities/hv_kvp.c optional hyperv dev/hyperv/utilities/hv_util.c optional hyperv dev/hyperv/vmbus/hv_channel.c optional hyperv dev/hyperv/vmbus/hv_channel_mgmt.c optional hyperv Modified: stable/10/sys/conf/files.i386 ============================================================================== --- stable/10/sys/conf/files.i386 Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/sys/conf/files.i386 Thu Sep 25 20:34:13 2014 (r272128) @@ -227,6 +227,7 @@ dev/hyperv/netvsc/hv_netvsc_drv_freebsd. dev/hyperv/netvsc/hv_rndis_filter.c optional hyperv dev/hyperv/stordisengage/hv_ata_pci_disengage.c optional hyperv dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv +dev/hyperv/utilities/hv_kvp.c optional hyperv dev/hyperv/utilities/hv_util.c optional hyperv dev/hyperv/vmbus/hv_channel.c optional hyperv dev/hyperv/vmbus/hv_channel_mgmt.c optional hyperv Modified: stable/10/sys/dev/hyperv/include/hyperv.h ============================================================================== --- stable/10/sys/dev/hyperv/include/hyperv.h Thu Sep 25 19:22:26 2014 (r272127) +++ stable/10/sys/dev/hyperv/include/hyperv.h Thu Sep 25 20:34:13 2014 (r272128) @@ -795,5 +795,34 @@ hv_get_phys_addr(void *virt) return (ret); } + +/** + * KVP related structures + * + */ +typedef struct hv_vmbus_service { + hv_guid guid; /* Hyper-V GUID */ + char *name; /* name of service */ + boolean_t enabled; /* service enabled */ + hv_work_queue *work_queue; /* background work queue */ + + /* + * function to initialize service + */ + int (*init)(struct hv_vmbus_service *); + + /* + * function to process Hyper-V messages + */ + void (*callback)(void *); +} hv_vmbus_service; + +extern uint8_t* receive_buffer[]; +extern hv_vmbus_service service_table[]; + +void hv_kvp_callback(void *context); +int hv_kvp_init(hv_vmbus_service *serv); +void hv_kvp_deinit(void); + #endif /* __HYPERV_H__ */ Copied: stable/10/sys/dev/hyperv/utilities/hv_kvp.c (from r271493, head/sys/dev/hyperv/utilities/hv_kvp.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/dev/hyperv/utilities/hv_kvp.c Thu Sep 25 20:34:13 2014 (r272128, copy of r271493, head/sys/dev/hyperv/utilities/hv_kvp.c) @@ -0,0 +1,1001 @@ +/*- + * Copyright (c) 2014 Microsoft Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Author: Sainath Varanasi. + * Date: 4/2012 + * Email: bsdic@microsoft.com + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "unicode.h" +#include "hv_kvp.h" + +/* hv_kvp defines */ +#define BUFFERSIZE sizeof(struct hv_kvp_msg) +#define KVP_SUCCESS 0 +#define KVP_ERROR 1 +#define kvp_hdr hdr.kvp_hdr + +/* hv_kvp debug control */ +static int hv_kvp_log = 0; +SYSCTL_INT(_dev, OID_AUTO, hv_kvp_log, CTLFLAG_RW, &hv_kvp_log, 0, + "hv_kvp log"); + +#define hv_kvp_log_error(...) do { \ + if (hv_kvp_log > 0) \ + log(LOG_ERR, "hv_kvp: " __VA_ARGS__); \ +} while (0) + +#define hv_kvp_log_info(...) do { \ + if (hv_kvp_log > 1) \ + log(LOG_INFO, "hv_kvp: " __VA_ARGS__); \ +} while (0) + +/* character device prototypes */ +static d_open_t hv_kvp_dev_open; +static d_close_t hv_kvp_dev_close; +static d_read_t hv_kvp_dev_daemon_read; +static d_write_t hv_kvp_dev_daemon_write; +static d_poll_t hv_kvp_dev_daemon_poll; + +/* hv_kvp prototypes */ +static int hv_kvp_req_in_progress(void); +static void hv_kvp_transaction_init(uint32_t, hv_vmbus_channel *, uint64_t, uint8_t *); +static void hv_kvp_send_msg_to_daemon(void); +static void hv_kvp_process_request(void *context); + +/* hv_kvp character device structure */ +static struct cdevsw hv_kvp_cdevsw = +{ + .d_version = D_VERSION, + .d_open = hv_kvp_dev_open, + .d_close = hv_kvp_dev_close, + .d_read = hv_kvp_dev_daemon_read, + .d_write = hv_kvp_dev_daemon_write, + .d_poll = hv_kvp_dev_daemon_poll, + .d_name = "hv_kvp_dev", +}; +static struct cdev *hv_kvp_dev; +static struct hv_kvp_msg *hv_kvp_dev_buf; +struct proc *daemon_task; + +/* + * Global state to track and synchronize multiple + * KVP transaction requests from the host. + */ +static struct { + + /* Pre-allocated work item for queue */ + hv_work_item work_item; + + /* Unless specified the pending mutex should be + * used to alter the values of the following paramters: + * 1. req_in_progress + * 2. req_timed_out + * 3. pending_reqs. + */ + struct mtx pending_mutex; + + /* To track if transaction is active or not */ + boolean_t req_in_progress; + /* Tracks if daemon did not reply back in time */ + boolean_t req_timed_out; + /* Tracks if daemon is serving a request currently */ + boolean_t daemon_busy; + /* Count of KVP requests from Hyper-V. */ + uint64_t pending_reqs; + + + /* Length of host message */ + uint32_t host_msg_len; + + /* Pointer to channel */ + hv_vmbus_channel *channelp; + + /* Host message id */ + uint64_t host_msg_id; + + /* Current kvp message from the host */ + struct hv_kvp_msg *host_kvp_msg; + + /* Current kvp message for daemon */ + struct hv_kvp_msg daemon_kvp_msg; + + /* Rcv buffer for communicating with the host*/ + uint8_t *rcv_buf; + + /* Device semaphore to control communication */ + struct sema dev_sema; + + /* Indicates if daemon registered with driver */ + boolean_t register_done; + + /* Character device status */ + boolean_t dev_accessed; +} kvp_globals; + +/* global vars */ +MALLOC_DECLARE(M_HV_KVP_DEV_BUF); +MALLOC_DEFINE(M_HV_KVP_DEV_BUF, "hv_kvp_dev buffer", "buffer for hv_kvp_dev module"); + +/* + * hv_kvp low level functions + */ + +/* + * Check if kvp transaction is in progres + */ +static int +hv_kvp_req_in_progress(void) +{ + + return (kvp_globals.req_in_progress); +} + + +/* + * This routine is called whenever a message is received from the host + */ +static void +hv_kvp_transaction_init(uint32_t rcv_len, hv_vmbus_channel *rcv_channel, + uint64_t request_id, uint8_t *rcv_buf) +{ + + /* Store all the relevant message details in the global structure */ + /* Do not need to use mutex for req_in_progress here */ + kvp_globals.req_in_progress = true; + kvp_globals.host_msg_len = rcv_len; + kvp_globals.channelp = rcv_channel; + kvp_globals.host_msg_id = request_id; + kvp_globals.rcv_buf = rcv_buf; + kvp_globals.host_kvp_msg = (struct hv_kvp_msg *)&rcv_buf[ + sizeof(struct hv_vmbus_pipe_hdr) + + sizeof(struct hv_vmbus_icmsg_hdr)]; +} + + +/* + * hv_kvp - version neogtiation function + */ +static void +hv_kvp_negotiate_version(struct hv_vmbus_icmsg_hdr *icmsghdrp, + struct hv_vmbus_icmsg_negotiate *negop, + uint8_t *buf) +{ + 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 + */ +static int +hv_kvp_convert_utf8_ipinfo_to_utf16(struct hv_kvp_msg *umsg, + struct hv_kvp_ip_msg *host_ip_msg) +{ + int err_ip, err_subnet, err_gway, err_dns, err_adap; + int UNUSED_FLAG = 1; + + utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.ip_addr, + MAX_IP_ADDR_SIZE, + (char *)umsg->body.kvp_ip_val.ip_addr, + strlen((char *)umsg->body.kvp_ip_val.ip_addr), + UNUSED_FLAG, + &err_ip); + utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.sub_net, + MAX_IP_ADDR_SIZE, + (char *)umsg->body.kvp_ip_val.sub_net, + strlen((char *)umsg->body.kvp_ip_val.sub_net), + UNUSED_FLAG, + &err_subnet); + utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.gate_way, + MAX_GATEWAY_SIZE, + (char *)umsg->body.kvp_ip_val.gate_way, + strlen((char *)umsg->body.kvp_ip_val.gate_way), + UNUSED_FLAG, + &err_gway); + utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.dns_addr, + MAX_IP_ADDR_SIZE, + (char *)umsg->body.kvp_ip_val.dns_addr, + strlen((char *)umsg->body.kvp_ip_val.dns_addr), + UNUSED_FLAG, + &err_dns); + utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.adapter_id, + MAX_IP_ADDR_SIZE, + (char *)umsg->body.kvp_ip_val.adapter_id, + strlen((char *)umsg->body.kvp_ip_val.adapter_id), + UNUSED_FLAG, + &err_adap); + + host_ip_msg->kvp_ip_val.dhcp_enabled = umsg->body.kvp_ip_val.dhcp_enabled; + host_ip_msg->kvp_ip_val.addr_family = umsg->body.kvp_ip_val.addr_family; + + return (err_ip | err_subnet | err_gway | err_dns | err_adap); +} + + +/* + * Convert ip related info in hmsg from utf16 to utf8 and store in umsg + */ +static int +hv_kvp_convert_utf16_ipinfo_to_utf8(struct hv_kvp_ip_msg *host_ip_msg, + struct hv_kvp_msg *umsg) +{ + int err_ip, err_subnet, err_gway, err_dns, err_adap; + int UNUSED_FLAG = 1; + int guid_index; + struct hv_device *hv_dev; /* GUID Data Structure */ + hn_softc_t *sc; /* hn softc structure */ + char if_name[4]; + unsigned char guid_instance[40]; + char *guid_data = NULL; + char buf[39]; + + struct guid_extract { + char a1[2]; + char a2[2]; + char a3[2]; + char a4[2]; + char b1[2]; + char b2[2]; + char c1[2]; + char c2[2]; + char d[4]; + char e[12]; + }; + + struct guid_extract *id; + device_t *devs; + int devcnt; + + /* IP Address */ + utf16_to_utf8((char *)umsg->body.kvp_ip_val.ip_addr, + MAX_IP_ADDR_SIZE, + (uint16_t *)host_ip_msg->kvp_ip_val.ip_addr, + MAX_IP_ADDR_SIZE, + UNUSED_FLAG, + &err_ip); + + /* Adapter ID : GUID */ + utf16_to_utf8((char *)umsg->body.kvp_ip_val.adapter_id, + MAX_ADAPTER_ID_SIZE, + (uint16_t *)host_ip_msg->kvp_ip_val.adapter_id, + MAX_ADAPTER_ID_SIZE, + UNUSED_FLAG, + &err_adap); + + if (devclass_get_devices(devclass_find("hn"), &devs, &devcnt) == 0) { + for (devcnt = devcnt - 1; devcnt >= 0; devcnt--) { + sc = device_get_softc(devs[devcnt]); + + /* Trying to find GUID of Network Device */ + hv_dev = sc->hn_dev_obj; + + for (guid_index = 0; guid_index < 16; guid_index++) { + sprintf(&guid_instance[guid_index * 2], "%02x", + hv_dev->device_id.data[guid_index]); + } + + guid_data = (char *)guid_instance; + id = (struct guid_extract *)guid_data; + snprintf(buf, sizeof(buf), "{%.2s%.2s%.2s%.2s-%.2s%.2s-%.2s%.2s-%.4s-%s}", + id->a4, id->a3, id->a2, id->a1, + id->b2, id->b1, id->c2, id->c1, id->d, id->e); + guid_data = NULL; + sprintf(if_name, "%s%d", "hn", device_get_unit(devs[devcnt])); + + if (strncmp(buf, (char *)umsg->body.kvp_ip_val.adapter_id, 39) == 0) { + strcpy((char *)umsg->body.kvp_ip_val.adapter_id, if_name); + break; + } + } + free(devs, M_TEMP); + } + + /* Address Family , DHCP , SUBNET, Gateway, DNS */ + umsg->kvp_hdr.operation = host_ip_msg->operation; + umsg->body.kvp_ip_val.addr_family = host_ip_msg->kvp_ip_val.addr_family; + umsg->body.kvp_ip_val.dhcp_enabled = host_ip_msg->kvp_ip_val.dhcp_enabled; + utf16_to_utf8((char *)umsg->body.kvp_ip_val.sub_net, MAX_IP_ADDR_SIZE, + (uint16_t *)host_ip_msg->kvp_ip_val.sub_net, + MAX_IP_ADDR_SIZE, + UNUSED_FLAG, + &err_subnet); + + utf16_to_utf8((char *)umsg->body.kvp_ip_val.gate_way, MAX_GATEWAY_SIZE, + (uint16_t *)host_ip_msg->kvp_ip_val.gate_way, + MAX_GATEWAY_SIZE, + UNUSED_FLAG, + &err_gway); + + utf16_to_utf8((char *)umsg->body.kvp_ip_val.dns_addr, MAX_IP_ADDR_SIZE, + (uint16_t *)host_ip_msg->kvp_ip_val.dns_addr, + MAX_IP_ADDR_SIZE, + UNUSED_FLAG, + &err_dns); + + return (err_ip | err_subnet | err_gway | err_dns | err_adap); +} + + +/* + * Prepare a user kvp msg based on host kvp msg (utf16 to utf8) + * Ensure utf16_utf8 takes care of the additional string terminating char!! + */ +static void +hv_kvp_convert_hostmsg_to_usermsg(void) +{ + int utf_err = 0; + uint32_t value_type; + struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *) + kvp_globals.host_kvp_msg; + + struct hv_kvp_msg *hmsg = kvp_globals.host_kvp_msg; + struct hv_kvp_msg *umsg = &kvp_globals.daemon_kvp_msg; + + memset(umsg, 0, sizeof(struct hv_kvp_msg)); + + umsg->kvp_hdr.operation = hmsg->kvp_hdr.operation; + umsg->kvp_hdr.pool = hmsg->kvp_hdr.pool; + + switch (umsg->kvp_hdr.operation) { + case HV_KVP_OP_SET_IP_INFO: + hv_kvp_convert_utf16_ipinfo_to_utf8(host_ip_msg, umsg); + break; + + case HV_KVP_OP_GET_IP_INFO: + utf16_to_utf8((char *)umsg->body.kvp_ip_val.adapter_id, + MAX_ADAPTER_ID_SIZE, + (uint16_t *)host_ip_msg->kvp_ip_val.adapter_id, + MAX_ADAPTER_ID_SIZE, 1, &utf_err); + + umsg->body.kvp_ip_val.addr_family = + host_ip_msg->kvp_ip_val.addr_family; + break; + + case HV_KVP_OP_SET: + value_type = hmsg->body.kvp_set.data.value_type; + + switch (value_type) { + case HV_REG_SZ: + umsg->body.kvp_set.data.value_size = + utf16_to_utf8( + (char *)umsg->body.kvp_set.data.msg_value.value, + HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1, + (uint16_t *)hmsg->body.kvp_set.data.msg_value.value, + hmsg->body.kvp_set.data.value_size, + 1, &utf_err); + /* utf8 encoding */ + umsg->body.kvp_set.data.value_size = + umsg->body.kvp_set.data.value_size / 2; + break; + + case HV_REG_U32: + umsg->body.kvp_set.data.value_size = + sprintf(umsg->body.kvp_set.data.msg_value.value, "%d", + hmsg->body.kvp_set.data.msg_value.value_u32) + 1; + break; + + case HV_REG_U64: + umsg->body.kvp_set.data.value_size = + sprintf(umsg->body.kvp_set.data.msg_value.value, "%llu", + (unsigned long long) + hmsg->body.kvp_set.data.msg_value.value_u64) + 1; + break; + } + + umsg->body.kvp_set.data.key_size = + utf16_to_utf8( + umsg->body.kvp_set.data.key, + HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1, + (uint16_t *)hmsg->body.kvp_set.data.key, + hmsg->body.kvp_set.data.key_size, + 1, &utf_err); + + /* utf8 encoding */ + umsg->body.kvp_set.data.key_size = + umsg->body.kvp_set.data.key_size / 2; + break; + + case HV_KVP_OP_GET: + umsg->body.kvp_get.data.key_size = + utf16_to_utf8(umsg->body.kvp_get.data.key, + HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1, + (uint16_t *)hmsg->body.kvp_get.data.key, + hmsg->body.kvp_get.data.key_size, + 1, &utf_err); + /* utf8 encoding */ + umsg->body.kvp_get.data.key_size = + umsg->body.kvp_get.data.key_size / 2; + break; + + case HV_KVP_OP_DELETE: + umsg->body.kvp_delete.key_size = + utf16_to_utf8(umsg->body.kvp_delete.key, + HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1, + (uint16_t *)hmsg->body.kvp_delete.key, + hmsg->body.kvp_delete.key_size, + 1, &utf_err); + /* utf8 encoding */ + umsg->body.kvp_delete.key_size = + umsg->body.kvp_delete.key_size / 2; + break; + + case HV_KVP_OP_ENUMERATE: + umsg->body.kvp_enum_data.index = + hmsg->body.kvp_enum_data.index; + break; + + default: + hv_kvp_log_info("%s: daemon_kvp_msg: Invalid operation : %d\n", + __func__, umsg->kvp_hdr.operation); + } +} + + +/* + * Prepare a host kvp msg based on user kvp msg (utf8 to utf16) + */ +static int +hv_kvp_convert_usermsg_to_hostmsg(void) +{ + int hkey_len = 0, hvalue_len = 0, utf_err = 0; + struct hv_kvp_exchg_msg_value *host_exchg_data; + char *key_name, *value; + + struct hv_kvp_msg *umsg = &kvp_globals.daemon_kvp_msg; + struct hv_kvp_msg *hmsg = kvp_globals.host_kvp_msg; + struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *)hmsg; + + switch (hmsg->kvp_hdr.operation) { + case HV_KVP_OP_GET_IP_INFO: + return (hv_kvp_convert_utf8_ipinfo_to_utf16(umsg, host_ip_msg)); + + case HV_KVP_OP_SET_IP_INFO: + case HV_KVP_OP_SET: + case HV_KVP_OP_DELETE: + return (KVP_SUCCESS); + + case HV_KVP_OP_ENUMERATE: + host_exchg_data = &hmsg->body.kvp_enum_data.data; + key_name = umsg->body.kvp_enum_data.data.key; + hkey_len = utf8_to_utf16((uint16_t *)host_exchg_data->key, + ((HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2), + key_name, strlen(key_name), + 1, &utf_err); + /* utf16 encoding */ + host_exchg_data->key_size = 2 * (hkey_len + 1); + value = umsg->body.kvp_enum_data.data.msg_value.value; + hvalue_len = utf8_to_utf16( + (uint16_t *)host_exchg_data->msg_value.value, + ((HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2), + value, strlen(value), + 1, &utf_err); + host_exchg_data->value_size = 2 * (hvalue_len + 1); + host_exchg_data->value_type = HV_REG_SZ; + + if ((hkey_len < 0) || (hvalue_len < 0)) + return (HV_KVP_E_FAIL); + + return (KVP_SUCCESS); + + case HV_KVP_OP_GET: + host_exchg_data = &hmsg->body.kvp_get.data; + value = umsg->body.kvp_get.data.msg_value.value; + hvalue_len = utf8_to_utf16( + (uint16_t *)host_exchg_data->msg_value.value, + ((HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2), + value, strlen(value), + 1, &utf_err); + /* Convert value size to uft16 */ + host_exchg_data->value_size = 2 * (hvalue_len + 1); + /* Use values by string */ + host_exchg_data->value_type = HV_REG_SZ; + + if ((hkey_len < 0) || (hvalue_len < 0)) + return (HV_KVP_E_FAIL); + + return (KVP_SUCCESS); + + default: + return (HV_KVP_E_FAIL); + } +} + + +/* + * Send the response back to the host. + */ +static void +hv_kvp_respond_host(int error) +{ + struct hv_vmbus_icmsg_hdr *hv_icmsg_hdrp; + + hv_icmsg_hdrp = (struct hv_vmbus_icmsg_hdr *) + &kvp_globals.rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)]; + + if (error) + error = HV_KVP_E_FAIL; + + hv_icmsg_hdrp->status = error; + hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE; + + error = hv_vmbus_channel_send_packet(kvp_globals.channelp, + kvp_globals.rcv_buf, + kvp_globals.host_msg_len, kvp_globals.host_msg_id, + HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); + + if (error) + hv_kvp_log_info("%s: hv_kvp_respond_host: sendpacket error:%d\n", + __func__, error); +} + + +/* + * This is the main kvp kernel process that interacts with both user daemon + * and the host + */ +static void +hv_kvp_send_msg_to_daemon(void) +{ + /* Prepare kvp_msg to be sent to user */ + hv_kvp_convert_hostmsg_to_usermsg(); + + /* Send the msg to user via function deamon_read - setting sema */ + sema_post(&kvp_globals.dev_sema); +} + + +/* + * Function to read the kvp request buffer from host + * and interact with daemon + */ +static void +hv_kvp_process_request(void *context) +{ + uint8_t *kvp_buf; + hv_vmbus_channel *channel = context; + uint32_t recvlen = 0; + uint64_t requestid; + struct hv_vmbus_icmsg_hdr *icmsghdrp; + int ret = 0; + uint64_t pending_cnt = 1; + + hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__); + kvp_buf = receive_buffer[HV_KVP]; + ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE, + &recvlen, &requestid); + + /* + * We start counting only after the daemon registers + * and therefore there could be requests pending in + * the VMBus that are not reflected in pending_cnt. + * Therefore we continue reading as long as either of + * the below conditions is true. + */ + + while ((pending_cnt>0) || ((ret == 0) && (recvlen > 0))) { + + if ((ret == 0) && (recvlen>0)) { + + icmsghdrp = (struct hv_vmbus_icmsg_hdr *) + &kvp_buf[sizeof(struct hv_vmbus_pipe_hdr)]; + + hv_kvp_transaction_init(recvlen, channel, requestid, kvp_buf); + if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) { + hv_kvp_negotiate_version(icmsghdrp, NULL, kvp_buf); + hv_kvp_respond_host(ret); + + /* + * It is ok to not acquire the mutex before setting + * req_in_progress here because negotiation is the + * first thing that happens and hence there is no + * chance of a race condition. + */ + + kvp_globals.req_in_progress = false; + hv_kvp_log_info("%s :version negotiated\n", __func__); + + } else { + if (!kvp_globals.daemon_busy) { + + hv_kvp_log_info("%s: issuing qury to daemon\n", __func__); + mtx_lock(&kvp_globals.pending_mutex); + kvp_globals.req_timed_out = false; + kvp_globals.daemon_busy = true; + mtx_unlock(&kvp_globals.pending_mutex); + + hv_kvp_send_msg_to_daemon(); + hv_kvp_log_info("%s: waiting for daemon\n", __func__); + } + + /* Wait 5 seconds for daemon to respond back */ + tsleep(&kvp_globals, 0, "kvpworkitem", 5 * hz); + hv_kvp_log_info("%s: came out of wait\n", __func__); + } + } + + mtx_lock(&kvp_globals.pending_mutex); + + /* Notice that once req_timed_out is set to true + * it will remain true until the next request is + * sent to the daemon. The response from daemon + * is forwarded to host only when this flag is + * false. + */ + kvp_globals.req_timed_out = true; + + /* + * Cancel request if so need be. + */ + if (hv_kvp_req_in_progress()) { + hv_kvp_log_info("%s: request was still active after wait so failing\n", __func__); + hv_kvp_respond_host(HV_KVP_E_FAIL); + kvp_globals.req_in_progress = false; + } + + /* + * Decrement pending request count and + */ + if (kvp_globals.pending_reqs>0) { + kvp_globals.pending_reqs = kvp_globals.pending_reqs - 1; + } + pending_cnt = kvp_globals.pending_reqs; + + mtx_unlock(&kvp_globals.pending_mutex); + + /* + * Try reading next buffer + */ + recvlen = 0; + ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE, + &recvlen, &requestid); + hv_kvp_log_info("%s: read: context %p, pending_cnt %ju ret =%d, recvlen=%d\n", + __func__, context, pending_cnt, ret, recvlen); + } +} + + +/* + * Callback routine that gets called whenever there is a message from host + */ +void +hv_kvp_callback(void *context) +{ + uint64_t pending_cnt = 0; + + if (kvp_globals.register_done == false) { + + kvp_globals.channelp = context; + } else { + + mtx_lock(&kvp_globals.pending_mutex); + kvp_globals.pending_reqs = kvp_globals.pending_reqs + 1; + pending_cnt = kvp_globals.pending_reqs; + mtx_unlock(&kvp_globals.pending_mutex); + if (pending_cnt == 1) { + hv_kvp_log_info("%s: Queuing work item\n", __func__); + hv_queue_work_item( + service_table[HV_KVP].work_queue, + hv_kvp_process_request, + context + ); + } + } +} + + +/* + * This function is called by the hv_kvp_init - + * creates character device hv_kvp_dev + * allocates memory to hv_kvp_dev_buf + * + */ +static int +hv_kvp_dev_init(void) +{ + int error = 0; + + /* initialize semaphore */ + sema_init(&kvp_globals.dev_sema, 0, "hv_kvp device semaphore"); + /* create character device */ + error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, + &hv_kvp_dev, + &hv_kvp_cdevsw, + 0, + UID_ROOT, + GID_WHEEL, + 0640, + "hv_kvp_dev"); + + if (error != 0) + return (error); + + /* + * Malloc with M_WAITOK flag will never fail. + */ + hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf), M_HV_KVP_DEV_BUF, M_WAITOK | + M_ZERO); + + return (0); +} + + +/* + * This function is called by the hv_kvp_deinit - + * destroy character device + */ +static void +hv_kvp_dev_destroy(void) +{ + + if (daemon_task != NULL) { + PROC_LOCK(daemon_task); + kern_psignal(daemon_task, SIGKILL); + PROC_UNLOCK(daemon_task); + } + + destroy_dev(hv_kvp_dev); + free(hv_kvp_dev_buf, M_HV_KVP_DEV_BUF); + return; +} + + +static int +hv_kvp_dev_open(struct cdev *dev, int oflags, int devtype, + struct thread *td) +{ + + hv_kvp_log_info("%s: Opened device \"hv_kvp_device\" successfully.\n", __func__); + if (kvp_globals.dev_accessed) + return (-EBUSY); + + daemon_task = curproc; + kvp_globals.dev_accessed = true; + kvp_globals.daemon_busy = false; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***