1250199Sgrehan/*- 2250199Sgrehan * Copyright (c) 2010-2012 Citrix Inc. 3250199Sgrehan * Copyright (c) 2009-2012 Microsoft Corp. 4250199Sgrehan * Copyright (c) 2012 NetApp Inc. 5250199Sgrehan * All rights reserved. 6250199Sgrehan * 7250199Sgrehan * Redistribution and use in source and binary forms, with or without 8250199Sgrehan * modification, are permitted provided that the following conditions 9250199Sgrehan * are met: 10250199Sgrehan * 1. Redistributions of source code must retain the above copyright 11250199Sgrehan * notice unmodified, this list of conditions, and the following 12250199Sgrehan * disclaimer. 13250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 14250199Sgrehan * notice, this list of conditions and the following disclaimer in the 15250199Sgrehan * documentation and/or other materials provided with the distribution. 16250199Sgrehan * 17250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27250199Sgrehan */ 28250199Sgrehan 29250199Sgrehan/*- 30250199Sgrehan * Copyright (c) 2004-2006 Kip Macy 31250199Sgrehan * All rights reserved. 32250199Sgrehan * 33250199Sgrehan * Redistribution and use in source and binary forms, with or without 34250199Sgrehan * modification, are permitted provided that the following conditions 35250199Sgrehan * are met: 36250199Sgrehan * 1. Redistributions of source code must retain the above copyright 37250199Sgrehan * notice, this list of conditions and the following disclaimer. 38250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 39250199Sgrehan * notice, this list of conditions and the following disclaimer in the 40250199Sgrehan * documentation and/or other materials provided with the distribution. 41250199Sgrehan * 42250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43250199Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44250199Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45250199Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46250199Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47250199Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48250199Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49250199Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50250199Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51250199Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52250199Sgrehan * SUCH DAMAGE. 53250199Sgrehan */ 54250199Sgrehan 55256363Sgrehan#include <sys/cdefs.h> 56256363Sgrehan__FBSDID("$FreeBSD: releng/10.2/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c 296955 2016-03-16 22:31:04Z glebius $"); 57256363Sgrehan 58285236Swhu#include "opt_inet6.h" 59285236Swhu#include "opt_inet.h" 60285236Swhu 61250199Sgrehan#include <sys/param.h> 62250199Sgrehan#include <sys/systm.h> 63250199Sgrehan#include <sys/sockio.h> 64250199Sgrehan#include <sys/mbuf.h> 65250199Sgrehan#include <sys/malloc.h> 66250199Sgrehan#include <sys/module.h> 67250199Sgrehan#include <sys/kernel.h> 68250199Sgrehan#include <sys/socket.h> 69250199Sgrehan#include <sys/queue.h> 70250199Sgrehan#include <sys/lock.h> 71250199Sgrehan#include <sys/sx.h> 72250199Sgrehan 73250199Sgrehan#include <net/if.h> 74250199Sgrehan#include <net/if_arp.h> 75250199Sgrehan#include <net/ethernet.h> 76250199Sgrehan#include <net/if_dl.h> 77250199Sgrehan#include <net/if_media.h> 78250199Sgrehan 79250199Sgrehan#include <net/bpf.h> 80250199Sgrehan 81250199Sgrehan#include <net/if_types.h> 82250199Sgrehan#include <net/if_vlan_var.h> 83250199Sgrehan#include <net/if.h> 84250199Sgrehan 85250199Sgrehan#include <netinet/in_systm.h> 86250199Sgrehan#include <netinet/in.h> 87250199Sgrehan#include <netinet/ip.h> 88250199Sgrehan#include <netinet/if_ether.h> 89285236Swhu#include <netinet/tcp.h> 90285236Swhu#include <netinet/udp.h> 91285236Swhu#include <netinet/ip6.h> 92250199Sgrehan 93250199Sgrehan#include <vm/vm.h> 94250199Sgrehan#include <vm/vm_param.h> 95250199Sgrehan#include <vm/vm_kern.h> 96250199Sgrehan#include <vm/pmap.h> 97250199Sgrehan 98250199Sgrehan#include <machine/bus.h> 99250199Sgrehan#include <machine/resource.h> 100250199Sgrehan#include <machine/frame.h> 101250199Sgrehan#include <machine/vmparam.h> 102250199Sgrehan 103250199Sgrehan#include <sys/bus.h> 104250199Sgrehan#include <sys/rman.h> 105250199Sgrehan#include <sys/mutex.h> 106250199Sgrehan#include <sys/errno.h> 107250199Sgrehan#include <sys/types.h> 108250199Sgrehan#include <machine/atomic.h> 109250199Sgrehan 110250199Sgrehan#include <machine/intr_machdep.h> 111250199Sgrehan 112285236Swhu#include <machine/in_cksum.h> 113285236Swhu 114250199Sgrehan#include <dev/hyperv/include/hyperv.h> 115250199Sgrehan#include "hv_net_vsc.h" 116250199Sgrehan#include "hv_rndis.h" 117250199Sgrehan#include "hv_rndis_filter.h" 118250199Sgrehan 119250199Sgrehan 120250199Sgrehan/* Short for Hyper-V network interface */ 121250199Sgrehan#define NETVSC_DEVNAME "hn" 122250199Sgrehan 123250199Sgrehan/* 124250199Sgrehan * It looks like offset 0 of buf is reserved to hold the softc pointer. 125250199Sgrehan * The sc pointer evidently not needed, and is not presently populated. 126250199Sgrehan * The packet offset is where the netvsc_packet starts in the buffer. 127250199Sgrehan */ 128250199Sgrehan#define HV_NV_SC_PTR_OFFSET_IN_BUF 0 129250199Sgrehan#define HV_NV_PACKET_OFFSET_IN_BUF 16 130250199Sgrehan 131296955Sglebius/* 132296955Sglebius * A unified flag for all outbound check sum flags is useful, 133296955Sglebius * and it helps avoiding unnecessary check sum calculation in 134296955Sglebius * network forwarding scenario. 135296955Sglebius */ 136296955Sglebius#define HV_CSUM_FOR_OUTBOUND \ 137296955Sglebius (CSUM_IP|CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP|CSUM_IP_TSO| \ 138296955Sglebius CSUM_IP_ISCSI|CSUM_IP6_UDP|CSUM_IP6_TCP|CSUM_IP6_SCTP| \ 139296955Sglebius CSUM_IP6_TSO|CSUM_IP6_ISCSI) 140250199Sgrehan 141250199Sgrehan/* 142250199Sgrehan * Data types 143250199Sgrehan */ 144250199Sgrehan 145250199Sgrehanstruct hv_netvsc_driver_context { 146250199Sgrehan uint32_t drv_inited; 147250199Sgrehan}; 148250199Sgrehan 149250199Sgrehan/* 150250199Sgrehan * Be aware that this sleepable mutex will exhibit WITNESS errors when 151250199Sgrehan * certain TCP and ARP code paths are taken. This appears to be a 152250199Sgrehan * well-known condition, as all other drivers checked use a sleeping 153250199Sgrehan * mutex to protect their transmit paths. 154250199Sgrehan * Also Be aware that mutexes do not play well with semaphores, and there 155250199Sgrehan * is a conflicting semaphore in a certain channel code path. 156250199Sgrehan */ 157250199Sgrehan#define NV_LOCK_INIT(_sc, _name) \ 158250199Sgrehan mtx_init(&(_sc)->hn_lock, _name, MTX_NETWORK_LOCK, MTX_DEF) 159250199Sgrehan#define NV_LOCK(_sc) mtx_lock(&(_sc)->hn_lock) 160250199Sgrehan#define NV_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->hn_lock, MA_OWNED) 161250199Sgrehan#define NV_UNLOCK(_sc) mtx_unlock(&(_sc)->hn_lock) 162250199Sgrehan#define NV_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->hn_lock) 163250199Sgrehan 164250199Sgrehan 165250199Sgrehan/* 166250199Sgrehan * Globals 167250199Sgrehan */ 168250199Sgrehan 169250199Sgrehanint hv_promisc_mode = 0; /* normal mode by default */ 170250199Sgrehan 171250199Sgrehan/* The one and only one */ 172250199Sgrehanstatic struct hv_netvsc_driver_context g_netvsc_drv; 173250199Sgrehan 174250199Sgrehan 175250199Sgrehan/* 176250199Sgrehan * Forward declarations 177250199Sgrehan */ 178250199Sgrehanstatic void hn_stop(hn_softc_t *sc); 179250199Sgrehanstatic void hn_ifinit_locked(hn_softc_t *sc); 180250199Sgrehanstatic void hn_ifinit(void *xsc); 181250199Sgrehanstatic int hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 182250199Sgrehanstatic int hn_start_locked(struct ifnet *ifp); 183250199Sgrehanstatic void hn_start(struct ifnet *ifp); 184250199Sgrehan 185285236Swhu/* 186285236Swhu * NetVsc get message transport protocol type 187285236Swhu */ 188285236Swhustatic uint32_t get_transport_proto_type(struct mbuf *m_head) 189285236Swhu{ 190285236Swhu uint32_t ret_val = TRANSPORT_TYPE_NOT_IP; 191285236Swhu uint16_t ether_type = 0; 192285236Swhu int ether_len = 0; 193285236Swhu struct ether_vlan_header *eh; 194285236Swhu#ifdef INET 195285236Swhu struct ip *iph; 196285236Swhu#endif 197285236Swhu#ifdef INET6 198285236Swhu struct ip6_hdr *ip6; 199285236Swhu#endif 200250199Sgrehan 201285236Swhu eh = mtod(m_head, struct ether_vlan_header*); 202285236Swhu if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 203285236Swhu ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 204285236Swhu ether_type = eh->evl_proto; 205285236Swhu } else { 206285236Swhu ether_len = ETHER_HDR_LEN; 207285236Swhu ether_type = eh->evl_encap_proto; 208285236Swhu } 209285236Swhu 210285236Swhu switch (ntohs(ether_type)) { 211285236Swhu#ifdef INET6 212285236Swhu case ETHERTYPE_IPV6: 213285236Swhu ip6 = (struct ip6_hdr *)(m_head->m_data + ether_len); 214285236Swhu 215285236Swhu if (IPPROTO_TCP == ip6->ip6_nxt) { 216285236Swhu ret_val = TRANSPORT_TYPE_IPV6_TCP; 217285236Swhu } else if (IPPROTO_UDP == ip6->ip6_nxt) { 218285236Swhu ret_val = TRANSPORT_TYPE_IPV6_UDP; 219285236Swhu } 220285236Swhu break; 221285236Swhu#endif 222285236Swhu#ifdef INET 223285236Swhu case ETHERTYPE_IP: 224285236Swhu iph = (struct ip *)(m_head->m_data + ether_len); 225285236Swhu 226285236Swhu if (IPPROTO_TCP == iph->ip_p) { 227285236Swhu ret_val = TRANSPORT_TYPE_IPV4_TCP; 228285236Swhu } else if (IPPROTO_UDP == iph->ip_p) { 229285236Swhu ret_val = TRANSPORT_TYPE_IPV4_UDP; 230285236Swhu } 231285236Swhu break; 232285236Swhu#endif 233285236Swhu default: 234285236Swhu ret_val = TRANSPORT_TYPE_NOT_IP; 235285236Swhu break; 236285236Swhu } 237285236Swhu 238285236Swhu return (ret_val); 239285236Swhu} 240285236Swhu 241250199Sgrehan/* 242250199Sgrehan * NetVsc driver initialization 243250199Sgrehan * Note: Filter init is no longer required 244250199Sgrehan */ 245250199Sgrehanstatic int 246250199Sgrehannetvsc_drv_init(void) 247250199Sgrehan{ 248250199Sgrehan return (0); 249250199Sgrehan} 250250199Sgrehan 251250199Sgrehan/* 252250199Sgrehan * NetVsc global initialization entry point 253250199Sgrehan */ 254250199Sgrehanstatic void 255250199Sgrehannetvsc_init(void) 256250199Sgrehan{ 257263853Sdelphij if (bootverbose) 258263853Sdelphij printf("Netvsc initializing... "); 259250199Sgrehan 260250199Sgrehan /* 261250199Sgrehan * XXXKYS: cleanup initialization 262250199Sgrehan */ 263250199Sgrehan if (!cold && !g_netvsc_drv.drv_inited) { 264250199Sgrehan g_netvsc_drv.drv_inited = 1; 265250199Sgrehan netvsc_drv_init(); 266263853Sdelphij if (bootverbose) 267263853Sdelphij printf("done!\n"); 268263853Sdelphij } else if (bootverbose) 269250199Sgrehan printf("Already initialized!\n"); 270250199Sgrehan} 271250199Sgrehan 272250199Sgrehan/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 273250199Sgrehanstatic const hv_guid g_net_vsc_device_type = { 274250199Sgrehan .data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 275250199Sgrehan 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 276250199Sgrehan}; 277250199Sgrehan 278250199Sgrehan/* 279250199Sgrehan * Standard probe entry point. 280250199Sgrehan * 281250199Sgrehan */ 282250199Sgrehanstatic int 283250199Sgrehannetvsc_probe(device_t dev) 284250199Sgrehan{ 285250199Sgrehan const char *p; 286250199Sgrehan 287250199Sgrehan p = vmbus_get_type(dev); 288250199Sgrehan if (!memcmp(p, &g_net_vsc_device_type.data, sizeof(hv_guid))) { 289250199Sgrehan device_set_desc(dev, "Synthetic Network Interface"); 290263853Sdelphij if (bootverbose) 291263853Sdelphij printf("Netvsc probe... DONE \n"); 292250199Sgrehan 293273580Sdelphij return (BUS_PROBE_DEFAULT); 294250199Sgrehan } 295250199Sgrehan 296250199Sgrehan return (ENXIO); 297250199Sgrehan} 298250199Sgrehan 299250199Sgrehan/* 300250199Sgrehan * Standard attach entry point. 301250199Sgrehan * 302250199Sgrehan * Called when the driver is loaded. It allocates needed resources, 303250199Sgrehan * and initializes the "hardware" and software. 304250199Sgrehan */ 305250199Sgrehanstatic int 306250199Sgrehannetvsc_attach(device_t dev) 307250199Sgrehan{ 308250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(dev); 309250199Sgrehan netvsc_device_info device_info; 310250199Sgrehan hn_softc_t *sc; 311250199Sgrehan int unit = device_get_unit(dev); 312250199Sgrehan struct ifnet *ifp; 313250199Sgrehan int ret; 314250199Sgrehan 315250199Sgrehan netvsc_init(); 316250199Sgrehan 317250199Sgrehan sc = device_get_softc(dev); 318250199Sgrehan if (sc == NULL) { 319250199Sgrehan return (ENOMEM); 320250199Sgrehan } 321250199Sgrehan 322250199Sgrehan bzero(sc, sizeof(hn_softc_t)); 323250199Sgrehan sc->hn_unit = unit; 324250199Sgrehan sc->hn_dev = dev; 325250199Sgrehan 326250199Sgrehan NV_LOCK_INIT(sc, "NetVSCLock"); 327250199Sgrehan 328250199Sgrehan sc->hn_dev_obj = device_ctx; 329250199Sgrehan 330250199Sgrehan ifp = sc->hn_ifp = sc->arpcom.ac_ifp = if_alloc(IFT_ETHER); 331250199Sgrehan ifp->if_softc = sc; 332250199Sgrehan 333250199Sgrehan if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 334250199Sgrehan ifp->if_dunit = unit; 335250199Sgrehan ifp->if_dname = NETVSC_DEVNAME; 336250199Sgrehan 337250199Sgrehan ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 338250199Sgrehan ifp->if_ioctl = hn_ioctl; 339250199Sgrehan ifp->if_start = hn_start; 340250199Sgrehan ifp->if_init = hn_ifinit; 341250199Sgrehan /* needed by hv_rf_on_device_add() code */ 342250199Sgrehan ifp->if_mtu = ETHERMTU; 343250199Sgrehan IFQ_SET_MAXLEN(&ifp->if_snd, 512); 344250199Sgrehan ifp->if_snd.ifq_drv_maxlen = 511; 345250199Sgrehan IFQ_SET_READY(&ifp->if_snd); 346250199Sgrehan 347250199Sgrehan /* 348250199Sgrehan * Tell upper layers that we support full VLAN capability. 349250199Sgrehan */ 350250199Sgrehan ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 351285236Swhu ifp->if_capabilities |= 352285236Swhu IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_TSO; 353285236Swhu ifp->if_capenable |= 354285236Swhu IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_TSO; 355286058Swhu /* 356286058Swhu * Only enable UDP checksum offloading when it is on 2012R2 or 357286058Swhu * later. UDP checksum offloading doesn't work on earlier 358286058Swhu * Windows releases. 359286058Swhu */ 360286058Swhu if (hv_vmbus_protocal_version >= HV_VMBUS_VERSION_WIN8_1) 361286058Swhu ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 362286058Swhu else 363286058Swhu ifp->if_hwassist = CSUM_TCP | CSUM_TSO; 364250199Sgrehan 365250199Sgrehan ret = hv_rf_on_device_add(device_ctx, &device_info); 366250199Sgrehan if (ret != 0) { 367250199Sgrehan if_free(ifp); 368250199Sgrehan 369250199Sgrehan return (ret); 370250199Sgrehan } 371250199Sgrehan if (device_info.link_state == 0) { 372250199Sgrehan sc->hn_carrier = 1; 373250199Sgrehan } 374250199Sgrehan 375250199Sgrehan ether_ifattach(ifp, device_info.mac_addr); 376250199Sgrehan 377250199Sgrehan return (0); 378250199Sgrehan} 379250199Sgrehan 380250199Sgrehan/* 381250199Sgrehan * Standard detach entry point 382250199Sgrehan */ 383250199Sgrehanstatic int 384250199Sgrehannetvsc_detach(device_t dev) 385250199Sgrehan{ 386250199Sgrehan struct hv_device *hv_device = vmbus_get_devctx(dev); 387250199Sgrehan 388263853Sdelphij if (bootverbose) 389263853Sdelphij printf("netvsc_detach\n"); 390250199Sgrehan 391250199Sgrehan /* 392250199Sgrehan * XXXKYS: Need to clean up all our 393250199Sgrehan * driver state; this is the driver 394250199Sgrehan * unloading. 395250199Sgrehan */ 396250199Sgrehan 397250199Sgrehan /* 398250199Sgrehan * XXXKYS: Need to stop outgoing traffic and unregister 399250199Sgrehan * the netdevice. 400250199Sgrehan */ 401250199Sgrehan 402250199Sgrehan hv_rf_on_device_remove(hv_device, HV_RF_NV_DESTROY_CHANNEL); 403250199Sgrehan 404250199Sgrehan return (0); 405250199Sgrehan} 406250199Sgrehan 407250199Sgrehan/* 408250199Sgrehan * Standard shutdown entry point 409250199Sgrehan */ 410250199Sgrehanstatic int 411250199Sgrehannetvsc_shutdown(device_t dev) 412250199Sgrehan{ 413250199Sgrehan return (0); 414250199Sgrehan} 415250199Sgrehan 416250199Sgrehan/* 417250199Sgrehan * Send completion processing 418250199Sgrehan * 419250199Sgrehan * Note: It looks like offset 0 of buf is reserved to hold the softc 420250199Sgrehan * pointer. The sc pointer is not currently needed in this function, and 421250199Sgrehan * it is not presently populated by the TX function. 422250199Sgrehan */ 423250199Sgrehanvoid 424250199Sgrehannetvsc_xmit_completion(void *context) 425250199Sgrehan{ 426250199Sgrehan netvsc_packet *packet = (netvsc_packet *)context; 427250199Sgrehan struct mbuf *mb; 428250199Sgrehan uint8_t *buf; 429250199Sgrehan 430266794Smarius mb = (struct mbuf *)(uintptr_t)packet->compl.send.send_completion_tid; 431250199Sgrehan buf = ((uint8_t *)packet) - HV_NV_PACKET_OFFSET_IN_BUF; 432250199Sgrehan 433285236Swhu free(buf, M_NETVSC); 434250199Sgrehan 435250199Sgrehan if (mb != NULL) { 436250199Sgrehan m_freem(mb); 437250199Sgrehan } 438250199Sgrehan} 439250199Sgrehan 440250199Sgrehan/* 441250199Sgrehan * Start a transmit of one or more packets 442250199Sgrehan */ 443250199Sgrehanstatic int 444250199Sgrehanhn_start_locked(struct ifnet *ifp) 445250199Sgrehan{ 446250199Sgrehan hn_softc_t *sc = ifp->if_softc; 447250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); 448285236Swhu netvsc_dev *net_dev = sc->net_dev; 449285236Swhu device_t dev = device_ctx->device; 450250199Sgrehan uint8_t *buf; 451250199Sgrehan netvsc_packet *packet; 452250199Sgrehan struct mbuf *m_head, *m; 453250199Sgrehan struct mbuf *mc_head = NULL; 454285236Swhu struct ether_vlan_header *eh; 455285236Swhu rndis_msg *rndis_mesg; 456285236Swhu rndis_packet *rndis_pkt; 457285236Swhu rndis_per_packet_info *rppi; 458285236Swhu ndis_8021q_info *rppi_vlan_info; 459285236Swhu rndis_tcp_ip_csum_info *csum_info; 460285236Swhu rndis_tcp_tso_info *tso_info; 461285236Swhu int ether_len; 462250199Sgrehan int i; 463250199Sgrehan int num_frags; 464250199Sgrehan int len; 465250199Sgrehan int retries = 0; 466285236Swhu int ret = 0; 467285236Swhu uint32_t rndis_msg_size = 0; 468285236Swhu uint32_t trans_proto_type; 469285236Swhu uint32_t send_buf_section_idx = 470285236Swhu NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; 471250199Sgrehan 472250199Sgrehan while (!IFQ_DRV_IS_EMPTY(&sc->hn_ifp->if_snd)) { 473250199Sgrehan IFQ_DRV_DEQUEUE(&sc->hn_ifp->if_snd, m_head); 474250199Sgrehan if (m_head == NULL) { 475250199Sgrehan break; 476250199Sgrehan } 477250199Sgrehan 478250199Sgrehan len = 0; 479250199Sgrehan num_frags = 0; 480250199Sgrehan 481250199Sgrehan /* Walk the mbuf list computing total length and num frags */ 482250199Sgrehan for (m = m_head; m != NULL; m = m->m_next) { 483250199Sgrehan if (m->m_len != 0) { 484250199Sgrehan num_frags++; 485250199Sgrehan len += m->m_len; 486250199Sgrehan } 487250199Sgrehan } 488250199Sgrehan 489250199Sgrehan /* 490250199Sgrehan * Reserve the number of pages requested. Currently, 491250199Sgrehan * one page is reserved for the message in the RNDIS 492250199Sgrehan * filter packet 493250199Sgrehan */ 494250199Sgrehan num_frags += HV_RF_NUM_TX_RESERVED_PAGE_BUFS; 495250199Sgrehan 496250199Sgrehan /* If exceeds # page_buffers in netvsc_packet */ 497250199Sgrehan if (num_frags > NETVSC_PACKET_MAXPAGE) { 498285236Swhu device_printf(dev, "exceed max page buffers,%d,%d\n", 499285236Swhu num_frags, NETVSC_PACKET_MAXPAGE); 500285236Swhu m_freem(m_head); 501285236Swhu if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 502250199Sgrehan return (EINVAL); 503250199Sgrehan } 504250199Sgrehan 505250199Sgrehan /* 506250199Sgrehan * Allocate a buffer with space for a netvsc packet plus a 507250199Sgrehan * number of reserved areas. First comes a (currently 16 508250199Sgrehan * bytes, currently unused) reserved data area. Second is 509285236Swhu * the netvsc_packet. Third is an area reserved for an 510285236Swhu * rndis_filter_packet struct. Fourth (optional) is a 511285236Swhu * rndis_per_packet_info struct. 512250199Sgrehan * Changed malloc to M_NOWAIT to avoid sleep under spin lock. 513250199Sgrehan * No longer reserving extra space for page buffers, as they 514250199Sgrehan * are already part of the netvsc_packet. 515250199Sgrehan */ 516250199Sgrehan buf = malloc(HV_NV_PACKET_OFFSET_IN_BUF + 517285236Swhu sizeof(netvsc_packet) + 518285236Swhu sizeof(rndis_msg) + 519285236Swhu RNDIS_VLAN_PPI_SIZE + 520285236Swhu RNDIS_TSO_PPI_SIZE + 521285236Swhu RNDIS_CSUM_PPI_SIZE, 522285236Swhu M_NETVSC, M_ZERO | M_NOWAIT); 523250199Sgrehan if (buf == NULL) { 524285236Swhu device_printf(dev, "hn:malloc packet failed\n"); 525285236Swhu m_freem(m_head); 526285236Swhu if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 527250199Sgrehan return (ENOMEM); 528250199Sgrehan } 529250199Sgrehan 530250199Sgrehan packet = (netvsc_packet *)(buf + HV_NV_PACKET_OFFSET_IN_BUF); 531250199Sgrehan *(vm_offset_t *)buf = HV_NV_SC_PTR_OFFSET_IN_BUF; 532250199Sgrehan 533285236Swhu packet->is_data_pkt = TRUE; 534285236Swhu 535285236Swhu /* Set up the rndis header */ 536285236Swhu packet->page_buf_count = num_frags; 537285236Swhu 538285236Swhu /* Initialize it from the mbuf */ 539285236Swhu packet->tot_data_buf_len = len; 540285236Swhu 541250199Sgrehan /* 542250199Sgrehan * extension points to the area reserved for the 543250199Sgrehan * rndis_filter_packet, which is placed just after 544250199Sgrehan * the netvsc_packet (and rppi struct, if present; 545250199Sgrehan * length is updated later). 546250199Sgrehan */ 547285236Swhu packet->rndis_mesg = packet + 1; 548285236Swhu rndis_mesg = (rndis_msg *)packet->rndis_mesg; 549285236Swhu rndis_mesg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; 550250199Sgrehan 551285236Swhu rndis_pkt = &rndis_mesg->msg.packet; 552285236Swhu rndis_pkt->data_offset = sizeof(rndis_packet); 553285236Swhu rndis_pkt->data_length = packet->tot_data_buf_len; 554285236Swhu rndis_pkt->per_pkt_info_offset = sizeof(rndis_packet); 555250199Sgrehan 556285236Swhu rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet); 557250199Sgrehan 558250199Sgrehan /* 559250199Sgrehan * If the Hyper-V infrastructure needs to embed a VLAN tag, 560250199Sgrehan * initialize netvsc_packet and rppi struct values as needed. 561250199Sgrehan */ 562285236Swhu if (m_head->m_flags & M_VLANTAG) { 563285236Swhu /* 564285236Swhu * set up some additional fields so the Hyper-V infrastructure will stuff the VLAN tag 565285236Swhu * into the frame. 566285236Swhu */ 567250199Sgrehan packet->vlan_tci = m_head->m_pkthdr.ether_vtag; 568285236Swhu 569285236Swhu rndis_msg_size += RNDIS_VLAN_PPI_SIZE; 570285236Swhu 571285236Swhu rppi = hv_set_rppi_data(rndis_mesg, RNDIS_VLAN_PPI_SIZE, 572285236Swhu ieee_8021q_info); 573285236Swhu 574285236Swhu /* VLAN info immediately follows rppi struct */ 575285236Swhu rppi_vlan_info = (ndis_8021q_info *)((char*)rppi + 576285236Swhu rppi->per_packet_info_offset); 577285236Swhu /* FreeBSD does not support CFI or priority */ 578285236Swhu rppi_vlan_info->u1.s1.vlan_id = 579285236Swhu packet->vlan_tci & 0xfff; 580250199Sgrehan } 581250199Sgrehan 582296955Sglebius /* Only check the flags for outbound and ignore the ones for inbound */ 583296955Sglebius if (0 == (m_head->m_pkthdr.csum_flags & HV_CSUM_FOR_OUTBOUND)) { 584285236Swhu goto pre_send; 585285236Swhu } 586285236Swhu 587285236Swhu eh = mtod(m_head, struct ether_vlan_header*); 588285236Swhu if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 589285236Swhu ether_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 590285236Swhu } else { 591285236Swhu ether_len = ETHER_HDR_LEN; 592285236Swhu } 593285236Swhu 594285236Swhu trans_proto_type = get_transport_proto_type(m_head); 595285236Swhu if (TRANSPORT_TYPE_NOT_IP == trans_proto_type) { 596285236Swhu goto pre_send; 597285236Swhu } 598285236Swhu 599250199Sgrehan /* 600285236Swhu * TSO packet needless to setup the send side checksum 601285236Swhu * offload. 602285236Swhu */ 603285236Swhu if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 604285236Swhu goto do_tso; 605285236Swhu } 606285236Swhu 607285236Swhu /* setup checksum offload */ 608285236Swhu rndis_msg_size += RNDIS_CSUM_PPI_SIZE; 609285236Swhu rppi = hv_set_rppi_data(rndis_mesg, RNDIS_CSUM_PPI_SIZE, 610285236Swhu tcpip_chksum_info); 611285236Swhu csum_info = (rndis_tcp_ip_csum_info *)((char*)rppi + 612285236Swhu rppi->per_packet_info_offset); 613285236Swhu 614285236Swhu if (trans_proto_type & (TYPE_IPV4 << 16)) { 615285236Swhu csum_info->xmit.is_ipv4 = 1; 616285236Swhu } else { 617285236Swhu csum_info->xmit.is_ipv6 = 1; 618285236Swhu } 619285236Swhu 620285236Swhu if (trans_proto_type & TYPE_TCP) { 621285236Swhu csum_info->xmit.tcp_csum = 1; 622285236Swhu csum_info->xmit.tcp_header_offset = 0; 623285236Swhu } else if (trans_proto_type & TYPE_UDP) { 624285236Swhu csum_info->xmit.udp_csum = 1; 625285236Swhu } 626285236Swhu 627285236Swhu goto pre_send; 628285236Swhu 629285236Swhudo_tso: 630285236Swhu /* setup TCP segmentation offload */ 631285236Swhu rndis_msg_size += RNDIS_TSO_PPI_SIZE; 632285236Swhu rppi = hv_set_rppi_data(rndis_mesg, RNDIS_TSO_PPI_SIZE, 633285236Swhu tcp_large_send_info); 634285236Swhu 635285236Swhu tso_info = (rndis_tcp_tso_info *)((char *)rppi + 636285236Swhu rppi->per_packet_info_offset); 637285236Swhu tso_info->lso_v2_xmit.type = 638285236Swhu RNDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; 639285236Swhu 640285236Swhu#ifdef INET 641285236Swhu if (trans_proto_type & (TYPE_IPV4 << 16)) { 642285236Swhu struct ip *ip = 643285236Swhu (struct ip *)(m_head->m_data + ether_len); 644285236Swhu unsigned long iph_len = ip->ip_hl << 2; 645285236Swhu struct tcphdr *th = 646285236Swhu (struct tcphdr *)((caddr_t)ip + iph_len); 647285236Swhu 648285236Swhu tso_info->lso_v2_xmit.ip_version = 649285236Swhu RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; 650285236Swhu ip->ip_len = 0; 651285236Swhu ip->ip_sum = 0; 652285236Swhu 653285236Swhu th->th_sum = in_pseudo(ip->ip_src.s_addr, 654285236Swhu ip->ip_dst.s_addr, 655285236Swhu htons(IPPROTO_TCP)); 656285236Swhu } 657285236Swhu#endif 658285236Swhu#if defined(INET6) && defined(INET) 659285236Swhu else 660285236Swhu#endif 661285236Swhu#ifdef INET6 662285236Swhu { 663285236Swhu struct ip6_hdr *ip6 = 664285236Swhu (struct ip6_hdr *)(m_head->m_data + ether_len); 665285236Swhu struct tcphdr *th = (struct tcphdr *)(ip6 + 1); 666285236Swhu 667285236Swhu tso_info->lso_v2_xmit.ip_version = 668285236Swhu RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; 669285236Swhu ip6->ip6_plen = 0; 670285236Swhu th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 671285236Swhu } 672285236Swhu#endif 673285236Swhu tso_info->lso_v2_xmit.tcp_header_offset = 0; 674285236Swhu tso_info->lso_v2_xmit.mss = m_head->m_pkthdr.tso_segsz; 675285236Swhu 676285236Swhupre_send: 677285236Swhu rndis_mesg->msg_len = packet->tot_data_buf_len + rndis_msg_size; 678285236Swhu packet->tot_data_buf_len = rndis_mesg->msg_len; 679285236Swhu 680285236Swhu /* send packet with send buffer */ 681285236Swhu if (packet->tot_data_buf_len < net_dev->send_section_size) { 682285236Swhu send_buf_section_idx = 683285236Swhu hv_nv_get_next_send_section(net_dev); 684285236Swhu if (send_buf_section_idx != 685285236Swhu NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { 686285236Swhu char *dest = ((char *)net_dev->send_buf + 687285236Swhu send_buf_section_idx * 688285236Swhu net_dev->send_section_size); 689285236Swhu 690285236Swhu memcpy(dest, rndis_mesg, rndis_msg_size); 691285236Swhu dest += rndis_msg_size; 692285236Swhu for (m = m_head; m != NULL; m = m->m_next) { 693285236Swhu if (m->m_len) { 694285236Swhu memcpy(dest, 695285236Swhu (void *)mtod(m, vm_offset_t), 696285236Swhu m->m_len); 697285236Swhu dest += m->m_len; 698285236Swhu } 699285236Swhu } 700285236Swhu 701285236Swhu packet->send_buf_section_idx = 702285236Swhu send_buf_section_idx; 703285236Swhu packet->send_buf_section_size = 704285236Swhu packet->tot_data_buf_len; 705285236Swhu packet->page_buf_count = 0; 706285236Swhu goto do_send; 707285236Swhu } 708285236Swhu } 709285236Swhu 710285236Swhu /* send packet with page buffer */ 711285236Swhu packet->page_buffers[0].pfn = 712285236Swhu atop(hv_get_phys_addr(rndis_mesg)); 713285236Swhu packet->page_buffers[0].offset = 714285236Swhu (unsigned long)rndis_mesg & PAGE_MASK; 715285236Swhu packet->page_buffers[0].length = rndis_msg_size; 716285236Swhu 717285236Swhu /* 718250199Sgrehan * Fill the page buffers with mbuf info starting at index 719250199Sgrehan * HV_RF_NUM_TX_RESERVED_PAGE_BUFS. 720250199Sgrehan */ 721250199Sgrehan i = HV_RF_NUM_TX_RESERVED_PAGE_BUFS; 722250199Sgrehan for (m = m_head; m != NULL; m = m->m_next) { 723250199Sgrehan if (m->m_len) { 724250199Sgrehan vm_offset_t paddr = 725250199Sgrehan vtophys(mtod(m, vm_offset_t)); 726250199Sgrehan packet->page_buffers[i].pfn = 727250199Sgrehan paddr >> PAGE_SHIFT; 728250199Sgrehan packet->page_buffers[i].offset = 729250199Sgrehan paddr & (PAGE_SIZE - 1); 730250199Sgrehan packet->page_buffers[i].length = m->m_len; 731250199Sgrehan i++; 732250199Sgrehan } 733250199Sgrehan } 734250199Sgrehan 735285236Swhu packet->send_buf_section_idx = 736285236Swhu NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; 737285236Swhu packet->send_buf_section_size = 0; 738285236Swhu 739285236Swhudo_send: 740285236Swhu 741250199Sgrehan /* 742250199Sgrehan * If bpf, copy the mbuf chain. This is less expensive than 743250199Sgrehan * it appears; the mbuf clusters are not copied, only their 744250199Sgrehan * reference counts are incremented. 745250199Sgrehan * Needed to avoid a race condition where the completion 746250199Sgrehan * callback is invoked, freeing the mbuf chain, before the 747250199Sgrehan * bpf_mtap code has a chance to run. 748250199Sgrehan */ 749250199Sgrehan if (ifp->if_bpf) { 750250199Sgrehan mc_head = m_copypacket(m_head, M_DONTWAIT); 751250199Sgrehan } 752250199Sgrehanretry_send: 753250199Sgrehan /* Set the completion routine */ 754250199Sgrehan packet->compl.send.on_send_completion = netvsc_xmit_completion; 755250199Sgrehan packet->compl.send.send_completion_context = packet; 756266794Smarius packet->compl.send.send_completion_tid = (uint64_t)(uintptr_t)m_head; 757250199Sgrehan 758250199Sgrehan /* Removed critical_enter(), does not appear necessary */ 759285236Swhu ret = hv_nv_on_send(device_ctx, packet); 760250199Sgrehan if (ret == 0) { 761250199Sgrehan ifp->if_opackets++; 762250199Sgrehan /* if bpf && mc_head, call bpf_mtap code */ 763250199Sgrehan if (mc_head) { 764250199Sgrehan ETHER_BPF_MTAP(ifp, mc_head); 765250199Sgrehan } 766250199Sgrehan } else { 767250199Sgrehan retries++; 768250199Sgrehan if (retries < 4) { 769250199Sgrehan goto retry_send; 770250199Sgrehan } 771250199Sgrehan 772250199Sgrehan IF_PREPEND(&ifp->if_snd, m_head); 773250199Sgrehan ifp->if_drv_flags |= IFF_DRV_OACTIVE; 774250199Sgrehan 775250199Sgrehan /* 776250199Sgrehan * Null the mbuf pointer so the completion function 777250199Sgrehan * does not free the mbuf chain. We just pushed the 778250199Sgrehan * mbuf chain back on the if_snd queue. 779250199Sgrehan */ 780250199Sgrehan packet->compl.send.send_completion_tid = 0; 781250199Sgrehan 782250199Sgrehan /* 783250199Sgrehan * Release the resources since we will not get any 784250199Sgrehan * send completion 785250199Sgrehan */ 786250199Sgrehan netvsc_xmit_completion(packet); 787285236Swhu if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 788250199Sgrehan } 789250199Sgrehan 790250199Sgrehan /* if bpf && mc_head, free the mbuf chain copy */ 791250199Sgrehan if (mc_head) { 792250199Sgrehan m_freem(mc_head); 793250199Sgrehan } 794250199Sgrehan } 795250199Sgrehan 796250199Sgrehan return (ret); 797250199Sgrehan} 798250199Sgrehan 799250199Sgrehan/* 800250199Sgrehan * Link up/down notification 801250199Sgrehan */ 802250199Sgrehanvoid 803250199Sgrehannetvsc_linkstatus_callback(struct hv_device *device_obj, uint32_t status) 804250199Sgrehan{ 805250199Sgrehan hn_softc_t *sc = device_get_softc(device_obj->device); 806250199Sgrehan 807250199Sgrehan if (sc == NULL) { 808250199Sgrehan return; 809250199Sgrehan } 810250199Sgrehan 811250199Sgrehan if (status == 1) { 812250199Sgrehan sc->hn_carrier = 1; 813250199Sgrehan } else { 814250199Sgrehan sc->hn_carrier = 0; 815250199Sgrehan } 816250199Sgrehan} 817250199Sgrehan 818250199Sgrehan/* 819250199Sgrehan * Append the specified data to the indicated mbuf chain, 820250199Sgrehan * Extend the mbuf chain if the new data does not fit in 821250199Sgrehan * existing space. 822250199Sgrehan * 823250199Sgrehan * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 824250199Sgrehan * There should be an equivalent in the kernel mbuf code, 825250199Sgrehan * but there does not appear to be one yet. 826250199Sgrehan * 827250199Sgrehan * Differs from m_append() in that additional mbufs are 828250199Sgrehan * allocated with cluster size MJUMPAGESIZE, and filled 829250199Sgrehan * accordingly. 830250199Sgrehan * 831250199Sgrehan * Return 1 if able to complete the job; otherwise 0. 832250199Sgrehan */ 833250199Sgrehanstatic int 834250199Sgrehanhv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 835250199Sgrehan{ 836250199Sgrehan struct mbuf *m, *n; 837250199Sgrehan int remainder, space; 838250199Sgrehan 839250199Sgrehan for (m = m0; m->m_next != NULL; m = m->m_next) 840250199Sgrehan ; 841250199Sgrehan remainder = len; 842250199Sgrehan space = M_TRAILINGSPACE(m); 843250199Sgrehan if (space > 0) { 844250199Sgrehan /* 845250199Sgrehan * Copy into available space. 846250199Sgrehan */ 847250199Sgrehan if (space > remainder) 848250199Sgrehan space = remainder; 849250199Sgrehan bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 850250199Sgrehan m->m_len += space; 851250199Sgrehan cp += space; 852250199Sgrehan remainder -= space; 853250199Sgrehan } 854250199Sgrehan while (remainder > 0) { 855250199Sgrehan /* 856250199Sgrehan * Allocate a new mbuf; could check space 857250199Sgrehan * and allocate a cluster instead. 858250199Sgrehan */ 859250199Sgrehan n = m_getjcl(M_DONTWAIT, m->m_type, 0, MJUMPAGESIZE); 860250199Sgrehan if (n == NULL) 861250199Sgrehan break; 862250199Sgrehan n->m_len = min(MJUMPAGESIZE, remainder); 863250199Sgrehan bcopy(cp, mtod(n, caddr_t), n->m_len); 864250199Sgrehan cp += n->m_len; 865250199Sgrehan remainder -= n->m_len; 866250199Sgrehan m->m_next = n; 867250199Sgrehan m = n; 868250199Sgrehan } 869250199Sgrehan if (m0->m_flags & M_PKTHDR) 870250199Sgrehan m0->m_pkthdr.len += len - remainder; 871250199Sgrehan 872250199Sgrehan return (remainder == 0); 873250199Sgrehan} 874250199Sgrehan 875250199Sgrehan 876250199Sgrehan/* 877250199Sgrehan * Called when we receive a data packet from the "wire" on the 878250199Sgrehan * specified device 879250199Sgrehan * 880250199Sgrehan * Note: This is no longer used as a callback 881250199Sgrehan */ 882250199Sgrehanint 883285236Swhunetvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet, 884285236Swhu rndis_tcp_ip_csum_info *csum_info) 885250199Sgrehan{ 886250199Sgrehan hn_softc_t *sc = (hn_softc_t *)device_get_softc(device_ctx->device); 887250199Sgrehan struct mbuf *m_new; 888257513Sdelphij struct ifnet *ifp; 889285236Swhu device_t dev = device_ctx->device; 890250199Sgrehan int size; 891250199Sgrehan 892250199Sgrehan if (sc == NULL) { 893250199Sgrehan return (0); /* TODO: KYS how can this be! */ 894250199Sgrehan } 895257513Sdelphij 896257513Sdelphij ifp = sc->hn_ifp; 897250199Sgrehan 898250199Sgrehan ifp = sc->arpcom.ac_ifp; 899250199Sgrehan 900250199Sgrehan if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 901250199Sgrehan return (0); 902250199Sgrehan } 903250199Sgrehan 904250199Sgrehan /* 905250199Sgrehan * Bail out if packet contains more data than configured MTU. 906250199Sgrehan */ 907250199Sgrehan if (packet->tot_data_buf_len > (ifp->if_mtu + ETHER_HDR_LEN)) { 908250199Sgrehan return (0); 909250199Sgrehan } 910250199Sgrehan 911250199Sgrehan /* 912250199Sgrehan * Get an mbuf with a cluster. For packets 2K or less, 913250199Sgrehan * get a standard 2K cluster. For anything larger, get a 914250199Sgrehan * 4K cluster. Any buffers larger than 4K can cause problems 915250199Sgrehan * if looped around to the Hyper-V TX channel, so avoid them. 916250199Sgrehan */ 917250199Sgrehan size = MCLBYTES; 918250199Sgrehan 919250199Sgrehan if (packet->tot_data_buf_len > MCLBYTES) { 920250199Sgrehan /* 4096 */ 921250199Sgrehan size = MJUMPAGESIZE; 922250199Sgrehan } 923250199Sgrehan 924250199Sgrehan m_new = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); 925250199Sgrehan 926285236Swhu if (m_new == NULL) { 927285236Swhu device_printf(dev, "alloc mbuf failed.\n"); 928250199Sgrehan return (0); 929285236Swhu } 930250199Sgrehan 931285236Swhu hv_m_append(m_new, packet->tot_data_buf_len, 932285236Swhu packet->data); 933250199Sgrehan 934285236Swhu m_new->m_pkthdr.rcvif = ifp; 935250199Sgrehan 936285236Swhu /* receive side checksum offload */ 937285236Swhu m_new->m_pkthdr.csum_flags = 0; 938285236Swhu if (NULL != csum_info) { 939285236Swhu /* IP csum offload */ 940285236Swhu if (csum_info->receive.ip_csum_succeeded) { 941285236Swhu m_new->m_pkthdr.csum_flags |= 942285236Swhu (CSUM_IP_CHECKED | CSUM_IP_VALID); 943285236Swhu } 944285236Swhu 945285236Swhu /* TCP csum offload */ 946285236Swhu if (csum_info->receive.tcp_csum_succeeded) { 947285236Swhu m_new->m_pkthdr.csum_flags |= 948285236Swhu (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 949285236Swhu m_new->m_pkthdr.csum_data = 0xffff; 950285236Swhu } 951250199Sgrehan } 952250199Sgrehan 953250199Sgrehan if ((packet->vlan_tci != 0) && 954285236Swhu (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 955250199Sgrehan m_new->m_pkthdr.ether_vtag = packet->vlan_tci; 956250199Sgrehan m_new->m_flags |= M_VLANTAG; 957250199Sgrehan } 958250199Sgrehan 959250199Sgrehan /* 960250199Sgrehan * Note: Moved RX completion back to hv_nv_on_receive() so all 961250199Sgrehan * messages (not just data messages) will trigger a response. 962250199Sgrehan */ 963250199Sgrehan 964250199Sgrehan ifp->if_ipackets++; 965250199Sgrehan 966250199Sgrehan /* We're not holding the lock here, so don't release it */ 967250199Sgrehan (*ifp->if_input)(ifp, m_new); 968250199Sgrehan 969250199Sgrehan return (0); 970250199Sgrehan} 971250199Sgrehan 972250199Sgrehan/* 973256363Sgrehan * Rules for using sc->temp_unusable: 974256363Sgrehan * 1. sc->temp_unusable can only be read or written while holding NV_LOCK() 975256363Sgrehan * 2. code reading sc->temp_unusable under NV_LOCK(), and finding 976256363Sgrehan * sc->temp_unusable set, must release NV_LOCK() and exit 977256363Sgrehan * 3. to retain exclusive control of the interface, 978256363Sgrehan * sc->temp_unusable must be set by code before releasing NV_LOCK() 979256363Sgrehan * 4. only code setting sc->temp_unusable can clear sc->temp_unusable 980256363Sgrehan * 5. code setting sc->temp_unusable must eventually clear sc->temp_unusable 981256363Sgrehan */ 982256363Sgrehan 983256363Sgrehan/* 984250199Sgrehan * Standard ioctl entry point. Called when the user wants to configure 985250199Sgrehan * the interface. 986250199Sgrehan */ 987250199Sgrehanstatic int 988250199Sgrehanhn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 989250199Sgrehan{ 990250199Sgrehan hn_softc_t *sc = ifp->if_softc; 991250199Sgrehan struct ifreq *ifr = (struct ifreq *)data; 992285236Swhu#ifdef INET 993285236Swhu struct ifaddr *ifa = (struct ifaddr *)data; 994285236Swhu#endif 995250199Sgrehan netvsc_device_info device_info; 996250199Sgrehan struct hv_device *hn_dev; 997250199Sgrehan int mask, error = 0; 998256363Sgrehan int retry_cnt = 500; 999256363Sgrehan 1000250199Sgrehan switch(cmd) { 1001250199Sgrehan 1002250199Sgrehan case SIOCSIFADDR: 1003283100Sdelphij#ifdef INET 1004283100Sdelphij if (ifa->ifa_addr->sa_family == AF_INET) { 1005283100Sdelphij ifp->if_flags |= IFF_UP; 1006283100Sdelphij if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1007283100Sdelphij hn_ifinit(sc); 1008283100Sdelphij arp_ifinit(ifp, ifa); 1009283100Sdelphij } else 1010283100Sdelphij#endif 1011250199Sgrehan error = ether_ioctl(ifp, cmd, data); 1012250199Sgrehan break; 1013250199Sgrehan case SIOCSIFMTU: 1014250199Sgrehan hn_dev = vmbus_get_devctx(sc->hn_dev); 1015250199Sgrehan 1016256363Sgrehan /* Check MTU value change */ 1017256363Sgrehan if (ifp->if_mtu == ifr->ifr_mtu) 1018256363Sgrehan break; 1019250199Sgrehan 1020250199Sgrehan if (ifr->ifr_mtu > NETVSC_MAX_CONFIGURABLE_MTU) { 1021250199Sgrehan error = EINVAL; 1022250199Sgrehan break; 1023250199Sgrehan } 1024256363Sgrehan 1025250199Sgrehan /* Obtain and record requested MTU */ 1026250199Sgrehan ifp->if_mtu = ifr->ifr_mtu; 1027256363Sgrehan 1028256363Sgrehan do { 1029256363Sgrehan NV_LOCK(sc); 1030256363Sgrehan if (!sc->temp_unusable) { 1031256363Sgrehan sc->temp_unusable = TRUE; 1032256363Sgrehan retry_cnt = -1; 1033256363Sgrehan } 1034256363Sgrehan NV_UNLOCK(sc); 1035256363Sgrehan if (retry_cnt > 0) { 1036256363Sgrehan retry_cnt--; 1037256363Sgrehan DELAY(5 * 1000); 1038256363Sgrehan } 1039256363Sgrehan } while (retry_cnt > 0); 1040250199Sgrehan 1041256363Sgrehan if (retry_cnt == 0) { 1042256363Sgrehan error = EINVAL; 1043256363Sgrehan break; 1044256363Sgrehan } 1045256363Sgrehan 1046256363Sgrehan /* We must remove and add back the device to cause the new 1047250199Sgrehan * MTU to take effect. This includes tearing down, but not 1048250199Sgrehan * deleting the channel, then bringing it back up. 1049250199Sgrehan */ 1050250199Sgrehan error = hv_rf_on_device_remove(hn_dev, HV_RF_NV_RETAIN_CHANNEL); 1051250199Sgrehan if (error) { 1052256363Sgrehan NV_LOCK(sc); 1053256363Sgrehan sc->temp_unusable = FALSE; 1054250199Sgrehan NV_UNLOCK(sc); 1055250199Sgrehan break; 1056250199Sgrehan } 1057250199Sgrehan error = hv_rf_on_device_add(hn_dev, &device_info); 1058250199Sgrehan if (error) { 1059256363Sgrehan NV_LOCK(sc); 1060256363Sgrehan sc->temp_unusable = FALSE; 1061250199Sgrehan NV_UNLOCK(sc); 1062250199Sgrehan break; 1063250199Sgrehan } 1064250199Sgrehan 1065250199Sgrehan hn_ifinit_locked(sc); 1066250199Sgrehan 1067256363Sgrehan NV_LOCK(sc); 1068256363Sgrehan sc->temp_unusable = FALSE; 1069250199Sgrehan NV_UNLOCK(sc); 1070250199Sgrehan break; 1071250199Sgrehan case SIOCSIFFLAGS: 1072256363Sgrehan do { 1073256363Sgrehan NV_LOCK(sc); 1074256363Sgrehan if (!sc->temp_unusable) { 1075256363Sgrehan sc->temp_unusable = TRUE; 1076256363Sgrehan retry_cnt = -1; 1077256363Sgrehan } 1078256363Sgrehan NV_UNLOCK(sc); 1079256363Sgrehan if (retry_cnt > 0) { 1080256363Sgrehan retry_cnt--; 1081256363Sgrehan DELAY(5 * 1000); 1082256363Sgrehan } 1083256363Sgrehan } while (retry_cnt > 0); 1084256363Sgrehan 1085256363Sgrehan if (retry_cnt == 0) { 1086256363Sgrehan error = EINVAL; 1087256363Sgrehan break; 1088256363Sgrehan } 1089256363Sgrehan 1090250199Sgrehan if (ifp->if_flags & IFF_UP) { 1091250199Sgrehan /* 1092250199Sgrehan * If only the state of the PROMISC flag changed, 1093250199Sgrehan * then just use the 'set promisc mode' command 1094250199Sgrehan * instead of reinitializing the entire NIC. Doing 1095250199Sgrehan * a full re-init means reloading the firmware and 1096250199Sgrehan * waiting for it to start up, which may take a 1097250199Sgrehan * second or two. 1098250199Sgrehan */ 1099250199Sgrehan#ifdef notyet 1100250199Sgrehan /* Fixme: Promiscuous mode? */ 1101250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1102250199Sgrehan ifp->if_flags & IFF_PROMISC && 1103250199Sgrehan !(sc->hn_if_flags & IFF_PROMISC)) { 1104250199Sgrehan /* do something here for Hyper-V */ 1105250199Sgrehan } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1106256363Sgrehan !(ifp->if_flags & IFF_PROMISC) && 1107256363Sgrehan sc->hn_if_flags & IFF_PROMISC) { 1108250199Sgrehan /* do something here for Hyper-V */ 1109250199Sgrehan } else 1110250199Sgrehan#endif 1111250199Sgrehan hn_ifinit_locked(sc); 1112250199Sgrehan } else { 1113250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1114250199Sgrehan hn_stop(sc); 1115250199Sgrehan } 1116250199Sgrehan } 1117256363Sgrehan NV_LOCK(sc); 1118256363Sgrehan sc->temp_unusable = FALSE; 1119256363Sgrehan NV_UNLOCK(sc); 1120250199Sgrehan sc->hn_if_flags = ifp->if_flags; 1121250199Sgrehan error = 0; 1122250199Sgrehan break; 1123250199Sgrehan case SIOCSIFCAP: 1124250199Sgrehan mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1125285236Swhu if (mask & IFCAP_TXCSUM) { 1126285236Swhu if (IFCAP_TXCSUM & ifp->if_capenable) { 1127285236Swhu ifp->if_capenable &= ~IFCAP_TXCSUM; 1128285236Swhu ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); 1129250199Sgrehan } else { 1130285236Swhu ifp->if_capenable |= IFCAP_TXCSUM; 1131286058Swhu /* 1132286058Swhu * Only enable UDP checksum offloading on 1133286058Swhu * Windows Server 2012R2 or later releases. 1134286058Swhu */ 1135286058Swhu if (hv_vmbus_protocal_version >= 1136286058Swhu HV_VMBUS_VERSION_WIN8_1) { 1137286058Swhu ifp->if_hwassist |= 1138286058Swhu (CSUM_TCP | CSUM_UDP); 1139286058Swhu } else { 1140286058Swhu ifp->if_hwassist |= CSUM_TCP; 1141286058Swhu } 1142250199Sgrehan } 1143250199Sgrehan } 1144285236Swhu 1145285236Swhu if (mask & IFCAP_RXCSUM) { 1146285236Swhu if (IFCAP_RXCSUM & ifp->if_capenable) { 1147285236Swhu ifp->if_capenable &= ~IFCAP_RXCSUM; 1148285236Swhu } else { 1149285236Swhu ifp->if_capenable |= IFCAP_RXCSUM; 1150285236Swhu } 1151285236Swhu } 1152285236Swhu 1153285236Swhu if (mask & IFCAP_TSO4) { 1154285236Swhu ifp->if_capenable ^= IFCAP_TSO4; 1155285236Swhu ifp->if_hwassist ^= CSUM_IP_TSO; 1156285236Swhu } 1157285236Swhu 1158285236Swhu if (mask & IFCAP_TSO6) { 1159285236Swhu ifp->if_capenable ^= IFCAP_TSO6; 1160285236Swhu ifp->if_hwassist ^= CSUM_IP6_TSO; 1161285236Swhu } 1162285236Swhu 1163250199Sgrehan error = 0; 1164250199Sgrehan break; 1165250199Sgrehan case SIOCADDMULTI: 1166250199Sgrehan case SIOCDELMULTI: 1167250199Sgrehan#ifdef notyet 1168250199Sgrehan /* Fixme: Multicast mode? */ 1169250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1170250199Sgrehan NV_LOCK(sc); 1171250199Sgrehan netvsc_setmulti(sc); 1172250199Sgrehan NV_UNLOCK(sc); 1173250199Sgrehan error = 0; 1174250199Sgrehan } 1175250199Sgrehan#endif 1176250199Sgrehan /* FALLTHROUGH */ 1177250199Sgrehan case SIOCSIFMEDIA: 1178250199Sgrehan case SIOCGIFMEDIA: 1179250199Sgrehan error = EINVAL; 1180250199Sgrehan break; 1181250199Sgrehan default: 1182250199Sgrehan error = ether_ioctl(ifp, cmd, data); 1183250199Sgrehan break; 1184250199Sgrehan } 1185250199Sgrehan 1186250199Sgrehan return (error); 1187250199Sgrehan} 1188250199Sgrehan 1189250199Sgrehan/* 1190250199Sgrehan * 1191250199Sgrehan */ 1192250199Sgrehanstatic void 1193250199Sgrehanhn_stop(hn_softc_t *sc) 1194250199Sgrehan{ 1195250199Sgrehan struct ifnet *ifp; 1196250199Sgrehan int ret; 1197250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); 1198250199Sgrehan 1199250199Sgrehan ifp = sc->hn_ifp; 1200250199Sgrehan 1201263853Sdelphij if (bootverbose) 1202263853Sdelphij printf(" Closing Device ...\n"); 1203250199Sgrehan 1204250199Sgrehan ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1205283100Sdelphij if_link_state_change(ifp, LINK_STATE_DOWN); 1206250199Sgrehan sc->hn_initdone = 0; 1207250199Sgrehan 1208250199Sgrehan ret = hv_rf_on_close(device_ctx); 1209250199Sgrehan} 1210250199Sgrehan 1211250199Sgrehan/* 1212250199Sgrehan * FreeBSD transmit entry point 1213250199Sgrehan */ 1214250199Sgrehanstatic void 1215250199Sgrehanhn_start(struct ifnet *ifp) 1216250199Sgrehan{ 1217250199Sgrehan hn_softc_t *sc; 1218250199Sgrehan 1219250199Sgrehan sc = ifp->if_softc; 1220250199Sgrehan NV_LOCK(sc); 1221256363Sgrehan if (sc->temp_unusable) { 1222256363Sgrehan NV_UNLOCK(sc); 1223256363Sgrehan return; 1224256363Sgrehan } 1225250199Sgrehan hn_start_locked(ifp); 1226250199Sgrehan NV_UNLOCK(sc); 1227250199Sgrehan} 1228250199Sgrehan 1229250199Sgrehan/* 1230250199Sgrehan * 1231250199Sgrehan */ 1232250199Sgrehanstatic void 1233250199Sgrehanhn_ifinit_locked(hn_softc_t *sc) 1234250199Sgrehan{ 1235250199Sgrehan struct ifnet *ifp; 1236250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); 1237250199Sgrehan int ret; 1238250199Sgrehan 1239250199Sgrehan ifp = sc->hn_ifp; 1240250199Sgrehan 1241250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1242250199Sgrehan return; 1243250199Sgrehan } 1244250199Sgrehan 1245250199Sgrehan hv_promisc_mode = 1; 1246250199Sgrehan 1247250199Sgrehan ret = hv_rf_on_open(device_ctx); 1248250199Sgrehan if (ret != 0) { 1249250199Sgrehan return; 1250250199Sgrehan } else { 1251250199Sgrehan sc->hn_initdone = 1; 1252250199Sgrehan } 1253250199Sgrehan ifp->if_drv_flags |= IFF_DRV_RUNNING; 1254250199Sgrehan ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1255283100Sdelphij if_link_state_change(ifp, LINK_STATE_UP); 1256250199Sgrehan} 1257250199Sgrehan 1258250199Sgrehan/* 1259250199Sgrehan * 1260250199Sgrehan */ 1261250199Sgrehanstatic void 1262250199Sgrehanhn_ifinit(void *xsc) 1263250199Sgrehan{ 1264250199Sgrehan hn_softc_t *sc = xsc; 1265250199Sgrehan 1266250199Sgrehan NV_LOCK(sc); 1267256363Sgrehan if (sc->temp_unusable) { 1268256363Sgrehan NV_UNLOCK(sc); 1269256363Sgrehan return; 1270256363Sgrehan } 1271256363Sgrehan sc->temp_unusable = TRUE; 1272256363Sgrehan NV_UNLOCK(sc); 1273256363Sgrehan 1274250199Sgrehan hn_ifinit_locked(sc); 1275256363Sgrehan 1276256363Sgrehan NV_LOCK(sc); 1277256363Sgrehan sc->temp_unusable = FALSE; 1278250199Sgrehan NV_UNLOCK(sc); 1279250199Sgrehan} 1280250199Sgrehan 1281250199Sgrehan#ifdef LATER 1282250199Sgrehan/* 1283250199Sgrehan * 1284250199Sgrehan */ 1285250199Sgrehanstatic void 1286250199Sgrehanhn_watchdog(struct ifnet *ifp) 1287250199Sgrehan{ 1288250199Sgrehan hn_softc_t *sc; 1289250199Sgrehan sc = ifp->if_softc; 1290250199Sgrehan 1291250199Sgrehan printf("hn%d: watchdog timeout -- resetting\n", sc->hn_unit); 1292250199Sgrehan hn_ifinit(sc); /*???*/ 1293250199Sgrehan ifp->if_oerrors++; 1294250199Sgrehan} 1295250199Sgrehan#endif 1296250199Sgrehan 1297250199Sgrehanstatic device_method_t netvsc_methods[] = { 1298250199Sgrehan /* Device interface */ 1299250199Sgrehan DEVMETHOD(device_probe, netvsc_probe), 1300250199Sgrehan DEVMETHOD(device_attach, netvsc_attach), 1301250199Sgrehan DEVMETHOD(device_detach, netvsc_detach), 1302250199Sgrehan DEVMETHOD(device_shutdown, netvsc_shutdown), 1303250199Sgrehan 1304250199Sgrehan { 0, 0 } 1305250199Sgrehan}; 1306250199Sgrehan 1307250199Sgrehanstatic driver_t netvsc_driver = { 1308250199Sgrehan NETVSC_DEVNAME, 1309250199Sgrehan netvsc_methods, 1310250199Sgrehan sizeof(hn_softc_t) 1311250199Sgrehan}; 1312250199Sgrehan 1313250199Sgrehanstatic devclass_t netvsc_devclass; 1314250199Sgrehan 1315250199SgrehanDRIVER_MODULE(hn, vmbus, netvsc_driver, netvsc_devclass, 0, 0); 1316250199SgrehanMODULE_VERSION(hn, 1); 1317250199SgrehanMODULE_DEPEND(hn, vmbus, 1, 1, 1); 1318253869SgrehanSYSINIT(netvsc_initx, SI_SUB_KTHREAD_IDLE, SI_ORDER_MIDDLE + 1, netvsc_init, 1319250199Sgrehan NULL); 1320250199Sgrehan 1321