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