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