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