]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/netvsc/hv_rndis_filter.c
MFC 305049,305050
[FreeBSD/stable/10.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/kernel.h>
34 #include <sys/mbuf.h>
35 #include <sys/socket.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <net/if.h>
39 #include <net/if_arp.h>
40 #include <net/if_var.h>
41 #include <net/ethernet.h>
42 #include <sys/types.h>
43 #include <machine/atomic.h>
44 #include <sys/sema.h>
45 #include <vm/vm.h>
46 #include <vm/vm_param.h>
47 #include <vm/pmap.h>
48
49 #include <dev/hyperv/include/hyperv.h>
50 #include <dev/hyperv/include/vmbus_xact.h>
51 #include <dev/hyperv/netvsc/hv_net_vsc.h>
52 #include <dev/hyperv/netvsc/hv_rndis.h>
53 #include <dev/hyperv/netvsc/hv_rndis_filter.h>
54 #include <dev/hyperv/netvsc/if_hnreg.h>
55 #include <dev/hyperv/netvsc/ndis.h>
56
57 #define HV_RF_RECVINFO_VLAN     0x1
58 #define HV_RF_RECVINFO_CSUM     0x2
59 #define HV_RF_RECVINFO_HASHINF  0x4
60 #define HV_RF_RECVINFO_HASHVAL  0x8
61 #define HV_RF_RECVINFO_ALL              \
62         (HV_RF_RECVINFO_VLAN |          \
63          HV_RF_RECVINFO_CSUM |          \
64          HV_RF_RECVINFO_HASHINF |       \
65          HV_RF_RECVINFO_HASHVAL)
66
67 #define HN_RNDIS_RID_COMPAT_MASK        0xffff
68 #define HN_RNDIS_RID_COMPAT_MAX         HN_RNDIS_RID_COMPAT_MASK
69
70 #define HN_RNDIS_XFER_SIZE              2048
71
72 /*
73  * Forward declarations
74  */
75 static void hv_rf_receive_response(rndis_device *device,
76     const rndis_msg *response);
77 static void hv_rf_receive_indicate_status(rndis_device *device,
78     const rndis_msg *response);
79 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
80     const void *data, int dlen);
81 static inline int hv_rf_query_device_mac(rndis_device *device);
82 static inline int hv_rf_query_device_link_status(rndis_device *device);
83 static int  hv_rf_init_device(rndis_device *device);
84
85 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
86     const void *idata, size_t idlen, void *odata, size_t *odlen0);
87 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
88     size_t dlen);
89 static int hn_rndis_conf_offload(struct hn_softc *sc);
90 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
91 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
92
93 static __inline uint32_t
94 hn_rndis_rid(struct hn_softc *sc)
95 {
96         uint32_t rid;
97
98 again:
99         rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
100         if (rid == 0)
101                 goto again;
102
103         /* Use upper 16 bits for non-compat RNDIS messages. */
104         return ((rid & 0xffff) << 16);
105 }
106
107 /*
108  * Set the Per-Packet-Info with the specified type
109  */
110 void *
111 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
112         int pkt_type)
113 {
114         rndis_packet *rndis_pkt;
115         rndis_per_packet_info *rppi;
116
117         rndis_pkt = &rndis_mesg->msg.packet;
118         rndis_pkt->data_offset += rppi_size;
119
120         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
121             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
122
123         rppi->size = rppi_size;
124         rppi->type = pkt_type;
125         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
126
127         rndis_pkt->per_pkt_info_length += rppi_size;
128
129         return (rppi);
130 }
131
132 /*
133  * Get the Per-Packet-Info with the specified type
134  * return NULL if not found.
135  */
136 void *
137 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
138 {
139         rndis_per_packet_info *ppi;
140         int len;
141
142         if (rpkt->per_pkt_info_offset == 0)
143                 return (NULL);
144
145         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
146             rpkt->per_pkt_info_offset);
147         len = rpkt->per_pkt_info_length;
148
149         while (len > 0) {
150                 if (ppi->type == type)
151                         return (void *)((unsigned long)ppi +
152                             ppi->per_packet_info_offset);
153
154                 len -= ppi->size;
155                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
156         }
157
158         return (NULL);
159 }
160
161
162 /*
163  * Allow module_param to work and override to switch to promiscuous mode.
164  */
165 static inline rndis_device *
166 hv_get_rndis_device(void)
167 {
168         rndis_device *device;
169
170         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
171
172         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
173
174         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
175         STAILQ_INIT(&device->myrequest_list);
176
177         device->state = RNDIS_DEV_UNINITIALIZED;
178
179         return (device);
180 }
181
182 /*
183  *
184  */
185 static inline void
186 hv_put_rndis_device(rndis_device *device)
187 {
188         mtx_destroy(&device->req_lock);
189         free(device, M_NETVSC);
190 }
191
192 /*
193  * RNDIS filter receive response
194  */
195 static void 
196 hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
197 {
198         rndis_request *request = NULL;
199         rndis_request *next_request;
200         boolean_t found = FALSE;
201
202         mtx_lock(&device->req_lock);
203         request = STAILQ_FIRST(&device->myrequest_list);
204         while (request != NULL) {
205                 /*
206                  * All request/response message contains request_id as the
207                  * first field
208                  */
209                 if (request->request_msg.msg.init_request.request_id ==
210                                       response->msg.init_complete.request_id) {
211                         found = TRUE;
212                         break;
213                 }
214                 next_request = STAILQ_NEXT(request, mylist_entry);
215                 request = next_request;
216         }
217         mtx_unlock(&device->req_lock);
218
219         if (found) {
220                 if (response->msg_len <= sizeof(rndis_msg)) {
221                         memcpy(&request->response_msg, response,
222                             response->msg_len);
223                 } else {
224                         request->response_msg.msg.init_complete.status =
225                             RNDIS_STATUS_BUFFER_OVERFLOW;
226                 }
227                 sema_post(&request->wait_sema);
228         }
229 }
230
231 /*
232  * RNDIS filter receive indicate status
233  */
234 static void 
235 hv_rf_receive_indicate_status(rndis_device *device, const rndis_msg *response)
236 {
237         const rndis_indicate_status *indicate = &response->msg.indicate_status;
238                 
239         switch(indicate->status) {
240         case RNDIS_STATUS_MEDIA_CONNECT:
241                 netvsc_linkstatus_callback(device->sc, 1);
242                 break;
243         case RNDIS_STATUS_MEDIA_DISCONNECT:
244                 netvsc_linkstatus_callback(device->sc, 0);
245                 break;
246         default:
247                 /* TODO: */
248                 device_printf(device->sc->hn_dev,
249                     "unknown status %d received\n", indicate->status);
250                 break;
251         }
252 }
253
254 static int
255 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
256 {
257         const rndis_per_packet_info *ppi;
258         uint32_t mask, len;
259
260         info->vlan_info = NULL;
261         info->csum_info = NULL;
262         info->hash_info = NULL;
263         info->hash_value = NULL;
264
265         if (rpkt->per_pkt_info_offset == 0)
266                 return 0;
267
268         ppi = (const rndis_per_packet_info *)
269             ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
270         len = rpkt->per_pkt_info_length;
271         mask = 0;
272
273         while (len != 0) {
274                 const void *ppi_dptr;
275                 uint32_t ppi_dlen;
276
277                 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
278                         return EINVAL;
279                 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
280                 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
281
282                 switch (ppi->type) {
283                 case ieee_8021q_info:
284                         if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
285                                 return EINVAL;
286                         info->vlan_info = ppi_dptr;
287                         mask |= HV_RF_RECVINFO_VLAN;
288                         break;
289
290                 case tcpip_chksum_info:
291                         if (__predict_false(ppi_dlen <
292                             sizeof(rndis_tcp_ip_csum_info)))
293                                 return EINVAL;
294                         info->csum_info = ppi_dptr;
295                         mask |= HV_RF_RECVINFO_CSUM;
296                         break;
297
298                 case nbl_hash_value:
299                         if (__predict_false(ppi_dlen <
300                             sizeof(struct rndis_hash_value)))
301                                 return EINVAL;
302                         info->hash_value = ppi_dptr;
303                         mask |= HV_RF_RECVINFO_HASHVAL;
304                         break;
305
306                 case nbl_hash_info:
307                         if (__predict_false(ppi_dlen <
308                             sizeof(struct rndis_hash_info)))
309                                 return EINVAL;
310                         info->hash_info = ppi_dptr;
311                         mask |= HV_RF_RECVINFO_HASHINF;
312                         break;
313
314                 default:
315                         goto skip;
316                 }
317
318                 if (mask == HV_RF_RECVINFO_ALL) {
319                         /* All found; done */
320                         break;
321                 }
322 skip:
323                 if (__predict_false(len < ppi->size))
324                         return EINVAL;
325                 len -= ppi->size;
326                 ppi = (const rndis_per_packet_info *)
327                     ((const uint8_t *)ppi + ppi->size);
328         }
329         return 0;
330 }
331
332 /*
333  * RNDIS filter receive data
334  */
335 static void
336 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
337 {
338         const rndis_msg *message = data;
339         const rndis_packet *rndis_pkt;
340         uint32_t data_offset;
341         struct hn_recvinfo info;
342
343         rndis_pkt = &message->msg.packet;
344
345         /*
346          * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
347          * netvsc packet (ie tot_data_buf_len != message_length)
348          */
349
350         /* Remove rndis header, then pass data packet up the stack */
351         data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
352
353         dlen -= data_offset;
354         if (dlen < rndis_pkt->data_length) {
355                 if_printf(rxr->hn_ifp,
356                     "total length %u is less than data length %u\n",
357                     dlen, rndis_pkt->data_length);
358                 return;
359         }
360
361         dlen = rndis_pkt->data_length;
362         data = (const uint8_t *)data + data_offset;
363
364         if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
365                 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
366                 return;
367         }
368         netvsc_recv(rxr, data, dlen, &info);
369 }
370
371 /*
372  * RNDIS filter on receive
373  */
374 int
375 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
376     const void *data, int dlen)
377 {
378         rndis_device *rndis_dev;
379         const rndis_msg *rndis_hdr;
380         const struct rndis_comp_hdr *comp;
381
382         rndis_dev = sc->rndis_dev;
383         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
384                 return (EINVAL);
385
386         rndis_hdr = data;
387         switch (rndis_hdr->ndis_msg_type) {
388         /* data message */
389         case REMOTE_NDIS_PACKET_MSG:
390                 hv_rf_receive_data(rxr, data, dlen);
391                 break;
392
393         /* completion messages */
394         case REMOTE_NDIS_INITIALIZE_CMPLT:
395         case REMOTE_NDIS_QUERY_CMPLT:
396         case REMOTE_NDIS_SET_CMPLT:
397         case REMOTE_NDIS_KEEPALIVE_CMPLT:
398                 comp = data;
399                 if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
400                         /* Transition time compat code */
401                         hv_rf_receive_response(rndis_dev, rndis_hdr);
402                 } else {
403                         vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
404                 }
405                 break;
406
407         /* notification message */
408         case REMOTE_NDIS_INDICATE_STATUS_MSG:
409                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
410                 break;
411
412         case REMOTE_NDIS_RESET_CMPLT:
413                 /*
414                  * Reset completed, no rid.
415                  *
416                  * NOTE:
417                  * RESET is not issued by hn(4), so this message should
418                  * _not_ be observed.
419                  */
420                 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
421                 break;
422
423         default:
424                 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
425                         rndis_hdr->ndis_msg_type);
426                 break;
427         }
428         return (0);
429 }
430
431 /*
432  * RNDIS filter query device MAC address
433  */
434 static int
435 hv_rf_query_device_mac(rndis_device *device)
436 {
437         struct hn_softc *sc = device->sc;
438         size_t hwaddr_len;
439         int error;
440
441         hwaddr_len = ETHER_ADDR_LEN;
442         error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
443             device->hw_mac_addr, &hwaddr_len);
444         if (error)
445                 return (error);
446         if (hwaddr_len != ETHER_ADDR_LEN) {
447                 if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
448                 return (EINVAL);
449         }
450         return (0);
451 }
452
453 /*
454  * RNDIS filter query device link status
455  */
456 static inline int
457 hv_rf_query_device_link_status(rndis_device *device)
458 {
459         struct hn_softc *sc = device->sc;
460         size_t size;
461         int error;
462
463         size = sizeof(uint32_t);
464         error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
465             &device->link_status, &size);
466         if (error)
467                 return (error);
468         if (size != sizeof(uint32_t)) {
469                 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
470                 return (EINVAL);
471         }
472         return (0);
473 }
474
475 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
476         0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
477         0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
478         0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
479         0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
480         0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
481 };
482
483 static const void *
484 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
485     struct hn_send_ctx *sndc, size_t *comp_len)
486 {
487         struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
488         int gpa_cnt, error;
489         bus_addr_t paddr;
490
491         KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
492             ("invalid request length %zu", reqlen));
493
494         /*
495          * Setup the SG list.
496          */
497         paddr = vmbus_xact_req_paddr(xact);
498         KASSERT((paddr & PAGE_MASK) == 0,
499             ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
500         for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
501                 int len = PAGE_SIZE;
502
503                 if (reqlen == 0)
504                         break;
505                 if (reqlen < len)
506                         len = reqlen;
507
508                 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
509                 gpa[gpa_cnt].gpa_len = len;
510                 gpa[gpa_cnt].gpa_ofs = 0;
511
512                 reqlen -= len;
513         }
514         KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
515
516         /*
517          * Send this RNDIS control message and wait for its completion
518          * message.
519          */
520         vmbus_xact_activate(xact);
521         error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
522             gpa, gpa_cnt);
523         if (error) {
524                 vmbus_xact_deactivate(xact);
525                 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
526                 return (NULL);
527         }
528         return (vmbus_xact_wait(xact, comp_len));
529 }
530
531 static const void *
532 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
533     size_t reqlen, size_t *comp_len0, uint32_t comp_type)
534 {
535         const struct rndis_comp_hdr *comp;
536         size_t comp_len, min_complen = *comp_len0;
537
538         KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
539         KASSERT(min_complen >= sizeof(*comp),
540             ("invalid minimum complete len %zu", min_complen));
541
542         /*
543          * Execute the xact setup by the caller.
544          */
545         comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
546             &comp_len);
547         if (comp == NULL)
548                 return (NULL);
549
550         /*
551          * Check this RNDIS complete message.
552          */
553         if (comp_len < min_complen) {
554                 if (comp_len >= sizeof(*comp)) {
555                         /* rm_status field is valid */
556                         if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
557                             "status 0x%08x\n", comp_len, comp->rm_status);
558                 } else {
559                         if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
560                             comp_len);
561                 }
562                 return (NULL);
563         }
564         if (comp->rm_len < min_complen) {
565                 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
566                     comp->rm_len);
567                 return (NULL);
568         }
569         if (comp->rm_type != comp_type) {
570                 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
571                     "expect 0x%08x\n", comp->rm_type, comp_type);
572                 return (NULL);
573         }
574         if (comp->rm_rid != rid) {
575                 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
576                     "expect %u\n", comp->rm_rid, rid);
577                 return (NULL);
578         }
579         /* All pass! */
580         *comp_len0 = comp_len;
581         return (comp);
582 }
583
584 static int
585 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
586     const void *idata, size_t idlen, void *odata, size_t *odlen0)
587 {
588         struct rndis_query_req *req;
589         const struct rndis_query_comp *comp;
590         struct vmbus_xact *xact;
591         size_t reqlen, odlen = *odlen0, comp_len;
592         int error, ofs;
593         uint32_t rid;
594
595         reqlen = sizeof(*req) + idlen;
596         xact = vmbus_xact_get(sc->hn_xact, reqlen);
597         if (xact == NULL) {
598                 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
599                 return (ENXIO);
600         }
601         rid = hn_rndis_rid(sc);
602         req = vmbus_xact_req_data(xact);
603         req->rm_type = REMOTE_NDIS_QUERY_MSG;
604         req->rm_len = reqlen;
605         req->rm_rid = rid;
606         req->rm_oid = oid;
607         /*
608          * XXX
609          * This is _not_ RNDIS Spec conforming:
610          * "This MUST be set to 0 when there is no input data
611          *  associated with the OID."
612          *
613          * If this field was set to 0 according to the RNDIS Spec,
614          * Hyper-V would set non-SUCCESS status in the query
615          * completion.
616          */
617         req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
618
619         if (idlen > 0) {
620                 req->rm_infobuflen = idlen;
621                 /* Input data immediately follows RNDIS query. */
622                 memcpy(req + 1, idata, idlen);
623         }
624
625         comp_len = sizeof(*comp) + odlen;
626         comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
627             REMOTE_NDIS_QUERY_CMPLT);
628         if (comp == NULL) {
629                 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
630                 error = EIO;
631                 goto done;
632         }
633
634         if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
635                 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
636                     "status 0x%08x\n", oid, comp->rm_status);
637                 error = EIO;
638                 goto done;
639         }
640         if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
641                 /* No output data! */
642                 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
643                 *odlen0 = 0;
644                 error = 0;
645                 goto done;
646         }
647
648         /*
649          * Check output data length and offset.
650          */
651         /* ofs is the offset from the beginning of comp. */
652         ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
653         if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
654                 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
655                     "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
656                 error = EINVAL;
657                 goto done;
658         }
659
660         /*
661          * Save output data.
662          */
663         if (comp->rm_infobuflen < odlen)
664                 odlen = comp->rm_infobuflen;
665         memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
666         *odlen0 = odlen;
667
668         error = 0;
669 done:
670         vmbus_xact_put(xact);
671         return (error);
672 }
673
674 static int
675 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
676 {
677         struct ndis_rss_caps in, caps;
678         size_t caps_len;
679         int error;
680
681         /*
682          * Only NDIS 6.30+ is supported.
683          */
684         KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
685             ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
686         *rxr_cnt = 0;
687
688         memset(&in, 0, sizeof(in));
689         in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
690         in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
691         in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
692
693         caps_len = NDIS_RSS_CAPS_SIZE;
694         error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
695             &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
696         if (error)
697                 return (error);
698         if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
699                 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
700                     caps_len);
701                 return (EINVAL);
702         }
703
704         if (caps.ndis_nrxr == 0) {
705                 if_printf(sc->hn_ifp, "0 RX rings!?\n");
706                 return (EINVAL);
707         }
708         *rxr_cnt = caps.ndis_nrxr;
709
710         if (caps_len == NDIS_RSS_CAPS_SIZE) {
711                 if (bootverbose) {
712                         if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
713                             caps.ndis_nind);
714                 }
715         }
716         return (0);
717 }
718
719 static int
720 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
721 {
722         struct rndis_set_req *req;
723         const struct rndis_set_comp *comp;
724         struct vmbus_xact *xact;
725         size_t reqlen, comp_len;
726         uint32_t rid;
727         int error;
728
729         KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
730
731         reqlen = sizeof(*req) + dlen;
732         xact = vmbus_xact_get(sc->hn_xact, reqlen);
733         if (xact == NULL) {
734                 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
735                 return (ENXIO);
736         }
737         rid = hn_rndis_rid(sc);
738         req = vmbus_xact_req_data(xact);
739         req->rm_type = REMOTE_NDIS_SET_MSG;
740         req->rm_len = reqlen;
741         req->rm_rid = rid;
742         req->rm_oid = oid;
743         req->rm_infobuflen = dlen;
744         req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
745         /* Data immediately follows RNDIS set. */
746         memcpy(req + 1, data, dlen);
747
748         comp_len = sizeof(*comp);
749         comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
750             REMOTE_NDIS_SET_CMPLT);
751         if (comp == NULL) {
752                 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
753                 error = EIO;
754                 goto done;
755         }
756
757         if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
758                 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
759                     "status 0x%08x\n", oid, comp->rm_status);
760                 error = EIO;
761                 goto done;
762         }
763         error = 0;
764 done:
765         vmbus_xact_put(xact);
766         return (error);
767 }
768
769 static int
770 hn_rndis_conf_offload(struct hn_softc *sc)
771 {
772         struct ndis_offload_params params;
773         size_t paramsz;
774         int error;
775
776         /* NOTE: 0 means "no change" */
777         memset(&params, 0, sizeof(params));
778
779         params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
780         if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
781                 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
782                 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
783         } else {
784                 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
785                 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
786         }
787         params.ndis_hdr.ndis_size = paramsz;
788
789         params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
790         params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
791         params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
792         if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
793                 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
794                 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
795         }
796         params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
797         /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
798
799         error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, &params, paramsz);
800         if (error) {
801                 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
802         } else {
803                 if (bootverbose)
804                         if_printf(sc->hn_ifp, "offload config done\n");
805         }
806         return (error);
807 }
808
809 static int
810 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
811 {
812         struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
813         struct ndis_rss_params *prm = &rss->rss_params;
814         int i, error;
815
816         /*
817          * Only NDIS 6.30+ is supported.
818          */
819         KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
820             ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
821
822         memset(rss, 0, sizeof(*rss));
823         prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
824         prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
825         prm->ndis_hdr.ndis_size = sizeof(*rss);
826         prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
827             NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
828             NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
829         /* TODO: Take ndis_rss_caps.ndis_nind into account */
830         prm->ndis_indsize = sizeof(rss->rss_ind);
831         prm->ndis_indoffset =
832             __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
833         prm->ndis_keysize = sizeof(rss->rss_key);
834         prm->ndis_keyoffset =
835             __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
836
837         /* Setup RSS key */
838         memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
839
840         /* Setup RSS indirect table */
841         /* TODO: Take ndis_rss_caps.ndis_nind into account */
842         for (i = 0; i < NDIS_HASH_INDCNT; ++i)
843                 rss->rss_ind[i] = i % nchan;
844
845         error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
846             rss, sizeof(*rss));
847         if (error) {
848                 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
849         } else {
850                 if (bootverbose)
851                         if_printf(sc->hn_ifp, "RSS config done\n");
852         }
853         return (error);
854 }
855
856 static int
857 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
858 {
859         int error;
860
861         error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
862             &filter, sizeof(filter));
863         if (error) {
864                 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
865                     filter, error);
866         } else {
867                 if (bootverbose) {
868                         if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
869                             filter);
870                 }
871         }
872         return (error);
873 }
874
875 /*
876  * RNDIS filter init device
877  */
878 static int
879 hv_rf_init_device(rndis_device *device)
880 {
881         struct hn_softc *sc = device->sc;
882         struct rndis_init_req *req;
883         const struct rndis_init_comp *comp;
884         struct vmbus_xact *xact;
885         size_t comp_len;
886         uint32_t rid;
887         int error;
888
889         /* XXX */
890         device->state = RNDIS_DEV_INITIALIZED;
891
892         xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
893         if (xact == NULL) {
894                 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
895                 return (ENXIO);
896         }
897         rid = hn_rndis_rid(sc);
898         req = vmbus_xact_req_data(xact);
899         req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
900         req->rm_len = sizeof(*req);
901         req->rm_rid = rid;
902         req->rm_ver_major = RNDIS_VERSION_MAJOR;
903         req->rm_ver_minor = RNDIS_VERSION_MINOR;
904         req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
905
906         comp_len = RNDIS_INIT_COMP_SIZE_MIN;
907         comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
908             REMOTE_NDIS_INITIALIZE_CMPLT);
909         if (comp == NULL) {
910                 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
911                 error = EIO;
912                 goto done;
913         }
914
915         if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
916                 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
917                     comp->rm_status);
918                 error = EIO;
919                 goto done;
920         }
921         if (bootverbose) {
922                 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
923                     comp->rm_ver_major, comp->rm_ver_minor,
924                     comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
925         }
926         error = 0;
927
928 done:
929         if (xact != NULL)
930                 vmbus_xact_put(xact);
931         return (error);
932 }
933
934 /*
935  * RNDIS filter halt device
936  */
937 static int
938 hv_rf_halt_device(struct hn_softc *sc)
939 {
940         struct vmbus_xact *xact;
941         struct rndis_halt_req *halt;
942         struct hn_send_ctx sndc;
943         size_t comp_len;
944
945         xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
946         if (xact == NULL) {
947                 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
948                 return (ENXIO);
949         }
950         halt = vmbus_xact_req_data(xact);
951         halt->rm_type = REMOTE_NDIS_HALT_MSG;
952         halt->rm_len = sizeof(*halt);
953         halt->rm_rid = hn_rndis_rid(sc);
954
955         /* No RNDIS completion; rely on NVS message send completion */
956         hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
957         hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
958
959         vmbus_xact_put(xact);
960         if (bootverbose)
961                 if_printf(sc->hn_ifp, "RNDIS halt done\n");
962         return (0);
963 }
964
965 /*
966  * RNDIS filter on device add
967  */
968 int
969 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
970     int *nchan0, struct hn_rx_ring *rxr)
971 {
972         int ret;
973         rndis_device *rndis_dev;
974         netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
975         device_t dev = sc->hn_dev;
976         struct hn_nvs_subch_req *req;
977         const struct hn_nvs_subch_resp *resp;
978         size_t resp_len;
979         struct vmbus_xact *xact = NULL;
980         uint32_t status, nsubch;
981         int nchan = *nchan0;
982         int rxr_cnt;
983
984         rndis_dev = hv_get_rndis_device();
985         if (rndis_dev == NULL) {
986                 return (ENOMEM);
987         }
988         sc->rndis_dev = rndis_dev;
989         rndis_dev->sc = sc;
990
991         /*
992          * Let the inner driver handle this first to create the netvsc channel
993          * NOTE! Once the channel is created, we may get a receive callback 
994          * (hv_rf_on_receive()) before this call is completed.
995          * Note:  Earlier code used a function pointer here.
996          */
997         ret = hv_nv_on_device_add(sc, rxr);
998         if (ret != 0) {
999                 hv_put_rndis_device(rndis_dev);
1000                 return (ret);
1001         }
1002
1003         /*
1004          * Initialize the rndis device
1005          */
1006
1007         /* Send the rndis initialization message */
1008         ret = hv_rf_init_device(rndis_dev);
1009         if (ret != 0) {
1010                 /*
1011                  * TODO: If rndis init failed, we will need to shut down
1012                  * the channel
1013                  */
1014         }
1015
1016         /* Get the mac address */
1017         ret = hv_rf_query_device_mac(rndis_dev);
1018         if (ret != 0) {
1019                 /* TODO: shut down rndis device and the channel */
1020         }
1021
1022         /* Configure NDIS offload settings */
1023         hn_rndis_conf_offload(sc);
1024         
1025         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN);
1026
1027         hv_rf_query_device_link_status(rndis_dev);
1028         
1029         dev_info->link_state = rndis_dev->link_status;
1030
1031         if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
1032                 /*
1033                  * Either RSS is not supported, or multiple RX/TX rings
1034                  * are not requested.
1035                  */
1036                 *nchan0 = 1;
1037                 return (0);
1038         }
1039
1040         /*
1041          * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1042          * table entries.
1043          */
1044         ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1045         if (ret) {
1046                 /* No RSS; this is benign. */
1047                 *nchan0 = 1;
1048                 return (0);
1049         }
1050         if (nchan > rxr_cnt)
1051                 nchan = rxr_cnt;
1052         if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1053             rxr_cnt, nchan);
1054
1055         if (nchan == 1) {
1056                 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1057                 goto out;
1058         }
1059         
1060         /*
1061          * Ask NVS to allocate sub-channels.
1062          */
1063         xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1064         if (xact == NULL) {
1065                 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1066                 ret = ENXIO;
1067                 goto out;
1068         }
1069         req = vmbus_xact_req_data(xact);
1070         req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1071         req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1072         req->nvs_nsubch = nchan - 1;
1073
1074         resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len);
1075         if (resp == NULL) {
1076                 if_printf(sc->hn_ifp, "exec subch failed\n");
1077                 ret = EIO;
1078                 goto out;
1079         }
1080         if (resp_len < sizeof(*resp)) {
1081                 if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
1082                     resp_len);
1083                 ret = EINVAL;
1084                 goto out;
1085         }
1086         if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
1087                 if_printf(sc->hn_ifp, "not subch resp, type %u\n",
1088                     resp->nvs_type);
1089                 ret = EINVAL;
1090                 goto out;
1091         }
1092
1093         status = resp->nvs_status;
1094         nsubch = resp->nvs_nsubch;
1095         vmbus_xact_put(xact);
1096         xact = NULL;
1097
1098         if (status != HN_NVS_STATUS_OK) {
1099                 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1100                 ret = EIO;
1101                 goto out;
1102         }
1103         if (nsubch > nchan - 1) {
1104                 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1105                     nsubch, nchan - 1);
1106                 nsubch = nchan - 1;
1107         }
1108         nchan = nsubch + 1;
1109
1110         ret = hn_rndis_conf_rss(sc, nchan);
1111         if (ret != 0)
1112                 *nchan0 = 1;
1113         else
1114                 *nchan0 = nchan;
1115 out:
1116         if (xact != NULL)
1117                 vmbus_xact_put(xact);
1118         return (ret);
1119 }
1120
1121 /*
1122  * RNDIS filter on device remove
1123  */
1124 int
1125 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1126 {
1127         rndis_device *rndis_dev = sc->rndis_dev;
1128         int ret;
1129
1130         /* Halt and release the rndis device */
1131         ret = hv_rf_halt_device(sc);
1132
1133         sc->rndis_dev = NULL;
1134         hv_put_rndis_device(rndis_dev);
1135
1136         /* Pass control to inner driver to remove the device */
1137         ret |= hv_nv_on_device_remove(sc, destroy_channel);
1138
1139         return (ret);
1140 }
1141
1142 /*
1143  * RNDIS filter on open
1144  */
1145 int
1146 hv_rf_on_open(struct hn_softc *sc)
1147 {
1148         uint32_t filter;
1149
1150         /* XXX */
1151         if (hv_promisc_mode != 1) {
1152                 filter = NDIS_PACKET_TYPE_BROADCAST |
1153                     NDIS_PACKET_TYPE_ALL_MULTICAST |
1154                     NDIS_PACKET_TYPE_DIRECTED;
1155         } else {
1156                 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1157         }
1158         return (hn_rndis_set_rxfilter(sc, filter));
1159 }
1160
1161 /*
1162  * RNDIS filter on close
1163  */
1164 int 
1165 hv_rf_on_close(struct hn_softc *sc)
1166 {
1167
1168         return (hn_rndis_set_rxfilter(sc, 0));
1169 }
1170
1171 void
1172 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1173 {
1174
1175         netvsc_channel_rollup(rxr, txr);
1176 }