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