1271493Sdelphij/*- 2271493Sdelphij * Copyright (c) 2014 Microsoft Corp. 3271493Sdelphij * All rights reserved. 4271493Sdelphij * 5271493Sdelphij * Redistribution and use in source and binary forms, with or without 6271493Sdelphij * modification, are permitted provided that the following conditions 7271493Sdelphij * are met: 8271493Sdelphij * 1. Redistributions of source code must retain the above copyright 9271493Sdelphij * notice unmodified, this list of conditions, and the following 10271493Sdelphij * disclaimer. 11271493Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 12271493Sdelphij * notice, this list of conditions and the following disclaimer in the 13271493Sdelphij * documentation and/or other materials provided with the distribution. 14271493Sdelphij * 15271493Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16271493Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17271493Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18271493Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19271493Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20271493Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21271493Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22271493Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23271493Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24271493Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25271493Sdelphij */ 26271493Sdelphij 27271493Sdelphij/* 28271493Sdelphij * Author: Sainath Varanasi. 29271493Sdelphij * Date: 4/2012 30271493Sdelphij * Email: bsdic@microsoft.com 31271493Sdelphij */ 32271493Sdelphij 33271493Sdelphij#include <sys/cdefs.h> 34271493Sdelphij__FBSDID("$FreeBSD$"); 35271493Sdelphij 36271493Sdelphij#include <sys/param.h> 37271493Sdelphij#include <sys/kernel.h> 38271493Sdelphij#include <sys/conf.h> 39271493Sdelphij#include <sys/uio.h> 40271493Sdelphij#include <sys/bus.h> 41271493Sdelphij#include <sys/malloc.h> 42271493Sdelphij#include <sys/mbuf.h> 43271493Sdelphij#include <sys/module.h> 44271493Sdelphij#include <sys/reboot.h> 45271493Sdelphij#include <sys/lock.h> 46271493Sdelphij#include <sys/taskqueue.h> 47296954Sglebius#include <sys/selinfo.h> 48271493Sdelphij#include <sys/sysctl.h> 49271493Sdelphij#include <sys/poll.h> 50271493Sdelphij#include <sys/proc.h> 51271493Sdelphij#include <sys/kthread.h> 52271493Sdelphij#include <sys/syscallsubr.h> 53271493Sdelphij#include <sys/sysproto.h> 54271493Sdelphij#include <sys/un.h> 55271493Sdelphij#include <sys/endian.h> 56271493Sdelphij#include <sys/_null.h> 57271493Sdelphij#include <sys/signal.h> 58271493Sdelphij#include <sys/syslog.h> 59271493Sdelphij#include <sys/mutex.h> 60271493Sdelphij#include <net/if_arp.h> 61271493Sdelphij 62271493Sdelphij#include <dev/hyperv/include/hyperv.h> 63271493Sdelphij#include <dev/hyperv/netvsc/hv_net_vsc.h> 64271493Sdelphij 65271493Sdelphij#include "unicode.h" 66271493Sdelphij#include "hv_kvp.h" 67271493Sdelphij 68271493Sdelphij/* hv_kvp defines */ 69271493Sdelphij#define BUFFERSIZE sizeof(struct hv_kvp_msg) 70271493Sdelphij#define KVP_SUCCESS 0 71271493Sdelphij#define KVP_ERROR 1 72271493Sdelphij#define kvp_hdr hdr.kvp_hdr 73271493Sdelphij 74271493Sdelphij/* hv_kvp debug control */ 75271493Sdelphijstatic int hv_kvp_log = 0; 76271493SdelphijSYSCTL_INT(_dev, OID_AUTO, hv_kvp_log, CTLFLAG_RW, &hv_kvp_log, 0, 77271493Sdelphij "hv_kvp log"); 78271493Sdelphij 79271493Sdelphij#define hv_kvp_log_error(...) do { \ 80271493Sdelphij if (hv_kvp_log > 0) \ 81271493Sdelphij log(LOG_ERR, "hv_kvp: " __VA_ARGS__); \ 82271493Sdelphij} while (0) 83271493Sdelphij 84271493Sdelphij#define hv_kvp_log_info(...) do { \ 85271493Sdelphij if (hv_kvp_log > 1) \ 86271493Sdelphij log(LOG_INFO, "hv_kvp: " __VA_ARGS__); \ 87271493Sdelphij} while (0) 88271493Sdelphij 89271493Sdelphij/* character device prototypes */ 90271493Sdelphijstatic d_open_t hv_kvp_dev_open; 91271493Sdelphijstatic d_close_t hv_kvp_dev_close; 92271493Sdelphijstatic d_read_t hv_kvp_dev_daemon_read; 93271493Sdelphijstatic d_write_t hv_kvp_dev_daemon_write; 94271493Sdelphijstatic d_poll_t hv_kvp_dev_daemon_poll; 95271493Sdelphij 96271493Sdelphij/* hv_kvp prototypes */ 97271493Sdelphijstatic int hv_kvp_req_in_progress(void); 98271493Sdelphijstatic void hv_kvp_transaction_init(uint32_t, hv_vmbus_channel *, uint64_t, uint8_t *); 99271493Sdelphijstatic void hv_kvp_send_msg_to_daemon(void); 100271493Sdelphijstatic void hv_kvp_process_request(void *context); 101271493Sdelphij 102271493Sdelphij/* hv_kvp character device structure */ 103271493Sdelphijstatic struct cdevsw hv_kvp_cdevsw = 104271493Sdelphij{ 105271493Sdelphij .d_version = D_VERSION, 106271493Sdelphij .d_open = hv_kvp_dev_open, 107271493Sdelphij .d_close = hv_kvp_dev_close, 108271493Sdelphij .d_read = hv_kvp_dev_daemon_read, 109271493Sdelphij .d_write = hv_kvp_dev_daemon_write, 110271493Sdelphij .d_poll = hv_kvp_dev_daemon_poll, 111271493Sdelphij .d_name = "hv_kvp_dev", 112271493Sdelphij}; 113271493Sdelphijstatic struct cdev *hv_kvp_dev; 114271493Sdelphijstatic struct hv_kvp_msg *hv_kvp_dev_buf; 115271493Sdelphijstruct proc *daemon_task; 116271493Sdelphij 117296954Sglebiusstatic struct selinfo hv_kvp_selinfo; 118296954Sglebius 119271493Sdelphij/* 120271493Sdelphij * Global state to track and synchronize multiple 121271493Sdelphij * KVP transaction requests from the host. 122271493Sdelphij */ 123271493Sdelphijstatic struct { 124271493Sdelphij 125271493Sdelphij /* Pre-allocated work item for queue */ 126271493Sdelphij hv_work_item work_item; 127271493Sdelphij 128271493Sdelphij /* Unless specified the pending mutex should be 129271493Sdelphij * used to alter the values of the following paramters: 130271493Sdelphij * 1. req_in_progress 131271493Sdelphij * 2. req_timed_out 132271493Sdelphij * 3. pending_reqs. 133271493Sdelphij */ 134271493Sdelphij struct mtx pending_mutex; 135271493Sdelphij 136271493Sdelphij /* To track if transaction is active or not */ 137271493Sdelphij boolean_t req_in_progress; 138271493Sdelphij /* Tracks if daemon did not reply back in time */ 139271493Sdelphij boolean_t req_timed_out; 140271493Sdelphij /* Tracks if daemon is serving a request currently */ 141271493Sdelphij boolean_t daemon_busy; 142271493Sdelphij /* Count of KVP requests from Hyper-V. */ 143271493Sdelphij uint64_t pending_reqs; 144271493Sdelphij 145271493Sdelphij 146271493Sdelphij /* Length of host message */ 147271493Sdelphij uint32_t host_msg_len; 148271493Sdelphij 149271493Sdelphij /* Pointer to channel */ 150271493Sdelphij hv_vmbus_channel *channelp; 151271493Sdelphij 152271493Sdelphij /* Host message id */ 153271493Sdelphij uint64_t host_msg_id; 154271493Sdelphij 155271493Sdelphij /* Current kvp message from the host */ 156271493Sdelphij struct hv_kvp_msg *host_kvp_msg; 157271493Sdelphij 158271493Sdelphij /* Current kvp message for daemon */ 159271493Sdelphij struct hv_kvp_msg daemon_kvp_msg; 160271493Sdelphij 161271493Sdelphij /* Rcv buffer for communicating with the host*/ 162271493Sdelphij uint8_t *rcv_buf; 163271493Sdelphij 164271493Sdelphij /* Device semaphore to control communication */ 165271493Sdelphij struct sema dev_sema; 166271493Sdelphij 167271493Sdelphij /* Indicates if daemon registered with driver */ 168271493Sdelphij boolean_t register_done; 169271493Sdelphij 170271493Sdelphij /* Character device status */ 171271493Sdelphij boolean_t dev_accessed; 172271493Sdelphij} kvp_globals; 173271493Sdelphij 174271493Sdelphij/* global vars */ 175271493SdelphijMALLOC_DECLARE(M_HV_KVP_DEV_BUF); 176271493SdelphijMALLOC_DEFINE(M_HV_KVP_DEV_BUF, "hv_kvp_dev buffer", "buffer for hv_kvp_dev module"); 177271493Sdelphij 178271493Sdelphij/* 179271493Sdelphij * hv_kvp low level functions 180271493Sdelphij */ 181271493Sdelphij 182271493Sdelphij/* 183271493Sdelphij * Check if kvp transaction is in progres 184271493Sdelphij */ 185271493Sdelphijstatic int 186271493Sdelphijhv_kvp_req_in_progress(void) 187271493Sdelphij{ 188271493Sdelphij 189271493Sdelphij return (kvp_globals.req_in_progress); 190271493Sdelphij} 191271493Sdelphij 192271493Sdelphij 193271493Sdelphij/* 194271493Sdelphij * This routine is called whenever a message is received from the host 195271493Sdelphij */ 196271493Sdelphijstatic void 197271493Sdelphijhv_kvp_transaction_init(uint32_t rcv_len, hv_vmbus_channel *rcv_channel, 198271493Sdelphij uint64_t request_id, uint8_t *rcv_buf) 199271493Sdelphij{ 200271493Sdelphij 201271493Sdelphij /* Store all the relevant message details in the global structure */ 202271493Sdelphij /* Do not need to use mutex for req_in_progress here */ 203271493Sdelphij kvp_globals.req_in_progress = true; 204271493Sdelphij kvp_globals.host_msg_len = rcv_len; 205271493Sdelphij kvp_globals.channelp = rcv_channel; 206271493Sdelphij kvp_globals.host_msg_id = request_id; 207271493Sdelphij kvp_globals.rcv_buf = rcv_buf; 208271493Sdelphij kvp_globals.host_kvp_msg = (struct hv_kvp_msg *)&rcv_buf[ 209271493Sdelphij sizeof(struct hv_vmbus_pipe_hdr) + 210271493Sdelphij sizeof(struct hv_vmbus_icmsg_hdr)]; 211271493Sdelphij} 212271493Sdelphij 213271493Sdelphij 214271493Sdelphij/* 215271493Sdelphij * hv_kvp - version neogtiation function 216271493Sdelphij */ 217271493Sdelphijstatic void 218271493Sdelphijhv_kvp_negotiate_version(struct hv_vmbus_icmsg_hdr *icmsghdrp, 219271493Sdelphij struct hv_vmbus_icmsg_negotiate *negop, 220271493Sdelphij uint8_t *buf) 221271493Sdelphij{ 222271493Sdelphij int icframe_vercnt; 223271493Sdelphij int icmsg_vercnt; 224271493Sdelphij 225271493Sdelphij icmsghdrp->icmsgsize = 0x10; 226271493Sdelphij 227271493Sdelphij negop = (struct hv_vmbus_icmsg_negotiate *)&buf[ 228271493Sdelphij sizeof(struct hv_vmbus_pipe_hdr) + 229271493Sdelphij sizeof(struct hv_vmbus_icmsg_hdr)]; 230271493Sdelphij icframe_vercnt = negop->icframe_vercnt; 231271493Sdelphij icmsg_vercnt = negop->icmsg_vercnt; 232271493Sdelphij 233271493Sdelphij /* 234271493Sdelphij * Select the framework version number we will support 235271493Sdelphij */ 236271493Sdelphij if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) { 237271493Sdelphij icframe_vercnt = 3; 238271493Sdelphij if (icmsg_vercnt >= 2) 239271493Sdelphij icmsg_vercnt = 4; 240271493Sdelphij else 241271493Sdelphij icmsg_vercnt = 3; 242271493Sdelphij } else { 243271493Sdelphij icframe_vercnt = 1; 244271493Sdelphij icmsg_vercnt = 1; 245271493Sdelphij } 246271493Sdelphij 247271493Sdelphij negop->icframe_vercnt = 1; 248271493Sdelphij negop->icmsg_vercnt = 1; 249271493Sdelphij negop->icversion_data[0].major = icframe_vercnt; 250271493Sdelphij negop->icversion_data[0].minor = 0; 251271493Sdelphij negop->icversion_data[1].major = icmsg_vercnt; 252271493Sdelphij negop->icversion_data[1].minor = 0; 253271493Sdelphij} 254271493Sdelphij 255271493Sdelphij 256271493Sdelphij/* 257271493Sdelphij * Convert ip related info in umsg from utf8 to utf16 and store in hmsg 258271493Sdelphij */ 259271493Sdelphijstatic int 260271493Sdelphijhv_kvp_convert_utf8_ipinfo_to_utf16(struct hv_kvp_msg *umsg, 261271493Sdelphij struct hv_kvp_ip_msg *host_ip_msg) 262271493Sdelphij{ 263271493Sdelphij int err_ip, err_subnet, err_gway, err_dns, err_adap; 264271493Sdelphij int UNUSED_FLAG = 1; 265271493Sdelphij 266271493Sdelphij utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.ip_addr, 267271493Sdelphij MAX_IP_ADDR_SIZE, 268271493Sdelphij (char *)umsg->body.kvp_ip_val.ip_addr, 269271493Sdelphij strlen((char *)umsg->body.kvp_ip_val.ip_addr), 270271493Sdelphij UNUSED_FLAG, 271271493Sdelphij &err_ip); 272271493Sdelphij utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.sub_net, 273271493Sdelphij MAX_IP_ADDR_SIZE, 274271493Sdelphij (char *)umsg->body.kvp_ip_val.sub_net, 275271493Sdelphij strlen((char *)umsg->body.kvp_ip_val.sub_net), 276271493Sdelphij UNUSED_FLAG, 277271493Sdelphij &err_subnet); 278271493Sdelphij utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.gate_way, 279271493Sdelphij MAX_GATEWAY_SIZE, 280271493Sdelphij (char *)umsg->body.kvp_ip_val.gate_way, 281271493Sdelphij strlen((char *)umsg->body.kvp_ip_val.gate_way), 282271493Sdelphij UNUSED_FLAG, 283271493Sdelphij &err_gway); 284271493Sdelphij utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.dns_addr, 285271493Sdelphij MAX_IP_ADDR_SIZE, 286271493Sdelphij (char *)umsg->body.kvp_ip_val.dns_addr, 287271493Sdelphij strlen((char *)umsg->body.kvp_ip_val.dns_addr), 288271493Sdelphij UNUSED_FLAG, 289271493Sdelphij &err_dns); 290271493Sdelphij utf8_to_utf16((uint16_t *)host_ip_msg->kvp_ip_val.adapter_id, 291271493Sdelphij MAX_IP_ADDR_SIZE, 292271493Sdelphij (char *)umsg->body.kvp_ip_val.adapter_id, 293271493Sdelphij strlen((char *)umsg->body.kvp_ip_val.adapter_id), 294271493Sdelphij UNUSED_FLAG, 295271493Sdelphij &err_adap); 296271493Sdelphij 297271493Sdelphij host_ip_msg->kvp_ip_val.dhcp_enabled = umsg->body.kvp_ip_val.dhcp_enabled; 298271493Sdelphij host_ip_msg->kvp_ip_val.addr_family = umsg->body.kvp_ip_val.addr_family; 299271493Sdelphij 300271493Sdelphij return (err_ip | err_subnet | err_gway | err_dns | err_adap); 301271493Sdelphij} 302271493Sdelphij 303271493Sdelphij 304271493Sdelphij/* 305271493Sdelphij * Convert ip related info in hmsg from utf16 to utf8 and store in umsg 306271493Sdelphij */ 307271493Sdelphijstatic int 308271493Sdelphijhv_kvp_convert_utf16_ipinfo_to_utf8(struct hv_kvp_ip_msg *host_ip_msg, 309271493Sdelphij struct hv_kvp_msg *umsg) 310271493Sdelphij{ 311271493Sdelphij int err_ip, err_subnet, err_gway, err_dns, err_adap; 312271493Sdelphij int UNUSED_FLAG = 1; 313271493Sdelphij int guid_index; 314271493Sdelphij struct hv_device *hv_dev; /* GUID Data Structure */ 315271493Sdelphij hn_softc_t *sc; /* hn softc structure */ 316271493Sdelphij char if_name[4]; 317271493Sdelphij unsigned char guid_instance[40]; 318271493Sdelphij char *guid_data = NULL; 319271493Sdelphij char buf[39]; 320271493Sdelphij 321271493Sdelphij struct guid_extract { 322271493Sdelphij char a1[2]; 323271493Sdelphij char a2[2]; 324271493Sdelphij char a3[2]; 325271493Sdelphij char a4[2]; 326271493Sdelphij char b1[2]; 327271493Sdelphij char b2[2]; 328271493Sdelphij char c1[2]; 329271493Sdelphij char c2[2]; 330271493Sdelphij char d[4]; 331271493Sdelphij char e[12]; 332271493Sdelphij }; 333271493Sdelphij 334271493Sdelphij struct guid_extract *id; 335271493Sdelphij device_t *devs; 336271493Sdelphij int devcnt; 337271493Sdelphij 338271493Sdelphij /* IP Address */ 339271493Sdelphij utf16_to_utf8((char *)umsg->body.kvp_ip_val.ip_addr, 340271493Sdelphij MAX_IP_ADDR_SIZE, 341271493Sdelphij (uint16_t *)host_ip_msg->kvp_ip_val.ip_addr, 342271493Sdelphij MAX_IP_ADDR_SIZE, 343271493Sdelphij UNUSED_FLAG, 344271493Sdelphij &err_ip); 345271493Sdelphij 346271493Sdelphij /* Adapter ID : GUID */ 347271493Sdelphij utf16_to_utf8((char *)umsg->body.kvp_ip_val.adapter_id, 348271493Sdelphij MAX_ADAPTER_ID_SIZE, 349271493Sdelphij (uint16_t *)host_ip_msg->kvp_ip_val.adapter_id, 350271493Sdelphij MAX_ADAPTER_ID_SIZE, 351271493Sdelphij UNUSED_FLAG, 352271493Sdelphij &err_adap); 353271493Sdelphij 354271493Sdelphij if (devclass_get_devices(devclass_find("hn"), &devs, &devcnt) == 0) { 355271493Sdelphij for (devcnt = devcnt - 1; devcnt >= 0; devcnt--) { 356271493Sdelphij sc = device_get_softc(devs[devcnt]); 357271493Sdelphij 358271493Sdelphij /* Trying to find GUID of Network Device */ 359271493Sdelphij hv_dev = sc->hn_dev_obj; 360271493Sdelphij 361271493Sdelphij for (guid_index = 0; guid_index < 16; guid_index++) { 362271493Sdelphij sprintf(&guid_instance[guid_index * 2], "%02x", 363271493Sdelphij hv_dev->device_id.data[guid_index]); 364271493Sdelphij } 365271493Sdelphij 366271493Sdelphij guid_data = (char *)guid_instance; 367271493Sdelphij id = (struct guid_extract *)guid_data; 368271493Sdelphij snprintf(buf, sizeof(buf), "{%.2s%.2s%.2s%.2s-%.2s%.2s-%.2s%.2s-%.4s-%s}", 369271493Sdelphij id->a4, id->a3, id->a2, id->a1, 370271493Sdelphij id->b2, id->b1, id->c2, id->c1, id->d, id->e); 371271493Sdelphij guid_data = NULL; 372271493Sdelphij sprintf(if_name, "%s%d", "hn", device_get_unit(devs[devcnt])); 373271493Sdelphij 374271493Sdelphij if (strncmp(buf, (char *)umsg->body.kvp_ip_val.adapter_id, 39) == 0) { 375271493Sdelphij strcpy((char *)umsg->body.kvp_ip_val.adapter_id, if_name); 376271493Sdelphij break; 377271493Sdelphij } 378271493Sdelphij } 379271493Sdelphij free(devs, M_TEMP); 380271493Sdelphij } 381271493Sdelphij 382271493Sdelphij /* Address Family , DHCP , SUBNET, Gateway, DNS */ 383271493Sdelphij umsg->kvp_hdr.operation = host_ip_msg->operation; 384271493Sdelphij umsg->body.kvp_ip_val.addr_family = host_ip_msg->kvp_ip_val.addr_family; 385271493Sdelphij umsg->body.kvp_ip_val.dhcp_enabled = host_ip_msg->kvp_ip_val.dhcp_enabled; 386271493Sdelphij utf16_to_utf8((char *)umsg->body.kvp_ip_val.sub_net, MAX_IP_ADDR_SIZE, 387271493Sdelphij (uint16_t *)host_ip_msg->kvp_ip_val.sub_net, 388271493Sdelphij MAX_IP_ADDR_SIZE, 389271493Sdelphij UNUSED_FLAG, 390271493Sdelphij &err_subnet); 391271493Sdelphij 392271493Sdelphij utf16_to_utf8((char *)umsg->body.kvp_ip_val.gate_way, MAX_GATEWAY_SIZE, 393271493Sdelphij (uint16_t *)host_ip_msg->kvp_ip_val.gate_way, 394271493Sdelphij MAX_GATEWAY_SIZE, 395271493Sdelphij UNUSED_FLAG, 396271493Sdelphij &err_gway); 397271493Sdelphij 398271493Sdelphij utf16_to_utf8((char *)umsg->body.kvp_ip_val.dns_addr, MAX_IP_ADDR_SIZE, 399271493Sdelphij (uint16_t *)host_ip_msg->kvp_ip_val.dns_addr, 400271493Sdelphij MAX_IP_ADDR_SIZE, 401271493Sdelphij UNUSED_FLAG, 402271493Sdelphij &err_dns); 403271493Sdelphij 404271493Sdelphij return (err_ip | err_subnet | err_gway | err_dns | err_adap); 405271493Sdelphij} 406271493Sdelphij 407271493Sdelphij 408271493Sdelphij/* 409271493Sdelphij * Prepare a user kvp msg based on host kvp msg (utf16 to utf8) 410271493Sdelphij * Ensure utf16_utf8 takes care of the additional string terminating char!! 411271493Sdelphij */ 412271493Sdelphijstatic void 413271493Sdelphijhv_kvp_convert_hostmsg_to_usermsg(void) 414271493Sdelphij{ 415271493Sdelphij int utf_err = 0; 416271493Sdelphij uint32_t value_type; 417271493Sdelphij struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *) 418271493Sdelphij kvp_globals.host_kvp_msg; 419271493Sdelphij 420271493Sdelphij struct hv_kvp_msg *hmsg = kvp_globals.host_kvp_msg; 421271493Sdelphij struct hv_kvp_msg *umsg = &kvp_globals.daemon_kvp_msg; 422271493Sdelphij 423271493Sdelphij memset(umsg, 0, sizeof(struct hv_kvp_msg)); 424271493Sdelphij 425271493Sdelphij umsg->kvp_hdr.operation = hmsg->kvp_hdr.operation; 426271493Sdelphij umsg->kvp_hdr.pool = hmsg->kvp_hdr.pool; 427271493Sdelphij 428271493Sdelphij switch (umsg->kvp_hdr.operation) { 429271493Sdelphij case HV_KVP_OP_SET_IP_INFO: 430271493Sdelphij hv_kvp_convert_utf16_ipinfo_to_utf8(host_ip_msg, umsg); 431271493Sdelphij break; 432271493Sdelphij 433271493Sdelphij case HV_KVP_OP_GET_IP_INFO: 434271493Sdelphij utf16_to_utf8((char *)umsg->body.kvp_ip_val.adapter_id, 435271493Sdelphij MAX_ADAPTER_ID_SIZE, 436271493Sdelphij (uint16_t *)host_ip_msg->kvp_ip_val.adapter_id, 437271493Sdelphij MAX_ADAPTER_ID_SIZE, 1, &utf_err); 438271493Sdelphij 439271493Sdelphij umsg->body.kvp_ip_val.addr_family = 440271493Sdelphij host_ip_msg->kvp_ip_val.addr_family; 441271493Sdelphij break; 442271493Sdelphij 443271493Sdelphij case HV_KVP_OP_SET: 444271493Sdelphij value_type = hmsg->body.kvp_set.data.value_type; 445271493Sdelphij 446271493Sdelphij switch (value_type) { 447271493Sdelphij case HV_REG_SZ: 448271493Sdelphij umsg->body.kvp_set.data.value_size = 449271493Sdelphij utf16_to_utf8( 450271493Sdelphij (char *)umsg->body.kvp_set.data.msg_value.value, 451271493Sdelphij HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1, 452271493Sdelphij (uint16_t *)hmsg->body.kvp_set.data.msg_value.value, 453271493Sdelphij hmsg->body.kvp_set.data.value_size, 454271493Sdelphij 1, &utf_err); 455271493Sdelphij /* utf8 encoding */ 456271493Sdelphij umsg->body.kvp_set.data.value_size = 457271493Sdelphij umsg->body.kvp_set.data.value_size / 2; 458271493Sdelphij break; 459271493Sdelphij 460271493Sdelphij case HV_REG_U32: 461271493Sdelphij umsg->body.kvp_set.data.value_size = 462271493Sdelphij sprintf(umsg->body.kvp_set.data.msg_value.value, "%d", 463271493Sdelphij hmsg->body.kvp_set.data.msg_value.value_u32) + 1; 464271493Sdelphij break; 465271493Sdelphij 466271493Sdelphij case HV_REG_U64: 467271493Sdelphij umsg->body.kvp_set.data.value_size = 468271493Sdelphij sprintf(umsg->body.kvp_set.data.msg_value.value, "%llu", 469271493Sdelphij (unsigned long long) 470271493Sdelphij hmsg->body.kvp_set.data.msg_value.value_u64) + 1; 471271493Sdelphij break; 472271493Sdelphij } 473271493Sdelphij 474271493Sdelphij umsg->body.kvp_set.data.key_size = 475271493Sdelphij utf16_to_utf8( 476271493Sdelphij umsg->body.kvp_set.data.key, 477271493Sdelphij HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1, 478271493Sdelphij (uint16_t *)hmsg->body.kvp_set.data.key, 479271493Sdelphij hmsg->body.kvp_set.data.key_size, 480271493Sdelphij 1, &utf_err); 481271493Sdelphij 482271493Sdelphij /* utf8 encoding */ 483271493Sdelphij umsg->body.kvp_set.data.key_size = 484271493Sdelphij umsg->body.kvp_set.data.key_size / 2; 485271493Sdelphij break; 486271493Sdelphij 487271493Sdelphij case HV_KVP_OP_GET: 488271493Sdelphij umsg->body.kvp_get.data.key_size = 489271493Sdelphij utf16_to_utf8(umsg->body.kvp_get.data.key, 490271493Sdelphij HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1, 491271493Sdelphij (uint16_t *)hmsg->body.kvp_get.data.key, 492271493Sdelphij hmsg->body.kvp_get.data.key_size, 493271493Sdelphij 1, &utf_err); 494271493Sdelphij /* utf8 encoding */ 495271493Sdelphij umsg->body.kvp_get.data.key_size = 496271493Sdelphij umsg->body.kvp_get.data.key_size / 2; 497271493Sdelphij break; 498271493Sdelphij 499271493Sdelphij case HV_KVP_OP_DELETE: 500271493Sdelphij umsg->body.kvp_delete.key_size = 501271493Sdelphij utf16_to_utf8(umsg->body.kvp_delete.key, 502271493Sdelphij HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1, 503271493Sdelphij (uint16_t *)hmsg->body.kvp_delete.key, 504271493Sdelphij hmsg->body.kvp_delete.key_size, 505271493Sdelphij 1, &utf_err); 506271493Sdelphij /* utf8 encoding */ 507271493Sdelphij umsg->body.kvp_delete.key_size = 508271493Sdelphij umsg->body.kvp_delete.key_size / 2; 509271493Sdelphij break; 510271493Sdelphij 511271493Sdelphij case HV_KVP_OP_ENUMERATE: 512271493Sdelphij umsg->body.kvp_enum_data.index = 513271493Sdelphij hmsg->body.kvp_enum_data.index; 514271493Sdelphij break; 515271493Sdelphij 516271493Sdelphij default: 517271493Sdelphij hv_kvp_log_info("%s: daemon_kvp_msg: Invalid operation : %d\n", 518271493Sdelphij __func__, umsg->kvp_hdr.operation); 519271493Sdelphij } 520271493Sdelphij} 521271493Sdelphij 522271493Sdelphij 523271493Sdelphij/* 524271493Sdelphij * Prepare a host kvp msg based on user kvp msg (utf8 to utf16) 525271493Sdelphij */ 526271493Sdelphijstatic int 527271493Sdelphijhv_kvp_convert_usermsg_to_hostmsg(void) 528271493Sdelphij{ 529271493Sdelphij int hkey_len = 0, hvalue_len = 0, utf_err = 0; 530271493Sdelphij struct hv_kvp_exchg_msg_value *host_exchg_data; 531271493Sdelphij char *key_name, *value; 532271493Sdelphij 533271493Sdelphij struct hv_kvp_msg *umsg = &kvp_globals.daemon_kvp_msg; 534271493Sdelphij struct hv_kvp_msg *hmsg = kvp_globals.host_kvp_msg; 535271493Sdelphij struct hv_kvp_ip_msg *host_ip_msg = (struct hv_kvp_ip_msg *)hmsg; 536271493Sdelphij 537271493Sdelphij switch (hmsg->kvp_hdr.operation) { 538271493Sdelphij case HV_KVP_OP_GET_IP_INFO: 539271493Sdelphij return (hv_kvp_convert_utf8_ipinfo_to_utf16(umsg, host_ip_msg)); 540271493Sdelphij 541271493Sdelphij case HV_KVP_OP_SET_IP_INFO: 542271493Sdelphij case HV_KVP_OP_SET: 543271493Sdelphij case HV_KVP_OP_DELETE: 544271493Sdelphij return (KVP_SUCCESS); 545271493Sdelphij 546271493Sdelphij case HV_KVP_OP_ENUMERATE: 547271493Sdelphij host_exchg_data = &hmsg->body.kvp_enum_data.data; 548271493Sdelphij key_name = umsg->body.kvp_enum_data.data.key; 549271493Sdelphij hkey_len = utf8_to_utf16((uint16_t *)host_exchg_data->key, 550271493Sdelphij ((HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2), 551271493Sdelphij key_name, strlen(key_name), 552271493Sdelphij 1, &utf_err); 553271493Sdelphij /* utf16 encoding */ 554271493Sdelphij host_exchg_data->key_size = 2 * (hkey_len + 1); 555271493Sdelphij value = umsg->body.kvp_enum_data.data.msg_value.value; 556271493Sdelphij hvalue_len = utf8_to_utf16( 557271493Sdelphij (uint16_t *)host_exchg_data->msg_value.value, 558271493Sdelphij ((HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2), 559271493Sdelphij value, strlen(value), 560271493Sdelphij 1, &utf_err); 561271493Sdelphij host_exchg_data->value_size = 2 * (hvalue_len + 1); 562271493Sdelphij host_exchg_data->value_type = HV_REG_SZ; 563271493Sdelphij 564271493Sdelphij if ((hkey_len < 0) || (hvalue_len < 0)) 565271493Sdelphij return (HV_KVP_E_FAIL); 566271493Sdelphij 567271493Sdelphij return (KVP_SUCCESS); 568271493Sdelphij 569271493Sdelphij case HV_KVP_OP_GET: 570271493Sdelphij host_exchg_data = &hmsg->body.kvp_get.data; 571271493Sdelphij value = umsg->body.kvp_get.data.msg_value.value; 572271493Sdelphij hvalue_len = utf8_to_utf16( 573271493Sdelphij (uint16_t *)host_exchg_data->msg_value.value, 574271493Sdelphij ((HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2), 575271493Sdelphij value, strlen(value), 576271493Sdelphij 1, &utf_err); 577271493Sdelphij /* Convert value size to uft16 */ 578271493Sdelphij host_exchg_data->value_size = 2 * (hvalue_len + 1); 579271493Sdelphij /* Use values by string */ 580271493Sdelphij host_exchg_data->value_type = HV_REG_SZ; 581271493Sdelphij 582271493Sdelphij if ((hkey_len < 0) || (hvalue_len < 0)) 583271493Sdelphij return (HV_KVP_E_FAIL); 584271493Sdelphij 585271493Sdelphij return (KVP_SUCCESS); 586271493Sdelphij 587271493Sdelphij default: 588271493Sdelphij return (HV_KVP_E_FAIL); 589271493Sdelphij } 590271493Sdelphij} 591271493Sdelphij 592271493Sdelphij 593271493Sdelphij/* 594271493Sdelphij * Send the response back to the host. 595271493Sdelphij */ 596271493Sdelphijstatic void 597271493Sdelphijhv_kvp_respond_host(int error) 598271493Sdelphij{ 599271493Sdelphij struct hv_vmbus_icmsg_hdr *hv_icmsg_hdrp; 600271493Sdelphij 601271493Sdelphij hv_icmsg_hdrp = (struct hv_vmbus_icmsg_hdr *) 602271493Sdelphij &kvp_globals.rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)]; 603271493Sdelphij 604271493Sdelphij if (error) 605271493Sdelphij error = HV_KVP_E_FAIL; 606271493Sdelphij 607271493Sdelphij hv_icmsg_hdrp->status = error; 608271493Sdelphij hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE; 609271493Sdelphij 610271493Sdelphij error = hv_vmbus_channel_send_packet(kvp_globals.channelp, 611271493Sdelphij kvp_globals.rcv_buf, 612271493Sdelphij kvp_globals.host_msg_len, kvp_globals.host_msg_id, 613271493Sdelphij HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 614271493Sdelphij 615271493Sdelphij if (error) 616271493Sdelphij hv_kvp_log_info("%s: hv_kvp_respond_host: sendpacket error:%d\n", 617271493Sdelphij __func__, error); 618271493Sdelphij} 619271493Sdelphij 620271493Sdelphij 621271493Sdelphij/* 622271493Sdelphij * This is the main kvp kernel process that interacts with both user daemon 623271493Sdelphij * and the host 624271493Sdelphij */ 625271493Sdelphijstatic void 626271493Sdelphijhv_kvp_send_msg_to_daemon(void) 627271493Sdelphij{ 628271493Sdelphij /* Prepare kvp_msg to be sent to user */ 629271493Sdelphij hv_kvp_convert_hostmsg_to_usermsg(); 630271493Sdelphij 631271493Sdelphij /* Send the msg to user via function deamon_read - setting sema */ 632271493Sdelphij sema_post(&kvp_globals.dev_sema); 633296954Sglebius 634296954Sglebius /* We should wake up the daemon, in case it's doing poll() */ 635296954Sglebius selwakeup(&hv_kvp_selinfo); 636271493Sdelphij} 637271493Sdelphij 638271493Sdelphij 639271493Sdelphij/* 640271493Sdelphij * Function to read the kvp request buffer from host 641271493Sdelphij * and interact with daemon 642271493Sdelphij */ 643271493Sdelphijstatic void 644271493Sdelphijhv_kvp_process_request(void *context) 645271493Sdelphij{ 646271493Sdelphij uint8_t *kvp_buf; 647271493Sdelphij hv_vmbus_channel *channel = context; 648271493Sdelphij uint32_t recvlen = 0; 649271493Sdelphij uint64_t requestid; 650271493Sdelphij struct hv_vmbus_icmsg_hdr *icmsghdrp; 651271493Sdelphij int ret = 0; 652271493Sdelphij uint64_t pending_cnt = 1; 653271493Sdelphij 654271493Sdelphij hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__); 655271493Sdelphij kvp_buf = receive_buffer[HV_KVP]; 656271493Sdelphij ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE, 657271493Sdelphij &recvlen, &requestid); 658271493Sdelphij 659271493Sdelphij /* 660271493Sdelphij * We start counting only after the daemon registers 661271493Sdelphij * and therefore there could be requests pending in 662271493Sdelphij * the VMBus that are not reflected in pending_cnt. 663271493Sdelphij * Therefore we continue reading as long as either of 664271493Sdelphij * the below conditions is true. 665271493Sdelphij */ 666271493Sdelphij 667271493Sdelphij while ((pending_cnt>0) || ((ret == 0) && (recvlen > 0))) { 668271493Sdelphij 669271493Sdelphij if ((ret == 0) && (recvlen>0)) { 670271493Sdelphij 671271493Sdelphij icmsghdrp = (struct hv_vmbus_icmsg_hdr *) 672271493Sdelphij &kvp_buf[sizeof(struct hv_vmbus_pipe_hdr)]; 673271493Sdelphij 674271493Sdelphij hv_kvp_transaction_init(recvlen, channel, requestid, kvp_buf); 675271493Sdelphij if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) { 676271493Sdelphij hv_kvp_negotiate_version(icmsghdrp, NULL, kvp_buf); 677271493Sdelphij hv_kvp_respond_host(ret); 678271493Sdelphij 679271493Sdelphij /* 680271493Sdelphij * It is ok to not acquire the mutex before setting 681271493Sdelphij * req_in_progress here because negotiation is the 682271493Sdelphij * first thing that happens and hence there is no 683271493Sdelphij * chance of a race condition. 684271493Sdelphij */ 685271493Sdelphij 686271493Sdelphij kvp_globals.req_in_progress = false; 687271493Sdelphij hv_kvp_log_info("%s :version negotiated\n", __func__); 688271493Sdelphij 689271493Sdelphij } else { 690271493Sdelphij if (!kvp_globals.daemon_busy) { 691271493Sdelphij 692271493Sdelphij hv_kvp_log_info("%s: issuing qury to daemon\n", __func__); 693271493Sdelphij mtx_lock(&kvp_globals.pending_mutex); 694271493Sdelphij kvp_globals.req_timed_out = false; 695271493Sdelphij kvp_globals.daemon_busy = true; 696271493Sdelphij mtx_unlock(&kvp_globals.pending_mutex); 697271493Sdelphij 698271493Sdelphij hv_kvp_send_msg_to_daemon(); 699271493Sdelphij hv_kvp_log_info("%s: waiting for daemon\n", __func__); 700271493Sdelphij } 701271493Sdelphij 702271493Sdelphij /* Wait 5 seconds for daemon to respond back */ 703271493Sdelphij tsleep(&kvp_globals, 0, "kvpworkitem", 5 * hz); 704271493Sdelphij hv_kvp_log_info("%s: came out of wait\n", __func__); 705271493Sdelphij } 706271493Sdelphij } 707271493Sdelphij 708271493Sdelphij mtx_lock(&kvp_globals.pending_mutex); 709271493Sdelphij 710271493Sdelphij /* Notice that once req_timed_out is set to true 711271493Sdelphij * it will remain true until the next request is 712271493Sdelphij * sent to the daemon. The response from daemon 713271493Sdelphij * is forwarded to host only when this flag is 714271493Sdelphij * false. 715271493Sdelphij */ 716271493Sdelphij kvp_globals.req_timed_out = true; 717271493Sdelphij 718271493Sdelphij /* 719271493Sdelphij * Cancel request if so need be. 720271493Sdelphij */ 721271493Sdelphij if (hv_kvp_req_in_progress()) { 722271493Sdelphij hv_kvp_log_info("%s: request was still active after wait so failing\n", __func__); 723271493Sdelphij hv_kvp_respond_host(HV_KVP_E_FAIL); 724271493Sdelphij kvp_globals.req_in_progress = false; 725271493Sdelphij } 726271493Sdelphij 727271493Sdelphij /* 728271493Sdelphij * Decrement pending request count and 729271493Sdelphij */ 730271493Sdelphij if (kvp_globals.pending_reqs>0) { 731271493Sdelphij kvp_globals.pending_reqs = kvp_globals.pending_reqs - 1; 732271493Sdelphij } 733271493Sdelphij pending_cnt = kvp_globals.pending_reqs; 734271493Sdelphij 735271493Sdelphij mtx_unlock(&kvp_globals.pending_mutex); 736271493Sdelphij 737271493Sdelphij /* 738271493Sdelphij * Try reading next buffer 739271493Sdelphij */ 740271493Sdelphij recvlen = 0; 741271493Sdelphij ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE, 742271493Sdelphij &recvlen, &requestid); 743271493Sdelphij hv_kvp_log_info("%s: read: context %p, pending_cnt %ju ret =%d, recvlen=%d\n", 744271493Sdelphij __func__, context, pending_cnt, ret, recvlen); 745271493Sdelphij } 746271493Sdelphij} 747271493Sdelphij 748271493Sdelphij 749271493Sdelphij/* 750271493Sdelphij * Callback routine that gets called whenever there is a message from host 751271493Sdelphij */ 752271493Sdelphijvoid 753271493Sdelphijhv_kvp_callback(void *context) 754271493Sdelphij{ 755271493Sdelphij uint64_t pending_cnt = 0; 756271493Sdelphij 757271493Sdelphij if (kvp_globals.register_done == false) { 758271493Sdelphij 759271493Sdelphij kvp_globals.channelp = context; 760271493Sdelphij } else { 761271493Sdelphij 762271493Sdelphij mtx_lock(&kvp_globals.pending_mutex); 763271493Sdelphij kvp_globals.pending_reqs = kvp_globals.pending_reqs + 1; 764271493Sdelphij pending_cnt = kvp_globals.pending_reqs; 765271493Sdelphij mtx_unlock(&kvp_globals.pending_mutex); 766271493Sdelphij if (pending_cnt == 1) { 767271493Sdelphij hv_kvp_log_info("%s: Queuing work item\n", __func__); 768271493Sdelphij hv_queue_work_item( 769271493Sdelphij service_table[HV_KVP].work_queue, 770271493Sdelphij hv_kvp_process_request, 771271493Sdelphij context 772271493Sdelphij ); 773271493Sdelphij } 774271493Sdelphij } 775271493Sdelphij} 776271493Sdelphij 777271493Sdelphij 778271493Sdelphij/* 779271493Sdelphij * This function is called by the hv_kvp_init - 780271493Sdelphij * creates character device hv_kvp_dev 781271493Sdelphij * allocates memory to hv_kvp_dev_buf 782271493Sdelphij * 783271493Sdelphij */ 784271493Sdelphijstatic int 785271493Sdelphijhv_kvp_dev_init(void) 786271493Sdelphij{ 787271493Sdelphij int error = 0; 788271493Sdelphij 789271493Sdelphij /* initialize semaphore */ 790271493Sdelphij sema_init(&kvp_globals.dev_sema, 0, "hv_kvp device semaphore"); 791271493Sdelphij /* create character device */ 792271493Sdelphij error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, 793271493Sdelphij &hv_kvp_dev, 794271493Sdelphij &hv_kvp_cdevsw, 795271493Sdelphij 0, 796271493Sdelphij UID_ROOT, 797271493Sdelphij GID_WHEEL, 798271493Sdelphij 0640, 799271493Sdelphij "hv_kvp_dev"); 800271493Sdelphij 801271493Sdelphij if (error != 0) 802271493Sdelphij return (error); 803271493Sdelphij 804271493Sdelphij /* 805271493Sdelphij * Malloc with M_WAITOK flag will never fail. 806271493Sdelphij */ 807271493Sdelphij hv_kvp_dev_buf = malloc(sizeof(*hv_kvp_dev_buf), M_HV_KVP_DEV_BUF, M_WAITOK | 808271493Sdelphij M_ZERO); 809271493Sdelphij 810271493Sdelphij return (0); 811271493Sdelphij} 812271493Sdelphij 813271493Sdelphij 814271493Sdelphij/* 815271493Sdelphij * This function is called by the hv_kvp_deinit - 816271493Sdelphij * destroy character device 817271493Sdelphij */ 818271493Sdelphijstatic void 819271493Sdelphijhv_kvp_dev_destroy(void) 820271493Sdelphij{ 821271493Sdelphij 822271493Sdelphij if (daemon_task != NULL) { 823271493Sdelphij PROC_LOCK(daemon_task); 824271493Sdelphij kern_psignal(daemon_task, SIGKILL); 825271493Sdelphij PROC_UNLOCK(daemon_task); 826271493Sdelphij } 827271493Sdelphij 828271493Sdelphij destroy_dev(hv_kvp_dev); 829271493Sdelphij free(hv_kvp_dev_buf, M_HV_KVP_DEV_BUF); 830271493Sdelphij return; 831271493Sdelphij} 832271493Sdelphij 833271493Sdelphij 834271493Sdelphijstatic int 835271493Sdelphijhv_kvp_dev_open(struct cdev *dev, int oflags, int devtype, 836271493Sdelphij struct thread *td) 837271493Sdelphij{ 838271493Sdelphij 839271493Sdelphij hv_kvp_log_info("%s: Opened device \"hv_kvp_device\" successfully.\n", __func__); 840271493Sdelphij if (kvp_globals.dev_accessed) 841271493Sdelphij return (-EBUSY); 842271493Sdelphij 843271493Sdelphij daemon_task = curproc; 844271493Sdelphij kvp_globals.dev_accessed = true; 845271493Sdelphij kvp_globals.daemon_busy = false; 846271493Sdelphij return (0); 847271493Sdelphij} 848271493Sdelphij 849271493Sdelphij 850271493Sdelphijstatic int 851271493Sdelphijhv_kvp_dev_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused, 852271493Sdelphij struct thread *td __unused) 853271493Sdelphij{ 854271493Sdelphij 855271493Sdelphij hv_kvp_log_info("%s: Closing device \"hv_kvp_device\".\n", __func__); 856271493Sdelphij kvp_globals.dev_accessed = false; 857271493Sdelphij kvp_globals.register_done = false; 858271493Sdelphij return (0); 859271493Sdelphij} 860271493Sdelphij 861271493Sdelphij 862271493Sdelphij/* 863271493Sdelphij * hv_kvp_daemon read invokes this function 864271493Sdelphij * acts as a send to daemon 865271493Sdelphij */ 866271493Sdelphijstatic int 867271493Sdelphijhv_kvp_dev_daemon_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused) 868271493Sdelphij{ 869271493Sdelphij size_t amt; 870271493Sdelphij int error = 0; 871271493Sdelphij 872271493Sdelphij /* Check hv_kvp daemon registration status*/ 873271493Sdelphij if (!kvp_globals.register_done) 874271493Sdelphij return (KVP_ERROR); 875271493Sdelphij 876271493Sdelphij sema_wait(&kvp_globals.dev_sema); 877271493Sdelphij 878271493Sdelphij memcpy(hv_kvp_dev_buf, &kvp_globals.daemon_kvp_msg, sizeof(struct hv_kvp_msg)); 879271493Sdelphij 880271493Sdelphij amt = MIN(uio->uio_resid, uio->uio_offset >= BUFFERSIZE + 1 ? 0 : 881271493Sdelphij BUFFERSIZE + 1 - uio->uio_offset); 882271493Sdelphij 883271493Sdelphij if ((error = uiomove(hv_kvp_dev_buf, amt, uio)) != 0) 884271493Sdelphij hv_kvp_log_info("%s: hv_kvp uiomove read failed!\n", __func__); 885271493Sdelphij 886271493Sdelphij return (error); 887271493Sdelphij} 888271493Sdelphij 889271493Sdelphij 890271493Sdelphij/* 891271493Sdelphij * hv_kvp_daemon write invokes this function 892271493Sdelphij * acts as a recieve from daemon 893271493Sdelphij */ 894271493Sdelphijstatic int 895271493Sdelphijhv_kvp_dev_daemon_write(struct cdev *dev __unused, struct uio *uio, int ioflag __unused) 896271493Sdelphij{ 897271493Sdelphij size_t amt; 898271493Sdelphij int error = 0; 899271493Sdelphij 900271493Sdelphij uio->uio_offset = 0; 901271493Sdelphij 902271493Sdelphij amt = MIN(uio->uio_resid, BUFFERSIZE); 903271493Sdelphij error = uiomove(hv_kvp_dev_buf, amt, uio); 904271493Sdelphij 905271493Sdelphij if (error != 0) 906271493Sdelphij return (error); 907271493Sdelphij 908271493Sdelphij memcpy(&kvp_globals.daemon_kvp_msg, hv_kvp_dev_buf, sizeof(struct hv_kvp_msg)); 909271493Sdelphij 910271493Sdelphij if (kvp_globals.register_done == false) { 911271493Sdelphij if (kvp_globals.daemon_kvp_msg.kvp_hdr.operation == HV_KVP_OP_REGISTER) { 912271493Sdelphij 913271493Sdelphij kvp_globals.register_done = true; 914271493Sdelphij if (kvp_globals.channelp) { 915271493Sdelphij 916271493Sdelphij hv_kvp_callback(kvp_globals.channelp); 917271493Sdelphij } 918271493Sdelphij } 919271493Sdelphij else { 920271493Sdelphij hv_kvp_log_info("%s, KVP Registration Failed\n", __func__); 921271493Sdelphij return (KVP_ERROR); 922271493Sdelphij } 923271493Sdelphij } else { 924271493Sdelphij 925271493Sdelphij mtx_lock(&kvp_globals.pending_mutex); 926271493Sdelphij 927271493Sdelphij if(!kvp_globals.req_timed_out) { 928271493Sdelphij 929271493Sdelphij hv_kvp_convert_usermsg_to_hostmsg(); 930271493Sdelphij hv_kvp_respond_host(KVP_SUCCESS); 931271493Sdelphij wakeup(&kvp_globals); 932271493Sdelphij kvp_globals.req_in_progress = false; 933271493Sdelphij } 934271493Sdelphij 935271493Sdelphij kvp_globals.daemon_busy = false; 936271493Sdelphij mtx_unlock(&kvp_globals.pending_mutex); 937271493Sdelphij } 938271493Sdelphij 939271493Sdelphij return (error); 940271493Sdelphij} 941271493Sdelphij 942271493Sdelphij 943271493Sdelphij/* 944271493Sdelphij * hv_kvp_daemon poll invokes this function to check if data is available 945271493Sdelphij * for daemon to read. 946271493Sdelphij */ 947271493Sdelphijstatic int 948296954Sglebiushv_kvp_dev_daemon_poll(struct cdev *dev __unused, int events, struct thread *td) 949271493Sdelphij{ 950271493Sdelphij int revents = 0; 951271493Sdelphij 952271493Sdelphij mtx_lock(&kvp_globals.pending_mutex); 953271493Sdelphij /* 954271493Sdelphij * We check global flag daemon_busy for the data availiability for 955271493Sdelphij * userland to read. Deamon_busy is set to true before driver has data 956271493Sdelphij * for daemon to read. It is set to false after daemon sends 957271493Sdelphij * then response back to driver. 958271493Sdelphij */ 959271493Sdelphij if (kvp_globals.daemon_busy == true) 960271493Sdelphij revents = POLLIN; 961296954Sglebius else 962296954Sglebius selrecord(td, &hv_kvp_selinfo); 963296954Sglebius 964271493Sdelphij mtx_unlock(&kvp_globals.pending_mutex); 965271493Sdelphij 966271493Sdelphij return (revents); 967271493Sdelphij} 968271493Sdelphij 969271493Sdelphij 970271493Sdelphij/* 971271493Sdelphij * hv_kvp initialization function 972271493Sdelphij * called from hv_util service. 973271493Sdelphij * 974271493Sdelphij */ 975271493Sdelphijint 976271493Sdelphijhv_kvp_init(hv_vmbus_service *srv) 977271493Sdelphij{ 978271493Sdelphij int error = 0; 979271493Sdelphij hv_work_queue *work_queue = NULL; 980271493Sdelphij 981271493Sdelphij memset(&kvp_globals, 0, sizeof(kvp_globals)); 982271493Sdelphij 983271493Sdelphij work_queue = hv_work_queue_create("KVP Service"); 984271493Sdelphij if (work_queue == NULL) { 985271493Sdelphij hv_kvp_log_info("%s: Work queue alloc failed\n", __func__); 986271493Sdelphij error = ENOMEM; 987271493Sdelphij hv_kvp_log_error("%s: ENOMEM\n", __func__); 988271493Sdelphij goto Finish; 989271493Sdelphij } 990271493Sdelphij srv->work_queue = work_queue; 991271493Sdelphij 992271493Sdelphij error = hv_kvp_dev_init(); 993271493Sdelphij mtx_init(&kvp_globals.pending_mutex, "hv-kvp pending mutex", 994271493Sdelphij NULL, MTX_DEF); 995271493Sdelphij kvp_globals.pending_reqs = 0; 996271493Sdelphij 997271493Sdelphij 998271493SdelphijFinish: 999271493Sdelphij return (error); 1000271493Sdelphij} 1001271493Sdelphij 1002271493Sdelphij 1003271493Sdelphijvoid 1004271493Sdelphijhv_kvp_deinit(void) 1005271493Sdelphij{ 1006271493Sdelphij hv_kvp_dev_destroy(); 1007271493Sdelphij mtx_destroy(&kvp_globals.pending_mutex); 1008271493Sdelphij 1009271493Sdelphij return; 1010271493Sdelphij} 1011