Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 9 Sep 2013 08:07:46 +0000 (UTC)
From:      Peter Grehan <grehan@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r255414 - in projects/hyperv/sys: conf dev/hyperv dev/hyperv/utilities dev/hyperv/vmbus modules/hyperv/netvsc modules/hyperv/utilities
Message-ID:  <201309090807.r8987kMm053821@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: grehan
Date: Mon Sep  9 08:07:46 2013
New Revision: 255414
URL: http://svnweb.freebsd.org/changeset/base/255414

Log:
  Latest update from Microsoft.
  
  Obtained from:	Microsoft Hyper-v dev team

Added:
  projects/hyperv/sys/dev/hyperv/utilities/hv_kvp.c   (contents, props changed)
  projects/hyperv/sys/dev/hyperv/utilities/hv_kvp.h   (contents, props changed)
Deleted:
  projects/hyperv/sys/dev/hyperv/README
Modified:
  projects/hyperv/sys/conf/files.amd64
  projects/hyperv/sys/dev/hyperv/utilities/hv_util.c
  projects/hyperv/sys/dev/hyperv/vmbus/hv_hv.c
  projects/hyperv/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
  projects/hyperv/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
  projects/hyperv/sys/modules/hyperv/netvsc/Makefile
  projects/hyperv/sys/modules/hyperv/utilities/Makefile

Modified: projects/hyperv/sys/conf/files.amd64
==============================================================================
--- projects/hyperv/sys/conf/files.amd64	Mon Sep  9 06:02:30 2013	(r255413)
+++ projects/hyperv/sys/conf/files.amd64	Mon Sep  9 08:07:46 2013	(r255414)
@@ -226,6 +226,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

