hyperv/hn: Switch to new RNDIS set for RX filters.
[freebsd.git] / sys / dev / hyperv / netvsc / hv_rndis_filter.c
1 /*-
2  * Copyright (c) 2009-2012,2016 Microsoft Corp.
3  * Copyright (c) 2010-2012 Citrix Inc.
4  * Copyright (c) 2012 NetApp Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <net/if_var.h>
40 #include <net/ethernet.h>
41 #include <sys/types.h>
42 #include <machine/atomic.h>
43 #include <sys/sema.h>
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/pmap.h>
47
48 #include <dev/hyperv/include/hyperv.h>
49 #include <dev/hyperv/include/vmbus_xact.h>
50 #include <dev/hyperv/netvsc/hv_net_vsc.h>
51 #include <dev/hyperv/netvsc/hv_rndis.h>
52 #include <dev/hyperv/netvsc/hv_rndis_filter.h>
53 #include <dev/hyperv/netvsc/if_hnreg.h>
54 #include <dev/hyperv/netvsc/ndis.h>
55
56 #define HV_RF_RECVINFO_VLAN     0x1
57 #define HV_RF_RECVINFO_CSUM     0x2
58 #define HV_RF_RECVINFO_HASHINF  0x4
59 #define HV_RF_RECVINFO_HASHVAL  0x8
60 #define HV_RF_RECVINFO_ALL              \
61         (HV_RF_RECVINFO_VLAN |          \
62          HV_RF_RECVINFO_CSUM |          \
63          HV_RF_RECVINFO_HASHINF |       \
64          HV_RF_RECVINFO_HASHVAL)
65
66 #define HN_RNDIS_RID_COMPAT_MASK        0xffff
67 #define HN_RNDIS_RID_COMPAT_MAX         HN_RNDIS_RID_COMPAT_MASK
68
69 #define HN_RNDIS_XFER_SIZE              2048
70
71 /*
72  * Forward declarations
73  */
74 static int  hv_rf_send_request(rndis_device *device, rndis_request *request,
75                                uint32_t message_type);
76 static void hv_rf_receive_response(rndis_device *device,
77     const rndis_msg *response);
78 static void hv_rf_receive_indicate_status(rndis_device *device,
79     const rndis_msg *response);
80 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
81     const void *data, int dlen);
82 static inline int hv_rf_query_device_mac(rndis_device *device);
83 static inline int hv_rf_query_device_link_status(rndis_device *device);
84 static int  hv_rf_init_device(rndis_device *device);
85 int
86 hv_rf_send_offload_request(struct hn_softc *sc,
87     rndis_offload_params *offloads);
88
89 static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
90     struct hn_softc *sc, struct vmbus_channel *chan,
91     const void *data, int dlen);
92 static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
93     struct hn_softc *sc, struct vmbus_channel *chan,
94     const void *data, int dlen);
95 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
96     const void *idata, size_t idlen, void *odata, size_t *odlen0);
97 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
98     size_t dlen);
99 static int hn_rndis_conf_offload(struct hn_softc *sc);
100 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
101 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
102
103 static __inline uint32_t
104 hn_rndis_rid(struct hn_softc *sc)
105 {
106         uint32_t rid;
107
108 again:
109         rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
110         if (rid == 0)
111                 goto again;
112
113         /* Use upper 16 bits for non-compat RNDIS messages. */
114         return ((rid & 0xffff) << 16);
115 }
116
117 /*
118  * Set the Per-Packet-Info with the specified type
119  */
120 void *
121 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
122         int pkt_type)
123 {
124         rndis_packet *rndis_pkt;
125         rndis_per_packet_info *rppi;
126
127         rndis_pkt = &rndis_mesg->msg.packet;
128         rndis_pkt->data_offset += rppi_size;
129
130         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
131             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
132
133         rppi->size = rppi_size;
134         rppi->type = pkt_type;
135         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
136
137         rndis_pkt->per_pkt_info_length += rppi_size;
138
139         return (rppi);
140 }
141
142 /*
143  * Get the Per-Packet-Info with the specified type
144  * return NULL if not found.
145  */
146 void *
147 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
148 {
149         rndis_per_packet_info *ppi;
150         int len;
151
152         if (rpkt->per_pkt_info_offset == 0)
153                 return (NULL);
154
155         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
156             rpkt->per_pkt_info_offset);
157         len = rpkt->per_pkt_info_length;
158
159         while (len > 0) {
160                 if (ppi->type == type)
161                         return (void *)((unsigned long)ppi +
162                             ppi->per_packet_info_offset);
163
164                 len -= ppi->size;
165                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
166         }
167
168         return (NULL);
169 }
170
171
172 /*
173  * Allow module_param to work and override to switch to promiscuous mode.
174  */
175 static inline rndis_device *
176 hv_get_rndis_device(void)
177 {
178         rndis_device *device;
179
180         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
181
182         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
183
184         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
185         STAILQ_INIT(&device->myrequest_list);
186
187         device->state = RNDIS_DEV_UNINITIALIZED;
188
189         return (device);
190 }
191
192 /*
193  *
194  */
195 static inline void
196 hv_put_rndis_device(rndis_device *device)
197 {
198         mtx_destroy(&device->req_lock);
199         free(device, M_NETVSC);
200 }
201
202 /*
203  *
204  */
205 static inline rndis_request *
206 hv_rndis_request(rndis_device *device, uint32_t message_type,
207                  uint32_t message_length)
208 {
209         rndis_request *request;
210         rndis_msg *rndis_mesg;
211         rndis_set_request *set;
212
213         request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
214
215         sema_init(&request->wait_sema, 0, "rndis sema");
216         
217         rndis_mesg = &request->request_msg;
218         rndis_mesg->ndis_msg_type = message_type;
219         rndis_mesg->msg_len = message_length;
220
221         /*
222          * Set the request id. This field is always after the rndis header
223          * for request/response packet types so we just use the set_request
224          * as a template.
225          */
226         set = &rndis_mesg->msg.set_request;
227         set->request_id = atomic_fetchadd_int(&device->new_request_id, 1) &
228             HN_RNDIS_RID_COMPAT_MASK;
229
230         /* Add to the request list */
231         mtx_lock(&device->req_lock);
232         STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
233         mtx_unlock(&device->req_lock);
234
235         return (request);
236 }
237
238 /*
239  *
240  */
241 static inline void
242 hv_put_rndis_request(rndis_device *device, rndis_request *request)
243 {
244         mtx_lock(&device->req_lock);
245         /* Fixme:  Has O(n) performance */
246         /*
247          * XXXKYS: Use Doubly linked lists.
248          */
249         STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
250             mylist_entry);
251         mtx_unlock(&device->req_lock);
252
253         sema_destroy(&request->wait_sema);
254         free(request, M_NETVSC);
255 }
256
257 /*
258  *
259  */
260 static int
261 hv_rf_send_request(rndis_device *device, rndis_request *request,
262     uint32_t message_type)
263 {
264         struct hn_softc *sc = device->sc;
265         uint32_t send_buf_section_idx, tot_data_buf_len;
266         struct vmbus_gpa gpa[2];
267         int gpa_cnt, send_buf_section_size;
268         hn_sent_callback_t cb;
269
270         /* Set up the packet to send it */
271         tot_data_buf_len = request->request_msg.msg_len;
272
273         gpa_cnt = 1;
274         gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
275         gpa[0].gpa_len = request->request_msg.msg_len;
276         gpa[0].gpa_ofs = (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
277
278         if (gpa[0].gpa_ofs + gpa[0].gpa_len > PAGE_SIZE) {
279                 gpa_cnt = 2;
280                 gpa[0].gpa_len = PAGE_SIZE - gpa[0].gpa_ofs;
281                 gpa[1].gpa_page =
282                     hv_get_phys_addr((char*)&request->request_msg +
283                     gpa[0].gpa_len) >> PAGE_SHIFT;
284                 gpa[1].gpa_ofs = 0;
285                 gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
286         }
287
288         if (message_type != REMOTE_NDIS_HALT_MSG)
289                 cb = hn_rndis_sent_cb;
290         else
291                 cb = hn_rndis_sent_halt;
292
293         if (tot_data_buf_len < sc->hn_chim_szmax) {
294                 send_buf_section_idx = hn_chim_alloc(sc);
295                 if (send_buf_section_idx != HN_NVS_CHIM_IDX_INVALID) {
296                         uint8_t *dest = sc->hn_chim +
297                                 (send_buf_section_idx * sc->hn_chim_szmax);
298
299                         memcpy(dest, &request->request_msg, request->request_msg.msg_len);
300                         send_buf_section_size = tot_data_buf_len;
301                         gpa_cnt = 0;
302                         goto sendit;
303                 }
304                 /* Failed to allocate chimney send buffer; move on */
305         }
306         send_buf_section_idx = HN_NVS_CHIM_IDX_INVALID;
307         send_buf_section_size = 0;
308
309 sendit:
310         hn_send_ctx_init(&request->send_ctx, cb, request,
311             send_buf_section_idx, send_buf_section_size);
312         return hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
313             &request->send_ctx, gpa, gpa_cnt);
314 }
315
316 /*
317  * RNDIS filter receive response
318  */
319 static void 
320 hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
321 {
322         rndis_request *request = NULL;
323         rndis_request *next_request;
324         boolean_t found = FALSE;
325
326         mtx_lock(&device->req_lock);
327         request = STAILQ_FIRST(&device->myrequest_list);
328         while (request != NULL) {
329                 /*
330                  * All request/response message contains request_id as the
331                  * first field
332                  */
333                 if (request->request_msg.msg.init_request.request_id ==
334                                       response->msg.init_complete.request_id) {
335                         found = TRUE;
336                         break;
337                 }
338                 next_request = STAILQ_NEXT(request, mylist_entry);
339                 request = next_request;
340         }
341         mtx_unlock(&device->req_lock);
342
343         if (found) {
344                 if (response->msg_len <= sizeof(rndis_msg)) {
345                         memcpy(&request->response_msg, response,
346                             response->msg_len);
347                 } else {
348                         request->response_msg.msg.init_complete.status =
349                             RNDIS_STATUS_BUFFER_OVERFLOW;
350                 }
351                 sema_post(&request->wait_sema);
352         }
353 }
354
355 int
356 hv_rf_send_offload_request(struct hn_softc *sc,
357     rndis_offload_params *offloads)
358 {
359         rndis_request *request;
360         rndis_set_request *set;
361         rndis_offload_params *offload_req;
362         rndis_set_complete *set_complete;       
363         rndis_device *rndis_dev = sc->rndis_dev;
364         device_t dev = sc->hn_dev;
365         uint32_t extlen = sizeof(rndis_offload_params);
366         int ret;
367
368         if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_4) {
369                 extlen = VERSION_4_OFFLOAD_SIZE;
370                 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
371                  * UDP checksum offload.
372                  */
373                 offloads->udp_ipv4_csum = 0;
374                 offloads->udp_ipv6_csum = 0;
375         }
376
377         request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
378             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
379         if (!request)
380                 return (ENOMEM);
381
382         set = &request->request_msg.msg.set_request;
383         set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
384         set->info_buffer_length = extlen;
385         set->info_buffer_offset = sizeof(rndis_set_request);
386         set->device_vc_handle = 0;
387
388         offload_req = (rndis_offload_params *)((unsigned long)set +
389             set->info_buffer_offset);
390         *offload_req = *offloads;
391         offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
392         offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
393         offload_req->header.size = extlen;
394
395         ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
396         if (ret != 0) {
397                 device_printf(dev, "hv send offload request failed, ret=%d!\n",
398                     ret);
399                 goto cleanup;
400         }
401
402         ret = sema_timedwait(&request->wait_sema, 5 * hz);
403         if (ret != 0) {
404                 device_printf(dev, "hv send offload request timeout\n");
405                 goto cleanup;
406         }
407
408         set_complete = &request->response_msg.msg.set_complete;
409         if (set_complete->status == RNDIS_STATUS_SUCCESS) {
410                 device_printf(dev, "hv send offload request succeeded\n");
411                 ret = 0;
412         } else {
413                 if (set_complete->status == RNDIS_STATUS_NOT_SUPPORTED) {
414                         device_printf(dev, "HV Not support offload\n");
415                         ret = 0;
416                 } else {
417                         ret = set_complete->status;
418                 }
419         }
420
421 cleanup:
422         hv_put_rndis_request(rndis_dev, request);
423
424         return (ret);
425 }
426
427 /*
428  * RNDIS filter receive indicate status
429  */
430 static void 
431 hv_rf_receive_indicate_status(rndis_device *device, const rndis_msg *response)
432 {
433         const rndis_indicate_status *indicate = &response->msg.indicate_status;
434                 
435         switch(indicate->status) {
436         case RNDIS_STATUS_MEDIA_CONNECT:
437                 netvsc_linkstatus_callback(device->sc, 1);
438                 break;
439         case RNDIS_STATUS_MEDIA_DISCONNECT:
440                 netvsc_linkstatus_callback(device->sc, 0);
441                 break;
442         default:
443                 /* TODO: */
444                 device_printf(device->sc->hn_dev,
445                     "unknown status %d received\n", indicate->status);
446                 break;
447         }
448 }
449
450 static int
451 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
452 {
453         const rndis_per_packet_info *ppi;
454         uint32_t mask, len;
455
456         info->vlan_info = NULL;
457         info->csum_info = NULL;
458         info->hash_info = NULL;
459         info->hash_value = NULL;
460
461         if (rpkt->per_pkt_info_offset == 0)
462                 return 0;
463
464         ppi = (const rndis_per_packet_info *)
465             ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
466         len = rpkt->per_pkt_info_length;
467         mask = 0;
468
469         while (len != 0) {
470                 const void *ppi_dptr;
471                 uint32_t ppi_dlen;
472
473                 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
474                         return EINVAL;
475                 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
476                 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
477
478                 switch (ppi->type) {
479                 case ieee_8021q_info:
480                         if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
481                                 return EINVAL;
482                         info->vlan_info = ppi_dptr;
483                         mask |= HV_RF_RECVINFO_VLAN;
484                         break;
485
486                 case tcpip_chksum_info:
487                         if (__predict_false(ppi_dlen <
488                             sizeof(rndis_tcp_ip_csum_info)))
489                                 return EINVAL;
490                         info->csum_info = ppi_dptr;
491                         mask |= HV_RF_RECVINFO_CSUM;
492                         break;
493
494                 case nbl_hash_value:
495                         if (__predict_false(ppi_dlen <
496                             sizeof(struct rndis_hash_value)))
497                                 return EINVAL;
498                         info->hash_value = ppi_dptr;
499                         mask |= HV_RF_RECVINFO_HASHVAL;
500                         break;
501
502                 case nbl_hash_info:
503                         if (__predict_false(ppi_dlen <
504                             sizeof(struct rndis_hash_info)))
505                                 return EINVAL;
506                         info->hash_info = ppi_dptr;
507                         mask |= HV_RF_RECVINFO_HASHINF;
508                         break;
509
510                 default:
511                         goto skip;
512                 }
513
514                 if (mask == HV_RF_RECVINFO_ALL) {
515                         /* All found; done */
516                         break;
517                 }
518 skip:
519                 if (__predict_false(len < ppi->size))
520                         return EINVAL;
521                 len -= ppi->size;
522                 ppi = (const rndis_per_packet_info *)
523                     ((const uint8_t *)ppi + ppi->size);
524         }
525         return 0;
526 }
527
528 /*
529  * RNDIS filter receive data
530  */
531 static void
532 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
533 {
534         const rndis_msg *message = data;
535         const rndis_packet *rndis_pkt;
536         uint32_t data_offset;
537         struct hn_recvinfo info;
538
539         rndis_pkt = &message->msg.packet;
540
541         /*
542          * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
543          * netvsc packet (ie tot_data_buf_len != message_length)
544          */
545
546         /* Remove rndis header, then pass data packet up the stack */
547         data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
548
549         dlen -= data_offset;
550         if (dlen < rndis_pkt->data_length) {
551                 if_printf(rxr->hn_ifp,
552                     "total length %u is less than data length %u\n",
553                     dlen, rndis_pkt->data_length);
554                 return;
555         }
556
557         dlen = rndis_pkt->data_length;
558         data = (const uint8_t *)data + data_offset;
559
560         if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
561                 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
562                 return;
563         }
564         netvsc_recv(rxr, data, dlen, &info);
565 }
566
567 /*
568  * RNDIS filter on receive
569  */
570 int
571 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
572     const void *data, int dlen)
573 {
574         rndis_device *rndis_dev;
575         const rndis_msg *rndis_hdr;
576         const struct rndis_comp_hdr *comp;
577
578         rndis_dev = sc->rndis_dev;
579         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
580                 return (EINVAL);
581
582         rndis_hdr = data;
583         switch (rndis_hdr->ndis_msg_type) {
584         /* data message */
585         case REMOTE_NDIS_PACKET_MSG:
586                 hv_rf_receive_data(rxr, data, dlen);
587                 break;
588
589         /* completion messages */
590         case REMOTE_NDIS_INITIALIZE_CMPLT:
591         case REMOTE_NDIS_QUERY_CMPLT:
592         case REMOTE_NDIS_SET_CMPLT:
593         case REMOTE_NDIS_KEEPALIVE_CMPLT:
594                 comp = data;
595                 if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
596                         /* Transition time compat code */
597                         hv_rf_receive_response(rndis_dev, rndis_hdr);
598                 } else {
599                         vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
600                 }
601                 break;
602
603         /* notification message */
604         case REMOTE_NDIS_INDICATE_STATUS_MSG:
605                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
606                 break;
607
608         case REMOTE_NDIS_RESET_CMPLT:
609                 /*
610                  * Reset completed, no rid.
611                  *
612                  * NOTE:
613                  * RESET is not issued by hn(4), so this message should
614                  * _not_ be observed.
615                  */
616                 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
617                 break;
618
619         default:
620                 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
621                         rndis_hdr->ndis_msg_type);
622                 break;
623         }
624         return (0);
625 }
626
627 /*
628  * RNDIS filter query device MAC address
629  */
630 static int
631 hv_rf_query_device_mac(rndis_device *device)
632 {
633         struct hn_softc *sc = device->sc;
634         size_t hwaddr_len;
635         int error;
636
637         hwaddr_len = ETHER_ADDR_LEN;
638         error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
639             device->hw_mac_addr, &hwaddr_len);
640         if (error)
641                 return (error);
642         if (hwaddr_len != ETHER_ADDR_LEN) {
643                 if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
644                 return (EINVAL);
645         }
646         return (0);
647 }
648
649 /*
650  * RNDIS filter query device link status
651  */
652 static inline int
653 hv_rf_query_device_link_status(rndis_device *device)
654 {
655         struct hn_softc *sc = device->sc;
656         size_t size;
657         int error;
658
659         size = sizeof(uint32_t);
660         error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
661             &device->link_status, &size);
662         if (error)
663                 return (error);
664         if (size != sizeof(uint32_t)) {
665                 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
666                 return (EINVAL);
667         }
668         return (0);
669 }
670
671 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
672         0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
673         0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
674         0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
675         0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
676         0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
677 };
678
679 static const void *
680 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
681     size_t reqlen, size_t *comp_len0, uint32_t comp_type)
682 {
683         struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
684         const struct rndis_comp_hdr *comp;
685         bus_addr_t paddr;
686         size_t comp_len, min_complen = *comp_len0;
687         int gpa_cnt, error;
688
689         KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
690         KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
691             ("invalid request length %zu", reqlen));
692         KASSERT(min_complen >= sizeof(*comp),
693             ("invalid minimum complete len %zu", min_complen));
694
695         /*
696          * Setup the SG list.
697          */
698         paddr = vmbus_xact_req_paddr(xact);
699         KASSERT((paddr & PAGE_MASK) == 0,
700             ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
701         for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
702                 int len = PAGE_SIZE;
703
704                 if (reqlen == 0)
705                         break;
706                 if (reqlen < len)
707                         len = reqlen;
708
709                 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
710                 gpa[gpa_cnt].gpa_len = len;
711                 gpa[gpa_cnt].gpa_ofs = 0;
712
713                 reqlen -= len;
714         }
715         KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
716
717         /*
718          * Send this RNDIS control message and wait for its completion
719          * message.
720          */
721         vmbus_xact_activate(xact);
722         error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
723             &hn_send_ctx_none, gpa, gpa_cnt);
724         if (error) {
725                 vmbus_xact_deactivate(xact);
726                 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
727                 return (NULL);
728         }
729         comp = vmbus_xact_wait(xact, &comp_len);
730
731         /*
732          * Check this RNDIS complete message.
733          */
734         if (comp_len < min_complen) {
735                 if (comp_len >= sizeof(*comp)) {
736                         /* rm_status field is valid */
737                         if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
738                             "status 0x%08x\n", comp_len, comp->rm_status);
739                 } else {
740                         if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
741                             comp_len);
742                 }
743                 return (NULL);
744         }
745         if (comp->rm_len < min_complen) {
746                 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
747                     comp->rm_len);
748                 return (NULL);
749         }
750         if (comp->rm_type != comp_type) {
751                 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
752                     "expect 0x%08x\n", comp->rm_type, comp_type);
753                 return (NULL);
754         }
755         if (comp->rm_rid != rid) {
756                 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
757                     "expect %u\n", comp->rm_rid, rid);
758                 return (NULL);
759         }
760         /* All pass! */
761         *comp_len0 = comp_len;
762         return (comp);
763 }
764
765 static int
766 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
767     const void *idata, size_t idlen, void *odata, size_t *odlen0)
768 {
769         struct rndis_query_req *req;
770         const struct rndis_query_comp *comp;
771         struct vmbus_xact *xact;
772         size_t reqlen, odlen = *odlen0, comp_len;
773         int error, ofs;
774         uint32_t rid;
775
776         reqlen = sizeof(*req) + idlen;
777         xact = vmbus_xact_get(sc->hn_xact, reqlen);
778         if (xact == NULL) {
779                 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
780                 return (ENXIO);
781         }
782         rid = hn_rndis_rid(sc);
783         req = vmbus_xact_req_data(xact);
784         req->rm_type = REMOTE_NDIS_QUERY_MSG;
785         req->rm_len = reqlen;
786         req->rm_rid = rid;
787         req->rm_oid = oid;
788         /*
789          * XXX
790          * This is _not_ RNDIS Spec conforming:
791          * "This MUST be set to 0 when there is no input data
792          *  associated with the OID."
793          *
794          * If this field was set to 0 according to the RNDIS Spec,
795          * Hyper-V would set non-SUCCESS status in the query
796          * completion.
797          */
798         req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
799
800         if (idlen > 0) {
801                 req->rm_infobuflen = idlen;
802                 /* Input data immediately follows RNDIS query. */
803                 memcpy(req + 1, idata, idlen);
804         }
805
806         comp_len = sizeof(*comp) + odlen;
807         comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
808             REMOTE_NDIS_QUERY_CMPLT);
809         if (comp == NULL) {
810                 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
811                 error = EIO;
812                 goto done;
813         }
814
815         if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
816                 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
817                     "status 0x%08x\n", oid, comp->rm_status);
818                 error = EIO;
819                 goto done;
820         }
821         if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
822                 /* No output data! */
823                 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
824                 *odlen0 = 0;
825                 error = 0;
826                 goto done;
827         }
828
829         /*
830          * Check output data length and offset.
831          */
832         /* ofs is the offset from the beginning of comp. */
833         ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
834         if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
835                 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
836                     "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
837                 error = EINVAL;
838                 goto done;
839         }
840
841         /*
842          * Save output data.
843          */
844         if (comp->rm_infobuflen < odlen)
845                 odlen = comp->rm_infobuflen;
846         memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
847         *odlen0 = odlen;
848
849         error = 0;
850 done:
851         vmbus_xact_put(xact);
852         return (error);
853 }
854
855 static int
856 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
857 {
858         struct ndis_rss_caps in, caps;
859         size_t caps_len;
860         int error;
861
862         /*
863          * Only NDIS 6.30+ is supported.
864          */
865         KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
866             ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
867         *rxr_cnt = 0;
868
869         memset(&in, 0, sizeof(in));
870         in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
871         in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
872         in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
873
874         caps_len = NDIS_RSS_CAPS_SIZE;
875         error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
876             &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
877         if (error)
878                 return (error);
879         if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
880                 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
881                     caps_len);
882                 return (EINVAL);
883         }
884
885         if (caps.ndis_nrxr == 0) {
886                 if_printf(sc->hn_ifp, "0 RX rings!?\n");
887                 return (EINVAL);
888         }
889         *rxr_cnt = caps.ndis_nrxr;
890
891         if (caps_len == NDIS_RSS_CAPS_SIZE) {
892                 if (bootverbose) {
893                         if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
894                             caps.ndis_nind);
895                 }
896         }
897         return (0);
898 }
899
900 static int
901 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
902 {
903         struct rndis_set_req *req;
904         const struct rndis_set_comp *comp;
905         struct vmbus_xact *xact;
906         size_t reqlen, comp_len;
907         uint32_t rid;
908         int error;
909
910         KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
911
912         reqlen = sizeof(*req) + dlen;
913         xact = vmbus_xact_get(sc->hn_xact, reqlen);
914         if (xact == NULL) {
915                 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
916                 return (ENXIO);
917         }
918         rid = hn_rndis_rid(sc);
919         req = vmbus_xact_req_data(xact);
920         req->rm_type = REMOTE_NDIS_SET_MSG;
921         req->rm_len = reqlen;
922         req->rm_rid = rid;
923         req->rm_oid = oid;
924         req->rm_infobuflen = dlen;
925         req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
926         /* Data immediately follows RNDIS set. */
927         memcpy(req + 1, data, dlen);
928
929         comp_len = sizeof(*comp);
930         comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
931             REMOTE_NDIS_SET_CMPLT);
932         if (comp == NULL) {
933                 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
934                 error = EIO;
935                 goto done;
936         }
937
938         if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
939                 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
940                     "status 0x%08x\n", oid, comp->rm_status);
941                 error = EIO;
942                 goto done;
943         }
944         error = 0;
945 done:
946         vmbus_xact_put(xact);
947         return (error);
948 }
949
950 static int
951 hn_rndis_conf_offload(struct hn_softc *sc)
952 {
953         struct ndis_offload_params params;
954         size_t paramsz;
955         int error;
956
957         /* NOTE: 0 means "no change" */
958         memset(&params, 0, sizeof(params));
959
960         params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
961         if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
962                 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
963                 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
964         } else {
965                 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
966                 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
967         }
968         params.ndis_hdr.ndis_size = paramsz;
969
970         params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
971         params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
972         params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
973         if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
974                 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
975                 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
976         }
977         params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
978         /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
979
980         error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, &params, paramsz);
981         if (error) {
982                 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
983         } else {
984                 if (bootverbose)
985                         if_printf(sc->hn_ifp, "offload config done\n");
986         }
987         return (error);
988 }
989
990 static int
991 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
992 {
993         struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
994         struct ndis_rss_params *prm = &rss->rss_params;
995         int i, error;
996
997         /*
998          * Only NDIS 6.30+ is supported.
999          */
1000         KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
1001             ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
1002
1003         memset(rss, 0, sizeof(*rss));
1004         prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
1005         prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
1006         prm->ndis_hdr.ndis_size = sizeof(*rss);
1007         prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
1008             NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
1009             NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
1010         /* TODO: Take ndis_rss_caps.ndis_nind into account */
1011         prm->ndis_indsize = sizeof(rss->rss_ind);
1012         prm->ndis_indoffset =
1013             __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
1014         prm->ndis_keysize = sizeof(rss->rss_key);
1015         prm->ndis_keyoffset =
1016             __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
1017
1018         /* Setup RSS key */
1019         memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
1020
1021         /* Setup RSS indirect table */
1022         /* TODO: Take ndis_rss_caps.ndis_nind into account */
1023         for (i = 0; i < NDIS_HASH_INDCNT; ++i)
1024                 rss->rss_ind[i] = i % nchan;
1025
1026         error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
1027             rss, sizeof(*rss));
1028         if (error) {
1029                 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
1030         } else {
1031                 if (bootverbose)
1032                         if_printf(sc->hn_ifp, "RSS config done\n");
1033         }
1034         return (error);
1035 }
1036
1037 static int
1038 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
1039 {
1040         int error;
1041
1042         error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
1043             &filter, sizeof(filter));
1044         if (error) {
1045                 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
1046                     filter, error);
1047         } else {
1048                 if (bootverbose) {
1049                         if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
1050                             filter);
1051                 }
1052         }
1053         return (error);
1054 }
1055
1056 /*
1057  * RNDIS filter init device
1058  */
1059 static int
1060 hv_rf_init_device(rndis_device *device)
1061 {
1062         struct hn_softc *sc = device->sc;
1063         struct rndis_init_req *req;
1064         const struct rndis_init_comp *comp;
1065         struct vmbus_xact *xact;
1066         size_t comp_len;
1067         uint32_t rid;
1068         int error;
1069
1070         /* XXX */
1071         device->state = RNDIS_DEV_INITIALIZED;
1072
1073         xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1074         if (xact == NULL) {
1075                 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
1076                 return (ENXIO);
1077         }
1078         rid = hn_rndis_rid(sc);
1079         req = vmbus_xact_req_data(xact);
1080         req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
1081         req->rm_len = sizeof(*req);
1082         req->rm_rid = rid;
1083         req->rm_ver_major = RNDIS_VERSION_MAJOR;
1084         req->rm_ver_minor = RNDIS_VERSION_MINOR;
1085         req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
1086
1087         comp_len = RNDIS_INIT_COMP_SIZE_MIN;
1088         comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
1089             REMOTE_NDIS_INITIALIZE_CMPLT);
1090         if (comp == NULL) {
1091                 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
1092                 error = EIO;
1093                 goto done;
1094         }
1095
1096         if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
1097                 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
1098                     comp->rm_status);
1099                 error = EIO;
1100                 goto done;
1101         }
1102         if (bootverbose) {
1103                 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
1104                     comp->rm_ver_major, comp->rm_ver_minor,
1105                     comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
1106         }
1107         error = 0;
1108
1109 done:
1110         if (xact != NULL)
1111                 vmbus_xact_put(xact);
1112         return (error);
1113 }
1114
1115 #define HALT_COMPLETION_WAIT_COUNT      25
1116
1117 /*
1118  * RNDIS filter halt device
1119  */
1120 static int
1121 hv_rf_halt_device(rndis_device *device)
1122 {
1123         rndis_request *request;
1124         int i, ret;
1125
1126         /* Attempt to do a rndis device halt */
1127         request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
1128             RNDIS_MESSAGE_SIZE(rndis_halt_request));
1129         if (request == NULL) {
1130                 return (-1);
1131         }
1132
1133         /* initialize "poor man's semaphore" */
1134         request->halt_complete_flag = 0;
1135
1136         ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
1137         if (ret != 0) {
1138                 return (-1);
1139         }
1140
1141         /*
1142          * Wait for halt response from halt callback.  We must wait for
1143          * the transaction response before freeing the request and other
1144          * resources.
1145          */
1146         for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
1147                 if (request->halt_complete_flag != 0) {
1148                         break;
1149                 }
1150                 DELAY(400);
1151         }
1152         if (i == 0) {
1153                 return (-1);
1154         }
1155
1156         device->state = RNDIS_DEV_UNINITIALIZED;
1157
1158         hv_put_rndis_request(device, request);
1159
1160         return (0);
1161 }
1162
1163 /*
1164  * RNDIS filter on device add
1165  */
1166 int
1167 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1168     int *nchan0, struct hn_rx_ring *rxr)
1169 {
1170         int ret;
1171         rndis_device *rndis_dev;
1172         netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1173         device_t dev = sc->hn_dev;
1174         struct hn_nvs_subch_req *req;
1175         const struct hn_nvs_subch_resp *resp;
1176         size_t resp_len;
1177         struct vmbus_xact *xact = NULL;
1178         uint32_t status, nsubch;
1179         int nchan = *nchan0;
1180         int rxr_cnt;
1181
1182         rndis_dev = hv_get_rndis_device();
1183         if (rndis_dev == NULL) {
1184                 return (ENOMEM);
1185         }
1186         sc->rndis_dev = rndis_dev;
1187         rndis_dev->sc = sc;
1188
1189         /*
1190          * Let the inner driver handle this first to create the netvsc channel
1191          * NOTE! Once the channel is created, we may get a receive callback 
1192          * (hv_rf_on_receive()) before this call is completed.
1193          * Note:  Earlier code used a function pointer here.
1194          */
1195         ret = hv_nv_on_device_add(sc, rxr);
1196         if (ret != 0) {
1197                 hv_put_rndis_device(rndis_dev);
1198                 return (ret);
1199         }
1200
1201         /*
1202          * Initialize the rndis device
1203          */
1204
1205         /* Send the rndis initialization message */
1206         ret = hv_rf_init_device(rndis_dev);
1207         if (ret != 0) {
1208                 /*
1209                  * TODO: If rndis init failed, we will need to shut down
1210                  * the channel
1211                  */
1212         }
1213
1214         /* Get the mac address */
1215         ret = hv_rf_query_device_mac(rndis_dev);
1216         if (ret != 0) {
1217                 /* TODO: shut down rndis device and the channel */
1218         }
1219
1220         /* Configure NDIS offload settings */
1221         hn_rndis_conf_offload(sc);
1222         
1223         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN);
1224
1225         hv_rf_query_device_link_status(rndis_dev);
1226         
1227         dev_info->link_state = rndis_dev->link_status;
1228
1229         if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
1230                 /*
1231                  * Either RSS is not supported, or multiple RX/TX rings
1232                  * are not requested.
1233                  */
1234                 *nchan0 = 1;
1235                 return (0);
1236         }
1237
1238         /*
1239          * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1240          * table entries.
1241          */
1242         ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1243         if (ret) {
1244                 /* No RSS; this is benign. */
1245                 *nchan0 = 1;
1246                 return (0);
1247         }
1248         if (nchan > rxr_cnt)
1249                 nchan = rxr_cnt;
1250         if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1251             rxr_cnt, nchan);
1252
1253         if (nchan == 1) {
1254                 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1255                 goto out;
1256         }
1257         
1258         /*
1259          * Ask NVS to allocate sub-channels.
1260          */
1261         xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1262         if (xact == NULL) {
1263                 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1264                 ret = ENXIO;
1265                 goto out;
1266         }
1267         req = vmbus_xact_req_data(xact);
1268         req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1269         req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1270         req->nvs_nsubch = nchan - 1;
1271
1272         resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len);
1273         if (resp == NULL) {
1274                 if_printf(sc->hn_ifp, "exec subch failed\n");
1275                 ret = EIO;
1276                 goto out;
1277         }
1278         if (resp_len < sizeof(*resp)) {
1279                 if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
1280                     resp_len);
1281                 ret = EINVAL;
1282                 goto out;
1283         }
1284         if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
1285                 if_printf(sc->hn_ifp, "not subch resp, type %u\n",
1286                     resp->nvs_type);
1287                 ret = EINVAL;
1288                 goto out;
1289         }
1290
1291         status = resp->nvs_status;
1292         nsubch = resp->nvs_nsubch;
1293         vmbus_xact_put(xact);
1294         xact = NULL;
1295
1296         if (status != HN_NVS_STATUS_OK) {
1297                 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1298                 ret = EIO;
1299                 goto out;
1300         }
1301         if (nsubch > nchan - 1) {
1302                 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1303                     nsubch, nchan - 1);
1304                 nsubch = nchan - 1;
1305         }
1306         nchan = nsubch + 1;
1307
1308         ret = hn_rndis_conf_rss(sc, nchan);
1309         if (ret != 0)
1310                 *nchan0 = 1;
1311         else
1312                 *nchan0 = nchan;
1313 out:
1314         if (xact != NULL)
1315                 vmbus_xact_put(xact);
1316         return (ret);
1317 }
1318
1319 /*
1320  * RNDIS filter on device remove
1321  */
1322 int
1323 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1324 {
1325         rndis_device *rndis_dev = sc->rndis_dev;
1326         int ret;
1327
1328         /* Halt and release the rndis device */
1329         ret = hv_rf_halt_device(rndis_dev);
1330
1331         sc->rndis_dev = NULL;
1332         hv_put_rndis_device(rndis_dev);
1333
1334         /* Pass control to inner driver to remove the device */
1335         ret |= hv_nv_on_device_remove(sc, destroy_channel);
1336
1337         return (ret);
1338 }
1339
1340 /*
1341  * RNDIS filter on open
1342  */
1343 int
1344 hv_rf_on_open(struct hn_softc *sc)
1345 {
1346         uint32_t filter;
1347
1348         /* XXX */
1349         if (hv_promisc_mode != 1) {
1350                 filter = NDIS_PACKET_TYPE_BROADCAST |
1351                     NDIS_PACKET_TYPE_ALL_MULTICAST |
1352                     NDIS_PACKET_TYPE_DIRECTED;
1353         } else {
1354                 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1355         }
1356         return (hn_rndis_set_rxfilter(sc, filter));
1357 }
1358
1359 /*
1360  * RNDIS filter on close
1361  */
1362 int 
1363 hv_rf_on_close(struct hn_softc *sc)
1364 {
1365
1366         return (hn_rndis_set_rxfilter(sc, 0));
1367 }
1368
1369 static void
1370 hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct hn_softc *sc,
1371     struct vmbus_channel *chan __unused, const void *data __unused,
1372     int dlen __unused)
1373 {
1374         if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1375                 hn_chim_free(sc, sndc->hn_chim_idx);
1376 }
1377
1378 static void
1379 hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct hn_softc *sc,
1380     struct vmbus_channel *chan __unused, const void *data __unused,
1381     int dlen __unused)
1382 {
1383         rndis_request *request = sndc->hn_cbarg;
1384
1385         if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1386                 hn_chim_free(sc, sndc->hn_chim_idx);
1387
1388         /*
1389          * Notify hv_rf_halt_device() about halt completion.
1390          * The halt code must wait for completion before freeing
1391          * the transaction resources.
1392          */
1393         request->halt_complete_flag = 1;
1394 }
1395
1396 void
1397 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1398 {
1399
1400         netvsc_channel_rollup(rxr, txr);
1401 }