Index: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c =================================================================== --- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -51,6 +51,7 @@ #include #include #include +#include #define HV_RF_RECVINFO_VLAN 0x1 #define HV_RF_RECVINFO_CSUM 0x2 @@ -98,6 +99,9 @@ const void *data, int dlen); static int hn_rndis_query(struct hn_softc *sc, uint32_t oid, const void *idata, size_t idlen, void *odata, size_t *odlen0); +static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, + size_t dlen); +static int hn_rndis_conf_offload(struct hn_softc *sc); static __inline uint32_t hn_rndis_rid(struct hn_softc *sc) @@ -1002,7 +1006,7 @@ reqlen = sizeof(*req) + idlen; xact = vmbus_xact_get(sc->hn_xact, reqlen); if (xact == NULL) { - if_printf(sc->hn_ifp, "no xact for RNDIS query\n"); + if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid); return (ENXIO); } rid = hn_rndis_rid(sc); @@ -1078,6 +1082,96 @@ return (error); } +static int +hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen) +{ + struct rndis_set_req *req; + const struct rndis_set_comp *comp; + struct vmbus_xact *xact; + size_t reqlen, comp_len; + uint32_t rid; + int error; + + KASSERT(dlen > 0, ("invalid dlen %zu", dlen)); + + reqlen = sizeof(*req) + dlen; + xact = vmbus_xact_get(sc->hn_xact, reqlen); + if (xact == NULL) { + if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid); + return (ENXIO); + } + rid = hn_rndis_rid(sc); + req = vmbus_xact_req_data(xact); + req->rm_type = REMOTE_NDIS_SET_MSG; + req->rm_len = reqlen; + req->rm_rid = rid; + req->rm_oid = oid; + req->rm_infobuflen = dlen; + req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET; + /* Data immediately follows RNDIS set. */ + memcpy(req + 1, data, dlen); + + comp_len = sizeof(*comp); + comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len, + REMOTE_NDIS_SET_CMPLT); + if (comp == NULL) { + if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid); + error = EIO; + goto done; + } + + if (comp->rm_status != RNDIS_STATUS_SUCCESS) { + if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: " + "status 0x%08x\n", oid, comp->rm_status); + error = EIO; + goto done; + } + error = 0; +done: + vmbus_xact_put(xact); + return (error); +} + +static int +hn_rndis_conf_offload(struct hn_softc *sc) +{ + struct ndis_offload_params params; + size_t paramsz; + int error; + + /* NOTE: 0 means "no change" */ + memset(¶ms, 0, sizeof(params)); + + params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT; + if (sc->hn_ndis_ver < NDIS_VERSION_6_30) { + params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2; + paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1; + } else { + params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3; + paramsz = NDIS_OFFLOAD_PARAMS_SIZE; + } + params.ndis_hdr.ndis_size = paramsz; + + params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX; + params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX; + params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX; + if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) { + params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX; + params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX; + } + params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON; + /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */ + + error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz); + if (error) { + if_printf(sc->hn_ifp, "offload config failed: %d\n", error); + } else { + if (bootverbose) + if_printf(sc->hn_ifp, "offload config done\n"); + } + return (error); +} + /* * RNDIS filter init device */ @@ -1243,7 +1337,6 @@ { int ret; rndis_device *rndis_dev; - rndis_offload_params offloads; struct rndis_recv_scale_cap rsscaps; uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap); netvsc_device_info *dev_info = (netvsc_device_info *)additl_info; @@ -1293,21 +1386,8 @@ /* TODO: shut down rndis device and the channel */ } - /* config csum offload and send request to host */ - memset(&offloads, 0, sizeof(offloads)); - offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; - offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; - offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; - offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; - offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; - offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; - - ret = hv_rf_send_offload_request(sc, &offloads); - if (ret != 0) { - /* TODO: shut down rndis device and the channel */ - device_printf(dev, - "hv_rf_send_offload_request failed, ret=%d\n", ret); - } + /* Configure NDIS offload settings */ + hn_rndis_conf_offload(sc); memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN); Index: head/sys/dev/hyperv/netvsc/ndis.h =================================================================== --- head/sys/dev/hyperv/netvsc/ndis.h +++ head/sys/dev/hyperv/netvsc/ndis.h @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2016 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. + * + * $FreeBSD$ + */ + +#ifndef _NET_NDIS_H_ +#define _NET_NDIS_H_ + +#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C + +#define NDIS_OBJTYPE_DEFAULT 0x80 + +/* common_set */ +#define NDIS_OFFLOAD_SET_NOCHG 0 +#define NDIS_OFFLOAD_SET_ON 1 +#define NDIS_OFFLOAD_SET_OFF 2 + +/* a.k.a GRE MAC */ +#define NDIS_ENCAP_TYPE_NVGRE 0x00000001 + +struct ndis_object_hdr { + uint8_t ndis_type; /* NDIS_OBJTYPE_ */ + uint8_t ndis_rev; /* type specific */ + uint16_t ndis_size; /* incl. this hdr */ +}; + +/* OID_TCP_OFFLOAD_PARAMETERS */ +struct ndis_offload_params { + struct ndis_object_hdr ndis_hdr; + uint8_t ndis_ip4csum; /* param_set */ + uint8_t ndis_tcp4csum; /* param_set */ + uint8_t ndis_udp4csum; /* param_set */ + uint8_t ndis_tcp6csum; /* param_set */ + uint8_t ndis_udp6csum; /* param_set */ + uint8_t ndis_lsov1; /* lsov1_set */ + uint8_t ndis_ipsecv1; /* ipsecv1_set */ + uint8_t ndis_lsov2_ip4; /* lsov2_set */ + uint8_t ndis_lsov2_ip6; /* lsov2_set */ + uint8_t ndis_tcp4conn; /* PARAM_NOCHG */ + uint8_t ndis_tcp6conn; /* PARAM_NOCHG */ + uint32_t ndis_flags; /* 0 */ + /* NDIS >= 6.1 */ + uint8_t ndis_ipsecv2; /* ipsecv2_set */ + uint8_t ndis_ipsecv2_ip4; /* ipsecv2_set */ + /* NDIS >= 6.30 */ + uint8_t ndis_rsc_ip4; /* rsc_set */ + uint8_t ndis_rsc_ip6; /* rsc_set */ + uint8_t ndis_encap; /* common_set */ + uint8_t ndis_encap_types; /* NDIS_ENCAP_TYPE_ */ +}; + +#define NDIS_OFFLOAD_PARAMS_SIZE sizeof(struct ndis_offload_params) +#define NDIS_OFFLOAD_PARAMS_SIZE_6_1 \ + __offsetof(struct ndis_offload_params, ndis_rsc_ip4) + +#define NDIS_OFFLOAD_PARAMS_REV_2 2 /* NDIS 6.1 */ +#define NDIS_OFFLOAD_PARAMS_REV_3 3 /* NDIS 6.30 */ + +/* param_set */ +#define NDIS_OFFLOAD_PARAM_NOCHG 0 /* common to all sets */ +#define NDIS_OFFLOAD_PARAM_OFF 1 +#define NDIS_OFFLOAD_PARAM_TX 2 +#define NDIS_OFFLOAD_PARAM_RX 3 +#define NDIS_OFFLOAD_PARAM_TXRX 4 + +/* lsov1_set */ +/* NDIS_OFFLOAD_PARAM_NOCHG */ +#define NDIS_OFFLOAD_LSOV1_OFF 1 +#define NDIS_OFFLOAD_LSOV1_ON 2 + +/* ipsecv1_set */ +/* NDIS_OFFLOAD_PARAM_NOCHG */ +#define NDIS_OFFLOAD_IPSECV1_OFF 1 +#define NDIS_OFFLOAD_IPSECV1_AH 2 +#define NDIS_OFFLOAD_IPSECV1_ESP 3 +#define NDIS_OFFLOAD_IPSECV1_AH_ESP 4 + +/* lsov2_set */ +/* NDIS_OFFLOAD_PARAM_NOCHG */ +#define NDIS_OFFLOAD_LSOV2_OFF 1 +#define NDIS_OFFLOAD_LSOV2_ON 2 + +/* ipsecv2_set */ +/* NDIS_OFFLOAD_PARAM_NOCHG */ +#define NDIS_OFFLOAD_IPSECV2_OFF 1 +#define NDIS_OFFLOAD_IPSECV2_AH 2 +#define NDIS_OFFLOAD_IPSECV2_ESP 3 +#define NDIS_OFFLOAD_IPSECV2_AH_ESP 4 + +/* rsc_set */ +/* NDIS_OFFLOAD_PARAM_NOCHG */ +#define NDIS_OFFLOAD_RSC_OFF 1 +#define NDIS_OFFLOAD_RSC_ON 2 + +#endif /* !_NET_NDIS_H_ */ Index: head/sys/net/rndis.h =================================================================== --- head/sys/net/rndis.h +++ head/sys/net/rndis.h @@ -202,6 +202,10 @@ uint32_t rm_devicevchdl; }; +#define RNDIS_SET_REQ_INFOBUFOFFSET \ + (sizeof(struct rndis_set_req) - \ + __offsetof(struct rndis_set_req, rm_rid)) + struct rndis_set_comp { uint32_t rm_type; uint32_t rm_len;