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