/* * An implementation of key value pair (KVP) functionality for Linux. * * * Copyright (C) 2010, Novell, Inc. * Author : K. Y. Srinivasan <[email protected]> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * */ #define pr_fmt(fmt) … #include <linux/net.h> #include <linux/nls.h> #include <linux/connector.h> #include <linux/workqueue.h> #include <linux/hyperv.h> #include <asm/hyperv-tlfs.h> #include "hyperv_vmbus.h" #include "hv_utils_transport.h" /* * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7) */ #define WS2008_SRV_MAJOR … #define WS2008_SRV_MINOR … #define WS2008_SRV_VERSION … #define WIN7_SRV_MAJOR … #define WIN7_SRV_MINOR … #define WIN7_SRV_VERSION … #define WIN8_SRV_MAJOR … #define WIN8_SRV_MINOR … #define WIN8_SRV_VERSION … #define KVP_VER_COUNT … static const int kvp_versions[] = …; #define FW_VER_COUNT … static const int fw_versions[] = …; /* * Global state maintained for transaction that is being processed. For a class * of integration services, including the "KVP service", the specified protocol * is a "request/response" protocol which means that there can only be single * outstanding transaction from the host at any given point in time. We use * this to simplify memory management in this driver - we cache and process * only one message at a time. * * While the request/response protocol is guaranteed by the host, we further * ensure this by serializing packet processing in this driver - we do not * read additional packets from the VMBUS until the current packet is fully * handled. */ static struct { … } kvp_transaction; /* * This state maintains the version number registered by the daemon. */ static int dm_reg_value; static void kvp_send_key(struct work_struct *dummy); static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error); static void kvp_timeout_func(struct work_struct *dummy); static void kvp_host_handshake_func(struct work_struct *dummy); static void kvp_register(int); static DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func); static DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func); static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); static const char kvp_devname[] = …; static u8 *recv_buffer; static struct hvutil_transport *hvt; /* * Register the kernel component with the user-level daemon. * As part of this registration, pass the LIC version number. * This number has no meaning, it satisfies the registration protocol. */ #define HV_DRV_VERSION … static void kvp_poll_wrapper(void *channel) { … } static void kvp_register_done(void) { … } static void kvp_register(int reg_value) { … } static void kvp_timeout_func(struct work_struct *dummy) { … } static void kvp_host_handshake_func(struct work_struct *dummy) { … } static int kvp_handle_handshake(struct hv_kvp_msg *msg) { … } /* * Callback when data is received from user mode. */ static int kvp_on_msg(void *msg, int len) { … } static int process_ob_ipinfo(void *in_msg, void *out_msg, int op) { … } static void process_ib_ipinfo(void *in_msg, void *out_msg, int op) { … } static void kvp_send_key(struct work_struct *dummy) { … } /* * Send a response back to the host. */ static void kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) { … } /* * This callback is invoked when we get a KVP message from the host. * The host ensures that only one KVP transaction can be active at a time. * KVP implementation in Linux needs to forward the key to a user-mde * component to retrieve the corresponding value. Consequently, we cannot * respond to the host in the context of this callback. Since the host * guarantees that at most only one transaction can be active at a time, * we stash away the transaction state in a set of global variables. */ void hv_kvp_onchannelcallback(void *context) { … } static void kvp_on_reset(void) { … } int hv_kvp_init(struct hv_util_service *srv) { … } static void hv_kvp_cancel_work(void) { … } int hv_kvp_pre_suspend(void) { … } int hv_kvp_pre_resume(void) { … } void hv_kvp_deinit(void) { … }