Added: projects/hyperv/sys/dev/hyperv/utilities/hv_kvp.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/hyperv/sys/dev/hyperv/utilities/hv_kvp.c	Mon Sep  9 08:07:46 2013	(r255414)
@@ -0,0 +1,982 @@
+/*-
+ * Copyright (c) 2009-2012 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.
+ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron.
+ *
+ * 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, 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+ /* An implementation of key value pair (KVP) functionality for FreeBSD */ 
+
+/**
+ * Code for handling all KVP related messages 
+ */
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kthread.h>
+#include <sys/socket.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysproto.h>
+#include <sys/un.h>
+#include <sys/endian.h>
+
+#include <net/if_arp.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/netvsc/hv_net_vsc.h>
+#include "hv_kvp.h"
+
+/* Unicode Conversions */
+#include <sys/cdefs.h>
+#include <sys/_null.h>
+
+static int hv_kvp_daemon_ack = 0;
+SYSCTL_INT(_dev, OID_AUTO, hv_kvp_daemon_ack, CTLFLAG_RW, &hv_kvp_daemon_ack,
+		0, "First ack when daemon is ready");
+
+static size_t convert8_to_16(uint16_t *, size_t, const char *, size_t, int *);
+static size_t convert16_to_8(char *, size_t, const uint16_t *, size_t, int *);
+
+/* Unicode declarations ends */
+#define KVP_SUCCESS	0
+#define kvp_hdr hdr.kvp_hdr
+typedef struct hv_kvp_msg hv_kvp_bsd_msg;
+
+static int hv_kvp_ready(void);
+static int hv_kvp_transaction_active(void);
+static void hv_kvp_transaction_init(uint32_t, hv_vmbus_channel *, uint64_t,
+    uint8_t *);
+static void hv_kvp_conn_register(void);
+static void hv_kvp_process_msg(void *p);
+
+/*
+ * We maintain a global state, assuming only one transaction can be active
+ * at any point in time.
+ * Inited by the kvp callback routine (utils file) when a valid message is
+ * received from the host;
+ */
+static struct {
+	boolean_t kvp_ready; /* indicates if kvp module is ready or not */
+	boolean_t in_progress; /* transaction status - active or not */
+	uint32_t host_msg_len; /* length of host message */
+	hv_vmbus_channel *channelp; /* pointer to channel */
+	uint64_t host_msg_id; /* host message id */
+	hv_kvp_bsd_msg  *host_kvp_msg; /* current message from the host */
+	uint8_t *rcv_buf; /* rcv buffer for communicating with the host*/
+} kvp_msg_state;
+
+
+/* We use an alternative, more convenient representation in the generator. */
+
+/* 
+ * Data Buffer used by kernel for to/from communication with user daemon 
+ */
+static hv_kvp_bsd_msg  hv_user_kvp_msg; 
+
+static boolean_t conn_ready; /* indicates if connection to daemon done */
+static boolean_t register_done; /* indicates daemon registered with driver */
+
+/* Original socket created during connection establishment */
+static int sock_fd;
+
+/* Handle to KVP device */ 
+struct hv_device* kvp_hv_dev;
+
+/*
+ * Check if kvp routines are ready to receive and respond
+ */
+static int 
+hv_kvp_ready(void)
+{
+
+	return (kvp_msg_state.kvp_ready);
+}
+
+/*
+ * Check if kvp transaction is in progres
+ */
+static int 
+hv_kvp_transaction_active(void)
+{
+
+	return (kvp_msg_state.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
+	 */
+	kvp_msg_state.in_progress = TRUE;
+	kvp_msg_state.host_msg_len = rcv_len;
+	kvp_msg_state.channelp = rcv_channel;
+	kvp_msg_state.host_msg_id = request_id;
+	kvp_msg_state.rcv_buf = rcv_buf;
+	kvp_msg_state.host_kvp_msg = (hv_kvp_bsd_msg *)&rcv_buf[
+	    sizeof(struct hv_vmbus_pipe_hdr) +
+            sizeof(struct hv_vmbus_icmsg_hdr)];
+}
+
+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;
+
+	if (bootverbose)
+		printf("hv_kvp_negotiate_version\n");
+
+        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; 			
+	}
+
+        /*
+	 * Respond with the maximum framework and service
+	 * version numbers we can support.
+	 */
+        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;
+}
+
+/*
+ * Establish a UNIX socket connection with user daemon 
+ */
+static int
+kvp_connect_user(void)
+{
+	int sock_error;
+	struct socket_args unix_sock;
+	struct sockaddr_un sock_sun;
+	struct thread *thread_ptr;
+
+	thread_ptr = curthread;
+
+	/* Open a Unix Domain socket */
+	unix_sock.domain = AF_UNIX;
+	unix_sock.type = SOCK_STREAM;
+	unix_sock.protocol = 0;
+	sock_error = sys_socket(thread_ptr, &unix_sock);
+	if (sock_error) {
+                return sock_error;
+	}
+
+	/* Try to connect to user daemon using Unix socket */
+	sock_fd = thread_ptr->td_retval[0];
+	sock_sun.sun_family = AF_UNIX;
+	strcpy(sock_sun.sun_path, BSD_SOC_PATH);
+	sock_sun.sun_len = sizeof(struct sockaddr_un) - 
+	    sizeof(sock_sun.sun_path) + strlen(sock_sun.sun_path) + 1;
+
+	sock_error = kern_connect(thread_ptr, sock_fd, 
+	    (struct sockaddr *) &sock_sun);
+	if (sock_error) {
+                kern_close(thread_ptr, sock_fd);
+	}
+
+	return (sock_error);
+}
+
+
+/*
+ * Send kvp msg on the established unix socket connection to the user
+ */
+static int
+kvp_send_user(void)
+{
+	int send_fd, send_error;
+	struct uio send_uio;
+	struct iovec send_iovec;
+	struct thread *thread_ptr = curthread;
+
+	if (!hv_kvp_ready()) {
+		hv_kvp_conn_register();
+	}
+
+	send_fd = sock_fd;
+	memset(&send_uio, 0, sizeof(struct uio));
+	
+	send_iovec.iov_base = (void *)&hv_user_kvp_msg;
+	send_iovec.iov_len = sizeof(hv_kvp_bsd_msg);
+	send_uio.uio_iov = &send_iovec;
+	send_uio.uio_iovcnt = 1;
+	send_uio.uio_resid = send_iovec.iov_len;
+	send_uio.uio_segflg = UIO_SYSSPACE;
+	send_error = kern_writev(thread_ptr, send_fd, &send_uio);
+
+	return (send_error);
+}
+
+
+/*
+ * Receive kvp msg on the established unix socket connection from the user
+ */
+static int
+kvp_rcv_user(void)
+{
+	int rcv_fd, rcv_error=0;
+	struct uio rcv_uio;
+	struct iovec rcv_iovec;
+	struct thread *thread_ptr = curthread;
+
+	rcv_fd = sock_fd;
+
+	memset(&rcv_uio, 0, sizeof(struct uio)); 	
+
+	rcv_iovec.iov_base = (void *)&hv_user_kvp_msg;
+	rcv_iovec.iov_len = sizeof(hv_kvp_bsd_msg);
+	rcv_uio.uio_iov = &rcv_iovec;
+	rcv_uio.uio_iovcnt = 1;
+	rcv_uio.uio_resid = rcv_iovec.iov_len;
+	rcv_uio.uio_segflg = UIO_SYSSPACE;
+	rcv_error = kern_readv(thread_ptr, rcv_fd, &rcv_uio);
+
+	return (rcv_error);
+}
+
+/*
+ * Converts utf8 to utf16
+ */
+static size_t
+convert8_to_16(uint16_t *dst, size_t dst_len,const char *src, size_t src_len,
+   int *errp)
+{
+    const unsigned char *s;
+    size_t spos, dpos;
+    int error, flags = 1;
+    uint16_t c;
+#define IS_CONT(c)      (((c)&0xc0) == 0x80)
+
+    error = 0;
+    s = (const unsigned char *)src;
+    spos = dpos = 0;
+ 
+    while (spos<src_len) {
+        if (s[spos] < 0x80)
+            c = s[spos++];
+        else if ((flags & 0x03)
+                 && (spos >= src_len || !IS_CONT(s[spos+1]))
+                 && s[spos]>=0xa0) {
+            /* not valid UTF-8, assume ISO 8859-1 */
+            c = s[spos++];
+        }
+        else if (s[spos] < 0xc0 || s[spos] >= 0xf5) {
+            /* continuation byte without lead byte
+               or lead byte for codepoint above 0x10ffff */
+            error++;
+            spos++;
+            continue;
+        }
+        else if (s[spos] < 0xe0) {
+            if (spos >= src_len || !IS_CONT(s[spos+1])) {
+                spos++;
+                error++;
+                continue;
+            }
+            c = ((s[spos] & 0x3f) << 6) | (s[spos+1] & 0x3f);
+            spos += 2;
+            if (c < 0x80) {
+                /* overlong encoding */
+                error++;
+                continue;
+		}
+        }
+        else if (s[spos] < 0xf0) {
+            if (spos >= src_len-2
+                || !IS_CONT(s[spos+1]) || !IS_CONT(s[spos+2])) {
+                spos++;
+                error++;
+                continue;
+            }
+            c = ((s[spos] & 0x0f) << 12) | ((s[spos+1] & 0x3f) << 6)
+                | (s[spos+2] & 0x3f);
+            spos += 3;
+            if (c < 0x800 || (c & 0xdf00) == 0xd800 ) {
+                /* overlong encoding or encoded surrogate */
+                error++;
+                continue;
+            }
+        }
+        else {
+            uint32_t cc;
+            /* UTF-16 surrogate pair */
+
+            if (spos >= src_len-3 || !IS_CONT(s[spos+1])
+                || !IS_CONT(s[spos+2]) || !IS_CONT(s[spos+3])) {
+                spos++;
+                error++;
+
+                continue;
+            }
+            cc = ((s[spos] & 0x03) << 18) | ((s[spos+1] & 0x3f) << 12)
+| ((s[spos+2] & 0x3f) << 6) | (s[spos+3] & 0x3f);
+            spos += 4;
+            if (cc < 0x10000) {
+                /* overlong encoding */
+                error++;
+                continue;
+            }
+            if (dst && dpos < dst_len)
+                dst[dpos] = (0xd800 | ((cc-0x10000)>>10));
+            dpos++;
+            c = 0xdc00 | ((cc-0x10000) & 0x3ffff);
+        }
+
+        if (dst && dpos < dst_len)
+            dst[dpos] = c;
+        dpos++;
+    }
+
+    if (errp)
+       *errp = error;
+
+    return dpos;
+
+#undef IS_CONT
+}
+
+/*
+ * Converts utf16 to utf8
+*/
+static size_t
+convert16_to_8(char *dst, size_t dst_len, const uint16_t *src, size_t src_len,
+    int *errp)
+{
+    uint16_t spos, dpos;
+    int error;
+#define CHECK_LENGTH(l) (dpos > dst_len-(l) ? dst=NULL : NULL)
+#define ADD_BYTE(b)     (dst ? dst[dpos] = (b) : 0, dpos++)
+
+    error = 0;
+    dpos = 0;
+ for (spos=0; spos<src_len; spos++) {
+	 if (src[spos] < 0x80) {
+            CHECK_LENGTH(1);
+            ADD_BYTE(src[spos]);
+        }
+        else if (src[spos] < 0x800) {
+            CHECK_LENGTH(2);
+            ADD_BYTE(0xc0 | (src[spos]>>6));
+            ADD_BYTE(0x80 | (src[spos] & 0x3f));
+        }
+        else if ((src[spos] & 0xdc00) == 0xd800) {
+            uint32_t c;
+            /* first surrogate */
+            if (spos == src_len - 1 || (src[spos] & 0xdc00) != 0xdc00) {
+                /* no second surrogate present */
+                error++;
+                continue;
+            }
+            spos++;
+            CHECK_LENGTH(4);
+            c = (((src[spos]&0x3ff) << 10) | (src[spos+1]&0x3ff)) + 0x10000;
+            ADD_BYTE(0xf0 | (c>>18));
+            ADD_BYTE(0x80 | ((c>>12) & 0x3f));
+            ADD_BYTE(0x80 | ((c>>6) & 0x3f));
+            ADD_BYTE(0x80 | (c & 0x3f));
+        }
+        else if ((src[spos] & 0xdc00) == 0xdc00) {
+            /* second surrogate without preceding first surrogate */
+            error++;
+        }
+        else {
+            CHECK_LENGTH(3);
+            ADD_BYTE(0xe0 | src[spos]>>12);
+            ADD_BYTE(0x80 | ((src[spos]>>6) & 0x3f));
+            ADD_BYTE(0x80 | (src[spos] & 0x3f));
+        }
+    }
+
+    if (errp)
+ *errp = error;
+  return dpos;
+
+#undef ADD_BYTE
+#undef CHECK_LENGTH
+}
+
+
+/*
+ * Convert ip related info in umsg from utf8 to utf16 and store in hmsg
+ */
+static int 
+ipinfo_utf8_utf16(hv_kvp_bsd_msg *umsg, struct hv_kvp_ip_msg *host_ip_msg)
+{
+        int err_ip, err_subnet, err_gway, err_dns, err_adap;
+
+	size_t len=0;
+        len = convert8_to_16((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),
+			&err_ip);
+        len = convert8_to_16((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),
+                        &err_subnet);
+        len = convert8_to_16((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),
+                        &err_gway);
+        len = convert8_to_16((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),
+                        &err_dns);
+        len = convert8_to_16((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),
+                        &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 
+ipinfo_utf16_utf8(struct hv_kvp_ip_msg *host_ip_msg, hv_kvp_bsd_msg *umsg)
+{
+	int err_ip, err_subnet, err_gway, err_dns, err_adap;
+	int j;
+ 	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];			 
+	int len=16;
+	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];
+	} *id;
+	device_t *devs;
+	int devcnt;
+
+	/* IP Address */
+	len = convert16_to_8((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,  &err_ip);
+
+	/* Adapter ID : GUID */
+	len = convert16_to_8((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,  &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 (j = 0; j < 16 ; j++) {
+	           		sprintf(&guid_instance[j * 2], "%02x",
+       		   		hv_dev->device_id.data[j]);
+			}
+			
+			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]));
+
+			/*
+			 * XXX Need to implement multiple network adapter
+			 * handler
+			 */
+			if (strncmp(buf,
+			    (char *)umsg->body.kvp_ip_val.adapter_id,39) == 
+			    0) {
+				/* Pass interface Name */
+				strcpy((char *)umsg->body.kvp_ip_val.adapter_id,if_name);
+				break;
+			} else {
+				/* XXX Implement safe exit */
+			}
+		}
+		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;
+	convert16_to_8((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,  &err_subnet);
+	convert16_to_8((char *)umsg->body.kvp_ip_val.gate_way,
+		       MAX_GATEWAY_SIZE,
+		       (uint16_t *)host_ip_msg->kvp_ip_val.gate_way,
+		       MAX_GATEWAY_SIZE,  &err_gway);
+       convert16_to_8((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,  &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
+host_user_kvp_msg(void)
+{
+	int utf_err=0;
+	uint32_t value_type;
+	struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *)kvp_msg_state.host_kvp_msg;
+	hv_kvp_bsd_msg *hmsg = kvp_msg_state.host_kvp_msg;
+	hv_kvp_bsd_msg *umsg = &hv_user_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:
+		ipinfo_utf16_utf8(host_ip_msg, umsg);
+		break;
+	case HV_KVP_OP_GET_IP_INFO:		
+        	convert16_to_8((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,  &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 =
+				convert16_to_8(
+				(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,
+				&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 =
+			convert16_to_8(
+				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,
+				&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 =
+			convert16_to_8(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,
+			 &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 =
+			convert16_to_8(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,
+			 &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:
+		printf("host_user_kvp_msg: Invalid operation : %d\n", 
+			umsg->kvp_hdr.operation);
+	}
+}
+
+/* 
+ * Prepare a host kvp msg based on user kvp msg (utf8 to utf16)
+ */
+static int
+user_host_kvp_msg(void)
+{
+	int hkey_len=0, hvalue_len=0, utf_err=0;
+	struct hv_kvp_exchg_msg_value  *host_exchg_data;
+	char *key_name, *value;
+	hv_kvp_bsd_msg *umsg = &hv_user_kvp_msg;
+	hv_kvp_bsd_msg *hmsg = kvp_msg_state.host_kvp_msg;
+	struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *)hmsg;
+ 
+	switch (kvp_msg_state.host_kvp_msg->kvp_hdr.operation) {
+	case HV_KVP_OP_GET_IP_INFO:
+		return(ipinfo_utf8_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 = convert8_to_16((uint16_t *) host_exchg_data->key,
+				((HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2),
+				key_name, strlen(key_name), 
+				 &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 = 
+		convert8_to_16( (uint16_t *)host_exchg_data->msg_value.value,
+				( (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2),
+				value, strlen(value),
+				 &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 = convert8_to_16(
+				(uint16_t *) host_exchg_data->msg_value.value,
+				((HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2),
+				value, strlen(value), 
+				 &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
+kvp_respond_host(int error)
+{
+	struct hv_vmbus_icmsg_hdr *hv_icmsg_hdrp;
+
+	if (!hv_kvp_transaction_active()) {
+		/* XXX Triage why we are here */
+		goto finish;
+	}
+
+	hv_icmsg_hdrp = (struct hv_vmbus_icmsg_hdr *)
+	    &kvp_msg_state.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_msg_state.channelp, 
+			kvp_msg_state.rcv_buf, 
+			kvp_msg_state.host_msg_len, kvp_msg_state.host_msg_id,
+			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
+
+	if (error) {
+		printf("kvp_respond_host: sendpacket error:%d\n", error);
+	}
+
+	/* Now ready to process another transaction */
+	kvp_msg_state.in_progress = FALSE;
+
+finish:
+	return;
+}
+
+/* 
+ * Initiate a connection and receive REGISTER message from the user daemon
+ */
+static void
+hv_kvp_conn_register()
+{
+	int error = KVP_SUCCESS;
+
+	if (conn_ready == FALSE) {		
+		/* Wait until the user daemon is ready */
+		if (!hv_kvp_daemon_ack) {
+			return;
+		}
+		
+		if (kvp_connect_user() != KVP_SUCCESS) {
+			return;
+		} else {
+			conn_ready = TRUE;
+		}
+	}
+
+	/*
+	 * First message from the user should be a HV_KVP_OP_REGISTER msg
+	 */
+	if (register_done == FALSE) {
+		error = kvp_rcv_user();	/* receive a message from user */
+
+		if (hv_user_kvp_msg.kvp_hdr.operation == HV_KVP_OP_REGISTER) {
+			register_done = TRUE;
+			kvp_msg_state.kvp_ready = TRUE;
+		}
+	}
+}
+
+
+/**
+ * This is the main kvp kernel process that interacts with both user daemon 
+ * and the host 
+ */
+static void
+hv_kvp_process_msg(void *p)
+{
+	int error = KVP_SUCCESS; 
+
+	/* Prepare kvp_msg to be sent to user */
+	host_user_kvp_msg(); 
+
+	/* Send msg to user on Unix Socket */
+	error = kvp_send_user();
+
+	if (error != KVP_SUCCESS) {
+		if (error == EPIPE) {
+			conn_ready = FALSE;
+			register_done = FALSE;
+			kvp_msg_state.kvp_ready = FALSE;
+		}
+       	
+		kvp_respond_host(HV_KVP_E_FAIL);
+		return;
+	}
+
+	/* Rcv response from user on Unix Socket */
+	hv_user_kvp_msg.hdr.error = HV_KVP_E_FAIL;
+	error = kvp_rcv_user();
+
+	if ((error == KVP_SUCCESS) && 
+	    (hv_user_kvp_msg.hdr.error != HV_KVP_E_FAIL)) {
+		/* Convert user kvp to host kvp and then respond */
+		error = user_host_kvp_msg();
+
+		if (error != KVP_SUCCESS) {
+			kvp_respond_host(HV_KVP_E_FAIL);
+		} else {
+			kvp_respond_host(hv_user_kvp_msg.hdr.error);
+		} 
+	} else {
+		if (error == EPIPE) {
+			conn_ready = FALSE;
+			register_done = FALSE;
+			kvp_msg_state.kvp_ready = FALSE;
+		}
+		kvp_respond_host(HV_KVP_E_FAIL);
+	}
+}
+
+/* 
+ * Callback routine that gets called whenever there is a message from host
+ */
+void
+hv_kvp_callback(void *context)
+{
+	uint8_t*		kvp_buf;
+	hv_vmbus_channel*	channel = context;
+	uint32_t		recvlen;
+	uint64_t		requestid;
+	int			ret = 0;
+	struct hv_vmbus_icmsg_hdr *icmsghdrp;
+
+	kvp_buf = receive_buffer[HV_KVP];
+
+	/*
+	 * Check if already one transaction is under process
+	 */
+	if (!hv_kvp_transaction_active()) {
+		ret = hv_vmbus_channel_recv_packet(channel, kvp_buf,
+		    2 * PAGE_SIZE, &recvlen, &requestid);
+
+		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);
+				kvp_respond_host(ret);
+			} else {
+				/*
+				 * Queue packet for processing.
+				 */
+				hv_queue_work_item(
+				    service_table[HV_KVP].work_queue,
+				    hv_kvp_process_msg,
+				    NULL);
+			}
+		} else {
+			ret = HV_KVP_E_FAIL;
+		}
+	} else {
+		ret = HV_KVP_E_FAIL;
+	}
+	
+	if (ret != 0)
+		kvp_respond_host(ret);
+}
+
+int 
+hv_kvp_init(hv_vmbus_service *srv)
+{
+	int error;
+	hv_work_queue *work_queue;
+
+	error = 0;
+
+	work_queue = hv_work_queue_create("KVP Service");
+	if (work_queue == NULL) {
+		error = ENOMEM;
+	} else
+		srv->work_queue = work_queue;
+
+	return (error);
+}

Added: projects/hyperv/sys/dev/hyperv/utilities/hv_kvp.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/hyperv/sys/dev/hyperv/utilities/hv_kvp.h	Mon Sep  9 08:07:46 2013	(r255414)
@@ -0,0 +1,287 @@
+/*-
+ * Copyright (c) 2009-2012 Microsoft Corp.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309090807.r8987kMm053821>